Esempio n. 1
0
    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)
Esempio n. 3
0
 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))
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 7
0
    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)
Esempio n. 8
0
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)
Esempio n. 9
0
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)