author | Mahlon E. Smith <mahlon@martini.nu> |
Sat, 16 Jan 2016 11:31:53 -0800 | |
branch | vim-stuff |
changeset 29 | a0e6ddfadf82 |
parent 19 | specky/plugin/specky.vim@763cef799c74 |
permissions | -rw-r--r-- |
2 | 1 |
" vim: set noet nosta sw=4 ts=4 fdm=marker : |
2 |
" |
|
3 |
" Specky! |
|
4 |
" Mahlon E. Smith <mahlon@martini.nu> |
|
5 |
" $Id$ |
|
6 |
" |
|
7 |
||
8 | 8 |
|
2 | 9 |
" Hook up the functions to the user supplied key bindings. {{{ |
10 |
" |
|
11 |
if exists( 'g:speckySpecSwitcherKey' ) |
|
8 | 12 |
execute 'map ' . g:speckySpecSwitcherKey . ' :call <SID>SpecSwitcher()<CR>' |
13 |
" map &g:speckySpecSwitcherKey <SID>SpecSwitcher() |
|
2 | 14 |
endif |
15 |
||
16 |
if exists( 'g:speckyQuoteSwitcherKey' ) |
|
8 | 17 |
execute 'map ' . g:speckyQuoteSwitcherKey . ' :call <SID>QuoteSwitcher()<CR>' |
2 | 18 |
endif |
19 |
||
3 | 20 |
if exists( 'g:speckyBannerKey' ) |
8 | 21 |
execute 'map ' . g:speckyBannerKey . ' :call <SID>MakeBanner()<CR>' |
3 | 22 |
endif |
23 |
||
2 | 24 |
if exists( 'g:speckyRunSpecKey' ) |
8 | 25 |
execute 'map ' . g:speckyRunSpecKey . ' :call <SID>RunSpec()<CR>' |
2 | 26 |
endif |
27 |
||
28 |
if exists( 'g:speckyRunRdocKey' ) |
|
8 | 29 |
execute 'map ' . g:speckyRunRdocKey . ' :call <SID>RunRdoc()<CR>' |
2 | 30 |
endif |
31 |
||
32 |
if exists( 'specky_loaded' ) |
|
33 |
finish |
|
34 |
endif |
|
11
a9ebb6c22d14
Alter the build Makefiles to implement a suggestion from Antoine Mechelynck.
Mahlon E. Smith <mahlon@martini.nu>
parents:
8
diff
changeset
|
35 |
let specky_loaded = '$Rev$' |
2 | 36 |
|
37 |
||
38 |
"}}} |
|
39 |
" Menu configuration {{{ |
|
40 |
" |
|
41 |
let s:menuloc = '&Plugin.&specky' |
|
42 |
execute 'menu ' . s:menuloc . '.&Jump\ to\ code/spec :call <SID>SpecSwitcher()<CR>' |
|
43 |
execute 'menu ' . s:menuloc . '.Run\ &spec :call <SID>RunSpec()<CR>' |
|
44 |
execute 'menu ' . s:menuloc . '.&RDoc\ lookup :call <SID>RunRdoc()<CR>' |
|
45 |
execute 'menu ' . s:menuloc . '.Rotate\ "e\ style :call <SID>QuoteSwitcher()<CR>' |
|
3 | 46 |
execute 'menu ' . s:menuloc . '.Make\ a\ &banner :call <SID>MakeBanner()<CR>' |
2 | 47 |
|
48 |
||
49 |
" }}} |
|
50 |
" SpecSwitcher() {{{ |
|
51 |
" |
|
52 |
" When in ruby code or an rspec BDD file, try and search recursively through |
|
53 |
" the filesystem (within the current working directory) to find the |
|
54 |
" respectively matching file. (code to spec, spec to code.) |
|
55 |
" |
|
56 |
" This operates under the assumption that you've used chdir() to put vim into |
|
57 |
" the top level directory of your project. |
|
58 |
" |
|
59 |
function! <SID>SpecSwitcher() |
|
60 |
||
5 | 61 |
" If we aren't in a ruby or rspec file then we probably don't care |
62 |
" too much about this function. |
|
2 | 63 |
" |
5 | 64 |
if &ft != 'ruby' && &ft != 'rspec' |
65 |
call s:err( "Not currently in ruby or rspec mode." ) |
|
2 | 66 |
return |
67 |
endif |
|
68 |
||
69 |
" Ensure that we can always search recursively for files to open. |
|
70 |
" |
|
71 |
let l:orig_path = &path |
|
72 |
set path=** |
|
73 |
||
74 |
" Get the current buffer name, and determine if it is a spec file. |
|
75 |
" |
|
76 |
" /tmp/something/whatever/rubycode.rb ---> rubycode.rb |
|
77 |
" A requisite of the specfiles is that they match to the class/code file, |
|
78 |
" this emulates the eigenclass stuff, but doesn't require the same |
|
79 |
" directory structures. |
|
80 |
" |
|
81 |
" rubycode.rb ---> rubycode_spec.rb |
|
82 |
" |
|
83 |
let l:filename = matchstr( bufname('%'), '[0-9A-Za-z_.-]*$' ) |
|
84 |
let l:is_spec_file = match( l:filename, '_spec.rb$' ) == -1 ? 0 : 1 |
|
85 |
||
86 |
if l:is_spec_file |
|
87 |
let l:other_file = substitute( l:filename, '_spec\.rb$', '\.rb', '' ) |
|
88 |
else |
|
89 |
let l:other_file = substitute( l:filename, '\.rb$', '_spec\.rb', '' ) |
|
90 |
endif |
|
91 |
||
92 |
let l:bufnum = bufnr( l:other_file ) |
|
93 |
if l:bufnum == -1 |
|
94 |
" The file isn't currently open, so let's search for it. |
|
95 |
execute 'find ' . l:other_file |
|
96 |
else |
|
97 |
" We've already got an open buffer with this file, just go to it. |
|
98 |
execute 'buffer' . l:bufnum |
|
99 |
endif |
|
100 |
||
101 |
" Restore the original path. |
|
102 |
execute 'set path=' . l:orig_path |
|
103 |
endfunction |
|
104 |
||
105 |
||
106 |
" }}} |
|
107 |
" QuoteSwitcher() {{{ |
|
108 |
" |
|
109 |
" Wrap the word under the cursor in quotes. If in ruby mode, |
|
110 |
" cycle between quoting styles and symbols. |
|
111 |
" |
|
112 |
" variable -> "variable" -> 'variable' -> :variable |
|
113 |
" |
|
114 |
function! <SID>QuoteSwitcher() |
|
115 |
let l:type = strpart( expand("<cWORD>"), 0, 1 ) |
|
116 |
let l:word = expand("<cword>") |
|
117 |
||
118 |
if l:type == '"' |
|
119 |
" Double quote to single |
|
3 | 120 |
execute ":normal viWc'" . l:word . "'" |
2 | 121 |
|
122 |
elseif l:type == "'" |
|
5 | 123 |
if &ft == 'ruby' || &ft == 'rspec' |
2 | 124 |
" Single quote to symbol |
3 | 125 |
execute ':normal viWc:' . l:word |
2 | 126 |
else |
127 |
" Single quote to double |
|
3 | 128 |
execute ':normal viWc"' . l:word . '"' |
2 | 129 |
end |
130 |
||
131 |
else |
|
132 |
" Whatever to double quote |
|
3 | 133 |
execute ':normal viWc"' . l:word . '"' |
2 | 134 |
endif |
135 |
||
136 |
" Move the cursor back into the cl:word |
|
137 |
call cursor( 0, getpos('.')[2] - 1 ) |
|
138 |
endfunction |
|
139 |
||
140 |
||
141 |
" }}} |
|
3 | 142 |
" MakeBanner() {{{ |
143 |
" |
|
144 |
" Create a quick banner from the current line's text. |
|
145 |
" |
|
146 |
function! <SID>MakeBanner() |
|
147 |
let l:banner_text = toupper(join( split( getline('.'), '\zs' ), ' ' )) |
|
148 |
let l:banner_text = substitute( l:banner_text, '^\s\+', '', '' ) |
|
6 | 149 |
let l:sep = repeat( '#', &textwidth == 0 ? 72 : &textwidth ) |
3 | 150 |
let l:line = line('.') |
151 |
||
152 |
call setline( l:line, l:sep ) |
|
153 |
call append( l:line, [ '### ' . l:banner_text, l:sep ] ) |
|
6 | 154 |
execute 'normal 3==' |
3 | 155 |
call cursor( l:line + 3, 0 ) |
156 |
endfunction |
|
157 |
||
158 |
||
159 |
" }}} |
|
2 | 160 |
" RunSpec() {{{ |
161 |
" |
|
162 |
" Run this function while in a spec file to run the specs within vim. |
|
163 |
" |
|
164 |
function! <SID>RunSpec() |
|
165 |
||
166 |
" If we're in the code instead of the spec, try and switch |
|
167 |
" before running tests. |
|
168 |
" |
|
169 |
let l:filename = matchstr( bufname('%'), '[0-9A-Za-z_.-]*$' ) |
|
170 |
let l:is_spec_file = match( l:filename, '_spec.rb$' ) == -1 ? 0 : 1 |
|
171 |
if ( ! l:is_spec_file ) |
|
172 |
silent call <SID>SpecSwitcher() |
|
173 |
endif |
|
174 |
||
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
175 |
let l:spec = bufname('%') |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
176 |
let l:buf = 'specky:specrun' |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
177 |
let l:bufnum = bufnr( l:buf ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
178 |
let l:specver = (exists( 'g:speckySpecVersion') && g:speckySpecVersion == 1) ? 1 : 2 |
2 | 179 |
|
180 |
" Squash the old buffer, if it exists. |
|
181 |
" |
|
182 |
if buflisted( l:buf ) |
|
183 |
execute 'bd! ' . l:buf |
|
184 |
endif |
|
185 |
||
6 | 186 |
execute <SID>NewWindowCmd() . l:buf |
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
187 |
setlocal buftype=nofile bufhidden=delete noswapfile |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
188 |
if ( l:specver == 1 ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
189 |
setlocal filetype=specrun1 |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
190 |
set foldtext='--'.getline(v:foldstart).v:folddashes |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
191 |
else |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
192 |
setlocal filetype=specrun |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
193 |
set foldtext=_formatFoldText() |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
194 |
endif |
2 | 195 |
|
196 |
" Set up some convenient keybindings. |
|
197 |
" |
|
198 |
nnoremap <silent> <buffer> q :close<CR> |
|
199 |
nnoremap <silent> <buffer> e :call <SID>FindSpecError(1)<CR> |
|
200 |
nnoremap <silent> <buffer> r :call <SID>FindSpecError(-1)<CR> |
|
201 |
nnoremap <silent> <buffer> E :call <SID>FindSpecError(0)<CR> |
|
202 |
nnoremap <silent> <buffer> <C-e> :let b:err_line=1<CR> |
|
203 |
||
204 |
" Default cmd for spec |
|
205 |
" |
|
206 |
if !exists( 'g:speckyRunSpecCmd' ) |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
207 |
let g:speckyRunSpecCmd = l:specver == 1 ? 'spec -fs' : 'rspec' |
2 | 208 |
endif |
209 |
||
210 |
" Call spec and gather up the output |
|
211 |
" |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
212 |
let l:cmd = g:speckyRunSpecCmd . ' ' . l:spec |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
213 |
call append( line('$'), 'Output of: ' . l:cmd ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
214 |
call append( line('$'), '' ) |
2 | 215 |
let l:output = system( l:cmd ) |
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
216 |
call append( line('$'), split( l:output, "\n" ) ) |
2 | 217 |
normal gg |
218 |
||
219 |
" Lockdown the buffer |
|
220 |
setlocal nomodifiable |
|
221 |
endfunction |
|
222 |
||
223 |
||
224 |
" }}} |
|
225 |
" RunRdoc() {{{ |
|
226 |
" |
|
227 |
" Get documentation for the word under the cursor. |
|
228 |
" |
|
229 |
function! <SID>RunRdoc() |
|
230 |
||
231 |
" If we aren't in a ruby file (specs are ruby-mode too) then we probably |
|
232 |
" don't care too much about this function. |
|
233 |
" |
|
6 | 234 |
if ( &ft != 'ruby' && &ft != 'rdoc' && &ft != 'rspec' ) |
235 |
call s:err( "Not currently in a rubyish-mode." ) |
|
2 | 236 |
return |
237 |
endif |
|
238 |
||
239 |
" Set defaults |
|
240 |
" |
|
241 |
if !exists( 'g:speckyRunRdocCmd' ) |
|
242 |
let g:speckyRunRdocCmd = 'ri' |
|
243 |
endif |
|
244 |
||
245 |
let l:buf = 'specky:rdoc' |
|
246 |
let l:bufname = bufname('%') |
|
247 |
||
248 |
if ( match( l:bufname, l:buf ) != -1 ) |
|
249 |
" Already in the rdoc buffer. This allows us to lookup |
|
250 |
" something like Kernel#require. |
|
251 |
" |
|
252 |
let l:word = expand('<cWORD>') |
|
253 |
else |
|
254 |
" Not in the rdoc buffer. This allows us to lookup |
|
255 |
" something like 'each' in some_hash.each { ... } |
|
256 |
" |
|
257 |
let l:word = expand('<cword>') |
|
258 |
endif |
|
259 |
||
260 |
" Squash the old buffer, if it exists. |
|
261 |
" |
|
262 |
if buflisted( l:buf ) |
|
263 |
execute 'bd! ' . l:buf |
|
264 |
endif |
|
265 |
||
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
266 |
" With multiple matches, strip the commas from the cWORD. |
2 | 267 |
let l:word = substitute( l:word, ',', '', 'eg' ) |
268 |
||
6 | 269 |
execute <SID>NewWindowCmd() . l:buf |
2 | 270 |
setlocal buftype=nofile bufhidden=delete noswapfile filetype=rdoc |
271 |
nnoremap <silent> <buffer> q :close<CR> |
|
272 |
||
273 |
" Call the documentation and gather up the output |
|
274 |
" |
|
275 |
let l:cmd = g:speckyRunRdocCmd . ' ' . l:word |
|
276 |
let l:output = system( l:cmd ) |
|
277 |
call append( 0, split( l:output, "\n" ) ) |
|
278 |
execute 'normal gg' |
|
279 |
||
280 |
" Lockdown the buffer |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
281 |
setlocal nomodifiable |
2 | 282 |
endfunction |
283 |
||
284 |
||
285 |
" }}} |
|
286 |
" FindSpecError( detail ) {{{ |
|
287 |
" |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
288 |
" detail: |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
289 |
" 1 -- find the next failure |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
290 |
" -1 -- find the previous failure |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
291 |
" 0 -- expand the current failure's detail |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
292 |
" |
2 | 293 |
" Convenience searches for jumping to spec failures. |
294 |
" |
|
295 |
function! <SID>FindSpecError( detail ) |
|
296 |
||
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
297 |
let l:specver = (exists( 'g:speckySpecVersion') && g:speckySpecVersion == 1) ? 1 : 2 |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
298 |
let l:err_str = l:specver == 1 ? '(FAILED\|ERROR - \d\+)$' : 'FAILED - #\d\+)$' |
2 | 299 |
|
300 |
if ( a:detail == 0 ) |
|
301 |
" Find the detailed failure text for the current failure line, |
|
302 |
" and unfold it. |
|
303 |
" |
|
304 |
let l:orig_so = &so |
|
305 |
set so=100 |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
306 |
if l:specver == 1 |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
307 |
call search('^' . matchstr(getline('.'),'\d\+)$') ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
308 |
else |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
309 |
call search('^FAILURE - #' . matchstr(getline('.'),'\d\+)$') ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
310 |
endif |
2 | 311 |
if has('folding') |
312 |
silent! normal za |
|
313 |
endif |
|
314 |
execute 'set so=' . l:orig_so |
|
315 |
||
316 |
else |
|
317 |
" Find the 'regular' failure line |
|
318 |
" |
|
319 |
if exists( 'b:err_line' ) |
|
320 |
call cursor( b:err_line, a:detail == -1 ? 1 : strlen(getline(b:err_line)) ) |
|
321 |
endif |
|
322 |
call search( l:err_str, a:detail == -1 ? 'b' : '' ) |
|
323 |
let b:err_line = line('.') |
|
324 |
nohl |
|
325 |
||
326 |
endif |
|
327 |
endfunction |
|
328 |
||
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
329 |
|
6 | 330 |
" }}} |
331 |
" NewWindowCmd() {{{ |
|
332 |
" |
|
333 |
" Return the stringified command for a new window, based on user preferences. |
|
334 |
" |
|
335 |
function! <SID>NewWindowCmd() |
|
336 |
if ( ! exists('g:speckyWindowType' ) ) |
|
337 |
return 'tabnew ' |
|
338 |
endif |
|
339 |
||
340 |
if ( g:speckyWindowType == 1 ) |
|
341 |
return 'new ' |
|
342 |
elseif ( g:speckyWindowType == 2 ) |
|
343 |
return 'vert new ' |
|
344 |
else |
|
345 |
return 'tabnew ' |
|
346 |
endif |
|
347 |
endfunction |
|
2 | 348 |
|
19
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
349 |
|
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
350 |
" }}} |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
351 |
" _formatFoldText() {{{ |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
352 |
" |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
353 |
" Make folded failure detail visually appealing when folded. |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
354 |
" |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
355 |
function! _formatFoldText() |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
356 |
let l:fold = tolower( getline(v:foldstart) ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
357 |
let l:fold = substitute( l:fold, '-', 'detail', 'e' ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
358 |
let l:fold = '--[ ' . substitute( l:fold, ')', ' ]', 'e' ) |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
359 |
return l:fold |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
360 |
endfunction |
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
361 |
|
763cef799c74
Specky: support rspec 2.x by default.
Mahlon E. Smith <mahlon@martini.nu>
parents:
11
diff
changeset
|
362 |
|
2 | 363 |
" }}} |
364 |
" s:err( msg ) "{{{ |
|
365 |
" Notify of problems in a consistent fashion. |
|
366 |
" |
|
367 |
function! s:err( msg ) |
|
368 |
echohl WarningMsg|echomsg 'specky: ' . a:msg|echohl None |
|
369 |
endfunction " }}} |
|
370 |