├── .gitignore ├── .python-version ├── Default.sublime-commands ├── MIT-LICENSE ├── Main.sublime-menu ├── README.md ├── messages.json ├── messages ├── install.txt └── v1.0.0.txt ├── packages.json ├── settings.py ├── sublime-package.json ├── tox.ini ├── trailing_spaces.py └── trailing_spaces.sublime-settings /.gitignore: -------------------------------------------------------------------------------- 1 | .mypy_cache 2 | TODO.md 3 | *.pyc 4 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.8 2 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Trailing Spaces: Toggle Trailing Spaces Highlighting", 4 | "command": "toggle_trailing_spaces" 5 | }, 6 | { 7 | "caption": "Trailing Spaces: Delete Trailing Spaces", 8 | "command": "delete_trailing_spaces" 9 | }, 10 | { 11 | "caption": "Preferences: Trailing Spaces Settings", 12 | "command": "edit_settings", 13 | "args": { 14 | "base_file": "${packages}/TrailingSpaces/trailing_spaces.sublime-settings", 15 | "default": "// Settings in here override those in \"TrailingSpaces/trailing_spaces.sublime-settings\"\n\n{\n\t$0\n}\n", 16 | }, 17 | }, 18 | 19 | ] 20 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 Jean-Denis Vauguet 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "edit", 4 | "children": 5 | [ 6 | { 7 | "caption": "Trailing Spaces", 8 | "id": "trailing-spaces", 9 | "children": 10 | [ 11 | { 12 | "command": "delete_trailing_spaces", 13 | "caption": "Delete" 14 | }, 15 | { "caption": "-" }, 16 | { 17 | "command": "toggle_trailing_spaces_modified_lines_only", 18 | "caption": "Modified Lines Only", 19 | "checkbox": true 20 | }, 21 | { 22 | "command": "toggle_trailing_spaces", 23 | "caption": "Highlight Regions", 24 | "checkbox": true 25 | } 26 | ] 27 | } 28 | ] 29 | }, 30 | { 31 | "id": "preferences", 32 | "children": 33 | [ 34 | { 35 | "caption": "Package Settings", 36 | "mnemonic": "P", 37 | "id": "package-settings", 38 | "children": 39 | [ 40 | { 41 | "caption": "Trailing Spaces", 42 | "children": 43 | [ 44 | { 45 | "command": "edit_settings", 46 | "args": { 47 | "base_file": "${packages}/TrailingSpaces/trailing_spaces.sublime-settings", 48 | "default": "// Settings in here override those in \"TrailingSpaces/trailing_spaces.sublime-settings\"\n\n{\n\t$0\n}\n", 49 | }, 50 | "caption": "Settings" 51 | }, 52 | { "caption": "-" }, 53 | { 54 | "command": "open_file", 55 | "args": { 56 | "file": "${packages}/TrailingSpaces/README.md", 57 | }, 58 | "caption": "Help" 59 | }, 60 | ] 61 | } 62 | ] 63 | } 64 | ] 65 | } 66 | ] 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Trailing Spaces 2 | =============== 3 | 4 | A [Sublime Text](http://www.sublimetext.com) plugin that allows you to… 5 | 6 | **highlight trailing spaces and delete them in a flash!** 7 | 8 | --- 9 | 10 | - [Synopsis](#synopsis) 11 | - [Installation](#installation) 12 | - [Alternative installation methods](#alternative-installation-methods) 13 | - [From github](#from-github) 14 | - [Manually](#manually) 15 | - [Usage](#usage) 16 | - [Deletion](#deletion) 17 | - [Toggling highlighting](#toggling-highlighting) 18 | - [Options](#options) 19 | - [Changing the highlighting color](#changing-the-highlighting-color) 20 | - [Keeping trailing spaces invisible](#keeping-trailing-spaces-invisible) 21 | - [Include Current Line](#include-current-line) 22 | - [Include Empty Lines](#include-empty-lines) 23 | - [Modified Lines Only](#modified-lines-only) 24 | - [Trim On Save](#trim-on-save) 25 | - [Save After Trim](#save-after-trim) 26 | - [Live Matching vs On-demand Matching](#live-matching-vs-on-demand-matching) 27 | - [Ignore Scope](#ignore-scope) 28 | - [For power-users only!](#for-power-users-only) 29 | - [Disabled for large files](#disabled-for-large-files) 30 | - [The matching pattern](#the-matching-pattern) 31 | - [About Sublime Text's built-in features](#about-sublime-texts-built-in-features) 32 | 33 | Synopsis 34 | -------- 35 | 36 | Sublime Text provides a way to automate deletion of trailing spaces *upon file 37 | saving* (more on this at the end of this file). Depending on your settings, it 38 | may be more handy to just highlight them and/or delete them by hand, at any 39 | time. This plugin provides just that, and a *lot* of options to fine-tune the 40 | way you want to decimate trailing spaces. 41 | 42 | Installation 43 | ------------ 44 | 45 | It is available through 46 | [Sublime Package Control](http://wbond.net/sublime_packages/package_control) and 47 | this is the recommended way of installation (brings configuration instructions, 48 | automatic updates with changelogs…). 49 | 50 | ### Alternative installation methods 51 | 52 | #### From github 53 | 54 | You can install from github if you want, although Package Control automates 55 | just that. Go to your `Packages` directory (find out where it is by running 56 | `Preferences: Browse Packages` from The _Command Palette_) and clone this repository: 57 | 58 | git clone https://github.com/SublimeText/TrailingSpaces.git 59 | 60 | #### Manually 61 | 62 | [Download](https://github.com/SublimeText/TrailingSpaces/archive/master.zip) 63 | the plugin as a zip. Copy the *Trailing Spaces* directory to its location 64 | (see prior section). 65 | 66 | Usage 67 | ----- 68 | 69 | ### Deletion 70 | 71 | The main feature you gain from using this plugin is that of deleting all 72 | trailing spaces in the currently edited document. In order to use this 73 | deletion feature, you may either: 74 | 75 | * click on "Edit / Trailing Spaces / Delete"; 76 | * bind the deletion command to a keyboard shortcut: 77 | 78 | To add a key binding, open "Preferences / Key Bindings - User" and add: 79 | 80 | ``` js 81 | { "keys": ["ctrl+shift+t"], "command": "delete_trailing_spaces" } 82 | ``` 83 | 84 | With this setting, pressing Ctrl + Shift + t will delete all 85 | trailing spaces at once in the current file! For OSX users, quoting wbond: 86 | "When porting a key binding across OSes, it is common for the ctrl key on 87 | Windows and Linux to be swapped out for super on OS X" 88 | (eg. use "super+shift+t" instead). 89 | 90 | *Beware*: the binding from this example overrides the default ST's mapping 91 | for reopening last closed file. You can look at the default bindings in 92 | "Preferences / Key Bindings - Default". 93 | 94 | ### Toggling highlighting 95 | 96 | At any time, you can toggle highlighting on and off. You may either: 97 | 98 | - click on "Edit / Trailing Spaces / Highlight Regions" 99 | - bind the toggling command to a keyboard shortcut: 100 | 101 | ``` js 102 | // I like "d", as in "detect" (overrides a default binding, though). 103 | { "keys": ["ctrl+shift+d"], "command": "toggle_trailing_spaces" } 104 | ``` 105 | 106 | Options 107 | ------- 108 | 109 | Several options are available to customize the plugin's behavior. Those 110 | settings are stored in a configuration file, as JSON. You must use a specific 111 | file: Go to "Preferences / Package Settings / Trailing Spaces / Settings" to 112 | add you custom settings. 113 | 114 | A few of them are also accessible through the "Edit / Trailing Spaces" menu. 115 | Sometimes, editing a setting will require a fresh Sublime Text to be applied 116 | properly, so try relaunching ST before reporting an issue ;) 117 | 118 | All settings are global (ie. applied to all opened documents). 119 | 120 | ### Changing the highlighting color 121 | 122 | *Default: "invalid"* 123 | 124 | You may change the highlighting color, providing a color scope name such as 125 | "error", "comment"… just like that: 126 | 127 | ``` js 128 | { "highlight_color": "comment" } 129 | ``` 130 | 131 | The scope should be defined in your current theme file. Here is a dummy, 132 | fully-fledged example (feel free to cut irrelevant pieces for your settings) 133 | of such a custom color scope: 134 | 135 | ``` xml 136 | 137 | name 138 | Invalid - Illegal 139 | scope 140 | invalid.illegal 141 | settings 142 | 143 | background 144 | #F93232 145 | fontStyle 146 | 147 | foreground 148 | #F9F2CE 149 | 150 | 151 | ``` 152 | 153 | You would then use the value of "invalid.illegal". 154 | 155 | ### Keeping trailing spaces invisible 156 | 157 | You can make trailing spaces "invisible" yet still rely on the deletion 158 | command. To do that, set the highlight scope to an empty string: 159 | 160 | ``` js 161 | { "highlight_color": "" } 162 | ``` 163 | 164 | Beware: this is **not** the same as *disabling* the highlighting (see "On- 165 | Demand Matching" below). With this setting, the plugin still runs when opening 166 | a file, and in the background afterwards; you just won't see the trailing 167 | spaces (they are being highlighted with a "transparent" color). 168 | 169 | ### Include Current Line 170 | 171 | *Default: true* 172 | 173 | Highlighting of trailing spaces in the currently edited line can be annoying: 174 | each time you are about to start a new word, the space you type is matched as 175 | a trailing spaces. Currently edited line can thus be ignored: 176 | 177 | ``` js 178 | { "include_current_line": false } 179 | ``` 180 | 181 | Even though the trailing spaces are not highlighted on this line, they are 182 | still internally matched and will be delete when firing the deletion command. 183 | 184 | ### Include Empty Lines 185 | 186 | *Default: true* 187 | 188 | When firing the deletion command, empty lines are matched as trailing regions, 189 | and end up being deleted. You can specifically ignore them: 190 | 191 | ``` js 192 | { "include_empty_lines": false } 193 | ``` 194 | 195 | They will not be highlighted either. 196 | 197 | ### Modified Lines Only 198 | 199 | *Default: false (reopen ST to update)* 200 | 201 | When firing the deletion command, trailing regions *in the entire document* are 202 | deleted. There are some use-cases when deleting trailing spaces *only on lines 203 | you edited* is smarter; for instance when commiting changes to some third-party 204 | source code. 205 | 206 | At any time, you can change which area is covered when deleting trailing 207 | regions. You may either: 208 | 209 | - click on "Edit / Trailing Spaces / Modified Lines Only" 210 | - specify as a setting: 211 | 212 | ``` js 213 | { "modified_lines_only": true } 214 | ``` 215 | 216 | There is also a command to toggle this feature on and off. You may thus define 217 | a key binding: 218 | 219 | ``` js 220 | { "keys": ["pick+a+shortcut"], "command": "toggle_trailing_spaces_modified_lines_only" } 221 | ``` 222 | 223 | ### Trim On Save 224 | 225 | *Default: false* 226 | 227 | Setting this to `true` will ensure trailing spaces are deleted when you save 228 | your document. It abides by the other settings, such as *Modified Lines Only*. 229 | 230 | ``` js 231 | { "trim_on_save": true } 232 | ``` 233 | 234 | ### Save After Trim 235 | 236 | *Default: false* 237 | 238 | You may not want to always trim trailing spaces on save, but the other way 239 | around could prove useful. Setting this to `true` will automatically save your 240 | document after you fire the deletion command: 241 | 242 | ``` js 243 | { "save_after_trim": true } 244 | ``` 245 | 246 | It is obviously ignored if *Trim On Save* is on. 247 | 248 | ### Live Matching vs On-demand Matching 249 | 250 | *Default: true (reopen ST to update)* 251 | 252 | By default, trailing regions are matched every time you edit the document, and 253 | when you open it. 254 | 255 | This feature is entirely optional and you may set it off: firing the deletion 256 | command will cause the trailing spaces to be deleted as expected even though 257 | they were not matched prior to your request. If you are afraid of the plugin 258 | to cause slowness (for instance, you already installed several *heavy* 259 | plugins), you can disable live matching: 260 | 261 | ``` js 262 | { "enabled": false } 263 | ``` 264 | 265 | In this case, for no trailing regions are matched until you request them to be 266 | deleted, no highlighting occurs—it is in fact disabled, regardless of your 267 | "scope" setting. If you want to check the trailing spaces regions, you can 268 | toggle highlighting on and off. In this case, it may come in handy to define 269 | a binding for the toggling command. When "On-demand Matching" is on and some 270 | trailing spaces are highlighted, added ones will obviously not be. Toggling 271 | highlight off and on will refresh them. 272 | 273 | ### Ignore Scope 274 | 275 | *Default: ["text.find-in-files", "source.build_output", "source.diff", "text.html.markdown"]* 276 | 277 | With this option you can ignore lines being highlighted based on the scope of 278 | their trailing region. 279 | 280 | If at least one scope in the configured list matches a scope in the trailing 281 | region of the line, it won't be highlighted. 282 | 283 | By default, the scope under the mouse cursor is shown by pressing 284 | `Option+Command+P` (OS X) or `Ctrl+Alt+Shift+P` (Windows, Linux) 285 | 286 | ``` js 287 | // Trailing spaces for Find Results, Build output, Diff and Markdown are ignored 288 | { "scope_ignore": ["text.find-in-files", "source.build_output", "source.diff", "text.html.markdown"] } 289 | ``` 290 | 291 | ### For power-users only! 292 | 293 | #### Disabled for large files 294 | 295 | The plugin is disabled altogether for large files, for it may cause slowness. 296 | The default threshold is around 1 million of characters. This is 297 | configurable (in "File Settings - User") and the unit is number of chars: 298 | 299 | ``` js 300 | { "file_max_size": 1000} 301 | ``` 302 | 303 | #### The matching pattern 304 | 305 | *Default: [ \t]+* 306 | 307 | Trailing spaces are line-ending regions containing at least one simple space, 308 | tabs, or both. This pattern should be all you ever need, but if you *do* want 309 | to abide by another definition to cover edge-cases, go ahead: 310 | 311 | ``` js 312 | // *danger* will match newline chars and many other folks 313 | "regexp": "[\\s]+" 314 | ``` 315 | 316 | About Sublime Text's built-in features 317 | -------------------------------------- 318 | 319 | Trailing Spaces is designed to be a drop-in replacement of the limited 320 | *Trim Whitespace On Save* built-in feature. ST is indeed able to delete 321 | trailing spaces upon saving files, and maybe that's all you need! 322 | 323 | In order to enable this behavior, edit "Preferences / Settings" 324 | to add the following: 325 | 326 | ``` js 327 | { "trim_trailing_white_space_on_save": true } 328 | ``` 329 | 330 | As Trailing Spaces bypasses this setting, you will have to uninstall it to 331 | benefit from this setting. 332 | 333 | Made a little less obvious in the documentation are settings to showcase 334 | whitespaces (*not only trailing ones!*): 335 | 336 | ``` js 337 | { "draw_white_space": "all" } 338 | ``` 339 | 340 | and to ensure a newline is kept at end of file upon saving: 341 | 342 | ``` js 343 | { "ensure_newline_at_eof_on_save": true } 344 | ``` 345 | 346 | The former will display *all* whitespaces in your files. There is another value 347 | of "selection" which display whitespaces under (you got it) your current text 348 | selection. 349 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt", 3 | "v1.0.0": "messages/v1.0.0.txt" 4 | } 5 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Thank you for installing Trailing Spaces 4 | ---------------------------------------- 5 | 6 | You're now ready to give trailing spaces *a hard time*! 7 | 8 | 9 | Documentation 10 | ============= 11 | 12 | Although the usage of this plugin is dead simple, it comes with several options. All 13 | details are available in the documentation, and you can read it by clicking on 14 | "Preferences / Package Settings / Trailing Spaces / Help", or in a prettier form, by 15 | browsing https://github.com/SublimeText/TrailingSpaces. 16 | 17 | Key Binding 18 | =========== 19 | 20 | This plugin does not come with a default key binding for the deletion command. You can 21 | pick your own key binding and define it in "Preferences / Key Bindings - User", or just 22 | stick to using the menu entry under "Edit". Check the help for advice on this. 23 | 24 | Upgrades & Issues 25 | ================= 26 | 27 | Package Control will automatically update all packages every time the editor is started, 28 | so there is nothing for you to worry about. If you however do find the plugin not to work 29 | as it used to, head to the issues tracker (see links below) to report the problem. 30 | 31 | Useful Links 32 | ============ 33 | 34 | * Documentation & Code: https://github.com/SublimeText/TrailingSpaces 35 | * Report issues / Request New Features / Roadmap: https://github.com/SublimeText/TrailingSpaces/issues 36 | * Follow me on twitter: @jdvauguet 37 | -------------------------------------------------------------------------------- /messages/v1.0.0.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Trailing Spaces update [v1.0.0] 4 | ------------------------------- 5 | 6 | Hope you've been happy gaving trailin' a hard time so far. 7 | 8 | I added several features to help you in this honorable quest… 9 | 10 | All details accessible through: 11 | 12 | "Preferences / Package Settings / Trailing Spaces / Help" 13 | 14 | 15 | 16 | New feature: Modified Lines Only 17 | ================================ 18 | 19 | As proposed by a fellow user, it is now possible to target only the lines 20 | modified by You and You Only when deleting trailing spaces. 21 | 22 | This feature will certainly please coders who edit third-party code filled 23 | with trailing spaces but do not want to commit giant diffs, just their little 24 | fix, while keeping it clean. 25 | 26 | New feature: Trim On Save 27 | ========================= 28 | 29 | This option allows for automatic deletion upon saving. No more lost trailing 30 | spaces! A perfect combo to the "Modified Lines Only" setting I guess. 31 | 32 | New feature: Save After Trim 33 | ============================ 34 | 35 | A different kind of automation: many users just want those trailings out and 36 | forget 'bout them. It is now made even easier with this auto-saving hook. Fire 37 | the deletion command, and your document is clean on the hard drive! 38 | 39 | At the current time, "Trim On Save" and "Save After Trim" cannot be both 40 | enabled (the former wins), but this is on the roadmap. 41 | 42 | New Menu 43 | ======== 44 | 45 | Some of the settings seemed a bit more important than the others. Along the 46 | deletion command, the toggling command/state and the "Modified Lines Only" 47 | setting have been elected first-class citizens of the new "Edit / Trailing 48 | Spaces" menu. Any change made by click here is live, persistent and reflected 49 | in the JSON settings file. Settings are global to all open documents. 50 | 51 | Improvements & Misc. 52 | ==================== 53 | 54 | - Support for custom matching patterns (danger!). 55 | - Performance improvements (reduced overhead, with some room for further 56 | improvements). 57 | - Better documentation (both code & user doc). 58 | - Lazy "On-demand" matching improved. 59 | 60 | Useful Links 61 | ============ 62 | 63 | * Documentation & Code: https://github.com/SublimeText/TrailingSpaces 64 | * Report issues / Request New Features / Roadmap: https://github.com/SublimeText/TrailingSpaces/issues 65 | * Follow me on twitter: @jdvauguet 66 | -------------------------------------------------------------------------------- /packages.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_version": "1.2", 3 | "packages": [ 4 | { 5 | "name": "TrailingSpaces", 6 | "description": "Highlight trailing spaces and delete them in a flash.", 7 | "author": "Jean-Denis Vauguet", 8 | "homepage": "https://github.com/SublimeText/TrailingSpaces/", 9 | "last_modified": "2013-03-08 01:00:00", 10 | "platforms": { 11 | "*": [ 12 | { 13 | "version": "1.0.0", 14 | "url": "https://nodeload.github.com/SublimeText/TrailingSpaces/zip/v1.0.0" 15 | } 16 | ] 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | from typing import Any, List 2 | import sublime 3 | 4 | 5 | class TrailingSpacesSettings: 6 | SETTINGS_FILENAME = 'trailing_spaces.sublime-settings' 7 | 8 | def __init__(self): 9 | self._settings = sublime.Settings(0) 10 | 11 | def load(self) -> None: 12 | self._settings = sublime.load_settings(self.SETTINGS_FILENAME) 13 | 14 | def save(self) -> None: 15 | sublime.save_settings(self.SETTINGS_FILENAME) 16 | 17 | def _get(self, key: str, value_type: Any) -> Any: 18 | value = self._settings.get(key) 19 | if not isinstance(value, value_type): 20 | raise Exception(f'Invalid value for setting "{key}". Expected "{value_type}", got "{type(value)}') 21 | return value 22 | 23 | def _set(self, key: str, value: Any, value_type: Any) -> None: 24 | if not isinstance(value, value_type): 25 | raise Exception(f'Invalid value when setting "{key}". Expected "{value_type}", got "{type(value)}') 26 | self._settings.set(key, value) 27 | 28 | # -- Getters and setters for supported options --------------------------------------------------------------------- 29 | 30 | @property 31 | def enabled(self) -> bool: 32 | return self._get('enabled', bool) 33 | 34 | @property 35 | def file_max_size(self) -> int: 36 | return self._get('file_max_size', int) 37 | 38 | @property 39 | def highlight_color(self) -> str: 40 | return self._get('highlight_color', str) 41 | 42 | @highlight_color.setter 43 | def highlight_color(self, value: str) -> None: 44 | self._set('highlight_color', value, str) 45 | 46 | @property 47 | def include_current_line(self) -> bool: 48 | return self._get('include_current_line', bool) 49 | 50 | @property 51 | def include_empty_lines(self) -> bool: 52 | return self._get('include_empty_lines', bool) 53 | 54 | @property 55 | def modified_lines_only(self) -> bool: 56 | return self._get('modified_lines_only', bool) 57 | 58 | @modified_lines_only.setter 59 | def modified_lines_only(self, value: bool) -> None: 60 | self._set('modified_lines_only', value, bool) 61 | 62 | @property 63 | def non_visible_highlighting(self) -> int: 64 | return self._get('non_visible_highlighting', int) 65 | 66 | @property 67 | def regexp(self) -> str: 68 | return self._get('regexp', str) 69 | 70 | @property 71 | def save_after_trim(self) -> bool: 72 | return self._get('save_after_trim', bool) 73 | 74 | @property 75 | def scope_ignore(self) -> List[str]: 76 | return self._get('scope_ignore', list) 77 | 78 | @property 79 | def syntax_ignore(self) -> List[str]: 80 | value = self._settings.get('syntax_ignore') 81 | return value if isinstance(value, list) else [] 82 | 83 | @property 84 | def trim_on_save(self) -> bool: 85 | return self._get('trim_on_save', bool) 86 | 87 | @property 88 | def update_interval(self) -> int: 89 | return self._get('update_interval', int) 90 | -------------------------------------------------------------------------------- /sublime-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "contributions": { 3 | "settings": [ 4 | { 5 | "file_patterns": [ 6 | "/trailing_spaces.sublime-settings" 7 | ], 8 | "schema": { 9 | "$id": "sublime://settings/TrailingSpaces", 10 | "properties": { 11 | "enabled": { 12 | "type": "boolean", 13 | "default": true, 14 | "markdownDescription": "By default, Trailing Spaces is \"live\". It means the trailing spaces regions will be matched in the background, and highlighted if a color scope is defined, when the document is opened and edited. Set to false to disable live matching and highlighting (the deletion command remains available, so-called \"lazy matching\")." 15 | }, 16 | "highlight_color": { 17 | "type": "string", 18 | "default": "region.redish", 19 | "markdownDescription": "Highlight color is specified as a scope. You may define and use a custom scope to better fit your colorscheme. A value of empty string `\"\"` will make highlights invisible." 20 | }, 21 | "include_empty_lines": { 22 | "type": "boolean", 23 | "default": true, 24 | "markdownDescription": "By default, empty lines are cleared as well when calling the deletion command. Set to ` to ignore empty lines upon deletion." 25 | }, 26 | "include_current_line": { 27 | "type": "boolean", 28 | "default": true, 29 | "markdownDescription": "By default, the line being currently edited will have its trailing spaces highlighted. Set to `false` to ignore trailing spaces on the edited line." 30 | }, 31 | "scope_ignore": { 32 | "type": "array", 33 | "default": ["text.find-in-files", "source.build_output", "source.diff", "text.html.markdown"], 34 | "items": { 35 | "type": "string" 36 | }, 37 | "uniqueItems": true, 38 | "markdownDescription": "By default, any lines in the Find Results, Build output, Diff and Markdown views are ignored. Add scopes to this list if you need to ignore them." 39 | }, 40 | "modified_lines_only": { 41 | "type": "boolean", 42 | "default": false, 43 | "markdownDescription": "By default, trailing spaces are deleted within the whole document. Set to `true` to affect only the lines you edited since last save. Trailing spaces will still be searched for and highlighted in the whole document." 44 | }, 45 | "trim_on_save": { 46 | "type": "boolean", 47 | "default": false, 48 | "markdownDescription": "By default, nothing happens on save. Set to `true` to trim trailing spaces before saving, with respect to the other settings." 49 | }, 50 | "save_after_trim": { 51 | "type": "boolean", 52 | "default": false, 53 | "markdownDescription": "By default, deleting trailing spaces does not cause the document to be saved. Set to `true` to force saving after trailing spaces have been deleted. This setting is irrelevant and will be ignored if `trim_on_save` is `true`." 54 | }, 55 | "non_visible_highlighting": { 56 | "type": "number", 57 | "default": 500, 58 | "markdownDescription": "The number of characters before and after the visible region of text to include in the highlighting. This is useful to also show the highlighting immediately for text that just became visible through scrolling. Adjust the value (in the number of characters) to whatever fits your needs and performance." 59 | }, 60 | "update_interval": { 61 | "type": "number", 62 | "default": 250, 63 | "markdownDescription": "This is the interval at which the active view is tested for changes (due to scrolling) to update the highlighting of the currently visible region of text. Adjust the value (in milliseconds) to whatever fits your needs and performance." 64 | }, 65 | "file_max_size": { 66 | "type": "number", 67 | "default": 1048576, 68 | "markdownDescription": "Highlighting will be disabled if the edited file's size is larger than this. Adjust the value (in number of chars) to whatever fits your performance." 69 | }, 70 | "regexp": { 71 | "type": "string", 72 | "default": "[ \\t]+", 73 | "markdownDescription": "By default, only simple spaces and tabs are matched as \"trailing spaces\"." 74 | }, 75 | }, 76 | "additionalProperties": false 77 | } 78 | } 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py3 3 | skipsdist = True 4 | 5 | [pycodestyle] 6 | max-line-length = 120 7 | 8 | [flake8] 9 | max-line-length = 120 10 | -------------------------------------------------------------------------------- /trailing_spaces.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Provides both a trailing spaces highlighter and a deletion command. 3 | 4 | See README.md for details. 5 | 6 | @author: Jean-Denis Vauguet , Oktay Acikalin 7 | @license: MIT (http://www.opensource.org/licenses/mit-license.php) 8 | @since: 2011-02-25 9 | ''' 10 | 11 | from .settings import TrailingSpacesSettings 12 | from os.path import isfile 13 | from typing import Dict, List, Literal, Tuple, Union, cast 14 | import codecs 15 | import difflib 16 | import re 17 | import sublime 18 | import sublime_plugin 19 | 20 | # dictionary of currently active view ids and last visible regions 21 | active_views: Dict[int, sublime.Region] = {} 22 | current_highlight_color = '' 23 | on_disk = None 24 | # Highlight color as defined in settings. Plugin mutates that setting when disabled so 25 | # that has to be stored. 26 | INITIAL_HIGHLIGHT_COLOR = '' 27 | HIGHLIGHT_REGION_KEY = 'TrailingSpacesHighlightedRegions' 28 | settings = TrailingSpacesSettings() 29 | 30 | 31 | def plugin_loaded() -> None: 32 | global current_highlight_color, INITIAL_HIGHLIGHT_COLOR 33 | 34 | settings.load() 35 | 36 | current_highlight_color = settings.highlight_color 37 | INITIAL_HIGHLIGHT_COLOR = current_highlight_color 38 | 39 | if not settings.enabled: 40 | current_highlight_color = "" 41 | if settings.highlight_color != current_highlight_color: 42 | settings.save() 43 | 44 | 45 | # Private: Makes sure all timers are stopped. 46 | # 47 | # Returns nothing. 48 | def plugin_unloaded() -> None: 49 | global on_disk 50 | 51 | # clear all active views to kill all timeouts 52 | active_views.clear() 53 | on_disk = None 54 | 55 | 56 | # Private: Returns all regions within region that match regex. 57 | # 58 | # view - the view, you know 59 | # regions - a list of regions to search 60 | # regex - the regex pattern to search for 61 | # 62 | # Returns all matching trailing regions within regions. 63 | def view_find_all_in_regions(view: sublime.View, regions: List[sublime.Region], regex: str) -> List[sublime.Region]: 64 | found: List[sublime.Region] = [] 65 | 66 | # find all matches in the region's text 67 | for region in regions: 68 | text = view.substr(region) 69 | # translate positions to the region's starting position 70 | matches = re.finditer(regex, text, re.MULTILINE) 71 | found.extend(sublime.Region(m.start() + region.begin(), m.end() + region.begin()) for m in matches) 72 | 73 | return found 74 | 75 | 76 | # Private: Get the regions matching trailing spaces. 77 | # 78 | # As the core regexp matches lines, the regions are, well, "per lines". 79 | # 80 | # view - the view, you know 81 | # scan_only_visible - whether to limit scanning to only visible region 82 | # 83 | # Returns both the list of regions which map to trailing spaces and the list of 84 | # regions which are to be highlighted, as a list [matched, highlightable]. 85 | def find_trailing_spaces( 86 | view: sublime.View, scan_only_visible: bool = True 87 | ) -> Tuple[List[sublime.Region], List[sublime.Region]]: 88 | include_empty_lines = settings.include_empty_lines 89 | include_current_line = settings.include_current_line 90 | regexp = settings.regexp + "$" 91 | 92 | if not include_empty_lines: 93 | regexp = "(?<=\\S)%s$" % regexp 94 | 95 | trailing_regions: List[sublime.Region] = [] 96 | 97 | non_visible_highlighting = settings.non_visible_highlighting 98 | 99 | if scan_only_visible: 100 | # find all matches in the currently visible region plus a little before and after 101 | searched_region = view.visible_region() 102 | searched_region.a = max(searched_region.a - non_visible_highlighting, 0) 103 | searched_region.b = min(searched_region.b + non_visible_highlighting, view.size()) 104 | 105 | searched_region = view.line(searched_region) # align to line start and end 106 | trailing_regions = view_find_all_in_regions(view, [searched_region], regexp) 107 | else: 108 | trailing_regions = view.find_all(regexp) 109 | 110 | ignored_scopes = ",".join(settings.scope_ignore) 111 | # filter out ignored scopes 112 | trailing_regions = [ 113 | region for region in trailing_regions 114 | if not ignored_scopes or not view.match_selector(region.begin(), ignored_scopes) 115 | ] 116 | 117 | sel = view.sel() 118 | 119 | if include_current_line or len(sel) == 0: 120 | return (trailing_regions, trailing_regions) 121 | else: 122 | selection_lines = [view.line(region.b) for region in sel] 123 | # find all matches in the current line and exclude them from highlighting 124 | selection_offenders = view_find_all_in_regions(view, selection_lines, regexp) 125 | highlightable = [r for r in trailing_regions if r not in selection_offenders] 126 | return (trailing_regions, highlightable) 127 | 128 | 129 | # Private: Find the freaking trailing spaces in the view and flags them as such! 130 | # 131 | # It will refresh highlighted regions as well. Does not execute if the 132 | # document's size exceeds the file_max_size setting, or if the fired in a view 133 | # which is not a legacy document (helper/build views and so on). 134 | # 135 | # view - the view, you know 136 | # 137 | # Returns nothing. 138 | def match_trailing_spaces(view: sublime.View) -> None: 139 | # Silently pass ignored views. 140 | if ignore_view(view): 141 | return 142 | 143 | # Silently pass if file is too big. 144 | if max_size_exceeded(view): 145 | return 146 | 147 | (matched, highlightable) = find_trailing_spaces(view) 148 | highlight_trailing_spaces_regions(view, highlightable) 149 | 150 | 151 | # Private: Checks if the view should be ignored. 152 | # 153 | # view - the view to check. 154 | # 155 | # Returns True if the view should be ignored, False otherwise. 156 | def ignore_view(view: sublime.View) -> bool: 157 | if view.is_scratch(): 158 | return True 159 | 160 | view_settings = view.settings() 161 | view_syntax = view_settings.get('syntax') 162 | 163 | if not isinstance(view_syntax, str) or view_settings.get('is_widget'): 164 | return False 165 | 166 | for syntax_ignore in settings.syntax_ignore: 167 | if syntax_ignore in view_syntax: 168 | return True 169 | 170 | return False 171 | 172 | 173 | # Private: Checks whether the document is bigger than the max_size setting. 174 | # 175 | # view - the view, you know 176 | # 177 | # Returns True or False. 178 | def max_size_exceeded(view: sublime.View) -> bool: 179 | return view.size() > settings.file_max_size 180 | 181 | 182 | # Private: Highlights specified regions as trailing spaces. 183 | # 184 | # It will use the scope enforced by the state of the toggable highlighting. 185 | # 186 | # view - the view, you know 187 | # regions - regions qualified as trailing spaces 188 | # 189 | # Returns nothing. 190 | def highlight_trailing_spaces_regions(view: sublime.View, regions: List[sublime.Region]) -> None: 191 | view.erase_regions(HIGHLIGHT_REGION_KEY) 192 | if regions: 193 | view.add_regions(HIGHLIGHT_REGION_KEY, regions, current_highlight_color or "", "", sublime.HIDE_ON_MINIMAP) 194 | 195 | 196 | # Private: Toggles highlighting of all trailing spaces in the view. 197 | # 198 | # It has no effect is the plugin is disabled. 199 | # 200 | # view - the view, you know 201 | # 202 | # Returns True (highlighting was turned on) or False (turned off). 203 | def toggle_highlighting(view: sublime.View) -> Literal['disabled!', 'off', 'on']: 204 | global current_highlight_color 205 | 206 | # If the scope is that of an invisible, there is nothing to toggle. 207 | if INITIAL_HIGHLIGHT_COLOR == "": 208 | return "disabled!" 209 | 210 | # If performing live, highlighted trailing regions must be updated 211 | # internally. 212 | if not settings.enabled: 213 | (matched, highlightable) = find_trailing_spaces(view) 214 | highlight_trailing_spaces_regions(view, highlightable) 215 | 216 | scope = INITIAL_HIGHLIGHT_COLOR if current_highlight_color == "" else "" 217 | current_highlight_color = scope 218 | highlight_trailing_spaces_regions(view, view.get_regions(HIGHLIGHT_REGION_KEY)) 219 | return "off" if current_highlight_color == "" else "on" 220 | 221 | 222 | # Clear all the highlighted regions in all views. 223 | # 224 | # FIXME: this is not used! Delete? 225 | # 226 | # window - the window, you know 227 | # 228 | # Returns nothing. 229 | def clear_trailing_spaces_highlight(window: sublime.Window) -> None: 230 | for view in window.views(): 231 | view.erase_regions('TrailingSpacesMatchedRegions') 232 | 233 | 234 | # Find edited lines since last save, as line numbers, based on diff. 235 | # 236 | # It uses a Differ object to compute the diff between the file as red on the 237 | # disk, and the current buffer (which may differ from the disk's state). See 238 | # http://docs.python.org/2/library/difflib.html for details about diff codes. 239 | # 240 | # It relies on a full diff, so it may be expensive computation for very large 241 | # files (diff generation + looping through all lines). 242 | # 243 | # old - a buffer of lines, as in "old version" 244 | # new - a buffer of lines, as in "new version" 245 | # 246 | # Returns the list of edited line numbers. 247 | def modified_lines_as_numbers(old: List[str], new: List[str]) -> Union[Literal[False], List[int]]: 248 | d = difflib.Differ() 249 | diffs = d.compare(old, new) 250 | 251 | # Pretty Naive Algorithm (tm): 252 | # - split off the "Differ code", to check whether: 253 | # - the line is in either in both files or just b: increment the line number 254 | # - the line is only in b: it qualifies as an edited line! 255 | # Starting from -1 as ST2 is internally 0-based for lines. 256 | lineNum = -1 257 | edited_lines: List[int] = [] 258 | for line in diffs: 259 | code = line[:2] 260 | # those lines with "? " are not real! watch out! 261 | if code in (" ", "+ "): 262 | lineNum += 1 263 | if code == "+ ": 264 | edited_lines.append(lineNum) 265 | 266 | return False if not edited_lines else edited_lines 267 | 268 | 269 | # Private: Find the dirty lines. 270 | # 271 | # view - the view, you know 272 | # 273 | # Returns the list of regions matching dirty lines. 274 | def get_modified_lines(view: sublime.View) -> List[sublime.Region]: 275 | on_buffer = view.substr(sublime.Region(0, view.size())).splitlines() 276 | lines = [] 277 | line_numbers = modified_lines_as_numbers(on_disk or [], on_buffer) 278 | if line_numbers: 279 | lines = [view.full_line(view.text_point(number, 0)) for number in line_numbers] 280 | return lines 281 | 282 | 283 | # Private: Finds the trailing spaces regions to be deleted. 284 | # 285 | # It abides by the user settings: while in mode "Only Modified Lines", it returns 286 | # the subset of trailing spaces regions which are within dirty lines; otherwise, it 287 | # returns all trailing spaces regions for the document. 288 | # 289 | # view - the view, you know 290 | # 291 | # Returns a list of regions to be deleted. 292 | def find_regions_to_delete(view: sublime.View) -> List[sublime.Region]: 293 | (regions, highlightable) = find_trailing_spaces(view, scan_only_visible=False) 294 | 295 | # Filtering is required in case triming is restricted to dirty regions only. 296 | if settings.modified_lines_only: 297 | modified_lines = get_modified_lines(view) 298 | 299 | # If there are no dirty lines, don't do nothing. 300 | if not modified_lines: 301 | return [] 302 | 303 | # Super-private: filters trailing spaces regions to dirty lines only. 304 | # 305 | # As one cannot perform a smart find_all within arbitrary boundaries, we must do some 306 | # extra work: 307 | # - we want to loop through the modified lines set, not the whole trailing regions 308 | # - but we need a way to match modified lines with trailings to those very regions 309 | # 310 | # Hence the reversed dict on regions: keys are the text_point of the begining of 311 | # each region, values are the region's actual boundaries. As a Region is unhashable, 312 | # trailing regions are being recreated later on from those two values. 313 | # 314 | # We loop then loop through the modified lines: for each line, we get its begining 315 | # text_point, and check whether it matches a line with trailing spaces in the 316 | # reversed dict. If so, this is a match (a modified line with trailing spaces), so 317 | # we can re-create and store a Region for the relevant trailing spaces boundaries. 318 | # 319 | # Returns the filtered list of trailing spaces regions for the modified lines set. 320 | def only_those_with_trailing_spaces() -> List[sublime.Region]: 321 | regions_by_begin: Dict[sublime.Point, Tuple[sublime.Point, sublime.Point]] = {} 322 | matches: List[sublime.Region] = [] 323 | for region in regions: 324 | begin = view.line(region).begin() 325 | regions_by_begin[begin] = (region.begin(), region.end()) 326 | 327 | for line in modified_lines: 328 | text_point = line.begin() 329 | if text_point in regions_by_begin: 330 | matches.append(sublime.Region(regions_by_begin[text_point][0], regions_by_begin[text_point][1])) 331 | 332 | return matches 333 | 334 | regions = only_those_with_trailing_spaces() 335 | 336 | return regions 337 | 338 | 339 | # Private: Deletes the trailing spaces regions. 340 | # 341 | # view - the view, you know 342 | # edit - the Edit object spawned by the deletion command 343 | # 344 | # Returns the number of deleted regions. 345 | def delete_trailing_regions(view: sublime.View, edit: sublime.Edit) -> int: 346 | regions = find_regions_to_delete(view) 347 | 348 | if regions: 349 | # Trick: reversing the regions takes care of the growing offset while 350 | # deleting the successive regions. 351 | regions.reverse() 352 | for r in regions: 353 | view.erase(edit, r) 354 | return len(regions) 355 | else: 356 | return 0 357 | 358 | 359 | # Public: Toggles the highlighting on or off. 360 | class ToggleTrailingSpacesCommand(sublime_plugin.WindowCommand): 361 | def run(self) -> None: 362 | view = self.window.active_view() 363 | if not view: 364 | return 365 | 366 | if max_size_exceeded(view): 367 | sublime.status_message("File is too big, trailing spaces handling disabled.") 368 | return 369 | 370 | state = toggle_highlighting(view) 371 | settings.highlight_color = current_highlight_color 372 | settings.save() 373 | sublime.status_message('Highlighting of trailing spaces is %s' % state) 374 | 375 | def is_checked(self) -> bool: 376 | return current_highlight_color != "" 377 | 378 | 379 | # Public: Toggles "Modified Lines Only" mode on or off. 380 | class ToggleTrailingSpacesModifiedLinesOnlyCommand(sublime_plugin.WindowCommand): 381 | def run(self) -> None: 382 | was_on = settings.modified_lines_only 383 | settings.modified_lines_only = not was_on 384 | settings.save() 385 | 386 | message = "Let's trim trailing spaces everywhere" if was_on \ 387 | else "Let's trim trailing spaces only on modified lines" 388 | sublime.status_message(message) 389 | 390 | def is_checked(self) -> bool: 391 | return settings.modified_lines_only 392 | 393 | 394 | # Public: Matches and highlights trailing spaces on key events, according to the 395 | # current settings. 396 | class TrailingSpacesListener(sublime_plugin.EventListener): 397 | def on_modified_async(self, view: sublime.View) -> None: 398 | if settings.enabled: 399 | match_trailing_spaces(view) 400 | 401 | def on_selection_modified_async(self, view: sublime.View) -> None: 402 | if settings.enabled: 403 | match_trailing_spaces(view) 404 | 405 | def on_activated_async(self, view: sublime.View) -> None: 406 | if settings.modified_lines_only: 407 | self.freeze_last_version(view) 408 | 409 | if settings.enabled: 410 | match_trailing_spaces(view) 411 | 412 | # continuously watch view for changes to the visible region 413 | if view.id() not in active_views: 414 | # track 415 | active_views[view.id()] = view.visible_region() 416 | self.update_on_region_change(view) 417 | 418 | def on_pre_save(self, view: sublime.View) -> None: 419 | if settings.modified_lines_only: 420 | self.freeze_last_version(view) 421 | 422 | if settings.trim_on_save: 423 | view.run_command("delete_trailing_spaces") 424 | 425 | def on_close(self, view: sublime.View) -> None: 426 | # untrack 427 | active_views.pop(view.id(), None) 428 | 429 | def update_on_region_change(self, view: sublime.View) -> None: 430 | # remove views not currently visible 431 | if not self.is_view_visible(view): 432 | active_views.pop(view.id(), None) 433 | return 434 | 435 | # compare the currently visible region to the previous (if any) and 436 | # update if there were changes 437 | if view.visible_region() != active_views.get(view.id(), view.visible_region()): 438 | match_trailing_spaces(view) 439 | active_views[view.id()] = view.visible_region() 440 | 441 | # continue only if the view is still active 442 | if settings.enabled and view.id() in active_views: 443 | sublime.set_timeout_async(lambda: self.update_on_region_change(view), settings.update_interval) 444 | 445 | # Toggling messes with what is red from the disk, and it breaks the diff 446 | # used when modified_lines_only is true. Honestly, I don't know why (yet). 447 | # Anyway, let's cache the persisted version of the document's buffer for 448 | # later use on specific event, so that we always have a decent version of 449 | # "what's on the disk" to work with. 450 | def freeze_last_version(self, view: sublime.View) -> None: 451 | global on_disk 452 | 453 | file_name = view.file_name() 454 | # For some reasons, the on_activated hook gets fired on a ghost document 455 | # from time to time. 456 | if file_name and not view.is_scratch() and isfile(file_name): 457 | encoding = view.encoding() 458 | 459 | if encoding == "Undefined": 460 | encoding = cast(str, view.settings().get("default_encoding", "UTF-8")) 461 | 462 | if encoding == "Hexadecimal": # not supported? 463 | on_disk = None 464 | return 465 | 466 | match = re.match(r'.+\(([^)]+)\)$', encoding) 467 | encoding = match.group(1) if match else encoding 468 | 469 | with codecs.open(file_name, "r", encoding) as f: 470 | on_disk = f.read().splitlines() 471 | 472 | def is_view_visible(self, view: sublime.View) -> bool: 473 | window = view.window() 474 | if not window: 475 | return False 476 | 477 | # panel views don't trigger on_close but are also not valid anymore 478 | # after being hidden, so try to detect these cases here 479 | if view.size() == 0 and not view.file_name(): 480 | return False 481 | 482 | # see if this view is visible in its group 483 | group = window.get_view_index(view)[0] 484 | if group != -1: 485 | active_view_in_group = window.active_view_in_group(group) 486 | # won't be present if a html sheet is active 487 | if active_view_in_group: 488 | return view.id() == active_view_in_group.id() 489 | 490 | # check if this view is the active panel 491 | active_panel = window.active_panel() or "" 492 | 493 | # find_output_panel only works without the "output."" prefix 494 | if active_panel.startswith("output."): 495 | active_panel = active_panel[len("output."):] 496 | 497 | panel_view = window.find_output_panel(active_panel) 498 | if panel_view and view.id() == panel_view.id(): 499 | return True 500 | 501 | return False 502 | 503 | 504 | # Public: Deletes the trailing spaces. 505 | class DeleteTrailingSpacesCommand(sublime_plugin.TextCommand): 506 | def run(self, edit: sublime.Edit) -> None: 507 | if max_size_exceeded(self.view): 508 | sublime.status_message("File is too big, trailing spaces handling disabled.") 509 | return 510 | 511 | deleted = delete_trailing_regions(self.view, edit) 512 | 513 | if deleted: 514 | if settings.save_after_trim and not settings.trim_on_save: 515 | sublime.set_timeout(lambda: self.save(self.view), 10) 516 | 517 | msg_parts = {"nbRegions": deleted, 518 | "plural": 's' if deleted > 1 else ''} 519 | message = "Deleted %(nbRegions)s trailing spaces region%(plural)s" % msg_parts 520 | else: 521 | message = "No trailing spaces to delete!" 522 | 523 | sublime.status_message(message) 524 | 525 | def save(self, view: sublime.View) -> None: 526 | if view.file_name() is None: 527 | view.run_command('prompt_save_as') 528 | else: 529 | view.run_command('save') 530 | -------------------------------------------------------------------------------- /trailing_spaces.sublime-settings: -------------------------------------------------------------------------------- 1 | // Trailing Spaces' default settings. 2 | // 3 | // See Trailing Spaces' README for detailed instructions. 4 | { 5 | // By default, Trailing Spaces is "live". It means the trailing spaces 6 | // regions will be matched in the background, and highlighted if a color 7 | // scope is defined, when the document is opened and edited. 8 | // Set to false to disable live matching and highlighting (the deletion 9 | // command remains available, so-called "lazy matching"). 10 | "enabled" : true, 11 | 12 | // Highlight color is specified as a scope. You may define and use a custom 13 | // scope to better fit your colorscheme. A value of empty string "" will 14 | // make highlights invisible. 15 | "highlight_color" : "region.redish", 16 | 17 | // By default, empty lines are cleared as well when calling the deletion 18 | // command. 19 | // Set to false to ignore empty lines upon deletion. 20 | "include_empty_lines" : true, 21 | 22 | // By default, the line being currently edited will have its trailing 23 | // spaces highlighted. 24 | // Set to false to ignore trailing spaces on the edited line. 25 | "include_current_line" : true, 26 | 27 | // By default, any lines in the Find Results, Build output, Diff and Markdown views are ignored 28 | // Add scopes to this list if you need to ignore them. 29 | "scope_ignore": ["text.find-in-files", "source.build_output", "source.diff", "text.html.markdown"], 30 | 31 | // By default, trailing spaces are deleted within the whole document. 32 | // Set to true to affect only the lines you edited since last save. 33 | // Trailing spaces will still be searched for and highlighted in the whole 34 | // document. 35 | "modified_lines_only": false, 36 | 37 | // By default, nothing happens on save. 38 | // Set to true to trim trailing spaces before saving, with respect to the 39 | // other settings. 40 | "trim_on_save": false, 41 | 42 | // By default, deleting trailing spaces does not cause the document to be 43 | // saved. 44 | // Set to true to force saving after trailing spaces have been deleted. 45 | // This setting is irrelevant and will be ignored if trim_on_save is true. 46 | "save_after_trim": false, 47 | 48 | // ---- NEXT SETTINGS ARE FOR POWER USERS ONLY! ---- 49 | 50 | // The number of characters before and after the visible region of text to 51 | // include in the highlighting. This is useful to also show the highlighting 52 | // immediately for text that just became visible through scrolling. 53 | // Adjust the value (in the number of characters) to whatever fits your 54 | // needs and performance. 55 | "non_visible_highlighting" : 500, 56 | 57 | // This is the interval at which the active view is tested for changes 58 | // (due to scrolling) to update the highlighting of the currently visible 59 | // region of text. 60 | // Adjust the value (in milliseconds) to whatever fits your needs and 61 | // performance. 62 | "update_interval" : 250, 63 | 64 | // Highlighting will be disabled if the edited file's size is larger than 65 | // this. 66 | // Adjust the value (in number of chars) to whatever fits your performance. 67 | "file_max_size" : 1048576, 68 | 69 | // By default, only simple spaces and tabs are matched as "trailing spaces". 70 | "regexp": "[ \t]+" 71 | } 72 | --------------------------------------------------------------------------------