diff --git a/tern.py b/tern.py index c5c9d53..2c5b058 100644 --- a/tern.py +++ b/tern.py @@ -2,6 +2,11 @@ import sublime, sublime_plugin import os, sys, platform, subprocess, webbrowser, json, re, time, atexit +try: + # python 2 + from utils.renderer import create_arghints_renderer +except: + from .utils.renderer import create_arghints_renderer windows = platform.system() == "Windows" python3 = sys.version_info[0] > 2 @@ -12,11 +17,10 @@ def is_js_file(view): files = {} arghints_enabled = False -arghints_type = "status" +arghints_renderer = None arg_completion_enabled = False tern_command = None tern_arguments = [] -tern_arghint = "" def on_deactivated(view): pfile = files.get(view.file_name(), None) @@ -460,65 +464,10 @@ def show_argument_hints(pfile, view): render_argument_hints(pfile, view, parsed, argpos) def render_argument_hints(pfile, view, ftype, argpos): - global tern_arghint if ftype is None: - if pfile.showing_arguments: - if arghints_type == "panel": - panel = view.window().get_output_panel("tern_arghint") - tern_arghint = "" - panel.run_command("tern_arghint") - elif arghints_type == "status": - sublime.status_message("") - pfile.showing_arguments = False - return - - msg = ftype["name"] + "(" - i = 0 - for name, type in ftype["args"]: - if i > 0: msg += ", " - if i == argpos: msg += "*" - msg += name + ("" if type == "?" else ": " + type) - i += 1 - msg += ")" - if ftype["retval"] is not None: - msg += " -> " + ftype["retval"] - - if arghints_type == "panel": - panel = view.window().get_output_panel("tern_arghint") - tern_arghint = msg - panel.run_command("tern_arghint") - view.window().run_command("show_panel", {"panel": "output.tern_arghint"}) - elif arghints_type == "status": - sublime.status_message(msg) - elif arghints_type == "tooltip": - view.show_popup(render_tooltip(ftype, msg), sublime.COOPERATE_WITH_AUTO_COMPLETE, max_width=600, on_navigate=go_to_url) - pfile.showing_arguments = True - -def go_to_url(url=None): - if url: - import webbrowser - webbrowser.open(url) - -def render_tooltip(ftype, msg): - output = ''' - - ''' - output = output + '
{}
'.format(msg) - url = '
{url}
' - doc = '
{doc}
' - - if ftype['url']: - output += url.format(url=ftype['url']) - if ftype['doc']: - output += doc.format(doc=ftype['doc']) - return output + arghints_renderer.clean(pfile, view) + else: + arghints_renderer.render(pfile, view, ftype, argpos) def parse_function_type(data): type = data["type"] @@ -555,8 +504,8 @@ def parse_function_type(data): jump_stack = [] class TernArghintCommand(sublime_plugin.TextCommand): - def run(self, edit): - self.view.insert(edit, 0, tern_arghint) + def run(self, edit, **args): + self.view.insert(edit, 0, args.get('msg', '')) class TernJumpToDef(sublime_plugin.TextCommand): def run(self, edit, **args): @@ -604,15 +553,18 @@ def run(self, edit, **args): plugin_dir = os.path.abspath(os.path.dirname(__file__)) def plugin_loaded(): - global arghints_enabled, arghints_type, tern_command, tern_arguments + global arghints_enabled, arghints_renderer, tern_command, tern_arguments global arg_completion_enabled settings = sublime.load_settings("Preferences.sublime-settings") arghints_enabled = settings.get("tern_argument_hints", False) arg_completion_enabled = settings.get("tern_argument_completion", False) if arghints_enabled: if "show_popup" in dir(sublime.View): - arghints_type = "tooltip" - arghints_type = settings.get("tern_argument_hints_type", arghints_type) + default_arghints_type = "tooltip" + else: + default_arghints_type = "status" + arghints_type = settings.get("tern_argument_hints_type", default_arghints_type) + arghints_renderer = create_arghints_renderer(arghints_type) tern_arguments = settings.get("tern_arguments", []) if not isinstance(tern_arguments, list): tern_arguments = [tern_arguments] diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1 @@ + diff --git a/utils/renderer.py b/utils/renderer.py new file mode 100644 index 0000000..3dd6a87 --- /dev/null +++ b/utils/renderer.py @@ -0,0 +1,138 @@ +import sublime + +def get_message_from_ftype(ftype, argpos): + msg = ftype["name"] + "(" + i = 0 + for name, type in ftype["args"]: + if i > 0: msg += ", " + if i == argpos: msg += "*" + msg += name + ("" if type == "?" else ": " + type) + i += 1 + msg += ")" + if ftype["retval"] is not None: + msg += " -> " + ftype["retval"] + return msg + +def get_html_message_from_ftype(ftype, argpos): + style = ''' + + ''' + + func_signature = '{func_name}('.format(func_name=ftype["name"]) + i = 0 + for name, type in ftype["args"]: + if i > 0: func_signature += ", " + if i == argpos: + func_signature += '{name}'.format(name=name) + else: + func_signature += '{name}'.format(name=name) + if type != "?": + func_signature += ': {type}'.format(type=type) + i += 1 + func_signature += ")" + if ftype["retval"] is not None: + func_signature += '{type}'.format(type=ftype["retval"]) + + template = ''' + {style} +
+
{func_signature}
+ +
{doc}
+
+ ''' + + template_data = { + 'style': style, + 'func_signature': hint_line(func_signature), + 'doc_link': hint_line(link(ftype['url'])), + 'doc': hint_line(ftype['doc']) + } + + return template.format(**template_data) + +def maybe(fn): + def maybe_fn(arg): + return fn(arg) if arg else '' + return maybe_fn + +@maybe +def link(url): + return '{url}'.format(url=url) + +@maybe +def hint_line(txt): + return '
{txt}
'.format(txt=txt) + +def go_to_url(url=None): + if url: + import webbrowser + webbrowser.open(url) + +class TooltipArghintsRenderer(object): + def render(self, pfile, view, ftype, argpos): + view.show_popup(get_html_message_from_ftype(ftype, argpos), sublime.COOPERATE_WITH_AUTO_COMPLETE, max_width=600, on_navigate=go_to_url) + pfile.showing_arguments = True + + def clean(self, pfile, view): + pfile.showing_arguments = False + + +class StatusArghintsRenderer(object): + def render(self, pfile, view, ftype, argpos): + msg = get_message_from_ftype(ftype, argpos) + sublime.status_message(msg) + pfile.showing_arguments = True + + def clean(self, pfile, view): + if pfile.showing_arguments: + sublime.status_message("") + pfile.showing_arguments = False + + +class PanelArghintsRenderer(object): + def render(self, pfile, view, ftype, argpos): + msg = get_message_from_ftype(ftype, argpos) + panel = view.window().get_output_panel("tern_arghint") + panel.run_command("tern_arghint", {"msg": msg}) + view.window().run_command("show_panel", {"panel": "output.tern_arghint"}) + pfile.showing_arguments = True + + def clean(self, pfile, view): + if pfile.showing_arguments: + panel = view.window().get_output_panel("tern_arghint") + panel.run_command("tern_arghint", {"msg": ""}) + pfile.showing_arguments = False + + +def create_arghints_renderer(arghints_type): + if arghints_type == "tooltip": + return TooltipArghintsRenderer() + elif arghints_type == "status": + return StatusArghintsRenderer() + elif arghints_type == "panel": + return PanelArghintsRenderer() \ No newline at end of file