garybernhardt / dotfiles

My vim, bash, emacs, etc. configurations. These have grown over many years, so they may not make sense in places. ;)

commit 150: cae8e2328b60
parent 149: 11c651841192
branch: default
Added missing bike plugin to vim
Gary Bernhardt
4 months ago

Changed (Δ12.7 KB):

raw changeset »

.vim/plugin/bike.vim (430 lines added, 0 lines removed)

Up to file-list .vim/plugin/bike.vim:

1
" Bicycle Repair Man integration for Vim
2
" Version 0.3
3
" Copyright (c) 2003 Marius Gedminas <mgedmin@delfi.lt>
4
"
5
" Needs Vim 6.x with python interpreter (Python 2.2 or newer)
6
" Installation instructions: just drop it into $HOME/.vim/plugin and you
7
" should see the Bicycle Repair Menu appear in GVim (or you can check if
8
" any of the BikeXxx commands are defined in console mode Vim).  If bike.vim
9
" fails to load and you want to see the reason, try
10
"   let g:bike_exceptions = 1
11
"   source ~/.vim/plugin/bike.vim
12
"
13
" Configuration options you can add to your .vimrc:
14
"   let g:bike_exceptions = 1           " show tracebacks on exceptions
15
"   let g:bike_progress = 1             " show import progress
16
"
17
" Commands defined:
18
"
19
"   BikeShowScope
20
"       Show current scope.  Sample of usage:
21
"         autocmd CursorHold *.py BikeShowScope
22
"
23
"   <range> BikeShowType
24
"       Show selected expression type.  The range is ignored, '<,'> is always
25
"       used.  Use this in visual block mode.
26
"
27
"   BikeFindRefs
28
"       Finds all references of the function/method/class defined in current
29
"       line.
30
"
31
"   BikeFindDef
32
"       Finds the definition of the function/method/class under cursor.
33
"
34
"   BikeRename
35
"       Renames the function/method/class defined in current line.  Updates
36
"       all references in all files known (i.e. imported) to Bicycle Repair
37
"       Man.
38
"
39
"   <range> BikeExtract
40
"       Extracts a part of the function/method into a new function/method.
41
"       The range is ignored, '<,'> is always used.  Use this in visual mode.
42
"
43
"   BikeUndo
44
"       Globally undoes the previous refactoring.
45
"
46
" Issues:
47
"  - Saves all modified buffers to disk without asking the user -- not nice
48
"  - Does not reimport files that were modified outside of Vim
49
"  - Uses mktemp() -- I think that produces deprecation warnings in Python 2.3
50
"  - BikeShowType, BikeExtract ignores the specified range, that's confusing.
51
"    At least BikeExtract ought to work...
52
"  - BikeShowType/BikeExtract or their GUI counterparts work when not in
53
"    visual mode by using the previous values of '<,'>.  Might be confusing.
54
"  - Would be nice if :BikeImport<CR> asked to enter package
55
"  - Would be nice if :BikeRename myNewName<CR> worked
56
"  - The code is not very robust (grep for XXX)
57
58
"
59
" Default settings for global configuration variables                   {{{1
60
"
61
62
" Set to 1 to see full tracebacks
63
if !exists("g:bike_exceptions")
64
    let g:bike_exceptions = 0
65
endif
66
67
" Set to 1 to see import progress
68
if !exists("g:bike_progress")
69
    let g:bike_progress = 0
70
endif
71
72
"
73
" Initialization                                                        {{{1
74
"
75
76
" First check that Vim is sufficiently recent, that we have python interpreted
77
" support, and that Bicycle Repair Man is available.
78
"
79
" If something is wrong, fail silently, as error messages every time vim
80
" starts are very annoying.  But if the user wants to see why bike.vim failed
81
" to load, she can let g:bike_exceptions = 1
82
if version < 600
83
    if g:bike_exceptions
84
        echo 'Bicycle Repair Man needs Vim 6.0'
85
    endif
86
    finish
87
endif
88
89
if !has("python")
90
    if g:bike_exceptions
91
        echo 'Bicycle Repair Man needs Vim with Python interpreter support (2.2 or newer)'
92
    endif
93
    finish
94
endif
95
96
let s:has_bike=1
97
python << END
98
import vim
99
import sys
100
try:
101
    if sys.version_info < (2, 2):
102
        raise ImportError, 'Bicycle Repair Man needs Python 2.2 or newer'
103
    import bike
104
    bikectx = bike.init()
105
    bikectx.isLoaded        # make sure bike package is recent enough
106
except ImportError:
107
    vim.command("let s:has_bike=0")
108
    if vim.eval('g:bike_exceptions') not in (None, '', '0'):
109
        raise
110
END
111
if !s:has_bike
112
    finish
113
endif
114
115
" Use sane cpoptions
116
let s:cpo_save = &cpo
117
set cpo&vim
118
119
"
120
" Menu                                                                  {{{1
121
"
122
silent! aunmenu Bicycle\ Repair\ Man
123
124
" Shortcuts available: ab-----h-jk--nopq----vw--z
125
amenu <silent> Bicycle\ &Repair\ Man.-SEP1-
126
\       :
127
amenu <silent> Bicycle\ &Repair\ Man.&Find\ References
128
\       :call <SID>BikeFindRefs()<CR>
129
amenu <silent> Bicycle\ &Repair\ Man.Find\ &Definition
130
\       :call <SID>BikeFindDef()<CR>
131
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&List<tab>:cl
132
\       :cl<CR>
133
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Current<tab>:cc
134
\       :cc<CR>
135
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Next<tab>:cn
136
\       :cn<CR>
137
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Previous<tab>:cp
138
\       :cp<CR>
139
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&First<tab>:cfirst
140
\       :cfirst<CR>
141
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.Las&t<tab>:clast
142
\       :clast<CR>
143
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Older\ List<tab>:colder
144
\       :colder<CR>
145
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.N&ewer\ List<tab>:cnewer
146
\       :cnewer<CR>
147
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Update<tab>:cw
148
\       :cw<CR>
149
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Open<tab>:copen
150
\       :copen<CR>
151
amenu <silent> Bicycle\ &Repair\ Man.Resu<s.&Window.&Close<tab>:cclose
152
\       :cclose<CR>
153
amenu <silent> Bicycle\ &Repair\ Man.-SEP2-
154
\       :
155
amenu <silent> Bicycle\ &Repair\ Man.&Rename
156
\       :call <SID>BikeRename()<CR>
157
amenu <silent> Bicycle\ &Repair\ Man.E&xtract\ Method
158
\       :call <SID>BikeExtract('method')<CR>
159
amenu <silent> Bicycle\ &Repair\ Man.&Extract\ Function
160
\       :call <SID>BikeExtract('function')<CR>
161
amenu <silent> Bicycle\ &Repair\ Man.&Undo
162
\       :call <SID>BikeUndo()<CR>
163
amenu <silent> Bicycle\ &Repair\ Man.-SEP3-
164
\       :
165
amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Enable
166
\       :let g:bike_progress = 1<CR>
167
amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Disable
168
\       :let g:bike_progress = 0<CR>
169
amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Enable
170
\       :let g:bike_exceptions = 1<CR>
171
amenu <silent> Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Disable
172
\       :let g:bike_exceptions = 0<CR>
173
174
" Note: The three rename commands are basically identical.  The two extract
175
" commands are also identical behind the scenes.
176
177
"
178
" Commands                                                              {{{1
179
"
180
181
command! BikeShowScope          call <SID>BikeShowScope()
182
command! -range BikeShowType    call <SID>BikeShowType()
183
command! BikeFindRefs           call <SID>BikeFindRefs()
184
command! BikeFindDef            call <SID>BikeFindDef()
185
186
command! BikeRename             call <SID>BikeRename()
187
command! -range BikeExtract     call <SID>BikeExtract('function')
188
command! BikeUndo               call <SID>BikeUndo()
189
190
"
191
" Implementation                                                        {{{1
192
"
193
194
" Query functions                                                       {{{2
195
196
function! s:BikeShowScope()
197
" Shows the scope under cursor
198
    python << END
199
fn = vim.current.buffer.name
200
row, col = vim.current.window.cursor
201
try:
202
    print bikectx.getFullyQualifiedNameOfScope(fn, row)
203
except:
204
    show_exc()
205
END
206
endf
207
208
function! s:BikeShowType()
209
" Shows the inferred type of the selected expression
210
    if col("'<") == 0            " mark not set
211
        echo "Select a region first!"
212
        return
213
    endif
214
    if line("'<") != line("'>")  " multiline selection
215
        echo "Multi-line regions not supported"
216
        " XXX deficiency of bikefacade interface, expressions can easily span
217
        " several lines in Python
218
        return
219
    endif
220
    python << END
221
fn = vim.current.buffer.name
222
row1, col1 = vim.current.buffer.mark('<')
223
row2, col2 = vim.current.buffer.mark('>')
224
try:
225
    print bikectx.getTypeOfExpression(fn, row1, col1, col2)
226
except:
227
    show_exc()
228
END
229
endf
230
231
function! s:BikeFindRefs()
232
" Find all references to the item defined on current line
233
    wall
234
    python << END
235
fn = vim.current.buffer.name
236
row, col = vim.current.window.cursor
237
try:
238
    refs = bikectx.findReferencesByCoordinates(fn, row, col)
239
    quickfixdefs(refs)
240
except:
241
    show_exc()
242
END
243
endf
244
245
function! s:BikeFindDef()
246
" Find all definitions of the item under cursor.  Ideally there should be only
247
" one.
248
    wall
249
    python << END
250
fn = vim.current.buffer.name
251
row, col = vim.current.window.cursor
252
try:
253
    defs = bikectx.findDefinitionByCoordinates(fn, row, col)
254
    quickfixdefs(defs)
255
except:
256
    show_exc()
257
END
258
endf
259
260
" Refactoring commands                                                  {{{2
261
262
function! s:BikeRename()
263
" Rename a function/method/class.
264
265
    let newname = inputdialog('Rename to: ')
266
    wall
267
    python << END
268
fn = vim.current.buffer.name
269
row, col = vim.current.window.cursor
270
newname = vim.eval("newname")
271
if newname:
272
    try:
273
        bikectx.setRenameMethodPromptCallback(renameMethodPromptCallback)
274
        bikectx.renameByCoordinates(fn, row, col, newname)
275
    except:
276
        show_exc()
277
    saveChanges()
278
else:
279
    print "Aborted"
280
END
281
endf
282
283
function! s:BikeExtract(what)
284
" Extract a piece of code into a separate function/method.  The argument
285
" a:what can be 'method' or 'function'.
286
    if col("'<") == 0            " mark not set
287
        echo "Select a region first!"
288
        return
289
    endif
290
    let newname = inputdialog('New function name: ')
291
    wall
292
    python << END
293
fn = vim.current.buffer.name
294
row1, col1 = vim.current.buffer.mark('<')
295
row2, col2 = vim.current.buffer.mark('>')
296
newname = vim.eval("newname")
297
if newname:
298
    try:
299
		bikectx.extractMethod(fn, row1, col1, row2, col2, newname)
300
    except:
301
        show_exc()
302
    saveChanges()
303
else:
304
    print "Aborted"
305
END
306
endf
307
308
function! s:BikeUndo()
309
" Undoes the last refactoring
310
    wall
311
python << END
312
try:
313
    bikectx.undo()
314
    saveChanges()
315
except bike.UndoStackEmptyException, e:
316
    print "Nothing to undo"
317
END
318
endf
319
320
"
321
" Helper functions                                                      {{{1
322
"
323
324
" Python helpers
325
326
python << END
327
328
import tempfile
329
import os
330
import linecache
331
332
modified = {}   # a dictionary whose keys are the names of files modifed
333
                # in Vim since the last import
334
335
def show_exc():
336
    """Print exception according to bike settings."""
337
    if vim.eval('g:bike_exceptions') not in (None, '', '0'):
338
        import traceback
339
        traceback.print_exc()
340
    else:
341
        type, value = sys.exc_info()[:2]
342
        if value is not None:
343
            print "%s: %s" % (type, value)
344
        else:
345
            print type
346
347
def writedefs(defs, filename):
348
    """Write a list of file locations to a file."""
349
    ef = None
350
    curdir = os.getcwd()
351
    if not curdir.endswith(os.sep):
352
        curdir = curdir + os.sep
353
    for d in defs:
354
        if not ef:
355
            ef = open(filename, "w")
356
        fn = d.filename
357
        if fn.startswith(curdir):
358
            fn = fn[len(curdir):]
359
        line = linecache.getline(fn, d.lineno).strip()
360
        res ="%s:%d: %3d%%: %s" % (fn, d.lineno, d.confidence, line)
361
        print res
362
        print >> ef, res
363
    if ef:
364
        ef.close()
365
    return ef is not None
366
367
def quickfixdefs(defs):
368
    """Import a list of file locations into vim error list."""
369
    fn = tempfile.mktemp()      # XXX unsafe
370
    if writedefs(defs, fn):
371
        vim.command('let old_errorfile = &errorfile')
372
        vim.command('let old_errorformat = &errorformat')
373
        vim.command(r'set errorformat=\%f:\%l:\ \%m')
374
        vim.command("cfile %s" % fn)
375
        vim.command('let &errorformat = old_errorformat')
376
        vim.command('let &errorfile = old_errorfile')
377
        os.unlink(fn)
378
    else:
379
        print "Not found"
380
381
def renameMethodPromptCallback(filename, line, col1, col2):
382
    """Verify that the call in a given file position should be renamed."""
383
    vim.command('e +%d %s' % (line, filename))
384
    vim.command('normal %d|' % col1)
385
    vim.command('match Search /\%%%dl\%%>%dc\%%<%dc' % (line, col1, col2+1))
386
    vim.command('redraw')
387
    ans = vim.eval('confirm("Cannot deduce instance type.  Rename this call?",'
388
                   ' "&Yes\n&No", 1, "Question")')
389
    vim.command('match none')
390
    if ans == '1':
391
        return 1
392
    else:
393
        return 0
394
395
396
def saveChanges():
397
    """Save refactoring changes to the file system and reload the modified
398
    files in Vim."""
399
    # bikectx.save() returns a list of modified file names.  We should make
400
    # sure that all those files are reloaded iff they were open in vim.
401
    files = map(os.path.abspath, bikectx.save())
402
403
    opened_files = {}
404
    for b in vim.buffers:
405
        if b.name is not None:
406
            opened_files[os.path.abspath(b.name)] = b.name
407
408
    for f in files:
409
        try:
410
            # XXX might fail when file name contains funny characters
411
            vim.command("sp %s | q" % opened_files[f])
412
        except KeyError:
413
            pass
414
415
    # Just in case:
416
    vim.command("checktime")
417
    vim.command("e")
418
419
END
420
421
" Make sure modified files are reimported into BRM
422
autocmd BufWrite * python modified[os.path.abspath(vim.current.buffer.name)] = 1
423
424
"
425
" Cleanup                                                               {{{1
426
"
427
428
" Restore cpoptions
429
let &cpo = s:cpo_save
430
unlet s:cpo_save