##// END OF EJS Templates
Applied Joergen's patch for %run completer quote mismatch exception, closing #127.
vivainio -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,230 +1,248 b''
1 """ Tab completion support for a couple of linux package managers
1 """ Tab completion support for a couple of linux package managers
2
2
3 This is also an example of how to write custom completer plugins
3 This is also an example of how to write custom completer plugins
4 or hooks.
4 or hooks.
5
5
6 Practical use:
6 Practical use:
7
7
8 [ipython]|1> import ipy_linux_package_managers
8 [ipython]|1> import ipy_linux_package_managers
9 [ipython]|2> apt-get u<<< press tab here >>>
9 [ipython]|2> apt-get u<<< press tab here >>>
10 update upgrade
10 update upgrade
11 [ipython]|2> apt-get up
11 [ipython]|2> apt-get up
12
12
13 """
13 """
14 import IPython.ipapi
14 import IPython.ipapi
15 import glob,os,shlex,sys
15 import glob,os,shlex,sys
16
16
17 ip = IPython.ipapi.get()
17 ip = IPython.ipapi.get()
18
18
19 def vcs_completer(commands, event):
19 def vcs_completer(commands, event):
20 """ utility to make writing typical version control app completers easier
20 """ utility to make writing typical version control app completers easier
21
21
22 VCS command line apps typically have the format:
22 VCS command line apps typically have the format:
23
23
24 [sudo ]PROGNAME [help] [command] file file...
24 [sudo ]PROGNAME [help] [command] file file...
25
25
26 """
26 """
27
27
28
28
29 cmd_param = event.line.split()
29 cmd_param = event.line.split()
30 if event.line.endswith(' '):
30 if event.line.endswith(' '):
31 cmd_param.append('')
31 cmd_param.append('')
32
32
33 if cmd_param[0] == 'sudo':
33 if cmd_param[0] == 'sudo':
34 cmd_param = cmd_param[1:]
34 cmd_param = cmd_param[1:]
35
35
36 if len(cmd_param) == 2 or 'help' in cmd_param:
36 if len(cmd_param) == 2 or 'help' in cmd_param:
37 return commands.split()
37 return commands.split()
38
38
39 return ip.IP.Completer.file_matches(event.symbol)
39 return ip.IP.Completer.file_matches(event.symbol)
40
40
41
41
42
42
43 def apt_completers(self, event):
43 def apt_completers(self, event):
44 """ This should return a list of strings with possible completions.
44 """ This should return a list of strings with possible completions.
45
45
46 Note that all the included strings that don't start with event.symbol
46 Note that all the included strings that don't start with event.symbol
47 are removed, in order to not confuse readline.
47 are removed, in order to not confuse readline.
48
48
49 """
49 """
50 # print event # dbg
50 # print event # dbg
51
51
52 # commands are only suggested for the 'command' part of package manager
52 # commands are only suggested for the 'command' part of package manager
53 # invocation
53 # invocation
54
54
55 cmd = (event.line + "<placeholder>").rsplit(None,1)[0]
55 cmd = (event.line + "<placeholder>").rsplit(None,1)[0]
56 # print cmd
56 # print cmd
57 if cmd.endswith('apt-get') or cmd.endswith('yum'):
57 if cmd.endswith('apt-get') or cmd.endswith('yum'):
58 return ['update', 'upgrade', 'install', 'remove']
58 return ['update', 'upgrade', 'install', 'remove']
59
59
60 # later on, add dpkg -l / whatever to get list of possible
60 # later on, add dpkg -l / whatever to get list of possible
61 # packages, add switches etc. for the rest of command line
61 # packages, add switches etc. for the rest of command line
62 # filling
62 # filling
63
63
64 raise IPython.ipapi.TryNext
64 raise IPython.ipapi.TryNext
65
65
66
66
67 # re_key specifies the regexp that triggers the specified completer
67 # re_key specifies the regexp that triggers the specified completer
68
68
69 ip.set_hook('complete_command', apt_completers, re_key = '.*apt-get')
69 ip.set_hook('complete_command', apt_completers, re_key = '.*apt-get')
70 ip.set_hook('complete_command', apt_completers, re_key = '.*yum')
70 ip.set_hook('complete_command', apt_completers, re_key = '.*yum')
71
71
72 pkg_cache = None
72 pkg_cache = None
73
73
74 def module_completer(self,event):
74 def module_completer(self,event):
75 """ Give completions after user has typed 'import' """
75 """ Give completions after user has typed 'import' """
76
76
77 # only a local version for py 2.4, pkgutil has no walk_packages() there
77 # only a local version for py 2.4, pkgutil has no walk_packages() there
78 if sys.version_info < (2,5):
78 if sys.version_info < (2,5):
79 for el in [f[:-3] for f in glob.glob("*.py")]:
79 for el in [f[:-3] for f in glob.glob("*.py")]:
80 yield el
80 yield el
81 return
81 return
82
82
83 global pkg_cache
83 global pkg_cache
84 import pkgutil,imp,time
84 import pkgutil,imp,time
85 #current =
85 #current =
86 if pkg_cache is None:
86 if pkg_cache is None:
87 print "\n\n[Standby while scanning modules, this can take a while]\n\n"
87 print "\n\n[Standby while scanning modules, this can take a while]\n\n"
88 pkg_cache = list(pkgutil.walk_packages())
88 pkg_cache = list(pkgutil.walk_packages())
89
89
90 already = set()
90 already = set()
91 for ld, name, ispkg in pkg_cache:
91 for ld, name, ispkg in pkg_cache:
92 if name.count('.') < event.symbol.count('.') + 1:
92 if name.count('.') < event.symbol.count('.') + 1:
93 if name not in already:
93 if name not in already:
94 already.add(name)
94 already.add(name)
95 yield name + (ispkg and '.' or '')
95 yield name + (ispkg and '.' or '')
96 return
96 return
97
97
98 ip.set_hook('complete_command', module_completer, str_key = 'import')
98 ip.set_hook('complete_command', module_completer, str_key = 'import')
99 ip.set_hook('complete_command', module_completer, str_key = 'from')
99 ip.set_hook('complete_command', module_completer, str_key = 'from')
100
100
101 svn_commands = """\
101 svn_commands = """\
102 add blame praise annotate ann cat checkout co cleanup commit ci copy
102 add blame praise annotate ann cat checkout co cleanup commit ci copy
103 cp delete del remove rm diff di export help ? h import info list ls
103 cp delete del remove rm diff di export help ? h import info list ls
104 lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
104 lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
105 pe propget pget pg proplist plist pl propset pset ps resolved revert
105 pe propget pget pg proplist plist pl propset pset ps resolved revert
106 status stat st switch sw unlock update
106 status stat st switch sw unlock update
107 """
107 """
108
108
109 def svn_completer(self,event):
109 def svn_completer(self,event):
110 return vcs_completer(svn_commands, event)
110 return vcs_completer(svn_commands, event)
111
111
112 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
112 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
113
113
114 hg_commands = """
114 hg_commands = """
115 add addremove annotate archive backout branch branches bundle cat
115 add addremove annotate archive backout branch branches bundle cat
116 clone commit copy diff export grep heads help identify import incoming
116 clone commit copy diff export grep heads help identify import incoming
117 init locate log manifest merge outgoing parents paths pull push
117 init locate log manifest merge outgoing parents paths pull push
118 qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
118 qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
119 qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
119 qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
120 qselect qseries qtop qunapplied recover remove rename revert rollback
120 qselect qseries qtop qunapplied recover remove rename revert rollback
121 root serve showconfig status strip tag tags tip unbundle update verify
121 root serve showconfig status strip tag tags tip unbundle update verify
122 version
122 version
123 """
123 """
124
124
125 def hg_completer(self,event):
125 def hg_completer(self,event):
126 """ Completer for mercurial commands """
126 """ Completer for mercurial commands """
127
127
128 return vcs_completer(hg_commands, event)
128 return vcs_completer(hg_commands, event)
129
129
130 ip.set_hook('complete_command', hg_completer, str_key = 'hg')
130 ip.set_hook('complete_command', hg_completer, str_key = 'hg')
131
131
132
132
133 bzr_commands = """
133 bzr_commands = """
134 add annotate bind branch break-lock bundle-revisions cat check
134 add annotate bind branch break-lock bundle-revisions cat check
135 checkout commit conflicts deleted diff export gannotate gbranch
135 checkout commit conflicts deleted diff export gannotate gbranch
136 gcommit gdiff help ignore ignored info init init-repository inventory
136 gcommit gdiff help ignore ignored info init init-repository inventory
137 log merge missing mkdir mv nick pull push reconcile register-branch
137 log merge missing mkdir mv nick pull push reconcile register-branch
138 remerge remove renames resolve revert revno root serve sign-my-commits
138 remerge remove renames resolve revert revno root serve sign-my-commits
139 status testament unbind uncommit unknowns update upgrade version
139 status testament unbind uncommit unknowns update upgrade version
140 version-info visualise whoami
140 version-info visualise whoami
141 """
141 """
142
142
143 def bzr_completer(self,event):
143 def bzr_completer(self,event):
144 """ Completer for bazaar commands """
144 """ Completer for bazaar commands """
145 cmd_param = event.line.split()
145 cmd_param = event.line.split()
146 if event.line.endswith(' '):
146 if event.line.endswith(' '):
147 cmd_param.append('')
147 cmd_param.append('')
148
148
149 if len(cmd_param) > 2:
149 if len(cmd_param) > 2:
150 cmd = cmd_param[1]
150 cmd = cmd_param[1]
151 param = cmd_param[-1]
151 param = cmd_param[-1]
152 output_file = (param == '--output=')
152 output_file = (param == '--output=')
153 if cmd == 'help':
153 if cmd == 'help':
154 return bzr_commands.split()
154 return bzr_commands.split()
155 elif cmd in ['bundle-revisions','conflicts',
155 elif cmd in ['bundle-revisions','conflicts',
156 'deleted','nick','register-branch',
156 'deleted','nick','register-branch',
157 'serve','unbind','upgrade','version',
157 'serve','unbind','upgrade','version',
158 'whoami'] and not output_file:
158 'whoami'] and not output_file:
159 return []
159 return []
160 else:
160 else:
161 # the rest are probably file names
161 # the rest are probably file names
162 return ip.IP.Completer.file_matches(event.symbol)
162 return ip.IP.Completer.file_matches(event.symbol)
163
163
164 return bzr_commands.split()
164 return bzr_commands.split()
165
165
166 ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
166 ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
167
167
168 def shlex_split(x):
169 """Helper function to split lines into segments."""
170 #shlex.split raise exception if syntax error in sh syntax
171 #for example if no closing " is found. This function keeps dropping
172 #the last character of the line until shlex.split does not raise
173 #exception. Adds end of the line to the result of shlex.split
174 #example: %run "c:/python -> ['%run','"c:/python']
175 endofline=[]
176 while x!="":
177 try:
178 comps=shlex.split(x)
179 if endofline>=1:
180 comps.append("".join(endofline))
181 return comps
182 except ValueError:
183 endofline=[x[-1:]]+endofline
184 x=x[:-1]
185 return ["".join(endofline)]
168
186
169 def runlistpy(self, event):
187 def runlistpy(self, event):
170 comps = shlex.split(event.line)
188 comps = shlex_split(event.line)
171 relpath = (len(comps) > 1 and comps[-1] or '')
189 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
172
190
173 #print "\nev=",event # dbg
191 #print "\nev=",event # dbg
174 #print "rp=",relpath # dbg
192 #print "rp=",relpath # dbg
175 #print 'comps=',comps # dbg
193 #print 'comps=',comps # dbg
176
194
177 lglob = glob.glob
195 lglob = glob.glob
178 isdir = os.path.isdir
196 isdir = os.path.isdir
179 if relpath.startswith('~'):
197 if relpath.startswith('~'):
180 relpath = os.path.expanduser(relpath)
198 relpath = os.path.expanduser(relpath)
181 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
199 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
182 if isdir(f)]
200 if isdir(f)]
183
201
184 # Find if the user has already typed the first filename, after which we
202 # Find if the user has already typed the first filename, after which we
185 # should complete on all files, since after the first one other files may
203 # should complete on all files, since after the first one other files may
186 # be arguments to the input script.
204 # be arguments to the input script.
187 #filter(
205 #filter(
188 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy'),comps):
206 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy'),comps):
189 pys = [f.replace('\\','/') for f in lglob('*')]
207 pys = [f.replace('\\','/') for f in lglob('*')]
190 else:
208 else:
191 pys = [f.replace('\\','/')
209 pys = [f.replace('\\','/')
192 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy')]
210 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy')]
193 return dirs + pys
211 return dirs + pys
194
212
195 ip.set_hook('complete_command', runlistpy, str_key = '%run')
213 ip.set_hook('complete_command', runlistpy, str_key = '%run')
196
214
197 def cd_completer(self, event):
215 def cd_completer(self, event):
198 relpath = event.symbol
216 relpath = event.symbol
199 #print event # dbg
217 #print event # dbg
200 if '-b' in event.line:
218 if '-b' in event.line:
201 # return only bookmark completions
219 # return only bookmark completions
202 bkms = self.db.get('bookmarks',{})
220 bkms = self.db.get('bookmarks',{})
203 return bkms.keys()
221 return bkms.keys()
204
222
205
223
206 if event.symbol == '-':
224 if event.symbol == '-':
207 # jump in directory history by number
225 # jump in directory history by number
208 ents = ['-%d [%s]' % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
226 ents = ['-%d [%s]' % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
209 if len(ents) > 1:
227 if len(ents) > 1:
210 return ents
228 return ents
211 return []
229 return []
212
230
213 if relpath.startswith('~'):
231 if relpath.startswith('~'):
214 relpath = os.path.expanduser(relpath).replace('\\','/')
232 relpath = os.path.expanduser(relpath).replace('\\','/')
215 found = []
233 found = []
216 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
234 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
217 if os.path.isdir(f)]:
235 if os.path.isdir(f)]:
218 if ' ' in d:
236 if ' ' in d:
219 # we don't want to deal with any of that, complex code
237 # we don't want to deal with any of that, complex code
220 # for this is elsewhere
238 # for this is elsewhere
221 raise IPython.ipapi.TryNext
239 raise IPython.ipapi.TryNext
222 found.append( d )
240 found.append( d )
223
241
224 if not found:
242 if not found:
225 if os.path.isdir(relpath):
243 if os.path.isdir(relpath):
226 return [relpath]
244 return [relpath]
227 raise IPython.ipapi.TryNext
245 raise IPython.ipapi.TryNext
228 return found
246 return found
229
247
230 ip.set_hook('complete_command', cd_completer, str_key = '%cd')
248 ip.set_hook('complete_command', cd_completer, str_key = '%cd')
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now