Skip to content

Commit f5bfa6f

Browse files
committed
Merge branch 'source-map' into develop
2 parents 949768e + ce0a56d commit f5bfa6f

File tree

4 files changed

+117
-33
lines changed

4 files changed

+117
-33
lines changed

autoload/themis/style/vimspec.vim

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ function s:parse_describe(tokens, lnum, context_stack, scope_id) abort
1919

2020
let funcname = printf('s:themis_vimspec_scope_%d', a:scope_id)
2121
call add(a:context_stack, ['describe', a:lnum, funcname, a:scope_id])
22-
return [
22+
let result = [
2323
\ printf('function %s() abort', funcname),
2424
\ printf('let s:themis_vimspec_bundles += [%s]', bundle_new),
2525
\ 'let s:themis_vimspec_bundles[-1]._vimspec_hooks = {}',
2626
\ 'function s:themis_vimspec_bundles[-1]._vimspec_hooks.start_test()',
2727
\ printf(' call s:themis_vimspec_scopes.tmp_scope(%d)', a:scope_id),
2828
\ 'endfunction',
2929
\ ]
30+
return {
31+
\ 'result': result,
32+
\ 'map_pos': 1,
33+
\ }
3034
endfunction
3135

3236
function s:parse_example(tokens, lnum, context_stack, func_id) abort
@@ -42,14 +46,18 @@ function s:parse_example(tokens, lnum, context_stack, func_id) abort
4246
call add(a:context_stack, ['example', a:lnum])
4347
let bundle_var = 's:themis_vimspec_bundles'
4448
let scope_var = 's:themis_vimspec_scopes'
45-
return [
49+
let result = [
4650
\ printf('let %s[-1].suite_descriptions["T_%05d"] = %s',
4751
\ bundle_var, a:func_id, string(example)),
4852
\ printf('function %s[-1].suite.T_%05d() abort',
4953
\ bundle_var, a:func_id),
5054
\ printf('execute %s.extend("%s.scope(%d)", 0)',
5155
\ scope_var, scope_var, scope_id),
5256
\ ]
57+
return {
58+
\ 'result': result,
59+
\ 'map_pos': 2,
60+
\ }
5361
endfunction
5462

5563
function s:parse_hook(tokens, lnum, context_stack) abort
@@ -72,12 +80,16 @@ function s:parse_hook(tokens, lnum, context_stack) abort
7280
call add(a:context_stack, ['hook', a:lnum, timing])
7381
let bundle_var = 's:themis_vimspec_bundles'
7482
let scope_var = 's:themis_vimspec_scopes'
75-
return [
83+
let result = [
7684
\ printf('function %s[-1]._vimspec_hooks.%s() abort',
7785
\ bundle_var, hook_point),
7886
\ printf('execute %s.extend("%s.scope(%d)", %d)',
7987
\ scope_var, scope_var, scope_id, copy),
8088
\ ]
89+
return {
90+
\ 'result': result,
91+
\ 'map_pos': 1,
92+
\ }
8193
endfunction
8294

8395
function s:parse_end(tokens, lnum, context_stack) abort
@@ -125,6 +137,8 @@ function s:translate_script(lines) abort
125137
let lnum = 0
126138
let heredoc_endmarker = ''
127139

140+
let map_lines = []
141+
128142
for line in a:lines
129143
let lnum += 1
130144

@@ -145,24 +159,30 @@ function s:translate_script(lines) abort
145159

146160
let tokens = matchlist(line, '^\s*\([Dd]escribe\|[Cc]ontext\)\s*\(.*\)$')
147161
if !empty(tokens)
148-
let result +=
162+
let parsed =
149163
\ s:parse_describe(tokens, lnum, context_stack, current_scope_id)
150164
let current_scope_id += 1
165+
let map_lines += [[len(result) + parsed.map_pos, lnum, 'desc']]
166+
let result += parsed.result
151167
continue
152168
endif
153169

154170
let tokens = matchlist(line, '^\s*\([Ii]t\)\s*\(.*\)$')
155171
if !empty(tokens)
156-
let result +=
172+
let parsed =
157173
\ s:parse_example(tokens, lnum, context_stack, current_func_id)
158174
let current_func_id += 1
175+
let map_lines += [[len(result) + parsed.map_pos, lnum, 'it']]
176+
let result += parsed.result
159177
continue
160178
endif
161179

162180
let tokens = matchlist(line,
163181
\ '^\s*\([Bb]efore\|[Aa]fter\)\%(\s\+\(.*\)\)\?$')
164182
if !empty(tokens)
165-
let result += s:parse_hook(tokens, lnum, context_stack)
183+
let parsed = s:parse_hook(tokens, lnum, context_stack)
184+
let map_lines += [[len(result) + parsed.map_pos, lnum, 'hook']]
185+
let result += parsed.result
166186
continue
167187
endif
168188

@@ -180,13 +200,14 @@ function s:translate_script(lines) abort
180200
throw printf('vimspec:%d:This declaration is not closed.', opened_lnum)
181201
endif
182202

183-
return result
203+
return [result, map_lines]
184204
endfunction
185205

186206
function s:compile_specfile(specfile_path, result_path) abort
187207
let slines = readfile(a:specfile_path)
188-
let rlines = s:translate_script(slines)
208+
let [rlines, map_lines] = s:translate_script(slines)
189209
call writefile(rlines, a:result_path)
210+
return map_lines
190211
endfunction
191212

192213

@@ -294,8 +315,12 @@ function s:style.load_script(filename, runner) abort
294315
let compiled_specfile_path = tempname()
295316
call add(self.event._converted_files, compiled_specfile_path)
296317
try
297-
call s:compile_specfile(a:filename, compiled_specfile_path)
318+
let map_lines = s:compile_specfile(a:filename, compiled_specfile_path)
298319
execute 'source' fnameescape(compiled_specfile_path)
320+
call themis#util#add_source_map(compiled_specfile_path, {
321+
\ 'original_filename': a:filename,
322+
\ 'map_lines': reverse(map_lines),
323+
\ })
299324
catch /^vimspec:/
300325
let pat = '\v^vimspec:(\d+):(.*)'
301326
let [lnum, message] = matchlist(v:exception, pat)[1 : 2]

autoload/themis/util.vim

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
let s:func_aliases = {}
66
let s:line_adjuster = {}
7+
let s:source_maps = {}
78

89
let s:StackInfo = {
910
\ 'stack': '',
1011
\ 'type': '',
11-
\ 'line': 0,
12+
\ 'lnum': 0,
1213
\ 'filled': 0,
1314
\ }
1415

@@ -20,13 +21,16 @@ function s:StackInfo.fill_info() abort
2021
if themis#util#is_funcname(self.stack)
2122
call extend(self, themis#util#funcdata(self.stack), 'keep')
2223
let self.type = 'function'
24+
call self.apply_source_map()
2325
return
2426
endif
2527
if filereadable(self.stack)
2628
let self.exists = 1
2729
let self.filename = self.stack
2830
let self.funcname = ''
2931
let self.type = 'file'
32+
33+
call self.apply_source_map()
3034
return
3135
endif
3236
let matched = matchlist(self.stack, '^\(\w\+\) Autocommands for \(.*\)')
@@ -43,6 +47,25 @@ function s:StackInfo.fill_info() abort
4347
let self.type = 'unknown'
4448
endfunction
4549

50+
function s:StackInfo.apply_source_map() abort
51+
let source_map = get(s:source_maps, self.filename, 0)
52+
if source_map is 0
53+
return
54+
endif
55+
let self.filename = get(source_map, 'original_filename', self.filename)
56+
57+
let deflnum = self.deflnum
58+
let map_lines = get(source_map, 'map_lines', [])
59+
if deflnum && len(map_lines) != 0
60+
for [slnum, alnum; _] in map_lines
61+
if slnum <= deflnum
62+
let self.deflnum = alnum + (deflnum - slnum)
63+
break
64+
endif
65+
endfor
66+
endif
67+
endfunction
68+
4669
function s:StackInfo.make_signature() abort
4770
let funcname = get(s:func_aliases, self.funcname, self.funcname)
4871
let args = join(self.arguments, ', ')
@@ -70,14 +93,14 @@ function s:StackInfo.format() abort
7093
endif
7194

7295
if self.type ==# 'file'
73-
return printf('%s Line:%d', self.filename, self.line)
96+
return printf('%s Line:%d', self.filename, self.lnum)
7497
endif
7598
if self.type ==# 'function'
7699
let result = self.make_signature()
77-
if self.line
100+
if self.lnum
78101
let result .= ' Line:' . self.adjusted_lnum()
79102
endif
80-
if self.defline
103+
if self.deflnum
81104
let result .= ' [ Absolute Line: ' . self.adjusted_abs_lnum() . ' ]'
82105
endif
83106
return result . ' (' . self.filename . ')'
@@ -89,7 +112,7 @@ function s:StackInfo.format() abort
89112
endfunction
90113

91114
function s:StackInfo.get_line(...) abort
92-
let lnum = a:0 ? a:1 : self.line
115+
let lnum = a:0 ? a:1 : self.lnum
93116
call self.fill_info()
94117
if self.type ==# 'file'
95118
if !has_key(self, 'body')
@@ -110,20 +133,17 @@ function s:StackInfo.get_line(...) abort
110133
endfunction
111134

112135
function s:StackInfo.adjusted_lnum(...) abort
113-
let lnum = a:0 ? a:1 : self.line
136+
let lnum = a:0 ? a:1 : self.lnum
114137
let adjuster = get(s:line_adjuster, self.funcname, 0)
115138
return lnum + adjuster
116139
endfunction
117140

118-
function s:StackInfo.adjusted_abs_lnum(...) abort
119-
let lnum = a:0 ? a:1 : self.line
120-
let deflnum = self.defline
121-
let adjuster = get(s:line_adjuster, self.funcname, 0)
122-
return lnum + deflnum + adjuster
141+
function s:StackInfo.adjusted_abs_lnum() abort
142+
return self.adjusted_lnum() + self.deflnum
123143
endfunction
124144

125145
function s:StackInfo.get_line_with_lnum(...) abort
126-
let lnum = a:0 ? a:1 : self.line
146+
let lnum = a:0 ? a:1 : self.lnum
127147
let line = self.get_line(lnum)
128148
return printf('%3d: %s', self.adjusted_lnum(lnum), line)
129149
endfunction
@@ -141,7 +161,7 @@ function themis#util#stack_info(stack) abort
141161
let matched = matchlist(a:stack, pat)
142162
if !empty(matched)
143163
let info.stack = matched[1]
144-
let info.line = matched[2] - 0
164+
let info.lnum = matched[2] - 0
145165
endif
146166
endfor
147167
endif
@@ -179,6 +199,11 @@ function themis#util#adjust_func_line(target, line) abort
179199
endif
180200
endfunction
181201

202+
function themis#util#add_source_map(filename, source_map) abort
203+
let filename = substitute(a:filename, '[/\\]\+', '/', 'g')
204+
let s:source_maps[filename] = a:source_map
205+
endfunction
206+
182207
function themis#util#callstacklines(throwpoint, ...) abort
183208
let infos = call('themis#util#callstack', [a:throwpoint] + a:000)
184209
return map(infos, 'v:val.format()')
@@ -228,7 +253,7 @@ function themis#util#funcdata(func) abort
228253
let signature = matchstr(lines[0], '^\s*\zs.*')
229254
let file = matchstr(lines[1], '^\t\%(Last set from\|.\{-}:\)\s*\zs.*$')
230255
let file = substitute(file, '[/\\]\+', '/', 'g')
231-
let defline = str2nr(matchstr(file, '\d\+$'))
256+
let deflnum = str2nr(matchstr(file, '\d\+$'))
232257
" XXX: Remove ' line 10' at tail. But the message may be translated.
233258
" This can fail in some languages.
234259
let file = substitute(file, ' \S\+ \d\+$', '', '')
@@ -239,7 +264,7 @@ function themis#util#funcdata(func) abort
239264
\ 'exists': 1,
240265
\ 'filename': file,
241266
\ 'funcname': func,
242-
\ 'defline': defline,
267+
\ 'deflnum': deflnum,
243268
\ 'signature': signature,
244269
\ 'arguments': arguments,
245270
\ 'arity': arity,
@@ -255,7 +280,7 @@ endfunction
255280
function themis#util#error_info(stacktrace) abort
256281
let tracelines = map(copy(a:stacktrace), 'v:val.format()')
257282
let tail = a:stacktrace[-1]
258-
if tail.line
283+
if tail.lnum
259284
let tracelines += [tail.get_line_with_lnum()]
260285
endif
261286
return join(tracelines, "\n")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Describe vimspec-style
2+
Describe source_map
3+
Before
4+
try
5+
throw 'hook' " Here is line 5 in file
6+
catch
7+
let hook_point = v:throwpoint
8+
endtry
9+
End
10+
11+
It treats correct line number
12+
try
13+
throw 'error' " Here is line 13 in file
14+
catch
15+
let throwpoint = v:throwpoint
16+
endtry
17+
let stacks = themis#util#parse_callstack(throwpoint)
18+
let last_stack = stacks[-1]
19+
call last_stack.fill_info()
20+
Assert Equals(fnamemodify(last_stack.filename, ':t'), 'source_map.vimspec')
21+
Assert Equals(last_stack.adjusted_lnum(), 2)
22+
Assert Equals(last_stack.adjusted_abs_lnum(), 13)
23+
End
24+
25+
It treats correct line number in hook
26+
let stacks = themis#util#parse_callstack(hook_point)
27+
let last_stack = stacks[-1]
28+
call last_stack.fill_info()
29+
Assert Equals(fnamemodify(last_stack.filename, ':t'), 'source_map.vimspec')
30+
Assert Equals(last_stack.adjusted_lnum(), 2)
31+
Assert Equals(last_stack.adjusted_abs_lnum(), 5)
32+
End
33+
End
34+
End

test/util.vimspec

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,25 @@ Describe util
4141
It can parse tail line number
4242
let info = themis#util#stack_info('<SNR>567_foo, line 5')
4343
Assert Equals(info.stack, '<SNR>567_foo')
44-
Assert Equals(info.line, 5)
44+
Assert Equals(info.lnum, 5)
4545
End
4646

4747
It can parse nested function line number
4848
let info = themis#util#stack_info('<SNR>567_foo[5]')
4949
Assert Equals(info.stack, '<SNR>567_foo')
50-
Assert Equals(info.line, 5)
50+
Assert Equals(info.lnum, 5)
5151
End
5252

5353
It accepts old stacktrace
5454
let info = themis#util#stack_info('<SNR>567_foo')
5555
Assert Equals(info.stack, '<SNR>567_foo')
56-
Assert Equals(info.line, 0)
56+
Assert Equals(info.lnum, 0)
5757
End
5858

5959
It can treat autocmd entry
6060
let info = themis#util#stack_info('FileType Autocommands for "vim"')
6161
Assert Equals(info.stack, 'FileType Autocommands for "vim"')
62-
Assert Equals(info.line, 0)
62+
Assert Equals(info.lnum, 0)
6363
End
6464
End
6565

@@ -68,11 +68,11 @@ Describe util
6868
let stacks = themis#util#parse_callstack(ExecuteCmd('return expand("<sfile>")'))
6969
for stack in stacks
7070
Assert HasKey(stack, 'stack')
71-
Assert HasKey(stack, 'line')
71+
Assert HasKey(stack, 'lnum')
7272
endfor
7373
let laststack = stacks[-1]
7474
Assert Equals(laststack.stack, 'ExecuteCmd')
75-
Assert Equals(laststack.line, 0)
75+
Assert Equals(laststack.lnum, 0)
7676
End
7777

7878
It can parse throwpoint
@@ -83,11 +83,11 @@ Describe util
8383
endtry
8484
for stack in stacks
8585
Assert HasKey(stack, 'stack')
86-
Assert HasKey(stack, 'line')
86+
Assert HasKey(stack, 'lnum')
8787
endfor
8888
let laststack = stacks[-1]
8989
Assert Equals(laststack.stack, 'ExecuteCmd')
90-
Assert Equals(laststack.line, 1)
90+
Assert Equals(laststack.lnum, 1)
9191
End
9292
End
9393

0 commit comments

Comments
 (0)