1
0
Fork 0
mirror of synced 2024-11-22 08:45:34 -05:00

Updated plugins

This commit is contained in:
Amir Salihefendic 2018-11-01 11:03:42 +01:00
parent 44dca49794
commit d2d303593e
105 changed files with 2141 additions and 510 deletions

View file

@ -1,6 +1,12 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com> " Author: Bjorn Neergaard <bjorn@neersighted.com>
" Description: ansible-lint for ansible-yaml files " Description: ansible-lint for ansible-yaml files
call ale#Set('ansible_ansible_lint_executable', 'ansible-lint')
function! ale_linters#ansible#ansible_lint#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ansible_ansible_lint_executable')
endfunction
function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
for l:line in a:lines[:10] for l:line in a:lines[:10]
if match(l:line, '^Traceback') >= 0 if match(l:line, '^Traceback') >= 0
@ -42,8 +48,9 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
endfunction endfunction
call ale#linter#Define('ansible', { call ale#linter#Define('ansible', {
\ 'name': 'ansible', \ 'name': 'ansible_lint',
\ 'executable': 'ansible', \ 'aliases': ['ansible', 'ansible-lint'],
\ 'command': 'ansible-lint -p %t', \ 'executable_callback': 'ale_linters#ansible#ansible_lint#GetExecutable',
\ 'command': '%e -p %t',
\ 'callback': 'ale_linters#ansible#ansible_lint#Handle', \ 'callback': 'ale_linters#ansible#ansible_lint#Handle',
\}) \})

View file

@ -10,7 +10,7 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
" Consult the check list in clang-tidy's documentation: " Consult the check list in clang-tidy's documentation:
" http://clang.llvm.org/extra/clang-tidy/checks/list.html " http://clang.llvm.org/extra/clang-tidy/checks/list.html
call ale#Set('c_clangtidy_checks', ['*']) call ale#Set('c_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy. " Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection. " This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '') call ale#Set('c_clangtidy_options', '')

View file

@ -4,7 +4,7 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy') call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply. " Set this option to check the checks clang-tidy will apply.
call ale#Set('cpp_clangtidy_checks', ['*']) call ale#Set('cpp_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy. " Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection. " This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '') call ale#Set('cpp_clangtidy_options', '')

View file

@ -0,0 +1,22 @@
" Author: aurieh <me@aurieh.me>
" Description: A Language Server implementation for D
call ale#Set('d_dls_executable', 'dls')
function! ale_linters#d#dls#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'd_dls_executable')
endfunction
function! ale_linters#d#dls#FindProjectRoot(buffer) abort
" Note: this will return . if dub config is empty
" dls can run outside DUB projects just fine
return fnamemodify(ale#d#FindDUBConfig(a:buffer), ':h')
endfunction
call ale#linter#Define('d', {
\ 'name': 'dls',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#d#dls#GetExecutable',
\ 'command_callback': 'ale_linters#d#dls#GetExecutable',
\ 'project_root_callback': 'ale_linters#d#dls#FindProjectRoot',
\})

View file

@ -1,20 +1,6 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: "dmd for D files" " Description: "dmd for D files"
function! s:FindDUBConfig(buffer) abort
" Find a DUB configuration file in ancestor paths.
" The most DUB-specific names will be tried first.
for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
let l:dub_file = ale#path#FindNearestFile(a:buffer, l:possible_filename)
if !empty(l:dub_file)
return l:dub_file
endif
endfor
return ''
endfunction
function! ale_linters#d#dmd#DUBCommand(buffer) abort function! ale_linters#d#dmd#DUBCommand(buffer) abort
" If we can't run dub, then skip this command. " If we can't run dub, then skip this command.
if !executable('dub') if !executable('dub')
@ -22,7 +8,7 @@ function! ale_linters#d#dmd#DUBCommand(buffer) abort
return '' return ''
endif endif
let l:dub_file = s:FindDUBConfig(a:buffer) let l:dub_file = ale#d#FindDUBConfig(a:buffer)
if empty(l:dub_file) if empty(l:dub_file)
return '' return ''

View file

@ -0,0 +1,61 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
call ale#Set('dockerfile_dockerfile_lint_executable', 'dockerfile_lint')
call ale#Set('dockerfile_dockerfile_lint_options', '')
function! ale_linters#dockerfile#dockerfile_lint#GetType(type) abort
if a:type is? 'error'
return 'E'
elseif a:type is? 'warn'
return 'W'
endif
return 'I'
endfunction
function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
try
let l:data = json_decode(join(a:lines, ''))
catch
return []
endtry
if empty(l:data)
" Should never happen, but it's better to be on the safe side
return []
endif
let l:messages = []
for l:type in ['error', 'warn', 'info']
for l:object in l:data[l:type]['data']
let l:line = get(l:object, 'line', -1)
let l:message = l:object['message']
if get(l:object, 'description', 'None') isnot# 'None'
let l:message = l:message . '. ' . l:object['description']
endif
call add(l:messages, {
\ 'lnum': l:line,
\ 'text': l:message,
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
\})
endfor
endfor
return l:messages
endfunction
function! ale_linters#dockerfile#dockerfile_lint#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'dockerfile_dockerfile_lint_options'))
\ . ' -p -j -f'
\ . ' %t'
endfunction
call ale#linter#Define('dockerfile', {
\ 'name': 'dockerfile_lint',
\ 'executable_callback': ale#VarFunc('dockerfile_dockerfile_lint_executable'),
\ 'command_callback': 'ale_linters#dockerfile#dockerfile_lint#GetCommand',
\ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle',
\})

View file

@ -11,10 +11,18 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
let l:type = l:match[3] let l:type = l:match[3]
let l:text = l:match[4] let l:text = l:match[4]
if l:type is# 'C' " Refactoring opportunities
let l:type = 'E' if l:type is# 'F'
elseif l:type is# 'R'
let l:type = 'W' let l:type = 'W'
" Consistency
elseif l:type is# 'C'
let l:type = 'W'
" Software Design
elseif l:type is# 'D'
let l:type = 'I'
" Code Readability
elseif l:type is# 'R'
let l:type = 'I'
endif endif
call add(l:output, { call add(l:output, {
@ -29,9 +37,16 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
return ale#path#CdString(l:project_root)
\ . ' mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'credo', \ 'name': 'credo',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s', \ 'command_callback': 'ale_linters#elixir#credo#GetCommand',
\ 'callback': 'ale_linters#elixir#credo#Handle', \ 'callback': 'ale_linters#elixir#credo#Handle',
\}) \})

View file

@ -25,10 +25,17 @@ function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#dialyxir#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
return ale#path#CdString(l:project_root)
\ . ' mix help dialyzer && mix dialyzer'
endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'dialyxir', \ 'name': 'dialyxir',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': 'mix help dialyzer && mix dialyzer', \ 'command_callback': 'ale_linters#elixir#dialyxir#GetCommand',
\ 'callback': 'ale_linters#elixir#dialyxir#Handle', \ 'callback': 'ale_linters#elixir#dialyxir#Handle',
\}) \})

View file

@ -29,10 +29,17 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#dogma#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
return ale#path#CdString(l:project_root)
\ . ' mix help dogma && mix dogma %s --format=flycheck'
endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'dogma', \ 'name': 'dogma',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': 'mix help dogma && mix dogma %s --format=flycheck', \ 'command_callback': 'ale_linters#elixir#dogma#GetCommand',
\ 'lint_file': 1, \ 'lint_file': 1,
\ 'callback': 'ale_linters#elixir#dogma#Handle', \ 'callback': 'ale_linters#elixir#dogma#Handle',
\}) \})

View file

@ -0,0 +1,19 @@
" Author: Jon Parise <jon@indelible.org>
" Description: elixir-ls integration (https://github.com/JakeBecker/elixir-ls)
call ale#Set('elixir_elixir_ls_release', 'elixir-ls')
function! ale_linters#elixir#elixir_ls#GetExecutable(buffer) abort
let l:dir = ale#path#Simplify(ale#Var(a:buffer, 'elixir_elixir_ls_release'))
let l:cmd = ale#Has('win32') ? '\language_server.bat' : '/language_server.sh'
return l:dir . l:cmd
endfunction
call ale#linter#Define('elixir', {
\ 'name': 'elixir-ls',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
\ 'command_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
\ 'project_root_callback': 'ale#handlers#elixir#FindMixProjectRoot',
\})

View file

@ -29,18 +29,8 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#mix#FindProjectRoot(buffer) abort
let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
if !empty(l:mix_file)
return fnamemodify(l:mix_file, ':p:h')
endif
return '.'
endfunction
function! ale_linters#elixir#mix#GetCommand(buffer) abort function! ale_linters#elixir#mix#GetCommand(buffer) abort
let l:project_root = ale_linters#elixir#mix#FindProjectRoot(a:buffer) let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:temp_dir = ale#engine#CreateDirectory(a:buffer) let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
@ -49,8 +39,8 @@ function! ale_linters#elixir#mix#GetCommand(buffer) abort
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir) \ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root) return ale#path#CdString(l:project_root)
\ . l:mix_build_path \ . l:mix_build_path
\ . ' mix compile %s' \ . ' mix compile %s'
endfunction endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {

View file

@ -16,7 +16,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_build', \ 'name': 'stack_build',
\ 'aliases': ['stack-build'], \ 'aliases': ['stack-build'],
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'stack', \ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand', \ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand',
\ 'lint_file': 1, \ 'lint_file': 1,
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',

View file

@ -5,7 +5,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_ghc', \ 'name': 'stack_ghc',
\ 'aliases': ['stack-ghc'], \ 'aliases': ['stack-ghc'],
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'stack', \ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command': 'stack ghc -- -fno-code -v0 %t', \ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})

View file

@ -2,7 +2,7 @@
" Description: PMD for Java files " Description: PMD for Java files
function! ale_linters#java#pmd#Handle(buffer, lines) abort function! ale_linters#java#pmd#Handle(buffer, lines) abort
let l:pattern = '"\(\d\+\)",".\+","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$' let l:pattern = '"\(\d\+\)",".*","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
let l:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)

View file

@ -18,7 +18,7 @@ function! ale_linters#javascript#jshint#GetCommand(buffer) abort
let l:command .= ' --config ' . ale#Escape(l:jshint_config) let l:command .= ' --config ' . ale#Escape(l:jshint_config)
endif endif
let l:command .= ' -' let l:command .= ' --filename %s -'
return l:command return l:command
endfunction endfunction

View file

@ -0,0 +1,166 @@
" Author:Travis Gibson <https://github.com/Garland-g>
" Description: This file adds support for checking perl6 syntax
let g:ale_perl6_perl6_executable =
\ get(g:, 'ale_perl6_perl6_executable', 'perl6')
let g:ale_perl6_perl6_options =
\ get(g:, 'ale_perl6_perl6_options', '-c -Ilib')
let $PERL6_EXCEPTIONS_HANDLER = 'JSON'
let $RAKUDO_ERROR_COLOR = 0
function! ale_linters#perl6#perl6#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'perl6_perl6_executable')
endfunction
function! ale_linters#perl6#perl6#GetCommand(buffer) abort
return ale_linters#perl6#perl6#GetExecutable(a:buffer)
\ . ' ' . ale#Var(a:buffer, 'perl6_perl6_options')
\ . ' %t'
endfunction
function! ale_linters#perl6#perl6#ExtractError(dict, item, type, buffer) abort
let l:file = ''
let l:line = 1
let l:column = ''
let l:text = ''
let l:pre = ''
let l:counter = 2
let l:end_line = ''
let l:linepatternmessage = 'at\s\+line\s\+\(\d\+\)'
if has_key(a:dict[a:item], 'filename') && !empty(a:dict[a:item]['filename'])
let l:file = a:dict[a:item]['filename']
endif
if has_key(a:dict[a:item], 'line') && !empty(a:dict[a:item]['line'])
let l:line = a:dict[a:item]['line']
let l:counter -= 1
endif
if has_key(a:dict[a:item], 'column') && !empty(a:dict[a:item]['column'])
let l:column = a:dict[a:item]['column']
endif
if has_key(a:dict[a:item], 'message') && !empty(a:dict[a:item]['message'])
let l:text = substitute(a:dict[a:item]['message'], '\s*\n\s*', ' ', 'g')
let l:counter -= 1
endif
if has_key(a:dict[a:item], 'line-real') && !empty(a:dict[a:item]['line-real'])
let l:end_line = l:line
let l:line = a:dict[a:item]['line-real']
endif
for l:match in ale#util#GetMatches(l:text, l:linepatternmessage)
let l:line = l:match[1]
let l:counter -= 1
endfor
" Currently, filenames and line numbers are not always given in the error output
if l:counter < 2
\&& ( ale#path#IsBufferPath(a:buffer, l:file) || l:file is# '' )
return {
\ 'lnum': '' . l:line,
\ 'text': l:text,
\ 'type': a:type,
\ 'col': l:column,
\ 'end_lnum': l:end_line,
\ 'code': a:item,
\}
endif
return ''
endfunction
function! ale_linters#perl6#perl6#Handle(buffer, lines) abort
let l:output = []
if empty(a:lines)
return l:output
endif
if a:lines[0] is# 'Syntax OK'
return l:output
endif
try
let l:json = json_decode(join(a:lines, ''))
catch /E474/
call add(l:output, {
\ 'lnum': '1',
\ 'text': 'Received output in the default Perl6 error format. See :ALEDetail for details',
\ 'detail': join(a:lines, "\n"),
\ 'type': 'W',
\ })
return l:output
endtry
if type(l:json) is v:t_dict
for l:key in keys(l:json)
if has_key(l:json[l:key], 'sorrows') &&
\ has_key(l:json[l:key], 'worries')
if !empty(l:json[l:key]['sorrows'])
for l:dictionary in get(l:json[l:key], 'sorrows')
for l:item in keys(l:dictionary)
let l:result =
\ ale_linters#perl6#perl6#ExtractError(
\ l:dictionary,
\ l:item,
\ 'E',
\ a:buffer,
\ )
if l:result isnot# ''
call add(l:output, l:result)
endif
endfor
endfor
endif
if !empty(l:json[l:key]['worries'])
for l:dictionary in get(l:json[l:key], 'worries')
for l:item in keys(l:dictionary)
let l:result =
\ ale_linters#perl6#perl6#ExtractError(
\ l:dictionary,
\ l:item,
\ 'W',
\ a:buffer,
\ )
if l:result isnot# ''
call add(l:output, l:result)
endif
endfor
endfor
endif
else
let l:result = ale_linters#perl6#perl6#ExtractError(
\ l:json,
\ l:key,
\ 'E',
\ a:buffer,
\ )
if l:result isnot# ''
call add(l:output, l:result)
endif
endif
endfor
endif
return l:output
endfunction
call ale#linter#Define('perl6', {
\ 'name': 'perl6',
\ 'executable_callback': 'ale_linters#perl6#perl6#GetExecutable',
\ 'output_stream': 'both',
\ 'command_callback': 'ale_linters#perl6#perl6#GetCommand',
\ 'callback': 'ale_linters#perl6#perl6#Handle',
\})

View file

@ -1,28 +1,21 @@
" Author: richard marmorstein <https://github.com/twitchard> " Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP " Description: plugin for Psalm, static analyzer for PHP
call ale#Set('php_psalm_executable', 'psalm') call ale#Set('psalm_langserver_executable', 'psalm-language-server')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#Handle(buffer, lines) abort function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
" Matches patterns like the following: let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
let l:pattern = '^.*:\(\d\+\):\(\d\+\):\(\w\+\) - \(.*\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'text': l:match[4],
\ 'type': l:match[3][:0] is# 'e' ? 'E' : 'W',
\})
endfor
return l:output
endfunction endfunction
call ale#linter#Define('php', { call ale#linter#Define('php', {
\ 'name': 'psalm', \ 'name': 'psalm',
\ 'command': '%e --diff --output-format=emacs %s', \ 'lsp': 'stdio',
\ 'executable_callback': ale#VarFunc('php_psalm_executable'), \ 'executable_callback': ale#node#FindExecutableFunc('psalm_langserver', [
\ 'callback': 'ale_linters#php#psalm#Handle', \ 'vendor/bin/psalm-language-server',
\ 'lint_file': 1, \ ]),
\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#php#psalm#GetProjectRoot',
\}) \})

View file

@ -0,0 +1,100 @@
" Author: Takuya Fujiwara <tyru.exe@gmail.com>
" Description: swipl syntax / semantic check for Prolog files
call ale#Set('prolog_swipl_executable', 'swipl')
call ale#Set('prolog_swipl_load', 'current_prolog_flag(argv, [File]), load_files(File, [sandboxed(true)]), halt.')
call ale#Set('prolog_swipl_timeout', 3)
call ale#Set('prolog_swipl_alarm', 'alarm(%t, (%h), _, [])')
call ale#Set('prolog_swipl_alarm_handler', 'writeln(user_error, "ERROR: Exceeded %t seconds, Please change g:prolog_swipl_timeout to modify the limit."), halt(1)')
function! ale_linters#prolog#swipl#GetCommand(buffer) abort
let l:goals = ale#Var(a:buffer, 'prolog_swipl_load')
let l:goals = l:goals =~# '^\s*$' ? 'halt' : l:goals
let l:timeout = ale#Var(a:buffer, 'prolog_swipl_timeout') + 0
if l:timeout > 0
let l:goals = s:GetAlarm(a:buffer, l:timeout) . ', ' . l:goals
endif
return '%e -g ' . ale#Escape(l:goals) . ' -- %s'
endfunction
function! s:GetAlarm(buffer, timeout) abort
let l:handler = ale#Var(a:buffer, 'prolog_swipl_alarm_handler')
let l:handler = s:Subst(l:handler, {'t': a:timeout})
let l:alarm = ale#Var(a:buffer, 'prolog_swipl_alarm')
let l:alarm = s:Subst(l:alarm, {'t': a:timeout, 'h': l:handler})
return l:alarm
endfunction
function! s:Subst(format, vars) abort
let l:vars = extend(copy(a:vars), {'%': '%'})
return substitute(a:format, '%\(.\)', '\=get(l:vars, submatch(1), "")', 'g')
endfunction
function! ale_linters#prolog#swipl#Handle(buffer, lines) abort
let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$'
let l:output = []
let l:i = 0
while l:i < len(a:lines)
let l:match = matchlist(a:lines[l:i], l:pattern)
if empty(l:match)
let l:i += 1
continue
endif
let [l:i, l:text] = s:GetErrMsg(l:i, a:lines, l:match[4])
let l:item = {
\ 'lnum': (l:match[2] + 0 ? l:match[2] + 0 : 1),
\ 'col': l:match[3] + 0,
\ 'text': l:text,
\ 'type': (l:match[1] is# 'ERROR' ? 'E' : 'W'),
\}
if !s:Ignore(l:item)
call add(l:output, l:item)
endif
endwhile
return l:output
endfunction
" This returns [<next line number>, <error message string>]
function! s:GetErrMsg(i, lines, text) abort
if a:text !~# '^\s*$'
return [a:i + 1, a:text]
endif
let l:i = a:i + 1
let l:text = []
while l:i < len(a:lines) && a:lines[l:i] =~# '^\s'
call add(l:text, s:Trim(a:lines[l:i]))
let l:i += 1
endwhile
return [l:i, join(l:text, '. ')]
endfunction
function! s:Trim(str) abort
return substitute(a:str, '\v^\s+|\s+$', '', 'g')
endfunction
" Skip sandbox error which is caused by directives
" because what we want is syntactic or semantic check.
function! s:Ignore(item) abort
return a:item.type is# 'E' &&
\ a:item.text =~# '\vNo permission to (call|directive|assert) sandboxed'
endfunction
call ale#linter#Define('prolog', {
\ 'name': 'swipl',
\ 'output_stream': 'stderr',
\ 'executable_callback': ale#VarFunc('prolog_swipl_executable'),
\ 'command_callback': 'ale_linters#prolog#swipl#GetCommand',
\ 'callback': 'ale_linters#prolog#swipl#Handle',
\})

View file

@ -30,7 +30,7 @@ function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort
\ : '' \ : ''
return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek') return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
\ . ' -f json --no-progress --no-color' \ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args \ . l:display_name_args
endfunction endfunction

View file

@ -5,6 +5,7 @@
" Description: updated to use stdio " Description: updated to use stdio
call ale#Set('ruby_solargraph_executable', 'solargraph') call ale#Set('ruby_solargraph_executable', 'solargraph')
call ale#Set('ruby_solargraph_options', {})
function! ale_linters#ruby#solargraph#GetCommand(buffer) abort function! ale_linters#ruby#solargraph#GetCommand(buffer) abort
return '%e' . ale#Pad('stdio') return '%e' . ale#Pad('stdio')
@ -17,4 +18,5 @@ call ale#linter#Define('ruby', {
\ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'), \ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'),
\ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand', \ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand',
\ 'project_root_callback': 'ale#ruby#FindProjectRoot', \ 'project_root_callback': 'ale#ruby#FindProjectRoot',
\ 'initialization_options_callback': ale#VarFunc('ruby_solargraph_options'),
\}) \})

View file

@ -9,6 +9,8 @@ call ale#Set('rust_cargo_check_tests', 0)
call ale#Set('rust_cargo_avoid_whole_workspace', 1) call ale#Set('rust_cargo_avoid_whole_workspace', 1)
call ale#Set('rust_cargo_default_feature_behavior', 'default') call ale#Set('rust_cargo_default_feature_behavior', 'default')
call ale#Set('rust_cargo_include_features', '') call ale#Set('rust_cargo_include_features', '')
call ale#Set('rust_cargo_use_clippy', 0)
call ale#Set('rust_cargo_clippy_options', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# '' if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@ -70,14 +72,23 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
let l:default_feature = '' let l:default_feature = ''
endif endif
let l:subcommand = l:use_check ? 'check' : 'build'
let l:clippy_options = ''
if ale#Var(a:buffer, 'rust_cargo_use_clippy')
let l:subcommand = 'clippy'
let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options')
endif
return l:nearest_cargo_prefix . 'cargo ' return l:nearest_cargo_prefix . 'cargo '
\ . (l:use_check ? 'check' : 'build') \ . l:subcommand
\ . (l:use_all_targets ? ' --all-targets' : '') \ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '') \ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '') \ . (l:use_tests ? ' --tests' : '')
\ . ' --frozen --message-format=json -q' \ . ' --frozen --message-format=json -q'
\ . l:default_feature \ . l:default_feature
\ . l:include_features \ . l:include_features
\ . l:clippy_options
endfunction endfunction
call ale#linter#Define('rust', { call ale#linter#Define('rust', {

View file

@ -10,8 +10,7 @@ let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {}) let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
let s:lint_timer = -1 let s:lint_timer = -1
let s:queued_buffer_number = -1 let s:getcmdwintype_exists = exists('*getcmdwintype')
let s:should_lint_file_for_buffer = {}
" Return 1 if a file is too large for ALE to handle. " Return 1 if a file is too large for ALE to handle.
function! ale#FileTooLarge(buffer) abort function! ale#FileTooLarge(buffer) abort
@ -20,8 +19,6 @@ function! ale#FileTooLarge(buffer) abort
return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0 return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0
endfunction endfunction
let s:getcmdwintype_exists = exists('*getcmdwintype')
" A function for checking various conditions whereby ALE just shouldn't " A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim. " attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing(buffer) abort function! ale#ShouldDoNothing(buffer) abort
@ -86,18 +83,44 @@ function! ale#ShouldDoNothing(buffer) abort
return 0 return 0
endfunction endfunction
function! s:Lint(buffer, should_lint_file, timer_id) abort
" Use the filetype from the buffer
let l:filetype = getbufvar(a:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype)
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:linters = !empty(l:ignore_config)
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
\ : l:linters
" Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer
silent doautocmd <nomodeline> User ALEWantResults
unlet! g:ale_want_results_buffer
" Don't set up buffer data and so on if there are no linters to run.
if !has_key(g:ale_buffer_info, a:buffer) && empty(l:linters)
return
endif
" Clear lint_file linters, or only run them if the file exists.
let l:lint_file = empty(l:linters)
\ || (a:should_lint_file && filereadable(expand('#' . a:buffer . ':p')))
call ale#engine#RunLinters(a:buffer, l:linters, l:lint_file)
endfunction
" (delay, [linting_flag, buffer_number]) " (delay, [linting_flag, buffer_number])
function! ale#Queue(delay, ...) abort function! ale#Queue(delay, ...) abort
if a:0 > 2 if a:0 > 2
throw 'too many arguments!' throw 'too many arguments!'
endif endif
" Default linting_flag to '' let l:buffer = get(a:000, 1, v:null)
let l:linting_flag = get(a:000, 0, '')
let l:buffer = get(a:000, 1, bufnr(''))
if l:linting_flag isnot# '' && l:linting_flag isnot# 'lint_file' if l:buffer is v:null
throw "linting_flag must be either '' or 'lint_file'" let l:buffer = bufnr('')
endif endif
if type(l:buffer) isnot v:t_number if type(l:buffer) isnot v:t_number
@ -108,80 +131,24 @@ function! ale#Queue(delay, ...) abort
return return
endif endif
" Remember that we want to check files for this buffer. " Default linting_flag to ''
" We will remember this until we finally run the linters, via any event. let l:should_lint_file = get(a:000, 0) is# 'lint_file'
if l:linting_flag is# 'lint_file'
let s:should_lint_file_for_buffer[l:buffer] = 1
endif
if s:lint_timer != -1 if s:lint_timer != -1
call timer_stop(s:lint_timer) call timer_stop(s:lint_timer)
let s:lint_timer = -1 let s:lint_timer = -1
endif endif
let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
" Don't set up buffer data and so on if there are no linters to run.
if empty(l:linters)
" If we have some previous buffer data, then stop any jobs currently
" running and clear everything.
if has_key(g:ale_buffer_info, l:buffer)
call ale#engine#RunLinters(l:buffer, [], 1)
endif
return
endif
if a:delay > 0 if a:delay > 0
let s:queued_buffer_number = l:buffer let s:lint_timer = timer_start(
let s:lint_timer = timer_start(a:delay, function('ale#Lint')) \ a:delay,
\ function('s:Lint', [l:buffer, l:should_lint_file])
\)
else else
call ale#Lint(-1, l:buffer) call s:Lint(l:buffer, l:should_lint_file, 0)
endif endif
endfunction endfunction
function! ale#Lint(...) abort
if a:0 > 1
" Use the buffer number given as the optional second argument.
let l:buffer = a:2
elseif a:0 > 0 && a:1 == s:lint_timer
" Use the buffer number for the buffer linting was queued for.
let l:buffer = s:queued_buffer_number
else
" Use the current buffer number.
let l:buffer = bufnr('')
endif
if ale#ShouldDoNothing(l:buffer)
return
endif
" Use the filetype from the buffer
let l:filetype = getbufvar(l:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype)
let l:should_lint_file = 0
" Check if we previously requested checking the file.
if has_key(s:should_lint_file_for_buffer, l:buffer)
unlet s:should_lint_file_for_buffer[l:buffer]
" Lint files if they exist.
let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
endif
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(l:buffer, 'linters_ignore')
let l:linters = !empty(l:ignore_config)
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
\ : l:linters
call ale#engine#RunLinters(l:buffer, l:linters, l:should_lint_file)
endfunction
" Reset flags indicating that files should be checked for all buffers.
function! ale#ResetLintFileMarkers() abort
let s:should_lint_file_for_buffer = {}
endfunction
let g:ale_has_override = get(g:, 'ale_has_override', {}) let g:ale_has_override = get(g:, 'ale_has_override', {})
" Call has(), but check a global Dictionary so we can force flags on or off " Call has(), but check a global Dictionary so we can force flags on or off

View file

@ -85,6 +85,14 @@ function! ale#assert#LSPOptions(expected_options) abort
AssertEqual a:expected_options, l:initialization_options AssertEqual a:expected_options, l:initialization_options
endfunction endfunction
function! ale#assert#LSPConfig(expected_config) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:config = ale#lsp_linter#GetConfig(l:buffer, l:linter)
AssertEqual a:expected_config, l:config
endfunction
function! ale#assert#LSPLanguage(expected_language) abort function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:linter = s:GetLinter() let l:linter = s:GetLinter()
@ -147,6 +155,7 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>) command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted() command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>) command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig(<args>)
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>) command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>) command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>) command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
@ -172,6 +181,10 @@ function! ale#assert#TearDownLinterTest() abort
delcommand AssertLSPOptions delcommand AssertLSPOptions
endif endif
if exists(':AssertLSPConfig')
delcommand AssertLSPConfig
endif
if exists(':AssertLSPLanguage') if exists(':AssertLSPLanguage')
delcommand AssertLSPLanguage delcommand AssertLSPLanguage
endif endif

View file

@ -26,7 +26,20 @@ function! ale#cursor#TruncatedEcho(original_message) abort
" The message is truncated and saved to the history. " The message is truncated and saved to the history.
setlocal shortmess+=T setlocal shortmess+=T
exec "norm! :echomsg l:message\n"
try
exec "norm! :echomsg l:message\n"
catch /^Vim\%((\a\+)\)\=:E523/
" Fallback into manual truncate (#1987)
let l:winwidth = winwidth(0)
if l:winwidth < strdisplaywidth(l:message)
" Truncate message longer than window width with trailing '...'
let l:message = l:message[:l:winwidth - 4] . '...'
endif
exec 'echomsg l:message'
endtry
" Reset the cursor position if we moved off the end of the line. " Reset the cursor position if we moved off the end of the line.
" Using :norm and :echomsg can move the cursor off the end of the " Using :norm and :echomsg can move the cursor off the end of the

View file

@ -0,0 +1,16 @@
" Author: Auri <me@aurieh.me>
" Description: Functions for integrating with D linters.
function! ale#d#FindDUBConfig(buffer) abort
" Find a DUB configuration file in ancestor paths.
" The most DUB-specific names will be tried first.
for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
let l:dub_file = ale#path#FindNearestFile(a:buffer, l:possible_filename)
if !empty(l:dub_file)
return l:dub_file
endif
endfor
return ''
endfunction

View file

@ -79,6 +79,7 @@ function! ale#engine#InitBufferInfo(buffer) abort
let g:ale_buffer_info[a:buffer] = { let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [], \ 'job_list': [],
\ 'active_linter_list': [], \ 'active_linter_list': [],
\ 'active_other_sources_list': [],
\ 'loclist': [], \ 'loclist': [],
\ 'temporary_file_list': [], \ 'temporary_file_list': [],
\ 'temporary_directory_list': [], \ 'temporary_directory_list': [],
@ -97,6 +98,7 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
return !empty(get(l:info, 'active_linter_list', [])) return !empty(get(l:info, 'active_linter_list', []))
\ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction endfunction
" Register a temporary file to be managed with the ALE engine for " Register a temporary file to be managed with the ALE engine for
@ -177,20 +179,27 @@ function! s:GatherOutput(job_id, line) abort
endif endif
endfunction endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:info) if empty(l:info)
return return
endif endif
" Remove this linter from the list of active linters. if !a:from_other_source
" This may have already been done when the job exits. " Remove this linter from the list of active linters.
call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name') " This may have already been done when the job exits.
call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name')
endif
" Make some adjustments to the loclists to fix common problems, and also " Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items. " to set default values for loclist items.
let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist) let l:linter_loclist = ale#engine#FixLocList(
\ a:buffer,
\ a:linter_name,
\ a:from_other_source,
\ a:loclist,
\)
" Remove previous items for this linter. " Remove previous items for this linter.
call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name') call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name')
@ -263,7 +272,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:loclist = [] let l:loclist = []
endtry endtry
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0)
endfunction endfunction
function! ale#engine#SetResults(buffer, loclist) abort function! ale#engine#SetResults(buffer, loclist) abort
@ -335,7 +344,7 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfor endfor
endfunction endfunction
function! ale#engine#FixLocList(buffer, linter_name, loclist) abort function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:bufnr_map = {} let l:bufnr_map = {}
let l:new_loclist = [] let l:new_loclist = []
@ -368,6 +377,10 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
\ 'linter_name': a:linter_name, \ 'linter_name': a:linter_name,
\} \}
if a:from_other_source
let l:item.from_other_source = 1
endif
if has_key(l:old_item, 'code') if has_key(l:old_item, 'code')
let l:item.code = l:old_item.code let l:item.code = l:old_item.code
endif endif
@ -691,6 +704,7 @@ endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove " Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled. " problems for linters which are no longer enabled.
" Problems from other sources will be kept.
let l:name_map = {} let l:name_map = {}
for l:linter in a:linters for l:linter in a:linters
@ -699,7 +713,7 @@ function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
call filter( call filter(
\ get(g:ale_buffer_info[a:buffer], 'loclist', []), \ get(g:ale_buffer_info[a:buffer], 'loclist', []),
\ 'get(l:name_map, get(v:val, ''linter_name''))', \ 'get(v:val, ''from_other_source'') || get(l:name_map, get(v:val, ''linter_name''))',
\) \)
endfunction endfunction

View file

@ -250,6 +250,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['c', 'cpp', 'cs', 'objc', 'objcpp', 'd', 'java', 'p', 'vala' ], \ 'suggested_filetypes': ['c', 'cpp', 'cs', 'objc', 'objcpp', 'd', 'java', 'p', 'vala' ],
\ 'description': 'Fix C, C++, C#, ObjectiveC, ObjectiveC++, D, Java, Pawn, and VALA files with uncrustify.', \ 'description': 'Fix C, C++, C#, ObjectiveC, ObjectiveC++, D, Java, Pawn, and VALA files with uncrustify.',
\ }, \ },
\ 'terraform': {
\ 'function': 'ale#fixers#terraform#Fix',
\ 'suggested_filetypes': ['hcl', 'terraform'],
\ 'description': 'Fix tf and hcl files with terraform fmt.',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.

View file

@ -1,13 +1,13 @@
" Author: butlerx <butlerx@notthe,cloud> " Author: butlerx <butlerx@notthe,cloud>
" Description: Integration of Google-java-format with ALE. " Description: Integration of Google-java-format with ALE.
call ale#Set('google_java_format_executable', 'google-java-format') call ale#Set('java_google_java_format_executable', 'google-java-format')
call ale#Set('google_java_format_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('java_google_java_format_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('google_java_format_options', '') call ale#Set('java_google_java_format_options', '')
function! ale#fixers#google_java_format#Fix(buffer) abort function! ale#fixers#google_java_format#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'google_java_format_options') let l:options = ale#Var(a:buffer, 'java_google_java_format_options')
let l:executable = ale#Var(a:buffer, 'google_java_format_executable') let l:executable = ale#Var(a:buffer, 'java_google_java_format_executable')
if !executable(l:executable) if !executable(l:executable)
return 0 return 0

View file

@ -1,5 +1,6 @@
call ale#Set('json_jq_executable', 'jq') call ale#Set('json_jq_executable', 'jq')
call ale#Set('json_jq_options', '') call ale#Set('json_jq_options', '')
call ale#Set('json_jq_filters', '.')
function! ale#fixers#jq#GetExecutable(buffer) abort function! ale#fixers#jq#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'json_jq_executable') return ale#Var(a:buffer, 'json_jq_executable')
@ -7,9 +8,15 @@ endfunction
function! ale#fixers#jq#Fix(buffer) abort function! ale#fixers#jq#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'json_jq_options') let l:options = ale#Var(a:buffer, 'json_jq_options')
let l:filters = ale#Var(a:buffer, 'json_jq_filters')
if empty(l:filters)
return 0
endif
return { return {
\ 'command': ale#Escape(ale#fixers#jq#GetExecutable(a:buffer)) \ 'command': ale#Escape(ale#fixers#jq#GetExecutable(a:buffer))
\ . ' . ' . l:options, \ . ' ' . l:filters . ' '
\ . l:options,
\} \}
endfunction endfunction

View file

@ -9,7 +9,7 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop') return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --auto-correct %t' \ . ' --auto-correct --force-exclusion %t'
endfunction endfunction
function! ale#fixers#rubocop#Fix(buffer) abort function! ale#fixers#rubocop#Fix(buffer) abort

View file

@ -0,0 +1,17 @@
" Author: dsifford <dereksifford@gmail.com>
" Description: Fixer for terraform and .hcl files
call ale#Set('terraform_fmt_executable', 'terraform')
call ale#Set('terraform_fmt_options', '')
function! ale#fixers#terraform#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'terraform_fmt_executable')
let l:options = ale#Var(a:buffer, 'terraform_fmt_options')
return {
\ 'command': ale#Escape(l:executable)
\ . ' fmt'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' -'
\}
endfunction

View file

@ -0,0 +1,13 @@
" Author: Matteo Centenaro (bugant) - https://github.com/bugant
"
" Description: find the root directory for an elixir project that uses mix
function! ale#handlers#elixir#FindMixProjectRoot(buffer) abort
let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
if !empty(l:mix_file)
return fnamemodify(l:mix_file, ':p:h')
endif
return '.'
endfunction

View file

@ -1,5 +1,15 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Error handling for the format GHC outputs. " Description: Error handling for the format GHC outputs.
"
function! ale#handlers#haskell#GetStackExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'stack.yaml') isnot# ''
return 'stack'
endif
" if there is no stack.yaml file, we don't use stack even if it exists,
" so we return '', because executable('') apparently always fails
return ''
endfunction
" Remember the directory used for temporary files for Vim. " Remember the directory used for temporary files for Vim.
let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h') let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')

View file

@ -7,6 +7,10 @@ if !exists('g:ale_rust_ignore_error_codes')
let g:ale_rust_ignore_error_codes = [] let g:ale_rust_ignore_error_codes = []
endif endif
if !exists('g:ale_rust_ignore_secondary_spans')
let g:ale_rust_ignore_secondary_spans = 0
endif
function! s:FindSpan(buffer, span) abort function! s:FindSpan(buffer, span) abort
if ale#path#IsBufferPath(a:buffer, a:span.file_name) || a:span.file_name is# '<anon>' if ale#path#IsBufferPath(a:buffer, a:span.file_name) || a:span.file_name is# '<anon>'
return a:span return a:span
@ -47,6 +51,10 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
for l:root_span in l:error.spans for l:root_span in l:error.spans
let l:span = s:FindSpan(a:buffer, l:root_span) let l:span = s:FindSpan(a:buffer, l:root_span)
if ale#Var(a:buffer, 'rust_ignore_secondary_spans') && !get(l:span, 'is_primary', 1)
continue
endif
if !empty(l:span) if !empty(l:span)
call add(l:output, { call add(l:output, {
\ 'lnum': l:span.line_start, \ 'lnum': l:span.line_start,

View file

@ -35,6 +35,7 @@ let s:default_ale_linters = {
\ 'hack': ['hack'], \ 'hack': ['hack'],
\ 'help': [], \ 'help': [],
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'], \ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'], \ 'rust': ['cargo'],
\ 'spec': [], \ 'spec': [],
@ -255,6 +256,24 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'initialization_options') elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options let l:obj.initialization_options = a:linter.initialization_options
endif endif
if has_key(a:linter, 'lsp_config_callback')
if has_key(a:linter, 'lsp_config')
throw 'Only one of `lsp_config` or `lsp_config_callback` should be set'
endif
let l:obj.lsp_config_callback = a:linter.lsp_config_callback
if !s:IsCallback(l:obj.lsp_config_callback)
throw '`lsp_config_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'lsp_config')
if type(a:linter.lsp_config) isnot v:t_dict
throw '`lsp_config` must be a Dictionary'
endif
let l:obj.lsp_config = a:linter.lsp_config
endif
endif endif
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout') let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
@ -337,8 +356,9 @@ endfunction
function! s:GetAliasedFiletype(original_filetype) abort function! s:GetAliasedFiletype(original_filetype) abort
let l:buffer_aliases = get(b:, 'ale_linter_aliases', {}) let l:buffer_aliases = get(b:, 'ale_linter_aliases', {})
" b:ale_linter_aliases can be set to a List. " b:ale_linter_aliases can be set to a List or String.
if type(l:buffer_aliases) is v:t_list if type(l:buffer_aliases) is v:t_list
\|| type(l:buffer_aliases) is v:t_string
return l:buffer_aliases return l:buffer_aliases
endif endif

View file

@ -19,6 +19,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
" initialized: 0 if the connection is ready, 1 otherwise. " initialized: 0 if the connection is ready, 1 otherwise.
" init_request_id: The ID for the init request. " init_request_id: The ID for the init request.
" init_options: Options to send to the server. " init_options: Options to send to the server.
" config: Configuration settings to send to the server.
" callback_list: A list of callbacks for handling LSP responses. " callback_list: A list of callbacks for handling LSP responses.
" message_queue: Messages queued for sending to callbacks. " message_queue: Messages queued for sending to callbacks.
" capabilities_queue: The list of callbacks to call with capabilities. " capabilities_queue: The list of callbacks to call with capabilities.
@ -32,6 +33,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
\ 'initialized': 0, \ 'initialized': 0,
\ 'init_request_id': 0, \ 'init_request_id': 0,
\ 'init_options': a:init_options, \ 'init_options': a:init_options,
\ 'config': {},
\ 'callback_list': [], \ 'callback_list': [],
\ 'message_queue': [], \ 'message_queue': [],
\ 'capabilities_queue': [], \ 'capabilities_queue': [],
@ -41,6 +43,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
\ 'completion': 0, \ 'completion': 0,
\ 'completion_trigger_characters': [], \ 'completion_trigger_characters': [],
\ 'definition': 0, \ 'definition': 0,
\ 'symbol_search': 0,
\ }, \ },
\} \}
endif endif
@ -203,8 +206,31 @@ function! s:UpdateCapabilities(conn, capabilities) abort
if get(a:capabilities, 'definitionProvider') is v:true if get(a:capabilities, 'definitionProvider') is v:true
let a:conn.capabilities.definition = 1 let a:conn.capabilities.definition = 1
endif endif
if get(a:capabilities, 'workspaceSymbolProvider') is v:true
let a:conn.capabilities.symbol_search = 1
endif
endfunction endfunction
" Update a connection's configuration dictionary and notify LSP servers
" of any changes since the last update. Returns 1 if a configuration
" update was sent; otherwise 0 will be returned.
function! ale#lsp#UpdateConfig(conn_id, buffer, config) abort
let l:conn = get(s:connections, a:conn_id, {})
if empty(l:conn) || a:config ==# l:conn.config " no-custom-checks
return 0
endif
let l:conn.config = a:config
let l:message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:config)
call ale#lsp#Send(a:conn_id, l:message)
return 1
endfunction
function! ale#lsp#HandleInitResponse(conn, response) abort function! ale#lsp#HandleInitResponse(conn, response) abort
if get(a:response, 'method', '') is# 'initialize' if get(a:response, 'method', '') is# 'initialize'
let a:conn.initialized = 1 let a:conn.initialized = 1
@ -285,6 +311,7 @@ function! ale#lsp#MarkConnectionAsTsserver(conn_id) abort
let l:conn.capabilities.completion = 1 let l:conn.capabilities.completion = 1
let l:conn.capabilities.completion_trigger_characters = ['.'] let l:conn.capabilities.completion_trigger_characters = ['.']
let l:conn.capabilities.definition = 1 let l:conn.capabilities.definition = 1
let l:conn.capabilities.symbol_search = 1
endfunction endfunction
" Start a program for LSP servers. " Start a program for LSP servers.

View file

@ -130,6 +130,12 @@ function! ale#lsp#message#References(buffer, line, column) abort
\}] \}]
endfunction endfunction
function! ale#lsp#message#Symbol(query) abort
return [0, 'workspace/symbol', {
\ 'query': a:query,
\}]
endfunction
function! ale#lsp#message#Hover(buffer, line, column) abort function! ale#lsp#message#Hover(buffer, line, column) abort
return [0, 'textDocument/hover', { return [0, 'textDocument/hover', {
\ 'textDocument': { \ 'textDocument': {
@ -138,3 +144,9 @@ function! ale#lsp#message#Hover(buffer, line, column) abort
\ 'position': {'line': a:line - 1, 'character': a:column}, \ 'position': {'line': a:line - 1, 'character': a:column},
\}] \}]
endfunction endfunction
function! ale#lsp#message#DidChangeConfiguration(buffer, config) abort
return [0, 'workspace/didChangeConfiguration', {
\ 'settings': a:config,
\}]
endfunction

View file

@ -17,7 +17,7 @@ function! ale#lsp#reset#StopAllLSPs() abort
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype')) for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call ale#engine#HandleLoclist(l:linter.name, l:buffer, []) call ale#engine#HandleLoclist(l:linter.name, l:buffer, [], 0)
endif endif
endfor endfor
endfor endfor

View file

@ -38,7 +38,7 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response) let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist) call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
@ -81,7 +81,7 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:loclist = get(l:info, 'semantic_loclist', []) let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', []) \ + get(l:info, 'syntax_loclist', [])
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist) call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort function! s:HandleLSPErrorMessage(linter_name, response) abort
@ -140,6 +140,18 @@ function! ale#lsp_linter#GetOptions(buffer, linter) abort
return l:initialization_options return l:initialization_options
endfunction endfunction
function! ale#lsp_linter#GetConfig(buffer, linter) abort
let l:config = {}
if has_key(a:linter, 'lsp_config_callback')
let l:config = ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
elseif has_key(a:linter, 'lsp_config')
let l:config = a:linter.lsp_config
endif
return l:config
endfunction
" Given a buffer, an LSP linter, start up an LSP linter and get ready to " Given a buffer, an LSP linter, start up an LSP linter and get ready to
" receive messages for the document. " receive messages for the document.
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter) abort
@ -188,6 +200,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id) call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif endif
let l:config = ale#lsp_linter#GetConfig(a:buffer, a:linter)
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer) let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
let l:details = { let l:details = {
@ -198,6 +211,8 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
\ 'language_id': l:language_id, \ 'language_id': l:language_id,
\} \}
call ale#lsp#UpdateConfig(l:conn_id, a:buffer, l:config)
if ale#lsp#OpenDocument(l:conn_id, a:buffer, l:language_id) if ale#lsp#OpenDocument(l:conn_id, a:buffer, l:language_id)
if g:ale_history_enabled && !empty(l:command) if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command) call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)

View file

@ -0,0 +1,21 @@
" Tell ALE that another source has started checking a buffer.
function! ale#other_source#StartChecking(buffer, linter_name) abort
call ale#engine#InitBufferInfo(a:buffer)
let l:list = g:ale_buffer_info[a:buffer].active_other_sources_list
call add(l:list, a:linter_name)
call uniq(sort(l:list))
endfunction
" Show some results, and stop checking a buffer.
" To clear results or cancel checking a buffer, an empty List can be given.
function! ale#other_source#ShowResults(buffer, linter_name, loclist) abort
call ale#engine#InitBufferInfo(a:buffer)
let l:info = g:ale_buffer_info[a:buffer]
" Remove this linter name from the active list.
let l:list = l:info.active_other_sources_list
call filter(l:list, 'v:val isnot# a:linter_name')
call ale#engine#HandleLoclist(a:linter_name, a:buffer, a:loclist, 1)
endfunction

View file

@ -65,7 +65,11 @@ endfunction
" Output 'cd <directory> && ' " Output 'cd <directory> && '
" This function can be used changing the directory for a linter command. " This function can be used changing the directory for a linter command.
function! ale#path#CdString(directory) abort function! ale#path#CdString(directory) abort
return 'cd ' . ale#Escape(a:directory) . ' && ' if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && '
else
return 'cd ' . ale#Escape(a:directory) . ' && '
endif
endfunction endfunction
" Output 'cd <buffer_filename_directory> && ' " Output 'cd <buffer_filename_directory> && '

View file

@ -46,11 +46,14 @@ function! ale#preview#ShowSelection(item_list) abort
" Create lines to display to users. " Create lines to display to users.
for l:item in a:item_list for l:item in a:item_list
let l:match = get(l:item, 'match', '')
call add( call add(
\ l:lines, \ l:lines,
\ l:item.filename \ l:item.filename
\ . ':' . l:item.line \ . ':' . l:item.line
\ . ':' . l:item.column, \ . ':' . l:item.column
\ . (!empty(l:match) ? ' ' . l:match : ''),
\) \)
endfor endfor

View file

@ -0,0 +1,109 @@
let s:symbol_map = {}
" Used to get the symbol map in tests.
function! ale#symbol#GetMap() abort
return deepcopy(s:symbol_map)
endfunction
" Used to set the symbol map in tests.
function! ale#symbol#SetMap(map) abort
let s:symbol_map = a:map
endfunction
function! ale#symbol#ClearLSPData() abort
let s:symbol_map = {}
endfunction
function! ale#symbol#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:symbol_map, a:response.id)
let l:options = remove(s:symbol_map, a:response.id)
let l:result = get(a:response, 'result', v:null)
let l:item_list = []
if type(l:result) is v:t_list
" Each item looks like this:
" {
" 'name': 'foo',
" 'kind': 123,
" 'deprecated': v:false,
" 'location': {
" 'uri': 'file://...',
" 'range': {
" 'start': {'line': 0, 'character': 0},
" 'end': {'line': 0, 'character': 0},
" },
" },
" 'containerName': 'SomeContainer',
" }
for l:response_item in l:result
let l:location = l:response_item.location
call add(l:item_list, {
\ 'filename': ale#path#FromURI(l:location.uri),
\ 'line': l:location.range.start.line + 1,
\ 'column': l:location.range.start.character + 1,
\ 'match': l:response_item.name,
\})
endfor
endif
if empty(l:item_list)
call ale#util#Execute('echom ''No symbols found.''')
else
call ale#preview#ShowSelection(l:item_list)
endif
endif
endfunction
function! s:OnReady(linter, lsp_details, query, ...) abort
let l:buffer = a:lsp_details.buffer
" If we already made a request, stop here.
if getbufvar(l:buffer, 'ale_symbol_request_made', 0)
return
endif
let l:id = a:lsp_details.connection_id
let l:Callback = function('ale#symbol#HandleLSPResponse')
call ale#lsp#RegisterCallback(l:id, l:Callback)
let l:message = ale#lsp#message#Symbol(a:query)
let l:request_id = ale#lsp#Send(l:id, l:message)
call setbufvar(l:buffer, 'ale_symbol_request_made', 1)
let s:symbol_map[l:request_id] = {
\ 'buffer': l:buffer,
\}
endfunction
function! s:Search(linter, buffer, query) abort
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter)
if !empty(l:lsp_details)
call ale#lsp#WaitForCapability(
\ l:lsp_details.connection_id,
\ 'symbol_search',
\ function('s:OnReady', [a:linter, l:lsp_details, a:query]),
\)
endif
endfunction
function! ale#symbol#Search(query) abort
if type(a:query) isnot v:t_string || empty(a:query)
throw 'A non-empty string must be provided!'
endif
let l:buffer = bufnr('')
" Set a flag so we only make one request.
call setbufvar(l:buffer, 'ale_symbol_request_made', 0)
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp) && l:linter.lsp isnot# 'tsserver'
call s:Search(l:linter, l:buffer, a:query)
endif
endfor
endfunction

View file

@ -0,0 +1,16 @@
===============================================================================
ALE Ansible Integration *ale-ansible-options*
===============================================================================
ansible-lint *ale-ansible-ansible-lint*
g:ale_ansible_ansible_lint_executable *g:ale_ansible_ansible_lint_executable*
*b:ale_ansible_ansible_lint_executable*
Type: |String|
Default: `'ansible-lint'`
This variable can be changed to modify the executable used for ansible-lint.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -130,7 +130,7 @@ overrides |g:ale_c_build_dir_names|.
g:ale_c_clangtidy_checks *g:ale_c_clangtidy_checks* g:ale_c_clangtidy_checks *g:ale_c_clangtidy_checks*
*b:ale_c_clangtidy_checks* *b:ale_c_clangtidy_checks*
Type: |List| Type: |List|
Default: `['*']` Default: `[]`
The checks to enable for clang-tidy with the `-checks` argument. The checks to enable for clang-tidy with the `-checks` argument.

View file

@ -103,7 +103,7 @@ overrides |g:ale_c_build_dir_names|.
g:ale_cpp_clangtidy_checks *g:ale_cpp_clangtidy_checks* g:ale_cpp_clangtidy_checks *g:ale_cpp_clangtidy_checks*
*b:ale_cpp_clangtidy_checks* *b:ale_cpp_clangtidy_checks*
Type: |List| Type: |List|
Default: `['*']` Default: `[]`
The checks to enable for clang-tidy with the `-checks` argument. The checks to enable for clang-tidy with the `-checks` argument.

View file

@ -2,6 +2,10 @@
ALE C# Integration *ale-cs-options* ALE C# Integration *ale-cs-options*
In addition to the linters that are provided with ALE, C# code can be checked
with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim
=============================================================================== ===============================================================================
mcs *ale-cs-mcs* mcs *ale-cs-mcs*

View file

@ -2,6 +2,17 @@
ALE D Integration *ale-d-options* ALE D Integration *ale-d-options*
===============================================================================
dls *ale-d-dls*
g:ale_d_dls_executable *g:ale_d_dls_executable*
*b:ale_d_dls_executable*
Type: |String|
Default: `dls`
See |ale-integrations-local-executables|
=============================================================================== ===============================================================================
uncrustify *ale-d-uncrustify* uncrustify *ale-d-uncrustify*

View file

@ -306,6 +306,7 @@ given the above setup are as follows.
`AssertLinterNotExecuted` - Check that linters will not be executed. `AssertLinterNotExecuted` - Check that linters will not be executed.
`AssertLSPLanguage language` - Check the language given to an LSP server. `AssertLSPLanguage language` - Check the language given to an LSP server.
`AssertLSPOptions options_dict` - Check the options given to an LSP server. `AssertLSPOptions options_dict` - Check the options given to an LSP server.
`AssertLSPConfig config_dict` - Check the config given to an LSP server.
`AssertLSPProject project_root` - Check the root given to an LSP server. `AssertLSPProject project_root` - Check the root given to an LSP server.
`AssertLSPAddress address` - Check the address to an LSP server. `AssertLSPAddress address` - Check the address to an LSP server.

View file

@ -2,6 +2,29 @@
ALE Dockerfile Integration *ale-dockerfile-options* ALE Dockerfile Integration *ale-dockerfile-options*
===============================================================================
dockerfile_lint *ale-dockerfile-dockerfile_lint*
g:ale_dockerfile_dockerfile_lint_executable
*g:ale_dockerfile_dockerfile_lint_executable*
*b:ale_dockerfile_dockerfile_lint_executable*
Type: |String|
Default: `'dockerfile_lint'`
This variable can be changed to specify the executable used to run
dockerfile_lint.
g:ale_dockerfile_dockerfile_lint_options
*g:ale_dockerfile_dockerfile_lint_options*
*b:ale_dockerfile_dockerfile_lint_options*
Type: |String|
Default: `''`
This variable can be changed to add additional command-line arguments to
the dockerfile lint invocation - like custom rule file definitions.
=============================================================================== ===============================================================================
hadolint *ale-dockerfile-hadolint* hadolint *ale-dockerfile-hadolint*

View file

@ -40,5 +40,18 @@ configured on your project's `mix.exs`.
See https://github.com/jeremyjh/dialyxir#with-explaining-stuff for more See https://github.com/jeremyjh/dialyxir#with-explaining-stuff for more
information. information.
===============================================================================
elixir-ls *ale-elixir-elixir-ls*
Elixir Language Server (https://github.com/JakeBecker/elixir-ls)
g:ale_elixir_elixir_ls_release *g:ale_elixir_elixir_ls_release*
*b:ale_elixir_elixir_ls_release*
Type: |String|
Default: `'elixir-ls'`
Location of the elixir-ls release directory. This directory must contain
the language server scripts (language_server.sh and language_server.bat).
=============================================================================== ===============================================================================
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

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

View file

@ -73,6 +73,13 @@ g:ale_json_jq_options *g:ale_json_jq_options*
This option can be changed to pass extra options to `jq`. This option can be changed to pass extra options to `jq`.
g:ale_json_jq_filters *g:ale_json_jq_filters*
*b:ale_json_jq_filters*
Type: |String|
Default: `'.'`
This option can be changed to pass custom filters to `jq`.
=============================================================================== ===============================================================================
prettier *ale-json-prettier* prettier *ale-json-prettier*

View file

@ -0,0 +1,43 @@
===============================================================================
ALE Perl6 Integration *ale-perl6-options*
Checking code with `perl6` is disabled by default, as `perl6` code cannot be
checked without executing it. Specifically, we use the `-c` flag to see if
`perl6` code compiles. This does not execute all of the code in a file, but it
does run `BEGIN` and `CHECK` blocks. See `perl6 --help`
Full support requires a perl6 implementation that supports the
PERL6_EXCEPTIONS_HANDLER environment variable and JSON error output,
which was specified in 6.d. Rakudo version 2018.08 is the first rakudo release
that supports this. See `perl6 --version` and
https://docs.perl6.org/programs/03-environment-variables.
Without this variable, errors and warnings will appear at line 1, and can be
viewed with ALEDetail. This also serves as a fallback for errors and warnings
that do not trigger JSON output.
See |g:ale_linters|.
===============================================================================
perl6 *ale-perl6-perl6*
g:ale_perl6_perl6_executable *g:ale_perl6_perl6_executable*
*b:ale_perl6_perl6_executable*
Type: |String|
Default: `'perl6'`
This variable can be changed to modify the executable used for linting
perl6.
g:ale_perl6_perl6_options *g:ale_perl6_perl6_options*
*b:ale_perl6_perl6_options*
Type: |String|
Default: `'-c -Ilib'`
This variable can be changed to alter the command-line arguments to the
perl6 invocation.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -0,0 +1,56 @@
===============================================================================
ALE Prolog Integration *ale-prolog-options*
===============================================================================
swipl *ale-prolog-swipl*
g:ale_prolog_swipl_executable *g:ale_prolog_swipl_executable*
*b:ale_prolog_swipl_executable*
Type: |String|
Default: `'swipl'`
The executable that will be run for the `swipl` linter.
g:ale_prolog_swipl_load *g:ale_prolog_swipl_load*
*b:ale_prolog_swipl_load*
Type: |String|
Default: `'current_prolog_flag(argv, [File]), load_files(File, [sandboxed(true)]), halt.'`
The prolog goals that will be passed to |g:ale_prolog_swipl_executable| with `-g` option.
It does:
1. Takes the first command argument (current file path)
2. Checks (syntactic / semantic) problems and output to stderr
NOTE: `sandboxed(true)` prohibits executing some directives such as 'initialization main'.
g:ale_prolog_swipl_timeout *g:ale_prolog_swipl_timeout*
*b:ale_prolog_swipl_timeout*
Type: |Number|
Default: `3`
Timeout seconds to detect long-running linter.
It is done by setting SIGALRM.
See |g:ale_prolog_swipl_alarm| and |g:ale_prolog_swipl_alarm_handler|.
g:ale_prolog_swipl_alarm *g:ale_prolog_swipl_alarm*
*b:ale_prolog_swipl_alarm*
Type: |String|
Default: `'alarm(%t, (%h), _, [])'`
The prolog goals to be expected to set SIGALRM.
`%t` is replaced by |g:ale_prolog_swipl_timeout|.
`%h` is replaced by |g:ale_prolog_swipl_alarm_handler|.
g:ale_prolog_swipl_alarm_handler *g:ale_prolog_swipl_alarm_handler*
*b:ale_prolog_swipl_alarm_handler*
Type: |String|
Default: `'writeln(user_error, "ERROR: Exceeded %t seconds, Please change g:prolog_swipl_timeout to modify the limit."), halt(1)'`
The prolog goals to be expected that will be run on SIGALRM.
`%t` is replaced by |g:ale_prolog_swipl_timeout|.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -109,6 +109,7 @@ g:ale_rust_cargo_include_features *g:ale_rust_cargo_include_features*
When defined, ALE will set the `--features` option when invoking `cargo` to When defined, ALE will set the `--features` option when invoking `cargo` to
perform the lint check. See |g:ale_rust_cargo_default_feature_behavior|. perform the lint check. See |g:ale_rust_cargo_default_feature_behavior|.
g:ale_rust_cargo_avoid_whole_workspace *g:ale_rust_cargo_avoid_whole_workspace* g:ale_rust_cargo_avoid_whole_workspace *g:ale_rust_cargo_avoid_whole_workspace*
*b:ale_rust_cargo_avoid_whole_workspace* *b:ale_rust_cargo_avoid_whole_workspace*
Type: |Number| Type: |Number|
@ -119,6 +120,36 @@ g:ale_rust_cargo_avoid_whole_workspace *g:ale_rust_cargo_avoid_whole_workspace*
in the crate's directory. Otherwise, behave as usual. in the crate's directory. Otherwise, behave as usual.
g:ale_rust_cargo_use_clippy
*g:ale_rust_cargo_use_clippy*
*b:ale_rust_cargo_use_clippy*
Type: |Number|
Default: `0`
When set to 1, `cargo clippy` will be used instead of `cargo check` or
`cargo build` as linter.
For details of `cargo clippy`, please visit the following link:
https://github.com/rust-lang-nursery/rust-clippy
Since `cargo clippy` is optional toolchain, it's safer to check whether
`cargo-clippy` is executable as follows:
>
let g:ale_rust_cargo_use_clippy = executable('cargo-clippy')
<
g:ale_rust_cargo_clippy_options
*g:ale_rust_cargo_clippy_options*
*b:ale_rust_cargo_clippy_options*
Type: |String|
Default: `''`
When `cargo clippy` is used, this value will be added to a command line to run
it. This variable is useful when you want to add some extra options which
only `cargo clippy` supports (e.g. `--deny`).
=============================================================================== ===============================================================================
rls *ale-rust-rls* rls *ale-rust-rls*
@ -167,6 +198,22 @@ g:ale_rust_ignore_error_codes *g:ale_rust_ignore_error_codes*
> >
let g:ale_rust_ignore_error_codes = ['E0432', 'E0433'] let g:ale_rust_ignore_error_codes = ['E0432', 'E0433']
g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
*b:ale_rust_ignore_secondary_spans*
Type: Number
Default: 0
When set to 1, instructs the Rust error repporting to ignore secondary
spans. The problem with secondary spans is that they sometimes appear in
error messages before the main cause of the error, for example: >
1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5
parameters were supplied: defined here
2 src/main.rs|430 col 32 error| this function takes 4 parameters but 5
parameters were supplied: expected 4 parameters
<
This is due to the sorting by line numbers. With this option set to 1,
the 'defined here' span will not be presented.
=============================================================================== ===============================================================================
rustfmt *ale-rust-rustfmt* rustfmt *ale-rust-rustfmt*

View file

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

View file

@ -9,15 +9,20 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction| 1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support| 2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint| 3. Linting..............................|ale-lint|
3.1 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix| 4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp| 5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion| 5.1 Completion........................|ale-completion|
5.2 Go To Definition..................|ale-go-to-definition| 5.2 Go To Definition..................|ale-go-to-definition|
5.3 Find References...................|ale-find-references| 5.3 Find References...................|ale-find-references|
5.4 Hovering..........................|ale-hover|
5.5 Symbol Search.....................|ale-symbol-search|
6. Global Options.......................|ale-options| 6. Global Options.......................|ale-options|
6.1 Highlights........................|ale-highlights| 6.1 Highlights........................|ale-highlights|
6.2 Options for write-good Linter.....|ale-write-good-options| 6.2 Options for write-good Linter.....|ale-write-good-options|
7. Integration Documentation............|ale-integrations| 7. Integration Documentation............|ale-integrations|
ansible...............................|ale-ansible-options|
ansible-lint........................|ale-ansible-ansible-lint|
asciidoc..............................|ale-asciidoc-options| asciidoc..............................|ale-asciidoc-options|
write-good..........................|ale-asciidoc-write-good| write-good..........................|ale-asciidoc-write-good|
asm...................................|ale-asm-options| asm...................................|ale-asm-options|
@ -67,16 +72,19 @@ CONTENTS *ale-contents*
cuda..................................|ale-cuda-options| cuda..................................|ale-cuda-options|
nvcc................................|ale-cuda-nvcc| nvcc................................|ale-cuda-nvcc|
d.....................................|ale-d-options| d.....................................|ale-d-options|
dls.................................|ale-d-dls|
uncrustify..........................|ale-d-uncrustify| uncrustify..........................|ale-d-uncrustify|
dart..................................|ale-dart-options| dart..................................|ale-dart-options|
dartanalyzer........................|ale-dart-dartanalyzer| dartanalyzer........................|ale-dart-dartanalyzer|
dartfmt.............................|ale-dart-dartfmt| dartfmt.............................|ale-dart-dartfmt|
dockerfile............................|ale-dockerfile-options| dockerfile............................|ale-dockerfile-options|
dockerfile_lint.....................|ale-dockerfile-dockerfile_lint|
hadolint............................|ale-dockerfile-hadolint| hadolint............................|ale-dockerfile-hadolint|
elixir................................|ale-elixir-options| elixir................................|ale-elixir-options|
mix.................................|ale-elixir-mix| mix.................................|ale-elixir-mix|
mix_format..........................|ale-elixir-mix-format| mix_format..........................|ale-elixir-mix-format|
dialyxir............................|ale-elixir-dialyxir| dialyxir............................|ale-elixir-dialyxir|
elixir-ls...........................|ale-elixir-elixir-ls|
elm...................................|ale-elm-options| elm...................................|ale-elm-options|
elm-format..........................|ale-elm-elm-format| elm-format..........................|ale-elm-elm-format|
elm-make............................|ale-elm-elm-make| elm-make............................|ale-elm-elm-make|
@ -125,6 +133,8 @@ CONTENTS *ale-contents*
stack-build.........................|ale-haskell-stack-build| stack-build.........................|ale-haskell-stack-build|
stylish-haskell.....................|ale-haskell-stylish-haskell| stylish-haskell.....................|ale-haskell-stylish-haskell|
hie.................................|ale-haskell-hie| hie.................................|ale-haskell-hie|
hcl...................................|ale-hcl-options|
terraform-fmt.......................|ale-hcl-terraform-fmt|
html..................................|ale-html-options| html..................................|ale-html-options|
htmlhint............................|ale-html-htmlhint| htmlhint............................|ale-html-htmlhint|
tidy................................|ale-html-tidy| tidy................................|ale-html-tidy|
@ -203,6 +213,8 @@ CONTENTS *ale-contents*
perl................................|ale-perl-perl| perl................................|ale-perl-perl|
perlcritic..........................|ale-perl-perlcritic| perlcritic..........................|ale-perl-perlcritic|
perltidy............................|ale-perl-perltidy| perltidy............................|ale-perl-perltidy|
perl6.................................|ale-perl6-options|
perl6...............................|ale-perl6-perl6|
php...................................|ale-php-options| php...................................|ale-php-options|
langserver..........................|ale-php-langserver| langserver..........................|ale-php-langserver|
phan................................|ale-php-phan| phan................................|ale-php-phan|
@ -218,6 +230,8 @@ CONTENTS *ale-contents*
write-good..........................|ale-pod-write-good| write-good..........................|ale-pod-write-good|
pony..................................|ale-pony-options| pony..................................|ale-pony-options|
ponyc...............................|ale-pony-ponyc| ponyc...............................|ale-pony-ponyc|
prolog................................|ale-prolog-options|
swipl...............................|ale-prolog-swipl|
proto.................................|ale-proto-options| proto.................................|ale-proto-options|
protoc-gen-lint.....................|ale-proto-protoc-gen-lint| protoc-gen-lint.....................|ale-proto-protoc-gen-lint|
pug...................................|ale-pug-options| pug...................................|ale-pug-options|
@ -293,6 +307,7 @@ CONTENTS *ale-contents*
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|
tflint..............................|ale-terraform-tflint| tflint..............................|ale-terraform-tflint|
tex...................................|ale-tex-options| tex...................................|ale-tex-options|
chktex..............................|ale-tex-chktex| chktex..............................|ale-tex-chktex|
@ -393,11 +408,11 @@ Notes:
* CSS: `csslint`, `prettier`, `stylelint` * CSS: `csslint`, `prettier`, `stylelint`
* Cucumber: `cucumber` * Cucumber: `cucumber`
* Cython (pyrex filetype): `cython` * Cython (pyrex filetype): `cython`
* D: `dmd`, `uncrustify` * D: `dls`, `dmd`, `uncrustify`
* Dafny: `dafny`!! * Dafny: `dafny`!!
* Dart: `dartanalyzer`!!, `language_server`, dartfmt!! * Dart: `dartanalyzer`!!, `language_server`, dartfmt!!
* Dockerfile: `hadolint` * Dockerfile: `dockerfile_lint`, `hadolint`
* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!! * Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!, `elixir-ls`
* Elm: `elm-format, elm-make` * Elm: `elm-format, elm-make`
* Erb: `erb`, `erubi`, `erubis` * Erb: `erb`, `erubi`, `erubis`
* Erlang: `erlc`, `SyntaxErl` * Erlang: `erlc`, `SyntaxErl`
@ -413,6 +428,7 @@ Notes:
* Haml: `haml-lint` * Haml: `haml-lint`
* Handlebars: `ember-template-lint` * Handlebars: `ember-template-lint`
* Haskell: `brittany`, `ghc`, `cabal-ghc`, `stylish-haskell`, `stack-ghc`, `stack-build`!!, `ghc-mod`, `hlint`, `hdevtools`, `hfmt`, `hie` * Haskell: `brittany`, `ghc`, `cabal-ghc`, `stylish-haskell`, `stack-ghc`, `stack-build`!!, `ghc-mod`, `hlint`, `hdevtools`, `hfmt`, `hie`
* HCL: `terraform-fmt`
* HTML: `alex`!!, `HTMLHint`, `proselint`, `tidy`, `write-good` * HTML: `alex`!!, `HTMLHint`, `proselint`, `tidy`, `write-good`
* Idris: `idris` * Idris: `idris`
* Java: `checkstyle`, `javac`, `google-java-format`, `PMD`, `javalsp`, `uncrustify` * Java: `checkstyle`, `javac`, `google-java-format`, `PMD`, `javalsp`, `uncrustify`
@ -438,10 +454,12 @@ Notes:
* OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`, `ocamlformat` * OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`, `ocamlformat`
* Pawn: `uncrustify` * Pawn: `uncrustify`
* Perl: `perl -c`, `perl-critic`, `perltidy` * Perl: `perl -c`, `perl-critic`, `perltidy`
* Perl6: `perl6 -c`
* PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`, `psalm`!! * PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`, `psalm`!!
* PO: `alex`!!, `msgfmt`, `proselint`, `write-good` * PO: `alex`!!, `msgfmt`, `proselint`, `write-good`
* Pod: `alex`!!, `proselint`, `write-good` * Pod: `alex`!!, `proselint`, `write-good`
* Pony: `ponyc` * Pony: `ponyc`
* Prolog: `swipl`
* proto: `protoc-gen-lint` * proto: `protoc-gen-lint`
* Pug: `pug-lint` * Pug: `pug-lint`
* Puppet: `languageserver`, `puppet`, `puppet-lint` * Puppet: `languageserver`, `puppet`, `puppet-lint`
@ -464,7 +482,7 @@ Notes:
* SQL: `sqlint`, `sqlfmt` * SQL: `sqlint`, `sqlfmt`
* Swift: `swiftlint`, `swiftformat` * Swift: `swiftlint`, `swiftformat`
* Tcl: `nagelfar`!! * Tcl: `nagelfar`!!
* Terraform: `tflint` * Terraform: `fmt`, `tflint`
* Texinfo: `alex`!!, `proselint`, `write-good` * Texinfo: `alex`!!, `proselint`, `write-good`
* Text^: `alex`!!, `proselint`, `redpen`, `textlint`, `vale`, `write-good` * Text^: `alex`!!, `proselint`, `redpen`, `textlint`, `vale`, `write-good`
* Thrift: `thrift` * Thrift: `thrift`
@ -559,6 +577,68 @@ ALE offers several options for controlling which linters are run.
* Only running linters you asked for. - |g:ale_linters_explicit| * Only running linters you asked for. - |g:ale_linters_explicit|
-------------------------------------------------------------------------------
3.1 Other Sources *ale-lint-other-sources*
Problems for a buffer can be taken from other sources and rendered by ALE.
This allows ALE to be used in combination with other plugins which also want
to display any problems they might find with a buffer. ALE's API includes the
following components for making this possible.
* |ale#other_source#StartChecking()| - Tell ALE that a buffer is being checked.
* |ale#other_source#ShowResults()| - Show results from another source.
* |ALEWantResults| - A signal for when ALE wants results.
Other resources can provide results for ALE to display at any time, following
ALE's loclist format. (See |ale-loclist-format|) For example: >
" Tell ALE to show some results.
" This function can be called at any time.
call ale#other_source#ShowResults(bufnr(''), 'some-linter-name', [
\ {'text': 'Something went wrong', 'lnum': 13},
\])
<
Other sources should use a unique name for identifying themselves. A single
linter name can be used for all problems from another source, or a series of
unique linter names can be used. Results can be cleared for that source by
providing an empty List.
|ale#other_source#StartChecking()| should be called whenever another source
starts checking a buffer, so other tools can know that a buffer is being
checked by some plugin. The |ALEWantResults| autocmd event can be used to
start checking a buffer for problems every time that ALE does. When
|ALEWantResults| is signaled, |g:ale_want_results_buffer| will be set to the
number of the buffer that ALE wants to check.
|ale#other_source#StartChecking()| should be called synchronously, and other
sources should perform their checks on a buffer in the background
asynchronously, so they don't interrupt editing.
A plugin might integrate its own checks with ALE like so: >
augroup SomeGroupName
autocmd!
autocmd User ALEWantResults call Hook(g:ale_want_results_buffer)
augroup END
function! DoBackgroundWork(buffer) abort
" Start some work in the background here.
" ...
" Then call WorkDone(a:buffer, results)
endfunction
function! Hook(buffer) abort
" Tell ALE we're going to check this buffer.
call ale#other_source#StartChecking(a:buffer, 'some-name')
call DoBackgroundWork(a:buffer)
endfunction
function! WorkDone(buffer, results) abort
" Send results to ALE after they have been collected.
call ale#other_source#ShowResults(buffer, 'some-name', a:results)
endfunction
<
=============================================================================== ===============================================================================
4. Fixing Problems *ale-fix* 4. Fixing Problems *ale-fix*
@ -709,10 +789,11 @@ Completion is only supported while at least one LSP linter is enabled. ALE
will only suggest symbols provided by the LSP servers. will only suggest symbols provided by the LSP servers.
Suggestions will be made while you type after completion is enabled. Suggestions will be made while you type after completion is enabled.
Completion can be enabled by setting |g:ale_completion_enabled| to `1`. The Completion can be enabled by setting |g:ale_completion_enabled| to `1`. This
delay for completion can be configured with |g:ale_completion_delay|. ALE will setting must be set to `1` before ALE is loaded. The delay for completion can
only suggest so many possible matches for completion. The maximum number of be configured with |g:ale_completion_delay|. ALE will only suggest so many
items can be controlled with |g:ale_completion_max_suggestions|. possible matches for completion. The maximum number of items can be controlled
with |g:ale_completion_max_suggestions|.
If you don't like some of the suggestions you see, you can filter them out If you don't like some of the suggestions you see, you can filter them out
with |g:ale_completion_excluded_words| or |b:ale_completion_excluded_words|. with |g:ale_completion_excluded_words| or |b:ale_completion_excluded_words|.
@ -758,12 +839,34 @@ at the cursor taken from LSP linters. The following commands are supported:
|ALEHover| - Print information about the symbol at the cursor. |ALEHover| - Print information about the symbol at the cursor.
If |b:ale_set_balloons| is set to `1` and your version of Vim supports the If |g:ale_set_balloons| is set to `1` and your version of Vim supports the
|balloon_show()| function, then "hover" information also show up when you move |balloon_show()| function, then "hover" information also show up when you move
the mouse over a symbol in a buffer. Diagnostic information will take priority the mouse over a symbol in a buffer. Diagnostic information will take priority
over hover information for balloons. If a line contains a problem, that over hover information for balloons. If a line contains a problem, that
problem will be displayed in a balloon instead of hover information. problem will be displayed in a balloon instead of hover information.
For Vim 8.1+ terminals, mouse hovering is disabled by default. Enabling
|balloonexpr| commands in terminals can cause scrolling issues in terminals,
so ALE will not attempt to show balloons unless |g:ale_set_balloons| is set to
`1` before ALE is loaded.
For enabling mouse support in terminals, you may have to change your mouse
settings. For example: >
" Example mouse settings.
" You will need to try different settings, depending on your terminal.
set mouse=a
set ttymouse=xterm
<
-------------------------------------------------------------------------------
5.5 Symbol Search *ale-symbol-search*
ALE supports searching for workspace symbols via LSP linters. The following
commands are supported:
|ALESymbolSearch| - Search for symbols in the workspace.
=============================================================================== ===============================================================================
6. Global Options *ale-options* 6. Global Options *ale-options*
@ -876,6 +979,9 @@ g:ale_completion_enabled *g:ale_completion_enabled*
When this option is set to `1`, completion support will be enabled. When this option is set to `1`, completion support will be enabled.
This setting must be set to `1` before ALE is loaded for this behavior
to be enabled.
See |ale-completion| See |ale-completion|
@ -1282,10 +1388,12 @@ g:ale_linter_aliases *g:ale_linter_aliases*
ALE will first look for aliases for filetypes in the `b:ale_linter_aliases` ALE will first look for aliases for filetypes in the `b:ale_linter_aliases`
variable, then `g:ale_linter_aliases`, and then a default Dictionary. variable, then `g:ale_linter_aliases`, and then a default Dictionary.
`b:ale_linter_aliases` can be set to a |List|, to tell ALE to load the `b:ale_linter_aliases` can be set to a |List| or a |String|, to tell ALE to
linters for specific filetypes for a given buffer. > load the linters for specific filetypes for a given buffer. >
let b:ale_linter_aliases = ['html', 'javascript', 'css'] let b:ale_linter_aliases = ['html', 'javascript', 'css']
" OR, Alias a filetype to only a single filetype with a String.
let b:ale_linter_aliases = 'javascript'
< <
No linters will be loaded when the buffer's filetype is empty. No linters will be loaded when the buffer's filetype is empty.
@ -1306,6 +1414,7 @@ g:ale_linters *g:ale_linters*
\ 'hack': ['hack'], \ 'hack': ['hack'],
\ 'help': [], \ 'help': [],
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'], \ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'], \ 'rust': ['cargo'],
\ 'spec': [], \ 'spec': [],
@ -2049,6 +2158,14 @@ ALEHover *ALEHover*
A plug mapping `<Plug>(ale_hover)` is defined for this command. A plug mapping `<Plug>(ale_hover)` is defined for this command.
ALESymbolSearch `<query>` *ALESymbolSearch*
Search for symbols in the workspace, taken from any available LSP linters.
The arguments provided to this command will be used as a search query for
finding symbols in the workspace, such as functions, types, etc.
*:ALELint* *:ALELint*
ALELint *ALELint* ALELint *ALELint*
@ -2568,6 +2685,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`initialization_options_callback` may be defined to `initialization_options_callback` may be defined to
pass initialization options to the LSP. pass initialization options to the LSP.
An optional `lsp_config` or `lsp_config_callback` may
be defined to pass configuration settings to the LSP.
`address_callback` A |String| or |Funcref| for a callback function `address_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |String| should be accepting a buffer number. A |String| should be
returned with an address to connect to. returned with an address to connect to.
@ -2628,6 +2748,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
This can be used in place of `initialization_options` This can be used in place of `initialization_options`
when more complicated processing is needed. when more complicated processing is needed.
`lsp_config` A |Dictionary| of configuration settings for LSPs.
This will be fed (as JSON) to the LSP in the
workspace/didChangeConfiguration command.
`lsp_config_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |Dictionary| should be
returned for configuration settings to pass the LSP.
This can be used in place of `lsp_config` when more
complicated processing is needed.
Only one of `command`, `command_callback`, or `command_chain` should be Only one of `command`, `command_callback`, or `command_chain` should be
specified. `command_callback` is generally recommended when a command string specified. `command_callback` is generally recommended when a command string
needs to be generated dynamically, or any global options are used. needs to be generated dynamically, or any global options are used.
@ -2728,6 +2858,25 @@ ale#linter#PreventLoading(filetype) *ale#linter#PreventLoading()*
|runtimepath| for that filetype. This function can be called from vimrc or |runtimepath| for that filetype. This function can be called from vimrc or
similar to prevent ALE from loading linters. similar to prevent ALE from loading linters.
ale#other_source#ShowResults(buffer, linter_name, loclist)
*ale#other_source#ShowResults()*
Show results from another source of information.
`buffer` must be a valid buffer number, and `linter_name` must be a unique
name for identifying another source of information. The `loclist` given
where the problems in a buffer are, and should be provided in the format ALE
uses for regular linter results. See |ale-loclist-format|.
ale#other_source#StartChecking(buffer, linter_name)
*ale#other_source#StartChecking()*
Tell ALE that another source of information has started checking a buffer.
`buffer` must be a valid buffer number, and `linter_name` must be a unique
name for identifying another source of information.
ale#statusline#Count(buffer) *ale#statusline#Count()* ale#statusline#Count(buffer) *ale#statusline#Count()*
@ -2756,10 +2905,21 @@ b:ale_linted *b:ale_linted*
echo getbufvar(bufnr(''), 'ale_linted', 0) > 0 ? 'checked' : 'not checked' echo getbufvar(bufnr(''), 'ale_linted', 0) > 0 ? 'checked' : 'not checked'
< <
g:ale_want_results_buffer *g:ale_want_results_buffer*
`g:ale_want_results_buffer` is set to the number of the buffer being checked
when the |ALEWantResults| event is signaled. This variable should be read to
figure out which buffer other sources should lint.
ALELintPre *ALELintPre-autocmd* ALELintPre *ALELintPre-autocmd*
*ALELintPre*
ALELintPost *ALELintPost-autocmd* ALELintPost *ALELintPost-autocmd*
*ALELintPost*
ALEFixPre *ALEFixPre-autocmd* ALEFixPre *ALEFixPre-autocmd*
*ALEFixPre*
ALEFixPost *ALEFixPost-autocmd* ALEFixPost *ALEFixPost-autocmd*
*ALEFixPost*
These |User| autocommands are triggered before and after every lint or fix These |User| autocommands are triggered before and after every lint or fix
cycle. They can be used to update statuslines, send notifications, etc. cycle. They can be used to update statuslines, send notifications, etc.
@ -2773,7 +2933,7 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd! autocmd!
autocmd User ALELintPre hi Statusline ctermfg=darkgrey autocmd User ALELintPre hi Statusline ctermfg=darkgrey
autocmd User ALELintPost hi Statusline ctermfg=NONE autocmd User ALELintPost hi Statusline ctermfg=NONE
augroup end augroup END
< <
Or to display the progress in the statusline: Or to display the progress in the statusline:
> >
@ -2783,10 +2943,11 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd! autocmd!
autocmd User ALELintPre let s:ale_running = 1 | redrawstatus autocmd User ALELintPre let s:ale_running = 1 | redrawstatus
autocmd User ALELintPost let s:ale_running = 0 | redrawstatus autocmd User ALELintPost let s:ale_running = 0 | redrawstatus
augroup end augroup END
< <
ALEJobStarted *ALEJobStarted-autocmd* ALEJobStarted *ALEJobStarted-autocmd*
*ALEJobStarted*
This |User| autocommand is triggered immediately after a job is successfully This |User| autocommand is triggered immediately after a job is successfully
run. This provides better accuracy for checking linter status with run. This provides better accuracy for checking linter status with
@ -2794,6 +2955,22 @@ ALEJobStarted *ALEJobStarted-autocmd*
triggered before any linters are executed. triggered before any linters are executed.
ALEWantResults *ALEWantResults-autocmd*
*ALEWantResults*
This |User| autocommand is triggered before ALE begins a lint cycle. Another
source can respond by calling |ale#other_source#StartChecking()|, and
|ALELintPre| will be signaled thereafter, to allow other plugins to know
that another source is checking the buffer.
|g:ale_want_results_buffer| will be set to the number for a buffer being
checked when the event is signaled, and deleted after the event is done.
This variable should be read to know which buffer to check.
Other plugins can use this event to start checking buffers when ALE events
for checking buffers are triggered.
=============================================================================== ===============================================================================
10. Special Thanks *ale-special-thanks* 10. Special Thanks *ale-special-thanks*

View file

@ -194,6 +194,9 @@ command! -bar ALEFindReferences :call ale#references#Find()
command! -bar ALEHover :call ale#hover#Show(bufnr(''), getcurpos()[1], command! -bar ALEHover :call ale#hover#Show(bufnr(''), getcurpos()[1],
\ getcurpos()[2], {}) \ getcurpos()[2], {})
" Search for appearances of a symbol, such as a type name or function name.
command! -nargs=1 ALESymbolSearch :call ale#symbol#Search(<q-args>)
" <Plug> mappings for commands " <Plug> mappings for commands
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return> nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>
nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return> nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return>

View file

@ -2015,7 +2015,7 @@ fu! s:bufnrfilpath(line)
let filpath = s:dyncwd.s:lash().a:line let filpath = s:dyncwd.s:lash().a:line
en en
let filpath = fnamemodify(filpath, ':p') let filpath = fnamemodify(filpath, ':p')
let bufnr = bufnr('^'.filpath.'$') let bufnr = bufnr('^'.fnameescape(filpath).'$')
if (!filereadable(filpath) && bufnr < 1) if (!filereadable(filpath) && bufnr < 1)
if (a:line =~ '[\/]\?\[\d\+\*No Name\]$') if (a:line =~ '[\/]\?\[\d\+\*No Name\]$')
let bufnr = str2nr(matchstr(a:line, '[\/]\?\[\zs\d\+\ze\*No Name\]$')) let bufnr = str2nr(matchstr(a:line, '[\/]\?\[\zs\d\+\ze\*No Name\]$'))

View file

@ -255,6 +255,7 @@ function! s:findAndRevealPath(pathStr)
endif endif
try try
let l:pathStr = g:NERDTreePath.Resolve(l:pathStr)
let l:pathObj = g:NERDTreePath.New(l:pathStr) let l:pathObj = g:NERDTreePath.New(l:pathStr)
catch /^NERDTree.InvalidArgumentsError/ catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echoWarning('invalid path') call nerdtree#echoWarning('invalid path')
@ -524,10 +525,17 @@ endfunction
" Reloads the current root. All nodes below this will be lost and the root dir " Reloads the current root. All nodes below this will be lost and the root dir
" will be reloaded. " will be reloaded.
function! s:refreshRoot() function! s:refreshRoot()
if !g:NERDTree.IsOpen()
return
endif
call nerdtree#echo("Refreshing the root node. This could take a while...") call nerdtree#echo("Refreshing the root node. This could take a while...")
let l:curWin = winnr()
call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w")
call b:NERDTree.root.refresh() call b:NERDTree.root.refresh()
call b:NERDTree.render() call b:NERDTree.render()
redraw redraw
call nerdtree#exec(l:curWin . "wincmd w")
call nerdtree#echo("Refreshing the root node. This could take a while... DONE") call nerdtree#echo("Refreshing the root node. This could take a while... DONE")
endfunction endfunction
@ -554,6 +562,7 @@ function! nerdtree#ui_glue#setupCommands()
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreateTabTree('<args>') command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreateTabTree('<args>')
command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror() command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
command! -n=? -complete=file -bar NERDTreeFind call s:findAndRevealPath('<args>') command! -n=? -complete=file -bar NERDTreeFind call s:findAndRevealPath('<args>')
command! -n=0 -bar NERDTreeRefreshRoot call s:refreshRoot()
command! -n=0 -bar NERDTreeFocus call NERDTreeFocus() command! -n=0 -bar NERDTreeFocus call NERDTreeFocus()
command! -n=0 -bar NERDTreeCWD call NERDTreeCWD() command! -n=0 -bar NERDTreeCWD call NERDTreeCWD()
endfunction endfunction

View file

@ -145,6 +145,9 @@ The following features and functionality are provided by the NERD tree:
Change the NERDTree root to the current working directory. If no Change the NERDTree root to the current working directory. If no
NERDTree exists for this tab, a new one is opened. NERDTree exists for this tab, a new one is opened.
:NERDTreeRefreshRoot *:NERDTreeRefreshRoot*
Refreshes the NERD tree root node.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
2.2. Bookmarks *NERDTreeBookmarks* 2.2. Bookmarks *NERDTreeBookmarks*
@ -992,17 +995,33 @@ appended to the array.
The regex '\/$' should be used to match directory nodes. The regex '\/$' should be used to match directory nodes.
A special flag can be used to sort by the modification timestamps of files and
directories. It is either '[[timestamp]]' for ascending, or '[[-timestamp]]'
for descending. If placed at the beginning of the list, files and directories
are sorted by timestamp, and then by the remaining items in the sort order
list. If this flag is in any other position of the list, timestamp sorting is
done secondarily. See examples 4, 5, and 6 below.
After this sorting is done, the files in each group are sorted alphabetically. After this sorting is done, the files in each group are sorted alphabetically.
Other examples: > Other examples: >
(1) ['*', '\/$'] (1) ['*', '\/$']
(2) [] (2) []
(3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$']
(4) ['[[timestamp]]']
(5) ['\/$', '*', '[[-timestamp]]']
(6) ['\.md$', '\.c$', '[[-timestamp]]', '*']
< <
1. Directories will appear last, everything else will appear above. 1. Directories will appear last, everything else will appear above.
2. Everything will simply appear in alphabetical order. 2. Everything will simply appear in alphabetical order.
3. Dirs will appear first, then ruby and php. Swap files, bak files and vim 3. Dirs will appear first, then ruby and php. Swap files, bak files and vim
backup files will appear last with everything else preceding them. backup files will appear last with everything else preceding them.
4. All files and directories are sorted by timestamp, oldest first. If any
files have identical timestamps, they are sorted alphabetically.
5. Directories are first, newest to oldest, then everything else, newest to
oldest.
6. Markdown files first, followed by C source files, then everything else.
Each group is shown newest to oldest.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*'NERDTreeStatusline'* *'NERDTreeStatusline'*
@ -1014,7 +1033,7 @@ Defines the value for the |'statusline'| setting in NERDTree windows.
Note: The setting is actually applied using |:let-&|, not |:set|, so Note: The setting is actually applied using |:let-&|, not |:set|, so
escaping spaces is not necessary. escaping spaces is not necessary.
Setting this option to -1 will will deactivate it so that your global Setting this option to -1 will deactivate it so that your global
|'statusline'| setting is used. |'statusline'| setting is used.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

View file

@ -39,10 +39,10 @@ endfunction
" FUNCTION: Path.cacheDisplayString() {{{1 " FUNCTION: Path.cacheDisplayString() {{{1
function! s:Path.cacheDisplayString() abort function! s:Path.cacheDisplayString() abort
let self.cachedDisplayString = self.getLastPathComponent(1) let self.cachedDisplayString = g:NERDTreeNodeDelimiter . self.getLastPathComponent(1)
if self.isExecutable if self.isExecutable
let self.cachedDisplayString = self.cachedDisplayString . '*' let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . '*'
endif endif
let self._bookmarkNames = [] let self._bookmarkNames = []
@ -52,15 +52,24 @@ function! s:Path.cacheDisplayString() abort
endif endif
endfor endfor
if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks == 1 if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks == 1
let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' {' . join(self._bookmarkNames) . '}'
endif endif
if self.isSymLink if self.isSymLink
let self.cachedDisplayString .= ' -> ' . self.symLinkDest let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' -> ' . self.symLinkDest
endif endif
if self.isReadOnly if self.isReadOnly
let self.cachedDisplayString .= ' ['.g:NERDTreeGlyphReadOnly.']' let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' ['.g:NERDTreeGlyphReadOnly.']'
endif
endfunction
" FUNCTION: Path.addDelimiter() {{{1
function! s:Path.addDelimiter(line)
if a:line =~# '\(.*' . g:NERDTreeNodeDelimiter . '\)\{2}'
return a:line
else
return a:line . g:NERDTreeNodeDelimiter
endif endif
endfunction endfunction
@ -392,7 +401,17 @@ endfunction
" FUNCTION: Path.getSortKey() {{{1 " FUNCTION: Path.getSortKey() {{{1
" returns a key used in compare function for sorting " returns a key used in compare function for sorting
function! s:Path.getSortKey() function! s:Path.getSortKey()
if !exists("self._sortKey") || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder let l:ascending = index(g:NERDTreeSortOrder,'[[timestamp]]')
let l:descending = index(g:NERDTreeSortOrder,'[[-timestamp]]')
if !exists("self._sortKey") || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder || l:ascending >= 0 || l:descending >= 0
let self._sortKey = [self.getSortOrderIndex()]
if l:descending >= 0
call insert(self._sortKey, -getftime(self.str()), l:descending == 0 ? 0 : len(self._sortKey))
elseif l:ascending >= 0
call insert(self._sortKey, getftime(self.str()), l:ascending == 0 ? 0 : len(self._sortKey))
endif
let path = self.getLastPathComponent(1) let path = self.getLastPathComponent(1)
if !g:NERDTreeSortHiddenFirst if !g:NERDTreeSortHiddenFirst
let path = substitute(path, '^[._]', '', '') let path = substitute(path, '^[._]', '', '')
@ -400,13 +419,9 @@ function! s:Path.getSortKey()
if !g:NERDTreeCaseSensitiveSort if !g:NERDTreeCaseSensitiveSort
let path = tolower(path) let path = tolower(path)
endif endif
if !g:NERDTreeNaturalSort
let self._sortKey = [self.getSortOrderIndex(), path]
else
let self._sortKey = [self.getSortOrderIndex()] + self._splitChunks(path)
endif
endif
call extend(self._sortKey, (g:NERDTreeNaturalSort ? self._splitChunks(path) : [path]))
endif
return self._sortKey return self._sortKey
endfunction endfunction

View file

@ -99,7 +99,8 @@ function! s:TreeDirNode.displayString()
let l:label = '' let l:label = ''
let l:cascade = self.getCascade() let l:cascade = self.getCascade()
for l:dirNode in l:cascade for l:dirNode in l:cascade
let l:label .= l:dirNode.path.displayString() let l:next = l:dirNode.path.displayString()
let l:label .= l:label == '' ? l:next : substitute(l:next,'^.','','')
endfor endfor
" Select the appropriate open/closed status indicator symbol. " Select the appropriate open/closed status indicator symbol.
@ -304,9 +305,11 @@ function! s:TreeDirNode._glob(pattern, all)
for l:file in l:globList for l:file in l:globList
let l:tail = fnamemodify(l:file, ':t') let l:tail = fnamemodify(l:file, ':t')
" Double the modifier if only a separator was stripped. " If l:file has a trailing slash, then its :tail will be ''. Use
" :h to drop the slash and the empty string after it; then use :t
" to get the directory name.
if l:tail == '' if l:tail == ''
let l:tail = fnamemodify(l:file, ':t:t') let l:tail = fnamemodify(l:file, ':h:t')
endif endif
if l:tail == '.' || l:tail == '..' if l:tail == '.' || l:tail == '..'

View file

@ -180,7 +180,7 @@ function! s:TreeFileNode.GetSelected()
endif endif
return b:NERDTree.root.findNode(l:path) return b:NERDTree.root.findNode(l:path)
catch /^NERDTree/ catch
return {} return {}
endtry endtry
endfunction endfunction
@ -242,7 +242,7 @@ endfunction
" FUNCTION: TreeFileNode.openInNewTab(options) {{{1 " FUNCTION: TreeFileNode.openInNewTab(options) {{{1
function! s:TreeFileNode.openInNewTab(options) function! s:TreeFileNode.openInNewTab(options)
echomsg 'TreeFileNode.openInNewTab is deprecated' call nerdtree#deprecated('TreeFileNode.openinNewTab', 'is deprecated, use .open() instead.')
call self.open(extend({'where': 't'}, a:options)) call self.open(extend({'where': 't'}, a:options))
endfunction endfunction

View file

@ -300,7 +300,7 @@ endfunction
" FUNCTION: s:UI.MarkupReg() {{{1 " FUNCTION: s:UI.MarkupReg() {{{1
function! s:UI.MarkupReg() function! s:UI.MarkupReg()
return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)' return '^ *['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']\? '
endfunction endfunction
" FUNCTION: s:UI._renderBookmarks {{{1 " FUNCTION: s:UI._renderBookmarks {{{1
@ -363,30 +363,13 @@ function! s:UI.setShowHidden(val)
endfunction endfunction
" FUNCTION: s:UI._stripMarkup(line){{{1 " FUNCTION: s:UI._stripMarkup(line){{{1
" returns the given line with all the tree parts stripped off " find the filename in the given line, and return it.
" "
" Args: " Args:
" line: the subject line " line: the subject line
function! s:UI._stripMarkup(line) function! s:UI._stripMarkup(line)
let line = a:line let l:line = substitute(a:line, '^.\{-}' . g:NERDTreeNodeDelimiter, '', '')
" remove the tree parts and the leading space return substitute(l:line, g:NERDTreeNodeDelimiter.'.*$', '', '')
let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","")
" strip off any read only flag
let line = substitute (line, ' \['.g:NERDTreeGlyphReadOnly.'\]', "","")
" strip off any bookmark flags
let line = substitute (line, ' {[^}]*}', "","")
" strip off any executable flags
let line = substitute (line, '*\ze\($\| \)', "","")
" strip off any generic flags
let line = substitute (line, '\[[^]]*\]', "","")
let line = substitute (line,' -> .*',"","") " remove link to
return line
endfunction endfunction
" FUNCTION: s:UI.render() {{{1 " FUNCTION: s:UI.render() {{{1

View file

@ -83,31 +83,32 @@ function! s:promptToDelBuffer(bufnum, msg)
endif endif
endfunction endfunction
"FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1 "FUNCTION: s:renameBuffer(bufNum, newNodeName, isDirectory){{{1
"prints out the given msg and, if the user responds by pushing 'y' then the "The buffer with the given bufNum is replaced with a new one
"buffer with the given bufnum is replaced with a new one
" "
"Args: "Args:
"bufnum: the buffer that may be deleted "bufNum: the buffer that may be deleted
"msg: a message that will be echoed to the user asking them if they wish to "newNodeName: the name given to the renamed node
" del the buffer "isDirectory: determines how to do the create the new filenames
function! s:promptToRenameBuffer(bufnum, msg, newFileName) function! s:renameBuffer(bufNum, newNodeName, isDirectory)
echo a:msg if a:isDirectory
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y' let quotedFileName = fnameescape(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t'))
let quotedFileName = fnameescape(a:newFileName) let editStr = g:NERDTreePath.New(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t')).str({'format': 'Edit'})
" 1. ensure that a new buffer is loaded else
exec "badd " . quotedFileName let quotedFileName = fnameescape(a:newNodeName)
" 2. ensure that all windows which display the just deleted filename let editStr = g:NERDTreePath.New(a:newNodeName).str({'format': 'Edit'})
" display a buffer for a new filename.
let s:originalTabNumber = tabpagenr()
let s:originalWindowNumber = winnr()
let editStr = g:NERDTreePath.New(a:newFileName).str({'format': 'Edit'})
exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':e! " . editStr . "' | endif"
exec "tabnext " . s:originalTabNumber
exec s:originalWindowNumber . "wincmd w"
" 3. We don't need a previous buffer anymore
exec "bwipeout! " . a:bufnum
endif endif
" 1. ensure that a new buffer is loaded
exec "badd " . quotedFileName
" 2. ensure that all windows which display the just deleted filename
" display a buffer for a new filename.
let s:originalTabNumber = tabpagenr()
let s:originalWindowNumber = winnr()
exec "tabdo windo if winbufnr(0) == " . a:bufNum . " | exec ':e! " . editStr . "' | endif"
exec "tabnext " . s:originalTabNumber
exec s:originalWindowNumber . "wincmd w"
" 3. We don't need a previous buffer anymore
exec "bwipeout! " . a:bufNum
endfunction endfunction
"FUNCTION: NERDTreeAddNode(){{{1 "FUNCTION: NERDTreeAddNode(){{{1
function! NERDTreeAddNode() function! NERDTreeAddNode()
@ -128,6 +129,9 @@ function! NERDTreeAddNode()
let parentNode = b:NERDTree.root.findNode(newPath.getParent()) let parentNode = b:NERDTree.root.findNode(newPath.getParent())
let newTreeNode = g:NERDTreeFileNode.New(newPath, b:NERDTree) let newTreeNode = g:NERDTreeFileNode.New(newPath, b:NERDTree)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
if empty(parentNode) if empty(parentNode)
call b:NERDTree.root.refresh() call b:NERDTree.root.refresh()
call b:NERDTree.render() call b:NERDTree.render()
@ -155,17 +159,33 @@ function! NERDTreeMoveNode()
endif endif
try try
let bufnum = bufnr("^".curNode.path.str()."$") if curNode.path.isDirectory
let l:openBuffers = filter(range(1,bufnr("$")),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") =~# curNode.path.str() . "/.*"')
else
let l:openBuffers = filter(range(1,bufnr("$")),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") ==# curNode.path.str()')
endif
call curNode.rename(newNodePath) call curNode.rename(newNodePath)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
call b:NERDTree.root.refresh() call b:NERDTree.root.refresh()
call NERDTreeRender() call NERDTreeRender()
"if the node is open in a buffer, ask the user if they want to " If the file node is open, or files under the directory node are
"close that buffer " open, ask the user if they want to replace the file(s) with the
if bufnum != -1 " renamed files.
let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Replace this buffer with the new file? (yN)" if !empty(l:openBuffers)
call s:promptToRenameBuffer(bufnum, prompt, newNodePath) if curNode.path.isDirectory
echo "\nDirectory renamed.\n\nFiles with the old directory name are open in buffers " . join(l:openBuffers, ', ') . ". Replace these buffers with the new files? (yN)"
else
echo "\nFile renamed.\n\nThe old file is open in buffer " . l:openBuffers[0] . ". Replace this buffer with the new file? (yN)"
endif
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
for bufNum in l:openBuffers
call s:renameBuffer(bufNum, newNodePath, curNode.path.isDirectory)
endfor
endif
endif endif
call curNode.putCursorHere(1, 0) call curNode.putCursorHere(1, 0)
@ -226,9 +246,9 @@ function! NERDTreeListNode()
let treenode = g:NERDTreeFileNode.GetSelected() let treenode = g:NERDTreeFileNode.GetSelected()
if !empty(treenode) if !empty(treenode)
let s:uname = system("uname") let s:uname = system("uname")
let stat_cmd = 'stat -c "%s" ' let stat_cmd = 'stat -c "%s" '
if s:uname =~? "Darwin" if s:uname =~? "Darwin"
let stat_cmd = 'stat -f "%z" ' let stat_cmd = 'stat -f "%z" '
endif endif
@ -248,33 +268,13 @@ function! NERDTreeListNodeWin32()
let l:node = g:NERDTreeFileNode.GetSelected() let l:node = g:NERDTreeFileNode.GetSelected()
if !empty(l:node) if !empty(l:node)
let l:path = l:node.path.str()
let l:save_shell = &shell call nerdtree#echo(printf("%s:%s MOD:%s BYTES:%d PERMISSIONS:%s",
set shell& \ toupper(getftype(l:path)),
\ fnamemodify(l:path, ':t'),
if exists('+shellslash') \ strftime("%c", getftime(l:path)),
let l:save_shellslash = &shellslash \ getfsize(l:path),
set noshellslash \ getfperm(l:path)))
endif
let l:command = 'DIR /Q '
\ . shellescape(l:node.path.str())
\ . ' | FINDSTR "^[012][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9]"'
let l:metadata = split(system(l:command), "\n")
if v:shell_error == 0
call nerdtree#echo(l:metadata[0])
else
call nerdtree#echoError('shell command failed')
endif
let &shell = l:save_shell
if exists('l:save_shellslash')
let &shellslash = l:save_shellslash
endif
return return
endif endif
@ -303,6 +303,9 @@ function! NERDTreeCopyNode()
if confirmed if confirmed
try try
let newNode = currentNode.copy(newNodePath) let newNode = currentNode.copy(newNodePath)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
if empty(newNode) if empty(newNode)
call b:NERDTree.root.refresh() call b:NERDTree.root.refresh()
call b:NERDTree.render() call b:NERDTree.render()

View file

@ -86,6 +86,9 @@ let g:NERDTreeOldSortOrder = []
call s:initVariable("g:NERDTreeGlyphReadOnly", "RO") call s:initVariable("g:NERDTreeGlyphReadOnly", "RO")
" ASCII 160: non-breaking space used to delimit items in the tree's nodes.
call s:initVariable("g:NERDTreeNodeDelimiter", "\u00a0")
if !exists('g:NERDTreeStatusline') if !exists('g:NERDTreeStatusline')
"the exists() crap here is a hack to stop vim spazzing out when "the exists() crap here is a hack to stop vim spazzing out when

View file

@ -36,6 +36,15 @@ exec 'syn match NERDTreeRO # *\zs.*\ze \['.g:NERDTreeGlyphReadOnly.'\]# contains
syn match NERDTreeFlags #^ *\zs\[.\]# containedin=NERDTreeFile,NERDTreeExecFile syn match NERDTreeFlags #^ *\zs\[.\]# containedin=NERDTreeFile,NERDTreeExecFile
syn match NERDTreeFlags #\[.\]# containedin=NERDTreeDir syn match NERDTreeFlags #\[.\]# containedin=NERDTreeDir
"highlighing to conceal the delimiter around the file/dir name
if has("conceal")
exec 'syn match NERDTreeNodeDelimiters #' . g:NERDTreeNodeDelimiter . '# conceal containedin=NERDTreeFile,NERDTreeLinkFile,NERDTreeExecFile,NERDTreeRO,NERDTreeDir'
setlocal conceallevel=3 concealcursor=nvic
else
exec 'syn match NERDTreeNodeDelimiters #' . g:NERDTreeNodeDelimiter . '# containedin=NERDTreeFile,NERDTreeLinkFile,NERDTreeExecFile,NERDTreeRO,NERDTreeDir'
hi! link NERDTreeNodeDelimiters Ignore
endif
syn match NERDTreeCWD #^[</].*$# syn match NERDTreeCWD #^[</].*$#
"highlighting for bookmarks "highlighting for bookmarks

View file

@ -76,8 +76,12 @@ It also has auto-completion for location and server blocks with `location<tab>`
## Installation ## Installation
Just plug it into your favorite Vim package manager: ### Pathogen
```bash
git clone https://github.com/chr4/nginx.vim ~/.vim/bundle/nginx.vim
```
### Other (Plug, Dein.vim, Vundle)
```vim ```vim
" Plug " Plug
Plug 'chr4/nginx.vim' Plug 'chr4/nginx.vim'

View file

@ -29,9 +29,9 @@ endfunction
function! s:send(self,func,...) function! s:send(self,func,...)
if type(a:func) == type('') || type(a:func) == type(0) if type(a:func) == type('') || type(a:func) == type(0)
let Func = get(a:self,a:func,'') let l:Func = get(a:self,a:func,'')
else else
let Func = a:func let l:Func = a:func
endif endif
let s = type(a:self) == type({}) ? a:self : {} let s = type(a:self) == type({}) ? a:self : {}
if type(Func) == type(function('tr')) if type(Func) == type(function('tr'))
@ -578,45 +578,54 @@ call extend(Abolish.Coercions, {
\ "function missing": s:function("s:unknown_coercion") \ "function missing": s:function("s:unknown_coercion")
\}, "keep") \}, "keep")
function! s:coerce(transformation) function! s:coerce(type) abort
if a:type !~# '^\%(line\|char\|block\)'
let s:transformation = a:type
let &opfunc = matchstr(expand('<sfile>'), '<SNR>\w*')
return 'g@'
endif
let selection = &selection
let clipboard = &clipboard let clipboard = &clipboard
try try
set clipboard= set selection=inclusive clipboard-=unnamed clipboard-=unnamedplus
let regbody = getreg('"') let regbody = getreg('"')
let regtype = getregtype('"') let regtype = getregtype('"')
let c = v:count1 let c = v:count1
while c > 0 while c > 0
let c -= 1 let c -= 1
norm! yiw if a:type ==# 'line'
let move = "'[V']"
elseif a:type ==# 'block'
let move = "`[\<C-V>`]"
else
let move = "`[v`]"
endif
silent exe 'normal!' move.'y'
let word = @@ let word = @@
let @@ = s:send(g:Abolish.Coercions,a:transformation,word) let @@ = s:send(g:Abolish.Coercions,s:transformation,word)
if !exists('begin') if !exists('begin')
let begin = getpos("'[") let begin = getpos("'[")
endif endif
if word !=# @@ if word !=# @@
let changed = 1 let changed = 1
norm! viwpw exe 'normal!' move.'p'
else
norm! w
endif endif
endwhile endwhile
call setreg('"',regbody,regtype) call setreg('"',regbody,regtype)
call setpos("'[",begin) call setpos("'[",begin)
call setpos(".",begin) call setpos(".",begin)
if exists("changed")
silent! call repeat#set("\<Plug>Coerce".a:transformation)
endif
finally finally
let &selection = selection
let &clipboard = clipboard let &clipboard = clipboard
endtry endtry
endfunction endfunction
nnoremap <silent> <Plug>Coerce :<C-U>call <SID>coerce(nr2char(getchar()))<CR> nnoremap <expr> <Plug>(abolish-coerce) <SID>coerce(nr2char(getchar())).'iw'
" }}}1 " }}}1
if !exists("g:abolish_no_mappings") || ! g:abolish_no_mappings if !exists("g:abolish_no_mappings") || ! g:abolish_no_mappings
nmap cr <Plug>Coerce nmap cr <Plug>(abolish-coerce)
endif endif
command! -nargs=+ -bang -bar -range=0 -complete=custom,s:Complete Abolish command! -nargs=+ -bang -bar -range=0 -complete=custom,s:Complete Abolish

View file

@ -376,7 +376,7 @@ function! fugitive#repo(...) abort
endif endif
return extend(repo, s:repo_prototype, 'keep') return extend(repo, s:repo_prototype, 'keep')
endif endif
call s:throw('not a git repository: '.expand('%:p')) call s:throw('not a Git repository: ' . string(dir))
endfunction endfunction
function! s:repo_dir(...) dict abort function! s:repo_dir(...) dict abort
@ -400,19 +400,19 @@ function! s:repo_bare() dict abort
endif endif
endfunction endfunction
function! s:repo_route(object) dict abort function! s:repo_find(object) dict abort
return fugitive#Route(a:object, self.git_dir) return fugitive#Find(a:object, self.git_dir)
endfunction endfunction
function! s:repo_translate(rev) dict abort function! s:repo_translate(rev) dict abort
return s:Slash(fugitive#Route(substitute(a:rev, '^/', ':(top)', ''), self.git_dir)) return s:Slash(fugitive#Find(substitute(a:rev, '^/', ':(top)', ''), self.git_dir))
endfunction endfunction
function! s:repo_head(...) dict abort function! s:repo_head(...) dict abort
return fugitive#Head(a:0 ? a:1 : 0, self.git_dir) return fugitive#Head(a:0 ? a:1 : 0, self.git_dir)
endfunction endfunction
call s:add_methods('repo',['dir','tree','bare','route','translate','head']) call s:add_methods('repo',['dir','tree','bare','find','translate','head'])
function! s:repo_prepare(...) dict abort function! s:repo_prepare(...) dict abort
return call('fugitive#Prepare', [self.git_dir] + a:000) return call('fugitive#Prepare', [self.git_dir] + a:000)
@ -485,8 +485,24 @@ function! s:Owner(path, ...) abort
return '' return ''
endif endif
let [pdir, commit, file] = s:DirCommitFile(a:path) let [pdir, commit, file] = s:DirCommitFile(a:path)
if s:cpath(dir, pdir) && commit =~# '^\x\{40\}$' if s:cpath(dir, pdir)
return commit if commit =~# '^\x\{40\}$'
return commit
elseif commit ==# '2'
return 'HEAD^{}'
endif
if filereadable(dir . '/MERGE_HEAD')
let merge_head = 'MERGE_HEAD'
elseif filereadable(dir . '/REBASE_HEAD')
let merge_head = 'REBASE_HEAD'
else
return ''
endif
if commit ==# '3'
return merge_head . '^{}'
elseif commit ==# '1'
return s:TreeChomp('merge-base', 'HEAD', merge_head, '--')
endif
endif endif
let path = fnamemodify(a:path, ':p') let path = fnamemodify(a:path, ':p')
if s:cpath(dir . '/', path[0 : len(dir)]) && a:path =~# 'HEAD$' if s:cpath(dir . '/', path[0 : len(dir)]) && a:path =~# 'HEAD$'
@ -565,7 +581,7 @@ function! s:Relative(...) abort
return fugitive#Path(@%, a:0 ? a:1 : ':(top)') return fugitive#Path(@%, a:0 ? a:1 : ':(top)')
endfunction endfunction
function! fugitive#Route(object, ...) abort function! fugitive#Find(object, ...) abort
if type(a:object) == type(0) if type(a:object) == type(0)
let name = bufname(a:object) let name = bufname(a:object)
return s:PlatformSlash(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name) return s:PlatformSlash(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name)
@ -622,7 +638,7 @@ function! fugitive#Route(object, ...) abort
else else
let altdir = FugitiveExtractGitDir(f) let altdir = FugitiveExtractGitDir(f)
if len(altdir) && !s:cpath(dir, altdir) if len(altdir) && !s:cpath(dir, altdir)
return fugitive#Route(a:object, altdir) return fugitive#Find(a:object, altdir)
endif endif
endif endif
elseif rev =~# '^:[0-3]:' elseif rev =~# '^:[0-3]:'
@ -654,7 +670,7 @@ function! fugitive#Route(object, ...) abort
else else
let altdir = FugitiveExtractGitDir(file) let altdir = FugitiveExtractGitDir(file)
if len(altdir) && !s:cpath(dir, altdir) if len(altdir) && !s:cpath(dir, altdir)
return fugitive#Route(a:object, altdir) return fugitive#Find(a:object, altdir)
endif endif
return file return file
endif endif
@ -682,7 +698,7 @@ function! s:Generate(rev, ...) abort
elseif a:rev =~# '^/' && len(tree) && getftime(tree . a:rev) >= 0 && getftime(a:rev) < 0 elseif a:rev =~# '^/' && len(tree) && getftime(tree . a:rev) >= 0 && getftime(a:rev) < 0
let object = ':(top)' . a:rev[1:-1] let object = ':(top)' . a:rev[1:-1]
endif endif
return fugitive#Route(object, dir) return fugitive#Find(object, dir)
endfunction endfunction
function! s:DotRelative(path) abort function! s:DotRelative(path) abort
@ -1082,7 +1098,7 @@ function! fugitive#buffer(...) abort
if buffer.getvar('git_dir') !=# '' if buffer.getvar('git_dir') !=# ''
return buffer return buffer
endif endif
call s:throw('not a git repository: '.bufname(buffer['#'])) call s:throw('not a Fugitive buffer: ' . string(bufname(buffer['#'])))
endfunction endfunction
function! s:buffer_getvar(var) dict abort function! s:buffer_getvar(var) dict abort
@ -1500,7 +1516,7 @@ function! fugitive#BufReadCmd(...) abort
if lnum if lnum
silent keepjumps delete_ silent keepjumps delete_
end end
silent exe (exists(':keeppatterns') ? 'keeppatterns' : '') 'keepjumps 1,/^diff --git\|\%$/g/\r$/s///' silent exe (exists(':keeppatterns') ? 'keeppatterns' : '') 'keepjumps 1,/^diff --git\|\%$/s/\r$//e'
keepjumps 1 keepjumps 1
endif endif
elseif b:fugitive_type ==# 'stage' elseif b:fugitive_type ==# 'stage'

View file

@ -43,8 +43,8 @@ function! FugitiveReal(...) abort
endif endif
endfunction endfunction
function! FugitiveRoute(...) abort function! FugitiveFind(...) abort
return fugitive#Route(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1)) return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
endfunction endfunction
function! FugitivePath(...) abort function! FugitivePath(...) abort
@ -104,6 +104,8 @@ function! FugitiveTreeForGitDir(path) abort
let dir = a:path let dir = a:path
if dir =~# '/\.git$' if dir =~# '/\.git$'
return len(dir) ==# 5 ? '/' : dir[0:-6] return len(dir) ==# 5 ? '/' : dir[0:-6]
elseif dir ==# ''
return ''
endif endif
if !has_key(s:worktree_for_dir, dir) if !has_key(s:worktree_for_dir, dir)
let s:worktree_for_dir[dir] = '' let s:worktree_for_dir[dir] = ''
@ -203,12 +205,12 @@ function! FugitiveDetect(path) abort
endif endif
endfunction endfunction
function! FugitiveFind(...) abort function! FugitiveRoute(...) abort
return call('FugitiveRoute', a:000) return call('FugitiveFind', a:000)
endfunction endfunction
function! FugitiveGenerate(...) abort function! FugitiveGenerate(...) abort
return call('FugitiveRoute', a:000) throw 'Use FugitiveFind() instead'
endfunction endfunction
function! s:Slash(path) abort function! s:Slash(path) abort
@ -258,7 +260,7 @@ augroup fugitive
autocmd FileType gitrebase autocmd FileType gitrebase
\ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' | \ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' |
\ if exists('b:git_dir') | \ if exists('b:git_dir') |
\ let &l:includeexpr = 'v:fname =~# ''^\x\{4,40\}$'' ? FugitiveRoute(v:fname) : ' . \ let &l:includeexpr = 'v:fname =~# ''^\x\{4,40\}$'' ? FugitiveFind(v:fname) : ' .
\ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') | \ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') |
\ endif | \ endif |
\ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc=' \ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc='

View file

@ -41,7 +41,7 @@ function! gitgutter#process_buffer(bufnr, force) abort
let diff = '' let diff = ''
try try
let diff = gitgutter#diff#run_diff(a:bufnr, 0) let diff = gitgutter#diff#run_diff(a:bufnr, 'index', 0)
catch /gitgutter not tracked/ catch /gitgutter not tracked/
call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr)) call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr))
catch /gitgutter diff failed/ catch /gitgutter diff failed/

View file

@ -11,10 +11,16 @@ endfunction
let s:c_flag = s:git_supports_command_line_config_override() let s:c_flag = s:git_supports_command_line_config_override()
let s:temp_index = tempname() let s:temp_from = tempname()
let s:temp_buffer = tempname() let s:temp_buffer = tempname()
" Returns a diff of the buffer. " Returns a diff of the buffer against the index or the working tree.
"
" After running the diff we pass it through grep where available to reduce
" subsequent processing by the plugin. If grep is not available the plugin
" does the filtering instead.
"
" When diffing against the index:
" "
" The buffer contents is not the same as the file on disk so we need to pass " The buffer contents is not the same as the file on disk so we need to pass
" two instances of the file to git-diff: " two instances of the file to git-diff:
@ -27,11 +33,6 @@ let s:temp_buffer = tempname()
" "
" and myfileB is the buffer contents. " and myfileB is the buffer contents.
" "
" After running the diff we pass it through grep where available to reduce
" subsequent processing by the plugin. If grep is not available the plugin
" does the filtering instead.
"
"
" Regarding line endings: " Regarding line endings:
" "
" git-show does not convert line endings. " git-show does not convert line endings.
@ -57,7 +58,15 @@ let s:temp_buffer = tempname()
" When writing the temporary files we preserve the original file's extension " When writing the temporary files we preserve the original file's extension
" so that repos using .gitattributes to control EOL conversion continue to " so that repos using .gitattributes to control EOL conversion continue to
" convert correctly. " convert correctly.
function! gitgutter#diff#run_diff(bufnr, preserve_full_diff) abort "
" Arguments:
"
" bufnr - the number of the buffer to be diffed
" from - 'index' or 'working_tree'; what the buffer is diffed against
" preserve_full_diff - truthy to return the full diff or falsey to return only
" the hunk headers (@@ -x,y +m,n @@); only possible if
" grep is available.
function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
while gitgutter#utility#repo_path(a:bufnr, 0) == -1 while gitgutter#utility#repo_path(a:bufnr, 0) == -1
sleep 5m sleep 5m
endwhile endwhile
@ -66,18 +75,13 @@ function! gitgutter#diff#run_diff(bufnr, preserve_full_diff) abort
throw 'gitgutter not tracked' throw 'gitgutter not tracked'
endif endif
" Wrap compound commands in parentheses to make Windows happy. " Wrap compound commands in parentheses to make Windows happy.
" bash doesn't mind the parentheses. " bash doesn't mind the parentheses.
let cmd = '(' let cmd = '('
" Append buffer number to avoid race conditions between writing and reading " Append buffer number to temp filenames to avoid race conditions between
" the files when asynchronously processing multiple buffers. " writing and reading the files when asynchronously processing multiple
" " buffers.
" Without the buffer number, index_file would have a race in the shell
" between the second process writing it (with git-show) and the first
" reading it (with git-diff).
let index_file = s:temp_index.'.'.a:bufnr
" Without the buffer number, buff_file would have a race between the " Without the buffer number, buff_file would have a race between the
" second gitgutter#process_buffer() writing the file (synchronously, below) " second gitgutter#process_buffer() writing the file (synchronously, below)
@ -87,26 +91,39 @@ function! gitgutter#diff#run_diff(bufnr, preserve_full_diff) abort
let extension = gitgutter#utility#extension(a:bufnr) let extension = gitgutter#utility#extension(a:bufnr)
if !empty(extension) if !empty(extension)
let index_file .= '.'.extension
let buff_file .= '.'.extension let buff_file .= '.'.extension
endif endif
" Write file from index to temporary file.
let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1)
let cmd .= g:gitgutter_git_executable.' --no-pager show '.index_name.' > '.index_file.' && '
" Write buffer to temporary file. " Write buffer to temporary file.
" Note: this is synchronous. " Note: this is synchronous.
call s:write_buffer(a:bufnr, buff_file) call s:write_buffer(a:bufnr, buff_file)
" Call git-diff with the temporary files. if a:from ==# 'index'
" Without the buffer number, from_file would have a race in the shell
" between the second process writing it (with git-show) and the first
" reading it (with git-diff).
let from_file = s:temp_from.'.'.a:bufnr
if !empty(extension)
let from_file .= '.'.extension
endif
" Write file from index to temporary file.
let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1)
let cmd .= g:gitgutter_git_executable.' --no-pager show '.index_name.' > '.from_file.' && '
elseif a:from ==# 'working_tree'
let from_file = gitgutter#utility#repo_path(a:bufnr, 1)
endif
" Call git-diff.
let cmd .= g:gitgutter_git_executable.' --no-pager '.g:gitgutter_git_args let cmd .= g:gitgutter_git_executable.' --no-pager '.g:gitgutter_git_args
if s:c_flag if s:c_flag
let cmd .= ' -c "diff.autorefreshindex=0"' let cmd .= ' -c "diff.autorefreshindex=0"'
let cmd .= ' -c "diff.noprefix=false"' let cmd .= ' -c "diff.noprefix=false"'
let cmd .= ' -c "core.safecrlf=false"' let cmd .= ' -c "core.safecrlf=false"'
endif endif
let cmd .= ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args.' -- '.index_file.' '.buff_file let cmd .= ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args.' -- '.from_file.' '.buff_file
" Pipe git-diff output into grep. " Pipe git-diff output into grep.
if !a:preserve_full_diff && !empty(g:gitgutter_grep) if !a:preserve_full_diff && !empty(g:gitgutter_grep)
@ -315,8 +332,14 @@ endfunction
" Returns a diff for the current hunk. " Returns a diff for the current hunk.
function! gitgutter#diff#hunk_diff(bufnr, full_diff) " Assumes there is only 1 current hunk unless the optional argument is given,
" in which case the cursor is in two hunks and the argument specifies the one
" to choose.
"
" Optional argument: 0 (to use the first hunk) or 1 (to use the second).
function! gitgutter#diff#hunk_diff(bufnr, full_diff, ...)
let modified_diff = [] let modified_diff = []
let hunk_index = 0
let keep_line = 1 let keep_line = 1
" Don't keepempty when splitting because the diff we want may not be the " Don't keepempty when splitting because the diff we want may not be the
" final one. Instead add trailing NL at end of function. " final one. Instead add trailing NL at end of function.
@ -324,6 +347,12 @@ function! gitgutter#diff#hunk_diff(bufnr, full_diff)
let hunk_info = gitgutter#diff#parse_hunk(line) let hunk_info = gitgutter#diff#parse_hunk(line)
if len(hunk_info) == 4 " start of new hunk if len(hunk_info) == 4 " start of new hunk
let keep_line = gitgutter#hunk#cursor_in_hunk(hunk_info) let keep_line = gitgutter#hunk#cursor_in_hunk(hunk_info)
if a:0 && hunk_index != a:1
let keep_line = 0
endif
let hunk_index += 1
endif endif
if keep_line if keep_line
call add(modified_diff, line) call add(modified_diff, line)

View file

@ -73,6 +73,7 @@ function! gitgutter#highlight#define_signs() abort
sign define GitGutterLineModified sign define GitGutterLineModified
sign define GitGutterLineRemoved sign define GitGutterLineRemoved
sign define GitGutterLineRemovedFirstLine sign define GitGutterLineRemovedFirstLine
sign define GitGutterLineRemovedAboveAndBelow
sign define GitGutterLineModifiedRemoved sign define GitGutterLineModifiedRemoved
sign define GitGutterDummy sign define GitGutterDummy
@ -82,11 +83,12 @@ function! gitgutter#highlight#define_signs() abort
endfunction endfunction
function! s:define_sign_text() abort function! s:define_sign_text() abort
execute "sign define GitGutterLineAdded text=" . g:gitgutter_sign_added execute "sign define GitGutterLineAdded text=" . g:gitgutter_sign_added
execute "sign define GitGutterLineModified text=" . g:gitgutter_sign_modified execute "sign define GitGutterLineModified text=" . g:gitgutter_sign_modified
execute "sign define GitGutterLineRemoved text=" . g:gitgutter_sign_removed execute "sign define GitGutterLineRemoved text=" . g:gitgutter_sign_removed
execute "sign define GitGutterLineRemovedFirstLine text=" . g:gitgutter_sign_removed_first_line execute "sign define GitGutterLineRemovedFirstLine text=" . g:gitgutter_sign_removed_first_line
execute "sign define GitGutterLineModifiedRemoved text=" . g:gitgutter_sign_modified_removed execute "sign define GitGutterLineRemovedAboveAndBelow text=" . g:gitgutter_sign_removed_above_and_below
execute "sign define GitGutterLineModifiedRemoved text=" . g:gitgutter_sign_modified_removed
endfunction endfunction
function! gitgutter#highlight#define_sign_text_highlights() abort function! gitgutter#highlight#define_sign_text_highlights() abort
@ -95,33 +97,37 @@ function! gitgutter#highlight#define_sign_text_highlights() abort
" off or disabling) we make them invisible by setting their foreground colours " off or disabling) we make them invisible by setting their foreground colours
" to the background's. " to the background's.
if g:gitgutter_signs if g:gitgutter_signs
sign define GitGutterLineAdded texthl=GitGutterAdd sign define GitGutterLineAdded texthl=GitGutterAdd
sign define GitGutterLineModified texthl=GitGutterChange sign define GitGutterLineModified texthl=GitGutterChange
sign define GitGutterLineRemoved texthl=GitGutterDelete sign define GitGutterLineRemoved texthl=GitGutterDelete
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDelete sign define GitGutterLineRemovedFirstLine texthl=GitGutterDelete
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDelete sign define GitGutterLineRemovedAboveAndBelow texthl=GitGutterDelete
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDelete
else else
sign define GitGutterLineAdded texthl=GitGutterAddInvisible sign define GitGutterLineAdded texthl=GitGutterAddInvisible
sign define GitGutterLineModified texthl=GitGutterChangeInvisible sign define GitGutterLineModified texthl=GitGutterChangeInvisible
sign define GitGutterLineRemoved texthl=GitGutterDeleteInvisible sign define GitGutterLineRemoved texthl=GitGutterDeleteInvisible
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDeleteInvisible sign define GitGutterLineRemovedFirstLine texthl=GitGutterDeleteInvisible
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDeleteInvisible sign define GitGutterLineRemovedAboveAndBelow texthl=GitGutterDeleteInvisible
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDeleteInvisible
endif endif
endfunction endfunction
function! s:define_sign_line_highlights() abort function! s:define_sign_line_highlights() abort
if g:gitgutter_highlight_lines if g:gitgutter_highlight_lines
sign define GitGutterLineAdded linehl=GitGutterAddLine sign define GitGutterLineAdded linehl=GitGutterAddLine
sign define GitGutterLineModified linehl=GitGutterChangeLine sign define GitGutterLineModified linehl=GitGutterChangeLine
sign define GitGutterLineRemoved linehl=GitGutterDeleteLine sign define GitGutterLineRemoved linehl=GitGutterDeleteLine
sign define GitGutterLineRemovedFirstLine linehl=GitGutterDeleteLine sign define GitGutterLineRemovedFirstLine linehl=GitGutterDeleteLine
sign define GitGutterLineModifiedRemoved linehl=GitGutterChangeDeleteLine sign define GitGutterLineRemovedAboveAndBelow linehl=GitGutterDeleteLine
sign define GitGutterLineModifiedRemoved linehl=GitGutterChangeDeleteLine
else else
sign define GitGutterLineAdded linehl= sign define GitGutterLineAdded linehl=
sign define GitGutterLineModified linehl= sign define GitGutterLineModified linehl=
sign define GitGutterLineRemoved linehl= sign define GitGutterLineRemoved linehl=
sign define GitGutterLineRemovedFirstLine linehl= sign define GitGutterLineRemovedFirstLine linehl=
sign define GitGutterLineModifiedRemoved linehl= sign define GitGutterLineRemovedAboveAndBelow linehl=
sign define GitGutterLineModifiedRemoved linehl=
endif endif
endfunction endfunction

View file

@ -93,6 +93,22 @@ function! s:current_hunk() abort
return current_hunk return current_hunk
endfunction endfunction
" Returns truthy if the cursor is in two hunks (which can only happen if the
" cursor is on the first line and lines above have been deleted and lines
" immediately below have been deleted) or falsey otherwise.
function! s:cursor_in_two_hunks()
let hunks = gitgutter#hunk#hunks(bufnr(''))
if line('.') == 1 && len(hunks) > 1 && hunks[0][2:3] == [0, 0] && hunks[1][2:3] == [1, 0]
return 1
endif
return 0
endfunction
" A line can be in 0 or 1 hunks, with the following exception: when the first
" line(s) of a file has been deleted, and the new second line (and
" optionally below) has been deleted, the new first line is in two hunks.
function! gitgutter#hunk#cursor_in_hunk(hunk) abort function! gitgutter#hunk#cursor_in_hunk(hunk) abort
let current_line = line('.') let current_line = line('.')
@ -151,13 +167,24 @@ function! s:hunk_op(op)
if gitgutter#utility#is_active(bufnr) if gitgutter#utility#is_active(bufnr)
" Get a (synchronous) diff. " Get a (synchronous) diff.
let [async, g:gitgutter_async] = [g:gitgutter_async, 0] let [async, g:gitgutter_async] = [g:gitgutter_async, 0]
let diff = gitgutter#diff#run_diff(bufnr, 1) let diff = gitgutter#diff#run_diff(bufnr, 'index', 1)
let g:gitgutter_async = async let g:gitgutter_async = async
call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff)) call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff))
if empty(s:current_hunk()) if empty(s:current_hunk())
call gitgutter#utility#warn('cursor is not in a hunk') call gitgutter#utility#warn('cursor is not in a hunk')
elseif s:cursor_in_two_hunks()
let choice = input('Choose hunk: upper or lower (u/l)? ')
" Clear input
normal! :<ESC>
if choice =~ 'u'
call a:op(gitgutter#diff#hunk_diff(bufnr, diff, 0))
elseif choice =~ 'l'
call a:op(gitgutter#diff#hunk_diff(bufnr, diff, 1))
else
call gitgutter#utility#warn('did not recognise your choice')
endif
else else
call a:op(gitgutter#diff#hunk_diff(bufnr, diff)) call a:op(gitgutter#diff#hunk_diff(bufnr, diff))
endif endif

View file

@ -170,7 +170,16 @@ function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort
let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs') let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs')
let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs') let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')
for line in a:modified_lines " Handle special case where the first line is the site of two hunks:
" lines deleted above at the start of the file, and lines deleted
" immediately below.
if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']]
let modified_lines = [[1, 'removed_above_and_below']] + a:modified_lines[2:]
else
let modified_lines = a:modified_lines
endif
for line in modified_lines
let line_number = line[0] " <number> let line_number = line[0] " <number>
if index(other_signs, line_number) == -1 " don't clobber others' signs if index(other_signs, line_number) == -1 " don't clobber others' signs
let name = s:highlight_name_for_change(line[1]) let name = s:highlight_name_for_change(line[1])
@ -213,6 +222,8 @@ function! s:highlight_name_for_change(text) abort
return 'GitGutterLineModified' return 'GitGutterLineModified'
elseif a:text ==# 'modified_removed' elseif a:text ==# 'modified_removed'
return 'GitGutterLineModifiedRemoved' return 'GitGutterLineModifiedRemoved'
elseif a:text ==# 'removed_above_and_below'
return 'GitGutterLineRemovedAboveAndBelow'
endif endif
endfunction endfunction

View file

@ -7,11 +7,12 @@ function! gitgutter#utility#supports_overscore_sign()
endfunction endfunction
function! gitgutter#utility#setbufvar(buffer, varname, val) function! gitgutter#utility#setbufvar(buffer, varname, val)
let dict = get(getbufvar(a:buffer, ''), 'gitgutter', {}) let buffer = +a:buffer
let dict = get(getbufvar(buffer, '', {}), 'gitgutter', {})
let needs_setting = empty(dict) let needs_setting = empty(dict)
let dict[a:varname] = a:val let dict[a:varname] = a:val
if needs_setting if needs_setting
call setbufvar(+a:buffer, 'gitgutter', dict) call setbufvar(buffer, 'gitgutter', dict)
endif endif
endfunction endfunction

View file

@ -34,9 +34,9 @@ if g:gitgutter_sign_column_always && exists('&signcolumn')
call gitgutter#utility#warn('please replace "let g:gitgutter_sign_column_always=1" with "set signcolumn=yes"') call gitgutter#utility#warn('please replace "let g:gitgutter_sign_column_always=1" with "set signcolumn=yes"')
endif endif
call s:set('g:gitgutter_override_sign_column_highlight', 1) call s:set('g:gitgutter_override_sign_column_highlight', 1)
call s:set('g:gitgutter_sign_added', '+') call s:set('g:gitgutter_sign_added', '+')
call s:set('g:gitgutter_sign_modified', '~') call s:set('g:gitgutter_sign_modified', '~')
call s:set('g:gitgutter_sign_removed', '_') call s:set('g:gitgutter_sign_removed', '_')
if gitgutter#utility#supports_overscore_sign() if gitgutter#utility#supports_overscore_sign()
call s:set('g:gitgutter_sign_removed_first_line', '‾') call s:set('g:gitgutter_sign_removed_first_line', '‾')
@ -44,14 +44,15 @@ else
call s:set('g:gitgutter_sign_removed_first_line', '_^') call s:set('g:gitgutter_sign_removed_first_line', '_^')
endif endif
call s:set('g:gitgutter_sign_modified_removed', '~_') call s:set('g:gitgutter_sign_removed_above_and_below', '[')
call s:set('g:gitgutter_git_args', '') call s:set('g:gitgutter_sign_modified_removed', '~_')
call s:set('g:gitgutter_diff_args', '') call s:set('g:gitgutter_git_args', '')
call s:set('g:gitgutter_diff_base', '') call s:set('g:gitgutter_diff_args', '')
call s:set('g:gitgutter_map_keys', 1) call s:set('g:gitgutter_diff_base', '')
call s:set('g:gitgutter_terminal_reports_focus', 1) call s:set('g:gitgutter_map_keys', 1)
call s:set('g:gitgutter_async', 1) call s:set('g:gitgutter_terminal_reports_focus', 1)
call s:set('g:gitgutter_log', 0) call s:set('g:gitgutter_async', 1)
call s:set('g:gitgutter_log', 0)
call s:set('g:gitgutter_git_executable', 'git') call s:set('g:gitgutter_git_executable', 'git')
if !executable(g:gitgutter_git_executable) if !executable(g:gitgutter_git_executable)

View file

@ -117,6 +117,16 @@ function Test_remove_first_lines()
endfunction endfunction
function Test_overlapping_hunks()
execute '3d'
execute '1d'
call s:trigger_gitgutter()
let expected = ["line=1 id=3000 name=GitGutterLineRemovedAboveAndBelow"]
call assert_equal(expected, s:signs('fixture.txt'))
endfunction
function Test_edit_file_with_same_name_as_a_branch() function Test_edit_file_with_same_name_as_a_branch()
normal 5Gi* normal 5Gi*
call system('git checkout -b fixture.txt') call system('git checkout -b fixture.txt')
@ -445,6 +455,42 @@ function Test_undo_nearby_hunk()
endfunction endfunction
function Test_overlapping_hunk_op()
func Answer(char)
call feedkeys(a:char."\<CR>")
endfunc
" Undo upper
execute '3d'
execute '1d'
call s:trigger_gitgutter()
normal gg
call timer_start(100, {-> Answer('u')} )
GitGutterUndoHunk
call s:trigger_gitgutter()
let expected = [
\ 'line=2 id=3000 name=GitGutterLineRemoved',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
" Undo lower
execute '1d'
call s:trigger_gitgutter()
normal gg
call timer_start(100, {-> Answer('l')} )
GitGutterUndoHunk
call s:trigger_gitgutter()
let expected = [
\ 'line=1 id=3000 name=GitGutterLineRemovedFirstLine',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
endfunction
function Test_write_option() function Test_write_option()
set nowrite set nowrite

View file

@ -55,7 +55,15 @@ IMPROVEMENTS:
[[GH-1978]](https://github.com/fatih/vim-go/pull/1978) [[GH-1978]](https://github.com/fatih/vim-go/pull/1978)
* Internal: install tools by their custom names * Internal: install tools by their custom names
[[GH-1984]](https://github.com/fatih/vim-go/pull/1984) [[GH-1984]](https://github.com/fatih/vim-go/pull/1984)
* Support the go-debugger features in Neovim.
[[GH-2007]](https://github.com/fatih/vim-go/pull/2007)
* color the statusline for termguicolors and Neovim.
[[GH-2014]](https://github.com/fatih/vim-go/pull/2014)
* add an option to disable highlighting of breakpoints and the current line
when debugging.
[[GH-2025]](https://github.com/fatih/vim-go/pull/2025)
* Update autocompletion to work with Go modules.
[[GH-1988]](https://github.com/fatih/vim-go/pull/1988)
BUG FIXES: BUG FIXES:
* Fix `:GoRun %` on Windows. * Fix `:GoRun %` on Windows.
@ -70,6 +78,14 @@ BUG FIXES:
[[GH-1794]](https://github.com/fatih/vim-go/pull/1794) [[GH-1794]](https://github.com/fatih/vim-go/pull/1794)
* Fix `:GoImport` when adding to an empty import block (i.e`import ()`) * Fix `:GoImport` when adding to an empty import block (i.e`import ()`)
[[GH-1938]](https://github.com/fatih/vim-go/pull/1938) [[GH-1938]](https://github.com/fatih/vim-go/pull/1938)
* Run shell commands with shellcmdflag set to `-c`.
[[GH-2006]](https://github.com/fatih/vim-go/pull/2006)
* Use the correct log output option for delve.
[[GH-1992]](https://github.com/fatih/vim-go/pull/1992)
* Pass empty arguments correctly in async jobs on Windows.
[[GH-2011]](https://github.com/fatih/vim-go/pull/2011)
* Don't close godoc scratch window when using arrow keys.
[[GH-2021]](https://github.com/fatih/vim-go/pull/2021)
BACKWARDS INCOMPATIBILITIES: BACKWARDS INCOMPATIBILITIES:
* Bump minimum required version of Vim to 7.4.2009. * Bump minimum required version of Vim to 7.4.2009.
@ -153,8 +169,7 @@ BUG FIXES:
* The `gohtmltmpl` filetype will now highlight `{{ .. }}` syntax HTML attributes * The `gohtmltmpl` filetype will now highlight `{{ .. }}` syntax HTML attributes
and some other locations. and some other locations.
[[GH-1790]](https://github.com/fatih/vim-go/pull/1790) [[GH-1790]](https://github.com/fatih/vim-go/pull/1790)
* Update using the correct logging flag option that was caused with the recent * Use the correct logging flag argument for delve.
delve changes
[[GH-1809]](https://github.com/fatih/vim-go/pull/1809) [[GH-1809]](https://github.com/fatih/vim-go/pull/1809)
* Fix gocode option string values that would cause gocode settings not to set * Fix gocode option string values that would cause gocode settings not to set
correctly correctly

View file

@ -1,5 +1,20 @@
function! s:gocodeCommand(cmd, args) abort function! s:gocodeCommand(cmd, args) abort
let bin_path = go#path#CheckBinPath("gocode") let l:gocode_bin = "gocode"
let l:gomod = go#util#gomod()
if filereadable(l:gomod)
" Save the file when in module mode so that go list can read the
" imports. If the user doesn't have autowrite or autorwriteall enabled,
" they'll need to write the file manually to get reliable results.
" See https://github.com/fatih/vim-go/pull/1988#issuecomment-428576989.
"
" TODO(bc): don't save the file when in module mode once
" golang.org/x/tools/go/packages has support for an overlay and it's used
" by gocode.
call go#cmd#autowrite()
let l:gocode_bin = "gocode-gomod"
endif
let bin_path = go#path#CheckBinPath(l:gocode_bin)
if empty(bin_path) if empty(bin_path)
return [] return []
endif endif
@ -18,6 +33,10 @@ function! s:gocodeCommand(cmd, args) abort
let cmd = extend(cmd, ['-source']) let cmd = extend(cmd, ['-source'])
endif endif
if go#config#GocodeUnimportedPackages()
let cmd = extend(cmd, ['-unimported-packages'])
endif
let cmd = extend(cmd, [a:cmd]) let cmd = extend(cmd, [a:cmd])
let cmd = extend(cmd, a:args) let cmd = extend(cmd, a:args)

View file

@ -135,6 +135,10 @@ function! go#config#SetGuruScope(scope) abort
endif endif
endfunction endfunction
function! go#config#GocodeUnimportedPackages() abort
return get(g:, 'go_gocode_unimported_packages', 0)
endfunction
let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix' let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
function! go#config#GocodeSocketType() abort function! go#config#GocodeSocketType() abort
return get(g:, 'go_gocode_socket_type', s:sock_type) return get(g:, 'go_gocode_socket_type', s:sock_type)
@ -420,6 +424,10 @@ function! go#config#HighlightVariableDeclarations() abort
return get(g:, 'go_highlight_variable_declarations', 0) return get(g:, 'go_highlight_variable_declarations', 0)
endfunction endfunction
function! go#config#HighlightDebug() abort
return get(g:, 'go_highlight_debug', 1)
endfunction
function! go#config#FoldEnable(...) abort function! go#config#FoldEnable(...) abort
if a:0 > 0 if a:0 > 0
return index(go#config#FoldEnable(), a:1) > -1 return index(go#config#FoldEnable(), a:1) > -1

View file

@ -29,6 +29,11 @@ function! s:complete(job, exit_status, data) abort
if has_key(s:state, 'job') if has_key(s:state, 'job')
call remove(s:state, 'job') call remove(s:state, 'job')
endif endif
if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif
call s:clearState() call s:clearState()
if a:exit_status > 0 if a:exit_status > 0
call go#util#EchoError(s:state['message']) call go#util#EchoError(s:state['message'])
@ -66,7 +71,6 @@ function! s:call_jsonrpc(method, ...) abort
let Cb = a:000[0] let Cb = a:000[0]
let args = a:000[1:] let args = a:000[1:]
else else
let Cb = v:none
let args = a:000 let args = a:000
endif endif
let s:state['rpcid'] += 1 let s:state['rpcid'] += 1
@ -78,9 +82,26 @@ function! s:call_jsonrpc(method, ...) abort
try try
" Use callback " Use callback
if type(Cb) == v:t_func if exists('l:Cb')
let s:ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'callback': Cb}) if has('nvim')
call ch_sendraw(s:ch, req_json) let state = {'callback': Cb}
function! state.on_data(ch, msg, event) abort
call self.state.callback(a:ch, a:msg)
endfunction
let l:ch = sockconnect('tcp', go#config#DebugAddress(), {'on_data': state.on_data, 'state': state})
call chansend(l:ch, req_json)
if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, {
\ 'request': req_json,
\ 'response': Cb,
\ })
endif
return
endif
let l:ch = ch_open(go#config#DebugAddress(), {'mode': 'nl', 'callback': Cb})
call ch_sendraw(l:ch, req_json)
if go#util#HasDebug('debugger-commands') if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, { let g:go_debug_commands = add(g:go_debug_commands, {
@ -91,9 +112,23 @@ function! s:call_jsonrpc(method, ...) abort
return return
endif endif
let ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'timeout': 20000}) if has('nvim')
call ch_sendraw(ch, req_json) let state = {'done': 0}
let resp_json = ch_readraw(ch) function! state.on_data(ch, msg, event) abort
let self.state.resp = a:msg
let self.state.done = 1
endfunction
let l:ch = sockconnect('tcp', go#config#DebugAddress(), {'on_data': state.on_data, 'state': state})
call chansend(l:ch, req_json)
while state.done == 0
sleep 50m
endwhile
let resp_json = state.resp
else
let ch = ch_open(go#config#DebugAddress(), {'mode': 'raw', 'timeout': 20000})
call ch_sendraw(ch, req_json)
let resp_json = ch_readraw(ch)
endif
if go#util#HasDebug('debugger-commands') if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, { let g:go_debug_commands = add(g:go_debug_commands, {
@ -115,7 +150,7 @@ endfunction
" Update the location of the current breakpoint or line we're halted on based on " Update the location of the current breakpoint or line we're halted on based on
" response from dlv. " response from dlv.
function! s:update_breakpoint(res) abort function! s:update_breakpoint(res) abort
if type(a:res) ==# v:t_none if type(a:res) ==# type(v:null)
return return
endif endif
@ -216,11 +251,17 @@ function! s:clearState() abort
endfunction endfunction
function! s:stop() abort function! s:stop() abort
" TODO(bc): call Detach
call go#job#Stop(s:state['job'])
call s:clearState() call s:clearState()
if has_key(s:state, 'job') if has_key(s:state, 'job')
call job_stop(s:state['job'])
call remove(s:state, 'job') call remove(s:state, 'job')
endif endif
if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif
endfunction endfunction
function! go#debug#Stop() abort function! go#debug#Stop() abort
@ -257,8 +298,10 @@ function! go#debug#Stop() abort
silent! exe bufwinnr(bufnr('__GODEBUG_VARIABLES__')) 'wincmd c' silent! exe bufwinnr(bufnr('__GODEBUG_VARIABLES__')) 'wincmd c'
silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c' silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c'
set noballooneval if has('balloon_eval')
set balloonexpr= set noballooneval
set balloonexpr=
endif
augroup vim-go-debug augroup vim-go-debug
autocmd! autocmd!
@ -453,8 +496,10 @@ function! s:start_cb(ch, json) abort
nnoremap <silent> <Plug>(go-debug-stop) :<C-u>call go#debug#Stop()<CR> nnoremap <silent> <Plug>(go-debug-stop) :<C-u>call go#debug#Stop()<CR>
nnoremap <silent> <Plug>(go-debug-print) :<C-u>call go#debug#Print(expand('<cword>'))<CR> nnoremap <silent> <Plug>(go-debug-print) :<C-u>call go#debug#Print(expand('<cword>'))<CR>
set balloonexpr=go#debug#BalloonExpr() if has('balloon_eval')
set ballooneval set balloonexpr=go#debug#BalloonExpr()
set ballooneval
endif
exe bufwinnr(oldbuf) 'wincmd w' exe bufwinnr(oldbuf) 'wincmd w'
@ -470,20 +515,29 @@ function! s:start_cb(ch, json) abort
endfunction endfunction
function! s:err_cb(ch, msg) abort function! s:err_cb(ch, msg) abort
if get(s:state, 'ready', 0) != 0
call call('s:logger', ['ERR: ', a:ch, a:msg])
return
endif
call go#util#EchoError(a:msg) call go#util#EchoError(a:msg)
let s:state['message'] += [a:msg] let s:state['message'] += [a:msg]
endfunction endfunction
function! s:out_cb(ch, msg) abort function! s:out_cb(ch, msg) abort
if get(s:state, 'ready', 0) != 0
call call('s:logger', ['OUT: ', a:ch, a:msg])
return
endif
call go#util#EchoProgress(a:msg) call go#util#EchoProgress(a:msg)
let s:state['message'] += [a:msg] let s:state['message'] += [a:msg]
" TODO: why do this in this callback?
if stridx(a:msg, go#config#DebugAddress()) != -1 if stridx(a:msg, go#config#DebugAddress()) != -1
call ch_setoptions(a:ch, { " After this block executes, Delve will be running with all the
\ 'out_cb': function('s:logger', ['OUT: ']), " breakpoints setup, so this callback doesn't have to run again; just log
\ 'err_cb': function('s:logger', ['ERR: ']), " future messages.
\}) let s:state['ready'] = 1
" Tell dlv about the breakpoints that the user added before delve started. " Tell dlv about the breakpoints that the user added before delve started.
let l:breaks = copy(s:state.breakpoint) let l:breaks = copy(s:state.breakpoint)
@ -501,17 +555,13 @@ endfunction
function! go#debug#Start(is_test, ...) abort function! go#debug#Start(is_test, ...) abort
call go#cmd#autowrite() call go#cmd#autowrite()
if has('nvim')
call go#util#EchoError('This feature only works in Vim for now; Neovim is not (yet) supported. Sorry :-(')
return
endif
if !go#util#has_job() if !go#util#has_job()
call go#util#EchoError('This feature requires Vim 8.0.0087 or newer with +job.') call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.')
return return
endif endif
" It's already running. " It's already running.
if has_key(s:state, 'job') && job_status(s:state['job']) == 'run' if has_key(s:state, 'job')
return return
endif endif
@ -556,7 +606,7 @@ function! go#debug#Start(is_test, ...) abort
\ '--output', tempname(), \ '--output', tempname(),
\ '--headless', \ '--headless',
\ '--api-version', '2', \ '--api-version', '2',
\ '--log', 'debugger', \ '--log', '--log-output', 'debugger,rpc',
\ '--listen', go#config#DebugAddress(), \ '--listen', go#config#DebugAddress(),
\ '--accept-multiclient', \ '--accept-multiclient',
\] \]
@ -807,10 +857,7 @@ function! go#debug#Restart() abort
call go#cmd#autowrite() call go#cmd#autowrite()
try try
call job_stop(s:state['job']) call go#job#Stop(s:state['job'])
while has_key(s:state, 'job') && job_status(s:state['job']) is# 'run'
sleep 50m
endwhile
let l:breaks = s:state['breakpoint'] let l:breaks = s:state['breakpoint']
let s:state = { let s:state = {
@ -857,7 +904,7 @@ function! go#debug#Breakpoint(...) abort
try try
" Check if we already have a breakpoint for this line. " Check if we already have a breakpoint for this line.
let found = v:none let found = {}
for k in keys(s:state.breakpoint) for k in keys(s:state.breakpoint)
let bt = s:state.breakpoint[k] let bt = s:state.breakpoint[k]
if bt.file == l:filename && bt.line == linenr if bt.file == l:filename && bt.line == linenr
@ -867,7 +914,7 @@ function! go#debug#Breakpoint(...) abort
endfor endfor
" Remove breakpoint. " Remove breakpoint.
if type(found) == v:t_dict if type(found) == v:t_dict && !empty(found)
call remove(s:state['breakpoint'], bt.id) call remove(s:state['breakpoint'], bt.id)
exe 'sign unplace '. found.id .' file=' . found.file exe 'sign unplace '. found.id .' file=' . found.file
if s:isActive() if s:isActive()

View file

@ -122,9 +122,12 @@ function! s:GodocView(newposition, position, content) abort
setlocal nomodifiable setlocal nomodifiable
sil normal! gg sil normal! gg
" close easily with <esc> or enter " close easily with enter
noremap <buffer> <silent> <CR> :<C-U>close<CR> noremap <buffer> <silent> <CR> :<C-U>close<CR>
noremap <buffer> <silent> <Esc> :<C-U>close<CR> noremap <buffer> <silent> <Esc> :<C-U>close<CR>
" make sure any key that sends an escape as a prefix (e.g. the arrow keys)
" don't cause the window to close.
nnoremap <buffer> <silent> <Esc>[ <Esc>[
endfunction endfunction
function! s:gogetdoc(json) abort function! s:gogetdoc(json) abort

View file

@ -0,0 +1,95 @@
function! Test_gomodVersion_highlight() abort
try
syntax on
let l:dir= gotest#write_file('gomodtest/go.mod', [
\ 'module github.com/fatih/vim-go',
\ '',
\ '\x1frequire (',
\ '\tversion/simple v1.0.0',
\ '\tversion/pseudo/premajor v1.0.0-20060102150405-0123456789abcdef',
\ '\tversion/pseudo/prerelease v1.0.0-prerelease.0.20060102150405-0123456789abcdef',
\ '\tversion/pseudo/prepatch v1.0.1-0.20060102150405-0123456789abcdef',
\ '\tversion/simple/incompatible v2.0.0+incompatible',
\ '\tversion/pseudo/premajor/incompatible v2.0.0-20060102150405-0123456789abcdef+incompatible',
\ '\tversion/pseudo/prerelease/incompatible v2.0.0-prerelease.0.20060102150405-0123456789abcdef+incompatible',
\ '\tversion/pseudo/prepatch/incompatible v2.0.1-0.20060102150405-0123456789abcdef+incompatible',
\ ')'])
let l:lineno = 4
let l:lineclose = line('$')
while l:lineno < l:lineclose
let l:line = getline(l:lineno)
let l:col = col([l:lineno, '$']) - 1
let l:idx = len(l:line) - 1
let l:from = stridx(l:line, ' ') + 1
while l:idx >= l:from
call cursor(l:lineno, l:col)
let l:synname = synIDattr(synID(l:lineno, l:col, 1), 'name')
let l:errlen = len(v:errors)
call assert_equal('gomodVersion', l:synname, 'version on line ' . l:lineno)
" continue at the next line if there was an error at this column;
" there's no need to test each column once an error is detected.
if l:errlen < len(v:errors)
break
endif
let l:col -= 1
let l:idx -= 1
endwhile
let l:lineno += 1
endwhile
finally
call delete(l:dir, 'rf')
endtry
endfunc
function! Test_gomodVersion_incompatible_highlight() abort
try
syntax on
let l:dir= gotest#write_file('gomodtest/go.mod', [
\ 'module github.com/fatih/vim-go',
\ '',
\ '\x1frequire (',
\ '\tversion/invalid/incompatible v1.0.0+incompatible',
\ '\tversion/invalid/premajor/incompatible v1.0.0-20060102150405-0123456789abcdef+incompatible',
\ '\tversion/invalid/prerelease/incompatible v1.0.0-prerelease.0.20060102150405-0123456789abcdef+incompatible',
\ '\tversion/invalid/prepatch/incompatible v1.0.1-0.20060102150405-0123456789abcdef+incompatible',
\ ')'])
let l:lineno = 4
let l:lineclose = line('$')
while l:lineno < l:lineclose
let l:line = getline(l:lineno)
let l:col = col([l:lineno, '$']) - 1
let l:idx = len(l:line) - 1
let l:from = stridx(l:line, '+')
while l:idx >= l:from
call cursor(l:lineno, l:col)
let l:synname = synIDattr(synID(l:lineno, l:col, 1), 'name')
let l:errlen = len(v:errors)
call assert_notequal('gomodVersion', l:synname, 'version on line ' . l:lineno)
" continue at the next line if there was an error at this column;
" there's no need to test each column once an error is detected.
if l:errlen < len(v:errors)
break
endif
let l:col -= 1
let l:idx -= 1
endwhile
let l:lineno += 1
endwhile
finally
call delete(l:dir, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

View file

@ -1,4 +1,7 @@
func! Test_indent_raw_string() abort func! Test_indent_raw_string() abort
" The goRawString discovery requires that syntax be enabled.
syntax on
try try
let l:dir= gotest#write_file('indent/indent.go', [ let l:dir= gotest#write_file('indent/indent.go', [
\ 'package main', \ 'package main',
@ -17,6 +20,43 @@ func! Test_indent_raw_string() abort
finally finally
call delete(l:dir, 'rf') call delete(l:dir, 'rf')
endtry endtry
endfunc
" vim: sw=2 ts=2 et try
let l:dir= gotest#write_file('indent/indent.go', [
\ 'package main',
\ '',
\ 'import "fmt"',
\ '',
\ 'func main() {',
\ "\t\x1fmsg := `",
\ '`',
\ '\tfmt.Println(msg)',
\ '}'])
silent execute "normal o" . "not indented\<Esc>"
let l:indent = indent(line('.'))
call assert_equal(0, l:indent)
finally
call delete(l:dir, 'rf')
endtry
try
let l:dir= gotest#write_file('indent/indent.go', [
\ 'package main',
\ '',
\ 'import "fmt"',
\ '',
\ 'func main() {',
\ "\tconst msg = `",
\ "\t\x1findented",
\ '`',
\ '\tfmt.Println(msg)',
\ '}'])
silent execute "normal o" . "indented\<Esc>"
let l:indent = indent(line('.'))
call assert_equal(shiftwidth(), l:indent)
finally
call delete(l:dir, 'rf')
endtry
endfunc

View file

@ -293,6 +293,10 @@ function! go#job#Start(cmd, options)
unlet l:options._start unlet l:options._start
endif endif
if go#util#HasDebug('shell-commands')
call go#util#EchoInfo('job command: ' . string(a:cmd))
endif
if has('nvim') if has('nvim')
let l:input = [] let l:input = []
if has_key(a:options, 'in_io') && a:options.in_io ==# 'file' && !empty(a:options.in_name) if has_key(a:options, 'in_io') && a:options.in_io ==# 'file' && !empty(a:options.in_name)
@ -307,7 +311,12 @@ function! go#job#Start(cmd, options)
call chanclose(job, 'stdin') call chanclose(job, 'stdin')
endif endif
else else
let job = job_start(a:cmd, l:options) let l:cmd = a:cmd
if go#util#IsWin()
let l:cmd = join(map(copy(a:cmd), function('s:winjobarg')), " ")
endif
let job = job_start(l:cmd, l:options)
endif endif
if !has_key(l:options, 'cwd') if !has_key(l:options, 'cwd')
@ -501,4 +510,33 @@ function! s:neooptions(options)
return l:options return l:options
endfunction endfunction
function! go#job#Stop(job) abort
if has('nvim')
call jobstop(a:job)
return
endif
call job_stop(a:job)
call go#job#Wait(a:job)
return
endfunction
function! go#job#Wait(job) abort
if has('nvim')
call jobwait(a:job)
return
endif
while job_status(a:job) is# 'run'
sleep 50m
endwhile
endfunction
function! s:winjobarg(idx, val) abort
if empty(a:val)
return '""'
endif
return a:val
endfunction
" vim: sw=2 ts=2 et " vim: sw=2 ts=2 et

View file

@ -3,7 +3,7 @@ let s:go_major_version = ""
function! go#mod#Format() abort function! go#mod#Format() abort
" go mod only exists in `v1.11` " go mod only exists in `v1.11`
if empty(s:go_major_version) if empty(s:go_major_version)
let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\) ') let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
let s:go_major_version = str2nr(tokens[1]) let s:go_major_version = str2nr(tokens[1])
endif endif

View file

@ -54,11 +54,11 @@ function! go#statusline#Show() abort
" only update highlight if status has changed. " only update highlight if status has changed.
if status_text != s:last_status if status_text != s:last_status
if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass" if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass"
hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 guibg=#5fd700 guifg=#005f00
elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling" elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling"
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 guibg=#ff8700 guifg=#870000
elseif status.state =~ "failed" elseif status.state =~ "failed"
hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 guibg=#ff0000 guifg=#5f0000
endif endif
endif endif

View file

@ -127,6 +127,13 @@ function! go#util#gopath() abort
return substitute(s:exec(['go', 'env', 'GOPATH'])[0], '\n', '', 'g') return substitute(s:exec(['go', 'env', 'GOPATH'])[0], '\n', '', 'g')
endfunction endfunction
" gomod returns 'go env GOMOD'. gomod changes depending on the folder. Don't
" use go#util#env as it caches the value.
function! go#util#gomod() abort
return substitute(s:exec(['go', 'env', 'GOMOD'])[0], '\n', '', 'g')
endfunction
function! go#util#osarch() abort function! go#util#osarch() abort
return go#util#env("goos") . '_' . go#util#env("goarch") return go#util#env("goos") . '_' . go#util#env("goarch")
endfunction endfunction
@ -137,12 +144,13 @@ endfunction
" so that we always use a standard POSIX-compatible Bourne shell (and not e.g. " so that we always use a standard POSIX-compatible Bourne shell (and not e.g.
" csh, fish, etc.) See #988 and #1276. " csh, fish, etc.) See #988 and #1276.
function! s:system(cmd, ...) abort function! s:system(cmd, ...) abort
" Preserve original shell and shellredir values " Preserve original shell, shellredir and shellcmdflag values
let l:shell = &shell let l:shell = &shell
let l:shellredir = &shellredir let l:shellredir = &shellredir
let l:shellcmdflag = &shellcmdflag
if !go#util#IsWin() && executable('/bin/sh') if !go#util#IsWin() && executable('/bin/sh')
set shell=/bin/sh shellredir=>%s\ 2>&1 set shell=/bin/sh shellredir=>%s\ 2>&1 shellcmdflag=-c
endif endif
try try
@ -151,6 +159,7 @@ function! s:system(cmd, ...) abort
" Restore original values " Restore original values
let &shell = l:shell let &shell = l:shell
let &shellredir = l:shellredir let &shellredir = l:shellredir
let &shellcmdflag = l:shellcmdflag
endtry endtry
endfunction endfunction

View file

@ -148,9 +148,6 @@ The following plugins are supported for use with vim-go:
https://github.com/SirVer/ultisnips or https://github.com/SirVer/ultisnips or
https://github.com/joereynolds/vim-minisnip https://github.com/joereynolds/vim-minisnip
* For a better documentation viewer check out:
https://github.com/garyburd/go-explorer
* Integration with `delve` (Neovim only): * Integration with `delve` (Neovim only):
https://github.com/jodosha/vim-godebug https://github.com/jodosha/vim-godebug
@ -1614,6 +1611,14 @@ package and packages that have been installed will proposed.
> >
let g:go_gocode_propose_source = 1 let g:go_gocode_propose_source = 1
< <
*'g:go_gocode_unimported_packages'*
Specifies whether `gocode` should include suggestions from unimported
packages. By default it is disabled.
>
let g:go_gocode_unimported_packages = 0
<
*'g:go_gocode_socket_type'* *'g:go_gocode_socket_type'*
Specifies whether `gocode` should use a different socket type. By default Specifies whether `gocode` should use a different socket type. By default
@ -1902,7 +1907,7 @@ The `gohtmltmpl` filetype is automatically set for `*.tmpl` files; the
*gomod* *ft-gomod-syntax* *gomod* *ft-gomod-syntax*
go.mod file syntax~ go.mod file syntax~
The `gomod` 'filetype' provides syntax highlighting for Go's module file The `gomod` 'filetype' provides syntax highlighting for Go's module file
`go.mod` `go.mod`
@ -1924,10 +1929,10 @@ features:
* Toggle breakpoint. * Toggle breakpoint.
* Stack operation continue/next/step out. * Stack operation continue/next/step out.
This feature requires Vim 8.0.0087 or newer with the |+job| feature. Neovim This feature requires either Vim 8.0.0087 or newer with the |+job| feature or
does _not_ work (yet). Neovim. This features also requires Delve 1.0.0 or newer, and it is
This requires Delve 1.0.0 or newer, and it is recommended to use Go 1.10 or recommended to use Go 1.10 or newer, as its new caching will speed up
newer, as its new caching will speed up recompiles. recompiles.
*go-debug-intro* *go-debug-intro*
GETTING STARTED WITH THE DEBUGGER~ GETTING STARTED WITH THE DEBUGGER~
@ -2112,6 +2117,14 @@ Defaults to `127.0.0.1:8181`:
let g:go_debug_address = '127.0.0.1:8181' let g:go_debug_address = '127.0.0.1:8181'
< <
*'g:go_highlight_debug'*
Highlight the current line and breakpoints in the debugger.
>
let g:go_highlight_debug = 1
<
============================================================================== ==============================================================================
FAQ TROUBLESHOOTING *go-troubleshooting* FAQ TROUBLESHOOTING *go-troubleshooting*

View file

@ -31,6 +31,11 @@ au BufReadPost *.s call s:gofiletype_post()
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
" remove the autocommands for modsim3, and lprolog files so that their
" highlight groups, syntax, etc. will not be loaded. *.MOD is included, so
" that on case insensitive file systems the module2 autocmds will not be
" executed.
au! BufNewFile,BufRead *.mod,*.MOD
" Set the filetype if the first non-comment and non-blank line starts with " Set the filetype if the first non-comment and non-blank line starts with
" 'module <path>'. " 'module <path>'.
au BufNewFile,BufRead go.mod call s:gomod() au BufNewFile,BufRead go.mod call s:gomod()

View file

@ -24,7 +24,7 @@ if exists("*GoIndent")
finish finish
endif endif
function! GoIndent(lnum) function! GoIndent(lnum) abort
let prevlnum = prevnonblank(a:lnum-1) let prevlnum = prevnonblank(a:lnum-1)
if prevlnum == 0 if prevlnum == 0
" top of file " top of file
@ -38,10 +38,17 @@ function! GoIndent(lnum)
let ind = previ let ind = previ
if prevl =~ ' = `[^`]*$' for synid in synstack(a:lnum, 1)
" previous line started a multi-line raw string if synIDattr(synid, 'name') == 'goRawString'
return 0 if prevl =~ '\%(\%(:\?=\)\|(\|,\)\s*`[^`]*$'
endif " previous line started a multi-line raw string
return 0
endif
" return -1 to keep the current indent.
return -1
endif
endfor
if prevl =~ '[({]\s*$' if prevl =~ '[({]\s*$'
" previous line opened a block " previous line opened a block
let ind += shiftwidth() let ind += shiftwidth()

View file

@ -47,10 +47,11 @@ let s:packages = {
\ 'errcheck': ['github.com/kisielk/errcheck'], \ 'errcheck': ['github.com/kisielk/errcheck'],
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'], \ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'],
\ 'gocode': ['github.com/mdempsky/gocode', {'windows': ['-ldflags', '-H=windowsgui']}], \ 'gocode': ['github.com/mdempsky/gocode', {'windows': ['-ldflags', '-H=windowsgui']}],
\ 'gocode-gomod': ['github.com/stamblerre/gocode'],
\ 'godef': ['github.com/rogpeppe/godef'], \ 'godef': ['github.com/rogpeppe/godef'],
\ 'gogetdoc': ['github.com/zmb3/gogetdoc'], \ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
\ 'goimports': ['golang.org/x/tools/cmd/goimports'], \ 'goimports': ['golang.org/x/tools/cmd/goimports'],
\ 'golint': ['github.com/golang/lint/golint'], \ 'golint': ['golang.org/x/lint/golint'],
\ 'gometalinter': ['github.com/alecthomas/gometalinter'], \ 'gometalinter': ['github.com/alecthomas/gometalinter'],
\ 'gomodifytags': ['github.com/fatih/gomodifytags'], \ 'gomodifytags': ['github.com/fatih/gomodifytags'],
\ 'gorename': ['golang.org/x/tools/cmd/gorename'], \ 'gorename': ['golang.org/x/tools/cmd/gorename'],

View file

@ -374,8 +374,10 @@ function! s:hi()
hi def goCoverageUncover ctermfg=red guifg=#F92672 hi def goCoverageUncover ctermfg=red guifg=#F92672
" :GoDebug commands " :GoDebug commands
hi GoDebugBreakpoint term=standout ctermbg=117 ctermfg=0 guibg=#BAD4F5 guifg=Black if go#config#HighlightDebug()
hi GoDebugCurrent term=reverse ctermbg=12 ctermfg=7 guibg=DarkBlue guifg=White hi GoDebugBreakpoint term=standout ctermbg=117 ctermfg=0 guibg=#BAD4F5 guifg=Black
hi GoDebugCurrent term=reverse ctermbg=12 ctermfg=7 guibg=DarkBlue guifg=White
endif
endfunction endfunction
augroup vim-go-hi augroup vim-go-hi

View file

@ -37,10 +37,26 @@ syntax match gomodReplaceOperator "\v\=\>"
highlight default link gomodReplaceOperator Operator highlight default link gomodReplaceOperator Operator
" highlight semver, note that this is very simple. But it works for now " highlight versions:
syntax match gomodVersion "v\d\+\.\d\+\.\d\+" " * vX.Y.Z
syntax match gomodVersion "v\d\+\.\d\+\.\d\+-\S*" " * vX.0.0-yyyyymmddhhmmss-abcdefabcdef
syntax match gomodVersion "v\d\+\.\d\+\.\d\++incompatible" " * vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
" * vX.Y.(Z+1)-0.yyyymmddhhss-abcdefabcdef
" * +incompatible suffix when X > 1
" match vX.Y.Z and their prereleases
syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14}-\x\+\)\?"
" match target when most recent version before the target is X.Y.Z
syntax match gomodVersion "v\d\+\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14}-\x\+\)\)\?"
" match target without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef)
syntax match gomodVersion "v\d\+\.0\.0-\d\{14\}-\x\+"
" match vX.Y.Z and their prereleases for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14\}-\x\+\)\?\%(+incompatible\>\)\?"
" match target when most recent version before the target is X.Y.Z for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14\}-\x\+\)\)\?\%(+incompatible\>\)\?"
" match target without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef) for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.0\.0-\d\{14\}-\x\+\%(+incompatible\>\)\?"
highlight default link gomodVersion Identifier highlight default link gomodVersion Identifier
let b:current_syntax = "gomod" let b:current_syntax = "gomod"

View file

@ -115,7 +115,7 @@ syn match mkdRule /^\s*_\s\{0,1}_\s\{0,1}_\(_\|\s\)*$/
" YAML frontmatter " YAML frontmatter
if get(g:, 'vim_markdown_frontmatter', 0) if get(g:, 'vim_markdown_frontmatter', 0)
syn include @yamlTop syntax/yaml.vim syn include @yamlTop syntax/yaml.vim
syn region Comment matchgroup=mkdDelimiter start="\%^---$" end="^\(---\|...\)$" contains=@yamlTop keepend syn region Comment matchgroup=mkdDelimiter start="\%^---$" end="^\(---\|\.\.\.\)$" contains=@yamlTop keepend
unlet! b:current_syntax unlet! b:current_syntax
endif endif

View file

@ -189,6 +189,14 @@ g:multi_cursor_select_all_key
#### **Q** <kbd>CTRL</kbd>+<kbd>n</kbd> doesn't seem to work in gVIM? #### **Q** <kbd>CTRL</kbd>+<kbd>n</kbd> doesn't seem to work in gVIM?
**A** Try setting `set selection=inclusive` in your `~/.gvimrc` **A** Try setting `set selection=inclusive` in your `~/.gvimrc`
**A** Alternatively, you can just temporarily disable _exclusive_ selection whenever the plugin is active:
```VimL
augroup MultipleCursorsSelectionFix
autocmd User MultipleCursorsPre if &selection ==# 'exclusive' | let g:multi_cursor_save_selection = &selection | set selection=inclusive | endif
autocmd User MultipleCursorsPost if exists('g:multi_cursor_save_selection') | let &selection = g:multi_cursor_save_selection | unlet g:multi_cursor_save_selection | endif
augroup END
```
#### **Q** is it also working on Mac? #### **Q** is it also working on Mac?
**A** On Mac OS, [MacVim](https://code.google.com/p/macvim/) is known to work. **A** On Mac OS, [MacVim](https://code.google.com/p/macvim/) is known to work.

Some files were not shown because too many files have changed in this diff Show more