comparison runtime/autoload/pythoncomplete.vim @ 827:fd1b3406fd1c v7.0d02

updated for version 7.0d02
author vimboss
date Wed, 12 Apr 2006 21:52:12 +0000
parents
children 8e5830943bff
comparison
equal deleted inserted replaced
826:1cdd2661f34c 827:fd1b3406fd1c
1 "pythoncomplete.vim - Omni Completion for python
2 " Maintainer: Aaron Griffin
3 " Version: 0.3
4 " Last Updated: 23 January 2006
5 "
6 " v0.3 Changes:
7 " added top level def parsing
8 " for safety, call returns are not evaluated
9 " handful of parsing changes
10 " trailing ( and . characters
11 " argument completion on open parens
12 " stop parsing at current line - ++performance, local var resolution
13 "
14 " TODO
15 " RExec subclass
16 " Code cleanup + make class
17 " use internal dict, not globals()
18
19 if !has('python')
20 echo "Error: Required vim compiled with +python"
21 finish
22 endif
23
24 function! pythoncomplete#Complete(findstart, base)
25 "findstart = 1 when we need to get the text length
26 if a:findstart
27 let line = getline('.')
28 let idx = col('.')
29 while idx > 0
30 let idx -= 1
31 let c = line[idx-1]
32 if c =~ '\w'
33 continue
34 elseif ! c =~ '\.'
35 idx = -1
36 break
37 else
38 break
39 endif
40 endwhile
41
42 return idx
43 "findstart = 0 when we need to return the list of completions
44 else
45 execute "python get_completions('" . a:base . "')"
46 return g:pythoncomplete_completions
47 endif
48 endfunction
49
50 function! s:DefPython()
51 python << PYTHONEOF
52 import vim, sys, types
53 import __builtin__
54 import tokenize, keyword, cStringIO
55
56 LOCALDEFS = \
57 ['LOCALDEFS', 'clean_up','eval_source_code', \
58 'get_completions', '__builtin__', '__builtins__', \
59 'dbg', '__name__', 'vim', 'sys', 'parse_to_end', \
60 'parse_statement', 'tokenize', 'keyword', 'cStringIO', \
61 'debug_level', 'safe_eval', '_ctor', 'get_arguments', \
62 'strip_calls', 'types', 'parse_block']
63
64 def dbg(level,msg):
65 debug_level = 1
66 try:
67 debug_level = vim.eval("g:pythoncomplete_debug_level")
68 except:
69 pass
70 if level <= debug_level: print(msg)
71
72 def strip_calls(stmt):
73 parsed=''
74 level = 0
75 for c in stmt:
76 if c in ['[','(']:
77 level += 1
78 elif c in [')',']']:
79 level -= 1
80 elif level == 0:
81 parsed += c
82 ##dbg(10,"stripped: %s" % parsed)
83 return parsed
84
85 def get_completions(base):
86 stmt = vim.eval('expand("<cWORD>")')
87 #dbg(1,"statement: %s - %s" % (stmt, base))
88 stmt = stmt+base
89 eval_source_code()
90
91 try:
92 ridx = stmt.rfind('.')
93 if stmt[-1] == '(':
94 match = ""
95 stmt = strip_calls(stmt[:len(stmt)-1])
96 all = get_arguments(eval(stmt))
97 elif ridx == -1:
98 match = stmt
99 all = globals() + __builtin__.__dict__
100 else:
101 match = stmt[ridx+1:]
102 stmt = strip_calls(stmt[:ridx])
103 all = eval(stmt).__dict__
104
105 #dbg(15,"completions for: %s, match=%s" % (stmt,match))
106 completions = []
107 if type(all) == types.DictType:
108 for m in all:
109 if m.find('_') != 0 and m.find(match) == 0 and \
110 m not in LOCALDEFS:
111 #dbg(25,"matched... %s, %s" % (m, m.find(match)))
112 typestr = str(all[m])
113 if "function" in typestr: m += '('
114 elif "method" in typestr: m += '('
115 elif "module" in typestr: m += '.'
116 elif "class" in typestr: m += '('
117 completions.append(m)
118 completions.sort()
119 else:
120 completions.append(all)
121 #dbg(10,"all completions: %s" % completions)
122 vim.command("let g:pythoncomplete_completions = %s" % completions)
123 except:
124 vim.command("let g:pythoncomplete_completions = []")
125 #dbg(1,"exception: %s" % sys.exc_info()[1])
126 clean_up()
127
128 def get_arguments(func_obj):
129 def _ctor(obj):
130 try:
131 return class_ob.__init__.im_func
132 except AttributeError:
133 for base in class_ob.__bases__:
134 rc = _find_constructor(base)
135 if rc is not None: return rc
136 return None
137
138 arg_offset = 1
139 if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj)
140 elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func
141 else: arg_offset = 0
142
143 #dbg(20,"%s, offset=%s" % (str(func_obj), arg_offset))
144
145 arg_text = ''
146 if type(func_obj) in [types.FunctionType, types.LambdaType]:
147 try:
148 cd = func_obj.func_code
149 real_args = cd.co_varnames[arg_offset:cd.co_argcount]
150 defaults = func_obj.func_defaults or []
151 defaults = list(map(lambda name: "=%s" % name, defaults))
152 defaults = [""] * (len(real_args)-len(defaults)) + defaults
153 items = map(lambda a,d: a+d, real_args, defaults)
154 if func_obj.func_code.co_flags & 0x4:
155 items.append("...")
156 if func_obj.func_code.co_flags & 0x8:
157 items.append("***")
158 arg_text = ", ".join(items) + ')'
159
160 except:
161 #dbg(1,"exception: %s" % sys.exc_info()[1])
162 pass
163 if len(arg_text) == 0:
164 # The doc string sometimes contains the function signature
165 # this works for alot of C modules that are part of the
166 # standard library
167 doc = getattr(func_obj, '__doc__', '')
168 if doc:
169 doc = doc.lstrip()
170 pos = doc.find('\n')
171 if pos > 0:
172 sigline = doc[:pos]
173 lidx = sigline.find('(')
174 ridx = sigline.find(')')
175 retidx = sigline.find('->')
176 ret = sigline[retidx+2:].strip()
177 if lidx > 0 and ridx > 0:
178 arg_text = sigline[lidx+1:ridx] + ')'
179 if len(ret) > 0: arg_text += ' #returns %s' % ret
180 #dbg(15,"argument completion: %s" % arg_text)
181 return arg_text
182
183 def parse_to_end(gen):
184 stmt=''
185 level = 0
186 for type, str, begin, end, line in gen:
187 if line == vim.eval('getline(\'.\')'): break
188 elif str == '\\': continue
189 elif str == ';':
190 break
191 elif type == tokenize.NEWLINE and level == 0:
192 break
193 elif str in ['[','(']:
194 level += 1
195 elif str in [')',']']:
196 level -= 1
197 elif level == 0:
198 stmt += str
199 #dbg(10,"current statement: %s" % stmt)
200 return stmt
201
202 def parse_block(gen):
203 lines = []
204 level = 0
205 for type, str, begin, end, line in gen:
206 if line.replace('\n','') == vim.eval('getline(\'.\')'): break
207 elif type == tokenize.INDENT:
208 level += 1
209 elif type == tokenize.DEDENT:
210 level -= 1
211 if level == 0: break;
212 else:
213 stmt = parse_statement(gen,str)
214 if len(stmt) > 0: lines.append(stmt)
215 return lines
216
217 def parse_statement(gen,curstr=''):
218 var = curstr
219 type, str, begin, end, line = gen.next()
220 if str == '=':
221 type, str, begin, end, line = gen.next()
222 if type == tokenize.NEWLINE:
223 return ''
224 elif type == tokenize.STRING or str == 'str':
225 return '%s = str' % var
226 elif str == '[' or str == 'list':
227 return '%s= list' % var
228 elif str == '{' or str == 'dict':
229 return '%s = dict' % var
230 elif type == tokenize.NUMBER:
231 return '%s = 0' % var
232 elif str == 'Set':
233 return '%s = Set' % var
234 elif str == 'open' or str == 'file':
235 return '%s = file' % var
236 else:
237 inst = str + parse_to_end(gen)
238 if len(inst) > 0:
239 #dbg(5,"found [%s = %s]" % (var, inst))
240 return '%s = %s' % (var, inst)
241 return ''
242
243 def eval_source_code():
244 LINE=vim.eval('getline(\'.\')')
245 s = cStringIO.StringIO('\n'.join(vim.current.buffer[:]) + '\n')
246 g = tokenize.generate_tokens(s.readline)
247
248 stmts = []
249 lineNo = 0
250 try:
251 for type, str, begin, end, line in g:
252 if line.replace('\n','') == vim.eval('getline(\'.\')'): break
253 elif begin[0] == lineNo: continue
254 #junk
255 elif type == tokenize.INDENT or \
256 type == tokenize.DEDENT or \
257 type == tokenize.ERRORTOKEN or \
258 type == tokenize.ENDMARKER or \
259 type == tokenize.NEWLINE or \
260 type == tokenize.COMMENT:
261 continue
262 #import statement
263 elif str == 'import':
264 import_stmt=parse_to_end(g)
265 if len(import_stmt) > 0:
266 #dbg(5,"found [import %s]" % import_stmt)
267 stmts.append("import %s" % import_stmt)
268 #import from statement
269 elif str == 'from':
270 type, str, begin, end, line = g.next()
271 mod = str
272
273 type, str, begin, end, line = g.next()
274 if str != "import": break
275 from_stmt=parse_to_end(g)
276 if len(from_stmt) > 0:
277 #dbg(5,"found [from %s import %s]" % (mod, from_stmt))
278 stmts.append("from %s import %s" % (mod, from_stmt))
279 #def statement
280 elif str == 'def':
281 funcstr = ''
282 for type, str, begin, end, line in g:
283 if line.replace('\n','') == vim.eval('getline(\'.\')'): break
284 elif str == ':':
285 stmts += parse_block(g)
286 break
287 funcstr += str
288 if len(funcstr) > 0:
289 #dbg(5,"found [def %s]" % funcstr)
290 stmts.append("def %s:\n pass" % funcstr)
291 #class declaration
292 elif str == 'class':
293 type, str, begin, end, line = g.next()
294 classname = str
295 #dbg(5,"found [class %s]" % classname)
296
297 level = 0
298 members = []
299 for type, str, begin, end, line in g:
300 if line.replace('\n','') == vim.eval('getline(\'.\')'): break
301 elif type == tokenize.INDENT:
302 level += 1
303 elif type == tokenize.DEDENT:
304 level -= 1
305 if level == 0: break;
306 elif str == 'def':
307 memberstr = ''
308 for type, str, begin, end, line in g:
309 if line.replace('\n','') == vim.eval('getline(\'.\')'): break
310 elif str == ':':
311 stmts += parse_block(g)
312 break
313 memberstr += str
314 #dbg(5," member [%s]" % memberstr)
315 members.append(memberstr)
316 classstr = 'class %s:' % classname
317 for m in members:
318 classstr += ("\n def %s:\n pass" % m)
319 stmts.append("%s\n" % classstr)
320 elif keyword.iskeyword(str) or str in globals():
321 #dbg(5,"keyword = %s" % str)
322 lineNo = begin[0]
323 else:
324 assign = parse_statement(g,str)
325 if len(assign) > 0: stmts.append(assign)
326
327 for s in stmts:
328 try:
329 #dbg(15,"evaluating: %s\n" % s)
330 exec(s) in globals()
331 except:
332 #dbg(1,"exception: %s" % sys.exc_info()[1])
333 pass
334 except:
335 #dbg(1,"exception: %s" % sys.exc_info()[1])
336 pass
337
338 def clean_up():
339 for o in globals().keys():
340 if o not in LOCALDEFS:
341 try:
342 exec('del %s' % o) in globals()
343 except: pass
344
345 sys.path.extend(['.','..'])
346 PYTHONEOF
347 endfunction
348
349 let g:pythoncomplete_debug_level = 0
350 call s:DefPython()
351 " vim: set et ts=4: