├── LICENSE ├── README.md └── all └── hyperhelpcore ├── HyperHelp ├── bootstrap.py ├── commands.py ├── contexts.py ├── devtools.py ├── events.py ├── help │ ├── api.txt │ ├── authoring.txt │ ├── bookmarks.txt │ ├── changelog.txt │ ├── commands.txt │ ├── example.txt │ ├── help_index.txt │ ├── help_on_help.txt │ ├── hyperhelp.json.sublime-ignored │ ├── index.txt │ ├── integration.txt │ ├── key_contexts.txt │ ├── settings.txt │ ├── style.txt │ └── syntax.txt ├── internalcmd.py └── resources │ ├── Context.sublime-menu.sublime-ignored │ ├── Default (Linux).sublime-keymap.sublime-ignored │ ├── Default (OSX).sublime-keymap.sublime-ignored │ ├── Default (Windows).sublime-keymap.sublime-ignored │ ├── HyperHelp-Help.sublime-settings.sublime-ignored │ ├── HyperHelp.sublime-commands.sublime-ignored │ ├── HyperHelp.sublime-settings.sublime-ignored │ ├── Main.sublime-menu.sublime-ignored │ ├── Preferences.sublime-settings-hints.sublime-ignored │ ├── Symbol List - Exclusions.tmPreferences.sublime-ignored │ ├── Symbol List - Headers.tmPreferences.sublime-ignored │ ├── Symbol List - Title.tmPreferences.sublime-ignored │ └── syntax │ ├── HyperHelp-Help.sublime-syntax.sublime-ignored │ ├── HyperHelp-Index.sublime-syntax.sublime-ignored │ └── HyperHelpComments.tmPreferences.sublime-ignored ├── __init__.py ├── bootstrapper.py ├── common.py ├── core.py ├── data.py ├── help.py ├── help_index.py ├── index_validator.py ├── startup.py ├── validictory ├── LICENSE.txt ├── __init__.py └── validator.py └── view.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2019 Terence Martin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HyperHelp and hyperhelpcore 2 | ============================ 3 | 4 | hyperhelpcore is a dependency package for Sublime Text 3 that allows package 5 | authors to provide context sensitive, hyperlinked help for their packages that 6 | is displayable directly from within Sublime Text itself. 7 | 8 | At first startup, hyperhelpcore will generate a HyperHelp package in the 9 | InstalledPackages folder to expose the help functionality, and ensure that it 10 | is always up to date. 11 | 12 | Some packages using hyperhelpcore: 13 | 14 | * [SnAPI](https://github.com/STealthy-and-haSTy/SnAPI) - View the 15 | documentation for Sublime Text directly within Sublime 16 | * [HyperHelpAuthor](https://github.com/STealthy-and-haSTy/HyperHelpAuthor) - 17 | Simple authoring tools for hyperhelpcore 18 | 19 | 20 | ------------------------------------------------------------------------------- 21 | 22 | 23 | **NOTE:** This is very much still a work in progress and still being actively 24 | developed and tweaked. At this point anything and everything is subject to 25 | change without notice. 26 | 27 | 28 | ------------------------------------------------------------------------------- 29 | 30 | 31 | ## License ## 32 | 33 | Copyright 2017-2019 Terence Martin 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of 36 | this software and associated documentation files (the "Software"), to deal in 37 | the Software without restriction, including without limitation the rights to 38 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 39 | of the Software, and to permit persons to whom the Software is furnished to do 40 | so, subject to the following conditions: 41 | 42 | The above copyright notice and this permission notice shall be included in all 43 | copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 51 | SOFTWARE. 52 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/bootstrap.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | from hyperhelpcore.bootstrapper import display_topic 4 | from hyperhelpcore.common import hh_setting 5 | 6 | 7 | ### --------------------------------------------------------------------------- 8 | 9 | 10 | # When the bootstrapped system package is created or updated, the value of this 11 | # tuple is updated to the version of the dependency that is doing the 12 | # bootstrap. 13 | # 14 | # The bootstrap code looks specifically for this line, so don't modify it. 15 | __core_version_tuple = (0, 0, 0) 16 | 17 | __version_tuple = __core_version_tuple 18 | __version__ = ".".join([str(num) for num in __version_tuple]) 19 | 20 | 21 | ### --------------------------------------------------------------------------- 22 | 23 | 24 | def version(): 25 | """ 26 | Get the currently installed version of the bootstrapped version of the 27 | package as a tuple. This is used during the bootstrap check to see if the 28 | version of the dependency has changed since the bootstrapped package was 29 | created. 30 | """ 31 | return __version_tuple 32 | 33 | 34 | def plugin_loaded(): 35 | """ 36 | On plugin load, see if we should display an initial help topic or not. 37 | This relies on a window setting that the bootstrapper applies to whatever 38 | the current window is, and will display an appropriate topic based on what 39 | the bootstrap did. 40 | """ 41 | topic = None 42 | for window in sublime.windows(): 43 | settings = window.settings() 44 | if settings.has("hyperhelp.initial_topic"): 45 | topic = topic or settings.get("hyperhelp.initial_topic") 46 | settings.erase("hyperhelp.initial_topic") 47 | 48 | if topic is not None and hh_setting("show_changelog"): 49 | package, topic = topic.split(":") 50 | display_topic(package, topic) 51 | 52 | 53 | ### --------------------------------------------------------------------------- -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/contexts.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from hyperhelpcore.common import log 5 | from hyperhelpcore.common import current_help_package, current_help_file 6 | from hyperhelpcore.view import find_help_view 7 | 8 | 9 | ###---------------------------------------------------------------------------- 10 | 11 | 12 | class HyperhelpContextListener(sublime_plugin.EventListener): 13 | def on_query_context(self, view, key, operator, operand, match_all): 14 | """ 15 | Provide custom key binding contexts for binding keys in hyperhelp 16 | views. 17 | """ 18 | if key == "hyperhelp.is_help_view": 19 | help_view = find_help_view(view.window()) 20 | lhs = help_view is not None and help_view.id() == view.id() 21 | rhs = bool(operand) 22 | 23 | elif key == "hyperhelp.is_help_source": 24 | lhs = (view.match_selector(0, "text.hyperhelp.help") and 25 | view.is_read_only() == False) 26 | rhs = bool(operand) 27 | 28 | elif key == "hyperhelp.is_help": 29 | lhs = view.match_selector(0, "text.hyperhelp.help") 30 | rhs = bool(operand) 31 | 32 | elif key == "hyperhelp.is_help_index": 33 | lhs = view.match_selector(0, "text.hyperhelp.index") 34 | rhs = bool(operand) 35 | 36 | elif key == "hyperhelp.is_help_visible": 37 | lhs = find_help_view(view.window()) is not None 38 | rhs = bool(operand) 39 | 40 | elif key == "hyperhelp.is_help_package": 41 | lhs = current_help_package(window=view.window()) 42 | rhs = str(operand) 43 | 44 | elif key == "hyperhelp.is_help_file": 45 | lhs = current_help_file(window=view.window()) 46 | rhs = str(operand) 47 | 48 | # This one is the legacy; remove this once the others are fully 49 | # tested. 50 | elif key == "hyperhelp.is_authoring": 51 | lhs = view.is_read_only() == False 52 | rhs = bool(operand) 53 | else: 54 | return None 55 | 56 | if operator == sublime.OP_EQUAL: 57 | return lhs == rhs 58 | elif operator == sublime.OP_NOT_EQUAL: 59 | return lhs != rhs 60 | 61 | return None 62 | 63 | 64 | ###---------------------------------------------------------------------------- 65 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/devtools.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | import textwrap 5 | 6 | from hyperhelpcore.bootstrapper import log, BootstrapThread 7 | 8 | 9 | 10 | ###---------------------------------------------------------------------------- 11 | 12 | 13 | def _wrap(msg, *args, **kwargs): 14 | return textwrap.dedent(msg.format(*args, **kwargs)).strip() 15 | 16 | 17 | def _is_developer_mode(): 18 | s = sublime.load_settings("HyperHelp.sublime-settings") 19 | return s.get("developer_mode", False) 20 | 21 | 22 | ###---------------------------------------------------------------------------- 23 | 24 | 25 | class HyperhelpDeveloperForceBootstrapCommand(sublime_plugin.ApplicationCommand): 26 | """ 27 | Verify with the user and then, if confirmed, force hyperhelpcore to run an 28 | immediate bootstrap sequence to re-bootstrap the package. 29 | 30 | This is a developer only command; if you're not actively developing the 31 | package, you shouldn't be invoking this command without being directed to 32 | do so by the developer or other person in the know. 33 | """ 34 | def run(self): 35 | if sublime.yes_no_cancel_dialog(_wrap( 36 | """ 37 | Force a HyperHelp bootstrap? 38 | 39 | This will execute a bootstrap and replace the existing 40 | HyperHelp system package (if any) with a newly generated 41 | one. 42 | """)) == sublime.DIALOG_YES: 43 | log("Developer: Forcing a bootstrap") 44 | BootstrapThread().start() 45 | 46 | def is_enabled(self): 47 | return _is_developer_mode() 48 | 49 | 50 | ###---------------------------------------------------------------------------- 51 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/events.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from collections import MutableSet 5 | 6 | from hyperhelpcore.common import log 7 | from hyperhelpcore.core import help_index_list, lookup_help_topic 8 | from hyperhelpcore.core import is_topic_file, is_topic_file_valid 9 | from hyperhelpcore.core import is_topic_url 10 | from hyperhelpcore.view import find_help_view 11 | from hyperhelpcore.help import _get_link_topic 12 | 13 | from hyperhelpcore.core import load_indexes_from_packages 14 | from hyperhelpcore.core import unload_help_indexes_from_packges 15 | 16 | 17 | ###---------------------------------------------------------------------------- 18 | 19 | 20 | _help_popup = """ 21 | 22 | 45 | {body} 46 | 47 | """ 48 | 49 | _missing_pkg = """ 50 |

Package not found

51 |

This link references a help package that is 52 | not currently installed.

53 |

{pkg} / {topic}

54 | """ 55 | 56 | _missing_topic = """ 57 |

Topic not found

58 |

This link references a topic that does not appear 59 | in the help index.

60 |

{pkg} / {topic}

61 | """ 62 | 63 | _missing_file = """ 64 |

Package File not found

65 |

This link opens a package file that does not 66 | currently exist.

67 |

{file}

68 | """ 69 | 70 | 71 | _topic_body = """ 72 |

{title}

73 |

{link_type}

74 |

{link}

75 | """ 76 | 77 | 78 | ###---------------------------------------------------------------------------- 79 | 80 | 81 | class PackageIndexWatcher(): 82 | """ 83 | A simple singleton class for determining when packages are being added to 84 | or removed from the list of ignored packages, so that we can trigger help 85 | indexes in those packages to be either unloaded or loaded, as needed. 86 | """ 87 | instance = None 88 | 89 | def __init__(self): 90 | if PackageIndexWatcher.instance is not None: 91 | return 92 | 93 | PackageIndexWatcher.instance = self 94 | self.settings = sublime.load_settings("Preferences.sublime-settings") 95 | self.cached_ignored = set(self.settings.get("ignored_packages", [])) 96 | 97 | self.settings.add_on_change("_hh_sw", lambda: self.__setting_changed()) 98 | 99 | @classmethod 100 | def unregister(cls): 101 | if PackageIndexWatcher.instance is not None: 102 | PackageIndexWatcher.instance.settings.clear_on_change("_hh_sw") 103 | PackageIndexWatcher.instance = None 104 | 105 | 106 | def __setting_changed(self): 107 | new_list = set(self.settings.get("ignored_packages", [])) 108 | if new_list == self.cached_ignored: 109 | return 110 | 111 | removed = self.cached_ignored - new_list 112 | added = new_list - self.cached_ignored 113 | self.cached_ignored = new_list 114 | 115 | if added: 116 | log("unloading all help indexes loaded from: %s", list(added)) 117 | sublime.set_timeout(lambda: unload_help_indexes_from_packges(list(added)), 2000) 118 | 119 | if removed: 120 | log("scanning for help indexes in: %s", list(removed)) 121 | sublime.set_timeout(lambda: load_indexes_from_packages(list(removed)), 2000) 122 | 123 | 124 | ###---------------------------------------------------------------------------- 125 | 126 | 127 | def plugin_loaded(): 128 | PackageIndexWatcher() 129 | for window in sublime.windows(): 130 | view = find_help_view(window) 131 | if view: 132 | view.run_command("hyperhelp_internal_flag_links") 133 | 134 | 135 | def plugin_unloaded(): 136 | PackageIndexWatcher.unregister() 137 | 138 | 139 | def _show_popup(view, point, popup): 140 | view.show_popup( 141 | _help_popup.format(body=popup), 142 | flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY, 143 | location=point, 144 | max_width=1024) 145 | 146 | 147 | ###---------------------------------------------------------------------------- 148 | 149 | 150 | class HyperhelpEventListener(sublime_plugin.EventListener): 151 | def on_text_command(self, view, command, args): 152 | """ 153 | Listen for the drag_select command with arguments that tell us that the 154 | user double clicked, see if they're double clicking on a link so we 155 | know if we should try to follow it or not. 156 | """ 157 | if (view.is_read_only() and command == "drag_select" and 158 | args.get("by", None) == "words"): 159 | event = args["event"] 160 | point = view.window_to_text((event["x"], event["y"])) 161 | 162 | if view.match_selector(point, "text.hyperhelp meta.link"): 163 | view.window().run_command("hyperhelp_navigate", 164 | {"nav": "follow_link"}) 165 | return ("noop") 166 | 167 | return None 168 | 169 | 170 | def on_hover(self, view, point, hover_zone): 171 | """ 172 | When the mouse hovers over a link in a help view, show a popup that 173 | tells you where the link goes or what file/URL it opens. 174 | """ 175 | if hover_zone != sublime.HOVER_TEXT: 176 | return 177 | 178 | default_pkg = view.settings().get("_hh_pkg", None) 179 | if default_pkg is None or not view.score_selector(point, "meta.link"): 180 | return 181 | 182 | link_info = _get_link_topic(view, view.extract_scope(point)) 183 | if link_info is None: 184 | return 185 | 186 | pkg = link_info.get("pkg", default_pkg) 187 | topic = link_info.get("topic") 188 | 189 | # Report if we don't know the package. In this case we may know what 190 | # the topic is but not what file it might appear in. 191 | pkg_info = help_index_list().get(pkg, None) 192 | if pkg_info is None: 193 | popup = _missing_pkg.format(pkg=pkg, topic=topic) 194 | return _show_popup(view, point, popup) 195 | 196 | # If there is no topic we can't really display anything useful. This is 197 | # an exceptional situation that is only possible if the help is broken. 198 | if topic is None: 199 | return 200 | 201 | # Look up the topic details. If we can't find it in the index, react 202 | # like a missing package since we can't know the file. 203 | topic_data = lookup_help_topic(pkg_info, topic) 204 | if topic_data is None: 205 | popup = _missing_topic.format(pkg=pkg, topic=topic) 206 | return _show_popup(view, point, popup) 207 | 208 | caption = topic_data.get("caption") 209 | file = topic_data.get("file") 210 | link = file 211 | 212 | # For links that open files, if that file does not exist as far as 213 | # Sublime is concerned, use a custom popup to let the user know. Such 214 | # a link will be highlighted as broken, so this explains why. 215 | # 216 | # This returns None for things that are not package files, so we need 217 | # to compare for False directkly. 218 | if is_topic_file_valid(pkg_info, topic_data) is False: 219 | popup = _missing_file.format(file=file) 220 | return _show_popup(view, point, popup) 221 | 222 | if is_topic_url(pkg_info, topic_data): 223 | link_type = "Opens URL: " 224 | elif is_topic_file(pkg_info, topic_data): 225 | link_type = "Opens File: " 226 | else: 227 | link_type = "Links To: " 228 | 229 | link = "" if default_pkg == pkg else pkg + " / " 230 | 231 | current_file = view.settings().get("_hh_file", None) 232 | if file != current_file: 233 | link = link + file + " / " 234 | 235 | link = link + topic 236 | 237 | popup = _topic_body.format(title=caption or topic, 238 | link_type=link_type, 239 | link=link) 240 | 241 | _show_popup(view, point, popup) 242 | 243 | 244 | ###---------------------------------------------------------------------------- 245 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/api.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp API" date="2019-03-23" 2 | 3 | 4 | # API Overview 5 | ================== 6 | 7 | HyperHelp provides several |commands|, |key contexts| and an api that allow you 8 | to customize the help experience for yourself or for users of your package by 9 | creating your own custom key bindings, menu entries or plugins. 10 | 11 | Since HyperHelp (more specifically |hyperhelpcore|, which provides the API) is 12 | still under active development and subject to change without notice, the API is 13 | not yet documented. 14 | 15 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/authoring.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp: Authoring Help" date="2019-03-25" 2 | 3 | 4 | # Authoring Overview 5 | ==================== 6 | 7 | HyperHelp is designed to make the barrier to entry as easy as possible in order 8 | to get help up and running. In order to create help for your package, you need 9 | to author: 10 | 11 | * A |hyperhelp.json| file to act as a help index file. This file tells 12 | HyperHelp what files in your package represent help files, and what 13 | topics appear in each file. 14 | 15 | As the name suggests, this is a |JSON| file; HyperHelp uses the internal 16 | JSON loader in Sublime, which is less strict than standard JSON and 17 | allows for comments, which can be of help in documenting your index. 18 | 19 | * One or more |help files| to provide the actual help content. These are 20 | regular text files which can make use of some simple |markup| to define 21 | the navigation elements in the file as well as some simple visual 22 | styling. There are some |:style.txt:style guidelines| to follow in your help files 23 | to ensure that everything is consistent for users. 24 | 25 | This help includes an |example hyperhelp.json| file and an |example index.txt| 26 | help file that demonstrate a simplistic help system and how everything ties 27 | together. 28 | 29 | Although you can create the needed files manually if desired, the 30 | |HyperHelpAuthor| package allows for easy creation of help indexes and files by 31 | doing some of the heavy lifting for you. 32 | 33 | `NOTE:` Like HyperHelp itself, HyperHelpAuthor is still under active 34 | development, so not all planned features exist yet. 35 | 36 | Once you have |:integration.txt:integrated| HyperHelp in your package and authored help, your 37 | job is done; HyperHelp will automatically find and present your help files to 38 | the user with no further setup. 39 | 40 | 41 | # Help Index Loading 42 | ==================== 43 | 44 | When the HyperHelp package loads, it scans the package directory for all of the 45 | |hyperhelp.json| files that exist, and loads them all in order to determine 46 | what help is currently available. These index files contain all of the meta 47 | information needed to know what packages contain help, and what that help 48 | consists of. 49 | 50 | In addition, as packages move in and out of the `ignored_packages` setting, 51 | any help indexes they contain will be either loaded or unloaded to keep the 52 | help information current. 53 | 54 | Note that it's possible for one physical package to contain multiple logical 55 | help packages within itself. Each index is treated as a separate package and 56 | presented as such. The |SnAPI| package that displays the official Sublime Text 57 | help is an example of this. 58 | 59 | 60 | # Navigating Topics 61 | =================== 62 | 63 | HyperHelp navigates help topics by looking up a |topic| in the index in order 64 | to determine what help file needs to be displayed. In order to do this, two 65 | pieces of information are required: 66 | 67 | * The help `topic` to view 68 | * The help `package` that the topic should be looked up in 69 | 70 | When no package is provided, the package whose help is currently being 71 | displayed is used by default. Similarly, if no help topic is provided, it is 72 | assumed to be `index.txt`. 73 | 74 | By looking up the help topic in the index for the appropriate package, 75 | HyperHelp can determine what help file it needs to display in the |help view|. 76 | Once that file is displayed, the |anchor| that matches the topic is found and 77 | focused. 78 | 79 | Based on this, some rules apply: 80 | 81 | * Only |help files| that appear in their package's help index can be opened 82 | and displayed because otherwise HyperHelp does not know where they are. 83 | 84 | * |:topic:Topics| within a help package must be unique; if there is more than one 85 | identical topic, HyperHelp is unable to determine which one to display. 86 | 87 | * An |anchor| must be present in a help file that matches the topic; 88 | otherwise once the help file is opened, HyperHelp can't know where in the 89 | file to look. 90 | 91 | By convention, all |help files| contain a |file header| which provides 92 | information on the title and last modification date of that particular file. 93 | When the help file is rendered, it contains an implicit anchor that specifies 94 | the name of the help file itself. 95 | 96 | This makes it possible to navigate to any help file in any package by using 97 | it's name as a help topic. 98 | 99 | Based on this convention and the fact that the default topic is `index.txt` 100 | when one is not provided, all help packages should contain an `index.txt` help 101 | file that specifies the entry point to the help in much the same way as the 102 | `index.html` file does for a folder on a web page. 103 | 104 | This allows a convenient way to open the help for any package by merely 105 | specifying that you which to browse that package directly. 106 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/bookmarks.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp Bookmarks" date="2019-03-23" 2 | 3 | 4 | # Bookmarks 5 | =========== 6 | 7 | HyperHelp allows you to create bookmarks for help topics that you often use, 8 | allowing you to jump back to them at any point. From within a |help view| you 9 | can create a bookmark by pressing or jump to an existing bookmark by 10 | pressing . 11 | 12 | The command palette command `HyperHelp: Open Bookmarked Help Topic` is also 13 | available from any view, and will navigate to a bookmarked help topic, creating 14 | the help view if it doesn't already exist. 15 | 16 | 17 | # Creating Bookmarks 18 | -------------------- 19 | 20 | When you invoke the command to create a bookmark, HyperHelp will prompt you to 21 | provide details on the bookmark to create; it's `type` and it's `name`. 22 | 23 | The `type` of the bookmark determines what happens when you navigate to that 24 | particular bookmark, while the `name` determines how it is displayed in the 25 | bookmark list. 26 | 27 | 28 | ## File Bookmark 29 | ---------------- 30 | 31 | A `file` bookmark bookmarks the file that you're currently viewing in the 32 | |help view|. When you navigate back to this bookmark, the cursor will be 33 | placed at the |anchor| in the |header| of the file after it's loaded. 34 | 35 | This is useful to bookmark a general help file, such as a reference 36 | document. 37 | 38 | 39 | ## View Bookmark 40 | ---------------- 41 | 42 | A `view`bookmark bookmarks the current state of the |help view|. When you 43 | navigate back to this bookmark later, not only will the file open but the 44 | cursor and viewport will be put back into the exact same state as they were 45 | when the bookmark was created. 46 | 47 | This is useful to take a snapshot of the help before leaving to do other 48 | things and still being able to find your way back to where you left off. 49 | 50 | 51 | ## Topic Bookmark 52 | ----------------- 53 | 54 | A `topic` bookmark is like a `file` bookmark, except that where the `file` 55 | bookmark creates a bookmark that opens a particular file, a `topic` 56 | bookmark bookmarks a specific topic instead. 57 | 58 | This type of bookmark is context sensitive; in order to be given this 59 | option for your bookmark, the cursor needs to be placed on top of a link to 60 | that topic first. 61 | 62 | HyperHelp supports three different kinds of bookmarks that allow you to create 63 | a bookmark -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/changelog.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp ChangeLog" date="2020-04-06" 2 | 3 | 4 | ## latest_update:Version 0.0.8 (2020-04-06) 5 | ------------------------------- 6 | 7 | * This introduces a new setting `focus_links_at_top`. This controls where the 8 | anchor of a link is focused in the window when you follow one. The default 9 | value is `true`, which forces the link anchor to the top of the window (as 10 | a traditional browser would). 11 | 12 | To get the legacy behaviour of centering the link in the window, set this 13 | to `false`. 14 | 15 | Note that this does not affect using the key to navigate between the 16 | anchors in a help file. 17 | 18 | 19 | ## _none:Version 0.0.7 (2019-10-31) 20 | ------------------------------- 21 | 22 | * On install or upgrade, the HyperHelp system package will now display 23 | either the `changelog.txt` file or the `help_on_help.txt` file, so 24 | that you either learn how to use the help system or see what is new. 25 | 26 | The new setting `show_changelog` controls whether this is active or 27 | not; it defaults to `True`. 28 | 29 | 30 | ## _none:Version 0.0.6 (2019-10-31) 31 | ------------------------------- 32 | 33 | * This changelog file now exists to indicate the version history of the 34 | package over time. The help index, command palette and the main menu can 35 | all be used to navigate to the file. 36 | 37 | * The |dependency settings| have been changed to use a prefix of `hyperhelp.` 38 | instead of `hyperhelp_`, as |PackageDev| syntax highlights that format 39 | directly. In addition, a hint file was added so that PackageDev can show 40 | you default values and auto-complete the settings directly. 41 | 42 | * The commands that create and navigate to bookmarks from the command palette 43 | have been modified to use the `show_overlay` command rather than invoking 44 | the command directly. 45 | 46 | 47 | ## _none:Version 0.0.5 (2019-03-31) 48 | ------------------------------- 49 | 50 | * Include a command to display the package version of the bootstrapped 51 | package and of the dependency in preparation for the initial public 52 | announcement on April 1. 53 | 54 | 55 | ## _none:Version 0.0.4 (2019-03-27) 56 | ----------------------------- 57 | 58 | * Bump the internal version number which was accidentally skipped from the 59 | 0.0.3 release, stopping existing installs from seeing the changes. 60 | 61 | 62 | ## _none:Version 0.0.3 (2019-03-25) 63 | ----------------------------- 64 | 65 | * Enhance key contexts used in key bindings 66 | 67 | * Ensure that when the history index panel is opened, the current help item 68 | is initially selected. 69 | 70 | * While post processing, removal of comments would also remove comments from 71 | in-line code blocks; this has been fixed. 72 | 73 | * Rewrite the internal help to be more up to date with how the package has 74 | been rewritten in the last year. 75 | 76 | 77 | ## _none:Version 0.0.2 (2019-03-07) 78 | ----------------------------- 79 | 80 | * Watch `ignored_packages` to determine when packages are being ignored or 81 | unignored and load or drop their indexes as needed to keep help in sync 82 | with packages. 83 | 84 | * Fix a bug in bootstrapping that would block it from happening if the 85 | package was unpacked. 86 | 87 | 88 | ## _none:Version 0.0.1 (2019-02-17) 89 | ----------------------------- 90 | 91 | * Initial release 92 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/commands.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp Commands" date="2019-03-23" 2 | 3 | 4 | # Command Overview 5 | ================== 6 | 7 | HyperHelp provides several commands, |key contexts| and an |api| that allow you 8 | to customize the help experience for yourself or for users of your package by 9 | creating your own custom key bindings, menu entries or plugins. 10 | 11 | The commands listed here expose the core of the HyperHelp commands for the most 12 | common tasks. For more complex operations, the |api| may be able to help. 13 | 14 | 15 | ## hyperhelp_topic 16 | ------------------ 17 | 18 | Arguments: `package` 19 | `topic` 20 | 21 | Navigate the current |help view| to the provided topic in the given package, 22 | creating a new help view if the current window does not already have one. 23 | 24 | When there is an existing help view, the `package` argument can be omitted and 25 | will default to the package currently being displayed. Similarly if the topic 26 | is missing, the default is `index.txt`. This allow this command to open any 27 | help package without having to know the name of a file that it contains. 28 | 29 | This command is always available, but will display an error in the status line 30 | if it cannot display the given help topic for any reason, such as if the topic 31 | does not appear in the index for the given package or the package cannot be 32 | found. 33 | 34 | 35 | ## hyperhelp_contents 36 | --------------------- 37 | 38 | Arguments: `package` 39 | `prompt` 40 | 41 | This command will display the |table of contents| for the help package given. 42 | If no package is provided, but there is currently a |help view| visible, the 43 | table of contents for the visible package is displayed. 44 | 45 | When `prompt` is `true` or no `package` was given and one cannot be inferred 46 | from an existing help view, you will be prompted to select the help package 47 | whose table of contents you wish to view. 48 | 49 | This command is unavailable if no `package` is provided, there is no current 50 | help view, and `prompt` is set to `False`. This allows key bindings and menu 51 | entries to not be available if there is no help view available to provide a 52 | package. 53 | 54 | In order to ensure that this command is always enabled, ensure that you pass a 55 | value of `true` to the `prompt` argument. 56 | 57 | 58 | ## hyperhelp_index 59 | ------------------ 60 | 61 | Arguments: `package` 62 | `prompt` 63 | 64 | This command will display the |topic| index for the help package given. If no 65 | package is provided, but there is currently a |help view| visible, the index 66 | for the visible package is displayed. 67 | 68 | When `prompt` is `true` or no `package` was given and one cannot be inferred 69 | from an existing help view, you will be prompted to select the help package 70 | whose index you wish to view. 71 | 72 | The index is a list of every known topic in every known help file within the 73 | given package, which allows you to quickly find and select a topic without 74 | knowing where it's located. 75 | 76 | This command is unavailable if no `package` is provided, there is no current 77 | help view, and `prompt` is set to `False`. This allows key bindings and menu 78 | entries to not be available if there is no help view available to provide a 79 | package. 80 | 81 | In order to ensure that this command is always enabled, ensure that you pass a 82 | value of `true` to the `prompt` argument. 83 | 84 | 85 | ## hyperhelp_navigate 86 | --------------------- 87 | 88 | Arguments: `nav` 89 | Possible values of this argument are: 90 | `find_anchor` 91 | `follow_link` 92 | `prev` 93 | 94 | This command is the core of navigating within help files in HyperHelp. The 95 | following types of navigation are available, based on the value of the `nav` 96 | command line argument: 97 | 98 | `find_anchor` will shift the cursor to the next or previous |anchor| within 99 | the current help view, wrapping around the ends of the file if needed. 100 | 101 | `follow_link` will navigate to the topic represented by the link that is 102 | currently under the first cursor in the |help view|, if there is one. If 103 | the cursor is not currently on a link, this does nothing. 104 | 105 | This command is only available when there is a help view visible in the current 106 | window and the value of the `nav` argument is one of the valid values. 107 | 108 | 109 | ## hyperhelp_history 110 | -------------------- 111 | 112 | Arguments: `action` 113 | Possible values of this argument are: 114 | `next` 115 | `prev` 116 | `jump` 117 | `clear` 118 | `index` 119 | This argument is only used when `action` is `jump`. 120 | 121 | This command allows for navigation within the history that each |help view| 122 | records as the user navigates through help topics. 123 | 124 | The action taken depends on the value provided in the `action` argument: 125 | 126 | `next` and `prev` will navigate to the next or previous item in the history 127 | for the current help view; this navigation will return the cursor location 128 | and viewport back to what it was at the time the history entry was created. 129 | 130 | `clear` will clear the entire history of the current help view. This puts 131 | the help view back into the state it was in when it was originally created. 132 | 133 | `jump` will jump the history to the `index` given (if possible). When the 134 | `index` value is `-1` (the default) or when the index is out of bounds for 135 | the number of history items that exist in the help view, the command will 136 | visualize the history for the user to allow them to select the appropriate 137 | history entry themselves. 138 | 139 | This command is only available when there is a help view in the current window 140 | and the value of the `action` argument is one of the valid values. In addition, 141 | the command is not available when the command makes no sense to execute, such 142 | as trying to go back when you're on the first history entry already or clearing 143 | the history when it's empty. 144 | 145 | 146 | ## hyperhelp_current_help 147 | ------------------------- 148 | 149 | Arguments: `help_fmt` 150 | `no_help_fmt` 151 | 152 | This command does nothing and is always disabled. If used as a command in a 153 | menu item, the caption will tell you the name of the package that help is 154 | currently being displayed for, if any. 155 | 156 | The provided arguments provide the text to use in either case, allowing you to 157 | customize the text used if desired. 158 | 159 | 160 | ## hyperhelp_create_bookmark 161 | ---------------------------- 162 | 163 | Arguments: `name` 164 | `package` 165 | `topic` 166 | `caret` 167 | `viewport` 168 | 169 | `NOTE:` This command does not validate that the arguments that you are 170 | providing make sense. The |hyperhelp_prompt_create_bookmark| 171 | command will create a bookmark after prompting the user. 172 | 173 | This command will create a bookmark using the provided properties; the bookmark 174 | will use the given `name` and will be to the `topic` given in the `package` 175 | provided. 176 | 177 | In addition, `caret` is an array of two numbers that represent a selection 178 | region in the file while `viewpoert` is an array of two numbers that represents 179 | a viewport position. 180 | 181 | These arguments are optional, and can be used to specify the initial selection 182 | in the help file and what portion of it should be focused. When they're not 183 | provided, the help topic is navigated to as per usual. 184 | 185 | Since this command unconditionally creates a bookmark, it is always available. 186 | 187 | 188 | ## hyperhelp_prompt_create_bookmark 189 | ------------------------------------ 190 | 191 | Arguments: None 192 | 193 | This command will prompt the user to create a bookmark by asking for the 194 | details of the new bookmark to be created. The prompts are based on the state 195 | of the current help view, and allow the user to customize them before commiting 196 | to the creation. 197 | 198 | This command is only available in windows that have an existing |help view|. If 199 | you need to create a bookmark when there is no help view open, you can view the 200 | appropriate help topic first or use |hyperhelp_create_bookmark| to directly 201 | create the appropriate bookmark. 202 | 203 | 204 | ## hyperhelp_open_bookmark 205 | -------------------------- 206 | 207 | Arguments: `bookmark_idx` 208 | 209 | This command will navigate the user directly to the bookmark at the provided 210 | bookmark index, if possible. Nothing will occur if the bookmark index is out of 211 | range, including when there are no bookmarks to navigate to. 212 | 213 | If no bookmark index is provided, the user is prompted to select the 214 | appropriate bookmark before the navigation happens. 215 | 216 | This command is always available; if there is no current |help view|, one will 217 | be created when the user selects the bookmark to open. 218 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/example.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="Help Examples" date="2019-03-25" 2 | 3 | 4 | # Example hyperhelp.json 5 | ------------------------ 6 | 7 | This is an example help index for a package containing a single help file. The 8 | metadata at the top instructs HyperHelp that this is the index for a package 9 | named `Sample`, and that inside of that package, the help files (i.e. 10 | `index.txt`) are inside of a folder named `help/`. 11 | 12 | The topics in a single file are declared, along with captions and aliases. In 13 | addition some externals are also defined to open the `exec.py` file in the 14 | default package and the home page for `hyperhelpcore` itself. 15 | 16 | The `help_contents` provides a simple hierarchical table of contents that lets 17 | you jump to the top level of the file and also sections. This also demonstrates 18 | overriding the captions for some items. 19 | 20 | 21 | ```json 22 | { 23 | "package": "Sample", 24 | "description": "Help for Sample Package", 25 | "doc_root": "help/", 26 | 27 | "help_files": { 28 | "index.txt": [ 29 | "Index file for Sample package", 30 | 31 | { 32 | "topic": "index.txt", 33 | "caption": "Index file", 34 | "aliases": ["index file"] 35 | }, 36 | { 37 | "topic": "introduction", 38 | "caption": "Introduction Section" 39 | }, 40 | { 41 | "topic": "anchor", 42 | "caption": "Sample Anchor" 43 | }, 44 | { 45 | "topic": "section two", 46 | "caption": "Second Section" 47 | }, 48 | { 49 | "topic": "hidden anchor", 50 | "caption": "An anchor that is not visible in the document" 51 | }, 52 | { 53 | "topic": "section three", 54 | "caption": "The third and last section" 55 | }, 56 | ] 57 | }, 58 | 59 | "externals": { 60 | "Packages/Default/exec.py": [ 61 | "The exec plugin", 62 | 63 | { 64 | "topic": "exec.py", 65 | }, 66 | ], 67 | 68 | "https://github.com/STealthy-and-haSTy/hyperhelpcore": [ 69 | "The HyperHelp core dependency", 70 | 71 | { 72 | "topic": "hyperhelpcore", 73 | "caption": "Core Dependency" 74 | }, 75 | ] 76 | 77 | }, 78 | 79 | "help_contents": [ 80 | "index.txt", 81 | { 82 | "topic": "index.txt", 83 | "caption": "The Sections", 84 | "children": [ 85 | { 86 | "topic": "introduction", 87 | "caption": "Section One" 88 | }, 89 | "section two", 90 | "section three" 91 | ] 92 | }, 93 | ] 94 | } 95 | ``` 96 | 97 | 98 | # Example index.txt 99 | ------------------- 100 | 101 | This is the help file that goes with the sample above. It should be placed in 102 | the same package as the above index, in a folder named `help/` (or you can 103 | change the |doc_root| in the sample to suit). 104 | 105 | This shows some of the simpler |markup| elements, such as |anchors|, |links| 106 | and |:headings:section headings|. 107 | 108 | 109 | ```help 110 | %hyperhelp title="Index file for Sample package" date="2019-03-22" 111 | 112 | This is the root help file for the 'Sample' package. 113 | 114 | If you use `Goto > Goto Symbol` in the main menu, the symbol list will show you 115 | the section heading, indented based on the level of the section header itself. 116 | You can also press and to jump back and forth between the 117 | sections. 118 | 119 | Follow links by double clicking on them or pressing while the cursor is 120 | on them. 121 | 122 | 123 | # Introduction 124 | -------------- 125 | 126 | This part of the file would be a simple introduction. It also has an inline 127 | *anchor* for a link to jump to. 128 | 129 | 130 | ## Section Two 131 | -------------- 132 | 133 | This is a second section in the sample file. Along with a link to the |anchor| 134 | in the previous section, this also contains a *|hidden anchor|*, which 135 | functions the same as a regular one but is not visible in the document. 136 | 137 | 138 | ### Section Three 139 | ----------------- 140 | 141 | This is the third section. Apart from being here to show that three levels of 142 | section header are possible, it also shows that you can link to a |hidden 143 | anchor| the same as a regular one. 144 | 145 | In addition, you can also open the |exec.py| plugin by following this link or 146 | view the code for |hyperhelpcore|, the dependency that powers HyperHelp. 147 | ``` 148 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/help_index.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="Help Index Files" date="2019-03-23" 2 | 3 | 4 | # hyperhelp.json:The hyperhelp.json file 5 | ========================= 6 | 7 | 8 | Every package which contains help must include a `hyperhelp.json` file which 9 | provides all of the meta information to allow HyperHelp to know what help is 10 | available in that particular package. 11 | 12 | The name of the file is important; HyperHelp only looks specifically for files 13 | with the name `hyperhelp.json`. As the name suggests, the file is a |JSON| 14 | formatted file, with a schema that outlines all of the information that 15 | HyperHelp needs in order to present the help. 16 | 17 | The sections below specify the structure of the index as a series of keys that 18 | can be used and what they are used for. See the |example hyperhelp.json| file 19 | for a complete example of a minimal help index; you can use this as a starting 20 | point for your own help index if you're not using |HyperHelpAuthor| to author 21 | your help files. 22 | 23 | 24 | ## Package Description 25 | ---------------------- 26 | 27 | These keys are used in the `hyperhelp.json` file to tell HyperHelp how to 28 | present the help in this index file to the user and what files it contains. 29 | With the exception of the `package` key, all of these keys are optional; 30 | you only need to specify them when you want to override the default value. 31 | 32 | *package* `[REQUIRED]` 33 | 34 | The name of the package that this help index is for. This does not need 35 | to be the same as the physical package that the index is stored inside; 36 | for example if you are creating a package that contains help for some 37 | other package. 38 | 39 | If multiple index files present themselves as being the help for the 40 | same package, one index will be selected as the one to use. The index 41 | stored in the physical package of the same name is chosen as the 42 | canonical index and used; otherwise the last loaded index is used 43 | instead. 44 | 45 | 46 | *description* 47 | 48 | The human readable description of the help in this package. This is 49 | presented to the user in places where they are allowed to select a 50 | help package, such as when using `HyperHelp: Browse Available Help`. 51 | 52 | If this key is not present, a default value is used: 53 | 54 | ```json 55 | "description": "Help for PackageName" 56 | ``` 57 | 58 | 59 | *doc_root* 60 | 61 | A relative path inside of the package containing the index file that 62 | indicates where the help files for this package are located. When this 63 | is not specified, the default is to assume that the help files are 64 | stored alongside the index. 65 | 66 | 67 | *default_caption* 68 | 69 | The default caption to apply to a |:help topics:help topic| that doesn't have one 70 | explicitly defined. This is a string which can contain the placeholder 71 | values `{topic}`, `{source}` and `{package}` to indicate the help 72 | topic, source help file and containing package, respectively. 73 | 74 | When this is not provided, the following default is used: 75 | 76 | ```json 77 | "default_caption": "Topic {topic} in help source {source}" 78 | ``` 79 | 80 | 81 | ## help_files:Package Help Files 82 | --------------------- 83 | 84 | The top level key `help_files` is used to specify the list of help files 85 | that make up the help in this help index. The value is a dictionary in 86 | which the keys are the names of help files and the values are lists of help 87 | topics that exist in that help file. 88 | 89 | The contents of this key and the |externals| key are used to collate the 90 | complete list of all help topics that exist within the help package, and by 91 | extension in what file those help topics can be found. 92 | 93 | Help files that don't appear here as well as help topics that aren't listed 94 | in their related file cannot be viewed or loaded. |HyperHelpAuthor| 95 | contains linting tools to ensure that all help topics and files in a 96 | package are addressable. 97 | 98 | ```json 99 | "help_files": { 100 | "index.txt": [ /* help topics */ ], 101 | "other.txt": [ /* help topics */ ], 102 | } 103 | ``` 104 | 105 | 106 | ### Help Topics 107 | 108 | Each help file listed in the |help_files| key is a JSON list that 109 | contains all of the help topics contained within that particular help 110 | file. 111 | 112 | In this list, the first item must be a string which represents the 113 | title of the help file itself; this is used to display the name of the 114 | help file itself in various places. 115 | 116 | Every help file in a help package is an implicit topic which uses the 117 | title of the help file as the caption, and every rendered help file 118 | includes an |anchor| in the header line that represents the file name. 119 | Thus, all help files are readily addressable by name. 120 | 121 | The remainder of the items in the list are a list of dictionaries which 122 | represent each topic which is contained in that file. 123 | 124 | *topic* `[REQUIRED]` 125 | 126 | A string which represents a help topic that can be found in this 127 | help file. Help topics must be unique within a single package. In 128 | addition, the help file should have an |anchor| that matches this 129 | topic, or the user will be unable to navigate there. 130 | 131 | `NOTE:` Topics that begin with leading underscores are reserved for 132 | use by HyperHelp itself (see for example the `_none` topic 133 | as outlined in the |markup| section on |:anchor:anchors|). 134 | 135 | In addition, due to the syntax of |anchors| and |links|, a 136 | `:` character is not allowed in a topic (although it can 137 | appear in the anchor or link text). 138 | 139 | *caption* 140 | 141 | A textual caption for this particular topic. This is used in places 142 | where the user is prompted to select a help topic, such as in the 143 | |table of contents|. 144 | 145 | When no caption is provided for a help topic, the |default_caption| 146 | is applied instead. 147 | 148 | 149 | *aliases* 150 | 151 | A list of other topic aliases that represent this particular topic. 152 | This allows you to associate multiple potential topics to a single 153 | topic in cases where that makes logical sense. 154 | 155 | Aliases share the same namespace as topics, and as such must also 156 | be unique amongst all other topics and aliases within the same 157 | help package. 158 | 159 | 160 | ```json 161 | "help_files": { 162 | // This help file contains two topics; one implicitly defined by 163 | // its file name and one explicit topic. In addition, the explicit 164 | // topic is also known by an alias. 165 | "index.txt": [ 166 | "Title of the Index File", 167 | 168 | { 169 | "topic": "sample topic", 170 | "caption": "The sample topic in index.txt", 171 | "aliases": ["sample"] 172 | } 173 | ] 174 | } 175 | ``` 176 | 177 | 178 | ### External Resources 179 | ---------------------- 180 | 181 | In addition to standard help files, HyperHelp can also automatically 182 | open package files and web URLs through the use of `externals`. This 183 | allows you the freedom to do things such as open other resource files 184 | (e.g. a README file) as well as link to external web documentation as 185 | needed. 186 | 187 | *externals* 188 | 189 | This key operates similar to the |help_files| key, except that 190 | where that key specifies the names of help files, this key 191 | specifies the names of external resources. 192 | 193 | As in that key, every external is implicitly defined as a topic 194 | with it's title as a caption. In addition, any topics inside of 195 | an external definition are implicit aliases and will share the 196 | same caption unless one is specified. 197 | 198 | ```json 199 | "externals": { 200 | // An external to open my home page. This defines a topic that is 201 | // the explicit URL with a caption of "OdatNurd's Home Page". It 202 | // also defines a topic named "homepage" with a caption of "My 203 | // Homepage". Either topic will result in the web page being 204 | // opened. 205 | "https://odatnurd.net/": [ 206 | "OdatNurd's Home Page", 207 | 208 | { 209 | "topic": "homepage", 210 | "caption": "My Homepage" 211 | } 212 | ], 213 | 214 | // An external to open a package file. As above, there are two 215 | // topics defined here; one that is the package file name and one 216 | // that is just "exec.py". This time both have the same caption. 217 | // Both will open the package file. 218 | "Packages/Default/exec.py": [ 219 | "The default exec command", 220 | 221 | { 222 | "topic": "exec.py" 223 | } 224 | ] 225 | } 226 | ``` 227 | 228 | 229 | ### Table of Contents 230 | --------------------- 231 | 232 | Every help index can define a custom table of contents via the 233 | `help_contents` key if desired, to allow the user to see and browse the 234 | help in a hierarchy defined by the help author. If this key is not 235 | present in the help index, a table of contents is generated 236 | automatically by gathering every help topic contained in the packge. 237 | 238 | *help_contents* 239 | 240 | This key specifies a list of help topics which should be presented 241 | to the user when they open the table of contents (by default this 242 | is done via the key). The table of contents is presented as a 243 | structured list of help topics, and displays the topic captions for 244 | clarity. 245 | 246 | For simplicity, items in the list can be strings that represent 247 | help topics. This will perform a lookup of the topic and use that 248 | to infer the caption to use. 249 | 250 | For more control items in the list can also be |:help topics:topic dictionaries| 251 | as well. In this case the topics must already exist, but the 252 | caption used can be altered. 253 | 254 | The *children** key can be used in topic dictionaries contained in 255 | the `help_contents` in order to specify that when selected this 256 | topic should present a list of other related help topics in a 257 | hierarchy. This allows for more complex contents without making the 258 | list overwhelming. 259 | 260 | ```json 261 | // This table of contents specifies four top level items. The first 262 | // two topics use their default captions and the third has a custom 263 | // caption. The "options.txt" topic presents a list of three child 264 | // topics, with the last one having a custom caption. 265 | "help_contents": [ 266 | "index.txt", 267 | "syntax.txt", 268 | { 269 | "topic": "other.txt", 270 | "caption": "Replaced Caption" 271 | }, 272 | { 273 | "topic": "options.txt", 274 | "children": [ 275 | "option1", 276 | "option2", 277 | { 278 | "topic": "option3", 279 | "caption": "Customized Option 3 Caption" 280 | } 281 | ] 282 | } 283 | 284 | ] 285 | ``` 286 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/help_on_help.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="How to use HyperHelp" date="2019-03-25" 2 | 3 | 4 | # Introduction 5 | ============== 6 | 7 | HyperHelp is a Sublime Text package that provides a simple text based, context 8 | sensitive help system for Sublime Text 3. Using HyperHelp, package authors can 9 | easily provide interactive help for their packages in a consistent way. 10 | 11 | Using HyperHelp, any package in Sublime Text can contain help, which includes 12 | not only third party packages but also your own `User` package. This allows you 13 | to create your own custom set of user specific documentation for reference 14 | materials you often refer to, all without having to leave Sublime. 15 | 16 | 17 | # Navigating Help 18 | ================= 19 | 20 | This tab contains a HyperHelp |help view| for displaying help text. Along with 21 | regular text, help files can also contain some simple |markup|. The most 22 | important things to keep in mind are: 23 | 24 | * Text within `|` characters are |links|, which take you to other 25 | navigation locations in a help file. 26 | * Text within `*` characters are |anchors|, which provide the destination 27 | that a link jumps to. 28 | * Lines that begin with `#` are |headings|, which are special anchors that 29 | allow you to quickly jump to a section in the current file using the 30 | Sublime Text `symbol list` (see `Goto > Goto Symbol` in the main menu). 31 | 32 | The common navigation keys you're used to using in Sublime allow you to move 33 | around within help files. Additionally, the following additional key bindings 34 | are also available: 35 | 36 | 37 | Open the |table of contents|. This gives you a hierarchical view of the 38 | help layout for this package. 39 | 40 | 41 | Open the topic index. This allows you to jump immediately to any help 42 | topic in the current package. 43 | 44 | / 45 | Move the cursor to the next or previous |anchor| or |heading| within 46 | the current help file. 47 | 48 | / 49 | Follow a |link|; the help view will switch to the appropriate location 50 | in the target help file. Some links can also open web pages or files in 51 | packages. Hover your mouse over a link to see where it leads. 52 | 53 | / 54 | As in your web browser, HyperHelp keeps a |history| of what help topics 55 | you have been viewing. These keys allow you to navigate forward and 56 | backward through your history. 57 | 58 | 59 | Open a quick panel with your topic history, allowing you to jump 60 | directly to any help topic you have previously viewed. 61 | 62 | 63 | Create a |bookmark| so you can find this topic again easier in the 64 | future. You can use the command palette to jump to a bookmark. 65 | 66 | 67 | Opens the bookmark selector to allow you to quickly jump to an existing 68 | bookmark. 69 | 70 | 71 | # Help View 72 | =========== 73 | 74 | Each Sublime window has it's own `help view` with a |history| independent of 75 | other help views in other windows. This allows you to keep the help most 76 | relevant to the work at hand available. 77 | 78 | A single help view always displays help provided by one package at a time, 79 | although you can freely switch the help package at any time in order to see 80 | more relevant help. 81 | 82 | 83 | # History 84 | ========= 85 | 86 | Each |help view| records a history of the topics that it has displayed since it 87 | was created. This works similarly to how history works in your web browser: 88 | 89 | * Opening a new help file adds that file to the end of the history. 90 | 91 | * When moving backwards and forwards through the history, the file and 92 | cursor position is saved before a topic is left and restored to what it 93 | was when you return. 94 | 95 | It is important to note that if you move backwards through history to a 96 | previous topic and then navigate to a new help file, the previous history after 97 | the current topic is replaced with the new topic you visited. 98 | 99 | See the section on |navigating help| for information on how to move through 100 | history in the help view. 101 | 102 | 103 | # _none:Bookmarks 104 | =========== 105 | 106 | HyperHelp allows you to create bookmarks to your most frequently used help 107 | topics, allowing you to quickly find what you're looking for. While in the help 108 | view, the key will create a bookmark at your current location, while the 109 | key will allow you to jump directly to a bookmark. 110 | 111 | More information on the various types of bookmarks is outlined in 112 | |bookmarks.txt|. 113 | 114 | 115 | # Opening Help 116 | ============== 117 | 118 | Opening the initial help view in a window can be accomplished by: 119 | 120 | 121 | * Selecting `HyperHelp: Browse Available Help` in the command palette or 122 | `Help > HyperHelp > Browse Available Help...` from the menu will show you 123 | a list of all packages that currently provide help. 124 | 125 | * Custom key bindings, command palette entries or menu items that use the 126 | appropriate |commands| to open help for a package. These can be created by 127 | you or by a package author. 128 | 129 | * Packages can open context sensitive help to provide more information on 130 | their operation at any point. How this works is up to the package author 131 | and the package in question. 132 | 133 | 134 | # _none:Next Steps 135 | ============ 136 | 137 | Now that you know a little bit more about HyperHelp, feel free to explore the 138 | help system a little bit and see what you can do. 139 | 140 | To begin, use the key to open the |table of contents| for this help and 141 | explore around to get more information on how things work. 142 | 143 | If you're a package author you may want to check out |integration.txt| to see 144 | how you can integrate HyperHelp into your own package (pro tip: it's super 145 | easy). 146 | 147 | You may also want to check out |authoring.txt| to see more information on how 148 | to create help files and the authoring tools that are available. 149 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/hyperhelp.json.sublime-ignored: -------------------------------------------------------------------------------- 1 | { 2 | "package": "HyperHelp", 3 | "description": "HyperHelp System Documentation", 4 | "doc_root": "help/", 5 | "default_caption": "Topic {topic} in help source {source}", 6 | 7 | "help_files": { 8 | "index.txt": [ 9 | "HyperHelp: About HyperHelp", 10 | 11 | { 12 | "topic": "what is hyperhelp", 13 | "caption": "HyperHelp: What is it?" 14 | }, 15 | { 16 | "topic": "how it works", 17 | "caption": "HyperHelp: How it works" 18 | }, 19 | { 20 | "topic": "bootstrapping", 21 | "caption": "HyperHelp: Bootstrapping" 22 | }, 23 | { 24 | "topic": "help files", 25 | "caption": "HyperHelp: Help Files" 26 | }, 27 | { 28 | "topic": "example", 29 | "caption": "Example Anchor" 30 | } 31 | ], 32 | 33 | "help_on_help.txt": [ 34 | "How to use HyperHelp", 35 | 36 | { 37 | "topic": "introduction", 38 | "caption": "Introduction to HyperHelp" 39 | }, 40 | { 41 | "topic": "navigating help", 42 | "caption": "Navigating Help" 43 | }, 44 | { 45 | "topic": "help view", 46 | "caption": "The Help view" 47 | }, 48 | { 49 | "topic": "opening help", 50 | "caption": "Opening HyperHelp" 51 | }, 52 | { 53 | "topic": "history", 54 | "caption": "Help History" 55 | } 56 | ], 57 | 58 | "syntax.txt": [ 59 | "HyperHelp: Help Syntax", 60 | 61 | { 62 | "topic": "file header", 63 | "caption": "Help Header Definition", 64 | "aliases": ["header"] 65 | }, 66 | { 67 | "topic": "markup", 68 | "caption": "Markup - Overview" 69 | }, 70 | { 71 | "topic": "key bindings", 72 | "caption": "Markup - Key Bindings" 73 | }, 74 | { 75 | "topic": "code blocks", 76 | "caption": "Markup - Code Blocks" 77 | }, 78 | { 79 | "topic": "anchors", 80 | "caption": "Markup - Anchors", 81 | "aliases": ["anchor"] 82 | }, 83 | { 84 | "topic": "headings", 85 | "caption": "Markup - Headings", 86 | "aliases": ["heading"] 87 | }, 88 | { 89 | "topic": "links", 90 | "caption": "Markup - Links", 91 | "aliases": ["link"] 92 | }, 93 | { 94 | "topic": "separators", 95 | "caption": "Markup - Visual Separators" 96 | }, 97 | { 98 | "topic": "comments", 99 | "caption": "Markup - Comments" 100 | } 101 | ], 102 | 103 | "style.txt": [ 104 | "HyperHelp: Style Conventions", 105 | ], 106 | 107 | "authoring.txt": [ 108 | "HyperHelp: Authoring Help", 109 | 110 | { 111 | "topic": "authoring overview", 112 | "caption": "Authoring Overview" 113 | }, 114 | { 115 | "topic": "help index loading", 116 | "caption": "Help Index Loading" 117 | }, 118 | { 119 | "topic": "navigating topics", 120 | "caption": "Navigating Topics" 121 | } 122 | ], 123 | 124 | "help_index.txt": [ 125 | "Help Index Files", 126 | 127 | { 128 | "topic": "help_index.txt", 129 | "caption": "hyperhelp.json", 130 | "aliases": ["hyperhelp.json"] 131 | }, 132 | { 133 | "topic": "package description", 134 | "caption": "Help Index: Package Description" 135 | }, 136 | { 137 | "topic": "package", 138 | "caption": "hyperhelp.json: package key" 139 | }, 140 | { 141 | "topic": "description", 142 | "caption": "hyperhelp.json: description key" 143 | }, 144 | { 145 | "topic": "doc_root", 146 | "caption": "hyperhelp.json: doc_root key" 147 | }, 148 | { 149 | "topic": "default_caption", 150 | "caption": "hyperhelp.json: default_caption key" 151 | }, 152 | { 153 | "topic": "help_files", 154 | "caption": "hyperhelp.json: help_files key" 155 | }, 156 | { 157 | "topic": "help_contents", 158 | "caption": "hyperhelp.json: help_contents key" 159 | }, 160 | { 161 | "topic": "children", 162 | "caption": "help_contents: children key" 163 | }, 164 | { 165 | "topic": "external resources", 166 | "caption": "hyperhelp.json: External Resources" 167 | }, 168 | { 169 | "topic": "externals", 170 | "caption": "hyperhelp.json: externals key" 171 | }, 172 | { 173 | "topic": "help topics", 174 | "caption": "hyperhelp.json: Help Topics" 175 | }, 176 | { 177 | "topic": "topic", 178 | "caption": "Help Topics: topic key" 179 | }, 180 | { 181 | "topic": "caption", 182 | "caption": "Help Topics: caption key" 183 | }, 184 | { 185 | "topic": "aliases", 186 | "caption": "Help Topics: aliases key" 187 | }, 188 | { 189 | "topic": "table of contents", 190 | "caption": "Table of Contents" 191 | } 192 | ], 193 | 194 | "integration.txt": [ 195 | "Integrating HyperHelp", 196 | 197 | { 198 | "topic": "integration.txt", 199 | "caption": "Integrating HyperHelp into your Package" 200 | } 201 | ], 202 | 203 | "settings.txt": [ 204 | "HyperHelp Settings", 205 | 206 | { 207 | "topic": "package settings", 208 | "caption": "HyperHelp Package Settings" 209 | }, 210 | { 211 | "topic": "dependency settings", 212 | "caption": "HyperHelp Dependency Settings" 213 | }, 214 | { 215 | "topic": "hyperhelp_date_format", 216 | "caption": "Setting: hyperhelp_date_format" 217 | }, 218 | { 219 | "topic": "show_changelog", 220 | "caption": "Setting: show_changelog" 221 | }, 222 | { 223 | "topic": "focus_links_at_top", 224 | "caption": "Setting: focus_links_at_top" 225 | }, 226 | { 227 | "topic": "hyperhelp.ignore_disabled", 228 | "caption": "Setting: hyperhelp.ignore_disabled" 229 | } 230 | ], 231 | 232 | "commands.txt": [ 233 | "HyperHelp Commands", 234 | 235 | { 236 | "topic": "command overview", 237 | "caption": "Command Overview", 238 | "aliases": ["commands"] 239 | }, 240 | { 241 | "topic": "hyperhelp_topic", 242 | "caption": "Command: hyperhelp_topic" 243 | }, 244 | { 245 | "topic": "hyperhelp_contents", 246 | "caption": "Command: hyperhelp_contents" 247 | }, 248 | { 249 | "topic": "hyperhelp_index", 250 | "caption": "Command: hyperhelp_index" 251 | }, 252 | { 253 | "topic": "hyperhelp_navigate", 254 | "caption": "Command: hyperhelp_navigate" 255 | }, 256 | { 257 | "topic": "hyperhelp_current_help", 258 | "caption": "Command: hyperhelp_current_help" 259 | }, 260 | { 261 | "topic": "hyperhelp_history", 262 | "caption": "Command: hyperhelp_history" 263 | }, 264 | { 265 | "topic": "hyperhelp_create_bookmark", 266 | "caption": "Command: hyperhelp_create_bookmark" 267 | }, 268 | { 269 | "topic": "hyperhelp_prompt_create_bookmark", 270 | "caption": "Command: hyperhelp_prompt_create_bookmark" 271 | }, 272 | { 273 | "topic": "hyperhelp_open_bookmark", 274 | "caption": "Command: hyperhelp_open_bookmark" 275 | } 276 | ], 277 | 278 | "key_contexts.txt": [ 279 | "HyperHelp Key Contexts", 280 | 281 | { 282 | "topic": "key_contexts.txt", 283 | "caption": "HyperHelp Key Contexts", 284 | "aliases": ["key contexts"] 285 | }, 286 | { 287 | "topic": "context overview", 288 | "caption": "Context: context overview" 289 | }, 290 | { 291 | "topic": "hyperhelp.is_help_view", 292 | "caption": "Context: hyperhelp.is_help_view" 293 | }, 294 | { 295 | "topic": "hyperhelp.is_help_visible", 296 | "caption": "Context: hyperhelp.is_help_visible" 297 | }, 298 | { 299 | "topic": "hyperhelp.is_help", 300 | "caption": "Context: hyperhelp.is_help" 301 | }, 302 | { 303 | "topic": "hyperhelp.is_help_source", 304 | "caption": "Context: hyperhelp.is_help_source" 305 | }, 306 | { 307 | "topic": "hyperhelp.is_help_index", 308 | "caption": "Context: hyperhelp.is_help_index" 309 | }, 310 | { 311 | "topic": "hyperhelp.is_help_package", 312 | "caption": "Context: hyperhelp.is_help_package" 313 | }, 314 | { 315 | "topic": "hyperhelp.is_help_file", 316 | "caption": "Context: hyperhelp.is_help_file" 317 | } 318 | ], 319 | 320 | "api.txt": [ 321 | "HyperHelp API", 322 | 323 | { 324 | "topic": "api.txt", 325 | "caption": "HyperHelp API", 326 | "aliases": ["api"] 327 | }, 328 | { 329 | "topic": "api overview", 330 | "caption": "API Overview" 331 | } 332 | ], 333 | 334 | "bookmarks.txt": [ 335 | "HyperHelp Bookmarks", 336 | 337 | { 338 | "topic": "bookmarks", 339 | "caption": "About Bookmarks", 340 | "aliases": ["bookmark"] 341 | }, 342 | { 343 | "topic": "creating bookmarks", 344 | "caption": "Bookmarks: Creation" 345 | }, 346 | { 347 | "topic": "file bookmark", 348 | "caption": "Bookmarks: File Bookmark" 349 | }, 350 | { 351 | "topic": "view bookmark", 352 | "caption": "Bookmarks: View Bookmark" 353 | }, 354 | { 355 | "topic": "topic bookmark", 356 | "caption": "Bookmarks: Topic Bookmark" 357 | } 358 | ], 359 | 360 | "example.txt": [ 361 | "Help Examples", 362 | 363 | { 364 | "topic": "example hyperhelp.json", 365 | "caption": "Example hyperhelp.json Index File" 366 | }, 367 | { 368 | "topic": "example index.txt", 369 | "caption": "Example index.txt Help File" 370 | } 371 | ], 372 | 373 | "changelog.txt": [ 374 | "HyperHelp ChangeLog", 375 | 376 | { 377 | "topic": "latest_update", 378 | "caption": "ChangeLog: Recent Changes" 379 | }, 380 | ], 381 | }, 382 | 383 | "externals": { 384 | "https://github.com/STealthy-and-haSTy/HyperHelpAuthor": [ 385 | "HyperHelpAuthor: Help Authoring Package", 386 | 387 | { "topic": "HyperHelpAuthor"} 388 | ], 389 | 390 | "https://github.com/STealthy-and-haSTy/SnAPI": [ 391 | "SnAPI: Sublime Text Documentation", 392 | 393 | { "topic": "SnAPI" } 394 | ], 395 | 396 | "https://github.com/STealthy-and-haSTy/hyperhelpcore": [ 397 | "hyperhelpcore: The HyperHelp core Dependency", 398 | 399 | { "topic": "hyperhelpcore" } 400 | ], 401 | 402 | 403 | "https://packagecontrol.io/docs/dependencies": [ 404 | "Package Control Dependency Documentation", 405 | 406 | { "topic": "Package Control Dependency Documentation" } 407 | ], 408 | 409 | "https://odatnurd.net/overrideaudit/": [ 410 | "OverrideAudit Home Page", 411 | 412 | { "topic": "OverrideAudit" } 413 | ], 414 | 415 | "https://packagecontrol.io/packages/PackageDev": [ 416 | "PackageDev: Sublime Text utility package", 417 | 418 | { "topic": "PackageDev"} 419 | ], 420 | 421 | "https://json.org/": [ 422 | "Introducing JSON", 423 | 424 | { "topic": "json" } 425 | ], 426 | 427 | "https://docs.python.org/3.3/": [ 428 | "Python 3.3.7 documentation", 429 | 430 | { "topic": "python 3.3 docs" } 431 | ], 432 | 433 | "https://docs.python.org/3.3/library/datetime.html#strftime-and-strptime-behavior": [ 434 | "strftime() and strptime() Behavior", 435 | 436 | { "topic": "strftime() and strptime() Behavior" } 437 | ], 438 | 439 | "Packages/Default/exec.py": [ 440 | "The default exec command", 441 | 442 | { "topic": "exec.py" } 443 | ], 444 | 445 | "Packages/User/Preferences.sublime-settings": [ 446 | "User specific Sublime Settings", 447 | 448 | { 449 | "topic": "Preferences.sublime-settings", 450 | "aliases": ["your user preferences"] 451 | } 452 | ] 453 | }, 454 | 455 | "help_contents": [ 456 | { 457 | "caption": "Change History", 458 | "topic": "changelog.txt" 459 | }, 460 | "help_on_help.txt", 461 | "what is hyperhelp", 462 | "settings.txt", 463 | { 464 | "topic": "syntax.txt", 465 | "children": [ 466 | "syntax.txt", 467 | "markup", 468 | "anchors", 469 | "headings", 470 | "links", 471 | "code blocks", 472 | "key bindings", 473 | "comments", 474 | "separators" 475 | ] 476 | }, 477 | "commands.txt", 478 | "style.txt", 479 | "authoring.txt", 480 | "integration.txt", 481 | ] 482 | } -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/index.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp: About HyperHelp" date="2019-03-25" 2 | 3 | 4 | # What is HyperHelp 5 | =================== 6 | 7 | HyperHelp is a hypertext help system for Sublime Text 3 in a vein similar to 8 | the help system in other text editors such as `vim` and `emacs`. The goal is to 9 | bridge the gap between providing just a simple text file (e.g. a `README` file) 10 | and a full HTML based documentation site. 11 | 12 | HyperHelp employs simple plain text files (with some |markup|) but also 13 | provides the power of web based documentation by allowing you to easily find 14 | and navigate from help file to help file and topic to topic, including the 15 | ability to navigate through the history of your help viewing and bookmarking 16 | often used topics. 17 | 18 | If you're new to HyperHelp, more immediate help on how to use it is available 19 | in |heLp_on_help.txt|. To view it, follow the link by either double clicking it 20 | or putting the text cursor on the underlined text and pressing enter. 21 | 22 | 23 | # How it works 24 | ============== 25 | 26 | HyperHelp is special in that it consists of two parts; a `dependency` library 27 | that Sublime Text packages can depend on and which provides the core API of the 28 | help system itself, and a `package` that provides the commands and extensions 29 | that use the API to allow you to navigate help. 30 | 31 | Due to this hybrid nature, you cannot directly install HyperHelp. Instead, it 32 | will automatically be installed when you use a package that wants to provide 33 | help using HyperHelp. 34 | 35 | When HyperHelp is first installed, it |:bootstrapping:bootstraps| itself in order to finalize 36 | the setup process. This bootstrap process also happens whenever HyperHelp is 37 | upgraded, in order to finalize the upgrade. 38 | 39 | These operations are transparent to you; you'll see a popup whenever they occur 40 | to let you know what's going on, but otherwise you can just get on with 41 | business as usual. 42 | 43 | 44 | # Help Files 45 | ============ 46 | 47 | Your interaction with HyperHelp takes place in the context of Help Files. These 48 | files are plain text files with minimal |markup| and are grouped together 49 | according to the `package` they provide help for. 50 | 51 | The available help markup is somewhat similar to `Markdown`, but is designed to 52 | be more easily human readable since there is no extra display steps other than 53 | syntax highlighting. 54 | 55 | `NOTE:` Although Sublime Text does allow for display of HTML in documents 56 | by using |SublimeAPI:phantom:phantoms|, HyperHelp does not use them for help content 57 | because you cannot copy the content of a phantom for use elsewhere. 58 | 59 | The two main aspects of help files are *example:anchors* and |:example:links|. An `anchor` is a 60 | navigation point in a document that is considered to be a point of interest in 61 | that document (a section title, information on a topic, and so on), while a 62 | `link` allows you to jump directly to any anchor. The first sentence of this 63 | paragraph contains an |anchor| followed by a |link| that links to it. 64 | 65 | In order to be as easy to use as possible, HyperHelp is almost entirely 66 | transparent to both package authors that want to add help to their packages as 67 | well as to the end user of the help system. 68 | 69 | This means that as a package developer, you only need to follow the simple 70 | steps in |integration.txt| to ensure that HyperHelp will be available to your 71 | package users, and then focus on writing your help. 72 | 73 | Once you've followed the integration steps, you can use Sublime itself to 74 | create your help content, or use the |HyperHelpAuthor| package to help you 75 | create the appropriate files. More information on creating help files can be 76 | found in |authoring.txt|. A simple example of the required files is also 77 | available in |example.txt|. 78 | 79 | HyperHelp is designed to be used not only as a system for displaying generic 80 | help but also context specific help. To that end you can optionally also use 81 | the |api|, |commands| and |key contexts| provided to customize the help 82 | experience your users have with your package and HyperHelp. 83 | 84 | 85 | # Bootstrapping 86 | =============== 87 | 88 | HyperHelp is different than standard packages that you might have used with 89 | Sublime Text in that it consists of two parts; a `dependency` library that 90 | provides the core of the help API, and a `package` that exposes the API and 91 | acts as you would expect a package to act. 92 | 93 | The HyperHelp package itself is shipped inside of the dependency, and the act 94 | of copying it out and deploying it as a standard package is known as 95 | `bootstrapping` the package. 96 | 97 | The bootstrap is seamless and happens automatically when required: 98 | 99 | * When the first package that uses HyperHelp is installed, the dependency 100 | will be installed and will bootstrap the HyperHelp package 101 | 102 | * If the dependency is updated, a new version of the HyperHelp package will 103 | be bootstrapped in order to keep things up to date 104 | 105 | * If the HyperHelp package is missing, a new copy will be created to put the 106 | system back into working order 107 | 108 | Whenever a bootstrap occurs, a dialog box will pop up to tell you that it 109 | happened. In some cases (such as when the dependency has been updated), you may 110 | be required to restart Sublime Text in order for the update to finish; the 111 | dialog will tell you when this is the case. 112 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/integration.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="Integrating HyperHelp" date="2019-03-25" 2 | 3 | 4 | # _none:Integrating HyperHelp into your Package 5 | ========================================== 6 | 7 | One of the core design goals of HyperHelp is to be as easy as possible to 8 | integrate with any package in order to promote a simple, easily accessible and 9 | useful help system that provides consistency for the user. 10 | 11 | Follow this simple set of steps in order to add HyperHelp support to your 12 | package: 13 | 14 | 15 | ## _none:Step 1: Add a dependency on `hyperhelpcore` 16 | ---------------------------------------------- 17 | 18 | As HyperHelp is shipped as a dependency, you need to modify your package to 19 | indicate to Package Control that it depends on `hyperhelpcore`; doing so 20 | will cause Package Control to automatically install HyperHelp for you as 21 | needed. 22 | 23 | See the |Package Control Dependency Documentation| for full details, but 24 | to get started, add a file named `dependencies.json` to your package with 25 | the following contents: 26 | 27 | ```json 28 | { 29 | "*": { 30 | "*": [ 31 | "hyperhelpcore" 32 | ] 33 | } 34 | } 35 | ``` 36 | 37 | Once you've done this, select `Package Control: Satisfy Dependencies` from 38 | the command palette to tell Package Control to install the dependency for 39 | you. 40 | 41 | 42 | ## _none:Step 2: Initialize the help system in `plugin_loaded()` 43 | ---------------------------------------------------------- 44 | 45 | Since HyperHelp is a dependency and needs to |:bootstrapping:bootstrap| the user facing 46 | package if it hasn't already, all packages that want active HyperHelp 47 | support need to tell it to perform that step if needed. 48 | 49 | To do this, add the following code to one of the plugins in your package. 50 | If that plugin already has a `plugin_loaded()` endpoint, don't create a 51 | second one; add the line of code here to yours: 52 | 53 | ```python 54 | import hyperhelpcore 55 | 56 | def plugin_loaded(): 57 | hyperhelpcore.initialize() 58 | 59 | ``` 60 | 61 | Once you save the plugin, `hyperhelpcore.initialize()` will be invoked, 62 | which will cause the first boostrap to occur, finalizing the install. Going 63 | forward, on every startup `hyperhelpcore` will check to verify that the 64 | bootstrapped package exists and is up to date. 65 | 66 | 67 | ## _none:Step 3: Author your Help 68 | --------------------------- 69 | 70 | You've now told Package Control that your package depends on HyperHelp so 71 | that it will be installed, and you've told HyperHelp at load time that it 72 | should check and verify that everything is running, so all that's left is 73 | to write your help. 74 | 75 | This is likely the hardest part of the entire operation. There is more 76 | information on creating help in |authoring.txt|. You may also find 77 | |syntax.txt| useful as a guide to the help file syntax. 78 | 79 | 80 | ## _none:Step 4: Implement context sensitive help (optional) 81 | ------------------------------------------------------ 82 | 83 | Although not strictly required, the power of HyperHelp allows you to create 84 | customized, context sensitive help for your package or help system by using 85 | the built in |commands|, |key contexts| and |api|. 86 | 87 | These allow you to include things like a custom key bindings or commands 88 | that jump directly from something in your package directly to associated 89 | help, and so on. 90 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/key_contexts.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp Key Contexts" date="2019-03-23" 2 | 3 | 4 | # Context Overview 5 | ================== 6 | 7 | HyperHelp provides several |commands|, key contexts and an |api| that allow you 8 | to customize the help experience for yourself or for users of your package by 9 | creating your own custom key bindings, menu entries or plugins. 10 | 11 | The key contexts listed here can be used in key bindings in order to ensure 12 | that your bindings only take effect in the appropriate circumstances. 13 | 14 | 15 | ## hyperhelp.is_help_view 16 | ------------------------- 17 | 18 | key: `"hyperhelp.is_help_view"` 19 | operator: `"equal"`, `"not_equal"` 20 | operand: `true`, `false` 21 | 22 | This context yields `true` when the currently focused view in the current 23 | window is a |help view|. 24 | 25 | 26 | ## hyperhelp.is_help_visible 27 | ------------------------- 28 | 29 | key: `"hyperhelp.is_help_visible"` 30 | operator: `"equal"`, `"not_equal"` 31 | operand: `true`, `false` 32 | 33 | This context yields `true` when the current window has a |help view| already 34 | created within it. This is not an indication that the help view is currently 35 | focused, only that it exists. 36 | 37 | 38 | ## hyperhelp.is_help 39 | ------------------------- 40 | 41 | key: `"hyperhelp.is_help"` 42 | operator: `"equal"`, `"not_equal"` 43 | operand: `true`, `false` 44 | 45 | This context yields `true` when the currently focused view in the current 46 | window contains a hyperhelp source file; that is, a file whose syntax indicates 47 | that it is a HyperHelp help file. 48 | 49 | This is true for any file using the appropriate syntax, which includes not only 50 | the contents of the |help view| but also a help file that you might be 51 | |:authoring.txt:authoring|. 52 | 53 | 54 | 55 | ## hyperhelp.is_help_source 56 | ------------------------- 57 | 58 | key: `"hyperhelp.is_help_source"` 59 | operator: `"equal"`, `"not_equal"` 60 | operand: `true`, `false` 61 | 62 | This context extends |hyperhelp.is_help| by only yielding `true` when the 63 | current help file is a help file that is not being authored; that is, it is 64 | marked as read-only. 65 | 66 | 67 | ## hyperhelp.is_help_index 68 | ------------------------- 69 | 70 | key: `"hyperhelp.is_help_index"` 71 | operator: `"equal"`, `"not_equal"` 72 | operand: `true`, `false` 73 | 74 | This context yields `true` when the currently focused view in the current 75 | window contains a hyperhelp index file; that is, a file whose syntax indicates 76 | that it is a HyperHelp index file. 77 | 78 | 79 | ## hyperhelp.is_help_package 80 | ------------------------- 81 | 82 | key: `"hyperhelp.is_help_package"` 83 | operator: `"equal"`, `"not_equal"` 84 | operand: a string that is a package name 85 | 86 | This context yields `true` when the current window contains a |help view| and 87 | the currently displayed help file is displaying a help file for the given 88 | package. 89 | 90 | 91 | ## hyperhelp.is_help_file 92 | ------------------------- 93 | 94 | key: `"hyperhelp.is_help_file"` 95 | operator: `"equal"`, `"not_equal"` 96 | operand: a string that is a package name 97 | 98 | This context yields `true` when the current window contains a |help view| and 99 | the currently displayed help file has the same name as the help file given. 100 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/settings.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp Settings" date="2020-04-06" 2 | 3 | 4 | # _none:Settings Overview 5 | =================== 6 | 7 | Like most packages, HyperHelp allows you to customize its behaviour by 8 | providing various settings for you to configure as you see fit. However, unlike 9 | most packages, HyperHelp consists of both a dependency that powers the help 10 | system and a regular package that allows you to interact with it. 11 | 12 | For this reason, some settings are specific to the HyperHelp package and work 13 | like normal package settings, while others are specific to the dependency and 14 | go in the global |Preferences.sublime-settings| preferences file instead. 15 | 16 | 17 | ## Package Settings 18 | ------------------- 19 | 20 | The settings here go in the HyperHelp specific settings file, which you can get 21 | to by selecting `Preferences > Package Settings > HyperHelp > Settings` from 22 | the main menu. 23 | 24 | *hyperhelp_date_format* 25 | 26 | This setting controls the format of the last modification date that 27 | appears in the |header| line of all help files. Changes to this setting 28 | will be applied when the next help file is loaded. 29 | 30 | The default value for this is setting is `%x`, which sets a date format 31 | that's appropriate for the area of the world in which you live. 32 | 33 | You can use any of the format specifiers given in the |Python 3.3 docs| 34 | on the |strftime() and strptime() behavior| page. 35 | 36 | Note however that no time stamps are stored for file times, only dates. 37 | As such you should avoid any fields that tell you the time of the day. 38 | 39 | *show_changelog* 40 | 41 | When this setting is enabled (which is the default), when HyperHelp is 42 | first installed it will display the |help_on_help.txt| file to help you 43 | learn how to use it. 44 | 45 | Similarly, whenever the package is upgraded the |:latest_update:latest entry| in the 46 | |changelog.txt| file will be displayed to keep you informed on the most 47 | recent changes and bug fixes. 48 | 49 | *focus_links_at_top* 50 | 51 | When this setting is enabled (which is the default), HyperHelp will 52 | focus the anchor of the link at the top of the help view. When 53 | disabled, the link achor will be centered in the help view instead. 54 | 55 | This setting does not affect the focus of anchors during anchor 56 | navigation through the file. 57 | 58 | 59 | ## Dependency Settings 60 | ---------------------- 61 | 62 | The settings here are referenced by the dependency portion of HyperHelp and go 63 | in the |Preferences.sublime-settings| file because they need to be available 64 | even if the HyperHelp package is ignored or unavailable. 65 | 66 | If you use the |PackageDev| package, it will syntax highlight these settings 67 | differently, and will also provide auto-complete and hover popups for them as 68 | well. 69 | 70 | *hyperhelp.ignore_disabled* 71 | 72 | Normally, the hyperhelp core dependency performs a check at startup to 73 | ensure that the HyperHelp package itself is not in the list of ignored 74 | packages. 75 | 76 | This is to ensure that problems caused by partial |:bootstrapping:bootstraps| don't go 77 | unnoticed, which can cause confusing issues. 78 | 79 | Should you actually want to have HyperHelp in the list of ignored 80 | packages, this setting should be added to your user preferences to tell 81 | the core that you intentionally ignored HyperHelp. 82 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/style.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp: Style Conventions" date="2019-03-25" 2 | 3 | 4 | # _none:Style Conventions 5 | =================== 6 | 7 | In order to remain as consistent as possible for all users of help, HyperHelp 8 | includes customized syntax specific settings for the |help view|. 9 | 10 | * `word_wrap` is disabled, so all help should optimally be presentable in 11 | no more than 80 characters of text. This matches the width of the 12 | generated |file header| in the displayed help. 13 | 14 | * `translate_tabs_to_spaces` is enabled for help files to ensure identical 15 | formatting for both the help author and the person viewing the help. 16 | 17 | 18 | # _none:View Conventions 19 | ================== 20 | 21 | In addition to the style rules outlined above, several settings are included in 22 | the syntax specific settings of the |help view| in order to provide a cleaner 23 | appearance. 24 | 25 | * `rulers` are disabled 26 | 27 | * `fade_fold_buttons` and `draw_indent_guides` are enabled and disabled 28 | respectively, since help text tends to be more free form and less code 29 | based, where indentation levels are less ordered. 30 | 31 | * `match_selection` is turned off to avoid visual noise when text is 32 | selected, such as when navigating between |anchors| 33 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/help/syntax.txt: -------------------------------------------------------------------------------- 1 | %hyperhelp title="HyperHelp: Help Syntax" date="2019-03-25" 2 | 3 | 4 | # _none:Help Syntax Overview 5 | ====================== 6 | 7 | Help files in HyperHelp are plain text files with an extension of `.txt` that 8 | support a minimal |markup| language to provide emphasis and navigation hints to 9 | the help system. Each help file in a help package must be referenced in the 10 | |hyperhelp.json| help index for the package so that HyperHelp knows that it 11 | exists. 12 | 13 | `NOTE:` Every help package should contain a file named `index.txt`, which 14 | is used as the default entry point for help in the package similar 15 | to how `index.html` is used for folders in web pages. 16 | 17 | 18 | # File Header 19 | ============= 20 | 21 | Every HyperHelp help file should start with a header structured as follows: 22 | 23 | ``` 24 | %hyperhelp title="Help File Title" date="YYYY-MM-DD" 25 | ``` 26 | 27 | 28 | When the help file is loaded into the |help view|, the header will be parsed 29 | and converted into a standard header line in the buffer. The title of the file 30 | is always centered within the 80 column width of the help view, and the date is 31 | displayed in a user-selectable format via the |hyperhelp_date_format| setting. 32 | 33 | The file header is not mandatory, but it is highly recommended that your help 34 | files contain one. This helps to ensure that all help displayed to the user is 35 | in a consistent format and ensures that every help file can be easily opened by 36 | name (since the expanded header contains the file name as an |anchor|). 37 | 38 | 39 | # Markup 40 | ======== 41 | 42 | Although HyperHelp is primarily plain text, there is a small markup language 43 | provided to add navigation information and visual emphasis where needed. 44 | 45 | Bu design, all markup is simple, contextual and non-ambiguous due to how 46 | Sublime Text syntax highlighting is performed. 47 | 48 | 49 | ## Anchors 50 | ---------- 51 | 52 | Normal: `*topic:anchor text*` 53 | `*:anchor text*` 54 | `*anchor text*` 55 | 56 | Hidden: `*|topic:anchor text|*` 57 | `*|:anchor text|*` 58 | `*|anchor text|*` 59 | 60 | `NOTE:` All anchors must have a unique `topic` (|headings| and anchors 61 | share the same topic name space). The special topic `_none` can 62 | be used to indicate an anchor can be navigated to by keyboard 63 | but not by a link (for example a section header). 64 | 65 | 66 | Anchors represent points of interest in help documents; they declare the 67 | point where a |topic| navigates to. Navigation to an anchor can occur as 68 | the result of following a link, as well as via keyboard navigation in a 69 | file; by default this is the and keys. 70 | 71 | The body of the anchor itself is of the form `topic:text`, which indicates 72 | that this anchor represents a topic named `topic`, but presents in the file 73 | as `text` instead. 74 | 75 | Since it is a common idiom for an anchor to use a topic and text that are 76 | identical, `*topic:topic*`, `*:topic*` and `*topic*` are treated as being 77 | the same; an anchor whose topic is identical to it's text. The second form 78 | is required when the topic text contains a literal `:` character, since in 79 | that case the result would be ambiguous. 80 | 81 | There are two styles of anchor, `Normal` and `Hidden`; the only functional 82 | difference between the two is that `normal` anchors are represented in the 83 | resulting text file wrapped in `*asterisks`, while a hidden anchor is not 84 | visibly distinct from the surrounding text in any way. 85 | 86 | 87 | ## Headings 88 | ----------- 89 | 90 | `# topic:text` 91 | `## topic:text` 92 | `### topic:text` 93 | 94 | `NOTE:` All anchors must have a unique `topic` (headings and |anchors| 95 | share the same topic name space). The special topic `_none` can 96 | be used to indicate an anchor can be navigated to by keyboard 97 | but not by a link (for example a section header). 98 | 99 | 100 | A heading is a special case of a normal |anchor|, which is prefixed by one 101 | or more `#` characters to indicate what level of heading that it is. As 102 | they are treated as anchors, topics can link to them. 103 | 104 | Headers are visually distinct from normal anchors due to their `#` prefix. 105 | Their purpose is to allow for easier navigation within the sections of a 106 | file by using `Goto > Goto Symbol`. 107 | 108 | In the symbol list, headers are displayed with an indentation level that 109 | corresponds to the number of `#` prefix characters they have, up to an 110 | indentation level of three. 111 | 112 | 113 | ## Links 114 | ------- 115 | 116 | `|package:topic:text|` 117 | `|:topic:text|` 118 | `|package::text|` 119 | `|::text|` 120 | `|text|` 121 | 122 | `NOTE:` The target of a link is resolved at the time the help file is 123 | loaded into the |help view| and is visible by hovering your 124 | mouse over a link. If the target of a link can not be found, 125 | the link will be visually styled with a different colored 126 | underline to indicate that it is broken. 127 | 128 | 129 | Links are the main method by which a user can interactively jump to another 130 | location in the current or some other help file. You can follow a link by 131 | doing a on the link, or placing the cursor on the link 132 | text and pressing . 133 | 134 | The general form of a link is `package:topic:text`, which indicates that 135 | the link targets the given |topic| in the given help package, and will 136 | display using the provided text. 137 | 138 | The `package` portion is optional and only required for links that target a 139 | topic in a different package; when it is not specified, the default is the 140 | current package. This is demonstrated in the second, fourth and fifth 141 | examples above. 142 | 143 | As with |anchors|, it is a common idiom to link to a topic by using the 144 | topic as the text of the link. In such a case, the topic is also optional 145 | and defaults to the link text, as in the last three examples above. 146 | 147 | In order to avoid ambiguity, if the link text contains a literal `:` 148 | character, all sections must be provided (though you can allow them to 149 | default). 150 | 151 | 152 | ## Code Blocks 153 | ------------- 154 | 155 | `Inline Code Block` 156 | 157 | ``` 158 | Multi Line Code Block 159 | ``` 160 | 161 | 162 | HyperHelp supports both inline code blocks and multi line code blocks in a 163 | manner similar to that used in Markdown. Unlike in standard markdown, it is 164 | not possible to include or quote a back tick inside of an inline code 165 | block. 166 | 167 | Multi line code blocks allow the ability to specify the syntax highlighting 168 | to use. Any value will be accepted, but syntax highlighting will only be 169 | performed for `python`, `py`, `xml`, `plist` and `json`, since these are 170 | the core file formats used by Sublime internally. 171 | 172 | 173 | ## Key Bindings 174 | -------------- 175 | 176 | `` 177 | `` 178 | `>` 179 | 180 | 181 | HyperHelp include a simple key binding markup by wrapping text in pairs of 182 | less than and greater than signs. Although intended primarily for use as a 183 | key binding (as the name suggets), there is no internal functionality that 184 | relies on this fact, so you are free to use them for any emphasis that you 185 | want. 186 | 187 | <****> 188 | 189 | ## Comments 190 | ----------- 191 | 192 | `<** Comment Text **>` 193 | 194 | `NOTE:` Due to a potential ambiguity, it is not possible to denote 195 | a key binding of four consecutive asterisk characters 196 | without including whitespace of some form; such a binding 197 | will be recognized as a comment instead. 198 | 199 | 200 | A simple comment syntax is allowed in HyperHelp by wrapping text in 201 | `<**` and `**>` sequences. 202 | 203 | When the help file is rendered in the |help view|, the comment is 204 | completely redacted from the contents of the file so that it doesn't appear 205 | to the user at all. 206 | 207 | When the `**>` is followed by the end of the line (with no intervening 208 | characters or whitespace), the end of line character will also be removed 209 | when the comment is redacted. 210 | 211 | This allows you to include comments in locations without adding extra 212 | blank lines to the output. 213 | 214 | 215 | ## Separators 216 | ------------ 217 | 218 | `----` 219 | `====` 220 | `+----|----+` 221 | `|` 222 | 223 | 224 | Separators allow for drawing simple horizontal and vertical lines, allowing 225 | you to emphasize text by underlining it (as is done in this help system) as 226 | well as to draw tables: 227 | 228 | 229 | +------------|----------+ 230 | | Sample Box | Column 2 | 231 | +============+==========+ 232 | 233 | 234 | Horizontal separators consist of four or more consecutive `=` or `-` 235 | characters. Additionally the sequence can begin with an `+` character and 236 | end with a `+` or `|` character to aid in line drawing. 237 | 238 | In addition, any `|` characters which are not a part of a |link| are 239 | considered to be vertical separators and are treated as such. 240 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/internalcmd.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | import time 5 | 6 | from hyperhelpcore.core import parse_help_header, parse_anchor_body, parse_link_body 7 | from hyperhelpcore.core import help_index_list, lookup_help_topic 8 | from hyperhelpcore.core import is_topic_file, is_topic_file_valid 9 | from hyperhelpcore.help import _get_link_topic 10 | from hyperhelpcore.common import hh_setting 11 | from hyperhelpcore.common import current_help_package, current_help_file 12 | 13 | 14 | ###---------------------------------------------------------------------------- 15 | 16 | 17 | def _can_post_process(view): 18 | """ 19 | Determine if the provided view is eligible for a post processing command to 20 | execute within it or not. 21 | """ 22 | return (view.match_selector(0, "text.hyperhelp.help") and 23 | view.settings().get("_hh_post_processing", False)) 24 | 25 | 26 | ###---------------------------------------------------------------------------- 27 | 28 | 29 | class HyperhelpInternalProcessHeaderCommand(sublime_plugin.TextCommand): 30 | """ 31 | Process the header in a newly loaded help file by finding and replacing the 32 | source level meta header with the fully expanded user-facing header. 33 | 34 | Nothing happens if the current file does not appear to have an appropriate 35 | meta-header line. 36 | """ 37 | def run(self, edit): 38 | help_file = current_help_file(self.view) 39 | first_line = self.view.substr(self.view.full_line(0)) 40 | 41 | header = parse_help_header(help_file, first_line) 42 | if header is None: 43 | return 44 | 45 | _hdr_width = 80 46 | _time_fmt = hh_setting("hyperhelp_date_format") 47 | 48 | file_target = "*%s*" % help_file 49 | title = header.title 50 | date_str = "Not Available" 51 | 52 | if header.date != 0: 53 | date_str = time.strftime(_time_fmt, time.localtime(header.date)) 54 | 55 | # Take into account two extra spaces on either side of the title 56 | max_title_len = _hdr_width - len(file_target) - len(date_str) - 4 57 | if len(title) > max_title_len: 58 | title = title[:max_title_len-1] + '\u2026' 59 | 60 | header_line = "%s %s %s\n%s\n" % ( 61 | file_target, 62 | "%s" % title.center(max_title_len, " "), 63 | date_str, 64 | ("=" * _hdr_width) 65 | ) 66 | 67 | self.view.replace(edit, self.view.full_line(0), header_line) 68 | 69 | def is_enabled(self): 70 | return _can_post_process(self.view) 71 | 72 | 73 | class HyperhelpInternalProcessCommentsCommand(sublime_plugin.TextCommand): 74 | """ 75 | Remove all hyperhelp comments from a newly loaded help file. 76 | 77 | All text scoped as a comment (including newlines) will be redacted from the 78 | file. 79 | """ 80 | def run(self, edit): 81 | for region in reversed(self.view.find_by_selector("comment.block.help")): 82 | self.view.erase(edit, region) 83 | 84 | def is_enabled(self): 85 | return _can_post_process(self.view) 86 | 87 | 88 | class HyperhelpInternalProcessAnchorsCommand(sublime_plugin.TextCommand): 89 | """ 90 | Process all anchors in a newly loaded help file. This does the work of 91 | rewriting anchors so that only their anchor text appears as well as 92 | removing the markup that makes hidden anchors hidden. 93 | 94 | This results in regions and settings being applied to the view that allow 95 | the help core to navigate within the file. 96 | """ 97 | def run(self, edit): 98 | v = self.view 99 | v.add_regions("_hh_anchors", v.find_by_selector("meta.anchor"), "", 100 | flags=sublime.HIDDEN | sublime.PERSISTENT) 101 | 102 | for pos in reversed(v.find_by_selector("punctuation.anchor.hidden")): 103 | v.erase(edit, pos) 104 | 105 | hh_nav = {} 106 | regions = v.get_regions("_hh_anchors") 107 | for idx, region in enumerate(reversed(regions)): 108 | topic, text = parse_anchor_body(v.substr(region)) 109 | v.replace(edit, region, text) 110 | hh_nav[topic] = len(regions) - idx - 1 111 | 112 | v.settings().set("_hh_nav", hh_nav) 113 | 114 | def is_enabled(self): 115 | return _can_post_process(self.view) 116 | 117 | 118 | class HyperhelpInternalProcessLinksCommand(sublime_plugin.TextCommand): 119 | """ 120 | Process all links in a newly loaded help file. This does the work of 121 | rewriting links so that only their link text appears, while keeping track 122 | of the topic ID and package designations of each link. 123 | 124 | This results in regions and settings being applied to the view that allow 125 | the help core to navigate within the file. 126 | """ 127 | def run(self, edit): 128 | v = self.view 129 | regions = v.find_by_selector("meta.link") 130 | default_pkg = current_help_package(self.view) 131 | 132 | v.add_regions("_hh_links", regions, "", 133 | flags=sublime.HIDDEN | sublime.PERSISTENT) 134 | 135 | 136 | hh_links = [None] * len(regions) 137 | for idx,region in enumerate(reversed(regions)): 138 | base_text = v.substr(region) 139 | pkg_name, topic, text = parse_link_body(base_text) 140 | pkg_name = pkg_name or default_pkg 141 | 142 | if text is None: 143 | topic = "_broken" 144 | text = base_text 145 | 146 | v.replace(edit, region, text) 147 | hh_links[len(regions) - idx - 1] = { 148 | "pkg": pkg_name, 149 | "topic": topic 150 | } 151 | 152 | v.settings().set("_hh_links", hh_links) 153 | 154 | v.run_command("hyperhelp_internal_flag_links") 155 | 156 | def is_enabled(self): 157 | return _can_post_process(self.view) 158 | 159 | 160 | class HyperhelpInternalFlagLinksCommand(sublime_plugin.TextCommand): 161 | """ 162 | Given a help file which has had its links post processed already via 163 | hyperhelp_internal_process_links, this checks each link in the file and 164 | classifies them as either active or broken, depending on whether or not 165 | they point to a valid destination. 166 | 167 | This is a non-destructive command and may be executed any time the 168 | underlying help indexes may have changed, such as at Sublime startup. 169 | """ 170 | def run(self, edit): 171 | v = self.view 172 | active = [] 173 | broken = [] 174 | 175 | regions = v.get_regions("_hh_links") 176 | for idx, region in enumerate(regions): 177 | link_dat = _get_link_topic(v, idx) 178 | 179 | pkg_info = help_index_list().get(link_dat["pkg"], None) 180 | topic = lookup_help_topic(pkg_info, link_dat["topic"]) 181 | 182 | if self.link_is_active(pkg_info, topic): 183 | active.append(region) 184 | else: 185 | broken.append(region) 186 | 187 | v.add_regions("_hh_links_active", active, "storage", 188 | flags=sublime.DRAW_SOLID_UNDERLINE | sublime.PERSISTENT | 189 | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE) 190 | 191 | v.add_regions("_hh_links_broken", broken, "comment", 192 | flags=sublime.DRAW_STIPPLED_UNDERLINE | sublime.PERSISTENT | 193 | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE) 194 | 195 | def link_is_active(self, pkg_info, topic): 196 | if topic is None: 197 | return False 198 | 199 | # Returns None if the topic is not a file, so only consider the topic 200 | # broken when the return is definitely false. 201 | if is_topic_file_valid(pkg_info, topic) is False: 202 | return False 203 | 204 | return True 205 | 206 | def is_enabled(self): 207 | return self.view.match_selector(0, "text.hyperhelp.help") 208 | 209 | 210 | ###---------------------------------------------------------------------------- 211 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Context.sublime-menu.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "-", "id": "end" }, 3 | { "command": "hyperhelp_context_create_bookmark" }, 4 | { "caption": "-" }, 5 | ] 6 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Default (Linux).sublime-keymap.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | // View the table of contents for the current help package. 3 | { 4 | "keys": ["?"], "command": "hyperhelp_contents", 5 | "context": [ 6 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 7 | ] 8 | }, 9 | 10 | // View the topic index for the current help package 11 | { 12 | "keys": ["i"], "command": "hyperhelp_index", 13 | "context": [ 14 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 15 | ] 16 | }, 17 | 18 | // Show the history of the help view in a quick panel and allow the user to 19 | // jump to a specific entry directly. 20 | { 21 | "keys": ["h"], "command": "hyperhelp_history", 22 | "args": {"action": "jump"}, 23 | "context": [ 24 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 25 | ] 26 | }, 27 | 28 | // Prompt the user to bookmark the current file or topic. 29 | { 30 | "keys": ["b"], 31 | "command": "show_overlay", 32 | "args": { 33 | "overlay": "command_palette", 34 | "command": "hyperhelp_prompt_create_bookmark" 35 | }, 36 | "context": [ 37 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 38 | ] 39 | }, 40 | 41 | // Prompt the user to select a bookmark, then navigate there. 42 | { 43 | "keys": ["g"], 44 | "command": "show_overlay", 45 | "args": { 46 | "overlay": "command_palette", 47 | "command": "hyperhelp_open_bookmark" 48 | }, 49 | "context": [ 50 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 51 | ] 52 | }, 53 | 54 | // Navigate forward and backward through anchors in the current help file. 55 | { 56 | "keys": ["tab"], "command": "hyperhelp_navigate", "args": { 57 | "nav": "find_anchor", 58 | "prev": false, 59 | }, 60 | "context": [ 61 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 62 | ], 63 | }, 64 | { 65 | "keys": ["shift+tab"], "command": "hyperhelp_navigate", "args": { 66 | "nav": "find_anchor", 67 | "prev": true, 68 | }, 69 | "context": [ 70 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 71 | ], 72 | }, 73 | 74 | // Follow links in the current help file. 75 | { 76 | "keys": ["enter"], "command": "hyperhelp_navigate", "args": { 77 | "nav": "follow_link" 78 | }, 79 | "context": [ 80 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 81 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 82 | ] 83 | }, 84 | { 85 | "keys": ["keypad_enter"], "command": "hyperhelp_navigate", "args": { 86 | "nav": "follow_link" 87 | }, 88 | "context": [ 89 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 90 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 91 | ] 92 | }, 93 | 94 | // Navigate through the topic history 95 | { 96 | "keys": ["alt+left"], "command": "hyperhelp_history", "args": { 97 | "action": "prev" 98 | }, 99 | "context": [ 100 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 101 | ] 102 | }, 103 | { 104 | "keys": ["alt+right"], "command": "hyperhelp_history", "args": { 105 | "action": "next" 106 | }, 107 | "context": [ 108 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 109 | ] 110 | }, 111 | 112 | // Open the command palette with all help commands displayed. 113 | { 114 | "keys": ["super+h"], "command": "show_overlay", 115 | "args": { 116 | "overlay": "command_palette", 117 | "text" : "HyperHelp: " 118 | } 119 | } 120 | ] -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Default (OSX).sublime-keymap.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | // View the table of contents for the current help package. 3 | { 4 | "keys": ["?"], "command": "hyperhelp_contents", 5 | "context": [ 6 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 7 | ] 8 | }, 9 | 10 | // View the topic index for the current help package 11 | { 12 | "keys": ["i"], "command": "hyperhelp_index", 13 | "context": [ 14 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 15 | ] 16 | }, 17 | 18 | // Show the history of the help view in a quick panel and allow the user to 19 | // jump to a specific entry directly. 20 | { 21 | "keys": ["h"], "command": "hyperhelp_history", 22 | "args": {"action": "jump"}, 23 | "context": [ 24 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 25 | ] 26 | }, 27 | 28 | // Prompt the user to bookmark the current file or topic. 29 | { 30 | "keys": ["b"], "command": "hyperhelp_prompt_create_bookmark", 31 | "context": [ 32 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 33 | ] 34 | }, 35 | 36 | // Prompt the user to select a bookmark, then navigate there. 37 | { 38 | "keys": ["g"], "command": "hyperhelp_open_bookmark", 39 | "context": [ 40 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 41 | ] 42 | }, 43 | 44 | // Navigate forward and backward through anchors in the current help file. 45 | { 46 | "keys": ["tab"], "command": "hyperhelp_navigate", "args": { 47 | "nav": "find_anchor", 48 | "prev": false, 49 | }, 50 | "context": [ 51 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 52 | ], 53 | }, 54 | { 55 | "keys": ["shift+tab"], "command": "hyperhelp_navigate", "args": { 56 | "nav": "find_anchor", 57 | "prev": true, 58 | }, 59 | "context": [ 60 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 61 | ], 62 | }, 63 | 64 | // Follow links in the current help file. 65 | { 66 | "keys": ["enter"], "command": "hyperhelp_navigate", "args": { 67 | "nav": "follow_link" 68 | }, 69 | "context": [ 70 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 71 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 72 | ] 73 | }, 74 | { 75 | "keys": ["keypad_enter"], "command": "hyperhelp_navigate", "args": { 76 | "nav": "follow_link" 77 | }, 78 | "context": [ 79 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 80 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 81 | ] 82 | }, 83 | 84 | // Navigate through the topic history 85 | { 86 | "keys": ["super+["], "command": "hyperhelp_history", "args": { 87 | "action": "prev" 88 | }, 89 | "context": [ 90 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 91 | ] 92 | }, 93 | { 94 | "keys": ["super+]"], "command": "hyperhelp_history", "args": { 95 | "action": "next" 96 | }, 97 | "context": [ 98 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 99 | ] 100 | }, 101 | 102 | // Open the command palette with all help commands displayed. 103 | { 104 | "keys": ["super+h"], "command": "show_overlay", 105 | "args": { 106 | "overlay": "command_palette", 107 | "text" : "HyperHelp: " 108 | } 109 | } 110 | ] -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Default (Windows).sublime-keymap.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | // View the table of contents for the current help package. 3 | { 4 | "keys": ["?"], "command": "hyperhelp_contents", 5 | "context": [ 6 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 7 | ] 8 | }, 9 | 10 | // View the topic index for the current help package 11 | { 12 | "keys": ["i"], "command": "hyperhelp_index", 13 | "context": [ 14 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 15 | ] 16 | }, 17 | 18 | // Show the history of the help view in a quick panel and allow the user to 19 | // jump to a specific entry directly. 20 | { 21 | "keys": ["h"], "command": "hyperhelp_history", 22 | "args": {"action": "jump"}, 23 | "context": [ 24 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 25 | ] 26 | }, 27 | 28 | // Prompt the user to bookmark the current file or topic. 29 | { 30 | "keys": ["b"], "command": "hyperhelp_prompt_create_bookmark", 31 | "context": [ 32 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 33 | ] 34 | }, 35 | 36 | // Prompt the user to select a bookmark, then navigate there. 37 | { 38 | "keys": ["g"], "command": "hyperhelp_open_bookmark", 39 | "context": [ 40 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 41 | ] 42 | }, 43 | 44 | // Navigate forward and backward through anchors in the current help file. 45 | { 46 | "keys": ["tab"], "command": "hyperhelp_navigate", "args": { 47 | "nav": "find_anchor", 48 | "prev": false, 49 | }, 50 | "context": [ 51 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 52 | ], 53 | }, 54 | { 55 | "keys": ["shift+tab"], "command": "hyperhelp_navigate", "args": { 56 | "nav": "find_anchor", 57 | "prev": true, 58 | }, 59 | "context": [ 60 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 61 | ], 62 | }, 63 | 64 | // Follow links in the current help file. 65 | { 66 | "keys": ["enter"], "command": "hyperhelp_navigate", "args": { 67 | "nav": "follow_link" 68 | }, 69 | "context": [ 70 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 71 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 72 | ] 73 | }, 74 | { 75 | "keys": ["keypad_enter"], "command": "hyperhelp_navigate", "args": { 76 | "nav": "follow_link" 77 | }, 78 | "context": [ 79 | { "key": "selector", "operator": "equal", "operand": "text.hyperhelp.help meta.link" }, 80 | { "key": "hyperhelp.is_authoring", "operator": "equal", "operand": false } 81 | ] 82 | }, 83 | 84 | // Navigate through the topic history 85 | { 86 | "keys": ["alt+left"], "command": "hyperhelp_history", "args": { 87 | "action": "prev" 88 | }, 89 | "context": [ 90 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 91 | ] 92 | }, 93 | { 94 | "keys": ["alt+right"], "command": "hyperhelp_history", "args": { 95 | "action": "next" 96 | }, 97 | "context": [ 98 | { "key": "hyperhelp.is_help_view", "operator": "equal", "operand": true }, 99 | ] 100 | }, 101 | 102 | // Open the command palette with all help commands displayed. 103 | { 104 | "keys": ["ctrl+alt+h"], "command": "show_overlay", 105 | "args": { 106 | "overlay": "command_palette", 107 | "text" : "HyperHelp: " 108 | } 109 | } 110 | ] -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/HyperHelp-Help.sublime-settings.sublime-ignored: -------------------------------------------------------------------------------- 1 | { 2 | // Help files are standardized on 80 characters wide, but they should not 3 | // wrap. 4 | "wrap_width": 80, 5 | "word_wrap": false, 6 | 7 | // Remove visual clutter from the help view; authoring tools can apply 8 | // settings as required to edited views, or you can override these options 9 | // if desired in your own settings. 10 | "fade_fold_buttons": true, 11 | "match_selection": false, 12 | "draw_indent_guides": false, 13 | "rulers": [], 14 | 15 | // All help files should contain no physical tabs since there will never be 16 | // any concensus on how wide they should be. 17 | "detect_indentation": false, 18 | "translate_tabs_to_spaces": true 19 | } -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/HyperHelp.sublime-commands.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "About HyperHelp", "command": "hyper_help_about" }, 3 | { "caption": "HyperHelp ChangeLog", "command": "hyperhelp_topic", "args": { "package": "HyperHelp", "topic": "changelog.txt" } }, 4 | 5 | { "caption": "HyperHelp: Help on Help", "command": "hyperhelp_topic", "args": { "package": "HyperHelp", "topic": "help_on_help.txt" } }, 6 | { "caption": "HyperHelp: Browse Available Help", "command": "hyperhelp_contents", "args": { "prompt": true } }, 7 | { "caption": "HyperHelp: Table of Contents", "command": "hyperhelp_contents", "args": { "prompt": false } }, 8 | { "caption": "HyperHelp: Help Index", "command": "hyperhelp_index", "args": { "prompt": false } }, 9 | 10 | { "caption": "HyperHelp: Open Bookmarked help topic", "command": "hyperhelp_open_bookmark" }, 11 | { "caption": "HyperHelp: Create Bookmark", "command": "hyperhelp_prompt_create_bookmark" }, 12 | 13 | { "caption": "HyperHelp: Clear topic history list", "command": "hyperhelp_history", "args": {"action": "clear" } }, 14 | { "caption": "HyperHelp: Jump to topic in history list", "command": "hyperhelp_history", "args": {"action": "jump" } }, 15 | 16 | { 17 | "caption": "Preferences: HyperHelp", "command": "edit_settings", 18 | "args": 19 | { 20 | "base_file": "${packages}/HyperHelp/resources/HyperHelp.sublime-settings", 21 | "default": "{\n\t$0\n}\n" 22 | } 23 | }, 24 | { 25 | "caption": "Preferences: HyperHelp Key Bindings", 26 | "command": "edit_settings", 27 | "args": 28 | { 29 | "base_file": "${packages}/HyperHelp/resources/Default (${platform}).sublime-keymap", 30 | "default": "[\n\t$0\n]\n" 31 | } 32 | }, 33 | ] -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/HyperHelp.sublime-settings.sublime-ignored: -------------------------------------------------------------------------------- 1 | { 2 | // Specify the date format to be used for help dates in the loaded help 3 | // view. This uses the standard Python date format string formatting codes. 4 | "hyperhelp_date_format": "%x", 5 | 6 | // When HyperHelp is first installed and every time it's updated, it will 7 | // request that you restart Sublime to ensure that everything reloads 8 | // properly. 9 | // 10 | // If this setting is enabled, then on that restart HyperHelp will open and 11 | // display either its own changelog or the help on help topic. 12 | // 13 | // Disable this to not see the changelog (or the help on help, if you have 14 | // previously installed the package). 15 | "show_changelog": true, 16 | 17 | // When following a link, HyperHelp needs to display the correct help file 18 | // and ensure that the anchor is visible in the window. This setting 19 | // controls where the anchor will end up. 20 | // 21 | // When the value is true, the focused anchor will appear at the top of the 22 | // window, maximizing how much of the associated text you can see. 23 | // 24 | // When false, the anchor will be centered in the help view instead. This 25 | // was the default behaviour prior to this setting being introduced. 26 | "focus_links_at_top": true, 27 | 28 | // Specify a list of bookmarked help topics. These topics can be quickly 29 | // navigated to via the bookmark command in the command palette and the 30 | // main menu. 31 | "bookmarks": [ 32 | ] 33 | } -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Main.sublime-menu.sublime-ignored: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "HyperHelp", 16 | "children": 17 | [ 18 | { 19 | "caption": "Documentation", 20 | "command": "hyperhelp_topic", 21 | "args": { 22 | "package": "HyperHelp", 23 | "topic": "help_on_help.txt" 24 | } 25 | }, 26 | { 27 | "caption": "View ChangeLog", 28 | "command": "hyperhelp_topic", 29 | "args": { 30 | "package": "HyperHelp", 31 | "topic": "changelog.txt" 32 | } 33 | }, 34 | { 35 | "caption": "-" 36 | }, 37 | { 38 | "caption": "Settings", 39 | "command": "edit_settings", 40 | "args": { 41 | "base_file": "${packages}/HyperHelp/resources/HyperHelp.sublime-settings", 42 | "default": "{\n\t$0\n}\n" 43 | } 44 | }, 45 | { 46 | "caption": "Key Bindings", 47 | "command": "edit_settings", 48 | "args": { 49 | "base_file": "${packages}/HyperHelp/resources/Default ($platform).sublime-keymap", 50 | "default": "[\n\t$0\n]\n" 51 | } 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | ] 58 | }, 59 | 60 | { 61 | "id": "help", 62 | "children": 63 | [ 64 | { 65 | "id": "hyperhelp", 66 | "caption": "HyperHelp", 67 | "mnemonic": "y", 68 | "children": [ 69 | { 70 | "caption": "Help on help", 71 | "command": "hyperhelp_topic", 72 | "args": { 73 | "package": "HyperHelp", 74 | "topic": "help_on_help.txt" 75 | } 76 | }, 77 | { 78 | "caption": "Browse Available Help…", 79 | "command": "hyperhelp_contents", 80 | "args": { "prompt": true } 81 | }, 82 | 83 | { 84 | "caption": "Create Bookmark…", 85 | "command": "hyperhelp_prompt_create_bookmark" 86 | }, 87 | { 88 | "caption": "Open bookmarked help topic…", 89 | "command": "hyperhelp_open_bookmark" 90 | }, 91 | 92 | { "caption": "-" }, 93 | 94 | { "command": "hyperhelp_current_help" }, 95 | 96 | { "caption": "-" }, 97 | 98 | { 99 | "caption": "Table of Contents", 100 | "command": "hyperhelp_contents", 101 | }, 102 | { 103 | "caption": "Help Index", 104 | "command": "hyperhelp_index", 105 | }, 106 | 107 | { "caption": "-" }, 108 | 109 | { 110 | "caption": "Clear topic history list", 111 | "command": "hyperhelp_history", 112 | "args": { 113 | "action": "clear" 114 | } 115 | }, 116 | 117 | { "caption": "-" }, 118 | 119 | { 120 | "caption": "Jump to item in history…", 121 | "command": "hyperhelp_history", 122 | "args": { 123 | "action": "jump" 124 | } 125 | }, 126 | { 127 | "command": "hyperhelp_history", 128 | "args": { 129 | "action": "prev" 130 | } 131 | }, 132 | { 133 | "command": "hyperhelp_history", 134 | "args": { 135 | "action": "next" 136 | } 137 | }, 138 | 139 | { "caption": "-" }, 140 | 141 | { 142 | "caption": "About HyperHelp", 143 | "command": "hyper_help_about", 144 | }, 145 | { 146 | "caption": "View ChangeLog", 147 | "command": "hyperhelp_topic", 148 | "args": { 149 | "package": "HyperHelp", 150 | "topic": "changelog.txt" 151 | } 152 | } 153 | ] 154 | } 155 | ] 156 | } 157 | ] -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Preferences.sublime-settings-hints.sublime-ignored: -------------------------------------------------------------------------------- 1 | { 2 | // In normal operation, the help system will perform a bootstrap of the 3 | // HyperHelp package at startup if the package is missing or out of date. 4 | // In order to subvert this check and force a bootstrap to happen at every 5 | // startup, set this setting to true. 6 | // 7 | // This is intended for debugging and troubleshooting purposes. 8 | "hyperhelp.force_bootstrap": false, 9 | 10 | // The help system generates a warning at startup if the HyperHelp package 11 | // is in the list of ignored_packages, since this is an indications that the 12 | // last bootstrap did not complete successfully. 13 | // 14 | // You can disable the warning by changing the value of this setting to 15 | // true. 16 | "hyperhelp.ignore_disabled": false, 17 | 18 | // The help system generates a warning at startup if it detects a HyperHelp 19 | // folder in the Packages folder, since such a folder may contain overrides 20 | // that can cause issues such as masking updates. 21 | // 22 | // If you understand the ramifications of overriding the help system, you 23 | // can disable the warning by setting this setting to true. 24 | "hyperhelp.allow_unpacked": false, 25 | } -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Symbol List - Exclusions.tmPreferences.sublime-ignored: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List: Discard Inline Python 7 | scope 8 | text.hyperhelp.help source.python meta.function - meta.function.inline, text.hyperhelp.help source.python meta.class 9 | settings 10 | 11 | showInSymbolList 12 | 0 13 | 14 | 15 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Symbol List - Headers.tmPreferences.sublime-ignored: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List: Section Headers 7 | scope 8 | text.hyperhelp.help meta.heading.anchor 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 19 | 20 | uuid 21 | c484f41d-5700-48ba-a93e-facea4b9dee2 22 | 23 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/Symbol List - Title.tmPreferences.sublime-ignored: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List: Document Title 7 | scope 8 | text.hyperhelp.help meta.help.header meta.title 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 18 | 19 | uuid 20 | c484f41d-5700-48ba-a93e-facea4b9dee2 21 | 22 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/syntax/HyperHelp-Help.sublime-syntax.sublime-ignored: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | name: Help 4 | scope: text.hyperhelp.help 5 | first_line_match: '^%hyperhelp' 6 | hidden: true 7 | variables: 8 | block_markup: '^\s*(`{3})(?![^`]*`)' 9 | block_markup_end: '^\s*(`{3})\s*$' 10 | separator: '(?:(?:\+|\|)?([=-])\1{3,}(?:\+|\|)?)|(?:\|)' 11 | 12 | contexts: 13 | main: 14 | - include: help-header 15 | - include: help-source-header 16 | - match: '' 17 | set: body 18 | help-header: 19 | - match: '^(\*)([^*\|]+)(\*)\s+(.*?)\s{2,}(.*)' 20 | captures: 21 | 0: meta.help.header 22 | 1: string.unquoted punctuation.anchor.begin 23 | 2: string.unquoted meta.anchor 24 | 3: string.unquoted punctuation.anchor.end 25 | 4: storage.type.class meta.title 26 | 5: variable.language meta.date 27 | set: body 28 | help-source-header: 29 | - match: '^(%)(hyperhelp)' 30 | captures: 31 | 1: punctuation.definition.directive 32 | 2: keyword.other.directive meta.directive 33 | push: header-keypairs 34 | header-keypairs: 35 | - match: '\b([a-z]+)(=)(")([^"]*)(")' 36 | captures: 37 | 1: storage.type.class meta.key 38 | 2: keyword.operator 39 | 3: string.quoted.double 40 | 4: string.quoted.double meta.value 41 | 5: string.quoted.double 42 | - match: '\S' 43 | scope: invalid.illegal.hyperhelp.header 44 | - match: '$' 45 | set: body 46 | comments: 47 | - match: '<\*\*' 48 | scope: punctuation.definition.comment.begin.help 49 | push: 50 | - meta_scope: comment.block.help 51 | - match: '(\*\*>)(\n)?' 52 | captures: 53 | 1: punctuation.definition.comment.end.help 54 | pop: true 55 | key-bindings: 56 | - match: '<(?=[>\w?])' 57 | scope: variable.language punctuation.definition.keybind.begin.help 58 | push: 59 | - meta_scope: variable.language meta.keybind 60 | - match: '>(?=[^>])' 61 | pop: true 62 | inline-code-block: 63 | - match: '`' 64 | scope: punctuation.definition.raw.begin 65 | push: 66 | - meta_content_scope: markup.raw.inline 67 | - match: '`' 68 | scope: punctuation.definition.raw.end 69 | pop: true 70 | code-blocks: 71 | - match: '{{block_markup}}(json).*$\n?' 72 | captures: 73 | 0: meta.code-fence.definition.begin.json 74 | 1: punctuation.definition.code-fence.begin.json 75 | 2: constant.other.language-name 76 | embed: scope:source.json 77 | embed_scope: markup.raw.code-fence.json 78 | escape: '{{block_markup_end}}' 79 | escape_captures: 80 | 0: meta.code-fence.definition.end.json 81 | 1: punctuation.definition.code-fence.end.json 82 | - match: '{{block_markup}}(python|py).*$\n?' 83 | captures: 84 | 0: meta.code-fence.definition.begin.python 85 | 1: punctuation.definition.code-fence.begin.python 86 | 2: constant.other.language-name 87 | embed: scope:source.python 88 | embed_scope: markup.raw.code-fence.python 89 | escape: '{{block_markup_end}}' 90 | escape_captures: 91 | 0: meta.code-fence.definition.end.python 92 | 1: punctuation.definition.code-fence.end.python 93 | - match: '{{block_markup}}(xml|plist).*$\n?' 94 | captures: 95 | 0: meta.code-fence.definition.begin.xml 96 | 1: punctuation.definition.code-fence.begin.xml 97 | 2: constant.other.language-name 98 | embed: scope:text.xml 99 | embed_scope: markup.raw.code-fence.xml 100 | escape: '{{block_markup_end}}' 101 | escape_captures: 102 | 0: meta.code-fence.definition.end.xml 103 | 1: punctuation.definition.code-fence.end.xml 104 | - match: '{{block_markup}}([\w-]*).*$\n?' 105 | captures: 106 | 0: meta.code-fence.definition.begin 107 | 1: punctuation.definition.code-fence.begin 108 | 2: constant.other.language-name 109 | push: 110 | - meta_content_scope: markup.raw.code-fence 111 | - match: '{{block_markup_end}}' 112 | captures: 113 | 0: meta.code-fence.definition.end 114 | 1: punctuation.definition.code-fence.end 115 | pop: true 116 | links: 117 | - match: '\|(?=[\w:$])' 118 | scope: storage punctuation.link.begin 119 | push: 120 | - meta_content_scope: storage meta.link 121 | - match: '\|' 122 | scope: storage punctuation.link.end 123 | pop: true 124 | anchors: 125 | - match: '\*(?=[\w:$])' 126 | scope: string.unquoted punctuation.anchor.begin 127 | push: 128 | - meta_content_scope: string.unquoted meta.anchor 129 | - match: '\*' 130 | scope: string.unquoted punctuation.anchor.end 131 | pop: true 132 | - match: '\*\|(?=[\w:$])' 133 | scope: string.unquoted punctuation.anchor.hidden.begin 134 | push: 135 | - meta_content_scope: string.unquoted meta.anchor.hidden 136 | - match: '\|\*' 137 | scope: string.unquoted punctuation.anchor.hidden.end 138 | pop: true 139 | - match: '^\s*(?=#)' 140 | push: header-anchors 141 | header-anchor-terminator: 142 | - match: '[ ]*(#*)[ ]*($\n?)' 143 | captures: 144 | 1: string.unquoted punctuation.anchor.end.heading 145 | pop: true 146 | header-anchors: 147 | - match: '(#)(?!#)\s*(?=\S)' 148 | captures: 149 | 1: string.unquoted punctuation.anchor.begin.heading 150 | set: 151 | - meta_scope: meta.heading.anchor 152 | - meta_content_scope: string.unquoted meta.anchor.heading.1 153 | - include: header-anchor-terminator 154 | - match: '(##)(?!#)\s*(?=\S)' 155 | captures: 156 | 1: string.unquoted punctuation.anchor.begin.heading 157 | set: 158 | - meta_scope: meta.heading.anchor 159 | - meta_content_scope: string.unquoted meta.anchor.heading.2 160 | - include: header-anchor-terminator 161 | - match: '(#{3,})(?!#)\s*(?=\S)' 162 | captures: 163 | 1: string.unquoted punctuation.anchor.begin.heading 164 | set: 165 | - meta_scope: meta.heading.anchor 166 | - meta_content_scope: string.unquoted meta.anchor.heading.3 167 | - include: header-anchor-terminator 168 | - match: '' 169 | pop: true 170 | separators: 171 | - match: '{{separator}}' 172 | scope: storage meta.separator 173 | body: 174 | - include: comments 175 | - include: key-bindings 176 | - include: code-blocks 177 | - include: inline-code-block 178 | - include: links 179 | - include: anchors 180 | - include: separators 181 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/syntax/HyperHelp-Index.sublime-syntax.sublime-ignored: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | name: Help Index 4 | scope: text.hyperhelp.index 5 | hidden: true 6 | file_extensions: 7 | - hyperhelp.json 8 | 9 | contexts: 10 | main: 11 | - include: scope:source.json 12 | -------------------------------------------------------------------------------- /all/hyperhelpcore/HyperHelp/resources/syntax/HyperHelpComments.tmPreferences.sublime-ignored: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | name 5 | Comments 6 | scope 7 | text.hyperhelp.index 8 | settings 9 | 10 | shellVariables 11 | 12 | 13 | name 14 | TM_COMMENT_START 15 | value 16 | // 17 | 18 | 19 | name 20 | TM_COMMENT_START_2 21 | value 22 | /* 23 | 24 | 25 | name 26 | TM_COMMENT_END_2 27 | value 28 | */ 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /all/hyperhelpcore/__init__.py: -------------------------------------------------------------------------------- 1 | ### --------------------------------------------------------------------------- 2 | 3 | 4 | from .startup import initialize 5 | 6 | __version_tuple = (0, 0, 8) 7 | __version__ = ".".join([str(num) for num in __version_tuple]) 8 | 9 | 10 | ### --------------------------------------------------------------------------- 11 | 12 | 13 | __all__ = [ 14 | "common", 15 | "core", 16 | "data", 17 | "help", 18 | "initialize", 19 | "version" 20 | "view", 21 | ] 22 | 23 | 24 | ### --------------------------------------------------------------------------- 25 | 26 | 27 | def version(): 28 | """ 29 | Get the version of the installed dependency package as a tuple. This is 30 | used during the bootstrap check to see if the version of the dependency has 31 | changed. 32 | """ 33 | return __version_tuple 34 | 35 | 36 | ### --------------------------------------------------------------------------- -------------------------------------------------------------------------------- /all/hyperhelpcore/bootstrapper.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | import os 4 | import re 5 | import codecs 6 | import textwrap 7 | from zipfile import ZipFile 8 | 9 | from threading import Thread 10 | 11 | from os.path import join, dirname, normpath, relpath 12 | from importlib import __import__ as do_import 13 | 14 | 15 | ### --------------------------------------------------------------------------- 16 | 17 | 18 | # These name the bootstrap package that we use to give Sublime access to our 19 | # resources and commands, and the base name of the file within that package 20 | # that is responsible for loading the commands into Sublime when the package 21 | # is loaded. 22 | bootstrap_pkg = "HyperHelp" 23 | bootloader = "bootstrap" 24 | 25 | 26 | ### --------------------------------------------------------------------------- 27 | 28 | 29 | def log(msg, *args, dialog=False, error=False, **kwargs): 30 | """ 31 | Generate a message to the console and optionally as either a message or 32 | error dialog. The message will be formatted and dedented before being 33 | displayed, and will be prefixed with its origin. 34 | """ 35 | msg = textwrap.dedent(msg.format(*args, **kwargs)).strip() 36 | 37 | if error: 38 | print("hyperhelp error:") 39 | return sublime.error_message(msg) 40 | 41 | for line in msg.splitlines(): 42 | print("hyperhelp: {msg}".format(msg=line)) 43 | 44 | if dialog: 45 | sublime.message_dialog(msg) 46 | 47 | 48 | def set_initial_topic(package, topic): 49 | """ 50 | Set a setting in the active window that tells the bootstrapped package to 51 | open an initial help topic the next time the package loads. 52 | """ 53 | settings = sublime.active_window().settings() 54 | settings.set("hyperhelp.initial_topic", "%s:%s" % (package, topic)) 55 | 56 | 57 | def display_topic(package, topic): 58 | """ 59 | Invoke the appropriate command to display the given help topic. The topic 60 | is presumed to be from our own package. This uses a timeout so that it can 61 | be invoked from within the bootstrap code. 62 | """ 63 | sublime.set_timeout(lambda: sublime.run_command("hyperhelp_topic", { 64 | "package": package, 65 | "topic": topic 66 | })) 67 | 68 | 69 | ### --------------------------------------------------------------------------- 70 | 71 | 72 | class BootstrapThread(Thread): 73 | """ 74 | Spawns a background thread that will create or update the hyperhelp 75 | bootstrap package. 76 | """ 77 | def __init__(self): 78 | super().__init__() 79 | self.settings = sublime.load_settings("Preferences.sublime-settings") 80 | 81 | 82 | def enable_package(self, reenable_resources): 83 | """ 84 | Enables the system bootstrap package (if it exists) by ensuring that 85 | it is not in the list of ignored packages and then restoring any 86 | resources that were unloaded back to the views that were using them. 87 | """ 88 | ignored_packages = self.settings.get("ignored_packages", []) 89 | 90 | if bootstrap_pkg in ignored_packages: 91 | ignored_packages.remove(bootstrap_pkg) 92 | self.settings.set("ignored_packages", ignored_packages) 93 | 94 | # Enable resources after a short delay to ensure that Sublime has had a 95 | # change to re-index them. 96 | if reenable_resources: 97 | sublime.set_timeout_async(lambda: self.enable_resources()) 98 | 99 | 100 | def disable_package(self): 101 | """ 102 | Disables the system bootstrap package (if it exists) by ensuring that 103 | none of the resources that it provides are currently in use and then 104 | adding it to the list of ignored packages so that Sublime will unload 105 | it. 106 | """ 107 | self.disable_resources() 108 | 109 | ignored_packages = self.settings.get("ignored_packages", []) 110 | if bootstrap_pkg not in ignored_packages: 111 | ignored_packages.append(bootstrap_pkg) 112 | self.settings.set("ignored_packages", ignored_packages) 113 | 114 | 115 | def enable_resources(self): 116 | """ 117 | Enables all resources being provided by the system boostrap package by 118 | restoring the state that was saved when the resources were disabled. 119 | """ 120 | for window in sublime.windows(): 121 | for view in window.views(): 122 | s = view.settings() 123 | old_syntax = s.get("_hh_boot_syntax", None) 124 | if old_syntax is not None: 125 | s.set("syntax", old_syntax) 126 | s.erase("_hh_boot_syntax") 127 | 128 | 129 | def disable_resources(self): 130 | """ 131 | Disables all resources being provided by the system bootstrap package 132 | by saving the state of items that are using them and then reverting 133 | them to temporary defaults. 134 | """ 135 | prefix = "Packages/{pkg}/".format(pkg=bootstrap_pkg) 136 | 137 | # TODO if the package also contains a custom color scheme, this should 138 | # also temporarily reset the color scheme back to defaults and then 139 | # restore them later. 140 | for window in sublime.windows(): 141 | for view in window.views(): 142 | s = view.settings() 143 | syntax = s.get("syntax") 144 | if syntax.startswith(prefix): 145 | s.set("_hh_boot_syntax", syntax) 146 | s.set("syntax", "Packages/Text/Plain text.tmLanguage") 147 | 148 | 149 | def create_boot_loader(self, stub_loader_name): 150 | """ 151 | Given the name of a file containing a stub system bootstrap loader, 152 | return the body of a loader that contains the version number of the 153 | core dependency. 154 | """ 155 | try: 156 | from hyperhelpcore import version as ver_info 157 | 158 | with codecs.open(stub_loader_name, 'r', 'utf-8') as file: 159 | content = file.read() 160 | 161 | return re.sub(r"^__core_version_tuple\s+=\s+\(.*\)$", 162 | "__core_version_tuple = {version}". 163 | format(version=str(ver_info())), 164 | content, 165 | count=1, 166 | flags=re.MULTILINE) 167 | except: 168 | log("Bootstrap error: Unable to create bootloader") 169 | raise 170 | 171 | 172 | def create_bootstrap_package(self, package, res_path): 173 | """ 174 | Perform the task of actually creating the system bootstrap package from 175 | files in the given resource folder into the provided package. 176 | """ 177 | try: 178 | success = True 179 | boot_file = "{file}.py".format(file=bootloader) 180 | 181 | with ZipFile(package, 'w') as zFile: 182 | for (path, dirs, files) in os.walk(res_path): 183 | rPath = relpath(path, res_path) if path != res_path else "" 184 | 185 | for file in files: 186 | real_file = join(res_path, path, file) 187 | archive_file = join(rPath, file) 188 | 189 | if archive_file.endswith(".sublime-ignored"): 190 | archive_file = archive_file[:-len(".sublime-ignored")] 191 | 192 | if archive_file == boot_file: 193 | content = self.create_boot_loader(real_file) 194 | zFile.writestr(archive_file, content) 195 | else: 196 | zFile.write(real_file, archive_file) 197 | 198 | except Exception as err: 199 | success = False 200 | log("Bootstrap error: {reason}", reason=str(err)) 201 | if os.path.exists(package): 202 | os.remove(package) 203 | 204 | return success 205 | 206 | 207 | def run(self): 208 | """ 209 | Creates or updates the system bootstrap package by packaging up the 210 | contents of the resource directory. 211 | """ 212 | self.disable_package() 213 | 214 | res_path = normpath(join(dirname(__file__), bootstrap_pkg)) 215 | package = join(sublime.installed_packages_path(), bootstrap_pkg + 216 | ".sublime-package") 217 | 218 | prefix = os.path.commonprefix([res_path, package]) 219 | log("Bootstraping {path} to {pkg}", 220 | path=res_path[len(prefix):], 221 | pkg=package[len(prefix):]) 222 | 223 | pkg_existed = os.path.isfile(package) 224 | success = self.create_bootstrap_package(package, res_path) 225 | 226 | self.enable_package(success) 227 | 228 | if not success: 229 | return log( 230 | """ 231 | An error was encountered while updating HyperHelp. 232 | 233 | Please check the console to see what went wrong. 234 | HyperHelp will not be available until the problem 235 | is resolved. 236 | """, error=True) 237 | 238 | if pkg_existed: 239 | set_initial_topic("HyperHelp", "latest_update") 240 | log( 241 | """ 242 | HyperHelp has been updated! 243 | 244 | In order to complete the update, restart Sublime 245 | Text. 246 | """, dialog=True) 247 | else: 248 | # TODO: A restart should not be required here, but there are 249 | # currently bootstrap issues. 250 | set_initial_topic("HyperHelp", "help_on_help.txt") 251 | log( 252 | """ 253 | HyperHelp has been installed! 254 | 255 | In order to complete the install, restart Sublime 256 | Text. 257 | """, dialog=True) 258 | 259 | 260 | ### --------------------------------------------------------------------------- -------------------------------------------------------------------------------- /all/hyperhelpcore/common.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | import os 4 | import codecs 5 | 6 | from .view import find_help_view 7 | 8 | 9 | ###---------------------------------------------------------------------------- 10 | 11 | 12 | def log(message, *args, status=False, dialog=False): 13 | """ 14 | Log the provided message to the console, optionally also sending it to the 15 | status bar and a dialog box. 16 | """ 17 | message = message % args 18 | for line in message.splitlines(): 19 | print("HyperHelp:", line) 20 | if status: 21 | sublime.status_message(message) 22 | if dialog: 23 | sublime.message_dialog(message) 24 | 25 | 26 | def hh_syntax(base_file): 27 | """ 28 | Return the syntax file associated with the given base syntax file name. 29 | This can return None if the syntax is not known. 30 | """ 31 | syn_list = sublime.find_resources(base_file) 32 | if len(syn_list) == 1: 33 | return syn_list[0] 34 | 35 | log("Unable to locate unique syntax '%s'", base_file) 36 | 37 | 38 | def hh_setting(key): 39 | """ 40 | Get a HyperHelp setting from a cached settings object. 41 | """ 42 | if not hasattr(hh_setting, "obj"): 43 | hh_setting.obj = sublime.load_settings("HyperHelp.sublime-settings") 44 | hh_setting.default = { 45 | "hyperhelp_date_format": "%x", 46 | "show_changelog": True, 47 | "focus_links_at_top": True, 48 | "bookmarks": [] 49 | } 50 | 51 | default = hh_setting.default.get(key, None) 52 | return hh_setting.obj.get(key, default) 53 | 54 | 55 | def hh_update_setting(key, value, save=False): 56 | """ 57 | Set the value of a HyperHelp setting to the value provided. Optionally, the 58 | call can also persist the change to disk. 59 | """ 60 | hh_setting.obj.set(key, value) 61 | if save: 62 | sublime.save_settings("HyperHelp.sublime-settings") 63 | 64 | 65 | def load_resource(res_name): 66 | """ 67 | Attempt to load and decode the UTF-8 encoded string with normalized line 68 | endings, returning the string on success or None on error. 69 | 70 | If no resource can be found with the resource specification provided, the 71 | call tries to load a file by this name from the packages folder instead. 72 | """ 73 | try: 74 | text = sublime.load_binary_resource(res_name).decode("utf-8") 75 | return text.replace('\r\n', '\n').replace('\r', '\n') 76 | 77 | except OSError: 78 | pass 79 | 80 | except UnicodeError: 81 | return log("Unable to decode '%s'; resource is not UTF-8" % res_name) 82 | 83 | try: 84 | spp = os.path.split(sublime.packages_path())[0] 85 | file_name = os.path.join(spp, res_name) 86 | 87 | with codecs.open(file_name, 'r', 'utf-8') as file: 88 | return file.read().replace('\r\n', '\n').replace('\r', '\n') 89 | 90 | except OSError: 91 | return log("Unable to load '%s'; resource not found" % res_name) 92 | 93 | except UnicodeError: 94 | return log("Unable to decode '%s'; resource is not UTF-8" % res_name) 95 | 96 | 97 | def current_help_package(view=None, window=None): 98 | """ 99 | Obtain the package that contains the currently displayed help file or None 100 | if help is not visible. 101 | 102 | Looks in the help view provided, or the help view in the passed in window, 103 | or the help view in the currently active window. 104 | """ 105 | view = view or find_help_view(window) 106 | return (view.settings().get("_hh_pkg") if view is not None else None) 107 | 108 | 109 | def current_help_file(view=None, window=None): 110 | """ 111 | Obtain the file that is currently being displayed in the help view or None 112 | if help is not visible. 113 | 114 | Looks in the help view provided, or the help view in the passed in window, 115 | or the help view in the currently active window. 116 | """ 117 | view = view or find_help_view(window) 118 | return (view.settings().get("_hh_file") if view is not None else None) 119 | 120 | 121 | def help_package_prompt(help_list, on_select, on_cancel=None): 122 | """ 123 | Given a list of loaded help indexes, prompt the user to select one of the 124 | packages. on_select is invoked with the name of the selected package, 125 | while on_cancel is invoked if the user cancels the selection. 126 | """ 127 | if not help_list: 128 | return log("No packages with help are installed", status=True) 129 | 130 | pkg_list = sorted([key for key in help_list]) 131 | captions = [[help_list[key].package, 132 | help_list[key].description] 133 | for key in pkg_list] 134 | 135 | def pick_package(index): 136 | package = None if index < 0 else captions[index][0] 137 | 138 | if index >= 0: 139 | return on_select(package) if on_select is not None else None 140 | 141 | return on_cancel() if on_cancel is not None else None 142 | 143 | sublime.active_window().show_quick_panel( 144 | captions, 145 | on_select=lambda index: pick_package(index)) 146 | 147 | 148 | ###---------------------------------------------------------------------------- 149 | -------------------------------------------------------------------------------- /all/hyperhelpcore/core.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | import os 4 | import re 5 | import time 6 | import webbrowser 7 | 8 | from urllib.parse import urlparse 9 | 10 | from .common import log, hh_syntax, hh_setting 11 | from .view import find_help_view, update_help_view 12 | 13 | from .help_index import _load_help_index, _scan_help_packages 14 | from .help import _resource_for_help 15 | from .help import _load_help_file, _display_help_file, _reload_help_file 16 | from .help import HistoryData, _update_help_history 17 | from .data import HeaderData 18 | 19 | 20 | ###---------------------------------------------------------------------------- 21 | 22 | 23 | _header_prefix_re = re.compile(r'^%hyperhelp(\b|$)') 24 | _header_keypair_re = re.compile(r'\b([a-z]+)\b="([^"]*)"') 25 | 26 | 27 | ###---------------------------------------------------------------------------- 28 | 29 | 30 | def load_help_index(index_resource): 31 | """ 32 | Given an index resource that points to a hyperhelp.json file, load the help 33 | index and return back a normalized version. Returns None on error. 34 | """ 35 | return _load_help_index(index_resource) 36 | 37 | 38 | def load_help_file(pkg_info, help_file): 39 | """ 40 | Load the contents of a help file contained in the provided help package. 41 | The help file should be relative to the document root of the package. 42 | 43 | Returns None if the help file cannot be loaded. 44 | """ 45 | return _load_help_file(pkg_info, help_file) 46 | 47 | 48 | def help_index_list(reload=False, package=None): 49 | """ 50 | Obtain or reload the help index information for all packages. This demand 51 | loads the indexes on first access and can optionally reload all package 52 | indexes or only a single one, as desired. 53 | """ 54 | initial_load = False 55 | if not hasattr(help_index_list, "index"): 56 | initial_load = True 57 | help_index_list.index = _scan_help_packages() 58 | 59 | if reload and not initial_load: 60 | help_index_list.index = reload_help_index(help_index_list.index, package) 61 | 62 | return help_index_list.index 63 | 64 | 65 | def load_indexes_from_packages(packages): 66 | """ 67 | Given a physical package name or list of names, load all help indexes that 68 | appear in that package and add them to the list of known help indexes. This 69 | implicitly loads all help indexes if they have never been loaded before. 70 | The new list of known help indexes is returned. 71 | """ 72 | if not packages: 73 | return log("Cannot demand load package indexes; no packages provided") 74 | 75 | return _scan_help_packages(help_index_list(), packages) 76 | 77 | 78 | def unload_help_indexes_from_packges(packages): 79 | """ 80 | Given a physical package name or list of names, unload any help indexes 81 | that are contained within that package. This implicitlly loads all help 82 | indexes if they have never been loaded before, and messages are printed to 83 | the console for each unloaded package. The new list of known help indexes 84 | is returned. 85 | """ 86 | if not packages: 87 | return log("Cannot demand unload package indexes; no packages provided") 88 | 89 | if not isinstance(packages, list): 90 | packages = [packages] 91 | 92 | indexes = help_index_list() 93 | for pkg_info in list(indexes.values()): 94 | package = os.path.split(pkg_info.index_file)[0].split("/")[1] 95 | if package in packages: 96 | del indexes[pkg_info.package] 97 | log("Unloading help index for package '%s'", pkg_info.package) 98 | 99 | return indexes 100 | 101 | 102 | def reload_help_index(help_list, package): 103 | """ 104 | Reload the help index for the provided package from within the given help 105 | list, updating the help list to record the new data. 106 | 107 | If no package name is provided, the help list provided is ignored and all 108 | help indexes are reloaded and returned in a new help list. 109 | 110 | Attempts to reload a package that is not in the given help list has no 111 | effect. 112 | """ 113 | if package is None: 114 | log("Recanning all help index files") 115 | return _scan_help_packages() 116 | 117 | pkg_info = help_list.get(package, None) 118 | if pkg_info is None: 119 | log("Package '%s' was not previously loaded; cannot reload", package) 120 | else: 121 | log("Reloading help index for package '%s'", package) 122 | 123 | result = _load_help_index(pkg_info.index_file) 124 | if result is not None: 125 | help_list[result.package] = result 126 | 127 | # If the package changed from what it used to be, remove the old 128 | # one from the list of packages. 129 | if result.package != package: 130 | log("Warning: package name in index changed (%s became %s)", 131 | package, result.package) 132 | del help_list[package] 133 | 134 | return help_list 135 | 136 | 137 | def help_file_resource(pkg_info, help_file): 138 | """ 139 | Get the resource name that references the help file in the given help 140 | package. The help file should be relative to the document root of the 141 | package. 142 | """ 143 | return _resource_for_help(pkg_info, help_file) 144 | 145 | 146 | def display_help_file(pkg_info, help_file): 147 | """ 148 | Load and display the help file contained in the provided help package. The 149 | heop file should be relative to the document root of the package. 150 | 151 | The help will be displayed in the help view of the current window, which 152 | will be created if it does not exist. 153 | 154 | Does nothing if the help view is already displaying this file. 155 | 156 | Returns None if the help file could not be found/loaded or the help view 157 | on success. 158 | """ 159 | return _display_help_file(pkg_info, help_file) 160 | 161 | 162 | def reload_help_file(help_list, help_view): 163 | """ 164 | Reload the help file currently being displayed in the given view to pick 165 | up changes made since it was displayed. The information on the package and 166 | help file should be contained in the provided help list. 167 | 168 | Returns True if the file was reloaded successfully or False if not. 169 | """ 170 | return _reload_help_file(help_list, help_view) 171 | 172 | 173 | def lookup_help_topic(pkg_info, topic): 174 | """ 175 | Given a help data tuple or the name of a package, look up the topic and 176 | return the topic structure if needed. 177 | 178 | This does all manipulations on the incoming topic, such as case folding and 179 | space replacement. 180 | 181 | Returns the topic structure or None. 182 | """ 183 | if isinstance(pkg_info, str): 184 | pkg_info = help_index_list().get(pkg_info, None) 185 | 186 | if pkg_info is not None: 187 | topic = " ".join(topic.casefold().split()) 188 | alias = pkg_info.help_aliases.get(topic, None) 189 | return pkg_info.help_topics.get(alias or topic, None) 190 | 191 | return None 192 | 193 | 194 | def is_topic_normal(pkg_info, topic_dict): 195 | """ 196 | Given a topic dictionary such as returned by lookup_help_topic(), determine 197 | if the topic represents a "normal" topic or not. 198 | """ 199 | return (not is_topic_url(pkg_info, topic_dict) and 200 | not is_topic_file(pkg_info, topic_dict)) 201 | 202 | 203 | def is_topic_url(pkg_info, topic_dict): 204 | """ 205 | Given a topic dictionary such as returned by lookup_help_topic(), determine 206 | if the topic represents a topic that will open a URL or not. 207 | """ 208 | return topic_dict["file"] in pkg_info.urls 209 | 210 | 211 | def is_topic_file(pkg_info, topic_dict): 212 | """ 213 | Given a topic dictionary such as returned by lookup_help_topic(), determine 214 | if the topic represents a topic that will open a URL or not. 215 | """ 216 | return topic_dict["file"] in pkg_info.package_files 217 | 218 | 219 | def is_topic_url_valid(pkg_info, topic_dict): 220 | """ 221 | Given a topic dictionary such as returned by lookup_help_topic() that 222 | represents a URL, return an indication as to whether the URL is valid or 223 | not. 224 | 225 | None is returned if a topic does not represent a URL. 226 | """ 227 | if is_topic_url(pkg_info, topic_dict): 228 | try: 229 | result = urlparse(topic_dict["file"]) 230 | return result.scheme and result.netloc 231 | except: 232 | return False 233 | 234 | return None 235 | 236 | 237 | def is_topic_file_valid(pkg_info, topic_dict): 238 | """ 239 | Given a topic dictionary such as returned by lookup_help_topic() that 240 | represents a package file, return an indication as to whether that file 241 | exists or not as a package resource. 242 | 243 | None is returned if a topic does not represent a package file. 244 | """ 245 | if is_topic_file(pkg_info, topic_dict): 246 | file = topic_dict["file"] 247 | base = os.path.split(file)[1] 248 | if file not in sublime.find_resources(base): 249 | return False 250 | 251 | return True 252 | 253 | return None 254 | 255 | 256 | def show_help_topic(package, topic, history): 257 | """ 258 | Attempt to display the help for the provided topic in the given package 259 | (both strings) as appropriate. This will transparently create a new help 260 | view, open the underlying package file or open the URL as needed. 261 | 262 | If history is True, the history for the help view is updated after a 263 | successful help navigation to a help file; otherwise the history is left 264 | untouched. history is implicitly True when this has to create a help view 265 | for the first time so that history is properly initialized. 266 | 267 | The return value is None on error or a string that represents the kind of 268 | topic that was navigated to ("file", "pkg_file" or "url") 269 | """ 270 | pkg_info = help_index_list().get(package, None) 271 | if pkg_info is None: 272 | return None 273 | 274 | topic_data = lookup_help_topic(pkg_info, topic) 275 | if topic_data is None: 276 | log("Unknown help topic '%s'", topic, status=True) 277 | return None 278 | 279 | help_file = topic_data["file"] 280 | 281 | if help_file in pkg_info.urls: 282 | webbrowser.open_new_tab(help_file) 283 | return "url" 284 | 285 | if help_file in pkg_info.package_files: 286 | help_file = help_file.replace("Packages/", "${packages}/") 287 | window = sublime.active_window() 288 | window.run_command("open_file", {"file": help_file}) 289 | return "pkg_file" 290 | 291 | # Update the current history entry if there is a help view. 292 | if history: 293 | _update_help_history(find_help_view()) 294 | 295 | existing_view = True if find_help_view() is not None else False 296 | help_view = display_help_file(pkg_info, help_file) 297 | if help_view is None: 298 | log("Unable to load help file '%s'", help_file, status=True) 299 | return None 300 | 301 | found = False 302 | anchor_dict = help_view.settings().get("_hh_nav", []) 303 | idx = anchor_dict.get(topic_data["topic"], -1) 304 | if idx >= 0: 305 | anchor_pos = help_view.get_regions("_hh_anchors")[idx] 306 | help_view.run_command("hyperhelp_focus", 307 | { 308 | "position": [anchor_pos.b, anchor_pos.a], 309 | "at_top": hh_setting("focus_links_at_top"), 310 | "at_center": not hh_setting("focus_links_at_top") 311 | }) 312 | found = True 313 | 314 | # Update history to track the new file, but only if the help view already 315 | # existed; otherwise its creation set up the default history already. 316 | if history and existing_view: 317 | _update_help_history(help_view, append=True) 318 | 319 | if not found: 320 | log("Unable to find topic '%s' in help file '%s'", topic, help_file, 321 | status=True) 322 | return "file" 323 | 324 | 325 | def navigate_help_history(help_view, prev): 326 | """ 327 | Navigate through the help history for the provided help view, either going 328 | forward or backward as appropriate. This will update the current history 329 | entry before displaying the historic topic. 330 | 331 | If no help view is provided, the current help view is used instead, if any. 332 | 333 | Returns a boolean to tell you if the history position changed or not. 334 | """ 335 | help_view = help_view or find_help_view() 336 | if help_view is None: 337 | return False 338 | 339 | hist_pos = help_view.settings().get("_hh_hist_pos") 340 | hist_info = help_view.settings().get("_hh_hist") 341 | 342 | if (prev and hist_pos == 0) or (not prev and hist_pos == len(hist_info) - 1): 343 | log("Cannot navigate %s through history; already at the end", 344 | "backwards" if prev else "forwards", status=True) 345 | return False 346 | 347 | hist_pos = (hist_pos - 1) if prev else (hist_pos + 1) 348 | entry = HistoryData._make(hist_info[hist_pos]) 349 | 350 | # Update the current history entry's viewport and caret location 351 | _update_help_history(help_view) 352 | 353 | # Navigate to the destination file in the history; need to manually set 354 | # the cursor position 355 | if show_help_topic(entry.package, entry.file, history=False) is not None: 356 | help_view.sel().clear() 357 | help_view.sel().add(sublime.Region(entry.caret[0], entry.caret[1])) 358 | help_view.set_viewport_position(entry.viewport, False) 359 | 360 | help_view.settings().set("_hh_hist_pos", hist_pos) 361 | return True 362 | 363 | return False 364 | 365 | 366 | def jump_help_history(help_view, new_pos): 367 | """ 368 | Jump to a specific point in the help history for the provided help view. 369 | 370 | If no help view is provided, the current help view is used instead, if any. 371 | 372 | Returns a boolean to tell you if the history position changed or not; it 373 | may not change if the history index is not valid, for example. 374 | """ 375 | help_view = help_view or find_help_view() 376 | if help_view is None: 377 | return False 378 | 379 | hist_pos = help_view.settings().get("_hh_hist_pos") 380 | hist_info = help_view.settings().get("_hh_hist") 381 | 382 | if new_pos < 0 or new_pos >= len(hist_info) or new_pos == hist_pos: 383 | return False 384 | 385 | entry = HistoryData._make(hist_info[new_pos]) 386 | 387 | # Update the current history entry's viewport and caret location 388 | _update_help_history(help_view) 389 | 390 | # Navigate to the destination file in the history; need to manually set 391 | # the cursor position 392 | if show_help_topic(entry.package, entry.file, history=False) is not None: 393 | help_view.sel().clear() 394 | help_view.sel().add(sublime.Region(entry.caret[0], entry.caret[1])) 395 | help_view.set_viewport_position(entry.viewport, False) 396 | 397 | help_view.settings().set("_hh_hist_pos", new_pos) 398 | return True 399 | 400 | 401 | def clear_help_history(help_view): 402 | """ 403 | Clear the help history for the provided help file, leaving only the current 404 | entry in the list as the sole history entry. 405 | 406 | If no help view is provided, the current help view is used instead, if any. 407 | 408 | Returns a boolean to tell you if history changed or not. 409 | """ 410 | help_view = help_view or find_help_view() 411 | if help_view is None: 412 | return False 413 | 414 | hist_pos = help_view.settings().get("_hh_hist_pos") 415 | hist_info = help_view.settings().get("_hh_hist") 416 | 417 | entry = HistoryData._make(hist_info[hist_pos]) 418 | 419 | help_view.settings().set("_hh_hist_pos", 0) 420 | help_view.settings().set("_hh_hist", [entry]) 421 | 422 | return True 423 | 424 | 425 | def parse_help_header(help_file, header_line): 426 | """ 427 | Given the first line of a help file, check to see if it looks like a help 428 | source file, and if so parse the header and return the parsed values back. 429 | """ 430 | if not _header_prefix_re.match(header_line): 431 | return None 432 | 433 | title = "No Title Provided" 434 | date = 0.0 435 | 436 | for match in re.findall(_header_keypair_re, header_line): 437 | if match[0] == "title": 438 | title = match[1] 439 | elif match[0] == "date": 440 | try: 441 | date = time.mktime(time.strptime(match[1], "%Y-%m-%d")) 442 | except Exception as e: 443 | print(e) 444 | date = 0.0 445 | log("Ignoring invalid file date '%s' in '%s'", 446 | match[1], help_file) 447 | else: 448 | log("Ignoring unknown header key '%s' in '%s'", 449 | match[1], help_file) 450 | 451 | return HeaderData(help_file, title, date) 452 | 453 | 454 | def parse_anchor_body(anchor_body): 455 | """ 456 | Given the body of an anchor, parse it to determine what topic ID it's 457 | anchored to and what text the anchor uses in the source help file. 458 | 459 | This always returns a 2-tuple, though based on the anchor body in the file 460 | it may end up thinking that the topic ID and the text are identical. 461 | """ 462 | c_pos = anchor_body.find(':') 463 | if c_pos >= 0: 464 | id_val = anchor_body[:c_pos] 465 | anchor_body = anchor_body[c_pos+1:] 466 | 467 | id_val = id_val or anchor_body 468 | else: 469 | id_val = anchor_body 470 | 471 | return (id_val.casefold().rstrip(), anchor_body.strip()) 472 | 473 | 474 | def parse_link_body(link_body): 475 | """ 476 | Given the body of a link, parse it to determine what package and topic ID 477 | the link will navigate to as well as what the visual link text should be. 478 | 479 | This always returns a 3-tuple, though the value of the link text will be 480 | None if the parse failed. It's possible for the package to be None, in 481 | which case you can infer what the default package should be. 482 | """ 483 | parts = link_body.split(':') 484 | if len(parts) == 1: 485 | return None, link_body.rstrip(), link_body.rstrip() 486 | 487 | if len(parts) >= 3: 488 | pkg = parts[0] 489 | topic = parts[1] 490 | text = ":".join(parts[2:]) 491 | else: 492 | return (None, None, None) 493 | 494 | pkg = pkg or None 495 | topic = topic or text 496 | return (pkg, topic.strip(), text.strip()) 497 | 498 | 499 | ###---------------------------------------------------------------------------- 500 | -------------------------------------------------------------------------------- /all/hyperhelpcore/data.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict, namedtuple 2 | 3 | 4 | ###---------------------------------------------------------------------------- 5 | 6 | 7 | # A representation of the data that was contained in a hyperhelp help document 8 | # header. This is used to construct a more human readable header. 9 | HeaderData = namedtuple("HeaderData", [ 10 | "file", "title", "date" 11 | ]) 12 | 13 | # A representation of a history node that tracks what help topics have been 14 | # viewed and where the viewport was left. 15 | HistoryData = namedtuple("HistoryData", [ 16 | "package", "file", "viewport", "caret" 17 | ]) 18 | 19 | # A representation of all of the help available for a particular package. 20 | # 21 | # This tells us all of the information we need about the help for a package at 22 | # load time so that we don't need to look it up later. 23 | HelpData = namedtuple("HelpData", [ 24 | "package", "index_file", "description", "doc_root", "help_topics", 25 | "help_aliases", "help_files", "package_files", "urls", "help_toc" 26 | ]) 27 | 28 | 29 | ###---------------------------------------------------------------------------- 30 | -------------------------------------------------------------------------------- /all/hyperhelpcore/help.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | import re 5 | import time 6 | 7 | from .view import find_help_view, update_help_view 8 | from .common import log, hh_syntax, current_help_file, current_help_package 9 | from .common import load_resource 10 | from .data import HistoryData 11 | 12 | 13 | ###---------------------------------------------------------------------------- 14 | 15 | 16 | def _resource_for_help(pkg_info, help_file): 17 | """ 18 | Get the resource name that references the help file in the given help 19 | package. The help file should be relative to the document root of the 20 | package. 21 | """ 22 | return "Packages/%s/%s" % (pkg_info.doc_root, help_file) 23 | 24 | 25 | def _load_help_file(pkg_info, help_file): 26 | """ 27 | Load the contents of a help file contained in the provided help package. 28 | The help file should be relative to the document root of the package. 29 | 30 | Returns None if the help file cannot be loaded. 31 | """ 32 | return load_resource(_resource_for_help(pkg_info, help_file)) 33 | 34 | 35 | def _update_help_history(view, append=False, selection=None): 36 | """ 37 | Update the help history for the provided view by either updating the 38 | contents of the current history entry or adding a new entry to the end of 39 | the history list. 40 | 41 | When appending a new history entry, any history after the current position 42 | in the list is truncated away. 43 | 44 | The selection used to capture the cursor is the first selection in the 45 | view unless a selection region is provided. 46 | """ 47 | if view is None: 48 | return 49 | 50 | selection = view.sel()[0] if selection is None else selection 51 | settings = view.settings() 52 | 53 | hist_pos = settings.get("_hh_hist_pos", 0) 54 | hist_info = settings.get("_hh_hist", []) 55 | 56 | if append: 57 | # Truncate all history after this point; new timeline branches out. 58 | if hist_pos != len(hist_info) - 1: 59 | hist_info = hist_info[:hist_pos + 1] 60 | 61 | # Should probably truncate in the other direction to keep history in 62 | # check. 63 | hist_pos += 1 64 | 65 | history = HistoryData(current_help_package(view), 66 | current_help_file(view), 67 | view.viewport_position(), 68 | (selection.a, selection.b)) 69 | 70 | if hist_pos >= len(hist_info): 71 | hist_info.append(history) 72 | else: 73 | hist_info[hist_pos] = history 74 | 75 | settings.set("_hh_hist_pos", hist_pos) 76 | settings.set("_hh_hist", hist_info) 77 | 78 | 79 | def _enable_post_processing(help_view, enable): 80 | """ 81 | Enable or disable post processing on the provided help view, which controls 82 | whether or not the file can be edited and whether various post-processing 83 | commands are enabled. 84 | """ 85 | help_view.set_read_only(not enable); 86 | help_view.settings().set("_hh_post_processing", enable) 87 | 88 | 89 | def _display_help_file(pkg_info, help_file): 90 | """ 91 | Load and display the help file contained in the provided help package. The 92 | help file should be relative to the document root of the package. 93 | 94 | The help will be displayed in the help view of the current window, which 95 | will be created if it does not exist. 96 | 97 | Does nothing if the help view is already displaying this file. 98 | 99 | Returns None if the help file could not be found/loaded or the help view 100 | on success. 101 | """ 102 | view = find_help_view() 103 | window = view.window() if view is not None else sublime.active_window() 104 | 105 | if view is not None: 106 | window.focus_view(view) 107 | 108 | current_pkg = current_help_package(view) 109 | current_file = current_help_file(view) 110 | 111 | if help_file == current_file and pkg_info.package == current_pkg: 112 | return view 113 | 114 | help_text = _load_help_file(pkg_info, help_file) 115 | if help_text is not None: 116 | view = update_help_view(help_text, pkg_info.package, help_file, 117 | hh_syntax("HyperHelp-Help.sublime-syntax")) 118 | 119 | # if there is no history yet, add one selection the start of the file. 120 | if not view.settings().has("_hh_hist_pos"): 121 | _update_help_history(view, selection=sublime.Region(0)) 122 | 123 | _enable_post_processing(view, True) 124 | view.run_command("hyperhelp_internal_process_header") 125 | view.run_command("hyperhelp_internal_process_comments") 126 | view.run_command("hyperhelp_internal_process_anchors") 127 | view.run_command("hyperhelp_internal_process_links") 128 | _enable_post_processing(view, False) 129 | 130 | return view 131 | 132 | return log("Unable to find help file '%s'", help_file, status=True) 133 | 134 | 135 | def _reload_help_file(help_list, help_view): 136 | """ 137 | Reload the help file currently being displayed in the given view to pick 138 | up changes made since it was displayed. The information on the package and 139 | help file should be contained in the provided help list. 140 | 141 | Returns True if the file was reloaded successfully or False if not. 142 | """ 143 | if help_view is None: 144 | log("No help topic is visible; cannot reload") 145 | return False 146 | 147 | package = current_help_package(help_view) 148 | file = current_help_file(help_view) 149 | pkg_info = help_list.get(package, None) 150 | 151 | if pkg_info is not None and file is not None: 152 | # Remove the file setting so the view will reload; put it back if the 153 | # reload fails so we can still track what the file used to be. 154 | settings = help_view.settings() 155 | settings.set("_hh_file", "") 156 | if _display_help_file(pkg_info, file) is None: 157 | settings.set("_hh_file", file) 158 | return false 159 | 160 | return True 161 | 162 | log("Unable to reload the current help topic") 163 | return False 164 | 165 | 166 | def _get_link_topic(help_view, link_region): 167 | """ 168 | Given a help view and information about a link, return back an object that 169 | provides the package and topic ID that the link references. 170 | 171 | region can be a Region object, in which case the link data is looked up by 172 | region. It can also be an integer, in which case it represents the index of 173 | that link, with the first link in the file being numbered as 0. 174 | 175 | None is returned when the information cannot be found. 176 | """ 177 | topic_data = None 178 | topics = help_view.settings().get("_hh_links") 179 | 180 | try: 181 | # If the incoming region is an index, our job is easy. 182 | if isinstance(link_region, int): 183 | return topics[link_region] 184 | 185 | for idx, region in enumerate(help_view.get_regions("_hh_links")): 186 | if region == link_region: 187 | return topics[idx] 188 | except: 189 | pass 190 | 191 | return None 192 | 193 | 194 | ###---------------------------------------------------------------------------- 195 | -------------------------------------------------------------------------------- /all/hyperhelpcore/help_index.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | # Inside packages, paths are always posix regardless of the platform in use. 5 | import posixpath as path 6 | from collections import OrderedDict 7 | import os 8 | import re 9 | import codecs 10 | 11 | from .common import log, load_resource 12 | from .data import HelpData 13 | from .index_validator import validate_index 14 | 15 | 16 | ###---------------------------------------------------------------------------- 17 | 18 | 19 | _url_prefix_re = re.compile(r'^https?://') 20 | 21 | 22 | ###---------------------------------------------------------------------------- 23 | 24 | 25 | def _import_topics(package, topics, aliases, help_topic_dict, caption_tpl, 26 | external=False): 27 | """ 28 | Parse out a dictionary of help topics from the help index and store all 29 | topics into the topic dictionary passed in. During the parsing, the 30 | contents are validated. 31 | 32 | When def_captions is True, topics that don't have a caption use the document 33 | title as the caption by default. 34 | """ 35 | def _make_caption(topic, source): 36 | return caption_tpl.format(topic=topic, source=source, package=package) 37 | 38 | for help_source in help_topic_dict: 39 | topic_list = help_topic_dict[help_source] 40 | 41 | # Don't include topics from invalid externals. 42 | if (external 43 | and not _url_prefix_re.match(help_source) 44 | and not help_source.startswith("Packages/")): 45 | log("Discarding invalid external '%s' in %s", 46 | help_source, package) 47 | continue 48 | 49 | default_caption = topic_list[0] if external else None 50 | 51 | # Skip the first entry since it's the title of the help source 52 | for topic_entry in topic_list[1:]: 53 | name = topic_entry.get("topic") 54 | caption = topic_entry.get("caption", None) 55 | alias_list = topic_entry.get("aliases", []) 56 | if caption is None: 57 | caption = default_caption or _make_caption(name, help_source) 58 | 59 | # Normalize whitespace that appears in topics so that only a single 60 | # whitespace character appears wherever there might be two or more 61 | # in a row. 62 | # TODO: This could be a lot cleaner 63 | name = " ".join(name.casefold().split()) 64 | if name in topics: 65 | log("Skipping duplicate topic '%s' in %s:%s", 66 | name, package, help_source) 67 | elif name in aliases: 68 | log("Topic %s is already an alias in %s:%s", 69 | name, package, help_source) 70 | else: 71 | topics[name] = { 72 | "topic": name, 73 | "caption": caption, 74 | "file": help_source 75 | } 76 | 77 | for new_name in [" ".join(name.casefold().split()) for name in alias_list]: 78 | if new_name in topics: 79 | log("Alias '%s' is already a topic in %s:%s", 80 | new_name, package, help_source) 81 | elif new_name in aliases: 82 | log("Skipping duplicate alias '%s' in %s:%s", 83 | new_name, package, help_source) 84 | else: 85 | aliases[new_name] = name 86 | 87 | # All help sources should be in the topic list so you can jump to a 88 | # file by name. The help file name is the default. 89 | name = help_source.casefold() 90 | if name not in topics: 91 | topics[name] = { 92 | "topic": name, 93 | "caption": topic_list[0], 94 | "file": help_source 95 | } 96 | 97 | return topics 98 | 99 | 100 | def _merge_externals(package, externals, topics, package_files, urls): 101 | """ 102 | Merge the externals into the topic list provided. This ensures that there 103 | are no duplicate topics during the merge (discarding the external) while 104 | also splitting the externals into package file specifications and urls. 105 | """ 106 | for topic, entry in externals.items(): 107 | if topic in topics: 108 | log("Discarding duplicate external topic '%s' in %s:%s", 109 | topic, package, entry["file"]) 110 | continue 111 | 112 | file = entry["file"] 113 | file_list = urls if _url_prefix_re.match(file) else package_files 114 | if file not in file_list: 115 | file_list.append(file) 116 | 117 | topics[topic] = entry 118 | 119 | 120 | def _get_file_metadata(help_topic_dict): 121 | """ 122 | Parse a dictionary of help topics from the help index and return back an 123 | ordered dictionary associating help file names with their titles. 124 | 125 | Assumes the help dictionary has already been validated. 126 | """ 127 | retVal = OrderedDict() 128 | for file in sorted(help_topic_dict.keys()): 129 | retVal[file] = help_topic_dict[file][0] 130 | 131 | return retVal 132 | 133 | 134 | def _get_toc_metadata(help_toc_list, topics, aliases, package): 135 | """ 136 | Given the table of contents key from the help index and the complete list of 137 | known topics, return back a table of contents. This will extrapolate a list 138 | even if the incoming list is empty or non-existant. 139 | """ 140 | if not help_toc_list: 141 | return [topics.get(topic) for topic in sorted(topics.keys())] 142 | 143 | def lookup_topic_entry(entry): 144 | """ 145 | Expand a toc entry from the index into a full topic object. 146 | """ 147 | if isinstance(entry, str): 148 | # A string looks up a topic directly; this goes through the alias 149 | # list if it has to. 150 | topic = aliases.get(entry, entry) 151 | return topic, topics.get(topic, None) 152 | 153 | # Use the caption for the topic being referenced if not overridden. 154 | topic = " ".join(entry["topic"].casefold().split()) 155 | alias = aliases.get(topic, None) 156 | base_obj = topics.get(alias or topic, None) 157 | if base_obj is None: 158 | return topic, None 159 | 160 | entry["file"] = base_obj["file"] 161 | entry["caption"] = entry.get("caption", base_obj["caption"]) 162 | 163 | return topic, entry 164 | 165 | def expand_topic_list(item_list): 166 | """ 167 | Expand an array of help topics that make up part of a table of contents 168 | into an array of full topic objects recursively. 169 | """ 170 | retVal = list() 171 | 172 | for item in item_list: 173 | topic, info = lookup_topic_entry(item) 174 | if info is None: 175 | log("TOC for '%s' is missing topic '%s'; skipping", package, topic) 176 | continue 177 | 178 | child_topics = info.get("children", None) 179 | if child_topics: 180 | info["children"] = expand_topic_list(child_topics) 181 | 182 | retVal.append(info) 183 | 184 | return retVal 185 | 186 | return expand_topic_list(help_toc_list) 187 | 188 | 189 | def _load_help_index(index_res): 190 | """ 191 | Given a package name and the resource filename of the hyperhelp json file, 192 | load the help index and return it. The return value is None on failure or 193 | HelpData on success. 194 | """ 195 | if not index_res.casefold().startswith("packages/"): 196 | return log("Index source is not in a package: %s", index_res) 197 | 198 | content = load_resource(index_res) 199 | 200 | if content is None: 201 | return log("Unable to load index information from '%s'", index_res) 202 | 203 | raw_dict = validate_index(content, index_res) 204 | if raw_dict is None: 205 | return None 206 | 207 | containing_pkg = path.split(index_res)[0].split("/")[1] 208 | 209 | # Top level index keys 210 | package = raw_dict.pop("package", None) 211 | description = raw_dict.pop("description", "Help for %s" % package) 212 | doc_root = raw_dict.pop("doc_root", None) 213 | help_files = raw_dict.pop("help_files", dict()) 214 | help_toc = raw_dict.pop("help_contents", None) 215 | externals = raw_dict.pop("externals", None) 216 | caption_tpl = raw_dict.pop("default_caption", 217 | "Topic {topic} in help source {source}") 218 | 219 | # Warn if the dictionary has too many keys 220 | for key in raw_dict.keys(): 221 | log("Ignoring unknown key '%s' in index file %s", key, package) 222 | 223 | # If there is no document root, set it from the index resource; otherwise 224 | # ensure that it's normalized to appear in the appropriate package. 225 | if not doc_root: 226 | doc_root = path.split(index_res[len("Packages/"):])[0] 227 | else: 228 | doc_root = path.normpath("%s/%s" % (containing_pkg, doc_root)) 229 | 230 | # Gather the unique list of topics. 231 | topic_list = dict() 232 | alias_list = dict() 233 | _import_topics(package, topic_list, alias_list, help_files, caption_tpl) 234 | 235 | externals_list = dict() 236 | package_files = list() 237 | urls = list() 238 | if externals is not None: 239 | _import_topics(package, externals_list, alias_list, externals, caption_tpl, external=True) 240 | _merge_externals(package, externals_list, topic_list, package_files, urls) 241 | 242 | # Everything has succeeded. 243 | return HelpData(package, index_res, description, doc_root, 244 | topic_list, alias_list, 245 | _get_file_metadata(help_files), package_files, urls, 246 | _get_toc_metadata(help_toc, topic_list, alias_list, package)) 247 | 248 | 249 | def _is_canonical_pkg_idx(pkg_idx): 250 | """ 251 | Given a loaded package index, return a determination as to whether it is 252 | the canonical help for that package or not, which is determined by it being 253 | present in its own package. 254 | """ 255 | containing_pkg = path.split(pkg_idx.index_file)[0].split("/")[1] 256 | return containing_pkg == pkg_idx.package 257 | 258 | 259 | def _resolve_index_conflict(existing_idx, new_idx): 260 | """ 261 | Takes two loaded index files that are for the same package and selects one 262 | to use, which is returned back. The one selected is determined based on the 263 | load order of the indexes and user settings. 264 | 265 | The return may be None to indicate that neither package should be used. 266 | """ 267 | existing_canon = _is_canonical_pkg_idx(existing_idx) 268 | new_canon = _is_canonical_pkg_idx(new_idx) 269 | 270 | log("Warning: Multiple indexes found for package '%s'", new_idx.package) 271 | log(" %s", existing_idx.index_file) 272 | log(" %s", new_idx.index_file) 273 | 274 | # When only one of the two packages is canonical, that is the one to use. 275 | if existing_canon != new_canon: 276 | if existing_canon: 277 | log("Warning: Ignoring non-canonical index (%s)", new_idx.index_file) 278 | return existing_idx 279 | 280 | log("Warning: Using canonical index (%s)", new_idx.index_file) 281 | return new_idx 282 | 283 | # The canon of both indexes is identical. If neither is canon, always use 284 | # the most recently loaded one (in package load order), just as result 285 | # Sublime resources would. 286 | if existing_canon == False: 287 | log("Warning: Selecting new index (%s)", new_idx.index_file) 288 | return new_idx 289 | 290 | # Both are canon, which is not good. This is an error, and we will return 291 | # None to signal that. 292 | log("Error: Multiple indexes for '%s' are canonical", new_idx.package) 293 | return None 294 | 295 | 296 | def _filter_index(resources, name_filter): 297 | """ 298 | Filter a list of package index resources so that only indexes contained in 299 | the package(s) named are returned. When the filter is empty, the entire 300 | resource list is returned untouched. The filter can be a single package 301 | name or a list of packages. 302 | """ 303 | if not name_filter: 304 | return resources 305 | 306 | if not isinstance(name_filter, list): 307 | name_filter = [name_filter] 308 | 309 | retVal = [] 310 | for index_file in resources: 311 | path_parts = path.split(index_file)[0].split("/") 312 | if path_parts[0] == "Packages" and path_parts[1] in name_filter: 313 | retVal.append(index_file) 314 | 315 | return retVal 316 | 317 | 318 | def _scan_help_packages(help_list=None, name_filter=None): 319 | """ 320 | Scan for packages with a help index and load them. If a help list is 321 | provided, only the help for packages not already in the list will be 322 | loaded. 323 | """ 324 | help_list = dict() if help_list is None else help_list 325 | 326 | # Find all of the index file resources and the list of those that are 327 | # currently loaded in the provided help list (if any). 328 | indexes = _filter_index(sublime.find_resources("hyperhelp.json"), name_filter) 329 | loaded = [help_list[pkg].index_file for pkg in help_list.keys()] 330 | 331 | # The list of packages that are considered broken because they have at 332 | # least two canonical help indexes dedicated to them. 333 | broken = [] 334 | 335 | # Load all of the indexes that aren't already loaded. 336 | for index_file in [idx for idx in indexes if idx not in loaded]: 337 | new_idx = _load_help_index(index_file) 338 | if new_idx is not None: 339 | # If this package index is broken, ignore it completely 340 | if new_idx.package in broken: 341 | log("Error: Ignoring index for '%s' (%s)", new_idx.package, 342 | new_idx.index_file) 343 | continue 344 | 345 | # If an index already exists for this package, we need to determine 346 | # which one to use. 347 | existing_idx = help_list.get(new_idx.package, None) 348 | if existing_idx is not None: 349 | # Returns None if both are canonical index files. 350 | new_idx = _resolve_index_conflict(existing_idx, new_idx) 351 | if new_idx is None: 352 | del help_list[existing_idx.package] 353 | broken.append(existing_idx.package) 354 | continue 355 | 356 | help_list[new_idx.package] = new_idx 357 | 358 | return help_list 359 | 360 | 361 | ###---------------------------------------------------------------------------- 362 | -------------------------------------------------------------------------------- /all/hyperhelpcore/index_validator.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | from .validictory import validate 4 | from .validictory import SchemaError, ValidationError 5 | 6 | from .common import log 7 | 8 | 9 | ###---------------------------------------------------------------------------- 10 | 11 | 12 | # The schema to validate that a help file entry in the "help_files" key of the 13 | # help index is properly formattted. 14 | _help_file_schema = { 15 | "type": "object", 16 | "required": True, 17 | 18 | # Any key is allowed, but all must have values which are arrays. The first 19 | # item in the array must be a string and the remainder must be topic 20 | # dictionaries. 21 | "additionalProperties": { 22 | "type": "array", 23 | "items": [ { "type": "string", "required": True } ], 24 | 25 | "additionalItems": { 26 | "type": "object", 27 | "properties": { 28 | "topic": { "type": "string", "required": True }, 29 | "caption": { "type": "string", "required": False }, 30 | "aliases": { 31 | "type": "array", 32 | "items": { "type": "string", "required": True }, 33 | "required": False 34 | } 35 | }, 36 | "additionalProperties": False 37 | } 38 | } 39 | } 40 | 41 | # The schema to validate that the help table of contents in the "help_contents" 42 | # key of the help index is properly formattted. 43 | # 44 | # NOTE: This recursively references itself in the children element. See the 45 | # following line of code. 46 | _help_contents_schema = { 47 | "type": "array", 48 | "required": False, 49 | 50 | # Items must be topic dictionaries or strings. Topic dictionaries require 51 | # a topic key but may also contain a caption key and a children key which 52 | # is an array that is recursively identical to this one. 53 | # 54 | # Values that are strings are expanded to be topic dictionaries with no 55 | # children and an inherited caption. 56 | "items": { 57 | "type": [ 58 | {"type": "string", "required": True }, 59 | { 60 | "type": "object", 61 | "required": True, 62 | "properties": { 63 | "topic": { "type": "string", "required": True }, 64 | "caption": { "type": "string", "required": False }, 65 | 66 | # This is recursive; see below 67 | "children": "_help_contents_schema" 68 | }, 69 | "additionalProperties": False 70 | } 71 | ] 72 | } 73 | } 74 | 75 | # The second type of item is a dictionary with a property that has the same 76 | # format as the top level key. 77 | _help_contents_schema["items"]["type"][1]["properties"]["children"] = _help_contents_schema 78 | 79 | # The schema to validate that the list of external resources in the "externals" 80 | # key of the help index is properly formatted. 81 | _externals_schema = { 82 | "type": "object", 83 | "required": False, 84 | 85 | # Any key is allowed, but all must have values which are arrays. The first 86 | # item in the array must be a string and the remainder must be topic 87 | # dictionaries. 88 | "additionalProperties": { 89 | "type": "array", 90 | "items": [ { "type": "string", "required": True } ], 91 | 92 | "additionalItems": { 93 | "type": "object", 94 | "properties": { 95 | "topic": { "type": "string", "required": True }, 96 | "caption": { "type": "string", "required": False }, 97 | "aliases": { 98 | "type": "array", 99 | "items": { "type": "string", "required": True }, 100 | "required": False 101 | } 102 | }, 103 | "additionalProperties": False 104 | } 105 | } 106 | } 107 | 108 | # The overall schema used to validate a hyperhelp index file. 109 | _index_schema = { 110 | "type": "object", 111 | "properties": { 112 | "package": { "type": "string", "required": True }, 113 | "description": { "type": "string", "required": False }, 114 | "doc_root": { "type": "string", "required": False }, 115 | "default_caption": { "type": "string", "required": False }, 116 | 117 | "help_files": _help_file_schema, 118 | "help_contents": _help_contents_schema, 119 | "externals": _externals_schema 120 | }, 121 | "additionalProperties": False 122 | } 123 | 124 | 125 | ###---------------------------------------------------------------------------- 126 | 127 | 128 | def validate_index(content, index_res): 129 | """ 130 | Given a raw JSON string that represents a help index for a package, perform 131 | validation on it to ensure that it's valid JSON and also that it conforms 132 | to the appropriate index file help schema. 133 | 134 | Return a decoded dict object on success or None on failure. 135 | """ 136 | def validate_fail(message, *args): 137 | log("Error validating index in '%s': %s", index_res, message % args) 138 | 139 | try: 140 | log("Loading help index from '%s'", index_res) 141 | raw_dict = sublime.decode_value(content) 142 | except: 143 | return validate_fail("Invalid JSON detected; unable to decode") 144 | 145 | try: 146 | validate(raw_dict, _index_schema) 147 | return raw_dict 148 | 149 | # The schema provided is itself broken. 150 | except SchemaError as error: 151 | return validate_fail("Invalid schema detected: %s", error) 152 | 153 | # One of the fields failed to validate. This generates extremely messy 154 | # output, but this can be fixed later. 155 | except ValidationError as error: 156 | return validate_fail("in %s: %s", error.fieldname, error) 157 | 158 | # Seems like validictory has a bug in which if you tell it to verify an 159 | # array has contents but the array is empty, it blows up. This can happen 160 | # if the array that provides the contents of a help file is empty, for 161 | # example. 162 | except Exception as error: 163 | return validate_fail("%s", error) 164 | 165 | 166 | ###---------------------------------------------------------------------------- 167 | -------------------------------------------------------------------------------- /all/hyperhelpcore/startup.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | import os 4 | 5 | from .bootstrapper import log, bootstrap_pkg, bootloader, BootstrapThread 6 | 7 | 8 | ### --------------------------------------------------------------------------- 9 | 10 | 11 | def _should_bootstrap(settings): 12 | """ 13 | Check to see if the bootstrap package needs to be created/updated or not. 14 | This checks both for the existence of the package as well as for when the 15 | bootstrapped version is different from ours. 16 | """ 17 | # For debugging/testing/troubleshooting purposes, this allows you to set a 18 | # setting that forces the bootstrap to occur, even if it doesn't need to be 19 | # done. 20 | if settings.get("hyperhelp.force_bootstrap", False): 21 | log("hyperhelp bootstrap forced; skipping check") 22 | return True 23 | 24 | try: 25 | from importlib import __import__ as do_import 26 | from hyperhelpcore import __version__ as mp_sys_version 27 | 28 | mod = do_import("{pkg}.{file}".format( 29 | pkg=bootstrap_pkg, file=bootloader), 30 | fromlist=("__version__")) 31 | bootstrapped_version = mod.__dict__["__version__"] 32 | 33 | if bootstrapped_version == mp_sys_version: 34 | msg = "hyperhelpcore system package {pkg_name} is up to date (v{sys})" 35 | else: 36 | msg = "upgrading hyperhelpcore system package {pkg_name} from v{boot} to v{sys}" 37 | 38 | log(msg, sys=mp_sys_version, boot=bootstrapped_version, pkg_name=bootstrap_pkg) 39 | return not bootstrapped_version == mp_sys_version 40 | 41 | except: 42 | log("hyperhelpcore system package is missing ({pkg_name}); bootstrapping", 43 | pkg_name=bootstrap_pkg) 44 | 45 | return True 46 | 47 | 48 | def initialize(): 49 | """ 50 | Ensures that the resource package that provides the syntax and other 51 | Sublime resources exists and is up to date; does nothing if this has 52 | already been called once. 53 | 54 | This *must* be invoked by all packages that are using hyperhelp actively 55 | and *must* be invoked after plugin_loaded() has been called, as it requires 56 | the Sublime API to be available. 57 | """ 58 | if hasattr(initialize, "complete"): 59 | return 60 | 61 | initialize.complete = True 62 | 63 | settings = sublime.load_settings("Preferences.sublime-settings") 64 | ignored_packages = settings.get("ignored_packages", []) 65 | 66 | # Checks to see if the bootstrapped package is in the list of ignored 67 | # packages and complains if it is unless the user has also purposefully set 68 | # a setting telling us not to. 69 | # 70 | # This makes disabling the package a two step operation to stop potential 71 | # confusion on the behalf of the user, since they technically did not 72 | # install the bootstrapped package directly and might not know what it's 73 | # for. 74 | if bootstrap_pkg in ignored_packages: 75 | if settings.get("hyperhelp.ignore_disabled", False): 76 | return log("{pkg_name} package ignored; hyperhelp disabled", 77 | pkg_name=bootstrap_pkg) 78 | 79 | return log( 80 | """ 81 | The {pkg_name} package is currently disabled. 82 | 83 | Please remove this package from the 84 | `ignored_packages` setting and restart Sublime. 85 | 86 | If your intention was to disable {pkg_name}, 87 | set the value of the 'hyperhelp.ignore_disabled' 88 | setting to True in your Preferences.sublime-settings 89 | file to remove this warning message at startup. 90 | """, pkg_name=bootstrap_pkg, error=True) 91 | 92 | # If the boostrapped package is overridden, the user will block themselves 93 | # from getting updates when the dependency updates. So check if that is the 94 | # case and generate an error and refuse to proceed. 95 | # 96 | # An undocumented setting exists to turn this from an error to just a log 97 | # warning instead, in which case we proceed. 98 | pkg_folder = os.path.join(sublime.packages_path(), bootstrap_pkg) 99 | if os.path.lexists(pkg_folder): 100 | if settings.get("hyperhelp.allow_unpacked", False) == False: 101 | return log( 102 | """ 103 | The {pkg_name} package is unpacked. 104 | 105 | This package should not be overridden as it 106 | blocks updates and causes problems with 107 | bootstrapping. 108 | 109 | Please remove the {pkg_name} folder from 110 | the Packages folder and restart sublime. 111 | """, pkg_name=bootstrap_pkg, error=True) 112 | 113 | log("hyperhelpcore system package {pkg_name} is unpacked; issues may arise", 114 | pkg_name=bootstrap_pkg) 115 | 116 | if _should_bootstrap(settings): 117 | BootstrapThread().start() 118 | 119 | 120 | ### --------------------------------------------------------------------------- -------------------------------------------------------------------------------- /all/hyperhelpcore/validictory/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 James Turk 2 | 3 | Contains code from jsonschema 0.2, copyright 2008 Ian Lewis, Yusuke Muraoka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /all/hyperhelpcore/validictory/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from .validator import (SchemaValidator, FieldValidationError, MultipleValidationError, 4 | ValidationError, SchemaError) 5 | 6 | __all__ = ['validate', 'SchemaValidator', 'FieldValidationError', 'MultipleValidationError', 7 | 'ValidationError', 'SchemaError'] 8 | __version__ = '1.1.2' 9 | 10 | 11 | def validate(data, schema, validator_cls=SchemaValidator, 12 | format_validators=None, required_by_default=True, 13 | blank_by_default=False, disallow_unknown_properties=False, 14 | apply_default_to_data=False, fail_fast=True, 15 | remove_unknown_properties=False): 16 | ''' 17 | Validates a parsed json document against the provided schema. If an 18 | error is found a :class:`ValidationError` is raised. 19 | 20 | If there is an issue in the schema a :class:`SchemaError` will be raised. 21 | 22 | :param data: python data to validate 23 | :param schema: python dictionary representing the schema (see 24 | `schema format`_) 25 | :param validator_cls: optional validator class (default is 26 | :class:`SchemaValidator`) 27 | :param format_validators: optional dictionary of custom format validators 28 | :param required_by_default: defaults to True, set to False to make 29 | ``required`` schema attribute False by default. 30 | :param disallow_unknown_properties: defaults to False, set to True to 31 | disallow properties not listed in the schema definition 32 | :param apply_default_to_data: defaults to False, set to True to modify the 33 | data in case the schema definition includes a "default" property 34 | :param fail_fast: defaults to True, set to False if you prefer to get 35 | all validation errors back instead of only the first one 36 | :param remove_unknown_properties: defaults to False, set to True to 37 | filter out properties not listed in the schema definition. Only applies 38 | when disallow_unknown_properties is False. 39 | ''' 40 | v = validator_cls(format_validators, required_by_default, blank_by_default, 41 | disallow_unknown_properties, apply_default_to_data, fail_fast, 42 | remove_unknown_properties) 43 | return v.validate(data, schema) 44 | 45 | if __name__ == '__main__': 46 | import sys 47 | import json 48 | if len(sys.argv) == 2: 49 | if sys.argv[1] == "--help": 50 | raise SystemExit("%s SCHEMAFILE [INFILE]" % (sys.argv[0],)) 51 | schemafile = open(sys.argv[1], 'rb') 52 | infile = sys.stdin 53 | elif len(sys.argv) == 3: 54 | schemafile = open(sys.argv[1], 'rb') 55 | infile = open(sys.argv[2], 'rb') 56 | else: 57 | raise SystemExit("%s SCHEMAFILE [INFILE]" % (sys.argv[0],)) 58 | try: 59 | obj = json.load(infile) 60 | schema = json.load(schemafile) 61 | validate(obj, schema) 62 | except ValueError as e: 63 | raise SystemExit(e) 64 | -------------------------------------------------------------------------------- /all/hyperhelpcore/view.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | 4 | _get_window = lambda wnd: wnd if wnd is not None else sublime.active_window() 5 | 6 | 7 | ###---------------------------------------------------------------------------- 8 | 9 | 10 | def find_help_view(window=None): 11 | """ 12 | Search for and return the help view in the provided window. Defaults to 13 | searching the current window if none is provided. 14 | """ 15 | window = window if window is not None else sublime.active_window() 16 | for view in window.views(): 17 | if view.name().startswith("HyperHelp"): 18 | s = view.settings() 19 | if s.has("_hh_pkg") and s.has("_hh_file"): 20 | return view 21 | 22 | 23 | def new_help_view(syntax=None, window=None): 24 | """ 25 | Create and return a new help view in the provided window. Defaults to the 26 | current window if none is specified. 27 | """ 28 | hView = _get_window(window).new_file() 29 | hView.set_scratch(True) 30 | hView.set_name("HyperHelp") 31 | 32 | if syntax is not None: 33 | hView.assign_syntax(syntax) 34 | 35 | return hView 36 | 37 | 38 | def update_help_view(help_content, help_pkg, help_file, 39 | syntax=None, window=None): 40 | """ 41 | Find or create the help view in the provided window and set it's contents 42 | to the help string provided. The help view will have it's internal state 43 | set up to track the given help package and file. 44 | """ 45 | window = _get_window(window) 46 | help_view = find_help_view(window) 47 | 48 | if help_view is None: 49 | help_view = new_help_view(syntax, window) 50 | else: 51 | help_view.set_read_only(False) 52 | help_view.run_command("select_all") 53 | help_view.run_command("left_delete") 54 | 55 | if window.active_view() != help_view: 56 | window.focus_view(help_view) 57 | 58 | help_view.settings().set("_hh_pkg", help_pkg) 59 | help_view.settings().set("_hh_file", help_file) 60 | 61 | help_view.run_command("append", {"characters": help_content}) 62 | help_view.set_read_only(True) 63 | 64 | return help_view 65 | 66 | 67 | ###---------------------------------------------------------------------------- 68 | --------------------------------------------------------------------------------