--- /dev/null
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Support for the Eclipse language server https://github.com/eclipse/eclipse.jdt.ls
+
+let s:version_cache = {}
+
+call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls'))
+call ale#Set('java_eclipselsp_config_path', '')
+call ale#Set('java_eclipselsp_workspace_path', '')
+call ale#Set('java_eclipselsp_executable', 'java')
+call ale#Set('java_eclipselsp_javaagent', '')
+
+function! ale_linters#java#eclipselsp#Executable(buffer) abort
+ return ale#Var(a:buffer, 'java_eclipselsp_executable')
+endfunction
+
+function! ale_linters#java#eclipselsp#TargetPath(buffer) abort
+ return ale#Var(a:buffer, 'java_eclipselsp_path')
+endfunction
+
+function! ale_linters#java#eclipselsp#JarPath(buffer) abort
+ let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer)
+
+ if has('win32')
+ let l:platform = 'win32'
+ elseif has('macunix')
+ let l:platform = 'macosx'
+ else
+ let l:platform = 'linux'
+ endif
+
+ " Search jar file within repository path when manually built using mvn
+ let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1)
+
+ if len(l:files) >= 1
+ return l:files[0]
+ endif
+
+ " Search jar file within VSCode extensions folder.
+ let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1)
+
+ if len(l:files) >= 1
+ return l:files[0]
+ endif
+
+ " Search jar file within unzipped tar.gz file
+ let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1)
+
+ if len(l:files) >= 1
+ return l:files[0]
+ endif
+
+ " Search jar file within system package path
+ let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_*\.jar', 1, 1)
+
+ if len(l:files) >= 1
+ return l:files[0]
+ endif
+
+ return ''
+endfunction
+
+function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort
+ let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h')
+ let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path')
+
+ if !empty(l:config_path)
+ return ale#path#Simplify(l:config_path)
+ endif
+
+ if has('win32')
+ let l:path = l:path . '/config_win'
+ elseif has('macunix')
+ let l:path = l:path . '/config_mac'
+ else
+ let l:path = l:path . '/config_linux'
+ endif
+
+ return ale#path#Simplify(l:path)
+endfunction
+
+function! ale_linters#java#eclipselsp#VersionCheck(version_lines) abort
+ return s:GetVersion('', a:version_lines)
+endfunction
+
+function! s:GetVersion(executable, version_lines) abort
+ let l:version = []
+
+ for l:line in a:version_lines
+ let l:match = matchlist(l:line, '\(\d\+\)\.\(\d\+\)\.\(\d\+\)')
+
+ if !empty(l:match)
+ let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
+ let s:version_cache[a:executable] = l:version
+ break
+ endif
+ endfor
+
+ return l:version
+endfunction
+
+function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines, meta) abort
+ let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
+ let l:version = s:GetVersion(l:executable, a:version_lines)
+
+ return ale_linters#java#eclipselsp#Command(a:buffer, l:version)
+endfunction
+
+function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
+ let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path')
+
+ if !empty(l:wspath)
+ return l:wspath
+ endif
+
+ return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
+endfunction
+
+function! ale_linters#java#eclipselsp#Javaagent(buffer) abort
+ let l:rets = []
+ let l:raw = ale#Var(a:buffer, 'java_eclipselsp_javaagent')
+
+ if empty(l:raw)
+ return ''
+ endif
+
+ let l:jars = split(l:raw)
+
+ for l:jar in l:jars
+ call add(l:rets, ale#Escape('-javaagent:' . l:jar))
+ endfor
+
+ return join(l:rets, ' ')
+endfunction
+
+function! ale_linters#java#eclipselsp#Command(buffer, version) abort
+ let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
+
+ let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
+
+ let l:cmd = [ ale#Escape(l:executable),
+ \ ale_linters#java#eclipselsp#Javaagent(a:buffer),
+ \ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
+ \ '-Dosgi.bundles.defaultStartLevel=4',
+ \ '-Declipse.product=org.eclipse.jdt.ls.core.product',
+ \ '-Dlog.level=ALL',
+ \ '-noverify',
+ \ '-Xmx1G',
+ \ '-jar',
+ \ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)),
+ \ '-configuration',
+ \ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)),
+ \ '-data',
+ \ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer))
+ \ ]
+
+ if ale#semver#GTE(a:version, [1, 9])
+ call add(l:cmd, '--add-modules=ALL-SYSTEM')
+ call add(l:cmd, '--add-opens java.base/java.util=ALL-UNNAMED')
+ call add(l:cmd, '--add-opens java.base/java.lang=ALL-UNNAMED')
+ endif
+
+ return join(l:cmd, ' ')
+endfunction
+
+function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
+ let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
+
+ if empty(l:executable)
+ return ''
+ endif
+
+ let l:cache = s:version_cache
+
+ if has_key(s:version_cache, l:executable)
+ return ale_linters#java#eclipselsp#Command(a:buffer, s:version_cache[l:executable])
+ endif
+
+ let l:command = ale#Escape(l:executable) . ' -version'
+
+ return ale#command#Run(
+ \ a:buffer,
+ \ l:command,
+ \ function('ale_linters#java#eclipselsp#CommandWithVersion'),
+ \ { 'output_stream': 'both' }
+ \)
+endfunction
+
+call ale#linter#Define('java', {
+\ 'name': 'eclipselsp',
+\ 'lsp': 'stdio',
+\ 'executable': function('ale_linters#java#eclipselsp#Executable'),
+\ 'command': function('ale_linters#java#eclipselsp#RunWithVersionCheck'),
+\ 'language': 'java',
+\ 'project_root': function('ale#java#FindProjectRoot'),
+\ 'initialization_options': {
+\ 'extendedClientCapabilities': {
+\ 'classFileContentsSupport': v:true
+\ }
+\ }
+\})