diff --git a/buffer.py b/buffer.py index 5af75e2..7e642a7 100644 --- a/buffer.py +++ b/buffer.py @@ -478,6 +478,14 @@ class IperlBuffer(InterpreterBuffer): return ('iperl', '-p') def get_env(self): return {'PERL5LIB': self.application.config.get('perl.lib', '.')} + def get_completions(self, x1, x2, line): + self.pipe.stdin.write("COMPLETE:%d:%d:%s\n" % (x1, x2, line)) + self.pipe.stdin.flush() + (typ_, value) = self.pipe_readline() + assert typ_ == 'COMPLETIONS', '%r %r' % (typ_, value) + candidates = [x for x in value.split('|') if x] + self.pipe_read() + return candidates class IpythonBuffer(InterpreterBuffer): _basename = 'IPython' diff --git a/method/introspect.py b/method/introspect.py index 10779f7..385e0a1 100644 --- a/method/introspect.py +++ b/method/introspect.py @@ -83,41 +83,34 @@ class GetToken(Method): class TokenComplete(Method): '''Complete token names based on other tokens in the buffer''' - name_overrides = {} + def _prune_candidates(self, t, minlen, candidates): + if not candidates: + return ([], t.string) + i = len(t.string) + while i < minlen: + c = candidates[0][i] + for s in candidates: + if s[i] != c: + return (candidates, candidates[0][:i]) + i += 1 + return (candidates, candidates[0][:minlen]) def _min_completion(self, w, t): h = w.get_highlighter() minlen = None - if t.name in self.name_overrides: - ok = name_overrides[t.name] - else: - ok = (t.name,) - - strings = {} + candidates = {} for line in h.tokens: for t2 in line: if t2 is t: continue - elif False and t2.name not in ok: + elif False and t2.name != t.name: continue elif t2.string.startswith(t.string): - strings[t2.string] = 1 + candidates[t2.string] = 1 if minlen is None: minlen = len(t2.string) else: minlen = min(minlen, len(t2.string)) - - strings = strings.keys() - if not strings: - return ([], t.string) - - i = len(t.string) - while i < minlen: - c = strings[0][i] - for s in strings: - if s[i] != c: - return (strings, strings[0][:i]) - i += 1 - return (strings, strings[0][:minlen]) + return self._prune_candidates(t, minlen, candidates.keys()) def _execute(self, w, **vargs): t = w.get_token2() diff --git a/mode/__init__.py b/mode/__init__.py index 2dad4ef..067ac80 100644 --- a/mode/__init__.py +++ b/mode/__init__.py @@ -190,7 +190,7 @@ class Fundamental(Handler): self.add_bindings('justify-left', ('C-c b',)) self.add_bindings('indent-block', ('C-c >',)) self.add_bindings('unindent-block', ('C-c <',)) - self.add_bindings('token-complete', ('M-c', 'C-c c', 'C-c TAB',)) + self.add_bindings('token-complete', ('C-x TAB',)) self.add_bindings('open-aes-file', ('C-c a',)) self.add_bindings('open-console', ('M-e',)) self.add_bindings('show-bindings-buffer', ('C-c M-h',)) diff --git a/mode/iperlmini.py b/mode/iperlmini.py index 59342d8..b10d528 100644 --- a/mode/iperlmini.py +++ b/mode/iperlmini.py @@ -26,7 +26,7 @@ class IperlExec(method.Method): b.pipe.stdin.write("ENTER:%s\n" % s) b.pipe.stdin.flush() - output = w.mode._read() + output = b.pipe_read() b.insert_string(b.get_buffer_end(), output, force=True) class IperlTab(method.Method): @@ -47,14 +47,7 @@ class IperlTab(method.Method): x1 -= 1 word = line[x1:x2] - b.pipe.stdin.write("COMPLETE:%d:%d:%s\n" % (x1, x2, s)) - b.pipe.stdin.flush() - (typ_, value) = w.mode._readline() - assert typ_ == 'COMPLETIONS', '%r %r' % (typ_, value) - - candidates = [x for x in value.split('|') if x] - w.mode._read() - + candidates = b.get_completions(x1, x2, s) if candidates: s = completer.find_common_string(candidates) w.buffer.delete(Point(x1, 0), Point(x2, 0), force=True) @@ -63,7 +56,7 @@ class IperlTab(method.Method): class IperlPathStart(method.Method): '''Interactively run perl statements in the context of a buffer''' - def _start(self, w, parent): + def _start(self, w, parent, switch=True): a = w.application if w.buffer.btype == 'iperl': b = w.buffer @@ -76,17 +69,17 @@ class IperlPathStart(method.Method): else: b = a.get_buffer_by_name(name) self.main_buffer = b - if a.window().buffer is not b: + if switch and a.window().buffer is not b: a.switch_buffer(b) - f = lambda x: None - w.application.open_mini_buffer('*** ', f, self, None, 'iperlmini') - def execute(self, w, **vargs): - self._start(w, w.buffer) + if switch: + w.application.open_mini_buffer('*** ', lambda x: None, self, None, 'iperlmini') + def execute(self, w, switch=True): + self._start(w, w.buffer, switch) class IperlStart(IperlPathStart): '''Interactively run perl statements''' - def execute(self, w, **vargs): - self._start(w, None) + def execute(self, w, switch=True): + self._start(w, None, switch=True) class IperlPageUp(mode.consolemini.ConsolePageUp): subbuf = '*IPerl*' diff --git a/mode/perl.py b/mode/perl.py index 0f91369..325f3c1 100644 --- a/mode/perl.py +++ b/mode/perl.py @@ -1,5 +1,5 @@ import os, re, sets, string, sys -import color, commands, completer, context, default, method, mode, regex, tab +import buffer, color, commands, completer, context, default, method, mode, regex, tab from point import Point from lex import Grammar, PatternRule, ContextPatternRule, RegionRule, OverridePatternRule, PatternGroupRule from method import Argument, Method, WrapParagraph @@ -486,6 +486,27 @@ class PerlWrapParagraph(method.WrapParagraph): else: w.set_error("did not detect comment or pod lines") +class PerlSemanticComplete(method.introspect.TokenComplete): + def _min_completion(self, w, t): + a = w.application + a.methods['iperl-path-start'].execute(w, switch=False) + + name = buffer.IperlBuffer.create_name(w.buffer) + b = a.get_buffer_by_name(name) + + line = w.buffer.lines[t.y] + (x1, x2) = (t.x, t.end_x()) + candidates = b.get_completions(x1, x2, line) + + minlen = None + for candidate in candidates: + if minlen is None: + minlen = len(candidate) + else: + minlen = min(minlen, len(candidate)) + + return self._prune_candidates(t, minlen, candidates) + class PerlOpenModule(method.Method): args = [Argument("module", type=type(""), prompt="Open Perl Module: ")] def _execute(self, w, **vargs): @@ -670,7 +691,8 @@ class Perl(mode.Fundamental): actions = [PerlSetLib, PerlCheckSyntax, PerlHashCleanup, PerlViewModulePerldoc, PerlViewWordPerldoc, PerlWrapParagraph, PerlInitFunctions, PerlGotoFunction, PerlWhichFunction, - PerlListFunctions, PerlOpenModule, PerlOpenModuleWord] + PerlListFunctions, PerlOpenModule, PerlOpenModuleWord, + PerlSemanticComplete] completers = { 'perlfunction': PerlFunctionCompleter(), } @@ -700,6 +722,7 @@ class Perl(mode.Fundamental): self.add_bindings('perl-goto-function', ('C-c M-g',)) self.add_bindings('perl-open-module', ('C-c C-f',)) self.add_bindings('perl-open-module-word', ('C-c M-f',)) + self.add_bindings('perl-semantic-complete', ('C-c TAB',)) self.add_bindings('close-paren', (')')) self.add_bindings('close-bracket', (']')) self.add_bindings('close-brace', ('}'))