def hover_content(self, point, response: 'Optional[Any]') -> str: contents = ["No description available."] if isinstance(response, dict): # Flow returns None sometimes # See: https://github.com/flowtype/flow-language-server/issues/51 response_content = response.get('contents') if response_content: if isinstance(response_content, list): contents = response_content else: contents = [response_content] formatted = [] for item in contents: value = "" language = None if isinstance(item, str): value = item else: value = item.get("value") language = mdpopups.get_language_from_view(self.view) if language: formatted.append("```{}\n{}\n```\n".format(language, value)) else: formatted.append(value) return mdpopups.md2html(self.view, "\n".join(formatted))
def __init__(self, view, pos=None): merlin = merlin_view(view) merlin.sync() if pos == None: pos = view.sel()[0].begin() line, col = view.rowcol(pos) # FIXME: proper integration into sublime-text # enclosing is a list of json objects of the form: # { 'type': string; # 'tail': "no"|"position"|"call" // tailcall information # 'start', 'end': {'line': int, 'col': int} # } self.enclosing = merlin.type_enclosing(line + 1, col) self.view = view self.language = mdpopups.get_language_from_view(self.view)
def run(self): try: w = self.window v = w.active_view() import mdpopups l = mdpopups.get_language_from_view(v) md_preview = mdpopups.syntax_highlight( view=v, src=v.substr(sublime.Region(0, v.size())), language=l ) p = os.path.join(sublime.packages_path(), 'User', 'Print Preview.cache', 'index.html') os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True) with open(p, mode='w', newline='\n') as f: f.write(md_preview) # TODO: remove pathlib from dependencies.json for py3.8 import pathlib w.run_command('open_url', { 'url': pathlib.Path(p).as_uri() }) except Exception as e: # TODO: update for py3.8 print('Print: Exception: {}'.format(e))
def _show_diff_popup_impl(git_gutter, line, highlight_diff, flags, diff_info): """Show and update the diff popup. Arguments: git_gutter (GitGutterCommand): The main command object, which represents GitGutter. line (int): The line number the diff popup is requested for highlight_diff (bool): If True to the diff is displayed instead of the old revision. flags (int): Sublime Text popup flags. diff_info (tuple): All the information required to display the diff popup. """ del_lines, start, size, meta = diff_info if start == -1: return view = git_gutter.view # extract the type of the hunk: removed, modified, (x)or added is_removed = size == 0 is_modified = not is_removed and bool(del_lines) is_added = not is_removed and not is_modified def navigate(href): # allow navigate() to manipulate the outer variables nonlocal highlight_diff if href == 'hide': view.hide_popup() elif href == 'copy': del_text = '\n'.join(del_lines) sublime.set_clipboard(del_text) sublime.status_message('Copied: {0} characters'.format( len(del_text))) elif href == 'revert': # hide the popup and update the view view.hide_popup() revert.revert_change_impl(view, diff_info) elif href == 'disable_hl_diff': # show a diff popup with the same diff info (previous revision) highlight_diff = False _show_diff_popup_impl(git_gutter, line, highlight_diff, flags, diff_info) elif href == 'enable_hl_diff': # show a diff popup with the same diff info (highlight diff) highlight_diff = True _show_diff_popup_impl(git_gutter, line, highlight_diff, flags, diff_info) elif href in ('first_change', 'next_change', 'prev_change'): next_line = meta.get(href, line) point = view.text_point(next_line - 1, 0) def show_new_popup(): # wait until scrolling has completed if not view.visible_region().contains(point): return sublime.set_timeout_async(show_new_popup, 20) # show a diff popup with new diff info _show_diff_popup_impl( git_gutter, next_line, highlight_diff, 0, git_gutter.git_handler.diff_line_change(next_line)) view.hide_popup() view.show_at_center(point) show_new_popup() # write the symbols/text for each button buttons = _built_toolbar_buttons(start, meta) location = _visible_text_point(view, line - 1, 0) code_wrap = view.settings().get('word_wrap') if code_wrap == 'auto': code_wrap = view.match_selector(location, 'source') if highlight_diff: # (*) show a highlighted diff of the merged git and editor content new_lines = meta['added_lines'] tab_width = view.settings().get('tab_width', 4) min_indent = _get_min_indent(del_lines + new_lines, tab_width) content = ( '<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{disable_hl_diff} {revert}' '</div>'.format(**buttons)) + differ.highlight_diff([ line.expandtabs(tab_width)[min_indent:] for line in del_lines ], [line.expandtabs(tab_width)[min_indent:] for line in new_lines]) elif not is_added: # (modified/removed) show content from git database tab_width = view.settings().get('tab_width', 4) min_indent = _get_min_indent(del_lines, tab_width) source_content = '\n'.join( (line.expandtabs(tab_width)[min_indent:] for line in del_lines)) content = ('<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {copy} {revert}' '</div>'.format(**buttons)) + mdpopups.syntax_highlight( view, source_content, language=mdpopups.get_language_from_view(view) or '', allow_code_wrap=code_wrap) else: # (added) only show the button line without the copy button # (there is nothing to show or copy) content = ('<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {revert}' '</div>'.format(**buttons)) # common arguments used to create or update the popup popup_kwargs = { 'view': view, 'content': content, 'md': False, 'css': _load_popup_css(git_gutter.settings.theme_path), 'wrapper_class': 'git-gutter' } # update visible popup if view.is_popup_visible(): return mdpopups.update_popup(**popup_kwargs) # calculate optimal popup width to apply desired wrapping popup_width = int(view.viewport_extent()[0]) if code_wrap: line_length = view.settings().get('wrap_width', 0) if line_length > 0: popup_width = (line_length + 5) * view.em_width() # create new popup return mdpopups.show_popup(location=location, max_width=popup_width, flags=flags, on_navigate=navigate, **popup_kwargs)
def _show_diff_popup_impl(git_gutter, line, highlight_diff, flags, diff_info): """Show and update the diff popup. Arguments: git_gutter (GitGutterCommand): The main command object, which represents GitGutter. line (int): The line number the diff popup is requested for highlight_diff (bool): If True to the diff is displayed instead of the old revision. flags (int): Sublime Text popup flags. diff_info (tuple): All the information required to display the diff popup. """ del_lines, start, size, meta = diff_info if start == -1: return view = git_gutter.view # extract the type of the hunk: removed, modified, (x)or added is_removed = size == 0 is_modified = not is_removed and bool(del_lines) is_added = not is_removed and not is_modified def navigate(href): # allow navigate() to manipulate the outer variables nonlocal highlight_diff if href == 'hide': view.hide_popup() elif href == 'copy': del_text = '\n'.join(del_lines) sublime.set_clipboard(del_text) sublime.status_message( 'Copied: {0} characters'.format(len(del_text))) elif href == 'revert': # hide the popup and update the view view.hide_popup() revert.revert_change_impl(view, diff_info) elif href == 'disable_hl_diff': # show a diff popup with the same diff info (previous revision) highlight_diff = False _show_diff_popup_impl( git_gutter, line, highlight_diff, flags, diff_info) elif href == 'enable_hl_diff': # show a diff popup with the same diff info (highlight diff) highlight_diff = True _show_diff_popup_impl( git_gutter, line, highlight_diff, flags, diff_info) elif href in ('first_change', 'next_change', 'prev_change'): next_line = meta.get(href, line) point = view.text_point(next_line - 1, 0) def show_new_popup(): # wait until scrolling has completed if not view.visible_region().contains(point): return sublime.set_timeout_async(show_new_popup, 20) # show a diff popup with new diff info _show_diff_popup_impl( git_gutter, next_line, highlight_diff, 0, git_gutter.git_handler.diff_line_change(next_line)) view.hide_popup() view.show_at_center(point) show_new_popup() # write the symbols/text for each button buttons = _built_toolbar_buttons(start, meta) location = _visible_text_point(view, line - 1, 0) code_wrap = view.settings().get('word_wrap') if code_wrap == 'auto': code_wrap = view.match_selector(location, 'source') if highlight_diff: # (*) show a highlighted diff of the merged git and editor content new_lines = meta['added_lines'] tab_width = view.settings().get('tab_width', 4) min_indent = _get_min_indent(del_lines + new_lines, tab_width) content = ( '<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{disable_hl_diff} {revert}' '</div>' .format(**buttons) ) + differ.highlight_diff( [line.expandtabs(tab_width)[min_indent:] for line in del_lines], [line.expandtabs(tab_width)[min_indent:] for line in new_lines]) elif not is_added: # (modified/removed) show content from git database tab_width = view.settings().get('tab_width', 4) min_indent = _get_min_indent(del_lines, tab_width) source_content = '\n'.join( (line.expandtabs(tab_width)[min_indent:] for line in del_lines)) # common arguments used to highlight the content popup_kwargs = { 'allow_code_wrap': code_wrap, 'language': mdpopups.get_language_from_view(view) or '' } content = ( '<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {copy} {revert}' '</div>' .format(**buttons) ) + mdpopups.syntax_highlight(view, source_content, **popup_kwargs) else: # (added) only show the button line without the copy button # (there is nothing to show or copy) content = ( '<div class="toolbar">' '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {revert}' '</div>' .format(**buttons) ) # common arguments used to create or update the popup popup_kwargs = { 'view': view, 'content': content, 'md': False, 'css': _load_popup_css(git_gutter.settings.theme_path), 'wrapper_class': 'git-gutter', 'allow_code_wrap': code_wrap } # update visible popup if view.is_popup_visible(): return mdpopups.update_popup(**popup_kwargs) # calculate optimal popup width to apply desired wrapping popup_width = int(view.viewport_extent()[0]) if code_wrap: line_length = view.settings().get('wrap_width', 0) if line_length > 0: popup_width = (line_length + 5) * view.em_width() # create new popup return mdpopups.show_popup( location=location, max_width=popup_width, flags=flags, on_navigate=navigate, **popup_kwargs)
def _show_diff_popup_impl(view, point, highlight_diff, flags, diff_info): (deleted_lines, start, size, meta) = diff_info if start == -1: return line = view.rowcol(point)[0] + 1 # extract the type of the hunk: removed, modified, (x)or added is_removed = size == 0 is_modified = not is_removed and bool(deleted_lines) is_added = not is_removed and not is_modified def navigate(href): if href == "hide": view.hide_popup() elif href == "revert": new_text = "\n".join(deleted_lines) # (removed) if there is no text to remove, set the # region to the end of the line, where the hunk starts # and add a new line to the start of the text if is_removed: if start != 0: # set the start and the end to the end of the start line start_point = end_point = view.text_point(start, 0) - 1 # add a leading newline before inserting the text new_text = "\n" + new_text else: # (special handling for deleted at the start of the file) # if we are before the start we need to set the start # to 0 and add the newline behind the text start_point = end_point = 0 new_text = new_text + "\n" # (modified/added) # set the start point to the start of the hunk # and the end point to the end of the hunk else: start_point = view.text_point(start - 1, 0) end_point = view.text_point(start + size - 1, 0) # (modified) if there is text to insert, we # don't want to capture the trailing newline, # because we insert lines without a trailing newline if is_modified and end_point != view.size(): end_point -= 1 replace_param = { "a": start_point, "b": end_point, "text": new_text } view.run_command("git_gutter_replace_text", replace_param) # hide the popup and update the gutter view.hide_popup() view.run_command("git_gutter") elif href in ["disable_hl_diff", "enable_hl_diff"]: do_diff = { "disable_hl_diff": False, "enable_hl_diff": True }.get(href) # show a diff popup with the same diff info _show_diff_popup_impl( view, point, highlight_diff=do_diff, flags=0, diff_info=diff_info) elif href == "copy": sublime.set_clipboard("\n".join(deleted_lines)) copy_message = " ".join(l.strip() for l in deleted_lines) sublime.status_message("Copied: " + copy_message) elif href in ["next_change", "prev_change", "first_change"]: next_line = meta.get(href, line) pt = view.text_point(next_line - 1, 0) def show_new_popup(): if view.visible_region().contains(pt): popup_kwargs = { 'action': 'show_diff_popup', 'highlight_diff': highlight_diff, 'point': pt, 'flags': 0 } view.run_command('git_gutter', popup_kwargs) else: sublime.set_timeout(show_new_popup, 10) view.show_at_center(pt) show_new_popup() # write the symbols/text for each button use_icons = settings.get("diff_popup_use_icon_buttons") # the buttons as a map from the href to the caption/icon button_descriptions = { "hide": chr(0x00D7) if use_icons else "(close)", "copy": chr(0x2398) if use_icons else "(copy)", "revert": chr(0x27F2) if use_icons else "(revert)", "disable_hl_diff": chr(0x2249) if use_icons else "(diff)", "enable_hl_diff": chr(0x2248) if use_icons else "(diff)", "first_change": chr(0x2912) if use_icons else "(first)", "prev_change": chr(0x2191) if use_icons else "(previous)", "next_change": chr(0x2193) if use_icons else "(next)" } def is_button_enabled(k): if k in ["first_change", "next_change", "prev_change"]: return meta.get(k, start) != start return True buttons = {} for k, v in button_descriptions.items(): if is_button_enabled(k): button = '<a href={1}>{0}</a>'.format(v, k) else: button = v buttons[k] = ( '<span class="gitgutter-button">{0}</span>' .format(button) ) if highlight_diff: # (*) show a highlighted diff of the merged git and editor content min_indent = _get_min_indent(deleted_lines + meta["added_lines"]) old_content = "\n".join(l[min_indent:] for l in deleted_lines) new_content = "\n".join(l[min_indent:] for l in meta["added_lines"]) source_html = _highlight_diff(old_content, new_content) button_line = ( '{hide} ' '{first_change} {prev_change} {next_change} ' '{disable_hl_diff} {revert}' .format(**buttons) ) content = ( '{button_line}' '{source_html}' .format(**locals()) ) elif not is_added: # (modified/removed) show the button line above the content, # which in git lang = mdpopups.get_language_from_view(view) or "" # strip the indent to the minimal indentation is_tab_indent = any(l.startswith("\t") for l in deleted_lines) indent_char = "\t" if is_tab_indent else " " min_indent = _get_min_indent(deleted_lines) source_content = "\n".join(l[min_indent:] for l in deleted_lines) # replace spaces by non-breakable ones to avoid line wrapping # (this has been added to mdpopups in version 1.11.0) if mdpopups.version() < (1, 11, 0): source_content = source_content.replace(" ", "\u00A0") source_html = mdpopups.syntax_highlight( view, source_content, language=lang) button_line = ( '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {copy} {revert}' .format(**buttons) ) content = ( '{button_line}' '{source_html}' .format(**locals()) ) else: # (added) only show the button line without the copy button # (there is nothing to show or copy) button_line = ( '{hide} ' '{first_change} {prev_change} {next_change} ' '{enable_hl_diff} {revert}' .format(**buttons) ) content = button_line css = '' if _MD_POPUPS_USE_WRAPPER_CLASS: wrapper_class = ".git-gutter" else: wrapper_class = "" # load the user css file css = sublime.load_resource("Packages/GitGutter/gitgutter_popup.css") try: user_css = sublime.load_resource("Packages/User/gitgutter_popup.css") css += "\n" css += user_css except OSError: pass # apply the jinja template jinja_kwargs = { "wrapper_class": wrapper_class, "use_icons": use_icons } tmpl = jinja2.environment.Template(css) css = tmpl.render(**jinja_kwargs) # create the popup location = view.line(point).a window_width = int(view.viewport_extent()[0]) mdpopups.show_popup( view, content, location=location, on_navigate=navigate, md=False, wrapper_class=wrapper_class[1:], css=css, flags=flags, max_width=window_width)
def on_selection_modified(self, view): if not Pref.show_tooltips: return if Pref.isActive: return if not any(x in view.scope_name(view.sel()[0].a) for x in SCOPES): return command = Pref.data.get(view.substr(view.word(view.sel()[0])).lower()) if not command: return Pref.isActive = True global copy, menus menus = ["<body id='mohtooltip'>"] menus.append("<style>{}</style>".format(Pref.css)) menus.append("<div class='header'>") if command["class"]: menus.append("<div class='class-container'>") menus.append("<span>Class:</span>") for i, cl in enumerate(command["class"]): if i: menus.append(",") menus.append("<span class='class'> {}</span>".format(cl)) menus.append("</div>") if command["gamever"]: menus.append("<div class='version-container'>") menus.append(" [") for i, ver in enumerate(command["gamever"]): if i: menus.append(", ") menus.append( "<span class='version {0}' title='{1}'>{0}</span>".format( ver, VERSION[ver])) menus.append("]</div>") menus.append("</div>") menus.append("<div class='content'>") if command["syntax"]: name, *args = re.split("(\\W)", command["syntax"], maxsplit=1) menus.append("<div class='syntax-container'>") menus.append("<strong class='name'>{}</strong>".format(name)) if args: menus.append("<var>{}</var>".format("".join(args).replace( "\n", "<br>"))) menus.append("</div>") if command["description"]: menus.append("<div class='description-container'>{}</div>".format( command["description"].replace("\n", "<br>"))) menus.append("</div>") if command["example"]: lang = mdpopups.get_language_from_view(view) or "" example = mdpopups.syntax_highlight(view, command["example"], language=lang) menus.append("<div class='example-container'>") menus.append("Example:") menus.append( "<code class='example-code'>{}</code>".format(example)) menus.append( "<a class='example-copy' href='tooltip.copy'>copy</a>") menus.append("</div>") copy = command["example"] menus.append("<div class='footer'>") menus.append( "<a href='https://x-null.net/wiki' title='MoH:AA Reborn Wiki'>Wiki</a>" .format(name)) menus.append( "<a href='https://www.x-null.net/forums/forum.php' title='xNULL | MoH:AA 1.12 Reborn Forums'>xNULL</a>" ) menus.append( "<a href='http://mohreborn.com' title='mohreborn.com'>MoHReborn</a>" ) menus.append("</div>") menus.append("</body>") max_width, max_height = view.viewport_extent() max_width *= 0.90 max_height *= 0.90 a = view.word(view.sel()[0]).begin() b = view.word(view.sel()[0]).end() self.view = view view.show_popup("".join(menus), sublime.HIDE_ON_MOUSE_MOVE_AWAY, location=b, max_width=max_width, max_height=max_height, on_navigate=self.on_navigate, on_hide=self.on_hide) view.add_regions("moh_tooltip", [sublime.Region(a, b)], "invalid", "", sublime.HIDE_ON_MINIMAP | sublime.DRAW_NO_FILL)
def show_diff_popup(view, point, flags=0): if not _MDPOPUPS_INSTALLED: return line = view.rowcol(point)[0] + 1 lines, start, size, meta = ViewCollection.diff_line_change(view, line) if start == -1: return # extract the type of the hunk: removed, modified, (x)or added is_removed = size == 0 is_modified = not is_removed and bool(lines) is_added = not is_removed and not is_modified def navigate(href): if href == "hide": view.hide_popup() elif href == "revert": new_text = "\n".join(lines) # (removed) if there is no text to remove, set the # region to the end of the line, where the hunk starts # and add a new line to the start of the text if is_removed: if start != 0: # set the start and the end to the end of the start line start_point = end_point = view.text_point(start, 0) - 1 # add a leading newline before inserting the text new_text = "\n" + new_text else: # (special handling for deleted at the start of the file) # if we are before the start we need to set the start # to 0 and add the newline behind the text start_point = end_point = 0 new_text = new_text + "\n" # (modified/added) # set the start point to the start of the hunk # and the end point to the end of the hunk else: start_point = view.text_point(start - 1, 0) end_point = view.text_point(start + size - 1, 0) # (modified) if there is text to insert, we # don't want to capture the trailing newline, # because we insert lines without a trailing newline if is_modified and end_point != view.size(): end_point -= 1 replace_param = { "a": start_point, "b": end_point, "text": new_text } view.run_command("git_gutter_replace_text", replace_param) # hide the popup and update the gutter view.hide_popup() view.window().run_command("git_gutter") elif href == "copy": sublime.set_clipboard("\n".join(lines)) copy_message = " ".join(l.strip() for l in lines) sublime.status_message("Copied: " + copy_message) elif href in ["next_change", "prev_change", "first_change"]: next_line = meta.get(href, line) pt = view.text_point(next_line - 1, 0) def show_new_popup(): if view.visible_region().contains(pt): show_diff_popup(view, pt, flags=flags) else: sublime.set_timeout(show_new_popup, 10) view.show_at_center(pt) show_new_popup() # write the symbols/text for each button use_icons = settings.get("diff_popup_use_icon_buttons") # the buttons as a map from the href to the caption/icon button_descriptions = { "hide": chr(0x00D7) if use_icons else "(close)", "copy": chr(0x2398) if use_icons else "(copy)", "revert": chr(0x27F2) if use_icons else "(revert)", "first_change": chr(0x2912) if use_icons else "(first)", "prev_change": chr(0x2191) if use_icons else "(previous)", "next_change": chr(0x2193) if use_icons else "(next)" } def is_button_enabled(k): if k in ["first_change", "next_change", "prev_change"]: return meta.get(k, start) != start return True buttons = {} for k, v in button_descriptions.items(): if is_button_enabled(k): buttons[k] = '[{0}]({1})'.format(v, k) else: buttons[k] = v if not is_added: # (modified/removed) show the button line above the content, # which in git lang = mdpopups.get_language_from_view(view) or "" # strip the indent to the minimal indentation is_tab_indent = any(l.startswith("\t") for l in lines) indent_char = "\t" if is_tab_indent else " " min_indent = min(len(l) - len(l.lstrip(indent_char)) for l in lines) source_content = "\n".join(l[min_indent:] for l in lines) # replace spaces by non-breakable ones to avoid line wrapping source_content = source_content.replace(" ", "\u00A0") button_line = ( '{hide} ' '{first_change} {prev_change} {next_change} ' '{copy} {revert}' .format(**buttons) ) content = ( '{button_line}\n' '``` {lang}\n' '{source_content}\n' '```' .format(**locals()) ) else: # (added) only show the button line without the copy button # (there is nothing to show or copy) button_line = ( '{hide} ' '{first_change} {prev_change} {next_change} ' '{revert}' .format(**buttons) ) content = button_line css = '' if _MD_POPUPS_USE_WRAPPER_CLASS: wrapper_class = "git-gutter" if use_icons: css = 'div.git-gutter a { text-decoration: none; }' else: wrapper_class = "" if use_icons: css = 'a { text-decoration: none; }' location = view.line(point).a window_width = int(view.viewport_extent()[0]) mdpopups.show_popup( view, content, location=location, on_navigate=navigate, wrapper_class=wrapper_class, css=css, flags=flags, max_width=window_width)