forked from vim-test/vim-test
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbase.vim
More file actions
132 lines (118 loc) · 4.52 KB
/
Copy pathbase.vim
File metadata and controls
132 lines (118 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
function! test#base#test_file(runner, file) abort
return test#{a:runner}#test_file(a:file)
endfunction
function! test#base#build_position(runner, type, position) abort
return test#{a:runner}#build_position(a:type, a:position)
endfunction
function! test#base#options(runner, args, ...) abort
let options = get(g:, 'test#'.a:runner.'#options')
if empty(a:000) && type(options) == type('')
let options = split(options)
elseif !empty(a:000) && type(options) == type({})
let options = split(get(options, 'all', '')) + split(get(options, a:000[0], ''))
else
let options = []
endif
if exists('*test#'.a:runner.'#build_options')
return test#{a:runner}#build_options(a:args, options)
else
return options + a:args
endif
endfunction
function! test#base#executable(runner) abort
if exists('g:test#'.a:runner.'#executable')
return g:test#{a:runner}#executable
else
return test#{a:runner}#executable()
endif
endfunction
function! test#base#build_args(runner, args) abort
return test#{a:runner}#build_args(a:args)
endfunction
function! test#base#file_exists(file) abort
return !empty(glob(a:file)) || bufexists(a:file)
endfunction
function! test#base#escape_regex(string) abort
return escape(a:string, '?+*\^$.|{}[]()')
endfunction
function! test#base#no_colors() abort
let strategy = get(g:, 'test#strategy', 'basic')
return has('gui_running') && strategy ==# 'basic'
endfunction
" Takes a position and a dictionary of patterns, and returns list of strings
" that were matched in the file by the patterns from the given position
" upwards. It can be used when a runner doesn't support running nearest tests
" with line numbers, but supports regexes.
"
" The "position" argument is a dictionary created by this plugin:
"
" {
" 'file': 'test/foo_test.rb',
" 'line': 11,
" 'col': 2,
" }
"
" The "patterns" argument is a dictionary where keys are either "test" or
" "namespace", and values are lists of regexes:
"
" {
" 'test': ['\v^\s*def (test_\w+)'],
" 'namespace': ['\v^\s*%(class|module) (\S+)'],
" }
"
" If a line is matched, the substring corresponding to the 1st match group will
" be returned. So for the above patterns this function might return something
" like this:
"
" {
" 'test': ['test_calculates_time'],
" 'test_line': 54, " Line where 'test_calculates_time' was found
" 'namespace': ['CalculatorTest'],
" }
function! test#base#nearest_test(position, patterns) abort
return test#base#nearest_test_in_lines(a:position['file'], a:position['line'], 1, a:patterns)
endfunction
" This function is used internally by the test#base#nearest_test function
" So it behaves exactly like describe for test#base#nearest_test except that
" it can search forward or backward depending on the search range.
"
" Instead of taking a "position" argument, this function takes 3:
" - "filename" is the equivalent of "position['file']"
" - "from_line" the line number from where to start the search, is the
" equivalent fo "position['line']"
" - "to_line" the line number where to end the search (it would be 1 in
" test#base#nearest_test)
"
" If "from_line" is greater than "to_line" or equals '$' then the search will
" be backward.
" Otherwise it will be forward.
function! test#base#nearest_test_in_lines(filename, from_line, to_line, patterns) abort
let test = []
let namespace = []
let last_indent = -1
let current_line = a:from_line + 1
let test_line = -1
let is_reverse = '$' == a:from_line ? 1 : a:from_line > a:to_line
let lines = is_reverse
\ ? reverse(getbufline(a:filename, a:to_line, a:from_line))
\ : getbufline(a:filename, a:from_line, a:to_line)
for line in lines
let current_line = current_line + (is_reverse ? -1 : 1)
let test_match = s:find_match(line, a:patterns['test'])
let namespace_match = s:find_match(line, a:patterns['namespace'])
let indent = len(matchstr(line, '^\s*'))
if !empty(test_match) && last_indent == -1
call add(test, filter(test_match[1:], '!empty(v:val)')[0])
let last_indent = indent
let test_line = current_line
elseif !empty(namespace_match) && (indent < last_indent || last_indent == -1)
call add(namespace, filter(namespace_match[1:], '!empty(v:val)')[0])
let last_indent = indent
endif
endfor
return {'test': test, 'test_line': test_line, 'namespace': reverse(namespace)}
endfunction
function! s:find_match(line, patterns) abort
let matches = map(copy(a:patterns), 'matchlist(a:line, v:val)')
return get(filter(matches, '!empty(v:val)'), 0, [])
endfunction