├── Context.sublime-menu ├── Default (Linux).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── LICENSE ├── Main.sublime-menu ├── README.md ├── Zeal.sublime-settings ├── messages.json ├── messages └── 2.0.0.md └── zeal.py /Context.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "-"}, 3 | { "command": "zeal_search_selection", "caption": "Search Zeal" } 4 | ] -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["f1"], 4 | "command": "zeal_search_selection" 5 | }, 6 | { 7 | "keys": ["shift+f1"], 8 | "command": "zeal_search" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["f1"], 4 | "command": "zeal_search_selection" 5 | }, 6 | { 7 | "keys": ["shift+f1"], 8 | "command": "zeal_search" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences: Zeal", 4 | "command": "edit_settings", 5 | "args": { 6 | "base_file": "${packages}/Zeal/Zeal.sublime-settings", 7 | "default": "{\n\t\"docsets_user\": [$0],\n}", 8 | } 9 | }, 10 | { 11 | "caption": "Preferences: Zeal Key Bindings", 12 | "command": "edit_settings", 13 | "args": { 14 | "base_file": "${packages}/Zeal/Default (${platform}).sublime-keymap", 15 | "default": "[\n\t$0\n]\n", 16 | } 17 | }, 18 | { 19 | "caption": "Zeal: Open Readme", 20 | "command": "open_file", 21 | "args": { 22 | "file": "${packages}/Zeal/README.md" 23 | } 24 | }, 25 | 26 | { 27 | "caption": "Zeal: Search Selection", 28 | "command": "zeal_search_selection", 29 | }, 30 | { 31 | "caption": "Zeal: Search", 32 | "command": "zeal_search", 33 | }, 34 | ] 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Vaan (http://www.vaanwebdesign.ro) 2 | Copyright (c) 2020 FichteFoll 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": [ 7 | { 8 | "caption": "Package Settings", 9 | "mnemonic": "P", 10 | "id": "package-settings", 11 | "children": [ 12 | { 13 | "caption": "Zeal", 14 | "children": 15 | [ 16 | { 17 | "caption": "Settings", 18 | "command": "edit_settings", 19 | "args": { 20 | "base_file": "${packages}/Zeal/Zeal.sublime-settings", 21 | "default": "{\n\t\"docsets_user\": [$0],\n}", 22 | }, 23 | }, 24 | { 25 | "caption": "Key Bindings", 26 | "command": "edit_settings", 27 | "args": { 28 | "base_file": "${packages}/Zeal/Default (${platform}).sublime-keymap", 29 | }, 30 | }, 31 | ], 32 | }, 33 | ], 34 | }, 35 | ], 36 | }, 37 | ] 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zeal for Sublime Text 2 | 3 | [Zeal][] integration for Sublime Text. 4 | [Zeal][] is an offline documentation browser which similar to [Dash][]. 5 | 6 | [Zeal]: https://zealdocs.org/ 7 | [Dash]: https://kapeli.com/dash/ 8 | 9 | Tested on Windows & Linux. 10 | 11 | 12 | ## Usage 13 | 14 | - F1 - Search for the currently selected word. 15 | Shows a selection list if multiple docsets match for the current file. 16 | 17 | ![code](https://user-images.githubusercontent.com/931051/82086247-85d60500-96ee-11ea-83e2-154094db1af4.png) 18 | ![docset list](https://user-images.githubusercontent.com/931051/82086077-414a6980-96ee-11ea-8fa6-b3d895f97b1f.png) 19 | 20 | - Shift F1 - Custom search in Zeal docsets. 21 | 22 | ![custom search](https://user-images.githubusercontent.com/931051/82086076-40b1d300-96ee-11ea-92ae-9b922bd2434a.png) 23 | 24 | 25 | ## Installation 26 | 27 | The easiest way to install the package 28 | is to use [Package Control](https://packagecontrol.io/). 29 | Choose *Package Control: Install Package* in the Command Palette 30 | (Ctrl Shift P) 31 | and select "Zeal" from the list. 32 | 33 | ### Using Git 34 | 35 | Go to your Sublime Text `Packages` directory and clone the repository using the command below: 36 | 37 | $ git clone https://github.com/vaanwd/Zeal "Zeal" 38 | 39 | ### Download Manually 40 | 41 | 1. Download the files using the GitHub .zip download option. 42 | 1. Unzip the files and rename the folder to `Zeal`. 43 | 1. Copy the folder to your Sublime Text `Packages` directory. 44 | 45 | 46 | ## Configuration 47 | 48 | Select `Preferences: Zeal Settings` form the command palette 49 | to open the configuration files. 50 | 51 | If your zeal executable cannot be found by default, 52 | change the `zeal_command` setting. 53 | 54 | To add more docsets to choose from, 55 | add entries to the `docsets_user` list. 56 | 57 | 58 | [© 2014 Vaan Web Design](https://www.vaanwebdesign.ro)
59 | [© 2020 FichteFoll](https://github.com/FichteFoll) 60 | -------------------------------------------------------------------------------- /Zeal.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // Zeal executable path. Subject to $PATH resolution. 3 | // 4 | // For Linux: "zeal" 5 | // For Windows: "c:\\Program Files\\Zeal\\zeal.exe" 6 | "zeal_command": "zeal", 7 | 8 | // Configure behavior for when none of the docsets below match. 9 | // 10 | // "stop": Do nothing. 11 | // "none": Search for the selected word without a namespace. 12 | // "guess": Try to guess the docset namespace. 13 | "fallback": "none", 14 | 15 | // Configure behavior for when multiple docsets were match. 16 | // 17 | // "select": Open a list of all matching docsets to choose from. 18 | // "join": Join all matching docsets for the query. 19 | "multi_match": "select", 20 | 21 | // Set of docset configuration that help will be offered for, 22 | // based on the syntax of the current view. 23 | // You can add docsets to this list via `docsets_user`. 24 | // 25 | // The fields are: 26 | // name: The name shown in the popup and used as the default for the others. 27 | // selector: A scope selector used to determine whether this language is active. 28 | // Default: namespace: name.lower().replace(" ", "-") 29 | // namespace: Namespace to use for searching in Zeal. 30 | // Default: f"source.{namespace}` 31 | "docsets": [ 32 | { "name": "ActionScript" }, 33 | { "name": "C" }, 34 | { "name": "Clojure", "selector": "source.clojure - source.clojure.clojurescript" }, 35 | { "name": "ClojureScript", "selector": "source.clojurescript, source.clojure.clojurescript", "namespace": "cljs" }, 36 | { "name": "CMake" }, 37 | { "name": "CSS" }, 38 | { "name": "Go" }, 39 | { "name": "Haskell" }, 40 | { "name": "HTML", "selector": "text.html" }, 41 | { "name": "Java" }, 42 | { "name": "JavaScript", "selector": "source.js" }, 43 | { "name": "LaTeX", "selector": "text.tex.latex" }, 44 | { "name": "LESS", "selector": "source.css.less" }, 45 | { "name": "Lua" }, 46 | { "name": "Php" }, 47 | { "name": "Python" }, 48 | { "name": "Rust" }, 49 | { "name": "SASS", "selector": "source.sass" }, 50 | { "name": "SCSS", "selector": "source.scss" }, 51 | { "name": "Sublime Text", "selector": "source.json.sublime, source.yaml.sublime" }, 52 | ], 53 | 54 | // Entries in this list will be added 55 | // to the `docsets` set above. 56 | // Docsets with the same name override. 57 | "docsets_user": [ 58 | // { "name": "Sublime Text", "selector": "source.json.sublime, source.yaml.sublime, source.python" }, 59 | ], 60 | } 61 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "2.0.0": "messages/2.0.0.md" 3 | } 4 | -------------------------------------------------------------------------------- /messages/2.0.0.md: -------------------------------------------------------------------------------- 1 | v2.0.0 (2020-05-15) 2 | ------------------- 3 | 4 | The Zeal package has been rewritten entirely. 5 | It is now more flexible and easier to configure. 6 | 7 | **The old `language_mapping` setting has been removed and replaced by `docsets`!** 8 | 9 | If you added any custom entries to that setting, 10 | select *Preferences: Zeal Settings* from the Command Palette 11 | and add any entries you added to `docsets_user`, 12 | following the documentation provided in the comments. 13 | Please also note the addition of new settings `fallback` and `multi_match`. 14 | -------------------------------------------------------------------------------- /zeal.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import operator 3 | import subprocess 4 | import shutil 5 | 6 | import sublime 7 | import sublime_plugin 8 | 9 | settings = None 10 | 11 | 12 | def plugin_loaded(): 13 | global settings 14 | settings = sublime.load_settings('Zeal.sublime-settings') 15 | 16 | 17 | @functools.total_ordering 18 | class Docset: 19 | """A docset configuration item, computing defaults based on the given name. 20 | 21 | Comparison and hashing is reduced to the name attribute only. 22 | This is important when building sets, as later additions are discarded. 23 | """ 24 | def __init__(self, name, namespace=None, selector=None): 25 | self.name = name 26 | self.namespace = namespace or name.lower().replace(" ", "-") 27 | self.selector = selector or "source.{}".format(self.namespace) 28 | 29 | def score(self, scope): 30 | return sublime.score_selector(scope, self.selector) 31 | 32 | def __repr__(self): 33 | return ( 34 | "{self.__class__.__name__}" 35 | "(name={self.name!r}" 36 | ", namespace={self.namespace!r}" 37 | ", selector={self.selector!r}" 38 | ")".format(self=self) 39 | ) 40 | 41 | def __gt__(self, other): 42 | return self.name > other.name 43 | 44 | def __eq__(self, other): 45 | return self.name == other.name 46 | 47 | def __hash__(self): 48 | return hash(self.name) 49 | 50 | 51 | def get_word(view): 52 | for region in view.sel(): 53 | if region.empty(): 54 | region = view.word(region) 55 | text = view.substr(region).strip() 56 | if "\n" in text: 57 | return None, None # what are you doing? 58 | elif text: 59 | scope = view.scope_name(region.begin()) 60 | return text, scope 61 | 62 | return None, None 63 | 64 | 65 | def query_string(namespace, text): 66 | return "{}:{}".format(namespace, text) if namespace else text 67 | 68 | 69 | def status(msg): 70 | sublime.status_message("Zeal: {}".format(msg)) 71 | 72 | 73 | def open_zeal(query): 74 | cmd_setting = settings.get('zeal_command', "zeal") 75 | cmd_path = shutil.which(cmd_setting) 76 | if not cmd_path: 77 | sublime.error_message("Could not find your Zeal executable. ({})" 78 | '\n\nPlease edit Zeal.sublime-settings' 79 | .format(cmd_setting)) 80 | return 81 | try: 82 | subprocess.Popen([cmd_path, query]) 83 | except Exception as e: 84 | status(e) 85 | raise 86 | 87 | 88 | def match_docsets(docsets, scope): 89 | with_scores = [(lang.score(scope), lang) for lang in docsets] 90 | matching = filter(operator.itemgetter(0), with_scores) 91 | return map(operator.itemgetter(1), sorted(matching)) 92 | 93 | 94 | class ZealSearchSelectionCommand(sublime_plugin.TextCommand): 95 | 96 | handler = None 97 | 98 | def input(self, args): 99 | if self.handler: 100 | return self.handler 101 | 102 | def clear_handler(self): 103 | # This method is required to unset the handler 104 | # once ST requested the list of items *for real* 105 | # (and not to test whether an input handler 106 | # would theoretically be available). 107 | self.handler = None 108 | 109 | def run(self, edit, namespace=None): 110 | self.handler = None 111 | text, scope = get_word(self.view) 112 | 113 | if not text: 114 | status("No word was selected.") 115 | return 116 | 117 | if namespace is None: 118 | docset_dicts = settings.get("docsets_user", []) + settings.get("docsets", []) 119 | docsets = set(Docset(**d) for d in docset_dicts) 120 | matched_docsets = list(match_docsets(docsets, scope)) 121 | 122 | if len(matched_docsets) == 1: 123 | namespace = matched_docsets[0].namespace 124 | 125 | elif matched_docsets: 126 | multi_match = settings.get('multi_match', 'select') 127 | if multi_match == 'select': 128 | self.handler = ZealNameInputHandler(matched_docsets, text, self.clear_handler) 129 | raise TypeError("required positional argument") # cause ST to call input() 130 | elif multi_match == 'join': 131 | namespace = ",".join(ds.namespace for ds in matched_docsets) 132 | 133 | else: 134 | # Determine fallback behavior 135 | fallback = settings.get('fallback', 'none') 136 | if fallback == 'stop': 137 | sublime.status_message("No Zeal mapping found.") 138 | return 139 | elif fallback == 'none': 140 | pass # leave namespace unset 141 | elif fallback == 'guess': 142 | # Find innermost 'source' scope 143 | base_scopes = reversed(s for s in scope.split() if s.startswith("source.")) 144 | if not base_scopes: 145 | return 146 | base_scope = base_scopes[0] 147 | namespace = base_scope.split(".")[1] 148 | status("No docset matched {!r}, guessed {!r}.".format(base_scope, namespace)) 149 | else: 150 | status("Unrecognized 'fallback' setting.") 151 | return 152 | 153 | open_zeal(query_string(namespace, text)) 154 | 155 | 156 | class ZealSearchCommand(sublime_plugin.TextCommand): 157 | def input(self, args): 158 | if not args.get('text'): 159 | return SimpleTextInputHandler('text', placeholder="query string") 160 | 161 | def run(self, edit, text): 162 | open_zeal(text) 163 | 164 | 165 | class SimpleTextInputHandler(sublime_plugin.TextInputHandler): 166 | def __init__(self, param_name, *, placeholder=""): 167 | self.param_name = param_name 168 | self._placeholder = placeholder 169 | 170 | def name(self): 171 | return self.param_name 172 | 173 | def placeholder(self): 174 | return self._placeholder 175 | 176 | 177 | class ZealNameInputHandler(sublime_plugin.ListInputHandler): 178 | def __init__(self, docsets, text, *, on_offer=None): 179 | self.docsets = docsets 180 | self.text = text 181 | self.on_offer = on_offer 182 | 183 | def placeholder(self): 184 | return "Select docset" 185 | 186 | def list_items(self): 187 | if self.on_offer: 188 | self.on_offer() 189 | return sorted(lang.name for lang in self.docsets) 190 | 191 | def preview(self, value): 192 | lang = next(lang for lang in self.docsets if lang.name == value) 193 | return sublime.Html("Query: {}:{}".format(lang.namespace, self.text)) 194 | --------------------------------------------------------------------------------