1
0
Fork 0
mirror of synced 2024-12-26 00:33:20 -05:00

Merge branch 'Windows'

This commit is contained in:
Geezus 2019-05-31 13:39:54 -05:00
commit fa9998a288
71 changed files with 1121 additions and 487 deletions

View file

@ -5,7 +5,10 @@ call ale#Set('asm_gcc_executable', 'gcc')
call ale#Set('asm_gcc_options', '-Wall') call ale#Set('asm_gcc_options', '-Wall')
function! ale_linters#asm#gcc#GetCommand(buffer) abort function! ale_linters#asm#gcc#GetCommand(buffer) abort
return '%e -x assembler -fsyntax-only ' " `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction endfunction

View file

@ -4,12 +4,6 @@
call ale#Set('c_clangd_executable', 'clangd') call ale#Set('c_clangd_executable', 'clangd')
call ale#Set('c_clangd_options', '') call ale#Set('c_clangd_options', '')
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#clangd#GetCommand(buffer) abort function! ale_linters#c#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('c', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'c_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'c_clangd_executable')},
\ 'command': function('ale_linters#c#clangd#GetCommand'), \ 'command': function('ale_linters#c#clangd#GetCommand'),
\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View file

@ -9,19 +9,16 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
" "
" If we find it, we'll `cd` to where the compile_commands.json file is, " If we find it, we'll `cd` to where the compile_commands.json file is,
" then use the file to set up import paths, etc. " then use the file to set up import paths, etc.
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : ''
let l:cd_command = !empty(l:compile_commmands_path) let l:compile_commands_option = !empty(l:json_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h')) \ ? '--project=' . ale#Escape(l:json_path[len(l:dir) + 1: ])
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . '%e -q --language=c ' \ . '%e -q --language=c'
\ . l:compile_commands_option \ . ale#Pad(l:compile_commands_option)
\ . ale#Var(a:buffer, 'c_cppcheck_options') \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . ' %t' \ . ' %t'
endfunction endfunction

View file

@ -5,13 +5,15 @@ call ale#Set('c_cquery_executable', 'cquery')
call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery')) call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#c#cquery#GetProjectRoot(buffer) abort function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') " Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction
function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort

View file

@ -9,7 +9,11 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return '%e -S -x c -fsyntax-only' "
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -' \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'

View file

@ -12,7 +12,8 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir') let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir) if empty(l:build_dir)
let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
let l:build_dir = ale#path#Dirname(l:json_file)
endif endif
" The extra arguments in the command are used to prevent .plist files from " The extra arguments in the command are used to prevent .plist files from

View file

@ -4,12 +4,6 @@
call ale#Set('cpp_clangd_executable', 'clangd') call ale#Set('cpp_clangd_executable', 'clangd')
call ale#Set('cpp_clangd_options', '') call ale#Set('cpp_clangd_options', '')
function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#clangd#GetCommand(buffer) abort function! ale_linters#cpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('cpp', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')},
\ 'command': function('ale_linters#cpp#clangd#GetCommand'), \ 'command': function('ale_linters#cpp#clangd#GetCommand'),
\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View file

@ -9,19 +9,16 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
" "
" If we find it, we'll `cd` to where the compile_commands.json file is, " If we find it, we'll `cd` to where the compile_commands.json file is,
" then use the file to set up import paths, etc. " then use the file to set up import paths, etc.
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : ''
let l:cd_command = !empty(l:compile_commmands_path) let l:compile_commands_option = !empty(l:json_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h')) \ ? '--project=' . ale#Escape(l:json_path[len(l:dir) + 1: ])
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . '%e -q --language=c++ ' \ . '%e -q --language=c++'
\ . l:compile_commands_option \ . ale#Pad(l:compile_commands_option)
\ . ale#Var(a:buffer, 'cpp_cppcheck_options') \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . ' %t' \ . ' %t'
endfunction endfunction

View file

@ -5,13 +5,15 @@ call ale#Set('cpp_cquery_executable', 'cquery')
call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery')) call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') " Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort

View file

@ -9,7 +9,11 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return '%e -S -x c++ -fsyntax-only' "
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -' \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'

View file

@ -0,0 +1,93 @@
" Author: Autoine Gagne - https://github.com/AntoineGagne
" Description: Define a checker that runs dialyzer on Erlang files.
let g:ale_erlang_dialyzer_executable =
\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer')
let g:ale_erlang_dialyzer_plt_file =
\ get(g:, 'ale_erlang_dialyzer_plt_file', '')
let g:ale_erlang_dialyzer_rebar3_profile =
\ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default')
function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile')
endfunction
function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort
let l:plt_file = ''
let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer)
let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build' . l:rebar3_profile)
if !empty(l:plt_file_directory)
let l:plt_file = split(globpath(l:plt_file_directory, '/*_plt'), '\n')
endif
if !empty(l:plt_file)
return l:plt_file[0]
endif
if !empty($REBAR_PLT_DIR)
return expand('$REBAR_PLT_DIR/dialyzer/plt')
endif
return expand('$HOME/.dialyzer_plt')
endfunction
function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort
let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file')
if !empty(l:plt_file)
return l:plt_file
endif
return ale_linters#erlang#dialyzer#FindPlt(a:buffer)
endfunction
function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_executable')
endfunction
function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort
let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer))
\ . ' -n'
\ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer))
\ . ' -Wunmatched_returns'
\ . ' -Werror_handling'
\ . ' -Wrace_conditions'
\ . ' -Wunderspecs'
\ . ' %s'
return l:command
endfunction
function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort
" Match patterns like the following:
"
" erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available
let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) != 0
let l:code = l:match[2]
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'lcol': 0,
\ 'text': l:code,
\ 'type': 'W'
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'dialyzer',
\ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'),
\ 'command': function('ale_linters#erlang#dialyzer#GetCommand'),
\ 'callback': function('ale_linters#erlang#dialyzer#Handle'),
\ 'lint_file': 1
\})

View file

@ -17,6 +17,10 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
\}) \})
endfor endfor
if !empty(l:output)
return l:output
endif
" old checkstyle versions " old checkstyle versions
let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$' let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'

View file

@ -4,6 +4,8 @@
let s:version_cache = {} let s:version_cache = {}
call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls')) 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_executable', 'java')
function! ale_linters#java#eclipselsp#Executable(buffer) abort function! ale_linters#java#eclipselsp#Executable(buffer) abort
@ -32,11 +34,23 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
return l:files[0] return l:files[0]
endif endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) == 1
return l:files[0]
endif
return '' return ''
endfunction endfunction
function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort
let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h') 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') if has('win32')
let l:path = l:path . '/config_win' let l:path = l:path . '/config_win'
@ -76,6 +90,16 @@ function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines,
return ale_linters#java#eclipselsp#Command(a:buffer, l:version) return ale_linters#java#eclipselsp#Command(a:buffer, l:version)
endfunction 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#Command(buffer, version) abort function! ale_linters#java#eclipselsp#Command(buffer, version) abort
let l:path = ale#Var(a:buffer, 'java_eclipselsp_path') let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
@ -89,11 +113,11 @@ function! ale_linters#java#eclipselsp#Command(buffer, version) abort
\ '-noverify', \ '-noverify',
\ '-Xmx1G', \ '-Xmx1G',
\ '-jar', \ '-jar',
\ ale_linters#java#eclipselsp#JarPath(a:buffer), \ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)),
\ '-configuration', \ '-configuration',
\ ale_linters#java#eclipselsp#ConfigurationPath(a:buffer), \ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)),
\ '-data', \ '-data',
\ ale#java#FindProjectRoot(a:buffer) \ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer))
\ ] \ ]
if ale#semver#GTE(a:version, [1, 9]) if ale#semver#GTE(a:version, [1, 9])

View file

@ -4,12 +4,6 @@
call ale#Set('objc_clangd_executable', 'clangd') call ale#Set('objc_clangd_executable', 'clangd')
call ale#Set('objc_clangd_options', '') call ale#Set('objc_clangd_options', '')
function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objc#clangd#GetCommand(buffer) abort function! ale_linters#objc#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('objc', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')},
\ 'command': function('ale_linters#objc#clangd#GetCommand'), \ 'command': function('ale_linters#objc#clangd#GetCommand'),
\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View file

@ -4,12 +4,6 @@
call ale#Set('objcpp_clangd_executable', 'clangd') call ale#Set('objcpp_clangd_executable', 'clangd')
call ale#Set('objcpp_clangd_options', '') call ale#Set('objcpp_clangd_options', '')
function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objcpp#clangd#GetCommand(buffer) abort function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('objcpp', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')},
\ 'command': function('ale_linters#objcpp#clangd#GetCommand'), \ 'command': function('ale_linters#objcpp#clangd#GetCommand'),
\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View file

@ -10,13 +10,13 @@ call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#phpcs#GetCommand(buffer) abort function! ale_linters#php#phpcs#GetCommand(buffer) abort
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard') let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard) let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard \ ? '--standard=' . ale#Escape(l:standard)
\ : '' \ : ''
let l:options = ale#Var(a:buffer, 'php_phpcs_options')
return '%e -s --report=emacs --stdin-path=%s' return ale#path#BufferCdString(a:buffer)
\ . '%e -s --report=emacs --stdin-path=%s'
\ . ale#Pad(l:standard_option) \ . ale#Pad(l:standard_option)
\ . ale#Pad(l:options) \ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options'))
endfunction endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines) abort function! ale_linters#php#phpcs#Handle(buffer, lines) abort

View file

@ -0,0 +1,49 @@
" Author: Keith Maxwell <keith.maxwell@gmail.com>
" Description: terraform fmt to check for errors
call ale#Set('terraform_terraform_executable', 'terraform')
function! ale_linters#terraform#terraform#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'terraform_terraform_executable')
endfunction
function! ale_linters#terraform#terraform#GetCommand(buffer) abort
return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer))
\ . ' fmt -no-color --check=true -'
endfunction
function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
let l:head = '^Error running fmt: In <standard input>: '
let l:output = []
let l:patterns = [
\ l:head.'At \(\d\+\):\(\d\+\): \(.*\)$',
\ l:head.'\(.*\)$'
\]
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match[2]) > 0
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'text': l:match[3],
\ 'type': 'E',
\})
else
call add(l:output, {
\ 'lnum': line('$'),
\ 'text': l:match[1],
\ 'type': 'E',
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('terraform', {
\ 'name': 'terraform',
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'),
\ 'command': function('ale_linters#terraform#terraform#GetCommand'),
\ 'callback': 'ale_linters#terraform#terraform#Handle',
\})

View file

@ -96,6 +96,13 @@ function! ale#assert#Fixer(expected_result) abort
AssertEqual a:expected_result, l:result AssertEqual a:expected_result, l:result
endfunction endfunction
function! ale#assert#FixerNotExecuted() abort
let l:buffer = bufnr('')
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1]
Assert empty(l:result), "The fixer will be executed when it shouldn't be"
endfunction
function! ale#assert#LinterNotExecuted() abort function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:linter = s:GetLinter() let l:linter = s:GetLinter()
@ -158,6 +165,7 @@ endfunction
function! ale#assert#SetUpFixerTestCommands() abort function! ale#assert#SetUpFixerTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>) command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>) command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
endfunction endfunction
" A dummy function for making sure this module is loaded. " A dummy function for making sure this module is loaded.
@ -316,4 +324,8 @@ function! ale#assert#TearDownFixerTest() abort
if exists(':AssertFixer') if exists(':AssertFixer')
delcommand AssertFixer delcommand AssertFixer
endif endif
if exists(':AssertFixerNotExecuted')
delcommand AssertFixerNotExecuted
endif
endfunction endfunction

View file

@ -23,27 +23,9 @@ function! ale#c#GetBuildDirectory(buffer) abort
return l:build_dir return l:build_dir
endif endif
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
endfunction
return ale#path#Dirname(l:json_file)
function! ale#c#FindProjectRoot(buffer) abort
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
return l:path
endif
endfor
return ''
endfunction endfunction
function! ale#c#AreSpecialCharsBalanced(option) abort function! ale#c#AreSpecialCharsBalanced(option) abort
@ -120,7 +102,7 @@ endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile if !g:ale_c_parse_makefile
return '' return v:null
endif endif
let l:buffer_filename = expand('#' . a:buffer . ':t') let l:buffer_filename = expand('#' . a:buffer . ':t')
@ -140,14 +122,17 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line) return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
endfunction endfunction
" Given a buffer number, find the build subdirectory with compile commands " Given a buffer number, find the project directory containing
" The subdirectory is returned without the trailing / " compile_commands.json, and the path to the compile_commands.json file.
"
" If compile_commands.json cannot be found, two empty strings will be
" returned.
function! ale#c#FindCompileCommands(buffer) abort function! ale#c#FindCompileCommands(buffer) abort
" Look above the current source file to find compile_commands.json " Look above the current source file to find compile_commands.json
let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:json_file) if !empty(l:json_file)
return l:json_file return [fnamemodify(l:json_file, ':h'), l:json_file]
endif endif
" Search in build directories if we can't find it in the project. " Search in build directories if we can't find it in the project.
@ -157,12 +142,42 @@ function! ale#c#FindCompileCommands(buffer) abort
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json' let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
if filereadable(l:json_file) if filereadable(l:json_file)
return l:json_file return [l:path, l:json_file]
endif endif
endfor endfor
endfor endfor
return '' return ['', '']
endfunction
" Find the project root for C/C++ projects.
"
" The location of compile_commands.json will be used to find project roots.
"
" If compile_commands.json cannot be found, other common configuration files
" will be used to detect the project root.
function! ale#c#FindProjectRoot(buffer) abort
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
" Fall back on detecting the project root based on other filenames.
if empty(l:root)
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
return l:path
endif
endfor
endif
return l:root
endfunction endfunction
" Cache compile_commands.json data in a Dictionary, so we don't need to read " Cache compile_commands.json data in a Dictionary, so we don't need to read
@ -194,10 +209,14 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:raw_data = [] let l:raw_data = []
silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), '')) silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), ''))
if type(l:raw_data) isnot v:t_list
let l:raw_data = []
endif
let l:file_lookup = {} let l:file_lookup = {}
let l:dir_lookup = {} let l:dir_lookup = {}
for l:entry in l:raw_data for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
let l:basename = tolower(fnamemodify(l:entry.file, ':t')) let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
@ -274,25 +293,25 @@ function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
endfunction endfunction
function! ale#c#GetCFlags(buffer, output) abort function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = ' ' let l:cflags = v:null
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output) if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output) let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif endif
if ale#Var(a:buffer, 'c_parse_compile_commands') if ale#Var(a:buffer, 'c_parse_compile_commands')
let l:json_file = ale#c#FindCompileCommands(a:buffer) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
if !empty(l:json_file) if !empty(l:json_file)
let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file) let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
endif endif
endif endif
if l:cflags is# ' ' if l:cflags is v:null
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif endif
return l:cflags return l:cflags isnot v:null ? l:cflags : ''
endfunction endfunction
function! ale#c#GetMakeCommand(buffer) abort function! ale#c#GetMakeCommand(buffer) abort

View file

@ -169,7 +169,7 @@ function! s:ReplaceCompletionOptions() abort
let b:ale_old_omnifunc = &l:omnifunc let b:ale_old_omnifunc = &l:omnifunc
endif endif
let &l:omnifunc = 'ale#completion#OmniFunc' let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
endif endif
if l:source is# 'ale-automatic' if l:source is# 'ale-automatic'
@ -216,18 +216,6 @@ function! ale#completion#GetCompletionPosition() abort
endfunction endfunction
function! ale#completion#GetCompletionResult() abort function! ale#completion#GetCompletionResult() abort
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
if exists('b:ale_completion_result') if exists('b:ale_completion_result')
return b:ale_completion_result return b:ale_completion_result
endif endif
@ -235,7 +223,7 @@ function! ale#completion#GetCompletionResult() abort
return v:null return v:null
endfunction endfunction
function! ale#completion#OmniFunc(findstart, base) abort function! ale#completion#AutomaticOmniFunc(findstart, base) abort
if a:findstart if a:findstart
return ale#completion#GetCompletionPosition() return ale#completion#GetCompletionPosition()
else else
@ -247,15 +235,20 @@ function! ale#completion#OmniFunc(findstart, base) abort
endif endif
endfunction endfunction
function! ale#completion#Show(response, completion_parser) abort function! ale#completion#Show(result) abort
if ale#util#Mode() isnot# 'i' if ale#util#Mode() isnot# 'i'
return return
endif endif
" Set the list in the buffer, temporarily replace omnifunc with our " Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion. " function, and then start omni-completion.
let b:ale_completion_response = a:response let b:ale_completion_result = a:result
let b:ale_completion_parser = a:completion_parser
" Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result)
return
endif
" Replace completion options shortly before opening the menu. " Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions() call s:ReplaceCompletionOptions()
@ -279,6 +272,7 @@ function! s:CompletionStillValid(request_id) abort
\&& ( \&& (
\ b:ale_completion_info.column == l:column \ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'deoplete' \ || b:ale_completion_info.source is# 'deoplete'
\ || b:ale_completion_info.source is# 'ale-omnifunc'
\) \)
endfunction endfunction
@ -474,8 +468,7 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
endif endif
elseif l:command is# 'completionEntryDetails' elseif l:command is# 'completionEntryDetails'
call ale#completion#Show( call ale#completion#Show(
\ a:response, \ ale#completion#ParseTSServerCompletionEntryDetails(a:response),
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
\) \)
endif endif
endfunction endfunction
@ -487,8 +480,7 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
endif endif
call ale#completion#Show( call ale#completion#Show(
\ a:response, \ ale#completion#ParseLSPCompletions(a:response),
\ 'ale#completion#ParseLSPCompletions',
\) \)
endfunction endfunction
@ -529,10 +521,7 @@ function! s:OnReady(linter, lsp_details) abort
let l:message = ale#lsp#message#Completion( let l:message = ale#lsp#message#Completion(
\ l:buffer, \ l:buffer,
\ b:ale_completion_info.line, \ b:ale_completion_info.line,
\ min([
\ b:ale_completion_info.line_length,
\ b:ale_completion_info.column, \ b:ale_completion_info.column,
\ ]) + 1,
\ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix), \ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
\) \)
endif endif
@ -570,7 +559,7 @@ function! ale#completion#GetCompletions(source) abort
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if a:source is# 'ale-automatic' && empty(l:prefix) if a:source is# 'ale-automatic' && empty(l:prefix)
return return 0
endif endif
let l:line_length = len(getline('.')) let l:line_length = len(getline('.'))
@ -589,11 +578,40 @@ function! ale#completion#GetCompletions(source) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:Callback = function('s:OnReady') let l:Callback = function('s:OnReady')
let l:started = 0
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
let l:started = 1
endif
endif endif
endfor endfor
return l:started
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc')
if !l:started
" This is the special value for cancelling completions silently.
" See :help complete-functions
return -3
endif
return ale#completion#GetCompletionPosition()
else
let l:result = ale#completion#GetCompletionResult()
while l:result is v:null && !complete_check()
sleep 2ms
let l:result = ale#completion#GetCompletionResult()
endwhile
return l:result isnot v:null ? l:result : []
endif
endfunction endfunction
function! s:TimerHandler(...) abort function! s:TimerHandler(...) abort

View file

@ -238,6 +238,12 @@ function! ale#debugging#Info() abort
endfunction endfunction
function! ale#debugging#InfoToClipboard() abort function! ale#debugging#InfoToClipboard() abort
if !has('clipboard')
call s:Echo('clipboard not available. Try :ALEInfoToFile instead.')
return
endif
redir => l:output redir => l:output
silent call ale#debugging#Info() silent call ale#debugging#Info()
redir END redir END

View file

@ -2,47 +2,60 @@ call ale#Set('fix_on_save_ignore', {})
" Apply fixes queued up for buffers which may be hidden. " Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers. " Vim doesn't let you modify hidden buffers.
function! ale#fix#ApplyQueuedFixes() abort function! ale#fix#ApplyQueuedFixes(buffer) abort
let l:buffer = bufnr('') let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0})
let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0}) let l:has_bufline_api = exists('*deletebufline') && exists('*setbufline')
if !l:data.done if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr(''))
return return
endif endif
call remove(g:ale_fix_buffer_data, l:buffer) call remove(g:ale_fix_buffer_data, a:buffer)
if l:data.changes_made if l:data.changes_made
let l:start_line = len(l:data.output) + 1
let l:end_line = len(l:data.lines_before)
if l:end_line >= l:start_line
let l:save = winsaveview()
silent execute l:start_line . ',' . l:end_line . 'd_'
call winrestview(l:save)
endif
" If the file is in DOS mode, we have to remove carriage returns from " If the file is in DOS mode, we have to remove carriage returns from
" the ends of lines before calling setline(), or we will see them " the ends of lines before calling setline(), or we will see them
" twice. " twice.
let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos' let l:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
\ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')') \ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
\ : l:data.output \ : l:data.output
let l:first_line_to_remove = len(l:new_lines) + 1
call setline(1, l:lines_to_set) " Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines)
call deletebufline(a:buffer, l:first_line_to_remove, '$')
" Fall back on setting lines the old way, for the current buffer.
else
let l:old_line_length = len(l:data.lines_before)
if l:old_line_length >= l:first_line_to_remove
let l:save = winsaveview()
silent execute
\ l:first_line_to_remove . ',' . l:old_line_length . 'd_'
call winrestview(l:save)
endif
call setline(1, l:new_lines)
endif
if l:data.should_save if l:data.should_save
if a:buffer is bufnr('')
if empty(&buftype) if empty(&buftype)
noautocmd :w! noautocmd :w!
else else
set nomodified set nomodified
endif endif
else
call writefile(l:new_lines, expand(a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif
endif endif
endif endif
if l:data.should_save if l:data.should_save
let l:should_lint = g:ale_fix_on_save let l:should_lint = g:ale_fix_on_save
\ && ale#Var(l:buffer, 'lint_on_save') \ && ale#Var(a:buffer, 'lint_on_save')
else else
let l:should_lint = l:data.changes_made let l:should_lint = l:data.changes_made
endif endif
@ -53,7 +66,7 @@ function! ale#fix#ApplyQueuedFixes() abort
" fixing problems. " fixing problems.
if g:ale_enabled if g:ale_enabled
\&& l:should_lint \&& l:should_lint
\&& !ale#events#QuitRecently(l:buffer) \&& !ale#events#QuitRecently(a:buffer)
call ale#Queue(0, l:data.should_save ? 'lint_file' : '') call ale#Queue(0, l:data.should_save ? 'lint_file' : '')
endif endif
endfunction endfunction
@ -84,7 +97,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
" We can only change the lines of a buffer which is currently open, " We can only change the lines of a buffer which is currently open,
" so try and apply the fixes to the current buffer. " so try and apply the fixes to the current buffer.
call ale#fix#ApplyQueuedFixes() call ale#fix#ApplyQueuedFixes(a:buffer)
endfunction endfunction
function! s:HandleExit(job_info, buffer, job_output, data) abort function! s:HandleExit(job_info, buffer, job_output, data) abort
@ -400,5 +413,4 @@ endfunction
" Set up an autocmd command to try and apply buffer fixes when available. " Set up an autocmd command to try and apply buffer fixes when available.
augroup ALEBufferFixGroup augroup ALEBufferFixGroup
autocmd! autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes() autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END

View file

@ -305,6 +305,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['tex'], \ 'suggested_filetypes': ['tex'],
\ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.', \ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.',
\ }, \ },
\ 'pgformatter': {
\ 'function': 'ale#fixers#pgformatter#Fix',
\ 'suggested_filetypes': ['sql'],
\ 'description': 'A PostgreSQL SQL syntax beautifier',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.

View file

@ -35,9 +35,18 @@ endfunction
function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) let l:executable = ale#handlers#eslint#GetExecutable(a:buffer)
let l:config = ale#handlers#eslint#FindConfig(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_eslint_options')
if empty(l:config) " Use the configuration file from the options, if configured.
if l:options =~# '\v(^| )-c|(^| )--config'
let l:config = ''
let l:has_config = 1
else
let l:config = ale#handlers#eslint#FindConfig(a:buffer)
let l:has_config = !empty(l:config)
endif
if !l:has_config
return 0 return 0
endif endif
@ -45,6 +54,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-to-stdout', \ . ' --stdin-filename %s --stdin --fix-to-stdout',
\ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput',
\} \}
@ -54,6 +64,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
if ale#semver#GTE(a:version, [4, 9, 0]) if ale#semver#GTE(a:version, [4, 9, 0])
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',
\ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput',
\} \}
@ -61,7 +72,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ' -c ' . ale#Escape(l:config) \ . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' --fix %t', \ . ' --fix %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}

View file

@ -0,0 +1,12 @@
call ale#Set('sql_pgformatter_executable', 'pg_format')
call ale#Set('sql_pgformatter_options', '')
function! ale#fixers#pgformatter#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'sql_pgformatter_executable')
let l:options = ale#Var(a:buffer, 'sql_pgformatter_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options),
\}
endfunction

View file

@ -3,15 +3,17 @@ scriptencoding utf-8
" Description: Utilities for ccls " Description: Utilities for ccls
function! ale#handlers#ccls#GetProjectRoot(buffer) abort function! ale#handlers#ccls#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls-root') " Try to find ccls configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.ccls-root')
if empty(l:project_root) if empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let l:config = ale#path#FindNearestFile(a:buffer, '.ccls')
endif endif
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction

View file

@ -11,6 +11,7 @@ let s:pragma_error = '#pragma once in main file'
" <stdin>:10:27: error: invalid operands to binary - (have int and char *) " <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort function! s:IsHeaderFile(filename) abort
return a:filename =~? '\v\.(h|hpp)$' return a:filename =~? '\v\.(h|hpp)$'
@ -25,6 +26,28 @@ function! s:RemoveUnicodeQuotes(text) abort
return l:text return l:text
endfunction endfunction
function! s:ParseInlinedFunctionProblems(buffer, lines) abort
let l:output = []
let l:pos_match = []
for l:line in a:lines
let l:match = matchlist(l:line, s:pattern)
if !empty(l:match) && !empty(l:pos_match)
call add(l:output, {
\ 'lnum': str2nr(l:pos_match[1]),
\ 'col': str2nr(l:pos_match[2]),
\ 'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W',
\ 'text': s:RemoveUnicodeQuotes(l:match[5]),
\})
endif
let l:pos_match = matchlist(l:line, s:inline_pattern)
endfor
return l:output
endfunction
" Report problems inside of header files just for gcc and clang " Report problems inside of header files just for gcc and clang
function! s:ParseProblemsInHeaders(buffer, lines) abort function! s:ParseProblemsInHeaders(buffer, lines) abort
let l:output = [] let l:output = []
@ -129,6 +152,7 @@ endfunction
function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort
let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines) let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
call extend(l:output, s:ParseInlinedFunctionProblems(a:buffer, a:lines))
call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines)) call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines))
return l:output return l:output

View file

@ -26,41 +26,6 @@ endif
let s:MAX_POS_VALUES = 8 let s:MAX_POS_VALUES = 8
let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) let s:MAX_COL_SIZE = 1073741824 " pow(2, 30)
" Check if we have neovim's buffer highlight API
"
" Below we define some functions' implementation conditionally if this API
" exists or not.
"
" The API itself is more ergonomic and neovim performs highlights positions
" rebases during edits so we see less stalled highlights.
let s:nvim_api = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace')
function! ale#highlight#HasNeovimApi() abort
return s:nvim_api
endfunction
function! ale#highlight#nvim_buf_clear_namespace(...) abort
return call('nvim_buf_clear_namespace', a:000)
endfunction
function! ale#highlight#nvim_buf_add_highlight(...) abort
return call('nvim_buf_add_highlight', a:000)
endfunction
function! s:ale_nvim_highlight_id(bufnr) abort
let l:id = getbufvar(a:bufnr, 'ale_nvim_highlight_id', -1)
if l:id is -1
" NOTE: This will highlight nothing but will allocate new id
let l:id = ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, 0, '', 0, 0, -1
\)
call setbufvar(a:bufnr, 'ale_nvim_highlight_id', l:id)
endif
return l:id
endfunction
function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort
if a:line >= a:end_line if a:line >= a:end_line
" For single lines, just return the one position. " For single lines, just return the one position.
@ -86,88 +51,11 @@ endfunction
" except these which have matching loclist item entries. " except these which have matching loclist item entries.
function! ale#highlight#RemoveHighlights() abort function! ale#highlight#RemoveHighlights() abort
if ale#highlight#HasNeovimApi()
if get(b:, 'ale_nvim_highlight_id', 0)
let l:bufnr = bufnr('%')
" NOTE: 0, -1 means from 0 line till the end of buffer
call ale#highlight#nvim_buf_clear_namespace(
\ l:bufnr,
\ b:ale_nvim_highlight_id,
\ 0, -1
\)
endif
else
for l:match in getmatches() for l:match in getmatches()
if l:match.group =~# '^ALE' if l:match.group =~# '^ALE'
call matchdelete(l:match.id) call matchdelete(l:match.id)
endif endif
endfor endfor
endif
endfunction
function! s:highlight_line(bufnr, lnum, group) abort
if ale#highlight#HasNeovimApi()
let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr)
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ a:lnum - 1, 0, -1
\)
else
call matchaddpos(a:group, [a:lnum])
endif
endfunction
function! s:highlight_range(bufnr, range, group) abort
if ale#highlight#HasNeovimApi()
let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr)
" NOTE: lines and columns indicies are 0-based in nvim_buf_* API.
let l:lnum = a:range.lnum - 1
let l:end_lnum = a:range.end_lnum - 1
let l:col = a:range.col - 1
let l:end_col = a:range.end_col
if l:lnum >= l:end_lnum
" For single lines, just return the one position.
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:lnum, l:col, l:end_col
\)
else
" highlight first line from start till the line end
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:lnum, l:col, -1
\)
" highlight all lines between the first and last entirely
let l:cur = l:lnum + 1
while l:cur < l:end_lnum
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:cur, 0, -1
\ )
let l:cur += 1
endwhile
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:end_lnum, 0, l:end_col
\)
endif
else
" Set all of the positions, which are chunked into Lists which
" are as large as will be accepted by matchaddpos.
call map(
\ ale#highlight#CreatePositions(
\ a:range.lnum,
\ a:range.col,
\ a:range.end_lnum,
\ a:range.end_col
\ ),
\ 'matchaddpos(a:group, v:val)'
\)
endif
endfunction endfunction
function! s:highlight_line(bufnr, lnum, group) abort function! s:highlight_line(bufnr, lnum, group) abort

View file

@ -111,7 +111,7 @@ function! ale#loclist_jumping#Jump(direction, ...) abort
if !empty(l:nearest) if !empty(l:nearest)
normal! m` normal! m`
call cursor(l:nearest) call cursor([l:nearest[0], max([l:nearest[1], 1])])
endif endif
endfunction endfunction

View file

@ -321,7 +321,69 @@ endfunction
function! s:SendInitMessage(conn) abort function! s:SendInitMessage(conn) abort
let [l:init_id, l:init_data] = ale#lsp#CreateMessageData( let [l:init_id, l:init_data] = ale#lsp#CreateMessageData(
\ ale#lsp#message#Initialize(a:conn.root, a:conn.init_options), \ ale#lsp#message#Initialize(
\ a:conn.root,
\ a:conn.init_options,
\ {
\ 'workspace': {
\ 'applyEdit': v:false,
\ 'didChangeConfiguration': {
\ 'dynamicRegistration': v:false,
\ },
\ 'symbol': {
\ 'dynamicRegistration': v:false,
\ },
\ 'workspaceFolders': v:false,
\ 'configuration': v:false,
\ },
\ 'textDocument': {
\ 'synchronization': {
\ 'dynamicRegistration': v:false,
\ 'willSave': v:false,
\ 'willSaveWaitUntil': v:false,
\ 'didSave': v:true,
\ },
\ 'completion': {
\ 'dynamicRegistration': v:false,
\ 'completionItem': {
\ 'snippetSupport': v:false,
\ 'commitCharactersSupport': v:false,
\ 'documentationFormat': ['plaintext'],
\ 'deprecatedSupport': v:false,
\ 'preselectSupport': v:false,
\ },
\ 'contextSupport': v:false,
\ },
\ 'hover': {
\ 'dynamicRegistration': v:false,
\ 'contentFormat': ['plaintext'],
\ },
\ 'references': {
\ 'dynamicRegistration': v:false,
\ },
\ 'documentSymbol': {
\ 'dynamicRegistration': v:false,
\ 'hierarchicalDocumentSymbolSupport': v:false,
\ },
\ 'definition': {
\ 'dynamicRegistration': v:false,
\ 'linkSupport': v:false,
\ },
\ 'typeDefinition': {
\ 'dynamicRegistration': v:false,
\ },
\ 'publishDiagnostics': {
\ 'relatedInformation': v:true,
\ },
\ 'codeAction': {
\ 'dynamicRegistration': v:false,
\ },
\ 'rename': {
\ 'dynamicRegistration': v:false,
\ },
\ },
\ },
\ ),
\) \)
let a:conn.init_request_id = l:init_id let a:conn.init_request_id = l:init_id
call s:SendMessageData(a:conn, l:init_data) call s:SendMessageData(a:conn, l:init_data)

View file

@ -28,14 +28,13 @@ function! ale#lsp#message#GetNextVersionID() abort
return l:id return l:id
endfunction endfunction
function! ale#lsp#message#Initialize(root_path, initialization_options) abort function! ale#lsp#message#Initialize(root_path, options, capabilities) abort
" TODO: Define needed capabilities.
" NOTE: rootPath is deprecated in favour of rootUri " NOTE: rootPath is deprecated in favour of rootUri
return [0, 'initialize', { return [0, 'initialize', {
\ 'processId': getpid(), \ 'processId': getpid(),
\ 'rootPath': a:root_path, \ 'rootPath': a:root_path,
\ 'capabilities': {}, \ 'capabilities': a:capabilities,
\ 'initializationOptions': a:initialization_options, \ 'initializationOptions': a:options,
\ 'rootUri': ale#path#ToURI(a:root_path), \ 'rootUri': ale#path#ToURI(a:root_path),
\}] \}]
endfunction endfunction

View file

@ -31,7 +31,7 @@ endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id] let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri) let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename) let l:buffer = bufnr('^' . l:filename . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
@ -49,7 +49,7 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver' let l:linter_name = 'tsserver'
let l:buffer = bufnr(a:response.body.file) let l:buffer = bufnr('^' . a:response.body.file . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)

View file

@ -25,7 +25,7 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/tox.ini') \|| filereadable(l:path . '/tox.ini')
\|| filereadable(l:path . '/mypy.ini') \|| filereadable(l:path . '/mypy.ini')
\|| filereadable(l:path . '/pycodestyle.cfg') \|| filereadable(l:path . '/pycodestyle.cfg')
\|| filereadable(l:path . '/flake8.cfg') \|| filereadable(l:path . '/.flake8')
\|| filereadable(l:path . '/.flake8rc') \|| filereadable(l:path . '/.flake8rc')
\|| filereadable(l:path . '/pylama.ini') \|| filereadable(l:path . '/pylama.ini')
\|| filereadable(l:path . '/pylintrc') \|| filereadable(l:path . '/pylintrc')

View file

@ -151,9 +151,9 @@ ALE is tested with a suite of tests executed in Travis CI and AppVeyor. ALE
runs tests with the following versions of Vim in the following environments. runs tests with the following versions of Vim in the following environments.
1. Vim 8.0.0027 on Linux via Travis CI. 1. Vim 8.0.0027 on Linux via Travis CI.
2. Vim 8.1.0204 on Linux via Travis CI. 2. Vim 8.1.0519 on Linux via Travis CI.
3. NeoVim 0.2.0 on Linux via Travis CI. 3. NeoVim 0.2.0 on Linux via Travis CI.
4. NeoVim 0.3.0 on Linux via Travis CI. 4. NeoVim 0.3.5 on Linux via Travis CI.
5. Vim 8 (stable builds) on Windows via AppVeyor. 5. Vim 8 (stable builds) on Windows via AppVeyor.
If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
@ -351,6 +351,7 @@ given the above setup are as follows.
`GivenCommandOutput [...]` - Define output for ale#command#Run. `GivenCommandOutput [...]` - Define output for ale#command#Run.
`AssertFixer results` - Check the fixer results `AssertFixer results` - Check the fixer results
`AssertFixerNotExecuted` - Check that fixers will not be executed.
=============================================================================== ===============================================================================

View file

@ -3,6 +3,35 @@ ALE Erlang Integration *ale-erlang-options*
=============================================================================== ===============================================================================
dialyzer *ale-erlang-dialyzer*
g:ale_erlang_dialyzer_executable *g:ale_erlang_dialyzer_executable*
*b:ale_erlang_dialyzer_executable*
Type: |String|
Default: `'dialyzer'`
This variable can be changed to specify the dialyzer executable.
g:ale_erlang_dialyzer_plt_file *g:ale_erlang_dialyzer_plt_file*
*b:ale_erlang_dialyzer_plt_file*
Type: |String|
This variable can be changed to specify the path to the PLT file. By
default, it will search for the PLT file inside the `_build` directory. If
there isn't one, it will fallback to the path `$REBAR_PLT_DIR/dialyzer/plt`.
Otherwise, it will default to `$HOME/.dialyzer_plt`.
g:ale_erlang_dialyzer_rebar3_profile *g:ale_erlang_dialyzer_rebar3_profile*
*b:ale_erlang_dialyzer_rebar3_profile*
Type: |String|
Default: `'default'`
This variable can be changed to specify the profile that is used to
run dialyzer with rebar3.
-------------------------------------------------------------------------------
erlc *ale-erlang-erlc* erlc *ale-erlang-erlc*
g:ale_erlang_erlc_options *g:ale_erlang_erlc_options* g:ale_erlang_erlc_options *g:ale_erlang_erlc_options*

View file

@ -5,7 +5,7 @@ ALE HCL Integration *ale-hcl-options*
=============================================================================== ===============================================================================
terraform-fmt *ale-hcl-terraform-fmt* terraform-fmt *ale-hcl-terraform-fmt*
See |ale-terraform-fmt| for information about the available options. See |ale-terraform-fmt-fixer| for information about the available options.
=============================================================================== ===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -130,7 +130,7 @@ g:ale_java_eclipselsp_path *g:ale_java_eclipselsp_path*
Absolute path to the location of the eclipse.jdt.ls repository folder. Or if Absolute path to the location of the eclipse.jdt.ls repository folder. Or if
you have VSCode extension installed the absolute path to the VSCode extensions you have VSCode extension installed the absolute path to the VSCode extensions
folder (e.g. $HOME/.vscode/extensions in Linux). folder (e.g. $HOME/.vscode/extensions/redhat.java-0.4x.0 in Linux).
g:ale_java_eclipselsp_executable *g:ale_java_eclipse_executable* g:ale_java_eclipselsp_executable *g:ale_java_eclipse_executable*
@ -141,6 +141,31 @@ g:ale_java_eclipselsp_executable *g:ale_java_eclipse_executable*
This variable can be set to change the executable path used for java. This variable can be set to change the executable path used for java.
g:ale_java_eclipselsp_config_path *g:ale_java_eclipse_config_path*
*b:ale_java_eclipse_config_path*
Type: |String|
Default: `''`
Set this variable to change the configuration directory path used by
eclipselsp (e.g. `$HOME/.jdtls` in Linux).
By default ALE will attempt to use the configuration within the installation
directory.
This setting is particularly useful when eclipselsp is installed in a
non-writable directory like `/usr/share/java/jdtls`, as is the case when
installed via system package.
g:ale_java_eclipselsp_workspace_path *g:ale_java_eclipselsp_workspace_path*
*b:ale_java_eclipselsp_workspace_path*
Type: |String|
Default: `''`
If you have Eclipse installed is good idea to set this variable to the
absolute path of the Eclipse workspace. If not set this value will be set to
the parent folder of the project root.
=============================================================================== ===============================================================================
uncrustify *ale-java-uncrustify* uncrustify *ale-java-uncrustify*

View file

@ -29,7 +29,7 @@ ALE will look for configuration files with the following filenames. >
tox.ini tox.ini
mypy.ini mypy.ini
pycodestyle.cfg pycodestyle.cfg
flake8.cfg .flake8
.flake8rc .flake8rc
pylama.ini pylama.ini
pylintrc pylintrc

View file

@ -2,6 +2,24 @@
ALE SQL Integration *ale-sql-options* ALE SQL Integration *ale-sql-options*
===============================================================================
pgformatter *ale-sql-pgformatter*
g:ale_sql_pgformatter_executable *g:ale_sql_pgformatter_executable*
*b:ale_sql_pgformatter_executable*
Type: |String|
Default: `'pg_format'`
This variable sets executable used for pgformatter.
g:ale_sql_pgformatter_options *g:ale_sql_pgformatter_options*
*b:ale_sql_pgformatter_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to the pgformatter fixer.
=============================================================================== ===============================================================================
sqlfmt *ale-sql-sqlfmt* sqlfmt *ale-sql-sqlfmt*

View file

@ -415,6 +415,7 @@ Notes:
* `solhint` * `solhint`
* `solium` * `solium`
* SQL * SQL
* `pgformatter`
* `sqlfmt` * `sqlfmt`
* `sqlint` * `sqlint`
* Stylus * Stylus

View file

@ -3,7 +3,7 @@ ALE Terraform Integration *ale-terraform-options*
=============================================================================== ===============================================================================
fmt *ale-terraform-fmt* terraform-fmt-fixer *ale-terraform-fmt-fixer*
g:ale_terraform_fmt_executable *g:ale_terraform_fmt_executable* g:ale_terraform_fmt_executable *g:ale_terraform_fmt_executable*
*b:ale_terraform_fmt_executable* *b:ale_terraform_fmt_executable*
@ -20,6 +20,18 @@ g:ale_terraform_fmt_options *g:ale_terraform_fmt_options*
Default: `''` Default: `''`
===============================================================================
terraform *ale-terraform-terraform*
g:ale_terraform_terraform_executable *g:ale_terraform_terraform_executable*
*b:ale_terraform_terraform_executable*
Type: |String|
Default: `'terraform'`
This variable can be changed to use a different executable for terraform.
=============================================================================== ===============================================================================
tflint *ale-terraform-tflint* tflint *ale-terraform-tflint*

View file

@ -53,5 +53,25 @@ g:ale_tex_latexindent_options *g:ale_tex_latexindent_options*
===============================================================================
texlab *ale-tex-texlab*
g:ale_tex_texlab_executable *g:ale_tex_texlab_executable*
*b:ale_tex_texlab_executable*
Type: |String|
Default: `'texlab'`
This variable can be changed to change the path to texlab.
g:ale_tex_texlab_options *g:ale_tex_texlab_options*
*b:ale_tex_texlab_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to texlab.
=============================================================================== ===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -349,6 +349,12 @@ is loaded. The delay for completion can be configured with
|g:ale_completion_delay|. This setting should not be enabled if you wish to |g:ale_completion_delay|. This setting should not be enabled if you wish to
use ALE as a completion source for other plugins. use ALE as a completion source for other plugins.
ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering
completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| >
" Use ALE's function for omnicompletion.
set omnifunc=ale#completion#OmniFunc
<
ALE will only suggest so many possible matches for completion. The maximum ALE will only suggest so many possible matches for completion. The maximum
number of items can be controlled with |g:ale_completion_max_suggestions|. number of items can be controlled with |g:ale_completion_max_suggestions|.
@ -1991,6 +1997,7 @@ documented in additional help files.
elm-lsp...............................|ale-elm-elm-lsp| elm-lsp...............................|ale-elm-elm-lsp|
elm-make..............................|ale-elm-elm-make| elm-make..............................|ale-elm-elm-make|
erlang..................................|ale-erlang-options| erlang..................................|ale-erlang-options|
dialyzer..............................|ale-erlang-dialyzer|
erlc..................................|ale-erlang-erlc| erlc..................................|ale-erlang-erlc|
syntaxerl.............................|ale-erlang-syntaxerl| syntaxerl.............................|ale-erlang-syntaxerl|
eruby...................................|ale-eruby-options| eruby...................................|ale-eruby-options|
@ -2229,6 +2236,7 @@ documented in additional help files.
spec....................................|ale-spec-options| spec....................................|ale-spec-options|
rpmlint...............................|ale-spec-rpmlint| rpmlint...............................|ale-spec-rpmlint|
sql.....................................|ale-sql-options| sql.....................................|ale-sql-options|
pgformatter...........................|ale-sql-pgformatter|
sqlfmt................................|ale-sql-sqlfmt| sqlfmt................................|ale-sql-sqlfmt|
stylus..................................|ale-stylus-options| stylus..................................|ale-stylus-options|
stylelint.............................|ale-stylus-stylelint| stylelint.............................|ale-stylus-stylelint|
@ -2239,12 +2247,14 @@ documented in additional help files.
tcl.....................................|ale-tcl-options| tcl.....................................|ale-tcl-options|
nagelfar..............................|ale-tcl-nagelfar| nagelfar..............................|ale-tcl-nagelfar|
terraform...............................|ale-terraform-options| terraform...............................|ale-terraform-options|
fmt...................................|ale-terraform-fmt| terraform-fmt-fixer...................|ale-terraform-fmt-fixer|
terraform.............................|ale-terraform-terraform|
tflint................................|ale-terraform-tflint| tflint................................|ale-terraform-tflint|
tex.....................................|ale-tex-options| tex.....................................|ale-tex-options|
chktex................................|ale-tex-chktex| chktex................................|ale-tex-chktex|
lacheck...............................|ale-tex-lacheck| lacheck...............................|ale-tex-lacheck|
latexindent...........................|ale-tex-latexindent| latexindent...........................|ale-tex-latexindent|
texlab................................|ale-tex-texlab|
texinfo.................................|ale-texinfo-options| texinfo.................................|ale-texinfo-options|
write-good............................|ale-texinfo-write-good| write-good............................|ale-texinfo-write-good|
text....................................|ale-text-options| text....................................|ale-text-options|
@ -2797,6 +2807,13 @@ ale#command#ManageFile(buffer, filename) *ale#command#ManageFile()*
manages directories separately with the |ale#command#ManageDirectory| function. manages directories separately with the |ale#command#ManageDirectory| function.
ale#completion#OmniFunc(findstart, base) *ale#completion#OmniFunc()*
A completion function to use with 'omnifunc'.
See |ale-completion|.
ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()* ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()*
Given a buffer number, this function will return the list of problems Given a buffer number, this function will return the list of problems

View file

@ -424,6 +424,7 @@ formatting.
* [solhint](https://github.com/protofire/solhint) * [solhint](https://github.com/protofire/solhint)
* [solium](https://github.com/duaraghav8/Solium) * [solium](https://github.com/duaraghav8/Solium)
* SQL * SQL
* [pgformatter](https://github.com/darold/pgFormatter)
* [sqlfmt](https://github.com/jackc/sqlfmt) * [sqlfmt](https://github.com/jackc/sqlfmt)
* [sqlint](https://github.com/purcell/sqlint) * [sqlint](https://github.com/purcell/sqlint)
* Stylus * Stylus

View file

@ -170,66 +170,101 @@ endfun
" [-- <ELEMENT ? - - ...> --] " [-- <ELEMENT ? - - ...> --]
call <SID>HtmlIndentPush('a') call <SID>HtmlIndentPush('a')
call <SID>HtmlIndentPush('abbr') call <SID>HtmlIndentPush('abbr')
call <SID>HtmlIndentPush('acronym')
call <SID>HtmlIndentPush('address') call <SID>HtmlIndentPush('address')
call <SID>HtmlIndentPush('applet')
call <SID>HtmlIndentPush('article')
call <SID>HtmlIndentPush('aside')
call <SID>HtmlIndentPush('audio')
call <SID>HtmlIndentPush('b') call <SID>HtmlIndentPush('b')
call <SID>HtmlIndentPush('bdi')
call <SID>HtmlIndentPush('bdo') call <SID>HtmlIndentPush('bdo')
call <SID>HtmlIndentPush('big')
call <SID>HtmlIndentPush('blockquote') call <SID>HtmlIndentPush('blockquote')
call <SID>HtmlIndentPush('button') call <SID>HtmlIndentPush('button')
call <SID>HtmlIndentPush('canvas')
call <SID>HtmlIndentPush('caption') call <SID>HtmlIndentPush('caption')
call <SID>HtmlIndentPush('center')
call <SID>HtmlIndentPush('cite') call <SID>HtmlIndentPush('cite')
call <SID>HtmlIndentPush('code') call <SID>HtmlIndentPush('code')
call <SID>HtmlIndentPush('colgroup') call <SID>HtmlIndentPush('colgroup')
call <SID>HtmlIndentPush('content')
call <SID>HtmlIndentPush('data')
call <SID>HtmlIndentPush('datalist')
call <SID>HtmlIndentPush('del') call <SID>HtmlIndentPush('del')
call <SID>HtmlIndentPush('details')
call <SID>HtmlIndentPush('dfn') call <SID>HtmlIndentPush('dfn')
call <SID>HtmlIndentPush('dialog')
call <SID>HtmlIndentPush('dir') call <SID>HtmlIndentPush('dir')
call <SID>HtmlIndentPush('div') call <SID>HtmlIndentPush('div')
call <SID>HtmlIndentPush('dl') call <SID>HtmlIndentPush('dl')
call <SID>HtmlIndentPush('element')
call <SID>HtmlIndentPush('em') call <SID>HtmlIndentPush('em')
call <SID>HtmlIndentPush('fieldset') call <SID>HtmlIndentPush('fieldset')
call <SID>HtmlIndentPush('font') call <SID>HtmlIndentPush('figcaption')
call <SID>HtmlIndentPush('figure')
call <SID>HtmlIndentPush('footer')
call <SID>HtmlIndentPush('form') call <SID>HtmlIndentPush('form')
call <SID>HtmlIndentPush('frameset')
call <SID>HtmlIndentPush('h1') call <SID>HtmlIndentPush('h1')
call <SID>HtmlIndentPush('h2') call <SID>HtmlIndentPush('h2')
call <SID>HtmlIndentPush('h3') call <SID>HtmlIndentPush('h3')
call <SID>HtmlIndentPush('h4') call <SID>HtmlIndentPush('h4')
call <SID>HtmlIndentPush('h5') call <SID>HtmlIndentPush('h5')
call <SID>HtmlIndentPush('h6') call <SID>HtmlIndentPush('h6')
call <SID>HtmlIndentPush('header')
call <SID>HtmlIndentPush('hgroup')
call <SID>HtmlIndentPush('i') call <SID>HtmlIndentPush('i')
call <SID>HtmlIndentPush('iframe') call <SID>HtmlIndentPush('iframe')
call <SID>HtmlIndentPush('ins') call <SID>HtmlIndentPush('ins')
call <SID>HtmlIndentPush('kbd') call <SID>HtmlIndentPush('kbd')
call <SID>HtmlIndentPush('label') call <SID>HtmlIndentPush('label')
call <SID>HtmlIndentPush('legend') call <SID>HtmlIndentPush('legend')
call <SID>HtmlIndentPush('li')
call <SID>HtmlIndentPush('main')
call <SID>HtmlIndentPush('map') call <SID>HtmlIndentPush('map')
call <SID>HtmlIndentPush('mark')
call <SID>HtmlIndentPush('MediaStream')
call <SID>HtmlIndentPush('menu') call <SID>HtmlIndentPush('menu')
call <SID>HtmlIndentPush('noframes') call <SID>HtmlIndentPush('menuitem')
call <SID>HtmlIndentPush('meter')
call <SID>HtmlIndentPush('nav')
call <SID>HtmlIndentPush('noembed')
call <SID>HtmlIndentPush('noscript') call <SID>HtmlIndentPush('noscript')
call <SID>HtmlIndentPush('object') call <SID>HtmlIndentPush('object')
call <SID>HtmlIndentPush('ol') call <SID>HtmlIndentPush('ol')
call <SID>HtmlIndentPush('optgroup') call <SID>HtmlIndentPush('optgroup')
call <SID>HtmlIndentPush('option')
call <SID>HtmlIndentPush('output')
call <SID>HtmlIndentPush('picture')
call <SID>HtmlIndentPush('pre') call <SID>HtmlIndentPush('pre')
call <SID>HtmlIndentPush('progress')
call <SID>HtmlIndentPush('q') call <SID>HtmlIndentPush('q')
call <SID>HtmlIndentPush('rb')
call <SID>HtmlIndentPush('rp')
call <SID>HtmlIndentPush('rt')
call <SID>HtmlIndentPush('rtc')
call <SID>HtmlIndentPush('ruby')
call <SID>HtmlIndentPush('s') call <SID>HtmlIndentPush('s')
call <SID>HtmlIndentPush('samp') call <SID>HtmlIndentPush('samp')
call <SID>HtmlIndentPush('script') call <SID>HtmlIndentPush('script')
call <SID>HtmlIndentPush('section')
call <SID>HtmlIndentPush('select') call <SID>HtmlIndentPush('select')
call <SID>HtmlIndentPush('shadow')
call <SID>HtmlIndentPush('slot')
call <SID>HtmlIndentPush('small') call <SID>HtmlIndentPush('small')
call <SID>HtmlIndentPush('span') call <SID>HtmlIndentPush('span')
call <SID>HtmlIndentPush('strong') call <SID>HtmlIndentPush('strong')
call <SID>HtmlIndentPush('style') call <SID>HtmlIndentPush('style')
call <SID>HtmlIndentPush('sub') call <SID>HtmlIndentPush('sub')
call <SID>HtmlIndentPush('summary')
call <SID>HtmlIndentPush('sup') call <SID>HtmlIndentPush('sup')
call <SID>HtmlIndentPush('table') call <SID>HtmlIndentPush('table')
call <SID>HtmlIndentPush('template')
call <SID>HtmlIndentPush('textarea') call <SID>HtmlIndentPush('textarea')
call <SID>HtmlIndentPush('time')
call <SID>HtmlIndentPush('title') call <SID>HtmlIndentPush('title')
call <SID>HtmlIndentPush('tt') call <SID>HtmlIndentPush('tt')
call <SID>HtmlIndentPush('u') call <SID>HtmlIndentPush('u')
call <SID>HtmlIndentPush('ul') call <SID>HtmlIndentPush('ul')
call <SID>HtmlIndentPush('var') call <SID>HtmlIndentPush('var')
call <SID>HtmlIndentPush('video')
" For some reason the default HTML indentation script doesn't consider these " For some reason the default HTML indentation script doesn't consider these
" elements to be worthy of indentation. " elements to be worthy of indentation.
@ -256,6 +291,44 @@ if !exists('g:html_indent_strict_table')
call <SID>HtmlIndentPush('thead') call <SID>HtmlIndentPush('thead')
endif endif
" [-- <OBSOLETE ELEMENTS ? - - ...> --]
call <SID>HtmlIndentPush('abbr')
call <SID>HtmlIndentPush('acronym')
call <SID>HtmlIndentPush('applet')
call <SID>HtmlIndentPush('audio')
call <SID>HtmlIndentPush('basefont')
call <SID>HtmlIndentPush('bgsound')
call <SID>HtmlIndentPush('big')
call <SID>HtmlIndentPush('blink')
call <SID>HtmlIndentPush('center')
call <SID>HtmlIndentPush('command')
call <SID>HtmlIndentPush('content')
call <SID>HtmlIndentPush('dir')
call <SID>HtmlIndentPush('element')
call <SID>HtmlIndentPush('embed')
call <SID>HtmlIndentPush('font')
call <SID>HtmlIndentPush('frame')
call <SID>HtmlIndentPush('frameset')
call <SID>HtmlIndentPush('image')
call <SID>HtmlIndentPush('img')
call <SID>HtmlIndentPush('isindex')
call <SID>HtmlIndentPush('keygen')
call <SID>HtmlIndentPush('listing')
call <SID>HtmlIndentPush('marquee')
call <SID>HtmlIndentPush('menuitem')
call <SID>HtmlIndentPush('multicol')
call <SID>HtmlIndentPush('nextid')
call <SID>HtmlIndentPush('nobr')
call <SID>HtmlIndentPush('noembed')
call <SID>HtmlIndentPush('noframes')
call <SID>HtmlIndentPush('object')
call <SID>HtmlIndentPush('plaintext')
call <SID>HtmlIndentPush('shadow')
call <SID>HtmlIndentPush('spacer')
call <SID>HtmlIndentPush('strike')
call <SID>HtmlIndentPush('tt')
call <SID>HtmlIndentPush('xmp')
" [-- <Mako Elements> --] " [-- <Mako Elements> --]
call <SID>MakoIndentPush('%def') call <SID>MakoIndentPush('%def')
call <SID>MakoIndentPush('%block') call <SID>MakoIndentPush('%block')

View file

@ -3159,6 +3159,7 @@ function! s:Open(cmd, bang, mods, arg, args) abort
silent! execute '!' . escape(git . ' --no-pager ' . args, '!#%') . silent! execute '!' . escape(git . ' --no-pager ' . args, '!#%') .
\ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1') \ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1')
finally finally
redraw!
execute cdback execute cdback
endtry endtry
let temp = s:Resolve(temp) let temp = s:Resolve(temp)
@ -3168,7 +3169,7 @@ function! s:Open(cmd, bang, mods, arg, args) abort
endif endif
silent execute mods a:cmd temp silent execute mods a:cmd temp
call fugitive#ReloadStatus() call fugitive#ReloadStatus()
return 'redraw|echo ' . string(':!' . git . ' ' . args) return 'echo ' . string(':!' . git . ' ' . args)
endif endif
let [file, pre] = s:OpenParse(a:args) let [file, pre] = s:OpenParse(a:args)

View file

@ -10,7 +10,6 @@ function! gitgutter#all(force) abort
let file = expand('#'.bufnr.':p') let file = expand('#'.bufnr.':p')
if !empty(file) if !empty(file)
if index(visible, bufnr) != -1 if index(visible, bufnr) != -1
call gitgutter#init_buffer(bufnr)
call gitgutter#process_buffer(bufnr, a:force) call gitgutter#process_buffer(bufnr, a:force)
elseif a:force elseif a:force
call s:reset_tick(bufnr) call s:reset_tick(bufnr)
@ -21,22 +20,23 @@ function! gitgutter#all(force) abort
endfunction endfunction
" Finds the file's path relative to the repo root.
function! gitgutter#init_buffer(bufnr)
if gitgutter#utility#is_active(a:bufnr)
let p = gitgutter#utility#repo_path(a:bufnr, 0)
if type(p) != s:t_string || empty(p)
call gitgutter#utility#set_repo_path(a:bufnr)
call s:setup_maps()
endif
endif
endfunction
function! gitgutter#process_buffer(bufnr, force) abort function! gitgutter#process_buffer(bufnr, force) abort
" NOTE a:bufnr is not necessarily the current buffer. " NOTE a:bufnr is not necessarily the current buffer.
if gitgutter#utility#is_active(a:bufnr) if gitgutter#utility#is_active(a:bufnr)
call s:setup_maps(a:bufnr)
if has('patch-7.4.1559')
let l:Callback = function('gitgutter#process_buffer', [a:bufnr, a:force])
else
let l:Callback = {'function': 'gitgutter#process_buffer', 'arguments': [a:bufnr, a:force]}
endif
let how = s:setup_path(a:bufnr, l:Callback)
if [how] == ['async'] " avoid string-to-number conversion if how is a number
return
endif
if a:force || s:has_fresh_changes(a:bufnr) if a:force || s:has_fresh_changes(a:bufnr)
let diff = '' let diff = ''
@ -108,11 +108,15 @@ endfunction
" }}} " }}}
function! s:setup_maps() function! s:setup_maps(bufnr)
if !g:gitgutter_map_keys if !g:gitgutter_map_keys
return return
endif endif
if gitgutter#utility#getbufvar(a:bufnr, 'mapped', 0)
return
endif
if !hasmapto('<Plug>GitGutterPrevHunk') && maparg('[c', 'n') ==# '' if !hasmapto('<Plug>GitGutterPrevHunk') && maparg('[c', 'n') ==# ''
nmap <buffer> [c <Plug>GitGutterPrevHunk nmap <buffer> [c <Plug>GitGutterPrevHunk
endif endif
@ -142,6 +146,18 @@ function! s:setup_maps()
if !hasmapto('<Plug>GitGutterTextObjectOuterVisual') && maparg('ac', 'x') ==# '' if !hasmapto('<Plug>GitGutterTextObjectOuterVisual') && maparg('ac', 'x') ==# ''
xmap <buffer> ac <Plug>GitGutterTextObjectOuterVisual xmap <buffer> ac <Plug>GitGutterTextObjectOuterVisual
endif endif
call gitgutter#utility#setbufvar(a:bufnr, 'mapped', 1)
endfunction
function! s:setup_path(bufnr, continuation)
let p = gitgutter#utility#repo_path(a:bufnr, 0)
if type(p) == s:t_string && !empty(p) " if path is known
return
endif
return gitgutter#utility#set_repo_path(a:bufnr, a:continuation)
endfunction endfunction
function! s:has_fresh_changes(bufnr) abort function! s:has_fresh_changes(bufnr) abort

View file

@ -68,9 +68,9 @@ let s:counter = 0
" the hunk headers (@@ -x,y +m,n @@); only possible if " the hunk headers (@@ -x,y +m,n @@); only possible if
" grep is available. " grep is available.
function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
while gitgutter#utility#repo_path(a:bufnr, 0) == -1 if gitgutter#utility#repo_path(a:bufnr, 0) == -1
sleep 5m throw 'gitgutter author fail'
endwhile endif
if gitgutter#utility#repo_path(a:bufnr, 0) == -2 if gitgutter#utility#repo_path(a:bufnr, 0) == -2
throw 'gitgutter not tracked' throw 'gitgutter not tracked'

View file

@ -114,7 +114,29 @@ function! gitgutter#utility#repo_path(bufnr, shellesc) abort
return a:shellesc ? gitgutter#utility#shellescape(p) : p return a:shellesc ? gitgutter#utility#shellescape(p) : p
endfunction endfunction
function! gitgutter#utility#set_repo_path(bufnr) abort
let s:set_path_handler = {}
function! s:set_path_handler.out(buffer, path) abort
let path = s:strip_trailing_new_line(a:path)
call gitgutter#utility#setbufvar(a:buffer, 'path', path)
if type(self.continuation) == type(function('tr'))
call self.continuation()
else
call call(self.continuation.function, self.continuation.arguments)
endif
endfunction
function! s:set_path_handler.err(buffer) abort
call gitgutter#utility#setbufvar(a:buffer, 'path', -2)
endfunction
" continuation - a funcref or hash to call after setting the repo path asynchronously.
"
" Returns 'async' if the the path is set asynchronously, 0 otherwise.
function! gitgutter#utility#set_repo_path(bufnr, continuation) abort
" Values of path: " Values of path:
" * non-empty string - path " * non-empty string - path
" * -1 - pending " * -1 - pending
@ -124,48 +146,20 @@ function! gitgutter#utility#set_repo_path(bufnr) abort
let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr))) let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr)))
if g:gitgutter_async && gitgutter#async#available() if g:gitgutter_async && gitgutter#async#available()
if has('lambda') let handler = copy(s:set_path_handler)
call gitgutter#async#execute(cmd, a:bufnr, { let handler.continuation = a:continuation
\ 'out': {bufnr, path -> gitgutter#utility#setbufvar(bufnr, 'path', s:strip_trailing_new_line(path))}, call gitgutter#async#execute(cmd, a:bufnr, handler)
\ 'err': {bufnr -> gitgutter#utility#setbufvar(bufnr, 'path', -2)}, return 'async'
\ })
else
if has('nvim') && !has('nvim-0.2.0')
call gitgutter#async#execute(cmd, a:bufnr, {
\ 'out': function('s:set_path'),
\ 'err': function('s:not_tracked_by_git')
\ })
else
call gitgutter#async#execute(cmd, a:bufnr, {
\ 'out': function('s:set_path'),
\ 'err': function('s:set_path', [-2])
\ })
endif endif
endif
else
let path = gitgutter#utility#system(cmd) let path = gitgutter#utility#system(cmd)
if v:shell_error if v:shell_error
call gitgutter#utility#setbufvar(a:bufnr, 'path', -2) call gitgutter#utility#setbufvar(a:bufnr, 'path', -2)
else else
call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path)) call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path))
endif endif
endif
endfunction endfunction
if has('nvim') && !has('nvim-0.2.0')
function! s:not_tracked_by_git(bufnr)
call s:set_path(a:bufnr, -2)
endfunction
endif
function! s:set_path(bufnr, path)
if a:bufnr == -2
let [bufnr, path] = [a:path, a:bufnr]
call gitgutter#utility#setbufvar(bufnr, 'path', path)
else
call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(a:path))
endif
endfunction
function! gitgutter#utility#cd_cmd(bufnr, cmd) abort function! gitgutter#utility#cd_cmd(bufnr, cmd) abort
let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() ? 'cd /d' : 'cd') let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() ? 'cd /d' : 'cd')

View file

@ -190,7 +190,6 @@ function! s:on_bufenter()
let t:gitgutter_didtabenter = 0 let t:gitgutter_didtabenter = 0
call gitgutter#all(!g:gitgutter_terminal_reports_focus) call gitgutter#all(!g:gitgutter_terminal_reports_focus)
else else
call gitgutter#init_buffer(bufnr(''))
call gitgutter#process_buffer(bufnr(''), !g:gitgutter_terminal_reports_focus) call gitgutter#process_buffer(bufnr(''), !g:gitgutter_terminal_reports_focus)
endif endif
endfunction endfunction

View file

@ -71,7 +71,7 @@ function Test_add_lines()
normal ggo* normal ggo*
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=2 id=3000 name=GitGutterLineAdded"] let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -83,7 +83,7 @@ function Test_add_lines_fish()
normal ggo* normal ggo*
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=2 id=3000 name=GitGutterLineAdded"] let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
let &shell = _shell let &shell = _shell
@ -94,7 +94,7 @@ function Test_modify_lines()
normal ggi* normal ggi*
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=1 id=3000 name=GitGutterLineModified"] let expected = ["line=1 id=3000 name=GitGutterLineModified priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -103,7 +103,7 @@ function Test_remove_lines()
execute '5d' execute '5d'
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=4 id=3000 name=GitGutterLineRemoved"] let expected = ["line=4 id=3000 name=GitGutterLineRemoved priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -112,7 +112,7 @@ function Test_remove_first_lines()
execute '1d' execute '1d'
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=1 id=3000 name=GitGutterLineRemovedFirstLine"] let expected = ["line=1 id=3000 name=GitGutterLineRemovedFirstLine priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -122,7 +122,7 @@ function Test_overlapping_hunks()
execute '1d' execute '1d'
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=1 id=3000 name=GitGutterLineRemovedAboveAndBelow"] let expected = ["line=1 id=3000 name=GitGutterLineRemovedAboveAndBelow priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -132,7 +132,7 @@ function Test_edit_file_with_same_name_as_a_branch()
call system('git checkout -b fixture.txt') call system('git checkout -b fixture.txt')
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=5 id=3000 name=GitGutterLineModified"] let expected = ["line=5 id=3000 name=GitGutterLineModified priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -144,7 +144,7 @@ function Test_file_added_to_git()
normal ihello normal ihello
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=1 id=3000 name=GitGutterLineAdded"] let expected = ["line=1 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fileAddedToGit.tmp')) call assert_equal(expected, s:signs('fileAddedToGit.tmp'))
endfunction endfunction
@ -156,8 +156,8 @@ function Test_filename_with_equals()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=1 id=3000 name=GitGutterLineAdded', \ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded' \ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('=fixture=.txt')) call assert_equal(expected, s:signs('=fixture=.txt'))
endfunction endfunction
@ -170,8 +170,8 @@ function Test_filename_with_square_brackets()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=1 id=3000 name=GitGutterLineAdded', \ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded' \ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('fix[tu]re.txt')) call assert_equal(expected, s:signs('fix[tu]re.txt'))
endfunction endfunction
@ -184,8 +184,8 @@ function Test_filename_leading_dash()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=1 id=3000 name=GitGutterLineAdded', \ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded' \ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('-fixture.txt')) call assert_equal(expected, s:signs('-fixture.txt'))
endfunction endfunction
@ -198,8 +198,8 @@ function Test_filename_umlaut()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=1 id=3000 name=GitGutterLineAdded', \ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded' \ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('fixtüre.txt')) call assert_equal(expected, s:signs('fixtüre.txt'))
endfunction endfunction
@ -213,7 +213,7 @@ function Test_follow_symlink()
6d 6d
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ['line=5 id=3000 name=GitGutterLineRemoved'] let expected = ['line=5 id=3000 name=GitGutterLineRemoved priority=10']
call assert_equal(expected, s:signs('symlink')) call assert_equal(expected, s:signs('symlink'))
endfunction endfunction
@ -265,7 +265,7 @@ function Test_orphaned_signs()
6d 6d
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ['line=6 id=3001 name=GitGutterLineAdded'] let expected = ['line=6 id=3001 name=GitGutterLineAdded priority=10']
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -372,9 +372,9 @@ function Test_hunk_stage_nearby_hunk()
GitGutterStageHunk GitGutterStageHunk
let expected = [ let expected = [
\ 'line=3 id=3000 name=GitGutterLineAdded', \ 'line=3 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=4 id=3001 name=GitGutterLineAdded', \ 'line=4 id=3001 name=GitGutterLineAdded priority=10',
\ 'line=5 id=3002 name=GitGutterLineAdded' \ 'line=5 id=3002 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
@ -442,9 +442,9 @@ function Test_undo_nearby_hunk()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=3 id=3000 name=GitGutterLineAdded', \ 'line=3 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=4 id=3001 name=GitGutterLineAdded', \ 'line=4 id=3001 name=GitGutterLineAdded priority=10',
\ 'line=5 id=3002 name=GitGutterLineAdded' \ 'line=5 id=3002 name=GitGutterLineAdded priority=10'
\ ] \ ]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
@ -486,7 +486,7 @@ function Test_overlapping_hunk_op()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=2 id=3000 name=GitGutterLineRemoved', \ 'line=2 id=3000 name=GitGutterLineRemoved priority=10',
\ ] \ ]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
@ -500,7 +500,7 @@ function Test_overlapping_hunk_op()
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = [ let expected = [
\ 'line=1 id=3000 name=GitGutterLineRemovedFirstLine', \ 'line=1 id=3000 name=GitGutterLineRemovedFirstLine priority=10',
\ ] \ ]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
endfunction endfunction
@ -512,7 +512,7 @@ function Test_write_option()
normal ggo* normal ggo*
call s:trigger_gitgutter() call s:trigger_gitgutter()
let expected = ["line=2 id=3000 name=GitGutterLineAdded"] let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt')) call assert_equal(expected, s:signs('fixture.txt'))
set write set write

View file

@ -0,0 +1 @@
patreon: bhcleek

View file

@ -6,10 +6,8 @@ If possible, please provide clear steps for reproducing the problem.
### What did you expect to happen? ### What did you expect to happen?
### What happened instead? ### What happened instead?
### Configuration (**MUST** fill this out): ### Configuration (**MUST** fill this out):
#### vim-go version: #### vim-go version:
@ -20,10 +18,13 @@ If possible, please provide clear steps for reproducing the problem.
</pre></details> </pre></details>
#### Vim version (first three lines from `:version`): #### Vim version (first three lines from `:version`):
<!-- :version -->
#### Go version (`go version`): #### Go version (`go version`):
<!-- go version -->
#### Go environment #### Go environment
<details><summary><code>go env</code> Output:</summary><br><pre> <details><summary><code>go env</code> Output:</summary><br><pre>
<!-- go env -->
</pre></details> </pre></details>

View file

@ -8,6 +8,17 @@ IMPROVEMENTS:
[[GH-2261]](https://github.com/fatih/vim-go/pull/2261) [[GH-2261]](https://github.com/fatih/vim-go/pull/2261)
* Allow debugging of packages outside of GOPATH without a go.mod file. * Allow debugging of packages outside of GOPATH without a go.mod file.
[[GH-2269]](https://github.com/fatih/vim-go/pull/2269) [[GH-2269]](https://github.com/fatih/vim-go/pull/2269)
* Show which example failed when Example tests fail
[[GH-2277]](https://github.com/fatih/vim-go/pull/2277)
* Show function signature and return types in preview window when autocompleting functions and methods.
[[GH-2289]](https://github.com/fatih/vim-go/pull/2289)
* Improve the user experience when using null modules.
[[GH-2300]](https://github.com/fatih/vim-go/pull/2300)
* Add option, `g:go_null_module_warning` to silence the warning when trying to
use gopls with a null module.
[[GH-2309]](https://github.com/fatih/vim-go/pull/2309)
* Modify `:GoReportGitHubIssue` to include vim-go configuration values
[[GH-2323]](https://github.com/fatih/vim-go/pull/2323)
BUG FIXES: BUG FIXES:
* display info about function and function types whose parameters are * display info about function and function types whose parameters are
@ -26,6 +37,22 @@ BUG FIXES:
[[GH-2268]](https://github.com/fatih/vim-go/pull/2268) [[GH-2268]](https://github.com/fatih/vim-go/pull/2268)
* Set the anchor for method documentation correctly. * Set the anchor for method documentation correctly.
[[GH-2276]](https://github.com/fatih/vim-go/pull/2276) [[GH-2276]](https://github.com/fatih/vim-go/pull/2276)
* Respect the LSP information for determining where candidate matches start.
[[GH-2291]](https://github.com/fatih/vim-go/pull/2291)
* Restore environment variables with backslashes correctly.
[[GH-2292]](https://github.com/fatih/vim-go/pull/2292)
* Modify handling of gopls output for `:GoInfo` to ensure the value will be
displayed.
[[GH-2311]](https://github.com/fatih/vim-go/pull/2311)
* Run `:GoLint` successfully in null modules.
[[GH-2318]](https://github.com/fatih/vim-go/pull/2318)
* Ensure actions on save work in new buffers that have not yet been persisted to disk.
[[GH-2319]](https://github.com/fatih/vim-go/pull/2319)
* Restore population of information in `:GoReportGitHubIssue`.
[[GH-2312]](https://github.com/fatih/vim-go/pull/2312)
* Do not jump back to the originating window when jumping to definitions with
`g:go_def_mode='gopls'`.
[[GH-2327]](https://github.com/fatih/vim-go/pull/2327)
## 1.20 - (April 22, 2019) ## 1.20 - (April 22, 2019)

View file

@ -68,7 +68,16 @@ Depending on your installation method, you may have to generate the plugin's
[`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags) [`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags)
manually (e.g. `:helptags ALL`). manually (e.g. `:helptags ALL`).
We also have an [official vim-go tutorial](https://github.com/fatih/vim-go-tutorial). We also have an [official vim-go tutorial](https://github.com/fatih/vim-go/wiki).
## FAQ and troubleshooting
The FAQ and troubleshooting tips are in the documentation and can be quickly
accessed using `:help go-troubleshooting`. If you believe you've found a bug or
shortcoming in vim-go that is neither addressed by help nor in [existing
issues](https://github.com/fatih/vim-go/issues), please open an issue with
clear reproduction steps. `:GoReportGitHubIssue` can be used pre-populate a lot
of the information needed when creating a new issue.
## License ## License

View file

@ -33,7 +33,7 @@ function! go#auto#echo_go_info()
endfunction endfunction
function! go#auto#auto_type_info() function! go#auto#auto_type_info()
if !go#config#AutoTypeInfo() || !filereadable(expand('%:p')) if !go#config#AutoTypeInfo() || !isdirectory(expand('%:p:h'))
return return
endif endif
@ -42,7 +42,7 @@ function! go#auto#auto_type_info()
endfunction endfunction
function! go#auto#auto_sameids() function! go#auto#auto_sameids()
if !go#config#AutoSameids() || !filereadable(expand('%:p')) if !go#config#AutoSameids() || !isdirectory(expand('%:p:h'))
return return
endif endif
@ -51,7 +51,7 @@ function! go#auto#auto_sameids()
endfunction endfunction
function! go#auto#fmt_autosave() function! go#auto#fmt_autosave()
if !go#config#FmtAutosave() || !filereadable(expand('%:p')) if !go#config#FmtAutosave() || !isdirectory(expand('%:p:h'))
return return
endif endif
@ -60,7 +60,7 @@ function! go#auto#fmt_autosave()
endfunction endfunction
function! go#auto#metalinter_autosave() function! go#auto#metalinter_autosave()
if !go#config#MetalinterAutosave() || !filereadable(expand('%:p')) if !go#config#MetalinterAutosave() || !isdirectory(expand('%:p:h'))
return return
endif endif
@ -69,7 +69,7 @@ function! go#auto#metalinter_autosave()
endfunction endfunction
function! go#auto#modfmt_autosave() function! go#auto#modfmt_autosave()
if !go#config#ModFmtAutosave() || !filereadable(expand('%:p')) if !go#config#ModFmtAutosave() || !isdirectory(expand('%:p:h'))
return return
endif endif
@ -78,7 +78,7 @@ function! go#auto#modfmt_autosave()
endfunction endfunction
function! go#auto#asmfmt_autosave() function! go#auto#asmfmt_autosave()
if !go#config#AsmfmtAutosave() || !filereadable(expand('%:p')) if !go#config#AsmfmtAutosave() || !isdirectory(expand('%:p:h'))
return return
endif endif

View file

@ -9,8 +9,8 @@ function! go#cmd#autowrite() abort
for l:nr in range(0, bufnr('$')) for l:nr in range(0, bufnr('$'))
if buflisted(l:nr) && getbufvar(l:nr, '&modified') if buflisted(l:nr) && getbufvar(l:nr, '&modified')
" Sleep one second to make sure people see the message. Otherwise it is " Sleep one second to make sure people see the message. Otherwise it is
" often immediacy overwritten by the async messages (which also don't " often immediately overwritten by the async messages (which also
" invoke the "hit ENTER" prompt). " doesn't invoke the "hit ENTER" prompt).
call go#util#EchoWarning('[No write since last change]') call go#util#EchoWarning('[No write since last change]')
sleep 1 sleep 1
return return

View file

@ -216,6 +216,7 @@ function! s:info_complete(echo, result) abort
endfunction endfunction
function! s:trim_bracket(val) abort function! s:trim_bracket(val) abort
echom a:val
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '') let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
return a:val return a:val
endfunction endfunction
@ -240,7 +241,7 @@ function! go#complete#GocodeComplete(findstart, base) abort
else else
let s = getline(".")[col('.') - 1] let s = getline(".")[col('.') - 1]
if s =~ '[(){}\{\}]' if s =~ '[(){}\{\}]'
return map(copy(s:completions[1]), 's:trim_bracket(v:val)') return map(copy(s:completions), 's:trim_bracket(v:val)')
endif endif
return s:completions return s:completions
endif endif
@ -257,7 +258,10 @@ function! go#complete#Complete(findstart, base) abort
"findstart = 1 when we need to get the start of the match "findstart = 1 when we need to get the start of the match
if a:findstart == 1 if a:findstart == 1
call go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state])) let l:completion = go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state]))
if l:completion
return -3
endif
while !l:state.done while !l:state.done
sleep 10m sleep 10m

View file

@ -14,6 +14,10 @@ function! go#config#VersionWarning() abort
return get(g:, 'go_version_warning', 1) return get(g:, 'go_version_warning', 1)
endfunction endfunction
function! go#config#NullModuleWarning() abort
return get(g:, 'go_null_module_warning', 1)
endfunction
function! go#config#BuildTags() abort function! go#config#BuildTags() abort
return get(g:, 'go_build_tags', '') return get(g:, 'go_build_tags', '')
endfunction endfunction

View file

@ -18,20 +18,30 @@ function! s:issuebody() abort
for l in lines for l in lines
let body = add(body, l) let body = add(body, l)
if l =~ '^\* Vim version' if l =~ '^<!-- :version'
redir => out redir => out
silent version silent version
redir END redir END
let body = extend(body, split(out, "\n")[0:2]) let body = extend(body, split(out, "\n")[0:2])
elseif l =~ '^\* Go version' elseif l =~ '^<!-- go version -->'
let [out, err] = go#util#Exec(['go', 'version']) let [out, err] = go#util#Exec(['go', 'version'])
let body = add(body, substitute(l:out, rtrimpat, '', '')) let body = add(body, substitute(l:out, rtrimpat, '', ''))
elseif l =~ '^\* Go environment' elseif l =~ '^<!-- go env -->'
let [out, err] = go#util#Exec(['go', 'env']) let [out, err] = go#util#Exec(['go', 'env'])
let body = add(body, substitute(l:out, rtrimpat, '', '')) let body = add(body, substitute(l:out, rtrimpat, '', ''))
endif endif
endfor endfor
let body = add(body, "#### vim-go configuration:\n<details><summary>vim-go configuration</summary><br><pre>")
for k in keys(g:)
if k =~ '^go_'
let body = add(body, 'g:' . k . ' = ' . string(get(g:, k)))
endif
endfor
let body = add(body, '</pre></details>')
return join(body, "\n") return join(body, "\n")
endfunction endfunction

View file

@ -101,11 +101,10 @@ function! go#lint#Gometa(bang, autosave, ...) abort
endif endif
endfunction endfunction
" Golint calls 'golint' on the current directory. Any warnings are populated in " Golint calls 'golint'.
" the location list
function! go#lint#Golint(bang, ...) abort function! go#lint#Golint(bang, ...) abort
if a:0 == 0 if a:0 == 0
let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), go#package#ImportPath()]) let [l:out, l:err] = go#util#ExecInDir([go#config#GolintBin(), '.'])
else else
let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000) let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000)
endif endif

View file

@ -7,7 +7,7 @@ scriptencoding utf-8
let s:lspfactory = {} let s:lspfactory = {}
function! s:lspfactory.get() dict abort function! s:lspfactory.get() dict abort
if !has_key(self, 'current') || empty(self.current) if !has_key(self, 'current') || empty(self.current) || !has_key(self.current, 'job') || empty(self.current.job)
let self.current = s:newlsp() let self.current = s:newlsp()
endif endif
@ -22,9 +22,17 @@ endfunction
function! s:newlsp() abort function! s:newlsp() abort
if !go#util#has_job() if !go#util#has_job()
let l:oldshortmess=&shortmess
if has('nvim')
set shortmess-=F
endif
" TODO(bc): start the server in the background using a shell that waits for the right output before returning. " TODO(bc): start the server in the background using a shell that waits for the right output before returning.
call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.') call go#util#EchoWarning('Features that rely on gopls will not work without either Vim 8.0.0087 or newer with +job or Neovim')
return " Sleep one second to make sure people see the message. Otherwise it is
" often immediately overwritten by an async message.
sleep 1
let &shortmess=l:oldshortmess
return {'sendMessage': funcref('s:noop')}
endif endif
" job is the job used to talk to the backing instance of gopls. " job is the job used to talk to the backing instance of gopls.
@ -133,8 +141,17 @@ function! s:newlsp() abort
return return
endif endif
call l:handler.requestComplete(1) call l:handler.requestComplete(1)
let l:winidBeforeHandler = l:handler.winid
call call(l:handler.handleResult, [l:response.result]) call call(l:handler.handleResult, [l:response.result])
" change the window back to the window that was active when
" starting to handle the response _only_ if the handler didn't
" update the winid, so that handlers can set the winid if needed
" (e.g. :GoDef).
if l:handler.winid == l:winidBeforeHandler
call win_gotoid(l:winid) call win_gotoid(l:winid)
endif
finally finally
call remove(self.handlers, l:response.id) call remove(self.handlers, l:response.id)
endtry endtry
@ -162,13 +179,32 @@ function! s:newlsp() abort
let l:wd = go#util#ModuleRoot() let l:wd = go#util#ModuleRoot()
if l:wd == -1 if l:wd == -1
call go#util#EchoError('could not determine appropriate working directory for gopls') call go#util#EchoError('could not determine appropriate working directory for gopls')
return return -1
endif endif
if l:wd == '' if l:wd == ''
let l:wd = getcwd() let l:wd = getcwd()
endif endif
" do not attempt to send a message to gopls when using neither GOPATH
" mode nor module mode.
if go#package#FromPath(l:wd) == -2
if go#config#NullModuleWarning() && (!has_key(self, 'warned') || !self.warned)
let l:oldshortmess=&shortmess
if has('nvim')
set shortmess-=F
endif
call go#util#EchoWarning('Features that rely on gopls will not work correctly outside of GOPATH or a module.')
let self.warned = 1
" Sleep one second to make sure people see the message. Otherwise it is
" often immediately overwritten by an async message.
sleep 1
let &shortmess=l:oldshortmess
endif
return -1
endif
let l:msg = self.newMessage(go#lsp#message#Initialize(l:wd)) let l:msg = self.newMessage(go#lsp#message#Initialize(l:wd))
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
@ -351,7 +387,7 @@ function! go#lsp#Definition(fname, line, col, handler) abort
let l:state = s:newHandlerState('definition') let l:state = s:newHandlerState('definition')
let l:state.handleResult = funcref('s:definitionHandler', [function(a:handler, [], l:state)], l:state) let l:state.handleResult = funcref('s:definitionHandler', [function(a:handler, [], l:state)], l:state)
let l:msg = go#lsp#message#Definition(fnamemodify(a:fname, ':p'), a:line, a:col) let l:msg = go#lsp#message#Definition(fnamemodify(a:fname, ':p'), a:line, a:col)
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:definitionHandler(next, msg) abort dict function! s:definitionHandler(next, msg) abort dict
@ -373,7 +409,7 @@ function! go#lsp#TypeDef(fname, line, col, handler) abort
let l:state = s:newHandlerState('type definition') let l:state = s:newHandlerState('type definition')
let l:msg = go#lsp#message#TypeDefinition(fnamemodify(a:fname, ':p'), a:line, a:col) let l:msg = go#lsp#message#TypeDefinition(fnamemodify(a:fname, ':p'), a:line, a:col)
let l:state.handleResult = funcref('s:typeDefinitionHandler', [function(a:handler, [], l:state)], l:state) let l:state.handleResult = funcref('s:typeDefinitionHandler', [function(a:handler, [], l:state)], l:state)
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:typeDefinitionHandler(next, msg) abort dict function! s:typeDefinitionHandler(next, msg) abort dict
@ -396,9 +432,13 @@ function! go#lsp#DidOpen(fname) abort
let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n") let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n")
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop') let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state)
" TODO(bc): setting a buffer level variable here assumes that a:fname is the
" current buffer. Change to a:fname first before setting it and then change
" back to active buffer.
let b:go_lsp_did_open = 1 let b:go_lsp_did_open = 1
return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! go#lsp#DidChange(fname) abort function! go#lsp#DidChange(fname) abort
@ -419,7 +459,7 @@ function! go#lsp#DidChange(fname) abort
let l:msg = go#lsp#message#DidChange(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n") let l:msg = go#lsp#message#DidChange(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n")
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop') let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! go#lsp#DidClose(fname) abort function! go#lsp#DidClose(fname) abort
@ -435,9 +475,12 @@ function! go#lsp#DidClose(fname) abort
let l:msg = go#lsp#message#DidClose(fnamemodify(a:fname, ':p')) let l:msg = go#lsp#message#DidClose(fnamemodify(a:fname, ':p'))
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop') let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state) " TODO(bc): setting a buffer level variable here assumes that a:fname is the
" current buffer. Change to a:fname first before setting it and then change
" back to active buffer.
let b:go_lsp_did_open = 0 let b:go_lsp_did_open = 0
return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! go#lsp#Completion(fname, line, col, handler) abort function! go#lsp#Completion(fname, line, col, handler) abort
@ -448,7 +491,7 @@ function! go#lsp#Completion(fname, line, col, handler) abort
let l:state = s:newHandlerState('completion') let l:state = s:newHandlerState('completion')
let l:state.handleResult = funcref('s:completionHandler', [function(a:handler, [], l:state)], l:state) let l:state.handleResult = funcref('s:completionHandler', [function(a:handler, [], l:state)], l:state)
let l:state.error = funcref('s:completionErrorHandler', [function(a:handler, [], l:state)], l:state) let l:state.error = funcref('s:completionErrorHandler', [function(a:handler, [], l:state)], l:state)
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:completionHandler(next, msg) abort dict function! s:completionHandler(next, msg) abort dict
@ -462,6 +505,9 @@ function! s:completionHandler(next, msg) abort dict
let l:match = {'abbr': l:item.label, 'word': l:item.textEdit.newText, 'info': '', 'kind': go#lsp#completionitemkind#Vim(l:item.kind)} let l:match = {'abbr': l:item.label, 'word': l:item.textEdit.newText, 'info': '', 'kind': go#lsp#completionitemkind#Vim(l:item.kind)}
if has_key(l:item, 'detail') if has_key(l:item, 'detail')
let l:match.info = l:item.detail let l:match.info = l:item.detail
if go#lsp#completionitemkind#IsFunction(l:item.kind) || go#lsp#completionitemkind#IsMethod(l:item.kind)
let l:match.info = printf('func %s %s', l:item.label, l:item.detail)
endif
endif endif
if has_key(l:item, 'documentation') if has_key(l:item, 'documentation')
@ -475,7 +521,7 @@ function! s:completionHandler(next, msg) abort dict
endfunction endfunction
function! s:completionErrorHandler(next, error) abort dict function! s:completionErrorHandler(next, error) abort dict
call call(a:next, [[]]) call call(a:next, [-1, []])
endfunction endfunction
function! go#lsp#Hover(fname, line, col, handler) abort function! go#lsp#Hover(fname, line, col, handler) abort
@ -486,7 +532,7 @@ function! go#lsp#Hover(fname, line, col, handler) abort
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:hoverHandler', [function(a:handler, [], l:state)], l:state) let l:state.handleResult = funcref('s:hoverHandler', [function(a:handler, [], l:state)], l:state)
let l:state.error = funcref('s:noop') let l:state.error = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:hoverHandler(next, msg) abort dict function! s:hoverHandler(next, msg) abort dict
@ -515,13 +561,13 @@ function! go#lsp#Info(showstatus)
let l:state = s:newHandlerState('') let l:state = s:newHandlerState('')
endif endif
let l:state.handleResult = funcref('s:infoDefinitionHandler', [function('s:info', []), a:showstatus], l:state) let l:state.handleResult = funcref('s:infoDefinitionHandler', [a:showstatus], l:state)
let l:state.error = funcref('s:noop') let l:state.error = funcref('s:noop')
let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col) let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col)
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:infoDefinitionHandler(next, showstatus, msg) abort dict function! s:infoDefinitionHandler(showstatus, msg) abort dict
" gopls returns a []Location; just take the first one. " gopls returns a []Location; just take the first one.
let l:msg = a:msg[0] let l:msg = a:msg[0]
@ -540,11 +586,15 @@ function! s:infoDefinitionHandler(next, showstatus, msg) abort dict
let l:state.handleResult = funcref('s:hoverHandler', [function('s:info', [], l:state)], l:state) let l:state.handleResult = funcref('s:hoverHandler', [function('s:info', [], l:state)], l:state)
let l:state.error = funcref('s:noop') let l:state.error = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state) return l:lsp.sendMessage(l:msg, l:state)
endfunction endfunction
function! s:info(content) abort dict function! s:info(content) abort dict
let l:content = a:content[0] let l:content = a:content[0]
" strip godoc summary
let l:content = substitute(l:content, '^[^\n]\+\n', '', '')
" strip off the method set and fields of structs and interfaces. " strip off the method set and fields of structs and interfaces.
if l:content =~# '^type [^ ]\+ \(struct\|interface\)' if l:content =~# '^type [^ ]\+ \(struct\|interface\)'
let l:content = substitute(l:content, '{.*', '', '') let l:content = substitute(l:content, '{.*', '', '')

View file

@ -144,12 +144,19 @@ function! go#package#FromPath(arg) abort
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
let l:dir = getcwd() let l:dir = getcwd()
let l:path = a:arg let l:path = fnamemodify(a:arg, ':p')
if !isdirectory(l:path) if !isdirectory(l:path)
let l:path = fnamemodify(l:path, ':h') let l:path = fnamemodify(l:path, ':h')
endif endif
execute l:cd fnameescape(l:path) execute l:cd fnameescape(l:path)
if glob("*.go") == ""
" There's no Go code in this directory. We might be in a module directory
" which doesn't have any code at this level.
if !empty(s:module())
return -1
endif
endif
let [l:out, l:err] = go#util#Exec(['go', 'list']) let [l:out, l:err] = go#util#Exec(['go', 'list'])
execute l:cd fnameescape(l:dir) execute l:cd fnameescape(l:dir)
if l:err != 0 if l:err != 0

View file

@ -66,9 +66,9 @@ endfunc
func! Test_GoTestShowName() abort func! Test_GoTestShowName() abort
let expected = [ let expected = [
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'}, \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
\ {'lnum': 6, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'}, \ {'lnum': 6, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'}, \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
\ {'lnum': 9, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'}, \ {'lnum': 9, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
\ ] \ ]
let g:go_test_show_name=1 let g:go_test_show_name=1
@ -78,14 +78,14 @@ endfunc
func! Test_GoTestVet() abort func! Test_GoTestVet() abort
let expected = [ let expected = [
\ {'lnum': 6, 'bufnr': 10, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'}, \ {'lnum': 6, 'bufnr': 11, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
\ ] \ ]
call s:test('veterror/veterror.go', expected) call s:test('veterror/veterror.go', expected)
endfunc endfunc
func! Test_GoTestTestCompilerError() abort func! Test_GoTestTestCompilerError() abort
let expected = [ let expected = [
\ {'lnum': 10, 'bufnr': 8, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'}, \ {'lnum': 10, 'bufnr': 9, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'} \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'}
\ ] \ ]

View file

@ -557,7 +557,9 @@ function! go#util#SetEnv(name, value) abort
let l:remove = 1 let l:remove = 1
endif endif
call execute('let $' . a:name . ' = "' . a:value . '"') " wrap the value in single quotes so that it will work on windows when there
" are backslashes present in the value (e.g. $PATH).
call execute('let $' . a:name . " = '" . a:value . "'")
if l:remove if l:remove
function! s:remove(name) abort function! s:remove(name) abort

View file

@ -1204,6 +1204,22 @@ balloonexpr`.
============================================================================== ==============================================================================
SETTINGS *go-settings* SETTINGS *go-settings*
*'g:go_version_warning'*
Enable warning when using an unsupported version of Vim. By default it is
enabled.
>
let g:go_version_warning = 1
<
*'g:go_null_module_warning'*
Enable warning when trying to use lsp features in a null module. By default it
is enabled.
>
let g:go_null_module_warning = 1
<
*'g:go_code_completion_enabled'* *'g:go_code_completion_enabled'*
Enable code completion with |'omnifunc'|. By default it is enabled. Enable code completion with |'omnifunc'|. By default it is enabled.
@ -2183,6 +2199,24 @@ Highlight the current line and breakpoints in the debugger.
============================================================================== ==============================================================================
FAQ TROUBLESHOOTING *go-troubleshooting* FAQ TROUBLESHOOTING *go-troubleshooting*
How do I troubleshoot problems?~
One of the best ways to understand what vim-go is doing and the output from
the tools to which it delegates is to use leverage the features described in
|'g:go_debug'|.
Completion and other functions that use `gopls` don't work~
Vim-go is heavily reliant on `gopls` for completion and other functionality.
`gopls` requires either module mode or GOPATH mode; files that are neither in
GOPATH nor in a Go module will not be analyzed by `gopls`. Many of the
features that use `gopls` (e.g. completion, jumping to definitions, showing
identifier information, et al.) can be configured to delegate to other tools.
e.g. completion via |'omnifunc'|, |'g:go_info_mode'| and |'g:go_def_mode'| can
be set to use other tools for now (though some of the alternatives to `gopls`
are effectively at their end of life and support for them from within vim-go
may be removed soon).
I get "Unknown function: go#config#..." error when I open a Go file.~ I get "Unknown function: go#config#..." error when I open a Go file.~
This often happens to vim-polyglot users when new config options are added to This often happens to vim-polyglot users when new config options are added to

@ -1 +1 @@
Subproject commit 2fbab3401b7f81ac7f629e34e4f40a7e52934a99 Subproject commit a0663e91cd50686f39e96f4e51d10a37e2187df8

View file

@ -42,11 +42,24 @@ snippet pt
static propTypes = { static propTypes = {
${1}: React.PropTypes.${2:type}, ${1}: React.PropTypes.${2:type},
} }
snippet rfc
const ${1:ComponentName} = (${2:props}) => {
return (
<div>
$1
</div>
);
}
snippet rcc snippet rcc
class ${1:ClassName} extends React.Component { class ${1:ClassName} extends React.Component {
state = {
}
render() { render() {
return ( return (
${0:<div />} <div>
$1
</div>
); );
} }
} }

View file

@ -0,0 +1,37 @@
snippet ist
import { createStore } from 'redux';
snippet con
connect(${1:mapStateToProps}, ${2:mapDispatchToProps})(<${3:VISUAL}/>);
snippet act
const ${1:actionName} = (${2:arg}) => {
return {
type: ${3:VISUAL},
$2
};
};
snippet rdc
const ${1:reducerName} = (state={}, action) => {
switch(action.type) {
case ${1:action}:
return {
...state,
$2
};
default:
return state;
};
};
snippet mstp
const mapStateToProps = (state) => {
return {
${1:propName}: state.$1,
};
};
snippet mdtp
const mapDispatchToProps = (dispatch) => {
return {
${1:propName}: () => {
dispatch(${2:actionName}());
},
};
};

View file

@ -1,55 +0,0 @@
snippet const
const ${1} = ${0};
snippet let
let ${1} = ${0};
snippet im "import xyz from 'xyz'"
import ${1} from '${2:$1}';
snippet imas "import * as xyz from 'xyz'"
import * as ${1} from '${2:$1}';
snippet imm "import { member } from 'xyz'"
import { ${1} } from '${2}';
snippet cla
class ${1} {
${0:${VISUAL}}
}
snippet clax
class ${1} extends ${2} {
${0:${VISUAL}}
}
snippet clac
class ${1} {
constructor(${2}) {
${0:${VISUAL}}
}
}
snippet foro "for (const prop of object}) { ... }"
for (const ${1:prop} of ${2:object}) {
${0:$1}
}
# Generator
snippet fun*
function* ${1:function_name}(${2}) {
${0:${VISUAL}}
}
snippet c=>
const ${1:function_name} = (${2}) => {
${0:${VISUAL}}
}
snippet caf
const ${1:function_name} = (${2}) => {
${0:${VISUAL}}
}
snippet =>
(${1}) => {
${0:${VISUAL}}
}
snippet af
(${1}) => {
${0:${VISUAL}}
}
snippet sym
const ${1} = Symbol('${0}');
snippet ed
export default ${0}
snippet ${
${${1}}${0}

View file

@ -5,10 +5,14 @@ snippet proto
${0:${VISUAL}} ${0:${VISUAL}}
}; };
# Function # Function
snippet fun snippet fun "function"
function ${1:function_name}(${2}) { function ${1:function_name}(${2}) {
${0:${VISUAL}} ${0:${VISUAL}}
} }
snippet fun "async function"
async function ${1:function_name}(${2}) {
${0:${VISUAL}}
}
# Anonymous Function # Anonymous Function
snippet anf "" w snippet anf "" w
function(${1}) { function(${1}) {
@ -202,8 +206,6 @@ snippet @par
@param {${1:type}} ${2:name} ${0:description} @param {${1:type}} ${2:name} ${0:description}
snippet @ret snippet @ret
@return {${1:type}} ${0:description} @return {${1:type}} ${0:description}
# JSON
# JSON.parse # JSON.parse
snippet jsonp snippet jsonp
JSON.parse(${0:jstr}); JSON.parse(${0:jstr});
@ -273,9 +275,64 @@ snippet cprof "console.profile"
snippet ctable "console.table" snippet ctable "console.table"
console.table(${1:"${2:value}"}); console.table(${1:"${2:value}"});
# Misc # Misc
# 'use strict';
snippet us snippet us
'use strict'; 'use strict';
# setTimeout function # setTimeout function
snippet timeout snippet timeout
setTimeout(function () {${0}}${2}, ${1:10}); setTimeout(function () {${0}}${2}, ${1:10});
snippet const
const ${1} = ${0};
snippet let
let ${1} = ${0};
snippet im "import xyz from 'xyz'"
import ${1} from '${2:$1}';
snippet imas "import * as xyz from 'xyz'"
import * as ${1} from '${2:$1}';
snippet imm "import { member } from 'xyz'"
import { ${1} } from '${2}';
snippet cla
class ${1} {
${0:${VISUAL}}
}
snippet clax
class ${1} extends ${2} {
${0:${VISUAL}}
}
snippet clac
class ${1} {
constructor(${2}) {
${0:${VISUAL}}
}
}
snippet foro "for (const prop of object}) { ... }"
for (const ${1:prop} of ${2:object}) {
${0:$1}
}
snippet fun*
function* ${1:function_name}(${2}) {
${0:${VISUAL}}
}
snippet c=>
const ${1:function_name} = (${2}) => {
${0:${VISUAL}}
}
snippet caf
const ${1:function_name} = (${2}) => {
${0:${VISUAL}}
}
snippet =>
(${1}) => {
${0:${VISUAL}}
}
snippet af
(${1}) => {
${0:${VISUAL}}
}
snippet sym
const ${1} = Symbol('${0}');
snippet ed
export default ${0}
snippet ${
${${1}}${0}
snippet aw "await"
await ${0:${VISUAL}}