Skip to content

Commit 6a3cd0d

Browse files
Michal Vitecekvim-scripts
authored andcommitted
Version 0.7: Initial upload
0 parents  commit 6a3cd0d

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed

README

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This is a mirror of http://www.vim.org/scripts/script.php?script_id=435
2+
3+
Vim script to help moving around in larger Python source files. It displays current class, method or function the cursor is placed in in the status line for every python file. It's more clever than Yegappan Lakshmanan's taglist.vim because it takes into account indetation and comments to determine what tag the cursor is placed in and from version 0.80 doesn't need exuberant ctags utility.
4+
5+
Note: The script displays current tag on the status line only in NORMAL mode. This is because CursorHold event in VIM is fired up only in this mode. However if you'd like to know what tag you are in even in INSERT or VISUAL mode, contact me (email specified in the script) and I'll send you a patch that enables firing up CursorHold event in those modes as well.

plugin/pythonhelper.vim

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
" File: pythonhelper.vim
2+
" Author: Michal Vitecek <fuf-at-mageo-dot-cz>
3+
" Version: 0.7
4+
" Last Modified: Oct 2, 2002
5+
"
6+
" Overview
7+
" --------
8+
" Vim script to help moving around in larger Python source files. It displays
9+
" current class, method or function the cursor is placed in in the status
10+
" line for every python file. It's more clever than Yegappan Lakshmanan's
11+
" taglist.vim because it takes into account indetation and comments to
12+
" determine what tag the cursor is placed in.
13+
"
14+
" Requirements
15+
" ------------
16+
" This script needs VIM compiled with Python interpreter and relies on
17+
" exuberant ctags utility to generate the tag listing. You can determine
18+
" whether your VIM has Python support by issuing command :ver and looking for
19+
" +python in the list of features.
20+
"
21+
" The exuberant ctags can be downloaded from http://ctags.sourceforge.net/ and
22+
" should be reasonably new version (tested with 5.3).
23+
"
24+
" Note: The script doesn't display current tag on the status line only in
25+
" NORMAL mode. This is because CursorHold event is fired up only in this mode.
26+
" However if you badly need to know what tag you are on even in INSERT or
27+
" VISUAL mode, contact me on the above specified email address and I'll send
28+
" you patch that enables it.
29+
"
30+
" Installation
31+
" ------------
32+
" 1. Make sure your Vim has python feature on (+python). If not, you will need
33+
" to recompile it with --with-pythoninterp option to the configure script
34+
" 2. Copy script pythonhelper.vim to the $HOME/.vim/plugin directory
35+
" 3. Edit the script and modify the location of your exuberant tags utility
36+
" (variable CTAGS_PROGRAM).
37+
" 4. Run Vim and open any python file.
38+
"
39+
python << EOS
40+
41+
# import of required modules {{{
42+
import vim
43+
import os
44+
import popen2
45+
import time
46+
import sys
47+
# }}}
48+
49+
50+
# CTAGS program and parameters {{{
51+
CTAGS_PROGRAM = "/usr/local/bin/ctags"
52+
CTAGS_PARAMETERS = "--language-force=python --format=2 --sort=0 --fields=+nK -L - -f - "
53+
# }}}
54+
55+
# global dictionaries of tags and their line numbers, keys are buffer numbers {{{
56+
TAGS = {}
57+
TAGLINENUMBERS = {}
58+
BUFFERTICKS = {}
59+
# }}}
60+
61+
62+
def getNearestLineIndex(row, tagLineNumbers):
63+
# DOC {{{
64+
"""Returns index of line in tagLineNumbers list that is nearest to the
65+
current cursor row.
66+
67+
Parameters
68+
69+
row -- current cursor row
70+
71+
tagLineNumbers -- list of tags' line numbers (ie. their position)
72+
"""
73+
# }}}
74+
75+
# CODE {{{
76+
nearestLineNumber = -1
77+
nearestLineIndex = -1
78+
i = 0
79+
for lineNumber in tagLineNumbers:
80+
# if the current line is nearer the current cursor position, take it {{{
81+
if (nearestLineNumber < lineNumber <= row):
82+
nearestLineNumber = lineNumber
83+
nearestLineIndex = i
84+
# }}}
85+
# if we've got past the current cursor position, let's end the search {{{
86+
if (lineNumber >= row):
87+
break
88+
# }}}
89+
i += 1
90+
return nearestLineIndex
91+
# }}}
92+
93+
94+
def getTags(bufferNumber, changedTick):
95+
# DOC {{{
96+
"""Reads the tags for the specified buffer number. It does so by executing
97+
the CTAGS program and parsing its output. Returns tuple
98+
(taglinenumber[buffer], tags[buffer]).
99+
100+
Parameters
101+
102+
bufferNumber -- number of the current buffer
103+
104+
changedTick -- ever increasing number used to tell if the buffer has
105+
been modified since the last time
106+
"""
107+
# }}}
108+
109+
# CODE {{{
110+
global CTAGS_PROGRAM, CTAGS_PARAMETERS
111+
global TAGLINENUMBERS, TAGS, BUFFERTICKS
112+
113+
114+
# return immediately if there's no need to update the tags {{{
115+
if ((BUFFERTICKS.has_key(bufferNumber)) and (BUFFERTICKS[bufferNumber] == changedTick)):
116+
return (TAGLINENUMBERS[bufferNumber], TAGS[bufferNumber],)
117+
# }}}
118+
119+
# read the tags and fill the global variables {{{
120+
currentBuffer = vim.current.buffer
121+
currentWindow = vim.current.window
122+
row, col = currentWindow.cursor
123+
124+
# create a temporary file with the current content of the buffer {{{
125+
fileName = "/tmp/.%s.%u.ph" % (os.path.basename(currentBuffer.name), os.getpid(),)
126+
f = open(fileName, "w")
127+
128+
for line in currentBuffer:
129+
f.write(line)
130+
f.write('\n')
131+
f.close()
132+
# }}}
133+
134+
# run ctags on it {{{
135+
try:
136+
ctagsOutPut, ctagsInPut = popen2.popen4("%s %s" % (CTAGS_PROGRAM, CTAGS_PARAMETERS,))
137+
ctagsInPut.write(fileName + "\n")
138+
ctagsInPut.close()
139+
except:
140+
os.unlink(fileName)
141+
return
142+
# }}}
143+
144+
# parse the ctags' output {{{
145+
tagLineNumbers = []
146+
tags = {}
147+
while 1:
148+
line = ctagsOutPut.readline()
149+
# if empty line has been read, it's the end of the file {{{
150+
if (line == ''):
151+
break
152+
# }}}
153+
# if the line starts with !, then it's a comment line {{{
154+
if (line[0] == '!'):
155+
continue
156+
# }}}
157+
158+
# split the line into parts and parse the data {{{
159+
# the format is: [0]tagName [1]fileName [2]tagLine [3]tagType [4]tagLineNumber [[5]tagOwner]
160+
tagData = line.split('\t')
161+
name = tagData[0]
162+
# get the tag's indentation {{{
163+
start = 2
164+
j = 2
165+
while ((j < len(tagData[2])) and (tagData[2][j].isspace())):
166+
if (tagData[2][j] == '\t'):
167+
start += 8
168+
else:
169+
start += 1
170+
j += 1
171+
# }}}
172+
type = tagData[3]
173+
line = int(tagData[4][5:])
174+
if (len(tagData) == 6):
175+
owner = tagData[5].strip()
176+
else:
177+
owner = None
178+
# }}}
179+
tagLineNumbers.append(line)
180+
tags[line] = (name, type, owner, start)
181+
ctagsOutPut.close()
182+
# }}}
183+
184+
# clean up the now unnecessary stuff {{{
185+
os.unlink(fileName)
186+
# }}}
187+
188+
# update the global variables {{{
189+
TAGS[bufferNumber] = tags
190+
TAGLINENUMBERS[bufferNumber] = tagLineNumbers
191+
BUFFERTICKS[bufferNumber] = changedTick
192+
# }}}
193+
# }}}
194+
195+
return (TAGLINENUMBERS[bufferNumber], TAGS[bufferNumber],)
196+
# }}}
197+
198+
199+
def findTag(bufferNumber, changedTick):
200+
# DOC {{{
201+
"""Tries to find the best tag for the current cursor position.
202+
203+
Parameters
204+
205+
bufferNumber -- number of the current buffer
206+
207+
changedTick -- ever increasing number used to tell if the buffer has
208+
been modified since the last time
209+
"""
210+
# }}}
211+
212+
# CODE {{{
213+
try:
214+
# get the tags data for the current buffer
215+
tagLineNumbers, tags = getTags(bufferNumber, changedTick)
216+
217+
# link to vim internal data {{{
218+
currentBuffer = vim.current.buffer
219+
currentWindow = vim.current.window
220+
row, col = currentWindow.cursor
221+
# }}}
222+
223+
# get the index of the nearest line
224+
nearestLineIndex = getNearestLineIndex(row, tagLineNumbers)
225+
# if any line was found, try to find if the tag is appropriate {{{
226+
# (ie. the cursor can be below the last tag but on a code that has nothing
227+
# to do with the tag, because it's indented differently, in such case no
228+
# appropriate tag has been found.)
229+
if (nearestLineIndex > -1):
230+
nearestLineNumber = tagLineNumbers[nearestLineIndex]
231+
# walk through all the lines in range (nearestTagLine, cursorRow) {{{
232+
for i in xrange(nearestLineNumber + 1, row):
233+
line = currentBuffer[i]
234+
# count the indentation of the line, if it's lower that the tag's, the found tag is wrong {{{
235+
if (len(line)):
236+
# compute the indentation of the line {{{
237+
lineStart = 0
238+
j = 0
239+
while ((j < len(line)) and (line[j].isspace())):
240+
if (line[j] == '\t'):
241+
lineStart += 8
242+
else:
243+
lineStart += 1
244+
j += 1
245+
# if the line contains only spaces, it doesn't count {{{
246+
if (j == len(line)):
247+
continue
248+
# }}}
249+
# if the next character is # (python comment), this line doesn't count {{{
250+
if (line[j] == '#'):
251+
continue
252+
# }}}
253+
# }}}
254+
# if the line's indentation starts before the nearest tag's one, the tag is wrong {{{
255+
if (lineStart < tags[nearestLineNumber][3]):
256+
nearestLineNumber = -1
257+
break
258+
# }}}
259+
# }}}
260+
# }}}
261+
else:
262+
nearestLineNumber = -1
263+
# }}}
264+
265+
# describe the cursor position (what tag it's in) {{{
266+
tagDescription = ""
267+
if (nearestLineNumber > -1):
268+
tagInfo = tags[nearestLineNumber]
269+
# use the owner if any exists {{{
270+
if (tagInfo[2] != None):
271+
fullTagName = "%s.%s()" % (tagInfo[2].split(':')[1], tagInfo[0],)
272+
# }}}
273+
# otherwise use just the tag name {{{
274+
else:
275+
fullTagName = tagInfo[0]
276+
# }}}
277+
tagDescription = "[in %s (%s)]" % (fullTagName, tagInfo[1],)
278+
# }}}
279+
280+
# update the variable for the status line so it will be updated next time
281+
vim.command("let w:PHStatusLine=\"%s\"" % (tagDescription,))
282+
except:
283+
# spit out debugging information {{{
284+
ec, ei, tb = sys.exc_info()
285+
while (tb != None):
286+
if (tb.tb_next == None):
287+
break
288+
tb = tb.tb_next
289+
print "ERROR: %s %s %s:%u" % (ec.__name__, ei, tb.tb_frame.f_code.co_filename, tb.tb_lineno,)
290+
time.sleep(0.5)
291+
# }}}
292+
# }}}
293+
294+
295+
def deleteTags(bufferNumber):
296+
# DOC {{{
297+
"""Removes tags data for the specified buffer number.
298+
299+
Parameters
300+
301+
bufferNumber -- number of the buffer
302+
"""
303+
# }}}
304+
305+
# CODE {{{
306+
global TAGS, TAGLINENUMBERS, BUFFERTICKS
307+
308+
try:
309+
del TAGS[bufferNumber]
310+
del TAGLINENUMBERS[bufferNumber]
311+
del BUFFERTICKS[bufferNumber]
312+
except:
313+
pass
314+
# }}}
315+
316+
317+
EOS
318+
319+
320+
function! PHCursorHold()
321+
" only python is supported {{{
322+
if (exists('b:current_syntax') && (b:current_syntax != 'python'))
323+
let w:PHStatusLine = ''
324+
return
325+
endif
326+
" }}}
327+
328+
" call python function findTag() with the current buffer number and changed ticks
329+
execute 'python findTag(' . expand("<abuf>") . ', ' . b:changedtick . ')'
330+
endfunction
331+
332+
333+
function! PHBufferDelete()
334+
" call python function deleteTags() with the cur
335+
execute 'python deleteTags(' . expand("<abuf>") . ')'
336+
endfunction
337+
338+
339+
340+
" autocommands binding
341+
autocmd CursorHold * silent call PHCursorHold()
342+
autocmd BufWinEnter * silent call PHCursorHold()
343+
autocmd BufDelete * silent call PHBufferDelete()
344+
345+
" time that determines after how long time of no activity the CursorHold event
346+
" is fired up
347+
set updatetime=1000
348+
349+
" color of the current tag in the status line (bold cyan on black)
350+
highlight User1 gui=bold guifg=cyan guibg=black
351+
" color of the modified flag in the status line (bold black on red)
352+
highlight User2 gui=bold guifg=black guibg=red
353+
" the status line will be displayed for every window
354+
set laststatus=2
355+
" set the status variable for the current window
356+
let w:PHStatusLine = ''
357+
" set the status line to display some useful information
358+
set stl=%-f%r\ %2*%m%*\ \ \ \ %1*%{w:PHStatusLine}%*%=[%l:%c]\ \ \ \ [buf\ %n]

0 commit comments

Comments
 (0)