blob: 0fa773335d47967e3b15eed0bb34b807f5de12eb [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Vim filetype plugin file
Doug Kearns93197fd2024-01-14 20:59:02 +01002" Language: Java
Aliaksei Budavei40524742024-04-14 19:57:00 +03003" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
4" Former Maintainer: Dan Sharp
5" Repository: https://github.com/zzzyxwvut/java-vim.git
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +01006" Last Change: 2024 Dec 16
Doug Kearns93197fd2024-01-14 20:59:02 +01007" 2024 Jan 14 by Vim Project (browsefilter)
Riley Bruins0a083062024-06-03 20:40:45 +02008" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
Bram Moolenaar071d4272004-06-13 20:20:40 +00009
Bram Moolenaar071d4272004-06-13 20:20:40 +000010" Make sure the continuation lines below do not cause problems in
11" compatibility mode.
12let s:save_cpo = &cpo
13set cpo-=C
14
Aliaksei Budavei85f054a2024-09-30 19:40:04 +020015if (exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown")) &&
16 \ exists("*javaformat#RemoveCommonMarkdownWhitespace")
17 delfunction javaformat#RemoveCommonMarkdownWhitespace
18 unlet! g:loaded_javaformat
19endif
20
21if exists("b:did_ftplugin")
22 let &cpo = s:save_cpo
23 unlet s:save_cpo
24 finish
25endif
26
27let b:did_ftplugin = 1
28
Bram Moolenaar071d4272004-06-13 20:20:40 +000029" For filename completion, prefer the .java extension over the .class
30" extension.
31set suffixes+=.class
32
33" Enable gf on import statements. Convert . in the package
34" name to / and append .java to the name, then search the path.
35setlocal includeexpr=substitute(v:fname,'\\.','/','g')
36setlocal suffixesadd=.java
Aliaksei Budavei36e667a2024-04-18 23:01:52 +020037
38" Clean up in case this file is sourced again.
39unlet! s:zip_func_upgradable
40
Aliaksei Budavei85f054a2024-09-30 19:40:04 +020041"""" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0.
42
Aliaksei Budavei36e667a2024-04-18 23:01:52 +020043" Documented in ":help ft-java-plugin".
44if exists("g:ftplugin_java_source_path") &&
45 \ type(g:ftplugin_java_source_path) == type("")
46 if filereadable(g:ftplugin_java_source_path)
47 if exists("#zip") &&
48 \ g:ftplugin_java_source_path =~# '.\.\%(jar\|zip\)$'
49 if !exists("s:zip_files")
50 let s:zip_files = {}
51 endif
52
53 let s:zip_files[bufnr('%')] = g:ftplugin_java_source_path
54 let s:zip_files[0] = g:ftplugin_java_source_path
55 let s:zip_func_upgradable = 1
56
57 function! JavaFileTypeZipFile() abort
58 let @/ = substitute(v:fname, '\.', '\\/', 'g') . '.java'
59 return get(s:zip_files, bufnr('%'), s:zip_files[0])
60 endfunction
61
62 " E120 for "inex=s:JavaFileTypeZipFile()" before v8.2.3900.
63 setlocal includeexpr=JavaFileTypeZipFile()
64 setlocal suffixesadd<
65 endif
66 else
67 let &l:path = g:ftplugin_java_source_path . ',' . &l:path
68 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000069endif
70
71" Set 'formatoptions' to break comment lines but not other lines,
72" and insert the comment leader when hitting <CR> or using "o".
73setlocal formatoptions-=t formatoptions+=croql
74
Aliaksei Budavei85f054a2024-09-30 19:40:04 +020075" Set 'comments' to format Markdown Javadoc comments and dashed lists
76" in other multi-line comments (it behaves just like C).
77setlocal comments& comments^=:///,sO:*\ -,mO:*\ \ ,exO:*/
Bram Moolenaar071d4272004-06-13 20:20:40 +000078
Riley Bruins0a083062024-06-03 20:40:45 +020079setlocal commentstring=//\ %s
Bram Moolenaar071d4272004-06-13 20:20:40 +000080
81" Change the :browse e filter to primarily show Java-related files.
Doug Kearns93197fd2024-01-14 20:59:02 +010082if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
Bram Moolenaar071d4272004-06-13 20:20:40 +000083 let b:browsefilter="Java Files (*.java)\t*.java\n" .
84 \ "Properties Files (*.prop*)\t*.prop*\n" .
Doug Kearns93197fd2024-01-14 20:59:02 +010085 \ "Manifest Files (*.mf)\t*.mf\n"
86 if has("win32")
87 let b:browsefilter .= "All Files (*.*)\t*\n"
88 else
89 let b:browsefilter .= "All Files (*)\t*\n"
90 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000091endif
92
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +010093"""" Support pre- and post-compiler actions for SpotBugs.
94if (!empty(get(g:, 'spotbugs_properties', {})) ||
95 \ !empty(get(b:, 'spotbugs_properties', {}))) &&
96 \ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim')
Konfekt65311c62024-11-28 21:06:09 +010097
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +010098 function! s:SpotBugsGetProperty(name, default) abort
99 return get(
100 \ {s:spotbugs_properties_scope}spotbugs_properties,
101 \ a:name,
102 \ a:default)
103 endfunction
104
105 function! s:SpotBugsHasProperty(name) abort
106 return has_key(
107 \ {s:spotbugs_properties_scope}spotbugs_properties,
108 \ a:name)
109 endfunction
110
111 function! s:SpotBugsGetProperties() abort
112 return {s:spotbugs_properties_scope}spotbugs_properties
113 endfunction
114
115 " Work around ":bar"s and ":autocmd"s.
116 function! s:ExecuteActionOnce(cleanup_cmd, action_cmd) abort
117 try
118 execute a:cleanup_cmd
119 finally
120 execute a:action_cmd
121 endtry
122 endfunction
123
124 if exists("b:spotbugs_properties")
125 let s:spotbugs_properties_scope = 'b:'
126
127 " Merge global entries, if any, in buffer-local entries, favouring
128 " defined buffer-local ones.
129 call extend(
130 \ b:spotbugs_properties,
131 \ get(g:, 'spotbugs_properties', {}),
132 \ 'keep')
133 elseif exists("g:spotbugs_properties")
134 let s:spotbugs_properties_scope = 'g:'
135 endif
136
137 let s:commands = {}
138
139 for s:name in ['DefaultPreCompilerCommand',
140 \ 'DefaultPreCompilerTestCommand',
141 \ 'DefaultPostCompilerCommand']
142 if s:SpotBugsHasProperty(s:name)
143 let s:commands[s:name] = remove(
144 \ s:SpotBugsGetProperties(),
145 \ s:name)
146 endif
147 endfor
148
149 if s:SpotBugsHasProperty('compiler')
150 " XXX: Postpone loading the script until all state, if any, has been
151 " collected.
152 if !empty(s:commands)
153 let g:spotbugs#state = {
154 \ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
155 \ 'commands': copy(s:commands),
156 \ }
157 else
158 let g:spotbugs#state = {
159 \ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
160 \ }
161 endif
162
163 " Merge default entries in global (or buffer-local) entries, favouring
164 " defined global (or buffer-local) ones.
165 call extend(
166 \ {s:spotbugs_properties_scope}spotbugs_properties,
167 \ spotbugs#DefaultProperties(),
168 \ 'keep')
169 elseif !empty(s:commands)
170 " XXX: Postpone loading the script until all state, if any, has been
171 " collected.
172 let g:spotbugs#state = {'commands': copy(s:commands)}
173 endif
174
175 unlet s:commands s:name
Konfekt65311c62024-11-28 21:06:09 +0100176 let s:request = 0
177
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100178 if s:SpotBugsHasProperty('PostCompilerAction')
Konfekt65311c62024-11-28 21:06:09 +0100179 let s:request += 4
180 endif
181
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100182 if s:SpotBugsHasProperty('PreCompilerTestAction')
183 let s:dispatcher = printf('call call(%s, [])',
184 \ string(s:SpotBugsGetProperties().PreCompilerTestAction))
185 let s:request += 2
186 endif
187
188 if s:SpotBugsHasProperty('PreCompilerAction')
189 let s:dispatcher = printf('call call(%s, [])',
190 \ string(s:SpotBugsGetProperties().PreCompilerAction))
191 let s:request += 1
192 endif
193
194 " Adapt the tests for "s:FindClassFiles()" from "compiler/spotbugs.vim".
Konfekt65311c62024-11-28 21:06:09 +0100195 if (s:request == 3 || s:request == 7) &&
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100196 \ (!empty(s:SpotBugsGetProperty('sourceDirPath', [])) &&
197 \ !empty(s:SpotBugsGetProperty('classDirPath', [])) &&
198 \ !empty(s:SpotBugsGetProperty('testSourceDirPath', [])) &&
199 \ !empty(s:SpotBugsGetProperty('testClassDirPath', [])))
200 function! s:DispatchAction(paths_action_pairs) abort
Konfekt65311c62024-11-28 21:06:09 +0100201 let name = expand('%:p')
202
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100203 for [paths, Action] in a:paths_action_pairs
204 for path in paths
205 if name =~# (path . '.\{-}\.java\=$')
206 call Action()
207 return
208 endif
209 endfor
Konfekt65311c62024-11-28 21:06:09 +0100210 endfor
211 endfunction
212
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100213 let s:dir_cnt = min([
214 \ len(s:SpotBugsGetProperties().sourceDirPath),
215 \ len(s:SpotBugsGetProperties().classDirPath)])
216 let s:test_dir_cnt = min([
217 \ len(s:SpotBugsGetProperties().testSourceDirPath),
218 \ len(s:SpotBugsGetProperties().testClassDirPath)])
219
220 " Do not break up path pairs with filtering!
221 let s:dispatcher = printf('call s:DispatchAction(%s)',
222 \ string([[s:SpotBugsGetProperties().sourceDirPath[0 : s:dir_cnt - 1],
223 \ s:SpotBugsGetProperties().PreCompilerAction],
224 \ [s:SpotBugsGetProperties().testSourceDirPath[0 : s:test_dir_cnt - 1],
225 \ s:SpotBugsGetProperties().PreCompilerTestAction]]))
226 unlet s:test_dir_cnt s:dir_cnt
227 endif
228
229 if exists("s:dispatcher")
230 function! s:ExecuteActions(pre_action, post_action) abort
231 try
232 execute a:pre_action
233 catch /\<E42:/
234 execute a:post_action
235 endtry
236 endfunction
Konfekt65311c62024-11-28 21:06:09 +0100237 endif
238
239 if s:request
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100240 if exists("b:spotbugs_syntax_once") || empty(join(getline(1, 8), ''))
241 let s:actions = [{'event': 'User'}]
Konfekt65311c62024-11-28 21:06:09 +0100242 else
243 " XXX: Handle multiple FileType events when vimrc contains more
244 " than one filetype setting for the language, e.g.:
245 " :filetype plugin indent on
246 " :autocmd BufRead,BufNewFile *.java setlocal filetype=java ...
247 " XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin !
248 let b:spotbugs_syntax_once = 1
249 let s:actions = [{
250 \ 'event': 'Syntax',
251 \ 'once': 1,
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100252 \ }, {
253 \ 'event': 'User',
254 \ }]
Konfekt65311c62024-11-28 21:06:09 +0100255 endif
256
257 for s:idx in range(len(s:actions))
258 if s:request == 7 || s:request == 6 || s:request == 5
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100259 let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
260 \ string(s:dispatcher),
261 \ string(printf('compiler spotbugs | call call(%s, [])',
262 \ string(s:SpotBugsGetProperties().PostCompilerAction))))
Konfekt65311c62024-11-28 21:06:09 +0100263 elseif s:request == 4
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100264 let s:actions[s:idx].cmd = printf(
265 \ 'compiler spotbugs | call call(%s, [])',
266 \ string(s:SpotBugsGetProperties().PostCompilerAction))
Konfekt65311c62024-11-28 21:06:09 +0100267 elseif s:request == 3 || s:request == 2 || s:request == 1
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100268 let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
269 \ string(s:dispatcher),
270 \ string('compiler spotbugs'))
Konfekt65311c62024-11-28 21:06:09 +0100271 else
272 let s:actions[s:idx].cmd = ''
273 endif
274 endfor
275
276 if !exists("#java_spotbugs")
277 augroup java_spotbugs
278 augroup END
279 endif
280
281 " The events are defined in s:actions.
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100282 silent! autocmd! java_spotbugs User <buffer>
Konfekt65311c62024-11-28 21:06:09 +0100283 silent! autocmd! java_spotbugs Syntax <buffer>
284
285 for s:action in s:actions
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100286 if has_key(s:action, 'once')
287 execute printf('autocmd java_spotbugs %s <buffer> ' .
288 \ 'call s:ExecuteActionOnce(%s, %s)',
Konfekt65311c62024-11-28 21:06:09 +0100289 \ s:action.event,
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100290 \ string(printf('autocmd! java_spotbugs %s <buffer>',
291 \ s:action.event)),
292 \ string(s:action.cmd))
293 else
294 execute printf('autocmd java_spotbugs %s <buffer> %s',
295 \ s:action.event,
296 \ s:action.cmd)
297 endif
Konfekt65311c62024-11-28 21:06:09 +0100298 endfor
299
300 unlet! s:action s:actions s:idx s:dispatcher
301 endif
302
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100303 delfunction s:SpotBugsGetProperties
304 delfunction s:SpotBugsHasProperty
305 delfunction s:SpotBugsGetProperty
306 unlet! s:request s:spotbugs_properties_scope
Konfekt65311c62024-11-28 21:06:09 +0100307endif
308
309function! JavaFileTypeCleanUp() abort
310 setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr<
311 unlet! b:browsefilter
312
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100313 " The concatenated removals may be misparsed as a User autocmd.
314 silent! autocmd! java_spotbugs User <buffer>
Konfekt65311c62024-11-28 21:06:09 +0100315 silent! autocmd! java_spotbugs Syntax <buffer>
316endfunction
317
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318" Undo the stuff we changed.
Konfekt65311c62024-11-28 21:06:09 +0100319let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320
Aliaksei Budavei36e667a2024-04-18 23:01:52 +0200321" See ":help vim9-mix".
322if !has("vim9script")
323 let &cpo = s:save_cpo
324 unlet s:save_cpo
325 finish
326endif
327
328if exists("s:zip_func_upgradable")
329 delfunction! JavaFileTypeZipFile
330
331 def! s:JavaFileTypeZipFile(): string
332 @/ = substitute(v:fname, '\.', '\\/', 'g') .. '.java'
333 return get(zip_files, bufnr('%'), zip_files[0])
334 enddef
335
336 setlocal includeexpr=s:JavaFileTypeZipFile()
337 setlocal suffixesadd<
338endif
339
Konfekt65311c62024-11-28 21:06:09 +0100340if exists("*s:DispatchAction")
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100341 def! s:DispatchAction(paths_action_pairs: list<list<any>>)
Konfekt65311c62024-11-28 21:06:09 +0100342 const name: string = expand('%:p')
343
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100344 for [paths: list<string>, Action: func: any] in paths_action_pairs
345 for path in paths
346 if name =~# (path .. '.\{-}\.java\=$')
347 Action()
348 return
349 endif
350 endfor
Konfekt65311c62024-11-28 21:06:09 +0100351 endfor
352 enddef
353endif
354
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355" Restore the saved compatibility options.
356let &cpo = s:save_cpo
Bram Moolenaar84f72352012-03-11 15:57:40 +0100357unlet s:save_cpo
Aliaksei Budavei85f054a2024-09-30 19:40:04 +0200358" vim: fdm=syntax sw=4 ts=8 noet sta