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

Updated plugins

This commit is contained in:
Amir Salihefendic 2018-07-19 14:52:53 +02:00
parent 2f164fee9b
commit cc997dc3d0
99 changed files with 1572 additions and 1151 deletions

View file

@ -15,9 +15,9 @@ function! ale_linters#awk#gawk#GetCommand(buffer) abort
" note the --source 'BEGIN ...' is to prevent
" gawk from attempting to execute the body of the script
" it is linting.
return ale_linters#awk#gawk#GetExecutable(a:buffer)
return ale#Escape(ale_linters#awk#gawk#GetExecutable(a:buffer))
\ . " --source 'BEGIN { exit } END { exit 1 }'"
\ . ' ' . ale#Var(a:buffer, 'awk_gawk_options')
\ . ale#Pad(ale#Var(a:buffer, 'awk_gawk_options'))
\ . ' ' . '-f %t --lint /dev/null'
endfunction

View file

@ -30,5 +30,4 @@ call ale#linter#Define('cpp', {
\ 'command_callback': 'ale_linters#cpp#cquery#GetCommand',
\ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot',
\ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions',
\ 'language': 'cpp',
\})

View file

@ -1,7 +1,11 @@
let g:ale_cs_mcs_options = get(g:, 'ale_cs_mcs_options', '')
function! ale_linters#cs#mcs#GetCommand(buffer) abort
return 'mcs -unsafe --parse ' . ale#Var(a:buffer, 'cs_mcs_options') . ' %t'
let l:options = ale#Var(a:buffer, 'cs_mcs_options')
return 'mcs -unsafe --parse'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %t'
endfunction
function! ale_linters#cs#mcs#Handle(buffer, lines) abort

View file

@ -29,16 +29,16 @@ function! ale_linters#cs#mcsc#GetCommand(buffer) abort
\ : ''
" register temporary module target file with ale
let l:out = tempname()
call ale#engine#ManageFile(a:buffer, l:out)
" register temporary module target file with ALE.
let l:out = ale#engine#CreateFile(a:buffer)
" The code is compiled as a module and the output is redirected to a
" temporary file.
return ale#path#CdString(s:GetWorkingDirectory(a:buffer))
\ . 'mcs -unsafe'
\ . ' ' . ale#Var(a:buffer, 'cs_mcsc_options')
\ . ' ' . l:lib_option
\ . ' ' . l:r_option
\ . ale#Pad(ale#Var(a:buffer, 'cs_mcsc_options'))
\ . ale#Pad(l:lib_option)
\ . ale#Pad(l:r_option)
\ . ' -out:' . l:out
\ . ' -t:module'
\ . ' -recurse:' . ale#Escape('*.cs')

View file

@ -10,7 +10,7 @@ endfunction
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = tempname() . '.ii'
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#engine#ManageFile(a:buffer, l:output_file)
return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer))

View file

@ -20,6 +20,5 @@ call ale#linter#Define('dart', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#dart#language_server#GetExecutable',
\ 'command_callback': 'ale_linters#dart#language_server#GetExecutable',
\ 'language': 'dart',
\ 'project_root_callback': 'ale_linters#dart#language_server#GetProjectRoot',
\})

View file

@ -128,14 +128,7 @@ function! ale_linters#elm#make#HandleElm018Line(line, output) abort
endfunction
function! ale_linters#elm#make#FileIsBuffer(path) abort
let l:is_windows = has('win32')
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
if has('win32')
return a:path[0:len(l:temp_dir) - 1] is? l:temp_dir
else
return a:path[0:len(l:temp_dir) - 1] is# l:temp_dir
endif
return ale#path#IsTempName(a:path)
endfunction
function! ale_linters#elm#make#ParseMessage(message) abort

View file

@ -3,7 +3,7 @@
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
function! ale_linters#erlang#erlc#GetCommand(buffer) abort
let l:output_file = tempname()
let l:output_file = ale#util#Tempname()
call ale#engine#ManageFile(a:buffer, l:output_file)
return 'erlc -o ' . ale#Escape(l:output_file)

View file

@ -1,11 +1,8 @@
" Author: RyanSquared <vandor2012@gmail.com>
" Description: `fusion-lint` linter for FusionScript files
let g:ale_fuse_fusionlint_executable =
\ get(g:, 'ale_fuse_fusionlint_executable', 'fusion-lint')
let g:ale_fuse_fusionlint_options =
\ get(g:, 'ale_fuse_fusionlint_options', '')
call ale#Set('fuse_fusionlint_executable', 'fusion-lint')
call ale#Set('fuse_fusionlint_options', '')
function! ale_linters#fuse#fusionlint#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'fuse_fusionlint_executable')
@ -13,7 +10,7 @@ endfunction
function! ale_linters#fuse#fusionlint#GetCommand(buffer) abort
return ale#Escape(ale_linters#fuse#fusionlint#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'fuse_fusionlint_options')
\ . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options'))
\ . ' --filename %s -i'
endfunction

View file

@ -14,9 +14,9 @@ function! ale_linters#glsl#glslang#GetExecutable(buffer) abort
endfunction
function! ale_linters#glsl#glslang#GetCommand(buffer) abort
return ale_linters#glsl#glslang#GetExecutable(a:buffer)
\ . ' ' . ale#Var(a:buffer, 'glsl_glslang_options')
\ . ' ' . '-C %t'
return ale#Escape(ale_linters#glsl#glslang#GetExecutable(a:buffer))
\ . ale#Pad(ale#Var(a:buffer, 'glsl_glslang_options'))
\ . ' -C %t'
endfunction
function! ale_linters#glsl#glslang#Handle(buffer, lines) abort

View file

@ -29,6 +29,5 @@ call ale#linter#Define('glsl', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#glsl#glslls#GetExecutable',
\ 'command_callback': 'ale_linters#glsl#glslls#GetCommand',
\ 'language': 'glsl',
\ 'project_root_callback': 'ale_linters#glsl#glslls#GetProjectRoot',
\})

View file

@ -3,10 +3,9 @@
function! ale_linters#go#gotype#GetCommand(buffer) abort
if expand('#' . a:buffer . ':p') =~# '_test\.go$'
return
return ''
endif
return ale#path#BufferCdString(a:buffer) . ' gotype .'
endfunction

View file

@ -84,10 +84,10 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort
return ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable)
\ . ' -Xlint'
\ . ' ' . l:cp_option
\ . ' ' . l:sp_option
\ . ale#Pad(l:cp_option)
\ . ale#Pad(l:sp_option)
\ . ' -d ' . ale#Escape(l:class_file_directory)
\ . ' ' . ale#Var(a:buffer, 'java_javac_options')
\ . ale#Pad(ale#Var(a:buffer, 'java_javac_options'))
\ . ' %t'
endfunction

View file

@ -0,0 +1,38 @@
" Author: t_t <jamestthompson3@gmail.com>
" Description: Integrate ALE with flow-language-server.
call ale#Set('javascript_flow_ls_executable', 'flow')
call ale#Set('javascript_flow_ls_use_global',
\ get(g:, 'ale_use_global_executables', 0)
\)
function! ale_linters#javascript#flow_ls#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_flow_ls', [
\ 'node_modules/.bin/flow',
\])
endfunction
function! ale_linters#javascript#flow_ls#GetCommand(buffer) abort
let l:executable = ale_linters#javascript#flow_ls#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' lsp --from ale-lsp'
endfunction
function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort
let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig')
if !empty(l:flow_config)
return fnamemodify(l:flow_config, ':h')
endif
return ''
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow-language-server',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#javascript#flow_ls#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#flow_ls#GetCommand',
\ 'project_root_callback': 'ale_linters#javascript#flow_ls#FindProjectRoot',
\ 'language': 'javascript',
\})

View file

@ -0,0 +1,38 @@
" Author: MTDL9 <https://github.com/MTDL9>
" Description: Support for the Kotlin language server https://github.com/fwcd/KotlinLanguageServer
call ale#Set('kotlin_languageserver_executable', 'kotlin-language-server')
function! ale_linters#kotlin#languageserver#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'kotlin_languageserver_executable')
endfunction
function! ale_linters#kotlin#languageserver#GetCommand(buffer) abort
let l:executable = ale_linters#kotlin#languageserver#GetExecutable(a:buffer)
return ale#Escape(l:executable)
endfunction
function! ale_linters#kotlin#languageserver#GetProjectRoot(buffer) abort
let l:gradle_root = ale#gradle#FindProjectRoot(a:buffer)
if !empty(l:gradle_root)
return l:gradle_root
endif
let l:maven_pom_file = ale#path#FindNearestFile(a:buffer, 'pom.xml')
if !empty(l:maven_pom_file)
return fnamemodify(l:maven_pom_file, ':h')
endif
return ''
endfunction
call ale#linter#Define('kotlin', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#kotlin#languageserver#GetExecutable',
\ 'command_callback': 'ale_linters#kotlin#languageserver#GetCommand',
\ 'language': 'kotlin',
\ 'project_root_callback': 'ale_linters#kotlin#languageserver#GetProjectRoot',
\})

View file

@ -9,8 +9,7 @@ endfunction
function! ale_linters#llvm#llc#GetCommand(buffer) abort
return ale#Escape(ale_linters#llvm#llc#GetExecutable(a:buffer))
\ . ' -filetype=null -o='
\ . ale#Escape(g:ale#util#nul_file)
\ . ' -filetype=null -o=' . g:ale#util#nul_file
endfunction
function! ale_linters#llvm#llc#HandleErrors(buffer, lines) abort

View file

@ -1,5 +1,23 @@
" Author rhysd https://rhysd.github.io/, Dirk Roorda (dirkroorda), Adrián González Rus (@adrigzr)
" Description: remark-lint for Markdown files
call ale#Set('markdown_remark_lint_executable', 'remark')
call ale#Set('markdown_remark_lint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_remark_lint_options', '')
function! ale_linters#markdown#remark_lint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'markdown_remark_lint', [
\ 'node_modules/.bin/remark',
\])
endfunction
function! ale_linters#markdown#remark_lint#GetCommand(buffer) abort
let l:executable = ale_linters#markdown#remark_lint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options')
return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --no-stdout --no-color'
endfunction
function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort
" matches: ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint'
@ -26,9 +44,8 @@ endfunction
call ale#linter#Define('markdown', {
\ 'name': 'remark-lint',
\ 'executable': 'remark',
\ 'command': 'remark --no-stdout --no-color %s',
\ 'executable_callback': 'ale_linters#markdown#remark_lint#GetExecutable',
\ 'command_callback': 'ale_linters#markdown#remark_lint#GetCommand',
\ 'callback': 'ale_linters#markdown#remark_lint#Handle',
\ 'lint_file': 1,
\ 'output_stream': 'stderr',
\})

View file

@ -42,9 +42,9 @@ endfunction
call ale#linter#Define('nasm', {
\ 'name': 'nasm',
\ 'executable': 'nasm',
\ 'output_stream': 'stderr',
\ 'lint_file': 1,
\ 'executable_callback': 'ale_linters#nasm#nasm#GetExecutable',
\ 'command_callback': 'ale_linters#nasm#nasm#GetCommand',
\ 'callback': 'ale_linters#nasm#nasm#Handle',
\})

View file

@ -25,6 +25,5 @@ call ale#linter#Define('php', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
\ 'command_callback': 'ale_linters#php#langserver#GetCommand',
\ 'language': 'php',
\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
\})

View file

@ -0,0 +1,45 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
" Description: Puppet Language Server integration for ALE
call ale#Set('puppet_languageserver_executable', 'puppet-languageserver')
function! ale_linters#puppet#languageserver#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'puppet_languageserver_executable')
endfunction
function! ale_linters#puppet#languageserver#GetCommand(buffer) abort
let l:exe = ale#Escape(ale_linters#puppet#languageserver#GetExecutable(a:buffer))
return l:exe . ' --stdio'
endfunction
function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort
" Note: The metadata.json file is recommended for Puppet 4+ modules, but
" there's no requirement to have it, so fall back to the other possible
" Puppet module directories
let l:root_path = ale#path#FindNearestFile(a:buffer, 'metadata.json')
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h')
endif
for l:test_path in [
\ 'manifests',
\ 'templates',
\]
let l:root_path = ale#path#FindNearestDirectory(a:buffer, l:test_path)
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h:h')
endif
endfor
return ''
endfunction
call ale#linter#Define('puppet', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#puppet#languageserver#GetExecutable',
\ 'command_callback': 'ale_linters#puppet#languageserver#GetCommand',
\ 'language': 'puppet',
\ 'project_root_callback': 'ale_linters#puppet#languageserver#GetProjectRoot',
\})

View file

@ -23,7 +23,6 @@ call ale#linter#Define('python', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#python#pyls#GetExecutable',
\ 'command_callback': 'ale_linters#python#pyls#GetCommand',
\ 'language': 'python',
\ 'project_root_callback': 'ale#python#FindProjectRoot',
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\})

View file

@ -23,7 +23,6 @@ call ale#linter#Define('python', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#python#pyre#GetExecutable',
\ 'command_callback': 'ale_linters#python#pyre#GetCommand',
\ 'language': 'python',
\ 'project_root_callback': 'ale#python#FindProjectRoot',
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\})

View file

@ -1,8 +1,8 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: rails_best_practices, a code metric tool for rails projects
let g:ale_ruby_rails_best_practices_options =
\ get(g:, 'ale_ruby_rails_best_practices_options', '')
call ale#Set('ruby_rails_best_practices_options', '')
call ale#Set('ruby_rails_best_practices_executable', 'rails_best_practices')
function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
let l:output = []
@ -22,8 +22,12 @@ function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
return l:output
endfunction
function! ale_linters#ruby#rails_best_practices#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
endfunction
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
let l:executable = ale#handlers#rails_best_practices#GetExecutable(a:buffer)
let l:executable = ale_linters#ruby#rails_best_practices#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'bundle$'
\ ? ' exec rails_best_practices'
\ : ''
@ -46,7 +50,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
\ 'executable_callback': 'ale#handlers#rails_best_practices#GetExecutable',
\ 'executable_callback': 'ale_linters#ruby#rails_best_practices#GetExecutable',
\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
\ 'lint_file': 1,

View file

@ -30,6 +30,5 @@ call ale#linter#Define('rust', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#rust#rls#GetExecutable',
\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
\ 'language': 'rust',
\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
\})

View file

@ -1,11 +1,11 @@
" Author: Kevin Kays - https://github.com/okkays
" Description: Support for the scalastyle checker.
let g:ale_scala_scalastyle_options =
\ get(g:, 'ale_scala_scalastyle_options', '')
let g:ale_scalastyle_config_loc =
call ale#Set('scala_scalastyle_options', '')
" TODO: Remove support for the old option name in ALE 3.0.
call ale#Set('scala_scalastyle_config',
\ get(g:, 'ale_scalastyle_config_loc', '')
\)
function! ale_linters#scala#scalastyle#Handle(buffer, lines) abort
" Look for help output from scalastyle first, which indicates that no
@ -66,23 +66,13 @@ function! ale_linters#scala#scalastyle#GetCommand(buffer) abort
" If all else fails, try the global config.
if empty(l:scalastyle_config)
let l:scalastyle_config = get(g:, 'ale_scalastyle_config_loc', '')
let l:scalastyle_config = ale#Var(a:buffer, 'scala_scalastyle_config')
endif
" Build the command using the config file and additional options.
let l:command = 'scalastyle'
if !empty(l:scalastyle_config)
let l:command .= ' --config ' . ale#Escape(l:scalastyle_config)
endif
if !empty(g:ale_scala_scalastyle_options)
let l:command .= ' ' . g:ale_scala_scalastyle_options
endif
let l:command .= ' %t'
return l:command
return 'scalastyle'
\ . (!empty(l:scalastyle_config) ? ' --config ' . ale#Escape(l:scalastyle_config) : '')
\ . ale#Pad(ale#Var(a:buffer, 'scala_scalastyle_options'))
\ . ' %t'
endfunction
call ale#linter#Define('scala', {

View file

@ -28,6 +28,5 @@ call ale#linter#Define('sh', {
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#sh#language_server#GetExecutable',
\ 'command_callback': 'ale_linters#sh#language_server#GetCommand',
\ 'language': 'sh',
\ 'project_root_callback': 'ale_linters#sh#language_server#GetProjectRoot',
\})

View file

@ -20,14 +20,12 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:generators = ['cpp']
endif
let l:output_dir = tempname()
call mkdir(l:output_dir)
call ale#engine#ManageDirectory(a:buffer, l:output_dir)
let l:output_dir = ale#engine#CreateDirectory(a:buffer)
return ale#Escape(ale_linters#thrift#thrift#GetExecutable(a:buffer))
\ . ' ' . join(map(copy(l:generators), "'--gen ' . v:val"))
\ . ' ' . join(map(copy(l:includes), "'-I ' . v:val"))
\ . ' ' . ale#Var(a:buffer, 'thrift_thrift_options')
\ . ale#Pad(join(map(copy(l:generators), "'--gen ' . v:val")))
\ . ale#Pad(join(map(copy(l:includes), "'-I ' . v:val")))
\ . ale#Pad(ale#Var(a:buffer, 'thrift_thrift_options'))
\ . ' -out ' . ale#Escape(l:output_dir)
\ . ' %t'
endfunction

View file

@ -1,17 +1,7 @@
" Author: Prashanth Chandra <https://github.com/prashcr>, Jonathan Clem <https://jclem.net>
" Description: tslint for TypeScript files
call ale#Set('typescript_tslint_executable', 'tslint')
call ale#Set('typescript_tslint_config_path', '')
call ale#Set('typescript_tslint_rules_dir', '')
call ale#Set('typescript_tslint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('typescript_tslint_ignore_empty_files', 0)
function! ale_linters#typescript#tslint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'typescript_tslint', [
\ 'node_modules/.bin/tslint',
\])
endfunction
call ale#handlers#tslint#InitVariables()
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
" Do not output any errors for empty files if the option is on.
@ -70,7 +60,7 @@ function! ale_linters#typescript#tslint#GetCommand(buffer) abort
\ : ''
return ale#path#BufferCdString(a:buffer)
\ . ale#Escape(ale_linters#typescript#tslint#GetExecutable(a:buffer))
\ . ale#Escape(ale#handlers#tslint#GetExecutable(a:buffer))
\ . ' --format json'
\ . l:tslint_config_option
\ . l:tslint_rules_option
@ -79,7 +69,7 @@ endfunction
call ale#linter#Define('typescript', {
\ 'name': 'tslint',
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable',
\ 'executable_callback': 'ale#handlers#tslint#GetExecutable',
\ 'command_callback': 'ale_linters#typescript#tslint#GetCommand',
\ 'callback': 'ale_linters#typescript#tslint#Handle',
\})

View file

@ -7,7 +7,7 @@ if !exists('g:ale_verilog_verilator_options')
endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = tempname() . '_verilator_linted.v'
let l:filename = ale#util#Tempname() . '_verilator_linted.v'
" Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename)

View file

@ -0,0 +1,32 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
" Description: Vue vls Language Server integration for ALE
call ale#Set('vue_vls_executable', 'vls')
call ale#Set('vue_vls_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#vue#vls#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'vue_vls', [
\ 'node_modules/.bin/vls',
\])
endfunction
function! ale_linters#vue#vls#GetCommand(buffer) abort
let l:exe = ale#Escape(ale_linters#vue#vls#GetExecutable(a:buffer))
return l:exe . ' --stdio'
endfunction
function! ale_linters#vue#vls#GetProjectRoot(buffer) abort
let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json')
return !empty(l:package_path) ? fnamemodify(l:package_path, ':h') : ''
endfunction
call ale#linter#Define('vue', {
\ 'name': 'vls',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#vue#vls#GetExecutable',
\ 'command_callback': 'ale_linters#vue#vls#GetCommand',
\ 'language': 'vue',
\ 'project_root_callback': 'ale_linters#vue#vls#GetProjectRoot',
\})

View file

@ -11,7 +11,7 @@ endfunction
function! ale_linters#xml#xmllint#GetCommand(buffer) abort
return ale#Escape(ale_linters#xml#xmllint#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'xml_xmllint_options')
\ . ale#Pad(ale#Var(a:buffer, 'xml_xmllint_options'))
\ . ' --noout -'
endfunction

View file

@ -191,15 +191,12 @@ endfunction
"
" Every variable name will be prefixed with 'ale_'.
function! ale#Var(buffer, variable_name) abort
let l:nr = str2nr(a:buffer)
let l:full_name = 'ale_' . a:variable_name
let l:vars = getbufvar(str2nr(a:buffer), '', 0)
if bufexists(l:nr)
let l:vars = getbufvar(l:nr, '')
elseif has_key(g:, 'ale_fix_buffer_data')
let l:vars = get(g:ale_fix_buffer_data, l:nr, {'vars': {}}).vars
else
let l:vars = {}
if l:vars is 0
" Look for variables from deleted buffers, saved from :ALEFix
let l:vars = get(get(g:ale_fix_buffer_data, a:buffer, {}), 'vars', {})
endif
return get(l:vars, l:full_name, g:[l:full_name])
@ -210,10 +207,29 @@ endfunction
" Every variable name will be prefixed with 'ale_'.
function! ale#Set(variable_name, default) abort
let l:full_name = 'ale_' . a:variable_name
let l:value = get(g:, l:full_name, a:default)
let g:[l:full_name] = l:value
return l:value
if !has_key(g:, l:full_name)
let g:[l:full_name] = a:default
endif
endfunction
" Given a string for adding to a command, return the string padded with a
" space on the left if it is not empty. Otherwise return an empty string.
"
" This can be used for making command strings cleaner and easier to test.
function! ale#Pad(string) abort
return !empty(a:string) ? ' ' . a:string : ''
endfunction
" Given a environment variable name and a value, produce part of a command for
" setting an environment variable before running a command. The syntax will be
" valid for cmd on Windows, or most shells on Unix.
function! ale#Env(variable_name, value) abort
if has('win32')
return 'set ' . a:variable_name . '=' . ale#Escape(a:value) . ' && '
endif
return a:variable_name . '=' . ale#Escape(a:value) . ' '
endfunction
" Escape a string suitably for each platform.

View file

@ -0,0 +1,159 @@
let s:chain_results = []
function! ale#assert#WithChainResults(...) abort
let s:chain_results = a:000
endfunction
function! s:GetLinter() abort
let l:linters = ale#linter#GetLintersLoaded()
let l:filetype_linters = get(values(l:linters), 0, [])
if len(l:linters) is 0 || len(l:filetype_linters) is 0
throw 'No linters were loaded'
endif
if len(l:linters) > 1 || len(l:filetype_linters) > 1
throw 'More than one linter was loaded'
endif
return l:filetype_linters[0]
endfunction
" Load the currently loaded linter for a test case, and check that the command
" matches the given string.
function! ale#assert#Linter(expected_executable, expected_command) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
if has_key(l:linter, 'command_chain')
let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback')
" If the expected command is a string, just check the last one.
if type(a:expected_command) is type('')
if len(l:callbacks) is 1
let l:command = call(l:callbacks[0], [l:buffer])
else
let l:input = get(s:chain_results, len(l:callbacks) - 2, [])
let l:command = call(l:callbacks[-1], [l:buffer, l:input])
endif
else
let l:command = []
let l:chain_index = 0
for l:Callback in l:callbacks
if l:chain_index is 0
call add(l:command, call(l:Callback, [l:buffer]))
else
let l:input = get(s:chain_results, l:chain_index - 1, [])
call add(l:command, call(l:Callback, [l:buffer, l:input]))
endif
let l:chain_index += 1
endfor
endif
else
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
" Replace %e with the escaped executable, so tests keep passing after
" linters are changed to use %e.
let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g')
endif
AssertEqual
\ [a:expected_executable, a:expected_command],
\ [l:executable, l:command]
endfunction
function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
Assert empty(l:executable), "The linter will be executed when it shouldn't be"
endfunction
function! ale#assert#LSPOptions(expected_options) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:initialization_options = ale#lsp_linter#GetOptions(l:buffer, l:linter)
AssertEqual a:expected_options, l:initialization_options
endfunction
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
AssertEqual a:expected_language, l:language
endfunction
function! ale#assert#LSPProject(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:root = ale#util#GetFunction(l:linter.project_root_callback)(l:buffer)
AssertEqual a:expected_root, l:root
endfunction
" A dummy function for making sure this module is loaded.
function! ale#assert#SetUpLinterTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames.
let g:ale_create_dummy_temporary_file = 1
" Remove current linters.
call ale#linter#Reset()
call ale#linter#PreventLoading(a:filetype)
let l:prefix = 'ale_' . a:filetype . '_' . a:name
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
Save g:ale_c_build_dir
unlet! g:ale_c_build_dir
" Save and clear linter variables.
" We'll load the runtime file to reset them to defaults.
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
unlet! b:ale_c_build_dir
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
call ale#test#SetDirectory('/testplugin/test/command_callback')
command! -nargs=+ WithChainResults :call ale#assert#WithChainResults(<args>)
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=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
endfunction
function! ale#assert#TearDownLinterTest() abort
unlet! g:ale_create_dummy_temporary_file
let s:chain_results = []
delcommand WithChainResults
delcommand AssertLinter
delcommand AssertLinterNotExecuted
delcommand AssertLSPOptions
delcommand AssertLSPLanguage
delcommand AssertLSPProject
call ale#test#RestoreDirectory()
Restore
call ale#linter#Reset()
if exists('*ale#semver#ResetVersionCache')
call ale#semver#ResetVersionCache()
endif
endfunction

View file

@ -13,14 +13,14 @@ function! s:TemporaryFilename(buffer) abort
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
return tempname() . (has('win32') ? '\' : '/') . l:filename
return ale#util#Tempname() . (has('win32') ? '\' : '/') . l:filename
endfunction
" Given a command string, replace every...
" %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory
" %% -> with a literal %
function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed) abort
let l:temporary_file = ''
let l:command = a:command
@ -28,6 +28,11 @@ function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort
" with an ugly string.
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
" Replace %e with the escaped executable, if available.
if !empty(a:executable) && l:command =~# '%e'
let l:command = substitute(l:command, '%e', '\=ale#Escape(a:executable)', 'g')
endif
" Replace all %s occurrences in the string with the name of the current
" file.
if l:command =~# '%s'

View file

@ -1,6 +1,17 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Completion support for LSP linters
" The omnicompletion menu is shown through a special Plug mapping which is
" only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough.
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o>
" If we hit the key sequence in normal mode, then we won't show the menu, so
" we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
cnoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
vnoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
onoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
@ -129,7 +140,16 @@ function! ale#completion#Filter(buffer, suggestions, prefix) abort
return l:filtered_suggestions
endfunction
function! s:ReplaceCompleteopt() abort
function! s:ReplaceCompletionOptions() abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
let &l:omnifunc = 'ale#completion#OmniFunc'
if !exists('b:ale_old_completopt')
let b:ale_old_completopt = &l:completeopt
endif
@ -141,6 +161,22 @@ function! s:ReplaceCompleteopt() abort
endif
endfunction
function! ale#completion#RestoreCompletionOptions() abort
" Reset settings when completion is done.
if exists('b:ale_old_omnifunc')
if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete'
let &l:omnifunc = b:ale_old_omnifunc
endif
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
endif
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:line = b:ale_completion_info.line
@ -163,33 +199,30 @@ function! ale#completion#OmniFunc(findstart, base) abort
let b:ale_completion_result = function(l:parser)(l:response)
endif
call s:ReplaceCompleteopt()
call s:ReplaceCompletionOptions()
return get(b:, 'ale_completion_result', [])
endif
endfunction
function! ale#completion#Show(response, completion_parser) abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
if ale#util#Mode() isnot# 'i'
return
endif
" Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion.
let b:ale_completion_response = a:response
let b:ale_completion_parser = a:completion_parser
let &l:omnifunc = 'ale#completion#OmniFunc'
call s:ReplaceCompleteopt()
call ale#util#FeedKeys("\<C-x>\<C-o>", 'n')
call s:ReplaceCompletionOptions()
call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
endfunction
function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getcurpos()[1:2]
return has_key(b:, 'ale_completion_info')
return ale#util#Mode() is# 'i'
\&& has_key(b:, 'ale_completion_info')
\&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line
\&& b:ale_completion_info.column == l:column
@ -477,7 +510,7 @@ function! s:TimerHandler(...) abort
" When running the timer callback, we have to be sure that the cursor
" hasn't moved from where it was when we requested completions by typing.
if s:timer_pos == [l:line, l:column]
if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i'
call ale#completion#GetCompletions()
endif
endfunction
@ -518,19 +551,7 @@ endfunction
function! ale#completion#Done() abort
silent! pclose
" Reset settings when completion is done.
if exists('b:ale_old_omnifunc')
if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete'
let &l:omnifunc = b:ale_old_omnifunc
endif
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
endif
call ale#completion#RestoreCompletionOptions()
let s:last_done_pos = getcurpos()[1:2]
endfunction

View file

@ -96,9 +96,26 @@ function! ale#engine#ManageDirectory(buffer, directory) abort
call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory)
endfunction
function! ale#engine#CreateFile(buffer) abort
" This variable can be set to 1 in tests to stub this out.
if get(g:, 'ale_create_dummy_temporary_file')
return 'TEMP'
endif
let l:temporary_file = ale#util#Tempname()
call ale#engine#ManageFile(a:buffer, l:temporary_file)
return l:temporary_file
endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
let l:temporary_directory = tempname()
" This variable can be set to 1 in tests to stub this out.
if get(g:, 'ale_create_dummy_temporary_file')
return 'TEMP_DIR'
endif
let l:temporary_directory = ale#util#Tempname()
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:temporary_directory, '', 0750)
@ -189,6 +206,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:linter = l:job_info.linter
let l:output = l:job_info.output
let l:buffer = l:job_info.buffer
let l:executable = l:job_info.executable
let l:next_chain_index = l:job_info.next_chain_index
if g:ale_history_enabled
@ -212,7 +230,7 @@ function! s:HandleExit(job_id, exit_code) abort
endif
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
call s:InvokeChain(l:buffer, l:executable, l:linter, l:next_chain_index, l:output)
return
endif
@ -221,7 +239,12 @@ function! s:HandleExit(job_id, exit_code) abort
call ale#history#RememberOutput(l:buffer, a:job_id, l:output[:])
endif
try
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
" Handle the function being unknown, or being deleted.
catch /E700/
let l:loclist = []
endtry
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction
@ -440,6 +463,12 @@ endfunction
" Returns 1 when the job was started successfully.
function! s:RunJob(options) abort
let l:command = a:options.command
if empty(l:command)
return 0
endif
let l:executable = a:options.executable
let l:buffer = a:options.buffer
let l:linter = a:options.linter
let l:output_stream = a:options.output_stream
@ -447,11 +476,12 @@ function! s:RunJob(options) abort
let l:read_buffer = a:options.read_buffer
let l:info = g:ale_buffer_info[l:buffer]
if empty(l:command)
return 0
endif
let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer)
let [l:temporary_file, l:command] = ale#command#FormatCommand(
\ l:buffer,
\ l:executable,
\ l:command,
\ l:read_buffer,
\)
if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file)
" If a temporary filename has been formatted in to the command, then
@ -512,6 +542,7 @@ function! s:RunJob(options) abort
let s:job_info_map[l:job_id] = {
\ 'linter': l:linter,
\ 'buffer': l:buffer,
\ 'executable': l:executable,
\ 'output': [],
\ 'next_chain_index': l:next_chain_index,
\}
@ -604,8 +635,9 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
\}
endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort
function! s:InvokeChain(buffer, executable, linter, chain_index, input) abort
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
let l:options.executable = a:executable
return s:RunJob(l:options)
endfunction
@ -699,7 +731,7 @@ function! s:RunLinter(buffer, linter) abort
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if ale#engine#IsExecutable(a:buffer, l:executable)
return s:InvokeChain(a:buffer, a:linter, 0, [])
return s:InvokeChain(a:buffer, l:executable, a:linter, 0, [])
endif
endif

View file

@ -39,43 +39,56 @@ function! ale#events#SaveEvent(buffer) abort
endif
endfunction
function! s:LintOnEnter(buffer) abort
if ale#Var(a:buffer, 'enabled')
\&& g:ale_lint_on_enter
\&& has_key(b:, 'ale_file_changed')
call remove(b:, 'ale_file_changed')
function! ale#events#LintOnEnter(buffer) abort
" Unmark a file as being changed outside of Vim after we try to check it.
call setbufvar(a:buffer, 'ale_file_changed', 0)
if ale#Var(a:buffer, 'enabled') && g:ale_lint_on_enter
call ale#Queue(0, 'lint_file', a:buffer)
endif
endfunction
function! ale#events#EnterEvent(buffer) abort
function! ale#events#ReadOrEnterEvent(buffer) abort
" Apply pattern options if the variable is set.
if get(g:, 'ale_pattern_options_enabled', 1)
\&& !empty(get(g:, 'ale_pattern_options'))
call ale#pattern_options#SetOptions(a:buffer)
endif
" When entering a buffer, we are no longer quitting it.
call setbufvar(a:buffer, 'ale_quitting', 0)
let l:filetype = getbufvar(a:buffer, '&filetype')
call setbufvar(a:buffer, 'ale_original_filetype', l:filetype)
call s:LintOnEnter(a:buffer)
" If the file changed outside of Vim, check it on BufEnter,BufRead
if getbufvar(a:buffer, 'ale_file_changed')
call ale#events#LintOnEnter(a:buffer)
endif
endfunction
function! ale#events#FileTypeEvent(buffer, new_filetype) abort
let l:filetype = getbufvar(a:buffer, 'ale_original_filetype', '')
" The old filetype will be set to an empty string by the BuFEnter event,
" and not linting when the old filetype hasn't been set yet prevents
" buffers being checked when you enter them when linting on enter is off.
let l:old_filetype = getbufvar(a:buffer, 'ale_original_filetype', v:null)
" If we're setting the filetype for the first time after it was blank,
" and the option for linting on enter is off, then we should set this
" filetype as the original filetype. Otherwise ALE will still appear to
" lint files because of the BufEnter event, etc.
if empty(l:filetype) && !ale#Var(a:buffer, 'lint_on_enter')
if l:old_filetype isnot v:null
\&& !empty(a:new_filetype)
\&& a:new_filetype isnot# l:old_filetype
" Remember what the new filetype is.
call setbufvar(a:buffer, 'ale_original_filetype', a:new_filetype)
elseif a:new_filetype isnot# l:filetype
if g:ale_lint_on_filetype_changed
call ale#Queue(300, 'lint_file', a:buffer)
endif
endif
endfunction
function! ale#events#FileChangedEvent(buffer) abort
call setbufvar(a:buffer, 'ale_file_changed', 1)
if bufnr('') == a:buffer
call s:LintOnEnter(a:buffer)
call ale#events#LintOnEnter(a:buffer)
endif
endfunction
@ -87,7 +100,7 @@ function! ale#events#Init() abort
autocmd!
" These events always need to be set up.
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
autocmd BufEnter,BufRead * call ale#events#ReadOrEnterEvent(str2nr(expand('<abuf>')))
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
if g:ale_enabled
@ -99,11 +112,8 @@ function! ale#events#Init() abort
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
endif
" Handle everything that needs to happen when buffers are entered.
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
if g:ale_lint_on_enter
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
autocmd BufWinEnter * call ale#events#LintOnEnter(str2nr(expand('<abuf>')))
" Track when the file is changed outside of Vim.
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
endif

View file

@ -1,10 +1,3 @@
" This global Dictionary tracks the ALE fix data for jobs, etc.
" This Dictionary should not be accessed outside of the plugin. It is only
" global so it can be modified in Vader tests.
if !has_key(g:, 'ale_fix_buffer_data')
let g:ale_fix_buffer_data = {}
endif
if !has_key(s:, 'job_info_map')
let s:job_info_map = {}
endif
@ -219,6 +212,7 @@ function! s:RunJob(options) abort
let [l:temporary_file, l:command] = ale#command#FormatCommand(
\ l:buffer,
\ '',
\ l:command,
\ l:read_buffer,
\)

View file

@ -242,6 +242,9 @@ endfunction
" Add a function for fixing problems to the registry.
" (name, func, filetypes, desc, aliases)
function! ale#fix#registry#Add(name, func, filetypes, desc, ...) abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
if type(a:name) != type('')
throw '''name'' must be a String'
endif

View file

@ -2,9 +2,12 @@
" Description: Fixing Python imports with isort.
call ale#Set('python_isort_executable', 'isort')
call ale#Set('python_isort_options', '')
call ale#Set('python_isort_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#isort#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_isort_options')
let l:executable = ale#python#FindExecutable(
\ a:buffer,
\ 'python_isort',
@ -17,6 +20,6 @@ function! ale#fixers#isort#Fix(buffer) abort
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . ' -',
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\}
endfunction

View file

@ -2,7 +2,7 @@
" Description: Fixing files with tslint.
function! ale#fixers#tslint#Fix(buffer) abort
let l:executable = ale_linters#typescript#tslint#GetExecutable(a:buffer)
let l:executable = ale#handlers#tslint#GetExecutable(a:buffer)
let l:tslint_config_path = ale#path#ResolveLocalPath(
\ a:buffer,

View file

@ -2,7 +2,7 @@
" Description: Error handling for the format GHC outputs.
" Remember the directory used for temporary files for Vim.
let s:temp_dir = fnamemodify(tempname(), ':h')
let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')
" Build part of a regular expression for matching ALE temporary filenames.
let s:temp_regex_prefix =
\ '\M'

View file

@ -1,6 +0,0 @@
call ale#Set('ruby_rails_best_practices_options', '')
call ale#Set('ruby_rails_best_practices_executable', 'rails_best_practices')
function! ale#handlers#rails_best_practices#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
endfunction

View file

@ -0,0 +1,13 @@
function! ale#handlers#tslint#InitVariables() abort
call ale#Set('typescript_tslint_executable', 'tslint')
call ale#Set('typescript_tslint_config_path', '')
call ale#Set('typescript_tslint_rules_dir', '')
call ale#Set('typescript_tslint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('typescript_tslint_ignore_empty_files', 0)
endfunction
function! ale#handlers#tslint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'typescript_tslint', [
\ 'node_modules/.bin/tslint',
\])
endfunction

View file

@ -1,4 +1,3 @@
call ale#Set('wrap_command_as_one_argument', 0)
" Author: w0rp <devw0rp@gmail.com>
" Description: Linter registration and lazy-loading
" Retrieves linters as requested by the engine, loading them if needed.
@ -47,6 +46,16 @@ function! ale#linter#Reset() abort
let s:linters = {}
endfunction
" Return a reference to the linters loaded.
" This is only for tests.
" Do not call this function.
function! ale#linter#GetLintersLoaded() abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
return s:linters
endfunction
function! s:IsCallback(value) abort
return type(a:value) == type('') || type(a:value) == type(function('type'))
endfunction
@ -59,7 +68,7 @@ function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(linter) abort
function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) != type({})
throw 'The linter object must be a Dictionary'
endif
@ -193,13 +202,20 @@ function! ale#linter#PreProcess(linter) abort
endif
if l:needs_lsp_details
if has_key(a:linter, 'language')
if has_key(a:linter, 'language_callback')
if has_key(a:linter, 'language')
throw 'Only one of `language` or `language_callback` '
\ . 'should be set'
endif
let l:obj.language = get(a:linter, 'language')
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
else
" Default to using the filetype as the language.
let l:obj.language = get(a:linter, 'language', a:filetype)
if type(l:obj.language) != type('')
throw '`language` must be a string'
@ -207,12 +223,6 @@ function! ale#linter#PreProcess(linter) abort
" Make 'language_callback' return the 'language' value.
let l:obj.language_callback = function('s:LanguageGetter')
else
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
endif
let l:obj.project_root_callback = get(a:linter, 'project_root_callback')
@ -282,11 +292,14 @@ function! ale#linter#PreProcess(linter) abort
endfunction
function! ale#linter#Define(filetype, linter) abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
let l:new_linter = ale#linter#PreProcess(a:linter)
let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter)
call add(s:linters[a:filetype], l:new_linter)
endfunction
@ -297,6 +310,12 @@ function! ale#linter#PreventLoading(filetype) abort
endfunction
function! ale#linter#GetAll(filetypes) abort
" Don't return linters in the sandbox.
" Otherwise a sandboxed script could modify them.
if ale#util#InSandbox()
return []
endif
let l:combined_linters = []
for l:filetype in a:filetypes

View file

@ -105,12 +105,18 @@ function! ale#lsp#response#GetErrorMessage(response) abort
return ''
endif
" Include the traceback as details, if it's there.
let l:traceback = get(get(a:response.error, 'data', {}), 'traceback', [])
" Include the traceback or error data as details, if present.
let l:error_data = get(a:response.error, 'data', {})
if type(l:error_data) is type('')
let l:message .= "\n" . l:error_data
else
let l:traceback = get(l:error_data, 'traceback', [])
if type(l:traceback) is type([]) && !empty(l:traceback)
let l:message .= "\n" . join(l:traceback, "\n")
endif
endif
return l:message
endfunction

View file

@ -114,6 +114,18 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
endif
endfunction
function! ale#lsp_linter#GetOptions(buffer, linter) abort
let l:initialization_options = {}
if has_key(a:linter, 'initialization_options_callback')
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
elseif has_key(a:linter, 'initialization_options')
let l:initialization_options = a:linter.initialization_options
endif
return l:initialization_options
endfunction
" Given a buffer, an LSP linter, and a callback to register for handling
" messages, start up an LSP linter and get ready to receive errors or
" completions.
@ -128,13 +140,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
return {}
endif
let l:initialization_options = {}
if has_key(a:linter, 'initialization_options_callback')
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
elseif has_key(a:linter, 'initialization_options')
let l:initialization_options = a:linter.initialization_options
endif
let l:initialization_options = ale#lsp_linter#GetOptions(a:buffer, a:linter)
if a:linter.lsp is# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
@ -147,14 +153,14 @@ function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if !executable(l:executable)
if empty(l:executable) || !executable(l:executable)
return {}
endif
let l:command = ale#job#PrepareCommand(
\ a:buffer,
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
" Format the command, so %e can be formatted into it.
let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0)[1]
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:conn_id = ale#lsp#StartProgram(
\ l:executable,
\ l:command,

View file

@ -84,7 +84,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(tempname(), ':h'))
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h'))
" Given a filename, return 1 if the file represents some temporary file
" created by Vim.

View file

@ -1,11 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Set options in files based on regex patterns.
" A dictionary mapping regular expression patterns to arbitrary buffer
" variables to be set. Useful for configuring ALE based on filename patterns.
let g:ale_pattern_options = get(g:, 'ale_pattern_options', {})
let g:ale_pattern_options_enabled = get(g:, 'ale_pattern_options_enabled', !empty(g:ale_pattern_options))
" These variables are used to cache the sorting of patterns below.
let s:last_pattern_options = {}
let s:sorted_items = []
@ -23,17 +18,19 @@ function! s:CmpPatterns(left_item, right_item) abort
endfunction
function! ale#pattern_options#SetOptions(buffer) abort
if !get(g:, 'ale_pattern_options_enabled', 0)
\|| empty(get(g:, 'ale_pattern_options', 0))
let l:pattern_options = get(g:, 'ale_pattern_options', {})
if empty(l:pattern_options)
" Stop if no options are set.
return
endif
" The items will only be sorted whenever the patterns change.
if g:ale_pattern_options != s:last_pattern_options
let s:last_pattern_options = deepcopy(g:ale_pattern_options)
if l:pattern_options != s:last_pattern_options
let s:last_pattern_options = deepcopy(l:pattern_options)
" The patterns are sorted, so they are applied consistently.
let s:sorted_items = sort(
\ items(g:ale_pattern_options),
\ items(l:pattern_options),
\ function('s:CmpPatterns')
\)
endif

View file

@ -6,6 +6,7 @@ let s:sep = has('win32') ? '\' : '/'
let s:bin_dir = has('unix') ? 'bin' : 'Scripts'
let g:ale_virtualenv_dir_names = get(g:, 'ale_virtualenv_dir_names', [
\ '.env',
\ '.venv',
\ 'env',
\ 've-py3',
\ 've',
@ -23,6 +24,8 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/mypy.ini')
\|| filereadable(l:path . '/pycodestyle.cfg')
\|| filereadable(l:path . '/flake8.cfg')
\|| filereadable(l:path . '/Pipfile')
\|| filereadable(l:path . '/Pipfile.lock')
return l:path
endif
endfor

View file

@ -45,14 +45,12 @@ if !hlexists('ALESignColumnWithErrors')
highlight link ALESignColumnWithErrors error
endif
if !hlexists('ALESignColumnWithoutErrors')
function! s:SetSignColumnWithoutErrorsHighlight() abort
function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort
redir => l:output
silent highlight SignColumn
0verbose silent highlight SignColumn
redir end
let l:highlight_syntax = join(split(l:output)[2:])
let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
if !empty(l:match)
@ -62,8 +60,8 @@ if !hlexists('ALESignColumnWithoutErrors')
endif
endfunction
call s:SetSignColumnWithoutErrorsHighlight()
delfunction s:SetSignColumnWithoutErrorsHighlight
if !hlexists('ALESignColumnWithoutErrors')
call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight()
endif
" Signs show up on the left for error markers.

View file

@ -268,9 +268,8 @@ endfunction
" See :help sandbox
function! ale#util#InSandbox() abort
try
function! s:SandboxCheck() abort
endfunction
catch /^Vim\%((\a\+)\)\=:E48/
let &equalprg=&equalprg
catch /E48/
" E48 is the sandbox error.
return 1
endtry
@ -278,6 +277,25 @@ function! ale#util#InSandbox() abort
return 0
endfunction
function! ale#util#Tempname() abort
let l:clear_tempdir = 0
if exists('$TMPDIR') && empty($TMPDIR)
let l:clear_tempdir = 1
let $TMPDIR = '/tmp'
endif
try
let l:name = tempname() " no-custom-checks
finally
if l:clear_tempdir
let $TMPDIR = ''
endif
endtry
return l:name
endfunction
" Given a single line, or a List of lines, and a single pattern, or a List
" of patterns, return all of the matches for the lines(s) from the given
" patterns, using matchlist().

View file

@ -10,6 +10,7 @@ CONTENTS *ale-development-contents*
2. Design Goals.........................|ale-design-goals|
3. Coding Standards.....................|ale-coding-standards|
4. Testing ALE..........................|ale-development-tests|
4.1. Writing Linter Tests.............|ale-development-linter-tests|
===============================================================================
1. Introduction *ale-development-introduction*
@ -111,6 +112,9 @@ these are reported with ALE's `custom-linting-rules` script. See
* Don't use the `shellescape()` function. It doesn't escape arguments properly
on Windows. Use `ale#Escape()` instead, which will avoid escaping where it
isn't needed, and generally escape arguments better on Windows.
* Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't
set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR`
appropriately where needed.
Apply the following guidelines when writing Vader test files.
@ -170,6 +174,9 @@ Look at existing tests in the codebase for examples of how to write tests.
Refer to the Vader documentation for general information on how to write Vader
tests: https://github.com/junegunn/vader.vim
See |ale-development-linter-tests| for more information on how to write linter
tests.
When you add new linters or fixers, make sure to add them into the table in
the README, and also into the |ale-support| list in the main help file. If you
forget to keep them both in sync, you should see an error like the following
@ -219,5 +226,82 @@ margin. For example, if you add a heading for an `aardvark` tool to
Make sure to make the table of contents match the headings, and to keep the
doc tags on the right margin.
===============================================================================
4.1 Writing Linter Tests *ale-development-linter-tests*
Tests for ALE linters take two forms.
1. Tests for handling the output of commands.
2. Tests for checking which commands are run, or connections are made.
Tests of the first form should go in the `test/handler` directory, and should
be written like so. >
Before:
" Load the file which defines the linter.
runtime ale_linters/filetype/linter_name_here.vim
After:
" Unload all linters again.
call ale#linter#Reset()
Execute(The output should be correct):
" Test that the right loclist items are parsed from the handler.
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'type': 'E',
\ 'text': 'Something went wrong',
\ },
\ ],
\ ale_linters#filetype#linter_name#Handle(bufnr(''), [
\ '1:Something went wrong',
\ ]
<
Tests for what ALE runs should go in the `test/command_callback` directory,
and should be written like so. >
Before:
" Load the linter and set up a series of commands, reset linter variables,
" clear caches, etc.
"
" Vader's 'Save' command will be called here for linter variables.
call ale#assert#SetUpLinterTest('filetype', 'linter_name')
After:
" Reset linters, variables, etc.
"
" Vader's 'Restore' command will be called here.
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
" AssertLinter checks the executable and command.
" Pass expected_executable, expected_command
AssertLinter 'some-command', ale#Escape('some-command') . ' --foo'
Execute(Check chained commands):
" WithChainResults can be called with 1 or more list for passing output
" to chained commands. The output for each callback defaults to an empty
" list.
WithChainResults ['v2.1.2']
" Given a List of commands, check all of them.
" Given a String, only the last command in the chain will be checked.
AssertLinter 'some-command', [
\ ale#Escape('some-command') . ' --version',
\ ale#Escape('some-command') . ' --foo',
\]
<
The full list of commands that will be temporarily defined for linter tests
given the above setup are as follows.
`WithChainResults [...]` - Define output for command chain functions.
`AssertLinter executable, command` - Check the executable and command.
`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.
`AssertLSPProject project_root` - Check the root given to an LSP server.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -87,4 +87,19 @@ g:ale_kotlin_ktlint_rulesets *g:ale_kotlin_ktlint_rulesets*
let g:ale_kotlin_ktlint_rulesets = ['/path/to/custom-rulset.jar',
'com.ktlint.rulesets:mycustomrule:1.0.0']
===============================================================================
languageserver *ale-kotlin-languageserver*
g:ale_kotlin_languageserver_executable *g:ale_kotlin_languageserver_executable*
Type: |String|
Default: `''`
The kotlin-language-server executable.
Executables are located inside the bin/ folder of the language server
release.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -28,6 +28,33 @@ prettier *ale-markdown-prettier*
See |ale-javascript-prettier| for information about the available options.
===============================================================================
remark-lint *ale-markdown-remark-lint*
g:ale_markdown_remark_lint_executable *g:ale_markdown_remark_lint_executable*
*b:ale_markdown_remark_lint_executable*
Type: |String|
Default: `'remark'`
See |ale-integrations-local-executables|
g:ale_markdown_remark_lint_options *g:ale_markdown_remark_lint_options*
*b:ale_markdown_remark_lint_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to remark-lint.
g:ale_markdown_remark_lint_use_global *g:ale_markdown_remark_lint_use_global*
*b:ale_markdown_remark_lint_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
textlint *ale-markdown-textlint*

View file

@ -22,5 +22,16 @@ g:ale_puppet_puppetlint_options *g:ale_puppet_puppetlint_options*
puppet-lint invocation.
===============================================================================
puppet-languageserver *ale-puppet-languageserver*
g:ale_puppet_languageserver_executable *g:ale_puppet_languageserver_executable*
*b:ale_puppet_languageserver_executable*
type: |String|
Default: `'puppet-languageserver'`
This variable can be used to specify the executable used for
puppet-languageserver.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -22,6 +22,8 @@ ALE will look for configuration files with the following filenames. >
mypy.ini
pycodestyle.cfg
flake8.cfg
Pipfile
Pipfile.lock
<
The first directory containing any of the files named above will be used.
@ -145,6 +147,14 @@ g:ale_python_isort_executable *g:ale_python_isort_executable*
See |ale-integrations-local-executables|
g:ale_python_isort_options *g:ale_python_isort_options*
*b:ale_python_isort_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to isort.
g:ale_python_isort_use_global *g:ale_python_isort_use_global*
*b:ale_python_isort_use_global*
Type: |Number|

View file

@ -41,8 +41,8 @@ To disable `scalastyle` globally, use |g:ale_linters| like so: >
See |g:ale_linters| for more information on disabling linters.
g:ale_scalastyle_config_loc *g:ale_scalastyle_config_loc*
g:ale_scala_scalastyle_config *g:ale_scala_scalastyle_config*
*b:ale_scala_scalastyle_config*
Type: |String|
Default: `''`
@ -54,7 +54,7 @@ g:ale_scalastyle_config_loc *g:ale_scalastyle_config_loc*
g:ale_scala_scalastyle_options *g:ale_scala_scalastyle_options*
*b:ale_scala_scalastyle_options*
Type: |String|
Default: `''`

View file

@ -7,5 +7,25 @@ prettier *ale-vue-prettier*
See |ale-javascript-prettier| for information about the available options.
===============================================================================
vls *ale-vue-vls*
g:ale_vue_vls_executable *g:ale_vue_vls_executable*
*b:ale_vue_vls_executable*
Type: |String|
Default: `'vls'`
See |ale-integrations-local-executables|
g:ale_vue_vls_use_global *g:ale_vue_vls_use_global*
*b:ale_vue_vls_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -131,6 +131,7 @@ CONTENTS *ale-contents*
kotlin................................|ale-kotlin-options|
kotlinc.............................|ale-kotlin-kotlinc|
ktlint..............................|ale-kotlin-ktlint|
languageserver......................|ale-kotlin-languageserver|
latex.................................|ale-latex-options|
write-good..........................|ale-latex-write-good|
less..................................|ale-less-options|
@ -145,6 +146,7 @@ CONTENTS *ale-contents*
markdown..............................|ale-markdown-options|
mdl.................................|ale-markdown-mdl|
prettier............................|ale-markdown-prettier|
remark-lint.........................|ale-markdown-remark-lint|
textlint............................|ale-markdown-textlint|
write-good..........................|ale-markdown-write-good|
mercury...............................|ale-mercury-options|
@ -186,6 +188,7 @@ CONTENTS *ale-contents*
puglint.............................|ale-pug-puglint|
puppet................................|ale-puppet-options|
puppetlint..........................|ale-puppet-puppetlint|
puppet-languageserver...............|ale-puppet-languageserver|
pyrex (cython)........................|ale-pyrex-options|
cython..............................|ale-pyrex-cython|
python................................|ale-python-options|
@ -273,6 +276,7 @@ CONTENTS *ale-contents*
write-good..........................|ale-vim-help-write-good|
vue...................................|ale-vue-options|
prettier............................|ale-vue-prettier|
vls.................................|ale-vue-vls|
xhtml.................................|ale-xhtml-options|
write-good..........................|ale-xhtml-write-good|
xml...................................|ale-xml-options|
@ -366,7 +370,7 @@ Notes:
* Java: `checkstyle`, `javac`, `google-java-format`, `PMD`
* JavaScript: `eslint`, `flow`, `jscs`, `jshint`, `prettier`, `prettier-eslint`, `prettier-standard`, `standard`, `xo`
* JSON: `fixjson`, `jsonlint`, `jq`, `prettier`
* Kotlin: `kotlinc`, `ktlint`
* Kotlin: `kotlinc`!!, `ktlint`!!, `languageserver`
* LaTeX (tex): `alex`!!, `chktex`, `lacheck`, `proselint`, `redpen`, `vale`, `write-good`
* Less: `lessc`, `prettier`, `stylelint`
* LLVM: `llc`
@ -390,7 +394,7 @@ Notes:
* Pony: `ponyc`
* proto: `protoc-gen-lint`
* Pug: `pug-lint`
* Puppet: `puppet`, `puppet-lint`
* Puppet: `languageserver`, `puppet`, `puppet-lint`
* Python: `autopep8`, `black`, `flake8`, `isort`, `mypy`, `prospector`, `pycodestyle`, `pyls`, `pyre`, `pylint`!!, `yapf`
* QML: `qmlfmt`, `qmllint`
* R: `lintr`
@ -418,7 +422,7 @@ Notes:
* Verilog: `iverilog`, `verilator`
* Vim: `vint`
* Vim help^: `alex`!!, `proselint`, `write-good`
* Vue: `prettier`
* Vue: `prettier`, `vls`
* XHTML: `alex`!!, `proselint`, `write-good`
* XML: `xmllint`
* YAML: `swaglint`, `yamllint`
@ -444,14 +448,20 @@ have even saved your changes. ALE will check your code in the following
circumstances, which can be configured with the associated options.
* When you modify a buffer. - |g:ale_lint_on_text_changed|
* On leaving insert mode. (off by default) - |g:ale_lint_on_insert_leave|
* When you open a new or modified buffer. - |g:ale_lint_on_enter|
* When you save a buffer. - |g:ale_lint_on_save|
* When the filetype changes for a buffer. - |g:ale_lint_on_filetype_changed|
* If ALE is used to check code manually. - |:ALELint|
In addition to the above options, ALE can also check buffers for errors when
you leave insert mode with |g:ale_lint_on_insert_leave|, which is off by
default. It is worth reading the documentation for every option.
*ale-lint-settings-on-startup*
It is worth reading the documentation for every option. You should configure
which events ALE will use before ALE is loaded, so it can optimize which
autocmd commands to run. You can force autocmd commands to be reloaded with
`:ALEDisable | ALEEnable`
This also applies to the autocmd commands used for |g:ale_echo_cursor|.
*ale-lint-file-linters*
@ -641,9 +651,6 @@ ALE supports the following LSP/tsserver features.
-------------------------------------------------------------------------------
5.1 Completion *ale-completion*
NOTE: At the moment, only `tsserver` for TypeScript code is supported for
completion.
ALE offers limited support for automatic completion of code while you type.
Completion is only supported while a least one LSP linter is enabled. ALE
will only suggest symbols provided by the LSP servers.
@ -842,6 +849,9 @@ g:ale_echo_cursor *g:ale_echo_cursor*
this behaviour.
The format of the message can be customizable in |g:ale_echo_msg_format|.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
g:ale_echo_delay *g:ale_echo_delay*
*b:ale_echo_delay*
@ -1042,19 +1052,16 @@ g:ale_lint_on_enter *g:ale_lint_on_enter*
Type: |Number|
Default: `1`
When this option is set to `1`, the |BufWinEnter| and |BufRead| events will
be used to apply linters when buffers are first opened. If this is not
desired, this variable can be set to `0` in your vimrc file to disable this
behaviour.
When this option is set to `1`, the |BufWinEnter| event will be used to
apply linters when buffers are first opened. If this is not desired, this
variable can be set to `0` in your vimrc file to disable this behavior.
The |FileChangedShellPost| and |BufEnter| events will be used to check if
files have been changed outside of Vim. If a file is changed outside of
Vim, it will be checked when it is next opened.
A |BufWinLeave| event will be used to look for the |E924|, |E925|, or |E926|
errors after moving from a loclist or quickfix window to a new buffer. If
prompts for these errors are opened after moving to new buffers, then ALE
will automatically send the `<CR>` key needed to close the prompt.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
g:ale_lint_on_filetype_changed *g:ale_lint_on_filetype_changed*
@ -1062,14 +1069,13 @@ g:ale_lint_on_filetype_changed *g:ale_lint_on_filetype_changed*
Type: |Number|
Default: `1`
This option will cause ALE to run whenever the filetype is changed. A short
delay will be used before linting will be done, so the filetype can be
changed quickly several times in a row, but resulting in only one lint
cycle.
This option will cause ALE to run when the filetype for a file is changed
after a buffer has first been loaded. A short delay will be used before
linting will be done, so the filetype can be changed quickly several times
in a row, but resulting in only one lint cycle.
If |g:ale_lint_on_enter| is set to `0`, then ALE will not lint a file when
the filetype is initially set. Otherwise ALE would still lint files when
buffers are opened, and the option for doing so is turned off.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
g:ale_lint_on_save *g:ale_lint_on_save*
@ -1087,17 +1093,22 @@ g:ale_lint_on_save *g:ale_lint_on_save*
g:ale_lint_on_text_changed *g:ale_lint_on_text_changed*
Type: |String|
Default: `always`
Default: `'always'`
By default, ALE will check files with the various supported programs when
text is changed by using the |TextChanged| event. If this behaviour is not
desired, then this option can be disabled by setting it to `never`. The
|g:ale_lint_delay| variable will be used to set a |timer_start()| on a
delay, and each change to a file will continue to call |timer_stop()| and
|timer_start()| repeatedly until the timer ticks by, and the linters will be
run. The checking of files will run in the background, so it should not
inhibit editing files. This option can also be set to `insert` or `normal`
to lint when text is changed only in insert or normal mode respectively.
This option controls how ALE will check your files as you make changes.
The following values can be used.
`'always'`, `'1'`, or `1` - Check buffers on |TextChanged| or |TextChangedI|.
`'normal'` - Check buffers only on |TextChanged|.
`'insert'` - Check buffers only on |TextChangedI|.
`'never'`, `'0'`, or `0` - Never check buffers on changes.
ALE will check buffers after a short delay, with a timer which resets on
each change. The delay can be configured by adjusting the |g:ale_lint_delay|
variable.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave*
@ -1115,6 +1126,9 @@ g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave*
" Make using Ctrl+C do the same as Escape, to trigger autocmd commands
inoremap <C-c> <Esc>
<
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
g:ale_linter_aliases *g:ale_linter_aliases*
*b:ale_linter_aliases*
@ -1360,7 +1374,7 @@ g:ale_open_list *g:ale_open_list*
g:ale_pattern_options *g:ale_pattern_options*
Type: |Dictionary|
Default: `{}`
Default: undefined
This option maps regular expression patterns to |Dictionary| values for
buffer variables. This option can be set to automatically configure
@ -1389,12 +1403,10 @@ g:ale_pattern_options *g:ale_pattern_options*
g:ale_pattern_options_enabled *g:ale_pattern_options_enabled*
Type: |Number|
Default: `!empty(g:ale_pattern_options)`
Default: undefined
This option can be used for turning the behaviour of setting
|g:ale_pattern_options| on or off. By default, setting a single key for
|g:ale_pattern_options| will turn this option on, as long as the setting is
configured before ALE is loaded.
This option can be used for disabling pattern options. If set to `0`, ALE
will not set buffer variables per |g:ale_pattern_options|.
g:ale_set_balloons *g:ale_set_balloons*
@ -1636,7 +1648,7 @@ g:ale_virtualenv_dir_names *g:ale_virtualenv_dir_names*
b:ale_virtualenv_dir_names *b:ale_virtualenv_dir_names*
Type: |List|
Default: `['.env', 'env', 've-py3', 've', 'virtualenv', 'venv']`
Default: `['.env', '.venv', 'env', 've-py3', 've', 'virtualenv', 'venv']`
A list of directory names to be used when searching upwards from Python
files to discover virtulenv directories with.
@ -2075,6 +2087,29 @@ ALEStopAllLSPs *ALEStopAllLSPs*
===============================================================================
9. API *ale-api*
ALE offers a number of functions for running linters or fixers, or defining
them. The following functions are part of the publicly documented part of that
API, and should be expected to continue to work.
ale#Env(variable_name, value) *ale#Env()*
Given a variable name and a string value, produce a string for including in
a command for setting environment variables. This function can be used for
building a command like so. >
:echo string(ale#Env('VAR', 'some value') . 'command')
'VAR=''some value'' command' # On Linux or Mac OSX
'set VAR="some value" && command' # On Windows
ale#Pad(string) *ale#Pad()*
Given a string or any |empty()| value, return either the string prefixed
with a single space, or an empty string. This function can be used to build
parts of a command from variables.
ale#Queue(delay, [linting_flag, buffer_number]) *ale#Queue()*
Run linters for the current buffer, based on the filetype of the buffer,
@ -2099,8 +2134,17 @@ ale#Queue(delay, [linting_flag, buffer_number]) *ale#Queue()*
ale#engine#CreateDirectory(buffer) *ale#engine#CreateDirectory()*
Create a new temporary directory with a unique name, and manage that
directory with |ale#engine#ManageDirectory()|, so it will be removed as
soon as possible.
directory with |ale#engine#ManageDirectory()|, so it will be removed as soon
as possible.
It is advised to only call this function from a callback function for
returning a linter command to run.
ale#engine#CreateFile(buffer) *ale#engine#CreateFile()*
Create a new temporary file with a unique name, and manage that file with
|ale#engine#ManageFile()|, so it will be removed as soon as possible.
It is advised to only call this function from a callback function for
returning a linter command to run.
@ -2206,6 +2250,10 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
defined, as LSP linters handle diagnostics
automatically. See |ale-lsp-linters|.
If the function named does not exist, including if
the function is later deleted, ALE will behave as if
the callback returned an empty list.
The keys for each item in the List will be handled in
the following manner:
*ale-loclist-format*
@ -2383,9 +2431,12 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
with a callback returning an address to connect to.
ALE will not start a server automatically.
When this argument is not empty, only one of either
`language` or `language_callback` must be defined,
and `project_root_callback` must be defined.
When this argument is not empty
`project_root_callback` must be defined.
`language` or `language_callback` can be defined to
describe the language for a file. The filetype will
be used as the language by default.
LSP linters handle diagnostics automatically, so
the `callback` argument must not be defined.
@ -2418,8 +2469,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
being checked. This string will be sent to the LSP to
tell it what type of language is being checked.
This argument must only be set if the `lsp` argument
is also set to a non-empty string.
If this or `language_callback` isn't set, the
language will default to the value of the filetype
given to |ale#linter#Define|.
`language_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |String| should be
@ -2489,15 +2541,23 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
For example: >
'command': 'ghc -fno-code -v0 %t',
<
Any substring `%e` will be replaced with the escaped executable supplied
with `executable` or `executable_callback`. This provides a convenient way
to define a command string which needs to include a dynamic executable name,
but which is otherwise static.
For example: >
'command': '%e --some-argument',
<
The character sequence `%%` can be used to emit a literal `%` into a
command, so literal character sequences `%s` and `%t` can be escaped by
using `%%s` and `%%t` instead, etc.
If a callback for a command generates part of a command string which might
possibly contain `%%`, `%s`, or `%t` where the special formatting behaviour
is not desired, the |ale#engine#EscapeCommandPart()| function can be used to
replace those characters to avoid formatting issues.
possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting
behavior is not desired, the |ale#engine#EscapeCommandPart()| function can
be used to replace those characters to avoid formatting issues.
*ale-linter-loading-behavior*
*ale-linter-loading-behaviour*

View file

@ -35,15 +35,11 @@ endif
" Set this flag so that other plugins can use it, like airline.
let g:loaded_ale = 1
" Set the TMPDIR environment variable if it is not set automatically.
" This can automatically fix some environments.
if has('unix') && empty($TMPDIR)
let $TMPDIR = '/tmp'
endif
" This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against.
let g:ale_buffer_info = {}
" This global Dictionary tracks data for fixing code. Don't mess with it.
let g:ale_fix_buffer_data = {}
" User Configuration

View file

@ -92,7 +92,7 @@ add the following configuration to your `.vimrc`.
set laststatus=2
```
If the statusline does not be coloured like
If the statusline is not coloured like
![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/20.png)
then modify `TERM` in your shell configuration (`.zshrc` for example)

View file

@ -18,15 +18,13 @@ uncomments a set of adjacent commented lines.
## Installation
If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:
Install using your favorite package manager, or use Vim's built-in package
support:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-commentary.git
Once help tags have been generated, you can view the manual with
`:help commentary`.
mkdir -p ~/.vim/pack/tpope/start
cd ~/.vim/pack/tpope/start
git clone https://tpope.io/vim/commentary.git
vim -u NONE -c "helptags commentary/doc" -c q
## FAQ

View file

@ -93,7 +93,7 @@ command! -range -bar Commentary call s:go(<line1>,<line2>)
xnoremap <expr> <Plug>Commentary <SID>go()
nnoremap <expr> <Plug>Commentary <SID>go()
nnoremap <expr> <Plug>CommentaryLine <SID>go() . '_'
onoremap <silent> <Plug>Commentary :<C-U>call <SID>textobject(0)<CR>
onoremap <silent> <Plug>Commentary :<C-U>call <SID>textobject(get(v:, 'operator', '') ==# 'c')<CR>
nnoremap <silent> <Plug>ChangeCommentary c:<C-U>call <SID>textobject(1)<CR>
nmap <silent> <Plug>CommentaryUndo :echoerr "Change your <Plug>CommentaryUndo map to <Plug>Commentary<Plug>Commentary"<CR>
@ -102,7 +102,7 @@ if !hasmapto('<Plug>Commentary') || maparg('gc','n') ==# ''
nmap gc <Plug>Commentary
omap gc <Plug>Commentary
nmap gcc <Plug>CommentaryLine
if maparg('c','n') ==# ''
if maparg('c','n') ==# '' && !exists('v:operator')
nmap cgc <Plug>ChangeCommentary
endif
nmap gcu <Plug>Commentary<Plug>Commentary

View file

@ -46,6 +46,14 @@ function! s:fnameescape(file) abort
endif
endfunction
function! s:tempname() abort
let temp = resolve(tempname())
if has('win32')
let temp = fnamemodify(fnamemodify(temp, ':h'), ':p').fnamemodify(temp, ':t')
endif
return temp
endfunction
function! s:throw(string) abort
let v:errmsg = 'fugitive: '.a:string
throw v:errmsg
@ -83,12 +91,21 @@ function! s:executable(binary) abort
return s:executables[a:binary]
endfunction
let s:git_versions = {}
function! s:git_command() abort
return get(g:, 'fugitive_git_command', g:fugitive_git_executable)
endfunction
function! fugitive#Prepare(...) abort
let args = copy(a:000)
if empty(args)
return g:fugitive_git_executable
elseif args[0] !~# '^-' && args[0] =~# '[\/.]'
let args[0] = '--git-dir=' . args[0]
endif
return g:fugitive_git_executable . ' ' . join(map(args, 's:shellesc(v:val)'), ' ')
endfunction
let s:git_versions = {}
function! fugitive#GitVersion(...) abort
if !has_key(s:git_versions, g:fugitive_git_executable)
let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), "\\S\\+\\ze\n")
@ -173,7 +190,7 @@ function! fugitive#Init() abort
call s:map('n', 'y<C-G>', ':call setreg(v:register, <SID>recall())<CR>', '<silent>')
endif
let buffer = fugitive#buffer()
if expand('%:p') =~# '://'
if expand('%:p') =~# ':[\/][\/]'
call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', ''))
endif
if stridx(buffer.getvar('&tags'), escape(b:git_dir, ', ')) == -1
@ -315,9 +332,7 @@ function! s:repo_git_command(...) dict abort
endfunction
function! s:repo_git_chomp(...) dict abort
let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir)
let output = git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'')
return s:sub(system(output),'\n$','')
return s:sub(system(call('fugitive#Prepare', [self.git_dir] + a:000)),'\n$','')
endfunction
function! s:repo_git_chomp_in_tree(...) dict abort
@ -429,11 +444,16 @@ call s:add_methods('repo',['keywordprg'])
" Section: Buffer
function! s:DirCommitFile(path) abort
let vals = matchlist(s:shellslash(a:path), '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\w\+\)\(/.*\)\=$')
let vals = matchlist(s:shellslash(a:path), '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40\}\|[0-3]\)\(/.*\)\=$')
if empty(vals)
return ['', '', '']
endif
return [vals[1], (vals[2] =~# '^.$' ? ':' : '') . vals[2], vals[3]]
return vals[1:3]
endfunction
function! s:DirRev(url) abort
let [dir, commit, file] = s:DirCommitFile(a:url)
return [dir, (commit =~# '^.$' ? ':' : '') . commit . substitute(file, '^/', ':', '')]
endfunction
function! fugitive#Path(url) abort
@ -454,7 +474,7 @@ endfunction
let s:trees = {}
let s:indexes = {}
function! s:TreeInfo(dir, commit) abort
let git = g:fugitive_git_executable . ' --git-dir=' . s:shellesc(a:dir)
let git = fugitive#Prepare(a:dir)
if a:commit =~# '^:\=[0-3]$'
let index = get(s:indexes, a:dir, [])
let newftime = getftime(a:dir . '/index')
@ -547,7 +567,7 @@ function! fugitive#getfsize(url) abort
let entry = s:PathInfo(a:url)
if entry[4] == -2 && entry[2] ==# 'blob' && len(entry[3])
let dir = s:DirCommitFile(a:url)[0]
let size = +system(g:fugitive_git_executable . ' ' . s:shellesc('--git-dir=' . dir) . ' cat-file -s ' . entry[3])
let size = +system(fugitive#Prepare(dir, 'cat-file', '-s', entry[3]))
let entry[4] = v:shell_error ? -1 : size
endif
return entry[4]
@ -572,9 +592,8 @@ function! fugitive#readfile(url, ...) abort
if entry[2] !=# 'blob'
return []
endif
let [dir, commit, file] = s:DirCommitFile(a:url)
let cmd = g:fugitive_git_executable . ' --git-dir=' . s:shellesc(dir) .
\ ' cat-file blob ' . s:shellesc(commit . ':' . file[1:-1])
let [dir, rev] = s:DirRev(a:url)
let cmd = fugitive#Prepare(dir, 'cat-file', 'blob', rev)
if max > 0 && s:executable('head')
let cmd .= '|head -' . max
endif
@ -634,7 +653,7 @@ function! s:buffer(...) abort
if buffer.getvar('git_dir') !=# ''
return buffer
endif
call s:throw('not a git repository: '.expand('%:p'))
call s:throw('not a git repository: '.bufname(buffer['#']))
endfunction
function! fugitive#buffer(...) abort
@ -658,9 +677,9 @@ function! s:buffer_repo() dict abort
endfunction
function! s:buffer_type(...) dict abort
if self.getvar('fugitive_type') != ''
if !empty(self.getvar('fugitive_type'))
let type = self.getvar('fugitive_type')
elseif fnamemodify(self.spec(),':p') =~# '.\git/refs/\|\.git/\w*HEAD$'
elseif fnamemodify(self.spec(),':p') =~# '\.git/refs/\|\.git/\w*HEAD$'
let type = 'head'
elseif self.getline(1) =~ '^tree \x\{40\}$' && self.getline(2) == ''
let type = 'tree'
@ -843,9 +862,9 @@ function! s:Git(bang, mods, args) abort
let git .= ' --no-pager'
endif
let args = matchstr(a:args,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=')
if exists(':terminal') && has('nvim')
if exists(':terminal') && has('nvim') && !get(g:, 'fugitive_force_bang_command')
let dir = s:repo().tree()
if expand('%') != ''
if len(@%)
-tabedit %
else
-tabnew
@ -1239,7 +1258,14 @@ function! s:Commit(mods, args, ...) abort
let args = a:args
let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-[esp]|--edit|--interactive|--patch|--signoff)%($| )','')
let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-c|--reedit-message|--reuse-message|-F|--file|-m|--message)%(\s+|\=)%(''[^'']*''|"%(\\.|[^"])*"|\\.|\S)*','')
let args = s:gsub(args,'%(^| )@<=[%#]%(:\w)*','\=expand(submatch(0))')
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
let cwd = getcwd()
try
exe cd s:fnameescape(repo.tree())
let args = s:gsub(args,'\\@<!(\%|##=|#\<=\d+)(:\w)*','\=fnamemodify(FugitivePath(expand(submatch(1))),":." . submatch(2))')
finally
exe cd cwd
endtry
let args = s:sub(args, '\ze -- |$', ' --no-edit --no-interactive --no-signoff')
let args = '-F '.s:shellesc(msgfile).' '.args
if args !~# '\%(^\| \)--cleanup\>'
@ -1560,10 +1586,7 @@ function! s:Edit(cmd, bang, mods, ...) abort
diffupdate
return 'redraw|echo '.string(':!'.git.' '.args)
else
let temp = resolve(tempname())
if has('win32')
let temp = fnamemodify(fnamemodify(temp, ':h'), ':p').fnamemodify(temp, ':t')
endif
let temp = s:tempname()
let s:temp_files[s:cpath(temp)] = { 'dir': buffer.repo().dir(), 'args': arglist }
silent execute mods a:cmd temp
if a:cmd =~# 'pedit'
@ -2113,7 +2136,7 @@ augroup fugitive_blame
autocmd!
autocmd FileType fugitiveblame setlocal nomodeline | if exists('b:git_dir') | let &l:keywordprg = s:repo().keywordprg() | endif
autocmd Syntax fugitiveblame call s:BlameSyntax()
autocmd User Fugitive if s:buffer().type('file', 'blob') | exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:Blame(<bang>0,<line1>,<line2>,<count>,[<f-args>])" | endif
autocmd User Fugitive if s:buffer().type('file', 'blob', 'blame') | exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:Blame(<bang>0,<line1>,<line2>,<count>,[<f-args>])" | endif
autocmd ColorScheme,GUIEnter * call s:RehighlightBlame()
autocmd BufWinLeave * execute getwinvar(+bufwinnr(+expand('<abuf>')), 'fugitive_leave')
augroup END
@ -2157,7 +2180,7 @@ function! s:Blame(bang,line1,line2,count,args) abort
if a:count
execute 'write !'.substitute(basecmd,' blame ',' blame -L '.a:line1.','.a:line2.' ','g')
else
let error = resolve(tempname())
let error = s:tempname()
let temp = error.'.fugitiveblame'
if &shell =~# 'csh'
silent! execute '%write !('.basecmd.' > '.temp.') >& '.error
@ -2197,12 +2220,10 @@ function! s:Blame(bang,line1,line2,count,args) abort
endif
let top = line('w0') + &scrolloff
let current = line('.')
if has('win32')
let temp = fnamemodify(fnamemodify(temp, ':h'), ':p').fnamemodify(temp, ':t')
endif
let s:temp_files[s:cpath(temp)] = { 'dir': s:repo().dir(), 'args': cmd }
exe 'keepalt leftabove vsplit '.temp
let b:fugitive_blamed_bufnr = bufnr
let b:fugitive_type = 'blame'
let w:fugitive_leave = restore
let b:fugitive_blame_arguments = join(a:args,' ')
execute top
@ -2633,12 +2654,10 @@ call extend(g:fugitive_browse_handlers,
" Section: File access
function! s:ReplaceCmd(cmd,...) abort
let fn = expand('%:p')
let tmp = tempname()
function! s:WriteCmd(out, cmd, ...) abort
let prefix = ''
try
if a:0 && a:1 != ''
if a:0 && len(a:1)
if s:winshell()
let old_index = $GIT_INDEX_FILE
let $GIT_INDEX_FILE = a:1
@ -2646,23 +2665,29 @@ function! s:ReplaceCmd(cmd,...) abort
let prefix = 'env GIT_INDEX_FILE='.s:shellesc(a:1).' '
endif
endif
let redir = ' > '.tmp
if &shellpipe =~ '2>&1'
let redir .= ' 2>&1'
endif
let redir = ' > '.a:out
if s:winshell()
let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^'
call system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').redir.'"')
return system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').redir.'"')
elseif &shell =~# 'fish'
call system(' begin;'.prefix.a:cmd.redir.';end ')
return system(' begin;'.prefix.a:cmd.redir.';end ')
else
call system(' ('.prefix.a:cmd.redir.') ')
return system(' ('.prefix.a:cmd.redir.') ')
endif
finally
if exists('old_index')
let $GIT_INDEX_FILE = old_index
endif
endtry
endfunction
function! s:ReplaceCmd(cmd, ...) abort
let tmp = tempname()
let err = s:WriteCmd(tmp, a:cmd, a:0 ? a:1 : '')
if v:shell_error
call s:throw((len(err) ? err : filereadable(tmp) ? join(readfile(tmp), ' ') : 'unknown error running ' . a:cmd))
endif
let fn = expand('%:p')
silent exe 'doau BufReadPre '.s:fnameescape(fn)
silent exe 'keepalt file '.tmp
try
@ -2729,10 +2754,10 @@ function! fugitive#BufReadStatus() abort
nnoremap <buffer> <silent> <C-P> :<C-U>execute <SID>StagePrevious(v:count1)<CR>
nnoremap <buffer> <silent> - :<C-U>silent execute <SID>StageToggle(line('.'),line('.')+v:count1-1)<CR>
xnoremap <buffer> <silent> - :<C-U>silent execute <SID>StageToggle(line("'<"),line("'>"))<CR>
nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += 1<Bar>exe fugitive#BufReadIndex()<CR>
nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= 1<Bar>exe fugitive#BufReadIndex()<CR>
nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += 1<Bar>exe fugitive#BufReadStatus()<CR>
nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= 1<Bar>exe fugitive#BufReadStatus()<CR>
nnoremap <buffer> <silent> C :<C-U>Gcommit<CR>:echohl WarningMsg<Bar>echo ':Gstatus C is deprecated in favor of cc'<Bar>echohl NONE<CR>
nnoremap <buffer> <silent> cA :<C-U>Gcommit --amend --reuse-message=HEAD<CR>:echohl WarningMsg<Bar>echo ':Gstatus cA is deprecated in favor of ce'<CR>
nnoremap <buffer> <silent> cA :<C-U>Gcommit --amend --reuse-message=HEAD<CR>:echohl WarningMsg<Bar>echo ':Gstatus cA is deprecated in favor of ce'<Bar>echohl NONE<CR>
nnoremap <buffer> <silent> ca :<C-U>Gcommit --amend<CR>
nnoremap <buffer> <silent> cc :<C-U>Gcommit<CR>
nnoremap <buffer> <silent> ce :<C-U>Gcommit --amend --no-edit<CR>
@ -2761,21 +2786,16 @@ function! fugitive#BufReadStatus() abort
endfunction
function! fugitive#FileRead() abort
try
let [dir, commit, file] = s:DirCommitFile(expand('<amatch>'))
let repo = s:repo(dir)
let path = commit . substitute(file, '^/', ':', '')
let hash = repo.rev_parse(path)
if path =~ '^:'
let type = 'blob'
else
let type = repo.git_chomp('cat-file','-t',hash)
let [dir, rev] = s:DirRev(expand('<amatch>'))
if empty(dir)
return "noautocmd '[read <amatch>"
endif
" TODO: use count, if possible
return "read !".escape(repo.git_command('cat-file',type,hash),'%#\')
catch /^fugitive:/
return 'echoerr v:errmsg'
endtry
if rev !~# ':'
let cmd = fugitive#Prepare(dir, 'log', '--pretty=format:%B', '-1', rev)
else
let cmd = fugitive#Prepare(dir, 'cat-file', '-p', rev)
endif
return "'[read !" . escape(cmd, '!#%')
endfunction
function! fugitive#BufReadIndex() abort
@ -2916,10 +2936,6 @@ function! fugitive#BufReadObject() abort
endtry
endfunction
augroup fugitive_files
autocmd!
augroup END
" Section: Temp files
if !exists('s:temp_files')
@ -2931,7 +2947,7 @@ augroup fugitive_temp
autocmd BufNewFile,BufReadPost *
\ if has_key(s:temp_files,s:cpath(expand('<afile>:p'))) |
\ let b:git_dir = s:temp_files[s:cpath(expand('<afile>:p'))].dir |
\ let b:git_type = 'temp' |
\ call extend(b:, {'fugitive_type': 'temp'}, 'keep') |
\ let b:git_args = s:temp_files[s:cpath(expand('<afile>:p'))].args |
\ call FugitiveDetect(expand('<afile>:p')) |
\ setlocal bufhidden=delete nobuflisted |

View file

@ -54,8 +54,8 @@ that are part of Git repositories).
dv |:Gvdiff|
O |:Gtabedit|
o |:Gsplit|
p |:Git| add --patch
p |:Git| reset --patch (staged files)
P |:Git| add --patch
P |:Git| reset --patch (staged files)
q close status
r reload status
S |:Gvsplit|

View file

@ -1,6 +1,6 @@
" fugitive.vim - A Git wrapper so awesome, it should be illegal
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 2.3
" Version: 2.4
" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
if exists('g:loaded_fugitive')
@ -110,7 +110,7 @@ function! FugitiveExtractGitDir(path) abort
endfunction
function! FugitiveDetect(path) abort
if exists('b:git_dir') && (b:git_dir ==# '' || b:git_dir =~# '/$')
if exists('b:git_dir') && b:git_dir =~# '^$\|/$\|^fugitive:'
unlet b:git_dir
endif
if !exists('b:git_dir')
@ -156,7 +156,10 @@ augroup fugitive
autocmd BufNewFile,BufReadPost * call FugitiveDetect(expand('%:p'))
autocmd FileType netrw call FugitiveDetect(fnamemodify(get(b:, 'netrw_curdir', @%), ':p'))
autocmd User NERDTreeInit,NERDTreeNewRoot call FugitiveDetect(b:NERDTree.root.path.str())
autocmd User NERDTreeInit,NERDTreeNewRoot
\ if exists('b:NERDTree.root.path.str') |
\ call FugitiveDetect(b:NERDTree.root.path.str()) |
\ endif
autocmd VimEnter * if expand('<amatch>')==''|call FugitiveDetect(getcwd())|endif
autocmd CmdWinEnter * call FugitiveDetect(expand('#:p'))

View file

@ -3,11 +3,19 @@ let s:t_string = type('')
" Primary functions {{{
function! gitgutter#all(force) abort
for bufnr in s:uniq(tabpagebuflist())
let visible = tabpagebuflist()
for bufnr in range(1, bufnr('$') + 1)
if buflisted(bufnr)
let file = expand('#'.bufnr.':p')
if !empty(file)
if index(visible, bufnr) != -1
call gitgutter#init_buffer(bufnr)
call gitgutter#process_buffer(bufnr, a:force)
elseif a:force
call s:reset_tick(bufnr)
endif
endif
endif
endfor
endfunction
@ -16,10 +24,10 @@ endfunction
" Finds the file's path relative to the repo root.
function! gitgutter#init_buffer(bufnr)
if gitgutter#utility#is_active(a:bufnr)
call s:setup_maps()
let p = gitgutter#utility#repo_path(a:bufnr, 0)
if type(p) != s:t_string || empty(p)
call gitgutter#utility#set_repo_path(a:bufnr)
call s:setup_maps()
endif
endif
endfunction
@ -52,16 +60,13 @@ endfunction
function! gitgutter#disable() abort
" get list of all buffers (across all tabs)
let buflist = []
for i in range(tabpagenr('$'))
call extend(buflist, tabpagebuflist(i + 1))
endfor
for bufnr in s:uniq(buflist)
for bufnr in range(1, bufnr('$') + 1)
if buflisted(bufnr)
let file = expand('#'.bufnr.':p')
if !empty(file)
call s:clear(bufnr)
endif
endif
endfor
let g:gitgutter_enabled = 0
@ -132,19 +137,3 @@ function! s:clear(bufnr)
call gitgutter#hunk#reset(a:bufnr)
call s:reset_tick(a:bufnr)
endfunction
if exists('*uniq') " Vim 7.4.218
function! s:uniq(list)
return uniq(sort(a:list))
endfunction
else
function! s:uniq(list)
let processed = []
for e in a:list
if index(processed, e) == -1
call add(processed, e)
endif
endfor
return processed
endfunction
endif

View file

@ -173,26 +173,10 @@ nnoremap <silent> <Plug>GitGutterPreviewHunk :GitGutterPreviewHunk<CR>
" }}}
function! s:flag_inactive_tabs()
let active_tab = tabpagenr()
for i in range(1, tabpagenr('$'))
if i != active_tab
call settabvar(i, 'gitgutter_force', 1)
endif
endfor
endfunction
function! s:on_bufenter()
if exists('t:gitgutter_didtabenter') && t:gitgutter_didtabenter
let t:gitgutter_didtabenter = 0
let force = !g:gitgutter_terminal_reports_focus
if exists('t:gitgutter_force') && t:gitgutter_force
let t:gitgutter_force = 0
let force = 1
endif
call gitgutter#all(force)
call gitgutter#all(!g:gitgutter_terminal_reports_focus)
else
call gitgutter#init_buffer(bufnr(''))
call gitgutter#process_buffer(bufnr(''), !g:gitgutter_terminal_reports_focus)
@ -209,14 +193,14 @@ augroup gitgutter
autocmd BufEnter * call s:on_bufenter()
autocmd CursorHold,CursorHoldI * call gitgutter#process_buffer(bufnr(''), 0)
autocmd FileChangedShellPost,ShellCmdPost * call gitgutter#process_buffer(bufnr(''), 1)
autocmd FileChangedShellPost * call gitgutter#process_buffer(bufnr(''), 1)
" Ensure that all buffers are processed when opening vim with multiple files, e.g.:
"
" vim -o file1 file2
autocmd VimEnter * if winnr() != winnr('$') | call gitgutter#all(0) | endif
autocmd FocusGained * call gitgutter#all(1) | call s:flag_inactive_tabs()
autocmd FocusGained,ShellCmdPost * call gitgutter#all(1)
autocmd ColorScheme * call gitgutter#highlight#define_sign_column_highlight() | call gitgutter#highlight#define_highlights()

View file

@ -8,9 +8,16 @@ matrix:
- env: SCRIPT="test -c" VIM_VERSION=vim-7.4
- env: SCRIPT="test -c" VIM_VERSION=vim-8.0
- env: SCRIPT="test -c" VIM_VERSION=nvim
- env: SCRIPT=lint VIM_VERSION=vim-8.0
- env: ENV=vimlint SCRIPT=lint VIM_VERSION=vim-8.0
language: python
python: 3.6
install:
- ./scripts/install-vim $VIM_VERSION
- pip install --user vim-vint covimerage codecov
- |
if [ "$ENV" = "vimlint" ]; then
pip install vim-vint covimerage codecov pathlib
else
pip install --user vim-vint covimerage codecov pathlib
fi
script:
- ./scripts/$SCRIPT $VIM_VERSION

View file

@ -1,5 +1,11 @@
## unplanned
IMPROVEMENTS:
* Unify async job handling for Vim8 and Neovim.
[[GH-1864]](https://github.com/fatih/vim-go/pull/1864)
## 1.18 - (July 18, 2018)
FEATURES:
* Add **:GoIfErr** command together with the `<Plug>(go-iferr)` plug key to
@ -12,6 +18,7 @@ func doSomething() (string, error) {
f, err := os.Open("file")
}
```
Becomes:
```
@ -56,6 +63,10 @@ IMPROVEMENTS:
manually. [[GH-1861]](https://github.com/fatih/vim-go/pull/1861).
* Cleanup title of terminal window.
[[GH-1861]](https://github.com/fatih/vim-go/pull/1861).
* Add `:GoImpl` is able to complete interfaces by their full import path in
addition to the current package name (i.e: `:GoImpl t *T github.com/BurntSushi/toml.Unmarshaller`
is now possible)
[[GH-1884]](https://github.com/fatih/vim-go/pull/1884)
BUG FIXES:
@ -76,24 +87,14 @@ BUG FIXES:
[[GH-1818]](https://github.com/fatih/vim-go/pull/1818)
* Fix Neovim handling of guru output.
[[GH-1846]](https://github.com/fatih/vim-go/pull/1846)
BACKWARDS INCOMPATIBILITIES:
* We switched to a [maintained fork of * gocode](https://github.com/mdempsky/gocode).
The new fork doesn't support the following settings anymore and therefore are
invalid. Please remove them from your vimrc until those are again supported
by `gocode`.
```
g:go_gocode_autobuild
g:go_gocode_propose_builtins
g:go_gocode_unimported_packages
```
Checkout the issue for more details [[GH-1851]](https://github.com/fatih/vim-go/pull/1851)
* Execute commands correctly when they are in $GOBIN but not $PATH.
[[GH-1866]](https://github.com/fatih/vim-go/pull/1866)
* Open files correctly with ctrlp.
[[GH-1878]](https://github.com/fatih/vim-go/pull/1878)
* Fix checking guru binary path
[[GH-1886]](https://github.com/fatih/vim-go/pull/1886)
* Add build tags to `:GoDef` if only it's present
[[GH-1882]](https://github.com/fatih/vim-go/pull/1882)
## 1.17 - (March 27, 2018)

View file

@ -117,7 +117,7 @@ function! ctrlp#decls#enter() abort
call add(s:decls, printf("%s\t%s |%s:%s:%s|\t%s",
\ decl.ident . space,
\ decl.keyword,
\ fnamemodify(decl.filename, ":t"),
\ fnamemodify(decl.filename, ":."),
\ decl.line,
\ decl.col,
\ decl.full,

View file

@ -30,8 +30,8 @@ function! go#cmd#Build(bang, ...) abort
\ map(copy(a:000), "expand(v:val)") +
\ [".", "errors"]
" Vim async.
if go#util#has_job()
" Vim and Neovim async.
if go#util#has_job() || has('nvim')
if go#config#EchoCommandInfo()
call go#util#EchoProgress("building dispatched ...")
endif
@ -42,14 +42,6 @@ function! go#cmd#Build(bang, ...) abort
\ 'for': 'GoBuild',
\})
" Nvim async.
elseif has('nvim')
if go#config#EchoCommandInfo()
call go#util#EchoProgress("building dispatched ...")
endif
call go#jobcontrol#Spawn(a:bang, "build", "GoBuild", args)
" Vim 7.4 without async
else
let default_makeprg = &makeprg
@ -297,44 +289,7 @@ function s:cmd_job(args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
function! s:complete(job, exit_status, data) closure abort
let status = {
\ 'desc': 'last status',
\ 'type': a:args.cmd[1],
\ 'state': "success",
\ }
if a:exit_status
let status.state = "failed"
endif
let elapsed_time = reltimestr(reltime(started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(status_dir, status)
endfunction
let a:args.complete = funcref('s:complete')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
call go#job#Spawn(a:args.cmd, a:args)
endfunction
" vim: sw=2 ts=2 et

View file

@ -48,12 +48,13 @@ function! go#coverage#Buffer(bang, ...) abort
call go#util#EchoProgress("testing...")
endif
if go#util#has_job()
if go#util#has_job() || has('nvim')
call s:coverage_job({
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname] + a:000,
\ 'complete': function('s:coverage_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ 'statustype': 'coverage',
\ })
return
endif
@ -63,24 +64,8 @@ function! go#coverage#Buffer(bang, ...) abort
call extend(args, a:000)
endif
let disabled_term = 0
if go#config#TermEnabled()
let disabled_term = 1
call go#config#SetTermEnabled(0)
endif
let id = call('go#test#Test', args)
if disabled_term
call go#config#SetTermEnabled(1)
endif
if has('nvim')
call go#jobcontrol#AddHandler(function('s:coverage_handler'))
let s:coverage_handler_jobs[id] = l:tmpname
return
endif
if go#util#ShellError() == 0
call go#coverage#overlay(l:tmpname)
endif
@ -104,7 +89,7 @@ endfunction
" a new HTML coverage page from that profile in a new browser
function! go#coverage#Browser(bang, ...) abort
let l:tmpname = tempname()
if go#util#has_job()
if go#util#has_job() || has('nvim')
call s:coverage_job({
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname],
\ 'complete': function('s:coverage_browser_callback', [l:tmpname]),
@ -120,11 +105,6 @@ function! go#coverage#Browser(bang, ...) abort
endif
let id = call('go#test#Test', args)
if has('nvim')
call go#jobcontrol#AddHandler(function('s:coverage_browser_handler'))
let s:coverage_browser_handler_jobs[id] = l:tmpname
return
endif
if go#util#ShellError() == 0
call go#tool#ExecuteInDir(['go', 'tool', 'cover', '-html=' . l:tmpname])
@ -275,48 +255,17 @@ function s:coverage_job(args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let status_dir = expand('%:p:h')
let Complete = a:args.complete
function! s:complete(job, exit_status, data) closure
let status = {
\ 'desc': 'last status',
\ 'type': "coverage",
\ 'state': "finished",
\ }
if a:exit_status
let status.state = "failed"
let disabled_term = 0
if go#config#TermEnabled()
let disabled_term = 1
call go#config#SetTermEnabled(0)
endif
call go#statusline#Update(status_dir, status)
return Complete(a:job, a:exit_status, a:data)
endfunction
call go#job#Spawn(a:args.cmd, a:args)
let a:args.complete = funcref('s:complete')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': "coverage",
\ 'state': "started",
\})
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
if disabled_term
call go#config#SetTermEnabled(1)
endif
endfunction
" coverage_callback is called when the coverage execution is finished
@ -336,39 +285,4 @@ function! s:coverage_browser_callback(coverfile, job, exit_status, data)
call delete(a:coverfile)
endfunction
" -----------------------
" | Neovim job handlers |
" -----------------------
let s:coverage_handler_jobs = {}
let s:coverage_browser_handler_jobs = {}
function! s:coverage_handler(job, exit_status, data) abort
if !has_key(s:coverage_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_handler_jobs[a:job.id]
if a:exit_status == 0
call go#coverage#overlay(l:tmpname)
endif
call delete(l:tmpname)
unlet s:coverage_handler_jobs[a:job.id]
endfunction
function! s:coverage_browser_handler(job, exit_status, data) abort
if !has_key(s:coverage_browser_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_browser_handler_jobs[a:job.id]
if a:exit_status == 0
call go#tool#ExecuteInDir(['go', 'tool', 'cover', '-html=' . l:tmpname])
endif
call delete(l:tmpname)
unlet s:coverage_browser_handler_jobs[a:job.id]
endfunction
" vim: sw=2 ts=2 et

View file

@ -26,7 +26,12 @@ function! go#def#Jump(mode) abort
endif
elseif bin_name == 'guru'
let cmd = [bin_name, '-tags', go#config#BuildTags()]
let cmd = [go#path#CheckBinPath(bin_name)]
let buildtags = go#config#BuildTags()
if buildtags isnot ''
let cmd += ['-tags', buildtags]
endif
let stdin_content = ""
if &modified
@ -278,13 +283,7 @@ function! go#def#Stack(...) abort
endfunction
function s:def_job(args) abort
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
let l:start_options = go#job#Options(a:args)
if &modified
let l:tmpname = tempname()
@ -293,7 +292,7 @@ function s:def_job(args) abort
let l:start_options.in_name = l:tmpname
endif
call job_start(a:args.cmd, start_options)
call go#job#Start(a:args.cmd, start_options)
endfunction
" vim: sw=2 ts=2 et

View file

@ -101,13 +101,29 @@ function! s:root_dirs() abort
return dirs
endfunction
function! s:go_packages(dirs) abort
function! s:go_packages(dirs, arglead) abort
let pkgs = []
for d in a:dirs
let pkg_root = expand(d . '/pkg/' . go#util#osarch())
call extend(pkgs, split(globpath(pkg_root, '**/*.a', 1), "\n"))
for dir in a:dirs
" this may expand to multiple lines
let scr_root = expand(dir . '/src/')
for pkg in split(globpath(scr_root, a:arglead.'*'), "\n")
if isdirectory(pkg)
let pkg .= '/'
elseif pkg !~ '\.a$'
continue
endif
" without this the result can have duplicates in form of
" 'encoding/json' and '/encoding/json/'
let pkg = go#util#StripPathSep(pkg)
" remove the scr root and keep the package in tact
let pkg = substitute(pkg, scr_root, "", "")
call add(pkgs, pkg)
endfor
return map(pkgs, "fnamemodify(v:val, ':t:r')")
endfor
return pkgs
endfunction
function! s:interface_list(pkg) abort
@ -124,13 +140,24 @@ endfunction
" Complete package and interface for {interface}
function! go#impl#Complete(arglead, cmdline, cursorpos) abort
let words = split(a:cmdline, '\s\+', 1)
if words[-1] ==# ''
return s:uniq(sort(s:go_packages(s:root_dirs())))
elseif words[-1] =~# '^\h\w*$'
return s:uniq(sort(filter(s:go_packages(s:root_dirs()), 'stridx(v:val, words[-1]) == 0')))
elseif words[-1] =~# '^\h\w*\.\%(\h\w*\)\=$'
let [pkg, interface] = split(words[-1], '\.', 1)
echomsg pkg
" if no words are given, just start completing the first package we found
return s:uniq(sort(s:go_packages(s:root_dirs(), a:arglead)))
elseif words[-1] =~# '^\(\h\w.*\.\%(\h\w*\)\=$\)\@!\S*$'
" start matching go packages. It's negate match of the below match
return s:uniq(sort(s:go_packages(s:root_dirs(), a:arglead)))
elseif words[-1] =~# '^\h\w.*\.\%(\h\w*\)\=$'
" match the following, anything that could indicate an interface candidate
"
" io.
" io.Wr
" github.com/fatih/color.
" github.com/fatih/color.U
" github.com/fatih/color.Un
let splitted = split(words[-1], '\.', 1)
let pkg = join(splitted[:-2], '.')
let interface = splitted[-1]
return s:uniq(sort(filter(s:interface_list(pkg), 'v:val =~? words[-1]')))
else
return []

View file

@ -1,7 +1,25 @@
" Spawn returns callbacks to be used with job_start. It is abstracted to be
" Spawn starts an asynchronous job. See the description of go#job#Options to
" understand the args parameter.
"
" Spawn returns a job.
function! go#job#Spawn(cmd, args)
let l:options = go#job#Options(a:args)
return go#job#Start(a:cmd, l:options)
endfunction
" Spawn starts an asynchronous job. See the description of go#job#Options to
" understand the args parameter.
"
" Spawn returns a job.
function! go#job#Spawn(cmd, args)
let l:options = go#job#Options(a:args)
return go#job#Start(a:cmd, l:options)
endfunction
" Options returns callbacks to be used with job_start. It is abstracted to be
" used with various go commands, such as build, test, install, etc.. This
" allows us to avoid writing the same callback over and over for some
" commands. It's fully customizable so each command can change it to it's own
" commands. It's fully customizable so each command can change it to its own
" logic.
"
" args is a dictionary with the these keys:
@ -10,9 +28,16 @@
" 'bang':
" Set to 0 to jump to the first error in the error list.
" Defaults to 0.
" 'statustype':
" The status type to use when updating the status.
" See statusline.vim.
" 'for':
" The g:go_list_type_command key to use to get the error list type to use.
" Defaults to '_job'
" 'errorformat':
" The errorformat string to use when parsing errors. Defaults to
" &errorformat.
" See :help 'errorformat'.
" 'complete':
" A function to call after the job exits and the channel is closed. The
" function will be passed three arguments: the job, its exit code, and the
@ -30,22 +55,28 @@
" 'close_cb':
" A function suitable to be passed as a job close_cb handler. See
" job-close_cb.
function go#job#Spawn(args)
" 'cwd':
" The path to the directory which contains the current buffer.
function! go#job#Options(args)
let cbs = {}
let state = {
\ 'winid': win_getid(winnr()),
\ 'dir': getcwd(),
\ 'jobdir': fnameescape(expand("%:p:h")),
\ 'messages': [],
\ 'args': a:args.cmd,
\ 'bang': 0,
\ 'for': "_job",
\ 'exited': 0,
\ 'exit_status': 0,
\ 'closed': 0,
\ 'errorformat': &errorformat
\ 'errorformat': &errorformat,
\ 'statustype' : ''
\ }
if has("patch-8.0.0902") || has('nvim')
let cbs.cwd = state.jobdir
endif
if has_key(a:args, 'bang')
let state.bang = a:args.bang
endif
@ -54,14 +85,78 @@ function go#job#Spawn(args)
let state.for = a:args.for
endif
if has_key(a:args, 'statustype')
let state.statustype = a:args.statustype
endif
if has_key(a:args, 'errorformat')
let state.errorformat = a:args.errorformat
endif
" do nothing in state.complete by default.
function state.complete(job, exit_status, data)
endfunction
function state.show_status(job, exit_status) dict
if go#config#EchoCommandInfo()
let prefix = ""
if self.statustype != ''
let prefix = '[' . self.statustype . '] '
endif
if a:exit_status == 0
call go#util#EchoSuccess(prefix . "SUCCESS")
else
call go#util#EchoError(prefix . "FAIL")
endif
endif
if self.statustype == ''
return
endif
let status = {
\ 'desc': 'last status',
\ 'type': self.statustype,
\ 'state': "success",
\ }
if a:exit_status
let status.state = "failed"
endif
if has_key(self, 'started_at')
let elapsed_time = reltimestr(reltime(self.started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
endif
call go#statusline#Update(self.jobdir, status)
endfunction
if has_key(a:args, 'complete')
let state.complete = a:args.complete
endif
function! s:start(args) dict
if self.statustype != ''
let status = {
\ 'desc': 'current status',
\ 'type': self.statustype,
\ 'state': "started",
\ }
call go#statusline#Update(self.jobdir, status)
endif
let self.started_at = reltime()
endfunction
" explicitly bind _start to state so that within it, self will
" always refer to state. See :help Partial for more information.
"
" _start is intended only for internal use and should not be referenced
" outside of this file.
let cbs._start = function('s:start', [''], state)
function! s:callback(chan, msg) dict
call add(self.messages, a:msg)
endfunction
@ -73,15 +168,9 @@ function go#job#Spawn(args)
let self.exit_status = a:exitval
let self.exited = 1
if go#config#EchoCommandInfo()
if a:exitval == 0
call go#util#EchoSuccess("SUCCESS")
else
call go#util#EchoError("FAILED")
endif
endif
call self.show_status(a:job, a:exitval)
if self.closed
if self.closed || has('nvim')
call self.complete(a:job, self.exit_status, self.messages)
call self.show_errors(a:job, self.exit_status, self.messages)
endif
@ -123,14 +212,14 @@ function go#job#Spawn(args)
let out = join(self.messages, "\n")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
try
" parse the errors relative to self.jobdir
execute cd self.jobdir
execute l:cd self.jobdir
call go#list#ParseFormat(l:listtype, self.errorformat, out, self.for)
let errors = go#list#Get(l:listtype)
finally
execute cd . fnameescape(self.dir)
execute l:cd fnameescape(self.dir)
endtry
@ -149,7 +238,178 @@ function go#job#Spawn(args)
endif
endfunction
if has('nvim')
return s:neooptions(cbs)
endif
return cbs
endfunction
function! go#job#Start(cmd, options)
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
let l:options = copy(a:options)
if !has_key(l:options, 'cwd')
" pre start
let dir = getcwd()
execute l:cd fnameescape(expand("%:p:h"))
endif
if has_key(l:options, '_start')
call l:options._start()
" remove _start to play nicely with vim (when vim encounters an unexpected
" job option it reports an "E475: invalid argument" error.
unlet l:options._start
endif
if has('nvim')
let l:input = []
if has_key(l:options, 'in_io') && l:options.in_io ==# 'file' && !empty(l:options.in_name)
let l:input = readfile(l:options.in_name, 1)
endif
let job = jobstart(a:cmd, l:options)
if len(l:input) > 0
call chansend(job, l:input)
" close stdin to signal that no more bytes will be sent.
call chanclose(job, 'stdin')
endif
else
let job = job_start(a:cmd, l:options)
endif
if !has_key(l:options, 'cwd')
" post start
execute l:cd fnameescape(dir)
endif
return job
endfunction
" s:neooptions returns a dictionary of job options suitable for use by Neovim
" based on a dictionary of job options suitable for Vim8.
function! s:neooptions(options)
let l:options = {}
let l:options['stdout_buf'] = ''
let l:options['stderr_buf'] = ''
for key in keys(a:options)
if key == 'callback'
let l:options['callback'] = a:options['callback']
if !has_key(a:options, 'out_cb')
let l:options['stdout_buffered'] = v:true
function! s:callback2on_stdout(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stdout_buf . l:data[0]
let self.stdout_buf = ""
if l:data[-1] != ""
let self.stdout_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.callback(a:ch, join(l:data, "\n"))
endfunction
let l:options['on_stdout'] = function('s:callback2on_stdout', [], l:options)
endif
if !has_key(a:options, 'err_cb')
let l:options['stderr_buffered'] = v:true
function! s:callback2on_stderr(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stderr_buf . l:data[0]
let self.stderr_buf = ""
if l:data[-1] != ""
let self.stderr_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.callback(a:ch, join(l:data, "\n"))
endfunction
let l:options['on_stderr'] = function('s:callback2on_stderr', [], l:options)
endif
continue
endif
if key == 'out_cb'
let l:options['out_cb'] = a:options['out_cb']
let l:options['stdout_buffered'] = v:true
function! s:on_stdout(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stdout_buf . l:data[0]
let self.stdout_buf = ""
if l:data[-1] != ""
let self.stdout_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.out_cb(a:ch, join(l:data, "\n"))
endfunction
let l:options['on_stdout'] = function('s:on_stdout', [], l:options)
continue
endif
if key == 'err_cb'
let l:options['err_cb'] = a:options['err_cb']
let l:options['stderr_buffered'] = v:true
function! s:on_stderr(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stderr_buf . l:data[0]
let self.stderr_buf = ""
if l:data[-1] != ""
let self.stderr_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.err_cb(a:ch, join(l:data, "\n"))
endfunction
let l:options['on_stderr'] = function('s:on_stderr', [], l:options)
continue
endif
if key == 'exit_cb'
let l:options['exit_cb'] = a:options['exit_cb']
function! s:on_exit(jobid, exitval, event) dict
call self.exit_cb(a:jobid, a:exitval)
endfunction
let l:options['on_exit'] = function('s:on_exit', [], l:options)
continue
endif
if key == 'close_cb'
continue
endif
endfor
return l:options
endfunction
" vim: sw=2 ts=2 et

View file

@ -1,195 +0,0 @@
" s:jobs is a global reference to all jobs started with Spawn() or with the
" internal function s:spawn
let s:jobs = {}
" s:handlers is a global event handlers for all jobs started with Spawn() or
" with the internal function s:spawn
let s:handlers = {}
" Spawn is a wrapper around s:spawn. It can be executed by other files and
" scripts if needed. Desc defines the description for printing the status
" during the job execution (useful for statusline integration).
function! go#jobcontrol#Spawn(bang, desc, for, args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let job = s:spawn(a:bang, a:desc, a:for, a:args)
return job.id
endfunction
" AddHandler adds a on_exit callback handler and returns the id.
function! go#jobcontrol#AddHandler(handler) abort
let i = len(s:handlers)
while has_key(s:handlers, string(i))
let i += 1
break
endwhile
let s:handlers[string(i)] = a:handler
return string(i)
endfunction
" RemoveHandler removes a callback handler by id.
function! go#jobcontrol#RemoveHandler(id) abort
unlet s:handlers[a:id]
endfunction
" spawn spawns a go subcommand with the name and arguments with jobstart. Once a
" job is started a reference will be stored inside s:jobs. The job is started
" inside the current files folder.
function! s:spawn(bang, desc, for, args) abort
let status_type = a:args[0]
let status_dir = expand('%:p:h')
let started_at = reltime()
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': status_type,
\ 'state': "started",
\})
let job = {
\ 'desc': a:desc,
\ 'bang': a:bang,
\ 'winid': win_getid(winnr()),
\ 'importpath': go#package#ImportPath(),
\ 'state': "RUNNING",
\ 'stderr' : [],
\ 'stdout' : [],
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit' : function('s:on_exit'),
\ 'status_type' : status_type,
\ 'status_dir' : status_dir,
\ 'started_at' : started_at,
\ 'for' : a:for,
\ 'errorformat': &errorformat,
\ }
" execute go build in the files directory
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
" cleanup previous jobs for this file
for jb in values(s:jobs)
if jb.importpath == job.importpath
unlet s:jobs[jb.id]
endif
endfor
let dir = getcwd()
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
" append the subcommand, such as 'build'
let argv = ['go'] + a:args
" run, forrest, run!
let id = jobstart(argv, job)
let job.id = id
let job.dir = jobdir
let s:jobs[id] = job
execute cd . fnameescape(dir)
return job
endfunction
" on_exit is the exit handler for jobstart(). It handles cleaning up the job
" references and also displaying errors in the quickfix window collected by
" on_stderr handler. If there are no errors and a quickfix window is open,
" it'll be closed.
function! s:on_exit(job_id, exit_status, event) dict abort
let l:winid = win_getid(winnr())
call win_gotoid(self.winid)
let status = {
\ 'desc': 'last status',
\ 'type': self.status_type,
\ 'state': "success",
\ }
if a:exit_status
let status.state = "failed"
endif
let elapsed_time = reltimestr(reltime(self.started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(self.status_dir, status)
let std_combined = self.stderr + self.stdout
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
execute cd self.dir
call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined)
let l:listtype = go#list#Type(self.for)
if a:exit_status == 0
call go#list#Clean(l:listtype)
let self.state = "SUCCESS"
if go#config#EchoCommandInfo()
call go#util#EchoSuccess("[" . self.status_type . "] SUCCESS")
endif
execute cd . fnameescape(dir)
call win_gotoid(l:winid)
return
endif
let self.state = "FAILED"
if go#config#EchoCommandInfo()
call go#util#EchoError("[" . self.status_type . "] FAILED")
endif
" parse the errors relative to self.jobdir
call go#list#ParseFormat(l:listtype, self.errorformat, std_combined, self.for)
let errors = go#list#Get(l:listtype)
execute cd . fnameescape(dir)
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(std_combined[0])
call win_gotoid(l:winid)
return
endif
" if we are still in the same windows show the list
if self.winid == l:winid
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !self.bang
call go#list#JumpToFirst(l:listtype)
endif
endif
endfunction
" callback_handlers_on_exit runs all handlers for job on exit event.
function! s:callback_handlers_on_exit(job, exit_status, data) abort
if empty(s:handlers)
return
endif
for s:handler in values(s:handlers)
call s:handler(a:job, a:exit_status, a:data)
endfor
endfunction
" on_stdout is the stdout handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stdout list.
function! s:on_stdout(job_id, data, event) dict abort
call extend(self.stdout, a:data)
endfunction
" on_stderr is the stderr handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stderr list.
function! s:on_stderr(job_id, data, event) dict abort
call extend(self.stderr, a:data)
endfunction
" vim: sw=2 ts=2 et

View file

@ -34,28 +34,21 @@ function! go#test#Test(bang, compile, ...) abort
endif
endif
if go#util#has_job()
if go#util#has_job() || has('nvim')
" use vim's job functionality to call it asynchronously
let job_args = {
\ 'cmd': ['go'] + args,
let job_options = {
\ 'bang': a:bang,
\ 'winid': win_getid(winnr()),
\ 'dir': getcwd(),
\ 'compile_test': a:compile,
\ 'jobdir': fnameescape(expand("%:p:h")),
\ 'for': 'GoTest',
\ 'statustype': 'test',
\ 'errorformat': s:errorformat(),
\ }
call s:test_job(job_args)
return
elseif has('nvim')
" use nvims's job functionality
if go#config#TermEnabled()
let id = go#term#new(a:bang, ["go"] + args)
else
let id = go#jobcontrol#Spawn(a:bang, "test", "GoTest", args)
if a:compile
let job_options.statustype = 'compile ' . job_options.statustype
endif
return id
call s:test_job(['go'] + args, job_options)
return
endif
call go#cmd#autowrite()
@ -129,156 +122,13 @@ function! go#test#Func(bang, ...) abort
call call('go#test#Test', args)
endfunction
function! s:test_job(args) abort
let status = {
\ 'desc': 'current status',
\ 'type': "test",
\ 'state': "started",
\ }
if a:args.compile_test
let status.state = "compiling"
endif
function! s:test_job(cmd, args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let state = {
\ 'exited': 0,
\ 'closed': 0,
\ 'exitval': 0,
\ 'messages': [],
\ 'args': a:args,
\ 'compile_test': a:args.compile_test,
\ 'status_dir': expand('%:p:h'),
\ 'started_at': reltime()
\ }
call go#statusline#Update(state.status_dir, status)
function! s:callback(chan, msg) dict
call add(self.messages, a:msg)
call go#job#Spawn(a:cmd, a:args)
endfunction
function! s:exit_cb(job, exitval) dict
let self.exited = 1
let self.exitval = a:exitval
let status = {
\ 'desc': 'last status',
\ 'type': "test",
\ 'state': "pass",
\ }
if self.compile_test
let status.state = "success"
endif
if a:exitval
let status.state = "failed"
endif
if go#config#EchoCommandInfo()
if a:exitval == 0
if self.compile_test
call go#util#EchoSuccess("[test] SUCCESS")
else
call go#util#EchoSuccess("[test] PASS")
endif
else
call go#util#EchoError("[test] FAIL")
endif
endif
let elapsed_time = reltimestr(reltime(self.started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(self.status_dir, status)
if self.closed
call s:show_errors(self.args, self.exitval, self.messages)
endif
endfunction
function! s:close_cb(ch) dict
let self.closed = 1
if self.exited
call s:show_errors(self.args, self.exitval, self.messages)
endif
endfunction
" explicitly bind the callbacks to state so that self within them always
" refers to state. See :help Partial for more information.
let start_options = {
\ 'callback': funcref("s:callback", [], state),
\ 'exit_cb': funcref("s:exit_cb", [], state),
\ 'close_cb': funcref("s:close_cb", [], state)
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
endfunction
" show_errors parses the given list of lines of a 'go test' output and returns
" a quickfix compatible list of errors. It's intended to be used only for go
" test output.
function! s:show_errors(args, exit_val, messages) abort
let l:winid = win_getid(winnr())
call win_gotoid(a:args.winid)
let l:listtype = go#list#Type("GoTest")
if a:exit_val == 0
call go#list#Clean(l:listtype)
call win_gotoid(l:winid)
return
endif
" TODO(bc): When messages is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd a:args.jobdir
call go#list#ParseFormat(l:listtype, s:errorformat(), a:messages, join(a:args.cmd))
let errors = go#list#Get(l:listtype)
finally
execute cd . fnameescape(a:args.dir)
endtry
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(a:messages)
call go#util#EchoError(a:args.dir)
call win_gotoid(l:winid)
return
endif
if a:args.winid != l:winid
call win_gotoid(l:winid)
return
endif
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:args.bang
call go#list#JumpToFirst(l:listtype)
endif
endfunction
let s:efm = ""
let s:go_test_show_name = 0

View file

@ -89,15 +89,6 @@ func! Test_GoTestTestCompilerError() abort
endfunc
func! s:test(file, expected, ...) abort
if has('nvim')
" nvim mostly shows test errors correctly, but the the expected errors are
" slightly different; buffer numbers are not the same and stderr doesn't
" seem to be redirected to the job, so the lines from the panic aren't in
" the output to be parsed, and hence are not in the quickfix lists. Once
" those two issues are resolved, this early return should be removed so
" the tests will run for Neovim, too.
return
endif
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test'
silent exe 'e ' . $GOPATH . '/src/' . a:file

View file

@ -167,13 +167,16 @@ function! go#util#Exec(cmd, ...) abort
let l:bin = a:cmd[0]
" Lookup the full path, respecting settings such as 'go_bin_path'. On errors,
" CheckBinPath will show a warning for us.
let l:bin = go#path#CheckBinPath(l:bin)
if empty(l:bin)
return ['', 1]
endif
return call('s:exec', [a:cmd] + a:000)
" Finally execute the command using the full, resolved path. Do not pass the
" unmodified command as the correct program might not exist in $PATH.
return call('s:exec', [[l:bin] + a:cmd[1:]] + a:000)
endfunction
function! s:exec(cmd, ...) abort

View file

@ -39,9 +39,23 @@ Vim command sequence: `df[$r,0f,v<C-n>…<C-n>c<CR><Up><Del><Right><Right><Right
To see what keystrokes are used for the above examples, see [the wiki page](https://github.com/terryma/vim-multiple-cursors/wiki/Keystrokes-for-example-gifs).
## Installation
Install using [Pathogen], [Vundle], [Neobundle], or your favorite Vim package manager.
Install using [Pathogen], [Vundle], [Neobundle], [vim-plug], or your favorite Vim package manager.
Requires vim 7.4 or later for full functionality.
Requires vim 7.4 or newer for full functionality.
### vim-plug instructions
1. Paste this block into the top of `~/.vimrc`.
```vim script
call plug#begin()
Plug 'terryma/vim-multiple-cursors'
call plug#end()
```
2. Start vim and execute `:PlugInstall`.
## Quick Start
### normal mode / visual mode
@ -213,4 +227,5 @@ Obviously inspired by Sublime Text's [multiple selection][sublime-multiple-selec
[Pathogen]:http://github.com/tpope/vim-pathogen
[Vundle]:http://github.com/gmarik/vundle
[Neobundle]:http://github.com/Shougo/neobundle.vim
[vim-plug]:https://github.com/junegunn/vim-plug
[emacs-multiple-cursors]:https://github.com/magnars/multiple-cursors.el

View file

@ -9,94 +9,10 @@ ${1:pattern}${2: when ${3:guard}} ->
${4:body}
endsnippet
snippet beh "Behaviour Directive" b
-behaviour(${1:behaviour}).
endsnippet
snippet case "Case Expression"
case ${1:expression} of
${2:pattern}${3: when ${4:guard}} ->
${5:body}
end
endsnippet
snippet def "Define Directive" b
-define(${1:macro}${2: (${3:param})}, ${4:body}).
endsnippet
snippet exp "Export Directive" b
-export([${1:function}/${2:arity}]).
endsnippet
snippet fun "Fun Expression"
fun
(${1:pattern})${2: when ${3:guard}} ->
${4:body}
end
endsnippet
snippet fu "Function"
${1:function}(${2:param})${3: when ${4:guard}} ->
${5:body}
endsnippet
snippet if "If Expression"
if
${1:guard} ->
${2:body}
end
endsnippet
snippet ifdef "Ifdef Directive" b
-ifdef(${1:macro}).
endsnippet
snippet ifndef "Ifndef Directive" b
-ifndef(${1:macro}).
endsnippet
snippet imp "Import Directive" b
-import(${1:module}, [${2:function}/${3:arity}]).
endsnippet
snippet inc "Include Directive" b
-include("${1:file}").
endsnippet
snippet mod "Module Directive" b
-module(${1:`!p snip.rv = snip.basename or "module"`}).
endsnippet
snippet rcv "Receive Expression"
receive
${1: ${2:pattern}${3: when ${4:guard}} ->
${5:body}}
${6:after
${7:expression} ->
${8:body}}
end
endsnippet
snippet rec "Record Directive" b
-record(${1:record}, {${2:field}${3: = ${4:value}}}).
endsnippet
snippet try "Try Expression"
try${1: ${2:expression}${3: of
${4:pattern}${5: when ${6:guard}} ->
${7:body}}}
${8:catch
${9:pattern}${10: when ${11:guard}} ->
${12:body}}
${13:after
${14:body}}
end
endsnippet
snippet undef "Undef Directive" b
-undef(${1:macro}).
endsnippet
snippet || "List Comprehension"
[${1:X} || ${2:X} <- ${3:List}${4:, gen}]
endsnippet

View file

@ -50,6 +50,23 @@ snippet spar "Paragraph" b
$0
endsnippet
###################
# Text formatting #
###################
snippet * "italics"
*${1:${VISUAL}}*$0
endsnippet
snippet ** "bold"
**${1:${VISUAL}}**$0
endsnippet
snippet *** "bold italics"
***${1:${VISUAL}}***$0
endsnippet
################
# Common stuff #
################

View file

@ -7,10 +7,10 @@ endsnippet
snippet t "Simple tag" b
<${1:tag}>
${2:content}
${2:${VISUAL}}
</${1/([\w:._-]+).*/$1/}>
endsnippet
snippet ti "Inline tag" b
<${1:tag}>${2:content}</${1/([\w:._-]+).*/$1/}>
<${1:tag}>${2:${VISUAL}}</${1/([\w:._-]+).*/$1/}>
endsnippet

View file

@ -11,6 +11,10 @@ snippet modall
stop() ->
ok.
snippet d
erlang:display(${0}),
snippet dt
erlang:display({${1}, ${0}}),
# define directive
snippet def
-define(${1:macro}, ${2:body}).
@ -30,6 +34,12 @@ snippet ifd
-ifdef(${1:TEST}).
${0}
-endif.
snippet ifnd
-ifndef(${1:TEST}).
${0}
-endif.
snippet undef
-undef(${1:macro}).
# if expression
snippet if
if
@ -52,10 +62,17 @@ snippet try
catch
${2:_:_} -> ${0:got_some_exception}
end
snippet rcv "Receive Expression"
receive
${1: ${2:pattern}${3: when ${4:guard}} ->
${5:body}}
${6:after
${7:expression} ->
${8:body}}
end
# record directive
snippet rec
-record(${1:record}, {
${2:field}=${3:value}}).
-record(${1:record}, {${2:field}=${3:value}}).
# todo comment
snippet todo
%% TODO: ${0}
@ -121,17 +138,10 @@ snippet gen_server
-behaviour(gen_server).
%% API
-export([
start_link/0
]).
-export([start_link/0]).
%% gen_server callbacks
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
@ -180,14 +190,8 @@ snippet gen_fsm
-export([start_link/0]).
%% gen_fsm callbacks
-export([init/1,
state_name/2,
state_name/3,
handle_event/3,
handle_sync_event/4,
handle_info/3,
terminate/3,
code_change/4]).
-export([init/1, state_name/2, state_name/3, handle_event/3, handle_sync_event/4,
handle_info/3, terminate/3, code_change/4]).
-record(state, {}).
@ -497,6 +501,16 @@ snippet ieunit
${0}
-endif.
snippet itest
-ifdef(TEST).
${1}_test() ->
${0}
-endif.
snippet test
${1}_test() ->
${0}
snippet as
?assert(${0})
snippet asn

View file

@ -0,0 +1 @@
extends typescript