Updated plugins

This commit is contained in:
Amir Salihefendic 2019-03-27 16:08:56 +01:00
parent bf7b5985f1
commit 5a2572df03
73 changed files with 1924 additions and 598 deletions

View file

@ -37,11 +37,22 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
return l:output
endfunction
function! ale_linters#elixir#credo#GetMode() abort
if get(g:, 'ale_elixir_credo_strict', 0)
return '--strict'
else
return 'suggest'
endif
endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root)
\ . ' mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
\ . 'mix help credo && '
\ . 'mix credo ' . ale_linters#elixir#credo#GetMode()
\ . ' --format=flycheck --read-from-stdin %s'
endfunction
call ale#linter#Define('elixir', {

View file

@ -0,0 +1,22 @@
" Author: antew - https://github.com/antew
" Description: LSP integration for elm, currently supports diagnostics (linting)
call ale#Set('elm_lsp_executable', 'elm-lsp')
call ale#Set('elm_lsp_use_global', get(g:, 'ale_use_global_executables', 0))
function! elm_lsp#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction
call ale#linter#Define('elm', {
\ 'name': 'elm_lsp',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_lsp', [
\ 'node_modules/.bin/elm-lsp',
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('elm_lsp#GetRootDir'),
\ 'language': 'elm'
\})

View file

@ -1,4 +1,21 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" Author: KabbAmine <amine.kabb@gmail.com>, David Sierra <https://github.com/davidsierradz>
call ale#Set('json_jsonlint_executable', 'jsonlint')
call ale#Set('json_jsonlint_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#json#jsonlint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'json_jsonlint', [
\ 'node_modules/.bin/jsonlint',
\ 'node_modules/jsonlint/lib/cli.js',
\])
endfunction
function! ale_linters#json#jsonlint#GetCommand(buffer) abort
let l:executable = ale_linters#json#jsonlint#GetExecutable(a:buffer)
return ale#node#Executable(a:buffer, l:executable)
\ . ' --compact -'
endfunction
function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
" Matches patterns like the following:
@ -19,8 +36,8 @@ endfunction
call ale#linter#Define('json', {
\ 'name': 'jsonlint',
\ 'executable': 'jsonlint',
\ 'executable': function('ale_linters#json#jsonlint#GetExecutable'),
\ 'output_stream': 'stderr',
\ 'command': 'jsonlint --compact -',
\ 'command': function('ale_linters#json#jsonlint#GetCommand'),
\ 'callback': 'ale_linters#json#jsonlint#Handle',
\})

View file

@ -0,0 +1,5 @@
" Author: Vincent (wahrwolf [ät] wolfpit.net)
" Description: languagetool for mails
call ale#handlers#languagetool#DefineLinter('mail')

View file

@ -0,0 +1,5 @@
" Author: Vincent (wahrwolf [ät] wolfpit.net)
" Description: languagetool for markdown files
call ale#handlers#languagetool#DefineLinter('markdown')

View file

@ -5,6 +5,12 @@ call ale#Set('php_langserver_executable', 'php-language-server.php')
call ale#Set('php_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json')
if (!empty(l:composer_path))
return fnamemodify(l:composer_path, ':h')
endif
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''

View file

@ -0,0 +1,4 @@
" Author: Vincent (wahrwolf [ät] wolfpit.net)
" Description: languagetool for text files
call ale#handlers#languagetool#DefineLinter('text')

View file

@ -39,6 +39,9 @@ let s:LSP_COMPLETION_COLOR_KIND = 16
let s:LSP_COMPLETION_FILE_KIND = 17
let s:LSP_COMPLETION_REFERENCE_KIND = 18
let s:LSP_INSERT_TEXT_FORMAT_PLAIN = 1
let s:LSP_INSERT_TEXT_FORMAT_SNIPPET = 2
let s:lisp_regex = '\v[a-zA-Z_\-][a-zA-Z_\-0-9]*$'
" Regular expressions for checking the characters in the line before where
@ -165,8 +168,11 @@ function! s:ReplaceCompletionOptions() abort
let &l:omnifunc = 'ale#completion#OmniFunc'
if !exists('b:ale_old_completopt')
let b:ale_old_completopt = &l:completeopt
let l:info = get(b:, 'ale_completion_info', {})
if !get(l:info, 'manual')
if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt
endif
if &l:completeopt =~# 'preview'
@ -174,6 +180,7 @@ function! s:ReplaceCompletionOptions() abort
else
let &l:completeopt = 'menu,menuone,noselect,noinsert'
endif
endif
endfunction
function! ale#completion#RestoreCompletionOptions() abort
@ -186,9 +193,9 @@ function! ale#completion#RestoreCompletionOptions() abort
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
if exists('b:ale_old_completeopt')
let &l:completeopt = b:ale_old_completeopt
unlet b:ale_old_completeopt
endif
endfunction
@ -346,7 +353,14 @@ function! ale#completion#ParseLSPCompletions(response) abort
continue
endif
let l:word = matchstr(l:item.label, '\v^[^(]+')
if get(l:item, 'insertTextFormat') is s:LSP_INSERT_TEXT_FORMAT_PLAIN
\&& type(get(l:item, 'textEdit')) is v:t_dict
let l:text = l:item.textEdit.newText
else
let l:text = l:item.label
endif
let l:word = matchstr(l:text, '\v^[^(]+')
if empty(l:word)
continue
@ -385,10 +399,10 @@ function! ale#completion#ParseLSPCompletions(response) abort
endfor
if has_key(l:info, 'prefix')
return ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
let l:results = ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
endif
return l:results
return l:results[: g:ale_completion_max_suggestions - 1]
endfunction
function! ale#completion#HandleTSServerResponse(conn_id, response) abort
@ -503,22 +517,14 @@ function! s:OnReady(linter, lsp_details) abort
endif
endfunction
function! ale#completion#GetCompletions() abort
if !g:ale_completion_enabled
return
endif
call ale#completion#AlwaysGetCompletions(1)
endfunction
" This function can be used to manually trigger autocomplete, even when
" g:ale_completion_enabled is set to false
function! ale#completion#AlwaysGetCompletions(need_prefix) abort
function! ale#completion#GetCompletions(manual) abort
let [l:line, l:column] = getpos('.')[1:2]
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if a:need_prefix && empty(l:prefix)
if !a:manual && empty(l:prefix)
return
endif
@ -531,6 +537,7 @@ function! ale#completion#AlwaysGetCompletions(need_prefix) abort
\ 'prefix': l:prefix,
\ 'conn_id': 0,
\ 'request_id': 0,
\ 'manual': a:manual,
\}
let l:buffer = bufnr('')
@ -544,6 +551,10 @@ function! ale#completion#AlwaysGetCompletions(need_prefix) abort
endfunction
function! s:TimerHandler(...) abort
if !g:ale_completion_enabled
return
endif
let s:timer_id = -1
let [l:line, l:column] = getpos('.')[1:2]
@ -551,7 +562,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] && ale#util#Mode() is# 'i'
call ale#completion#GetCompletions()
call ale#completion#GetCompletions(0)
endif
endfunction

View file

@ -142,8 +142,8 @@ let s:default_registry = {
\ },
\ 'clang-format': {
\ 'function': 'ale#fixers#clangformat#Fix',
\ 'suggested_filetypes': ['c', 'cpp'],
\ 'description': 'Fix C/C++ files with clang-format.',
\ 'suggested_filetypes': ['c', 'cpp', 'cuda'],
\ 'description': 'Fix C/C++ and cuda files with clang-format.',
\ },
\ 'cmakeformat': {
\ 'function': 'ale#fixers#cmakeformat#Fix',

View file

@ -1,3 +1,4 @@
scriptencoding utf-8
" Author: Johannes Wienke <languitar@semipol.de>
" Description: Error handling for errors in alex output format
@ -44,8 +45,8 @@ function! ale#handlers#alex#DefineLinter(filetype, flags) abort
call ale#linter#Define(a:filetype, {
\ 'name': 'alex',
\ 'executable_callback': 'ale#handlers#alex#GetExecutable',
\ 'command_callback': ale#handlers#alex#CreateCommandCallback(a:flags),
\ 'executable': function('ale#handlers#alex#GetExecutable'),
\ 'command': ale#handlers#alex#CreateCommandCallback(a:flags),
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#alex#Handle',
\ 'lint_file': 1,

View file

@ -0,0 +1,74 @@
" Author: Vincent (wahrwolf [at] wolfpit.net)
" Description: languagetool for markdown files
"
call ale#Set('languagetool_executable', 'languagetool')
function! ale#handlers#languagetool#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'languagetool_executable')
endfunction
function! ale#handlers#languagetool#GetCommand(buffer) abort
let l:executable = ale#handlers#languagetool#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' --autoDetect %s'
endfunction
function! ale#handlers#languagetool#HandleOutput(buffer, lines) abort
" Match lines like:
" 1.) Line 5, column 1, Rule ID:
let l:head_pattern = '^\v.+.\) Line (\d+), column (\d+), Rule ID. (.+)$'
let l:head_matches = ale#util#GetMatches(a:lines, l:head_pattern)
" Match lines like:
" Message: Did you forget a comma after a conjunctive/linking adverb?
let l:message_pattern = '^\vMessage. (.+)$'
let l:message_matches = ale#util#GetMatches(a:lines, l:message_pattern)
" Match lines like:
" ^^^^^ "
let l:markers_pattern = '^\v *(\^+) *$'
let l:markers_matches = ale#util#GetMatches(a:lines, l:markers_pattern)
let l:output = []
" Okay tbh I was to lazy to figure out a smarter solution here
" We just check that the arrays are same sized and merge everything
" together
let l:i = 0
while l:i < len(l:head_matches)
\ && (
\ (len(l:head_matches) == len(l:markers_matches))
\ && (len(l:head_matches) == len(l:message_matches))
\ )
let l:item = {
\ 'lnum' : str2nr(l:head_matches[l:i][1]),
\ 'col' : str2nr(l:head_matches[l:i][2]),
\ 'end_col' : str2nr(l:head_matches[l:i][2]) + len(l:markers_matches[l:i][1])-1,
\ 'type' : 'W',
\ 'code' : l:head_matches[l:i][3],
\ 'text' : l:message_matches[l:i][1]
\}
call add(l:output, l:item)
let l:i+=1
endwhile
return l:output
endfunction
" Define the languagetool linter for a given filetype.
" TODO:
" - Add language detection settings based on user env (for mothertongue)
" - Add fixer
" - Add config options for rules
function! ale#handlers#languagetool#DefineLinter(filetype) abort
call ale#linter#Define(a:filetype, {
\ 'name': 'languagetool',
\ 'executable': function('ale#handlers#languagetool#GetExecutable'),
\ 'command': function('ale#handlers#languagetool#GetCommand'),
\ 'output_stream': 'stdout',
\ 'callback': 'ale#handlers#languagetool#HandleOutput',
\ 'lint_file': 1,
\})
endfunction

View file

@ -60,7 +60,7 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
\ 'lnum': l:span.line_start,
\ 'end_lnum': l:span.line_end,
\ 'col': l:span.column_start,
\ 'end_col': l:span.column_end,
\ 'end_col': l:span.column_end-1,
\ 'text': empty(l:span.label) ? l:error.message : printf('%s: %s', l:error.message, l:span.label),
\ 'type': toupper(l:error.level[0]),
\})

View file

@ -26,7 +26,6 @@ function! ale#handlers#sml#GetCmFile(buffer) abort
endfunction
" Only one of smlnj or smlnj-cm can be enabled at a time.
" executable_callback is called before *every* lint attempt
function! s:GetExecutable(buffer, source) abort
if ale#handlers#sml#GetCmFile(a:buffer) is# ''
" No CM file found; only allow single-file mode to be enabled

View file

@ -65,8 +65,8 @@ function! ale#handlers#writegood#DefineLinter(filetype) abort
call ale#linter#Define(a:filetype, {
\ 'name': 'writegood',
\ 'aliases': ['write-good'],
\ 'executable_callback': 'ale#handlers#writegood#GetExecutable',
\ 'command_callback': 'ale#handlers#writegood#GetCommand',
\ 'executable': function('ale#handlers#writegood#GetExecutable'),
\ 'command': function('ale#handlers#writegood#GetCommand'),
\ 'callback': 'ale#handlers#writegood#Handle',
\})
endfunction

View file

@ -205,10 +205,13 @@ function! ale#path#FromURI(uri) abort
let l:encoded_path = a:uri
endif
let l:path = ale#uri#Decode(l:encoded_path)
" If the path is like /C:/foo/bar, it should be C:\foo\bar instead.
if l:encoded_path =~# '^/[a-zA-Z]:'
let l:encoded_path = substitute(l:encoded_path[1:], '/', '\\', 'g')
if has('win32') && l:path =~# '^/[a-zA-Z][:|]'
let l:path = substitute(l:path[1:], '/', '\\', 'g')
let l:path = l:path[0] . ':' . l:path[2:]
endif
return ale#uri#Decode(l:encoded_path)
return l:path
endfunction

View file

@ -14,10 +14,10 @@ function! ale#semver#GetVersion(executable, version_lines) abort
let l:version = get(s:version_cache, a:executable, [])
for l:line in a:version_lines
let l:match = matchlist(l:line, '\v(\d+)\.(\d+)\.?(\d?)')
let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?')
if !empty(l:match)
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0]
let s:version_cache[a:executable] = l:version
break

View file

@ -64,16 +64,21 @@ if !hlexists('ALESignColumnWithoutErrors')
call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight()
endif
" Spaces and backslashes need to be escaped for signs.
function! s:EscapeSignText(sign_text) abort
return substitute(a:sign_text, '\\\| ', '\\\0', 'g')
endfunction
" Signs show up on the left for error markers.
execute 'sign define ALEErrorSign text=' . g:ale_sign_error
execute 'sign define ALEErrorSign text=' . s:EscapeSignText(g:ale_sign_error)
\ . ' texthl=ALEErrorSign linehl=ALEErrorLine'
execute 'sign define ALEStyleErrorSign text=' . g:ale_sign_style_error
execute 'sign define ALEStyleErrorSign text=' . s:EscapeSignText(g:ale_sign_style_error)
\ . ' texthl=ALEStyleErrorSign linehl=ALEErrorLine'
execute 'sign define ALEWarningSign text=' . g:ale_sign_warning
execute 'sign define ALEWarningSign text=' . s:EscapeSignText(g:ale_sign_warning)
\ . ' texthl=ALEWarningSign linehl=ALEWarningLine'
execute 'sign define ALEStyleWarningSign text=' . g:ale_sign_style_warning
execute 'sign define ALEStyleWarningSign text=' . s:EscapeSignText(g:ale_sign_style_warning)
\ . ' texthl=ALEStyleWarningSign linehl=ALEWarningLine'
execute 'sign define ALEInfoSign text=' . g:ale_sign_info
execute 'sign define ALEInfoSign text=' . s:EscapeSignText(g:ale_sign_info)
\ . ' texthl=ALEInfoSign linehl=ALEInfoLine'
sign define ALEDummySign

View file

@ -21,5 +21,12 @@ g:ale_cuda_nvcc_options *g:ale_cuda_nvcc_options*
This variable can be changed to modify flags given to nvcc.
===============================================================================
clang-format *ale-cuda-clangformat*
See |ale-c-clangformat| for information about the available options.
Note that the C options are also used for cuda.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -72,6 +72,18 @@ g:ale_elixir_elixir_ls_config *g:ale_elixir_elixir_ls_config*
\ }
<
Consult the ElixirLS documentation for more information about settings.
===============================================================================
credo *ale-elixir-credo*
Credo (https://github.com/rrrene/credo)
g:ale_elixir_credo_strict *g:ale_elixir_credo_strict*
Type: Integer
Default: 0
Tells credo to run in strict mode or suggest mode. Set variable to 1 to
enable --strict mode.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -28,6 +28,24 @@ g:ale_elm_format_options *g:ale_elm_format_options*
This variable can be set to pass additional options to elm-format.
===============================================================================
elm-lsp *ale-elm-elm-lsp*
g:ale_elm_lsp_executable *g:ale_elm_lsp_executable*
*b:ale_elm_lsp_executable*
Type: |String|
Default: `'elm-lsp'`
See |ale-integrations-local-executables|
g:ale_elm_lsp_use_global *g:ale_elm_lsp_use_global*
*b:ale_elm_lsp_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
elm-make *ale-elm-elm-make*

View file

@ -52,7 +52,21 @@ g:ale_json_fixjson_use_global *g:ale_json_fixjson_use_global*
===============================================================================
jsonlint *ale-json-jsonlint*
There are no options available.
g:ale_json_jsonlint_executable *g:ale_json_jsonlint_executable*
*b:ale_json_jsonlint_executable*
Type: |String|
Default: `'jsonlint'`
The executable that will be run for jsonlint.
g:ale_json_jsonlint_use_global *g:ale_json_jsonlint_use_global*
*b:ale_json_jsonlint_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================

View file

@ -118,6 +118,7 @@ Notes:
* `mix`!!
* Elm
* `elm-format`
* `elm-lsp`
* `elm-make`
* Erb
* `erb`
@ -241,12 +242,14 @@ Notes:
* `luacheck`
* Mail
* `alex`!!
* `languagetool`!!
* `proselint`
* `vale`
* Make
* `checkmake`
* Markdown
* `alex`!!
* `languagetool`!!
* `markdownlint`!!
* `mdl`
* `prettier`
@ -417,6 +420,7 @@ Notes:
* `write-good`
* Text^
* `alex`!!
* `languagetool`!!
* `proselint`
* `redpen`
* `textlint`

View file

@ -22,8 +22,9 @@ CONTENTS *ale-contents*
6.1 Highlights........................|ale-highlights|
7. Linter/Fixer Options.................|ale-integration-options|
7.1 Options for alex..................|ale-alex-options|
7.2 Options for write-good............|ale-write-good-options|
7.3 Other Linter/Fixer Options........|ale-other-integration-options|
7.2 Options for languagetool..........|ale-languagetool-options|
7.3 Options for write-good............|ale-write-good-options|
7.4 Other Linter/Fixer Options........|ale-other-integration-options|
8. Commands/Keybinds....................|ale-commands|
9. API..................................|ale-api|
10. Special Thanks......................|ale-special-thanks|
@ -103,6 +104,7 @@ ALE supports the following key features for linting:
stylelint...........................|ale-css-stylelint|
cuda..................................|ale-cuda-options|
nvcc................................|ale-cuda-nvcc|
clang-format........................|ale-cuda-clangformat|
d.....................................|ale-d-options|
dls.................................|ale-d-dls|
uncrustify..........................|ale-d-uncrustify|
@ -117,8 +119,10 @@ ALE supports the following key features for linting:
mix_format..........................|ale-elixir-mix-format|
dialyxir............................|ale-elixir-dialyxir|
elixir-ls...........................|ale-elixir-elixir-ls|
credo...............................|ale-elixir-credo|
elm...................................|ale-elm-options|
elm-format..........................|ale-elm-elm-format|
elm-lsp.............................|ale-elm-elm-lsp|
elm-make............................|ale-elm-elm-make|
erlang................................|ale-erlang-options|
erlc................................|ale-erlang-erlc|
@ -699,13 +703,13 @@ with |g:ale_completion_excluded_words| or |b:ale_completion_excluded_words|.
The |ALEComplete| command can be used to show completion suggestions manually,
even when |g:ale_completion_enabled| is set to `0`.
*ale-completion-completopt-bug*
*ale-completion-completeopt-bug*
ALE implements completion as you type by temporarily adjusting |completeopt|
before opening the omnicomplete menu with <C-x><C-o>. In some versions of Vim,
the value set for the option will not be respected. If you experience issues
with Vim automatically inserting text while you type, set the following option
in vimrc, and your issues should go away. >
Automatic completion replaces |completeopt| before opening the omnicomplete
menu with <C-x><C-o>. In some versions of Vim, the value set for the option
will not be respected. If you experience issues with Vim automatically
inserting text while you type, set the following option in vimrc, and your
issues should go away. >
set completeopt=menu,menuone,preview,noselect,noinsert
<
@ -2136,7 +2140,19 @@ g:ale_alex_use_global *g:ale_alex_use_global*
-------------------------------------------------------------------------------
7.2. Options for write-good *ale-write-good-options*
7.2. Options for languagetool *ale-languagetool-options*
g:ale_languagetool_executable *g:ale_languagetool_executable*
*b:ale_languagetool_executable*
Type: |String|
Default: `'languagetool'`
The executable to run for languagetool.
-------------------------------------------------------------------------------
7.3. Options for write-good *ale-write-good-options*
The options for `write-good` are shared between all filetypes, so options can
be configured once.
@ -2166,7 +2182,7 @@ g:ale_writegood_use_global *g:ale_writegood_use_global*
-------------------------------------------------------------------------------
7.3. Other Linter/Fixer Options *ale-other-integration-options*
7.4. Other Linter/Fixer Options *ale-other-integration-options*
ALE supports a very wide variety of tools. Other linter or fixer options are
documented in additional help files.
@ -2227,6 +2243,7 @@ documented in additional help files.
stylelint.............................|ale-css-stylelint|
cuda....................................|ale-cuda-options|
nvcc..................................|ale-cuda-nvcc|
clang-format..........................|ale-cuda-clangformat|
d.......................................|ale-d-options|
dls...................................|ale-d-dls|
uncrustify............................|ale-d-uncrustify|
@ -2241,8 +2258,10 @@ documented in additional help files.
mix_format............................|ale-elixir-mix-format|
dialyxir..............................|ale-elixir-dialyxir|
elixir-ls.............................|ale-elixir-elixir-ls|
credo.................................|ale-elixir-credo|
elm.....................................|ale-elm-options|
elm-format............................|ale-elm-elm-format|
elm-lsp...............................|ale-elm-elm-lsp|
elm-make..............................|ale-elm-elm-make|
erlang..................................|ale-erlang-options|
erlc..................................|ale-erlang-erlc|

View file

@ -216,7 +216,7 @@ command! -bar ALEDocumentation :call ale#hover#ShowDocumentationAtCursor()
" Search for appearances of a symbol, such as a type name or function name.
command! -nargs=1 ALESymbolSearch :call ale#symbol#Search(<q-args>)
command! -bar ALEComplete :call ale#completion#AlwaysGetCompletions(0)
command! -bar ALEComplete :call ale#completion#GetCompletions(1)
" <Plug> mappings for commands
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>

View file

@ -127,6 +127,7 @@ formatting.
* [mix](https://hexdocs.pm/mix/Mix.html) :warning: :floppy_disk:
* Elm
* [elm-format](https://github.com/avh4/elm-format)
* [elm-lsp](https://github.com/antew/elm-lsp)
* [elm-make](https://github.com/elm-lang/elm-make)
* Erb
* [erb](https://apidock.com/ruby/ERB)
@ -250,12 +251,14 @@ formatting.
* [luacheck](https://github.com/mpeterv/luacheck)
* Mail
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
* [proselint](http://proselint.com/)
* [vale](https://github.com/ValeLint/vale)
* Make
* [checkmake](https://github.com/mrtazz/checkmake)
* Markdown
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
* [markdownlint](https://github.com/DavidAnson/markdownlint) :floppy_disk:
* [mdl](https://github.com/mivok/markdownlint)
* [prettier](https://github.com/prettier/prettier)
@ -426,6 +429,7 @@ formatting.
* [write-good](https://github.com/btford/write-good)
* Text
* [alex](https://github.com/wooorm/alex) :warning: :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
* [proselint](http://proselint.com/) :warning:
* [redpen](http://redpen.cc/) :warning:
* [textlint](https://textlint.github.io/) :warning:

View file

@ -492,8 +492,7 @@ function! s:openNodeRecursively(node)
call nerdtree#echo("Recursively opening node. Please wait...")
call a:node.openRecursively()
call b:NERDTree.render()
redraw
call nerdtree#echo("Recursively opening node. Please wait... DONE")
redraw!
endfunction
" FUNCTION: s:previewBookmark(bookmark) {{{1
@ -544,9 +543,8 @@ function! s:refreshRoot()
call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w")
call b:NERDTree.root.refresh()
call b:NERDTree.render()
redraw
redraw!
call nerdtree#exec(l:curWin . "wincmd w")
call nerdtree#echo("Refreshing the root node. This could take a while... DONE")
endfunction
" FUNCTION: s:refreshCurrent(node) {{{1
@ -560,8 +558,7 @@ function! s:refreshCurrent(node)
call nerdtree#echo("Refreshing node. This could take a while...")
call node.refresh()
call b:NERDTree.render()
redraw
call nerdtree#echo("Refreshing node. This could take a while... DONE")
redraw!
endfunction
" FUNCTION: nerdtree#ui_glue#setupCommands() {{{1

View file

@ -564,7 +564,11 @@ endfunction
" Args:
" path: the other path obj to compare this with
function! s:Path.equals(path)
if nerdtree#runningWindows()
return self.str() ==? a:path.str()
else
return self.str() ==# a:path.str()
endif
endfunction
" FUNCTION: Path.New(pathStr) {{{1

View file

@ -432,9 +432,7 @@ function! s:TreeDirNode._initChildren(silent)
call self.sortChildren()
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
call nerdtree#echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
endif
redraw!
if invalidFilesFound
call nerdtree#echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree")

View file

@ -60,8 +60,10 @@ function! s:on_stdout_nvim(_job_id, data, _event) dict abort
endif
endfunction
function! s:on_stderr_nvim(_job_id, _data, _event) dict abort
function! s:on_stderr_nvim(_job_id, data, _event) dict abort
if a:data != [''] " With Neovim there is always [''] reported on stderr.
call self.handler.err(self.buffer)
endif
endfunction
function! s:on_exit_nvim(_job_id, exit_code, _event) dict abort

View file

@ -171,17 +171,17 @@ endfunction
function! gitgutter#hunk#stage() abort
call s:hunk_op(function('s:stage'))
silent! call repeat#set("\<Plug>GitGutterStageHunk", -1)<CR>
silent! call repeat#set("\<Plug>GitGutterStageHunk", -1)
endfunction
function! gitgutter#hunk#undo() abort
call s:hunk_op(function('s:undo'))
silent! call repeat#set("\<Plug>GitGutterUndoHunk", -1)<CR>
silent! call repeat#set("\<Plug>GitGutterUndoHunk", -1)
endfunction
function! gitgutter#hunk#preview() abort
call s:hunk_op(function('s:preview'))
silent! call repeat#set("\<Plug>GitGutterPreviewHunk", -1)<CR>
silent! call repeat#set("\<Plug>GitGutterPreviewHunk", -1)
endfunction

View file

@ -212,9 +212,16 @@ augroup gitgutter
" vim -o file1 file2
autocmd VimEnter * if winnr() != winnr('$') | call gitgutter#all(0) | endif
autocmd FocusGained,ShellCmdPost * call gitgutter#all(1)
autocmd ShellCmdPost * call gitgutter#all(1)
autocmd BufLeave term://* call gitgutter#all(1)
" Handle all buffers when focus is gained, but only after it was lost.
" FocusGained gets triggered on startup with Neovim at least already.
" Therefore this tracks also if it was lost before.
let s:focus_was_lost = 0
autocmd FocusGained * if s:focus_was_lost | let focus_was_lost = 0 | call gitgutter#all(1) | endif
autocmd FocusLost * let s:focus_was_lost = 1
if exists('##VimResume')
autocmd VimResume * call gitgutter#all(1)
endif

View file

@ -1,4 +1,5 @@
.local/
.config/
.cache/
.dlv/
.git/

View file

@ -1,6 +1,6 @@
language: go
go:
- 1.11.x
- 1.12.1
notifications:
email: false
matrix:

View file

@ -1,7 +1,17 @@
## unplanned
FEATURES:
* ***gopls support!***
* use gopls for autocompletion by default in Vim8 and Neovim.
* use gopls for `:GoDef` by setting `g:go_def_mode='gopls'`.
* Add support for golangci-lint.
* set `g:go_metalinter_command='golanci-lint'` to use golangci-lint instead
of gometalinter.
* New `:GoDefType` command to jump to a type definition from an instance of the
type.
BACKWARDS INCOMPATABILITIES:
* g:go_highlight_function_arguments is renamed to g:go_highlight_function_parameters
* `g:go_highlight_function_arguments` is renamed to `g:go_highlight_function_parameters`
[[GH-2117]](https://github.com/fatih/vim-go/pull/2117)
IMPROVEMENTS:
@ -19,12 +29,12 @@ IMPROVEMENTS:
* Do not require `'autowrite'` or `'autowriteall'` to be set when using
autocompletion in module mode.
[[GH-2091]](https://github.com/fatih/vim-go/pull/2091)
* Fix use of g:go_metalinter_command _and_ apply it even when autosaving.
* Fix use of `g:go_metalinter_command` _and_ apply it even when autosaving.
[[GH-2101]](https://github.com/fatih/vim-go/pull/2101)
* Report errors in quickfix when Delve fails to start (e.g. compiler errors).
[[GH-2111]](https://github.com/fatih/vim-go/pull/2111)
* Support undo_ftplugin, make most autocmd's buffer-local, and only do the bare
minimum based on file names alone.
* Support `'undo_ftplugin'`, make most autocmds buffer-local, and only do the
bare minimum based on file names alone.
[[GH-2108]](https://github.com/fatih/vim-go/pull/2108)
* Write a message when `:GoInfo` can't display any results when `g:go_info_mode='gocode'`.
[[GH-2122]](https://github.com/fatih/vim-go/pull/2122)
@ -35,8 +45,21 @@ IMPROVEMENTS:
* Run `godef` from the current buffer's directory to make sure it works with modules.
[[GH-2150]](https://github.com/fatih/vim-go/pull/2150)
* Add a function, `go#tool#DescribeBalloon`, to show information in a balloon
with `'balloonexpr`. (Vim8 only).
with `'balloonexpr'`. (Vim8 only).
[[GH-1975]](https://github.com/fatih/vim-go/pull/1975)
* Add initial support for `gopls`.
[[GH-2163]](https://github.com/fatih/vim-go/pull/2163).
* Add `:GoDefType` to jump to the type definition of the identifier under the
cursor.
[[GH-2165]](https://github.com/fatih/vim-go/pull/2165)
* Notify gopls about changes.
[[GH-2171]](https://github.com/fatih/vim-go/pull/2171)
* Respect `g:go_jump_to_error` when running `gometalinter` automatically on
save. [[GH-2176]](https://github.com/fatih/vim-go/pull/2176)
* Use gopls for code completion by default in Vim8 and Neovim.
[[GH-2172]](https://github.com/fatih/vim-go/pull/2172)
* Add support for golangci-lint.
[[GH-2182]](https://github.com/fatih/vim-go/pull/2182)
BUG FIXES:
* Fix opening of non-existent file from `:GoDeclsDir` when the current
@ -55,10 +78,10 @@ BUG FIXES:
[[GH-2097]](https://github.com/fatih/vim-go/pull/2097)
* Do not clear buffer-local autocmds of other buffers.
[[GH-2109]](https://github.com/fatih/vim-go/pull/2109)
* Highlight return parameter types when g:go_highlight_function_arguments is set.
[[GH-2116]](https://github.com/fatih/vim-go/pull/2116)
* Fix lockup in Neovim when trying to run `:GoDebugTest` when there are no tests.
[[GH-2125]](https://github.com/fatih/vim-go/pull/2125)
* Highlight return parameter types when g:go_highlight_function_arguments is
set. [[GH-2116]](https://github.com/fatih/vim-go/pull/2116)
* Fix lockup in Neovim when trying to run `:GoDebugTest` when there are no
tests. [[GH-2125]](https://github.com/fatih/vim-go/pull/2125)
* Keep track of breakpoints correctly when buffer is edited after breakpoints
are set.
[[GH-2126]](https://github.com/fatih/vim-go/pull/2126)
@ -66,6 +89,10 @@ BUG FIXES:
[[GH-2127]](https://github.com/fatih/vim-go/pull/2127)
* Fix jumping to module or package using godef.
[[GH-2141]](https://github.com/fatih/vim-go/pull/2141)
* Fix errors caused by redefining functions within functions.
[[GH-2189]](https://github.com/fatih/vim-go/pull/2189)
* Highlight pre-release and metadata in versions in go.mod.
[[GH-2192]](https://github.com/fatih/vim-go/pull/2192)
## 1.19 - (November 4, 2018)

View file

@ -1,4 +1,4 @@
FROM golang:1.11
FROM golang:1.12.1
RUN apt-get update -y && \
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \

View file

@ -1,6 +1,6 @@
VIMS ?= vim-7.4 vim-8.0 nvim
all: install test lint
all: install lint test
install:
@echo "==> Installing Vims: $(VIMS)"

View file

@ -13,7 +13,7 @@ This plugin adds Go language support for Vim, with the following main features:
* Quickly execute your current file(s) with `:GoRun`.
* Improved syntax highlighting and folding.
* Debug programs with integrated `delve` support with `:GoDebugStart`.
* Completion support via `gocode`.
* Completion support via `gocode` and `gopls`.
* `gofmt` or `goimports` on save keeps the cursor position and undo history.
* Go to symbol/declaration with `:GoDef`.
* Look up documentation with `:GoDoc` or `:GoDocBrowser`.

View file

@ -65,7 +65,7 @@ function! go#auto#metalinter_autosave()
endif
" run gometalinter on save
call go#lint#Gometa(0, 1)
call go#lint#Gometa(!g:go_jump_to_error, 1)
endfunction
function! go#auto#modfmt_autosave()

View file

@ -219,12 +219,22 @@ function! s:trim_bracket(val) abort
return a:val
endfunction
let s:completions = ""
function! go#complete#Complete(findstart, base) abort
let s:completions = []
function! go#complete#GocodeComplete(findstart, base) abort
"findstart = 1 when we need to get the text length
if a:findstart == 1
execute "silent let s:completions = " . s:gocodeAutocomplete()
return col('.') - s:completions[0] - 1
let l:completions = []
execute "silent let l:completions = " . s:gocodeAutocomplete()
if len(l:completions) == 0 || len(l:completions) >= 2 && len(l:completions[1]) == 0
" no matches. cancel and leave completion mode.
call go#util#EchoInfo("no matches")
return -3
endif
let s:completions = l:completions[1]
return col('.') - l:completions[0] - 1
"findstart = 0 when we need to return the list of completions
else
let s = getline(".")[col('.') - 1]
@ -236,6 +246,36 @@ function! go#complete#Complete(findstart, base) abort
endif
endfunction
function! go#complete#Complete(findstart, base) abort
let l:state = {'done': 0, 'matches': []}
function! s:handler(state, matches) abort dict
let a:state.matches = a:matches
let a:state.done = 1
endfunction
"findstart = 1 when we need to get the start of the match
if a:findstart == 1
call go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state]))
while !l:state.done
sleep 10m
endwhile
let s:completions = l:state.matches
if len(l:state.matches) == 0
" no matches. cancel and leave completion mode.
call go#util#EchoInfo("no matches")
return -3
endif
return col('.')
else "findstart = 0 when we need to return the list of completions
return s:completions
endif
endfunction
function! go#complete#ToggleAutoTypeInfo() abort
if go#config#AutoTypeInfo()
call go#config#SetAutoTypeInfo(0)

View file

@ -210,6 +210,12 @@ function! go#config#DebugCommands() abort
return g:go_debug_commands
endfunction
function! go#config#LspLog() abort
" make sure g:go_lsp_log is set so that it can be added to easily.
let g:go_lsp_log = get(g:, 'go_lsp_log', [])
return g:go_lsp_log
endfunction
function! go#config#SetDebugDiag(value) abort
let g:go_debug_diag = a:value
endfunction
@ -235,15 +241,27 @@ function! go#config#SetTemplateAutocreate(value) abort
endfunction
function! go#config#MetalinterCommand() abort
return get(g:, "go_metalinter_command", "")
return get(g:, "go_metalinter_command", "gometalinter")
endfunction
function! go#config#MetalinterAutosaveEnabled() abort
return get(g:, 'go_metalinter_autosave_enabled', ['vet', 'golint'])
let l:default_enabled = ["vet", "golint"]
if go#config#MetalinterCommand() == "golangci-lint"
let l:default_enabled = ["govet", "golint"]
endif
return get(g:, "go_metalinter_autosave_enabled", default_enabled)
endfunction
function! go#config#MetalinterEnabled() abort
return get(g:, "go_metalinter_enabled", ['vet', 'golint', 'errcheck'])
let l:default_enabled = ["vet", "golint", "errcheck"]
if go#config#MetalinterCommand() == "golangci-lint"
let l:default_enabled = ["govet", "golint"]
endif
return get(g:, "go_metalinter_enabled", default_enabled)
endfunction
function! go#config#MetalinterDisabled() abort
@ -444,7 +462,6 @@ function! go#config#EchoGoInfo() abort
return get(g:, "go_echo_go_info", 1)
endfunction
" Set the default value. A value of "1" is a shortcut for this, for
" compatibility reasons.
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1

View file

@ -507,23 +507,7 @@ function! s:out_cb(ch, msg) abort
if has('nvim')
let s:state['data'] = []
let l:state = {'databuf': ''}
function! s:on_data(ch, data, event) dict abort closure
let l:data = self.databuf
for msg in a:data
let l:data .= l:msg
endfor
try
let l:res = json_decode(l:data)
let s:state['data'] = add(s:state['data'], l:res)
let self.databuf = ''
catch
" there isn't a complete message in databuf: buffer l:data and try
" again when more data comes in.
let self.databuf = l:data
finally
endtry
endfunction
" explicitly bind callback to state so that within it, self will
" always refer to state. See :help Partial for more information.
let l:state.on_data = function('s:on_data', [], l:state)
@ -560,6 +544,24 @@ function! s:out_cb(ch, msg) abort
endif
endfunction
function! s:on_data(ch, data, event) dict abort
let l:data = self.databuf
for l:msg in a:data
let l:data .= l:msg
endfor
try
let l:res = json_decode(l:data)
let s:state['data'] = add(s:state['data'], l:res)
let self.databuf = ''
catch
" there isn't a complete message in databuf: buffer l:data and try
" again when more data comes in.
let self.databuf = l:data
finally
endtry
endfunction
" Start the debug mode. The first argument is the package name to compile and
" debug, anything else will be passed to the running program.
function! go#debug#Start(is_test, ...) abort

View file

@ -5,7 +5,7 @@ set cpo&vim
let s:go_stack = []
let s:go_stack_level = 0
function! go#def#Jump(mode) abort
function! go#def#Jump(mode, type) abort
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
" so guru right now is slow for some people. previously we were using
@ -65,8 +65,18 @@ function! go#def#Jump(mode) abort
else
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
endif
elseif bin_name == 'gopls'
let [l:line, l:col] = getpos('.')[1:2]
" delegate to gopls, with an empty job object and an exit status of 0
" (they're irrelevant for gopls).
if a:type
call go#lsp#TypeDef(l:fname, l:line, l:col, function('s:jump_to_declaration_cb', [a:mode, 'gopls', {}, 0]))
else
call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]')
call go#lsp#Definition(l:fname, l:line, l:col, function('s:jump_to_declaration_cb', [a:mode, 'gopls', {}, 0]))
endif
return
else
call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru, gopls]')
return
endif
@ -85,15 +95,19 @@ function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort
call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name)
" capture the active window so that after the exit_cb and close_cb callbacks
" can return to it when a:mode caused a split.
" capture the active window so that callbacks for jobs, exit_cb and
" close_cb, and callbacks for gopls can return to it when a:mode caused a
" split.
let self.winid = win_getid(winnr())
endfunction
" go#def#jump_to_declaration parses out (expected to be
" 'filename:line:col: message').
function! go#def#jump_to_declaration(out, mode, bin_name) abort
let final_out = a:out
if a:bin_name == "godef"
" append the type information to the same line so our we can parse it.
" append the type information to the same line so it will be parsed
" correctly using guru's output format.
" This makes it compatible with guru output.
let final_out = join(split(a:out, '\n'), ':')
endif

View file

@ -50,7 +50,7 @@ func! Test_Jump_leaves_lists() abort
let l:bufnr = bufnr('%')
call cursor(6, 7)
call go#def#Jump('')
call go#def#Jump('', 0)
let start = reltime()
while bufnr('%') == l:bufnr && reltimefloat(reltime(start)) < 10

View file

@ -128,10 +128,6 @@ function! s:async_guru(args) abort
\ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output"))
\ }
function! s:complete(job, exit_status, messages) dict abort
let output = join(a:messages, "\n")
call self.parse(a:exit_status, output, self.mode)
endfunction
" explicitly bind complete to state so that within it, self will
" always refer to state. See :help Partial for more information.
let state.complete = function('s:complete', [], state)
@ -164,6 +160,11 @@ function! s:async_guru(args) abort
endif
endfunc
function! s:complete(job, exit_status, messages) dict abort
let output = join(a:messages, "\n")
call self.parse(a:exit_status, output, self.mode)
endfunction
" run_guru runs the given guru argument
function! s:run_guru(args) abort
if go#util#has_job()
@ -239,7 +240,19 @@ function! go#guru#DescribeInfo(showstatus) abort
return
endif
function! s:info(exit_val, output, mode)
let args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:info'),
\ 'disable_progress': 1,
\ }
call s:run_guru(args)
endfunction
function! s:info(exit_val, output, mode)
if a:exit_val != 0
return
endif
@ -322,18 +335,6 @@ function! go#guru#DescribeInfo(showstatus) abort
endif
call go#util#ShowInfo(info)
endfunction
let args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:info'),
\ 'disable_progress': 1,
\ }
call s:run_guru(args)
endfunction
" Show possible targets of selected function call
@ -609,7 +610,29 @@ function! go#guru#DescribeBalloon() abort
return
endif
function! s:describe_balloon(exit_val, output, mode)
" change the active window to the window where the cursor is.
let l:winid = win_getid(winnr())
call win_gotoid(v:beval_winid)
let l:args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:describe_balloon'),
\ 'disable_progress': 1,
\ 'postype': 'balloon',
\ }
call s:async_guru(args)
" make the starting window active again
call win_gotoid(l:winid)
return ''
endfunction
function! s:describe_balloon(exit_val, output, mode)
if a:exit_val != 0
return
endif
@ -705,29 +728,6 @@ function! go#guru#DescribeBalloon() abort
endif
call balloon_show(l:info)
endfunction
" change the active window to the window where the cursor is.
let l:winid = win_getid(winnr())
call win_gotoid(v:beval_winid)
let l:args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:describe_balloon'),
\ 'disable_progress': 1,
\ 'postype': 'balloon',
\ }
call s:async_guru(args)
" make the starting window active again
call win_gotoid(l:winid)
return ''
endfunction
" restore Vi compatibility settings

View file

@ -6,11 +6,14 @@ function! Test_gomodVersion_highlight() abort
try
syntax on
let l:dir= gotest#write_file('gomodtest/go.mod', [
let l:dir = gotest#write_file('gomodtest/go.mod', [
\ 'module github.com/fatih/vim-go',
\ '',
\ '\x1frequire (',
\ '\tversion/simple v1.0.0',
\ '\tversion/simple-pre-release v1.0.0-rc',
\ '\tversion/simple-pre-release v1.0.0+meta',
\ '\tversion/simple-pre-release v1.0.0-rc+meta',
\ '\tversion/pseudo/premajor v1.0.0-20060102150405-0123456789abcdef',
\ '\tversion/pseudo/prerelease v1.0.0-prerelease.0.20060102150405-0123456789abcdef',
\ '\tversion/pseudo/prepatch v1.0.1-0.20060102150405-0123456789abcdef',
@ -55,11 +58,10 @@ function! Test_gomodVersion_incompatible_highlight() abort
try
syntax on
let l:dir= gotest#write_file('gomodtest/go.mod', [
let l:dir = gotest#write_file('gomodtest/go.mod', [
\ 'module github.com/fatih/vim-go',
\ '',
\ '\x1frequire (',
\ '\tversion/invalid/incompatible v1.0.0+incompatible',
\ '\tversion/invalid/premajor/incompatible v1.0.0-20060102150405-0123456789abcdef+incompatible',
\ '\tversion/invalid/prerelease/incompatible v1.0.0-prerelease.0.20060102150405-0123456789abcdef+incompatible',
\ '\tversion/invalid/prepatch/incompatible v1.0.1-0.20060102150405-0123456789abcdef+incompatible',

View file

@ -5,7 +5,7 @@ set cpo&vim
let s:templatepath = go#util#Join(expand('<sfile>:p:h:h:h'), '.github', 'ISSUE_TEMPLATE.md')
function! go#issue#New() abort
let body = substitute(s:issuebody(), '[^A-Za-z0-9_.~-]', '\="%".printf("%02X",char2nr(submatch(0)))', 'g')
let body = go#uriEncode(s:issuebody())
let url = "https://github.com/fatih/vim-go/issues/new?body=" . l:body
call go#util#OpenBrowser(l:url)
endfunction

View file

@ -145,23 +145,6 @@ function! go#job#Options(args)
let state.custom_complete = a:args.complete
endif
function! s:start(args) dict
if go#config#EchoCommandInfo() && self.statustype != ""
let prefix = '[' . self.statustype . '] '
call go#util#EchoSuccess(prefix . "dispatched")
endif
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.
"
@ -169,35 +152,14 @@ function! go#job#Options(args)
" outside of this file.
let cbs._start = function('s:start', [''], state)
function! s:callback(chan, msg) dict
call add(self.messages, a:msg)
endfunction
" explicitly bind callback to state so that within it, self will
" always refer to state. See :help Partial for more information.
let cbs.callback = function('s:callback', [], state)
function! s:exit_cb(job, exitval) dict
let self.exit_status = a:exitval
let self.exited = 1
call self.show_status(a:job, a:exitval)
if self.closed || has('nvim')
call self.complete(a:job, self.exit_status, self.messages)
endif
endfunction
" explicitly bind exit_cb to state so that within it, self will always refer
" to state. See :help Partial for more information.
let cbs.exit_cb = function('s:exit_cb', [], state)
function! s:close_cb(ch) dict
let self.closed = 1
if self.exited
let job = ch_getjob(a:ch)
call self.complete(job, self.exit_status, self.messages)
endif
endfunction
" explicitly bind close_cb to state so that within it, self will
" always refer to state. See :help Partial for more information.
let cbs.close_cb = function('s:close_cb', [], state)
@ -261,6 +223,48 @@ function! go#job#Options(args)
return cbs
endfunction
function! s:start(args) dict
if go#config#EchoCommandInfo() && self.statustype != ""
let prefix = '[' . self.statustype . '] '
call go#util#EchoSuccess(prefix . "dispatched")
endif
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
function! s:callback(chan, msg) dict
call add(self.messages, a:msg)
endfunction
function! s:exit_cb(job, exitval) dict
let self.exit_status = a:exitval
let self.exited = 1
call self.show_status(a:job, a:exitval)
if self.closed || has('nvim')
call self.complete(a:job, self.exit_status, self.messages)
endif
endfunction
function! s:close_cb(ch) dict
let self.closed = 1
if self.exited
let job = ch_getjob(a:ch)
call self.complete(job, self.exit_status, self.messages)
endif
endfunction
" go#job#Start runs a job. The options are expected to be the options
" suitable for Vim8 jobs. When called from Neovim, Vim8 options will be
" transformed to their Neovim equivalents.
@ -276,17 +280,24 @@ function! go#job#Start(cmd, options)
" early if the directory does not exist. This helps avoid errors when
" working with plugins that use virtual files that don't actually exist on
" the file system.
let filedir = expand("%:p:h")
let l:filedir = expand("%:p:h")
if has_key(l:options, 'cwd') && !isdirectory(l:options.cwd)
return
elseif !isdirectory(filedir)
elseif !isdirectory(l:filedir)
return
endif
let l:manualcd = 0
if !has_key(l:options, 'cwd')
" pre start
let l:manualcd = 1
let dir = getcwd()
execute l:cd fnameescape(filedir)
elseif !(has("patch-8.0.0902") || has('nvim'))
let l:manualcd = 1
let l:dir = l:options.cwd
execute l:cd fnameescape(l:dir)
call remove(l:options, 'cwd')
endif
if has_key(l:options, '_start')
@ -296,6 +307,11 @@ function! go#job#Start(cmd, options)
unlet l:options._start
endif
" noblock was added in 8.1.350; remove it if it's not supported.
if has_key(l:options, 'noblock') && (has('nvim') || !has("patch-8.1.350"))
call remove(l:options, 'noblock')
endif
if go#util#HasDebug('shell-commands')
call go#util#EchoInfo('job command: ' . string(a:cmd))
endif
@ -322,9 +338,9 @@ function! go#job#Start(cmd, options)
let job = job_start(l:cmd, l:options)
endif
if !has_key(l:options, 'cwd')
if l:manualcd
" post start
execute l:cd fnameescape(dir)
execute l:cd fnameescape(l:dir)
endif
return job
@ -337,6 +353,9 @@ function! s:neooptions(options)
let l:options['stdout_buf'] = ''
let l:options['stderr_buf'] = ''
let l:err_mode = get(a:options, 'err_mode', get(a:options, 'mode', ''))
let l:out_mode = get(a:options, 'out_mode', get(a:options, 'mode', ''))
for key in keys(a:options)
if key == 'cwd'
let l:options['cwd'] = a:options['cwd']
@ -347,17 +366,11 @@ function! s:neooptions(options)
let l:options['callback'] = a:options['callback']
if !has_key(a:options, 'out_cb')
function! s:callback2on_stdout(ch, data, event) dict
let self.stdout_buf = s:neocb(a:ch, self.stdout_buf, a:data, self.callback)
endfunction
let l:options['on_stdout'] = function('s:callback2on_stdout', [], l:options)
let l:options['on_stdout'] = function('s:callback2on_stdout', [l:out_mode], l:options)
endif
if !has_key(a:options, 'err_cb')
function! s:callback2on_stderr(ch, data, event) dict
let self.stderr_buf = s:neocb(a:ch, self.stderr_buf, a:data, self.callback)
endfunction
let l:options['on_stderr'] = function('s:callback2on_stderr', [], l:options)
let l:options['on_stderr'] = function('s:callback2on_stderr', [l:err_mode], l:options)
endif
continue
@ -365,29 +378,20 @@ function! s:neooptions(options)
if key == 'out_cb'
let l:options['out_cb'] = a:options['out_cb']
function! s:on_stdout(ch, data, event) dict
let self.stdout_buf = s:neocb(a:ch, self.stdout_buf, a:data, self.out_cb)
endfunction
let l:options['on_stdout'] = function('s:on_stdout', [], l:options)
let l:options['on_stdout'] = function('s:on_stdout', [l:out_mode], l:options)
continue
endif
if key == 'err_cb'
let l:options['err_cb'] = a:options['err_cb']
function! s:on_stderr(ch, data, event) dict
let self.stderr_buf = s:neocb(a:ch, self.stderr_buf, a:data, self.err_cb )
endfunction
let l:options['on_stderr'] = function('s:on_stderr', [], l:options)
let l:options['on_stderr'] = function('s:on_stderr', [l:err_mode], 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
@ -407,6 +411,26 @@ function! s:neooptions(options)
return l:options
endfunction
function! s:callback2on_stdout(mode, ch, data, event) dict
let self.stdout_buf = s:neocb(a:mode, a:ch, self.stdout_buf, a:data, self.callback)
endfunction
function! s:callback2on_stderr(mode, ch, data, event) dict
let self.stderr_buf = s:neocb(a:mode, a:ch, self.stderr_buf, a:data, self.callback)
endfunction
function! s:on_stdout(mode, ch, data, event) dict
let self.stdout_buf = s:neocb(a:mode, a:ch, self.stdout_buf, a:data, self.out_cb)
endfunction
function! s:on_stderr(mode, ch, data, event) dict
let self.stderr_buf = s:neocb(a:mode, a:ch, self.stderr_buf, a:data, self.err_cb )
endfunction
function! s:on_exit(jobid, exitval, event) dict
call self.exit_cb(a:jobid, a:exitval)
endfunction
function! go#job#Stop(job) abort
if has('nvim')
call jobstop(a:job)
@ -436,7 +460,7 @@ function! s:winjobarg(idx, val) abort
return a:val
endfunction
function! s:neocb(ch, buf, data, callback)
function! s:neocb(mode, ch, buf, data, callback)
" dealing with the channel lines of Neovim is awful. The docs (:help
" channel-lines) say:
" stream event handlers may receive partial (incomplete) lines. For a
@ -445,6 +469,25 @@ function! s:neocb(ch, buf, data, callback)
" - `abcdefg` may arrive as `['abc']`, `['defg']`.
" - `abc\nefg` may arrive as `['abc', '']`, `['efg']` or `['abc']`,
" `['','efg']`, or even `['ab']`, `['c','efg']`.
"
" Thankfully, though, this is explained a bit better in an issue:
" https://github.com/neovim/neovim/issues/3555. Specifically in these two
" comments:
" * https://github.com/neovim/neovim/issues/3555#issuecomment-152290804
" * https://github.com/neovim/neovim/issues/3555#issuecomment-152588749
"
" The key is
" Every item in the list passed to job control callbacks represents a
" string after a newline(Except the first, of course). If the program
" outputs: "hello\nworld" the corresponding list is ["hello", "world"].
" If the program outputs "hello\nworld\n", the corresponding list is
" ["hello", "world", ""]. In other words, you can always determine if
" the last line received is complete or not.
" and
" for every list you receive in a callback, all items except the first
" represent newlines.
let l:buf = ''
" a single empty string means EOF was reached.
if len(a:data) == 1 && a:data[0] == ''
@ -455,20 +498,28 @@ function! s:neocb(ch, buf, data, callback)
endif
let l:data = [a:buf]
let l:buf = ''
else
let l:data = copy(a:data)
let l:data[0] = a:buf . l:data[0]
" The last element may be a partial line; save it for next time.
if a:mode != 'raw'
let l:buf = l:data[-1]
let l:data = l:data[:-2]
endif
endif
for l:msg in l:data
let l:i = 0
let l:last = len(l:data) - 1
while l:i <= l:last
let l:msg = l:data[l:i]
if a:mode == 'raw' && l:i < l:last
let l:msg = l:msg . "\n"
endif
call a:callback(a:ch, l:msg)
endfor
let l:i += 1
endwhile
return l:buf
endfunction

View file

@ -9,22 +9,14 @@ function! go#lint#Gometa(bang, autosave, ...) abort
let goargs = a:000
endif
if empty(go#config#MetalinterCommand())
let bin_path = go#path#CheckBinPath("gometalinter")
if empty(bin_path)
let l:metalinter = go#config#MetalinterCommand()
if l:metalinter == 'gometalinter' || l:metalinter == 'golangci-lint'
let cmd = s:metalintercmd(l:metalinter)
if empty(cmd)
return
endif
let cmd = [bin_path]
let cmd += ["--disable-all"]
" gometalinter has a --tests flag to tell its linters whether to run
" against tests. While not all of its linters respect this flag, for those
" that do, it means if we don't pass --tests, the linter won't run against
" test files. One example of a linter that will not run against tests if
" we do not specify this flag is errcheck.
let cmd += ["--tests"]
" linters
let linters = a:autosave ? go#config#MetalinterAutosaveEnabled() : go#config#MetalinterEnabled()
for linter in linters
@ -44,15 +36,19 @@ function! go#lint#Gometa(bang, autosave, ...) abort
" will be cleared
redraw
if l:metalinter == "gometalinter"
" Include only messages for the active buffer for autosave.
let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))]
if go#util#has_job()
let include = [printf('--include=^%s:.*$', expand('%:p:t'))]
endif
let cmd += include
elseif l:metalinter == "golangci-lint"
let goargs[0] = expand('%:p')
endif
endif
" Call gometalinter asynchronously.
" Call metalinter asynchronously.
let deadline = go#config#MetalinterDeadline()
if deadline != ''
let cmd += ["--deadline=" . deadline]
@ -60,8 +56,21 @@ function! go#lint#Gometa(bang, autosave, ...) abort
let cmd += goargs
if l:metalinter == "gometalinter"
" Gometalinter can output one of the two, so we look for both:
" <file>:<line>:<column>:<severity>: <message> (<linter>)
" <file>:<line>::<severity>: <message> (<linter>)
" This can be defined by the following errorformat:
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
else
" Golangci-lint can output the following:
" <file>:<line>:<column>: <message> (<linter>)
" This can be defined by the following errorformat:
let errformat = "%f:%l:%c:\ %m"
endif
if go#util#has_job()
call s:lint_job({'cmd': cmd}, a:bang, a:autosave)
call s:lint_job({'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat}, a:bang, a:autosave)
return
endif
@ -77,12 +86,6 @@ function! go#lint#Gometa(bang, autosave, ...) abort
call go#list#Clean(l:listtype)
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
else
" GoMetaLinter can output one of the two, so we look for both:
" <file>:<line>:<column>:<severity>: <message> (<linter>)
" <file>:<line>::<severity>: <message> (<linter>)
" This can be defined by the following errorformat:
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
" Parse and populate our location list
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
@ -205,8 +208,8 @@ endfunction
function! s:lint_job(args, bang, autosave)
let l:opts = {
\ 'statustype': "gometalinter",
\ 'errorformat': '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m',
\ 'statustype': a:args.statustype,
\ 'errorformat': a:args.errformat,
\ 'for': "GoMetaLinter",
\ 'bang': a:bang,
\ }
@ -221,6 +224,45 @@ function! s:lint_job(args, bang, autosave)
call go#job#Spawn(a:args.cmd, l:opts)
endfunction
function! s:metalintercmd(metalinter)
let l:cmd = []
let bin_path = go#path#CheckBinPath(a:metalinter)
if !empty(bin_path)
if a:metalinter == "gometalinter"
let l:cmd = s:gometalintercmd(bin_path)
elseif a:metalinter == "golangci-lint"
let l:cmd = s:golangcilintcmd(bin_path)
endif
endif
return cmd
endfunction
function! s:gometalintercmd(bin_path)
let cmd = [a:bin_path]
let cmd += ["--disable-all"]
" gometalinter has a --tests flag to tell its linters whether to run
" against tests. While not all of its linters respect this flag, for those
" that do, it means if we don't pass --tests, the linter won't run against
" test files. One example of a linter that will not run against tests if
" we do not specify this flag is errcheck.
let cmd += ["--tests"]
return cmd
endfunction
function! s:golangcilintcmd(bin_path)
let cmd = [a:bin_path]
let cmd += ["run"]
let cmd += ["--print-issued-lines=false"]
let cmd += ["--disable-all"]
" do not use the default exclude patterns, because doing so causes golint
" problems about missing doc strings to be ignored and other things that
" golint identifies.
let cmd += ["--exclude-use-default=false"]
return cmd
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save

View file

@ -3,9 +3,19 @@ let s:cpo_save = &cpo
set cpo&vim
func! Test_Gometa() abort
call s:gometa('gometaliner')
endfunc
func! Test_GometaGolangciLint() abort
call s:gometa('golangci-lint')
endfunc
func! s:gometa(metalinter) abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
try
let g:go_metalinter_comand = a:metalinter
let expected = [
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
\ ]
@ -25,13 +35,25 @@ func! Test_Gometa() abort
endwhile
call gotest#assert_quickfix(actual, expected)
finally
unlet g:go_metalinter_enabled
endtry
endfunc
func! Test_GometaWithDisabled() abort
call s:gometawithdisabled('gometalinter')
endfunc
func! Test_GometaWithDisabledGolangciLint() abort
call s:gometawithdisabled('golangci-lint')
endfunc
func! s:gometawithdisabled(metalinter) abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
try
let g:go_metalinter_comand = a:metalinter
let expected = [
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
\ ]
@ -51,13 +73,25 @@ func! Test_GometaWithDisabled() abort
endwhile
call gotest#assert_quickfix(actual, expected)
finally
unlet g:go_metalinter_disabled
endtry
endfunc
func! Test_GometaAutoSave() abort
call s:gometaautosave('gometalinter')
endfunc
func! Test_GometaAutoSaveGolangciLint() abort
call s:gometaautosave('golangci-lint')
endfunc
func! s:gometaautosave(metalinter) abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
try
let g:go_metalinter_comand = a:metalinter
let expected = [
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'}
\ ]
@ -79,16 +113,18 @@ func! Test_GometaAutoSave() abort
endwhile
call gotest#assert_quickfix(actual, expected)
finally
unlet g:go_metalinter_autosave_enabled
endtry
endfunc
func! Test_Vet()
func! Test_Vet() abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/vet/vet.go'
compiler go
let expected = [
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '',
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '',
\ 'text': 'Printf format %d has arg str of wrong type string'}
\ ]

View file

@ -0,0 +1,444 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
scriptencoding utf-8
let s:lspfactory = {}
function! s:lspfactory.get() dict abort
if !has_key(self, 'current')
" TODO(bc): check that the lsp is still running.
let self.current = s:newlsp()
endif
return self.current
endfunction
function! s:lspfactory.reset() dict abort
if has_key(self, 'current')
call remove(self, 'current')
endif
endfunction
function! s:newlsp()
if !go#util#has_job()
" TODO(bc): start the server in the background using a shell that waits for the right output before returning.
call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.')
return
endif
" job is the job used to talk to the backing instance of gopls.
" ready is 0 until the initialize response has been received. 1 afterwards.
" queue is messages to send after initialization
" last_request_id is id of the most recently sent request.
" buf is unprocessed/incomplete responses
" handlers is a mapping of request ids to dictionaries of functions.
" request id -> {start, requestComplete, handleResult, error}
" * start is a function that takes no arguments
" * requestComplete is a function that takes 1 argument. The parameter will be 1
" if the call was succesful.
" * handleResult takes a single argument, the result message received from gopls
" * error takes a single argument, the error message received from gopls.
" The error method is optional.
let l:lsp = {
\ 'job': '',
\ 'ready': 0,
\ 'queue': [],
\ 'last_request_id': 0,
\ 'buf': '',
\ 'handlers': {},
\ }
function! l:lsp.readMessage(data) dict abort
let l:responses = []
let l:rest = a:data
while 1
" Look for the end of the HTTP headers
let l:body_start_idx = matchend(l:rest, "\r\n\r\n")
if l:body_start_idx < 0
" incomplete header
break
endif
" Parse the Content-Length header.
let l:header = l:rest[:l:body_start_idx - 4]
let l:length_match = matchlist(
\ l:header,
\ '\vContent-Length: *(\d+)'
\)
if empty(l:length_match)
" TODO(bc): shutdown gopls?
throw "invalid JSON-RPC header:\n" . l:header
endif
" get the start of the rest
let l:rest_start_idx = l:body_start_idx + str2nr(l:length_match[1])
if len(l:rest) < l:rest_start_idx
" incomplete response body
break
endif
if go#util#HasDebug('lsp')
let g:go_lsp_log = add(go#config#LspLog(), "<-\n" . l:rest[:l:rest_start_idx - 1])
endif
let l:body = l:rest[l:body_start_idx : l:rest_start_idx - 1]
let l:rest = l:rest[l:rest_start_idx :]
try
" add the json body to the list.
call add(l:responses, json_decode(l:body))
catch
" TODO(bc): log the message and/or show an error message.
finally
" intentionally left blank.
endtry
endwhile
return [l:rest, l:responses]
endfunction
function! l:lsp.handleMessage(ch, data) dict abort
let self.buf .= a:data
let [self.buf, l:responses] = self.readMessage(self.buf)
" TODO(bc): handle notifications (e.g. window/showMessage).
for l:response in l:responses
if has_key(l:response, 'id') && has_key(self.handlers, l:response.id)
try
let l:handler = self.handlers[l:response.id]
if has_key(l:response, 'error')
call l:handler.requestComplete(0)
call go#util#EchoError(l:response.error.message)
if has_key(l:handler, 'error')
call call(l:handler.error, [l:response.error.message])
endif
return
endif
call l:handler.requestComplete(1)
call call(l:handler.handleResult, [l:response.result])
finally
call remove(self.handlers, l:response.id)
endtry
endif
endfor
endfunction
function! l:lsp.handleInitializeResult(result) dict abort
let self.ready = 1
" TODO(bc): send initialized message to the server?
" send messages queued while waiting for ready.
for l:item in self.queue
call self.sendMessage(l:item.data, l:item.handler)
endfor
" reset the queue
let self.queue = []
endfunction
function! l:lsp.sendMessage(data, handler) dict abort
if !self.last_request_id
" TODO(bc): run a server per module and one per GOPATH? (may need to
" keep track of servers by rootUri).
let l:msg = self.newMessage(go#lsp#message#Initialize(getcwd()))
let l:state = s:newHandlerState('gopls')
let l:state.handleResult = funcref('self.handleInitializeResult', [], l:self)
let self.handlers[l:msg.id] = l:state
call l:state.start()
call self.write(l:msg)
endif
if !self.ready
call add(self.queue, {'data': a:data, 'handler': a:handler})
return
endif
let l:msg = self.newMessage(a:data)
if has_key(l:msg, 'id')
let self.handlers[l:msg.id] = a:handler
endif
call a:handler.start()
call self.write(l:msg)
endfunction
" newMessage returns a message constructed from data. data should be a dict
" with 2 or 3 keys: notification, method, and optionally params.
function! l:lsp.newMessage(data) dict abort
let l:msg = {
\ 'method': a:data.method,
\ 'jsonrpc': '2.0',
\ }
if !a:data.notification
let self.last_request_id += 1
let l:msg.id = self.last_request_id
endif
if has_key(a:data, 'params')
let l:msg.params = a:data.params
endif
return l:msg
endfunction
function! l:lsp.write(msg) dict abort
let l:body = json_encode(a:msg)
let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body
if go#util#HasDebug('lsp')
let g:go_lsp_log = add(go#config#LspLog(), "->\n" . l:data)
endif
if has('nvim')
call chansend(self.job, l:data)
return
endif
call ch_sendraw(self.job, l:data)
endfunction
function! l:lsp.exit_cb(job, exit_status) dict abort
call s:lspfactory.reset()
endfunction
" explicitly bind close_cb to state so that within it, self will always refer
function! l:lsp.close_cb(ch) dict abort
" TODO(bc): does anything need to be done here?
endfunction
function! l:lsp.err_cb(ch, msg) dict abort
if go#util#HasDebug('lsp')
let g:go_lsp_log = add(go#config#LspLog(), "<-stderr\n" . a:msg)
endif
endfunction
" explicitly bind callbacks to l:lsp so that within it, self will always refer
" to l:lsp instead of l:opts. See :help Partial for more information.
let l:opts = {
\ 'in_mode': 'raw',
\ 'out_mode': 'raw',
\ 'err_mode': 'nl',
\ 'noblock': 1,
\ 'err_cb': funcref('l:lsp.err_cb', [], l:lsp),
\ 'out_cb': funcref('l:lsp.handleMessage', [], l:lsp),
\ 'close_cb': funcref('l:lsp.close_cb', [], l:lsp),
\ 'exit_cb': funcref('l:lsp.exit_cb', [], l:lsp),
\ 'cwd': getcwd(),
\}
let l:bin_path = go#path#CheckBinPath("gopls")
if empty(l:bin_path)
return
endif
" TODO(bc): output a message indicating which directory lsp is going to
" start in.
let l:lsp.job = go#job#Start([l:bin_path], l:opts)
" TODO(bc): send the initialize message now?
return l:lsp
endfunction
function! s:noop()
endfunction
function! s:newHandlerState(statustype)
let l:state = {
\ 'winid': win_getid(winnr()),
\ 'statustype': a:statustype,
\ 'jobdir': getcwd(),
\ }
" explicitly bind requestComplete to state so that within it, self will
" always refer to state. See :help Partial for more information.
let l:state.requestComplete = funcref('s:requestComplete', [], l:state)
" explicitly bind start to state so that within it, self will
" always refer to state. See :help Partial for more information.
let l:state.start = funcref('s:start', [], l:state)
return l:state
endfunction
function! s:requestComplete(ok) abort dict
if self.statustype == ''
return
endif
if go#config#EchoCommandInfo()
let prefix = '[' . self.statustype . '] '
if a:ok
call go#util#EchoSuccess(prefix . "SUCCESS")
else
call go#util#EchoError(prefix . "FAIL")
endif
endif
let status = {
\ 'desc': 'last status',
\ 'type': self.statustype,
\ 'state': "success",
\ }
if !a:ok
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
function! s:start() abort 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
" go#lsp#Definition calls gopls to get the definition of the identifier at
" line and col in fname. handler should be a dictionary function that takes a
" list of strings in the form 'file:line:col: message'. handler will be
" attached to a dictionary that manages state (statuslines, sets the winid,
" etc.)
function! go#lsp#Definition(fname, line, col, handler)
call go#lsp#DidChange(a:fname)
let l:lsp = s:lspfactory.get()
let l:state = s:newHandlerState('definition')
let l:state.handleResult = funcref('s:definitionHandler', [function(a:handler, [], l:state)], l:state)
let l:msg = go#lsp#message#Definition(fnamemodify(a:fname, ':p'), a:line, a:col)
call l:lsp.sendMessage(l:msg, l:state)
endfunction
function! s:definitionHandler(next, msg) abort dict
" gopls returns a []Location; just take the first one.
let l:msg = a:msg[0]
let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, l:msg.range.start.character+1, 'lsp does not supply a description')]]
call call(a:next, l:args)
endfunction
" go#lsp#Type calls gopls to get the type definition of the identifier at
" line and col in fname. handler should be a dictionary function that takes a
" list of strings in the form 'file:line:col: message'. handler will be
" attached to a dictionary that manages state (statuslines, sets the winid,
" etc.)
function! go#lsp#TypeDef(fname, line, col, handler)
call go#lsp#DidChange(a:fname)
let l:lsp = s:lspfactory.get()
let l:state = s:newHandlerState('type definition')
let l:msg = go#lsp#message#TypeDefinition(fnamemodify(a:fname, ':p'), a:line, a:col)
let l:state.handleResult = funcref('s:typeDefinitionHandler', [function(a:handler, [], l:state)], l:state)
call l:lsp.sendMessage(l:msg, l:state)
endfunction
function! s:typeDefinitionHandler(next, msg) abort dict
" gopls returns a []Location; just take the first one.
let l:msg = a:msg[0]
let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, l:msg.range.start.character+1, 'lsp does not supply a description')]]
call call(a:next, l:args)
endfunction
function! go#lsp#DidOpen(fname)
if get(b:, 'go_lsp_did_open', 0)
return
endif
let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n")
let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state)
let b:go_lsp_did_open = 1
endfunction
function! go#lsp#DidChange(fname)
if get(b:, 'go_lsp_did_open', 0)
return go#lsp#DidOpen(a:fname)
endif
let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#DidChange(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n")
let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state)
endfunction
function! go#lsp#DidClose(fname)
if !get(b:, 'go_lsp_did_open', 0)
return
endif
let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#DidClose(fnamemodify(a:fname, ':p'))
let l:state = s:newHandlerState('')
let l:state.handleResult = funcref('s:noop')
call l:lsp.sendMessage(l:msg, l:state)
let b:go_lsp_did_open = 0
endfunction
function! go#lsp#Completion(fname, line, col, handler)
call go#lsp#DidChange(a:fname)
let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#Completion(a:fname, a:line, a:col)
let l:state = s:newHandlerState('completion')
let l:state.handleResult = funcref('s:completionHandler', [function(a:handler, [], l:state)], l:state)
let l:state.error = funcref('s:completionErrorHandler', [function(a:handler, [], l:state)], l:state)
call l:lsp.sendMessage(l:msg, l:state)
endfunction
function! s:completionHandler(next, msg) abort dict
" gopls returns a CompletionList.
let l:matches = []
for l:item in a:msg.items
let l:match = {'abbr': l:item.label, 'word': l:item.textEdit.newText, 'info': '', 'kind': go#lsp#completionitemkind#Vim(l:item.kind)}
if has_key(l:item, 'detail')
let l:item.info = l:item.detail
endif
if has_key(l:item, 'documentation')
let l:match.info .= "\n\n" . l:item.documentation
endif
let l:matches = add(l:matches, l:match)
endfor
let l:args = [l:matches]
call call(a:next, l:args)
endfunction
function! s:completionErrorHandler(next, error) abort dict
call call(a:next, [[]])
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: sw=2 ts=2 et

View file

@ -0,0 +1,47 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
let s:Text = 1
let s:Method = 2
let s:Function = 3
let s:Constructor = 4
let s:Field = 5
let s:Variable = 6
let s:Class = 7
let s:Interface = 8
let s:Module = 9
let s:Property = 10
let s:Unit = 11
let s:Value = 12
let s:Enum = 13
let s:Keyword = 14
let s:Snippet = 15
let s:Color = 16
let s:File = 17
let s:Reference = 18
let s:Folder = 19
let s:EnumMember = 20
let s:Constant = 21
let s:Struct = 22
let s:Event = 23
let s:Operator = 24
let s:TypeParameter = 25
function! go#lsp#completionitemkind#Vim(kind)
if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor
return 'f'
elseif a:kind == s:Variable || a:kind == s:Constant
return 'v'
elseif a:kind == s:Field || a:kind == s:Property
return 'm'
elseif a:kind == s:Class || a:kind == s:Interface || a:kind == s:Struct
return 't'
endif
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: sw=2 ts=2 et

View file

@ -0,0 +1,111 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
function! go#lsp#message#Initialize(wd)
return {
\ 'notification': 0,
\ 'method': 'initialize',
\ 'params': {
\ 'processId': getpid(),
\ 'rootUri': go#path#ToURI(a:wd),
\ 'capabilities': {
\ 'workspace': {},
\ 'textDocument': {}
\ }
\ }
\ }
endfunction
function! go#lsp#message#Definition(file, line, col)
return {
\ 'notification': 0,
\ 'method': 'textDocument/definition',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file)
\ },
\ 'position': s:position(a:line, a:col)
\ }
\ }
endfunction
function! go#lsp#message#TypeDefinition(file, line, col)
return {
\ 'notification': 0,
\ 'method': 'textDocument/typeDefinition',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file)
\ },
\ 'position': s:position(a:line, a:col)
\ }
\ }
endfunction
function! go#lsp#message#DidOpen(file, content)
return {
\ 'notification': 1,
\ 'method': 'textDocument/didOpen',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file),
\ 'languageId': 'go',
\ 'text': a:content,
\ }
\ }
\ }
endfunction
function! go#lsp#message#DidChange(file, content)
return {
\ 'notification': 1,
\ 'method': 'textDocument/didChange',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file),
\ },
\ 'contentChanges': [
\ {
\ 'text': a:content,
\ }
\ ]
\ }
\ }
endfunction
function! go#lsp#message#DidClose(file)
return {
\ 'notification': 1,
\ 'method': 'textDocument/didClose',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file),
\ }
\ }
\ }
endfunction
function! go#lsp#message#Completion(file, line, col)
return {
\ 'notification': 0,
\ 'method': 'textDocument/completion',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file)
\ },
\ 'position': s:position(a:line, a:col),
\ }
\ }
endfunction
function! s:position(line, col)
return {'line': a:line - 1, 'character': a:col-1}
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: sw=2 ts=2 et

View file

@ -205,6 +205,37 @@ function! s:CygwinPath(path)
return substitute(a:path, '\\', '/', "g")
endfunction
" go#path#ToURI converts path to a file URI. path should be an absolute path.
" Relative paths cannot be properly converted to a URI; when path is a
" relative path, the file scheme will not be prepended.
function! go#path#ToURI(path)
let l:path = a:path
if l:path[1:2] is# ':\'
let l:path = '/' . l:path[0:1] . l:path[3:]
endif
return substitute(
\ (l:path[0] is# '/' ? 'file://' : '') . go#uri#EncodePath(l:path),
\ '\\',
\ '/',
\ 'g',
\)
endfunction
function! go#path#FromURI(uri) abort
let l:i = len('file://')
let l:encoded_path = a:uri[: l:i - 1] is# 'file://' ? a:uri[l:i :] : a:uri
let l:path = go#uri#Decode(l:encoded_path)
" If the path is like /C:/foo/bar, it should be C:\foo\bar instead.
if l:path =~# '^/[a-zA-Z]:'
let l:path = substitute(l:path[1:], '/', '\\', 'g')
endif
return l:path
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save

View file

@ -241,7 +241,7 @@ function! s:errorformat() abort
" e.g.:
" '\t/usr/local/go/src/time.go:1313 +0x5d'
" panicaddress, and readyaddress are identical except for
" panicaddress and readyaddress are identical except for
" panicaddress sets the filename and line number.
let panicaddress = "%\\t%f:%l +0x%[0-9A-Fa-f]%\\+"
let readyaddress = "%\\t%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+"
@ -264,6 +264,11 @@ function! s:errorformat() abort
" the running goroutine's stack.
let format .= ",%Z" . panicaddress
" Match and ignore errors from runtime.goparkunlock(). These started
" appearing in stack traces from Go 1.12 test timeouts.
let format .= ",%-Gruntime.goparkunlock(%.%#"
let format .= ",%-G%\\t" . goroot . "%\\f%\\+:%\\d%\\+"
" Match and ignore panic address without being part of a multi-line message.
" This is to catch those lines that come after the top most non-standard
" library line in stack traces.
@ -290,8 +295,8 @@ function! s:errorformat() abort
" It would be nice if this weren't necessary, but panic lines from tests are
" prefixed with a single leading tab, making them very similar to 2nd and
" later lines of a multi-line compiler error. Swallow it so that it doesn't
" cause a quickfix entry since the next entry can add a quickfix entry for
" 2nd and later lines of a multi-line compiler error.
" cause a quickfix entry since the next %G entry can add a quickfix entry
" for 2nd and later lines of a multi-line compiler error.
let format .= ",%-C%\\tpanic: %.%#"
let format .= ",%G%\\t%m"

View file

@ -78,7 +78,7 @@ endfunc
func! Test_GoTestVet() abort
let expected = [
\ {'lnum': 6, 'bufnr': 16, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
\ {'lnum': 6, 'bufnr': 16, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
\ ]
call s:test('veterror/veterror.go', expected)
endfunc

View file

@ -0,0 +1,34 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
function! go#uri#Encode(value) abort
return s:encode(a:value, '[^A-Za-z0-9_.~-]')
endfunction
function! go#uri#EncodePath(value) abort
return s:encode(a:value, '[^/A-Za-z0-9_.~-]')
endfunction
function! s:encode(value, unreserved)
return substitute(
\ a:value,
\ a:unreserved,
\ '\="%".printf(''%02X'', char2nr(submatch(0)))',
\ 'g'
\)
endfunction
function! go#uri#Decode(value) abort
return substitute(
\ a:value,
\ '%\(\x\x\)',
\ '\=nr2char(''0X'' . submatch(1))',
\ 'g'
\)
endfunction
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: sw=2 ts=2 et

View file

@ -42,7 +42,7 @@ tools developed by the Go community to provide a seamless Vim experience.
* Quickly execute your current file(s) with |:GoRun|.
* Improved syntax highlighting and folding.
* Debug programs with integrated `delve` support with |:GoDebugStart|.
* Completion support via `gocode`.
* Completion support via `gocode` and `gopls`.
* `gofmt` or `goimports` on save keeps the cursor position and undo history.
* Go to symbol/declaration with |:GoDef|.
* Look up documentation with |:GoDoc| or |:GoDocBrowser|.
@ -260,7 +260,7 @@ CTRL-]
g<C-LeftMouse>
<C-LeftMouse>
Goto declaration/definition for the declaration under the cursor. By
Go to declaration/definition for the identifier under the cursor. By
default the CTRL-] shortcut, the mapping `gd` and <C-LeftMouse>,
g<LeftMouse> are enabled to invoke :GoDef for the identifier under the
cursor. See |'g:go_def_mapping_enabled'| to disable them. No explicit
@ -272,6 +272,14 @@ g<C-LeftMouse>
list of file locations you have visited with :GoDef that is retained to
help you navigate software.
The per-window location stack is shared with |:GoDefType|.
*:GoDefType*
:GoDefType
Go to type definition for the identifier under the cursor.
The per-window location stack is shared with |:GoDef|.
*:GoDefStack*
:GoDefStack [number]
@ -1176,6 +1184,15 @@ cleaned for each package after `60` seconds. This can be changed with the
Returns the description of the identifer under the cursor. Can be used to plug
into the statusline.
*go#complete#Complete()*
Uses `gopls` for autocompletion. By default, it is hooked up to |'omnifunc'|
for Vim8 and Neovim.
*go#complete#GocodeComplete()*
Uses `gocode` for autocompletion. By default, it is hooked up to |'omnifunc'|
for Vim 7.4.
*go#tool#DescribeBalloon()*
@ -1350,7 +1367,7 @@ a private internal service. Default is 'https://godoc.org'.
Use this option to define the command to be used for |:GoDef|. By default
`guru` is being used as it covers all edge cases. But one might also use
`godef` as it's faster. Current valid options are: `[guru, godef]` >
`godef` as it's faster. Current valid options are: `[guru, godef, gopls]` >
let g:go_def_mode = 'guru'
<
@ -1498,11 +1515,12 @@ it's empty
<
*'g:go_metalinter_command'*
Overrides the command to be executed when |:GoMetaLinter| is called. This is
an advanced settings and is for users who want to have a complete control
over how `gometalinter` should be executed. By default it's empty.
Overrides the command to be executed when |:GoMetaLinter| is called. By
default it's `gometalinter`. `golangci-lint` is also supported. It can also be
used as an advanced setting for users who want to have more control over
the metalinter.
>
let g:go_metalinter_command = ""
let g:go_metalinter_command = "gometalinter"
<
*'g:go_metalinter_deadline'*
@ -1761,6 +1779,7 @@ Currently accepted values:
debugger-state Expose debugger state in 'g:go_debug_diag'.
debugger-commands Echo communication between vim-go and `dlv`; requests and
responses are recorded in `g:go_debug_commands`.
lsp Record lsp requests and responses in g:go_lsp_log.
>
let g:go_debug = []
<

View file

@ -25,8 +25,11 @@ setlocal noexpandtab
compiler go
" Set gocode completion
" Set autocompletion
setlocal omnifunc=go#complete#Complete
if !go#util#has_job()
setlocal omnifunc=go#complete#GocodeComplete
endif
if get(g:, "go_doc_keywordprg_enabled", 1)
" keywordprg doesn't allow to use vim commands, override it
@ -40,8 +43,8 @@ if get(g:, "go_def_mapping_enabled", 1)
nnoremap <buffer> <silent> <C-]> :GoDef<cr>
nnoremap <buffer> <silent> <C-LeftMouse> <LeftMouse>:GoDef<cr>
nnoremap <buffer> <silent> g<LeftMouse> <LeftMouse>:GoDef<cr>
nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump("split")<CR>
nnoremap <buffer> <silent> <C-w>] :<C-u>call go#def#Jump("split")<CR>
nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump("split", 0)<CR>
nnoremap <buffer> <silent> <C-w>] :<C-u>call go#def#Jump("split", 0)<CR>
nnoremap <buffer> <silent> <C-t> :<C-U>call go#def#StackPop(v:count1)<cr>
endif
@ -79,6 +82,10 @@ endif
augroup vim-go-buffer
autocmd! * <buffer>
" TODO(bc): notify gopls about changes on CursorHold when the buffer is
" modified.
" TODO(bc): notify gopls that the file on disk is correct on BufWritePost
autocmd CursorHold <buffer> call go#auto#auto_type_info()
autocmd CursorHold <buffer> call go#auto#auto_sameids()

View file

@ -54,7 +54,8 @@ command! -nargs=* -bang GoCoverageBrowser call go#coverage#Browser(<bang>0, <f-a
command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>)
" -- def
command! -nargs=* -range GoDef :call go#def#Jump('')
command! -nargs=* -range GoDef :call go#def#Jump('', 0)
command! -nargs=* -range GoDefType :call go#def#Jump('', 1)
command! -nargs=? GoDefPop :call go#def#StackPop(<f-args>)
command! -nargs=? GoDefStack :call go#def#Stack(<f-args>)
command! -nargs=? GoDefStackClear :call go#def#StackClear(<f-args>)

View file

@ -53,10 +53,15 @@ nnoremap <silent> <Plug>(go-rename) :<C-u>call go#rename#Rename(!g:go_jump_to_er
nnoremap <silent> <Plug>(go-decls) :<C-u>call go#decls#Decls(0, '')<CR>
nnoremap <silent> <Plug>(go-decls-dir) :<C-u>call go#decls#Decls(1, '')<CR>
nnoremap <silent> <Plug>(go-def) :<C-u>call go#def#Jump('')<CR>
nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit")<CR>
nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split")<CR>
nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab")<CR>
nnoremap <silent> <Plug>(go-def) :<C-u>call go#def#Jump('', 0)<CR>
nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit", 0)<CR>
nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split", 0)<CR>
nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab", 0)<CR>
nnoremap <silent> <Plug>(go-def-type) :<C-u>call go#def#Jump('', 1)<CR>
nnoremap <silent> <Plug>(go-def-type-vertical) :<C-u>call go#def#Jump("vsplit", 1)<CR>
nnoremap <silent> <Plug>(go-def-type-split) :<C-u>call go#def#Jump("split", 1)<CR>
nnoremap <silent> <Plug>(go-def-type-tab) :<C-u>call go#def#Jump("tab", 1)<CR>
nnoremap <silent> <Plug>(go-def-pop) :<C-u>call go#def#StackPop()<CR>
nnoremap <silent> <Plug>(go-def-stack) :<C-u>call go#def#Stack()<CR>

View file

@ -56,7 +56,9 @@ let s:packages = {
\ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
\ 'goimports': ['golang.org/x/tools/cmd/goimports'],
\ 'golint': ['golang.org/x/lint/golint'],
\ 'gopls': ['golang.org/x/tools/cmd/gopls'],
\ 'gometalinter': ['github.com/alecthomas/gometalinter'],
\ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint'],
\ 'gomodifytags': ['github.com/fatih/gomodifytags'],
\ 'gorename': ['golang.org/x/tools/cmd/gorename'],
\ 'gotags': ['github.com/jstemmer/gotags'],

View file

@ -38,25 +38,48 @@ highlight default link gomodReplaceOperator Operator
" highlight versions:
" * vX.Y.Z-pre
" * vX.Y.Z
" * vX.0.0-yyyyymmddhhmmss-abcdefabcdef
" * vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
" * vX.Y.(Z+1)-0.yyyymmddhhss-abcdefabcdef
" * +incompatible suffix when X > 1
" see https://godoc.org/golang.org/x/tools/internal/semver for more
" information about how semantic versions are parsed and
" https://golang.org/cmd/go/ for how pseudo-versions and +incompatible
" are applied.
" match vX.Y.Z and their prereleases
syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14}-\x\+\)\?"
" match target when most recent version before the target is X.Y.Z
syntax match gomodVersion "v\d\+\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14}-\x\+\)\)\?"
" match target without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef)
syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?"
" ^--- version ---^^------------ pre-release ---------------------^^--------------- metadata ---------------------^
" ^--------------------------------------- semantic version -------------------------------------------------------^
" match pseudo versions
" without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef)
syntax match gomodVersion "v\d\+\.0\.0-\d\{14\}-\x\+"
" when most recent version before target is a pre-release
syntax match gomodVersion "v\d\+\.\d\+\.\d\+-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?\.0\.\d\{14}-\x\+"
" ^--- version ---^^--- ------ pre-release -----------------^^--------------- metadata ---------------------^
" ^------------------------------------- semantic version --------------------------------------------------^
" most recent version before the target is X.Y.Z
syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?-0\.\d\{14}-\x\+"
" ^--- version ---^^--------------- metadata ---------------------^
" match vX.Y.Z and their prereleases for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14\}-\x\+\)\?\%(+incompatible\>\)\?"
" match target when most recent version before the target is X.Y.Z for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14\}-\x\+\)\)\?\%(+incompatible\>\)\?"
" match target without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef) for X>1
syntax match gomodVersion "v[2-9]\{1}\d\?\.0\.0-\d\{14\}-\x\+\%(+incompatible\>\)\?"
" match incompatible vX.Y.Z and their prereleases
syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+\%(-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?+incompatible"
" ^------- version -------^^------------- pre-release ---------------------^^--------------- metadata ---------------------^
" ^------------------------------------------- semantic version -----------------------------------------------------------^
" match incompatible pseudo versions
" incompatible without a major version before the commit (e.g. vX.0.0-yyyymmddhhmmss-abcdefabcdef)
syntax match gomodVersion "v[2-9]\{1}\d*\.0\.0-\d\{14\}-\x\++incompatible"
" when most recent version before target is a pre-release
syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?\.0\.\d\{14}-\x\++incompatible"
" ^------- version -------^^---------- pre-release -----------------^^--------------- metadata ---------------------^
" ^---------------------------------------- semantic version ------------------------------------------------------^
" most recent version before the target is X.Y.Z
syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+\%(+\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?-0\.\d\{14}-\x\++incompatible"
" ^------- version -------^^---------------- metadata ---------------------^
highlight default link gomodVersion Identifier
let b:current_syntax = "gomod"

View file

@ -14,7 +14,7 @@ Syntax highlighting, matching rules and mappings for [the original Markdown](htt
## Installation
If you use [Vundle](https://github.com/gmarik/vundle), add the following line to your `~/.vimrc`:
If you use [Vundle](https://github.com/gmarik/vundle), add the following lines to your `~/.vimrc`:
```vim
Plugin 'godlygeek/tabular'

View file

@ -151,10 +151,20 @@ let b:fenced_block = 0
let b:front_matter = 0
let s:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1)
if !get(g:, "vim_markdown_folding_disabled", 0)
function! s:MarkdownSetupFolding()
if !get(g:, "vim_markdown_folding_disabled", 0)
setlocal foldexpr=Foldexpr_markdown(v:lnum)
setlocal foldmethod=expr
if get(g:, "vim_markdown_folding_style_pythonic", 0) && get(g:, "vim_markdown_override_foldtext", 1)
setlocal foldtext=Foldtext_markdown()
endif
endif
endif
endfunction
call s:MarkdownSetupFolding()
augroup Mkd
" These autocmds need to be kept in sync with the autocmds calling
" s:MarkdownRefreshSyntax in ftplugin/markdown.vim.
autocmd BufWinEnter,BufWritePost <buffer> call s:MarkdownSetupFolding()
autocmd InsertEnter,InsertLeave <buffer> call s:MarkdownSetupFolding()
autocmd CursorHold,CursorHoldI <buffer> call s:MarkdownSetupFolding()
augroup END

View file

@ -780,6 +780,8 @@ function! s:MarkdownClearSyntaxVariables()
endfunction
augroup Mkd
" These autocmd calling s:MarkdownRefreshSyntax need to be kept in sync with
" the autocmds calling s:MarkdownSetupFolding in after/ftplugin/markdown.vim.
autocmd! * <buffer>
autocmd BufWinEnter <buffer> call s:MarkdownRefreshSyntax(1)
autocmd BufUnload <buffer> call s:MarkdownClearSyntaxVariables()

View file

@ -4,6 +4,8 @@ set rtp+=../build/tabular/
set rtp+=../build/vim-toml/
set rtp+=../build/vim-json/
set rtp+=../build/vader.vim/
set rtp-=~/.vim
set rtp-=~/.vim/after
let $LANG='en_US'
filetype on
filetype plugin on

View file

@ -1230,7 +1230,7 @@ function! s:wait_for_user_input(mode)
let s:saved_keys = ""
endif
" ambiguous mappings are note supported; e.g.:
" ambiguous mappings are not supported; e.g.:
" imap jj JJ
" imap jjj JJJ
" will always trigger the 'jj' mapping
@ -1239,8 +1239,8 @@ function! s:wait_for_user_input(mode)
let s_time = s:get_time_in_ms()
while 1
let map_dict = maparg(s:char, "i", 0, 1)
" break if chars exactly match mapping or if chars don't match beging of mapping anymore
if map_dict != {} || mapcheck(s:char, "i") == ""
" break if chars exactly match mapping
if map_dict != {}
if get(map_dict, 'expr', 0)
" handle case where {rhs} is a function
exec 'let char_mapping = ' . map_dict['rhs']
@ -1251,6 +1251,10 @@ function! s:wait_for_user_input(mode)
exec 'let s:char = "'.substitute(char_mapping, '<', '\\<', 'g').'"'
break
endif
" break if chars don't match beginning of mapping anymore
if mapcheck(s:char, "i") == ""
break
endif
if s:get_time_in_ms() > (s_time + &timeoutlen)
break
endif

View file

@ -170,9 +170,12 @@ describe "Multiple Cursors op pending & exit from insert|visual mode" do
end
describe "Multiple Cursors when using insert mapings" do
describe "Multiple Cursors when using insert mappings" do
let(:filename) { 'test.txt' }
let(:options) { ['set timeoutlen=10000', 'imap jj <esc>', 'imap jojo dude'] }
let(:options) { ['set timeoutlen=10000',
'imap jj <esc>',
'imap jojo dude',
'imap jk <esc>:%s/bla/hey/g<cr>'] }
specify "#mapping doing <Esc>" do
before <<-EOF
hello world!
@ -191,6 +194,24 @@ describe "Multiple Cursors when using insert mapings" do
EOF
end
specify "#mapping doing <Esc> and running a command" do
before <<-EOF
hello world!
hello world!
bla bla bla
bla bla bla
EOF
type 'w<C-n><C-n>ctherejk'
after <<-EOF
hello there!
hello there!
hey hey hey
hey hey hey
EOF
end
specify "#mapping using more than 2 characters" do
before <<-EOF
hello
@ -209,6 +230,24 @@ describe "Multiple Cursors when using insert mapings" do
EOF
end
specify "#unused mapping" do
before <<-EOF
hello world!
hello world!
bla bla bla
bla bla bla
EOF
type 'w<C-n><C-n>chey joseph blah blah blah<Esc>'
after <<-EOF
hello hey joseph blah blah blah!
hello hey joseph blah blah blah!
bla bla bla
bla bla bla
EOF
end
end
describe "Multiple Cursors when normal_maps is empty" do

View file

@ -96,4 +96,54 @@ snippet fund "function declaration" b
${1:void} ${2:function_name}($3);
endsnippet
global !p
def split_line(text):
import textwrap
lines = textwrap.wrap(text, 78 - 19)
output = list()
for line in lines:
output.append('*' + ' '*19 + line)
snip_line = snip.tabstops[4].end[0]
snip.buffer.append(output, snip_line + 1)
del snip.buffer[snip_line]
def get_args(arglist):
args = [arg.strip() for arg in arglist.split(',') if arg]
return args
endglobal
post_jump "if snip.tabstop == 0 : split_line(snip.tabstops[4].current_text)"
snippet head "File Header" b
/******************************************************************************
* File: `!p snip.rv = fn`
*
* Author: ${2}
* Created: `date +%m/%d/%y`
* Description: ${4:${VISUAL}}
*****************************************************************************/
${0}
endsnippet
post_jump "if snip.tabstop == 0 : split_line(snip.tabstops[4].current_text)"
snippet func "Function Header"
/******************************************************************************
* Function: $1
* Description: ${4:${VISUAL}}
* Where:`!p
snip.rv = ""
snip >> 2
args = get_args(t[2])
if args:
for arg in args:
snip.rv += '\n' + '*' + ' '*19 + arg + ' - TODO'
snip << 2
`
* Return: $5
* Error: $6
*****************************************************************************/
${1}($2){
${0}
}
endsnippet
# vim:ft=snippets:

View file

@ -656,6 +656,10 @@ snippet desc
describe ${1:`substitute(substitute(vim_snippets#Filename(), '_spec$', '', ''), '\(_\|^\)\(.\)', '\u\2', 'g')`} do
${0}
end
snippet rdesc
RSpec.describe ${1:`substitute(substitute(vim_snippets#Filename(), '_spec$', '', ''), '\(_\|^\)\(.\)', '\u\2', 'g')`} do
${0}
end
snippet descm
describe '${1:#method}' do
${0:pending 'Not implemented'}

View file

@ -212,7 +212,7 @@ snippet under underline text
snippet over overline text
\\overline{${1:${VISUAL:text}}} ${0}
snippet emp emphasize text
\\emph{${1:${VISUAL:text}}} ${0}
\\emph{${1:${VISUAL:text}}}${0}
snippet sc small caps text
\\textsc{${1:${VISUAL:text}}} ${0}
#Choosing font

View file

@ -28,26 +28,27 @@ snippet vbase
<script>
export default{
${0}
}
</script>
<style scoped>
</style>
snippet vimport:c
import New from './components/New.vue';
import ${1:Name} from './components/$1.vue';
export default{
export default {
components: {
appNew: New
$1
}
}
snippet vactionsis now
snippet vactions
actions: {
updateValue({commit}, payload) {
commit(updateValue, payload);
${1:updateValue}({commit}, ${2:payload}) {
commit($1, $2);
}
}
@ -58,6 +59,7 @@ snippet vanim:js:el
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-Leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@ -97,36 +99,36 @@ snippet vanim:js:method
}
snippet vcl
@click=""
@click="${1}"
snippet vdata
data: function () {
data() {
return {
key: value
${1:key}: ${2:value}
};
}
snippet vfilter
filters: {
fnName: function (v) {
${1:fnName}: function(${2:value}) {
return;
}
}
snippet vfor
<div v-for="item in items" :key="item.id">
{{ item }}
<div v-for="${1:item} in ${2:items}" :key="$1.id">
{{ $1 }}
</div
snippet vgetters
getters: {
value: state => {
return state.value;
${1:value}: state => {
return state.$1;
}
}
snippet vimport
import New from './components/New.vue';
import ${1:New} from './components/$1.vue';
snippet vkeep
<keep-alive>
@ -136,48 +138,41 @@ snippet vkeep
</keep-alive>
snippet vmixin
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
const ${1:mixinName} = {
mounted() {
console.log('hello from mixin!')
},
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
const ${2:Component} = Vue.extend({
mixins: [$1]
})
var component = new Component() // -> "hello from mixin!"
snippet vmutations
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
mutations: {
${1:updateValue}(state, ${3:payload}) => {
state.${2:value} = $3;
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // -> "hello from mixin!"
snippet vprops:d
propName: {
type: Number,
default: 100
${1:propName}: {
type: ${2:Number},
default: ${0}
},
snippet vprops
propName: {
type: Number
${1:propName}: {
type: ${2:Number}
},
snippet vstore
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
${1:key}: ${2:value}
}
});

View file

@ -135,6 +135,16 @@ tag, its attributes are kept in the new tag. End your input with > to discard
the those attributes. If <C-T> is used, the tags will appear on lines by
themselves.
If f, F, or <C-F> is used, Vim prompts for a function name to insert. The target
text will be wrapped in a function call. If f is used, the text is wrapped with
() parentheses; F adds additional spaces inside the parentheses. <C-F> inserts the
function name inside the parentheses.
Old text Command New text ~
"hello" ysWfprint<cr> print("hello")
"hello" ysWFprint<cr> print( "hello" )
"hello" ysW<C-f>print<cr> (print "hello")
If s is used, a leading but not trailing space is added. This is useful for
removing parentheses from a function call with csbs.