mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	=============== LIMITATIONS AND OBSERVATIONS ===============
* Remember that external-type names can only be found when
  they match filenames resolvable in "&path" with "import"
  declarations; load the source file of an external type to
  look up its nested types and sibling top types, if any.
* Strive to narrow the search by assigning only relevant
  pathnames for directories *or* an archive to "&path", e.g.
  ":set path-=/usr/include".
* Use "{Visual}gf" on fully-qualified names.
* Accept the fact that "&define" cannot contain end-of-line
  characters (":help definition-search").  A declaration
  whose matchable header is not contained within a line can
  be found iff all of its non-optional components belong to
  the same line; for types, such components are a keyword,
  e.g. "class", followed by a run of blank characters and
  an identifier, e.g. "Test"; for methods: a return type,
  e.g. "String", or a keyword "void", followed by a run of
  blank characters and an identifier, e.g. "toString", that
  is followed by "(".
* The members of the "java.lang" package are usually not
  associated with "import" declarations; to look up their
  declarations, load a source file for a member of that
  package, and then use, on a simple name of interest for
  a member, either "[-Ctrl-d" etc. for local declarations
  or "gf" for external declarations, assuming that "." *or*
  the appropriate pathname for a JDK archive is assigned to
  "&path".
* Follow the above instruction made for the "java.lang"
  members for any type whose simple name is not associated
  with an "import" declaration, i.e. a member type of the
  same package that is declared in another compilation unit.
* Append the "$" character to "&iskeyword" when looking up
  declarations of generated code.
See zzzyxwvut/java-vim#4.
closes: #17281
Co-authored-by: Konfekt <Konfekt@users.noreply.github.com>
Signed-off-by: Aliaksei Budavei <0x000c70@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
		
	
		
			
				
	
	
		
			419 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			VimL
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			VimL
		
	
	
	
	
	
| " Vim filetype plugin file
 | |
| " Language:		Java
 | |
| " Maintainer:		Aliaksei Budavei <0x000c70 AT gmail DOT com>
 | |
| " Former Maintainer:	Dan Sharp
 | |
| " Repository:		https://github.com/zzzyxwvut/java-vim.git
 | |
| " Last Change:		2025 May 08
 | |
| 
 | |
| " Make sure the continuation lines below do not cause problems in
 | |
| " compatibility mode.
 | |
| let s:save_cpo = &cpo
 | |
| set cpo-=C
 | |
| 
 | |
| if (exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown")) &&
 | |
| 	\ exists("*javaformat#RemoveCommonMarkdownWhitespace")
 | |
|     delfunction javaformat#RemoveCommonMarkdownWhitespace
 | |
|     unlet! g:loaded_javaformat
 | |
| endif
 | |
| 
 | |
| if exists("b:did_ftplugin")
 | |
|     let &cpo = s:save_cpo
 | |
|     unlet s:save_cpo
 | |
|     finish
 | |
| endif
 | |
| 
 | |
| let b:did_ftplugin = 1
 | |
| 
 | |
| " For filename completion, prefer the .java extension over the .class
 | |
| " extension.
 | |
| set suffixes+=.class
 | |
| 
 | |
| " Set up "&define" and "&include".
 | |
| let s:peek = ''
 | |
| 
 | |
| try
 | |
|     " Since v7.3.1037.
 | |
|     if 'ab' !~ 'a\@1<!b'
 | |
| 	let s:peek = string(strlen('instanceof') + 8)
 | |
|     endif
 | |
| catch /\<E59:/
 | |
| endtry
 | |
| 
 | |
| " Treat "s:common" as a non-backtracking unit to avoid matching constructor
 | |
| " declarations whose package-private headers are indistinguishable from method
 | |
| " invocation.  Note that "[@-]" must not and "$" may not be in "&l:iskeyword".
 | |
| let s:common = '\%(\%(\%(@\%(interface\)\@!\%(\K\k*\.\)*\K\k*\)\s\+\)*' .
 | |
| 	\ '\%(p\%(rivate\|rotected\|ublic\)\s\+\)\=\)\@>'
 | |
| let s:types = '\%(\%(abstract\|final\|non-sealed\|s\%(ealed\|tatic\|trictfp\)\)\s\+\)*' .
 | |
| 	\ '\%(class\|enum\|@\=interface\|record\)\s\+\ze\K\k*\>'
 | |
| let s:methods = '\%(\%(abstract\|default\|final\|native\|s\%(tatic\|trictfp\|ynchronized\)\)\s\+\)*' .
 | |
| 	\ '\%(<.\{-1,}>\s\+\)\=\%(\K\k*\.\)*\K\k*\s*\%(<.\{-1,}>\%(\s\|\[\)\@=\)\=\s*\%(\[\]\s*\)*' .
 | |
| 	\ '\s\+\ze\%(\<\%(assert\|case\|instanceof\|new\|return\|throw\|when\)\s\+\)\@' .
 | |
| 	\ s:peek . '<!\K\k*\s*('
 | |
| let &l:define = printf('\C\m^\s*%s\%%(%s\|%s\)', s:common, s:types, s:methods)
 | |
| let &l:include = '\C\m^\s*import\s\+\ze\%(\K\k*\.\)\+\K\k*;'
 | |
| unlet s:methods s:types s:common s:peek
 | |
| 
 | |
| " Enable gf on import statements.  Convert . in the package
 | |
| " name to / and append .java to the name, then search the path.
 | |
| setlocal includeexpr=substitute(v:fname,'\\.','/','g')
 | |
| setlocal suffixesadd=.java
 | |
| 
 | |
| " Clean up in case this file is sourced again.
 | |
| unlet! s:zip_func_upgradable
 | |
| 
 | |
| """" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0.
 | |
| 
 | |
| " Documented in ":help ft-java-plugin".
 | |
| if exists("g:ftplugin_java_source_path") &&
 | |
| 		\ type(g:ftplugin_java_source_path) == type("")
 | |
|     if filereadable(g:ftplugin_java_source_path)
 | |
| 	if exists("#zip") &&
 | |
| 		    \ g:ftplugin_java_source_path =~# '.\.\%(jar\|zip\)$'
 | |
| 	    if !exists("s:zip_files")
 | |
| 		let s:zip_files = {}
 | |
| 	    endif
 | |
| 
 | |
| 	    let s:zip_files[bufnr('%')] = g:ftplugin_java_source_path
 | |
| 	    let s:zip_files[0] = g:ftplugin_java_source_path
 | |
| 	    let s:zip_func_upgradable = 1
 | |
| 
 | |
| 	    function! JavaFileTypeZipFile() abort
 | |
| 		let @/ = substitute(v:fname, '\.', '\\/', 'g') . '.java'
 | |
| 		return get(s:zip_files, bufnr('%'), s:zip_files[0])
 | |
| 	    endfunction
 | |
| 
 | |
| 	    " E120 for "inex=s:JavaFileTypeZipFile()" before v8.2.3900.
 | |
| 	    setlocal includeexpr=JavaFileTypeZipFile()
 | |
| 	    setlocal suffixesadd<
 | |
| 	endif
 | |
|     else
 | |
| 	let &l:path = g:ftplugin_java_source_path . ',' . &l:path
 | |
|     endif
 | |
| endif
 | |
| 
 | |
| " Set 'formatoptions' to break comment lines but not other lines,
 | |
| " and insert the comment leader when hitting <CR> or using "o".
 | |
| setlocal formatoptions-=t formatoptions+=croql
 | |
| 
 | |
| " Set 'comments' to format Markdown Javadoc comments and dashed lists
 | |
| " in other multi-line comments (it behaves just like C).
 | |
| setlocal comments& comments^=:///,sO:*\ -,mO:*\ \ ,exO:*/
 | |
| 
 | |
| setlocal commentstring=//\ %s
 | |
| 
 | |
| " Change the :browse e filter to primarily show Java-related files.
 | |
| if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
 | |
|     let  b:browsefilter="Java Files (*.java)\t*.java\n" .
 | |
| 		\	"Properties Files (*.prop*)\t*.prop*\n" .
 | |
| 		\	"Manifest Files (*.mf)\t*.mf\n"
 | |
|     if has("win32")
 | |
| 	let b:browsefilter .= "All Files (*.*)\t*\n"
 | |
|     else
 | |
| 	let b:browsefilter .= "All Files (*)\t*\n"
 | |
|     endif
 | |
| endif
 | |
| 
 | |
| """" Support pre- and post-compiler actions for SpotBugs.
 | |
| if (!empty(get(g:, 'spotbugs_properties', {})) ||
 | |
| 	\ !empty(get(b:, 'spotbugs_properties', {}))) &&
 | |
| 	\ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim')
 | |
| 
 | |
|     function! s:SpotBugsGetProperty(name, default) abort
 | |
| 	return get(
 | |
| 	    \ {s:spotbugs_properties_scope}spotbugs_properties,
 | |
| 	    \ a:name,
 | |
| 	    \ a:default)
 | |
|     endfunction
 | |
| 
 | |
|     function! s:SpotBugsHasProperty(name) abort
 | |
| 	return has_key(
 | |
| 	    \ {s:spotbugs_properties_scope}spotbugs_properties,
 | |
| 	    \ a:name)
 | |
|     endfunction
 | |
| 
 | |
|     function! s:SpotBugsGetProperties() abort
 | |
| 	return {s:spotbugs_properties_scope}spotbugs_properties
 | |
|     endfunction
 | |
| 
 | |
|     " Work around ":bar"s and ":autocmd"s.
 | |
|     function! JavaFileTypeExecuteActionOnce(cleanup_cmd, action_cmd) abort
 | |
| 	try
 | |
| 	    execute a:cleanup_cmd
 | |
| 	finally
 | |
| 	    execute a:action_cmd
 | |
| 	endtry
 | |
|     endfunction
 | |
| 
 | |
|     if exists("b:spotbugs_properties")
 | |
| 	let s:spotbugs_properties_scope = 'b:'
 | |
| 
 | |
| 	" Merge global entries, if any, in buffer-local entries, favouring
 | |
| 	" defined buffer-local ones.
 | |
| 	call extend(
 | |
| 	    \ b:spotbugs_properties,
 | |
| 	    \ get(g:, 'spotbugs_properties', {}),
 | |
| 	    \ 'keep')
 | |
|     elseif exists("g:spotbugs_properties")
 | |
| 	let s:spotbugs_properties_scope = 'g:'
 | |
|     endif
 | |
| 
 | |
|     let s:commands = {}
 | |
| 
 | |
|     for s:name in ['DefaultPreCompilerCommand',
 | |
| 	    \ 'DefaultPreCompilerTestCommand',
 | |
| 	    \ 'DefaultPostCompilerCommand']
 | |
| 	if s:SpotBugsHasProperty(s:name)
 | |
| 	    let s:commands[s:name] = remove(
 | |
| 		\ s:SpotBugsGetProperties(),
 | |
| 		\ s:name)
 | |
| 	endif
 | |
|     endfor
 | |
| 
 | |
|     if s:SpotBugsHasProperty('compiler')
 | |
| 	" XXX: Postpone loading the script until all state, if any, has been
 | |
| 	" collected.
 | |
| 	if !empty(s:commands)
 | |
| 	    let g:spotbugs#state = {
 | |
| 		\ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
 | |
| 		\ 'commands': copy(s:commands),
 | |
| 	    \ }
 | |
| 	else
 | |
| 	    let g:spotbugs#state = {
 | |
| 		\ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
 | |
| 	    \ }
 | |
| 	endif
 | |
| 
 | |
| 	" Merge default entries in global (or buffer-local) entries, favouring
 | |
| 	" defined global (or buffer-local) ones.
 | |
| 	call extend(
 | |
| 	    \ {s:spotbugs_properties_scope}spotbugs_properties,
 | |
| 	    \ spotbugs#DefaultProperties(),
 | |
| 	    \ 'keep')
 | |
|     elseif !empty(s:commands)
 | |
| 	" XXX: Postpone loading the script until all state, if any, has been
 | |
| 	" collected.
 | |
| 	let g:spotbugs#state = {'commands': copy(s:commands)}
 | |
|     endif
 | |
| 
 | |
|     unlet s:commands s:name
 | |
|     let s:request = 0
 | |
| 
 | |
|     if s:SpotBugsHasProperty('PostCompilerAction')
 | |
| 	let s:request += 4
 | |
|     endif
 | |
| 
 | |
|     if s:SpotBugsHasProperty('PreCompilerTestAction')
 | |
| 	let s:dispatcher = printf('call call(%s, [])',
 | |
| 	    \ string(s:SpotBugsGetProperties().PreCompilerTestAction))
 | |
| 	let s:request += 2
 | |
|     endif
 | |
| 
 | |
|     if s:SpotBugsHasProperty('PreCompilerAction')
 | |
| 	let s:dispatcher = printf('call call(%s, [])',
 | |
| 	    \ string(s:SpotBugsGetProperties().PreCompilerAction))
 | |
| 	let s:request += 1
 | |
|     endif
 | |
| 
 | |
|     " Adapt the tests for "s:FindClassFiles()" from "compiler/spotbugs.vim".
 | |
|     if (s:request == 3 || s:request == 7) &&
 | |
| 	    \ (!empty(s:SpotBugsGetProperty('sourceDirPath', [])) &&
 | |
| 		\ !empty(s:SpotBugsGetProperty('classDirPath', [])) &&
 | |
| 	    \ !empty(s:SpotBugsGetProperty('testSourceDirPath', [])) &&
 | |
| 		\ !empty(s:SpotBugsGetProperty('testClassDirPath', [])))
 | |
| 	function! s:DispatchAction(paths_action_pairs) abort
 | |
| 	    let name = expand('%:p')
 | |
| 
 | |
| 	    for [paths, Action] in a:paths_action_pairs
 | |
| 		for path in paths
 | |
| 		    if name =~# (path . '.\{-}\.java\=$')
 | |
| 			call Action()
 | |
| 			return
 | |
| 		    endif
 | |
| 		endfor
 | |
| 	    endfor
 | |
| 	endfunction
 | |
| 
 | |
| 	let s:dir_cnt = min([
 | |
| 	    \ len(s:SpotBugsGetProperties().sourceDirPath),
 | |
| 	    \ len(s:SpotBugsGetProperties().classDirPath)])
 | |
| 	let s:test_dir_cnt = min([
 | |
| 	    \ len(s:SpotBugsGetProperties().testSourceDirPath),
 | |
| 	    \ len(s:SpotBugsGetProperties().testClassDirPath)])
 | |
| 
 | |
| 	" Do not break up path pairs with filtering!
 | |
| 	let s:dispatcher = printf('call s:DispatchAction(%s)',
 | |
| 	    \ string([[s:SpotBugsGetProperties().sourceDirPath[0 : s:dir_cnt - 1],
 | |
| 			\ s:SpotBugsGetProperties().PreCompilerAction],
 | |
| 		\ [s:SpotBugsGetProperties().testSourceDirPath[0 : s:test_dir_cnt - 1],
 | |
| 			\ s:SpotBugsGetProperties().PreCompilerTestAction]]))
 | |
| 	unlet s:test_dir_cnt s:dir_cnt
 | |
|     endif
 | |
| 
 | |
|     if exists("s:dispatcher")
 | |
| 	function! s:ExecuteActions(pre_action, post_action) abort
 | |
| 	    try
 | |
| 		execute a:pre_action
 | |
| 	    catch /\<E42:/
 | |
| 		execute a:post_action
 | |
| 	    endtry
 | |
| 	endfunction
 | |
|     endif
 | |
| 
 | |
|     if s:request
 | |
| 	if exists("b:spotbugs_syntax_once") || empty(join(getline(1, 8), ''))
 | |
| 	    let s:actions = [{'event': 'User'}]
 | |
| 	else
 | |
| 	    " XXX: Handle multiple FileType events when vimrc contains more
 | |
| 	    " than one filetype setting for the language, e.g.:
 | |
| 	    "	:filetype plugin indent on
 | |
| 	    "	:autocmd BufRead,BufNewFile *.java setlocal filetype=java ...
 | |
| 	    " XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin !
 | |
| 	    let b:spotbugs_syntax_once = 1
 | |
| 	    let s:actions = [{
 | |
| 		    \ 'event': 'Syntax',
 | |
| 		    \ 'once': 1,
 | |
| 		\ }, {
 | |
| 		    \ 'event': 'User',
 | |
| 		\ }]
 | |
| 	endif
 | |
| 
 | |
| 	for s:idx in range(len(s:actions))
 | |
| 	    if s:request == 7 || s:request == 6 || s:request == 5
 | |
| 		let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
 | |
| 		    \ string(s:dispatcher),
 | |
| 		    \ string(printf('compiler spotbugs | call call(%s, [])',
 | |
| 			\ string(s:SpotBugsGetProperties().PostCompilerAction))))
 | |
| 	    elseif s:request == 4
 | |
| 		let s:actions[s:idx].cmd = printf(
 | |
| 		    \ 'compiler spotbugs | call call(%s, [])',
 | |
| 		    \ string(s:SpotBugsGetProperties().PostCompilerAction))
 | |
| 	    elseif s:request == 3 || s:request == 2 || s:request == 1
 | |
| 		let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
 | |
| 		    \ string(s:dispatcher),
 | |
| 		    \ string('compiler spotbugs'))
 | |
| 	    else
 | |
| 		let s:actions[s:idx].cmd = ''
 | |
| 	    endif
 | |
| 	endfor
 | |
| 
 | |
| 	if !exists("#java_spotbugs")
 | |
| 	    augroup java_spotbugs
 | |
| 	    augroup END
 | |
| 	endif
 | |
| 
 | |
| 	" The events are defined in s:actions.
 | |
| 	silent! autocmd! java_spotbugs User <buffer>
 | |
| 	silent! autocmd! java_spotbugs Syntax <buffer>
 | |
| 
 | |
| 	for s:action in s:actions
 | |
| 	    if has_key(s:action, 'once')
 | |
| 		execute printf('autocmd java_spotbugs %s <buffer> ' .
 | |
| 			\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
 | |
| 		    \ s:action.event,
 | |
| 		    \ string(printf('autocmd! java_spotbugs %s <buffer>',
 | |
| 			\ s:action.event)),
 | |
| 		    \ string(s:action.cmd))
 | |
| 	    else
 | |
| 		execute printf('autocmd java_spotbugs %s <buffer> %s',
 | |
| 		    \ s:action.event,
 | |
| 		    \ s:action.cmd)
 | |
| 	    endif
 | |
| 	endfor
 | |
| 
 | |
| 	if s:SpotBugsHasProperty('PostCompilerActionExecutor') &&
 | |
| 		\ (s:request == 7 || s:request == 6 ||
 | |
| 		\ s:request == 5 || s:request == 4)
 | |
| 	    let s:augroup = s:SpotBugsGetProperty(
 | |
| 		\ 'augroupForPostCompilerAction',
 | |
| 		\ 'java_spotbugs_post')
 | |
| 	    let s:augroup = !empty(s:augroup) ? s:augroup : 'java_spotbugs_post'
 | |
| 
 | |
| 	    for s:candidate in ['java_spotbugs_post', s:augroup]
 | |
| 		if !exists("#" . s:candidate)
 | |
| 		    execute printf('augroup %s | augroup END', s:candidate)
 | |
| 		endif
 | |
| 	    endfor
 | |
| 
 | |
| 	    silent! autocmd! java_spotbugs_post User <buffer>
 | |
| 
 | |
| 	    " Define a User ":autocmd" to define a once-only ShellCmdPost
 | |
| 	    " ":autocmd" that will invoke "PostCompilerActionExecutor" and let
 | |
| 	    " it decide whether to proceed with ":compiler spotbugs" etc.; and
 | |
| 	    " seek explicit synchronisation with ":doautocmd ShellCmdPost" by
 | |
| 	    " omitting "nested" for "java_spotbugs_post" and "java_spotbugs".
 | |
| 	    execute printf('autocmd java_spotbugs_post User <buffer> ' .
 | |
| 				\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
 | |
| 		\ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)),
 | |
| 		\ string(printf('autocmd %s ShellCmdPost <buffer> ' .
 | |
| 				\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
 | |
| 		    \ s:augroup,
 | |
| 		    \ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)),
 | |
| 		    \ string(printf('call call(%s, [%s])',
 | |
| 			\ string(s:SpotBugsGetProperties().PostCompilerActionExecutor),
 | |
| 			\ string(printf('compiler spotbugs | call call(%s, [])',
 | |
| 			    \ string(s:SpotBugsGetProperties().PostCompilerAction))))))))
 | |
| 	endif
 | |
| 
 | |
| 	unlet! s:candidate s:augroup s:action s:actions s:idx s:dispatcher
 | |
|     endif
 | |
| 
 | |
|     delfunction s:SpotBugsGetProperties
 | |
|     delfunction s:SpotBugsHasProperty
 | |
|     delfunction s:SpotBugsGetProperty
 | |
|     unlet! s:request s:spotbugs_properties_scope
 | |
| endif
 | |
| 
 | |
| function! JavaFileTypeCleanUp() abort
 | |
|     setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr< include< define<
 | |
|     unlet! b:browsefilter
 | |
| 
 | |
|     " The concatenated ":autocmd" removals may be misparsed as an ":autocmd".
 | |
|     " A _once-only_ ShellCmdPost ":autocmd" is always a call-site definition.
 | |
|     silent! autocmd! java_spotbugs User <buffer>
 | |
|     silent! autocmd! java_spotbugs Syntax <buffer>
 | |
|     silent! autocmd! java_spotbugs_post User <buffer>
 | |
| endfunction
 | |
| 
 | |
| " Undo the stuff we changed.
 | |
| let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp'
 | |
| 
 | |
| " See ":help vim9-mix".
 | |
| if !has("vim9script")
 | |
|     let &cpo = s:save_cpo
 | |
|     unlet s:save_cpo
 | |
|     finish
 | |
| endif
 | |
| 
 | |
| if exists("s:zip_func_upgradable")
 | |
|     delfunction! JavaFileTypeZipFile
 | |
| 
 | |
|     def! s:JavaFileTypeZipFile(): string
 | |
| 	@/ = substitute(v:fname, '\.', '\\/', 'g') .. '.java'
 | |
| 	return get(zip_files, bufnr('%'), zip_files[0])
 | |
|     enddef
 | |
| 
 | |
|     setlocal includeexpr=s:JavaFileTypeZipFile()
 | |
|     setlocal suffixesadd<
 | |
| endif
 | |
| 
 | |
| if exists("*s:DispatchAction")
 | |
|     def! s:DispatchAction(paths_action_pairs: list<list<any>>)
 | |
| 	const name: string = expand('%:p')
 | |
| 
 | |
| 	for [paths: list<string>, Action: func: any] in paths_action_pairs
 | |
| 	    for path in paths
 | |
| 		if name =~# (path .. '.\{-}\.java\=$')
 | |
| 		    Action()
 | |
| 		    return
 | |
| 		endif
 | |
| 	    endfor
 | |
| 	endfor
 | |
|     enddef
 | |
| endif
 | |
| 
 | |
| " Restore the saved compatibility options.
 | |
| let &cpo = s:save_cpo
 | |
| unlet s:save_cpo
 | |
| " vim: fdm=syntax sw=4 ts=8 noet sta
 |