##// END OF EJS Templates
First round of 'complete_command' hook, implements customizable command line ...
vivainio -
Show More
@@ -0,0 +1,47 b''
1 """ Tab completion support for a couple of linux package managers
2
3 This is also an example of how to write custom completer plugins
4 or hooks.
5
6 Practical use:
7
8 [ipython]|1> import ipy_linux_package_managers
9 [ipython]|2> apt-get u<<< press tab here >>>
10 update upgrade
11 [ipython]|2> apt-get up
12
13 """
14 import IPython.ipapi
15
16 ip = IPython.ipapi.get()
17
18 def apt_completers(self, event):
19 """ This should return a list of strings with possible completions.
20
21 Note that all the included strings that don't start with event.symbol
22 are removed, in order to not confuse readline.
23
24 """
25 # print event # dbg
26
27 # commands are only suggested for the 'command' part of package manager
28 # invocation
29
30 cmd = (event.line + "<placeholder>").rsplit(None,1)[0]
31 # print cmd
32 if cmd.endswith('apt-get') or cmd.endswith('yum'):
33 return ['update', 'upgrade', 'install', 'remove']
34
35 # later on, add dpkg -l / whatever to get list of possible
36 # packages, add switches etc. for the rest of command line
37 # filling
38
39 raise IPython.ipapi.TryNext
40
41
42 # re_key specifies the regexp that triggers the specified completer
43
44 ip.set_hook('complete_command', apt_completers, re_key = '.*apt-get')
45
46 ip.set_hook('complete_command', apt_completers, re_key = '.*yum')
47 No newline at end of file
@@ -0,0 +1,57 b''
1 from IPython.hooks import CommandChainDispatcher
2 import IPython.hooks
3
4 import re
5
6 class StrDispatch(object):
7 """ Dispatch (lookup) a set of strings / regexps for match """
8 def __init__(self):
9 self.strs = {}
10 self.regexs = {}
11 def add_s(self, s, obj, priority= 0 ):
12 """ Adds a target 'string' for dispatching """
13
14 chain = self.strs.get(s, CommandChainDispatcher())
15 chain.add(obj,priority)
16 self.strs[s] = chain
17
18 def add_re(self, regex, obj, priority= 0 ):
19 """ Adds a target regexp for dispatching """
20
21 chain = self.regexs.get(regex, CommandChainDispatcher())
22 chain.add(obj,priority)
23 self.regexs[regex] = chain
24
25 def dispatch(self, key):
26 """ Get a seq of Commandchain objects that match key """
27 if key in self.strs:
28 yield self.strs[key]
29
30 for r, obj in self.regexs.items():
31 if re.match(r, key):
32 yield obj
33 else:
34 #print "nomatch",key
35 pass
36
37
38 def __repr__(self):
39 return "<Strdispatch %s, %s>" % (self.strs, self.regexs)
40 def flat_matches(self, key):
41 """ Yield all 'value' targets, without priority """
42 for val in self.dispatch(key):
43 for el in val:
44 yield el[1] # only value, no priority
45 return
46
47
48 def test():
49 d = StrDispatch()
50 d.add_s('hei',34, priority = 4)
51 d.add_s('hei',123, priority = 2)
52 print list(d.dispatch('hei'))
53 d.add_re('h.i', 686)
54 print list(d.flat_matches('hei'))
55
56 if __name__ == '__main__':
57 test() No newline at end of file
@@ -27,7 +27,7 b' IPython tries to:'
27 27
28 28 IPython requires Python 2.3 or newer.
29 29
30 $Id: __init__.py 1328 2006-05-25 07:47:56Z fperez $"""
30 $Id: __init__.py 1854 2006-10-30 19:54:25Z vivainio $"""
31 31
32 32 #*****************************************************************************
33 33 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
@@ -51,7 +51,7 b' sys.path.append(os.path.dirname(__file__) + "/Extensions")'
51 51 __all__ = ['deep_reload','genutils','ipstruct','ultraTB','DPyGetOpt',
52 52 'Itpl','hooks','ConfigLoader','OutputTrap','Release','Shell',
53 53 'platutils','platutils_win32','platutils_posix','platutils_dummy',
54 'ipapi','rlineimpl']
54 'ipapi','rlineimpl', 'strdispatch']
55 55
56 56 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
57 57 # access to them via IPython.<name>
@@ -72,6 +72,8 b' import re'
72 72 import shlex
73 73 import sys
74 74 import IPython.rlineimpl as readline
75 from IPython.ipstruct import Struct
76 from IPython import ipapi
75 77
76 78 import types
77 79
@@ -341,7 +343,7 b' class IPCompleter(Completer):'
341 343 current (as of Python 2.3) Python readline it's possible to do
342 344 better."""
343 345
344 #print 'Completer->file_matches: <%s>' % text # dbg
346 # print 'Completer->file_matches: <%s>' % text # dbg
345 347
346 348 # chars that require escaping with backslash - i.e. chars
347 349 # that readline treats incorrectly as delimiters, but we
@@ -526,6 +528,25 b' class IPCompleter(Completer):'
526 528 argMatches.append("%s=" %namedArg)
527 529 return argMatches
528 530
531 def dispatch_custom_completer(self,text):
532 # print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
533 line = self.lbuf
534 event = Struct()
535 event.line = line
536 event.symbol = text
537 event.command = None
538 for c in self.custom_completers.flat_matches(self.lbuf):
539 # print "try",c # dbg
540 try:
541 res = c(event)
542 return [r for r in res if r.startswith(text)]
543 except ipapi.TryNext:
544 pass
545
546 return None
547
548
549
529 550 def complete(self, text, state):
530 551 """Return the next possible completion for 'text'.
531 552
@@ -547,6 +568,7 b' class IPCompleter(Completer):'
547 568 self.readline.insert_text('\t')
548 569 return None
549 570
571
550 572 magic_escape = self.magic_escape
551 573 magic_prefix = self.magic_prefix
552 574
@@ -556,26 +578,31 b' class IPCompleter(Completer):'
556 578 elif text.startswith('~'):
557 579 text = os.path.expanduser(text)
558 580 if state == 0:
559 # Extend the list of completions with the results of each
560 # matcher, so we return results to the user from all
561 # namespaces.
562 if self.merge_completions:
563 self.matches = []
564 for matcher in self.matchers:
565 self.matches.extend(matcher(text))
581 custom_res = self.dispatch_custom_completer(text)
582 if custom_res is not None:
583 # did custom completers produce something?
584 self.matches = custom_res
566 585 else:
567 for matcher in self.matchers:
568 self.matches = matcher(text)
569 if self.matches:
570 break
586 # Extend the list of completions with the results of each
587 # matcher, so we return results to the user from all
588 # namespaces.
589 if self.merge_completions:
590 self.matches = []
591 for matcher in self.matchers:
592 self.matches.extend(matcher(text))
593 else:
594 for matcher in self.matchers:
595 self.matches = matcher(text)
596 if self.matches:
597 break
571 598
572 599 try:
573 600 return self.matches[state].replace(magic_prefix,magic_escape)
574 601 except IndexError:
575 602 return None
576 603 except:
577 #from IPython.ultraTB import AutoFormattedTB; # dbg
578 #tb=AutoFormattedTB('Verbose');tb() #dbg
604 from IPython.ultraTB import AutoFormattedTB; # dbg
605 tb=AutoFormattedTB('Verbose');tb() #dbg
579 606
580 607 # If completion fails, don't annoy the user.
581 608 return None
@@ -32,7 +32,7 b" ip.set_hook('editor', calljed)"
32 32 You can then enable the functionality by doing 'import myiphooks'
33 33 somewhere in your configuration files or ipython command line.
34 34
35 $Id: hooks.py 1366 2006-06-15 19:45:50Z vivainio $"""
35 $Id: hooks.py 1854 2006-10-30 19:54:25Z vivainio $"""
36 36
37 37 #*****************************************************************************
38 38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
@@ -145,6 +145,13 b' class CommandChainDispatcher:'
145 145 """ Add a func to the cmd chain with given priority """
146 146 bisect.insort(self.chain,(priority,func))
147 147
148 def __iter__(self):
149 """ Return all objects in chain.
150
151 Handy if the objects are not callable.
152 """
153 return iter(self.chain)
154
148 155 def result_display(self,arg):
149 156 """ Default display hook.
150 157
@@ -6,7 +6,7 b' Requires Python 2.3 or newer.'
6 6
7 7 This file contains all the classes and helper functions specific to IPython.
8 8
9 $Id: iplib.py 1853 2006-10-30 17:00:39Z vivainio $
9 $Id: iplib.py 1854 2006-10-30 19:54:25Z vivainio $
10 10 """
11 11
12 12 #*****************************************************************************
@@ -72,6 +72,7 b' from IPython.ipstruct import Struct'
72 72 from IPython.background_jobs import BackgroundJobManager
73 73 from IPython.usage import cmd_line_usage,interactive_usage
74 74 from IPython.genutils import *
75 from IPython.strdispatch import StrDispatch
75 76 import IPython.ipapi
76 77
77 78 # Globals
@@ -404,6 +405,8 b' class InteractiveShell(object,Magic):'
404 405 # hooks holds pointers used for user-side customizations
405 406 self.hooks = Struct()
406 407
408 self.strdispatchers = {}
409
407 410 # Set all default hooks, defined in the IPython.hooks module.
408 411 hooks = IPython.hooks
409 412 for hook_name in hooks.__all__:
@@ -737,7 +740,7 b' class InteractiveShell(object,Magic):'
737 740 __builtin__.__dict__[biname] = bival
738 741 self.builtins_added.clear()
739 742
740 def set_hook(self,name,hook, priority = 50):
743 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
741 744 """set_hook(name,hook) -> sets an internal IPython hook.
742 745
743 746 IPython exposes some of its internal API as user-modifiable hooks. By
@@ -747,13 +750,27 b' class InteractiveShell(object,Magic):'
747 750 # At some point in the future, this should validate the hook before it
748 751 # accepts it. Probably at least check that the hook takes the number
749 752 # of args it's supposed to.
753
754 f = new.instancemethod(hook,self,self.__class__)
755
756 # check if the hook is for strdispatcher first
757 if str_key is not None:
758 sdp = self.strdispatchers.get(name, StrDispatch())
759 sdp.add_s(str_key, f, priority )
760 self.strdispatchers[name] = sdp
761 return
762 if re_key is not None:
763 sdp = self.strdispatchers.get(name, StrDispatch())
764 sdp.add_re(re.compile(re_key), f, priority )
765 self.strdispatchers[name] = sdp
766 return
767
750 768 dp = getattr(self.hooks, name, None)
751 769 if name not in IPython.hooks.__all__:
752 770 print "Warning! Hook '%s' is not one of %s" % (name, IPython.hooks.__all__ )
753 771 if not dp:
754 772 dp = IPython.hooks.CommandChainDispatcher()
755 773
756 f = new.instancemethod(hook,self,self.__class__)
757 774 try:
758 775 dp.add(f,priority)
759 776 except AttributeError:
@@ -1220,7 +1237,9 b' want to merge them back into the new files.""" % locals()'
1220 1237 self.user_global_ns,
1221 1238 self.rc.readline_omit__names,
1222 1239 self.alias_table)
1223
1240 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1241 self.strdispatchers['complete_command'] = sdisp
1242 self.Completer.custom_completers = sdisp
1224 1243 # Platform-specific configuration
1225 1244 if os.name == 'nt':
1226 1245 self.readline_startup_hook = readline.set_pre_input_hook
@@ -3,6 +3,12 b''
3 3 * Debugger.py, iplib.py (debugger()): Add last set of Rocky
4 4 Bernsteins's patches for pydb integration.
5 5 http://bashdb.sourceforge.net/pydb/
6
7 * strdispatch.py, iplib.py, completer.py, IPython/__init__.py,
8 Extensions/ipy_linux_package_managers.py, hooks.py: Implement
9 custom completer hook to allow the users to implement their own
10 completers. See ipy_linux_package_managers.py for example. The
11 hook name is 'complete_command'.
6 12
7 13 2006-10-28 Fernando Perez <Fernando.Perez@colorado.edu>
8 14
General Comments 0
You need to be logged in to leave comments. Login now