mirror of
1
0
Fork 0

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>
" 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
for l:line in a:lines[:10]
if match(l:line, '^Traceback') >= 0
@ -42,8 +48,9 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
endfunction
call ale#linter#Define('ansible', {
\ 'name': 'ansible',
\ 'executable': 'ansible',
\ 'command': 'ansible-lint -p %t',
\ 'name': 'ansible_lint',
\ 'aliases': ['ansible', 'ansible-lint'],
\ 'executable_callback': 'ale_linters#ansible#ansible_lint#GetExecutable',
\ 'command': '%e -p %t',
\ '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:
" 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.
" This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '')

View File

@ -4,7 +4,7 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" 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.
" This will disable compile_commands.json detection.
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>
" 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
" If we can't run dub, then skip this command.
if !executable('dub')
@ -22,7 +8,7 @@ function! ale_linters#d#dmd#DUBCommand(buffer) abort
return ''
endif
let l:dub_file = s:FindDUBConfig(a:buffer)
let l:dub_file = ale#d#FindDUBConfig(a:buffer)
if empty(l:dub_file)
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:text = l:match[4]
if l:type is# 'C'
let l:type = 'E'
elseif l:type is# 'R'
" Refactoring opportunities
if l:type is# 'F'
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
call add(l:output, {
@ -29,9 +37,16 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
return l:output
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', {
\ 'name': 'credo',
\ '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',
\})

View File

@ -25,10 +25,17 @@ function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort
return l:output
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', {
\ 'name': 'dialyxir',
\ 'executable': 'mix',
\ 'command': 'mix help dialyzer && mix dialyzer',
\ 'command_callback': 'ale_linters#elixir#dialyxir#GetCommand',
\ 'callback': 'ale_linters#elixir#dialyxir#Handle',
\})

View File

@ -29,10 +29,17 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
return l:output
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', {
\ 'name': 'dogma',
\ 'executable': 'mix',
\ 'command': 'mix help dogma && mix dogma %s --format=flycheck',
\ 'command_callback': 'ale_linters#elixir#dogma#GetCommand',
\ 'lint_file': 1,
\ '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
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
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)
@ -49,8 +39,8 @@ function! ale_linters#elixir#mix#GetCommand(buffer) abort
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root)
\ . l:mix_build_path
\ . ' mix compile %s'
\ . l:mix_build_path
\ . ' mix compile %s'
endfunction
call ale#linter#Define('elixir', {

View File

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

View File

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

View File

@ -2,7 +2,7 @@
" Description: PMD for Java files
function! ale_linters#java#pmd#Handle(buffer, lines) abort
let l:pattern = '"\(\d\+\)",".\+","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
let l:pattern = '"\(\d\+\)",".*","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
let l:output = []
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)
endif
let l:command .= ' -'
let l:command .= ' --filename %s -'
return l:command
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
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
" Matches patterns like the following:
let l:pattern = '^.*:\(\d\+\):\(\d\+\):\(\w\+\) - \(.*\)$'
let l:output = []
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
for l:match in ale#util#GetMatches(a:lines, l:pattern)
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
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'command': '%e --diff --output-format=emacs %s',
\ 'executable_callback': ale#VarFunc('php_psalm_executable'),
\ 'callback': 'ale_linters#php#psalm#Handle',
\ 'lint_file': 1,
\ 'lsp': 'stdio',
\ 'executable_callback': ale#node#FindExecutableFunc('psalm_langserver', [
\ 'vendor/bin/psalm-language-server',
\ ]),
\ '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')
\ . ' -f json --no-progress --no-color'
\ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args
endfunction

View File

@ -5,6 +5,7 @@
" Description: updated to use stdio
call ale#Set('ruby_solargraph_executable', 'solargraph')
call ale#Set('ruby_solargraph_options', {})
function! ale_linters#ruby#solargraph#GetCommand(buffer) abort
return '%e' . ale#Pad('stdio')
@ -17,4 +18,5 @@ call ale#linter#Define('ruby', {
\ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'),
\ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand',
\ '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_default_feature_behavior', 'default')
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
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 = ''
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 '
\ . (l:use_check ? 'check' : 'build')
\ . l:subcommand
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features
\ . l:clippy_options
endfunction
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 s:lint_timer = -1
let s:queued_buffer_number = -1
let s:should_lint_file_for_buffer = {}
let s:getcmdwintype_exists = exists('*getcmdwintype')
" Return 1 if a file is too large for ALE to handle.
function! ale#FileTooLarge(buffer) abort
@ -20,8 +19,6 @@ function! ale#FileTooLarge(buffer) abort
return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0
endfunction
let s:getcmdwintype_exists = exists('*getcmdwintype')
" A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing(buffer) abort
@ -86,18 +83,44 @@ function! ale#ShouldDoNothing(buffer) abort
return 0
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])
function! ale#Queue(delay, ...) abort
if a:0 > 2
throw 'too many arguments!'
endif
" Default linting_flag to ''
let l:linting_flag = get(a:000, 0, '')
let l:buffer = get(a:000, 1, bufnr(''))
let l:buffer = get(a:000, 1, v:null)
if l:linting_flag isnot# '' && l:linting_flag isnot# 'lint_file'
throw "linting_flag must be either '' or 'lint_file'"
if l:buffer is v:null
let l:buffer = bufnr('')
endif
if type(l:buffer) isnot v:t_number
@ -108,80 +131,24 @@ function! ale#Queue(delay, ...) abort
return
endif
" Remember that we want to check files for this buffer.
" We will remember this until we finally run the linters, via any event.
if l:linting_flag is# 'lint_file'
let s:should_lint_file_for_buffer[l:buffer] = 1
endif
" Default linting_flag to ''
let l:should_lint_file = get(a:000, 0) is# 'lint_file'
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
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
let s:queued_buffer_number = l:buffer
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
let s:lint_timer = timer_start(
\ a:delay,
\ function('s:Lint', [l:buffer, l:should_lint_file])
\)
else
call ale#Lint(-1, l:buffer)
call s:Lint(l:buffer, l:should_lint_file, 0)
endif
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', {})
" 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
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
let l:buffer = bufnr('')
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=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
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=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
@ -172,6 +181,10 @@ function! ale#assert#TearDownLinterTest() abort
delcommand AssertLSPOptions
endif
if exists(':AssertLSPConfig')
delcommand AssertLSPConfig
endif
if exists(':AssertLSPLanguage')
delcommand AssertLSPLanguage
endif

View File

@ -26,7 +26,20 @@ function! ale#cursor#TruncatedEcho(original_message) abort
" The message is truncated and saved to the history.
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.
" 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] = {
\ 'job_list': [],
\ 'active_linter_list': [],
\ 'active_other_sources_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
@ -97,6 +98,7 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
return !empty(get(l:info, 'active_linter_list', []))
\ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction
" Register a temporary file to be managed with the ALE engine for
@ -177,20 +179,27 @@ function! s:GatherOutput(job_id, line) abort
endif
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, {})
if empty(l:info)
return
endif
" Remove this linter from the list of active linters.
" This may have already been done when the job exits.
call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name')
if !a:from_other_source
" Remove this linter from the list of active linters.
" 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
" 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.
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 = []
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
function! ale#engine#SetResults(buffer, loclist) abort
@ -335,7 +344,7 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfor
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:new_loclist = []
@ -368,6 +377,10 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
\ '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')
let l:item.code = l:old_item.code
endif
@ -691,6 +704,7 @@ endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
" Problems from other sources will be kept.
let l:name_map = {}
for l:linter in a:linters
@ -699,7 +713,7 @@ function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
call filter(
\ 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

View File

@ -250,6 +250,11 @@ let s:default_registry = {
\ '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.',
\ },
\ '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.

View File

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

View File

@ -1,5 +1,6 @@
call ale#Set('json_jq_executable', 'jq')
call ale#Set('json_jq_options', '')
call ale#Set('json_jq_filters', '.')
function! ale#fixers#jq#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'json_jq_executable')
@ -7,9 +8,15 @@ endfunction
function! ale#fixers#jq#Fix(buffer) abort
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 {
\ 'command': ale#Escape(ale#fixers#jq#GetExecutable(a:buffer))
\ . ' . ' . l:options,
\ . ' ' . l:filters . ' '
\ . l:options,
\}
endfunction

View File

@ -9,7 +9,7 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --auto-correct %t'
\ . ' --auto-correct --force-exclusion %t'
endfunction
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>
" 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.
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 = []
endif
if !exists('g:ale_rust_ignore_secondary_spans')
let g:ale_rust_ignore_secondary_spans = 0
endif
function! s:FindSpan(buffer, span) abort
if ale#path#IsBufferPath(a:buffer, a:span.file_name) || a:span.file_name is# '<anon>'
return a:span
@ -47,6 +51,10 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
for l:root_span in l:error.spans
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)
call add(l:output, {
\ 'lnum': l:span.line_start,

View File

@ -35,6 +35,7 @@ let s:default_ale_linters = {
\ 'hack': ['hack'],
\ 'help': [],
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'],
\ 'spec': [],
@ -255,6 +256,24 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
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
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
@ -337,8 +356,9 @@ endfunction
function! s:GetAliasedFiletype(original_filetype) abort
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
\|| type(l:buffer_aliases) is v:t_string
return l:buffer_aliases
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.
" init_request_id: The ID for the init request.
" 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.
" message_queue: Messages queued for sending to callbacks.
" 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,
\ 'init_request_id': 0,
\ 'init_options': a:init_options,
\ 'config': {},
\ 'callback_list': [],
\ 'message_queue': [],
\ 'capabilities_queue': [],
@ -41,6 +43,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
\ 'completion': 0,
\ 'completion_trigger_characters': [],
\ 'definition': 0,
\ 'symbol_search': 0,
\ },
\}
endif
@ -203,8 +206,31 @@ function! s:UpdateCapabilities(conn, capabilities) abort
if get(a:capabilities, 'definitionProvider') is v:true
let a:conn.capabilities.definition = 1
endif
if get(a:capabilities, 'workspaceSymbolProvider') is v:true
let a:conn.capabilities.symbol_search = 1
endif
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
if get(a:response, 'method', '') is# 'initialize'
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_trigger_characters = ['.']
let l:conn.capabilities.definition = 1
let l:conn.capabilities.symbol_search = 1
endfunction
" Start a program for LSP servers.

View File

@ -130,6 +130,12 @@ function! ale#lsp#message#References(buffer, line, column) abort
\}]
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
return [0, 'textDocument/hover', {
\ 'textDocument': {
@ -138,3 +144,9 @@ function! ale#lsp#message#Hover(buffer, line, column) abort
\ 'position': {'line': a:line - 1, 'character': a:column},
\}]
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'))
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
endfor
endfor

View File

@ -38,7 +38,7 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
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
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', [])
\ + 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
function! s:HandleLSPErrorMessage(linter_name, response) abort
@ -140,6 +140,18 @@ function! ale#lsp_linter#GetOptions(buffer, linter) abort
return l:initialization_options
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
" receive messages for the document.
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)
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:details = {
@ -198,6 +211,8 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
\ '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 g:ale_history_enabled && !empty(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> && '
" This function can be used changing the directory for a linter command.
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
" Output 'cd <buffer_filename_directory> && '

View File

@ -46,11 +46,14 @@ function! ale#preview#ShowSelection(item_list) abort
" Create lines to display to users.
for l:item in a:item_list
let l:match = get(l:item, 'match', '')
call add(
\ l:lines,
\ l:item.filename
\ . ':' . l:item.line
\ . ':' . l:item.column,
\ . ':' . l:item.column
\ . (!empty(l:match) ? ' ' . l:match : ''),
\)
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*
*b:ale_c_clangtidy_checks*
Type: |List|
Default: `['*']`
Default: `[]`
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*
*b:ale_cpp_clangtidy_checks*
Type: |List|
Default: `['*']`
Default: `[]`
The checks to enable for clang-tidy with the `-checks` argument.

View File

@ -2,6 +2,10 @@
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*

View File

@ -2,6 +2,17 @@
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*

View File

@ -306,6 +306,7 @@ given the above setup are as follows.
`AssertLinterNotExecuted` - Check that linters will not be executed.
`AssertLSPLanguage language` - Check the language 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.
`AssertLSPAddress address` - Check the address to an LSP server.

View File

@ -2,6 +2,29 @@
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*

View File

@ -40,5 +40,18 @@ configured on your project's `mix.exs`.
See https://github.com/jeremyjh/dialyxir#with-explaining-stuff for more
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:

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`.
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*

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
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*
*b:ale_rust_cargo_avoid_whole_workspace*
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.
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*
@ -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']
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*

View File

@ -2,6 +2,24 @@
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*

View File

@ -9,15 +9,20 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint|
3.1 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion|
5.2 Go To Definition..................|ale-go-to-definition|
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.1 Highlights........................|ale-highlights|
6.2 Options for write-good Linter.....|ale-write-good-options|
7. Integration Documentation............|ale-integrations|
ansible...............................|ale-ansible-options|
ansible-lint........................|ale-ansible-ansible-lint|
asciidoc..............................|ale-asciidoc-options|
write-good..........................|ale-asciidoc-write-good|
asm...................................|ale-asm-options|
@ -67,16 +72,19 @@ CONTENTS *ale-contents*
cuda..................................|ale-cuda-options|
nvcc................................|ale-cuda-nvcc|
d.....................................|ale-d-options|
dls.................................|ale-d-dls|
uncrustify..........................|ale-d-uncrustify|
dart..................................|ale-dart-options|
dartanalyzer........................|ale-dart-dartanalyzer|
dartfmt.............................|ale-dart-dartfmt|
dockerfile............................|ale-dockerfile-options|
dockerfile_lint.....................|ale-dockerfile-dockerfile_lint|
hadolint............................|ale-dockerfile-hadolint|
elixir................................|ale-elixir-options|
mix.................................|ale-elixir-mix|
mix_format..........................|ale-elixir-mix-format|
dialyxir............................|ale-elixir-dialyxir|
elixir-ls...........................|ale-elixir-elixir-ls|
elm...................................|ale-elm-options|
elm-format..........................|ale-elm-elm-format|
elm-make............................|ale-elm-elm-make|
@ -125,6 +133,8 @@ CONTENTS *ale-contents*
stack-build.........................|ale-haskell-stack-build|
stylish-haskell.....................|ale-haskell-stylish-haskell|
hie.................................|ale-haskell-hie|
hcl...................................|ale-hcl-options|
terraform-fmt.......................|ale-hcl-terraform-fmt|
html..................................|ale-html-options|
htmlhint............................|ale-html-htmlhint|
tidy................................|ale-html-tidy|
@ -203,6 +213,8 @@ CONTENTS *ale-contents*
perl................................|ale-perl-perl|
perlcritic..........................|ale-perl-perlcritic|
perltidy............................|ale-perl-perltidy|
perl6.................................|ale-perl6-options|
perl6...............................|ale-perl6-perl6|
php...................................|ale-php-options|
langserver..........................|ale-php-langserver|
phan................................|ale-php-phan|
@ -218,6 +230,8 @@ CONTENTS *ale-contents*
write-good..........................|ale-pod-write-good|
pony..................................|ale-pony-options|
ponyc...............................|ale-pony-ponyc|
prolog................................|ale-prolog-options|
swipl...............................|ale-prolog-swipl|
proto.................................|ale-proto-options|
protoc-gen-lint.....................|ale-proto-protoc-gen-lint|
pug...................................|ale-pug-options|
@ -293,6 +307,7 @@ CONTENTS *ale-contents*
tcl...................................|ale-tcl-options|
nagelfar............................|ale-tcl-nagelfar|
terraform.............................|ale-terraform-options|
fmt.................................|ale-terraform-fmt|
tflint..............................|ale-terraform-tflint|
tex...................................|ale-tex-options|
chktex..............................|ale-tex-chktex|
@ -393,11 +408,11 @@ Notes:
* CSS: `csslint`, `prettier`, `stylelint`
* Cucumber: `cucumber`
* Cython (pyrex filetype): `cython`
* D: `dmd`, `uncrustify`
* D: `dls`, `dmd`, `uncrustify`
* Dafny: `dafny`!!
* Dart: `dartanalyzer`!!, `language_server`, dartfmt!!
* Dockerfile: `hadolint`
* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!
* Dockerfile: `dockerfile_lint`, `hadolint`
* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!, `elixir-ls`
* Elm: `elm-format, elm-make`
* Erb: `erb`, `erubi`, `erubis`
* Erlang: `erlc`, `SyntaxErl`
@ -413,6 +428,7 @@ Notes:
* Haml: `haml-lint`
* Handlebars: `ember-template-lint`
* 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`
* Idris: `idris`
* Java: `checkstyle`, `javac`, `google-java-format`, `PMD`, `javalsp`, `uncrustify`
@ -438,10 +454,12 @@ Notes:
* OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`, `ocamlformat`
* Pawn: `uncrustify`
* Perl: `perl -c`, `perl-critic`, `perltidy`
* Perl6: `perl6 -c`
* PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`, `psalm`!!
* PO: `alex`!!, `msgfmt`, `proselint`, `write-good`
* Pod: `alex`!!, `proselint`, `write-good`
* Pony: `ponyc`
* Prolog: `swipl`
* proto: `protoc-gen-lint`
* Pug: `pug-lint`
* Puppet: `languageserver`, `puppet`, `puppet-lint`
@ -464,7 +482,7 @@ Notes:
* SQL: `sqlint`, `sqlfmt`
* Swift: `swiftlint`, `swiftformat`
* Tcl: `nagelfar`!!
* Terraform: `tflint`
* Terraform: `fmt`, `tflint`
* Texinfo: `alex`!!, `proselint`, `write-good`
* Text^: `alex`!!, `proselint`, `redpen`, `textlint`, `vale`, `write-good`
* 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|
-------------------------------------------------------------------------------
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*
@ -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.
Suggestions will be made while you type after completion is enabled.
Completion can be enabled by setting |g:ale_completion_enabled| to `1`. The
delay for completion can be configured with |g:ale_completion_delay|. ALE will
only suggest so many possible matches for completion. The maximum number of
items can be controlled with |g:ale_completion_max_suggestions|.
Completion can be enabled by setting |g:ale_completion_enabled| to `1`. This
setting must be set to `1` before ALE is loaded. The delay for completion can
be configured with |g:ale_completion_delay|. ALE will only suggest so many
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
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.
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
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
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*
@ -876,6 +979,9 @@ g:ale_completion_enabled *g:ale_completion_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|
@ -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`
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
linters for specific filetypes for a given buffer. >
`b:ale_linter_aliases` can be set to a |List| or a |String|, to tell ALE to
load the linters for specific filetypes for a given buffer. >
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.
@ -1306,6 +1414,7 @@ g:ale_linters *g:ale_linters*
\ 'hack': ['hack'],
\ 'help': [],
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'],
\ 'spec': [],
@ -2049,6 +2158,14 @@ ALEHover *ALEHover*
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*
@ -2568,6 +2685,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`initialization_options_callback` may be defined to
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
accepting a buffer number. A |String| should be
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`
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
specified. `command_callback` is generally recommended when a command string
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
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()*
@ -2756,10 +2905,21 @@ b:ale_linted *b:ale_linted*
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*
ALELintPost *ALELintPost-autocmd*
*ALELintPost*
ALEFixPre *ALEFixPre-autocmd*
*ALEFixPre*
ALEFixPost *ALEFixPost-autocmd*
*ALEFixPost*
These |User| autocommands are triggered before and after every lint or fix
cycle. They can be used to update statuslines, send notifications, etc.
@ -2773,7 +2933,7 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd!
autocmd User ALELintPre hi Statusline ctermfg=darkgrey
autocmd User ALELintPost hi Statusline ctermfg=NONE
augroup end
augroup END
<
Or to display the progress in the statusline:
>
@ -2783,10 +2943,11 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd!
autocmd User ALELintPre let s:ale_running = 1 | redrawstatus
autocmd User ALELintPost let s:ale_running = 0 | redrawstatus
augroup end
augroup END
<
ALEJobStarted *ALEJobStarted-autocmd*
*ALEJobStarted*
This |User| autocommand is triggered immediately after a job is successfully
run. This provides better accuracy for checking linter status with
@ -2794,6 +2955,22 @@ ALEJobStarted *ALEJobStarted-autocmd*
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*

View File

@ -194,6 +194,9 @@ command! -bar ALEFindReferences :call ale#references#Find()
command! -bar ALEHover :call ale#hover#Show(bufnr(''), getcurpos()[1],
\ 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
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<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
en
let filpath = fnamemodify(filpath, ':p')
let bufnr = bufnr('^'.filpath.'$')
let bufnr = bufnr('^'.fnameescape(filpath).'$')
if (!filereadable(filpath) && bufnr < 1)
if (a:line =~ '[\/]\?\[\d\+\*No Name\]$')
let bufnr = str2nr(matchstr(a:line, '[\/]\?\[\zs\d\+\ze\*No Name\]$'))

View File

@ -255,6 +255,7 @@ function! s:findAndRevealPath(pathStr)
endif
try
let l:pathStr = g:NERDTreePath.Resolve(l:pathStr)
let l:pathObj = g:NERDTreePath.New(l:pathStr)
catch /^NERDTree.InvalidArgumentsError/
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
" will be reloaded.
function! s:refreshRoot()
if !g:NERDTree.IsOpen()
return
endif
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.render()
redraw
call nerdtree#exec(l:curWin . "wincmd w")
call nerdtree#echo("Refreshing the root node. This could take a while... DONE")
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=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
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 NERDTreeCWD call NERDTreeCWD()
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
NERDTree exists for this tab, a new one is opened.
:NERDTreeRefreshRoot *:NERDTreeRefreshRoot*
Refreshes the NERD tree root node.
------------------------------------------------------------------------------
2.2. Bookmarks *NERDTreeBookmarks*
@ -992,17 +995,33 @@ appended to the array.
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.
Other examples: >
(1) ['*', '\/$']
(2) []
(3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$']
(4) ['[[timestamp]]']
(5) ['\/$', '*', '[[-timestamp]]']
(6) ['\.md$', '\.c$', '[[-timestamp]]', '*']
<
1. Directories will appear last, everything else will appear above.
2. Everything will simply appear in alphabetical order.
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.
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'*
@ -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
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.
------------------------------------------------------------------------------

View File

@ -39,10 +39,10 @@ endfunction
" FUNCTION: Path.cacheDisplayString() {{{1
function! s:Path.cacheDisplayString() abort
let self.cachedDisplayString = self.getLastPathComponent(1)
let self.cachedDisplayString = g:NERDTreeNodeDelimiter . self.getLastPathComponent(1)
if self.isExecutable
let self.cachedDisplayString = self.cachedDisplayString . '*'
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . '*'
endif
let self._bookmarkNames = []
@ -52,15 +52,24 @@ function! s:Path.cacheDisplayString() abort
endif
endfor
if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks == 1
let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}'
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' {' . join(self._bookmarkNames) . '}'
endif
if self.isSymLink
let self.cachedDisplayString .= ' -> ' . self.symLinkDest
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' -> ' . self.symLinkDest
endif
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
endfunction
@ -392,7 +401,17 @@ endfunction
" FUNCTION: Path.getSortKey() {{{1
" returns a key used in compare function for sorting
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)
if !g:NERDTreeSortHiddenFirst
let path = substitute(path, '^[._]', '', '')
@ -400,13 +419,9 @@ function! s:Path.getSortKey()
if !g:NERDTreeCaseSensitiveSort
let path = tolower(path)
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
endfunction

View File

@ -99,7 +99,8 @@ function! s:TreeDirNode.displayString()
let l:label = ''
let l:cascade = self.getCascade()
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
" Select the appropriate open/closed status indicator symbol.
@ -304,9 +305,11 @@ function! s:TreeDirNode._glob(pattern, all)
for l:file in l:globList
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 == ''
let l:tail = fnamemodify(l:file, ':t:t')
let l:tail = fnamemodify(l:file, ':h:t')
endif
if l:tail == '.' || l:tail == '..'

View File

@ -180,7 +180,7 @@ function! s:TreeFileNode.GetSelected()
endif
return b:NERDTree.root.findNode(l:path)
catch /^NERDTree/
catch
return {}
endtry
endfunction
@ -242,7 +242,7 @@ endfunction
" FUNCTION: TreeFileNode.openInNewTab(options) {{{1
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))
endfunction

View File

@ -300,7 +300,7 @@ endfunction
" FUNCTION: s:UI.MarkupReg() {{{1
function! s:UI.MarkupReg()
return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)'
return '^ *['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']\? '
endfunction
" FUNCTION: s:UI._renderBookmarks {{{1
@ -363,30 +363,13 @@ function! s:UI.setShowHidden(val)
endfunction
" 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:
" line: the subject line
function! s:UI._stripMarkup(line)
let line = a:line
" remove the tree parts and the leading space
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
let l:line = substitute(a:line, '^.\{-}' . g:NERDTreeNodeDelimiter, '', '')
return substitute(l:line, g:NERDTreeNodeDelimiter.'.*$', '', '')
endfunction
" FUNCTION: s:UI.render() {{{1

View File

@ -83,31 +83,32 @@ function! s:promptToDelBuffer(bufnum, msg)
endif
endfunction
"FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1
"prints out the given msg and, if the user responds by pushing 'y' then the
"buffer with the given bufnum is replaced with a new one
"FUNCTION: s:renameBuffer(bufNum, newNodeName, isDirectory){{{1
"The buffer with the given bufNum is replaced with a new one
"
"Args:
"bufnum: the buffer that may be deleted
"msg: a message that will be echoed to the user asking them if they wish to
" del the buffer
function! s:promptToRenameBuffer(bufnum, msg, newFileName)
echo a:msg
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
let quotedFileName = fnameescape(a:newFileName)
" 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()
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
"bufNum: the buffer that may be deleted
"newNodeName: the name given to the renamed node
"isDirectory: determines how to do the create the new filenames
function! s:renameBuffer(bufNum, newNodeName, isDirectory)
if a:isDirectory
let quotedFileName = fnameescape(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t'))
let editStr = g:NERDTreePath.New(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t')).str({'format': 'Edit'})
else
let quotedFileName = fnameescape(a:newNodeName)
let editStr = g:NERDTreePath.New(a:newNodeName).str({'format': 'Edit'})
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
"FUNCTION: NERDTreeAddNode(){{{1
function! NERDTreeAddNode()
@ -128,6 +129,9 @@ function! NERDTreeAddNode()
let parentNode = b:NERDTree.root.findNode(newPath.getParent())
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)
call b:NERDTree.root.refresh()
call b:NERDTree.render()
@ -155,17 +159,33 @@ function! NERDTreeMoveNode()
endif
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)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
call b:NERDTree.root.refresh()
call NERDTreeRender()
"if the node is open in a buffer, ask the user if they want to
"close that buffer
if bufnum != -1
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)"
call s:promptToRenameBuffer(bufnum, prompt, newNodePath)
" If the file node is open, or files under the directory node are
" open, ask the user if they want to replace the file(s) with the
" renamed files.
if !empty(l:openBuffers)
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
call curNode.putCursorHere(1, 0)
@ -248,33 +268,13 @@ function! NERDTreeListNodeWin32()
let l:node = g:NERDTreeFileNode.GetSelected()
if !empty(l:node)
let l:save_shell = &shell
set shell&
if exists('+shellslash')
let l:save_shellslash = &shellslash
set noshellslash
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
let l:path = l:node.path.str()
call nerdtree#echo(printf("%s:%s MOD:%s BYTES:%d PERMISSIONS:%s",
\ toupper(getftype(l:path)),
\ fnamemodify(l:path, ':t'),
\ strftime("%c", getftime(l:path)),
\ getfsize(l:path),
\ getfperm(l:path)))
return
endif
@ -303,6 +303,9 @@ function! NERDTreeCopyNode()
if confirmed
try
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)
call b:NERDTree.root.refresh()
call b:NERDTree.render()

View File

@ -86,6 +86,9 @@ let g:NERDTreeOldSortOrder = []
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')
"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 #\[.\]# 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 #^[</].*$#
"highlighting for bookmarks

View File

@ -76,8 +76,12 @@ It also has auto-completion for location and server blocks with `location<tab>`
## 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
" Plug
Plug 'chr4/nginx.vim'

View File

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

View File

@ -376,7 +376,7 @@ function! fugitive#repo(...) abort
endif
return extend(repo, s:repo_prototype, 'keep')
endif
call s:throw('not a git repository: '.expand('%:p'))
call s:throw('not a Git repository: ' . string(dir))
endfunction
function! s:repo_dir(...) dict abort
@ -400,19 +400,19 @@ function! s:repo_bare() dict abort
endif
endfunction
function! s:repo_route(object) dict abort
return fugitive#Route(a:object, self.git_dir)
function! s:repo_find(object) dict abort
return fugitive#Find(a:object, self.git_dir)
endfunction
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
function! s:repo_head(...) dict abort
return fugitive#Head(a:0 ? a:1 : 0, self.git_dir)
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
return call('fugitive#Prepare', [self.git_dir] + a:000)
@ -485,8 +485,24 @@ function! s:Owner(path, ...) abort
return ''
endif
let [pdir, commit, file] = s:DirCommitFile(a:path)
if s:cpath(dir, pdir) && commit =~# '^\x\{40\}$'
return commit
if s:cpath(dir, pdir)
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
let path = fnamemodify(a:path, ':p')
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)')
endfunction
function! fugitive#Route(object, ...) abort
function! fugitive#Find(object, ...) abort
if type(a:object) == type(0)
let name = bufname(a:object)
return s:PlatformSlash(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name)
@ -622,7 +638,7 @@ function! fugitive#Route(object, ...) abort
else
let altdir = FugitiveExtractGitDir(f)
if len(altdir) && !s:cpath(dir, altdir)
return fugitive#Route(a:object, altdir)
return fugitive#Find(a:object, altdir)
endif
endif
elseif rev =~# '^:[0-3]:'
@ -654,7 +670,7 @@ function! fugitive#Route(object, ...) abort
else
let altdir = FugitiveExtractGitDir(file)
if len(altdir) && !s:cpath(dir, altdir)
return fugitive#Route(a:object, altdir)
return fugitive#Find(a:object, altdir)
endif
return file
endif
@ -682,7 +698,7 @@ function! s:Generate(rev, ...) abort
elseif a:rev =~# '^/' && len(tree) && getftime(tree . a:rev) >= 0 && getftime(a:rev) < 0
let object = ':(top)' . a:rev[1:-1]
endif
return fugitive#Route(object, dir)
return fugitive#Find(object, dir)
endfunction
function! s:DotRelative(path) abort
@ -1082,7 +1098,7 @@ function! fugitive#buffer(...) abort
if buffer.getvar('git_dir') !=# ''
return buffer
endif
call s:throw('not a git repository: '.bufname(buffer['#']))
call s:throw('not a Fugitive buffer: ' . string(bufname(buffer['#'])))
endfunction
function! s:buffer_getvar(var) dict abort
@ -1500,7 +1516,7 @@ function! fugitive#BufReadCmd(...) abort
if lnum
silent keepjumps delete_
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
endif
elseif b:fugitive_type ==# 'stage'

View File

@ -43,8 +43,8 @@ function! FugitiveReal(...) abort
endif
endfunction
function! FugitiveRoute(...) abort
return fugitive#Route(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
function! FugitiveFind(...) abort
return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
endfunction
function! FugitivePath(...) abort
@ -104,6 +104,8 @@ function! FugitiveTreeForGitDir(path) abort
let dir = a:path
if dir =~# '/\.git$'
return len(dir) ==# 5 ? '/' : dir[0:-6]
elseif dir ==# ''
return ''
endif
if !has_key(s:worktree_for_dir, dir)
let s:worktree_for_dir[dir] = ''
@ -203,12 +205,12 @@ function! FugitiveDetect(path) abort
endif
endfunction
function! FugitiveFind(...) abort
return call('FugitiveRoute', a:000)
function! FugitiveRoute(...) abort
return call('FugitiveFind', a:000)
endfunction
function! FugitiveGenerate(...) abort
return call('FugitiveRoute', a:000)
throw 'Use FugitiveFind() instead'
endfunction
function! s:Slash(path) abort
@ -258,7 +260,7 @@ augroup fugitive
autocmd FileType gitrebase
\ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' |
\ 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') |
\ endif |
\ 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 = ''
try
let diff = gitgutter#diff#run_diff(a:bufnr, 0)
let diff = gitgutter#diff#run_diff(a:bufnr, 'index', 0)
catch /gitgutter not tracked/
call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr))
catch /gitgutter diff failed/

View File

@ -11,10 +11,16 @@ endfunction
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()
" 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
" two instances of the file to git-diff:
@ -27,11 +33,6 @@ let s:temp_buffer = tempname()
"
" 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:
"
" 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
" so that repos using .gitattributes to control EOL conversion continue to
" 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
sleep 5m
endwhile
@ -66,18 +75,13 @@ function! gitgutter#diff#run_diff(bufnr, preserve_full_diff) abort
throw 'gitgutter not tracked'
endif
" Wrap compound commands in parentheses to make Windows happy.
" bash doesn't mind the parentheses.
let cmd = '('
" Append buffer number to avoid race conditions between 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
" Append buffer number to temp filenames to avoid race conditions between
" writing and reading the files when asynchronously processing multiple
" buffers.
" Without the buffer number, buff_file would have a race between the
" 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)
if !empty(extension)
let index_file .= '.'.extension
let buff_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.' > '.index_file.' && '
" Write buffer to temporary file.
" Note: this is synchronous.
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
if s:c_flag
let cmd .= ' -c "diff.autorefreshindex=0"'
let cmd .= ' -c "diff.noprefix=false"'
let cmd .= ' -c "core.safecrlf=false"'
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.
if !a:preserve_full_diff && !empty(g:gitgutter_grep)
@ -315,8 +332,14 @@ endfunction
" 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 hunk_index = 0
let keep_line = 1
" Don't keepempty when splitting because the diff we want may not be the
" 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)
if len(hunk_info) == 4 " start of new hunk
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
if keep_line
call add(modified_diff, line)

View File

@ -73,6 +73,7 @@ function! gitgutter#highlight#define_signs() abort
sign define GitGutterLineModified
sign define GitGutterLineRemoved
sign define GitGutterLineRemovedFirstLine
sign define GitGutterLineRemovedAboveAndBelow
sign define GitGutterLineModifiedRemoved
sign define GitGutterDummy
@ -82,11 +83,12 @@ function! gitgutter#highlight#define_signs() abort
endfunction
function! s:define_sign_text() abort
execute "sign define GitGutterLineAdded text=" . g:gitgutter_sign_added
execute "sign define GitGutterLineModified text=" . g:gitgutter_sign_modified
execute "sign define GitGutterLineRemoved text=" . g:gitgutter_sign_removed
execute "sign define GitGutterLineRemovedFirstLine text=" . g:gitgutter_sign_removed_first_line
execute "sign define GitGutterLineModifiedRemoved text=" . g:gitgutter_sign_modified_removed
execute "sign define GitGutterLineAdded text=" . g:gitgutter_sign_added
execute "sign define GitGutterLineModified text=" . g:gitgutter_sign_modified
execute "sign define GitGutterLineRemoved text=" . g:gitgutter_sign_removed
execute "sign define GitGutterLineRemovedFirstLine text=" . g:gitgutter_sign_removed_first_line
execute "sign define GitGutterLineRemovedAboveAndBelow text=" . g:gitgutter_sign_removed_above_and_below
execute "sign define GitGutterLineModifiedRemoved text=" . g:gitgutter_sign_modified_removed
endfunction
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
" to the background's.
if g:gitgutter_signs
sign define GitGutterLineAdded texthl=GitGutterAdd
sign define GitGutterLineModified texthl=GitGutterChange
sign define GitGutterLineRemoved texthl=GitGutterDelete
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDelete
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDelete
sign define GitGutterLineAdded texthl=GitGutterAdd
sign define GitGutterLineModified texthl=GitGutterChange
sign define GitGutterLineRemoved texthl=GitGutterDelete
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDelete
sign define GitGutterLineRemovedAboveAndBelow texthl=GitGutterDelete
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDelete
else
sign define GitGutterLineAdded texthl=GitGutterAddInvisible
sign define GitGutterLineModified texthl=GitGutterChangeInvisible
sign define GitGutterLineRemoved texthl=GitGutterDeleteInvisible
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDeleteInvisible
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDeleteInvisible
sign define GitGutterLineAdded texthl=GitGutterAddInvisible
sign define GitGutterLineModified texthl=GitGutterChangeInvisible
sign define GitGutterLineRemoved texthl=GitGutterDeleteInvisible
sign define GitGutterLineRemovedFirstLine texthl=GitGutterDeleteInvisible
sign define GitGutterLineRemovedAboveAndBelow texthl=GitGutterDeleteInvisible
sign define GitGutterLineModifiedRemoved texthl=GitGutterChangeDeleteInvisible
endif
endfunction
function! s:define_sign_line_highlights() abort
if g:gitgutter_highlight_lines
sign define GitGutterLineAdded linehl=GitGutterAddLine
sign define GitGutterLineModified linehl=GitGutterChangeLine
sign define GitGutterLineRemoved linehl=GitGutterDeleteLine
sign define GitGutterLineRemovedFirstLine linehl=GitGutterDeleteLine
sign define GitGutterLineModifiedRemoved linehl=GitGutterChangeDeleteLine
sign define GitGutterLineAdded linehl=GitGutterAddLine
sign define GitGutterLineModified linehl=GitGutterChangeLine
sign define GitGutterLineRemoved linehl=GitGutterDeleteLine
sign define GitGutterLineRemovedFirstLine linehl=GitGutterDeleteLine
sign define GitGutterLineRemovedAboveAndBelow linehl=GitGutterDeleteLine
sign define GitGutterLineModifiedRemoved linehl=GitGutterChangeDeleteLine
else
sign define GitGutterLineAdded linehl=
sign define GitGutterLineModified linehl=
sign define GitGutterLineRemoved linehl=
sign define GitGutterLineRemovedFirstLine linehl=
sign define GitGutterLineModifiedRemoved linehl=
sign define GitGutterLineAdded linehl=
sign define GitGutterLineModified linehl=
sign define GitGutterLineRemoved linehl=
sign define GitGutterLineRemovedFirstLine linehl=
sign define GitGutterLineRemovedAboveAndBelow linehl=
sign define GitGutterLineModifiedRemoved linehl=
endif
endfunction

View File

@ -93,6 +93,22 @@ function! s:current_hunk() abort
return current_hunk
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
let current_line = line('.')
@ -151,13 +167,24 @@ function! s:hunk_op(op)
if gitgutter#utility#is_active(bufnr)
" Get a (synchronous) diff.
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
call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff))
if empty(s:current_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
call a:op(gitgutter#diff#hunk_diff(bufnr, diff))
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 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>
if index(other_signs, line_number) == -1 " don't clobber others' signs
let name = s:highlight_name_for_change(line[1])
@ -213,6 +222,8 @@ function! s:highlight_name_for_change(text) abort
return 'GitGutterLineModified'
elseif a:text ==# 'modified_removed'
return 'GitGutterLineModifiedRemoved'
elseif a:text ==# 'removed_above_and_below'
return 'GitGutterLineRemovedAboveAndBelow'
endif
endfunction

View File

@ -7,11 +7,12 @@ function! gitgutter#utility#supports_overscore_sign()
endfunction
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 dict[a:varname] = a:val
if needs_setting
call setbufvar(+a:buffer, 'gitgutter', dict)
call setbufvar(buffer, 'gitgutter', dict)
endif
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"')
endif
call s:set('g:gitgutter_override_sign_column_highlight', 1)
call s:set('g:gitgutter_sign_added', '+')
call s:set('g:gitgutter_sign_modified', '~')
call s:set('g:gitgutter_sign_removed', '_')
call s:set('g:gitgutter_sign_added', '+')
call s:set('g:gitgutter_sign_modified', '~')
call s:set('g:gitgutter_sign_removed', '_')
if gitgutter#utility#supports_overscore_sign()
call s:set('g:gitgutter_sign_removed_first_line', '‾')
@ -44,14 +44,15 @@ else
call s:set('g:gitgutter_sign_removed_first_line', '_^')
endif
call s:set('g:gitgutter_sign_modified_removed', '~_')
call s:set('g:gitgutter_git_args', '')
call s:set('g:gitgutter_diff_args', '')
call s:set('g:gitgutter_diff_base', '')
call s:set('g:gitgutter_map_keys', 1)
call s:set('g:gitgutter_terminal_reports_focus', 1)
call s:set('g:gitgutter_async', 1)
call s:set('g:gitgutter_log', 0)
call s:set('g:gitgutter_sign_removed_above_and_below', '[')
call s:set('g:gitgutter_sign_modified_removed', '~_')
call s:set('g:gitgutter_git_args', '')
call s:set('g:gitgutter_diff_args', '')
call s:set('g:gitgutter_diff_base', '')
call s:set('g:gitgutter_map_keys', 1)
call s:set('g:gitgutter_terminal_reports_focus', 1)
call s:set('g:gitgutter_async', 1)
call s:set('g:gitgutter_log', 0)
call s:set('g:gitgutter_git_executable', 'git')
if !executable(g:gitgutter_git_executable)

View File

@ -117,6 +117,16 @@ function Test_remove_first_lines()
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()
normal 5Gi*
call system('git checkout -b fixture.txt')
@ -445,6 +455,42 @@ function Test_undo_nearby_hunk()
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()
set nowrite

View File

@ -55,7 +55,15 @@ IMPROVEMENTS:
[[GH-1978]](https://github.com/fatih/vim-go/pull/1978)
* Internal: install tools by their custom names
[[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:
* Fix `:GoRun %` on Windows.
@ -70,6 +78,14 @@ BUG FIXES:
[[GH-1794]](https://github.com/fatih/vim-go/pull/1794)
* Fix `:GoImport` when adding to an empty import block (i.e`import ()`)
[[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:
* 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
and some other locations.
[[GH-1790]](https://github.com/fatih/vim-go/pull/1790)
* Update using the correct logging flag option that was caused with the recent
delve changes
* Use the correct logging flag argument for delve.
[[GH-1809]](https://github.com/fatih/vim-go/pull/1809)
* Fix gocode option string values that would cause gocode settings not to set
correctly

View File

@ -1,5 +1,20 @@
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)
return []
endif
@ -18,6 +33,10 @@ function! s:gocodeCommand(cmd, args) abort
let cmd = extend(cmd, ['-source'])
endif
if go#config#GocodeUnimportedPackages()
let cmd = extend(cmd, ['-unimported-packages'])
endif
let cmd = extend(cmd, [a:cmd])
let cmd = extend(cmd, a:args)

View File

@ -135,6 +135,10 @@ function! go#config#SetGuruScope(scope) abort
endif
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'
function! go#config#GocodeSocketType() abort
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)
endfunction
function! go#config#HighlightDebug() abort
return get(g:, 'go_highlight_debug', 1)
endfunction
function! go#config#FoldEnable(...) abort
if a:0 > 0
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')
call remove(s:state, 'job')
endif
if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif
call s:clearState()
if a:exit_status > 0
call go#util#EchoError(s:state['message'])
@ -66,7 +71,6 @@ function! s:call_jsonrpc(method, ...) abort
let Cb = a:000[0]
let args = a:000[1:]
else
let Cb = v:none
let args = a:000
endif
let s:state['rpcid'] += 1
@ -78,9 +82,26 @@ function! s:call_jsonrpc(method, ...) abort
try
" Use callback
if type(Cb) == v:t_func
let s:ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'callback': Cb})
call ch_sendraw(s:ch, req_json)
if exists('l:Cb')
if has('nvim')
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')
let g:go_debug_commands = add(g:go_debug_commands, {
@ -91,9 +112,23 @@ function! s:call_jsonrpc(method, ...) abort
return
endif
let ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'timeout': 20000})
call ch_sendraw(ch, req_json)
let resp_json = ch_readraw(ch)
if has('nvim')
let state = {'done': 0}
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')
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
" response from dlv.
function! s:update_breakpoint(res) abort
if type(a:res) ==# v:t_none
if type(a:res) ==# type(v:null)
return
endif
@ -216,11 +251,17 @@ function! s:clearState() abort
endfunction
function! s:stop() abort
" TODO(bc): call Detach
call go#job#Stop(s:state['job'])
call s:clearState()
if has_key(s:state, 'job')
call job_stop(s:state['job'])
call remove(s:state, 'job')
endif
if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif
endfunction
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_OUTPUT__')) 'wincmd c'
set noballooneval
set balloonexpr=
if has('balloon_eval')
set noballooneval
set balloonexpr=
endif
augroup vim-go-debug
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-print) :<C-u>call go#debug#Print(expand('<cword>'))<CR>
set balloonexpr=go#debug#BalloonExpr()
set ballooneval
if has('balloon_eval')
set balloonexpr=go#debug#BalloonExpr()
set ballooneval
endif
exe bufwinnr(oldbuf) 'wincmd w'
@ -470,20 +515,29 @@ function! s:start_cb(ch, json) abort
endfunction
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)
let s:state['message'] += [a:msg]
endfunction
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)
let s:state['message'] += [a:msg]
" TODO: why do this in this callback?
if stridx(a:msg, go#config#DebugAddress()) != -1
call ch_setoptions(a:ch, {
\ 'out_cb': function('s:logger', ['OUT: ']),
\ 'err_cb': function('s:logger', ['ERR: ']),
\})
" After this block executes, Delve will be running with all the
" breakpoints setup, so this callback doesn't have to run again; just log
" future messages.
let s:state['ready'] = 1
" Tell dlv about the breakpoints that the user added before delve started.
let l:breaks = copy(s:state.breakpoint)
@ -501,17 +555,13 @@ endfunction
function! go#debug#Start(is_test, ...) abort
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()
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
endif
" It's already running.
if has_key(s:state, 'job') && job_status(s:state['job']) == 'run'
if has_key(s:state, 'job')
return
endif
@ -556,7 +606,7 @@ function! go#debug#Start(is_test, ...) abort
\ '--output', tempname(),
\ '--headless',
\ '--api-version', '2',
\ '--log', 'debugger',
\ '--log', '--log-output', 'debugger,rpc',
\ '--listen', go#config#DebugAddress(),
\ '--accept-multiclient',
\]
@ -807,10 +857,7 @@ function! go#debug#Restart() abort
call go#cmd#autowrite()
try
call job_stop(s:state['job'])
while has_key(s:state, 'job') && job_status(s:state['job']) is# 'run'
sleep 50m
endwhile
call go#job#Stop(s:state['job'])
let l:breaks = s:state['breakpoint']
let s:state = {
@ -857,7 +904,7 @@ function! go#debug#Breakpoint(...) abort
try
" Check if we already have a breakpoint for this line.
let found = v:none
let found = {}
for k in keys(s:state.breakpoint)
let bt = s:state.breakpoint[k]
if bt.file == l:filename && bt.line == linenr
@ -867,7 +914,7 @@ function! go#debug#Breakpoint(...) abort
endfor
" Remove breakpoint.
if type(found) == v:t_dict
if type(found) == v:t_dict && !empty(found)
call remove(s:state['breakpoint'], bt.id)
exe 'sign unplace '. found.id .' file=' . found.file
if s:isActive()

View File

@ -122,9 +122,12 @@ function! s:GodocView(newposition, position, content) abort
setlocal nomodifiable
sil normal! gg
" close easily with <esc> or enter
" close easily with enter
noremap <buffer> <silent> <CR> :<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
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
" The goRawString discovery requires that syntax be enabled.
syntax on
try
let l:dir= gotest#write_file('indent/indent.go', [
\ 'package main',
@ -17,6 +20,43 @@ func! Test_indent_raw_string() abort
finally
call delete(l:dir, 'rf')
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
endif
if go#util#HasDebug('shell-commands')
call go#util#EchoInfo('job command: ' . string(a:cmd))
endif
if has('nvim')
let l:input = []
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')
endif
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
if !has_key(l:options, 'cwd')
@ -501,4 +510,33 @@ function! s:neooptions(options)
return l:options
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

View File

@ -3,7 +3,7 @@ let s:go_major_version = ""
function! go#mod#Format() abort
" go mod only exists in `v1.11`
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])
endif

View File

@ -54,11 +54,11 @@ function! go#statusline#Show() abort
" only update highlight if status has changed.
if status_text != s:last_status
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"
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 guibg=#ff8700 guifg=#870000
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

View File

@ -127,6 +127,13 @@ function! go#util#gopath() abort
return substitute(s:exec(['go', 'env', 'GOPATH'])[0], '\n', '', 'g')
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
return go#util#env("goos") . '_' . go#util#env("goarch")
endfunction
@ -137,12 +144,13 @@ endfunction
" so that we always use a standard POSIX-compatible Bourne shell (and not e.g.
" csh, fish, etc.) See #988 and #1276.
function! s:system(cmd, ...) abort
" Preserve original shell and shellredir values
" Preserve original shell, shellredir and shellcmdflag values
let l:shell = &shell
let l:shellredir = &shellredir
let l:shellcmdflag = &shellcmdflag
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
try
@ -151,6 +159,7 @@ function! s:system(cmd, ...) abort
" Restore original values
let &shell = l:shell
let &shellredir = l:shellredir
let &shellcmdflag = l:shellcmdflag
endtry
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/joereynolds/vim-minisnip
* For a better documentation viewer check out:
https://github.com/garyburd/go-explorer
* Integration with `delve` (Neovim only):
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
<
*'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'*
Specifies whether `gocode` should use a different socket type. By default
@ -1924,10 +1929,10 @@ features:
* Toggle breakpoint.
* Stack operation continue/next/step out.
This feature requires Vim 8.0.0087 or newer with the |+job| feature. Neovim
does _not_ work (yet).
This requires Delve 1.0.0 or newer, and it is recommended to use Go 1.10 or
newer, as its new caching will speed up recompiles.
This feature requires either Vim 8.0.0087 or newer with the |+job| feature or
Neovim. This features also requires Delve 1.0.0 or newer, and it is
recommended to use Go 1.10 or newer, as its new caching will speed up
recompiles.
*go-debug-intro*
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'
<
*'g:go_highlight_debug'*
Highlight the current line and breakpoints in the debugger.
>
let g:go_highlight_debug = 1
<
==============================================================================
FAQ TROUBLESHOOTING *go-troubleshooting*

View File

@ -31,6 +31,11 @@ au BufReadPost *.s call s:gofiletype_post()
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
" 'module <path>'.
au BufNewFile,BufRead go.mod call s:gomod()

View File

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

View File

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

View File

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

View File

@ -37,10 +37,26 @@ syntax match gomodReplaceOperator "\v\=\>"
highlight default link gomodReplaceOperator Operator
" highlight semver, note that this is very simple. But it works for now
syntax match gomodVersion "v\d\+\.\d\+\.\d\+"
syntax match gomodVersion "v\d\+\.\d\+\.\d\+-\S*"
syntax match gomodVersion "v\d\+\.\d\+\.\d\++incompatible"
" highlight versions:
" * vX.Y.Z
" * vX.0.0-yyyyymmddhhmmss-abcdefabcdef
" * 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
let b:current_syntax = "gomod"

View File

@ -115,7 +115,7 @@ syn match mkdRule /^\s*_\s\{0,1}_\s\{0,1}_\(_\|\s\)*$/
" YAML frontmatter
if get(g:, 'vim_markdown_frontmatter', 0)
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
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?
**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?
**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