Skip to content

Commit ce0a56d

Browse files
committed
Implement source map
1 parent 05e8a02 commit ce0a56d

3 files changed

Lines changed: 96 additions & 9 deletions

File tree

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: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

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

89
let s:StackInfo = {
910
\ 'stack': '',
@@ -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, ', ')
@@ -176,6 +199,11 @@ function themis#util#adjust_func_line(target, line) abort
176199
endif
177200
endfunction
178201

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+
179207
function themis#util#callstacklines(throwpoint, ...) abort
180208
let infos = call('themis#util#callstack', [a:throwpoint] + a:000)
181209
return map(infos, 'v:val.format()')
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

0 commit comments

Comments
 (0)