From f1308a4d34634b30c932e27c139a7a1387d5aa46 Mon Sep 17 00:00:00 2001 From: moculus Date: Fri, 25 Apr 2008 14:20:40 +0000 Subject: [PATCH] lots of rendering fixes, more general completion support --HG-- branch : pmacs2 --- application.py | 27 ++++++++----- completer.py | 12 ------ mode/__init__.py | 3 ++ mode/perl.py | 65 ++++++++++++++++-------------- mode/python.py | 102 ++++++++++++++++++++++++++++++++++++++--------- render.py | 7 +++- 6 files changed, 143 insertions(+), 73 deletions(-) diff --git a/application.py b/application.py index 1e13a71..e1d3e71 100755 --- a/application.py +++ b/application.py @@ -190,19 +190,20 @@ class Application(object): method.DATATYPES['method'] = completer.MethodCompleter() method.DATATYPES['register'] = completer.RegisterCompleter() method.DATATYPES['mode'] = completer.ModeCompleter() - method.DATATYPES['perlfunction'] = completer.PerlFunctionCompleter() - method.DATATYPES['pythonfunction'] = completer.PythonFunctionCompleter() + #method.DATATYPES['perlfunction'] = completer.PerlFunctionCompleter() # set up curses self.win = curses.newwin(self.y, self.x, 0, 0) self.win.leaveok(0) curses.meta(1) curses.cbreak() - #curses.halfdelay(5) curses.noecho() curses.nonl() curses.def_prog_mode() + def set_completer(self, datatype, completer): + method.DATATYPES[datatype] = completer + # this sets up a mode, as well as optionally adding information on when to # auto-load the mode def setmode(self, name, cls, paths=[], basenames=[], extensions=[], detection=[]): @@ -582,8 +583,8 @@ class Application(object): x = 0 y += 1 #XYZ - while w.ishidden(y) and y < len(w.buffer.lines): - y += 1 + #while w.ishidden(y) and y < len(w.buffer.lines): + # y += 1 else: x += swidth count += 1 @@ -628,8 +629,8 @@ class Application(object): x = 0 y += 1 #XYZ - while w.ishidden(y) and y < len(w.buffer.lines): - y += 1 + #while w.ishidden(y) and y < len(w.buffer.lines): + # y += 1 else: x += slot.width count += 1 @@ -665,8 +666,8 @@ class Application(object): x = 0 y += 1 #XYZ - while w.ishidden(y) and y < len(w.buffer.lines): - y += 1 + #while w.ishidden(y) and y < len(w.buffer.lines): + # y += 1 else: x += slot.width - 1 count += 1 @@ -684,9 +685,10 @@ class Application(object): w = slot.window redattr = color.build_attr(color.pairs('red', 'default')) x, y = w.first.xy() + lm, rm = w.mode.lmargin, w.mode.rmargin lines = w.buffer.lines count = 0 - lm, rm = w.mode.lmargin, w.mode.rmargin + k = x // (slot.width - lm - rm) modename = w.mode.name() lit = w.mode.name() in w.buffer.highlights ended = False @@ -695,7 +697,7 @@ class Application(object): rlines = w.render_line_lit(y, slot.width - lm - rm) else: rlines = w.render_line_raw(y, slot.width - lm - rm) - for j in range(0, len(rlines)): + for j in range(k, len(rlines)): if lm: lcont = j > 0 for rstr in slot.window.mode.get_lmargin(w, y, x, ended, lcont): @@ -707,6 +709,9 @@ class Application(object): for rstr in slot.window.mode.get_rmargin(w, y, x, ended, rcont): rstr.draw(self.win, slot.y_offset + count, slot.width - rm) count += 1 + if count >= slot.height: + break + k = 0 y += 1 ended = ended or y >= len(w.buffer.lines) diff --git a/completer.py b/completer.py index 481ad99..8d5f7bd 100644 --- a/completer.py +++ b/completer.py @@ -105,15 +105,3 @@ class RegisterCompleter(Completer): class ModeCompleter(Completer): def get_candidates(self, s, w=None): return [n for n in w.application.modes if n.startswith(s)] - -class PerlFunctionCompleter(Completer): - def get_candidates(self, s, w=None): - old_window = w.buffer.method.old_window - functions = old_window.mode.get_functions() - return [n for n in functions if n.startswith(s)] - -class PythonFunctionCompleter(Completer): - def get_candidates(self, s, w=None): - old_window = w.buffer.method.old_window - functions = old_window.mode.get_functions() - return [n for n in functions if n.startswith(s)] diff --git a/mode/__init__.py b/mode/__init__.py index 8f33818..cae8a09 100644 --- a/mode/__init__.py +++ b/mode/__init__.py @@ -89,6 +89,7 @@ class Fundamental(Handler): colors = {} config = {} actions = [] + completers = {} # margin/line numbering show_line_numbers = False @@ -113,6 +114,8 @@ class Fundamental(Handler): return else: app.methods[m.name] = m + for (datatype, completer) in cls.completers.iteritems(): + app.set_completer(datatype, completer) install = classmethod(install) def __init__(self, w): diff --git a/mode/perl.py b/mode/perl.py index e327f5f..aa2548e 100644 --- a/mode/perl.py +++ b/mode/perl.py @@ -1,5 +1,5 @@ import re, sets, string, sys -import color, commands, default, method, mode, regex, tab +import color, commands, completer, default, method, mode, regex, tab from point import Point from lex import Grammar, PatternRule, ContextPatternRule, RegionRule, OverridePatternRule, PatternGroupRule from method import Argument, Method, WrapParagraph @@ -577,6 +577,12 @@ class PerlWrapParagraph(method.WrapParagraph): else: w.set_error("did not detect comment or pod lines") +class PerlFunctionCompleter(completer.Completer): + def get_candidates(self, s, w=None): + old_window = w.buffer.method.old_window + functions = old_window.mode.get_functions() + return [n for n in functions if n.startswith(s)] + class Perl(mode.Fundamental): modename = 'Perl' extensions = ['.pl', '.pm'] @@ -602,32 +608,31 @@ class Perl(mode.Fundamental): 'pod.end': ('red', 'default'), # basic stuff - 'escaped': ('magenta', 'default'), - 'null': ('default', 'default'), - #'delimiter': ('default', 'default'), - 'sub': ('cyan', 'default'), - 'prototype': ('magenta', 'default'), - 'number': ('default', 'default'), - 'operator': ('default', 'default'), - 'noperator': ('magenta', 'default'), - 'endblock': ('red', 'default'), - 'perl_keyword': ('magenta', 'default'), - 'cast': ('yellow', 'default'), - 'scalar': ('yellow', 'default'), - 'array': ('yellow', 'default'), - 'deref': ('yellow', 'default'), - 'perl_hash': ('yellow', 'default'), - 'hash_key': ('green', 'default'), - 'perl_function': ('cyan', 'default'), - 'perl_builtin': ('magenta', 'default'), - #'method': ('cyan', 'default'), - #'bareword': ('default', 'default'), - 'perl_label': ('cyan', 'default'), - 'package': ('cyan', 'default'), - 'perl_class': ('cyan', 'default'), - 'use': ('cyan', 'default'), - 'require': ('cyan', 'default'), - #'method': ('cyan', 'default'), + 'escaped': ('magenta', 'default'), + 'null': ('default', 'default'), + 'sub': ('cyan', 'default'), + 'prototype': ('magenta', 'default'), + 'number': ('default', 'default'), + 'operator': ('default', 'default'), + 'noperator': ('magenta', 'default'), + 'endblock': ('red', 'default'), + 'perl_keyword': ('magenta', 'default'), + 'cast': ('yellow', 'default'), + 'scalar': ('yellow', 'default'), + 'array': ('yellow', 'default'), + 'deref': ('yellow', 'default'), + 'perl_hash': ('yellow', 'default'), + 'hash_key': ('green', 'default'), + 'perl_function': ('cyan', 'default'), + 'perl_builtin': ('magenta', 'default'), + #'method': ('cyan', 'default'), + #'bareword': ('default', 'default'), + 'perl_label': ('cyan', 'default'), + 'package': ('cyan', 'default'), + 'perl_class': ('cyan', 'default'), + 'use': ('cyan', 'default'), + 'require': ('cyan', 'default'), + #'method': ('cyan', 'default'), # heredoc/evaldoc 'heredoc.start': ('green', 'default'), @@ -689,9 +694,11 @@ class Perl(mode.Fundamental): PerlViewModulePerldoc, PerlViewWordPerldoc, PerlWrapParagraph, PerlInitFunctions, PerlGotoFunction, PerlWhichFunction, PerlListFunctions] + completers = { + 'perlfunction': PerlFunctionCompleter(), + } def __init__(self, w): mode.Fundamental.__init__(self, w) - self.add_bindings('perl-set-lib', ('C-c l',)) self.add_bindings('perl-check-syntax', ('C-c s',)) self.add_bindings('perl-hash-cleanup', ('C-c h',)) @@ -705,8 +712,6 @@ class Perl(mode.Fundamental): self.add_bindings('close-paren', (')')) self.add_bindings('close-bracket', (']')) self.add_bindings('close-brace', ('}')) - - # perl-specific self.functions = None def build_function_map(self): diff --git a/mode/python.py b/mode/python.py index 3e55ab7..0ca6598 100644 --- a/mode/python.py +++ b/mode/python.py @@ -173,12 +173,24 @@ class PythonTabber(tab.StackTabber): self._append(token.string, currlvl + w) return currlvl -class PythonInitFunctions(method.Method): +class PythonInitNames(method.Method): '''Jump to a function defined in this module''' def _execute(self, w, **vargs): - w.mode.build_function_map() - w.application.set_error("Initialized function map") + w.mode.build_name_map() + w.application.set_error("Initialized name maps") +class PythonGotoName(method.Method): + '''Jump to a class or function defined in this module''' + args = [method.Argument("name", type(""), "pythonname", "Goto Name: ")] + def _execute(self, w, **vargs): + name = vargs['name'] + d = {} + d.update(w.mode.get_classes()) + d.update(w.mode.get_functions()) + if name in d: + w.goto(Point(0, d[name])) + else: + w.application.set_error("Function %r was not found" % name) class PythonGotoFunction(method.Method): '''Jump to a function defined in this module''' args = [method.Argument("name", type(""), "pythonfunction", "Goto Function: ")] @@ -189,13 +201,24 @@ class PythonGotoFunction(method.Method): w.goto(Point(0, functions[name])) else: w.application.set_error("Function %r was not found" % name) +class PythonGotoClass(method.Method): + '''Jump to a class defined in this module''' + args = [method.Argument("name", type(""), "pythonclass", "Goto Class: ")] + def _execute(self, w, **vargs): + name = vargs['name'] + classes = w.mode.get_classes() + if name in classes: + w.goto(Point(0, classes[name])) + else: + w.application.set_error("Class %r was not found" % name) -class PythonListFunctions(method.Method): +class PythonListNames(method.Method): '''Show the user all functions defined in this module''' def _execute(self, w, **vargs): names = w.mode.get_function_names() - output = "\n".join(names) + "\n" - w.application.data_buffer("*Python-List-Functions*", output, switch_to=True) + names.extend(w.mode.get_class_names()) + output = '\n'.join(sorted(names)) + "\n" + w.application.data_buffer("*Python-List-Names*", output, switch_to=True) class PythonCheckSyntax(method.Method): '''Check the syntax of the current python file''' @@ -307,6 +330,24 @@ class PythonInsertTripleDquotes(method.Method): for i in range(0, 3): w.backward() +class PythonFunctionCompleter(completer.Completer): + def get_candidates(self, s, w=None): + old_window = w.buffer.method.old_window + functions = old_window.mode.get_functions() + return [n for n in functions if n.startswith(s)] +class PythonClassCompleter(completer.Completer): + def get_candidates(self, s, w=None): + old_window = w.buffer.method.old_window + classes = old_window.mode.get_classes() + return [n for n in classes if n.startswith(s)] +class PythonNameCompleter(completer.Completer): + def get_candidates(self, s, w=None): + old_window = w.buffer.method.old_window + names = [] + names.extend(old_window.mode.get_classes()) + names.extend(old_window.mode.get_functions()) + return [n for n in names if n.startswith(s)] + class Python(mode.Fundamental): modename = 'Python' extensions = ['.py'] @@ -332,26 +373,34 @@ class Python(mode.Fundamental): config = { 'python.lib': '.', } - actions = [PythonInitFunctions, PythonListFunctions, PythonGotoFunction, - PythonCheckSyntax, PythonDictCleanup, PythonInsertTripleSquotes, - PythonInsertTripleDquotes] + actions = [PythonInitNames, PythonListNames, PythonGotoName, + PythonGotoFunction, PythonGotoClass, PythonCheckSyntax, + PythonDictCleanup, + PythonInsertTripleSquotes, PythonInsertTripleDquotes] + completers = { + "pythonname": PythonNameCompleter(), + "pythonfunction": PythonFunctionCompleter(), + "pythonclass": PythonClassCompleter(), + } def __init__(self, w): mode.Fundamental.__init__(self, w) - # tag matching self.add_bindings('close-paren', (')',)) self.add_bindings('close-brace', ('}',)) self.add_bindings('close-bracket', (']',)) - # add python-specific methods - self.add_bindings('python-goto-function', ('C-c M-g',)) + self.add_bindings('python-goto-name', ('C-c M-g',)) + self.add_bindings('python-goto-function', ('C-c M-f',)) + self.add_bindings('python-goto-class', ('C-c M-c',)) self.add_bindings('python-check-syntax', ('C-c s',)) self.add_bindings('python-dict-cleanup', ('C-c h',)) self.add_bindings('python-insert-triple-squotes', ('C-c M-\'',)) self.add_bindings('python-insert-triple-dquotes', ('C-c M-"',)) - # other python + + self.classes = None self.functions = None - def build_function_map(self): - b = self.window.buffer - scope_stack = [] + def build_name_map(self): + b = self.window.buffer + scope_stack = [] + self.classes = {} self.functions = {} for i in range(0, len(b.lines)): if regex.whitespace.match(b.lines[i]): @@ -368,15 +417,20 @@ class Python(mode.Fundamental): if m: (ws, typ, name) = m.groups() lvl = len(ws) + if typ == 'class': + #raise Exception, repr(m.groups()) + d = self.classes + else: + d = self.functions if scope_stack: prefix = '.'.join([x[1] for x in scope_stack]) - self.functions['%s.%s' % (prefix, name)] = i + d['%s.%s' % (prefix, name)] = i else: - self.functions[name] = i + d[name] = i scope_stack.append((len(ws), name)) def get_functions(self): if self.functions is None: - self.build_function_map() + self.build_name_map() return self.functions def get_function_names(self): functions = self.get_functions() @@ -384,5 +438,15 @@ class Python(mode.Fundamental): pairs.sort() names = [x[1] for x in pairs] return names + def get_classes(self): + if self.classes is None: + self.build_name_map() + return self.classes + def get_class_names(self): + classes = self.get_classes() + pairs = [[classes[key], key] for key in classes] + pairs.sort() + names = [x[1] for x in pairs] + return names install = Python.install diff --git a/render.py b/render.py index 8b10cdf..a4f9af1 100644 --- a/render.py +++ b/render.py @@ -9,4 +9,9 @@ class RenderString(object): self.x = x self.attrs = attrs def draw(self, cwin, y, x): - cwin.addstr(y, self.x + x, self.string, self.attrs) + try: + cwin.addstr(y, self.x + x, self.string, self.attrs) + except: + #return + raise Exception, "cwin.addstr(%d, %d + %d, %r, %r) failed" % \ + (y, self.x, x, self.string, self.attrs)