├── .gitignore ├── LICENSE ├── README.md ├── config └── scripts.json ├── images ├── icon.png └── screenshot.png ├── main.py ├── manifest.json ├── src ├── __init__.py ├── consts.py ├── functions.py ├── items.py └── scripts.py └── versions.json /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nastuzzi Samy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Custom scripts 2 | 3 | This is a Ulauncher extension to launch your own scripts. 4 | 5 | ## Table of Contents 6 | 7 | - [Custom scripts](#custom-scripts) 8 | - [Table of Contents](#table-of-contents) 9 | - [Screenshot](#screenshot) 10 | - [Installation](#installation) 11 | - [Requirements](#requirements) 12 | - [Ulauncher's GUI](#ulaunchers-gui) 13 | - [Manually from source](#manually-from-source) 14 | - [Configuration](#configuration) 15 | - [Script file](#script-file) 16 | - [Usage](#usage) 17 | - [License](#license) 18 | 19 | ## Screenshot 20 | 21 | ![Screenshot](images/screenshot.png) 22 | 23 | ## Installation 24 | 25 | ### Requirements 26 | 27 | No external modules are required. Just install what you need for your custom scripts to work! 28 | 29 | ### Ulauncher's GUI 30 | 31 | 1. Open Ulauncher's settings and the "Extensions" tab 32 | 2. Click "Add extension" button 33 | 3. Paste this URL: `https://github.com/NastuzziSamy/ulauncher-custom-scripts` 34 | 4. Click "Add" button – the extension will be installed 35 | 36 | ### Manually from source 37 | 38 | The extensions' directory is located at: `$HOME/.local/share/ulauncher/extensions` 39 | 40 | Go to that location, and while being inside, just `git clone` this repository. 41 | 42 | ## Configuration 43 | 44 | In Ulauncher's settings, you can custom some settings: 45 | - Keyword 46 | - default: `sh` 47 | 48 | ### Script file 49 | 50 | This extension allows you to start custom scripts with your shell. 51 | 52 | To start them, you need to edit custom file `~/.config/ulauncher/scripts.json`. 53 | 54 | Quick command to edit: `xdg-open ~/.config/ulauncher/scripts.json`. 55 | 56 | Default scripts configuration: 57 | ```json 58 | [ 59 | { 60 | "name": "Edit_scripts", 61 | "description": "Select to edit scripts", 62 | "icon": null, 63 | "script": "xdg-open", 64 | "default_arguments": [ 65 | "~/.config/ulauncher/scripts.json" 66 | ] 67 | } 68 | ] 69 | ``` 70 | 71 | ## Usage 72 | 73 | To launch a script, use the keyword (default is `sh`), then type/paste to search one particular script. 74 | 75 | The first word allow you to search through your scripts name. 76 | If no more text is given, default arguments are used to run the script. If not, use the text given as arguments. 77 | 78 | Just click/press ENTER to start script. 79 | 80 | ## License 81 | 82 | [MIT License](LICENSE) 83 | -------------------------------------------------------------------------------- /config/scripts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "No_scripts", 4 | "description": "Select to edit scripts", 5 | "icon": null, 6 | "script": "xdg-open ~/.config/ulauncher/scripts.json", 7 | "default_arguments": [ 8 | "~/.config/ulauncher/scripts.json" 9 | ] 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NastuzziSamy/ulauncher-custom-scripts/7a68cbafb4acc01fed340d0d2ae99a6701724b31/images/icon.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NastuzziSamy/ulauncher-custom-scripts/7a68cbafb4acc01fed340d0d2ae99a6701724b31/images/screenshot.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import gi 2 | gi.require_version("Gdk", "3.0") 3 | 4 | from ulauncher.api.client.Extension import Extension 5 | from ulauncher.api.client.EventListener import EventListener 6 | from ulauncher.api.shared.event import KeywordQueryEvent 7 | from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction 8 | 9 | from src.functions import strip_list 10 | from src.items import no_config_items, no_results_item, generate_launcher_items 11 | from src.scripts import Scripts 12 | 13 | 14 | class CustomSearchExtension(Extension): 15 | def __init__(self): 16 | super(CustomSearchExtension, self).__init__() 17 | 18 | self.subscribe(KeywordQueryEvent, KeywordQueryEventListener()) 19 | 20 | 21 | class KeywordQueryEventListener(EventListener): 22 | def on_event(self, event, extension): 23 | query = event.get_argument() or str() 24 | launcher = Scripts(strip_list(query.split(' '))) 25 | 26 | if not launcher.has_config(): 27 | return RenderResultListAction(no_config_items()) 28 | 29 | if launcher.has_query(): 30 | results, params = launcher.execute() 31 | else: 32 | results, params = launcher.get_first_scripts() 33 | 34 | if not results or len(results) == 0: 35 | return RenderResultListAction(no_results_item()) 36 | 37 | return RenderResultListAction(generate_launcher_items(results, params)) 38 | 39 | 40 | if __name__ == "__main__": 41 | CustomSearchExtension().run() -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "required_api_version": "^2.0.0", 3 | "name": "Custom Scripts", 4 | "description": "Run your own scripts", 5 | "developer_name": "Samy NASTUZZI", 6 | "icon": "images/icon.png", 7 | "options": { 8 | "query_debounce": 0.1 9 | }, 10 | "preferences": [{ 11 | "id": "custom_scripts_kw", 12 | "type": "keyword", 13 | "name": "Custom scripts", 14 | "description": "Run your own scripts", 15 | "default_value": "sh" 16 | }] 17 | } 18 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NastuzziSamy/ulauncher-custom-scripts/7a68cbafb4acc01fed340d0d2ae99a6701724b31/src/__init__.py -------------------------------------------------------------------------------- /src/consts.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | EXTENSION_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 4 | ICON_FILE = 'images/icon.png' 5 | 6 | SCRIPT_FILE = 'scripts.json' 7 | SCRIPT_PATH = os.path.expanduser('~/.config/ulauncher/') + SCRIPT_FILE 8 | 9 | DEFAULT_CONFIG_PATH = EXTENSION_DIR + '/config/' + SCRIPT_FILE 10 | 11 | MAX_SCRIPTS = 10 -------------------------------------------------------------------------------- /src/functions.py: -------------------------------------------------------------------------------- 1 | def strip_list(elements): 2 | return [element for element in elements if len(element.strip()) > 0] 3 | -------------------------------------------------------------------------------- /src/items.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem 4 | from ulauncher.api.shared.action.CopyToClipboardAction import CopyToClipboardAction 5 | from ulauncher.api.shared.action.HideWindowAction import HideWindowAction 6 | from ulauncher.api.shared.action.DoNothingAction import DoNothingAction 7 | from ulauncher.api.shared.action.RunScriptAction import RunScriptAction 8 | 9 | from src.consts import ICON_FILE, SCRIPT_PATH 10 | 11 | def no_config_items(): 12 | return [ 13 | ExtensionResultItem( 14 | icon=ICON_FILE, 15 | name='No scripts', 16 | description='Add scripts in ' + SCRIPT_PATH, 17 | on_enter=RunScriptAction('xdg-open ' + SCRIPT_PATH) 18 | ) 19 | ] 20 | 21 | 22 | def no_results_item(): 23 | return [ 24 | ExtensionResultItem( 25 | icon=ICON_FILE, 26 | name='No results', 27 | on_enter=DoNothingAction() 28 | ) 29 | ] 30 | 31 | 32 | def get_icon(icon): 33 | icon = icon or ICON_FILE 34 | 35 | if icon.startswith('~'): 36 | icon = os.path.expanduser(icon) 37 | 38 | if not icon.startswith('/') or not os.path.exists(icon): 39 | return ICON_FILE 40 | 41 | return icon 42 | 43 | 44 | def generate_launcher_item(item, params): 45 | script = item.get('script', 'Missing script...') or 'Missing script...' 46 | 47 | if len(params) > 0: 48 | script += ' ' + ' '.join(params) 49 | elif len(item.get('default_arguments', [])) > 0: 50 | script += ' ' + ' '.join(item['default_arguments']) 51 | 52 | description = item['description'] + ' • ' + script if 'description' in item else script 53 | 54 | return ExtensionResultItem( 55 | icon=get_icon(item.get('icon')), 56 | name=item.get('name', script) or script, 57 | description=description, 58 | on_enter=RunScriptAction(script) if script else DoNothingAction() 59 | ) 60 | 61 | 62 | def generate_launcher_items(results, params): 63 | return [ 64 | generate_launcher_item(script, params) 65 | for script in results] -------------------------------------------------------------------------------- /src/scripts.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from shutil import copyfile 4 | 5 | from src.consts import SCRIPT_PATH, DEFAULT_CONFIG_PATH, MAX_SCRIPTS 6 | 7 | class Scripts(): 8 | def __init__(self, params): 9 | self.query = params.pop(0) if len(params) > 0 else "" 10 | self.params = params 11 | 12 | if not os.path.exists(SCRIPT_PATH): 13 | self.create_default_config() 14 | 15 | self.load_config() 16 | 17 | 18 | def create_default_config(self): 19 | copyfile(DEFAULT_CONFIG_PATH, SCRIPT_PATH) 20 | 21 | 22 | def load_config(self): 23 | with open(SCRIPT_PATH, 'r') as f: 24 | self.config = json.load(f) 25 | 26 | 27 | def has_config(self): 28 | return len(self.config) > 0 29 | 30 | 31 | def has_query(self): 32 | return len(self.query.strip()) > 0 33 | 34 | 35 | def get_first_scripts(self): 36 | return self.config[:MAX_SCRIPTS], [] 37 | 38 | 39 | def execute(self): 40 | scripts = [] 41 | 42 | for script in self.config: 43 | name = script.get('name', None).lower() 44 | path = script.get('script', None).lower() 45 | 46 | if self.query.lower() in name or self.query.lower() in path: 47 | scripts.append(script) 48 | 49 | return scripts[:MAX_SCRIPTS], self.params 50 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "required_api_version": "^2.0.0", 4 | "commit": "master" 5 | } 6 | ] 7 | --------------------------------------------------------------------------------