diff --git a/mode/scala.py b/mode/scala.py index 3dd8c67..2bb355e 100644 --- a/mode/scala.py +++ b/mode/scala.py @@ -9,6 +9,7 @@ from method import Method, arg import default import urllib2 import os +import re chr1 = '[a-zA-Z_]' chr2 = '[a-zA-Z_0-9]' @@ -167,6 +168,65 @@ class ScalaDocLookup(Method): w.set_error('error looking up %s...' % name) +class ScalaXRayBase(Method): + _is_method = False + pkg_re = re.compile('^package (.+)$') + def find_pkg(self, w): + for line in w.buffer.lines: + m = self.pkg_re.match(line) + if m: + return m.group(1) + raise Exception("no package found") + def get_sxr_dir(self, w): + # TODO: fixme fixme + path = 'target/scala_2.8.0/classes.sxr' + if os.path.exists(path): + return path + else: + raise Exception("classes.sxr not found") + def get_public_tags(self, w, base): + return os.path.join(base, 'public-tags') + def type_lookup(self, n, w): + pkg = self.find_pkg(w) + base = self.get_sxr_dir(w) + tags = os.path.join(base, pkg.replace('.', '/') + '.scala.txt') + + f = open(tags, 'r') + for line in f: + toks = line.split('\t') + i = int(toks[0]) + j = int(toks[1]) + if i <= n and n <= j: + return toks[2] + + return None + +class ScalaGetType(ScalaXRayBase): + type_re = re.compile('(?:[^ \[\]{}()\.,;:]+\.)*([^ \[\]{}()\.,;:]+)') + ret_re = re.compile('\)(?=[a-zA-Z0-9_])') + def _execute(self, w, **vargs): + word = w.get_token().string + if word is None or word.strip() == "": + w.set_error('no word selected') + return + + n = w.cursor_byte_offset() + t = self.type_lookup(n, w) + if t: + if w.application.config['scala.type-abbrev']: + t = self.type_re.sub(lambda m: m.group(1), t) + #t = t.replace(')', ') => ') + t = self.ret_re.sub(') => ', t) + t = t.replace(': ', ':') + t = t.replace(',', ', ') + w.set_error(t) + else: + w.set_error('%s has unknown type' % word) + +class ScalaGotoDefinition(ScalaXRayBase): + def _execute(self, w, **vargs): + w.set_error('borken') + # white is for delimiters, operators, numbers default = ('default', 'default') @@ -205,7 +265,7 @@ class Scala(Fundamental): tabbercls = ScalaTabber grammar = ScalaGrammar commentc = '//' - actions = [ScalaStart, ScalaDocBrowse, ScalaDocLookup] + actions = [ScalaStart, ScalaDocBrowse, ScalaDocLookup, ScalaGetType] opentokens = ('delimiter', 'sub.start', 'sub.sub.start', 'sub.sub.sub.start') opentags = {'(': ')', '[': ']', '{': '}'} closetokens = ('delimiter', 'sub.end', 'sub.sub.end', 'sub.sub.sub.end') @@ -213,6 +273,7 @@ class Scala(Fundamental): config = { 'scala.api': 'http://www.scala-lang.org/api/current/allclasses.html', 'scala.api-base': 'http://www.scala-lang.org/api/current', + 'scala.type-abbrev': True, } colors = { @@ -241,6 +302,7 @@ class Scala(Fundamental): } _bindings = { + 'scala-get-type': ('M-,',), 'close-paren': (')',), 'close-brace': ('}',), 'close-bracket': (']',), diff --git a/window.py b/window.py index d9210ad..fde4efe 100644 --- a/window.py +++ b/window.py @@ -477,6 +477,15 @@ class Window(object): self.first = Point(x - (x % self.width), y) self.redraw() + # TODO: multi-byte characters!!! + def point_byte_offset(self, p): + n = 0 + for i in xrange(0, p.y): + n += len(self.buffer.lines[i]) + 1 + return n + p.x + def cursor_byte_offset(self): + return self.point_byte_offset(self.logical_cursor()) + def last_visible_coords(self): (x, y) = self.buffer.get_buffer_end().xy() counter = 0