Skip to content

Commit 2f232dc

Browse files
authored
Merge pull request #744 from Milly/vital-fix-import-error-handling
vital: fix import error handling
2 parents ff55b7a + 59ce9bc commit 2f232dc

File tree

3 files changed

+79
-17
lines changed

3 files changed

+79
-17
lines changed

autoload/vital/vital.vim

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ function! s:_import(name) abort dict
149149
call module._vital_created(module)
150150
endif
151151
let export_module = filter(copy(module), 'v:key =~# "^\\a"')
152-
" Cache module before calling module.vital_loaded() to avoid cyclic
152+
" Cache module before calling module._vital_loaded() to avoid cyclic
153153
" dependences but remove the cache if module._vital_loaded() fails.
154154
" let s:loaded[a:name] = export_module
155155
let s:loaded[a:name] = export_module
@@ -167,30 +167,51 @@ let s:Vital._import = function('s:_import')
167167

168168
function! s:_format_throwpoint(throwpoint) abort
169169
let funcs = []
170-
let stack = matchstr(a:throwpoint, '^function \zs.*\ze, line \d\+$')
170+
let stack = matchstr(a:throwpoint, '^function \zs.*, .\{-} \d\+$')
171171
for line in split(stack, '\.\.')
172-
let m = matchlist(line, '^\%(<SNR>\(\d\+\)_\)\?\(.\+\)\[\(\d\+\)\]$')
173-
if empty(m)
174-
call add(funcs, line)
175-
continue
176-
endif
177-
let [sid, name, lnum] = m[1:3]
178-
let attr = ''
179-
if !empty(sid)
180-
let name = printf('<SNR>%d_%s', sid, name)
172+
let m = matchlist(line, '^\(.\+\)\%(\[\(\d\+\)\]\|, .\{-} \(\d\+\)\)$')
173+
if !empty(m)
174+
let [name, lnum, lnum2] = m[1:3]
175+
if empty(lnum)
176+
let lnum = lnum2
177+
endif
178+
let info = s:_get_func_info(name)
179+
if !empty(info)
180+
let attrs = empty(info.attrs) ? '' : join([''] + info.attrs)
181+
let flnum = info.lnum == 0 ? '' : printf(' Line:%d', info.lnum + lnum)
182+
call add(funcs, printf('function %s(...)%s Line:%d (%s%s)',
183+
\ info.funcname, attrs, lnum, info.filename, flnum))
184+
continue
185+
endif
181186
endif
182-
let file = s:_get_file_by_func_name(name)
183-
call add(funcs, printf('function %s(...)%s Line:%d (%s)', name, attr, lnum, file))
187+
" fallback when function information cannot be detected
188+
call add(funcs, line)
184189
endfor
185190
return join(funcs, "\n")
186191
endfunction
187192

188-
function! s:_get_file_by_func_name(name) abort
189-
let body = execute(printf('verbose function %s', a:name))
193+
function! s:_get_func_info(name) abort
194+
let name = a:name
195+
if a:name =~# '^\d\+$' " is anonymous-function
196+
let name = printf('{%s}', a:name)
197+
elseif a:name =~# '^<lambda>\d\+$' " is lambda-function
198+
let name = printf("{'%s'}", a:name)
199+
endif
200+
if !exists('*' . name)
201+
return {}
202+
endif
203+
let body = execute(printf('verbose function %s', name))
190204
let lines = split(body, "\n")
191205
let signature = matchstr(lines[0], '^\s*\zs.*')
192-
let file = matchstr(lines[1], '^\t\%(Last set from\|.\{-}:\)\s*\zs.*$')
193-
return substitute(file, '[/\\]\+', '/', 'g')
206+
let [_, file, lnum; __] = matchlist(lines[1],
207+
\ '^\t\%(Last set from\|.\{-}:\)\s*\zs\(.\{-}\)\%( \S\+ \(\d\+\)\)\?$')
208+
return {
209+
\ 'filename': substitute(file, '[/\\]\+', '/', 'g'),
210+
\ 'lnum': 0 + lnum,
211+
\ 'funcname': a:name,
212+
\ 'arguments': split(matchstr(signature, '(\zs.*\ze)'), '\s*,\s*'),
213+
\ 'attrs': filter(['dict', 'abort', 'range', 'closure'], 'signature =~# (").*" . v:val)'),
214+
\ }
194215
endfunction
195216

196217
" s:_get_module() returns module object wihch has all script local functions.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
let s:Obj = {}
2+
3+
function! s:_vital_loaded(V) abort
4+
if exists('s:Lambda')
5+
call s:Lambda()
6+
else
7+
call s:Obj._anonymous_func()
8+
endif
9+
endfunction
10+
11+
if has('lambda')
12+
let s:Lambda = {-> s:Obj._anonymous_func()}
13+
endif
14+
15+
function! s:Obj._anonymous_func() dict abort
16+
call s:_throwFOO()
17+
endfunction
18+
19+
function! s:_throwFOO() abort
20+
throw 'FOO'
21+
endfunction

test/vital.vimspec

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ Describe vital
220220
Assert Equals(JSON.decode('[1, "ni"]'), [1, "ni"])
221221
End
222222

223+
It can handle error stack in s:_vital_loaded(V)
224+
let errorpat = '/^vital: fail to call \._vital_loaded(): FOO from:\_.*\n'
225+
\ . 'function \S*_vital_loaded(\.\.\.) abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n'
226+
\ . (has('lambda') ? 'function <lambda>\d\+(\.\.\.) Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n' : '')
227+
\ . 'function \d\+(\.\.\.) dict abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n'
228+
\ . 'function \S*_throwFOO(\.\.\.) abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)$/'
229+
execute 'Throws' errorpat ':call V.import("ErrorSelfmodule")'
230+
End
231+
223232
It supports s:_vital_created(V)
224233
let JSON = V.import('Web.JSON')
225234
Assert HasKey(JSON, 'true')
@@ -299,6 +308,16 @@ Describe vital
299308
Assert Equals(V.Web.JSON.decode('[1, "ni"]'), [1, "ni"])
300309
End
301310

311+
It can handle error stack in s:_vital_loaded(V)
312+
let V = vital#{g:testplugin_name}#new()
313+
let errorpat = '/^vital: fail to call \._vital_loaded(): FOO from:\_.*\n'
314+
\ . 'function \S*_vital_loaded(\.\.\.) abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n'
315+
\ . (has('lambda') ? 'function <lambda>\d\+(\.\.\.) Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n' : '')
316+
\ . 'function \d\+(\.\.\.) dict abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)\n'
317+
\ . 'function \S*_throwFOO(\.\.\.) abort Line:\d\+ (.*\/ErrorSelfmodule\.vim\( Line:\d\+\)\?)$/'
318+
execute 'Throws' errorpat ':call V.load("ErrorSelfmodule")'
319+
End
320+
302321
It supports s:_vital_created(V)
303322
let V = vital#{g:testplugin_name}#new()
304323
Assert Equals(V.load('Web.JSON'), V)
@@ -312,6 +331,7 @@ Describe vital
312331
End
313332

314333
It does not supports invalid self module which is in __latest__ dir
334+
let V = vital#{g:testplugin_name}#new()
315335
Throws /vital: module not found: InvalidSelfmodule/ :call V.import('InvalidSelfmodule')
316336
End
317337

0 commit comments

Comments
 (0)