160 |
ira |
1 |
" -*- vim -*-
|
|
|
2 |
" FILE: python.vim
|
|
|
3 |
" LAST MODIFICATION: 2003/07/25 19:00
|
|
|
4 |
" (C) Copyright 2001-2003 Mikael Berthe <mikael.b@netcourrier.com>
|
|
|
5 |
" Version: 1.7
|
|
|
6 |
|
|
|
7 |
" USAGE:
|
|
|
8 |
"
|
|
|
9 |
" Just source this script when editing Python files.
|
|
|
10 |
" Example: au FileType python source ~me/.vim/scripts/python.vim
|
|
|
11 |
" You can set the global variable "g:py_select_leading_comments" to 0
|
|
|
12 |
" if you don't want to select comments preceding a declaration (these
|
|
|
13 |
" are usually the description of the function/class).
|
|
|
14 |
" You can set the global variable "g:py_select_trailing_comments" to 0
|
|
|
15 |
" if you don't want to select comments at the end of a function/class.
|
|
|
16 |
" If these variables are not defined, both leading and trailing comments
|
|
|
17 |
" are selected.
|
|
|
18 |
" Example: (in your .vimrc) "let g:py_select_leading_comments = 0"
|
|
|
19 |
" You may want to take a look at the 'shiftwidth' option for the
|
|
|
20 |
" shift commands...
|
|
|
21 |
"
|
|
|
22 |
" REQUIREMENTS:
|
|
|
23 |
" vim (>= 6)
|
|
|
24 |
"
|
|
|
25 |
" Shortcuts:
|
|
|
26 |
" [[ -- Jump to beginning of block
|
|
|
27 |
" ]] -- Jump to end of block
|
|
|
28 |
" ]v -- Select (Visual Line Mode) block
|
|
|
29 |
" ]< -- Shift block to left
|
|
|
30 |
" ]> -- Shift block to right
|
|
|
31 |
" ]c -- Select current/previous class
|
|
|
32 |
" ]f -- Select current/previous function
|
|
|
33 |
" ]<up> -- Jump to previous line with the same/lower indentation
|
|
|
34 |
" ]<down> -- Jump to next line with the same/lower indentation
|
|
|
35 |
|
|
|
36 |
|
|
|
37 |
map [[ :PBoB<CR>
|
|
|
38 |
vmap [[ :<C-U>PBoB<CR>m'gv``
|
|
|
39 |
map ]] :PEoB<CR>
|
|
|
40 |
vmap ]] :<C-U>PEoB<CR>m'gv``
|
|
|
41 |
|
|
|
42 |
map ]v [[V]]
|
|
|
43 |
map ]< [[V]]<
|
|
|
44 |
vmap ]< <
|
|
|
45 |
map ]> [[V]]>
|
|
|
46 |
vmap ]> >
|
|
|
47 |
|
|
|
48 |
map ]c :call PythonSelectObject("class")<CR>
|
|
|
49 |
map ]f :call PythonSelectObject("function")<CR>
|
|
|
50 |
|
|
|
51 |
map ]<up> :call PythonNextLine(-1)<CR>
|
|
|
52 |
map ]<down> :call PythonNextLine(1)<CR>
|
|
|
53 |
" You may prefer use <s-up> and <s-down>... :-)
|
|
|
54 |
|
|
|
55 |
|
|
|
56 |
|
|
|
57 |
" Menu entries
|
|
|
58 |
nmenu <silent> &Python.Update\ IM-Python\ Menu
|
|
|
59 |
\:call UpdateMenu()<CR>
|
|
|
60 |
nmenu &Python.-Sep1- :
|
|
|
61 |
nmenu <silent> &Python.Beginning\ of\ Block<Tab>[[
|
|
|
62 |
\[[
|
|
|
63 |
nmenu <silent> &Python.End\ of\ Block<Tab>]]
|
|
|
64 |
\]]
|
|
|
65 |
nmenu &Python.-Sep2- :
|
|
|
66 |
nmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
|
|
|
67 |
\]<
|
|
|
68 |
vmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
|
|
|
69 |
\]<
|
|
|
70 |
nmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
|
|
|
71 |
\]>
|
|
|
72 |
vmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
|
|
|
73 |
\]>
|
|
|
74 |
nmenu &Python.-Sep3- :
|
|
|
75 |
vmenu <silent> &Python.Comment\ Selection
|
|
|
76 |
\:call PythonCommentSelection()<CR>
|
|
|
77 |
nmenu <silent> &Python.Comment\ Selection
|
|
|
78 |
\:call PythonCommentSelection()<CR>
|
|
|
79 |
vmenu <silent> &Python.Uncomment\ Selection
|
|
|
80 |
\:call PythonUncommentSelection()<CR>
|
|
|
81 |
nmenu <silent> &Python.Uncomment\ Selection
|
|
|
82 |
\:call PythonUncommentSelection()<CR>
|
|
|
83 |
nmenu &Python.-Sep4- :
|
|
|
84 |
nmenu <silent> &Python.Previous\ Class
|
|
|
85 |
\:call PythonDec("class", -1)<CR>
|
|
|
86 |
nmenu <silent> &Python.Next\ Class
|
|
|
87 |
\:call PythonDec("class", 1)<CR>
|
|
|
88 |
nmenu <silent> &Python.Previous\ Function
|
|
|
89 |
\:call PythonDec("function", -1)<CR>
|
|
|
90 |
nmenu <silent> &Python.Next\ Function
|
|
|
91 |
\:call PythonDec("function", 1)<CR>
|
|
|
92 |
nmenu &Python.-Sep5- :
|
|
|
93 |
nmenu <silent> &Python.Select\ Block<Tab>]v
|
|
|
94 |
\]v
|
|
|
95 |
nmenu <silent> &Python.Select\ Function<Tab>]f
|
|
|
96 |
\]f
|
|
|
97 |
nmenu <silent> &Python.Select\ Class<Tab>]c
|
|
|
98 |
\]c
|
|
|
99 |
nmenu &Python.-Sep6- :
|
|
|
100 |
nmenu <silent> &Python.Previous\ Line\ wrt\ indent<Tab>]<up>
|
|
|
101 |
\]<up>
|
|
|
102 |
nmenu <silent> &Python.Next\ Line\ wrt\ indent<Tab>]<down>
|
|
|
103 |
\]<down>
|
|
|
104 |
|
|
|
105 |
|
|
|
106 |
:com! PBoB execute "normal ".PythonBoB(line('.'), -1, 1)."G"
|
|
|
107 |
:com! PEoB execute "normal ".PythonBoB(line('.'), 1, 1)."G"
|
|
|
108 |
:com! UpdateMenu call UpdateMenu()
|
|
|
109 |
|
|
|
110 |
|
|
|
111 |
" Go to a block boundary (-1: previous, 1: next)
|
|
|
112 |
" If force_sel_comments is true, 'g:py_select_trailing_comments' is ignored
|
|
|
113 |
function! PythonBoB(line, direction, force_sel_comments)
|
|
|
114 |
let ln = a:line
|
|
|
115 |
let ind = indent(ln)
|
|
|
116 |
let mark = ln
|
|
|
117 |
let indent_valid = strlen(getline(ln))
|
|
|
118 |
let ln = ln + a:direction
|
|
|
119 |
if (a:direction == 1) && (!a:force_sel_comments) &&
|
|
|
120 |
\ exists("g:py_select_trailing_comments") &&
|
|
|
121 |
\ (!g:py_select_trailing_comments)
|
|
|
122 |
let sel_comments = 0
|
|
|
123 |
else
|
|
|
124 |
let sel_comments = 1
|
|
|
125 |
endif
|
|
|
126 |
|
|
|
127 |
while((ln >= 1) && (ln <= line('$')))
|
|
|
128 |
if (sel_comments) || (match(getline(ln), "^\\s*#") == -1)
|
|
|
129 |
if (!indent_valid)
|
|
|
130 |
let indent_valid = strlen(getline(ln))
|
|
|
131 |
let ind = indent(ln)
|
|
|
132 |
let mark = ln
|
|
|
133 |
else
|
|
|
134 |
if (strlen(getline(ln)))
|
|
|
135 |
if (indent(ln) < ind)
|
|
|
136 |
break
|
|
|
137 |
endif
|
|
|
138 |
let mark = ln
|
|
|
139 |
endif
|
|
|
140 |
endif
|
|
|
141 |
endif
|
|
|
142 |
let ln = ln + a:direction
|
|
|
143 |
endwhile
|
|
|
144 |
|
|
|
145 |
return mark
|
|
|
146 |
endfunction
|
|
|
147 |
|
|
|
148 |
|
|
|
149 |
" Go to previous (-1) or next (1) class/function definition
|
|
|
150 |
function! PythonDec(obj, direction)
|
|
|
151 |
if (a:obj == "class")
|
|
|
152 |
let objregexp = "^\\s*class\\s\\+[a-zA-Z0-9_]\\+"
|
|
|
153 |
\ . "\\s*\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*:"
|
|
|
154 |
else
|
|
|
155 |
let objregexp = "^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*:"
|
|
|
156 |
endif
|
|
|
157 |
let flag = "W"
|
|
|
158 |
if (a:direction == -1)
|
|
|
159 |
let flag = flag."b"
|
|
|
160 |
endif
|
|
|
161 |
let res = search(objregexp, flag)
|
|
|
162 |
endfunction
|
|
|
163 |
|
|
|
164 |
|
|
|
165 |
" Comment out selected lines
|
|
|
166 |
" commentString is inserted in non-empty lines, and should be aligned with
|
|
|
167 |
" the block
|
|
|
168 |
function! PythonCommentSelection() range
|
|
|
169 |
let commentString = "#"
|
|
|
170 |
let cl = a:firstline
|
|
|
171 |
let ind = 1000 " I hope nobody use so long lines! :)
|
|
|
172 |
|
|
|
173 |
" Look for smallest indent
|
|
|
174 |
while (cl <= a:lastline)
|
|
|
175 |
if strlen(getline(cl))
|
|
|
176 |
let cind = indent(cl)
|
|
|
177 |
let ind = ((ind < cind) ? ind : cind)
|
|
|
178 |
endif
|
|
|
179 |
let cl = cl + 1
|
|
|
180 |
endwhile
|
|
|
181 |
if (ind == 1000)
|
|
|
182 |
let ind = 1
|
|
|
183 |
else
|
|
|
184 |
let ind = ind + 1
|
|
|
185 |
endif
|
|
|
186 |
|
|
|
187 |
let cl = a:firstline
|
|
|
188 |
execute ":".cl
|
|
|
189 |
" Insert commentString in each non-empty line, in column ind
|
|
|
190 |
while (cl <= a:lastline)
|
|
|
191 |
if strlen(getline(cl))
|
|
|
192 |
execute "normal ".ind."|i".commentString
|
|
|
193 |
endif
|
|
|
194 |
execute "normal \<Down>"
|
|
|
195 |
let cl = cl + 1
|
|
|
196 |
endwhile
|
|
|
197 |
endfunction
|
|
|
198 |
|
|
|
199 |
" Uncomment selected lines
|
|
|
200 |
function! PythonUncommentSelection() range
|
|
|
201 |
" commentString could be different than the one from CommentSelection()
|
|
|
202 |
" For example, this could be "# \\="
|
|
|
203 |
let commentString = "#"
|
|
|
204 |
let cl = a:firstline
|
|
|
205 |
while (cl <= a:lastline)
|
|
|
206 |
let ul = substitute(getline(cl),
|
|
|
207 |
\"\\(\\s*\\)".commentString."\\(.*\\)$", "\\1\\2", "")
|
|
|
208 |
call setline(cl, ul)
|
|
|
209 |
let cl = cl + 1
|
|
|
210 |
endwhile
|
|
|
211 |
endfunction
|
|
|
212 |
|
|
|
213 |
|
|
|
214 |
" Select an object ("class"/"function")
|
|
|
215 |
function! PythonSelectObject(obj)
|
|
|
216 |
" Go to the object declaration
|
|
|
217 |
normal $
|
|
|
218 |
call PythonDec(a:obj, -1)
|
|
|
219 |
let beg = line('.')
|
|
|
220 |
|
|
|
221 |
if !exists("g:py_select_leading_comments") || (g:py_select_leading_comments)
|
|
|
222 |
let decind = indent(beg)
|
|
|
223 |
let cl = beg
|
|
|
224 |
while (cl>1)
|
|
|
225 |
let cl = cl - 1
|
|
|
226 |
if (indent(cl) == decind) && (getline(cl)[decind] == "#")
|
|
|
227 |
let beg = cl
|
|
|
228 |
else
|
|
|
229 |
break
|
|
|
230 |
endif
|
|
|
231 |
endwhile
|
|
|
232 |
endif
|
|
|
233 |
|
|
|
234 |
if (a:obj == "class")
|
|
|
235 |
let eod = "\\(^\\s*class\\s\\+[a-zA-Z0-9_]\\+\\s*"
|
|
|
236 |
\ . "\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*\\)\\@<=:"
|
|
|
237 |
else
|
|
|
238 |
let eod = "\\(^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*\\)\\@<=:"
|
|
|
239 |
endif
|
|
|
240 |
" Look for the end of the declaration (not always the same line!)
|
|
|
241 |
call search(eod, "")
|
|
|
242 |
|
|
|
243 |
" Is it a one-line definition?
|
|
|
244 |
if match(getline('.'), "^\\s*\\(#.*\\)\\=$", col('.')) == -1
|
|
|
245 |
let cl = line('.')
|
|
|
246 |
execute ":".beg
|
|
|
247 |
execute "normal V".cl."G"
|
|
|
248 |
else
|
|
|
249 |
" Select the whole block
|
|
|
250 |
execute "normal \<Down>"
|
|
|
251 |
let cl = line('.')
|
|
|
252 |
execute ":".beg
|
|
|
253 |
execute "normal V".PythonBoB(cl, 1, 0)."G"
|
|
|
254 |
endif
|
|
|
255 |
endfunction
|
|
|
256 |
|
|
|
257 |
|
|
|
258 |
" Jump to the next line with the same (or lower) indentation
|
|
|
259 |
" Useful for moving between "if" and "else", for example.
|
|
|
260 |
function! PythonNextLine(direction)
|
|
|
261 |
let ln = line('.')
|
|
|
262 |
let ind = indent(ln)
|
|
|
263 |
let indent_valid = strlen(getline(ln))
|
|
|
264 |
let ln = ln + a:direction
|
|
|
265 |
|
|
|
266 |
while((ln >= 1) && (ln <= line('$')))
|
|
|
267 |
if (!indent_valid) && strlen(getline(ln))
|
|
|
268 |
break
|
|
|
269 |
else
|
|
|
270 |
if (strlen(getline(ln)))
|
|
|
271 |
if (indent(ln) <= ind)
|
|
|
272 |
break
|
|
|
273 |
endif
|
|
|
274 |
endif
|
|
|
275 |
endif
|
|
|
276 |
let ln = ln + a:direction
|
|
|
277 |
endwhile
|
|
|
278 |
|
|
|
279 |
execute "normal ".ln."G"
|
|
|
280 |
endfunction
|
|
|
281 |
|
|
|
282 |
|
|
|
283 |
" Update the IM-Python menu, that holds Classes and Functions
|
|
|
284 |
function! UpdateMenu()
|
|
|
285 |
let restore_fe = &foldenable
|
|
|
286 |
set nofoldenable
|
|
|
287 |
let cline=line('.')
|
|
|
288 |
call MakeClassStructure ()
|
|
|
289 |
call MakeFuncStructure ()
|
|
|
290 |
execute "normal ".cline."Gzz"
|
|
|
291 |
let &foldenable = restore_fe
|
|
|
292 |
endfunction
|
|
|
293 |
|
|
|
294 |
" Make a menu that holds all of the classes
|
|
|
295 |
function! MakeClassStructure ()
|
|
|
296 |
norm mpgg0
|
|
|
297 |
while line(".") <= line("$")
|
|
|
298 |
if match ( getline("."), '^\s*class\s\+' ) != -1
|
|
|
299 |
norm ^w"nyw
|
|
|
300 |
let name=@n
|
|
|
301 |
"exe 'menu IM-Python.classes.'.name.' '.line(".").'gg15zo'
|
|
|
302 |
exe 'menu IM-Python.classes.'.name.' :call <SID>JumpToAndUnfold('.line(".").')<CR>'
|
|
|
303 |
endif
|
|
|
304 |
if line(".") == line("$")
|
|
|
305 |
return
|
|
|
306 |
endif
|
|
|
307 |
norm j
|
|
|
308 |
endwhile
|
|
|
309 |
norm 'p
|
|
|
310 |
endfunction
|
|
|
311 |
|
|
|
312 |
" Make a menu that holds all of the function definitions
|
|
|
313 |
function! MakeFuncStructure ()
|
|
|
314 |
norm mpgg0
|
|
|
315 |
while line(".") <= line("$")
|
|
|
316 |
if match ( getline("."), '^\s*def\s\+' ) != -1
|
|
|
317 |
norm ^w"nyw
|
|
|
318 |
let name=@n
|
|
|
319 |
"exe 'menu IM-Python.functions.'.name.' '.line(".").'gg15zo'
|
|
|
320 |
exe 'menu IM-Python.functions.'.name.' :call <SID>JumpToAndUnfold('.line(".").')<CR>'
|
|
|
321 |
endif
|
|
|
322 |
if line(".") == line("$")
|
|
|
323 |
return
|
|
|
324 |
endif
|
|
|
325 |
norm j
|
|
|
326 |
endwhile
|
|
|
327 |
norm 'p
|
|
|
328 |
endfunction
|
|
|
329 |
|
|
|
330 |
function! s:JumpToAndUnfold(line)
|
|
|
331 |
" Go to the right line
|
|
|
332 |
execute 'normal '.a:line.'gg'
|
|
|
333 |
" Check to see if we are in a fold
|
|
|
334 |
let lvl = foldlevel(a:line)
|
|
|
335 |
if lvl != 0
|
|
|
336 |
" and if so, then expand the fold out, other wise, ignore this part.
|
|
|
337 |
execute 'normal 15zo'
|
|
|
338 |
endif
|
|
|
339 |
endfunction
|
|
|
340 |
|
|
|
341 |
"" This one will work only on vim 6.2 because of the try/catch expressions.
|
|
|
342 |
" function! s:JumpToAndUnfoldWithExceptions(line)
|
|
|
343 |
" try
|
|
|
344 |
" execute 'normal '.a:line.'gg15zo'
|
|
|
345 |
" catch /^Vim\((\a\+)\)\=:E490:/
|
|
|
346 |
" " Do nothing, just consume the error
|
|
|
347 |
" endtry
|
|
|
348 |
"endfunction
|
|
|
349 |
|
|
|
350 |
|
|
|
351 |
" vim:set et sts=2 sw=2:
|
|
|
352 |
|