##// 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 IPython requires Python 2.3 or newer.
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 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
33 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
@@ -51,7 +51,7 b' sys.path.append(os.path.dirname(__file__) + "/Extensions")'
51 __all__ = ['deep_reload','genutils','ipstruct','ultraTB','DPyGetOpt',
51 __all__ = ['deep_reload','genutils','ipstruct','ultraTB','DPyGetOpt',
52 'Itpl','hooks','ConfigLoader','OutputTrap','Release','Shell',
52 'Itpl','hooks','ConfigLoader','OutputTrap','Release','Shell',
53 'platutils','platutils_win32','platutils_posix','platutils_dummy',
53 'platutils','platutils_win32','platutils_posix','platutils_dummy',
54 'ipapi','rlineimpl']
54 'ipapi','rlineimpl', 'strdispatch']
55
55
56 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
56 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
57 # access to them via IPython.<name>
57 # access to them via IPython.<name>
@@ -72,6 +72,8 b' import re'
72 import shlex
72 import shlex
73 import sys
73 import sys
74 import IPython.rlineimpl as readline
74 import IPython.rlineimpl as readline
75 from IPython.ipstruct import Struct
76 from IPython import ipapi
75
77
76 import types
78 import types
77
79
@@ -341,7 +343,7 b' class IPCompleter(Completer):'
341 current (as of Python 2.3) Python readline it's possible to do
343 current (as of Python 2.3) Python readline it's possible to do
342 better."""
344 better."""
343
345
344 #print 'Completer->file_matches: <%s>' % text # dbg
346 # print 'Completer->file_matches: <%s>' % text # dbg
345
347
346 # chars that require escaping with backslash - i.e. chars
348 # chars that require escaping with backslash - i.e. chars
347 # that readline treats incorrectly as delimiters, but we
349 # that readline treats incorrectly as delimiters, but we
@@ -526,6 +528,25 b' class IPCompleter(Completer):'
526 argMatches.append("%s=" %namedArg)
528 argMatches.append("%s=" %namedArg)
527 return argMatches
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 def complete(self, text, state):
550 def complete(self, text, state):
530 """Return the next possible completion for 'text'.
551 """Return the next possible completion for 'text'.
531
552
@@ -547,6 +568,7 b' class IPCompleter(Completer):'
547 self.readline.insert_text('\t')
568 self.readline.insert_text('\t')
548 return None
569 return None
549
570
571
550 magic_escape = self.magic_escape
572 magic_escape = self.magic_escape
551 magic_prefix = self.magic_prefix
573 magic_prefix = self.magic_prefix
552
574
@@ -556,26 +578,31 b' class IPCompleter(Completer):'
556 elif text.startswith('~'):
578 elif text.startswith('~'):
557 text = os.path.expanduser(text)
579 text = os.path.expanduser(text)
558 if state == 0:
580 if state == 0:
559 # Extend the list of completions with the results of each
581 custom_res = self.dispatch_custom_completer(text)
560 # matcher, so we return results to the user from all
582 if custom_res is not None:
561 # namespaces.
583 # did custom completers produce something?
562 if self.merge_completions:
584 self.matches = custom_res
563 self.matches = []
564 for matcher in self.matchers:
565 self.matches.extend(matcher(text))
566 else:
585 else:
567 for matcher in self.matchers:
586 # Extend the list of completions with the results of each
568 self.matches = matcher(text)
587 # matcher, so we return results to the user from all
569 if self.matches:
588 # namespaces.
570 break
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 try:
599 try:
573 return self.matches[state].replace(magic_prefix,magic_escape)
600 return self.matches[state].replace(magic_prefix,magic_escape)
574 except IndexError:
601 except IndexError:
575 return None
602 return None
576 except:
603 except:
577 #from IPython.ultraTB import AutoFormattedTB; # dbg
604 from IPython.ultraTB import AutoFormattedTB; # dbg
578 #tb=AutoFormattedTB('Verbose');tb() #dbg
605 tb=AutoFormattedTB('Verbose');tb() #dbg
579
606
580 # If completion fails, don't annoy the user.
607 # If completion fails, don't annoy the user.
581 return None
608 return None
@@ -32,7 +32,7 b" ip.set_hook('editor', calljed)"
32 You can then enable the functionality by doing 'import myiphooks'
32 You can then enable the functionality by doing 'import myiphooks'
33 somewhere in your configuration files or ipython command line.
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 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
@@ -145,6 +145,13 b' class CommandChainDispatcher:'
145 """ Add a func to the cmd chain with given priority """
145 """ Add a func to the cmd chain with given priority """
146 bisect.insort(self.chain,(priority,func))
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 def result_display(self,arg):
155 def result_display(self,arg):
149 """ Default display hook.
156 """ Default display hook.
150
157
@@ -6,7 +6,7 b' Requires Python 2.3 or newer.'
6
6
7 This file contains all the classes and helper functions specific to IPython.
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 from IPython.background_jobs import BackgroundJobManager
72 from IPython.background_jobs import BackgroundJobManager
73 from IPython.usage import cmd_line_usage,interactive_usage
73 from IPython.usage import cmd_line_usage,interactive_usage
74 from IPython.genutils import *
74 from IPython.genutils import *
75 from IPython.strdispatch import StrDispatch
75 import IPython.ipapi
76 import IPython.ipapi
76
77
77 # Globals
78 # Globals
@@ -404,6 +405,8 b' class InteractiveShell(object,Magic):'
404 # hooks holds pointers used for user-side customizations
405 # hooks holds pointers used for user-side customizations
405 self.hooks = Struct()
406 self.hooks = Struct()
406
407
408 self.strdispatchers = {}
409
407 # Set all default hooks, defined in the IPython.hooks module.
410 # Set all default hooks, defined in the IPython.hooks module.
408 hooks = IPython.hooks
411 hooks = IPython.hooks
409 for hook_name in hooks.__all__:
412 for hook_name in hooks.__all__:
@@ -737,7 +740,7 b' class InteractiveShell(object,Magic):'
737 __builtin__.__dict__[biname] = bival
740 __builtin__.__dict__[biname] = bival
738 self.builtins_added.clear()
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 """set_hook(name,hook) -> sets an internal IPython hook.
744 """set_hook(name,hook) -> sets an internal IPython hook.
742
745
743 IPython exposes some of its internal API as user-modifiable hooks. By
746 IPython exposes some of its internal API as user-modifiable hooks. By
@@ -747,13 +750,27 b' class InteractiveShell(object,Magic):'
747 # At some point in the future, this should validate the hook before it
750 # At some point in the future, this should validate the hook before it
748 # accepts it. Probably at least check that the hook takes the number
751 # accepts it. Probably at least check that the hook takes the number
749 # of args it's supposed to.
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 dp = getattr(self.hooks, name, None)
768 dp = getattr(self.hooks, name, None)
751 if name not in IPython.hooks.__all__:
769 if name not in IPython.hooks.__all__:
752 print "Warning! Hook '%s' is not one of %s" % (name, IPython.hooks.__all__ )
770 print "Warning! Hook '%s' is not one of %s" % (name, IPython.hooks.__all__ )
753 if not dp:
771 if not dp:
754 dp = IPython.hooks.CommandChainDispatcher()
772 dp = IPython.hooks.CommandChainDispatcher()
755
773
756 f = new.instancemethod(hook,self,self.__class__)
757 try:
774 try:
758 dp.add(f,priority)
775 dp.add(f,priority)
759 except AttributeError:
776 except AttributeError:
@@ -1220,7 +1237,9 b' want to merge them back into the new files.""" % locals()'
1220 self.user_global_ns,
1237 self.user_global_ns,
1221 self.rc.readline_omit__names,
1238 self.rc.readline_omit__names,
1222 self.alias_table)
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 # Platform-specific configuration
1243 # Platform-specific configuration
1225 if os.name == 'nt':
1244 if os.name == 'nt':
1226 self.readline_startup_hook = readline.set_pre_input_hook
1245 self.readline_startup_hook = readline.set_pre_input_hook
@@ -3,6 +3,12 b''
3 * Debugger.py, iplib.py (debugger()): Add last set of Rocky
3 * Debugger.py, iplib.py (debugger()): Add last set of Rocky
4 Bernsteins's patches for pydb integration.
4 Bernsteins's patches for pydb integration.
5 http://bashdb.sourceforge.net/pydb/
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 2006-10-28 Fernando Perez <Fernando.Perez@colorado.edu>
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