-
Notifications
You must be signed in to change notification settings - Fork 1
/
scala_sxr.vim
250 lines (224 loc) · 7.35 KB
/
scala_sxr.vim
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
" Vim filetype plugin to provide type annotations and improved tag support in
" Scala source files.
"
" Version: 1.0.1-SNAPSHOT
" (c) 2010 Olivier Michallat (http://github.com/olim7t/scala_sxr_vim)
" License: new BSD (http://www.opensource.org/licenses/bsd-license.php)
"
" This plugin relies on data files generated by the sxr Scala compiler plugin,
" see INSTALL.markdown in the distribution for installation instructions.
" Save compatibility options to restore them at the end of the script.
let s:save_cpo = &cpo
" Use line-continuation within the script
set cpo&vim
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
let b:autodetect = !exists("g:sxr_disable_autodetect")
" Maps source to output directories for typical layouts
let s:dir_templates = {'src/main/scala' : 'classes.sxr', 'src/test/scala' : 'test-classes.sxr'}
if !exists("*s:SetTags")
" Configures the tag files for the current buffer
function s:SetTags()
execute "setlocal tags+=" . findfile("public-tags", b:sxr_output_dir)
execute "setlocal tags+=" . findfile("private-tags", b:sxr_output_dir)
" If this file exists, it contains a list of additional tag files
" coming from external projects.
let remote_tag_files = findfile("remote-public-tags", b:sxr_output_dir)
if strlen(remote_tag_files) > 0 && filereadable(remote_tag_files)
for remote_tag_file in readfile(remote_tag_files)
execute "setlocal tags+=" . remote_tag_file
endfor
endif
endfunction
endif
if !exists("*s:AutodetectDirs")
" Tries to autodetect source and output directories from the currently open
" file.
" Updates b:sxr_scala_dir and b:sxr_output_dir, returns a boolean indicating
" if both directories are set after execution.
function s:AutodetectDirs()
if !exists("b:sxr_scala_dir")
" Search one of the typical source directories above the file
" Note: requires vim to be compiled with the +file_in_path option
for template in keys(s:dir_templates)
let idx = stridx(b:scala_file, template)
if (idx > -1)
let b:sxr_scala_dir = strpart(b:scala_file, 0, idx + strlen(template))
let b:sxr_base_dir = strpart(b:scala_file, 0, idx)
let b:sxr_output_dir_name = s:dir_templates[template]
break
endif
endfor
if (strlen(b:sxr_scala_dir) == 0)
unlet b:sxr_scala_dir
endif
endif
if !exists("b:sxr_scala_dir")
echo "Could not autodetect scala directory."
return 0
endif
let b:sxr_output_dir = finddir(b:sxr_output_dir_name, b:sxr_base_dir . "**")
if strlen(b:sxr_output_dir) != 0
call s:SetTags()
else
unlet b:sxr_output_dir
endif
if !exists("b:sxr_output_dir")
echo "Could not autodetect SXR output directory."
return 0
endif
return 1
endfunction
endif
if !exists("*s:SetDirs")
" Sets the source and output directories according to the autodetect mode
" Returns a boolean indicating success or failure.
function s:SetDirs()
if b:autodetect
return s:AutodetectDirs()
else
let result = 1
if !exists("b:sxr_scala_dir")
if !exists("g:sxr_scala_dir")
echo "In manual mode, sxr_scala_dir must be set."
let result = 0
else
let b:sxr_scala_dir = g:sxr_scala_dir
endif
endif
if !exists("b:sxr_output_dir")
if !exists("g:sxr_output_dir")
echo "In manual mode, sxr_output_dir must be set."
let result = 0
else
let b:sxr_output_dir = g:sxr_output_dir
call s:SetTags()
endif
endif
return result
endif
endfunction
endif
" Absolute, UNIX-style path of the file in this buffer
let b:scala_file = expand("%:p:gs?\\?/?")
if !exists("*s:GetSxrFile")
" Computes the path of the SXR file corresponding to the current source
" file, and store its path in the buffer variable b:sxr_file
" Returns 1 if the function succeeded, 0 otherwise.
function s:GetSxrFile()
" If the directories were set manually, we still need to check their
" existence
let scala_dir_abs = fnamemodify(b:sxr_scala_dir, ":p:gs?\\?/?")
if !isdirectory(scala_dir_abs)
echo "Invalid directory : " . scala_dir_abs . ". Set the sxr_scala_dir variable."
unlet b:sxr_scala_dir
unlet! b:sxr_file
return 0
endif
let output_dir_abs = fnamemodify(b:sxr_output_dir, ":p:gs?\\?/?")
if !isdirectory(output_dir_abs)
echo "Invalid directory : " . output_dir_abs . ". Set the sxr_output_dir variable."
unlet b:sxr_output_dir
unlet! b:sxr_file
return 0
endif
if match(b:scala_file, scala_dir_abs) == 0
let b:sxr_file = substitute(b:scala_file, scala_dir_abs, output_dir_abs, "") . ".txt"
return 1
else
echo b:scala_file . " is not in the directory " . scala_dir_abs . ". Set the sxr_scala_dir variable."
unlet b:sxr_scala_dir
unlet! b:sxr_file
return 0
endif
endfunction
endif
if !exists("*s:Load")
" Loads the annotation data and stores it in the buffer variable b:sxr_data
" Returns 1 if the function succeeded, 0 otherwise.
function s:Load()
if !(exists("b:sxr_scala_dir") && exists("b:sxr_output_dir")) && !s:SetDirs()
return 0
endif
if !exists("b:sxr_file") && !s:GetSxrFile()
return 0
endif
if !filereadable(b:sxr_file)
echo b:sxr_file . " does not exist or can't be read. Check the value of sxr_output_dir."
return 0
endif
" Load data if not cached or stale
if !exists("b:last_loaded") || getftime(b:sxr_file) > b:last_loaded
let b:sxr_data = readfile(b:sxr_file)
let b:last_loaded = getftime(b:sxr_file)
endif
return 1
endfunction
endif
if !exists("*s:GetSxrData")
" Retrieves a token (identified by its index) from the line corresponding to
" the current offset in the SXR data file.
" Returns "default" if the data does not exist.
function s:GetSxrData(index, default)
" Note: requires vim to be compiled with the +byte_offset option
let offset = line2byte(line(".")) + col(".") - 2
for line in b:sxr_data
let matches = matchlist(line, '\(\d\+\)\t\(\d\+\)\t\(.*\)\t\(.*\)')
if get(matches, 1, -1) > offset
" Current line defines a token starting after the current offset,
" no match
return a:default
elseif offset <= get(matches, 2, -1)
" Current line defines a token containing the current offset,
" match
return get(matches, a:index, a:default)
endif
endfor
" Tried all lines, no match
return a:default
endfunction
endif
if !exists("*s:Annotate")
" Echoes the type annotation for the current cursor position
function s:Annotate()
if !s:Load()
return
endif
echo s:GetSxrData(3, "No annotation here.")
endfunction
endif
if !exists("*s:JumpTo")
" Jumps to the declaration of the symbol at the current position
function s:JumpTo()
if !s:Load()
return
endif
let tag_name = s:GetSxrData(4, "")
if strlen(tag_name) == 0
echo "No link here."
else
execute "tag " . tag_name
endif
endfunction
endif
" KEY MAPPINGS
" Gives the user a chance to disable mappings
if !exists("no_plugin_maps") && !exists("no_scala_maps")
" Mapping for Annotate
" Gives the user a chance to use a different mapping
if !hasmapto("<Plug>Annotate")
map <silent><buffer><unique> <F2> <Plug>Annotate
endif
noremap <silent><buffer><unique> <Plug>Annotate :call <Sid>Annotate()<CR>
" Mapping for JumpTo
if !hasmapto("<Plug>JumpTo")
" No <unique>, we are purposedly remapping an existing shortcut
map <silent><buffer> <C-]> <Plug>JumpTo
endif
map <silent><buffer><unique> <Plug>JumpTo :call <Sid>JumpTo()<CR>
endif
" Restore compatibility options
let &cpo = s:save_cpo