Skip to content

Instantly share code, notes, and snippets.

@trishume
Created March 30, 2017 00:12
Show Gist options
  • Save trishume/c24626e18d163e54addca04710d06f14 to your computer and use it in GitHub Desktop.
Save trishume/c24626e18d163e54addca04710d06f14 to your computer and use it in GitHub Desktop.
Patch to add type inference and definition popups to Sublime Text's Merlin plugin
diff --git a/Packages/Merlin/sublime-text-merlin.py b/Packages/Merlin/sublime-text-merlin.py
--- a/Packages/Merlin/sublime-text-merlin.py
+++ b/Packages/Merlin/sublime-text-merlin.py
@@ -248,6 +248,57 @@
else:
opened_view.run_command("insert_code", { "arg": sig })
+class MerlinInfoPopup:
+ """
+ Pop up a menu at a point describing an expression
+ """
+
+ def __init__(self, view, point):
+ merlin = merlin_view(view)
+ merlin.sync()
+
+ line, col = view.rowcol(point)
+
+ # 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.declaration = merlin.locate(line + 1, col, kind="mli")
+ self.definition = merlin.locate(line + 1, col, kind="ml")
+ self.view = view
+ self.point = point
+
+ def _type_str(self):
+ if len(self.enclosing) > 0:
+ return clean_whitespace(self.enclosing[0]['type'])
+ else:
+ return ""
+
+ def _loc_link(self, loc):
+ if isinstance(loc, dict):
+ pos = loc['pos']
+ if 'file' in loc:
+ short_file = os.path.basename(loc['file'])
+ filename = "%s:%d:%d" % (loc.get('file',''), pos['line'], pos['col'] + 1)
+ return "<a href=\"{}\">{}:{}</a>".format(filename, short_file,pos['line'])
+ else:
+ return "[this file]:" + pos['line']
+ else:
+ return ""+loc
+
+ def show_popup(self):
+ print('showing popup')
+ content = "<b>Definition:</b> {} <br><b>Declaration:</b> {}<br><b>Type:</b><br> {}".format(self._loc_link(self.definition),self._loc_link(self.declaration), self._type_str())
+ self.view.show_popup(content,
+ sublime.HIDE_ON_MOUSE_MOVE_AWAY, self.point,
+ 600,150, self.on_navigate)
+
+ def on_navigate(self, href):
+ self.view.window().open_file(href, sublime.ENCODED_POSITION)
+
class InsertCodeCommand(sublime_plugin.TextCommand):
def run(self, edit, arg):
self.view.insert(edit, self.view.size(), arg)
@@ -735,6 +786,11 @@
view.erase_regions('ocaml-underlines-errors')
#merlin_error_panel.close()
+ @only_ocaml
+ def on_hover(self, view, point, hover_zone):
+ if hover_zone == sublime.HOVER_TEXT:
+ popup = MerlinInfoPopup(view, point)
+ popup.show_popup()
def _plugin_dir(self):
path = os.path.realpath(__file__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment