├── .gitignore ├── .no-sublime-package ├── CHANGES.md ├── LICENSE.md ├── Main.sublime-menu ├── README.md ├── SublimeWritingStyle.py ├── SublimeWritingStyle.sublime-commands ├── SublimeWritingStyle.sublime-settings ├── icons ├── pencil-dark.png ├── pencil-light.png ├── weasel-dark.png └── weasel-light.png └── messages.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | README.html 4 | .DS_Store -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thedataking/SublimeWritingStyle/a8771565bfca721b60db145399399fe9b109e5e6/.no-sublime-package -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | Changes in Sublime Writing Style 2 | ================================ 3 | 4 | ## 1.0.2 5 | 6 | * Hooks for color theming 7 | * Light and Dark icons 8 | 9 | ## 1.0.1 10 | 11 | * Highlight consecutive duplicate words (e.g., `horse horse`) 12 | * Added `messages.json` and `CHANGES.md`. 13 | 14 | ## 1.0.0 15 | 16 | * Initial release 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2015 Per Larsen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "tools", 4 | "caption": "Tools", 5 | "children": 6 | [ 7 | { 8 | "id": "packages", 9 | "caption": "Packages", 10 | "children": 11 | [ 12 | { 13 | "id": "sublime_writing_style", 14 | "caption": "SublimeWritingStyle", 15 | "children": 16 | [ 17 | { 18 | "command": "toggle_sublime_writing_style" 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | ] 25 | }, 26 | { 27 | "caption": "Preferences", 28 | "mnemonic": "n", 29 | "id": "preferences", 30 | "children": 31 | [ 32 | { 33 | "caption": "Package Settings", 34 | "mnemonic": "P", 35 | "id": "package-settings", 36 | "children": 37 | [ 38 | { 39 | "caption": "SublimeWritingStyle", 40 | "children": 41 | [ 42 | { 43 | "command": "open_file", 44 | "args": {"file": "${packages}/Writing Style/SublimeWritingStyle.sublime-settings"}, 45 | "caption": "Settings – Default" 46 | }, 47 | { 48 | "command": "open_file", 49 | "args": {"file": "${packages}/User/SublimeWritingStyle.sublime-settings"}, 50 | "caption": "Settings – User" 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SublimeWritingStyle 2 | =================== 3 | 4 | Improve your writing style with this Sublime Text package. 5 | It supports both Sublime Text 2 and 3. 6 | 7 | Why Should I Write in Style? 8 | ------------------------------ 9 | 10 | Practicing your writing skills will make you a more effective communicator. 11 | 12 | How Does This Package Help Me? 13 | ----------------------------------- 14 | 15 | It does two things. First, it helps you use *active voice* instead of *passive voice*. 16 | Consider these two sentences: 17 | 18 | - The car was driven by the boy. 19 | 20 | - The boy drove the car. 21 | 22 | Which one is simpler? (Hint, it's the second, active one.) Using active voice simultaneously makes your text shorter and more engaging to the reader. Unfortunately, it takes some practice to spot passive sentences. 23 | Passive voice indicators are forms of *to be* (am, is, are, was, were, be, been, being) plus another verb (often ending in *ed*). 24 | 25 | Second, this package highlights *weasel words*. Use these judgmental words sparingly. A few examples: *very, clearly, and, relatively*. 26 | 27 | Both the list of passive voice indicators and weasel words are customizable using Sublime Text settings files. Use the `extra_words` settings key to define additional highlighted words. 28 | 29 | How to Install 30 | ------------------------------------------ 31 | 32 | #### Using [Package Control][0] (Recommended): 33 | 34 | 1. [Install][1] Package Control 35 | 2. Open the command palette (`cmd+shift+P`) then `Package Control: Install Package` 36 | 3. Search for `Writing Style` 37 | 4. (Optionally) Reopen any windows 38 | 39 | #### Manually: 40 | 41 | 1. Open the `Preferences > Browse Packages…` menu 42 | 2. Extract the [zip archive][zip] to the `Packages` directory, rename it to `Writing Style`, and delete the zip archive 43 | 3. Restart Sublime Text 44 | 45 | How Can I Configure What gets Highlighted? 46 | ------------------------------------------ 47 | Create (or open) a file called ```SublimeWritingStyle.sublime-settings``` in your Packages/User directory. 48 | For instance, you can add extra weasel words using the ```extra_words``` key or overwrite existing weasel words using the ```weasel_words``` key. 49 | You can enable the plugin on additional file types using the ```extra_extensions``` key. 50 | 51 | How Can I Adjust the Colors of the Highlights? 52 | ----------------------------------------------- 53 | The icons come in dark and light versions. You can switch this by adding this to your user settings: 54 | 55 | ```json 56 | "theme": "light" 57 | ``` 58 | 59 | Valid theme values are: `light`, `dark`, and `none`. The last option turns off gutter icons. 60 | 61 | 62 | Add this to your theme, and adjust the colors as necessary: 63 | 64 | ```xml 65 | 66 | 67 | name 68 | SublimeWritingStyle.Passive 69 | scope 70 | writingstyle.passive 71 | settings 72 | 73 | foreground 74 | #40BFFF 75 | 76 | 77 | 78 | name 79 | SublimeWritingStyle.Weasel 80 | scope 81 | writingstyle.weasel 82 | settings 83 | 84 | foreground 85 | #E09500 86 | 87 | 88 | ``` 89 | 90 | 91 | Who Inspired This Package? 92 | -------------------------- 93 | 94 | [Stefan Brunthaler](http://www.ics.uci.edu/~sbruntha/) extended the [writegood-mode](https://github.com/bnbeckwith/writegood-mode) for [Emacs](http://www.gnu.org/software/emacs/) in a similar fashion. 95 | 96 | Icons made by [Freepik][2] from [www.flaticon.com][3] is licensed by [Creative Commons BY 3.0][4] 97 | 98 | [0]: https://sublime.wbond.net/ 99 | [1]: https://sublime.wbond.net/installation 100 | [2]: http://www.freepik.com 101 | [3]: http://www.flaticon.com 102 | [4]: http://creativecommons.org/licenses/by/3.0/ 103 | [zip]: https://github.com/thedataking/SublimeWritingStyle/archive/master.zip 104 | -------------------------------------------------------------------------------- /SublimeWritingStyle.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sublime 3 | import sublime_plugin 4 | 5 | # Sublime Text 2 API reference: 6 | # http://www.sublimetext.com/docs/2/api_reference.html 7 | 8 | # Acknowledgements: 9 | # Several snippets inspired by WordHighlight plugin for 10 | # Sublime Text (https://github.com/SublimeText/WordHighlight) 11 | 12 | # TODO: detect long and complex sentences 13 | # TODO: detect adverbs 14 | # TODO: detect patterns that can be simplified 15 | 16 | weasel_word_regions = [] 17 | passive_voice_regions = [] 18 | 19 | def mark_words(view, search_all=True): 20 | global settings, weasel_word_regions, passive_voice_regions 21 | 22 | def find_words(pattern): 23 | if search_all: 24 | if settings.debug: 25 | print('sublimewritingstyle: searching whole document') 26 | found_regions = view.find_all(pattern, sublime.IGNORECASE, '', []) 27 | else: 28 | if settings.debug: 29 | print('sublimewritingstyle: searching around visible region') 30 | found_regions = [] 31 | chunk_size = 2 * 10 ** 3 32 | 33 | visible_region = view.visible_region() 34 | begin = max(visible_region.begin() - chunk_size, 0) 35 | end = min(visible_region.end() + chunk_size, view.size()) 36 | from_point = begin 37 | while True: 38 | region = view.find(pattern, from_point, sublime.IGNORECASE) 39 | if region: 40 | found_regions.append(region) 41 | rend = region.end() 42 | if rend > end: 43 | break 44 | else: 45 | from_point = rend 46 | else: 47 | break 48 | return found_regions 49 | # end of find_words 50 | 51 | def lazy_mark_regions(new_regions, old_regions, style_key, color_scope_name, symbol_name, draw_style): 52 | if old_regions != new_regions or True: 53 | # print 'adding new regions' 54 | view.erase_regions(style_key) 55 | # name, regions, style, symbol in gutter, draw outlined 56 | if settings.theme == 'none': 57 | view.add_regions(style_key, new_regions, color_scope_name, flags = draw_style) 58 | else: 59 | view.add_regions(style_key, new_regions, color_scope_name, symbol_name, draw_style) 60 | return new_regions 61 | # end of lazy_mark_regions 62 | 63 | # passive words 64 | new_regions = find_words(settings.passive_voice_pattern) 65 | passive_voice_regions = lazy_mark_regions( 66 | new_regions, 67 | passive_voice_regions, 68 | 'SublimeWritingStyle.Passive', 69 | 'writingstyle.passive', 70 | os.path.join('Packages', 'Writing Style', 'icons', 'pencil-dark.png' if settings.theme == 'dark' else 'pencil-light.png'), 71 | sublime.DRAW_NO_FILL + sublime.DRAW_NO_OUTLINE + sublime.DRAW_STIPPLED_UNDERLINE) 72 | 73 | # weasel words 74 | new_regions = find_words(settings.pattern) 75 | weasel_word_regions = lazy_mark_regions( 76 | new_regions, 77 | weasel_word_regions, 78 | 'SublimeWritingStyle.Weasel', 79 | 'writingstyle.weasel', 80 | os.path.join('Packages', 'Writing Style', 'icons', 'weasel-dark.png' if settings.theme == 'dark' else 'weasel-light.png'), 81 | sublime.DRAW_NO_FILL + sublime.DRAW_NO_OUTLINE + sublime.DRAW_SQUIGGLY_UNDERLINE) 82 | 83 | 84 | class SublimeWritingStyleListener(sublime_plugin.EventListener): 85 | enabled = False 86 | 87 | @classmethod 88 | def disable(cls): 89 | """ 90 | marks package as disabled and removes marked words. 91 | """ 92 | cls.enabled = False 93 | window = sublime.active_window() 94 | if window: 95 | view = window.active_view() 96 | if view: 97 | view.erase_regions("SublimeWritingStyle.Passive") 98 | view.erase_regions("SublimeWritingStyle.Weasel") 99 | 100 | def handle_event(self, view): 101 | """ 102 | determines if the package status changed. marks words when turned on. 103 | """ 104 | global settings 105 | 106 | # does settings enable package? 107 | if not settings.enabled: 108 | # ... no! 109 | SublimeWritingStyleListener.disable() 110 | return 111 | 112 | # check this file if either it's enabled or if the extensions list is empty 113 | file_name = view.file_name() 114 | 115 | ext = '' 116 | if file_name: 117 | # Use the extension if it exists, otherwise use the whole filename 118 | ext = os.path.splitext(file_name) 119 | if ext[1]: 120 | ext = ext[1] 121 | else: 122 | ext = os.path.split(file_name)[1] 123 | 124 | allowed_extensions = settings.get('extensions') 125 | if (not allowed_extensions) or ext in allowed_extensions: 126 | if not SublimeWritingStyleListener.enabled: 127 | SublimeWritingStyleListener.enabled = True 128 | 129 | mark_words(view) 130 | return 131 | 132 | SublimeWritingStyleListener.disable() # turn off for this file! 133 | 134 | def on_activated(self, view): 135 | if not view.is_loading(): 136 | self.handle_event(view) 137 | 138 | def on_post_save(self, view): 139 | self.handle_event(view) 140 | 141 | def on_load(self, view): 142 | self.handle_event(view) 143 | 144 | def on_modified(self, view): 145 | if SublimeWritingStyleListener.enabled: 146 | mark_words(view, search_all=False) 147 | 148 | 149 | def load_settings(): 150 | """ 151 | runs when package loads. 152 | """ 153 | settings = sublime.load_settings('SublimeWritingStyle.sublime-settings') 154 | 155 | def process_settings(settings): 156 | """ 157 | add properties reflecting the loaded settings. 158 | """ 159 | def build_passive_voice_regex(linking_verbs, irregulars): 160 | return r'(?\\)+\\([[:word:]]+ed\\|" 37 | "passive_voice_linking_verbs": ["am", "are", "were", "being", "is", "been", "was", "be"], 38 | "extensions": [".py", ".tex", ".md", ".mdown", ".markdown", ".txt", ".rst"], 39 | "enabled": true, 40 | "theme": "light" 41 | } 42 | -------------------------------------------------------------------------------- /icons/pencil-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thedataking/SublimeWritingStyle/a8771565bfca721b60db145399399fe9b109e5e6/icons/pencil-dark.png -------------------------------------------------------------------------------- /icons/pencil-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thedataking/SublimeWritingStyle/a8771565bfca721b60db145399399fe9b109e5e6/icons/pencil-light.png -------------------------------------------------------------------------------- /icons/weasel-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thedataking/SublimeWritingStyle/a8771565bfca721b60db145399399fe9b109e5e6/icons/weasel-dark.png -------------------------------------------------------------------------------- /icons/weasel-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thedataking/SublimeWritingStyle/a8771565bfca721b60db145399399fe9b109e5e6/icons/weasel-light.png -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "README.md", 3 | "1.0.1": "CHANGES.md", 4 | "1.0.2": "CHANGES.md" 5 | } --------------------------------------------------------------------------------