├── .gitignore ├── messages.json ├── symlink.sh ├── CHANGELOG.md ├── UNLICENSE ├── hooks.py ├── messages └── install.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.md" 3 | } -------------------------------------------------------------------------------- /symlink.sh: -------------------------------------------------------------------------------- 1 | ln -s $PWD ~/.config/sublime-text-2/Packages/hooks 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # sublime-hooks changelog 2 | 0.3.2 - Added closing square brackets in examples via @karlhorky in #6 3 | 4 | 0.3.1 - Improvded documentation 5 | 6 | 0.3.0 - Allow for `args` to be optional via #2 7 | 8 | 0.2.0 - Fixed regression against None as a setting in ST3. Fixed #1 9 | 10 | 0.1.1 - Added patch for view.window() is None 11 | 12 | 0.1.0 - Initial release 13 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /hooks.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | 5 | class HooksListener(sublime_plugin.EventListener): 6 | def get_hooks(self, view, namespace): 7 | # Retrieve the current settings 8 | view_settings = view.settings() 9 | 10 | # Collect all levels of cmds into a list 11 | # DEV: Occasionally, ST3 recognizes settings set to `None` causing errors like #1 12 | # DEV: As a result, we fallback outside of the `dict` lookup 13 | cmds = [] 14 | cmds += view_settings.get(namespace + '_user') or [] 15 | cmds += view_settings.get(namespace + '_project') or [] 16 | cmds += view_settings.get(namespace + '_language') or [] 17 | 18 | # Return the collection of cmds 19 | return cmds 20 | 21 | def run_hooks(self, view, namespace): 22 | # Resolve the commands 23 | cmds = self.get_hooks(view, namespace) 24 | 25 | # For each command, run it 26 | for cmd in cmds: 27 | self.run_cmd(view, cmd) 28 | 29 | def run_cmd(self, view, cmd): 30 | # By default, run the command on the view 31 | scope = view 32 | 33 | # If there is a scope key 34 | scope_key = cmd.get('scope', None) 35 | if scope_key: 36 | # If it is app, move to app 37 | if scope_key == 'app': 38 | scope = sublime 39 | elif scope_key == 'window': 40 | # Otherwise if it is window, move to window 41 | scope = view.window() or sublime.active_window() 42 | else: 43 | # Otherwise, complain 44 | raise Exception('Scope key "%s" for `hooks` plugin was not recognized.') 45 | 46 | # Run the command in its scope 47 | scope.run_command(cmd['command'], cmd.get('args', {})) 48 | 49 | 50 | # Set up all hooks 51 | ST_HOOKS = [ 52 | # ST2 / ST3 hooks 53 | 'on_new', 54 | 'on_clone', 55 | 'on_load', 56 | 'on_close', 57 | 'on_pre_save', 58 | 'on_post_save', 59 | # 'on_modified', # Disabled for potential overrun 60 | # 'on_selection_modified', # Disabled for potential overrun 61 | 'on_activated', 62 | 'on_deactivated', 63 | # 'on_query_context', # Disabled for potential overrun 64 | 65 | # ST3 hooks 66 | 'on_new_async', 67 | 'on_clone_async', 68 | 'on_load_async', 69 | 'on_pre_close', 70 | 'on_pre_save_async', 71 | 'on_post_save_async', 72 | # 'on_modified_async', # Disabled for potential overrun 73 | # 'on_selection_modified_async', # Disabled for potential overrun 74 | 'on_activated_async', 75 | 'on_deactivated_async', 76 | # 'on_text_command', # Disabled for potential overrun 77 | # 'on_window_command', # Disabled for potential overrun 78 | # 'post_text_command', # Disabled for potential overrun 79 | # 'post_window_command', # Disabled for potential overrun 80 | ] 81 | 82 | # For each hook, set it up 83 | for namespace in ST_HOOKS: 84 | def create_run_hook(namespace): 85 | def run_hook_namespace(self, view): 86 | self.run_hooks(view, namespace) 87 | return run_hook_namespace 88 | setattr(HooksListener, namespace, create_run_hook(namespace)) 89 | -------------------------------------------------------------------------------- /messages/install.md: -------------------------------------------------------------------------------- 1 | # sublime-hooks 2 | 3 | Run Sublime commands on common event hooks (e.g. `on_new`, `on_post_save`). 4 | 5 | This was designed to give event level bindings to other Sublime plugins. 6 | 7 | My use case was to make a [request][] (via [sublime-request][request] to a server when a save occurs. The result was: 8 | 9 | ```json 10 | "on_post_save_user": [ 11 | { 12 | "command": "request", 13 | "args": { 14 | "open_args": ["http://localhost:7060/"] 15 | }, 16 | "scope": "window" 17 | } 18 | ] 19 | ``` 20 | 21 | [request]: http://github.com/twolfson/sublime-request 22 | 23 | ## Getting started 24 | ### Creating a new hook 25 | For this exercise, we will be creating a binding that selects all text after a save occurs. 26 | 27 | A hook can be added at the `User`, `Project`, or `Language` level. We will add a `User` level hook. 28 | 29 | To edit `User` settings, open the command pallete, and select "Preferences: Settings - User". 30 | 31 | In the opened preferences, create a new key/value pair for `on_post_save_user` with the following: 32 | 33 | ```json 34 | "on_post_save_user": [ 35 | { 36 | "command": "select_all" 37 | } 38 | ] 39 | ``` 40 | 41 | Then, save twice (once to save settings, another to trigger the plugin). 42 | 43 | At this step, all text will be selected, demonstrating the hook and command were run. 44 | 45 | Examples of user, project, and language hooks can be [found below][examples]. 46 | 47 | [examples]: #examples 48 | 49 | ## Documentation 50 | Hooks are stored in the `User`, `Project`, or `Language` settings. Each of these expects a list of dictionaries. Each of those dictionaries satisfies the following: 51 | 52 | - `command` (required), Command for Sublime to run via `run_command` at the listed `scope`. 53 | - `args` (optional), Dictionary of arguments to be passed to . Comparable to `args` in "Key Bindings". 54 | - `scope` (optional), String indicating where to run `command`. By default, commands are run in the `view`. Other options are `window` and `app` which run at the `window` and `sublime` levels respectively. 55 | 56 | ```js 57 | "on_post_save_user": [ 58 | { 59 | // Runs `request` command 60 | "command": "request", 61 | 62 | // Invokes `request` with `open_args=["http://...:7060/"]` 63 | "args": { 64 | "open_args": ["http://localhost:7060/"] 65 | }, 66 | 67 | // Runs `request` via `window.run_command` 68 | "scope": "window" 69 | } 70 | ] 71 | ``` 72 | 73 | ### Accessing settings 74 | `User` settings are accessed via "Preferences: Settings - User" in the command pallete. 75 | 76 | `Project` settings are accessed via "Project -> Edit Project" from the menu bar. **You must be in a saved project for this option to be accessible.** 77 | 78 | `Language` settings are accessed via "Preferences -> Settings - More -> Syntax Specific - User". This will open settings specifically for the language in the open file. 79 | 80 | ### Namespacing 81 | Hooks are required to be namespaced at the `User`, `Project`, or `Language` level. The key will be the `event_name` followed by its `_level`. 82 | 83 | The namespaces are `_user`, `_project`, and `_language`. 84 | 85 | For demonstration: 86 | 87 | - An `on_new` hook at the `Project` level will be `on_new_project` 88 | - An `on_load` at the `Language` level will be `on_load_language` 89 | 90 | ### Events 91 | For both Sublime Text 2 and 3, you will have access to the following events: 92 | 93 | - `on_new` 94 | - `on_clone` 95 | - `on_load` 96 | - `on_close` 97 | - `on_pre_save` 98 | - `on_post_save` 99 | - `on_activated` 100 | - `on_deactivated` 101 | 102 | For Sublime Text 3, you gain access to: 103 | 104 | - `on_new_async` 105 | - `on_clone_async` 106 | - `on_load_async` 107 | - `on_pre_close` 108 | - `on_pre_save_async` 109 | - `on_post_save_async` 110 | - `on_activated_async` 111 | - `on_deactivated_async` 112 | 113 | Documentation on each hook can be found in the Sublime Text documentation: 114 | 115 | Sublime Text 2 - http://www.sublimetext.com/docs/2/api_reference.html#sublime_plugin.EventListener 116 | 117 | Sublime Text 3 - http://www.sublimetext.com/docs/3/api_reference.html#sublime_plugin.EventListener 118 | 119 | The events not on these lists were excluded due to potential performance issues (e.g. `on_modified`, `on_text_command`). 120 | 121 | ## Examples 122 | ### User 123 | User settings should be defined at the top level in your user's `.sublime-settings`. This can be accessed either via the `Preferences: Settings - User` command palette or `Preferences -> Settings - User` in the menu. 124 | 125 | ```js 126 | // Inside Packages/User/Preferences.sublime-settings 127 | { 128 | "ignored_packages": [ 129 | // ... 130 | "on_post_save_user": [ 131 | { 132 | "command": "select_all" 133 | } 134 | ] 135 | } 136 | ``` 137 | 138 | ### Project 139 | Project settings should be defined under a `settings` in your current `.sublime-project`. This can be accessed either via the `Project: Edit` command palette or `Project -> Edit` in the menu. 140 | 141 | ```js 142 | // Inside my-project.sublime-project 143 | { 144 | "folders": [ 145 | // ... 146 | "settings": { 147 | "on_post_save_project": [ 148 | { 149 | "command": "select_all" 150 | } 151 | ] 152 | } 153 | } 154 | ``` 155 | 156 | ### Language 157 | Language settings should be defined at the top level in your language's `.sublime-settings`. This can be accessed via `Preferences -> Settings - More -> Syntax Specific - User` in the menu. 158 | 159 | ```js 160 | // Inside my-language.sublime-settings 161 | { 162 | "extensions": [ 163 | // ... 164 | "on_post_save_language": [ 165 | { 166 | "command": "select_all" 167 | } 168 | ] 169 | } 170 | ``` 171 | 172 | ## Donating 173 | Support this project and [others by twolfson][gittip] via [gittip][]. 174 | 175 | [gittip]: https://www.gittip.com/twolfson/ 176 | 177 | ## Unlicense 178 | As of Sep 04 2013, Todd Wolfson has released this repository and its contents to the public domain. 179 | 180 | It has been released under the [UNLICENSE][]. 181 | 182 | [UNLICENSE]: ../UNLICENSE 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sublime-hooks 2 | 3 | Run [Sublime][subl] commands on common event hooks (e.g. `on_new`, `on_post_save`). 4 | 5 | [subl]: http://www.sublimetext.com/ 6 | 7 | This was designed to give event level bindings to other [Sublime][subl] plugins. 8 | 9 | My use case was to make a [request][] (via [sublime-request][request] to a server when a save occurs. The result was: 10 | 11 | ```js 12 | "on_post_save_user": [ 13 | { 14 | "command": "request", 15 | "args": { 16 | "open_args": ["http://localhost:7060/"] 17 | }, 18 | "scope": "window" 19 | } 20 | ] 21 | ``` 22 | 23 | [request]: http://github.com/twolfson/sublime-request 24 | 25 | ## Getting started 26 | ### Installation 27 | This package is available under `hooks` inside of [Package Control][pkg-control], a [Sublime Text][subl] plugin that allows for easy management of other plugins. 28 | 29 | [pkg-control]: http://wbond.net/sublime_packages/package_control 30 | 31 | If you prefer the manual route, you can install the script via the following command in the Sublime Text terminal (``ctrl+` ``) which utilizes `git clone`. 32 | 33 | ```python 34 | import os; path=sublime.packages_path(); (os.makedirs(path) if not os.path.exists(path) else None); window.run_command('exec', {'cmd': ['git', 'clone', 'https://github.com/twolfson/sublime-hooks', 'hooks'], 'working_dir': path}) 35 | ``` 36 | 37 | Packages can be uninstalled via "Package Control: Remove Package" via the command pallete, `ctrl+shift+p` on Windows/Linux, `command+shift+p` on Mac. 38 | 39 | ### Creating a new hook 40 | For this exercise, we will be creating a binding that selects all text after a save occurs. 41 | 42 | A hook can be added at the `User`, `Project`, or `Language` level. We will add a `User` level hook. 43 | 44 | To edit `User` settings, open the command pallete, and select "Preferences: Settings - User". 45 | 46 | In the opened preferences, create a new key/value pair for `on_post_save_user` with the following: 47 | 48 | ```js 49 | "on_post_save_user": [ 50 | { 51 | "command": "select_all" 52 | } 53 | ] 54 | ``` 55 | 56 | Then, save twice (once to save settings, another to trigger the plugin). 57 | 58 | At this step, all text will be selected, demonstrating the hook and command were run. 59 | 60 | Examples of user, project, and language hooks can be [found below][examples]. 61 | 62 | [examples]: #examples 63 | 64 | ## Documentation 65 | Hooks are stored in the `User`, `Project`, or `Language` settings. Each of these expects a list of dictionaries. Each of those dictionaries satisfies the following: 66 | 67 | - `command` (required), Command for Sublime to run via `run_command` at the listed `scope`. 68 | - `args` (optional), Dictionary of arguments to be passed to . Comparable to `args` in "Key Bindings". 69 | - `scope` (optional), String indicating where to run `command`. By default, commands are run in the `view`. Other options are `window` and `app` which run at the `window` and `sublime` levels respectively. 70 | 71 | ```js 72 | "on_post_save_user": [ 73 | { 74 | // Runs `request` command 75 | "command": "request", 76 | 77 | // Invokes `request` with `open_args=["http://...:7060/"]` 78 | "args": { 79 | "open_args": ["http://localhost:7060/"] 80 | }, 81 | 82 | // Runs `request` via `window.run_command` 83 | "scope": "window" 84 | } 85 | ] 86 | ``` 87 | 88 | ### Accessing settings 89 | `User` settings are accessed via "Preferences: Settings - User" in the command pallete. 90 | 91 | `Project` settings are accessed via "Project -> Edit Project" from the menu bar. **You must be in a saved project for this option to be accessible.** 92 | 93 | `Language` settings are accessed via "Preferences -> Settings - More -> Syntax Specific - User". This will open settings specifically for the language in the open file. 94 | 95 | ### Namespacing 96 | Hooks are required to be namespaced at the `User`, `Project`, or `Language` level. The key will be the `event_name` followed by its `_level`. 97 | 98 | The namespaces are `_user`, `_project`, and `_language`. 99 | 100 | For demonstration: 101 | 102 | - An `on_new` hook at the `Project` level will be `on_new_project` 103 | - An `on_load` at the `Language` level will be `on_load_language` 104 | 105 | ### Events 106 | For both Sublime Text 2 and 3, you will have access to the following events: 107 | 108 | - `on_new` 109 | - `on_clone` 110 | - `on_load` 111 | - `on_close` 112 | - `on_pre_save` 113 | - `on_post_save` 114 | - `on_activated` 115 | - `on_deactivated` 116 | 117 | For Sublime Text 3, you gain access to: 118 | 119 | - `on_new_async` 120 | - `on_clone_async` 121 | - `on_load_async` 122 | - `on_pre_close` 123 | - `on_pre_save_async` 124 | - `on_post_save_async` 125 | - `on_activated_async` 126 | - `on_deactivated_async` 127 | 128 | Documentation on each hook can be found in the Sublime Text documentation: 129 | 130 | Sublime Text 2 - http://www.sublimetext.com/docs/2/api_reference.html#sublime_plugin.EventListener 131 | 132 | Sublime Text 3 - http://www.sublimetext.com/docs/3/api_reference.html#sublime_plugin.EventListener 133 | 134 | The events not on these lists were excluded due to potential performance issues (e.g. `on_modified`, `on_text_command`). 135 | 136 | ## Examples 137 | ### User 138 | User settings should be defined at the top level in your user's `.sublime-settings`. This can be accessed either via the `Preferences: Settings - User` command palette or `Preferences -> Settings - User` in the menu. 139 | 140 | ```js 141 | // Inside Packages/User/Preferences.sublime-settings 142 | { 143 | "ignored_packages": [ 144 | // ... 145 | ], 146 | "on_post_save_user": [ 147 | { 148 | "command": "select_all" 149 | } 150 | ] 151 | } 152 | ``` 153 | 154 | ### Project 155 | Project settings should be defined under a `settings` in your current `.sublime-project`. This can be accessed either via the `Project: Edit` command palette or `Project -> Edit` in the menu. 156 | 157 | ```js 158 | // Inside my-project.sublime-project 159 | { 160 | "folders": [ 161 | // ... 162 | ], 163 | "settings": { 164 | "on_post_save_project": [ 165 | { 166 | "command": "select_all" 167 | } 168 | ] 169 | } 170 | } 171 | ``` 172 | 173 | ### Language 174 | Language settings should be defined at the top level in your language's `.sublime-settings`. This can be accessed via `Preferences -> Settings - More -> Syntax Specific - User` in the menu. 175 | 176 | ```js 177 | // Inside my-language.sublime-settings 178 | { 179 | "extensions": [ 180 | // ... 181 | ], 182 | "on_post_save_language": [ 183 | { 184 | "command": "select_all" 185 | } 186 | ] 187 | } 188 | ``` 189 | 190 | ## Donating 191 | Support this project and [others by twolfson][gittip] via [gittip][]. 192 | 193 | [![Support via Gittip][gittip-badge]][gittip] 194 | 195 | [gittip-badge]: https://rawgithub.com/twolfson/gittip-badge/master/dist/gittip.png 196 | [gittip]: https://www.gittip.com/twolfson/ 197 | 198 | ## Unlicense 199 | As of Sep 04 2013, Todd Wolfson has released this repository and its contents to the public domain. 200 | 201 | It has been released under the [UNLICENSE][]. 202 | 203 | [UNLICENSE]: UNLICENSE 204 | --------------------------------------------------------------------------------