From 3aefdbd21a18d5b83e42eaf4dc722b0c5918f6f2 Mon Sep 17 00:00:00 2001 From: Amir Salihefendic <amix@doist.com> Date: Thu, 22 Aug 2019 17:36:17 +0200 Subject: [PATCH] Updated plugins --- sources_non_forked/ale/LICENSE | 2 +- .../ale/ale_linters/asm/gcc.vim | 5 +- .../ale/ale_linters/c/clangd.vim | 8 +- .../ale/ale_linters/c/clangtidy.vim | 9 +- .../ale/ale_linters/c/cppcheck.vim | 22 +- .../ale/ale_linters/c/cquery.vim | 10 +- sources_non_forked/ale/ale_linters/c/gcc.vim | 6 +- .../ale/ale_linters/cpp/clangcheck.vim | 3 +- .../ale/ale_linters/cpp/clangd.vim | 8 +- .../ale/ale_linters/cpp/clangtidy.vim | 9 +- .../ale/ale_linters/cpp/cppcheck.vim | 22 +- .../ale/ale_linters/cpp/cquery.vim | 10 +- .../ale/ale_linters/cpp/gcc.vim | 6 +- sources_non_forked/ale/ale_linters/cs/csc.vim | 95 + .../ale/ale_linters/cs/mcsc.vim | 34 +- .../ale/ale_linters/elm/elm_ls.vim | 37 + .../ale/ale_linters/elm/elm_lsp.vim | 22 - .../ale/ale_linters/erlang/dialyzer.vim | 93 + .../ale/ale_linters/go/bingo.vim | 6 +- .../ale/ale_linters/go/gobuild.vim | 1 + .../ale/ale_linters/go/gofmt.vim | 8 +- .../ale/ale_linters/go/golangci_lint.vim | 3 + .../ale/ale_linters/go/golint.vim | 2 +- .../ale/ale_linters/go/gometalinter.vim | 2 + .../ale/ale_linters/go/gopls.vim | 8 +- .../ale/ale_linters/go/gosimple.vim | 3 +- .../ale/ale_linters/go/gotype.vim | 3 +- .../ale/ale_linters/go/govet.vim | 1 + .../ale/ale_linters/go/langserver.vim | 3 +- .../ale/ale_linters/go/staticcheck.vim | 5 +- .../ale/ale_linters/java/checkstyle.vim | 35 +- .../ale/ale_linters/java/eclipselsp.vim | 30 +- .../ale/ale_linters/java/javac.vim | 5 + .../ale/ale_linters/java/javalsp.vim | 36 +- .../ale/ale_linters/javascript/eslint.vim | 2 +- .../ale/ale_linters/javascript/xo.vim | 4 +- .../ale/ale_linters/objc/clangd.vim | 8 +- .../ale/ale_linters/objcpp/clangd.vim | 8 +- .../ale/ale_linters/php/phpcs.vim | 11 +- .../ale/ale_linters/powershell/powershell.vim | 22 +- .../ale/ale_linters/pug/puglint.vim | 16 +- .../ale/ale_linters/purescript/ls.vim | 49 + .../ale/ale_linters/python/mypy.vim | 1 + .../ale/ale_linters/reason/ls.vim | 23 + .../ale/ale_linters/ruby/sorbet.vim | 23 + .../ale/ale_linters/rust/cargo.vim | 19 +- .../ale/ale_linters/terraform/terraform.vim | 49 + .../ale/ale_linters/tex/texlab.vim | 21 + .../ale/ale_linters/typescript/eslint.vim | 2 +- .../ale/ale_linters/typescript/xo.vim | 4 +- sources_non_forked/ale/autoload/ale.vim | 2 +- sources_non_forked/ale/autoload/ale/ant.vim | 41 + .../ale/autoload/ale/assert.vim | 12 + sources_non_forked/ale/autoload/ale/c.vim | 220 +- .../ale/autoload/ale/completion.vim | 109 +- .../ale/autoload/ale/debugging.vim | 13 +- .../ale/autoload/ale/engine.vim | 4 + .../ale/autoload/ale/events.vim | 2 +- sources_non_forked/ale/autoload/ale/fix.vim | 61 +- .../ale/autoload/ale/fix/registry.vim | 32 +- .../ale/autoload/ale/fixers/black.vim | 4 + .../ale/autoload/ale/fixers/clangformat.vim | 13 +- .../ale/autoload/ale/fixers/clangtidy.vim | 52 + .../ale/autoload/ale/fixers/eslint.vim | 18 +- .../ale/autoload/ale/fixers/gnatpp.vim | 17 + .../ale/autoload/ale/fixers/gofmt.vim | 3 +- .../ale/autoload/ale/fixers/goimports.vim | 3 +- .../ale/autoload/ale/fixers/gomod.vim | 3 +- .../ale/autoload/ale/fixers/hindent.vim | 20 + .../ale/autoload/ale/fixers/pgformatter.vim | 12 + .../ale/autoload/ale/fixers/prettier.vim | 10 +- .../ale/fixers/reorder_python_imports.vim | 25 + .../ale/autoload/ale/fixers/sorbet.vim | 19 + sources_non_forked/ale/autoload/ale/go.vim | 17 + .../ale/autoload/ale/handlers/ccls.vim | 14 +- .../ale/autoload/ale/handlers/cppcheck.vim | 41 + .../ale/autoload/ale/handlers/eslint.vim | 143 +- .../ale/autoload/ale/handlers/gcc.vim | 24 + .../ale/autoload/ale/handlers/rust.vim | 10 +- .../ale/autoload/ale/highlight.vim | 126 +- sources_non_forked/ale/autoload/ale/java.vim | 6 + .../ale/autoload/ale/linter.vim | 9 +- sources_non_forked/ale/autoload/ale/list.vim | 84 +- .../ale/autoload/ale/loclist_jumping.vim | 2 +- sources_non_forked/ale/autoload/ale/lsp.vim | 93 +- .../ale/autoload/ale/lsp/message.vim | 7 +- .../ale/autoload/ale/lsp/response.vim | 2 +- .../ale/autoload/ale/lsp_linter.vim | 55 +- sources_non_forked/ale/autoload/ale/path.vim | 11 +- .../ale/autoload/ale/python.vim | 2 +- sources_non_forked/ale/autoload/ale/sign.vim | 28 + .../ale/autoload/asyncomplete/sources/ale.vim | 26 + sources_non_forked/ale/doc/ale-ada.txt | 11 + sources_non_forked/ale/doc/ale-c.txt | 19 +- sources_non_forked/ale/doc/ale-cpp.txt | 19 +- sources_non_forked/ale/doc/ale-cs.txt | 90 +- .../ale/doc/ale-development.txt | 5 +- sources_non_forked/ale/doc/ale-elm.txt | 38 +- sources_non_forked/ale/doc/ale-erlang.txt | 29 + sources_non_forked/ale/doc/ale-go.txt | 10 + sources_non_forked/ale/doc/ale-handlebars.txt | 7 + sources_non_forked/ale/doc/ale-haskell.txt | 22 + sources_non_forked/ale/doc/ale-hcl.txt | 2 +- sources_non_forked/ale/doc/ale-java.txt | 96 +- sources_non_forked/ale/doc/ale-purescript.txt | 33 + sources_non_forked/ale/doc/ale-python.txt | 32 +- sources_non_forked/ale/doc/ale-reasonml.txt | 38 +- sources_non_forked/ale/doc/ale-ruby.txt | 20 + sources_non_forked/ale/doc/ale-sql.txt | 18 + .../doc/ale-supported-languages-and-tools.txt | 10 + sources_non_forked/ale/doc/ale-terraform.txt | 14 +- sources_non_forked/ale/doc/ale-tex.txt | 20 + sources_non_forked/ale/doc/ale.txt | 138 +- sources_non_forked/ale/plugin/ale.vim | 11 +- .../rplugin/python3/deoplete/sources/ale.py | 16 +- sources_non_forked/ale/supported-tools.md | 16 +- sources_non_forked/goyo.vim/autoload/goyo.vim | 2 +- sources_non_forked/lightline.vim/.travis.yml | 4 +- sources_non_forked/lightline.vim/README.md | 6 + .../lightline.vim/autoload/lightline.vim | 10 +- .../lightline/colorscheme/ayu_mirage.vim | 39 + .../lightline/colorscheme/powerlineish.vim | 28 + .../lightline/colorscheme/selenized_dark.vim | 50 + .../lightline.vim/doc/lightline.txt | 19 +- .../lightline.vim/plugin/lightline.vim | 12 +- .../lightline.vim/test/.themisrc | 2 + .../lightline.vim/test/popup.vim | 19 + .../lightline.vim/test/quickfix.vim | 25 + .../nerdtree/.github/ISSUE_TEMPLATE.md | 28 - .../nerdtree/.github/ISSUE_TEMPLATE/bug.md | 45 + .../.github/ISSUE_TEMPLATE/feature_request.md | 8 + .../.github/ISSUE_TEMPLATE/question.md | 24 + .../nerdtree/.github/PULL_REQUEST_TEMPLATE.md | 13 + sources_non_forked/nerdtree/CHANGELOG | 179 - sources_non_forked/nerdtree/CHANGELOG.md | 222 ++ .../nerdtree/autoload/nerdtree.vim | 41 +- .../nerdtree/autoload/nerdtree/ui_glue.vim | 48 +- sources_non_forked/nerdtree/doc/NERDTree.txt | 151 +- .../nerdtree/lib/nerdtree/bookmark.vim | 4 +- .../nerdtree/lib/nerdtree/creator.vim | 11 +- .../nerdtree/lib/nerdtree/menu_controller.vim | 8 +- .../nerdtree/lib/nerdtree/nerdtree.vim | 16 +- .../nerdtree/lib/nerdtree/opener.vim | 30 +- .../nerdtree/lib/nerdtree/path.vim | 30 +- .../nerdtree/lib/nerdtree/tree_dir_node.vim | 5 + .../nerdtree/lib/nerdtree/ui.vim | 16 +- .../nerdtree/nerdtree_plugin/fs_menu.vim | 32 +- .../nerdtree/plugin/NERD_tree.vim | 1 + sources_non_forked/nginx.vim/README.md | 40 +- .../nginx.vim/snippets/nginx.snippets | 166 - .../vim-bundle-mako/indent/mako.vim | 85 +- .../vim-fugitive/autoload/fugitive.vim | 3356 +++++++++++------ .../vim-fugitive/doc/fugitive.txt | 340 +- .../vim-fugitive/plugin/fugitive.vim | 121 +- .../vim-fugitive/syntax/fugitive.vim | 31 +- .../vim-fugitive/syntax/fugitiveblame.vim | 7 + .../vim-gitgutter/.github/issue_template.md | 4 - sources_non_forked/vim-gitgutter/README.mkd | 95 +- .../vim-gitgutter/autoload/gitgutter.vim | 53 +- .../vim-gitgutter/autoload/gitgutter/diff.vim | 12 +- .../autoload/gitgutter/highlight.vim | 103 +- .../vim-gitgutter/autoload/gitgutter/hunk.vim | 98 +- .../vim-gitgutter/autoload/gitgutter/sign.vim | 170 +- .../autoload/gitgutter/utility.vim | 90 +- .../vim-gitgutter/doc/gitgutter.txt | 97 +- .../vim-gitgutter/plugin/gitgutter.vim | 31 +- sources_non_forked/vim-gitgutter/test/test | 2 +- .../vim-gitgutter/test/test_gitgutter.vim | 365 +- sources_non_forked/vim-go/.github/FUNDING.yml | 1 + .../vim-go/.github/ISSUE_TEMPLATE.md | 7 +- sources_non_forked/vim-go/CHANGELOG.md | 89 + sources_non_forked/vim-go/README.md | 11 +- .../vim-go/autoload/go/auto.vim | 12 +- sources_non_forked/vim-go/autoload/go/cmd.vim | 4 +- .../vim-go/autoload/go/complete.vim | 29 +- .../vim-go/autoload/go/complete_test.vim | 28 +- .../vim-go/autoload/go/config.vim | 21 +- .../vim-go/autoload/go/debug.vim | 23 +- .../vim-go/autoload/go/debug_test.vim | 12 + sources_non_forked/vim-go/autoload/go/def.vim | 4 +- .../vim-go/autoload/go/def_test.vim | 197 +- sources_non_forked/vim-go/autoload/go/doc.vim | 12 + .../vim-go/autoload/go/issue.vim | 16 +- .../vim-go/autoload/go/lint.vim | 34 +- .../vim-go/autoload/go/lint_test.vim | 129 +- sources_non_forked/vim-go/autoload/go/lsp.vim | 486 ++- .../autoload/go/lsp/completionitemkind.vim | 18 +- .../vim-go/autoload/go/lsp/lsp.vim | 58 + .../vim-go/autoload/go/lsp/lsp_test.vim | 32 + .../vim-go/autoload/go/lsp/message.vim | 80 +- .../vim-go/autoload/go/lsp_test.vim | 49 + sources_non_forked/vim-go/autoload/go/mod.vim | 8 +- .../vim-go/autoload/go/package.vim | 76 +- .../vim-go/autoload/go/promise.vim | 50 + .../vim-go/autoload/go/promise_test.vim | 41 + .../vim-go/autoload/go/statusline.vim | 16 +- .../vim-go/autoload/go/template.vim | 9 +- .../vim-go/autoload/go/term.vim | 28 +- .../vim-go/autoload/go/term_test.vim | 2 + .../test/src/example/example_test.go | 10 + .../vim-go/autoload/go/test.vim | 13 +- .../vim-go/autoload/go/test_test.vim | 15 +- .../vim-go/autoload/go/tool.vim | 10 +- .../vim-go/autoload/go/util.vim | 16 +- sources_non_forked/vim-go/autoload/gotest.vim | 21 +- sources_non_forked/vim-go/doc/vim-go.txt | 113 +- .../vim-go/ftplugin/go/commands.vim | 7 + .../vim-go/gosnippets/UltiSnips/go.snippets | 4 +- sources_non_forked/vim-go/plugin/go.vim | 102 +- sources_non_forked/vim-go/scripts/install-vim | 4 +- sources_non_forked/vim-go/scripts/runtest.vim | 10 +- sources_non_forked/vim-markdown/Makefile | 6 + sources_non_forked/vim-markdown/README.md | 303 +- .../vim-markdown/after/ftplugin/markdown.vim | 53 +- .../vim-markdown/doc/vim-markdown.txt | 269 +- .../vim-markdown/syntax/markdown.vim | 4 +- .../vim-markdown/test/python-folding.vader | 15 +- .../vim-markdown/test/toc.vader | 4 - .../vim-multiple-cursors/README.md | 28 +- .../doc/multiple_cursors.txt | 14 +- .../plugin/multiple_cursors.vim | 4 +- .../spec/multiple_cursors_spec.rb | 4 +- sources_non_forked/vim-repeat/README.markdown | 1 + .../vim-snippets/UltiSnips/html.snippets | 4 + .../UltiSnips/javascript-node.snippets | 2 +- .../vim-snippets/UltiSnips/lua.snippets | 2 +- .../vim-snippets/UltiSnips/python.snippets | 8 +- .../vim-snippets/UltiSnips/r.snippets | 3 +- .../vim-snippets/UltiSnips/ruby.snippets | 2 +- .../vim-snippets/UltiSnips/sh.snippets | 8 +- .../vim-snippets/UltiSnips/tex.snippets | 2 +- .../vim-snippets/UltiSnips/zsh.snippets | 9 +- .../vim-snippets/snippets/cpp.snippets | 4 + .../vim-snippets/snippets/css.snippets | 223 +- .../vim-snippets/snippets/eelixir.snippets | 34 +- .../vim-snippets/snippets/go.snippets | 6 - .../javascript/javascript-react.snippets | 17 +- .../javascript/javascript-redux.snippets | 37 + .../javascript/javascript.es6.snippets | 55 - .../snippets/javascript/javascript.snippets | 65 +- .../vim-snippets/snippets/sass.snippets | 228 ++ .../vim-snippets/snippets/stylus.snippets | 230 +- .../vim-snippets/snippets/tex.snippets | 2 +- .../vim-surround/plugin/surround.vim | 11 +- 244 files changed, 9486 insertions(+), 3395 deletions(-) create mode 100644 sources_non_forked/ale/ale_linters/cs/csc.vim create mode 100644 sources_non_forked/ale/ale_linters/elm/elm_ls.vim delete mode 100644 sources_non_forked/ale/ale_linters/elm/elm_lsp.vim create mode 100644 sources_non_forked/ale/ale_linters/erlang/dialyzer.vim create mode 100644 sources_non_forked/ale/ale_linters/purescript/ls.vim create mode 100644 sources_non_forked/ale/ale_linters/reason/ls.vim create mode 100644 sources_non_forked/ale/ale_linters/ruby/sorbet.vim create mode 100644 sources_non_forked/ale/ale_linters/terraform/terraform.vim create mode 100644 sources_non_forked/ale/ale_linters/tex/texlab.vim create mode 100644 sources_non_forked/ale/autoload/ale/ant.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/clangtidy.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/gnatpp.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/hindent.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/pgformatter.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/reorder_python_imports.vim create mode 100644 sources_non_forked/ale/autoload/ale/fixers/sorbet.vim create mode 100644 sources_non_forked/ale/autoload/asyncomplete/sources/ale.vim create mode 100644 sources_non_forked/ale/doc/ale-purescript.txt create mode 100644 sources_non_forked/lightline.vim/autoload/lightline/colorscheme/ayu_mirage.vim create mode 100644 sources_non_forked/lightline.vim/autoload/lightline/colorscheme/powerlineish.vim create mode 100644 sources_non_forked/lightline.vim/autoload/lightline/colorscheme/selenized_dark.vim create mode 100644 sources_non_forked/lightline.vim/test/popup.vim create mode 100644 sources_non_forked/lightline.vim/test/quickfix.vim delete mode 100644 sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md create mode 100644 sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/bug.md create mode 100644 sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/question.md create mode 100644 sources_non_forked/nerdtree/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 sources_non_forked/nerdtree/CHANGELOG create mode 100644 sources_non_forked/nerdtree/CHANGELOG.md delete mode 100644 sources_non_forked/nginx.vim/snippets/nginx.snippets create mode 100644 sources_non_forked/vim-fugitive/syntax/fugitiveblame.vim create mode 100644 sources_non_forked/vim-go/.github/FUNDING.yml create mode 100644 sources_non_forked/vim-go/autoload/go/lsp/lsp.vim create mode 100644 sources_non_forked/vim-go/autoload/go/lsp/lsp_test.vim create mode 100644 sources_non_forked/vim-go/autoload/go/lsp_test.vim create mode 100644 sources_non_forked/vim-go/autoload/go/promise.vim create mode 100644 sources_non_forked/vim-go/autoload/go/promise_test.vim create mode 100644 sources_non_forked/vim-go/autoload/go/test-fixtures/test/src/example/example_test.go create mode 100644 sources_non_forked/vim-snippets/snippets/javascript/javascript-redux.snippets delete mode 100644 sources_non_forked/vim-snippets/snippets/javascript/javascript.es6.snippets diff --git a/sources_non_forked/ale/LICENSE b/sources_non_forked/ale/LICENSE index 739ccae0..f8f3524d 100644 --- a/sources_non_forked/ale/LICENSE +++ b/sources_non_forked/ale/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2018, w0rp <devw0rp@gmail.com> +Copyright (c) 2016-2019, w0rp <devw0rp@gmail.com> All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/sources_non_forked/ale/ale_linters/asm/gcc.vim b/sources_non_forked/ale/ale_linters/asm/gcc.vim index 72b293c0..eecab6ef 100644 --- a/sources_non_forked/ale/ale_linters/asm/gcc.vim +++ b/sources_non_forked/ale/ale_linters/asm/gcc.vim @@ -5,7 +5,10 @@ call ale#Set('asm_gcc_executable', 'gcc') call ale#Set('asm_gcc_options', '-Wall') function! ale_linters#asm#gcc#GetCommand(buffer) abort - return '%e -x assembler -fsyntax-only ' + " `-o /dev/null` or `-o null` is needed to catch all errors, + " -fsyntax-only doesn't catch everything. + return '%e -x assembler' + \ . ' -o ' . g:ale#util#nul_file \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' endfunction diff --git a/sources_non_forked/ale/ale_linters/c/clangd.vim b/sources_non_forked/ale/ale_linters/c/clangd.vim index 918eadcc..79b600fa 100644 --- a/sources_non_forked/ale/ale_linters/c/clangd.vim +++ b/sources_non_forked/ale/ale_linters/c/clangd.vim @@ -4,12 +4,6 @@ call ale#Set('c_clangd_executable', 'clangd') call ale#Set('c_clangd_options', '') -function! ale_linters#c#clangd#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' -endfunction - function! ale_linters#c#clangd#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options')) endfunction @@ -19,5 +13,5 @@ call ale#linter#Define('c', { \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'c_clangd_executable')}, \ 'command': function('ale_linters#c#clangd#GetCommand'), -\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'), +\ 'project_root': function('ale#c#FindProjectRoot'), \}) diff --git a/sources_non_forked/ale/ale_linters/c/clangtidy.vim b/sources_non_forked/ale/ale_linters/c/clangtidy.vim index 6484f8af..f998866a 100644 --- a/sources_non_forked/ale/ale_linters/c/clangtidy.vim +++ b/sources_non_forked/ale/ale_linters/c/clangtidy.vim @@ -11,9 +11,12 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy') " http://clang.llvm.org/extra/clang-tidy/checks/list.html call ale#Set('c_clangtidy_checks', []) -" Set this option to manually set some options for clang-tidy. +" Set this option to manually set some options for clang-tidy to use as compile +" flags. " This will disable compile_commands.json detection. call ale#Set('c_clangtidy_options', '') +" Set this option to manually set options for clang-tidy directly. +call ale#Set('c_clangtidy_extra_options', '') call ale#Set('c_build_dir', '') function! ale_linters#c#clangtidy#GetCommand(buffer) abort @@ -25,8 +28,12 @@ function! ale_linters#c#clangtidy#GetCommand(buffer) abort \ ? ale#Var(a:buffer, 'c_clangtidy_options') \ : '' + " Get the options to pass directly to clang-tidy + let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options') + return '%e' \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') + \ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '') \ . ' %s' \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:options) ? ' -- ' . l:options : '') diff --git a/sources_non_forked/ale/ale_linters/c/cppcheck.vim b/sources_non_forked/ale/ale_linters/c/cppcheck.vim index 851f9f11..309b2851 100644 --- a/sources_non_forked/ale/ale_linters/c/cppcheck.vim +++ b/sources_non_forked/ale/ale_linters/c/cppcheck.vim @@ -5,23 +5,17 @@ call ale#Set('c_cppcheck_executable', 'cppcheck') call ale#Set('c_cppcheck_options', '--enable=style') function! ale_linters#c#cppcheck#GetCommand(buffer) abort - " Search upwards from the file for compile_commands.json. - " - " If we find it, we'll `cd` to where the compile_commands.json file is, - " then use the file to set up import paths, etc. - let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - let l:cd_command = !empty(l:compile_commmands_path) - \ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h')) - \ : '' - let l:compile_commands_option = !empty(l:compile_commmands_path) - \ ? '--project=compile_commands.json ' + let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer) + let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) + let l:buffer_path_include = empty(l:compile_commands_option) + \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ : '' return l:cd_command - \ . '%e -q --language=c ' - \ . l:compile_commands_option - \ . ale#Var(a:buffer, 'c_cppcheck_options') + \ . '%e -q --language=c' + \ . ale#Pad(l:compile_commands_option) + \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options')) + \ . l:buffer_path_include \ . ' %t' endfunction diff --git a/sources_non_forked/ale/ale_linters/c/cquery.vim b/sources_non_forked/ale/ale_linters/c/cquery.vim index d2be9cd9..ff0f34af 100644 --- a/sources_non_forked/ale/ale_linters/c/cquery.vim +++ b/sources_non_forked/ale/ale_linters/c/cquery.vim @@ -5,13 +5,15 @@ call ale#Set('c_cquery_executable', 'cquery') call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery')) function! ale_linters#c#cquery#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + " Try to find cquery configuration files first. + let l:config = ale#path#FindNearestFile(a:buffer, '.cquery') - if empty(l:project_root) - let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') + if !empty(l:config) + return fnamemodify(l:config, ':h') endif - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' + " Fall back on default project root detection. + return ale#c#FindProjectRoot(a:buffer) endfunction function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort diff --git a/sources_non_forked/ale/ale_linters/c/gcc.vim b/sources_non_forked/ale/ale_linters/c/gcc.vim index d965965d..1df1018e 100644 --- a/sources_non_forked/ale/ale_linters/c/gcc.vim +++ b/sources_non_forked/ale/ale_linters/c/gcc.vim @@ -9,7 +9,11 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort " -iquote with the directory the file is in makes #include work for " headers in the same directory. - return '%e -S -x c -fsyntax-only' + " + " `-o /dev/null` or `-o null` is needed to catch all errors, + " -fsyntax-only doesn't catch everything. + return '%e -S -x c' + \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ale#Pad(l:cflags) \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -' diff --git a/sources_non_forked/ale/ale_linters/cpp/clangcheck.vim b/sources_non_forked/ale/ale_linters/cpp/clangcheck.vim index b511a413..7d32a57c 100644 --- a/sources_non_forked/ale/ale_linters/cpp/clangcheck.vim +++ b/sources_non_forked/ale/ale_linters/cpp/clangcheck.vim @@ -12,7 +12,8 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort let l:build_dir = ale#Var(a:buffer, 'c_build_dir') if empty(l:build_dir) - let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) + let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) + let l:build_dir = ale#path#Dirname(l:json_file) endif " The extra arguments in the command are used to prevent .plist files from diff --git a/sources_non_forked/ale/ale_linters/cpp/clangd.vim b/sources_non_forked/ale/ale_linters/cpp/clangd.vim index 4a8ff4f6..fab605f4 100644 --- a/sources_non_forked/ale/ale_linters/cpp/clangd.vim +++ b/sources_non_forked/ale/ale_linters/cpp/clangd.vim @@ -4,12 +4,6 @@ call ale#Set('cpp_clangd_executable', 'clangd') call ale#Set('cpp_clangd_options', '') -function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' -endfunction - function! ale_linters#cpp#clangd#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options')) endfunction @@ -19,5 +13,5 @@ call ale#linter#Define('cpp', { \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')}, \ 'command': function('ale_linters#cpp#clangd#GetCommand'), -\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'), +\ 'project_root': function('ale#c#FindProjectRoot'), \}) diff --git a/sources_non_forked/ale/ale_linters/cpp/clangtidy.vim b/sources_non_forked/ale/ale_linters/cpp/clangtidy.vim index 841b795f..085bc332 100644 --- a/sources_non_forked/ale/ale_linters/cpp/clangtidy.vim +++ b/sources_non_forked/ale/ale_linters/cpp/clangtidy.vim @@ -5,9 +5,12 @@ call ale#Set('cpp_clangtidy_executable', 'clang-tidy') " Set this option to check the checks clang-tidy will apply. call ale#Set('cpp_clangtidy_checks', []) -" Set this option to manually set some options for clang-tidy. +" Set this option to manually set some options for clang-tidy to use as compile +" flags. " This will disable compile_commands.json detection. call ale#Set('cpp_clangtidy_options', '') +" Set this option to manually set options for clang-tidy directly. +call ale#Set('cpp_clangtidy_extra_options', '') call ale#Set('c_build_dir', '') function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort @@ -19,8 +22,12 @@ function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort \ ? ale#Var(a:buffer, 'cpp_clangtidy_options') \ : '' + " Get the options to pass directly to clang-tidy + let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options') + return '%e' \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') + \ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '') \ . ' %s' \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:options) ? ' -- ' . l:options : '') diff --git a/sources_non_forked/ale/ale_linters/cpp/cppcheck.vim b/sources_non_forked/ale/ale_linters/cpp/cppcheck.vim index 5173d698..7cd80dbc 100644 --- a/sources_non_forked/ale/ale_linters/cpp/cppcheck.vim +++ b/sources_non_forked/ale/ale_linters/cpp/cppcheck.vim @@ -5,23 +5,17 @@ call ale#Set('cpp_cppcheck_executable', 'cppcheck') call ale#Set('cpp_cppcheck_options', '--enable=style') function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort - " Search upwards from the file for compile_commands.json. - " - " If we find it, we'll `cd` to where the compile_commands.json file is, - " then use the file to set up import paths, etc. - let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - let l:cd_command = !empty(l:compile_commmands_path) - \ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h')) - \ : '' - let l:compile_commands_option = !empty(l:compile_commmands_path) - \ ? '--project=compile_commands.json ' + let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer) + let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) + let l:buffer_path_include = empty(l:compile_commands_option) + \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ : '' return l:cd_command - \ . '%e -q --language=c++ ' - \ . l:compile_commands_option - \ . ale#Var(a:buffer, 'cpp_cppcheck_options') + \ . '%e -q --language=c++' + \ . ale#Pad(l:compile_commands_option) + \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options')) + \ . l:buffer_path_include \ . ' %t' endfunction diff --git a/sources_non_forked/ale/ale_linters/cpp/cquery.vim b/sources_non_forked/ale/ale_linters/cpp/cquery.vim index 0dd9f6ad..2971cdcb 100644 --- a/sources_non_forked/ale/ale_linters/cpp/cquery.vim +++ b/sources_non_forked/ale/ale_linters/cpp/cquery.vim @@ -5,13 +5,15 @@ call ale#Set('cpp_cquery_executable', 'cquery') call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery')) function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + " Try to find cquery configuration files first. + let l:config = ale#path#FindNearestFile(a:buffer, '.cquery') - if empty(l:project_root) - let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') + if !empty(l:config) + return fnamemodify(l:config, ':h') endif - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' + " Fall back on default project root detection. + return ale#c#FindProjectRoot(a:buffer) endfunction function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort diff --git a/sources_non_forked/ale/ale_linters/cpp/gcc.vim b/sources_non_forked/ale/ale_linters/cpp/gcc.vim index c427020b..108d6d70 100644 --- a/sources_non_forked/ale/ale_linters/cpp/gcc.vim +++ b/sources_non_forked/ale/ale_linters/cpp/gcc.vim @@ -9,7 +9,11 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort " -iquote with the directory the file is in makes #include work for " headers in the same directory. - return '%e -S -x c++ -fsyntax-only' + " + " `-o /dev/null` or `-o null` is needed to catch all errors, + " -fsyntax-only doesn't catch everything. + return '%e -S -x c++' + \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ale#Pad(l:cflags) \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -' diff --git a/sources_non_forked/ale/ale_linters/cs/csc.vim b/sources_non_forked/ale/ale_linters/cs/csc.vim new file mode 100644 index 00000000..308abc77 --- /dev/null +++ b/sources_non_forked/ale/ale_linters/cs/csc.vim @@ -0,0 +1,95 @@ +call ale#Set('cs_csc_options', '') +call ale#Set('cs_csc_source', '') +call ale#Set('cs_csc_assembly_path', []) +call ale#Set('cs_csc_assemblies', []) + +function! s:GetWorkingDirectory(buffer) abort + let l:working_directory = ale#Var(a:buffer, 'cs_csc_source') + + if !empty(l:working_directory) + return l:working_directory + endif + + return expand('#' . a:buffer . ':p:h') +endfunction + +function! ale_linters#cs#csc#GetCommand(buffer) abort + " Pass assembly paths via the -lib: parameter. + let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path') + + let l:lib_option = !empty(l:path_list) + \ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',') + \ : '' + + " Pass paths to DLL files via the -r: parameter. + let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies') + + let l:r_option = !empty(l:assembly_list) + \ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',') + \ : '' + + " register temporary module target file with ale + " register temporary module target file with ALE. + let l:out = ale#command#CreateFile(a:buffer) + + " The code is compiled as a module and the output is redirected to a + " temporary file. + return ale#path#CdString(s:GetWorkingDirectory(a:buffer)) + \ . 'csc /unsafe' + \ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options')) + \ . ale#Pad(l:lib_option) + \ . ale#Pad(l:r_option) + \ . ' /out:' . l:out + \ . ' /t:module' + \ . ' /recurse:' . ale#Escape('*.cs') +endfunction + +function! ale_linters#cs#csc#Handle(buffer, lines) abort + " Look for lines like the following. + " + " Tests.cs(12,29): error CSXXXX: ; expected + " + " NOTE: pattern also captures file name as linter compiles all + " files within the source tree rooted at the specified source + " path and not just the file loaded in the buffer + let l:patterns = [ + \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', + \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', + \] + let l:output = [] + + let l:dir = s:GetWorkingDirectory(a:buffer) + + for l:match in ale#util#GetMatches(a:lines, l:patterns) + if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' + call add(l:output, { + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'type': l:match[4] is# 'error' ? 'E' : 'W', + \ 'code': l:match[5], + \ 'text': l:match[6] , + \}) + elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' + call add(l:output, { + \ 'filename':'<csc>', + \ 'lnum': -1, + \ 'col': -1, + \ 'type': l:match[1] is# 'error' ? 'E' : 'W', + \ 'code': l:match[2], + \ 'text': l:match[3], + \}) + endif + endfor + + return l:output +endfunction + +call ale#linter#Define('cs',{ +\ 'name': 'csc', +\ 'output_stream': 'stdout', +\ 'executable': 'csc', +\ 'command': function('ale_linters#cs#csc#GetCommand'), +\ 'callback': 'ale_linters#cs#csc#Handle', +\ 'lint_file': 1 +\}) diff --git a/sources_non_forked/ale/ale_linters/cs/mcsc.vim b/sources_non_forked/ale/ale_linters/cs/mcsc.vim index dd067eba..0e4e5667 100644 --- a/sources_non_forked/ale/ale_linters/cs/mcsc.vim +++ b/sources_non_forked/ale/ale_linters/cs/mcsc.vim @@ -52,20 +52,34 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort " NOTE: pattern also captures file name as linter compiles all " files within the source tree rooted at the specified source " path and not just the file loaded in the buffer - let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' + let l:patterns = [ + \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', + \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', + \] let l:output = [] let l:dir = s:GetWorkingDirectory(a:buffer) - for l:match in ale#util#GetMatches(a:lines, l:pattern) - call add(l:output, { - \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), - \ 'lnum': l:match[2] + 0, - \ 'col': l:match[3] + 0, - \ 'type': l:match[4] is# 'error' ? 'E' : 'W', - \ 'code': l:match[5], - \ 'text': l:match[6], - \}) + for l:match in ale#util#GetMatches(a:lines, l:patterns) + if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' + call add(l:output, { + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'type': l:match[4] is# 'error' ? 'E' : 'W', + \ 'code': l:match[5], + \ 'text': l:match[6] , + \}) + elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' + call add(l:output, { + \ 'filename':'<mcs>', + \ 'lnum': -1, + \ 'col': -1, + \ 'type': l:match[1] is# 'error' ? 'E' : 'W', + \ 'code': l:match[2], + \ 'text': l:match[3], + \}) + endif endfor return l:output diff --git a/sources_non_forked/ale/ale_linters/elm/elm_ls.vim b/sources_non_forked/ale/ale_linters/elm/elm_ls.vim new file mode 100644 index 00000000..374ef8de --- /dev/null +++ b/sources_non_forked/ale/ale_linters/elm/elm_ls.vim @@ -0,0 +1,37 @@ +" Author: antew - https://github.com/antew +" Description: elm-language-server integration for elm (diagnostics, formatting, and more) + +call ale#Set('elm_ls_executable', 'elm-language-server') +call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1)) +call ale#Set('elm_ls_elm_path', 'elm') +call ale#Set('elm_ls_elm_format_path', 'elm-format') +call ale#Set('elm_ls_elm_test_path', 'elm-test') + +function! elm_ls#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 + +function! elm_ls#GetOptions(buffer) abort + return { + \ 'runtime': 'node', + \ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'), + \ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'), + \ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'), + \} +endfunction + +call ale#linter#Define('elm', { +\ 'name': 'elm_ls', +\ 'lsp': 'stdio', +\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_ls', [ +\ 'node_modules/.bin/elm-language-server', +\ 'node_modules/.bin/elm-lsp', +\ 'elm-lsp' +\ ])}, +\ 'command': '%e --stdio', +\ 'project_root': function('elm_ls#GetRootDir'), +\ 'language': 'elm', +\ 'initialization_options': function('elm_ls#GetOptions') +\}) diff --git a/sources_non_forked/ale/ale_linters/elm/elm_lsp.vim b/sources_non_forked/ale/ale_linters/elm/elm_lsp.vim deleted file mode 100644 index 2259286f..00000000 --- a/sources_non_forked/ale/ale_linters/elm/elm_lsp.vim +++ /dev/null @@ -1,22 +0,0 @@ -" 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' -\}) diff --git a/sources_non_forked/ale/ale_linters/erlang/dialyzer.vim b/sources_non_forked/ale/ale_linters/erlang/dialyzer.vim new file mode 100644 index 00000000..7af64c4f --- /dev/null +++ b/sources_non_forked/ale/ale_linters/erlang/dialyzer.vim @@ -0,0 +1,93 @@ +" Author: Autoine Gagne - https://github.com/AntoineGagne +" Description: Define a checker that runs dialyzer on Erlang files. + +let g:ale_erlang_dialyzer_executable = +\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer') +let g:ale_erlang_dialyzer_plt_file = +\ get(g:, 'ale_erlang_dialyzer_plt_file', '') +let g:ale_erlang_dialyzer_rebar3_profile = +\ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default') + +function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort + return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile') +endfunction + +function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort + let l:plt_file = '' + let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer) + let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build' . l:rebar3_profile) + + if !empty(l:plt_file_directory) + let l:plt_file = split(globpath(l:plt_file_directory, '/*_plt'), '\n') + endif + + if !empty(l:plt_file) + return l:plt_file[0] + endif + + if !empty($REBAR_PLT_DIR) + return expand('$REBAR_PLT_DIR/dialyzer/plt') + endif + + return expand('$HOME/.dialyzer_plt') +endfunction + +function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort + let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file') + + if !empty(l:plt_file) + return l:plt_file + endif + + return ale_linters#erlang#dialyzer#FindPlt(a:buffer) +endfunction + +function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort + return ale#Var(a:buffer, 'erlang_dialyzer_executable') +endfunction + +function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort + let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer)) + \ . ' -n' + \ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer)) + \ . ' -Wunmatched_returns' + \ . ' -Werror_handling' + \ . ' -Wrace_conditions' + \ . ' -Wunderspecs' + \ . ' %s' + + return l:command +endfunction + +function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort + " Match patterns like the following: + " + " erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available + let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$' + let l:output = [] + + for l:line in a:lines + let l:match = matchlist(l:line, l:pattern) + + if len(l:match) != 0 + let l:code = l:match[2] + + call add(l:output, { + \ 'lnum': str2nr(l:match[1]), + \ 'lcol': 0, + \ 'text': l:code, + \ 'type': 'W' + \}) + endif + endfor + + return l:output +endfunction + +call ale#linter#Define('erlang', { +\ 'name': 'dialyzer', +\ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'), +\ 'command': function('ale_linters#erlang#dialyzer#GetCommand'), +\ 'callback': function('ale_linters#erlang#dialyzer#Handle'), +\ 'lint_file': 1 +\}) diff --git a/sources_non_forked/ale/ale_linters/go/bingo.vim b/sources_non_forked/ale/ale_linters/go/bingo.vim index e446bdcc..1e43f8e4 100644 --- a/sources_non_forked/ale/ale_linters/go/bingo.vim +++ b/sources_non_forked/ale/ale_linters/go/bingo.vim @@ -5,11 +5,13 @@ call ale#Set('go_bingo_executable', 'bingo') call ale#Set('go_bingo_options', '--mode stdio') function! ale_linters#go#bingo#GetCommand(buffer) abort - return '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options')) + return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options')) endfunction function! ale_linters#go#bingo#FindProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod') + let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off' + let l:project_root = l:go_modules_off ? + \ '' : ale#path#FindNearestFile(a:buffer, 'go.mod') let l:mods = ':h' if empty(l:project_root) diff --git a/sources_non_forked/ale/ale_linters/go/gobuild.vim b/sources_non_forked/ale/ale_linters/go/gobuild.vim index 374ded35..1dfb6daa 100644 --- a/sources_non_forked/ale/ale_linters/go/gobuild.vim +++ b/sources_non_forked/ale/ale_linters/go/gobuild.vim @@ -11,6 +11,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort " Run go test in local directory with relative path return ale#path#BufferCdString(a:buffer) + \ . ale#go#EnvString(a:buffer) \ . ale#Var(a:buffer, 'go_go_executable') . ' test' \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' -c -o /dev/null ./' diff --git a/sources_non_forked/ale/ale_linters/go/gofmt.vim b/sources_non_forked/ale/ale_linters/go/gofmt.vim index 337deef8..a233b422 100644 --- a/sources_non_forked/ale/ale_linters/go/gofmt.vim +++ b/sources_non_forked/ale/ale_linters/go/gofmt.vim @@ -1,10 +1,16 @@ " Author: neersighted <bjorn@neersighted.com> " Description: gofmt for Go files +function! ale_linters#go#gofmt#GetCommand(buffer) abort + return ale#go#EnvString(a:buffer) + \ . '%e -e %t' +endfunction + + call ale#linter#Define('go', { \ 'name': 'gofmt', \ 'output_stream': 'stderr', \ 'executable': 'gofmt', -\ 'command': 'gofmt -e %t', +\ 'command': function('ale_linters#go#gofmt#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) diff --git a/sources_non_forked/ale/ale_linters/go/golangci_lint.vim b/sources_non_forked/ale/ale_linters/go/golangci_lint.vim index 357f7949..dd0e975a 100644 --- a/sources_non_forked/ale/ale_linters/go/golangci_lint.vim +++ b/sources_non_forked/ale/ale_linters/go/golangci_lint.vim @@ -10,13 +10,16 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_golangci_lint_options') let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package') + if l:lint_package return ale#path#BufferCdString(a:buffer) + \ . ale#go#EnvString(a:buffer) \ . '%e run ' \ . l:options endif return ale#path#BufferCdString(a:buffer) + \ . ale#go#EnvString(a:buffer) \ . '%e run ' \ . ale#Escape(l:filename) \ . ' ' . l:options diff --git a/sources_non_forked/ale/ale_linters/go/golint.vim b/sources_non_forked/ale/ale_linters/go/golint.vim index 765e1477..79bfaeb5 100644 --- a/sources_non_forked/ale/ale_linters/go/golint.vim +++ b/sources_non_forked/ale/ale_linters/go/golint.vim @@ -7,7 +7,7 @@ call ale#Set('go_golint_options', '') function! ale_linters#go#golint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_golint_options') - return '%e' + return ale#go#EnvString(a:buffer) . '%e' \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' %t' endfunction diff --git a/sources_non_forked/ale/ale_linters/go/gometalinter.vim b/sources_non_forked/ale/ale_linters/go/gometalinter.vim index 19d70a81..eed9550a 100644 --- a/sources_non_forked/ale/ale_linters/go/gometalinter.vim +++ b/sources_non_forked/ale/ale_linters/go/gometalinter.vim @@ -14,11 +14,13 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort " be calculated to absolute paths in the Handler if l:lint_package return ale#path#BufferCdString(a:buffer) + \ . ale#go#EnvString(a:buffer) \ . '%e' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .' endif return ale#path#BufferCdString(a:buffer) + \ . ale#go#EnvString(a:buffer) \ . '%e' \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename)) \ . (!empty(l:options) ? ' ' . l:options : '') . ' .' diff --git a/sources_non_forked/ale/ale_linters/go/gopls.vim b/sources_non_forked/ale/ale_linters/go/gopls.vim index c411dc2b..dcff5ec7 100644 --- a/sources_non_forked/ale/ale_linters/go/gopls.vim +++ b/sources_non_forked/ale/ale_linters/go/gopls.vim @@ -6,11 +6,15 @@ call ale#Set('go_gopls_executable', 'gopls') call ale#Set('go_gopls_options', '--mode stdio') function! ale_linters#go#gopls#GetCommand(buffer) abort - return '%e' . ale#Pad(ale#Var(a:buffer, 'go_gopls_options')) + return ale#go#EnvString(a:buffer) + \ . '%e' + \ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options')) endfunction function! ale_linters#go#gopls#FindProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod') + let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off' + let l:project_root = l:go_modules_off ? + \ '' : ale#path#FindNearestFile(a:buffer, 'go.mod') let l:mods = ':h' if empty(l:project_root) diff --git a/sources_non_forked/ale/ale_linters/go/gosimple.vim b/sources_non_forked/ale/ale_linters/go/gosimple.vim index 281a0e53..ad52c621 100644 --- a/sources_non_forked/ale/ale_linters/go/gosimple.vim +++ b/sources_non_forked/ale/ale_linters/go/gosimple.vim @@ -2,7 +2,8 @@ " Description: gosimple for Go files function! ale_linters#go#gosimple#GetCommand(buffer) abort - return ale#path#BufferCdString(a:buffer) . ' gosimple .' + return ale#path#BufferCdString(a:buffer) . ' ' + \ . ale#go#EnvString(a:buffer) . 'gosimple .' endfunction call ale#linter#Define('go', { diff --git a/sources_non_forked/ale/ale_linters/go/gotype.vim b/sources_non_forked/ale/ale_linters/go/gotype.vim index d5d563aa..6a5149ca 100644 --- a/sources_non_forked/ale/ale_linters/go/gotype.vim +++ b/sources_non_forked/ale/ale_linters/go/gotype.vim @@ -6,7 +6,8 @@ function! ale_linters#go#gotype#GetCommand(buffer) abort return '' endif - return ale#path#BufferCdString(a:buffer) . ' gotype -e .' + return ale#path#BufferCdString(a:buffer) . ' ' + \ . ale#go#EnvString(a:buffer) . 'gotype -e .' endfunction call ale#linter#Define('go', { diff --git a/sources_non_forked/ale/ale_linters/go/govet.vim b/sources_non_forked/ale/ale_linters/go/govet.vim index bb81d5d0..dddafe17 100644 --- a/sources_non_forked/ale/ale_linters/go/govet.vim +++ b/sources_non_forked/ale/ale_linters/go/govet.vim @@ -11,6 +11,7 @@ function! ale_linters#go#govet#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_govet_options') return ale#path#BufferCdString(a:buffer) . ' ' + \ . ale#go#EnvString(a:buffer) \ . ale#Var(a:buffer, 'go_go_executable') . ' vet ' \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' .' diff --git a/sources_non_forked/ale/ale_linters/go/langserver.vim b/sources_non_forked/ale/ale_linters/go/langserver.vim index 776186c7..7130db40 100644 --- a/sources_non_forked/ale/ale_linters/go/langserver.vim +++ b/sources_non_forked/ale/ale_linters/go/langserver.vim @@ -15,8 +15,9 @@ function! ale_linters#go#langserver#GetCommand(buffer) abort endif let l:options = uniq(sort(l:options)) + let l:env = ale#go#EnvString(a:buffer) - return join(extend(l:executable, l:options), ' ') + return l:env . join(extend(l:executable, l:options), ' ') endfunction call ale#linter#Define('go', { diff --git a/sources_non_forked/ale/ale_linters/go/staticcheck.vim b/sources_non_forked/ale/ale_linters/go/staticcheck.vim index 26fe0193..ed40c6c2 100644 --- a/sources_non_forked/ale/ale_linters/go/staticcheck.vim +++ b/sources_non_forked/ale/ale_linters/go/staticcheck.vim @@ -8,17 +8,18 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort let l:filename = expand('#' . a:buffer . ':t') let l:options = ale#Var(a:buffer, 'go_staticcheck_options') let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package') + let l:env = ale#go#EnvString(a:buffer) " BufferCdString is used so that we can be sure the paths output from " staticcheck can be calculated to absolute paths in the Handler if l:lint_package return ale#path#BufferCdString(a:buffer) - \ . 'staticcheck' + \ . l:env . 'staticcheck' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .' endif return ale#path#BufferCdString(a:buffer) - \ . 'staticcheck' + \ . l:env . 'staticcheck' \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' ' . ale#Escape(l:filename) endfunction diff --git a/sources_non_forked/ale/ale_linters/java/checkstyle.vim b/sources_non_forked/ale/ale_linters/java/checkstyle.vim index 3159cd55..7901ff7e 100644 --- a/sources_non_forked/ale/ale_linters/java/checkstyle.vim +++ b/sources_non_forked/ale/ale_linters/java/checkstyle.vim @@ -1,6 +1,10 @@ " Author: Devon Meunier <devon.meunier@gmail.com> " Description: checkstyle for Java files +call ale#Set('java_checkstyle_executable', 'checkstyle') +call ale#Set('java_checkstyle_config', '/google_checks.xml') +call ale#Set('java_checkstyle_options', '') + function! ale_linters#java#checkstyle#Handle(buffer, lines) abort let l:output = [] @@ -17,6 +21,10 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort \}) endfor + if !empty(l:output) + return l:output + endif + " old checkstyle versions let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$' @@ -31,19 +39,32 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort return l:output endfunction +function! s:GetConfig(buffer, config) abort + if ale#path#IsAbsolute(a:config) + return a:config + endif + + let s:file = ale#path#FindNearestFile(a:buffer, a:config) + + return !empty(s:file) ? s:file : a:config +endfunction + function! ale_linters#java#checkstyle#GetCommand(buffer) abort - return 'checkstyle ' - \ . ale#Var(a:buffer, 'java_checkstyle_options') + let l:options = ale#Var(a:buffer, 'java_checkstyle_options') + let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config') + let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option) + \ ? s:GetConfig(a:buffer, l:config_option) + \ : '' + + return '%e' + \ . ale#Pad(l:options) + \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . ' %s' endfunction -if !exists('g:ale_java_checkstyle_options') - let g:ale_java_checkstyle_options = '-c /google_checks.xml' -endif - call ale#linter#Define('java', { \ 'name': 'checkstyle', -\ 'executable': 'checkstyle', +\ 'executable': {b -> ale#Var(b, 'java_checkstyle_executable')}, \ 'command': function('ale_linters#java#checkstyle#GetCommand'), \ 'callback': 'ale_linters#java#checkstyle#Handle', \ 'lint_file': 1, diff --git a/sources_non_forked/ale/ale_linters/java/eclipselsp.vim b/sources_non_forked/ale/ale_linters/java/eclipselsp.vim index d0ea9d6c..2648893b 100644 --- a/sources_non_forked/ale/ale_linters/java/eclipselsp.vim +++ b/sources_non_forked/ale/ale_linters/java/eclipselsp.vim @@ -4,6 +4,8 @@ let s:version_cache = {} call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls')) +call ale#Set('java_eclipselsp_config_path', '') +call ale#Set('java_eclipselsp_workspace_path', '') call ale#Set('java_eclipselsp_executable', 'java') function! ale_linters#java#eclipselsp#Executable(buffer) abort @@ -32,11 +34,23 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort return l:files[0] endif + " Search jar file within system package path + let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1) + + if len(l:files) == 1 + return l:files[0] + endif + return '' endfunction function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h') + let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path') + + if !empty(l:config_path) + return ale#path#Simplify(l:config_path) + endif if has('win32') let l:path = l:path . '/config_win' @@ -76,6 +90,16 @@ function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines, return ale_linters#java#eclipselsp#Command(a:buffer, l:version) endfunction +function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort + let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path') + + if !empty(l:wspath) + return l:wspath + endif + + return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer)) +endfunction + function! ale_linters#java#eclipselsp#Command(buffer, version) abort let l:path = ale#Var(a:buffer, 'java_eclipselsp_path') @@ -89,11 +113,11 @@ function! ale_linters#java#eclipselsp#Command(buffer, version) abort \ '-noverify', \ '-Xmx1G', \ '-jar', - \ ale_linters#java#eclipselsp#JarPath(a:buffer), + \ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)), \ '-configuration', - \ ale_linters#java#eclipselsp#ConfigurationPath(a:buffer), + \ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)), \ '-data', - \ ale#java#FindProjectRoot(a:buffer) + \ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer)) \ ] if ale#semver#GTE(a:version, [1, 9]) diff --git a/sources_non_forked/ale/ale_linters/java/javac.vim b/sources_non_forked/ale/ale_linters/java/javac.vim index 3883783b..8bb52c0b 100644 --- a/sources_non_forked/ale/ale_linters/java/javac.vim +++ b/sources_non_forked/ale/ale_linters/java/javac.vim @@ -21,6 +21,11 @@ function! ale_linters#java#javac#RunWithImportPaths(buffer) abort let l:command = ale#gradle#BuildClasspathCommand(a:buffer) endif + " Try to use Ant if Gradle and Maven aren't available + if empty(l:command) + let l:command = ale#ant#BuildClasspathCommand(a:buffer) + endif + if empty(l:command) return ale_linters#java#javac#GetCommand(a:buffer, [], {}) endif diff --git a/sources_non_forked/ale/ale_linters/java/javalsp.vim b/sources_non_forked/ale/ale_linters/java/javalsp.vim index a327363d..baf584c8 100644 --- a/sources_non_forked/ale/ale_linters/java/javalsp.vim +++ b/sources_non_forked/ale/ale_linters/java/javalsp.vim @@ -1,16 +1,47 @@ " Author: Horacio Sanson <https://github.com/hsanson> " Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac -call ale#Set('java_javalsp_executable', 'java') +call ale#Set('java_javalsp_executable', '') +call ale#Set('java_javalsp_config', {}) function! ale_linters#java#javalsp#Executable(buffer) abort return ale#Var(a:buffer, 'java_javalsp_executable') endfunction +function! ale_linters#java#javalsp#Config(buffer) abort + let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } } + let l:config = ale#Var(a:buffer, 'java_javalsp_config') + + " Ensure the config dictionary contains both classPath and + " externalDependencies keys to avoid a NPE crash on Java Language Server. + call extend(l:config, l:defaults, 'keep') + call extend(l:config['java'], l:defaults['java'], 'keep') + + return l:config +endfunction + function! ale_linters#java#javalsp#Command(buffer) abort let l:executable = ale_linters#java#javalsp#Executable(a:buffer) - return ale#Escape(l:executable) . ' -Xverify:none -m javacs/org.javacs.Main' + if fnamemodify(l:executable, ':t') is# 'java' + " For backward compatibility. + let l:cmd = [ + \ ale#Escape(l:executable), + \ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs', + \ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs', + \ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs', + \ '-m javacs/org.javacs.Main', + \] + + return join(l:cmd, ' ') + else + return ale#Escape(l:executable) + endif endfunction call ale#linter#Define('java', { @@ -20,4 +51,5 @@ call ale#linter#Define('java', { \ 'command': function('ale_linters#java#javalsp#Command'), \ 'language': 'java', \ 'project_root': function('ale#java#FindProjectRoot'), +\ 'lsp_config': function('ale_linters#java#javalsp#Config') \}) diff --git a/sources_non_forked/ale/ale_linters/javascript/eslint.vim b/sources_non_forked/ale/ale_linters/javascript/eslint.vim index 8aeac2d8..31fb413f 100644 --- a/sources_non_forked/ale/ale_linters/javascript/eslint.vim +++ b/sources_non_forked/ale/ale_linters/javascript/eslint.vim @@ -6,5 +6,5 @@ call ale#linter#Define('javascript', { \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'command': function('ale#handlers#eslint#GetCommand'), -\ 'callback': 'ale#handlers#eslint#Handle', +\ 'callback': 'ale#handlers#eslint#HandleJSON', \}) diff --git a/sources_non_forked/ale/ale_linters/javascript/xo.vim b/sources_non_forked/ale/ale_linters/javascript/xo.vim index 4ba39101..e24f4a82 100644 --- a/sources_non_forked/ale/ale_linters/javascript/xo.vim +++ b/sources_non_forked/ale/ale_linters/javascript/xo.vim @@ -14,7 +14,7 @@ endfunction function! ale_linters#javascript#xo#GetCommand(buffer) abort return ale#Escape(ale_linters#javascript#xo#GetExecutable(a:buffer)) \ . ' ' . ale#Var(a:buffer, 'javascript_xo_options') - \ . ' --reporter unix --stdin --stdin-filename %s' + \ . ' --reporter json --stdin --stdin-filename %s' endfunction " xo uses eslint and the output format is the same @@ -22,5 +22,5 @@ call ale#linter#Define('javascript', { \ 'name': 'xo', \ 'executable': function('ale_linters#javascript#xo#GetExecutable'), \ 'command': function('ale_linters#javascript#xo#GetCommand'), -\ 'callback': 'ale#handlers#eslint#Handle', +\ 'callback': 'ale#handlers#eslint#HandleJSON', \}) diff --git a/sources_non_forked/ale/ale_linters/objc/clangd.vim b/sources_non_forked/ale/ale_linters/objc/clangd.vim index ab52fec3..318d85b5 100644 --- a/sources_non_forked/ale/ale_linters/objc/clangd.vim +++ b/sources_non_forked/ale/ale_linters/objc/clangd.vim @@ -4,12 +4,6 @@ call ale#Set('objc_clangd_executable', 'clangd') call ale#Set('objc_clangd_options', '') -function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' -endfunction - function! ale_linters#objc#clangd#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options')) endfunction @@ -19,5 +13,5 @@ call ale#linter#Define('objc', { \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')}, \ 'command': function('ale_linters#objc#clangd#GetCommand'), -\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'), +\ 'project_root': function('ale#c#FindProjectRoot'), \}) diff --git a/sources_non_forked/ale/ale_linters/objcpp/clangd.vim b/sources_non_forked/ale/ale_linters/objcpp/clangd.vim index 3991d2ac..29455325 100644 --- a/sources_non_forked/ale/ale_linters/objcpp/clangd.vim +++ b/sources_non_forked/ale/ale_linters/objcpp/clangd.vim @@ -4,12 +4,6 @@ call ale#Set('objcpp_clangd_executable', 'clangd') call ale#Set('objcpp_clangd_options', '') -function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') - - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' -endfunction - function! ale_linters#objcpp#clangd#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options')) endfunction @@ -19,5 +13,5 @@ call ale#linter#Define('objcpp', { \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')}, \ 'command': function('ale_linters#objcpp#clangd#GetCommand'), -\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'), +\ 'project_root': function('ale#c#FindProjectRoot'), \}) diff --git a/sources_non_forked/ale/ale_linters/php/phpcs.vim b/sources_non_forked/ale/ale_linters/php/phpcs.vim index 1c92bbb2..11b81e84 100644 --- a/sources_non_forked/ale/ale_linters/php/phpcs.vim +++ b/sources_non_forked/ale/ale_linters/php/phpcs.vim @@ -10,13 +10,13 @@ call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#php#phpcs#GetCommand(buffer) abort let l:standard = ale#Var(a:buffer, 'php_phpcs_standard') let l:standard_option = !empty(l:standard) - \ ? '--standard=' . l:standard + \ ? '--standard=' . ale#Escape(l:standard) \ : '' - let l:options = ale#Var(a:buffer, 'php_phpcs_options') - return '%e -s --report=emacs --stdin-path=%s' - \ . ale#Pad(l:standard_option) - \ . ale#Pad(l:options) + return ale#path#BufferCdString(a:buffer) + \ . '%e -s --report=emacs --stdin-path=%s' + \ . ale#Pad(l:standard_option) + \ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options')) endfunction function! ale_linters#php#phpcs#Handle(buffer, lines) abort @@ -36,6 +36,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort \ 'col': l:match[2] + 0, \ 'text': l:text, \ 'type': l:type is# 'error' ? 'E' : 'W', + \ 'sub_type': 'style', \}) endfor diff --git a/sources_non_forked/ale/ale_linters/powershell/powershell.vim b/sources_non_forked/ale/ale_linters/powershell/powershell.vim index 51ded71d..a63191fd 100644 --- a/sources_non_forked/ale/ale_linters/powershell/powershell.vim +++ b/sources_non_forked/ale/ale_linters/powershell/powershell.vim @@ -49,11 +49,19 @@ function! ale_linters#powershell#powershell#Handle(buffer, lines) abort let l:matchcount = 1 endif - let l:item = { - \ 'lnum': str2nr(l:match[1]), - \ 'col': str2nr(l:match[2]), - \ 'type': 'E', - \} + " If the match is 0, it was a failed match + " probably due to an unexpected token which + " contained a newline. Reset matchcount. to + " continue to the next match + if !empty(l:match[1]) + let l:item = { + \ 'lnum': str2nr(l:match[1]), + \ 'col': str2nr(l:match[2]), + \ 'type': 'E', + \} + else + let l:matchcount = 0 + endif elseif l:matchcount == 2 " Second match[0] grabs the full line in order " to handles the text @@ -84,8 +92,8 @@ endfunction call ale#linter#Define('powershell', { \ 'name': 'powershell', -\ 'executable_callback': 'ale_linters#powershell#powershell#GetExecutable', -\ 'command_callback': 'ale_linters#powershell#powershell#GetCommand', +\ 'executable': function('ale_linters#powershell#powershell#GetExecutable'), +\ 'command': function('ale_linters#powershell#powershell#GetCommand'), \ 'output_stream': 'stdout', \ 'callback': 'ale_linters#powershell#powershell#Handle', \}) diff --git a/sources_non_forked/ale/ale_linters/pug/puglint.vim b/sources_non_forked/ale/ale_linters/pug/puglint.vim index c4e0e233..c819cc45 100644 --- a/sources_non_forked/ale/ale_linters/pug/puglint.vim +++ b/sources_non_forked/ale/ale_linters/pug/puglint.vim @@ -31,6 +31,20 @@ function! ale_linters#pug#puglint#GetCommand(buffer) abort \ . ' -r inline %t' endfunction +function! ale_linters#pug#puglint#Handle(buffer, lines) abort + for l:line in a:lines[:10] + if l:line =~# '^SyntaxError: ' + return [{ + \ 'lnum': 1, + \ 'text': 'puglint configuration error (type :ALEDetail for more information)', + \ 'detail': join(a:lines, "\n"), + \}] + endif + endfor + + return ale#handlers#unix#HandleAsError(a:buffer, a:lines) +endfunction + call ale#linter#Define('pug', { \ 'name': 'puglint', \ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [ @@ -38,5 +52,5 @@ call ale#linter#Define('pug', { \ ])}, \ 'output_stream': 'stderr', \ 'command': function('ale_linters#pug#puglint#GetCommand'), -\ 'callback': 'ale#handlers#unix#HandleAsError', +\ 'callback': 'ale_linters#pug#puglint#Handle', \}) diff --git a/sources_non_forked/ale/ale_linters/purescript/ls.vim b/sources_non_forked/ale/ale_linters/purescript/ls.vim new file mode 100644 index 00000000..1c5f937f --- /dev/null +++ b/sources_non_forked/ale/ale_linters/purescript/ls.vim @@ -0,0 +1,49 @@ +" Author: Drew Olson <drew@drewolson.org> +" Description: Integrate ALE with purescript-language-server. + +call ale#Set('purescript_ls_executable', 'purescript-language-server') +call ale#Set('purescript_ls_use_global', get(g:, 'ale_use_global_executables', 0)) +call ale#Set('purescript_ls_config', {}) + +function! ale_linters#purescript#ls#GetExecutable(buffer) abort + return ale#node#FindExecutable(a:buffer, 'purescript_ls', [ + \ 'node_modules/.bin/purescript-language-server', + \]) +endfunction + +function! ale_linters#purescript#ls#GetCommand(buffer) abort + let l:executable = ale_linters#purescript#ls#GetExecutable(a:buffer) + + return ale#Escape(l:executable) . ' --stdio' +endfunction + +function! ale_linters#purescript#ls#FindProjectRoot(buffer) abort + let l:config = ale#path#FindNearestFile(a:buffer, 'bower.json') + + if !empty(l:config) + return fnamemodify(l:config, ':h') + endif + + let l:config = ale#path#FindNearestFile(a:buffer, 'psc-package.json') + + if !empty(l:config) + return fnamemodify(l:config, ':h') + endif + + let l:config = ale#path#FindNearestFile(a:buffer, 'spago.dhall') + + if !empty(l:config) + return fnamemodify(l:config, ':h') + endif + + return '' +endfunction + +call ale#linter#Define('purescript', { +\ 'name': 'purescript-language-server', +\ 'lsp': 'stdio', +\ 'executable': function('ale_linters#purescript#ls#GetExecutable'), +\ 'command': function('ale_linters#purescript#ls#GetCommand'), +\ 'project_root': function('ale_linters#purescript#ls#FindProjectRoot'), +\ 'lsp_config': {b -> ale#Var(b, 'purescript_ls_config')}, +\}) diff --git a/sources_non_forked/ale/ale_linters/python/mypy.vim b/sources_non_forked/ale/ale_linters/python/mypy.vim index c4c6507f..dc4044e6 100644 --- a/sources_non_forked/ale/ale_linters/python/mypy.vim +++ b/sources_non_forked/ale/ale_linters/python/mypy.vim @@ -78,4 +78,5 @@ call ale#linter#Define('python', { \ 'executable': function('ale_linters#python#mypy#GetExecutable'), \ 'command': function('ale_linters#python#mypy#GetCommand'), \ 'callback': 'ale_linters#python#mypy#Handle', +\ 'output_stream': 'both' \}) diff --git a/sources_non_forked/ale/ale_linters/reason/ls.vim b/sources_non_forked/ale/ale_linters/reason/ls.vim new file mode 100644 index 00000000..fb1114ae --- /dev/null +++ b/sources_non_forked/ale/ale_linters/reason/ls.vim @@ -0,0 +1,23 @@ +" Author: David Buchan-Swanson <github@deecewan.com> +" Description: Integrate ALE with reason-language-server. + +call ale#Set('reason_ls_executable', '') + +function! ale_linters#reason#ls#FindProjectRoot(buffer) abort + let l:reason_config = ale#path#FindNearestFile(a:buffer, 'bsconfig.json') + + if !empty(l:reason_config) + return fnamemodify(l:reason_config, ':h') + endif + + return '' +endfunction + +call ale#linter#Define('reason', { +\ 'name': 'reason-language-server', +\ 'lsp': 'stdio', +\ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')}, +\ 'command': '%e', +\ 'project_root': function('ale_linters#reason#ls#FindProjectRoot'), +\ 'language': 'reason', +\}) diff --git a/sources_non_forked/ale/ale_linters/ruby/sorbet.vim b/sources_non_forked/ale/ale_linters/ruby/sorbet.vim new file mode 100644 index 00000000..ee765a6e --- /dev/null +++ b/sources_non_forked/ale/ale_linters/ruby/sorbet.vim @@ -0,0 +1,23 @@ +call ale#Set('ruby_sorbet_executable', 'srb') +call ale#Set('ruby_sorbet_options', '') + +function! ale_linters#ruby#sorbet#GetCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') + let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') + + return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb') + \ . ' tc' + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . ' --lsp --disable-watchman' +endfunction + +call ale#linter#Define('ruby', { +\ 'name': 'sorbet', +\ 'aliases': ['srb'], +\ 'lsp': 'stdio', +\ 'language': 'ruby', +\ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')}, +\ 'command': function('ale_linters#ruby#sorbet#GetCommand'), +\ 'project_root': function('ale#ruby#FindProjectRoot') +\}) + diff --git a/sources_non_forked/ale/ale_linters/rust/cargo.vim b/sources_non_forked/ale/ale_linters/rust/cargo.vim index f98dee9b..99178585 100644 --- a/sources_non_forked/ale/ale_linters/rust/cargo.vim +++ b/sources_non_forked/ale/ale_linters/rust/cargo.vim @@ -25,14 +25,11 @@ endfunction function! ale_linters#rust#cargo#GetCommand(buffer, version) abort let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') \ && ale#semver#GTE(a:version, [0, 17, 0]) - let l:use_all_targets = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_all_targets') + let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets') \ && ale#semver#GTE(a:version, [0, 22, 0]) - let l:use_examples = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_examples') + let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples') \ && ale#semver#GTE(a:version, [0, 22, 0]) - let l:use_tests = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_tests') + let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests') \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') @@ -69,7 +66,15 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort if ale#Var(a:buffer, 'rust_cargo_use_clippy') let l:subcommand = 'clippy' - let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options') + let l:clippy_options = ale#Var(a:buffer, 'rust_cargo_clippy_options') + + if l:clippy_options =~# '^-- ' + let l:clippy_options = join(split(l:clippy_options, '-- ')) + endif + + if l:clippy_options isnot# '' + let l:clippy_options = ' -- ' . l:clippy_options + endif endif return l:nearest_cargo_prefix . 'cargo ' diff --git a/sources_non_forked/ale/ale_linters/terraform/terraform.vim b/sources_non_forked/ale/ale_linters/terraform/terraform.vim new file mode 100644 index 00000000..0429cb7a --- /dev/null +++ b/sources_non_forked/ale/ale_linters/terraform/terraform.vim @@ -0,0 +1,49 @@ +" Author: Keith Maxwell <keith.maxwell@gmail.com> +" Description: terraform fmt to check for errors + +call ale#Set('terraform_terraform_executable', 'terraform') + +function! ale_linters#terraform#terraform#GetExecutable(buffer) abort + return ale#Var(a:buffer, 'terraform_terraform_executable') +endfunction + +function! ale_linters#terraform#terraform#GetCommand(buffer) abort + return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer)) + \ . ' fmt -no-color --check=true -' +endfunction + +function! ale_linters#terraform#terraform#Handle(buffer, lines) abort + let l:head = '^Error running fmt: In <standard input>: ' + let l:output = [] + let l:patterns = [ + \ l:head.'At \(\d\+\):\(\d\+\): \(.*\)$', + \ l:head.'\(.*\)$' + \] + + for l:match in ale#util#GetMatches(a:lines, l:patterns) + if len(l:match[2]) > 0 + call add(l:output, { + \ 'lnum': str2nr(l:match[1]), + \ 'col': str2nr(l:match[2]), + \ 'text': l:match[3], + \ 'type': 'E', + \}) + else + call add(l:output, { + \ 'lnum': line('$'), + \ 'text': l:match[1], + \ 'type': 'E', + \}) + endif + endfor + + return l:output +endfunction + +call ale#linter#Define('terraform', { +\ 'name': 'terraform', +\ 'output_stream': 'stderr', +\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'), +\ 'command': function('ale_linters#terraform#terraform#GetCommand'), +\ 'callback': 'ale_linters#terraform#terraform#Handle', +\}) diff --git a/sources_non_forked/ale/ale_linters/tex/texlab.vim b/sources_non_forked/ale/ale_linters/tex/texlab.vim new file mode 100644 index 00000000..5ead74b4 --- /dev/null +++ b/sources_non_forked/ale/ale_linters/tex/texlab.vim @@ -0,0 +1,21 @@ +" Author: Ricardo Liang <ricardoliang@gmail.com> +" Description: Texlab language server (Rust rewrite) + +call ale#Set('tex_texlab_executable', 'texlab') +call ale#Set('tex_texlab_options', '') + +function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort + return '' +endfunction + +function! ale_linters#tex#texlab#GetCommand(buffer) abort + return '%e' . ale#Pad(ale#Var(a:buffer, 'tex_texlab_options')) +endfunction + +call ale#linter#Define('tex', { +\ 'name': 'texlab', +\ 'lsp': 'stdio', +\ 'executable': {b -> ale#Var(b, 'tex_texlab_executable')}, +\ 'command': function('ale_linters#tex#texlab#GetCommand'), +\ 'project_root': function('ale_linters#tex#texlab#GetProjectRoot'), +\}) diff --git a/sources_non_forked/ale/ale_linters/typescript/eslint.vim b/sources_non_forked/ale/ale_linters/typescript/eslint.vim index bf849337..33a21440 100644 --- a/sources_non_forked/ale/ale_linters/typescript/eslint.vim +++ b/sources_non_forked/ale/ale_linters/typescript/eslint.vim @@ -5,5 +5,5 @@ call ale#linter#Define('typescript', { \ 'name': 'eslint', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'command': function('ale#handlers#eslint#GetCommand'), -\ 'callback': 'ale#handlers#eslint#Handle', +\ 'callback': 'ale#handlers#eslint#HandleJSON', \}) diff --git a/sources_non_forked/ale/ale_linters/typescript/xo.vim b/sources_non_forked/ale/ale_linters/typescript/xo.vim index 8b015efd..0a3a717b 100644 --- a/sources_non_forked/ale/ale_linters/typescript/xo.vim +++ b/sources_non_forked/ale/ale_linters/typescript/xo.vim @@ -11,7 +11,7 @@ endfunction function! ale_linters#typescript#xo#GetCommand(buffer) abort return ale#Escape(ale_linters#typescript#xo#GetExecutable(a:buffer)) \ . ale#Pad(ale#Var(a:buffer, 'typescript_xo_options')) - \ . ' --reporter unix --stdin --stdin-filename %s' + \ . ' --reporter json --stdin --stdin-filename %s' endfunction " xo uses eslint and the output format is the same @@ -19,5 +19,5 @@ call ale#linter#Define('typescript', { \ 'name': 'xo', \ 'executable': function('ale_linters#typescript#xo#GetExecutable'), \ 'command': function('ale_linters#typescript#xo#GetCommand'), -\ 'callback': 'ale#handlers#eslint#Handle', +\ 'callback': 'ale#handlers#eslint#HandleJSON', \}) diff --git a/sources_non_forked/ale/autoload/ale.vim b/sources_non_forked/ale/autoload/ale.vim index 04329dfd..3a4e79c8 100644 --- a/sources_non_forked/ale/autoload/ale.vim +++ b/sources_non_forked/ale/autoload/ale.vim @@ -156,7 +156,7 @@ function! ale#Queue(delay, ...) abort endif endfunction -let s:current_ale_version = [2, 4, 0] +let s:current_ale_version = [2, 5, 0] " A function used to check for ALE features in files outside of the project. function! ale#Has(feature) abort diff --git a/sources_non_forked/ale/autoload/ale/ant.vim b/sources_non_forked/ale/autoload/ale/ant.vim new file mode 100644 index 00000000..689b444b --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/ant.vim @@ -0,0 +1,41 @@ +" Author: Andrew Lee <andrewl@mbda.fun>. +" Inspired by ale/gradle.vim by Michael Pardo <michael@michaelpardo.com> +" Description: Functions for working with Ant projects. + +" Given a buffer number, find an Ant project root +function! ale#ant#FindProjectRoot(buffer) abort + let l:build_xml_path = ale#path#FindNearestFile(a:buffer, 'build.xml') + + if !empty(l:build_xml_path) + return fnamemodify(l:build_xml_path, ':h') + endif + + return '' +endfunction + +" Given a buffer number, find the path to the `ant` executable. Returns an empty +" string if cannot find the executable. +function! ale#ant#FindExecutable(buffer) abort + if executable('ant') + return 'ant' + endif + + return '' +endfunction + +" Given a buffer number, build a command to print the classpath of the root +" project. Returns an empty string if cannot build the command. +function! ale#ant#BuildClasspathCommand(buffer) abort + let l:executable = ale#ant#FindExecutable(a:buffer) + let l:project_root = ale#ant#FindProjectRoot(a:buffer) + + if !empty(l:executable) && !empty(l:project_root) + return ale#path#CdString(l:project_root) + \ . ale#Escape(l:executable) + \ . ' classpath' + \ . ' -S' + \ . ' -q' + endif + + return '' +endfunction diff --git a/sources_non_forked/ale/autoload/ale/assert.vim b/sources_non_forked/ale/autoload/ale/assert.vim index ed90792d..dac5efb7 100644 --- a/sources_non_forked/ale/autoload/ale/assert.vim +++ b/sources_non_forked/ale/autoload/ale/assert.vim @@ -96,6 +96,13 @@ function! ale#assert#Fixer(expected_result) abort AssertEqual a:expected_result, l:result endfunction +function! ale#assert#FixerNotExecuted() abort + let l:buffer = bufnr('') + let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1] + + Assert empty(l:result), "The fixer will be executed when it shouldn't be" +endfunction + function! ale#assert#LinterNotExecuted() abort let l:buffer = bufnr('') let l:linter = s:GetLinter() @@ -158,6 +165,7 @@ endfunction function! ale#assert#SetUpFixerTestCommands() abort command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>) command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>) + command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted() endfunction " A dummy function for making sure this module is loaded. @@ -316,4 +324,8 @@ function! ale#assert#TearDownFixerTest() abort if exists(':AssertFixer') delcommand AssertFixer endif + + if exists(':AssertFixerNotExecuted') + delcommand AssertFixerNotExecuted + endif endfunction diff --git a/sources_non_forked/ale/autoload/ale/c.vim b/sources_non_forked/ale/autoload/ale/c.vim index a9289e22..5540ec14 100644 --- a/sources_non_forked/ale/autoload/ale/c.vim +++ b/sources_non_forked/ale/autoload/ale/c.vim @@ -23,104 +23,117 @@ function! ale#c#GetBuildDirectory(buffer) abort return l:build_dir endif - return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) + let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) + + return ale#path#Dirname(l:json_file) endfunction - -function! ale#c#FindProjectRoot(buffer) abort - for l:project_filename in g:__ale_c_project_filenames - let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename) - - if !empty(l:full_path) - let l:path = fnamemodify(l:full_path, ':h') - - " Correct .git path detection. - if fnamemodify(l:path, ':t') is# '.git' - let l:path = fnamemodify(l:path, ':h') - endif - - return l:path - endif - endfor - - return '' -endfunction - -function! ale#c#AreSpecialCharsBalanced(option) abort - " Escape \" - let l:option_escaped = substitute(a:option, '\\"', '', 'g') - - " Retain special chars only - let l:special_chars = substitute(l:option_escaped, '[^"''()`]', '', 'g') - let l:special_chars = split(l:special_chars, '\zs') - - " Check if they are balanced +function! ale#c#ShellSplit(line) abort let l:stack = [] + let l:args = [''] + let l:prev = '' - for l:char in l:special_chars - if l:char is# ')' - if len(l:stack) == 0 || get(l:stack, -1) isnot# '(' - return 0 - endif - - call remove(l:stack, -1) - elseif l:char is# '(' - call add(l:stack, l:char) - else - if len(l:stack) > 0 && get(l:stack, -1) is# l:char + for l:char in split(a:line, '\zs') + if l:char is# '''' + if len(l:stack) > 0 && get(l:stack, -1) is# '''' call remove(l:stack, -1) - else + elseif (len(l:stack) == 0 || get(l:stack, -1) isnot# '"') && l:prev isnot# '\' call add(l:stack, l:char) endif + elseif (l:char is# '"' || l:char is# '`') && l:prev isnot# '\' + if len(l:stack) > 0 && get(l:stack, -1) is# l:char + call remove(l:stack, -1) + elseif len(l:stack) == 0 || get(l:stack, -1) isnot# '''' + call add(l:stack, l:char) + endif + elseif (l:char is# '(' || l:char is# '[' || l:char is# '{') && l:prev isnot# '\' + if len(l:stack) == 0 || get(l:stack, -1) isnot# '''' + call add(l:stack, l:char) + endif + elseif (l:char is# ')' || l:char is# ']' || l:char is# '}') && l:prev isnot# '\' + if len(l:stack) > 0 && get(l:stack, -1) is# {')': '(', ']': '[', '}': '{'}[l:char] + call remove(l:stack, -1) + endif + elseif l:char is# ' ' && len(l:stack) == 0 + if len(get(l:args, -1)) > 0 + call add(l:args, '') + endif + + continue endif + + let l:args[-1] = get(l:args, -1) . l:char endfor - return len(l:stack) == 0 + return l:args endfunction function! ale#c#ParseCFlags(path_prefix, cflag_line) abort - let l:split_lines = split(a:cflag_line) + let l:cflags_list = [] + + let l:split_lines = ale#c#ShellSplit(a:cflag_line) let l:option_index = 0 while l:option_index < len(l:split_lines) - let l:next_option_index = l:option_index + 1 - - " Join space-separated option - while l:next_option_index < len(l:split_lines) - \&& stridx(l:split_lines[l:next_option_index], '-') != 0 - let l:next_option_index += 1 - endwhile - - let l:option = join(l:split_lines[l:option_index : l:next_option_index-1], ' ') - call remove(l:split_lines, l:option_index, l:next_option_index-1) - call insert(l:split_lines, l:option, l:option_index) - - " Ignore invalid or conflicting options - if stridx(l:option, '-') != 0 - \|| stridx(l:option, '-o') == 0 - \|| stridx(l:option, '-c') == 0 - call remove(l:split_lines, l:option_index) - let l:option_index = l:option_index - 1 - " Fix relative path - elseif stridx(l:option, '-I') == 0 - if !(stridx(l:option, ':') == 2+1 || stridx(l:option, '/') == 2+0) - let l:option = '-I' . a:path_prefix . s:sep . l:option[2:] - call remove(l:split_lines, l:option_index) - call insert(l:split_lines, l:option, l:option_index) - endif - endif - + let l:option = l:split_lines[l:option_index] let l:option_index = l:option_index + 1 + + " Include options, that may need relative path fix + if stridx(l:option, '-I') == 0 + \ || stridx(l:option, '-iquote') == 0 + \ || stridx(l:option, '-isystem') == 0 + \ || stridx(l:option, '-idirafter') == 0 + if stridx(l:option, '-I') == 0 && l:option isnot# '-I' + let l:arg = join(split(l:option, '\zs')[2:], '') + let l:option = '-I' + else + let l:arg = l:split_lines[l:option_index] + let l:option_index = l:option_index + 1 + endif + + " Fix relative paths if needed + if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0 + let l:rel_path = substitute(l:arg, '"', '', 'g') + let l:rel_path = substitute(l:rel_path, '''', '', 'g') + let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path) + endif + + call add(l:cflags_list, l:option) + call add(l:cflags_list, l:arg) + " Options with arg that can be grouped with the option or separate + elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0 + call add(l:cflags_list, l:option) + + if l:option is# '-D' || l:option is# '-B' + call add(l:cflags_list, l:split_lines[l:option_index]) + let l:option_index = l:option_index + 1 + endif + " Options that have an argument (always separate) + elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0 + \ || l:option is# '-isysroot' || l:option is# '-imultilib' + call add(l:cflags_list, l:option) + call add(l:cflags_list, l:split_lines[l:option_index]) + let l:option_index = l:option_index + 1 + " Options without argument + elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0) + \ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0 + \ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0 + \ || (stridx(l:option, '-f') == 0 && stridx(l:option, '-fdump') != 0 && stridx(l:option, '-fdiagnostics') != 0 && stridx(l:option, '-fno-show-column') != 0) + \ || stridx(l:option, '-O') == 0 + \ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs' + \ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0 + \ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix' + \ || stridx(l:option, '-m') == 0 + call add(l:cflags_list, l:option) + endif endwhile - call uniq(l:split_lines) - - return join(l:split_lines, ' ') + return join(l:cflags_list, ' ') endfunction function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort if !g:ale_c_parse_makefile - return '' + return v:null endif let l:buffer_filename = expand('#' . a:buffer . ':t') @@ -140,14 +153,17 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line) endfunction -" Given a buffer number, find the build subdirectory with compile commands -" The subdirectory is returned without the trailing / +" Given a buffer number, find the project directory containing +" compile_commands.json, and the path to the compile_commands.json file. +" +" If compile_commands.json cannot be found, two empty strings will be +" returned. function! ale#c#FindCompileCommands(buffer) abort " Look above the current source file to find compile_commands.json let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') if !empty(l:json_file) - return l:json_file + return [fnamemodify(l:json_file, ':h'), l:json_file] endif " Search in build directories if we can't find it in the project. @@ -157,12 +173,42 @@ function! ale#c#FindCompileCommands(buffer) abort let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json' if filereadable(l:json_file) - return l:json_file + return [l:path, l:json_file] endif endfor endfor - return '' + return ['', ''] +endfunction + +" Find the project root for C/C++ projects. +" +" The location of compile_commands.json will be used to find project roots. +" +" If compile_commands.json cannot be found, other common configuration files +" will be used to detect the project root. +function! ale#c#FindProjectRoot(buffer) abort + let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) + + " Fall back on detecting the project root based on other filenames. + if empty(l:root) + for l:project_filename in g:__ale_c_project_filenames + let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename) + + if !empty(l:full_path) + let l:path = fnamemodify(l:full_path, ':h') + + " Correct .git path detection. + if fnamemodify(l:path, ':t') is# '.git' + let l:path = fnamemodify(l:path, ':h') + endif + + return l:path + endif + endfor + endif + + return l:root endfunction " Cache compile_commands.json data in a Dictionary, so we don't need to read @@ -194,10 +240,14 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort let l:raw_data = [] silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), '')) + if type(l:raw_data) isnot v:t_list + let l:raw_data = [] + endif + let l:file_lookup = {} let l:dir_lookup = {} - for l:entry in l:raw_data + for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : []) let l:basename = tolower(fnamemodify(l:entry.file, ':t')) let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] @@ -274,25 +324,25 @@ function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort endfunction function! ale#c#GetCFlags(buffer, output) abort - let l:cflags = ' ' + let l:cflags = v:null if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output) let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output) endif if ale#Var(a:buffer, 'c_parse_compile_commands') - let l:json_file = ale#c#FindCompileCommands(a:buffer) + let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) if !empty(l:json_file) let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file) endif endif - if l:cflags is# ' ' + if l:cflags is v:null let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) endif - return l:cflags + return l:cflags isnot v:null ? l:cflags : '' endfunction function! ale#c#GetMakeCommand(buffer) abort diff --git a/sources_non_forked/ale/autoload/ale/completion.vim b/sources_non_forked/ale/autoload/ale/completion.vim index 03cc6471..ebf32909 100644 --- a/sources_non_forked/ale/autoload/ale/completion.vim +++ b/sources_non_forked/ale/autoload/ale/completion.vim @@ -52,6 +52,7 @@ let s:should_complete_map = { \ 'lisp': s:lisp_regex, \ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$', \ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$', +\ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$', \} " Regular expressions for finding the start column to replace with completion. @@ -59,11 +60,13 @@ let s:omni_start_map = { \ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$', \} -" A map of exact characters for triggering LSP completions. +" A map of exact characters for triggering LSP completions. Do not forget to +" update self.input_patterns in ale.py in updating entries in this map. let s:trigger_character_map = { \ '<default>': ['.'], \ 'typescript': ['.', '''', '"'], \ 'rust': ['.', '::'], +\ 'cpp': ['.', '::', '->'], \} function! s:GetFiletypeValue(map, filetype) abort @@ -169,7 +172,7 @@ function! s:ReplaceCompletionOptions() abort let b:ale_old_omnifunc = &l:omnifunc endif - let &l:omnifunc = 'ale#completion#OmniFunc' + let &l:omnifunc = 'ale#completion#AutomaticOmniFunc' endif if l:source is# 'ale-automatic' @@ -215,19 +218,11 @@ function! ale#completion#GetCompletionPosition() abort return l:column - len(l:match) - 1 endfunction +function! ale#completion#GetCompletionPositionForDeoplete(input) abort + return match(a:input, '\k*$') +endfunction + function! ale#completion#GetCompletionResult() abort - " Parse a new response if there is one. - if exists('b:ale_completion_response') - \&& exists('b:ale_completion_parser') - let l:response = b:ale_completion_response - let l:parser = b:ale_completion_parser - - unlet b:ale_completion_response - unlet b:ale_completion_parser - - let b:ale_completion_result = function(l:parser)(l:response) - endif - if exists('b:ale_completion_result') return b:ale_completion_result endif @@ -235,7 +230,7 @@ function! ale#completion#GetCompletionResult() abort return v:null endfunction -function! ale#completion#OmniFunc(findstart, base) abort +function! ale#completion#AutomaticOmniFunc(findstart, base) abort if a:findstart return ale#completion#GetCompletionPosition() else @@ -247,15 +242,20 @@ function! ale#completion#OmniFunc(findstart, base) abort endif endfunction -function! ale#completion#Show(response, completion_parser) abort +function! ale#completion#Show(result) abort if ale#util#Mode() isnot# 'i' return endif " Set the list in the buffer, temporarily replace omnifunc with our " function, and then start omni-completion. - let b:ale_completion_response = a:response - let b:ale_completion_parser = a:completion_parser + let b:ale_completion_result = a:result + + " Don't try to open the completion menu if there's nothing to show. + if empty(b:ale_completion_result) + return + endif + " Replace completion options shortly before opening the menu. call s:ReplaceCompletionOptions() @@ -267,6 +267,14 @@ function! ale#completion#Show(response, completion_parser) abort \ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")} \) endif + + if l:source is# 'ale-callback' + call b:CompleteCallback(b:ale_completion_result) + endif +endfunction + +function! ale#completion#GetAllTriggers() abort + return deepcopy(s:trigger_character_map) endfunction function! s:CompletionStillValid(request_id) abort @@ -279,6 +287,8 @@ function! s:CompletionStillValid(request_id) abort \&& ( \ b:ale_completion_info.column == l:column \ || b:ale_completion_info.source is# 'deoplete' + \ || b:ale_completion_info.source is# 'ale-omnifunc' + \ || b:ale_completion_info.source is# 'ale-callback' \) endfunction @@ -474,8 +484,7 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort endif elseif l:command is# 'completionEntryDetails' call ale#completion#Show( - \ a:response, - \ 'ale#completion#ParseTSServerCompletionEntryDetails', + \ ale#completion#ParseTSServerCompletionEntryDetails(a:response), \) endif endfunction @@ -487,8 +496,7 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort endif call ale#completion#Show( - \ a:response, - \ 'ale#completion#ParseLSPCompletions', + \ ale#completion#ParseLSPCompletions(a:response), \) endfunction @@ -529,10 +537,7 @@ function! s:OnReady(linter, lsp_details) abort let l:message = ale#lsp#message#Completion( \ l:buffer, \ b:ale_completion_info.line, - \ min([ - \ b:ale_completion_info.line_length, - \ b:ale_completion_info.column, - \ ]) + 1, + \ b:ale_completion_info.column, \ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix), \) endif @@ -564,13 +569,26 @@ endfunction " This function can be used to manually trigger autocomplete, even when " g:ale_completion_enabled is set to false -function! ale#completion#GetCompletions(source) abort +function! ale#completion#GetCompletions(...) abort + let l:source = get(a:000, 0, '') + let l:options = get(a:000, 1, {}) + + if len(a:000) > 2 + throw 'Too many arguments!' + endif + + let l:CompleteCallback = get(l:options, 'callback', v:null) + + if l:CompleteCallback isnot v:null + let b:CompleteCallback = l:CompleteCallback + endif + let [l:line, l:column] = getpos('.')[1:2] let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) - if a:source is# 'ale-automatic' && empty(l:prefix) - return + if l:source is# 'ale-automatic' && empty(l:prefix) + return 0 endif let l:line_length = len(getline('.')) @@ -582,18 +600,47 @@ function! ale#completion#GetCompletions(source) abort \ 'prefix': l:prefix, \ 'conn_id': 0, \ 'request_id': 0, - \ 'source': a:source, + \ 'source': l:source, \} unlet! b:ale_completion_result let l:buffer = bufnr('') let l:Callback = function('s:OnReady') + let l:started = 0 + for l:linter in ale#linter#Get(&filetype) if !empty(l:linter.lsp) - call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) + if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) + let l:started = 1 + endif endif endfor + + return l:started +endfunction + +function! ale#completion#OmniFunc(findstart, base) abort + if a:findstart + let l:started = ale#completion#GetCompletions('ale-omnifunc') + + if !l:started + " This is the special value for cancelling completions silently. + " See :help complete-functions + return -3 + endif + + return ale#completion#GetCompletionPosition() + else + let l:result = ale#completion#GetCompletionResult() + + while l:result is v:null && !complete_check() + sleep 2ms + let l:result = ale#completion#GetCompletionResult() + endwhile + + return l:result isnot v:null ? l:result : [] + endif endfunction function! s:TimerHandler(...) abort diff --git a/sources_non_forked/ale/autoload/ale/debugging.vim b/sources_non_forked/ale/autoload/ale/debugging.vim index e4bf5e7e..379c0d73 100644 --- a/sources_non_forked/ale/autoload/ale/debugging.vim +++ b/sources_non_forked/ale/autoload/ale/debugging.vim @@ -62,7 +62,7 @@ function! s:Echo(message) abort execute 'echo a:message' endfunction -function! s:GetLinterVariables(filetype, linter_names) abort +function! s:GetLinterVariables(filetype, exclude_linter_names) abort let l:variable_list = [] let l:filetype_parts = split(a:filetype, '\.') @@ -73,7 +73,7 @@ function! s:GetLinterVariables(filetype, linter_names) abort " Include matching variables. if !empty(l:match) \&& index(l:filetype_parts, l:match[1]) >= 0 - \&& index(a:linter_names, l:match[2]) >= 0 + \&& index(a:exclude_linter_names, l:match[2]) == -1 call add(l:variable_list, l:key) endif endfor @@ -211,10 +211,11 @@ function! ale#debugging#Info() abort let l:all_names = map(copy(l:all_linters), 'v:val[''name'']') let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']') + let l:exclude_names = filter(copy(l:all_names), 'index(l:enabled_names, v:val) == -1') " Load linter variables to display " This must be done after linters are loaded. - let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names) + let l:variable_list = s:GetLinterVariables(l:filetype, l:exclude_names) let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype) let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1])) @@ -238,6 +239,12 @@ function! ale#debugging#Info() abort endfunction function! ale#debugging#InfoToClipboard() abort + if !has('clipboard') + call s:Echo('clipboard not available. Try :ALEInfoToFile instead.') + + return + endif + redir => l:output silent call ale#debugging#Info() redir END diff --git a/sources_non_forked/ale/autoload/ale/engine.vim b/sources_non_forked/ale/autoload/ale/engine.vim index 7db808d6..491d3c2e 100644 --- a/sources_non_forked/ale/autoload/ale/engine.vim +++ b/sources_non_forked/ale/autoload/ale/engine.vim @@ -710,6 +710,10 @@ function! ale#engine#Cleanup(buffer) abort return endif + if exists('*ale#lsp#CloseDocument') + call ale#lsp#CloseDocument(a:buffer) + endif + if !has_key(g:ale_buffer_info, a:buffer) return endif diff --git a/sources_non_forked/ale/autoload/ale/events.vim b/sources_non_forked/ale/autoload/ale/events.vim index c3dbd378..da554ef9 100644 --- a/sources_non_forked/ale/autoload/ale/events.vim +++ b/sources_non_forked/ale/autoload/ale/events.vim @@ -128,7 +128,7 @@ function! ale#events#Init() abort endif if g:ale_lint_on_insert_leave - autocmd InsertLeave * call ale#Queue(0) + autocmd InsertLeave * if ale#Var(str2nr(expand('<abuf>')), 'lint_on_insert_leave') | call ale#Queue(0) | endif endif if g:ale_echo_cursor || g:ale_cursor_detail diff --git a/sources_non_forked/ale/autoload/ale/fix.vim b/sources_non_forked/ale/autoload/ale/fix.vim index 92ae3e14..9987fbdd 100644 --- a/sources_non_forked/ale/autoload/ale/fix.vim +++ b/sources_non_forked/ale/autoload/ale/fix.vim @@ -2,46 +2,60 @@ call ale#Set('fix_on_save_ignore', {}) " Apply fixes queued up for buffers which may be hidden. " Vim doesn't let you modify hidden buffers. -function! ale#fix#ApplyQueuedFixes() abort - let l:buffer = bufnr('') - let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0}) +function! ale#fix#ApplyQueuedFixes(buffer) abort + let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0}) + let l:has_bufline_api = exists('*deletebufline') && exists('*setbufline') - if !l:data.done + if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr('')) return endif - call remove(g:ale_fix_buffer_data, l:buffer) + call remove(g:ale_fix_buffer_data, a:buffer) if l:data.changes_made - let l:start_line = len(l:data.output) + 1 - let l:end_line = len(l:data.lines_before) - - if l:end_line >= l:start_line - let l:save = winsaveview() - silent execute l:start_line . ',' . l:end_line . 'd_' - call winrestview(l:save) - endif - " If the file is in DOS mode, we have to remove carriage returns from " the ends of lines before calling setline(), or we will see them " twice. - let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos' + let l:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos' \ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')') \ : l:data.output + let l:first_line_to_remove = len(l:new_lines) + 1 - call setline(1, l:lines_to_set) + " Use a Vim API for setting lines in other buffers, if available. + if l:has_bufline_api + call setbufline(a:buffer, 1, l:new_lines) + call deletebufline(a:buffer, l:first_line_to_remove, '$') + " Fall back on setting lines the old way, for the current buffer. + else + let l:old_line_length = len(l:data.lines_before) + + if l:old_line_length >= l:first_line_to_remove + let l:save = winsaveview() + silent execute + \ l:first_line_to_remove . ',' . l:old_line_length . 'd_' + call winrestview(l:save) + endif + + call setline(1, l:new_lines) + endif if l:data.should_save - if empty(&buftype) - noautocmd :w! + if a:buffer is bufnr('') + if empty(&buftype) + noautocmd :w! + else + set nomodified + endif else - set nomodified + call writefile(l:new_lines, expand(a:buffer . ':p')) " no-custom-checks + call setbufvar(a:buffer, '&modified', 0) endif endif endif if l:data.should_save - let l:should_lint = g:ale_fix_on_save + let l:should_lint = ale#Var(a:buffer, 'fix_on_save') + \ && ale#Var(a:buffer, 'lint_on_save') else let l:should_lint = l:data.changes_made endif @@ -52,7 +66,7 @@ function! ale#fix#ApplyQueuedFixes() abort " fixing problems. if g:ale_enabled \&& l:should_lint - \&& !ale#events#QuitRecently(l:buffer) + \&& !ale#events#QuitRecently(a:buffer) call ale#Queue(0, l:data.should_save ? 'lint_file' : '') endif endfunction @@ -83,7 +97,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort " We can only change the lines of a buffer which is currently open, " so try and apply the fixes to the current buffer. - call ale#fix#ApplyQueuedFixes() + call ale#fix#ApplyQueuedFixes(a:buffer) endfunction function! s:HandleExit(job_info, buffer, job_output, data) abort @@ -399,5 +413,4 @@ endfunction " Set up an autocmd command to try and apply buffer fixes when available. augroup ALEBufferFixGroup autocmd! - autocmd BufEnter * call ale#fix#ApplyQueuedFixes() -augroup END + autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>'))) diff --git a/sources_non_forked/ale/autoload/ale/fix/registry.vim b/sources_non_forked/ale/autoload/ale/fix/registry.vim index 3a36f367..7a553ccc 100644 --- a/sources_non_forked/ale/autoload/ale/fix/registry.vim +++ b/sources_non_forked/ale/autoload/ale/fix/registry.vim @@ -115,6 +115,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['scala'], \ 'description': 'Fix Scala files using scalafmt', \ }, +\ 'sorbet': { +\ 'function': 'ale#fixers#sorbet#Fix', +\ 'suggested_filetypes': ['ruby'], +\ 'description': 'Fix ruby files with srb tc --autocorrect.', +\ }, \ 'standard': { \ 'function': 'ale#fixers#standard#Fix', \ 'suggested_filetypes': ['javascript'], @@ -145,6 +150,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['php'], \ 'description': 'Fix PHP files with php-cs-fixer.', \ }, +\ 'clangtidy': { +\ 'function': 'ale#fixers#clangtidy#Fix', +\ 'suggested_filetypes': ['c', 'cpp', 'objc'], +\ 'description': 'Fix C/C++ and ObjectiveC files with clang-tidy.', +\ }, \ 'clang-format': { \ 'function': 'ale#fixers#clangformat#Fix', \ 'suggested_filetypes': ['c', 'cpp', 'cuda'], @@ -205,6 +215,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['haskell'], \ 'description': 'Fix Haskell files with brittany.', \ }, +\ 'hindent': { +\ 'function': 'ale#fixers#hindent#Fix', +\ 'suggested_filetypes': ['haskell'], +\ 'description': 'Fix Haskell files with hindent.', +\ }, \ 'hlint': { \ 'function': 'ale#fixers#hlint#Fix', \ 'suggested_filetypes': ['haskell'], @@ -297,7 +312,7 @@ let s:default_registry = { \ }, \ 'styler': { \ 'function': 'ale#fixers#styler#Fix', -\ 'suggested_filetypes': ['r'], +\ 'suggested_filetypes': ['r', 'rmarkdown'], \ 'description': 'Fix R files with styler.', \ }, \ 'latexindent': { @@ -305,6 +320,21 @@ let s:default_registry = { \ 'suggested_filetypes': ['tex'], \ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.', \ }, +\ 'pgformatter': { +\ 'function': 'ale#fixers#pgformatter#Fix', +\ 'suggested_filetypes': ['sql'], +\ 'description': 'A PostgreSQL SQL syntax beautifier', +\ }, +\ 'reorder-python-imports': { +\ 'function': 'ale#fixers#reorder_python_imports#Fix', +\ 'suggested_filetypes': ['python'], +\ 'description': 'Sort Python imports with reorder-python-imports.', +\ }, +\ 'gnatpp': { +\ 'function': 'ale#fixers#gnatpp#Fix', +\ 'suggested_filetypes': ['ada'], +\ 'description': 'Format Ada files with gnatpp.', +\ }, \} " Reset the function registry to the default entries. diff --git a/sources_non_forked/ale/autoload/ale/fixers/black.vim b/sources_non_forked/ale/autoload/ale/fixers/black.vim index 367b8d52..fba6c3b4 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/black.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/black.vim @@ -29,6 +29,10 @@ function! ale#fixers#black#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'python_black_options') + if expand('#' . a:buffer . ':e') is? 'pyi' + let l:options .= '--pyi' + endif + return { \ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args \ . (!empty(l:options) ? ' ' . l:options : '') diff --git a/sources_non_forked/ale/autoload/ale/fixers/clangformat.vim b/sources_non_forked/ale/autoload/ale/fixers/clangformat.vim index eae1a7b4..ea5743a5 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/clangformat.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/clangformat.vim @@ -13,10 +13,15 @@ function! ale#fixers#clangformat#GetExecutable(buffer) abort endfunction function! ale#fixers#clangformat#Fix(buffer) abort + let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer)) + let l:filename = ale#Escape(bufname(a:buffer)) let l:options = ale#Var(a:buffer, 'c_clangformat_options') - return { - \ 'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer)) - \ . ' ' . l:options, - \} + let l:command = l:executable . ' --assume-filename=' . l:filename + + if l:options isnot# '' + let l:command .= ' ' . l:options + endif + + return {'command': l:command} endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/clangtidy.vim b/sources_non_forked/ale/autoload/ale/fixers/clangtidy.vim new file mode 100644 index 00000000..b37360a7 --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/clangtidy.vim @@ -0,0 +1,52 @@ +scriptencoding utf-8 +" Author: ObserverOfTime <chronobserver@disroot.org> +" Description: Fixing C/C++ files with clang-tidy. + +function! s:set_variables() abort + let l:use_global = get(g:, 'ale_use_global_executables', 0) + + for l:ft in ['c', 'cpp'] + call ale#Set(l:ft . '_clangtidy_executable', 'clang-tidy') + call ale#Set(l:ft . '_clangtidy_use_global', l:use_global) + call ale#Set(l:ft . '_clangtidy_checks', []) + call ale#Set(l:ft . '_clangtidy_options', '') + call ale#Set(l:ft . '_clangtidy_extra_options', '') + call ale#Set(l:ft . '_clangtidy_fix_errors', 1) + endfor + + call ale#Set('c_build_dir', '') +endfunction + +call s:set_variables() + +function! ale#fixers#clangtidy#Var(buffer, name) abort + let l:ft = getbufvar(str2nr(a:buffer), '&filetype') + let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c' + + return ale#Var(a:buffer, l:ft . '_clangtidy_' . a:name) +endfunction + +function! ale#fixers#clangtidy#GetCommand(buffer) abort + let l:checks = join(ale#fixers#clangtidy#Var(a:buffer, 'checks'), ',') + let l:extra_options = ale#fixers#clangtidy#Var(a:buffer, 'extra_options') + let l:build_dir = ale#c#GetBuildDirectory(a:buffer) + let l:options = empty(l:build_dir) + \ ? ale#fixers#clangtidy#Var(a:buffer, 'options') : '' + let l:fix_errors = ale#fixers#clangtidy#Var(a:buffer, 'fix_errors') + + return ' -fix' . (l:fix_errors ? ' -fix-errors' : '') + \ . (empty(l:checks) ? '' : ' -checks=' . ale#Escape(l:checks)) + \ . (empty(l:extra_options) ? '' : ' ' . l:extra_options) + \ . (empty(l:build_dir) ? '' : ' -p ' . ale#Escape(l:build_dir)) + \ . ' %t' . (empty(l:options) ? '' : ' -- ' . l:options) +endfunction + +function! ale#fixers#clangtidy#Fix(buffer) abort + let l:executable = ale#fixers#clangtidy#Var(a:buffer, 'executable') + let l:command = ale#fixers#clangtidy#GetCommand(a:buffer) + + return { + \ 'command': ale#Escape(l:executable) . l:command, + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/eslint.vim b/sources_non_forked/ale/autoload/ale/fixers/eslint.vim index 0f57cba6..62e692b1 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/eslint.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/eslint.vim @@ -35,9 +35,18 @@ endfunction function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) - let l:config = ale#handlers#eslint#FindConfig(a:buffer) + let l:options = ale#Var(a:buffer, 'javascript_eslint_options') - if empty(l:config) + " Use the configuration file from the options, if configured. + if l:options =~# '\v(^| )-c|(^| )--config' + let l:config = '' + let l:has_config = 1 + else + let l:config = ale#handlers#eslint#FindConfig(a:buffer) + let l:has_config = !empty(l:config) + endif + + if !l:has_config return 0 endif @@ -45,6 +54,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) return { \ 'command': ale#node#Executable(a:buffer, l:executable) + \ . ale#Pad(l:options) \ . ' --stdin-filename %s --stdin --fix-to-stdout', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \} @@ -54,6 +64,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort if ale#semver#GTE(a:version, [4, 9, 0]) return { \ 'command': ale#node#Executable(a:buffer, l:executable) + \ . ale#Pad(l:options) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \} @@ -61,7 +72,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort return { \ 'command': ale#node#Executable(a:buffer, l:executable) - \ . ' -c ' . ale#Escape(l:config) + \ . ale#Pad(l:options) + \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . ' --fix %t', \ 'read_temporary_file': 1, \} diff --git a/sources_non_forked/ale/autoload/ale/fixers/gnatpp.vim b/sources_non_forked/ale/autoload/ale/fixers/gnatpp.vim new file mode 100644 index 00000000..bf3d484e --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/gnatpp.vim @@ -0,0 +1,17 @@ +" Author: tim <tim@inept.tech> +" Description: Fix files with gnatpp. + +call ale#Set('ada_gnatpp_executable', 'gnatpp') +call ale#Set('ada_gnatpp_options', '') + +function! ale#fixers#gnatpp#Fix(buffer) abort + let l:executable = ale#Var(a:buffer, 'ada_gnatpp_executable') + let l:options = ale#Var(a:buffer, 'ada_gnatpp_options') + + return { + \ 'command': ale#Escape(l:executable) + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . ' %t', + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/gofmt.vim b/sources_non_forked/ale/autoload/ale/fixers/gofmt.vim index 66b67a9e..d5a539b9 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/gofmt.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/gofmt.vim @@ -7,9 +7,10 @@ call ale#Set('go_gofmt_options', '') function! ale#fixers#gofmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_gofmt_executable') let l:options = ale#Var(a:buffer, 'go_gofmt_options') + let l:env = ale#go#EnvString(a:buffer) return { - \ 'command': ale#Escape(l:executable) + \ 'command': l:env . ale#Escape(l:executable) \ . ' -l -w' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', diff --git a/sources_non_forked/ale/autoload/ale/fixers/goimports.vim b/sources_non_forked/ale/autoload/ale/fixers/goimports.vim index 783d0206..65f0fd98 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/goimports.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/goimports.vim @@ -7,13 +7,14 @@ call ale#Set('go_goimports_options', '') function! ale#fixers#goimports#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_goimports_executable') let l:options = ale#Var(a:buffer, 'go_goimports_options') + let l:env = ale#go#EnvString(a:buffer) if !executable(l:executable) return 0 endif return { - \ 'command': ale#Escape(l:executable) + \ 'command': l:env . ale#Escape(l:executable) \ . ' -l -w -srcdir %s' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', diff --git a/sources_non_forked/ale/autoload/ale/fixers/gomod.vim b/sources_non_forked/ale/autoload/ale/fixers/gomod.vim index 68895f9b..ee8c46c9 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/gomod.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/gomod.vim @@ -2,9 +2,10 @@ call ale#Set('go_go_executable', 'go') function! ale#fixers#gomod#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_go_executable') + let l:env = ale#go#EnvString(a:buffer) return { - \ 'command': ale#Escape(l:executable) . ' mod edit -fmt %t', + \ 'command': l:env . ale#Escape(l:executable) . ' mod edit -fmt %t', \ 'read_temporary_file': 1, \} endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/hindent.vim b/sources_non_forked/ale/autoload/ale/fixers/hindent.vim new file mode 100644 index 00000000..b6009a2c --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/hindent.vim @@ -0,0 +1,20 @@ +" Author: AlexeiDrake <drake.alexei@gmail.com> +" Description: Integration of hindent formatting with ALE. +" +call ale#Set('haskell_hindent_executable', 'hindent') + +function! ale#fixers#hindent#GetExecutable(buffer) abort + let l:executable = ale#Var(a:buffer, 'haskell_hindent_executable') + + return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hindent') +endfunction + +function! ale#fixers#hindent#Fix(buffer) abort + let l:executable = ale#fixers#hindent#GetExecutable(a:buffer) + + return { + \ 'command': l:executable + \ . ' %t', + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/pgformatter.vim b/sources_non_forked/ale/autoload/ale/fixers/pgformatter.vim new file mode 100644 index 00000000..9ea08ec6 --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/pgformatter.vim @@ -0,0 +1,12 @@ +call ale#Set('sql_pgformatter_executable', 'pg_format') +call ale#Set('sql_pgformatter_options', '') + +function! ale#fixers#pgformatter#Fix(buffer) abort + let l:executable = ale#Var(a:buffer, 'sql_pgformatter_executable') + let l:options = ale#Var(a:buffer, 'sql_pgformatter_options') + + return { + \ 'command': ale#Escape(l:executable) + \ . (empty(l:options) ? '' : ' ' . l:options), + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/prettier.vim b/sources_non_forked/ale/autoload/ale/fixers/prettier.vim index b7f0ecd7..23120777 100644 --- a/sources_non_forked/ale/autoload/ale/fixers/prettier.vim +++ b/sources_non_forked/ale/autoload/ale/fixers/prettier.vim @@ -39,9 +39,15 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort let l:options = ale#Var(a:buffer, 'javascript_prettier_options') let l:parser = '' + let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.') + + if index(l:filetypes, 'handlebars') > -1 + let l:parser = 'glimmer' + endif + " Append the --parser flag depending on the current filetype (unless it's " already set in g:javascript_prettier_options). - if empty(expand('#' . a:buffer . ':e')) && match(l:options, '--parser') == -1 + if empty(expand('#' . a:buffer . ':e')) && l:parser is# '' && match(l:options, '--parser') == -1 " Mimic Prettier's defaults. In cases without a file extension or " filetype (scratch buffer), Prettier needs `parser` set to know how " to process the buffer. @@ -65,7 +71,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort \ 'html': 'html', \} - for l:filetype in split(getbufvar(a:buffer, '&filetype'), '\.') + for l:filetype in l:filetypes if has_key(l:prettier_parsers, l:filetype) let l:parser = l:prettier_parsers[l:filetype] break diff --git a/sources_non_forked/ale/autoload/ale/fixers/reorder_python_imports.vim b/sources_non_forked/ale/autoload/ale/fixers/reorder_python_imports.vim new file mode 100644 index 00000000..42a0a6e2 --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/reorder_python_imports.vim @@ -0,0 +1,25 @@ +" Author: jake <me@jake.computer> +" Description: Fixing Python imports with reorder-python-imports. + +call ale#Set('python_reorder_python_imports_executable', 'reorder-python-imports') +call ale#Set('python_reorder_python_imports_options', '') +call ale#Set('python_reorder_python_imports_use_global', get(g:, 'ale_use_global_executables', 0)) + +function! ale#fixers#reorder_python_imports#Fix(buffer) abort + let l:executable = ale#python#FindExecutable( + \ a:buffer, + \ 'python_reorder_python_imports', + \ ['reorder-python-imports'], + \) + + if !executable(l:executable) + return 0 + endif + + let l:options = ale#Var(a:buffer, 'python_reorder_python_imports_options') + + return { + \ 'command': ale#Escape(l:executable) + \ . (!empty(l:options) ? ' ' . l:options : '') . ' -', + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/fixers/sorbet.vim b/sources_non_forked/ale/autoload/ale/fixers/sorbet.vim new file mode 100644 index 00000000..182f7300 --- /dev/null +++ b/sources_non_forked/ale/autoload/ale/fixers/sorbet.vim @@ -0,0 +1,19 @@ +call ale#Set('ruby_sorbet_executable', 'srb') +call ale#Set('ruby_sorbet_options', '') + +function! ale#fixers#sorbet#GetCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') + let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') + + return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb') + \ . ' tc' + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . ' --autocorrect --file %t' +endfunction + +function! ale#fixers#sorbet#Fix(buffer) abort + return { + \ 'command': ale#fixers#sorbet#GetCommand(a:buffer), + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/sources_non_forked/ale/autoload/ale/go.vim b/sources_non_forked/ale/autoload/ale/go.vim index cd7d9503..4a21e596 100644 --- a/sources_non_forked/ale/autoload/ale/go.vim +++ b/sources_non_forked/ale/autoload/ale/go.vim @@ -25,3 +25,20 @@ function! ale#go#FindProjectRoot(buffer) abort return '' endfunction + + +call ale#Set('go_go111module', '') + +" Return a string setting Go-specific environment variables +function! ale#go#EnvString(buffer) abort + let l:env = '' + + " GO111MODULE - turn go modules behavior on/off + let l:go111module = ale#Var(a:buffer, 'go_go111module') + + if !empty(l:go111module) + let l:env = ale#Env('GO111MODULE', l:go111module) . l:env + endif + + return l:env +endfunction diff --git a/sources_non_forked/ale/autoload/ale/handlers/ccls.vim b/sources_non_forked/ale/autoload/ale/handlers/ccls.vim index 29dd6aed..1e2aa318 100644 --- a/sources_non_forked/ale/autoload/ale/handlers/ccls.vim +++ b/sources_non_forked/ale/autoload/ale/handlers/ccls.vim @@ -3,15 +3,17 @@ scriptencoding utf-8 " Description: Utilities for ccls function! ale#handlers#ccls#GetProjectRoot(buffer) abort - let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls-root') + " Try to find ccls configuration files first. + let l:config = ale#path#FindNearestFile(a:buffer, '.ccls-root') - if empty(l:project_root) - let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + if empty(l:config) + let l:config = ale#path#FindNearestFile(a:buffer, '.ccls') endif - if empty(l:project_root) - let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls') + if !empty(l:config) + return fnamemodify(l:config, ':h') endif - return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' + " Fall back on default project root detection. + return ale#c#FindProjectRoot(a:buffer) endfunction diff --git a/sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim b/sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim index dc56cd0b..6d8fa15d 100644 --- a/sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim +++ b/sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim @@ -1,5 +1,46 @@ " Description: Handle errors for cppcheck. +function! ale#handlers#cppcheck#GetCdCommand(buffer) abort + let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer) + let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : '' + + return l:cd_command +endfunction + +function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort + let l:buffer_path_include = '' + + " Get path to this buffer so we can include it into cppcheck with -I + " This could be expanded to get more -I directives from the compile + " command in compile_commands.json, if it's found. + let l:buffer_path = fnamemodify(bufname(a:buffer), ':p:h') + let l:buffer_path_include = ' -I' . ale#Escape(l:buffer_path) + + return l:buffer_path_include +endfunction + +function! ale#handlers#cppcheck#GetCompileCommandsOptions(buffer) abort + " If the current buffer is modified, using compile_commands.json does no + " good, so include the file's directory instead. It's not quite as good as + " using --project, but is at least equivalent to running cppcheck on this + " file manually from the file's directory. + let l:modified = getbufvar(a:buffer, '&modified') + + if l:modified + return '' + endif + + " Search upwards from the file for compile_commands.json. + " + " If we find it, we'll `cd` to where the compile_commands.json file is, + " then use the file to set up import paths, etc. + let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer) + + return !empty(l:json_path) + \ ? '--project=' . ale#Escape(l:json_path[len(l:dir) + 1: ]) + \ : '' +endfunction + function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort " Look for lines like the following. " diff --git a/sources_non_forked/ale/autoload/ale/handlers/eslint.vim b/sources_non_forked/ale/autoload/ale/handlers/eslint.vim index 5183f4cd..4d533ff2 100644 --- a/sources_non_forked/ale/autoload/ale/handlers/eslint.vim +++ b/sources_non_forked/ale/autoload/ale/handlers/eslint.vim @@ -44,16 +44,9 @@ function! ale#handlers#eslint#GetCommand(buffer) abort return ale#node#Executable(a:buffer, l:executable) \ . (!empty(l:options) ? ' ' . l:options : '') - \ . ' -f unix --stdin --stdin-filename %s' + \ . ' -f json --stdin --stdin-filename %s' endfunction -let s:col_end_patterns = [ -\ '\vParsing error: Unexpected token (.+) ?', -\ '\v''(.+)'' is not defined.', -\ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]', -\ '\vUnexpected (console) statement', -\] - function! s:AddHintsForTypeScriptParsingErrors(output) abort for l:item in a:output let l:item.text = substitute( @@ -90,22 +83,71 @@ function! s:CheckForBadConfig(buffer, lines) abort return 0 endfunction -function! ale#handlers#eslint#Handle(buffer, lines) abort - if s:CheckForBadConfig(a:buffer, a:lines) - return [{ - \ 'lnum': 1, - \ 'text': 'eslint configuration error (type :ALEDetail for more information)', - \ 'detail': join(a:lines, "\n"), - \}] +function! s:parseJSON(buffer, lines) abort + try + let l:parsed = json_decode(a:lines[-1]) + catch + return [] + endtry + + if type(l:parsed) != v:t_list || empty(l:parsed) + return [] endif - if a:lines == ['Could not connect'] - return [{ - \ 'lnum': 1, - \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.', - \}] + let l:errors = l:parsed[0]['messages'] + + if empty(l:errors) + return [] endif + let l:output = [] + + for l:error in l:errors + let l:obj = ({ + \ 'lnum': get(l:error, 'line', 0), + \ 'text': get(l:error, 'message', ''), + \ 'type': 'E', + \}) + + if get(l:error, 'severity', 0) is# 1 + let l:obj.type = 'W' + endif + + if has_key(l:error, 'ruleId') + let l:code = l:error['ruleId'] + + " Sometimes ESLint returns null here + if !empty(l:code) + let l:obj.code = l:code + endif + endif + + if has_key(l:error, 'column') + let l:obj.col = l:error['column'] + endif + + if has_key(l:error, 'endColumn') + let l:obj.end_col = l:error['endColumn'] - 1 + endif + + if has_key(l:error, 'endLine') + let l:obj.end_lnum = l:error['endLine'] + endif + + call add(l:output, l:obj) + endfor + + return l:output +endfunction + +let s:col_end_patterns = [ +\ '\vParsing error: Unexpected token (.+) ?', +\ '\v''(.+)'' is not defined.', +\ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]', +\ '\vUnexpected (console) statement', +\] + +function! s:parseLines(buffer, lines) abort " Matches patterns line the following: " " /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle] @@ -120,12 +162,6 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:parsing_pattern]) let l:text = l:match[3] - if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore') - if l:text =~# '^File ignored' - continue - endif - endif - let l:obj = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, @@ -143,11 +179,6 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort " The code can be something like 'Error/foo/bar', or just 'Error' if !empty(get(l:split_code, 1)) let l:obj.code = join(l:split_code[1:], '/') - - if l:obj.code is# 'no-trailing-spaces' - \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') - continue - endif endif for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns) @@ -157,9 +188,59 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort call add(l:output, l:obj) endfor + return l:output +endfunction + +function! s:FilterResult(buffer, obj) abort + if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore') + if a:obj.text =~# '^File ignored' + return 0 + endif + endif + + if has_key(a:obj, 'code') && a:obj.code is# 'no-trailing-spaces' + \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') + return 0 + endif + + return 1 +endfunction + +function! s:HandleESLintOutput(buffer, lines, type) abort + if s:CheckForBadConfig(a:buffer, a:lines) + return [{ + \ 'lnum': 1, + \ 'text': 'eslint configuration error (type :ALEDetail for more information)', + \ 'detail': join(a:lines, "\n"), + \}] + endif + + if a:lines == ['Could not connect'] + return [{ + \ 'lnum': 1, + \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.', + \}] + endif + + if a:type is# 'json' + let l:output = s:parseJSON(a:buffer, a:lines) + else + let l:output = s:parseLines(a:buffer, a:lines) + endif + + call filter(l:output, {idx, obj -> s:FilterResult(a:buffer, obj)}) + if expand('#' . a:buffer . ':t') =~? '\.tsx\?$' call s:AddHintsForTypeScriptParsingErrors(l:output) endif return l:output endfunction + +function! ale#handlers#eslint#HandleJSON(buffer, lines) abort + return s:HandleESLintOutput(a:buffer, a:lines, 'json') +endfunction + +function! ale#handlers#eslint#Handle(buffer, lines) abort + return s:HandleESLintOutput(a:buffer, a:lines, 'lines') +endfunction diff --git a/sources_non_forked/ale/autoload/ale/handlers/gcc.vim b/sources_non_forked/ale/autoload/ale/handlers/gcc.vim index 72d639da..ec16b977 100644 --- a/sources_non_forked/ale/autoload/ale/handlers/gcc.vim +++ b/sources_non_forked/ale/autoload/ale/handlers/gcc.vim @@ -11,6 +11,7 @@ let s:pragma_error = '#pragma once in main file' " <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’) " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' +let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$' function! s:IsHeaderFile(filename) abort return a:filename =~? '\v\.(h|hpp)$' @@ -25,6 +26,28 @@ function! s:RemoveUnicodeQuotes(text) abort return l:text endfunction +function! s:ParseInlinedFunctionProblems(buffer, lines) abort + let l:output = [] + let l:pos_match = [] + + for l:line in a:lines + let l:match = matchlist(l:line, s:pattern) + + if !empty(l:match) && !empty(l:pos_match) + call add(l:output, { + \ 'lnum': str2nr(l:pos_match[1]), + \ 'col': str2nr(l:pos_match[2]), + \ 'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W', + \ 'text': s:RemoveUnicodeQuotes(l:match[5]), + \}) + endif + + let l:pos_match = matchlist(l:line, s:inline_pattern) + endfor + + return l:output +endfunction + " Report problems inside of header files just for gcc and clang function! s:ParseProblemsInHeaders(buffer, lines) abort let l:output = [] @@ -129,6 +152,7 @@ endfunction function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines) + call extend(l:output, s:ParseInlinedFunctionProblems(a:buffer, a:lines)) call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines)) return l:output diff --git a/sources_non_forked/ale/autoload/ale/handlers/rust.vim b/sources_non_forked/ale/autoload/ale/handlers/rust.vim index dda6466e..a7fac464 100644 --- a/sources_non_forked/ale/autoload/ale/handlers/rust.vim +++ b/sources_non_forked/ale/autoload/ale/handlers/rust.vim @@ -56,14 +56,20 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort endif if !empty(l:span) - call add(l:output, { + let l:output_line = { \ 'lnum': l:span.line_start, \ 'end_lnum': l:span.line_end, \ 'col': l:span.column_start, \ '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]), - \}) + \} + + if has_key(l:error, 'rendered') && !empty(l:error.rendered) + let l:output_line.detail = l:error.rendered + endif + + call add(l:output, l:output_line) endif endfor endfor diff --git a/sources_non_forked/ale/autoload/ale/highlight.vim b/sources_non_forked/ale/autoload/ale/highlight.vim index 172f9d54..cb7911e1 100644 --- a/sources_non_forked/ale/autoload/ale/highlight.vim +++ b/sources_non_forked/ale/autoload/ale/highlight.vim @@ -26,41 +26,6 @@ endif let s:MAX_POS_VALUES = 8 let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) -" Check if we have neovim's buffer highlight API -" -" Below we define some functions' implementation conditionally if this API -" exists or not. -" -" The API itself is more ergonomic and neovim performs highlights positions -" rebases during edits so we see less stalled highlights. -let s:nvim_api = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace') - -function! ale#highlight#HasNeovimApi() abort - return s:nvim_api -endfunction - -function! ale#highlight#nvim_buf_clear_namespace(...) abort - return call('nvim_buf_clear_namespace', a:000) -endfunction - -function! ale#highlight#nvim_buf_add_highlight(...) abort - return call('nvim_buf_add_highlight', a:000) -endfunction - -function! s:ale_nvim_highlight_id(bufnr) abort - let l:id = getbufvar(a:bufnr, 'ale_nvim_highlight_id', -1) - - if l:id is -1 - " NOTE: This will highlight nothing but will allocate new id - let l:id = ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, 0, '', 0, 0, -1 - \) - call setbufvar(a:bufnr, 'ale_nvim_highlight_id', l:id) - endif - - return l:id -endfunction - function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort if a:line >= a:end_line " For single lines, just return the one position. @@ -86,88 +51,29 @@ endfunction " except these which have matching loclist item entries. function! ale#highlight#RemoveHighlights() abort - if ale#highlight#HasNeovimApi() - if get(b:, 'ale_nvim_highlight_id', 0) - let l:bufnr = bufnr('%') - " NOTE: 0, -1 means from 0 line till the end of buffer - call ale#highlight#nvim_buf_clear_namespace( - \ l:bufnr, - \ b:ale_nvim_highlight_id, - \ 0, -1 - \) + for l:match in getmatches() + if l:match.group =~? '\v^ALE(Style)?(Error|Warning|Info)(Line)?$' + call matchdelete(l:match.id) endif - else - for l:match in getmatches() - if l:match.group =~# '^ALE' - call matchdelete(l:match.id) - endif - endfor - endif + endfor endfunction function! s:highlight_line(bufnr, lnum, group) abort - if ale#highlight#HasNeovimApi() - let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr) - call ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, l:highlight_id, a:group, - \ a:lnum - 1, 0, -1 - \) - else - call matchaddpos(a:group, [a:lnum]) - endif + call matchaddpos(a:group, [a:lnum]) endfunction function! s:highlight_range(bufnr, range, group) abort - if ale#highlight#HasNeovimApi() - let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr) - " NOTE: lines and columns indicies are 0-based in nvim_buf_* API. - let l:lnum = a:range.lnum - 1 - let l:end_lnum = a:range.end_lnum - 1 - let l:col = a:range.col - 1 - let l:end_col = a:range.end_col - - if l:lnum >= l:end_lnum - " For single lines, just return the one position. - call ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, l:highlight_id, a:group, - \ l:lnum, l:col, l:end_col - \) - else - " highlight first line from start till the line end - call ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, l:highlight_id, a:group, - \ l:lnum, l:col, -1 - \) - - " highlight all lines between the first and last entirely - let l:cur = l:lnum + 1 - - while l:cur < l:end_lnum - call ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, l:highlight_id, a:group, - \ l:cur, 0, -1 - \ ) - let l:cur += 1 - endwhile - - call ale#highlight#nvim_buf_add_highlight( - \ a:bufnr, l:highlight_id, a:group, - \ l:end_lnum, 0, l:end_col - \) - endif - else - " Set all of the positions, which are chunked into Lists which - " are as large as will be accepted by matchaddpos. - call map( - \ ale#highlight#CreatePositions( - \ a:range.lnum, - \ a:range.col, - \ a:range.end_lnum, - \ a:range.end_col - \ ), - \ 'matchaddpos(a:group, v:val)' - \) - endif + " Set all of the positions, which are chunked into Lists which + " are as large as will be accepted by matchaddpos. + call map( + \ ale#highlight#CreatePositions( + \ a:range.lnum, + \ a:range.col, + \ a:range.end_lnum, + \ a:range.end_col + \ ), + \ 'matchaddpos(a:group, v:val)' + \) endfunction function! ale#highlight#UpdateHighlights() abort diff --git a/sources_non_forked/ale/autoload/ale/java.vim b/sources_non_forked/ale/autoload/ale/java.vim index b7fd10bd..e641ac6c 100644 --- a/sources_non_forked/ale/autoload/ale/java.vim +++ b/sources_non_forked/ale/autoload/ale/java.vim @@ -16,5 +16,11 @@ function! ale#java#FindProjectRoot(buffer) abort return fnamemodify(l:maven_pom_file, ':h') endif + let l:ant_root = ale#ant#FindProjectRoot(a:buffer) + + if !empty(l:ant_root) + return l:ant_root + endif + return '' endfunction diff --git a/sources_non_forked/ale/autoload/ale/linter.vim b/sources_non_forked/ale/autoload/ale/linter.vim index 8c657675..78dcd3a2 100644 --- a/sources_non_forked/ale/autoload/ale/linter.vim +++ b/sources_non_forked/ale/autoload/ale/linter.vim @@ -13,10 +13,13 @@ let s:default_ale_linter_aliases = { \ 'Dockerfile': 'dockerfile', \ 'csh': 'sh', \ 'plaintex': 'tex', +\ 'rmarkdown': 'r', \ 'systemverilog': 'verilog', \ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'], \ 'vimwiki': 'markdown', \ 'vue': ['vue', 'javascript'], +\ 'xsd': ['xsd', 'xml'], +\ 'xslt': ['xslt', 'xml'], \ 'zsh': 'sh', \} @@ -355,12 +358,14 @@ function! ale#linter#Define(filetype, linter) abort " This command will throw from the sandbox. let &l:equalprg=&l:equalprg + let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter) + if !has_key(s:linters, a:filetype) let s:linters[a:filetype] = [] endif - let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter) - + " Remove previously defined linters with the same name. + call filter(s:linters[a:filetype], 'v:val.name isnot# a:linter.name') call add(s:linters[a:filetype], l:new_linter) endfunction diff --git a/sources_non_forked/ale/autoload/ale/list.vim b/sources_non_forked/ale/autoload/ale/list.vim index 63d97f35..4bfe2a7b 100644 --- a/sources_non_forked/ale/autoload/ale/list.vim +++ b/sources_non_forked/ale/autoload/ale/list.vim @@ -71,8 +71,8 @@ function! s:FixList(buffer, list) abort return l:new_list endfunction -function! s:BufWinId(buffer) abort - return exists('*bufwinid') ? bufwinid(str2nr(a:buffer)) : 0 +function! s:WinFindBuf(buffer) abort + return exists('*win_findbuf') ? win_findbuf(str2nr(a:buffer)) : [0] endfunction function! s:SetListsImpl(timer_id, buffer, loclist) abort @@ -88,19 +88,24 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort call setqflist([], 'r', {'title': l:title}) endif elseif g:ale_set_loclist - " If windows support is off, bufwinid() may not exist. + " If windows support is off, win_findbuf() may not exist. " We'll set result in the current window, which might not be correct, " but it's better than nothing. - let l:id = s:BufWinId(a:buffer) + let l:ids = s:WinFindBuf(a:buffer) - if has('nvim') - call setloclist(l:id, s:FixList(a:buffer, a:loclist), ' ', l:title) - else - call setloclist(l:id, s:FixList(a:buffer, a:loclist)) - call setloclist(l:id, [], 'r', {'title': l:title}) - endif + for l:id in l:ids + if has('nvim') + call setloclist(l:id, s:FixList(a:buffer, a:loclist), ' ', l:title) + else + call setloclist(l:id, s:FixList(a:buffer, a:loclist)) + call setloclist(l:id, [], 'r', {'title': l:title}) + endif + endfor endif + " Save the current view before opening/closing any window + call setbufvar(a:buffer, 'ale_winview', winsaveview()) + " Open a window to show the problems if we need to. " " We'll check if the current buffer's List is not empty here, so the @@ -108,8 +113,6 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort if s:ShouldOpen(a:buffer) && !empty(a:loclist) let l:winnr = winnr() let l:mode = mode() - let l:reset_visual_selection = l:mode is? 'v' || l:mode is# "\<c-v>" - let l:reset_character_selection = l:mode is? 's' || l:mode is# "\<c-s>" " open windows vertically instead of default horizontally let l:open_type = '' @@ -131,15 +134,18 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort wincmd p endif - if l:reset_visual_selection || l:reset_character_selection - " If we were in a selection mode before, select the last selection. - normal! gv - - if l:reset_character_selection - " Switch back to Select mode, if we were in that. + " Return to original mode when applicable + if mode() != l:mode + if l:mode is? 'v' || l:mode is# "\<c-v>" + " Reset our last visual selection + normal! gv + elseif l:mode is? 's' || l:mode is# "\<c-s>" + " Reset our last character selection normal! "\<c-g>" endif endif + + call s:RestoreViewIfNeeded(a:buffer) endif " If ALE isn't currently checking for more problems, close the window if @@ -150,6 +156,30 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort endif endfunction +" Try to restore the window view after closing any of the lists to avoid making +" the it moving around, especially useful when on insert mode +function! s:RestoreViewIfNeeded(buffer) abort + let l:saved_view = getbufvar(a:buffer, 'ale_winview', {}) + + " Saved view is empty, can't do anything + if empty(l:saved_view) + return + endif + + " Check wether the cursor has moved since linting was actually requested. If + " the user has indeed moved lines, do nothing + let l:current_view = winsaveview() + + if l:current_view['lnum'] != l:saved_view['lnum'] + return + endif + + " Anchor view by topline if the list is set to open horizontally + if ale#Var(a:buffer, 'list_vertical') == 0 + call winrestview({'topline': l:saved_view['topline']}) + endif +endfunction + function! ale#list#SetLists(buffer, loclist) abort if get(g:, 'ale_set_lists_synchronously') == 1 \|| getbufvar(a:buffer, 'ale_save_event_fired', 0) @@ -173,21 +203,31 @@ function! s:CloseWindowIfNeeded(buffer) abort return endif + let l:did_close_any_list = 0 + try " Only close windows if the quickfix list or loclist is completely empty, " including errors set through other means. if g:ale_set_quickfix if empty(getqflist()) cclose + let l:did_close_any_list = 1 endif else - let l:win_id = s:BufWinId(a:buffer) + let l:win_ids = s:WinFindBuf(a:buffer) - if g:ale_set_loclist && empty(getloclist(l:win_id)) - lclose - endif + for l:win_id in l:win_ids + if g:ale_set_loclist && empty(getloclist(l:win_id)) + lclose + let l:did_close_any_list = 1 + endif + endfor endif " Ignore 'Cannot close last window' errors. catch /E444/ endtry + + if l:did_close_any_list + call s:RestoreViewIfNeeded(a:buffer) + endif endfunction diff --git a/sources_non_forked/ale/autoload/ale/loclist_jumping.vim b/sources_non_forked/ale/autoload/ale/loclist_jumping.vim index 1d3ef7e5..55097d12 100644 --- a/sources_non_forked/ale/autoload/ale/loclist_jumping.vim +++ b/sources_non_forked/ale/autoload/ale/loclist_jumping.vim @@ -111,7 +111,7 @@ function! ale#loclist_jumping#Jump(direction, ...) abort if !empty(l:nearest) normal! m` - call cursor(l:nearest) + call cursor([l:nearest[0], max([l:nearest[1], 1])]) endif endfunction diff --git a/sources_non_forked/ale/autoload/ale/lsp.vim b/sources_non_forked/ale/autoload/ale/lsp.vim index 7186d2a9..017096cd 100644 --- a/sources_non_forked/ale/autoload/ale/lsp.vim +++ b/sources_non_forked/ale/autoload/ale/lsp.vim @@ -321,7 +321,69 @@ endfunction function! s:SendInitMessage(conn) abort let [l:init_id, l:init_data] = ale#lsp#CreateMessageData( - \ ale#lsp#message#Initialize(a:conn.root, a:conn.init_options), + \ ale#lsp#message#Initialize( + \ a:conn.root, + \ a:conn.init_options, + \ { + \ 'workspace': { + \ 'applyEdit': v:false, + \ 'didChangeConfiguration': { + \ 'dynamicRegistration': v:false, + \ }, + \ 'symbol': { + \ 'dynamicRegistration': v:false, + \ }, + \ 'workspaceFolders': v:false, + \ 'configuration': v:false, + \ }, + \ 'textDocument': { + \ 'synchronization': { + \ 'dynamicRegistration': v:false, + \ 'willSave': v:false, + \ 'willSaveWaitUntil': v:false, + \ 'didSave': v:true, + \ }, + \ 'completion': { + \ 'dynamicRegistration': v:false, + \ 'completionItem': { + \ 'snippetSupport': v:false, + \ 'commitCharactersSupport': v:false, + \ 'documentationFormat': ['plaintext'], + \ 'deprecatedSupport': v:false, + \ 'preselectSupport': v:false, + \ }, + \ 'contextSupport': v:false, + \ }, + \ 'hover': { + \ 'dynamicRegistration': v:false, + \ 'contentFormat': ['plaintext'], + \ }, + \ 'references': { + \ 'dynamicRegistration': v:false, + \ }, + \ 'documentSymbol': { + \ 'dynamicRegistration': v:false, + \ 'hierarchicalDocumentSymbolSupport': v:false, + \ }, + \ 'definition': { + \ 'dynamicRegistration': v:false, + \ 'linkSupport': v:false, + \ }, + \ 'typeDefinition': { + \ 'dynamicRegistration': v:false, + \ }, + \ 'publishDiagnostics': { + \ 'relatedInformation': v:true, + \ }, + \ 'codeAction': { + \ 'dynamicRegistration': v:false, + \ }, + \ 'rename': { + \ 'dynamicRegistration': v:false, + \ }, + \ }, + \ }, + \ ), \) let a:conn.init_request_id = l:init_id call s:SendMessageData(a:conn, l:init_data) @@ -484,6 +546,35 @@ function! ale#lsp#OpenDocument(conn_id, buffer, language_id) abort return l:opened endfunction +" Notify LSP servers or tsserver that a document is closed, if opened before. +" If a document is closed, 1 will be returned, otherwise 0 will be returned. +" +" Only the buffer number is required here. A message will be sent to every +" language server that was notified previously of the document being opened. +function! ale#lsp#CloseDocument(buffer) abort + let l:closed = 0 + + " The connection keys are sorted so the messages are easier to test, and + " so messages are sent in a consistent order. + for l:conn_id in sort(keys(s:connections)) + let l:conn = s:connections[l:conn_id] + + if l:conn.initialized && has_key(l:conn.open_documents, a:buffer) + if l:conn.is_tsserver + let l:message = ale#lsp#tsserver_message#Close(a:buffer) + else + let l:message = ale#lsp#message#DidClose(a:buffer) + endif + + call ale#lsp#Send(l:conn_id, l:message) + call remove(l:conn.open_documents, a:buffer) + let l:closed = 1 + endif + endfor + + return l:closed +endfunction + " Notify LSP servers or tsserver that a document has changed, if needed. " If a notification is sent, 1 will be returned, otherwise 0 will be returned. function! ale#lsp#NotifyForChanges(conn_id, buffer) abort diff --git a/sources_non_forked/ale/autoload/ale/lsp/message.vim b/sources_non_forked/ale/autoload/ale/lsp/message.vim index 4ad94c4b..b6b14a22 100644 --- a/sources_non_forked/ale/autoload/ale/lsp/message.vim +++ b/sources_non_forked/ale/autoload/ale/lsp/message.vim @@ -28,14 +28,13 @@ function! ale#lsp#message#GetNextVersionID() abort return l:id endfunction -function! ale#lsp#message#Initialize(root_path, initialization_options) abort - " TODO: Define needed capabilities. +function! ale#lsp#message#Initialize(root_path, options, capabilities) abort " NOTE: rootPath is deprecated in favour of rootUri return [0, 'initialize', { \ 'processId': getpid(), \ 'rootPath': a:root_path, - \ 'capabilities': {}, - \ 'initializationOptions': a:initialization_options, + \ 'capabilities': a:capabilities, + \ 'initializationOptions': a:options, \ 'rootUri': ale#path#ToURI(a:root_path), \}] endfunction diff --git a/sources_non_forked/ale/autoload/ale/lsp/response.vim b/sources_non_forked/ale/autoload/ale/lsp/response.vim index 9ce05260..30da77e1 100644 --- a/sources_non_forked/ale/autoload/ale/lsp/response.vim +++ b/sources_non_forked/ale/autoload/ale/lsp/response.vim @@ -90,7 +90,7 @@ function! ale#lsp#response#ReadTSServerDiagnostics(response) abort \ 'lnum': l:diagnostic.start.line, \ 'col': l:diagnostic.start.offset, \ 'end_lnum': l:diagnostic.end.line, - \ 'end_col': l:diagnostic.end.offset, + \ 'end_col': l:diagnostic.end.offset - 1, \} if has_key(l:diagnostic, 'code') diff --git a/sources_non_forked/ale/autoload/ale/lsp_linter.vim b/sources_non_forked/ale/autoload/ale/lsp_linter.vim index f70042dd..190a16b4 100644 --- a/sources_non_forked/ale/autoload/ale/lsp_linter.vim +++ b/sources_non_forked/ale/autoload/ale/lsp_linter.vim @@ -8,6 +8,9 @@ if !has_key(s:, 'lsp_linter_map') let s:lsp_linter_map = {} endif +" A Dictionary to track one-shot handlers for custom LSP requests +let s:custom_handlers_map = get(s:, 'custom_handlers_map', {}) + " Check if diagnostics for a particular linter should be ignored. function! s:ShouldIgnore(buffer, linter_name) abort " Ignore all diagnostics if LSP integration is disabled. @@ -31,7 +34,7 @@ endfunction function! s:HandleLSPDiagnostics(conn_id, response) abort let l:linter_name = s:lsp_linter_map[a:conn_id] let l:filename = ale#path#FromURI(a:response.params.uri) - let l:buffer = bufnr(l:filename) + let l:buffer = bufnr('^' . l:filename . '$') let l:info = get(g:ale_buffer_info, l:buffer, {}) if empty(l:info) @@ -49,7 +52,7 @@ endfunction function! s:HandleTSServerDiagnostics(response, error_type) abort let l:linter_name = 'tsserver' - let l:buffer = bufnr(a:response.body.file) + let l:buffer = bufnr('^' . a:response.body.file . '$') let l:info = get(g:ale_buffer_info, l:buffer, {}) if empty(l:info) @@ -407,9 +410,57 @@ endfunction " Clear LSP linter data for the linting engine. function! ale#lsp_linter#ClearLSPData() abort let s:lsp_linter_map = {} + let s:custom_handlers_map = {} endfunction " Just for tests. function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort let s:lsp_linter_map = a:replacement_map endfunction + +function! s:HandleLSPResponseToCustomRequests(conn_id, response) abort + if has_key(a:response, 'id') + \&& has_key(s:custom_handlers_map, a:response.id) + let l:Handler = remove(s:custom_handlers_map, a:response.id) + call l:Handler(a:response) + endif +endfunction + +function! s:OnReadyForCustomRequests(args, linter, lsp_details) abort + let l:id = a:lsp_details.connection_id + let l:request_id = ale#lsp#Send(l:id, a:args.message) + + if l:request_id > 0 && has_key(a:args, 'handler') + let l:Callback = function('s:HandleLSPResponseToCustomRequests') + call ale#lsp#RegisterCallback(l:id, l:Callback) + let s:custom_handlers_map[l:request_id] = a:args.handler + endif +endfunction + +" Send a custom request to an LSP linter. +function! ale#lsp_linter#SendRequest(buffer, linter_name, message, ...) abort + let l:filetype = ale#linter#ResolveFiletype(getbufvar(a:buffer, '&filetype')) + let l:linter_list = ale#linter#GetAll(l:filetype) + let l:linter_list = filter(l:linter_list, {_, v -> v.name is# a:linter_name}) + + if len(l:linter_list) < 1 + throw 'Linter "' . a:linter_name . '" not found!' + endif + + let l:linter = l:linter_list[0] + + if empty(l:linter.lsp) + throw 'Linter "' . a:linter_name . '" does not support LSP!' + endif + + let l:is_notification = a:message[0] + let l:callback_args = {'message': a:message} + + if !l:is_notification && a:0 + let l:callback_args.handler = a:1 + endif + + let l:Callback = function('s:OnReadyForCustomRequests', [l:callback_args]) + + return ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback) +endfunction diff --git a/sources_non_forked/ale/autoload/ale/path.vim b/sources_non_forked/ale/autoload/ale/path.vim index 60d42eb5..84c26d0a 100644 --- a/sources_non_forked/ale/autoload/ale/path.vim +++ b/sources_non_forked/ale/autoload/ale/path.vim @@ -3,13 +3,20 @@ " simplify a path, and fix annoying issues with paths on Windows. " -" Forward slashes are changed to back slashes so path equality works better. +" Forward slashes are changed to back slashes so path equality works better +" on Windows. Back slashes are changed to forward slashes on Unix. +" +" Unix paths can technically contain back slashes, but in practice no path +" should, and replacing back slashes with forward slashes makes linters work +" in environments like MSYS. " " Paths starting with more than one forward slash are changed to only one " forward slash, to prevent the paths being treated as special MSYS paths. function! ale#path#Simplify(path) abort if has('unix') - return substitute(simplify(a:path), '^//\+', '/', 'g') " no-custom-checks + let l:unix_path = substitute(a:path, '\\', '/', 'g') + + return substitute(simplify(l:unix_path), '^//\+', '/', 'g') " no-custom-checks endif let l:win_path = substitute(a:path, '/', '\\', 'g') diff --git a/sources_non_forked/ale/autoload/ale/python.vim b/sources_non_forked/ale/autoload/ale/python.vim index 2f28214b..7ed22367 100644 --- a/sources_non_forked/ale/autoload/ale/python.vim +++ b/sources_non_forked/ale/autoload/ale/python.vim @@ -25,7 +25,7 @@ function! ale#python#FindProjectRootIni(buffer) abort \|| filereadable(l:path . '/tox.ini') \|| filereadable(l:path . '/mypy.ini') \|| filereadable(l:path . '/pycodestyle.cfg') - \|| filereadable(l:path . '/flake8.cfg') + \|| filereadable(l:path . '/.flake8') \|| filereadable(l:path . '/.flake8rc') \|| filereadable(l:path . '/pylama.ini') \|| filereadable(l:path . '/pylintrc') diff --git a/sources_non_forked/ale/autoload/ale/sign.vim b/sources_non_forked/ale/autoload/ale/sign.vim index 7395b0e2..eb0dd1cd 100644 --- a/sources_non_forked/ale/autoload/ale/sign.vim +++ b/sources_non_forked/ale/autoload/ale/sign.vim @@ -82,6 +82,34 @@ execute 'sign define ALEInfoSign text=' . s:EscapeSignText(g:ale_sign_info) \ . ' texthl=ALEInfoSign linehl=ALEInfoLine' sign define ALEDummySign +if has('nvim-0.3.2') + if !hlexists('ALEErrorSignLineNr') + highlight link ALEErrorSignLineNr CursorLineNr + endif + + if !hlexists('ALEStyleErrorSignLineNr') + highlight link ALEStyleErrorSignLineNr CursorLineNr + endif + + if !hlexists('ALEWarningSignLineNr') + highlight link ALEWarningSignLineNr CursorLineNr + endif + + if !hlexists('ALEStyleWarningSignLineNr') + highlight link ALEStyleWarningSignLineNr CursorLineNr + endif + + if !hlexists('ALEInfoSignLineNr') + highlight link ALEInfoSignLineNr CursorLineNr + endif + + sign define ALEErrorSign numhl=ALEErrorSignLineNr + sign define ALEStyleErrorSign numhl=ALEStyleErrorSignLineNr + sign define ALEWarningSign numhl=ALEWarningSignLineNr + sign define ALEStyleWarningSign numhl=ALEStyleWarningSignLineNr + sign define ALEInfoSign numhl=ALEInfoSignLineNr +endif + function! ale#sign#GetSignName(sublist) abort let l:priority = g:ale#util#style_warning_priority diff --git a/sources_non_forked/ale/autoload/asyncomplete/sources/ale.vim b/sources_non_forked/ale/autoload/asyncomplete/sources/ale.vim new file mode 100644 index 00000000..ce793773 --- /dev/null +++ b/sources_non_forked/ale/autoload/asyncomplete/sources/ale.vim @@ -0,0 +1,26 @@ +function! asyncomplete#sources#ale#get_source_options(...) abort + let l:default = extend({ + \ 'name': 'ale', + \ 'completor': function('asyncomplete#sources#ale#completor'), + \ 'whitelist': ['*'], + \ 'triggers': asyncomplete#sources#ale#get_triggers(), + \ }, a:0 >= 1 ? a:1 : {}) + + return extend(l:default, {'refresh_pattern': '\k\+$'}) +endfunction + +function! asyncomplete#sources#ale#get_triggers() abort + let l:triggers = ale#completion#GetAllTriggers() + let l:triggers['*'] = l:triggers['<default>'] + + return l:triggers +endfunction + +function! asyncomplete#sources#ale#completor(options, context) abort + let l:keyword = matchstr(a:context.typed, '\w\+$') + let l:startcol = a:context.col - len(l:keyword) + + call ale#completion#GetCompletions('ale-callback', { 'callback': {completions -> + \ asyncomplete#complete(a:options.name, a:context, l:startcol, completions) + \ }}) +endfunction diff --git a/sources_non_forked/ale/doc/ale-ada.txt b/sources_non_forked/ale/doc/ale-ada.txt index 93e3261a..2ac30c0a 100644 --- a/sources_non_forked/ale/doc/ale-ada.txt +++ b/sources_non_forked/ale/doc/ale-ada.txt @@ -21,5 +21,16 @@ g:ale_ada_gcc_options *g:ale_ada_gcc_options* This variable can be set to pass additional options to gcc. +=============================================================================== +gnatpp *ale-ada-gnatpp* + +g:ale_ada_gnatpp_options *g:ale_ada_gnatpp_options* + *b:ale_ada_gnatpp_options* + Type: |String| + Default: `''` + + This variable can be set to pass extra options to the gnatpp fixer. + + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale-c.txt b/sources_non_forked/ale/doc/ale-c.txt index be0a3d77..c9eb79db 100644 --- a/sources_non_forked/ale/doc/ale-c.txt +++ b/sources_non_forked/ale/doc/ale-c.txt @@ -156,7 +156,7 @@ g:ale_c_clangtidy_options *g:ale_c_clangtidy_options* Type: |String| Default: `''` - This variable can be changed to modify flags given to clang-tidy. + This variable can be changed to modify compiler flags given to clang-tidy. - Setting this variable to a non-empty string, - and working in a buffer where no compilation database is found using @@ -169,6 +169,23 @@ g:ale_c_clangtidy_options *g:ale_c_clangtidy_options* of the |g:ale_c_build_dir_names| directories of the project tree. +g:ale_c_clangtidy_extra_options *g:ale_c_clangtidy_extra_options* + *b:ale_c_clangtidy_extra_options* + Type: |String| + Default: `''` + + This variable can be changed to modify flags given to clang-tidy. + + +g:ale_c_clangtidy_fix_errors *g:ale_c_clangtidy_fix_errors* + *b:ale_c_clangtidy_fix_errors* + Type: |Number| + Default: `1` + + This variable can be changed to disable the `-fix-errors` option for the + |clangtidy| fixer. + + =============================================================================== cppcheck *ale-c-cppcheck* diff --git a/sources_non_forked/ale/doc/ale-cpp.txt b/sources_non_forked/ale/doc/ale-cpp.txt index e1f64ab5..ead3be28 100644 --- a/sources_non_forked/ale/doc/ale-cpp.txt +++ b/sources_non_forked/ale/doc/ale-cpp.txt @@ -125,7 +125,7 @@ g:ale_cpp_clangtidy_options *g:ale_cpp_clangtidy_options* Type: |String| Default: `''` - This variable can be changed to modify flags given to clang-tidy. + This variable can be changed to modify compiler flags given to clang-tidy. - Setting this variable to a non-empty string, - and working in a buffer where no compilation database is found using @@ -138,6 +138,23 @@ g:ale_cpp_clangtidy_options *g:ale_cpp_clangtidy_options* of the |g:ale_c_build_dir_names| directories of the project tree. +g:ale_cpp_clangtidy_extra_options *g:ale_cpp_clangtidy_extra_options* + *b:ale_cpp_clangtidy_extra_options* + Type: |String| + Default: `''` + + This variable can be changed to modify flags given to clang-tidy. + + +g:ale_cpp_clangtidy_fix_errors *g:ale_cpp_clangtidy_fix_errors* + *b:ale_cpp_clangtidy_fix_errors* + Type: |Number| + Default: `1` + + This variable can be changed to disable the `-fix-errors` option for the + |clangtidy| fixer. + + =============================================================================== clazy *ale-cpp-clazy* diff --git a/sources_non_forked/ale/doc/ale-cs.txt b/sources_non_forked/ale/doc/ale-cs.txt index 01e6348f..abcc43eb 100644 --- a/sources_non_forked/ale/doc/ale-cs.txt +++ b/sources_non_forked/ale/doc/ale-cs.txt @@ -6,11 +6,97 @@ In addition to the linters that are provided with ALE, C# code can be checked with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim +=============================================================================== +csc *ale-cs-csc* + + The |ale-cs-csc| linter checks for semantic errors when files are opened or + saved. + + See |ale-lint-file-linters| for more information on linters which do not + check for problems while you type. + + The csc linter uses the mono csc compiler providing full c# 7 and newer + support to generate a temporary module target file (/t:module). The module + includes including all '*.cs' files contained in the directory tree rooted + at the path defined by the |g:ale_cs_csc_source| or |b:ale_cs_csc_source| + variabl and all sub directories. + + It will in future replace the |ale-cs-mcs| and |ale-cs-mcsc| linters as both + utilizer the mcsc compiler which according to mono porject ist further + developed and as of writint these lines only receives maintenance updates. + The down is that the csc compiler does not support the -sytax option any more + and therefore |ale-cs-csc| linter doese not offer any as you type syntax + checking like the |ale-cs-mcsc| linter doesn't. + + The paths to search for additional assembly files can be specified using the + |g:ale_cs_csc_assembly_path| or |b:ale_cs_csc_assembly_path| variables. + + NOTE: ALE will not find any errors in files apart from syntax errors if any + one of the source files contains a syntax error. Syntax errors must be fixed + first before other errors will be shown. + + +g:ale_cs_csc_options *g:ale_cs_csc_options* + *b:ale_cs_csc_options* + Type: |String| + Default: `''` + + This option can be set to pass additional arguments to the `csc` compiler. + + For example, to add the dotnet package which is not added per default: > + + let g:ale_cs_mcs_options = ' /warn:4 /langversion:7.2' +< + NOTE: the `/unsafe` option is always passed to `csc`. + + +g:ale_cs_csc_source *g:ale_cs_csc_source* + *b:ale_cs_csc_source* + Type: |String| + Default: `''` + + This variable defines the root path of the directory tree searched for the + '*.cs' files to be linted. If this option is empty, the source file's + directory will be used. + + NOTE: Currently it is not possible to specify sub directories and + directory sub trees which shall not be searched for *.cs files. + + +g:ale_cs_csc_assembly_path *g:ale_cs_csc_assembly_path* + *b:ale_cs_csc_assembly_path* + Type: |List| + Default: `[]` + + This variable defines a list of path strings to be searched for external + assembly files. The list is passed to the csc compiler using the `/lib:` + flag. + + +g:ale_cs_csc_assemblies *g:ale_cs_csc_assemblies* + *b:ale_cs_csc_assemblies* + Type: |List| + Default: `[]` + + This variable defines a list of external assembly (*.dll) files required + by the mono mcs compiler to generate a valid module target. The list is + passed the csc compiler using the `/r:` flag. + + For example: > + + " Compile C# programs with the Unity engine DLL file on Mac. + let g:ale_cs_mcsc_assemblies = [ + \ '/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll', + \ 'path-to-unityproject/obj/Debug', + \] +< + =============================================================================== mcs *ale-cs-mcs* - The `mcs` linter looks only for syntax errors while you type. See |ale-cs-mcsc| - for the separately configured linter for checking for semantic errors. + The `mcs` linter looks only for syntax errors while you type. See + |ale-cs-mcsc| for the separately configured linter for checking for semantic + errors. g:ale_cs_mcs_options *g:ale_cs_mcs_options* diff --git a/sources_non_forked/ale/doc/ale-development.txt b/sources_non_forked/ale/doc/ale-development.txt index 9c9f0394..16b16483 100644 --- a/sources_non_forked/ale/doc/ale-development.txt +++ b/sources_non_forked/ale/doc/ale-development.txt @@ -151,9 +151,9 @@ ALE is tested with a suite of tests executed in Travis CI and AppVeyor. ALE runs tests with the following versions of Vim in the following environments. 1. Vim 8.0.0027 on Linux via Travis CI. -2. Vim 8.1.0204 on Linux via Travis CI. +2. Vim 8.1.0519 on Linux via Travis CI. 3. NeoVim 0.2.0 on Linux via Travis CI. -4. NeoVim 0.3.0 on Linux via Travis CI. +4. NeoVim 0.3.5 on Linux via Travis CI. 5. Vim 8 (stable builds) on Windows via AppVeyor. If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs @@ -351,6 +351,7 @@ given the above setup are as follows. `GivenCommandOutput [...]` - Define output for ale#command#Run. `AssertFixer results` - Check the fixer results +`AssertFixerNotExecuted` - Check that fixers will not be executed. =============================================================================== diff --git a/sources_non_forked/ale/doc/ale-elm.txt b/sources_non_forked/ale/doc/ale-elm.txt index bb7a6132..823b53e1 100644 --- a/sources_non_forked/ale/doc/ale-elm.txt +++ b/sources_non_forked/ale/doc/ale-elm.txt @@ -29,20 +29,44 @@ 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* +elm-ls *ale-elm-elm-ls* -g:ale_elm_lsp_executable *g:ale_elm_lsp_executable* - *b:ale_elm_lsp_executable* +g:ale_elm_ls_executable *g:ale_elm_ls_executable* + *b:ale_elm_ls_executable* Type: |String| - Default: `'elm-lsp'` + Default: `'elm-language-server'` See |ale-integrations-local-executables| -g:ale_elm_lsp_use_global *g:ale_elm_lsp_use_global* - *b:ale_elm_lsp_use_global* +g:ale_elm_ls_use_global *g:ale_elm_ls_use_global* + *b:ale_elm_ls_use_global* Type: |Number| - Default: `get(g:, 'ale_use_global_executables', 0)` + Default: `get(g:, 'ale_use_global_executables', 1)` + + See |ale-integrations-local-executables| + + +g:ale_elm_ls_elm_path *g:ale_elm_ls_elm_path* + *b:ale_elm_ls_elm_path* + Type: |String| + Default: `'elm'` + + See |ale-integrations-local-executables| + + +g:ale_elm_ls_elm_format_path *g:ale_elm_ls_elm_format_path* + *b:ale_elm_ls_elm_format_path* + Type: |String| + Default: `'elm-format'` + + See |ale-integrations-local-executables| + + +g:ale_elm_ls_elm_test_path *g:ale_elm_ls_elm_test_path* + *b:ale_elm_ls_elm_test_path* + Type: |String| + Default: `'elm-test'` See |ale-integrations-local-executables| diff --git a/sources_non_forked/ale/doc/ale-erlang.txt b/sources_non_forked/ale/doc/ale-erlang.txt index ad3c1e5a..59993a99 100644 --- a/sources_non_forked/ale/doc/ale-erlang.txt +++ b/sources_non_forked/ale/doc/ale-erlang.txt @@ -3,6 +3,35 @@ ALE Erlang Integration *ale-erlang-options* =============================================================================== +dialyzer *ale-erlang-dialyzer* + +g:ale_erlang_dialyzer_executable *g:ale_erlang_dialyzer_executable* + *b:ale_erlang_dialyzer_executable* + Type: |String| + Default: `'dialyzer'` + + This variable can be changed to specify the dialyzer executable. + + +g:ale_erlang_dialyzer_plt_file *g:ale_erlang_dialyzer_plt_file* + *b:ale_erlang_dialyzer_plt_file* + Type: |String| + + This variable can be changed to specify the path to the PLT file. By + default, it will search for the PLT file inside the `_build` directory. If + there isn't one, it will fallback to the path `$REBAR_PLT_DIR/dialyzer/plt`. + Otherwise, it will default to `$HOME/.dialyzer_plt`. + + +g:ale_erlang_dialyzer_rebar3_profile *g:ale_erlang_dialyzer_rebar3_profile* + *b:ale_erlang_dialyzer_rebar3_profile* + Type: |String| + Default: `'default'` + + This variable can be changed to specify the profile that is used to + run dialyzer with rebar3. + +------------------------------------------------------------------------------- erlc *ale-erlang-erlc* g:ale_erlang_erlc_options *g:ale_erlang_erlc_options* diff --git a/sources_non_forked/ale/doc/ale-go.txt b/sources_non_forked/ale/doc/ale-go.txt index 611e3fdd..be53783e 100644 --- a/sources_non_forked/ale/doc/ale-go.txt +++ b/sources_non_forked/ale/doc/ale-go.txt @@ -30,6 +30,16 @@ g:ale_go_go_executable *g:ale_go_go_options* the `gomod` fixer. +g:ale_go_go111module *g:ale_go_go111module* + *b:ale_go_go111module* + Type: |String| + Default: `''` + + Override the value of the `$GO111MODULE` environment variable for + golang tools. + + + =============================================================================== bingo *ale-go-bingo* diff --git a/sources_non_forked/ale/doc/ale-handlebars.txt b/sources_non_forked/ale/doc/ale-handlebars.txt index 061c5d3c..5daec5b3 100644 --- a/sources_non_forked/ale/doc/ale-handlebars.txt +++ b/sources_non_forked/ale/doc/ale-handlebars.txt @@ -2,6 +2,13 @@ ALE Handlebars Integration *ale-handlebars-options* +=============================================================================== +prettier *ale-handlebars-prettier* + +See |ale-javascript-prettier| for information about the available options. +Uses glimmer parser by default. + + =============================================================================== ember-template-lint *ale-handlebars-embertemplatelint* diff --git a/sources_non_forked/ale/doc/ale-haskell.txt b/sources_non_forked/ale/doc/ale-haskell.txt index e2073e37..5dd3ec15 100644 --- a/sources_non_forked/ale/doc/ale-haskell.txt +++ b/sources_non_forked/ale/doc/ale-haskell.txt @@ -12,6 +12,7 @@ g:ale_haskell_brittany_executable *g:ale_haskell_brittany_executable* This variable can be changed to use a different executable for brittany. + =============================================================================== floskell *ale-haskell-floskell* @@ -22,6 +23,7 @@ g:ale_haskell_floskell_executable *g:ale_haskell_floskell_executable* This variable can be changed to use a different executable for floskell. + =============================================================================== ghc *ale-haskell-ghc* @@ -32,6 +34,7 @@ g:ale_haskell_ghc_options *g:ale_haskell_ghc_options* This variable can be changed to modify flags given to ghc. + =============================================================================== ghc-mod *ale-haskell-ghc-mod* @@ -42,6 +45,7 @@ g:ale_haskell_ghc_mod_executable *g:ale_haskell_ghc_mod_executable* This variable can be changed to use a different executable for ghc-mod. + =============================================================================== cabal-ghc *ale-haskell-cabal-ghc* @@ -53,6 +57,7 @@ g:ale_haskell_cabal_ghc_options *g:ale_haskell_cabal_ghc_options* This variable can be changed to modify flags given to ghc through cabal exec. + =============================================================================== hdevtools *ale-haskell-hdevtools* @@ -87,6 +92,18 @@ g:ale_haskell_hfmt_executable *g:ale_haskell_hfmt_executable* This variable can be changed to use a different executable for hfmt. + +=============================================================================== +hindent *ale-haskell-hindent* + +g:ale_haskell_hindent_executable *g:ale_haskell_hindent_executable* + *b:ale_haskell_hindent_executable* + Type: |String| + Default: `'hindent'` + + This variable can be changed to use a different executable for hindent. + + =============================================================================== hlint *ale-haskell-hlint* @@ -106,6 +123,7 @@ g:ale_haskell_hlint_options g:ale_haskell_hlint_options This variable can be used to pass extra options to the underlying hlint executable. + =============================================================================== stack-build *ale-haskell-stack-build* @@ -117,6 +135,7 @@ g:ale_haskell_stack_build_options *g:ale_haskell_stack_build_options* We default to using `'--fast'`. Since Stack generates binaries, your programs will be slower unless you separately rebuild them outside of ALE. + =============================================================================== stack-ghc *ale-haskell-stack-ghc* @@ -128,6 +147,7 @@ g:ale_haskell_stack_ghc_options *g:ale_haskell_stack_ghc_options* This variable can be changed to modify flags given to ghc through `stack ghc` + =============================================================================== stylish-haskell *ale-haskell-stylish-haskell* @@ -139,6 +159,7 @@ g:ale_haskell_stylish_haskell_executable This variable can be changed to use a different executable for stylish-haskell. + =============================================================================== hie *ale-haskell-hie* @@ -150,5 +171,6 @@ g:ale_haskell_hie_executable *g:ale_haskell_hie_executable* This variable can be changed to use a different executable for the haskell ide engine. i.e. `'hie-wrapper'` + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale-hcl.txt b/sources_non_forked/ale/doc/ale-hcl.txt index 8060ac44..59b0a9da 100644 --- a/sources_non_forked/ale/doc/ale-hcl.txt +++ b/sources_non_forked/ale/doc/ale-hcl.txt @@ -5,7 +5,7 @@ ALE HCL Integration *ale-hcl-options* =============================================================================== terraform-fmt *ale-hcl-terraform-fmt* -See |ale-terraform-fmt| for information about the available options. +See |ale-terraform-fmt-fixer| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale-java.txt b/sources_non_forked/ale/doc/ale-java.txt index 2805c9c8..32f0e6eb 100644 --- a/sources_non_forked/ale/doc/ale-java.txt +++ b/sources_non_forked/ale/doc/ale-java.txt @@ -5,14 +5,41 @@ ALE Java Integration *ale-java-options* =============================================================================== checkstyle *ale-java-checkstyle* +g:ale_java_checkstyle_config *g:ale_java_checkstyle_config* + *b:ale_java_checkstyle_config* + + Type: |String| + Default: `'/google_checks.xml'` + + A path to a checkstyle configuration file. + + If a configuration file is specified with |g:ale_java_checkstyle_options|, + it will be preferred over this setting. + + The path to the configuration file can be an absolute path or a relative + path. ALE will search for the relative path in parent directories. + + +g:ale_java_checkstyle_executable *g:ale_java_checkstyle_executable* + *b:ale_java_checkstyle_executable* + + Type: |String| + Default: 'checkstyle' + + This variable can be changed to modify the executable used for checkstyle. + + g:ale_java_checkstyle_options *g:ale_java_checkstyle_options* *b:ale_java_checkstyle_options* - Type: String - Default: '-c /google_checks.xml' + Type: |String| + Default: `''` This variable can be changed to modify flags given to checkstyle. + If a configuration file is specified with `-c`, it will be used instead of + configuration files set with |g:ale_java_checkstyle_config|. + =============================================================================== javac *ale-java-javac* @@ -90,16 +117,46 @@ or This generates a dist/mac or dist/windows directory that contains the language server. To let ALE use this language server you need to set the -g:ale_java_javalsp_executable variable to the absolute path of the java +g:ale_java_javalsp_executable variable to the absolute path of the launcher executable in this directory. g:ale_java_javalsp_executable *g:ale_java_javalsp_executable* *b:ale_java_javalsp_executable* Type: |String| - Default: `'java'` + Default: `''` -This variable can be changed to use a different executable for java. +This variable must be set to the absolute path of the language server launcher +executable. For example: +> + let g:ale_java_javalsp_executable=/java-language-server/dist/mac/bin/launcher +< +g:ale_java_javalsp_config *g:ale_java_javalsp_config* + *b:ale_java_javalsp_config* + Type: |Dictionary| + Default: `{}` + +The javalsp linter automatically detects external depenencies for Maven and +Gradle projects. In case the javalsp fails to detect some of them, you can +specify them setting a dictionary to |g:ale_java_javalsp_config| variable. +> + let g:ale_java_javalsp_executable = + \ { + \ 'java': { + \ 'externalDependencies': [ + \ 'junit:junit:jar:4.12:test', " Maven format + \ 'junit:junit:4.1' " Gradle format + \ ], + \ 'classPath': [ + \ 'lib/some-dependency.jar', + \ '/android-sdk/platforms/android-28.jar' + \ ] + \ } + \ } + +The Java language server will look for the dependencies you specify in +`externalDependencies` array in your Maven and Gradle caches ~/.m2 and +~/.gradle. =============================================================================== eclipselsp *ale-java-eclipselsp* @@ -118,7 +175,7 @@ located inside the repository folder `eclipse.jdt.ls`. Please ensure to set |g:ale_java_eclipselsp_path| to the absolute path of that folder. You could customize compiler options and code assists of the server. -Under your project folder, modify the file `.settings/org.eclipse.jdt.core.prefs` +Under your project folder, modify the file `.settings/org.eclipse.jdt.core.prefs` with options presented at https://help.eclipse.org/neon/topic/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/JavaCore.html. @@ -130,7 +187,7 @@ g:ale_java_eclipselsp_path *g:ale_java_eclipselsp_path* Absolute path to the location of the eclipse.jdt.ls repository folder. Or if you have VSCode extension installed the absolute path to the VSCode extensions - folder (e.g. $HOME/.vscode/extensions in Linux). + folder (e.g. $HOME/.vscode/extensions/redhat.java-0.4x.0 in Linux). g:ale_java_eclipselsp_executable *g:ale_java_eclipse_executable* @@ -141,6 +198,31 @@ g:ale_java_eclipselsp_executable *g:ale_java_eclipse_executable* This variable can be set to change the executable path used for java. +g:ale_java_eclipselsp_config_path *g:ale_java_eclipse_config_path* + *b:ale_java_eclipse_config_path* + Type: |String| + Default: `''` + + Set this variable to change the configuration directory path used by + eclipselsp (e.g. `$HOME/.jdtls` in Linux). + By default ALE will attempt to use the configuration within the installation + directory. + This setting is particularly useful when eclipselsp is installed in a + non-writable directory like `/usr/share/java/jdtls`, as is the case when + installed via system package. + + +g:ale_java_eclipselsp_workspace_path *g:ale_java_eclipselsp_workspace_path* + *b:ale_java_eclipselsp_workspace_path* + + Type: |String| + Default: `''` + + If you have Eclipse installed is good idea to set this variable to the + absolute path of the Eclipse workspace. If not set this value will be set to + the parent folder of the project root. + + =============================================================================== uncrustify *ale-java-uncrustify* diff --git a/sources_non_forked/ale/doc/ale-purescript.txt b/sources_non_forked/ale/doc/ale-purescript.txt new file mode 100644 index 00000000..33fd2429 --- /dev/null +++ b/sources_non_forked/ale/doc/ale-purescript.txt @@ -0,0 +1,33 @@ +=============================================================================== +ALE PureScript Integration *ale-purescript-options* + + +=============================================================================== +purescript-language-server *ale-purescript-language-server* + +PureScript Language Server + (https://github.com/nwolverson/purescript-language-server) + +g:ale_purescript_ls_executable g:ale_purescript_ls_executable + b:ale_purescript_ls_executable + Type: |String| + Default: `'purescript-language-server'` + + PureScript language server executable. + +g:ale_purescript_ls_config g:ale_purescript_ls_config + b:ale_purescript_ls_config + Type: |Dictionary| + Default: `{}` + + Dictionary containing configuration settings that will be passed to the + language server. For example, with a spago project: + { + \ 'purescript': { + \ 'addSpagoSources': v:true, + \ 'addNpmPath': v:true, + \ 'buildCommand': 'spago build -- --json-errors' + \ } + \} +=============================================================================== + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale-python.txt b/sources_non_forked/ale/doc/ale-python.txt index 7dd3b65d..9d5846d2 100644 --- a/sources_non_forked/ale/doc/ale-python.txt +++ b/sources_non_forked/ale/doc/ale-python.txt @@ -29,7 +29,7 @@ ALE will look for configuration files with the following filenames. > tox.ini mypy.ini pycodestyle.cfg - flake8.cfg + .flake8 .flake8rc pylama.ini pylintrc @@ -672,6 +672,36 @@ g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv* if true. This is overridden by a manually-set executable. +=============================================================================== +reorder-python-imports *ale-python-reorder_python_imports* + +g:ale_python_reorder_python_imports_executable + *g:ale_python_reorder_python_imports_executable* + *b:ale_python_reorder_python_imports_executable* + Type: |String| + Default: `'reorder-python-imports'` + + See |ale-integrations-local-executables| + + +g:ale_python_reorder_python_imports_options + *g:ale_python_reorder_python_imports_options* + *b:ale_python_reorder_python_imports_options* + Type: |String| + Default: `''` + + This variable can be set to pass extra options to reorder-python-imports. + + +g:ale_python_reorder_python_imports_use_global + *g:ale_python_reorder_python_imports_use_global* + *b:ale_python_reorder_python_imports_use_global* + Type: |Number| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== vulture *ale-python-vulture* diff --git a/sources_non_forked/ale/doc/ale-reasonml.txt b/sources_non_forked/ale/doc/ale-reasonml.txt index 426d4c46..b8729a55 100644 --- a/sources_non_forked/ale/doc/ale-reasonml.txt +++ b/sources_non_forked/ale/doc/ale-reasonml.txt @@ -5,18 +5,19 @@ ALE ReasonML Integration *ale-reasonml-options* =============================================================================== merlin *ale-reasonml-merlin* - To use merlin linter for ReasonML source code you need to make sure Merlin - for Vim is correctly configured. See the corresponding Merlin wiki page for - detailed instructions - (https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch). +To use merlin linter for ReasonML source code you need to make sure Merlin for +Vim is correctly configured. See the corresponding Merlin wiki page for +detailed instructions: +https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch =============================================================================== ols *ale-reasonml-ols* - The `ocaml-language-server` is the engine that powers OCaml and ReasonML - editor support using the Language Server Protocol. See the installation - instructions: - https://github.com/freebroccolo/ocaml-language-server#installation +The `ocaml-language-server` is the engine that powers OCaml and ReasonML +editor support using the Language Server Protocol. See the installation +instructions: +https://github.com/freebroccolo/ocaml-language-server#installation + g:ale_reason_ols_executable *g:ale_reason_ols_executable* *b:ale_reason_ols_executable* @@ -25,6 +26,7 @@ g:ale_reason_ols_executable *g:ale_reason_ols_executable* This variable can be set to change the executable path for `ols`. + g:ale_reason_ols_use_global *g:ale_reason_ols_use_global* *b:ale_reason_ols_use_global* Type: |String| @@ -33,6 +35,24 @@ g:ale_reason_ols_use_global *g:ale_reason_ols_use_global* This variable can be set to `1` to always use the globally installed executable. See also |ale-integrations-local-executables|. + +=============================================================================== +reason-language-server *ale-reasonml-language-server* + +Note: You must set an executable - there is no 'default' install location. +Go to https://github.com/jaredly/reason-language-server and download the +latest release. You can place it anywhere, but ensure you set the executable +path. + + +g:ale_reason_ls_executable *g:ale_reason_ls_executable* + *b:ale_reason_ls_executable* + Type: |String| + + This variable defines the standard location of the language server + executable. This must be set. + + =============================================================================== refmt *ale-reasonml-refmt* @@ -43,6 +63,7 @@ g:ale_reasonml_refmt_executable *g:ale_reasonml_refmt_executable* This variable can be set to pass the path of the refmt fixer. + g:ale_reasonml_refmt_options *g:ale_reasonml_refmt_options* *b:ale_reasonml_refmt_options* Type: |String| @@ -50,5 +71,6 @@ g:ale_reasonml_refmt_options *g:ale_reasonml_refmt_options* This variable can be set to pass additional options to the refmt fixer. + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale-ruby.txt b/sources_non_forked/ale/doc/ale-ruby.txt index bf971e7c..e373ab8e 100644 --- a/sources_non_forked/ale/doc/ale-ruby.txt +++ b/sources_non_forked/ale/doc/ale-ruby.txt @@ -129,6 +129,26 @@ g:ale_ruby_solargraph_executable *g:ale_ruby_solargraph_executable* from binstubs or a bundle. +=============================================================================== +sorbet *ale-ruby-sorbet* + +g:ale_ruby_sorbet_executable *g:ale_ruby_sorbet_executable* + *b:ale_ruby_sorbet_executable* + Type: String + Default: `'srb'` + + Override the invoked sorbet binary. Set this to `'bundle'` to invoke + `'bundle` `exec` srb'. + + +g:ale_ruby_sorbet_options *g:ale_ruby_sorbet_options* + *b:ale_ruby_sorbet_options* + Type: |String| + Default: `''` + + This variable can be change to modify flags given to sorbet. + + =============================================================================== standardrb *ale-ruby-standardrb* diff --git a/sources_non_forked/ale/doc/ale-sql.txt b/sources_non_forked/ale/doc/ale-sql.txt index 75d4b0cf..f9bc6ac2 100644 --- a/sources_non_forked/ale/doc/ale-sql.txt +++ b/sources_non_forked/ale/doc/ale-sql.txt @@ -2,6 +2,24 @@ ALE SQL Integration *ale-sql-options* +=============================================================================== +pgformatter *ale-sql-pgformatter* + +g:ale_sql_pgformatter_executable *g:ale_sql_pgformatter_executable* + *b:ale_sql_pgformatter_executable* + Type: |String| + Default: `'pg_format'` + + This variable sets executable used for pgformatter. + +g:ale_sql_pgformatter_options *g:ale_sql_pgformatter_options* + *b:ale_sql_pgformatter_options* + Type: |String| + Default: `''` + + This variable can be set to pass additional options to the pgformatter fixer. + + =============================================================================== sqlfmt *ale-sql-sqlfmt* diff --git a/sources_non_forked/ale/doc/ale-supported-languages-and-tools.txt b/sources_non_forked/ale/doc/ale-supported-languages-and-tools.txt index d6fbafa6..37345f7b 100644 --- a/sources_non_forked/ale/doc/ale-supported-languages-and-tools.txt +++ b/sources_non_forked/ale/doc/ale-supported-languages-and-tools.txt @@ -14,6 +14,7 @@ Notes: * Ada * `gcc` + * `gnatpp` * Ansible * `ansible-lint` * API Blueprint @@ -53,6 +54,7 @@ Notes: * `gcc` * `uncrustify` * C# + * `csc`!! * `mcs` * `mcsc`!! * `uncrustify` @@ -181,6 +183,7 @@ Notes: * `hdevtools` * `hfmt` * `hie` + * `hindent` * `hlint` * `stack-build`!! * `stack-ghc` @@ -236,6 +239,7 @@ Notes: * `lacheck` * `proselint` * `redpen` + * `texlab` * `textlint` * `vale` * `write-good` @@ -337,6 +341,8 @@ Notes: * `languageserver` * `puppet` * `puppet-lint` +* PureScript + * `purescript-language-server` * Python * `autopep8` * `bandit` @@ -352,6 +358,7 @@ Notes: * `pylint`!! * `pyls` * `pyre` + * `reorder-python-imports` * `vulture`!! * `yapf` * QML @@ -365,6 +372,7 @@ Notes: * ReasonML * `merlin` * `ols` + * `reason-language-server` * `refmt` * reStructuredText * `alex`!! @@ -386,6 +394,7 @@ Notes: * `ruby` * `rufo` * `solargraph` + * `sorbet` * `standardrb` * Rust * `cargo`!! @@ -414,6 +423,7 @@ Notes: * `solhint` * `solium` * SQL + * `pgformatter` * `sqlfmt` * `sqlint` * Stylus diff --git a/sources_non_forked/ale/doc/ale-terraform.txt b/sources_non_forked/ale/doc/ale-terraform.txt index 49a55028..387fd732 100644 --- a/sources_non_forked/ale/doc/ale-terraform.txt +++ b/sources_non_forked/ale/doc/ale-terraform.txt @@ -3,7 +3,7 @@ ALE Terraform Integration *ale-terraform-options* =============================================================================== -fmt *ale-terraform-fmt* +terraform-fmt-fixer *ale-terraform-fmt-fixer* g:ale_terraform_fmt_executable *g:ale_terraform_fmt_executable* *b:ale_terraform_fmt_executable* @@ -20,6 +20,18 @@ g:ale_terraform_fmt_options *g:ale_terraform_fmt_options* Default: `''` +=============================================================================== +terraform *ale-terraform-terraform* + +g:ale_terraform_terraform_executable *g:ale_terraform_terraform_executable* + *b:ale_terraform_terraform_executable* + + Type: |String| + Default: `'terraform'` + + This variable can be changed to use a different executable for terraform. + + =============================================================================== tflint *ale-terraform-tflint* diff --git a/sources_non_forked/ale/doc/ale-tex.txt b/sources_non_forked/ale/doc/ale-tex.txt index b1b09117..ceb9fa81 100644 --- a/sources_non_forked/ale/doc/ale-tex.txt +++ b/sources_non_forked/ale/doc/ale-tex.txt @@ -53,5 +53,25 @@ g:ale_tex_latexindent_options *g:ale_tex_latexindent_options* +=============================================================================== +texlab *ale-tex-texlab* + +g:ale_tex_texlab_executable *g:ale_tex_texlab_executable* + *b:ale_tex_texlab_executable* + Type: |String| + Default: `'texlab'` + + This variable can be changed to change the path to texlab. + + +g:ale_tex_texlab_options *g:ale_tex_texlab_options* + *b:ale_tex_texlab_options* + Type: |String| + Default: `''` + + This variable can be changed to modify flags given to texlab. + + + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/sources_non_forked/ale/doc/ale.txt b/sources_non_forked/ale/doc/ale.txt index 2a086981..beca8546 100644 --- a/sources_non_forked/ale/doc/ale.txt +++ b/sources_non_forked/ale/doc/ale.txt @@ -84,7 +84,7 @@ have even saved your changes. ALE will check your code in the following circumstances, which can be configured with the associated options. * When you modify a buffer. - |g:ale_lint_on_text_changed| -* On leaving insert mode. (off by default) - |g:ale_lint_on_insert_leave| +* On leaving insert mode. - |g:ale_lint_on_insert_leave| * When you open a new or modified buffer. - |g:ale_lint_on_enter| * When you save a buffer. - |g:ale_lint_on_save| * When the filetype changes for a buffer. - |g:ale_lint_on_filetype_changed| @@ -341,6 +341,17 @@ completion source for Deoplete is named `'ale'`, and should enabled automatically if Deoplete is enabled and configured correctly. Deoplete integration should not be combined with ALE's own implementation. + *ale-asyncomplete-integration* + +ALE additionally integrates with asyncomplete.vim for offering automatic +completion data. ALE's asyncomplete source requires registration and should +use the defaults provided by the|asyncomplete#sources#ale#get_source_options| function > + + " Use ALE's function for asyncomplete defaults + au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#ale#get_source_options({ + \ 'priority': 10, " Provide your own overrides here + \ })) +> ALE also offers its own completion implementation, which does not require any other plugins. Suggestions will be made while you type after completion is enabled. ALE's own completion implementation can be enabled by setting @@ -349,6 +360,12 @@ is loaded. The delay for completion can be configured with |g:ale_completion_delay|. This setting should not be enabled if you wish to use ALE as a completion source for other plugins. +ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering +completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| > + + " Use ALE's function for omnicompletion. + set omnifunc=ale#completion#OmniFunc +< ALE will only suggest so many possible matches for completion. The maximum number of items can be controlled with |g:ale_completion_max_suggestions|. @@ -947,7 +964,7 @@ g:ale_lint_on_save *g:ale_lint_on_save* g:ale_lint_on_text_changed *g:ale_lint_on_text_changed* Type: |String| - Default: `'always'` + Default: `'normal'` This option controls how ALE will check your files as you make changes. The following values can be used. @@ -972,9 +989,10 @@ g:ale_lint_on_text_changed *g:ale_lint_on_text_changed* g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave* + *b:ale_lint_on_insert_leave* Type: |Number| - Default: `0` + Default: `1` When set to `1` in your vimrc file, this option will cause ALE to run linters when you leave insert mode. @@ -986,6 +1004,10 @@ g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave* " Make using Ctrl+C do the same as Escape, to trigger autocmd commands inoremap <C-c> <Esc> < + A buffer-local version of this setting `b:ale_lint_on_insert_leave` can be + set to `0` to disable linting when leaving insert mode. The setting must + be enabled globally to be enabled locally. + You should set this setting once before ALE is loaded, and restart Vim if you want to change your preferences. See |ale-lint-settings-on-startup|. @@ -1006,10 +1028,13 @@ g:ale_linter_aliases *g:ale_linter_aliases* \ 'Dockerfile': 'dockerfile', \ 'csh': 'sh', \ 'plaintex': 'tex', + \ 'rmarkdown': 'r', \ 'systemverilog': 'verilog', \ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'], \ 'vimwiki': 'markdown', \ 'vue': ['vue', 'javascript'], + \ 'xsd': ['xsd', 'xml'], + \ 'xslt': ['xslt', 'xml'], \ 'zsh': 'sh', \} < @@ -1412,6 +1437,15 @@ g:ale_set_signs *g:ale_set_signs* |ALEWarningLine| - All items with `'type': 'W'` |ALEInfoLine| - All items with `'type': 'I'` + With Neovim 0.3.2 or higher, ALE uses `numhl` option to highlight 'number' + column. It uses the following highlight groups. + + |ALEErrorSignLineNr| - Items with `'type': 'E'` + |ALEWarningSignLineNr| - Items with `'type': 'W'` + |ALEInfoSignLineNr| - Items with `'type': 'I'` + |ALEStyleErrorSignLineNr| - Items with `'type': 'E'` and `'sub_type': 'style'` + |ALEStyleWarningSignLineNr| - Items with `'type': 'W'` and `'sub_type': 'style'` + The markers for the highlights can be customized with the following options: |g:ale_sign_error| @@ -1696,6 +1730,15 @@ ALEErrorSign *ALEErrorSign* The highlight for error signs. See |g:ale_set_signs|. +ALEErrorSignLineNr *ALEErrorSignLineNr* + + Default: `highlight link ALEErrorSignLineNr CursorLineNr` + + The highlight for error signs. See |g:ale_set_signs|. + + NOTE: This highlight is only available on Neovim 0.3.2 or higher. + + ALEInfo *ALEInfo.* *ALEInfo-highlight* Default: `highlight link ALEInfo ALEWarning` @@ -1720,6 +1763,15 @@ ALEInfoLine *ALEInfoLine* See |g:ale_set_signs| and |g:ale_set_highlights|. +ALEInfoSignLineNr *ALEInfoSignLineNr* + + Default: `highlight link ALEInfoSignLineNr CursorLineNr` + + The highlight for error signs. See |g:ale_set_signs|. + + NOTE: This highlight is only available on Neovim 0.3.2 or higher. + + ALEStyleError *ALEStyleError* Default: `highlight link ALEStyleError ALEError` @@ -1734,6 +1786,15 @@ ALEStyleErrorSign *ALEStyleErrorSign* The highlight for style error signs. See |g:ale_set_signs|. +ALEStyleErrorSignLineNr *ALEStyleErrorSignLineNr* + + Default: `highlight link ALEStyleErrorSignLineNr CursorLineNr` + + The highlight for error signs. See |g:ale_set_signs|. + + NOTE: This highlight is only available on Neovim 0.3.2 or higher. + + ALEStyleWarning *ALEStyleWarning* Default: `highlight link ALEStyleWarning ALEError` @@ -1748,6 +1809,15 @@ ALEStyleWarningSign *ALEStyleWarningSign* The highlight for style warning signs. See |g:ale_set_signs|. +ALEStyleWarningSignLineNr *ALEStyleWarningSignLineNr* + + Default: `highlight link ALEStyleWarningSignLineNr CursorLineNr` + + The highlight for error signs. See |g:ale_set_signs|. + + NOTE: This highlight is only available on Neovim 0.3.2 or higher. + + ALEVirtualTextError *ALEVirtualTextError* Default: `highlight link ALEVirtualTextError ALEError` @@ -1807,6 +1877,15 @@ ALEWarningSign *ALEWarningSign* The highlight for warning signs. See |g:ale_set_signs|. +ALEWarningSignLineNr *ALEWarningSignLineNr* + + Default: `highlight link ALEWarningSignLineNr CursorLineNr` + + The highlight for error signs. See |g:ale_set_signs|. + + NOTE: This highlight is only available on Neovim 0.3.2 or higher. + + =============================================================================== 7. Linter/Fixer Options *ale-integration-options* @@ -1913,6 +1992,7 @@ documented in additional help files. ada.....................................|ale-ada-options| gcc...................................|ale-ada-gcc| + gnatpp................................|ale-ada-gnatpp| ansible.................................|ale-ansible-options| ansible-lint..........................|ale-ansible-ansible-lint| asciidoc................................|ale-asciidoc-options| @@ -1961,6 +2041,7 @@ documented in additional help files. uncrustify............................|ale-cpp-uncrustify| ccls..................................|ale-cpp-ccls| c#......................................|ale-cs-options| + csc...................................|ale-cs-csc| mcs...................................|ale-cs-mcs| mcsc..................................|ale-cs-mcsc| uncrustify............................|ale-cs-uncrustify| @@ -1988,9 +2069,10 @@ documented in additional help files. credo.................................|ale-elixir-credo| elm.....................................|ale-elm-options| elm-format............................|ale-elm-elm-format| - elm-lsp...............................|ale-elm-elm-lsp| + elm-ls................................|ale-elm-elm-ls| elm-make..............................|ale-elm-elm-make| erlang..................................|ale-erlang-options| + dialyzer..............................|ale-erlang-dialyzer| erlc..................................|ale-erlang-erlc| syntaxerl.............................|ale-erlang-syntaxerl| eruby...................................|ale-eruby-options| @@ -2027,6 +2109,7 @@ documented in additional help files. hackfmt...............................|ale-hack-hackfmt| hhast.................................|ale-hack-hhast| handlebars..............................|ale-handlebars-options| + prettier..............................|ale-handlebars-prettier| ember-template-lint...................|ale-handlebars-embertemplatelint| haskell.................................|ale-haskell-options| brittany..............................|ale-haskell-brittany| @@ -2036,6 +2119,7 @@ documented in additional help files. cabal-ghc.............................|ale-haskell-cabal-ghc| hdevtools.............................|ale-haskell-hdevtools| hfmt..................................|ale-haskell-hfmt| + hindent...............................|ale-haskell-hindent| hlint.................................|ale-haskell-hlint| stack-build...........................|ale-haskell-stack-build| stack-ghc.............................|ale-haskell-stack-ghc| @@ -2160,6 +2244,8 @@ documented in additional help files. puppet................................|ale-puppet-puppet| puppetlint............................|ale-puppet-puppetlint| puppet-languageserver.................|ale-puppet-languageserver| + purescript..............................|ale-purescript-options| + purescript-language-server............|ale-purescript-language-server| pyrex (cython)..........................|ale-pyrex-options| cython................................|ale-pyrex-cython| python..................................|ale-python-options| @@ -2177,6 +2263,7 @@ documented in additional help files. pylint................................|ale-python-pylint| pyls..................................|ale-python-pyls| pyre..................................|ale-python-pyre| + reorder-python-imports................|ale-python-reorder_python_imports| vulture...............................|ale-python-vulture| yapf..................................|ale-python-yapf| qml.....................................|ale-qml-options| @@ -2187,6 +2274,7 @@ documented in additional help files. reasonml................................|ale-reasonml-options| merlin................................|ale-reasonml-merlin| ols...................................|ale-reasonml-ols| + reason-language-server................|ale-reasonml-language-server| refmt.................................|ale-reasonml-refmt| restructuredtext........................|ale-restructuredtext-options| textlint..............................|ale-restructuredtext-textlint| @@ -2199,6 +2287,7 @@ documented in additional help files. ruby..................................|ale-ruby-ruby| rufo..................................|ale-ruby-rufo| solargraph............................|ale-ruby-solargraph| + sorbet................................|ale-ruby-sorbet| standardrb............................|ale-ruby-standardrb| rust....................................|ale-rust-options| cargo.................................|ale-rust-cargo| @@ -2229,6 +2318,7 @@ documented in additional help files. spec....................................|ale-spec-options| rpmlint...............................|ale-spec-rpmlint| sql.....................................|ale-sql-options| + pgformatter...........................|ale-sql-pgformatter| sqlfmt................................|ale-sql-sqlfmt| stylus..................................|ale-stylus-options| stylelint.............................|ale-stylus-stylelint| @@ -2239,12 +2329,14 @@ documented in additional help files. tcl.....................................|ale-tcl-options| nagelfar..............................|ale-tcl-nagelfar| terraform...............................|ale-terraform-options| - fmt...................................|ale-terraform-fmt| + terraform-fmt-fixer...................|ale-terraform-fmt-fixer| + terraform.............................|ale-terraform-terraform| tflint................................|ale-terraform-tflint| tex.....................................|ale-tex-options| chktex................................|ale-tex-chktex| lacheck...............................|ale-tex-lacheck| latexindent...........................|ale-tex-latexindent| + texlab................................|ale-tex-texlab| texinfo.................................|ale-texinfo-options| write-good............................|ale-texinfo-write-good| text....................................|ale-text-options| @@ -2797,6 +2889,13 @@ ale#command#ManageFile(buffer, filename) *ale#command#ManageFile()* manages directories separately with the |ale#command#ManageDirectory| function. +ale#completion#OmniFunc(findstart, base) *ale#completion#OmniFunc()* + + A completion function to use with 'omnifunc'. + + See |ale-completion|. + + ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()* Given a buffer number, this function will return the list of problems @@ -3174,6 +3273,33 @@ ale#linter#PreventLoading(filetype) *ale#linter#PreventLoading()* |runtimepath| for that filetype. This function can be called from vimrc or similar to prevent ALE from loading linters. + +ale#lsp_linter#SendRequest(buffer, linter_name, message, [Handler]) + *ale#lsp_linter#SendRequest()* + + Send a custom request to an LSP linter. The arguments are defined as + follows: + + `buffer` A valid buffer number. + + `linter_name` A |String| identifying an LSP linter that is available and + enabled for the |filetype| of `buffer`. + + `message` A |List| in the form `[is_notification, method, parameters]`, + containing three elements: + `is_notification` - an |Integer| that has value 1 if the + request is a notification, 0 otherwise; + `method` - a |String|, identifying an LSP method supported + by `linter`; + `parameters` - a |dictionary| of LSP parameters that are + applicable to `method`. + + `Handler` Optional argument, meaningful only when `message[0]` is 0. + A |Funcref| that is called when a response to the request is + received, and takes as unique argument a dictionary + representing the response obtained from the server. + + ale#other_source#ShowResults(buffer, linter_name, loclist) *ale#other_source#ShowResults()* @@ -3312,7 +3438,7 @@ snazzy looking ale glass logo. Cheers, Mark! 11. Contact *ale-contact* If you like this plugin, and wish to get in touch, check out the GitHub -page for issues and more at https://github.com/w0rp/ale +page for issues and more at https://github.com/dense-analysis/ale If you wish to contact the author of this plugin directly, please feel free to send an email to devw0rp@gmail.com. diff --git a/sources_non_forked/ale/plugin/ale.vim b/sources_non_forked/ale/plugin/ale.vim index cf39d632..6262a7c4 100644 --- a/sources_non_forked/ale/plugin/ale.vim +++ b/sources_non_forked/ale/plugin/ale.vim @@ -71,12 +71,12 @@ let g:ale_linter_aliases = get(g:, 'ale_linter_aliases', {}) let g:ale_lint_delay = get(g:, 'ale_lint_delay', 200) " This flag can be set to 'never' to disable linting when text is changed. -" This flag can also be set to 'insert' or 'normal' to lint when text is -" changed only in insert or normal mode respectively. -let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 'always') +" This flag can also be set to 'always' or 'insert' to lint when text is +" changed in both normal and insert mode, or only in insert mode respectively. +let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 'normal') " This flag can be set to 1 to enable linting when leaving insert mode. -let g:ale_lint_on_insert_leave = get(g:, 'ale_lint_on_insert_leave', 0) +let g:ale_lint_on_insert_leave = get(g:, 'ale_lint_on_insert_leave', 1) " This flag can be set to 0 to disable linting when the buffer is entered. let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', 1) @@ -142,6 +142,9 @@ let g:ale_completion_enabled = get(g:, 'ale_completion_enabled', 0) " Enable automatic detection of pipenv for Python linters. let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0) +" This variable can be overridden to set the GO111MODULE environment variable. +let g:ale_go_go111module = get(g:, 'ale_go_go111module', '') + if g:ale_set_balloons call ale#balloon#Enable() endif diff --git a/sources_non_forked/ale/rplugin/python3/deoplete/sources/ale.py b/sources_non_forked/ale/rplugin/python3/deoplete/sources/ale.py index 7ed2f6c0..3955ed2d 100644 --- a/sources_non_forked/ale/rplugin/python3/deoplete/sources/ale.py +++ b/sources_non_forked/ale/rplugin/python3/deoplete/sources/ale.py @@ -21,13 +21,23 @@ class Source(Base): self.name = 'ale' self.mark = '[L]' - self.rank = 100 + self.rank = 1000 self.is_bytepos = True self.min_pattern_length = 1 + # Do not forget to update s:trigger_character_map in completion.vim in + # updating entries in this map. + self.input_patterns = { + '_': r'\.\w*$', + 'rust': r'(\.|::)\w*$', + 'typescript': r'(\.|\'|")\w*$', + 'cpp': r'(\.|::|->)\w*$', + } # Returns an integer for the start position, as with omnifunc. - def get_completion_position(self): - return self.vim.call('ale#completion#GetCompletionPosition') + def get_complete_position(self, context): + return self.vim.call( + 'ale#completion#GetCompletionPositionForDeoplete', context['input'] + ) def gather_candidates(self, context): # Stop early if ALE can't provide completion data for this buffer. diff --git a/sources_non_forked/ale/supported-tools.md b/sources_non_forked/ale/supported-tools.md index 18d69388..c933f510 100644 --- a/sources_non_forked/ale/supported-tools.md +++ b/sources_non_forked/ale/supported-tools.md @@ -23,6 +23,7 @@ formatting. * Ada * [gcc](https://gcc.gnu.org) + * [gnatpp](https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/gnat_utility_programs.html#the-gnat-pretty-printer-gnatpp) :floppy_disk: * Ansible * [ansible-lint](https://github.com/willthames/ansible-lint) * API Blueprint @@ -62,6 +63,7 @@ formatting. * [gcc](https://gcc.gnu.org/) * [uncrustify](https://github.com/uncrustify/uncrustify) * C# + * [csc](http://www.mono-project.com/docs/about-mono/languages/csharp/) :floppy_disk: see:`help ale-cs-csc` for details and configuration * [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) see:`help ale-cs-mcs` for details * [mcsc](http://www.mono-project.com/docs/about-mono/languages/csharp/) :floppy_disk: see:`help ale-cs-mcsc` for details and configuration * [uncrustify](https://github.com/uncrustify/uncrustify) @@ -124,14 +126,14 @@ formatting. * [hadolint](https://github.com/hadolint/hadolint) * Elixir * [credo](https://github.com/rrrene/credo) - * [dialyxir](https://github.com/jeremyjh/dialyxir) - * [dogma](https://github.com/lpil/dogma) + * [dialyxir](https://github.com/jeremyjh/dialyxir) :floppy_disk: + * [dogma](https://github.com/lpil/dogma) :floppy_disk: * [elixir-ls](https://github.com/JakeBecker/elixir-ls) :warning: * [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) + * [elm-make](https://github.com/elm/compiler) * Erb * [erb](https://apidock.com/ruby/ERB) * [erubi](https://github.com/jeremyevans/erubi) @@ -190,6 +192,7 @@ formatting. * [hdevtools](https://hackage.haskell.org/package/hdevtools) * [hfmt](https://github.com/danstiner/hfmt) * [hie](https://github.com/haskell/haskell-ide-engine) + * [hindent](https://hackage.haskell.org/package/hindent) * [hlint](https://hackage.haskell.org/package/hlint) * [stack-build](https://haskellstack.org/) :floppy_disk: * [stack-ghc](https://haskellstack.org/) @@ -245,6 +248,7 @@ formatting. * [lacheck](https://www.ctan.org/pkg/lacheck) * [proselint](http://proselint.com/) * [redpen](http://redpen.cc/) + * [texlab](https://texlab.netlify.com) ([Rust rewrite](https://github.com/latex-lsp/texlab/tree/rust)) * [textlint](https://textlint.github.io/) * [vale](https://github.com/ValeLint/vale) * [write-good](https://github.com/btford/write-good) @@ -346,6 +350,8 @@ formatting. * [languageserver](https://github.com/lingua-pupuli/puppet-editor-services) * [puppet](https://puppet.com) * [puppet-lint](https://puppet-lint.com) +* PureScript + * [purescript-language-server](https://github.com/nwolverson/purescript-language-server) * Python * [autopep8](https://github.com/hhatto/autopep8) * [bandit](https://github.com/PyCQA/bandit) :warning: @@ -361,6 +367,7 @@ formatting. * [pylint](https://www.pylint.org/) :floppy_disk: * [pyls](https://github.com/palantir/python-language-server) :warning: * [pyre](https://github.com/facebook/pyre-check) :warning: + * [reorder-python-imports](https://github.com/asottile/reorder_python_imports) * [vulture](https://github.com/jendrikseipp/vulture) :warning: :floppy_disk: * [yapf](https://github.com/google/yapf) * QML @@ -374,6 +381,7 @@ formatting. * ReasonML * [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-reasonml-ols` for configuration instructions * [ols](https://github.com/freebroccolo/ocaml-language-server) + * [reason-language-server](https://github.com/jaredly/reason-language-server) * [refmt](https://github.com/reasonml/reason-cli) * reStructuredText * [alex](https://github.com/wooorm/alex) :floppy_disk: @@ -395,6 +403,7 @@ formatting. * [ruby](https://www.ruby-lang.org) * [rufo](https://github.com/ruby-formatter/rufo) * [solargraph](https://solargraph.org) + * [sorbet](https://github.com/sorbet/sorbet) * [standardrb](https://github.com/testdouble/standard) * Rust * [cargo](https://github.com/rust-lang/cargo) :floppy_disk: (see `:help ale-integration-rust` for configuration instructions) @@ -423,6 +432,7 @@ formatting. * [solhint](https://github.com/protofire/solhint) * [solium](https://github.com/duaraghav8/Solium) * SQL + * [pgformatter](https://github.com/darold/pgFormatter) * [sqlfmt](https://github.com/jackc/sqlfmt) * [sqlint](https://github.com/purcell/sqlint) * Stylus diff --git a/sources_non_forked/goyo.vim/autoload/goyo.vim b/sources_non_forked/goyo.vim/autoload/goyo.vim index 94216d1a..6667620e 100644 --- a/sources_non_forked/goyo.vim/autoload/goyo.vim +++ b/sources_non_forked/goyo.vim/autoload/goyo.vim @@ -260,7 +260,7 @@ function! s:goyo_on(dim) augroup goyo autocmd! - autocmd TabLeave * call s:goyo_off() + autocmd TabLeave * nested call s:goyo_off() autocmd VimResized * call s:resize_pads() autocmd ColorScheme * call s:tranquilize() autocmd BufWinEnter * call s:hide_linenr() | call s:hide_statusline() diff --git a/sources_non_forked/lightline.vim/.travis.yml b/sources_non_forked/lightline.vim/.travis.yml index 179c66dc..9c8184a2 100644 --- a/sources_non_forked/lightline.vim/.travis.yml +++ b/sources_non_forked/lightline.vim/.travis.yml @@ -1,7 +1,5 @@ language: generic -sudo: false - install: - git clone --depth=1 https://github.com/thinca/vim-themis /tmp/themis - (if ! test -d $HOME/vim-$VIM_VERSION/bin; then @@ -18,6 +16,8 @@ cache: - $HOME/vim-$VIM_VERSION env: + - VIM_VERSION=8.1.1775 + - VIM_VERSION=8.1.1700 - VIM_VERSION=8.1.0000 - VIM_VERSION=8.0.0000 - VIM_VERSION=7.4 diff --git a/sources_non_forked/lightline.vim/README.md b/sources_non_forked/lightline.vim/README.md index 1e6eb816..656fe90c 100644 --- a/sources_non_forked/lightline.vim/README.md +++ b/sources_non_forked/lightline.vim/README.md @@ -52,11 +52,17 @@ landscape is my colorscheme, which is a high-contrast cterm-supported colorschem + Orthogonality. The plugin does not rely on the implementation of other plugins. Such plugin crossing settings should be configured by users. ## Installation +### [Vim packages](http://vimhelp.appspot.com/repeat.txt.html#packages) (since Vim 7.4.1528) + + git clone https://github.com/itchyny/lightline.vim ~/.vim/pack/plugins/start/lightline + ### [Pathogen](https://github.com/tpope/vim-pathogen) 1. Install with the following command. git clone https://github.com/itchyny/lightline.vim ~/.vim/bundle/lightline.vim +2. Generate help tags with `:Helptags`. + ### [Vundle](https://github.com/VundleVim/Vundle.vim) 1. Add the following configuration to your `.vimrc`. diff --git a/sources_non_forked/lightline.vim/autoload/lightline.vim b/sources_non_forked/lightline.vim/autoload/lightline.vim index 2076a114..127622c0 100644 --- a/sources_non_forked/lightline.vim/autoload/lightline.vim +++ b/sources_non_forked/lightline.vim/autoload/lightline.vim @@ -2,7 +2,7 @@ " Filename: autoload/lightline.vim " Author: itchyny " License: MIT License -" Last Change: 2018/11/24 12:00:00. +" Last Change: 2019/08/20 14:00:00. " ============================================================================= let s:save_cpo = &cpo @@ -11,6 +11,7 @@ set cpo&vim let s:_ = 1 " 1: uninitialized, 2: disabled function! lightline#update() abort + if &buftype ==# 'popup' | return | endif if s:_ if s:_ == 2 | return | endif call lightline#init() @@ -20,7 +21,7 @@ function! lightline#update() abort return endif let w = winnr() - let s = winnr('$') == 1 ? [lightline#statusline(0)] : [lightline#statusline(0), lightline#statusline(1)] + let s = winnr('$') == 1 && w > 0 ? [lightline#statusline(0)] : [lightline#statusline(0), lightline#statusline(1)] for n in range(1, winnr('$')) call setwinvar(n, '&statusline', s[n!=w]) call setwinvar(n, 'lightline', n!=w) @@ -45,7 +46,10 @@ function! lightline#enable() abort call lightline#update() augroup lightline autocmd! - autocmd WinEnter,BufWinEnter,FileType,SessionLoadPost * call lightline#update() + autocmd WinEnter,BufEnter,SessionLoadPost * call lightline#update() + if !has('patch-8.1.1715') + autocmd FileType qf call lightline#update() + endif autocmd SessionLoadPost * call lightline#highlight() autocmd ColorScheme * if !has('vim_starting') || expand('<amatch>') !=# 'macvim' \ | call lightline#update() | call lightline#highlight() | endif diff --git a/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/ayu_mirage.vim b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/ayu_mirage.vim new file mode 100644 index 00000000..85da9025 --- /dev/null +++ b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/ayu_mirage.vim @@ -0,0 +1,39 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/ayu_mirage.vim +" Author: impulse +" License: MIT License +" Last Change: 2019/08/11 11:52:20. +" ============================================================================= +let s:base0 = [ '#d9d7ce', 244 ] +let s:base1 = [ '#d9d7ce', 247 ] +let s:base2 = [ '#607080', 248 ] +let s:base3 = [ '#d9d7ce', 252 ] +let s:base00 = [ '#272d38', 242 ] +let s:base01 = [ '#272d38', 240 ] +let s:base02 = [ '#212733', 238 ] +let s:base023 = [ '#212733', 236 ] +let s:base03 = [ '#ffc44c', 235 ] +let s:yellow = [ '#ffc44c', 180 ] +let s:orange = [ '#ffae57', 173 ] +let s:red = [ '#f07178', 203 ] +let s:magenta = [ '#d4bfff', 216 ] +let s:blue = [ '#59c2ff', 117 ] +let s:cyan = s:blue +let s:green = [ '#bbe67e', 119 ] +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base2, s:base02 ] ] +let s:p.normal.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.left = [ [ s:base1, s:base01 ], [ s:base3, s:base01 ] ] +let s:p.inactive.middle = [ [ s:base1, s:base023 ] ] +let s:p.inactive.right = [ [ s:base1, s:base01 ], [ s:base2, s:base02 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base023, s:red ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base02, s:base03 ] ] +let s:p.tabline.left = [ [ s:base3, s:base00 ] ] +let s:p.tabline.middle = [ [ s:base2, s:base02 ] ] +let s:p.tabline.right = [ [ s:base2, s:base00 ] ] +let s:p.normal.error = [ [ s:base03, s:red ] ] +let s:p.normal.warning = [ [ s:base023, s:yellow ] ] +let g:lightline#colorscheme#ayu_mirage#palette = lightline#colorscheme#flatten(s:p) diff --git a/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/powerlineish.vim b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/powerlineish.vim new file mode 100644 index 00000000..34058a87 --- /dev/null +++ b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/powerlineish.vim @@ -0,0 +1,28 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/powerlineish.vim +" Author: itchyny +" License: MIT License +" Last Change: 2019/06/12 18:47:00. +" ============================================================================= + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ ['darkestgreen', 'brightgreen', 'bold'], ['white', 'gray0'] ] +let s:p.normal.right = [ ['gray10', 'gray2'], ['white', 'gray1'], ['white', 'gray0'] ] +let s:p.inactive.right = [ ['gray1', 'gray5'], ['gray4', 'gray1'], ['gray4', 'gray0'] ] +let s:p.inactive.left = s:p.inactive.right[1:] +let s:p.insert.left = [ ['darkestcyan', 'white', 'bold'], ['mediumcyan', 'darkestblue'] ] +let s:p.insert.right = [ [ 'darkestblue', 'mediumcyan' ], [ 'mediumcyan', 'darkblue' ], [ 'mediumcyan', 'darkestblue' ] ] +let s:p.replace.left = [ ['white', 'brightred', 'bold'], ['white', 'gray0'] ] +let s:p.visual.left = [ ['black', 'brightestorange', 'bold'], ['white', 'gray0'] ] +let s:p.normal.middle = [ [ 'white', 'gray0' ] ] +let s:p.insert.middle = [ [ 'mediumcyan', 'darkestblue' ] ] +let s:p.replace.middle = s:p.normal.middle +let s:p.replace.right = s:p.normal.right +let s:p.tabline.left = [ [ 'gray9', 'gray0' ] ] +let s:p.tabline.tabsel = [ [ 'gray9', 'gray2' ] ] +let s:p.tabline.middle = [ [ 'gray2', 'gray0' ] ] +let s:p.tabline.right = [ [ 'gray9', 'gray1' ] ] +let s:p.normal.error = [ [ 'gray9', 'brightestred' ] ] +let s:p.normal.warning = [ [ 'gray1', 'yellow' ] ] + +let g:lightline#colorscheme#powerlineish#palette = lightline#colorscheme#fill(s:p) diff --git a/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/selenized_dark.vim b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/selenized_dark.vim new file mode 100644 index 00000000..585b948b --- /dev/null +++ b/sources_non_forked/lightline.vim/autoload/lightline/colorscheme/selenized_dark.vim @@ -0,0 +1,50 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/selenized_dark.vim +" Author: Charles Hall +" License: MIT License +" Last Change: 2019/07/22 11:05:34. +" ============================================================================= + +" https://github.com/jan-warchol/selenized/blob/master/the-values.md#selenized-dark +let s:black = [ "#184956", 0 ] +let s:red = [ "#fa5750", 1 ] +let s:green = [ "#75b938", 2 ] +let s:yellow = [ "#dbb32d", 3 ] +let s:blue = [ "#4695f7", 4 ] +let s:magenta = [ "#f275be", 5 ] +let s:cyan = [ "#41c7b9", 6 ] +let s:white = [ "#72898f", 7 ] +let s:brblack = [ "#2d5b69", 8 ] +let s:brred = [ "#ff665c", 9 ] +let s:brgreen = [ "#84c747", 10 ] +let s:bryellow = [ "#ebc13d", 11 ] +let s:brblue = [ "#58a3ff", 12 ] +let s:brmagenta = [ "#ff84cd", 13 ] +let s:brcyan = [ "#53d6c7", 14 ] +let s:brwhite = [ "#cad8d9", 15 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +let s:p.normal.right = [[ s:black, s:blue ],[ s:cyan, s:brblack ],[ s:white, s:black ]] +let s:p.normal.left = [[ s:black, s:blue ],[ s:cyan, s:brblack ]] +let s:p.normal.middle = [[ s:black, s:black ]] +let s:p.normal.error = [[ s:black, s:red ]] +let s:p.normal.warning = [[ s:black, s:yellow ]] + +let s:p.insert.right = [[ s:black, s:green ],[ s:cyan, s:brblack ],[ s:white, s:black ]] +let s:p.insert.left = [[ s:black, s:green ],[ s:cyan, s:brblack ]] + +let s:p.visual.right = [[ s:black, s:magenta ],[ s:cyan, s:brblack ],[ s:white, s:black ]] +let s:p.visual.left = [[ s:black, s:magenta ],[ s:cyan, s:brblack ]] + +let s:p.inactive.left = [[ s:brblue, s:brblack ],[ s:cyan, s:brblack ]] +let s:p.inactive.right = [[ s:brblue, s:brblack ],[ s:cyan, s:brblack ]] + +let s:p.replace.right = [[ s:black, s:red ],[ s:cyan, s:brblack ],[ s:white, s:black ]] +let s:p.replace.left = [[ s:black, s:red ],[ s:cyan, s:brblack ]] + +let s:p.tabline.right = [[ s:black, s:red ]] +let s:p.tabline.left = [[ s:cyan, s:brblack ]] +let s:p.tabline.tabsel = [[ s:black, s:blue ]] + +let g:lightline#colorscheme#selenized_dark#palette = lightline#colorscheme#flatten(s:p) diff --git a/sources_non_forked/lightline.vim/doc/lightline.txt b/sources_non_forked/lightline.vim/doc/lightline.txt index 7c2a886b..cf64523b 100644 --- a/sources_non_forked/lightline.vim/doc/lightline.txt +++ b/sources_non_forked/lightline.vim/doc/lightline.txt @@ -4,7 +4,7 @@ Version: 0.1 Author: itchyny (https://github.com/itchyny) License: MIT License Repository: https://github.com/itchyny/lightline.vim -Last Change: 2018/04/28 00:08:18. +Last Change: 2019/08/14 10:46:55. CONTENTS *lightline-contents* @@ -226,10 +226,12 @@ OPTIONS *lightline-option* < g:lightline.colorscheme *g:lightline.colorscheme* The colorscheme for lightline.vim. - Currently, wombat, solarized, powerline, jellybeans, Tomorrow, - Tomorrow_Night, Tomorrow_Night_Blue, Tomorrow_Night_Eighties, - PaperColor, seoul256, landscape, one, darcula, molokai, materia, - material, OldHope, nord, 16color and deus are available. + Currently, wombat, solarized, powerline, powerlineish, + jellybeans, molokai, seoul256, darcula, selenized_dark, + Tomorrow, Tomorrow_Night, Tomorrow_Night_Blue, + Tomorrow_Night_Bright, Tomorrow_Night_Eighties, PaperColor, + landscape, one, materia, material, OldHope, nord, deus, + srcery_drk, ayu_mirage and 16color are available. The default value is: > let g:lightline.colorscheme = 'default' @@ -986,12 +988,15 @@ Problem 1: *lightline-problem-1* 1. Put all the files under $VIM. - If you are using |vim-pathogen|, install this plugin with the - following command. + If you are to install this plugin using |vim-pathogen|: + + 1. Install this plugin with the following command. > git clone https://github.com/itchyny/lightline.vim \ ~/.vim/bundle/lightline.vim < + 2. Generate help tags with |:Helptags|. + If you are to install this plugin using |Vundle|: 1. Add the following configuration to your diff --git a/sources_non_forked/lightline.vim/plugin/lightline.vim b/sources_non_forked/lightline.vim/plugin/lightline.vim index fc8f5981..d08517d7 100644 --- a/sources_non_forked/lightline.vim/plugin/lightline.vim +++ b/sources_non_forked/lightline.vim/plugin/lightline.vim @@ -2,7 +2,7 @@ " Filename: plugin/lightline.vim " Author: itchyny " License: MIT License -" Last Change: 2018/06/22 08:49:00. +" Last Change: 2019/07/30 12:00:00. " ============================================================================= if exists('g:loaded_lightline') || v:version < 700 @@ -15,12 +15,20 @@ set cpo&vim augroup lightline autocmd! - autocmd WinEnter,BufWinEnter,FileType,SessionLoadPost * call lightline#update() + autocmd WinEnter,BufEnter,SessionLoadPost * call lightline#update() + if !has('patch-8.1.1715') + autocmd FileType qf call lightline#update() + endif autocmd SessionLoadPost * call lightline#highlight() autocmd ColorScheme * if !has('vim_starting') || expand('<amatch>') !=# 'macvim' \ | call lightline#update() | call lightline#highlight() | endif autocmd CursorMoved,BufUnload * call lightline#update_once() augroup END +" This quickfix option was introduced at Vim 85850f3a5ef9, which is the commit +" just before 8.1.1715. Before this patch, autocmd FileType is required to +" overwrite the statusline of the quickfix and location windows. +let g:qf_disable_statusline = 1 + let &cpo = s:save_cpo unlet s:save_cpo diff --git a/sources_non_forked/lightline.vim/test/.themisrc b/sources_non_forked/lightline.vim/test/.themisrc index c226c089..6e0121ce 100644 --- a/sources_non_forked/lightline.vim/test/.themisrc +++ b/sources_non_forked/lightline.vim/test/.themisrc @@ -18,3 +18,5 @@ endfunction function! SID(name) abort return function(printf("\<SNR>%d_%s", s:sid('autoload/lightline.vim'), a:name)) endfunction + +filetype plugin on diff --git a/sources_non_forked/lightline.vim/test/popup.vim b/sources_non_forked/lightline.vim/test/popup.vim new file mode 100644 index 00000000..cc4e882a --- /dev/null +++ b/sources_non_forked/lightline.vim/test/popup.vim @@ -0,0 +1,19 @@ +if !exists('*popup_menu') || !exists('*win_execute') + finish +endif + +let s:suite = themis#suite('popup') +let s:assert = themis#helper('assert') + +function! s:suite.before_each() + let g:lightline = {} + call lightline#init() + tabnew + tabonly +endfunction + +function! s:suite.win_execute_setfiletype() + let id = popup_menu(['aaa', 'bbb'], {}) + call win_execute(id, 'setfiletype vim') + call popup_close(id) +endfunction diff --git a/sources_non_forked/lightline.vim/test/quickfix.vim b/sources_non_forked/lightline.vim/test/quickfix.vim new file mode 100644 index 00000000..df4fce7a --- /dev/null +++ b/sources_non_forked/lightline.vim/test/quickfix.vim @@ -0,0 +1,25 @@ +let s:suite = themis#suite('quickfix') +let s:assert = themis#helper('assert') + +function! s:suite.before_each() + let g:lightline = {} + call lightline#init() + tabnew + tabonly +endfunction + +function! s:suite.quickfix_statusline() + call setloclist(winnr(), []) + lopen + wincmd p + call setloclist(winnr(), []) + for n in range(1, winnr('$')) + let statusline = getwinvar(n, '&statusline') + call s:assert.match(statusline, 'lightline') + if has('patch-8.1.1715') + call s:assert.match(statusline, n == 1 ? '_active_' : '_inactive_') + else + call s:assert.match(statusline, n != 1 ? '_active_' : '_inactive_') + endif + endfor +endfunction diff --git a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index c3ca5eff..00000000 --- a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,28 +0,0 @@ -<!--- To assist in resolving your issue, provide as much information as possible. --> - -### Environment -<!--- Describe your Vim/NERDTree setup. --> - -* Operating System: -* Vim version `:version`: -* NERDTree version `git rev-parse --short HEAD`: -* NERDTree settings applied in your vimrc, if any: - ```vim - ``` - -### Process -<!--- List the steps that will recreate the issue. --> - -1. - -### Current Result -<!--- Describe what you you currently experience from this process. --> - -### Expected Result -<!--- Describe what you would have expected from this process. --> - -### Screenshot(s) - -### Possible Fix -<!--- If you have explored the code, share what you've found. --> - diff --git a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/bug.md b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 00000000..dd351350 --- /dev/null +++ b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,45 @@ +--- +name: "Bug Report" +about: "NERDTree is misbehaving? Tell us about it." +labels: bug +--- +<!-- Attention! Please Read! + +Please fill out ALL the information below so that the issue can be fully +understood. Omitting information will delay the resolution of your issue. It +will be labeled "Needs More Info", and may be closed until there is enough +information. + +Keep in mind that others may have the same question in the future. The better +your information, the more likely they'll be able to help themselves. --> + +#### Self-Diagnosis +<!-- Check the boxes after creating the issue, or use [x]. --> +- [ ] I have searched the [issues](https://github.com/scrooloose/nerdtree/issues) for an answer to my question. +- [ ] I have reviewed the NERDTree documentation. `:h NERDTree` +- [ ] I have reviewed the [Wiki](https://github.com/scrooloose/nerdtree/wiki). +- [ ] I have searched the web for an answer to my question. + +#### Environment (for bug reports) +- [ ] Operating System: +- [ ] Vim/Neovim version `:echo v:version`: +- [ ] NERDTree version, found on 1st line in NERDTree quickhelp `?`: +- [ ] vimrc settings + - [ ] NERDTree variables + ```vim + ``` + - Other NERDTree-dependent Plugins + - [ ] jistr/vim-nerdtree-tabs + - [ ] ryanoasis/vim-devicons + - [ ] tiagofumo/vim-nerdtree-syntax-highlight + - [ ] Xuyuanp/nerdtree-git-plugin + - [ ] Others (specify): + - [ ] I've verified the issue occurs with only NERDTree installed. + +#### Steps to Reproduce the Issue +1. + +#### Current Result (Include screenshots where appropriate.) + +#### Expected Result + diff --git a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/feature_request.md b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..35db0f6a --- /dev/null +++ b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,8 @@ +--- +name: "Feature Request" +about: "What new feature are you requesting for NERDTree?" +labels: "feature request" +--- + +#### Description + diff --git a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/question.md b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..25f15b02 --- /dev/null +++ b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,24 @@ +--- +name: "General Question" +about: "Having trouble setting up NERDTree? Need clarification on a setting? Ask your question here." +labels: "general question" +--- +<!-- Attention! Please Read! + +Please fill out ALL the information below so that the issue can be fully +understood. Omitting information will delay the resolution of your issue. It +will be labeled "Needs More Info", and may be closed until there is enough +information. + +Keep in mind that others may have the same question in the future. The better +your information, the more likely they'll be able to help themselves. --> + +#### Self-Diagnosis +<!-- Check the boxes after creating the issue, or use [x]. --> +- [ ] I have searched the [issues](https://github.com/scrooloose/nerdtree/issues) for an answer to my question. +- [ ] I have reviewed the NERDTree documentation. `:h NERDTree` +- [ ] I have reviewed the [Wiki](https://github.com/scrooloose/nerdtree/wiki). +- [ ] I have searched the web for an answer to my question. + +#### State Your Question + diff --git a/sources_non_forked/nerdtree/.github/PULL_REQUEST_TEMPLATE.md b/sources_non_forked/nerdtree/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..ccd5bf8d --- /dev/null +++ b/sources_non_forked/nerdtree/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +### Description of Changes +Closes # <!-- Issue number this PR addresses. If none, remove this line. --> + + +--- +### New Version Info + +- [ ] Derive a new version number. Increment the: + - [ ] `MAJOR` version when you make incompatible API changes + - [ ] `MINOR` version when you add functionality in a backwards-compatible manner + - [ ] `PATCH` version when you make backwards-compatible bug fixes +- [ ] Update [CHANGELOG.md](https://github.com/scrooloose/nerdtree/blob/master/CHANGELOG.md), following the established pattern. +- [ ] Tag the merge commit, e.g. `git tag -a 3.1.4 -m "v3.1.4" && git push origin --tags` diff --git a/sources_non_forked/nerdtree/CHANGELOG b/sources_non_forked/nerdtree/CHANGELOG deleted file mode 100644 index 6dac46dd..00000000 --- a/sources_non_forked/nerdtree/CHANGELOG +++ /dev/null @@ -1,179 +0,0 @@ -Next - - Fix broken "t" and "T" mappings, tabs now open at end (lifecrisis) #759 - - Update doc with already existing mapping variables (asnr) #699 - - Fix the broken g:NERDTreeBookmarksSort setting (lifecrisis) #696 - - Correct NERDTreeIgnore pattern in doc (cntoplolicon) #648 - - Remove empty segments when splitting path (sooth-sayer) #574 - - Suppress autocmds less agressively (wincent) #578 #691 - - Add an Issues template to ask for more info initially. - - Fix markdown headers in readme (josephfrazier) #676 - - Don't touch @o and @h registers when rendering - - Fix bug with files and directories with dollar signs (alegen) #649 - - Reuse/reopen existing window trees where possible #244 - - Remove NERDTree.previousBuf() - - Change color of arrow (Leeiio) #630 - - Improved a tip in README.markdown (ggicci) #628 - - Shorten delete confimration of empty directory to 'y' (mikeperri) #530 - - Fix API call to open directory tree in window (devm33) #533 - - Change default arrows on non-Windows platforms (gwilk) #546 - - Update to README - combine cd and git clone (zwhitchcox) #584 - - Update to README - Tip: start NERDTree when vim starts (therealplato) #593 - - Escape filename when moving an open buffer (zacharyvoase) #595 - - Fixed incorrect :helptags command in README (curran) #619 - - Fixed incomplete escaping of folder arrows (adityanatraj) #548 - - Added NERDTreeCascadeSingleChildDir option (juanibiapina) #558 - - Replace strchars() with backward compatible workaround. - - Add support for copy command in Windows (SkylerLipthay) #231 - - Fixed typo in README.markdown - :Helptags -> :helptags - - Rename "primary" and "secondary" trees to "tab" and "window" trees. - - Move a bunch of buffer level variables into the NERDTree and UI classes. - - Display cascading dirs on one line to save vertical/horizontal space (@matt-gardner: brainstorming/testing) - - Remove the old style UI - Remove 'NERDTreeDirArrows' option. - - On windows default to + and ~ for expand/collapse directory symbols. - - Lots more refactoring. Move a bunch of b: level vars into b:NERDTree and friends. - -5.0.0 - - Refactor the code significantly: - * Break the classes out into their own files. - * Make the majority of the code OO - previously large parts were - effectively a tangle of "global" methods. - - Add an API to assign flags to nodes. This allows VCS plugins like - https://github.com/Xuyuanp/nerdtree-git-plugin to exist. Thanks to - Xuyuanp for helping design/test/build said API. - - add 'scope' argument to the key map API see :help NERDTreeAddKeyMap() - - add magic [[dir]] and [[file]] flags to NERDTreeIgnore - - add support for custom path filters. See :help NERDTreeAddPathFilter() - - add path listener API. See :help NERDTreePathListenerAPI. - - expand the fs menu functionality to list file properties (PhilRunninger, - apbarrero, JESii) - - make bookmarks work with `~` home shortcuts (hiberabyss) - - show OSX specific fsmenu options in regular vim on mac (evindor) - - make dir arrow icons configurable (PickRelated) - - optimise node sorting performance when opening large dirs (vtsang) - - make the root note render prettier by truncating it at a path slash (gcmt) - - remove NERDChristmasTree option - its always christmas now - - add "cascade" open and closing for dirs containing only another single - dir. See :help NERDTreeCascadeOpenSingleChildDir (pendulm) - - Many other fixes, doc updates and contributions from: - actionshrimp - SchDen - egalpin - cperl82 - many small fixes - toiffel - WoLpH - handcraftedbits - devmanhinton - xiaodili - zhangoose - gastropoda - mixvin - alvan - lucascaton - kelaban - shanesmith - staeff - pendulm - stephenprater - franksort - agrussellknives - AndrewRadev - Twinside - -4.2.0 - - Add NERDTreeDirArrows option to make the UI use pretty arrow chars - instead of the old +~| chars to define the tree structure (sickill) - - shift the syntax highlighting out into its own syntax file (gnap) - - add some mac specific options to the filesystem menu - for macvim - only (andersonfreitas) - - Add NERDTreeMinimalUI option to remove some non functional parts of the - nerdtree ui (camthompson) - - tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the - new behaviour (benjamingeiger) - - if no name is given to :Bookmark, make it default to the name of the - target file/dir (minyoung) - - use 'file' completion when doing copying, create, and move - operations (EvanDotPro) - - lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly - Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) - -4.1.0 - features: - - NERDTreeFind to reveal the node for the current buffer in the tree, - see |NERDTreeFind|. This effectively merges the FindInNERDTree plugin (by - Doug McInnes) into the script. - - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to Stefan - Ritter and Rémi Prévost. - - truncate the root node if wider than the tree window. Thanks to Victor - Gonzalez. - - bugfixes: - - really fix window state restoring - - fix some win32 path escaping issues. Thanks to Stephan Baumeister, Ricky, - jfilip1024, and Chris Chambers - -4.0.0 - - add a new programmable menu system (see :help NERDTreeMenu). - - add new APIs to add menus/menu-items to the menu system as well as - custom key mappings to the NERD tree buffer (see :help NERDTreeAPI). - - removed the old API functions - - added a mapping to maximize/restore the size of nerd tree window, thanks - to Guillaume Duranceau for the patch. See :help NERDTree-A for details. - - - fix a bug where secondary nerd trees (netrw hijacked trees) and - NERDTreeQuitOnOpen didnt play nicely, thanks to Curtis Harvey. - - fix a bug where the script ignored directories whose name ended in a dot, - thanks to Aggelos Orfanakos for the patch. - - fix a bug when using the x mapping on the tree root, thanks to Bryan - Venteicher for the patch. - - fix a bug where the cursor position/window size of the nerd tree buffer - wasnt being stored on closing the window, thanks to Richard Hart. - - fix a bug where NERDTreeMirror would mirror the wrong tree - -3.1.1 - - fix a bug where a non-listed no-name buffer was getting created every - time the tree windows was created, thanks to Derek Wyatt and owen1 - - make <CR> behave the same as the 'o' mapping - - some helptag fixes in the doc, thanks strull - - fix a bug when using :set nohidden and opening a file where the previous - buf was modified. Thanks iElectric - - other minor fixes - -3.1.0 - New features: - - add mappings to open files in a vsplit, see :help NERDTree-s and :help - NERDTree-gs - - make the statusline for the nerd tree window default to something - hopefully more useful. See :help 'NERDTreeStatusline' - Bugfixes: - - make the hijack netrw functionality work when vim is started with "vim - <some dir>" (thanks to Alf Mikula for the patch). - - fix a bug where the CWD wasnt being changed for some operations even when - NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) - - add -bar to all the nerd tree :commands so they can chain with other - :commands (thanks to tpope) - - fix bugs when ignorecase was set (thanks to nach) - - fix a bug with the relative path code (thanks to nach) - - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) - - -3.0.1 - Bugfixes: - - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden - was not set - - fix a bug where :NERDTree <path> would fail if <path> was relative and - didnt start with a ./ or ../ Thanks to James Kanze. - - make the q mapping work with secondary (:e <dir> style) trees, - thanks to jamessan - - fix a bunch of small bugs with secondary trees - - More insane refactoring. - -3.0.0 - - hijack netrw so that doing an :edit <directory> will put a NERD tree in - the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' - - allow sharing of trees across tabs, see :help :NERDTreeMirror - - remove "top" and "bottom" as valid settings for NERDTreeWinPos - - change the '<tab>' mapping to 'i' - - change the 'H' mapping to 'I' - - lots of refactoring diff --git a/sources_non_forked/nerdtree/CHANGELOG.md b/sources_non_forked/nerdtree/CHANGELOG.md new file mode 100644 index 00000000..9e494175 --- /dev/null +++ b/sources_non_forked/nerdtree/CHANGELOG.md @@ -0,0 +1,222 @@ +# Change Log + +#### 5.3... +- **.0**: Add file extension and size to sorting capabilities [#1029](https://github.com/scrooloose/nerdtree/pull/1029) +#### 5.2... +- **.9**: Suppress events for intermediate window/tab/buffer changes [#1026](https://github.com/scrooloose/nerdtree/pull/1026) +- **.8**: Revert [#1019](https://github.com/scrooloose/nerdtree/pull/1019) to fix nvim artifacts and flickering. (PhilRunninger) [#1021](https://github.com/scrooloose/nerdtree/pull/1021) +- **.7**: Use :mode only in neovim. MacVim still needs to use :redraw! [#1019](https://github.com/scrooloose/nerdtree/pull/1019) +- **.6**: In CHANGELOG.md and PR template, make reference to PR a true HTML link. [#1017](https://github.com/scrooloose/nerdtree/pull/1017) +- **.5**: Use `:mode` instead of `:redraw!` when updating menu. (PhilRunninger) [#1016](https://github.com/scrooloose/nerdtree/pull/1016) +- **.4**: When searching for root line num, stop at end of file. (PhilRunninger) [#1015](https://github.com/scrooloose/nerdtree/pull/1015) +- **.3**: Fix `<CR>` key map on the bookmark (lkebin) [#1014](https://github.com/scrooloose/nerdtree/pull/1014) +- **.2**: Make Enter work on the `.. ( up a dir )` line (PhilRunninger) [#1013](https://github.com/scrooloose/nerdtree/pull/1013) +- **.1**: Fix nerdtree#version() on Windows. (PhilRunninger) +- **.0**: Expand functionality of `<CR>` mapping. (PhilRunninger) [#1011](https://github.com/scrooloose/nerdtree/pull/1011) +#### 5.1... +- **.3**: Remove @mentions from PR template and change log. They weren't working. (PhilRunninger) [#1009](https://github.com/scrooloose/nerdtree/pull/1009) +- **.2**: Fix NERDTree opening with the wrong size. (PhilRunninger) [#1008](https://github.com/scrooloose/nerdtree/pull/1008) +- **.1**: Update Changelog and create PR Template (PhilRunninger) [#1007](https://github.com/scrooloose/nerdtree/pull/1007) +- **.0**: Too many changes for one patch... + - Refresh a dir_node if the file wasn't found in it, and look once more. (PhilRunninger) [#1005](https://github.com/scrooloose/nerdtree/pull/1005) + - Add a "copy path to clipboard" menu option (PhilRunninger) [#1002](https://github.com/scrooloose/nerdtree/pull/1002) + - Enable root refresh on "vim ." a different way than [#999](https://github.com/scrooloose/nerdtree/pull/999). (PhilRunninger) [#1001](https://github.com/scrooloose/nerdtree/pull/1001) + - Fix refreshroot (PhilRunninger) [#999](https://github.com/scrooloose/nerdtree/pull/999) + - Change version check to look for 703 not 730 (vhalis) [#994](https://github.com/scrooloose/nerdtree/pull/994) + - Change minimum vim (PhilRunninger) [#991](https://github.com/scrooloose/nerdtree/pull/991) + - Allow multi-character DirArrows (PhilRunninger) [#985](https://github.com/scrooloose/nerdtree/pull/985) + - Remove redraw! while still clearing last message empty string. (PhilRunninger) [#979](https://github.com/scrooloose/nerdtree/pull/979) + - fix `_initChildren` function value set to numChildrenCached error (terryding77) [#969](https://github.com/scrooloose/nerdtree/pull/969) + - On Windows, do a case-insensitive comparison of paths. (PhilRunninger) [#967](https://github.com/scrooloose/nerdtree/pull/967) + - Remove the **Please wait... DONE** messages. (PhilRunninger) [#966](https://github.com/scrooloose/nerdtree/pull/966) + - Smarter delimiter default (PhilRunninger) [#963](https://github.com/scrooloose/nerdtree/pull/963) + - Update directory .vimdc readme example (spencerdcarlson) [#961](https://github.com/scrooloose/nerdtree/pull/961) + - Preview bookmarks (PhilRunninger) [#956](https://github.com/scrooloose/nerdtree/pull/956) + - Add new value to NERDTreeQuitOnOpen to close bookmark table (PhilRunninger) [#955](https://github.com/scrooloose/nerdtree/pull/955) + - Add an :EditBookmarks command to edit the bookmarks file (PhilRunninger) [#954](https://github.com/scrooloose/nerdtree/pull/954) + - Before copying, turn off &shellslash. Restore after copy is finished. (PhilRunninger) [#952](https://github.com/scrooloose/nerdtree/pull/952) + - Set a maximum window size when zooming. (PhilRunninger) [#950](https://github.com/scrooloose/nerdtree/pull/950) + - Confirm the wipeout of a unsaved buffer whose file has been renamed. (PhilRunninger) [#949](https://github.com/scrooloose/nerdtree/pull/949) + - Escape a backslash so it can be used in a key mapping. (PhilRunninger) [#948](https://github.com/scrooloose/nerdtree/pull/948) + - Add a NERDTreeMinimalMenu feature (tuzz) [#938](https://github.com/scrooloose/nerdtree/pull/938) + - fixed root path error for windows (zcodes) [#935](https://github.com/scrooloose/nerdtree/pull/935) + - Restore getDirChildren for use in nerdtree-project-plugin. (PhilRunninger) [#929](https://github.com/scrooloose/nerdtree/pull/929) + - Document NERDTreeNodeDelimiter [#912](https://github.com/scrooloose/nerdtree/pull/912) (PhilRunninger) [#926](https://github.com/scrooloose/nerdtree/pull/926) + - Allow modification of menu keybindings (Leandros) [#923](https://github.com/scrooloose/nerdtree/pull/923) + - Add two more disqualifications for isCascadable(). (PhilRunninger) [#914](https://github.com/scrooloose/nerdtree/pull/914) + - Allow highlighting more than one flag. (kristijanhusak) [#908](https://github.com/scrooloose/nerdtree/pull/908) + - Support sorting files and directories by modification time. (PhilRunninger) [#901](https://github.com/scrooloose/nerdtree/pull/901) + - Parse . and .. from path string with trailing slash. (PhilRunninger) [#899](https://github.com/scrooloose/nerdtree/pull/899) + - Force sort to recalculate the cached sortKey. (PhilRunninger) [#898](https://github.com/scrooloose/nerdtree/pull/898) + - Add NERDTreeRefreshRoot command (wgfm) [#897](https://github.com/scrooloose/nerdtree/pull/897) + - Call Resolve on the file's path when calling :NERDTreeFind. (PhilRunninger) [#896](https://github.com/scrooloose/nerdtree/pull/896) + - Catch all errors, not just NERDTree errors. (PhilRunninger) [#894](https://github.com/scrooloose/nerdtree/pull/894) + - Fix typo in help file (lvoisin) [#892](https://github.com/scrooloose/nerdtree/pull/892) + - Make NERDTreeCreator set the `'nolist'` option (lifecrisis) [#889](https://github.com/scrooloose/nerdtree/pull/889) + - Refresh buffers after `m`, `m` operation on a folder (PhilRunninger) [#888](https://github.com/scrooloose/nerdtree/pull/888) + - Use a better arg for FINDSTR when using the m,l command in Windows. (PhilRunninger) [#887](https://github.com/scrooloose/nerdtree/pull/887) + - Fix the <C-J>/<C-K> motions, which currently fail with cascades (lifecrisis) [#886](https://github.com/scrooloose/nerdtree/pull/886) + - Function "s:UI.getLineNum()" doesn't always work on cascades. (lifecrisis) [#882](https://github.com/scrooloose/nerdtree/pull/882) + - NERDTreeCWD: reset CWD if changed by NERDTreeFocus (PhilRunninger) [#878](https://github.com/scrooloose/nerdtree/pull/878) + - Use <count>tabnext instead of <count>gt to allow users to remap gt. (PhilRunninger) [#877](https://github.com/scrooloose/nerdtree/pull/877) + - Do a case sensitive comparison of new/existing buffers. (PhilRunninger) [#875](https://github.com/scrooloose/nerdtree/pull/875) + - Fix opening sub-directories that have commas in their name. (PhilRunninger) [#873](https://github.com/scrooloose/nerdtree/pull/873) + - Add new command to open NERDTree in the root of a VCS repository. (PhilRunninger) [#872](https://github.com/scrooloose/nerdtree/pull/872) + - Make sure the path to the bookmarks file exists before writing it. (PhilRunninger) [#871](https://github.com/scrooloose/nerdtree/pull/871) + - Unzoom NERDTree when opening a file (PhilRunninger) [#870](https://github.com/scrooloose/nerdtree/pull/870) + - Support unusual characters in file and directory names (PhilRunninger) [#868](https://github.com/scrooloose/nerdtree/pull/868) + - Reword renamed-buffer prompt to be more clear (aflock) [#867](https://github.com/scrooloose/nerdtree/pull/867) + - Default to placing cursor on root when closing bookmark table (lifecrisis) [#866](https://github.com/scrooloose/nerdtree/pull/866) + - Fix issues with sorting of nodes (PhilRunninger) [#856](https://github.com/scrooloose/nerdtree/pull/856) + - Better OSX detection (bubba-h57) [#853](https://github.com/scrooloose/nerdtree/pull/853) + - Bugfix - ensure keymaps dictionary exists before using it (mnussbaum) [#852](https://github.com/scrooloose/nerdtree/pull/852) + - Decrease startup-time by avoiding linear-time iteration over key mappings (mnussbaum) [#851](https://github.com/scrooloose/nerdtree/pull/851) + - Add code to sort mappings in quickhelp (lifecrisis) [#849](https://github.com/scrooloose/nerdtree/pull/849) + - Use ":clearjumps" in new NERDTree windows (lifecrisis) [#844](https://github.com/scrooloose/nerdtree/pull/844) + - Like m-c did before, create parent directories if needed on m-m. (PhilRunninger) [#840](https://github.com/scrooloose/nerdtree/pull/840) + - BUGFIX: Repair a problem with the `'u'` mapping. (lifecrisis) [#838](https://github.com/scrooloose/nerdtree/pull/838) + - Make the NERDTree buffer writable when rendering it. (PhilRunninger) [#837](https://github.com/scrooloose/nerdtree/pull/837) + - Code cleanup: Remove unsupported bookmark table mappings (lifecrisis) [#835](https://github.com/scrooloose/nerdtree/pull/835) + - Replace strcharpart() with substitute() for backward compatibility (bravestarr) [#834](https://github.com/scrooloose/nerdtree/pull/834) + - Fixed error `unknown function strcharpart` for older versions of Vim (hav4ik) [#833](https://github.com/scrooloose/nerdtree/pull/833) + - Clear output when NERDTree menu is aborted (lifecrisis) [#832](https://github.com/scrooloose/nerdtree/pull/832) + - Display a path with multi-byte characters correctly when it is truncated (bravestarr) [#830](https://github.com/scrooloose/nerdtree/pull/830) + - Support revealing file and executing file with xdg-open for Linux (ngnmhieu) [#824](https://github.com/scrooloose/nerdtree/pull/824) + - If node isn't open, count children on disk before deleting. (PhilRunninger) [#822](https://github.com/scrooloose/nerdtree/pull/822) + - Add new variable g:NERDTreeRemoveFileCmd (kutsan) [#816](https://github.com/scrooloose/nerdtree/pull/816) + - Use a better check for existence of the NERDTree buffer. (PhilRunninger) [#814](https://github.com/scrooloose/nerdtree/pull/814) + - Fix focussing previous buffer when closing NERDTree (mrubli) [#801](https://github.com/scrooloose/nerdtree/pull/801) + - Update the docs for "NERDTreeStatusline" (lifecrisis) [#796](https://github.com/scrooloose/nerdtree/pull/796) + - BUGFIX: Unstable behavior in the "getPath()" method (lifecrisis) [#795](https://github.com/scrooloose/nerdtree/pull/795) + - Revert the bugfix from pull request [#785](https://github.com/scrooloose/nerdtree/pull/785) (lifecrisis) [#794](https://github.com/scrooloose/nerdtree/pull/794) + - BUGFIX: Allow ":NERDTreeFind" to discover hidden files (lifecrisis) [#786](https://github.com/scrooloose/nerdtree/pull/786) + - BUGFIX: Allow ":NERDTreeFind" to reveal new files (lifecrisis) [#785](https://github.com/scrooloose/nerdtree/pull/785) + - Add modelines (lifecrisis) [#782](https://github.com/scrooloose/nerdtree/pull/782) + - Change the type of completion used by NERDTreeFind (lifecrisis) [#781](https://github.com/scrooloose/nerdtree/pull/781) + - change NERDTreeFind with args (zhenyangze) [#778](https://github.com/scrooloose/nerdtree/pull/778) + - Style Choice: Using confirm() when deleting a bookmark (lifecrisis) [#777](https://github.com/scrooloose/nerdtree/pull/777) + - remove useless substitute when `file =~# "/$"` (skyblueee) [#773](https://github.com/scrooloose/nerdtree/pull/773) + - remove useless removeLeadingSpaces in _stripMarkup (skyblueee) [#772](https://github.com/scrooloose/nerdtree/pull/772) + - Make the "o" mapping consistent with "x" (lifecrisis) [#769](https://github.com/scrooloose/nerdtree/pull/769) + - Fix a problem with the "x" handler (lifecrisis) [#768](https://github.com/scrooloose/nerdtree/pull/768) + - Clean up the handler for the "x" mapping (lifecrisis) [#767](https://github.com/scrooloose/nerdtree/pull/767) + - Revert change to tab opening method (lifecrisis) [#766](https://github.com/scrooloose/nerdtree/pull/766) + - BUGFIX: Add back support for "b:NERDTreeRoot" (lifecrisis) [#765](https://github.com/scrooloose/nerdtree/pull/765) + - Fix broken "t" and "T" mappings, tabs now open at end (lifecrisis) [#759](https://github.com/scrooloose/nerdtree/pull/759) + - Update doc with already existing mapping variables (asnr) [#699](https://github.com/scrooloose/nerdtree/pull/699) + - Fix the broken g:NERDTreeBookmarksSort setting (lifecrisis) [#696](https://github.com/scrooloose/nerdtree/pull/696) + - Correct NERDTreeIgnore pattern in doc (cntoplolicon) [#648](https://github.com/scrooloose/nerdtree/pull/648) + - Remove empty segments when splitting path (sooth-sayer) [#574](https://github.com/scrooloose/nerdtree/pull/574) + - Suppress autocmds less agressively (wincent) [#578](https://github.com/scrooloose/nerdtree/pull/578) [#691](https://github.com/scrooloose/nerdtree/pull/691) + - Add an Issues template to ask for more info initially. + - Fix markdown headers in readme (josephfrazier) [#676](https://github.com/scrooloose/nerdtree/pull/676) + - Don't touch `@o` and `@h` registers when rendering + - Fix bug with files and directories with dollar signs (alegen) [#649](https://github.com/scrooloose/nerdtree/pull/649) + - Reuse/reopen existing window trees where possible [#244](https://github.com/scrooloose/nerdtree/pull/244) + - Remove NERDTree.previousBuf() + - Change color of arrow (Leeiio) [#630](https://github.com/scrooloose/nerdtree/pull/630) + - Improved a tip in README.markdown (ggicci) [#628](https://github.com/scrooloose/nerdtree/pull/628) + - Shorten delete confimration of empty directory to `y` (mikeperri) [#530](https://github.com/scrooloose/nerdtree/pull/530) + - Fix API call to open directory tree in window (devm33) [#533](https://github.com/scrooloose/nerdtree/pull/533) + - Change default arrows on non-Windows platforms (gwilk) [#546](https://github.com/scrooloose/nerdtree/pull/546) + - Update to README - combine cd and git clone (zwhitchcox) [#584](https://github.com/scrooloose/nerdtree/pull/584) + - Update to README - Tip: start NERDTree when vim starts (therealplato) [#593](https://github.com/scrooloose/nerdtree/pull/593) + - Escape filename when moving an open buffer (zacharyvoase) [#595](https://github.com/scrooloose/nerdtree/pull/595) + - Fixed incorrect :helptags command in README (curran) [#619](https://github.com/scrooloose/nerdtree/pull/619) + - Fixed incomplete escaping of folder arrows (adityanatraj) [#548](https://github.com/scrooloose/nerdtree/pull/548) + - Added NERDTreeCascadeSingleChildDir option (juanibiapina) [#558](https://github.com/scrooloose/nerdtree/pull/558) + - Replace strchars() with backward compatible workaround. + - Add support for copy command in Windows (SkylerLipthay) [#231](https://github.com/scrooloose/nerdtree/pull/231) + - Fixed typo in README.markdown - :Helptags -> :helptags + - Rename "primary" and "secondary" trees to "tab" and "window" trees. + - Move a bunch of buffer level variables into the NERDTree and UI classes. + - Display cascading dirs on one line to save vertical/horizontal space (matt-gardner: brainstorming/testing) + - Remove the old style UI - Remove `NERDTreeDirArrows` option. + - On windows default to + and ~ for expand/collapse directory symbols. + - Lots more refactoring. Move a bunch of b: level vars into b:NERDTree and friends. + +#### 5.0.0 +- Refactor the code significantly: + * Break the classes out into their own files. + * Make the majority of the code OO - previously large parts were effectively a tangle of "global" methods. +- Add an API to assign flags to nodes. This allows VCS plugins like https://github.com/Xuyuanp/nerdtree-git-plugin to exist. Thanks to **Xuyuanp** for helping design/test/build said API. +- add `scope` argument to the key map API see :help NERDTreeAddKeyMap() +- add magic [[dir]] and [[file]] flags to NERDTreeIgnore +- add support for custom path filters. See :help NERDTreeAddPathFilter() +- add path listener API. See :help NERDTreePathListenerAPI. +- expand the fs menu functionality to list file properties (PhilRunninger, apbarrero, JESii) +- make bookmarks work with `~` home shortcuts (hiberabyss) +- show OSX specific fsmenu options in regular vim on mac (evindor) +- make dir arrow icons configurable (PickRelated) +- optimise node sorting performance when opening large dirs (vtsang) +- make the root note render prettier by truncating it at a path slash (gcmt) +- remove NERDChristmasTree option - its always christmas now +- add "cascade" open and closing for dirs containing only another single dir. See :help NERDTreeCascadeOpenSingleChildDir (pendulm) +- Many other fixes, doc updates and contributions from: **actionshrimp**, **agrussellknives**, **alvan**, **AndrewRadev**, **cperl82** (*many small fixes*), **devmanhinton**, **egalpin**, **franksort**, **gastropoda**, **handcraftedbits**, **kelaban**, **lucascaton**, **mixvin**, **pendulm**, **SchDen**, **shanesmith**, **staeff**, **stephenprater**, **toiffel**, **Twinside**, **WoLpH**, **xiaodili**, **zhangoose** + +#### 4.2.0 +- Add NERDTreeDirArrows option to make the UI use pretty arrow chars instead of the old +~| chars to define the tree structure (sickill) +- shift the syntax highlighting out into its own syntax file (gnap) +- add some mac specific options to the filesystem menu - for macvim only (andersonfreitas) +- Add NERDTreeMinimalUI option to remove some non functional parts of the nerdtree ui (camthompson) +- tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the new behaviour (benjamingeiger) +- if no name is given to :Bookmark, make it default to the name of the target file/dir (minyoung) +- use `file` completion when doing copying, create, and move operations (EvanDotPro) +- lots of misc bug fixes from: **AndrewRadev**, **Bogdanov**, **camthompson**, **kml**, **mathias**, **paddyoloughlin**, **scottstvnsn**, **sdewald**, **Vitaly**, **wycats**, me RAWR! + +#### 4.1.0 +- features: + - NERDTreeFind to reveal the node for the current buffer in the tree, see `|NERDTreeFind|`. This effectively merges the FindInNERDTree plugin (by **Doug McInnes**) into the script. + - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to **Stefan Ritter** and **Rémi Prévost**. + - truncate the root node if wider than the tree window. Thanks to **Victor Gonzalez**. + +- bugfixes: + - really fix window state restoring + - fix some win32 path escaping issues. Thanks to **Stephan Baumeister**, **Ricky**, **jfilip1024**, and **Chris Chambers**. + +#### 4.0.0 +- add a new programmable menu system (see `:help NERDTreeMenu`). +- add new APIs to add menus/menu-items to the menu system as well as custom key mappings to the NERD tree buffer (see `:help NERDTreeAPI`). +- removed the old API functions +- added a mapping to maximize/restore the size of nerd tree window, thanks to Guillaume Duranceau for the patch. See :help NERDTree-A for details. +- fix a bug where secondary nerd trees (netrw hijacked trees) and NERDTreeQuitOnOpen didnt play nicely, thanks to **Curtis Harvey**. +- fix a bug where the script ignored directories whose name ended in a dot, thanks to **Aggelos Orfanakos** for the patch. +- fix a bug when using the x mapping on the tree root, thanks to **Bryan Venteicher** for the patch. +- fix a bug where the cursor position/window size of the nerd tree buffer wasnt being stored on closing the window, thanks to **Richard Hart**. +- fix a bug where NERDTreeMirror would mirror the wrong tree + +#### 3.1.1 +- fix a bug where a non-listed no-name buffer was getting created every time the tree windows was created, thanks to **Derek Wyatt** and **owen1** +- make `<CR>` behave the same as the `o` mapping +- some helptag fixes in the doc, thanks **strull**. +- fix a bug when using `:set nohidden` and opening a file where the previous buf was modified. Thanks **iElectric**. +- other minor fixes + +#### 3.1.0 +- New features: + - add mappings to open files in a vsplit, see `:help NERDTree-s` and `:help NERDTree-gs` + - make the statusline for the nerd tree window default to something hopefully more useful. See `:help 'NERDTreeStatusline'` +- Bugfixes: + - make the hijack netrw functionality work when vim is started with `vim <some dir>` (thanks to **Alf Mikula** for the patch). + - fix a bug where the CWD wasnt being changed for some operations even when NERDTreeChDirMode==2 (thanks to **Lucas S. Buchala**) + - add -bar to all the nerd tree :commands so they can chain with other :commands (thanks to **tpope**) + - fix bugs when ignorecase was set (thanks to **nach**) + - fix a bug with the relative path code (thanks to **nach**) + - fix a bug where doing a `:cd` would cause `:NERDTreeToggle` to fail (thanks **nach**) + + +#### 3.0.1 +- Bugfixes: + - fix bugs with :NERDTreeToggle and :NERDTreeMirror when `'hidden'` was not set + - fix a bug where `:NERDTree <path>` would fail if `<path>` was relative and didnt start with a `./` or `../` Thanks to **James Kanze**. + - make the `q` mapping work with secondary (`:e <dir>` style) trees, thanks to **jamessan** + - fix a bunch of small bugs with secondary trees +- More insane refactoring. + +#### 3.0.0 +- hijack netrw so that doing an `:edit <directory>` will put a NERD tree in the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' +- allow sharing of trees across tabs, see `:help :NERDTreeMirror` +- remove "top" and "bottom" as valid settings for NERDTreeWinPos +- change the `'<tab>'` mapping to `'i'` +- change the `'H'` mapping to `'I'` +- lots of refactoring diff --git a/sources_non_forked/nerdtree/autoload/nerdtree.vim b/sources_non_forked/nerdtree/autoload/nerdtree.vim index fd192827..4391565e 100644 --- a/sources_non_forked/nerdtree/autoload/nerdtree.vim +++ b/sources_non_forked/nerdtree/autoload/nerdtree.vim @@ -3,13 +3,38 @@ if exists("g:loaded_nerdtree_autoload") endif let g:loaded_nerdtree_autoload = 1 -function! nerdtree#version() - return '5.0.0' +let s:rootNERDTreePath = resolve(expand("<sfile>:p:h:h")) +function! nerdtree#version(...) + let l:changelog = readfile(join([s:rootNERDTreePath, "CHANGELOG.md"], nerdtree#slash())) + let l:text = 'Unknown' + let l:line = 0 + while l:line <= len(l:changelog) + if l:changelog[l:line] =~ '\d\+\.\d\+' + let l:text = substitute(l:changelog[l:line], '.*\(\d\+.\d\+\).*', '\1', '') + let l:text .= substitute(l:changelog[l:line+1], '^.\{-}\(\.\d\+\).\{-}:\(.*\)', a:0>0 ? '\1:\2' : '\1', '') + break + endif + let l:line += 1 + endwhile + return l:text endfunction " SECTION: General Functions {{{1 "============================================================ +function! nerdtree#slash() + + if nerdtree#runningWindows() + if exists('+shellslash') && &shellslash + return '/' + endif + + return '\' + endif + + return '/' +endfunction + "FUNCTION: nerdtree#and(x,y) {{{2 " Implements and() function for Vim <= 7.2 function! nerdtree#and(x,y) @@ -129,13 +154,13 @@ function! nerdtree#deprecated(func, ...) endif endfunction -" FUNCTION: nerdtree#exec(cmd) {{{2 -" Same as :exec cmd but with eventignore set for the duration -" to disable the autocommands used by NERDTree (BufEnter, -" BufLeave and VimEnter) -function! nerdtree#exec(cmd) +" FUNCTION: nerdtree#exec(cmd, ignoreAll) {{{2 +" Same as :exec cmd but, if ignoreAll is TRUE, set eventignore=all for the duration +function! nerdtree#exec(cmd, ignoreAll) let old_ei = &ei - set ei=BufEnter,BufLeave,VimEnter + if a:ignoreAll + set ei=all + endif exec a:cmd let &ei = old_ei endfunction diff --git a/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim b/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim index a82ff18e..f0458680 100644 --- a/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim +++ b/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim @@ -14,6 +14,10 @@ function! nerdtree#ui_glue#createDefaultBindings() call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "Bookmark", 'callback': s."activateBookmark" }) call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "all", 'callback': s."activateAll" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'FileNode', 'callback': s."customOpenFile"}) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'DirNode', 'callback': s."customOpenDir"}) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'Bookmark', 'callback': s."customOpenBookmark"}) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'all', 'callback': s."activateAll" }) call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "DirNode", 'callback': s."activateDirNode" }) call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "FileNode", 'callback': s."activateFileNode" }) @@ -76,6 +80,35 @@ endfunction "SECTION: Interface bindings {{{1 "============================================================ +"FUNCTION: s:customOpenFile() {{{1 +" Open file node with the "custom" key, initially <CR>. +function! s:customOpenFile(node) + call a:node.activate(s:initCustomOpenArgs().file) +endfunction + +"FUNCTION: s:customOpenDir() {{{1 +" Open directory node with the "custom" key, initially <CR>. +function! s:customOpenDir(node) + call s:activateDirNode(a:node, s:initCustomOpenArgs().dir) +endfunction + +"FUNCTION: s:customOpenBookmark() {{{1 +" Open bookmark node with the "custom" key, initially <CR>. +function! s:customOpenBookmark(node) + if a:node.path.isDirectory + call a:node.activate(b:NERDTree, s:initCustomOpenArgs().dir) + else + call a:node.activate(b:NERDTree, s:initCustomOpenArgs().file) + endif +endfunction + +"FUNCTION: s:initCustomOpenArgs() {{{1 +" Make sure NERDTreeCustomOpenArgs has needed keys +function! s:initCustomOpenArgs() + let g:NERDTreeCustomOpenArgs = get(g:, 'NERDTreeCustomOpenArgs', {}) + return extend(g:NERDTreeCustomOpenArgs, {'file':{'reuse': 'all', 'where': 'p'}, 'dir':{}}, 'keep') +endfunction + "FUNCTION: s:activateAll() {{{1 "handle the user activating the updir line function! s:activateAll() @@ -84,15 +117,16 @@ function! s:activateAll() endif endfunction -" FUNCTION: s:activateDirNode(directoryNode) {{{1 -function! s:activateDirNode(directoryNode) +" FUNCTION: s:activateDirNode(directoryNode, options) {{{1 +" Open a directory with optional options +function! s:activateDirNode(directoryNode, ...) if a:directoryNode.isRoot() && a:directoryNode.isOpen call nerdtree#echo('cannot close tree root') return endif - call a:directoryNode.activate() + call a:directoryNode.activate((a:0 > 0) ? a:1 : {}) endfunction "FUNCTION: s:activateFileNode() {{{1 @@ -367,7 +401,7 @@ function! s:jumpToLastChild(node) call s:jumpToChild(a:node, 1) endfunction -" FUNCTION: s:jumpToChild(node, last) {{{2 +" FUNCTION: s:jumpToChild(node, last) {{{1 " Jump to the first or last child node at the same file system level. " " Args: @@ -425,7 +459,7 @@ function! s:jumpToPrevSibling(node) call s:jumpToSibling(a:node, 0) endfunction -" FUNCTION: s:jumpToSibling(node, forward) {{{2 +" FUNCTION: s:jumpToSibling(node, forward) {{{1 " Move the cursor to the next or previous node at the same file system level. " " Args: @@ -540,11 +574,11 @@ function! s:refreshRoot() call nerdtree#echo("Refreshing the root node. This could take a while...") let l:curWin = winnr() - call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w") + call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w", 1) call b:NERDTree.root.refresh() call b:NERDTree.render() redraw - call nerdtree#exec(l:curWin . "wincmd w") + call nerdtree#exec(l:curWin . "wincmd w", 1) call nerdtree#echo("") endfunction diff --git a/sources_non_forked/nerdtree/doc/NERDTree.txt b/sources_non_forked/nerdtree/doc/NERDTree.txt index 93635bd0..14f70782 100644 --- a/sources_non_forked/nerdtree/doc/NERDTree.txt +++ b/sources_non_forked/nerdtree/doc/NERDTree.txt @@ -247,12 +247,12 @@ i........Open selected file in a split window.......................|NERDTree-i| gi.......Same as i, but leave the cursor on the NERDTree...........|NERDTree-gi| s........Open selected file in a new vsplit.........................|NERDTree-s| gs.......Same as s, but leave the cursor on the NERDTree...........|NERDTree-gs| +<CR>.....User-definable custom open action.......................|NERDTree-<CR>| O........Recursively open the selected directory....................|NERDTree-O| x........Close the current nodes parent.............................|NERDTree-x| X........Recursively close all children of the current node.........|NERDTree-X| e........Edit the current dir.......................................|NERDTree-e| -<CR>............same as |NERDTree-o|. double-click....same as |NERDTree-o|. middle-click....same as |NERDTree-i| for files, and |NERDTree-e| for dirs. @@ -319,7 +319,7 @@ The default key combo for this mapping is "g" + NERDTreeMapActivateNode (see ------------------------------------------------------------------------------ *NERDTree-t* Default key: t -Map setting: NERDTreeMapOpenInTab +Map setting: *NERDTreeMapOpenInTab* Applies to: files and directories. Opens the selected file in a new tab. If a directory is selected, a fresh @@ -332,7 +332,7 @@ in a new tab. ------------------------------------------------------------------------------ *NERDTree-T* Default key: T -Map setting: NERDTreeMapOpenInTabSilent +Map setting: *NERDTreeMapOpenInTabSilent* Applies to: files and directories. The same as |NERDTree-t| except that the focus is kept in the current tab. @@ -340,7 +340,7 @@ The same as |NERDTree-t| except that the focus is kept in the current tab. ------------------------------------------------------------------------------ *NERDTree-i* Default key: i -Map setting: NERDTreeMapOpenSplit +Map setting: *NERDTreeMapOpenSplit* Applies to: files. Opens the selected file in a new split window and puts the cursor in the new @@ -349,7 +349,7 @@ window. ------------------------------------------------------------------------------ *NERDTree-gi* Default key: gi -Map setting: NERDTreeMapPreviewSplit +Map setting: *NERDTreeMapPreviewSplit* Applies to: files. The same as |NERDTree-i| except that the cursor is not moved. @@ -360,7 +360,7 @@ The default key combo for this mapping is "g" + NERDTreeMapOpenSplit (see ------------------------------------------------------------------------------ *NERDTree-s* Default key: s -Map setting: NERDTreeMapOpenVSplit +Map setting: *NERDTreeMapOpenVSplit* Applies to: files. Opens the selected file in a new vertically split window and puts the cursor @@ -369,7 +369,7 @@ in the new window. ------------------------------------------------------------------------------ *NERDTree-gs* Default key: gs -Map setting: NERDTreeMapPreviewVSplit +Map setting: *NERDTreeMapPreviewVSplit* Applies to: files. The same as |NERDTree-s| except that the cursor is not moved. @@ -377,10 +377,19 @@ The same as |NERDTree-s| except that the cursor is not moved. The default key combo for this mapping is "g" + NERDTreeMapOpenVSplit (see |NERDTree-s|). +------------------------------------------------------------------------------ + *NERDTree-<CR>* +Default key: <CR> +Map setting: *NERDTreeMapCustomOpen* +Applies to: files, directories, and bookmarks + +Performs a customized open action on the selected node. This allows the user +to define an action that behaves differently from any of the standard +keys. See |NERDTreeCustomOpenArgs| for more details. ------------------------------------------------------------------------------ *NERDTree-O* Default key: O -Map setting: NERDTreeMapOpenRecursively +Map setting: *NERDTreeMapOpenRecursively* Applies to: directories. Recursively opens the selected directory. @@ -393,7 +402,7 @@ cached. This is handy, especially if you have .svn directories. ------------------------------------------------------------------------------ *NERDTree-x* Default key: x -Map setting: NERDTreeMapCloseDir +Map setting: *NERDTreeMapCloseDir* Applies to: files and directories. Closes the parent of the selected node. @@ -401,7 +410,7 @@ Closes the parent of the selected node. ------------------------------------------------------------------------------ *NERDTree-X* Default key: X -Map setting: NERDTreeMapCloseChildren +Map setting: *NERDTreeMapCloseChildren* Applies to: directories. Recursively closes all children of the selected directory. @@ -411,7 +420,7 @@ Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping. ------------------------------------------------------------------------------ *NERDTree-e* Default key: e -Map setting: NERDTreeMapOpenExpl +Map setting: *NERDTreeMapOpenExpl* Applies to: files and directories. |:edit|s the selected directory, or the selected file's directory. This could @@ -421,7 +430,7 @@ result in a NERDTree or a netrw being opened, depending on ------------------------------------------------------------------------------ *NERDTree-D* Default key: D -Map setting: NERDTreeMapDeleteBookmark +Map setting: *NERDTreeMapDeleteBookmark* Applies to: lines in the bookmarks table Deletes the currently selected bookmark. @@ -429,7 +438,7 @@ Deletes the currently selected bookmark. ------------------------------------------------------------------------------ *NERDTree-P* Default key: P -Map setting: NERDTreeMapJumpRoot +Map setting: *NERDTreeMapJumpRoot* Applies to: no restrictions. Jump to the tree root. @@ -437,7 +446,7 @@ Jump to the tree root. ------------------------------------------------------------------------------ *NERDTree-p* Default key: p -Map setting: NERDTreeMapJumpParent +Map setting: *NERDTreeMapJumpParent* Applies to: files and directories. Jump to the parent node of the selected node. @@ -445,7 +454,7 @@ Jump to the parent node of the selected node. ------------------------------------------------------------------------------ *NERDTree-K* Default key: K -Map setting: NERDTreeMapJumpFirstChild +Map setting: *NERDTreeMapJumpFirstChild* Applies to: files and directories. Jump to the first child of the current nodes parent. @@ -458,7 +467,7 @@ If the cursor is already on the first node then do the following: ------------------------------------------------------------------------------ *NERDTree-J* Default key: J -Map setting: NERDTreeMapJumpLastChild +Map setting: *NERDTreeMapJumpLastChild* Applies to: files and directories. Jump to the last child of the current nodes parent. @@ -471,7 +480,7 @@ If the cursor is already on the last node then do the following: ------------------------------------------------------------------------------ *NERDTree-C-J* Default key: <C-J> -Map setting: NERDTreeMapJumpNextSibling +Map setting: *NERDTreeMapJumpNextSibling* Applies to: files and directories. Jump to the next sibling of the selected node. @@ -479,7 +488,7 @@ Jump to the next sibling of the selected node. ------------------------------------------------------------------------------ *NERDTree-C-K* Default key: <C-K> -Map setting: NERDTreeMapJumpPrevSibling +Map setting: *NERDTreeMapJumpPrevSibling* Applies to: files and directories. Jump to the previous sibling of the selected node. @@ -487,7 +496,7 @@ Jump to the previous sibling of the selected node. ------------------------------------------------------------------------------ *NERDTree-C* Default key: C -Map setting: NERDTreeMapChangeRoot +Map setting: *NERDTreeMapChangeRoot* Applies to: files and directories. Make the selected directory node the new tree root. If a file is selected, its @@ -496,7 +505,7 @@ parent is used. ------------------------------------------------------------------------------ *NERDTree-u* Default key: u -Map setting: NERDTreeMapUpdir +Map setting: *NERDTreeMapUpdir* Applies to: no restrictions. Move the tree root up a dir (like doing a "cd .."). @@ -504,7 +513,7 @@ Move the tree root up a dir (like doing a "cd .."). ------------------------------------------------------------------------------ *NERDTree-U* Default key: U -Map setting: NERDTreeMapUpdirKeepOpen +Map setting: *NERDTreeMapUpdirKeepOpen* Applies to: no restrictions. Like |NERDTree-u| except that the old tree root is kept open. @@ -512,7 +521,7 @@ Like |NERDTree-u| except that the old tree root is kept open. ------------------------------------------------------------------------------ *NERDTree-r* Default key: r -Map setting: NERDTreeMapRefresh +Map setting: *NERDTreeMapRefresh* Applies to: files and directories. If a dir is selected, recursively refresh that dir, i.e. scan the filesystem @@ -523,7 +532,7 @@ If a file node is selected then the above is done on it's parent. ------------------------------------------------------------------------------ *NERDTree-R* Default key: R -Map setting: NERDTreeMapRefreshRoot +Map setting: *NERDTreeMapRefreshRoot* Applies to: no restrictions. Recursively refresh the tree root. @@ -531,7 +540,7 @@ Recursively refresh the tree root. ------------------------------------------------------------------------------ *NERDTree-m* Default key: m -Map setting: NERDTreeMapMenu +Map setting: *NERDTreeMapMenu* Applies to: files and directories. Display the NERDTree menu. See |NERDTreeMenu| for details. @@ -539,7 +548,7 @@ Display the NERDTree menu. See |NERDTreeMenu| for details. ------------------------------------------------------------------------------ *NERDTree-cd* Default key: cd -Map setting: NERDTreeMapChdir +Map setting: *NERDTreeMapChdir* Applies to: files and directories. Change Vim's current working directory to that of the selected node. @@ -547,7 +556,7 @@ Change Vim's current working directory to that of the selected node. ------------------------------------------------------------------------------ *NERDTree-CD* Default key: CD -Map setting: NERDTreeMapCWD +Map setting: *NERDTreeMapCWD* Applies to: no restrictions. Change the NERDTree root to Vim's current working directory. @@ -555,7 +564,7 @@ Change the NERDTree root to Vim's current working directory. ------------------------------------------------------------------------------ *NERDTree-I* Default key: I -Map setting: NERDTreeMapToggleHidden +Map setting: *NERDTreeMapToggleHidden* Applies to: no restrictions. Toggles whether hidden files (i.e. "dot files") are displayed. @@ -563,7 +572,7 @@ Toggles whether hidden files (i.e. "dot files") are displayed. ------------------------------------------------------------------------------ *NERDTree-f* Default key: f -Map setting: NERDTreeMapToggleFilters +Map setting: *NERDTreeMapToggleFilters* Applies to: no restrictions. Toggles whether file filters are used. See |NERDTreeIgnore| for details. @@ -571,7 +580,7 @@ Toggles whether file filters are used. See |NERDTreeIgnore| for details. ------------------------------------------------------------------------------ *NERDTree-F* Default key: F -Map setting: NERDTreeMapToggleFiles +Map setting: *NERDTreeMapToggleFiles* Applies to: no restrictions. Toggles whether file nodes are displayed. @@ -579,7 +588,7 @@ Toggles whether file nodes are displayed. ------------------------------------------------------------------------------ *NERDTree-B* Default key: B -Map setting: NERDTreeMapToggleBookmarks +Map setting: *NERDTreeMapToggleBookmarks* Applies to: no restrictions. Toggles whether the bookmarks table is displayed. @@ -587,7 +596,7 @@ Toggles whether the bookmarks table is displayed. ------------------------------------------------------------------------------ *NERDTree-q* Default key: q -Map setting: NERDTreeMapQuit +Map setting: *NERDTreeMapQuit* Applies to: no restrictions. Closes the NERDTree window. @@ -595,7 +604,7 @@ Closes the NERDTree window. ------------------------------------------------------------------------------ *NERDTree-A* Default key: A -Map setting: NERDTreeMapToggleZoom +Map setting: *NERDTreeMapToggleZoom* Applies to: no restrictions. Maximize (zoom) and minimize the NERDTree window. @@ -603,7 +612,7 @@ Maximize (zoom) and minimize the NERDTree window. ------------------------------------------------------------------------------ *NERDTree-?* Default key: ? -Map setting: NERDTreeMapHelp +Map setting: *NERDTreeMapHelp* Applies to: no restrictions. Toggles whether the quickhelp is displayed. @@ -625,7 +634,7 @@ Related tags: |NERDTree-m| |NERDTreeApi| ------------------------------------------------------------------------------ *NERDTreeMenu-j* Default key: j -Map option: NERDTreeMenuDown +Map option: *NERDTreeMenuDown* Applies to: The NERDTree menu. Moves the cursor down. @@ -633,7 +642,7 @@ Moves the cursor down. ------------------------------------------------------------------------------ *NERDTreeMenu-k* Default key: k -Map option: NERDTreeMenuUp +Map option: *NERDTreeMenuUp* Applies to: The NERDTree menu. Moves the cursor up. @@ -754,6 +763,9 @@ the NERDTree. These settings should be set in your vimrc, using `:let`. file or directory name from the rest of the characters on the line of text. +|NERDTreeCustomOpenArgs| A dictionary with values that control how a node + is opened with the |NERDTree-<CR>| key. + ------------------------------------------------------------------------------ 3.2. Customisation details *NERDTreeSettingsDetails* @@ -1031,28 +1043,31 @@ window. Use one of the follow lines for this setting: > Values: a list of regular expressions. Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$'] -This setting is a list of regular expressions which are used to specify the -order of nodes under their parent. +This setting is a list of regular expressions which are used to group or sort +the nodes under their parent. For example, if the setting is: > ['\.vim$', '\.c$', '\.h$', '*', 'foobar'] < -then all .vim files will be placed at the top, followed by all .c files then +then all .vim files will be grouped at the top, followed by all .c files then all .h files. All files containing the string 'foobar' will be placed at the end. The star is a special flag: it tells the script that every node that doesn't match any of the other regexps should be placed here. -If no star is present in NERDTreeSortOrder then one is automatically -appended to the array. +If no star is present in NERDTreeSortOrder, then one is automatically +appended to the end of the list. The regex '\/$' should be used to match directory nodes. -A special flag can be used to sort by the modification timestamps of files and -directories. It is either '[[timestamp]]' for ascending, or '[[-timestamp]]' -for descending. If placed at the beginning of the list, files and directories -are sorted by timestamp, and then by the remaining items in the sort order -list. If this flag is in any other position of the list, timestamp sorting is -done secondarily. See examples 4, 5, and 6 below. +Files can also be sorted by 1) the modification timestamp, 2) the size, or 3) +the extension. Directories are always sorted by name. To accomplish this, the +following special flags are used: + [[timestamp]] [[-timestamp]] [[size]] [[-size]] [[extension]] +The hyphen specifies a descending sort; extensions are sorted in ascending +order only. If placed at the beginning of the list, files are sorted according +to these flags first, and then grouped by the remaining items in the list. If +the flags are in any other position of the list, this special sorting is done +secondarily. See examples 4, 5, and 6 below. After this sorting is done, the files in each group are sorted alphabetically. @@ -1060,20 +1075,20 @@ Examples: > (1) ['*', '\/$'] (2) [] (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] - (4) ['[[timestamp]]'] - (5) ['\/$', '*', '[[-timestamp]]'] - (6) ['\.md$', '\.c$', '[[-timestamp]]', '*'] + (4) ['[[-size]]'] + (5) ['\/$', '*', '[[timestamp]]'] + (6) ['foo','\/$','[[extension]]'] < 1. Directories will appear last, everything else will appear above. 2. Everything will simply appear in alphabetical order. 3. Dirs will appear first, then ruby and php. Swap files, bak files and vim backup files will appear last with everything else preceding them. -4. All files and directories are sorted by timestamp, oldest first. If any - files have identical timestamps, they are sorted alphabetically. -5. Directories are first, newest to oldest, then everything else, newest to - oldest. -6. Markdown files first, followed by C source files, then everything else. - Each group is shown newest to oldest. +4. Everything is sorted by size, largest to smallest, with directories + considered to have size 0 bytes. +5. Directories will appear first alphabetically, followed by files, sorted by + timestamp, oldest first. +6. Files and directories matching 'foo' first, followed by other directories, + then all other files. Each section of files is sorted by file extension. ------------------------------------------------------------------------------ *NERDTreeStatusline* @@ -1233,6 +1248,32 @@ when specifying by hex or Unicode. > let NERDTreeNodeDelimiter="\u00a0" "non-breaking space let NERDTreeNodeDelimiter="😀" "smiley face < +------------------------------------------------------------------------------ + *NERDTreeCustomOpenArgs* +Values: A nested dictionary, as described below +Default: {'file': {'reuse': 'all', 'where': 'p'}, 'dir': {}} + +This dictionary contains two keys, 'file' and 'dir', whose values each are +another dictionary. The inner dictionary is a set of parameters used by +|NERDTree-<CR>| to open a file or directory. Setting these parameters allows you +to customize the way the node is opened. The default value matches what +|NERDTree-o| does. To change that behavior, use these keys and +values in the inner dictionaries: + +'where': specifies whether the node should be opened in a new split ("h" or + "v"), in a new tab ("t") or, in the last window ("p"). +'reuse': if file is already shown in a window, jump there; takes values + "all", "currenttab", or empty +'keepopen': boolean (0 or 1); if true, the tree window will not be closed +'stay': boolean (0 or 1); if true, remain in tree window after opening + +For example: +To open files and directories (creating a new NERDTree) in a new tab, > + {'file':{'where': 't'}, 'dir':{'where':'t'}} +< +To open a file always in the current tab, and expand directories in place, > + {'file': {'reuse':'currenttab', 'where':'p', 'keepopen':1, 'stay':1}} +< ============================================================================== 4. The NERDTree API *NERDTreeAPI* diff --git a/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim b/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim index c633a8f2..b206e7a4 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim @@ -159,8 +159,8 @@ endfunction " FUNCTION: s:Edit() {{{1 " opens the NERDTreeBookmarks file for manual editing function! s:Bookmark.Edit() - execute "wincmd w" - execute "edit ".g:NERDTreeBookmarksFile + call nerdtree#exec("wincmd w", 1) + call nerdtree#exec("edit ".g:NERDTreeBookmarksFile, 1) endfunction " FUNCTION: Bookmark.getNode(nerdtree, searchFromAbsoluteRoot) {{{1 diff --git a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim index 980cf805..efd3cc81 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim @@ -13,9 +13,6 @@ let g:NERDTreeCreator = s:Creator " FUNCTION: s:Creator._bindMappings() {{{1 function! s:Creator._bindMappings() - "make <cr> do the same as the activate node mapping - nnoremap <silent> <buffer> <cr> :call nerdtree#ui_glue#invokeKeyMap(g:NERDTreeMapActivateNode)<cr> - call g:NERDTreeKeyMap.BindAll() command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('<args>') @@ -189,18 +186,20 @@ function! s:Creator._createTreeWin() let t:NERDTreeBufName = self._nextBufferName() silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' new' silent! execute 'edit ' . t:NERDTreeBufName + silent! execute 'vertical resize '. l:splitSize else silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' split' silent! execute 'buffer ' . t:NERDTreeBufName endif + setlocal winfixwidth + call self._setCommonBufOptions() if has('patch-7.4.1925') clearjumps endif - setlocal winfixwidth endfunction " FUNCTION: s:Creator._isBufHidden(nr) {{{1 @@ -218,14 +217,14 @@ function! s:Creator.New() return newCreator endfunction -" FUNCTION: s:Creator._nextBufferName() {{{2 +" FUNCTION: s:Creator._nextBufferName() {{{1 " returns the buffer name for the next nerd tree function! s:Creator._nextBufferName() let name = s:Creator.BufNamePrefix() . self._nextBufferNumber() return name endfunction -" FUNCTION: s:Creator._nextBufferNumber() {{{2 +" FUNCTION: s:Creator._nextBufferNumber() {{{1 " the number to add to the nerd tree buffer name to make the buf name unique function! s:Creator._nextBufferNumber() if !exists("s:Creator._NextBufNum") diff --git a/sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim b/sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim index 26dbd296..05e82d97 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim @@ -31,7 +31,11 @@ function! s:MenuController.showMenu() let l:done = 0 while !l:done - redraw! + if has('nvim') + mode + else + redraw! + endif call self._echoPrompt() let l:key = nr2char(getchar()) @@ -64,7 +68,7 @@ function! s:MenuController._echoPrompt() echo "Menu: [" . join(shortcuts, ",") . "] (" . navHelp . " or shortcut): " else - echo "NERDTree Menu. " . navHelp . " . or the shortcuts indicated" + echo "NERDTree Menu. " . navHelp . ", or the shortcuts indicated" echo "=========================================================" for i in range(0, len(self.menuItems)-1) diff --git a/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim b/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim index c1ce5ed0..705d4f9b 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim @@ -44,19 +44,19 @@ function! s:NERDTree.Close() let l:useWinId = exists('*win_getid') && exists('*win_gotoid') if winnr() == s:NERDTree.GetWinNum() - call nerdtree#exec("wincmd p") + call nerdtree#exec("wincmd p", 1) let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr("") - call nerdtree#exec("wincmd p") + call nerdtree#exec("wincmd p", 1) else let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr("") endif - call nerdtree#exec(s:NERDTree.GetWinNum() . " wincmd w") - close + call nerdtree#exec(s:NERDTree.GetWinNum() . " wincmd w", 1) + call nerdtree#exec("close", 1) if l:useWinId - call nerdtree#exec("call win_gotoid(" . l:activeBufOrWin . ")") + call nerdtree#exec("call win_gotoid(" . l:activeBufOrWin . ")", 0) else - call nerdtree#exec(bufwinnr(l:activeBufOrWin) . " wincmd w") + call nerdtree#exec(bufwinnr(l:activeBufOrWin) . " wincmd w", 0) endif else close @@ -98,7 +98,7 @@ endfunction "Places the cursor in the nerd tree window function! s:NERDTree.CursorToTreeWin() call g:NERDTree.MustBeOpen() - call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w") + call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w", 1) endfunction " Function: s:NERDTree.ExistsForBuffer() {{{1 @@ -153,7 +153,7 @@ endfunction "FUNCTION: s:NERDTree.IsOpen() {{{1 function! s:NERDTree.IsOpen() - return s:NERDTree.GetWinNum() != -1 + return s:NERDTree.GetWinNum() != -1 || bufname('%') =~# '^' . g:NERDTreeCreator.BufNamePrefix() . '\d\+$' endfunction "FUNCTION: s:NERDTree.isTabTree() {{{1 diff --git a/sources_non_forked/nerdtree/lib/nerdtree/opener.vim b/sources_non_forked/nerdtree/lib/nerdtree/opener.vim index f4bd6e06..5953eea2 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/opener.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/opener.vim @@ -107,10 +107,10 @@ function! s:Opener._isWindowUsable(winnumber) endif let oldwinnr = winnr() - call nerdtree#exec(a:winnumber . "wincmd p") + call nerdtree#exec(a:winnumber . "wincmd p", 1) let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') let modified = &modified - call nerdtree#exec(oldwinnr . "wincmd p") + call nerdtree#exec(oldwinnr . "wincmd p", 1) "if its a special window e.g. quickfix or another explorer plugin then we "have to split @@ -172,7 +172,7 @@ function! s:Opener._newSplit() let below=0 " Attempt to go to adjacent window - call nerdtree#exec(back) + call nerdtree#exec(back, 1) let onlyOneWin = (winnr("$") ==# 1) @@ -201,9 +201,9 @@ function! s:Opener._newSplit() "resize the tree window if no other window was open before if onlyOneWin let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize - call nerdtree#exec(there) + call nerdtree#exec(there, 1) exec("silent ". splitMode ." resize ". size) - call nerdtree#exec('wincmd p') + call nerdtree#exec('wincmd p', 0) endif " Restore splitmode settings @@ -219,8 +219,8 @@ function! s:Opener._newVSplit() let l:winwidth = g:NERDTreeWinSize endif - call nerdtree#exec('wincmd p') - vnew + call nerdtree#exec('wincmd p', 1) + call nerdtree#exec('vnew', 1) let l:currentWindowNumber = winnr() @@ -228,7 +228,7 @@ function! s:Opener._newVSplit() call g:NERDTree.CursorToTreeWin() execute 'silent vertical resize ' . l:winwidth - call nerdtree#exec(l:currentWindowNumber . 'wincmd w') + call nerdtree#exec(l:currentWindowNumber . 'wincmd w', 0) endfunction " FUNCTION: Opener.open(target) {{{1 @@ -290,9 +290,9 @@ function! s:Opener._previousWindow() else try if !self._isWindowUsable(winnr("#")) - call nerdtree#exec(self._firstUsableWindow() . "wincmd w") + call nerdtree#exec(self._firstUsableWindow() . "wincmd w", 1) else - call nerdtree#exec('wincmd p') + call nerdtree#exec('wincmd p', 1) endif catch /^Vim\%((\a\+)\)\=:E37/ call g:NERDTree.CursorToTreeWin() @@ -305,8 +305,8 @@ endfunction " FUNCTION: Opener._restoreCursorPos() {{{1 function! s:Opener._restoreCursorPos() - call nerdtree#exec(self._tabnr . 'tabnext') - call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w') + call nerdtree#exec(self._tabnr . 'tabnext', 1) + call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w', 1) endfunction " FUNCTION: Opener._reuseWindow() {{{1 @@ -321,7 +321,7 @@ function! s:Opener._reuseWindow() "check the current tab for the window let winnr = bufwinnr('^' . self._path.str() . '$') if winnr != -1 - call nerdtree#exec(winnr . "wincmd w") + call nerdtree#exec(winnr . "wincmd w", 0) call self._checkToCloseTree(0) return 1 endif @@ -334,9 +334,9 @@ function! s:Opener._reuseWindow() let tabnr = self._path.tabnr() if tabnr call self._checkToCloseTree(1) - call nerdtree#exec(tabnr . 'tabnext') + call nerdtree#exec(tabnr . 'tabnext', 1) let winnr = bufwinnr('^' . self._path.str() . '$') - call nerdtree#exec(winnr . "wincmd w") + call nerdtree#exec(winnr . "wincmd w", 0) return 1 endif diff --git a/sources_non_forked/nerdtree/lib/nerdtree/path.vim b/sources_non_forked/nerdtree/lib/nerdtree/path.vim index c3af1952..d00bb898 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/path.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/path.vim @@ -380,7 +380,8 @@ endfunction function! s:Path.getSortOrderIndex() let i = 0 while i < len(g:NERDTreeSortOrder) - if self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] + if g:NERDTreeSortOrder[i] !~? '\[\[-\?\(timestamp\|size\|extension\)\]\]' && + \ self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] return i endif let i = i + 1 @@ -407,15 +408,26 @@ endfunction " FUNCTION: Path.getSortKey() {{{1 " returns a key used in compare function for sorting function! s:Path.getSortKey() - let l:ascending = index(g:NERDTreeSortOrder,'[[timestamp]]') - let l:descending = index(g:NERDTreeSortOrder,'[[-timestamp]]') - if !exists("self._sortKey") || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder || l:ascending >= 0 || l:descending >= 0 - let self._sortKey = [self.getSortOrderIndex()] + if !exists("self._sortKey") || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder + " Look for file metadata tags: [[timestamp]], [[extension]], [[size]] + let metadata = [] + for tag in g:NERDTreeSortOrder + if tag =~? '\[\[-\?timestamp\]\]' + let metadata += [self.isDirectory ? 0 : getftime(self.str()) * (tag =~ '-' ? -1 : 1)] + elseif tag =~? '\[\[-\?size\]\]' + let metadata += [self.isDirectory ? 0 : getfsize(self.str()) * (tag =~ '-' ? -1 : 1)] + elseif tag =~? '\[\[extension\]\]' + let extension = matchstr(self.getLastPathComponent(0), '[^.]\+\.\zs[^.]\+$') + let metadata += [self.isDirectory ? '' : (extension == '' ? nr2char(str2nr('0x10ffff',16)) : extension)] + endif + endfor - if l:descending >= 0 - call insert(self._sortKey, -getftime(self.str()), l:descending == 0 ? 0 : len(self._sortKey)) - elseif l:ascending >= 0 - call insert(self._sortKey, getftime(self.str()), l:ascending == 0 ? 0 : len(self._sortKey)) + if g:NERDTreeSortOrder[0] =~ '\[\[.*\]\]' + " Apply tags' sorting first if specified first. + let self._sortKey = metadata + [self.getSortOrderIndex()] + else + " Otherwise, do regex grouping first. + let self._sortKey = [self.getSortOrderIndex()] + metadata endif let path = self.getLastPathComponent(1) diff --git a/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim b/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim index a834e7c1..aa9dea6a 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim @@ -620,6 +620,11 @@ function! s:TreeDirNode.reveal(path, ...) if self.path.equals(a:path.getParent()) let n = self.findNode(a:path) + " We may be looking for a newly-saved file that isn't in the tree yet. + if n == {} + call self.refresh() + let n = self.findNode(a:path) + endif if has_key(opts, "open") call n.open() endif diff --git a/sources_non_forked/nerdtree/lib/nerdtree/ui.vim b/sources_non_forked/nerdtree/lib/nerdtree/ui.vim index 6ff9878e..d384071d 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/ui.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/ui.vim @@ -6,7 +6,7 @@ let s:UI = {} let g:NERDTreeUI = s:UI -" FUNCTION: s:UI.centerView() {{{2 +" FUNCTION: s:UI.centerView() {{{1 " centers the nerd tree window around the cursor (provided the nerd tree " options permit) function! s:UI.centerView() @@ -28,7 +28,6 @@ function! s:UI._dumpHelp() let help .= "\" ============================\n" let help .= "\" File node mappings~\n" let help .= "\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" - let help .= "\" <CR>,\n" if self.nerdtree.isTabTree() let help .= "\" ". g:NERDTreeMapActivateNode .": open in prev window\n" else @@ -44,6 +43,7 @@ function! s:UI._dumpHelp() let help .= "\" ". g:NERDTreeMapPreviewSplit .": preview split\n" let help .= "\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" let help .= "\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + let help .= "\" ". g:NERDTreeMapCustomOpen .": custom open\n" let help .= "\"\n\" ----------------------------\n" let help .= "\" Directory node mappings~\n" @@ -52,6 +52,7 @@ function! s:UI._dumpHelp() let help .= "\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" let help .= "\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" let help .= "\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let help .= "\" ". g:NERDTreeMapCustomOpen .": custom open\n" let help .= "\" ". g:NERDTreeMapCloseDir .": close parent of node\n" let help .= "\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" let help .= "\" current node recursively\n" @@ -66,6 +67,7 @@ function! s:UI._dumpHelp() let help .= "\" ". g:NERDTreeMapPreview .": find dir in tree\n" let help .= "\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" let help .= "\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let help .= "\" ". g:NERDTreeMapCustomOpen .": custom open\n" let help .= "\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" let help .= "\"\n\" ----------------------------\n" @@ -252,7 +254,7 @@ endfunction " gets the line number of the root node function! s:UI.getRootLineNum() let rootLine = 1 - while getline(rootLine) !~# '^\(/\|<\)' + while rootLine <= line('$') && getline(rootLine) !~# '^\(/\|<\)' let rootLine = rootLine + 1 endwhile return rootLine @@ -338,7 +340,7 @@ function! s:UI.restoreScreenState() if !has_key(self, '_screenState') return endif - exec("silent vertical resize " . self._screenState['oldWindowSize']) + call nerdtree#exec("silent vertical resize " . self._screenState['oldWindowSize'], 1) let old_scrolloff=&scrolloff let &scrolloff=0 @@ -358,7 +360,7 @@ function! s:UI.saveScreenState() let self._screenState['oldPos'] = getpos(".") let self._screenState['oldTopLine'] = line("w0") let self._screenState['oldWindowSize']= winwidth("") - call nerdtree#exec(win . "wincmd w") + call nerdtree#exec(win . "wincmd w", 1) endfunction " FUNCTION: s:UI.setShowHidden(val) {{{1 @@ -504,10 +506,10 @@ endfunction function! s:UI.toggleZoom() if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize - exec "silent vertical resize ". size + call nerdtree#exec("silent vertical resize ". size, 1) let b:NERDTreeZoomed = 0 else - exec "vertical resize ". get(g:, 'NERDTreeWinSizeMax', '') + call nerdtree#exec("vertical resize ". get(g:, 'NERDTreeWinSizeMax', ''), 1) let b:NERDTreeZoomed = 1 endif endfunction diff --git a/sources_non_forked/nerdtree/nerdtree_plugin/fs_menu.vim b/sources_non_forked/nerdtree/nerdtree_plugin/fs_menu.vim index 3eef5176..0a5de8a4 100644 --- a/sources_non_forked/nerdtree/nerdtree_plugin/fs_menu.vim +++ b/sources_non_forked/nerdtree/nerdtree_plugin/fs_menu.vim @@ -37,6 +37,7 @@ endif if g:NERDTreePath.CopyingSupported() call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'}) endif +call NERDTreeAddMenuItem({'text': (has("clipboard")?'copy (p)ath to clipboard':'print (p)ath to screen'), 'shortcut': 'p', 'callback': 'NERDTreeCopyPath'}) if has("unix") || has("osx") call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNode'}) @@ -113,14 +114,14 @@ function! s:promptToDelBuffer(bufnum, msg) let l:listedBufferCount = 0 endif if l:listedBufferCount > 1 - exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':bnext! ' | endif" + call nerdtree#exec("tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':bnext! ' | endif", 1) else - exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif" + call nerdtree#exec("tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif", 1) endif - exec "tabnext " . s:originalTabNumber - exec s:originalWindowNumber . "wincmd w" + call nerdtree#exec("tabnext " . s:originalTabNumber, 1) + call nerdtree#exec(s:originalWindowNumber . "wincmd w", 1) " 3. We don't need a previous buffer anymore - exec "bwipeout! " . a:bufnum + call nerdtree#exec("bwipeout! " . a:bufnum, 0) endif endfunction @@ -140,17 +141,17 @@ function! s:renameBuffer(bufNum, newNodeName, isDirectory) let editStr = g:NERDTreePath.New(a:newNodeName).str({'format': 'Edit'}) endif " 1. ensure that a new buffer is loaded - exec "badd " . quotedFileName + call nerdtree#exec("badd " . quotedFileName, 1) " 2. ensure that all windows which display the just deleted filename " display a buffer for a new filename. let s:originalTabNumber = tabpagenr() let s:originalWindowNumber = winnr() - exec "tabdo windo if winbufnr(0) == " . a:bufNum . " | exec ':e! " . editStr . "' | endif" - exec "tabnext " . s:originalTabNumber - exec s:originalWindowNumber . "wincmd w" + call nerdtree#exec("tabdo windo if winbufnr(0) == " . a:bufNum . " | exec ':e! " . editStr . "' | endif", 1) + call nerdtree#exec("tabnext " . s:originalTabNumber, 1) + call nerdtree#exec(s:originalWindowNumber . "wincmd w", 1) " 3. We don't need a previous buffer anymore try - exec "confirm bwipeout " . a:bufNum + call nerdtree#exec("confirm bwipeout " . a:bufNum, 0) catch " This happens when answering Cancel if confirmation is needed. Do nothing. endtry @@ -364,6 +365,17 @@ function! NERDTreeCopyNode() redraw! endfunction +" FUNCTION: NERDTreeCopyPath() {{{1 +function! NERDTreeCopyPath() + let l:nodePath = g:NERDTreeFileNode.GetSelected().path.str() + if has("clipboard") + let @* = l:nodePath + call nerdtree#echo("The path [" . l:nodePath . "] was copied to your clipboard.") + else + call nerdtree#echo("The full path is: " . l:nodePath) + endif +endfunction + " FUNCTION: NERDTreeQuickLook() {{{1 function! NERDTreeQuickLook() let treenode = g:NERDTreeFileNode.GetSelected() diff --git a/sources_non_forked/nerdtree/plugin/NERD_tree.vim b/sources_non_forked/nerdtree/plugin/NERD_tree.vim index 595e780b..a8e26d4e 100644 --- a/sources_non_forked/nerdtree/plugin/NERD_tree.vim +++ b/sources_non_forked/nerdtree/plugin/NERD_tree.vim @@ -121,6 +121,7 @@ endif "SECTION: Init variable calls for key mappings {{{2 +call s:initVariable("g:NERDTreeMapCustomOpen", "<CR>") call s:initVariable("g:NERDTreeMapActivateNode", "o") call s:initVariable("g:NERDTreeMapChangeRoot", "C") call s:initVariable("g:NERDTreeMapChdir", "cd") diff --git a/sources_non_forked/nginx.vim/README.md b/sources_non_forked/nginx.vim/README.md index 856dff23..58eceefa 100644 --- a/sources_non_forked/nginx.vim/README.md +++ b/sources_non_forked/nginx.vim/README.md @@ -1,9 +1,12 @@ # nginx.vim ## Description + [Vim](http://www.vim.org/) plugin for [Nginx](http://www.nginx.org) + ## Features + The plugin is based on the recent vim-plugin distributed with `nginx-1.12.0` and additionally features the following syntax improvements: - Highlight IPv4 and IPv6 addresses @@ -24,6 +27,7 @@ Furthermore: ## Screenshots + A `server` block with highlighting of insecure `ssl_protocol` options:  @@ -37,46 +41,18 @@ Embedded LUA syntax highlighting:  -## Snippets -The plugin comes with useful snippets which can be accessed using e.g. [vim-snipmate](https://github.com/garbas/vim-snipmate). - -Select a decent cipher for your requirements (all of them can provide [SSLLabs A+ ratings](https://www.ssllabs.com/ssltest/analyze.html)) - -- `ciphers-paranoid<tab>`: Even-more-secure ciphers (elliptic curves, no GCM), not compatible with IE < 11, OpenSSL-0.9.8, Safari < 7, Android != 4.4 -- **`ciphers-modern<tab>`: High-security ciphers (elliptic curves), not compatible with IE < 11, OpenSSL-0.9.8, Safari < 7, Android < 4.4 (recommended)** -- `ciphers-compat<tab>`: Medium-security ciphers with good compatibility (No IE on WinXP) but TLSv1 and SHA required -- `ciphers-old<tab>`: Low-security ciphers (using weak DES and SHA ciphers, TLSv1), but compatible with everything but IE6 and Java6 -- `ssl-options<tab>`: Bootstrap secure SSL options - -Example: -```nginx -# High-security ciphers (elliptic curves), less compatibility -# No IE < 10, OpenSSL-0.9.8, Safari < 7, Android < 4.4 -ssl_protocols TLSv1.1 TLSv1.2; -ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; -``` - -Or add a robots.txt file with `robots.txt<tab>`: -```nginx -# Tell bots to not index this site -location /robots.txt { - default_type text/plain; - return 200 'User-agent: *\nDisallow: /\n'; -} -``` - -It also has auto-completion for location and server blocks with `location<tab>` resp. `server<tab>`, and [many more](https://github.com/chr4/nginx.vim/blob/master/snippets/nginx.snippets)! - -- Add useful [snippets](https://github.com/chr4/nginx.vim/blob/master/snippets/nginx.snippets) - ## References + - Based on the original `nginx-1.12.0/contrib/vim` - IPv4 and IPv6 address highlighting, based on expressions found in [this forum post](http://vim.1045645.n5.nabble.com/IPv6-support-for-quot-dns-quot-zonefile-syntax-highlighting-td1197292.html) - [Blog post](https://chr4.org/blog/2017/04/14/better-syntax-highlighting-and-snippets-for-nginx-in-vim/) introducing this plugin including some more examples +For help with secure cipher selection, visit [Mozillas SSL Configuration Generator](https://ssl-config.mozilla.org/) + ## Installation ### Pathogen + ```bash git clone https://github.com/chr4/nginx.vim ~/.vim/bundle/nginx.vim ``` diff --git a/sources_non_forked/nginx.vim/snippets/nginx.snippets b/sources_non_forked/nginx.vim/snippets/nginx.snippets deleted file mode 100644 index 68b1118a..00000000 --- a/sources_non_forked/nginx.vim/snippets/nginx.snippets +++ /dev/null @@ -1,166 +0,0 @@ -# vim: ft=nginx -snippet l80 - listen [::]:80 ipv6only=off; - $0 - -# Listen statements when using multiple http server blocks -snippet l80-multi - listen [::]:80 default_server; - listen 80 default_server; - $0 - -snippet l443 - listen [::]:443 ipv6only=off ssl http2 default_server; - $0 - -# Listen statements when using multiple ssl server blocks -snippet l443-multi - listen [::]:443 ssl http2 default_server; - listen 443 ssl http2 default_server; - $0 - -# Cipher suites are taken and adapted from Mozilla's recommendations -# https://wiki.mozilla.org/Security/Server_Side_TLS -# -# Paranoid mode -snippet ciphers-paranoid - # Paranoid ciphers, 256bit minimum, prefer ChaCha20/ Poly1305, bad compatibility - # No Android 5+6 (4.4 works), Chrome < 51, Firefox < 49, IE < 11, Java 6-8, GoogleBot - ssl_protocols TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; - $0 - -# Mozilla modern -snippet ciphers-modern - # High-security ciphers (elliptic curves), less compatibility - # No IE < 10, OpenSSL-0.9.8, Safari < 7, Android < 4.4 - ssl_protocols TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; - $0 - -# Mozilla intermediate (Removed DES for more security) -snippet ciphers-compat - # Medium-security ciphers with good compatibility (Weak: SHA) - # No IE on WinXP - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; - $0 - -# Mozilla old (Removed DSS, HIGH, SEED for more security) -snippet ciphers-low - # Low-security ciphers (Weak: DES, SHA) - # No IE6, Java6 - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:!SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!KRB5-DES-CBC3-SHA:!SRP:!DSS'; - $0 - -snippet ssl-options - # SSL certificate - ssl_certificate /etc/nginx/certs/${4:www.example.com}.crt; - ssl_certificate_key /etc/nginx/certs/${5:www.example.com}.key; - # ssl_dhparam /etc/nginx/certs/dhparam.pem; - - ssl_prefer_server_ciphers on; - ssl_stapling off; - ssl_stapling_verify off; - ssl_session_cache 'shared:SSL:10m'; - ssl_session_tickets off; - - # Enable HSTS (1 year) and some security options - add_header Strict-Transport-Security 'max-age=31536000 includeSubDomains; preload;'; - $0 - -snippet security-headers - add_header X-Frame-Options 'DENY'; - add_header X-Content-Type-Options 'nosniff'; - add_header X-Frame-Options 'SAMEORIGIN'; - add_header X-XSS-Protection '1; mode=block'; - add_header X-Robots-Tag 'none'; - add_header X-Download-Options 'noopen'; - add_header X-Permitted-Cross-Domain-Policies 'none'; - $0 - -snippet robots.txt - # Tell bots to not index this site - location /robots.txt { - default_type text/plain; - return 200 'User-agent: *\nDisallow: /\n'; - } - $0 - -snippet basic-auth - auth_basic 'Restricted'; - auth_basic_user_file ${1:/etc/nginx/htpasswd}; - $0 - -snippet proxy_pass - proxy_pass_header Date; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://${1:backend}; - $0 - -snippet php-fpm - location ~ \.php$ { - include fastcgi_params; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_index index.php; - fastcgi_intercept_errors on; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_pass ${1:127.0.0.1:9000}; - } - $0 - -snippet php-uwsgi - location ~ \.php$ { - include uwsgi_params; - uwsgi_max_temp_file_size 4096m; - uwsgi_modifier1 14; - uwsgi_read_timeout 900; - uwsgi_send_timeout 900; - uwsgi_pass ${1:unix:///run/uwsgi/php.sock}; - } - $0 - -snippet redirect-ssl - location / { - return 301 https://$http_host$request_uri; - } - $0 - -snippet redirect-other - # Redirect other requested hosts - if ($host != '${1:DOMAIN}') { - return 301 https://${2:DOMAIN}$request_uri; - } - $0 - -snippet letsencrypt - listen [::]:80 ipv6only=off; - - # Serve well-known path for letsencrypt - location /.well-known/acme-challenge { - root /etc/nginx/certs/acme; - default_type text/plain; - } - - location / { - return 301 https://$http_host$request_uri; - } - $0 - -snippet cut-trailing-slash - rewrite ^/(.*)/$ $scheme://$http_host:$server_port/$1 permanent; - $0 - -snippet location - location ${1:/} { - ${0:${VISUAL}} - } - -snippet server - server { - ${0:${VISUAL}} - } diff --git a/sources_non_forked/vim-bundle-mako/indent/mako.vim b/sources_non_forked/vim-bundle-mako/indent/mako.vim index 4433cc4a..f1f9482a 100644 --- a/sources_non_forked/vim-bundle-mako/indent/mako.vim +++ b/sources_non_forked/vim-bundle-mako/indent/mako.vim @@ -170,66 +170,101 @@ endfun " [-- <ELEMENT ? - - ...> --] call <SID>HtmlIndentPush('a') call <SID>HtmlIndentPush('abbr') -call <SID>HtmlIndentPush('acronym') call <SID>HtmlIndentPush('address') +call <SID>HtmlIndentPush('applet') +call <SID>HtmlIndentPush('article') +call <SID>HtmlIndentPush('aside') +call <SID>HtmlIndentPush('audio') call <SID>HtmlIndentPush('b') +call <SID>HtmlIndentPush('bdi') call <SID>HtmlIndentPush('bdo') -call <SID>HtmlIndentPush('big') call <SID>HtmlIndentPush('blockquote') call <SID>HtmlIndentPush('button') +call <SID>HtmlIndentPush('canvas') call <SID>HtmlIndentPush('caption') -call <SID>HtmlIndentPush('center') call <SID>HtmlIndentPush('cite') call <SID>HtmlIndentPush('code') call <SID>HtmlIndentPush('colgroup') +call <SID>HtmlIndentPush('content') +call <SID>HtmlIndentPush('data') +call <SID>HtmlIndentPush('datalist') call <SID>HtmlIndentPush('del') +call <SID>HtmlIndentPush('details') call <SID>HtmlIndentPush('dfn') +call <SID>HtmlIndentPush('dialog') call <SID>HtmlIndentPush('dir') call <SID>HtmlIndentPush('div') call <SID>HtmlIndentPush('dl') +call <SID>HtmlIndentPush('element') call <SID>HtmlIndentPush('em') call <SID>HtmlIndentPush('fieldset') -call <SID>HtmlIndentPush('font') +call <SID>HtmlIndentPush('figcaption') +call <SID>HtmlIndentPush('figure') +call <SID>HtmlIndentPush('footer') call <SID>HtmlIndentPush('form') -call <SID>HtmlIndentPush('frameset') call <SID>HtmlIndentPush('h1') call <SID>HtmlIndentPush('h2') call <SID>HtmlIndentPush('h3') call <SID>HtmlIndentPush('h4') call <SID>HtmlIndentPush('h5') call <SID>HtmlIndentPush('h6') +call <SID>HtmlIndentPush('header') +call <SID>HtmlIndentPush('hgroup') call <SID>HtmlIndentPush('i') call <SID>HtmlIndentPush('iframe') call <SID>HtmlIndentPush('ins') call <SID>HtmlIndentPush('kbd') call <SID>HtmlIndentPush('label') call <SID>HtmlIndentPush('legend') +call <SID>HtmlIndentPush('li') +call <SID>HtmlIndentPush('main') call <SID>HtmlIndentPush('map') +call <SID>HtmlIndentPush('mark') +call <SID>HtmlIndentPush('MediaStream') call <SID>HtmlIndentPush('menu') -call <SID>HtmlIndentPush('noframes') +call <SID>HtmlIndentPush('menuitem') +call <SID>HtmlIndentPush('meter') +call <SID>HtmlIndentPush('nav') +call <SID>HtmlIndentPush('noembed') call <SID>HtmlIndentPush('noscript') call <SID>HtmlIndentPush('object') call <SID>HtmlIndentPush('ol') call <SID>HtmlIndentPush('optgroup') +call <SID>HtmlIndentPush('option') +call <SID>HtmlIndentPush('output') +call <SID>HtmlIndentPush('picture') call <SID>HtmlIndentPush('pre') +call <SID>HtmlIndentPush('progress') call <SID>HtmlIndentPush('q') +call <SID>HtmlIndentPush('rb') +call <SID>HtmlIndentPush('rp') +call <SID>HtmlIndentPush('rt') +call <SID>HtmlIndentPush('rtc') +call <SID>HtmlIndentPush('ruby') call <SID>HtmlIndentPush('s') call <SID>HtmlIndentPush('samp') call <SID>HtmlIndentPush('script') +call <SID>HtmlIndentPush('section') call <SID>HtmlIndentPush('select') +call <SID>HtmlIndentPush('shadow') +call <SID>HtmlIndentPush('slot') call <SID>HtmlIndentPush('small') call <SID>HtmlIndentPush('span') call <SID>HtmlIndentPush('strong') call <SID>HtmlIndentPush('style') call <SID>HtmlIndentPush('sub') +call <SID>HtmlIndentPush('summary') call <SID>HtmlIndentPush('sup') call <SID>HtmlIndentPush('table') +call <SID>HtmlIndentPush('template') call <SID>HtmlIndentPush('textarea') +call <SID>HtmlIndentPush('time') call <SID>HtmlIndentPush('title') call <SID>HtmlIndentPush('tt') call <SID>HtmlIndentPush('u') call <SID>HtmlIndentPush('ul') call <SID>HtmlIndentPush('var') +call <SID>HtmlIndentPush('video') " For some reason the default HTML indentation script doesn't consider these " elements to be worthy of indentation. @@ -256,6 +291,44 @@ if !exists('g:html_indent_strict_table') call <SID>HtmlIndentPush('thead') endif +" [-- <OBSOLETE ELEMENTS ? - - ...> --] +call <SID>HtmlIndentPush('abbr') +call <SID>HtmlIndentPush('acronym') +call <SID>HtmlIndentPush('applet') +call <SID>HtmlIndentPush('audio') +call <SID>HtmlIndentPush('basefont') +call <SID>HtmlIndentPush('bgsound') +call <SID>HtmlIndentPush('big') +call <SID>HtmlIndentPush('blink') +call <SID>HtmlIndentPush('center') +call <SID>HtmlIndentPush('command') +call <SID>HtmlIndentPush('content') +call <SID>HtmlIndentPush('dir') +call <SID>HtmlIndentPush('element') +call <SID>HtmlIndentPush('embed') +call <SID>HtmlIndentPush('font') +call <SID>HtmlIndentPush('frame') +call <SID>HtmlIndentPush('frameset') +call <SID>HtmlIndentPush('image') +call <SID>HtmlIndentPush('img') +call <SID>HtmlIndentPush('isindex') +call <SID>HtmlIndentPush('keygen') +call <SID>HtmlIndentPush('listing') +call <SID>HtmlIndentPush('marquee') +call <SID>HtmlIndentPush('menuitem') +call <SID>HtmlIndentPush('multicol') +call <SID>HtmlIndentPush('nextid') +call <SID>HtmlIndentPush('nobr') +call <SID>HtmlIndentPush('noembed') +call <SID>HtmlIndentPush('noframes') +call <SID>HtmlIndentPush('object') +call <SID>HtmlIndentPush('plaintext') +call <SID>HtmlIndentPush('shadow') +call <SID>HtmlIndentPush('spacer') +call <SID>HtmlIndentPush('strike') +call <SID>HtmlIndentPush('tt') +call <SID>HtmlIndentPush('xmp') + " [-- <Mako Elements> --] call <SID>MakoIndentPush('%def') call <SID>MakoIndentPush('%block') diff --git a/sources_non_forked/vim-fugitive/autoload/fugitive.vim b/sources_non_forked/vim-fugitive/autoload/fugitive.vim index 8521f551..b012f20d 100644 --- a/sources_non_forked/vim-fugitive/autoload/fugitive.vim +++ b/sources_non_forked/vim-fugitive/autoload/fugitive.vim @@ -8,6 +8,8 @@ let g:autoloaded_fugitive = 1 if !exists('g:fugitive_git_executable') let g:fugitive_git_executable = 'git' +elseif g:fugitive_git_executable =~# '^\w\+=' + let g:fugitive_git_executable = 'env ' . g:fugitive_git_executable endif " Section: Utility @@ -44,7 +46,9 @@ function! s:winshell() abort endfunction function! s:shellesc(arg) abort - if a:arg =~ '^[A-Za-z0-9_/.-]\+$' + if type(a:arg) == type([]) + return join(map(copy(a:arg), 's:shellesc(v:val)')) + elseif a:arg =~ '^[A-Za-z0-9_/:.-]\+$' return a:arg elseif s:winshell() return '"'.s:gsub(s:gsub(a:arg, '"', '""'), '\%', '"%"').'"' @@ -55,7 +59,9 @@ endfunction let s:fnameescape = " \t\n*?[{`$\\%#'\"|!<" function! s:fnameescape(file) abort - if exists('*fnameescape') + if type(a:file) == type([]) + return join(map(copy(a:file), 's:fnameescape(v:val)')) + elseif exists('*fnameescape') return fnameescape(a:file) else return escape(a:file, s:fnameescape) @@ -63,15 +69,23 @@ function! s:fnameescape(file) abort endfunction function! s:throw(string) abort - let v:errmsg = 'fugitive: '.a:string - throw v:errmsg + throw 'fugitive: '.a:string endfunction -function! s:warn(str) abort - echohl WarningMsg - echomsg a:str - echohl None - let v:warningmsg = a:str +function! s:DirCheck(...) abort + if empty(a:0 ? s:Dir(a:1) : s:Dir()) + return 'return ' . string('echoerr "fugitive: not a Git repository"') + endif + return '' +endfunction + +function! s:Mods(mods, ...) abort + let mods = substitute(a:mods, '\C<mods>', '', '') + let mods = mods =~# '\S$' ? mods . ' ' : mods + if a:0 && mods !~# '\<\%(aboveleft\|belowright\|leftabove\|rightbelow\|topleft\|botright\|tab\)\>' + let mods = a:1 . ' ' . mods + endif + return substitute(mods, '\s\+', ' ', 'g') endfunction function! s:Slash(path) abort @@ -82,27 +96,19 @@ function! s:Slash(path) abort endif endfunction -function! s:PlatformSlash(path) abort - if exists('+shellslash') && !&shellslash - return tr(a:path, '/', '\') - else - return a:path - endif -endfunction - function! s:Resolve(path) abort let path = resolve(a:path) if has('win32') - let path = s:PlatformSlash(fnamemodify(fnamemodify(path, ':h'), ':p') . fnamemodify(path, ':t')) + let path = FugitiveVimPath(fnamemodify(fnamemodify(path, ':h'), ':p') . fnamemodify(path, ':t')) endif return path endfunction function! s:cpath(path, ...) abort if exists('+fileignorecase') && &fileignorecase - let path = s:PlatformSlash(tolower(a:path)) + let path = FugitiveVimPath(tolower(a:path)) else - let path = s:PlatformSlash(a:path) + let path = FugitiveVimPath(a:path) endif return a:0 ? path ==# s:cpath(a:1) : path endfunction @@ -129,59 +135,119 @@ function! s:executable(binary) abort return s:executables[a:binary] endfunction -function! s:map(mode, lhs, rhs, ...) abort - let flags = (a:0 ? a:1 : '') . (a:rhs =~# '<Plug>' ? '' : '<script>') - let head = a:lhs - let tail = '' - let keys = get(g:, a:mode.'remap', {}) - if type(keys) == type([]) - return - endif - while !empty(head) - if has_key(keys, head) - let head = keys[head] - if empty(head) - return +let s:nowait = v:version >= 704 ? '<nowait>' : '' + +function! s:Map(mode, lhs, rhs, ...) abort + for mode in split(a:mode, '\zs') + let flags = (a:0 ? a:1 : '') . (a:rhs =~# '<Plug>' ? '' : '<script>') + let head = a:lhs + let tail = '' + let keys = get(g:, mode.'remap', {}) + if type(keys) == type([]) + return + endif + while !empty(head) + if has_key(keys, head) + let head = keys[head] + if empty(head) + return + endif + break + endif + let tail = matchstr(head, '<[^<>]*>$\|.$') . tail + let head = substitute(head, '<[^<>]*>$\|.$', '', '') + endwhile + if flags !~# '<unique>' || empty(mapcheck(head.tail, mode)) + exe mode.'map <buffer>' s:nowait flags head.tail a:rhs + if a:0 > 1 + let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . + \ '|sil! exe "' . mode . 'unmap <buffer> ' . head.tail . '"' endif - break - endif - let tail = matchstr(head, '<[^<>]*>$\|.$') . tail - let head = substitute(head, '<[^<>]*>$\|.$', '', '') - endwhile - if flags !~# '<unique>' || empty(mapcheck(head.tail, a:mode)) - exe a:mode.'map <buffer>' flags head.tail a:rhs - if a:0 > 1 - let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . - \ '|sil! exe "' . a:mode . 'unmap <buffer> ' . head.tail . '"' endif + endfor +endfunction + +" Section: Quickfix + +function! s:QuickfixGet(nr, ...) abort + if a:nr < 0 + return call('getqflist', a:000) + else + return call('getloclist', [a:nr] + a:000) endif endfunction -function! s:System(cmd) abort - try - return system(a:cmd) - catch /^Vim\%((\a\+)\)\=:E484:/ - let opts = ['shell', 'shellcmdflag', 'shellredir', 'shellquote', 'shellxquote', 'shellxescape', 'shellslash'] - call filter(opts, 'exists("+".v:val) && !empty(eval("&".v:val))') - call map(opts, 'v:val."=".eval("&".v:val)') - call s:throw('failed to run `' . a:cmd . '` with ' . join(opts, ' ')) - endtry +function! s:QuickfixSet(nr, ...) abort + if a:nr < 0 + return call('setqflist', a:000) + else + return call('setloclist', [a:nr] + a:000) + endif +endfunction + +function! s:QuickfixCreate(nr, opts) abort + if has('patch-7.4.2200') + call s:QuickfixSet(a:nr, [], ' ', a:opts) + else + call s:QuickfixSet(a:nr, [], ' ') + endif +endfunction + +function! s:QuickfixStream(nr, title, cmd, first, callback, ...) abort + call s:QuickfixCreate(a:nr, {'title': a:title}) + let winnr = winnr() + exe a:nr < 0 ? 'copen' : 'lopen' + if winnr != winnr() + wincmd p + endif + + let buffer = [] + let lines = split(s:SystemError(s:shellesc(a:cmd))[0], "\n") + for line in lines + call extend(buffer, call(a:callback, a:000 + [line])) + if len(buffer) >= 20 + call s:QuickfixSet(a:nr, remove(buffer, 0, -1), 'a') + redraw + endif + endfor + call s:QuickfixSet(a:nr, extend(buffer, call(a:callback, a:000 + [0])), 'a') + + if a:first && len(s:QuickfixGet(a:nr)) + call s:BlurStatus() + return a:nr < 0 ? 'cfirst' : 'lfirst' + else + return 'exe' + endif endfunction " Section: Git -function! s:UserCommand() abort - return get(g:, 'fugitive_git_command', g:fugitive_git_executable) +function! s:UserCommandList(...) abort + let git = split(get(g:, 'fugitive_git_command', g:fugitive_git_executable), '\s\+') + let dir = a:0 ? s:Dir(a:1) : '' + if len(dir) + let tree = s:Tree(dir) + if empty(tree) + call add(git, '--git-dir=' . FugitiveGitPath(dir)) + elseif len(tree) && s:cpath(tree) !=# s:cpath(getcwd()) + if fugitive#GitVersion(1, 8, 5) + call extend(git, ['-C', FugitiveGitPath(tree)]) + else + throw 'fugitive: Git 1.8.5 or higher required to change directory' + endif + endif + endif + return git endfunction -function! s:Prepare(...) abort - return call('fugitive#Prepare', a:000) +function! s:UserCommand(...) abort + return s:shellesc(call('s:UserCommandList', a:0 ? [a:1] : []) + (a:0 ? a:2 : [])) endfunction let s:git_versions = {} function! fugitive#GitVersion(...) abort if !has_key(s:git_versions, g:fugitive_git_executable) - let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), '\d\S\+') + let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), '\d[^[:space:]]\+') endif if !a:0 return s:git_versions[g:fugitive_git_executable] @@ -209,11 +275,11 @@ function! fugitive#CommonDir(dir) abort if getfsize(a:dir . '/HEAD') < 10 let s:commondirs[a:dir] = '' elseif filereadable(a:dir . '/commondir') - let dir = get(readfile(a:dir . '/commondir', 1), 0, '') - if dir =~# '^/\|^\a:/' - let s:commondirs[a:dir] = dir + let cdir = get(readfile(a:dir . '/commondir', 1), 0, '') + if cdir =~# '^/\|^\a:/' + let s:commondirs[a:dir] = s:Slash(FugitiveVimPath(cdir)) else - let s:commondirs[a:dir] = simplify(a:dir . '/' . dir) + let s:commondirs[a:dir] = simplify(a:dir . '/' . cdir) endif else let s:commondirs[a:dir] = a:dir @@ -230,12 +296,33 @@ function! s:Tree(...) abort return a:0 ? FugitiveWorkTree(a:1) : FugitiveWorkTree() endfunction +function! s:HasOpt(args, ...) abort + let args = a:args[0 : index(a:args, '--')] + let opts = copy(a:000) + if type(opts[0]) == type([]) + if empty(args) || index(opts[0], args[0]) == -1 + return 0 + endif + call remove(opts, 0) + endif + for opt in opts + if index(args, opt) != -1 + return 1 + endif + endfor +endfunction + function! s:PreparePathArgs(cmd, dir, literal) abort let literal_supported = fugitive#GitVersion(1, 9) if a:literal && literal_supported call insert(a:cmd, '--literal-pathspecs') endif let split = index(a:cmd, '--') + for i in range(split < 0 ? len(a:cmd) : split) + if type(a:cmd[i]) == type(0) + let a:cmd[i] = fugitive#Path(bufname(a:cmd[i]), './', a:dir) + endif + endfor if split < 0 return a:cmd endif @@ -256,20 +343,19 @@ let s:prepare_env = { \ 'core.editor': 'GIT_EDITOR', \ 'core.askpass': 'GIT_ASKPASS', \ } -function! fugitive#Prepare(...) abort - if !a:0 - return g:fugitive_git_executable - endif - if type(a:1) ==# type([]) +function! fugitive#PrepareDirEnvArgv(...) abort + if a:0 && type(a:1) ==# type([]) let cmd = a:000[1:-1] + a:1 else let cmd = copy(a:000) endif - let pre = '' + let env = {} let i = 0 while i < len(cmd) if cmd[i] =~# '^$\|[\/.]' && cmd[i] !~# '^-' let dir = remove(cmd, 0) + elseif cmd[i] =~# '^--git-dir=' + let dir = remove(cmd, 0)[10:-1] elseif type(cmd[i]) ==# type(0) let dir = s:Dir(remove(cmd, i)) elseif cmd[i] ==# '-c' && len(cmd) > i + 1 @@ -277,11 +363,7 @@ function! fugitive#Prepare(...) abort if has_key(s:prepare_env, tolower(key)) || key !~# '\.' let var = get(s:prepare_env, tolower(key), key) let val = matchstr(cmd[i+1], '=\zs.*') - if s:winshell() - let pre .= 'set ' . var . '=' . s:shellesc(val) . ' & ' - else - let pre = (len(pre) ? pre : 'env ') . var . '=' . s:shellesc(val) . ' ' - endif + let env[var] = val endif if fugitive#GitVersion(1, 8) && cmd[i+1] =~# '\.' let i += 2 @@ -304,32 +386,105 @@ function! fugitive#Prepare(...) abort if !exists('dir') let dir = s:Dir() endif - let tree = s:Tree(dir) call s:PreparePathArgs(cmd, dir, !exists('explicit_pathspec_option')) - let args = join(map(copy(cmd), 's:shellesc(v:val)')) + return [dir, env, cmd] +endfunction + +function! s:BuildShell(dir, env, args) abort + let cmd = copy(a:args) + let tree = s:Tree(a:dir) + let pre = '' + for [var, val] in items(a:env) + if s:winshell() + let pre .= 'set ' . var . '=' . s:shellesc(val) . '& ' + else + let pre = (len(pre) ? pre : 'env ') . var . '=' . s:shellesc(val) . ' ' + endif + endfor if empty(tree) || index(cmd, '--') == len(cmd) - 1 - let args = s:shellesc('--git-dir=' . dir) . ' ' . args - elseif fugitive#GitVersion(1, 9) - let args = '-C ' . s:shellesc(tree) . ' ' . args + call insert(cmd, '--git-dir=' . FugitiveGitPath(a:dir)) + elseif fugitive#GitVersion(1, 8, 5) + call extend(cmd, ['-C', FugitiveGitPath(tree)], 'keep') else - let pre = 'cd ' . s:shellesc(tree) . (s:winshell() ? ' & ' : '; ') . pre + let pre = 'cd ' . s:shellesc(tree) . (s:winshell() ? '& ' : '; ') . pre endif - return pre . g:fugitive_git_executable . ' ' . args + return pre . g:fugitive_git_executable . ' ' . join(map(cmd, 's:shellesc(v:val)')) +endfunction + +function! fugitive#Prepare(...) abort + let [dir, env, argv] = call('fugitive#PrepareDirEnvArgv', a:000) + return s:BuildShell(dir, env, argv) +endfunction + +function! s:SystemError(cmd, ...) abort + try + if &shellredir ==# '>' && &shell =~# 'sh\|cmd' + let shellredir = &shellredir + if &shell =~# 'csh' + set shellredir=>& + else + set shellredir=>%s\ 2>&1 + endif + endif + let out = call('system', [type(a:cmd) ==# type([]) ? fugitive#Prepare(a:cmd) : a:cmd] + a:000) + return [out, v:shell_error] + catch /^Vim\%((\a\+)\)\=:E484:/ + let opts = ['shell', 'shellcmdflag', 'shellredir', 'shellquote', 'shellxquote', 'shellxescape', 'shellslash'] + call filter(opts, 'exists("+".v:val) && !empty(eval("&".v:val))') + call map(opts, 'v:val."=".eval("&".v:val)') + call s:throw('failed to run `' . a:cmd . '` with ' . join(opts, ' ')) + finally + if exists('shellredir') + let &shellredir = shellredir + endif + endtry +endfunction + +function! s:ChompError(...) abort + let [out, exec_error] = s:SystemError(call('fugitive#Prepare', a:000)) + return [s:sub(out, '\n$', ''), exec_error] +endfunction + +function! s:ChompDefault(default, ...) abort + let [out, exec_error] = call('s:ChompError', a:000) + return exec_error ? a:default : out +endfunction + +function! s:LinesError(...) abort + let [out, exec_error] = call('s:ChompError', a:000) + return [len(out) && !exec_error ? split(out, "\n", 1) : [], exec_error] +endfunction + +function! s:NullError(...) abort + let [out, exec_error] = s:SystemError(call('fugitive#Prepare', a:000)) + return [exec_error ? [] : split(out, "\1"), exec_error ? substitute(out, "\n$", "", "") : '', exec_error] endfunction function! s:TreeChomp(...) abort - return s:sub(s:System(call('fugitive#Prepare', a:000)), '\n$', '') + let cmd = call('fugitive#Prepare', a:000) + let [out, exec_error] = s:SystemError(cmd) + let out = s:sub(out, '\n$', '') + if !exec_error + return out + endif + throw 'fugitive: error running `' . cmd . '`: ' . out +endfunction + +function! s:EchoExec(...) abort + echo call('s:ChompError', a:000)[0] + call fugitive#ReloadStatus(-1, 1) + return 'checktime' endfunction function! fugitive#Head(...) abort let dir = a:0 > 1 ? a:2 : s:Dir() - if empty(dir) || !filereadable(dir . '/HEAD') + if empty(dir) || !filereadable(fugitive#Find('.git/HEAD', dir)) return '' endif - let head = readfile(dir . '/HEAD')[0] + let head = readfile(fugitive#Find('.git/HEAD', dir))[0] if head =~# '^ref: ' return substitute(head, '\C^ref: \%(refs/\%(heads/\|remotes/\|tags/\)\=\)\=', '', '') - elseif head =~# '^\x\{40\}$' + elseif head =~# '^\x\{40,\}$' let len = a:0 ? a:1 : 0 return len < 0 ? head : len ? head[0:len-1] : '' else @@ -338,11 +493,11 @@ function! fugitive#Head(...) abort endfunction function! fugitive#RevParse(rev, ...) abort - let hash = system(s:Prepare(a:0 ? a:1 : s:Dir(), 'rev-parse', '--verify', a:rev, '--'))[0:-2] - if !v:shell_error && hash =~# '^\x\{40\}$' + let [hash, exec_error] = s:ChompError([a:0 ? a:1 : s:Dir(), 'rev-parse', '--verify', a:rev, '--']) + if !exec_error && hash =~# '^\x\{40,\}$' return hash endif - call s:throw('rev-parse '.a:rev.': '.hash) + throw 'fugitive: rev-parse '.a:rev.': '.hash endfunction function! s:ConfigTimestamps(dir, dict) abort @@ -378,8 +533,8 @@ function! fugitive#Config(...) abort let dict = s:config[key][1] else let dict = {} - let lines = split(system(FugitivePrepare(['config', '--list', '-z'], dir)), "\1") - if v:shell_error + let [lines, message, exec_error] = s:NullError([dir, 'config', '--list', '-z']) + if exec_error return {} endif for line in lines @@ -413,9 +568,7 @@ function! fugitive#RemoteUrl(...) abort if !fugitive#GitVersion(2, 7) return fugitive#Config('remote.' . remote . '.url') endif - let cmd = s:Prepare(dir, 'remote', 'get-url', remote, '--') - let out = substitute(system(cmd), "\n$", '', '') - return v:shell_error ? '' : out + return s:ChompDefault('', [dir, 'remote', 'get-url', remote, '--']) endfunction " Section: Repository Object @@ -426,12 +579,30 @@ function! s:add_methods(namespace, method_names) abort endfor endfunction +function! s:Command(command, line1, line2, range, bang, mods, arg, args) abort + try + if a:command =~# '^\l[[:alnum:]-]\+$' + return s:GitCommand(a:line1, a:line2, a:range, a:line2, a:bang, s:Mods(a:mods), '', a:command . ' ' . a:arg, [a:command] + a:args) + endif + return s:{a:command}Command(a:line1, a:line2, a:range, a:line2, a:bang, s:Mods(a:mods), '', a:arg, a:args) + catch /^fugitive:/ + return 'echoerr ' . string(v:exception) + endtry +endfunction + let s:commands = [] function! s:command(definition, ...) abort + let def = a:definition + if !has('patch-7.4.542') + let def = substitute(def, '-addr=\S\+ ', '', '') + endif + if !has('patch-8.1.560') + let def = substitute(def, '-addr=other ', '', '') + endif if a:0 - call add(s:commands, a:definition . ' execute s:' . a:1 . "Command(<line1>, <line2>, +'<range>', <count>, <bang>0, '<mods>', <q-reg>, <q-args>, [<f-args>])") + call add(s:commands, def . ' execute s:Command(' . string(a:1) . ", <line1>, <count>, +'<range>', <bang>0, '<mods>', <q-args>, [<f-args>])") else - call add(s:commands, a:definition) + call add(s:commands, def) endif endfunction @@ -445,7 +616,7 @@ let s:repo_prototype = {} let s:repos = {} function! fugitive#repo(...) abort - let dir = a:0 ? a:1 : (len(s:Dir()) ? s:Dir() : FugitiveExtractGitDir(expand('%:p'))) + let dir = a:0 ? s:Dir(a:1) : (len(s:Dir()) ? s:Dir() : FugitiveExtractGitDir(expand('%:p'))) if dir !=# '' if has_key(s:repos, dir) let repo = get(s:repos, dir) @@ -455,7 +626,7 @@ function! fugitive#repo(...) abort endif return extend(repo, s:repo_prototype, 'keep') endif - call s:throw('not a Git repository: ' . string(dir)) + call s:throw('not a Git repository') endfunction function! s:repo_dir(...) dict abort @@ -505,7 +676,7 @@ endfunction function! s:repo_git_chomp(...) dict abort let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir) let output = git . join(map(copy(a:000),'" ".s:shellesc(v:val)'),'') - return s:sub(s:System(output),'\n$','') + return s:sub(system(output), '\n$', '') endfunction function! s:repo_git_chomp_in_tree(...) dict abort @@ -544,7 +715,7 @@ call s:add_methods('repo',['config', 'user']) " Section: File API function! s:DirCommitFile(path) abort - let vals = matchlist(s:Slash(a:path), '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40\}\|[0-3]\)\(/.*\)\=$') + let vals = matchlist(s:Slash(a:path), '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40,\}\|[0-3]\)\(/.*\)\=$') if empty(vals) return ['', '', ''] endif @@ -561,16 +732,17 @@ function! s:Owner(path, ...) abort if empty(dir) return '' endif + let actualdir = fugitive#Find('.git/', dir) let [pdir, commit, file] = s:DirCommitFile(a:path) if s:cpath(dir, pdir) - if commit =~# '^\x\{40\}$' + if commit =~# '^\x\{40,\}$' return commit elseif commit ==# '2' return 'HEAD^{}' endif - if filereadable(dir . '/MERGE_HEAD') + if filereadable(actualdir . 'MERGE_HEAD') let merge_head = 'MERGE_HEAD' - elseif filereadable(dir . '/REBASE_HEAD') + elseif filereadable(actualdir . 'REBASE_HEAD') let merge_head = 'REBASE_HEAD' else return '' @@ -582,10 +754,10 @@ function! s:Owner(path, ...) abort endif endif let path = fnamemodify(a:path, ':p') - if s:cpath(dir . '/', path[0 : len(dir)]) && a:path =~# 'HEAD$' - return strpart(path, len(dir) + 1) + if s:cpath(actualdir, strpart(path, 0, len(actualdir))) && a:path =~# 'HEAD$' + return strpart(path, len(actualdir)) endif - let refs = fugitive#CommonDir(dir) . '/refs' + let refs = fugitive#Find('.git/refs', dir) if s:cpath(refs . '/', path[0 : len(refs)]) && path !~# '[\/]$' return strpart(path, len(refs) - 4) endif @@ -599,7 +771,7 @@ function! fugitive#Real(url) abort let [dir, commit, file] = s:DirCommitFile(a:url) if len(dir) let tree = s:Tree(dir) - return s:PlatformSlash((len(tree) ? tree : dir) . file) + return FugitiveVimPath((len(tree) ? tree : dir) . file) endif let pre = substitute(matchstr(a:url, '^\a\a\+\ze:'), '^.', '\u&', '') if len(pre) && pre !=? 'fugitive' && exists('*' . pre . 'Real') @@ -607,7 +779,7 @@ function! fugitive#Real(url) abort else let url = fnamemodify(a:url, ':p' . (a:url =~# '[\/]$' ? '' : ':s?[\/]$??')) endif - return s:PlatformSlash(empty(url) ? a:url : url) + return FugitiveVimPath(empty(url) ? a:url : url) endfunction function! fugitive#Path(url, ...) abort @@ -635,8 +807,9 @@ function! fugitive#Path(url, ...) abort return a:1[0:-2] . path endif let url = a:url - if has_key(get(s:temp_files, s:cpath(url), {}), 'bufnr') - let url = bufname(s:temp_files[s:cpath(url)].bufnr) + let temp_state = s:TempState(url) + if has_key(temp_state, 'bufnr') + let url = bufname(temp_state.bufnr) endif let url = s:Slash(fnamemodify(url, ':p')) if url =~# '/$' && s:Slash(a:url) !~# '/$' @@ -653,34 +826,34 @@ function! fugitive#Path(url, ...) abort let file = '/' endif if empty(file) && a:1 =~# '^$\|^[.:]/$' - return s:Slash(fugitive#Real(a:url)) + return FugitiveGitPath(fugitive#Real(a:url)) endif return substitute(file, '^/', a:1, '') endfunction function! s:Relative(...) abort - return fugitive#Path(@%, a:0 ? a:1 : ':(top)') + return fugitive#Path(@%, a:0 ? a:1 : ':(top)', a:0 > 1 ? a:2 : s:Dir()) endfunction function! fugitive#Find(object, ...) abort if type(a:object) == type(0) let name = bufname(a:object) - return s:PlatformSlash(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name) + return FugitiveVimPath(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name) elseif a:object =~# '^[~$]' let prefix = matchstr(a:object, '^[~$]\i*') let owner = expand(prefix) - return s:PlatformSlash((len(owner) ? owner : prefix) . strpart(a:object, len(prefix))) + return FugitiveVimPath((len(owner) ? owner : prefix) . strpart(a:object, len(prefix))) elseif s:Slash(a:object) =~# '^$\|^/\|^\%(\a\a\+:\).*\%(//\|::\)' . (has('win32') ? '\|^\a:/' : '') - return s:PlatformSlash(a:object) + return FugitiveVimPath(a:object) elseif s:Slash(a:object) =~# '^\.\.\=\%(/\|$\)' - return s:PlatformSlash(simplify(getcwd() . '/' . a:object)) + return FugitiveVimPath(simplify(getcwd() . '/' . a:object)) endif let dir = a:0 ? a:1 : s:Dir() if empty(dir) let file = matchstr(a:object, '^\%(:\d:\|[^:]*:\)\zs.*', '', '') let dir = FugitiveExtractGitDir(file) if empty(dir) - return fnamemodify(len(file) ? file : a:object, ':p') + return fnamemodify(FugitiveVimPath(len(file) ? file : a:object), ':p') endif endif let rev = s:Slash(a:object) @@ -697,7 +870,8 @@ function! fugitive#Find(object, ...) abort let f = base . f[3:-1] elseif cdir !=# dir && ( \ f =~# '^/\%(config\|hooks\|info\|logs/refs\|objects\|refs\|worktrees\)\%(/\|$\)' || - \ f !~# '^/logs$\|/\w*HEAD$' && getftime(dir . f) < 0 && getftime(cdir . f) >= 0) + \ f !~# '^/\%(index$\|index\.lock$\|\w*MSG$\|\w*HEAD$\|logs/\w*HEAD$\|logs$\|rebase-\w\+\)\%(/\|$\)' && + \ getftime(FugitiveVimPath(dir . f)) < 0 && getftime(FugitiveVimPath(cdir . f)) >= 0) let f = simplify(cdir . f) else let f = simplify(dir . f) @@ -728,22 +902,21 @@ function! fugitive#Find(object, ...) abort if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && s:cpath(fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(dir)]) ==# s:cpath(dir . '/') && filereadable($GIT_INDEX_FILE) let f = fnamemodify($GIT_INDEX_FILE, ':p') else - let f = dir . '/index' + let f = fugitive#Find('.git/index', dir) endif elseif rev =~# '^:(\%(top\|top,literal\|literal,top\|literal\))' - let f = base . '/' . matchstr(rev, ')\zs.*') + let f = matchstr(rev, ')\zs.*') + if f=~# '^\.\.\=\%(/\|$\)' + let f = simplify(getcwd() . '/' . f) + elseif f !~# '^/\|^\%(\a\a\+:\).*\%(//\|::\)' . (has('win32') ? '\|^\a:/' : '') + let f = base . '/' . f + endif elseif rev =~# '^:/\@!' let f = 'fugitive://' . dir . '//0/' . rev[1:-1] else - if rev =~# 'HEAD$\|^refs/' && rev !~# ':' - let cdir = rev =~# '^refs/' ? fugitive#CommonDir(dir) : dir - if filereadable(cdir . '/' . rev) - let f = simplify(cdir . '/' . rev) - endif - endif if !exists('f') - let commit = substitute(matchstr(rev, '^[^:]\+\|^:.*'), '^@\%($\|[~^]\|@{\)\@=', 'HEAD', '') - let file = substitute(matchstr(rev, '^[^:]\+\zs:.*'), '^:', '/', '') + let commit = substitute(matchstr(rev, '^[^:.-][^:]*\|^:.*'), '^@\%($\|[~^]\|@{\)\@=', 'HEAD', '') + let file = substitute(matchstr(rev, '^[^:.-][^:]*\zs:.*'), '^:', '/', '') if file =~# '^/\.\.\=\%(/\|$\)\|^//\|^/\a\+:' let file = file =~# '^/\.' ? simplify(getcwd() . file) : file[1:-1] if s:cpath(base . '/', (file . '/')[0 : len(base)]) @@ -756,9 +929,13 @@ function! fugitive#Find(object, ...) abort return file endif endif - if commit !~# '^[0-9a-f]\{40\}$' - let commit = system(s:Prepare(dir, 'rev-parse', '--verify', commit, '--'))[0:-2] - let commit = v:shell_error ? '' : commit + let commits = split(commit, '\.\.\.-\@!', 1) + if len(commits) == 2 + call map(commits, 'empty(v:val) || v:val ==# "@" ? "HEAD" : v:val') + let commit = matchstr(s:ChompDefault('', [dir, 'merge-base'] + commits + ['--']), '\<[0-9a-f]\{40,\}\>') + endif + if commit !~# '^[0-9a-f]\{40,\}$' + let commit = matchstr(s:ChompDefault('', [dir, 'rev-parse', '--verify', commit, '--']), '\<[0-9a-f]\{40,\}\>') endif if len(commit) let f = 'fugitive://' . dir . '//' . commit . file @@ -767,25 +944,17 @@ function! fugitive#Find(object, ...) abort endif endif endif - return s:PlatformSlash(f) + return FugitiveVimPath(f) endfunction function! s:Generate(rev, ...) abort - let dir = a:0 ? a:1 : s:Dir() - let tree = s:Tree(dir) - let object = a:rev - if a:rev =~# '^/\.git\%(/\|$\)' - let object = a:rev[1:-1] - elseif a:rev =~# '^/' && len(tree) && getftime(tree . a:rev) >= 0 && getftime(a:rev) < 0 - let object = ':(top)' . a:rev[1:-1] - endif - return fugitive#Find(object, dir) + return fugitive#Find(a:rev, a:0 ? a:1 : s:Dir()) endfunction -function! s:DotRelative(path) abort - let cwd = getcwd() +function! s:DotRelative(path, ...) abort + let cwd = a:0 ? a:1 : getcwd() let path = substitute(a:path, '^[~$]\i*', '\=expand(submatch(0))', '') - if s:cpath(cwd . '/', (path . '/')[0 : len(cwd)]) + if len(cwd) && s:cpath(cwd . '/', (path . '/')[0 : len(cwd)]) return '.' . strpart(path, len(cwd)) endif return a:path @@ -801,13 +970,8 @@ function! fugitive#Object(...) abort if empty(rev) && empty(tree) elseif empty(rev) let rev = fugitive#Path(a:0 ? a:1 : @%, './', dir) - let cdir = fugitive#CommonDir(dir) - if rev =~# '^\./\.git/refs/\%(tags\|heads\|remotes\)/.\|^\./\.git/\w*HEAD$' - let rev = rev[7:-1] - elseif s:cpath(cdir . '/refs/', rev[0 : len(cdir)]) - let rev = strpart(rev, len(cdir)+1) - elseif rev =~# '^\./.git\%(/\|$\)' - return fnamemodify(a:0 ? a:1 : @%, ':p') + if rev =~# '^\./.git\%(/\|$\)' + return fnamemodify(a:0 ? a:1 : @%, ':p' . (rev =~# '/$' ? '' : ':s?/$??')) endif endif if rev !~# '^\.\%(/\|$\)' || s:cpath(getcwd(), tree) @@ -823,30 +987,43 @@ let s:expand = '\%(\(' . s:var . '\)\(' . s:flag . '*\)\(:S\)\=\)' function! s:BufName(var) abort if a:var ==# '%' - return bufname(get(b:, 'fugitive_blamed_bufnr', '')) + return bufname(get(s:TempState(), 'bufnr', '')) elseif a:var =~# '^#\d*$' - let nr = getbufvar(+a:var[1:-1], 'fugitive_blamed_bufnr', '') + let nr = get(s:TempState(bufname(+a:var[1:-1])), 'bufnr', '') return bufname(nr ? nr : +a:var[1:-1]) else return expand(a:var) endif endfunction -function! s:ExpandVar(other, var, flags, esc) abort +function! s:ExpandVarLegacy(str) abort + if get(g:, 'fugitive_legacy_quoting', 1) + return substitute(a:str, '\\\ze[%#!]', '', 'g') + else + return a:str + endif +endfunction + +function! s:ExpandVar(other, var, flags, esc, ...) abort + let cwd = a:0 ? a:1 : getcwd() if a:other =~# '^\' return a:other[1:-1] + elseif a:other =~# '^''' + return s:ExpandVarLegacy(substitute(a:other[1:-2], "''", "'", "g")) + elseif a:other =~# '^"' + return s:ExpandVarLegacy(substitute(a:other[1:-2], '""', '"', "g")) elseif a:other =~# '^!' let buffer = s:BufName(len(a:other) > 1 ? '#'. a:other[1:-1] : '%') let owner = s:Owner(buffer) return len(owner) ? owner : '@' endif let flags = a:flags - let file = s:DotRelative(fugitive#Real(s:BufName(a:var))) + let file = s:DotRelative(fugitive#Real(s:BufName(a:var)), cwd) while len(flags) let flag = matchstr(flags, s:flag) let flags = strpart(flags, len(flag)) if flag ==# ':.' - let file = s:DotRelative(file) + let file = s:DotRelative(file, cwd) else let file = fnamemodify(file, flag) endif @@ -855,22 +1032,19 @@ function! s:ExpandVar(other, var, flags, esc) abort return (len(a:esc) ? shellescape(file) : file) endfunction -function! s:Expand(rev) abort +function! s:Expand(rev, ...) abort if a:rev =~# '^:[0-3]$' - let file = a:rev . s:Relative(':') - elseif a:rev =~# '^-' - let file = 'HEAD^{}' . a:rev[1:-1] . s:Relative(':') - elseif a:rev =~# '^@{' - let file = 'HEAD' . a:rev. s:Relative(':') - elseif a:rev =~# '^\^[0-9~^{]\|^\~[0-9~^]' - let commit = substitute(s:DirCommitFile(@%)[1], '^\d\=$', 'HEAD', '') - let file = commit . a:rev . s:Relative(':') + let file = a:rev . ':%' + elseif a:rev =~# '^>[~^]\|^>@{\|^>$' + let file = 'HEAD' . a:rev[1:-1] . ':%' + elseif a:rev =~# '^>[> ]\@!' + let file = a:rev[1:-1] . ':%' else let file = a:rev endif return substitute(file, \ '\(\\[' . s:fnameescape . ']\|^\\[>+-]\|!\d*\)\|' . s:expand, - \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),"")', 'g') + \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),"", a:0 ? a:1 : getcwd())', 'g') endfunction function! fugitive#Expand(object) abort @@ -879,9 +1053,40 @@ function! fugitive#Expand(object) abort \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),submatch(5))', 'g') endfunction -function! s:ShellExpand(cmd) abort - return substitute(a:cmd, '\(\\[!#%]\|!\d*\)\|' . s:expand, - \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),submatch(5))', 'g') +function! s:ExpandSplit(string, ...) abort + let list = [] + let string = a:string + let handle_bar = a:0 && a:1 + let dquote = handle_bar ? '"\%([^"]\|""\|\\"\)*"\|' : '' + let cwd = a:0 > 1 ? a:2 : getcwd() + while string =~# '\S' + if handle_bar && string =~# '^\s*|' + return [list, substitute(string, '^\s*', '', '')] + endif + let arg = matchstr(string, '^\s*\%(' . dquote . '''[^'']*''\|\\.\|[^[:space:] ' . (handle_bar ? '|' : '') . ']\)\+') + let string = strpart(string, len(arg)) + let arg = substitute(arg, '^\s\+', '', '') + if !exists('seen_separator') + let arg = substitute(arg, '^\%([^:.][^:]*:\|^:\|^:[0-3]:\)\=\zs\.\.\=\%(/.*\)\=$', + \ '\=s:DotRelative(s:Slash(simplify(getcwd() . "/" . submatch(0))), cwd)', '') + endif + let arg = substitute(arg, + \ '\(' . dquote . '''\%(''''\|[^'']\)*''\|\\[' . s:fnameescape . ']\|^\\[>+-]\|!\d*\)\|' . s:expand, + \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),submatch(5), cwd)', 'g') + call add(list, arg) + if arg ==# '--' + let seen_separator = 1 + endif + endwhile + return handle_bar ? [list, ''] : list +endfunction + +function! s:SplitExpand(string, ...) abort + return s:ExpandSplit(a:string, 0, a:0 ? a:1 : getcwd()) +endfunction + +function! s:SplitExpandChain(string, ...) abort + return s:ExpandSplit(a:string, 1, a:0 ? a:1 : getcwd()) endfunction let s:trees = {} @@ -889,14 +1094,14 @@ let s:indexes = {} function! s:TreeInfo(dir, commit) abort if a:commit =~# '^:\=[0-3]$' let index = get(s:indexes, a:dir, []) - let newftime = getftime(a:dir . '/index') + let newftime = getftime(fugitive#Find('.git/index', a:dir)) if get(index, 0, -1) < newftime - let out = system(fugitive#Prepare(a:dir, 'ls-files', '--stage', '--')) + let [lines, exec_error] = s:LinesError([a:dir, 'ls-files', '--stage', '--']) let s:indexes[a:dir] = [newftime, {'0': {}, '1': {}, '2': {}, '3': {}}] - if v:shell_error + if exec_error return [{}, -1] endif - for line in split(out, "\n") + for line in lines let [info, filename] = split(line, "\t") let [mode, sha, stage] = split(info, '\s\+') let s:indexes[a:dir][1][stage][filename] = [newftime, mode, 'blob', sha, -2] @@ -907,25 +1112,25 @@ function! s:TreeInfo(dir, commit) abort endfor endif return [get(s:indexes[a:dir][1], a:commit[-1:-1], {}), newftime] - elseif a:commit =~# '^\x\{40\}$' + elseif a:commit =~# '^\x\{40,\}$' if !has_key(s:trees, a:dir) let s:trees[a:dir] = {} endif if !has_key(s:trees[a:dir], a:commit) - let ftime = +system(fugitive#Prepare(a:dir, 'log', '-1', '--pretty=format:%ct', a:commit, '--')) - if v:shell_error + let [ftime, exec_error] = s:ChompError([a:dir, 'log', '-1', '--pretty=format:%ct', a:commit, '--']) + if exec_error let s:trees[a:dir][a:commit] = [{}, -1] return s:trees[a:dir][a:commit] endif let s:trees[a:dir][a:commit] = [{}, +ftime] - let out = system(fugitive#Prepare(a:dir, 'ls-tree', '-rtl', '--full-name', a:commit, '--')) - if v:shell_error + let [lines, exec_error] = s:LinesError([a:dir, 'ls-tree', '-rtl', '--full-name', a:commit, '--']) + if exec_error return s:trees[a:dir][a:commit] endif - for line in split(out, "\n") + for line in lines let [info, filename] = split(line, "\t") let [mode, type, sha, size] = split(info, '\s\+') - let s:trees[a:dir][a:commit][0][filename] = [ftime, mode, type, sha, +size, filename] + let s:trees[a:dir][a:commit][0][filename] = [+ftime, mode, type, sha, +size, filename] endfor endif return s:trees[a:dir][a:commit] @@ -941,7 +1146,7 @@ function! s:PathInfo(url) abort let path = substitute(file[1:-1], '/*$', '', '') let [tree, ftime] = s:TreeInfo(dir, commit) let entry = empty(path) ? [ftime, '040000', 'tree', '', -1] : get(tree, path, []) - if empty(entry) || file =~# '/$' && entry[1] !=# 'tree' + if empty(entry) || file =~# '/$' && entry[2] !=# 'tree' return [-1, '000000', '', '', -1] else return entry @@ -958,11 +1163,11 @@ function! fugitive#simplify(url) abort if len(tree) let path = simplify(tree . file) if strpart(path . '/', 0, len(tree) + 1) !=# tree . '/' - return s:PlatformSlash(path) + return FugitiveVimPath(path) endif endif endif - return s:PlatformSlash('fugitive://' . simplify(dir) . '//' . commit . simplify(file)) + return FugitiveVimPath('fugitive://' . simplify(dir) . '//' . commit . simplify(file)) endfunction function! fugitive#resolve(url) abort @@ -982,8 +1187,7 @@ function! fugitive#getfsize(url) abort let entry = s:PathInfo(a:url) if entry[4] == -2 && entry[2] ==# 'blob' && len(entry[3]) let dir = s:DirCommitFile(a:url)[0] - let size = +system(s:Prepare(dir, 'cat-file', '-s', entry[3])) - let entry[4] = v:shell_error ? -1 : size + let entry[4] = +s:ChompDefault(-1, [dir, 'cat-file', '-s', entry[3]]) endif return entry[4] endfunction @@ -998,7 +1202,7 @@ endfunction function! fugitive#filewritable(url) abort let [dir, commit, file] = s:DirCommitFile(a:url) - if commit !~# '^\d$' || !filewritable(dir . '/index') + if commit !~# '^\d$' || !filewritable(fugitive#Find('.git/index', dir)) return 0 endif return s:PathInfo(a:url)[2] ==# 'blob' ? 1 : 2 @@ -1035,23 +1239,23 @@ function! fugitive#setfperm(url, perm) abort \ substitute(perm, 'x', '-', 'g') !=# substitute(a:perm, 'x', '-', 'g') return -2 endif - call system(s:Prepare(dir, 'update-index', '--index-info'), - \ (a:perm =~# 'x' ? '000755 ' : '000644 ') . entry[3] . ' ' . commit . "\t" . file[1:-1]) - return v:shell_error ? -1 : 0 + let exec_error = s:SystemError([dir, 'update-index', '--index-info'], + \ (a:perm =~# 'x' ? '000755 ' : '000644 ') . entry[3] . ' ' . commit . "\t" . file[1:-1])[1] + return exec_error ? -1 : 0 endfunction function! s:TempCmd(out, cmd) abort let prefix = '' try - let cmd = (type(a:cmd) == type([]) ? call('s:Prepare', a:cmd) : a:cmd) + let cmd = (type(a:cmd) == type([]) ? fugitive#Prepare(a:cmd) : a:cmd) let redir = ' > ' . a:out if s:winshell() let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^' - return s:System('cmd /c "' . prefix . s:gsub(cmd, '[<>]', cmd_escape_char . '&') . redir . '"') + return s:SystemError('cmd /c "' . prefix . s:gsub(cmd, '[<>]', cmd_escape_char . '&') . redir . '"') elseif &shell =~# 'fish' - return s:System(' begin;' . prefix . cmd . redir . ';end ') + return s:SystemError(' begin;' . prefix . cmd . redir . ';end ') else - return s:System(' (' . prefix . cmd . redir . ') ') + return s:SystemError(' (' . prefix . cmd . redir . ') ') endif endtry endfunction @@ -1074,9 +1278,8 @@ function! s:BlobTemp(url) abort endif if commit =~# '^\d$' || !filereadable(tempfile) let rev = s:DirRev(a:url)[1] - let command = s:Prepare(dir, 'cat-file', 'blob', rev) - call s:TempCmd(tempfile, command) - if v:shell_error + let exec_error = s:TempCmd(tempfile, [dir, 'cat-file', 'blob', rev])[1] + if exec_error call delete(tempfile) return '' endif @@ -1106,12 +1309,12 @@ function! fugitive#writefile(lines, url, ...) abort call writefile(fugitive#readfile(url, 'b'), temp, 'b') endif call call('writefile', [a:lines, temp] + a:000) - let hash = system(s:Prepare(dir, 'hash-object', '-w', temp))[0:-2] + let [hash, exec_error] = s:ChompError([dir, 'hash-object', '-w', temp]) let mode = len(entry[1]) ? entry[1] : '100644' - if !v:shell_error && hash =~# '^\x\{40\}$' - call system(s:Prepare(dir, 'update-index', '--index-info'), - \ mode . ' ' . hash . ' ' . commit . "\t" . file[1:-1]) - if !v:shell_error + if !exec_error && hash =~# '^\x\{40,\}$' + let exec_error = s:SystemError([dir, 'update-index', '--index-info'], + \ mode . ' ' . hash . ' ' . commit . "\t" . file[1:-1])[1] + if !exec_error return 0 endif endif @@ -1134,7 +1337,7 @@ function! fugitive#glob(url, ...) abort let pattern = '^' . substitute(glob, '/\=\*\*/\=\|/\=\*\|[.?\$]\|^^', '\=get(s:globsubs, submatch(0), "\\" . submatch(0))', 'g')[1:-1] . '$' let results = [] for dir in dirglob =~# '[*?]' ? split(glob(dirglob), "\n") : [dirglob] - if empty(dir) || !get(g:, 'fugitive_file_api', 1) || !filereadable(dir . '/HEAD') + if empty(dir) || !get(g:, 'fugitive_file_api', 1) || !filereadable(fugitive#Find('.git/HEAD', dir)) continue endif let files = items(s:TreeInfo(dir, commit)[0]) @@ -1145,7 +1348,7 @@ function! fugitive#glob(url, ...) abort call filter(files, 'v:val =~# pattern') let prepend = 'fugitive://' . dir . '//' . substitute(commit, '^:', '', '') . '/' call sort(files) - call map(files, 's:PlatformSlash(prepend . v:val . append)') + call map(files, 'FugitiveVimPath(prepend . v:val . append)') call extend(results, files) endfor if a:0 > 1 && a:2 @@ -1164,9 +1367,9 @@ function! fugitive#delete(url, ...) abort if entry[2] !=# 'blob' return -1 endif - call system(s:Prepare(dir, 'update-index', '--index-info'), - \ '000000 0000000000000000000000000000000000000000 ' . commit . "\t" . file[1:-1]) - return v:shell_error ? -1 : 0 + let exec_error = s:SystemError([dir, 'update-index', '--index-info'], + \ '000000 0000000000000000000000000000000000000000 ' . commit . "\t" . file[1:-1])[1] + return exec_error ? -1 : 0 endfunction " Section: Buffer Object @@ -1188,11 +1391,11 @@ function! s:buffer_getline(lnum) dict abort endfunction function! s:buffer_repo() dict abort - throw "fugitive: A third-party plugin or vimrc is calling fugitive#buffer().repo() which has been removed. Replace it with fugitive#repo()" + return fugitive#repo(self['#']) endfunction function! s:buffer_type(...) dict abort - throw "fugitive: A third-party plugin or vimrc is calling fugitive#buffer().type() which has been removed. Replace it with get(b:, 'fugitive_type', '')" + return getbufvar(self['#'], 'fugitive_type') endfunction function! s:buffer_spec() dict abort @@ -1219,8 +1422,18 @@ call s:add_methods('buffer',['getvar','getline','repo','type','spec','name','com " Section: Completion +function! s:FilterEscape(items, ...) abort + let items = copy(a:items) + if a:0 && type(a:1) == type('') + call filter(items, 'strpart(v:val, 0, strlen(a:1)) ==# a:1') + endif + return map(items, 's:fnameescape(v:val)') +endfunction + function! s:GlobComplete(lead, pattern) abort - if v:version >= 704 + if a:lead ==# '/' + return [] + elseif v:version >= 704 let results = glob(a:lead . a:pattern, 0, 1) else let results = split(glob(a:lead . a:pattern), "\n") @@ -1263,7 +1476,7 @@ endfunction function! fugitive#CompleteObject(base, ...) abort let dir = a:0 == 1 ? a:1 : a:0 == 3 ? a:3 : s:Dir() - let cwd = a:0 == 1 ? s:Tree(dir) : getcwd() + let cwd = getcwd() let tree = s:Tree(dir) . '/' let subdir = '' if len(tree) > 1 && s:cpath(tree, cwd[0 : len(tree) - 1]) @@ -1276,10 +1489,10 @@ function! fugitive#CompleteObject(base, ...) abort let results += map(s:GlobComplete(fugitive#CommonDir(dir) . '/', a:base . '*'), 's:Slash(v:val)') elseif a:base !~# '^\.\=/\|^:(' let heads = ['HEAD', 'ORIG_HEAD', 'FETCH_HEAD', 'MERGE_HEAD', 'refs/'] - let heads += sort(split(s:TreeChomp(["rev-parse","--symbolic","--branches","--tags","--remotes"], dir),"\n")) - if filereadable(fugitive#CommonDir(dir) . '/refs/stash') + let heads += sort(s:LinesError(["rev-parse","--symbolic","--branches","--tags","--remotes"], dir)[0]) + if filereadable(fugitive#Find('.git/refs/stash', dir)) let heads += ["stash"] - let heads += sort(split(s:TreeChomp(["stash","list","--pretty=format:%gd"], dir),"\n")) + let heads += sort(s:LinesError(["stash","list","--pretty=format:%gd"], dir)[0]) endif call filter(heads,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') let results += heads @@ -1291,7 +1504,7 @@ function! fugitive#CompleteObject(base, ...) abort return results elseif a:base =~# '^:' - let entries = split(s:TreeChomp(['ls-files','--stage'], dir),"\n") + let entries = s:LinesError(['ls-files','--stage'], dir)[0] if a:base =~# ':\./' call map(entries, 'substitute(v:val, "\\M\t\\zs" . subdir, "./", "")') endif @@ -1303,25 +1516,52 @@ function! fugitive#CompleteObject(base, ...) abort else let tree = matchstr(a:base, '.*[:/]') - let entries = split(s:TreeChomp(['ls-tree', substitute(tree, ':\zs\./', '\=subdir', '')], dir),"\n") + let entries = s:LinesError(['ls-tree', substitute(tree, ':\zs\./', '\=subdir', '')], dir)[0] call map(entries,'s:sub(v:val,"^04.*\\zs$","/")') call map(entries,'tree.s:sub(v:val,".*\t","")') endif - call filter(entries, 'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') - return map(entries, 's:fnameescape(v:val)') + return s:FilterEscape(entries, a:base) endfunction -function! fugitive#Complete(...) abort - return call('fugitive#CompleteObject', a:000) +function! s:CompleteSub(subcommand, A, L, P, ...) abort + let pre = strpart(a:L, 0, a:P) + if pre =~# ' -- ' + return fugitive#CompletePath(a:A) + elseif a:A =~# '^-' || a:A is# 0 + return s:FilterEscape(split(s:ChompDefault('', a:subcommand, '--git-completion-helper'), ' '), a:A) + elseif !a:0 + return fugitive#CompleteObject(a:A, s:Dir()) + elseif type(a:1) == type(function('tr')) + return call(a:1, [a:A, a:L, a:P]) + else + return s:FilterEscape(a:1, a:A) + endif +endfunction + +function! s:CompleteRevision(A, L, P) abort + return s:FilterEscape(['HEAD', 'FETCH_HEAD', 'MERGE_HEAD', 'ORIG_HEAD'] + + \ s:LinesError('rev-parse', '--symbolic', '--branches', '--tags', '--remotes')[0], a:A) +endfunction + +function! s:CompleteRemote(A, L, P) abort + let remote = matchstr(a:L, '\u\w*[! ] *\zs\S\+\ze ') + if !empty(remote) + let matches = s:LinesError('ls-remote', remote)[0] + call filter(matches, 'v:val =~# "\t" && v:val !~# "{"') + call map(matches, 's:sub(v:val, "^.*\t%(refs/%(heads/|tags/)=)=", "")') + else + let matches = s:LinesError('remote')[0] + endif + return s:FilterEscape(matches, a:A) endfunction " Section: Buffer auto-commands function! s:ReplaceCmd(cmd) abort let temp = tempname() - let err = s:TempCmd(temp, a:cmd) - if v:shell_error + let [err, exec_error] = s:TempCmd(temp, a:cmd) + if exec_error call s:throw((len(err) ? err : filereadable(temp) ? join(readfile(temp), ' ') : 'unknown error running ' . a:cmd)) endif let temp = s:Resolve(temp) @@ -1345,10 +1585,7 @@ function! s:ReplaceCmd(cmd) abort endfunction function! s:QueryLog(refspec) abort - let lines = split(system(FugitivePrepare('log', '-n', '256', '--format=%h%x09%s', a:refspec, '--')), "\n") - if v:shell_error - return [] - endif + let lines = s:LinesError(['log', '-n', '256', '--format=%h%x09%s', a:refspec, '--'])[0] call map(lines, 'split(v:val, "\t")') call map(lines, '{"type": "Log", "commit": v:val[0], "subject": v:val[-1]}') return lines @@ -1401,17 +1638,18 @@ endfunction function! fugitive#BufReadStatus() abort let amatch = s:Slash(expand('%:p')) let b:fugitive_type = 'index' + unlet! b:fugitive_reltime try silent doautocmd BufReadPre let cmd = [fnamemodify(amatch, ':h')] setlocal noro ma nomodeline buftype=nowrite - if s:cpath(fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : s:Dir() . '/index', ':p')) !=# s:cpath(amatch) + if s:cpath(fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : fugitive#Find('.git/index'), ':p')) !=# s:cpath(amatch) let cmd += ['-c', 'GIT_INDEX_FILE=' . amatch] endif let cmd += ['status', '--porcelain', '-bz'] - let output = split(system(fugitive#Prepare(cmd)), "\1") - if v:shell_error - throw 'fugitive: ' . join(output, ' ') + let [output, message, exec_error] = s:NullError(cmd) + if exec_error + throw 'fugitive: ' . message endif let head = matchstr(output[0], '^## \zs\S\+\ze\%($\| \[\)') @@ -1443,17 +1681,13 @@ function! fugitive#BufReadStatus() abort endif if line[0] !~# '[ ?!#]' call add(staged, {'type': 'File', 'status': line[0], 'filename': files}) - let b:fugitive_status['Staged'][files] = line[0] endif - if line[1] =~# '?' + if line[0:1] ==# '??' call add(untracked, {'type': 'File', 'status': line[1], 'filename': files}) - let b:fugitive_status['Unstaged'][files] = line[1] elseif line[1] !~# '[ !#]' call add(unstaged, {'type': 'File', 'status': line[1], 'filename': files}) - let b:fugitive_status['Unstaged'][files] = line[1] endif endwhile - let unstaged = extend(untracked, unstaged) for dict in staged let b:fugitive_status['Staged'][dict.filename] = dict.status @@ -1531,9 +1765,16 @@ function! fugitive#BufReadStatus() abort endfor endif - let b:fugitive_diff = { - \ 'Staged': split(system(fugitive#Prepare('diff', '--color=never', '--no-ext-diff', '--no-prefix', '--cached')), "\n"), - \ 'Unstaged': split(system(fugitive#Prepare('diff', '--color=never', '--no-ext-diff', '--no-prefix')), "\n")} + let diff = {'Staged': [], 'Unstaged': []} + if len(staged) + let diff['Staged'] = + \ s:LinesError(['diff', '--color=never', '--no-ext-diff', '--no-prefix', '--cached'])[0] + endif + if len(unstaged) + let diff['Unstaged'] = + \ s:LinesError(['diff', '--color=never', '--no-ext-diff', '--no-prefix'])[0] + endif + let b:fugitive_diff = diff let expanded = get(b:, 'fugitive_expanded', {'Staged': {}, 'Unstaged': {}}) let b:fugitive_expanded = {'Staged': {}, 'Unstaged': {}} @@ -1545,6 +1786,7 @@ function! fugitive#BufReadStatus() abort call s:AddHeader('Push', push) endif call s:AddSection('Rebasing ' . rebasing_head, rebasing) + call s:AddSection('Untracked', untracked) call s:AddSection('Unstaged', unstaged) let unstaged_end = len(unstaged) ? line('$') : 0 call s:AddSection('Staged', staged) @@ -1560,47 +1802,54 @@ function! fugitive#BufReadStatus() abort endif let b:dispatch = ':Gfetch --all' call fugitive#MapJumps() - let nowait = v:version >= 704 ? '<nowait>' : '' - nunmap <buffer> P - nunmap <buffer> ~ - nnoremap <buffer> <silent> <C-N> :<C-U>execute <SID>StageNext(v:count1)<CR> - nnoremap <buffer> <silent> <C-P> :<C-U>execute <SID>StagePrevious(v:count1)<CR> - exe "nnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>Do('Toggle',0)<CR>" - exe "xnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>Do('Toggle',1)<CR>" - exe "nnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>Do('Stage',0)<CR>" - exe "xnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>Do('Stage',1)<CR>" - exe "nnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>Do('Unstage',0)<CR>" - exe "xnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>Do('Unstage',1)<CR>" - nnoremap <buffer> <silent> C :<C-U>Gcommit<CR>:echohl WarningMsg<Bar>echo ':Gstatus C is deprecated in favor of cc'<Bar>echohl NONE<CR> - nnoremap <buffer> <silent> a :<C-U>execute <SID>Do('Toggle',0)<CR> - nnoremap <buffer> <silent> i :<C-U>execute <SID>StageIntend(v:count1)<CR> - exe 'nnoremap <buffer> <silent>' nowait "= :<C-U>execute <SID>StageInline('toggle',line('.'),v:count)<CR>" - exe 'nnoremap <buffer> <silent>' nowait "< :<C-U>execute <SID>StageInline('show', line('.'),v:count)<CR>" - exe 'nnoremap <buffer> <silent>' nowait "> :<C-U>execute <SID>StageInline('hide', line('.'),v:count)<CR>" - exe 'xnoremap <buffer> <silent>' nowait "= :<C-U>execute <SID>StageInline('toggle',line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>" - exe 'xnoremap <buffer> <silent>' nowait "< :<C-U>execute <SID>StageInline('show', line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>" - exe 'xnoremap <buffer> <silent>' nowait "> :<C-U>execute <SID>StageInline('hide', line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>" - nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<CR> - nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gdiff')<CR> - nnoremap <buffer> <silent> dh :<C-U>execute <SID>StageDiff('Gsdiff')<CR> - nnoremap <buffer> <silent> ds :<C-U>execute <SID>StageDiff('Gsdiff')<CR> - nnoremap <buffer> <silent> dp :<C-U>execute <SID>StageDiffEdit()<CR> - nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR> - nnoremap <buffer> <silent> J :<C-U>execute <SID>StageNext(v:count1)<CR> - nnoremap <buffer> <silent> K :<C-U>execute <SID>StagePrevious(v:count1)<CR> - nnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR> - xnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR> - nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR> - exe 'nnoremap <buffer> <silent>' nowait "gq :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR>" - nnoremap <buffer> <silent> R :<C-U>exe <SID>ReloadStatus()<CR> - nnoremap <buffer> <silent> U :<C-U>echoerr 'Changed to X'<CR> - nnoremap <buffer> <silent> g<Bar> :<C-U>execute <SID>StageDelete(line('.'),v:count)<CR> - xnoremap <buffer> <silent> g<Bar> :<C-U>execute <SID>StageDelete(line("'<"),line("'>")-line("'<")+1)<CR> - nnoremap <buffer> <silent> X :<C-U>execute <SID>StageDelete(line('.'),v:count)<CR> - xnoremap <buffer> <silent> X :<C-U>execute <SID>StageDelete(line("'<"),line("'>")-line("'<")+1)<CR> - nnoremap <buffer> . :<C-U> <C-R>=<SID>StageArgs(0)<CR><Home> - xnoremap <buffer> . :<C-U> <C-R>=<SID>StageArgs(1)<CR><Home> - nnoremap <buffer> <silent> <F1> :help fugitive-mappings<CR> + call s:Map('n', '-', ":<C-U>execute <SID>Do('Toggle',0)<CR>", '<silent>') + call s:Map('x', '-', ":<C-U>execute <SID>Do('Toggle',1)<CR>", '<silent>') + call s:Map('n', 's', ":<C-U>execute <SID>Do('Stage',0)<CR>", '<silent>') + call s:Map('x', 's', ":<C-U>execute <SID>Do('Stage',1)<CR>", '<silent>') + call s:Map('n', 'u', ":<C-U>execute <SID>Do('Unstage',0)<CR>", '<silent>') + call s:Map('x', 'u', ":<C-U>execute <SID>Do('Unstage',1)<CR>", '<silent>') + call s:Map('n', 'U', ":exe <SID>EchoExec('reset', '-q')<CR>", '<silent>') + call s:MapMotion('gu', "exe <SID>StageJump(v:count, 'Untracked', 'Unstaged')") + call s:MapMotion('gU', "exe <SID>StageJump(v:count, 'Unstaged', 'Untracked')") + call s:MapMotion('gs', "exe <SID>StageJump(v:count, 'Staged')") + call s:MapMotion('gp', "exe <SID>StageJump(v:count, 'Unpushed')") + call s:MapMotion('gP', "exe <SID>StageJump(v:count, 'Unpulled')") + call s:MapMotion('gr', "exe <SID>StageJump(v:count, 'Rebasing')") + call s:Map('n', 'C', ":<C-U>Gcommit<CR>:echohl WarningMsg<Bar>echo ':Gstatus C is deprecated in favor of cc'<Bar>echohl NONE<CR>", '<silent>') + call s:Map('n', 'a', ":<C-U>execute <SID>Do('Toggle',0)<CR>", '<silent>') + call s:Map('n', 'i', ":<C-U>execute <SID>NextExpandedHunk(v:count1)<CR>", '<silent>') + call s:Map('n', "=", ":<C-U>execute <SID>StageInline('toggle',line('.'),v:count)<CR>", '<silent>') + call s:Map('n', "<", ":<C-U>execute <SID>StageInline('hide', line('.'),v:count)<CR>", '<silent>') + call s:Map('n', ">", ":<C-U>execute <SID>StageInline('show', line('.'),v:count)<CR>", '<silent>') + call s:Map('x', "=", ":<C-U>execute <SID>StageInline('toggle',line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>", '<silent>') + call s:Map('x', "<", ":<C-U>execute <SID>StageInline('hide', line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>", '<silent>') + call s:Map('x', ">", ":<C-U>execute <SID>StageInline('show', line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>", '<silent>') + call s:Map('n', 'D', ":<C-U>execute <SID>StageDiff('Gdiffsplit')<Bar>redraw<Bar>echohl WarningMsg<Bar> echo ':Gstatus D is deprecated in favor of dd'<Bar>echohl NONE<CR>", '<silent>') + call s:Map('n', 'dd', ":<C-U>execute <SID>StageDiff('Gdiffsplit')<CR>", '<silent>') + call s:Map('n', 'dh', ":<C-U>execute <SID>StageDiff('Ghdiffsplit')<CR>", '<silent>') + call s:Map('n', 'ds', ":<C-U>execute <SID>StageDiff('Ghdiffsplit')<CR>", '<silent>') + call s:Map('n', 'dp', ":<C-U>execute <SID>StageDiffEdit()<CR>", '<silent>') + call s:Map('n', 'dv', ":<C-U>execute <SID>StageDiff('Gvdiffsplit')<CR>", '<silent>') + call s:Map('n', 'd?', ":<C-U>help fugitive_d<CR>", '<silent>') + call s:Map('n', 'P', ":<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>", '<silent>') + call s:Map('x', 'P', ":<C-U>execute <SID>StagePatch(line(\"'<\"),line(\"'>\"))<CR>", '<silent>') + call s:Map('n', 'p', ":<C-U>if v:count<Bar>silent exe <SID>GF('pedit')<Bar>else<Bar>echoerr 'Use = for inline diff, P for :Git add/reset --patch, 1p for :pedit'<Bar>endif<CR>", '<silent>') + call s:Map('x', 'p', ":<C-U>execute <SID>StagePatch(line(\"'<\"),line(\"'>\"))<CR>", '<silent>') + call s:Map('n', 'I', ":<C-U>execute <SID>StagePatch(line('.'),line('.'))<CR>", '<silent>') + call s:Map('x', 'I', ":<C-U>execute <SID>StagePatch(line(\"'<\"),line(\"'>\"))<CR>", '<silent>') + if empty(mapcheck('q', 'n')) + nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<Bar>echohl WarningMsg<Bar>echo ':Gstatus q is deprecated in favor of gq or the built-in <Lt>C-W>q'<Bar>echohl NONE<CR> + endif + call s:Map('n', 'gq', ":<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR>", '<silent>') + call s:Map('n', 'R', ":echohl WarningMsg<Bar>echo 'Reloading is automatic. Use :e to force'<Bar>echohl NONE<CR>", '<silent>') + call s:Map('n', 'g<Bar>', ":<C-U>echoerr 'Changed to X'<CR>", '<silent>') + call s:Map('x', 'g<Bar>', ":<C-U>echoerr 'Changed to X'<CR>", '<silent>') + call s:Map('n', 'X', ":<C-U>execute <SID>StageDelete(line('.'), 0, v:count)<CR>", '<silent>') + call s:Map('x', 'X', ":<C-U>execute <SID>StageDelete(line(\"'<\"), line(\"'>\"), v:count)<CR>", '<silent>') + call s:Map('n', 'gI', ":<C-U>execute <SID>StageIgnore(line('.'), line('.'), v:count)<CR>", '<silent>') + call s:Map('x', 'gI', ":<C-U>execute <SID>StageIgnore(line(\"'<\"), line(\"'>\"), v:count)<CR>", '<silent>') + call s:Map('n', '.', ':<C-U> <C-R>=<SID>StageArgs(0)<CR><Home>') + call s:Map('x', '.', ':<C-U> <C-R>=<SID>StageArgs(1)<CR><Home>') setlocal filetype=fugitive for [lnum, section] in [[staged_end, 'Staged'], [unstaged_end, 'Unstaged']] @@ -1613,9 +1862,10 @@ function! fugitive#BufReadStatus() abort endwhile endfor + let b:fugitive_reltime = reltime() return '' catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry endfunction @@ -1626,10 +1876,10 @@ function! fugitive#FileReadCmd(...) abort if empty(dir) return 'noautocmd ' . line . 'read ' . s:fnameescape(amatch) endif - if rev !~# ':' - let cmd = s:Prepare(dir, 'log', '--pretty=format:%B', '-1', rev, '--') + if rev !~# ':' && s:ChompDefault('', [dir, 'cat-file', '-t', rev]) =~# '^\%(commit\|tag\)$' + let cmd = fugitive#Prepare(dir, 'log', '--pretty=format:%B', '-1', rev, '--') else - let cmd = s:Prepare(dir, 'cat-file', '-p', rev) + let cmd = fugitive#Prepare(dir, 'cat-file', '-p', rev) endif return line . 'read !' . escape(cmd, '!#%') endfunction @@ -1646,20 +1896,19 @@ function! fugitive#FileWriteCmd(...) abort if commit !~# '^[0-3]$' || !v:cmdbang && (line("'[") != 1 || line("']") != line('$')) return "noautocmd '[,']write" . (v:cmdbang ? '!' : '') . ' ' . s:fnameescape(amatch) endif - silent execute "'[,']write !".s:Prepare(dir, 'hash-object', '-w', '--stdin', '--').' > '.tmp + silent execute "'[,']write !".fugitive#Prepare(dir, 'hash-object', '-w', '--stdin', '--').' > '.tmp let sha1 = readfile(tmp)[0] - let old_mode = matchstr(system(s:Prepare(dir, 'ls-files', '--stage', '.' . file)), '^\d\+') + let old_mode = matchstr(s:SystemError([dir, 'ls-files', '--stage', '.' . file])[0], '^\d\+') if empty(old_mode) let old_mode = executable(s:Tree(dir) . file) ? '100755' : '100644' endif let info = old_mode.' '.sha1.' '.commit."\t".file[1:-1] - let error = system(s:Prepare(dir, 'update-index', '--index-info'), info . "\n") - if v:shell_error == 0 + let [error, exec_error] = s:SystemError([dir, 'update-index', '--index-info'], info . "\n") + if !exec_error setlocal nomodified if exists('#' . autype . 'WritePost') execute 'doautocmd ' . autype . 'WritePost ' . s:fnameescape(amatch) endif - call fugitive#ReloadStatus() return '' else return 'echoerr '.string('fugitive: '.error) @@ -1669,6 +1918,8 @@ function! fugitive#FileWriteCmd(...) abort endtry endfunction +let s:nomodeline = (v:version >= 704 ? '<nomodeline>' : '') + function! fugitive#BufReadCmd(...) abort let amatch = a:0 ? a:1 : expand('<amatch>') try @@ -1679,20 +1930,25 @@ function! fugitive#BufReadCmd(...) abort if rev =~# '^:\d$' let b:fugitive_type = 'stage' else - let b:fugitive_type = system(s:Prepare(dir, 'cat-file', '-t', rev))[0:-2] - if v:shell_error && rev =~# '^:0' - let sha = system(s:Prepare(dir, 'write-tree', '--prefix=' . rev[3:-1]))[0:-2] - let b:fugitive_type = 'tree' + let [b:fugitive_type, exec_error] = s:ChompError([dir, 'cat-file', '-t', rev]) + if exec_error && rev =~# '^:0' + let sha = s:ChompDefault('', dir, 'write-tree', '--prefix=' . rev[3:-1]) + let exec_error = empty(sha) + let b:fugitive_type = exec_error ? '' : 'tree' endif - if v:shell_error + if exec_error let error = b:fugitive_type unlet b:fugitive_type + setlocal noswapfile + if empty(&bufhidden) + setlocal bufhidden=delete + endif if rev =~# '^:\d:' - let &l:readonly = !filewritable(dir . '/index') + let &l:readonly = !filewritable(fugitive#Find('.git/index', dir)) return 'silent doautocmd BufNewFile' else setlocal readonly nomodifiable - return 'echo ' . string(error) + return 'silent doautocmd BufNewFile|echo ' . string(error) endif elseif b:fugitive_type !~# '^\%(tag\|commit\|tree\|blob\)$' return "echoerr ".string("fugitive: unrecognized git type '".b:fugitive_type."'") @@ -1719,7 +1975,7 @@ function! fugitive#BufReadCmd(...) abort call s:ReplaceCmd([dir, 'ls-tree', exists('sha') ? sha : rev]) else if !exists('sha') - let sha = system(s:Prepare(dir, 'rev-parse', '--verify', rev, '--'))[0:-2] + let sha = s:TreeChomp(dir, 'rev-parse', '--verify', rev, '--') endif call s:ReplaceCmd([dir, 'show', '--no-color', sha]) endif @@ -1758,24 +2014,24 @@ function! fugitive#BufReadCmd(...) abort keepjumps call setpos('.',pos) setlocal nomodified noswapfile let modifiable = rev =~# '^:.:' && b:fugitive_type !=# 'tree' - let &l:readonly = !modifiable || !filewritable(dir . '/index') - if &bufhidden ==# '' + let &l:readonly = !modifiable || !filewritable(fugitive#Find('.git/index', dir)) + if empty(&bufhidden) setlocal bufhidden=delete endif let &l:modifiable = modifiable if b:fugitive_type !=# 'blob' setlocal filetype=git foldmethod=syntax - nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += v:count1<Bar>exe fugitive#BufReadCmd(@%)<CR> - nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= v:count1<Bar>exe fugitive#BufReadCmd(@%)<CR> + call s:Map('n', 'a', ":<C-U>let b:fugitive_display_format += v:count1<Bar>exe fugitive#BufReadCmd(@%)<CR>", '<silent>') + call s:Map('n', 'i', ":<C-U>let b:fugitive_display_format -= v:count1<Bar>exe fugitive#BufReadCmd(@%)<CR>", '<silent>') endif call fugitive#MapJumps() endtry setlocal modifiable - return 'silent doautocmd' . (v:version >= 704 ? ' <nomodeline>' : '') . + return 'silent doautocmd' . s:nomodeline . \ ' BufReadPost' . (modifiable ? '' : '|setl nomodifiable') catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry endfunction @@ -1802,24 +2058,38 @@ if !exists('s:temp_files') let s:temp_files = {} endif -function! s:SetupTemp(file) abort +function! s:TempState(...) abort + return get(s:temp_files, s:cpath(fnamemodify(a:0 ? a:1 : @%, ':p')), {}) +endfunction + +function! s:TempReadPre(file) abort + if has_key(s:temp_files, s:cpath(a:file)) + let dict = s:temp_files[s:cpath(a:file)] + setlocal nomodeline + setlocal bufhidden=delete nobuflisted + setlocal buftype=nowrite + if has_key(dict, 'modifiable') + let &l:modifiable = dict.modifiable + endif + if len(dict.dir) + let b:git_dir = dict.dir + call extend(b:, {'fugitive_type': 'temp'}, 'keep') + endif + endif +endfunction + +function! s:TempReadPost(file) abort if has_key(s:temp_files, s:cpath(a:file)) let dict = s:temp_files[s:cpath(a:file)] - let b:git_dir = dict.dir - call extend(b:, {'fugitive_type': 'temp'}, 'keep') if has_key(dict, 'filetype') && dict.filetype !=# &l:filetype let &l:filetype = dict.filetype endif setlocal foldmarker=<<<<<<<,>>>>>>> - setlocal bufhidden=delete nobuflisted - setlocal buftype=nowrite - nnoremap <buffer> <silent> q :<C-U>bdelete<CR> - if getline(1) !~# '^diff ' - setlocal nomodifiable + if empty(mapcheck('q', 'n')) + nnoremap <buffer> <silent> q :<C-U>bdelete<Bar>echohl WarningMsg<Bar>echo "Temp file q is deprecated in favor of the built-in <Lt>C-W>q"<Bar>echohl NONE<CR> endif - call FugitiveDetect(a:file) - if &filetype ==# 'git' - call fugitive#MapJumps() + if !&modifiable + call s:Map('n', 'gq', ":<C-U>bdelete<CR>", '<silent> <unique>') endif endif return '' @@ -1827,52 +2097,71 @@ endfunction augroup fugitive_temp autocmd! - autocmd BufNewFile,BufReadPost * exe s:SetupTemp(expand('<amatch>:p')) + autocmd BufReadPre * exe s:TempReadPre( expand('<amatch>:p')) + autocmd BufReadPost * exe s:TempReadPost(expand('<amatch>:p')) augroup END " Section: :Git -call s:command("-bang -nargs=? -complete=customlist,fugitive#CompleteGit Git", "Git") - function! s:GitCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort - if a:bang - return s:Open('edit', 1, a:mods, a:arg, a:args) + let dir = s:Dir() + let [args, after] = s:SplitExpandChain(a:arg, s:Tree(dir)) + if empty(args) + let cmd = s:StatusCommand(a:line1, a:line2, a:range, a:count, a:bang, a:mods, a:reg, '', []) + return (empty(cmd) ? 'exe' : cmd) . after + endif + let alias = get(s:Aliases(dir), args[0], '!') + if get(args, 1, '') !=# '--help' && alias !~# '^!\|[\"'']' && !filereadable(s:ExecPath() . '/git-' . args[0]) + \ && !(has('win32') && filereadable(s:ExecPath() . '/git-' . args[0] . '.exe')) + call remove(args, 0) + call extend(args, split(alias, '\s\+'), 'keep') + endif + let name = substitute(args[0], '\%(^\|-\)\(\l\)', '\u\1', 'g') + if exists('*s:' . name . 'Subcommand') && get(args, 1, '') !=# '--help' + try + exe s:DirCheck(dir) + return 'exe ' . string(s:{name}Subcommand(a:line1, a:count, a:range, a:bang, a:mods, args[1:-1])) . after + catch /^fugitive:/ + return 'echoerr ' . string(v:exception) + endtry + endif + if a:bang || args[0] =~# '^-P$\|^--no-pager$\|diff\%(tool\)\@!\|log\|^show$' || + \ (args[0] ==# 'stash' && get(args, 1, '') ==# 'show') || + \ (args[0] ==# 'help' || get(args, 1, '') ==# '--help') && !s:HasOpt(args, '--web') + return s:OpenExec((a:count > 0 ? a:count : '') . (a:count ? 'split' : 'edit'), a:mods, args, dir) . after + endif + if s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') || + \ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive') || + \ index(['--paginate', '-p'], args[0]) >= 0 + let mods = substitute(s:Mods(a:mods), '\<tab\>', '-tab', 'g') + if has('nvim') + if &autowrite || &autowriteall | silent! wall | endif + return mods . (a:count ? 'split' : 'edit') . ' term://' . s:fnameescape(s:UserCommand(dir, args)) . '|startinsert' . after + elseif has('terminal') + if &autowrite || &autowriteall | silent! wall | endif + return 'exe ' . string(mods . 'terminal ' . (a:count ? '' : '++curwin ') . join(map(s:UserCommandList(dir) + args, 's:fnameescape(v:val)'))) . after + endif endif - let git = s:UserCommand() if has('gui_running') && !has('win32') - let git .= ' --no-pager' + call insert(args, '--no-pager') endif - let args = matchstr(a:arg,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=') - let after = matchstr(a:arg, '\v\C\\@<!%(\\\\)*\zs\|.*') - let tree = s:Tree() - if !s:CanAutoReloadStatus() - let after = '|call fugitive#ReloadStatus()' . after - endif - if exists(':terminal') && has('nvim') && !get(g:, 'fugitive_force_bang_command') - if len(@%) - -tabedit % - else - -tabnew - endif - execute 'lcd' fnameescape(tree) - let exec = escape(git . ' ' . s:ShellExpand(args), '#%') - return 'exe ' . string('terminal ' . exec) . after - else - let cmd = "exe '!'.escape(" . string(git) . " . ' ' . s:ShellExpand(" . string(args) . "),'!#%')" - if s:cpath(tree) !=# s:cpath(getcwd()) - let cd = s:Cd() - let cmd = 'try|' . cd . ' ' . tree . '|' . cmd . '|finally|' . cd . ' ' . s:fnameescape(getcwd()) . '|endtry' - endif - return cmd . after + let pre = '' + if has('nvim') && executable('env') + let pre .= 'env GIT_TERMINAL_PROMPT=0 ' endif + return 'exe ' . string('!' . escape(pre . s:UserCommand(dir, args), '!#%')) . after endfunction let s:exec_paths = {} -function! s:Subcommands() abort +function! s:ExecPath() abort if !has_key(s:exec_paths, g:fugitive_git_executable) let s:exec_paths[g:fugitive_git_executable] = s:sub(system(g:fugitive_git_executable.' --exec-path'),'\n$','') endif - let exec_path = s:exec_paths[g:fugitive_git_executable] + return s:exec_paths[g:fugitive_git_executable] +endfunction + +function! s:Subcommands() abort + let exec_path = s:ExecPath() return map(split(glob(exec_path.'/git-*'),"\n"),'s:sub(v:val[strlen(exec_path)+5 : -1],"\\.exe$","")') endfunction @@ -1880,8 +2169,8 @@ let s:aliases = {} function! s:Aliases(dir) abort if !has_key(s:aliases, a:dir) let s:aliases[a:dir] = {} - let lines = split(s:TreeChomp('config','-z','--get-regexp','^alias[.]'),"\1") - for line in v:shell_error ? [] : lines + let lines = s:NullError([a:dir, 'config', '-z', '--get-regexp', '^alias[.]'])[0] + for line in lines let s:aliases[a:dir][matchstr(line, '\.\zs.\{-}\ze\n')] = matchstr(line, '\n\zs.*') endfor endif @@ -1891,16 +2180,26 @@ endfunction function! fugitive#CompleteGit(lead, ...) abort let dir = a:0 == 1 ? a:1 : a:0 == 3 ? a:3 : s:Dir() let pre = a:0 > 1 ? strpart(a:1, 0, a:2) : '' - if pre !~# ' [[:alnum:]-]\+ ' - let cmds = s:Subcommands() - return filter(sort(cmds+keys(s:Aliases(dir))), 'strpart(v:val, 0, strlen(a:lead)) ==# a:lead') + let subcmd = matchstr(pre, '\u\w*[! ] *\zs[[:alnum:]-]\+\ze ') + if empty(subcmd) + let results = sort(s:Subcommands() + keys(s:Aliases(dir))) elseif pre =~# ' -- ' return fugitive#CompletePath(a:lead, dir) + elseif a:lead =~# '^-' + let results = split(s:ChompDefault('', dir, subcmd, '--git-completion-helper'), ' ') else return fugitive#CompleteObject(a:lead, dir) endif + return filter(results, 'strpart(v:val, 0, strlen(a:lead)) ==# a:lead') endfunction +function! fugitive#Complete(...) abort + return call('fugitive#CompleteGit', a:000) +endfunction + +call s:command("-bang -nargs=? -range=-1 -addr=other -complete=customlist,fugitive#CompleteGit Git", "Git") +call s:command("-bang -nargs=? -range=-1 -addr=other -complete=customlist,fugitive#CompleteGit G", "Git") + " Section: :Gcd, :Glcd function! s:DirComplete(A, L, P) abort @@ -1912,32 +2211,36 @@ function! s:DirArg(path) abort if path =~# '^/\|^\a\+:\|^\.\.\=\%(/\|$\)' return path else - return (empty(s:Tree()) ? s:Dir() : s:Tree()) . '/' . path + return FugitiveVimPath((empty(s:Tree()) ? s:Dir() : s:Tree()) . '/' . path) endif endfunction -call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Gcd :exe 'cd<bang>' s:fnameescape(s:DirArg(<q-args>))") -call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :exe 'lcd<bang>' s:fnameescape(s:DirArg(<q-args>))") +call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Gcd :exe s:DirCheck()|exe 'cd<bang>' s:fnameescape(s:DirArg(<q-args>))") +call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :exe s:DirCheck()|exe 'lcd<bang>' s:fnameescape(s:DirArg(<q-args>))") " Section: :Gstatus -call s:command("-bar -bang -range=-1 Gstatus", "Status") -call s:command("-bar -bang -range=-1 G", "Status") +call s:command("-bar -bang -range=-1 -addr=other Gstatus", "Status") -function! s:StatusCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort +function! s:StatusCommand(line1, line2, range, count, bang, mods, reg, arg, args, ...) abort + let dir = a:0 ? a:1 : s:Dir() + exe s:DirCheck(dir) try - let mods = a:mods ==# '<mods>' || empty(a:mods) ? '' : a:mods . ' ' - if mods !~# 'aboveleft\|belowright\|leftabove\|rightbelow\|topleft\|botright' - let mods = (&splitbelow ? 'botright ' : 'topleft ') . mods - endif - let file = fugitive#Find(':') + let mods = s:Mods(a:mods, &splitbelow ? 'botright' : 'topleft') + let file = fugitive#Find(':', dir) let arg = ' +setl\ foldmethod=syntax\ foldlevel=1\|let\ w:fugitive_status=FugitiveGitDir() ' . \ s:fnameescape(file) for winnr in range(1, winnr('$')) if s:cpath(file, fnamemodify(bufname(winbufnr(winnr)), ':p')) - exe winnr . 'wincmd w' - let w:fugitive_status = FugitiveGitDir() - return s:ReloadStatus() + if winnr == winnr() + call s:ReloadStatus() + else + call s:ExpireStatus(dir) + exe winnr . 'wincmd w' + endif + let w:fugitive_status = dir + 1 + return '' endif endfor if a:count ==# 0 @@ -1948,11 +2251,37 @@ function! s:StatusCommand(line1, line2, range, count, bang, mods, reg, arg, args return mods . (a:count > 0 ? a:count : '') . 'split' . arg endif catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry return '' endfunction +function! s:StageJump(offset, section, ...) abort + let line = search('^\%(' . a:section . '\)', 'nw') + if !line && a:0 + let line = search('^\%(' . a:1 . '\)', 'nw') + endif + if line + exe line + if a:offset + for i in range(a:offset) + call search(s:file_commit_pattern . '\|^$', 'W') + if empty(getline('.')) && a:0 && getline(line('.') + 1) =~# '^\%(' . a:1 . '\)' + call search(s:file_commit_pattern . '\|^$', 'W') + endif + if empty(getline('.')) + return '' + endif + endfor + call s:StageReveal() + else + call s:StageReveal() + + + endif + endif + return '' +endfunction + function! s:StageSeek(info, fallback) abort let info = a:info if empty(info.section) @@ -1960,7 +2289,7 @@ function! s:StageSeek(info, fallback) abort endif let line = search('^' . info.section, 'wn') if !line - for section in get({'Staged': ['Unstaged'], 'Unstaged': ['Staged']}, info.section, []) + for section in get({'Staged': ['Unstaged', 'Untracked'], 'Unstaged': ['Untracked', 'Staged'], 'Untracked': ['Unstaged', 'Staged']}, info.section, []) let line = search('^' . section, 'wn') if line return line + (info.index > 0 ? 1 : 0) @@ -2013,6 +2342,7 @@ function! s:StageSeek(info, fallback) abort endfunction function! s:ReloadStatus(...) abort + call s:ExpireStatus(-1) if get(b:, 'fugitive_type', '') !=# 'index' return '' endif @@ -2024,57 +2354,100 @@ function! s:ReloadStatus(...) abort return '' endfunction -function! fugitive#ReloadStatus(...) abort - if exists('s:reloading_status') +let s:last_time = reltime() +if !exists('s:last_times') + let s:last_times = {} +endif + +function! s:ExpireStatus(bufnr) abort + if a:bufnr == -2 + let s:last_time = reltime() + return '' + endif + let dir = s:Dir(a:bufnr) + if len(dir) + let s:last_times[s:cpath(dir)] = reltime() + endif + return '' +endfunction + +function! FugitiveReloadCheck() abort + let t = b:fugitive_reltime + return [t, reltimestr(reltime(s:last_time, t)), + \ reltimestr(reltime(get(s:last_times, s:cpath(s:Dir()), t), t))] +endfunction + +function! s:ReloadWinStatus(...) abort + if get(b:, 'fugitive_type', '') !=# 'index' || &modified return endif - try - let s:reloading_status = 1 - let mytab = tabpagenr() - for tab in [mytab] + range(1,tabpagenr('$')) - for winnr in range(1,tabpagewinnr(tab,'$')) - if getbufvar(tabpagebuflist(tab)[winnr-1],'fugitive_type') ==# 'index' - execute 'tabnext '.tab - if winnr != winnr() - execute winnr.'wincmd w' - let restorewinnr = 1 - endif - try - if !&modified - exe s:ReloadStatus() - endif - finally - if exists('restorewinnr') - unlet restorewinnr - wincmd p - endif - execute 'tabnext '.mytab - endtry + if !exists('b:fugitive_reltime') + exe s:ReloadStatus() + return + endif + let t = b:fugitive_reltime + if reltimestr(reltime(s:last_time, t)) =~# '-\|\d\{10\}\.' || + \ reltimestr(reltime(get(s:last_times, s:cpath(s:Dir()), t), t)) =~# '-\|\d\{10\}\.' + exe s:ReloadStatus() + endif +endfunction + +function! s:ReloadTabStatus(...) abort + let mytab = tabpagenr() + let tab = a:0 ? a:1 : mytab + for winnr in range(1, tabpagewinnr(tab, '$')) + if getbufvar(tabpagebuflist(tab)[winnr-1], 'fugitive_type') ==# 'index' + execute 'tabnext '.tab + if winnr != winnr() + execute winnr.'wincmd w' + let restorewinnr = 1 + endif + try + call s:ReloadWinStatus() + finally + if exists('restorewinnr') + unlet restorewinnr + wincmd p endif - endfor + execute 'tabnext '.mytab + endtry + endif + endfor + unlet! t:fugitive_reload_status +endfunction + +function! fugitive#ReloadStatus(...) abort + call s:ExpireStatus(a:0 ? a:1 : -2) + if a:0 > 1 ? a:2 : s:CanAutoReloadStatus() + let t = reltime() + let t:fugitive_reload_status = t + for tabnr in exists('*settabvar') ? range(1, tabpagenr('$')) : [] + call settabvar(tabnr, 'fugitive_reload_status', t) endfor - finally - unlet! s:reloading_status - endtry + call s:ReloadTabStatus() + else + call s:ReloadWinStatus() + endif endfunction function! s:CanAutoReloadStatus() abort return get(g:, 'fugitive_autoreload_status', !has('win32')) endfunction -function! s:AutoReloadStatus(...) abort - if s:CanAutoReloadStatus() - return call('fugitive#ReloadStatus', a:000) - endif -endfunction - augroup fugitive_status autocmd! - autocmd ShellCmdPost * call s:AutoReloadStatus() - autocmd BufDelete term://* call s:AutoReloadStatus() + autocmd BufWritePost * call fugitive#ReloadStatus(-1, 0) + autocmd ShellCmdPost * nested call fugitive#ReloadStatus() + autocmd BufDelete term://* nested call fugitive#ReloadStatus() if !has('win32') - autocmd FocusGained * call s:AutoReloadStatus() + autocmd FocusGained * call fugitive#ReloadStatus(-2, 0) endif + autocmd BufEnter index,index.lock + \ call s:ReloadWinStatus() + autocmd TabEnter * + \ if exists('t:fugitive_reload_status') | + \ call s:ReloadTabStatus() | + \ endif augroup END function! s:StageInfo(...) abort @@ -2104,11 +2477,14 @@ function! s:StageInfo(...) abort let index += 1 endif endwhile + let text = matchstr(getline(lnum), '^[A-Z?] \zs.*') return {'section': section, \ 'heading': getline(slnum), \ 'sigil': sigil, \ 'offset': offset, - \ 'filename': matchstr(getline(lnum), '^[A-Z?] \zs.*'), + \ 'filename': text, + \ 'relative': reverse(split(text, ' -> ')), + \ 'paths': map(reverse(split(text, ' -> ')), 's:Tree() . "/" . v:val'), \ 'commit': matchstr(getline(lnum), '^\%(\%(\x\x\x\)\@!\l\+\s\+\)\=\zs[0-9a-f]\{4,\}\ze '), \ 'status': matchstr(getline(lnum), '^[A-Z?]\ze \|^\%(\x\x\x\)\@!\l\+\ze [0-9a-f]'), \ 'index': index} @@ -2117,7 +2493,7 @@ endfunction function! s:Selection(arg1, ...) abort if a:arg1 ==# 'n' let arg1 = line('.') - let arg2 = v:count + let arg2 = -v:count elseif a:arg1 ==# 'v' let arg1 = line("'<") let arg2 = line("'>") @@ -2158,6 +2534,7 @@ function! s:Selection(arg1, ...) abort \ 'heading': heading, \ 'section': matchstr(heading, '^\u\l\+\ze.* (\d\+)$'), \ 'filename': '', + \ 'relative': [], \ 'paths': [], \ 'commit': '', \ 'status': '', @@ -2182,6 +2559,7 @@ function! s:Selection(arg1, ...) abort call add(results, extend(deepcopy(template), { \ 'lnum': lnum, \ 'filename': filename, + \ 'relative': reverse(split(filename, ' -> ')), \ 'paths': map(reverse(split(filename, ' -> ')), 'root . v:val'), \ 'status': matchstr(line, '^[A-Z?]'), \ })) @@ -2229,23 +2607,24 @@ endfunction function! s:Do(action, visual) abort let line = getline('.') + let reload = 0 if !a:0 && !v:count && line =~# '^[A-Z][a-z]' let header = matchstr(line, '^\S\+\ze:') if len(header) && exists('*s:Do' . a:action . header . 'Header') - call s:Do{a:action}{header}Header(matchstr(line, ': \zs.*')) - endif - let section = matchstr(line, '^\S\+') - if exists('*s:Do' . a:action . section . 'Heading') - call s:Do{a:action}{section}Heading(line) - return s:ReloadStatus() + let reload = s:Do{a:action}{header}Header(matchstr(line, ': \zs.*')) > 0 + else + let section = matchstr(line, '^\S\+') + if exists('*s:Do' . a:action . section . 'Heading') + let reload = s:Do{a:action}{section}Heading(line) > 0 + endif endif + return reload ? s:ReloadStatus() : '' endif let selection = s:Selection(a:visual ? 'v' : 'n') if empty(selection) return '' endif call filter(selection, 'v:val.section ==# selection[0].section') - let reload = 0 let status = 0 let err = '' try @@ -2263,13 +2642,16 @@ function! s:Do(action, visual) abort if status < 0 execute record.lnum + 1 endif - call s:StageReveal() + let success = 1 catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) finally if reload execute s:ReloadStatus() endif + if exists('success') + call s:StageReveal() + endif endtry return '' endfunction @@ -2281,38 +2663,199 @@ function! s:StageReveal(...) abort while getline(end) =~# '^[ \+-]' let end += 1 endwhile - while end > line('w$') && line('.') > line('w0') + &scrolloff + elseif getline(begin) =~# '^commit ' + let end = begin + while end < line('$') && getline(end + 1) !~# '^commit ' + let end += 1 + endwhile + elseif getline(begin) =~# s:section_pattern + let end = begin + while len(getline(end + 1)) + let end += 1 + endwhile + endif + if exists('end') + while line('.') > line('w0') + &scrolloff && end > line('w$') execute "normal! \<C-E>" endwhile endif endfunction -function! s:StageNext(count) abort +let s:file_pattern = '^[A-Z?] .\|^diff --' +let s:file_commit_pattern = s:file_pattern . '\|^\%(\l\{3,\} \)\=[0-9a-f]\{4,\} ' +let s:item_pattern = s:file_commit_pattern . '\|^@@' + +function! s:NextHunk(count) abort + if &filetype ==# 'fugitive' && getline('.') =~# s:file_pattern + exe s:StageInline('show') + endif for i in range(a:count) - call search('^[A-Z?] .\|^[0-9a-f]\{4,\} \|^@','W') + if &filetype ==# 'fugitive' + call search(s:file_pattern . '\|^@', 'W') + if getline('.') =~# s:file_pattern + exe s:StageInline('show') + if getline(line('.') + 1) =~# '^@' + + + endif + endif + else + call search('^@@', 'W') + endif endfor call s:StageReveal() return '.' endfunction -function! s:StagePrevious(count) abort - if line('.') == 1 && exists(':CtrlP') && get(g:, 'ctrl_p_map') =~? '^<c-p>$' - return 'CtrlP '.fnameescape(s:Tree()) - else - for i in range(a:count) - call search('^[A-Z?] .\|^[0-9a-f]\{4,\} \|^@','Wbe') - endfor +function! s:PreviousHunk(count) abort + for i in range(a:count) + if &filetype ==# 'fugitive' + let lnum = search(s:file_pattern . '\|^@','Wbn') + call s:StageInline('show', lnum) + call search('^? .\|^@','Wb') + else + call search('^@@', 'Wb') + endif + endfor + call s:StageReveal() + return '.' +endfunction + +function! s:NextFile(count) abort + for i in range(a:count) + exe s:StageInline('hide') + if !search(s:file_pattern, 'W') + break + endif + endfor + exe s:StageInline('hide') + return '.' +endfunction + +function! s:PreviousFile(count) abort + exe s:StageInline('hide') + for i in range(a:count) + if !search(s:file_pattern, 'Wb') + break + endif + exe s:StageInline('hide') + endfor + return '.' +endfunction + +function! s:NextItem(count) abort + for i in range(a:count) + if !search(s:item_pattern, 'W') && getline('.') !~# s:item_pattern + call search('^commit ', 'W') + endif + endfor + call s:StageReveal() + return '.' +endfunction + +function! s:PreviousItem(count) abort + for i in range(a:count) + if !search(s:item_pattern, 'Wbe') && getline('.') !~# s:item_pattern + call search('^commit ', 'Wbe') + endif + endfor + call s:StageReveal() + return '.' +endfunction + +let s:section_pattern = '^[A-Z][a-z][^:]*$' +let s:section_commit_pattern = s:section_pattern . '\|^commit ' + +function! s:NextSection(count) abort + let orig = line('.') + if getline('.') !~# '^commit ' + - + endif + for i in range(a:count) + if !search(s:section_commit_pattern, 'W') + break + endif + endfor + if getline('.') =~# s:section_commit_pattern call s:StageReveal() - return '.' + return getline('.') =~# s:section_pattern ? '+' : ':' + else + return orig endif endfunction +function! s:PreviousSection(count) abort + let orig = line('.') + if getline('.') !~# '^commit ' + - + endif + for i in range(a:count) + if !search(s:section_commit_pattern . '\|\%^', 'bW') + break + endif + endfor + if getline('.') =~# s:section_commit_pattern || line('.') == 1 + call s:StageReveal() + return getline('.') =~# s:section_pattern ? '+' : ':' + else + return orig + endif +endfunction + +function! s:NextSectionEnd(count) abort + + + if empty(getline('.')) + + + endif + for i in range(a:count) + if !search(s:section_commit_pattern, 'W') + return '$' + endif + endfor + return search('^.', 'Wb') +endfunction + +function! s:PreviousSectionEnd(count) abort + let old = line('.') + for i in range(a:count) + if search(s:section_commit_pattern, 'Wb') <= 1 + exe old + if i + break + else + return '' + endif + endif + let old = line('.') + endfor + return search('^.', 'Wb') +endfunction + +function! s:PatchSearchExpr(reverse) abort + let line = getline('.') + if col('.') ==# 1 && line =~# '^[+-]' + if line =~# '^[+-]\{3\} ' + let pattern = '^[+-]\{3\} ' . substitute(escape(strpart(line, 4), '^$.*[]~\'), '^\w/', '\\w/', '') . '$' + else + let pattern = '^[+-]\s*' . escape(substitute(strpart(line, 1), '^\s*\|\s*$', '', ''), '^$.*[]~\') . '\s*$' + endif + if a:reverse + return '?' . escape(pattern, '/') . "\<CR>" + else + return '/' . escape(pattern, '/?') . "\<CR>" + endif + endif + return a:reverse ? '#' : '*' +endfunction + function! s:StageInline(mode, ...) abort + if &filetype !=# 'fugitive' + return '' + endif let lnum1 = a:0 ? a:1 : line('.') let lnum = lnum1 + 1 if a:0 > 1 && a:2 == 0 let info = s:StageInfo(lnum - 1) - if empty(info.filename) && len(info.section) + if empty(info.paths) && len(info.section) while len(getline(lnum)) let lnum += 1 endwhile @@ -2342,7 +2885,7 @@ function! s:StageInline(mode, ...) abort endif continue endif - if !has_key(b:fugitive_diff, info.section) || info.status !~# '^[ADM]$' || a:mode ==# 'hide' + if !has_key(b:fugitive_diff, info.section) || info.status !~# '^[ADMRU]$' || a:mode ==# 'hide' continue endif let mode = '' @@ -2359,9 +2902,9 @@ function! s:StageInline(mode, ...) abort endif let start = index let mode = 'head' - elseif mode ==# 'head' && substitute(line, "\t$", '', '') ==# '--- ' . info.filename + elseif mode ==# 'head' && substitute(line, "\t$", '', '') ==# '--- ' . info.relative[-1] let mode = 'await' - elseif mode ==# 'head' && substitute(line, "\t$", '', '') ==# '+++ ' . info.filename + elseif mode ==# 'head' && substitute(line, "\t$", '', '') ==# '+++ ' . info.relative[0] let mode = 'await' elseif mode ==# 'capture' call add(diff, line) @@ -2380,19 +2923,10 @@ function! s:StageInline(mode, ...) abort return lnum endfunction -function! s:StageIntend(count) abort +function! s:NextExpandedHunk(count) abort for i in range(a:count) - if getline('.')[0:1] ==# '? ' - call s:TreeChomp('add', '--intent-to-add', '--', s:Tree() . '/' . getline('.')[2:-1]) - - - exe s:ReloadStatus() - elseif getline('.') =~# '^Unstaged' - call s:TreeChomp('add', '--intent-to-add', '--', s:Tree()) - exe s:ReloadStatus() - else - call s:StageInline('show', line('.'), 1) - endif - call s:StageNext(1) + call s:StageInline('show', line('.'), 1) + call search(s:file_pattern . '\|^@','W') endfor return '.' endfunction @@ -2401,43 +2935,45 @@ function! s:StageDiff(diff) abort let lnum = line('.') let info = s:StageInfo(lnum) let prefix = info.offset > 0 ? '+' . info.offset : '' - if empty(info.filename) && info.section ==# 'Staged' + if empty(info.paths) && info.section ==# 'Staged' return 'Git! diff --no-ext-diff --cached' - elseif empty(info.filename) + elseif empty(info.paths) return 'Git! diff --no-ext-diff' - elseif info.filename =~# ' -> ' - let [old, new] = split(info.filename,' -> ') - execute 'Gedit' . prefix s:fnameescape(':0:'.new) - return a:diff.' HEAD:'.s:fnameescape(old) + elseif len(info.paths) > 1 + execute 'Gedit' . prefix s:fnameescape(':0:' . info.paths[0]) + return a:diff . '! HEAD:'.s:fnameescape(info.paths[1]) elseif info.section ==# 'Staged' && info.sigil ==# '-' - execute 'Gedit' prefix s:fnameescape('@:'.info.filename) - return a:diff.'! :0' + execute 'Gedit' prefix s:fnameescape(':0:'.info.paths[0]) + return a:diff . '! :0:%' elseif info.section ==# 'Staged' - execute 'Gedit' prefix s:fnameescape(':0:'.info.filename) - return a:diff . (info.sigil ==# '+' ? '!' : '') . ' -' + execute 'Gedit' prefix s:fnameescape(':0:'.info.paths[0]) + return a:diff . '! @:%' elseif info.sigil ==# '-' - execute 'Gedit' prefix s:fnameescape(':0:'.info.filename) - return a:diff . '!' + execute 'Gedit' prefix s:fnameescape(':0:'.info.paths[0]) + return a:diff . '! :(top)%' else - execute 'Gedit' prefix s:fnameescape(':(top)'.info.filename) - return a:diff . (info.sigil ==# '+' ? '!' : '') + execute 'Gedit' prefix s:fnameescape(':(top)'.info.paths[0]) + return a:diff . '!' endif endfunction function! s:StageDiffEdit() abort let info = s:StageInfo(line('.')) - let arg = (empty(info.filename) ? '.' : info.filename) + let arg = (empty(info.paths) ? s:Tree() : info.paths[0]) if info.section ==# 'Staged' - return 'Git! diff --no-ext-diff --cached '.s:shellesc(arg) + return 'Git! diff --no-ext-diff --cached '.s:fnameescape(arg) elseif info.status ==# '?' - call s:TreeChomp('add', '--intent-to-add', './' . arg) + call s:TreeChomp('add', '--intent-to-add', '--', arg) return s:ReloadStatus() else - return 'Git! diff --no-ext-diff '.s:shellesc(arg) + return 'Git! diff --no-ext-diff '.s:fnameescape(arg) endif endfunction function! s:StageApply(info, reverse, extra) abort + if a:info.status ==# 'R' + call s:throw('fugitive: patching renamed file not yet supported') + endif let cmd = ['apply', '-p0', '--recount'] + a:extra let info = a:info let start = info.patch @@ -2460,8 +2996,10 @@ function! s:StageApply(info, reverse, extra) abort call insert(lines, getline(start)) endif endwhile - if start == 0 || getline(start) !~# '^@@ ' - call s:throw("could not find hunk") + if start == 0 + throw 'fugitive: cold not find hunk' + elseif getline(start) !~# '^@@ ' + throw 'fugitive: cannot apply conflict hunk' endif let i = b:fugitive_expanded[info.section][info.filename][0] let head = [] @@ -2476,49 +3014,73 @@ function! s:StageApply(info, reverse, extra) abort call add(cmd, '--reverse') endif call extend(cmd, ['--', temp]) - let output = call('s:TreeChomp', cmd) - if !v:shell_error + let [output, exec_error] = s:ChompError(cmd) + if !exec_error return 1 endif call s:throw(output) endfunction -function! s:StageDelete(lnum, count) abort - let info = get(s:Selection(a:lnum, -a:count), 0, {'filename': ''}) - if empty(info.filename) - return '' - endif - let hash = s:TreeChomp('hash-object', '-w', '--', info.paths[0]) - if empty(hash) - return '' - elseif info.patch - try - call s:StageApply(info, 1, info.section ==# 'Staged' ? ['--index'] : []) - catch /^fugitive:/ - return 'echoerr v:errmsg' - endtry - elseif a:count == 2 - call s:TreeChomp('checkout', '--ours', '--', info.paths[0]) - elseif a:count == 3 - call s:TreeChomp('checkout', '--theirs', '--', info.paths[0]) - elseif info.status =~# '[ADU]' && - \ get(b:fugitive_status[info.section ==# 'Staged' ? 'Unstaged' : 'Staged'], info.filename, '') =~# '[AU]' - call s:TreeChomp('checkout', info.section ==# 'Staged' ? '--ours' : '--theirs', '--', info.paths[0]) - elseif info.status ==# 'U' - call s:TreeChomp('rm', '--', info.paths[0]) - elseif info.status ==# 'A' - call s:TreeChomp('rm', '-f', '--', info.paths[0]) - elseif info.status ==# '?' - call s:TreeChomp('clean', '-f', '--', info.paths[0]) - elseif info.section ==# 'Unstaged' - call s:TreeChomp('checkout', '--', info.paths[0]) - else - call s:TreeChomp('checkout', 'HEAD^{}', '--', info.paths[0]) +function! s:StageDelete(lnum1, lnum2, count) abort + let restore = [] + let err = '' + try + for info in s:Selection(a:lnum1, a:lnum2) + if empty(info.paths) + continue + endif + let hash = s:TreeChomp('hash-object', '-w', '--', info.paths[0]) + if empty(hash) + continue + endif + if info.patch + call s:StageApply(info, 1, info.section ==# 'Staged' ? ['--index'] : []) + elseif info.status ==# '?' + call s:TreeChomp('clean', '-f', '--', info.paths[0]) + elseif a:count == 2 + call s:TreeChomp('checkout', '--ours', '--', info.paths[0]) + elseif a:count == 3 + call s:TreeChomp('checkout', '--theirs', '--', info.paths[0]) + elseif info.status =~# '[ADU]' && + \ get(b:fugitive_status[info.section ==# 'Staged' ? 'Unstaged' : 'Staged'], info.filename, '') =~# '[AU]' + call s:TreeChomp('checkout', info.section ==# 'Staged' ? '--ours' : '--theirs', '--', info.paths[0]) + elseif info.status ==# 'U' + call s:TreeChomp('rm', '--', info.paths[0]) + elseif info.status ==# 'A' + call s:TreeChomp('rm', '-f', '--', info.paths[0]) + elseif info.section ==# 'Unstaged' + call s:TreeChomp('checkout', '--', info.paths[0]) + else + call s:TreeChomp('checkout', 'HEAD^{}', '--', info.paths[0]) + endif + call add(restore, ':Gsplit ' . s:fnameescape(info.relative[0]) . '|Gread ' . hash[0:6]) + endfor + catch /^fugitive:/ + let err = '|echoerr ' . string(v:exception) + endtry + if empty(restore) + return err[1:-1] endif exe s:ReloadStatus() - let @@ = hash - return 'checktime|redraw|echomsg ' . - \ string('To restore, :Git cat-file blob '.hash[0:6].' > '.info.filename) + call s:StageReveal() + return 'checktime|redraw|echomsg ' . string('To restore, ' . join(restore, '|')) . err +endfunction + +function! s:StageIgnore(lnum1, lnum2, count) abort + let paths = [] + for info in s:Selection(a:lnum1, a:lnum2) + call extend(paths, info.relative) + endfor + call map(paths, '"/" . v:val') + exe 'Gsplit' (a:count ? '.gitignore' : '.git/info/exclude') + let last = line('$') + if last == 1 && empty(getline(1)) + call setline(last, paths) + else + call append(last, paths) + exe last + 1 + endif + return '' endfunction function! s:DoToggleHeadHeader(value) abort @@ -2526,7 +3088,7 @@ function! s:DoToggleHeadHeader(value) abort call search('\C^index$', 'wc') endfunction -function! s:DoToggleUnpushedHeading(heading) abort +function! s:DoStageUnpushedHeading(heading) abort let remote = matchstr(a:heading, 'to \zs[^/]\+\ze/') if empty(remote) let remote = '.' @@ -2535,7 +3097,11 @@ function! s:DoToggleUnpushedHeading(heading) abort call feedkeys(':Gpush ' . remote . ' ' . 'HEAD:' . branch) endfunction -function! s:DoToggleUnpushed(record) abort +function! s:DoToggleUnpushedHeading(heading) abort + return s:DoStageUnpushedHeading(a:heading) +endfunction + +function! s:DoStageUnpushed(record) abort let remote = matchstr(a:record.heading, 'to \zs[^/]\+\ze/') if empty(remote) let remote = '.' @@ -2544,14 +3110,30 @@ function! s:DoToggleUnpushed(record) abort call feedkeys(':Gpush ' . remote . ' ' . a:record.commit . ':' . branch) endfunction -function! s:DoToggleUnpulledHeading(heading) abort +function! s:DoToggleUnpushed(record) abort + return s:DoStageUnpushed(a:record) +endfunction + +function! s:DoUnstageUnpulledHeading(heading) abort call feedkeys(':Grebase') endfunction -function! s:DoToggleUnpulled(record) abort +function! s:DoToggleUnpulledHeading(heading) abort + call s:DoUnstageUnpulledHeading(a:heading) +endfunction + +function! s:DoUnstageUnpulled(record) abort call feedkeys(':Grebase ' . a:record.commit) endfunction +function! s:DoToggleUnpulled(record) abort + call s:DoUnstageUnpulled(a:record) +endfunction + +function! s:DoUnstageUnpushed(record) abort + call feedkeys(':Grebase --autosquash ' . a:record.commit . '^') +endfunction + function! s:DoToggleStagedHeading(...) abort call s:TreeChomp('reset', '-q') return 1 @@ -2570,6 +3152,15 @@ function! s:DoStageUnstagedHeading(heading) abort return s:DoToggleUnstagedHeading(a:heading) endfunction +function! s:DoToggleUntrackedHeading(...) abort + call s:TreeChomp('add', '.') + return 1 +endfunction + +function! s:DoStageUntrackedHeading(heading) abort + return s:DoToggleUntrackedHeading(a:heading) +endfunction + function! s:DoToggleStaged(record) abort if a:record.patch return s:StageApply(a:record, 1, ['--cached']) @@ -2579,16 +3170,12 @@ function! s:DoToggleStaged(record) abort endif endfunction -function! s:DoStageStaged(record) abort - return -1 -endfunction - function! s:DoUnstageStaged(record) abort return s:DoToggleStaged(a:record) endfunction function! s:DoToggleUnstaged(record) abort - if a:record.patch + if a:record.patch && a:record.status !=# 'A' return s:StageApply(a:record, 0, ['--cached']) else call s:TreeChomp(['add', '-A', '--'] + a:record.paths) @@ -2609,184 +3196,223 @@ function! s:DoUnstageUnstaged(record) abort endif endfunction +function! s:DoToggleUntracked(record) abort + call s:TreeChomp(['add', '--'] + a:record.paths) + return 1 +endfunction + +function! s:DoStageUntracked(record) abort + return s:DoToggleUntracked(a:record) +endfunction + function! s:StagePatch(lnum1,lnum2) abort let add = [] let reset = [] + let intend = [] for lnum in range(a:lnum1,a:lnum2) let info = s:StageInfo(lnum) - if empty(info.filename) && info.section ==# 'Staged' + if empty(info.paths) && info.section ==# 'Staged' return 'Git reset --patch' - elseif empty(info.filename) && info.section ==# 'Unstaged' + elseif empty(info.paths) && info.section ==# 'Unstaged' return 'Git add --patch' - elseif info.filename ==# '' + elseif empty(info.paths) && info.section ==# 'Untracked' + return 'Git add --interactive' + elseif empty(info.paths) continue endif execute lnum - if info.filename =~ ' -> ' - let reset += [split(info.filename,' -> ')[1]] - elseif info.section ==# 'Staged' - let reset += [info.filename] + if info.section ==# 'Staged' + let reset += info.relative + elseif info.section ==# 'Untracked' + let intend += info.paths elseif info.status !~# '^D' - let add += [info.filename] + let add += info.relative endif endfor try + if !empty(intend) + call s:TreeChomp(['add', '--intent-to-add', '--'] + intend) + endif if !empty(add) - execute "Git add --patch -- ".join(map(add,'s:shellesc(v:val)')) + execute "Git add --patch -- ".join(map(add,'s:fnameescape(v:val)')) endif if !empty(reset) - execute "Git reset --patch -- ".join(map(reset,'s:shellesc(v:val)')) + execute "Git reset --patch -- ".join(map(reset,'s:fnameescape(v:val)')) endif catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry return s:ReloadStatus() endfunction -" Section: :Gcommit +" Section: :Gcommit, :Grevert -call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit", "Commit") +function! s:CommitInteractive(line1, line2, range, bang, mods, args, patch) abort + let status = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', []) + let status = len(status) ? status . '|' : '' + if a:patch + return status . 'if search("^Unstaged")|exe "normal >"|exe "+"|endif' + else + return status . 'if search("^Untracked\\|^Unstaged")|exe "+"|endif' + endif +endfunction -function! s:CommitCommand(line1, line2, range, count, bang, mods, reg, arg, args, ...) abort - let mods = s:gsub(a:mods ==# '<mods>' ? '' : a:mods, '<tab>', '-tab') +function! s:CommitSubcommand(line1, line2, range, bang, mods, args, ...) abort + let mods = substitute(s:Mods(a:mods), '\C\<tab\>', '-tab', 'g') let dir = a:0 ? a:1 : s:Dir() let tree = s:Tree(dir) - let msgfile = dir . '/COMMIT_EDITMSG' + let msgfile = fugitive#Find('.git/COMMIT_EDITMSG', dir) let outfile = tempname() - let errorfile = tempname() try - let guioptions = &guioptions - try - if &guioptions =~# '!' - setglobal guioptions-=! - endif - let cdback = s:Cd(tree) - if s:winshell() - let command = '' - let old_editor = $GIT_EDITOR - let $GIT_EDITOR = 'false' + if s:winshell() + let command = 'set GIT_EDITOR=false& ' + else + let command = 'env GIT_EDITOR=false ' + endif + let argv = a:args + let i = 0 + while get(argv, i, '--') !=# '--' + if argv[i] =~# '^-[apzsneiovq].' + call insert(argv, argv[i][0:1]) + let argv[i+1] = '-' . argv[i+1][2:-1] else - let command = 'env GIT_EDITOR=false ' + let i += 1 endif - let args = s:ShellExpand(a:arg) - let command .= s:UserCommand() . ' commit ' . args - if &shell =~# 'csh' - noautocmd silent execute '!('.escape(command, '!#%').' > '.outfile.') >& '.errorfile - elseif a:arg =~# '\%(^\| \)-\%(-interactive\|p\|-patch\)\>' - noautocmd execute '!'.command.' 2> '.errorfile - else - noautocmd silent execute '!'.command.' > '.outfile.' 2> '.errorfile - endif - let error = v:shell_error - finally - execute cdback - let &guioptions = guioptions - endtry + endwhile + let command .= s:UserCommand(dir, ['commit'] + argv) + if (&autowrite || &autowriteall) && !a:0 + silent! wall + endif + if s:HasOpt(argv, '-i', '--interactive') + return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, argv, 0) + elseif s:HasOpt(argv, '-p', '--patch') + return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, argv, 1) + else + let [error_string, exec_error] = s:TempCmd(outfile, command) + let errors = split(error_string, "\n") + endif if !has('gui_running') redraw! endif - if !error + if !exec_error + echo join(errors, "\n") if filereadable(outfile) - for line in readfile(outfile) - echo line - endfor + echo join(readfile(outfile), "\n") endif - call fugitive#ReloadStatus() + call fugitive#ReloadStatus(dir, 1) return '' else - let errors = readfile(errorfile) let error = get(errors,-2,get(errors,-1,'!')) if error =~# 'false''\=\.$' - let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-[esp]|--edit|--interactive|--patch|--signoff)%($| )','') - let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-c|--reedit-message|--reuse-message|-F|--file|-m|--message)%(\s+|\=)%(''[^'']*''|"%(\\.|[^"])*"|\\.|\S)*','') - let args = s:sub(args, '\ze -- |$', ' --no-edit --no-interactive --no-signoff') - let args = '-F '.s:shellesc(msgfile).' '.args - if args !~# '\%(^\| \)--cleanup\>' - let args = '--cleanup=strip '.args + let i = 0 + while get(argv, i, '--') !=# '--' + if argv[i] =~# '^\%(-[eips]\|-[CcFm].\+\|--edit\|--interactive\|--patch\|--signoff\|--reedit-message=.*\|--reuse-message=.*\|--file=.*\|--message=.*\)$' + call remove(argv, i) + elseif argv[i] =~# '^\%(-[CcFm]\|--reedit-message\|--reuse-message\|--file\|--message\)$' + call remove(argv, i, i + 1) + else + if argv[i] =~# '^--cleanup\>' + let cleanup = 1 + endif + let i += 1 + endif + endwhile + call insert(argv, '--no-signoff', i) + call insert(argv, '--no-interactive', i) + call insert(argv, '--no-edit', i) + if !exists('cleanup') + call insert(argv, '--cleanup=strip') endif - if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod - execute mods 'keepalt edit' s:fnameescape(msgfile) - elseif a:arg =~# '\%(^\| \)-\w*v' || mods =~# '\<tab\>' - execute mods 'keepalt -tabedit' s:fnameescape(msgfile) + call extend(argv, ['-F', msgfile], 'keep') + if (bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&modified) || a:line2 == 0 + execute mods . 'keepalt edit' s:fnameescape(msgfile) + elseif s:HasOpt(argv, '-v') || mods =~# '\<tab\>' + execute mods . 'keepalt -tabedit' s:fnameescape(msgfile) else - execute mods 'keepalt split' s:fnameescape(msgfile) + execute mods . 'keepalt split' s:fnameescape(msgfile) endif - let b:fugitive_commit_arguments = args + let b:fugitive_commit_arguments = argv setlocal bufhidden=wipe filetype=gitcommit return '1' - elseif error ==# '!' - echo get(readfile(outfile), -1, '') + elseif empty(errors) + let out = readfile(outfile) + echo get(out, -1, '') =~# 'stash\|\d' ? get(out, -2, '') : get(out, -1, '') return '' else - call s:throw(empty(error)?join(errors, ' '):error) + echo join(errors, "\n") + return '' endif endif catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) finally - if exists('old_editor') - let $GIT_EDITOR = old_editor - endif call delete(outfile) - call delete(errorfile) endtry endfunction -function! s:CommitComplete(A,L,P) abort +function! s:RevertSubcommand(line1, line2, range, bang, mods, args) abort + let dir = s:Dir() + let no_commit = s:HasOpt(a:args, '-n', '--no-commit', '--no-edit', '--abort', '--continue', '--quit') + let cmd = s:UserCommand(dir, ['revert'] + (no_commit ? [] : ['-n']) + a:args) + let [out, exec_error] = s:SystemError(cmd) + call fugitive#ReloadStatus(-1, 1) + if no_commit || exec_error + return 'echo ' . string(substitute(out, "\n$", '', '')) + endif + return s:CommitSubcommand(a:line1, a:line2, a:range, a:bang, a:mods, [], dir) +endfunction + +function! s:CommitComplete(A, L, P) abort if a:A =~# '^--fixup=\|^--squash=' - let commits = split(s:TreeChomp('log', '--pretty=format:%s', '@{upstream}..'), "\n") - if !v:shell_error - let pre = matchstr(a:A, '^--\w*=') . ':/^' - return map(commits, 'pre . tr(v:val, "\\ !^$*?[]()''\"`&;<>|#", "....................")') + let commits = s:LinesError(['log', '--pretty=format:%s', '@{upstream}..'])[0] + let pre = matchstr(a:A, '^--\w*=''\=') . ':/^' + if pre =~# "'" + call map(commits, 'pre . string(tr(v:val, "|\"^$*[]", "......."))[1:-1]') + call filter(commits, 'strpart(v:val, 0, strlen(a:A)) ==# a:A') + return commits + else + return s:FilterEscape(map(commits, 'pre . tr(v:val, "\\ !^$*?[]()''\"`&;<>|#", "....................")'), a:A) endif - elseif a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit -<Tab> - let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--fixup=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--squash=', '--template=', '--untracked-files', '--verbose'] - return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A') else - return fugitive#CompletePath(a:A, s:Dir()) + return s:CompleteSub('commit', a:A, a:L, a:P, function('fugitive#CompletePath')) endif return [] endfunction +function! s:RevertComplete(A, L, P) abort + return s:CompleteSub('revert', a:A, a:L, a:P, function('s:CompleteRevision')) +endfunction + function! s:FinishCommit() abort let buf = +expand('<abuf>') let args = getbufvar(buf, 'fugitive_commit_arguments') if !empty(args) - call setbufvar(buf, 'fugitive_commit_arguments', '') + call setbufvar(buf, 'fugitive_commit_arguments', []) if getbufvar(buf, 'fugitive_commit_rebase') call setbufvar(buf, 'fugitive_commit_rebase', 0) let s:rebase_continue = s:Dir(buf) endif - return s:CommitCommand(-1, -1, 0, -1, 0, '', '', args, [], s:Dir(buf)) + return s:CommitSubcommand(-1, -1, 0, 0, '', args, s:Dir(buf)) endif return '' endfunction +call s:command("-nargs=? -range=-1 -complete=customlist,s:CommitComplete Gcommit", "commit") +call s:command("-nargs=? -range=-1 -complete=customlist,s:RevertComplete Grevert", "revert") + " Section: :Gmerge, :Grebase, :Gpull -call s:command("-nargs=? -bang -complete=custom,s:RevisionComplete Gmerge " . - \ "execute s:Merge('merge', <bang>0, '<mods>', <q-args>)") -call s:command("-nargs=? -bang -complete=custom,s:RevisionComplete Grebase " . - \ "execute s:Merge('rebase', <bang>0, '<mods>', <q-args>)") -call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpull " . - \ "execute s:Merge('pull --progress', <bang>0, '<mods>', <q-args>)") - -function! s:RevisionComplete(A, L, P) abort - return s:TreeChomp('rev-parse', '--symbolic', '--branches', '--tags', '--remotes') - \ . "\nHEAD\nFETCH_HEAD\nMERGE_HEAD\nORIG_HEAD" +function! s:MergeComplete(A, L, P) abort + return s:CompleteSub('merge', a:A, a:L, a:P, function('s:CompleteRevision')) endfunction -function! s:RemoteComplete(A, L, P) abort - let remote = matchstr(a:L, ' \zs\S\+\ze ') - if !empty(remote) - let matches = split(s:TreeChomp('ls-remote', remote), "\n") - call filter(matches, 'v:val =~# "\t" && v:val !~# "{"') - call map(matches, 's:sub(v:val, "^.*\t%(refs/%(heads/|tags/)=)=", "")') - else - let matches = split(s:TreeChomp('remote'), "\n") - endif - return join(matches, "\n") +function! s:RebaseComplete(A, L, P) abort + return s:CompleteSub('rebase', a:A, a:L, a:P, function('s:CompleteRevision')) +endfunction + +function! s:PullComplete(A, L, P) abort + return s:CompleteSub('pull', a:A, a:L, a:P, function('s:CompleteRemote')) endfunction function! s:RebaseSequenceAborter() abort @@ -2836,14 +3462,35 @@ let s:rebase_abbrevs = { \ } function! s:RebaseEdit(cmd, dir) abort - return a:cmd . ' +setlocal\ bufhidden=wipe ' . s:fnameescape(a:dir . '/rebase-merge/git-rebase-todo') + let rebase_todo = s:fnameescape(fugitive#Find('.git/rebase-merge/git-rebase-todo', a:dir)) + + if filereadable(rebase_todo) + let new = readfile(rebase_todo) + let sha_length = 0 + let shas = {} + + for i in range(len(new)) + if new[i] =~# '^\l\+\s\+[0-9a-f]\{5,\}\>' + let sha = matchstr(new[i], '\C\<[a-f0-9]\{5,\}\>') + if !sha_length + let sha_length = len(s:TreeChomp(a:dir, 'rev-parse', '--short', sha)) + endif + let shortened_sha = strpart(sha, 0, sha_length) + let shas[shortened_sha] = sha + let new[i] = substitute(new[i], sha, shortened_sha, '') + endif + endfor + call writefile(new, rebase_todo) + endif + return a:cmd . ' +setlocal\ bufhidden=wipe\|' . escape('let b:fugitive_rebase_shas = ' . string(shas), ' ') . ' ' . rebase_todo endfunction -function! s:Merge(cmd, bang, mods, args, ...) abort +function! s:MergeRebase(cmd, bang, mods, args, ...) abort let dir = a:0 ? a:1 : s:Dir() - let mods = substitute(a:mods, '\C<mods>', '', '') . ' ' - if a:cmd =~# '^rebase' && ' '.a:args =~# ' -i\| --interactive' - let cmd = fugitive#Prepare(dir, '-c', 'sequence.editor=sh ' . s:RebaseSequenceAborter(), 'rebase') . ' ' . a:args + let args = a:args + let mods = s:Mods(a:mods) + if a:cmd =~# '^rebase' && s:HasOpt(args, '-i', '--interactive') + let cmd = fugitive#Prepare(dir, '-c', 'sequence.editor=sh ' . s:RebaseSequenceAborter(), 'rebase') . ' ' . s:shellesc(args) let out = system(cmd)[0:-2] for file in ['end', 'msgnum'] let file = fugitive#Find('.git/rebase-merge/' . file, dir) @@ -2854,24 +3501,38 @@ function! s:Merge(cmd, bang, mods, args, ...) abort endfor call writefile([], fugitive#Find('.git/rebase-merge/done', dir)) if a:bang - return '' + return 'exe' endif return s:RebaseEdit(mods . 'split', dir) - elseif a:cmd =~# '^rebase' && ' '.a:args =~# ' --edit-todo' && filereadable(dir . '/rebase-merge/git-rebase-todo') + elseif a:cmd =~# '^rebase' && s:HasOpt(args, '--edit-todo') && filereadable(fugitive#Find('.git/rebase-merge/git-rebase-todo', dir)) return s:RebaseEdit(mods . 'split', dir) - elseif a:cmd =~# '^rebase' && ' '.a:args =~# ' --continue' && !a:0 - let rdir = dir . '/rebase-merge' - call system(fugitive#Prepare(dir, 'diff-index', '--cached', '--quiet', 'HEAD', '--')) - if v:shell_error && isdirectory(rdir) + elseif a:cmd =~# '^rebase' && s:HasOpt(args, '--continue') && !a:0 + let rdir = fugitive#Find('.git/rebase-merge', dir) + let exec_error = s:ChompError([dir, 'diff-index', '--cached', '--quiet', 'HEAD', '--'])[1] + if exec_error && isdirectory(rdir) if getfsize(rdir . '/amend') <= 0 - return 'exe ' . string(mods . 'Gcommit -n -F ' . s:shellesc(dir . '/rebase-merge/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' + return 'exe ' . string(mods . 'Gcommit -n -F ' . s:fnameescape(rdir .'/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' elseif readfile(rdir . '/amend')[0] ==# fugitive#Head(-1, dir) - return 'exe ' . string(mods . 'Gcommit --amend -n -F ' . s:shellesc(dir . '/rebase-merge/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' + return 'exe ' . string(mods . 'Gcommit --amend -n -F ' . s:fnameescape(rdir . '/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' endif endif endif + let had_merge_msg = filereadable(fugitive#Find('.git/MERGE_MSG', dir)) + let argv = [] + if a:cmd ==# 'pull' + let argv += s:AskPassArgs(dir) + ['pull', '--progress'] + else + call add(argv, a:cmd) + endif + if !s:HasOpt(args, '--no-edit', '--abort', '-m') && a:cmd !=# 'rebase' + call add(argv, '--edit') + endif + if a:cmd ==# 'rebase' && s:HasOpt(args, '--autosquash') && !s:HasOpt(args, '--interactive', '-i') + call add(argv, '--interactive') + endif + call extend(argv, args) + let [mp, efm] = [&l:mp, &l:efm] - let had_merge_msg = filereadable(dir . '/MERGE_MSG') try let cdback = s:Cd(s:Tree(dir)) let &l:errorformat = '' @@ -2895,32 +3556,38 @@ function! s:Merge(cmd, bang, mods, args, ...) abort \ . "%+EXUNG \u0110\u1ed8T %.%#," \ . "%+E\u51b2\u7a81 %.%#," \ . 'U%\t%f' - if a:cmd =~# '^merge' && empty(a:args) && - \ (had_merge_msg || isdirectory(dir . '/rebase-apply') || + if a:cmd =~# '^merge' && empty(args) && + \ (had_merge_msg || isdirectory(fugitive#Find('.git/rebase-apply', dir)) || \ !empty(s:TreeChomp(dir, 'diff-files', '--diff-filter=U'))) - let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' + let cmd = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' else - let &l:makeprg = s:sub(s:UserCommand() . ' ' . a:cmd . - \ (' ' . a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' || a:cmd =~# '^rebase' ? '' : ' --edit') . - \ (' ' . a:args =~# ' --autosquash\>' && a:cmd =~# '^rebase' ? ' --interactive' : '') . - \ ' ' . a:args, ' *$', '') + let cmd = s:UserCommand(dir, argv) endif if !empty($GIT_SEQUENCE_EDITOR) || has('win32') let old_sequence_editor = $GIT_SEQUENCE_EDITOR let $GIT_SEQUENCE_EDITOR = 'true' else - let &l:makeprg = 'env GIT_SEQUENCE_EDITOR=true ' . &l:makeprg + let cmd = 'env GIT_SEQUENCE_EDITOR=true ' . cmd endif if !empty($GIT_EDITOR) || has('win32') let old_editor = $GIT_EDITOR let $GIT_EDITOR = 'false' else - let &l:makeprg = 'env GIT_EDITOR=false ' . substitute(&l:makeprg, '^env ', '', '') + let cmd = 'env GIT_EDITOR=false ' . substitute(cmd, '^env ', '', '') endif + if !has('patch-8.1.0334') && has('terminal') && &autowrite + let autowrite_was_set = 1 + set noautowrite + silent! wall + endif + let &l:makeprg = cmd silent noautocmd make! catch /^Vim\%((\a\+)\)\=:E211/ let err = v:exception finally + if exists('autowrite_was_set') + set autowrite + endif redraw! let [&l:mp, &l:efm] = [mp, efm] if exists('old_editor') @@ -2931,17 +3598,17 @@ function! s:Merge(cmd, bang, mods, args, ...) abort endif execute cdback endtry - call fugitive#ReloadStatus() + call fugitive#ReloadStatus(dir, 1) if empty(filter(getqflist(),'v:val.valid && v:val.type !=# "I"')) if a:cmd =~# '^rebase' && - \ filereadable(dir . '/rebase-merge/amend') && - \ filereadable(dir . '/rebase-merge/done') && - \ get(readfile(dir . '/rebase-merge/done'), -1, '') =~# '^[^e]' + \ filereadable(fugitive#Find('.git/rebase-merge/amend', dir)) && + \ filereadable(fugitive#Find('.git/rebase-merge/done', dir)) && + \ get(readfile(fugitive#Find('.git/rebase-merge/done', dir)), -1, '') =~# '^[^e]' cclose - return 'exe ' . string(mods . 'Gcommit --amend -n -F ' . s:shellesc(dir . '/rebase-merge/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' - elseif !had_merge_msg && filereadable(dir . '/MERGE_MSG') + return 'exe ' . string(mods . 'Gcommit --amend -n -F ' . s:fnameescape(fugitive#Find('.git/rebase-merge/message', dir)) . ' -e') . '|let b:fugitive_commit_rebase = 1' + elseif !had_merge_msg && filereadable(fugitive#Find('.git/MERGE_MSG', dir)) cclose - return mods . 'Gcommit --no-status -n -t '.s:shellesc(dir . '/MERGE_MSG') + return mods . 'Gcommit --no-status -n -t '.s:fnameescape(fugitive#Find('.git/MERGE_MSG', dir)) endif endif let qflist = getqflist() @@ -2956,10 +3623,11 @@ function! s:Merge(cmd, bang, mods, args, ...) abort if found call setqflist(qflist, 'r') if !a:bang + call s:BlurStatus() return 'cfirst' endif endif - return exists('err') ? 'echoerr '.string(err) : '' + return exists('err') ? 'echoerr '.string(err) : 'exe' endfunction function! s:RebaseClean(file) abort @@ -2970,6 +3638,12 @@ function! s:RebaseClean(file) abort let new = copy(old) for i in range(len(new)) let new[i] = substitute(new[i], '^\l\>', '\=get(s:rebase_abbrevs,submatch(0),submatch(0))', '') + + let sha = matchstr(new[i], '\C\<[a-f0-9]\{5,\}\>') + let rebase_shas = getbufvar(a:file, 'fugitive_rebase_shas') + if len(sha) && type(rebase_shas) == type({}) && has_key(rebase_shas, sha) + let new[i] = substitute(new[i], '\C\<' . sha . '\>', rebase_shas[sha], '') + endif endfor if new !=# old call writefile(new, a:file) @@ -2977,6 +3651,18 @@ function! s:RebaseClean(file) abort return '' endfunction +function! s:MergeSubcommand(line1, line2, range, bang, mods, args) abort + return s:MergeRebase('merge', a:bang, a:mods, a:args) +endfunction + +function! s:RebaseSubcommand(line1, line2, range, bang, mods, args) abort + return s:MergeRebase('rebase', a:bang, a:mods, a:args) +endfunction + +function! s:PullSubcommand(line1, line2, range, bang, mods, args) abort + return s:MergeRebase('pull', a:bang, a:mods, a:args) +endfunction + augroup fugitive_merge autocmd! autocmd VimLeavePre,BufDelete git-rebase-todo @@ -2988,10 +3674,14 @@ augroup fugitive_merge \ endif autocmd BufEnter * nested \ if exists('s:rebase_continue') | - \ exe s:Merge('rebase', 0, '', getfsize(fugitive#Find('.git/rebase-merge/git-rebase-todo', s:rebase_continue)) > 0 ? '--continue' : '--abort', remove(s:, 'rebase_continue')) | + \ exe s:MergeRebase('rebase', 0, '', [getfsize(fugitive#Find('.git/rebase-merge/git-rebase-todo', s:rebase_continue)) > 0 ? '--continue' : '--abort'], remove(s:, 'rebase_continue')) | \ endif augroup END +call s:command("-nargs=? -bang -complete=customlist,s:MergeComplete Gmerge", "merge") +call s:command("-nargs=? -bang -complete=customlist,s:RebaseComplete Grebase", "rebase") +call s:command("-nargs=? -bang -complete=customlist,s:PullComplete Gpull", "pull") + " Section: :Ggrep, :Glog if !exists('g:fugitive_summary_format') @@ -2999,107 +3689,240 @@ if !exists('g:fugitive_summary_format') endif function! s:GrepComplete(A, L, P) abort - if strpart(a:L, 0, a:P) =~# ' -- ' - return fugitive#CompletePath(a:A, s:Dir()) + return s:CompleteSub('grep', a:A, a:L, a:P) +endfunction + +function! s:LogComplete(A, L, P) abort + return s:CompleteSub('log', a:A, a:L, a:P) +endfunction + +function! s:GrepParseLine(prefix, name_only, dir, line) abort + let entry = {'valid': 1} + let match = matchlist(a:line, '^\(.\{-\}\):\(\d\+\):\(\d\+:\)\=\(.*\)$') + if len(match) + let entry.module = match[1] + let entry.lnum = +match[2] + let entry.col = +match[3] + let entry.text = match[4] + elseif a:line =~# '^git: \|^usage: \|^error: \|^fatal: ' + return {'text': a:line} else - return fugitive#CompleteObject(a:A, s:Dir()) + let entry.module = matchstr(a:line, '\CBinary file \zs.*\ze matches$') + if len(entry.module) + let entry.text = 'Binary file' + let entry.valid = 0 + endif + endif + if empty(entry.module) && a:name_only + let entry.module = a:line + endif + if empty(entry.module) + return {'text': a:line} + endif + if entry.module !~# ':' + let entry.filename = a:prefix . entry.module + else + let entry.filename = fugitive#Find(entry.module, a:dir) + endif + return entry +endfunction + +function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort + let dir = s:Dir() + exe s:DirCheck(dir) + let listnr = a:line1 == 0 ? a:line1 : a:line2 + let cmd = ['--no-pager', 'grep', '-n', '--no-color', '--full-name'] + if fugitive#GitVersion(2, 19) + call add(cmd, '--column') + endif + let tree = s:Tree(dir) + if type(a:args) == type([]) + let [args, after] = [a:args, ''] + else + let [args, after] = s:SplitExpandChain(a:args, tree) + endif + let prefix = FugitiveVimPath(s:HasOpt(args, '--cached') || empty(tree) ? 'fugitive://' . dir . '//0/' : tree . '/') + let name_only = s:HasOpt(args, '-l', '--files-with-matches', '--name-only', '-L', '--files-without-match') + let title = [listnr < 0 ? ':Ggrep' : ':Glgrep'] + args + if listnr > 0 + exe listnr 'wincmd w' + else + call s:BlurStatus() + endif + redraw + call s:QuickfixCreate(listnr, {'title': (listnr < 0 ? ':Ggrep ' : ':Glgrep ') . s:fnameescape(args)}) + let tempfile = tempname() + if v:version >= 704 | exe 'silent doautocmd <nomodeline> QuickFixCmdPre ' (listnr < 0 ? 'Ggrep' : 'Glgrep') | endif + exe '!' . escape(s:UserCommand(dir, cmd + args), '%#!') + \ printf(&shellpipe . (&shellpipe =~# '%s' ? '' : ' %s'), s:shellesc(tempfile)) + let list = map(readfile(tempfile), 's:GrepParseLine(prefix, name_only, dir, v:val)') + call s:QuickfixSet(listnr, list, 'a') + if v:version >= 704 | exe 'silent doautocmd <nomodeline> QuickFixCmdPost ' (listnr < 0 ? 'Ggrep' : 'Glgrep') | endif + if !has('gui_running') + redraw + endif + if !a:bang && !empty(list) + return (listnr < 0 ? 'c' : 'l').'first' . after + else + return after[1:-1] endif endfunction -call s:command("-bang -nargs=? -complete=customlist,s:GrepComplete Ggrep :execute s:Grep('grep',<bang>0,<q-args>)") -call s:command("-bang -nargs=? -complete=customlist,s:GrepComplete Glgrep :execute s:Grep('lgrep',<bang>0,<q-args>)") -call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:GrepComplete Glog :call s:Log('grep',<bang>0,<line1>,<count>,<q-args>)") -call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:GrepComplete Gllog :call s:Log('lgrep',<bang>0,<line1>,<count>,<q-args>)") - -function! s:Grep(cmd,bang,arg) abort - let grepprg = &grepprg - let grepformat = &grepformat - try - let cdback = s:Cd(s:Tree()) - let &grepprg = s:UserCommand() . ' --no-pager grep -n --no-color' - let &grepformat = '%f:%l:%c:%m,%f:%l:%m,%m %f match%ts,%f' - if fugitive#GitVersion(2, 19) - let &grepprg .= ' --column' - endif - exe a:cmd.'! '.escape(s:ShellExpand(matchstr(a:arg, '\v\C.{-}%($|[''" ]\@=\|)@=')), '|#%') - let list = a:cmd =~# '^l' ? getloclist(0) : getqflist() - for entry in list - if bufname(entry.bufnr) =~ ':' - let entry.filename = s:Generate(bufname(entry.bufnr)) - unlet! entry.bufnr - let changed = 1 - elseif a:arg =~# '\%(^\| \)--cached\>' - let entry.filename = s:Generate(':0:'.bufname(entry.bufnr)) - unlet! entry.bufnr - let changed = 1 - endif - endfor - if a:cmd =~# '^l' && exists('changed') - call setloclist(0, list, 'r') - elseif exists('changed') - call setqflist(list, 'r') - endif - if !a:bang && !empty(list) - return (a:cmd =~# '^l' ? 'l' : 'c').'first'.matchstr(a:arg,'\v\C[''" ]\zs\|.*') - else - return matchstr(a:arg,'\v\C[''" ]\|\zs.*') - endif - finally - let &grepprg = grepprg - let &grepformat = grepformat - execute cdback - endtry +function! s:LogFlushQueue(state) abort + let queue = remove(a:state, 'queue') + if a:state.child_found + call remove(queue, 0) + endif + if len(queue) && queue[-1] ==# {'text': ''} + call remove(queue, -1) + endif + return queue endfunction -function! s:Log(cmd, bang, line1, line2, ...) abort - let args = ' ' . join(a:000, ' ') - let before = substitute(args, ' --\S\@!.*', '', '') - let after = strpart(args, len(before)) - let path = s:Relative('/') - let relative = path[1:-1] - if path =~# '^/\.git\%(/\|$\)' || len(after) +function! s:LogParse(state, dir, line) abort + if a:state.context ==# 'hunk' && a:line =~# '^[-+ ]' + return [] + endif + let list = matchlist(a:line, '^\%(fugitive \(.\{-\}\)\t\|commit \|From \)\=\(\x\{40,\}\)\%( \(.*\)\)\=$') + if len(list) + let a:state.context = 'commit' + let a:state.base = 'fugitive://' . a:dir . '//' . list[2] + let a:state.base_module = len(list[1]) ? list[1] : list[2] + let a:state.message = list[3] + if has_key(a:state, 'diffing') + call remove(a:state, 'diffing') + endif + let queue = s:LogFlushQueue(a:state) + let a:state.queue = [{ + \ 'valid': 1, + \ 'filename': a:state.base . a:state.target, + \ 'module': a:state.base_module . substitute(a:state.target, '^/', ':', ''), + \ 'text': a:state.message}] + let a:state.child_found = 0 + return queue + elseif type(a:line) == type(0) + return s:LogFlushQueue(a:state) + elseif a:line =~# '^diff' + let a:state.context = 'diffhead' + elseif a:line =~# '^[+-]\{3\} \w/' && a:state.context ==# 'diffhead' + let a:state.diffing = a:line[5:-1] + elseif a:line =~# '^@@[^@]*+\d' && has_key(a:state, 'diffing') && has_key(a:state, 'base') + let a:state.context = 'hunk' + if empty(a:state.target) || a:state.target ==# a:state.diffing + let a:state.child_found = 1 + call add(a:state.queue, { + \ 'valid': 1, + \ 'filename': a:state.base . a:state.diffing, + \ 'module': a:state.base_module . substitute(a:state.diffing, '^/', ':', ''), + \ 'lnum': +matchstr(a:line, '+\zs\d\+'), + \ 'text': a:state.message . matchstr(a:line, ' @@\+ .\+')}) + endif + elseif a:state.follow && + \ a:line =~# '^ \%(mode change \d\|\%(create\|delete\) mode \d\|\%(rename\|copy\|rewrite\) .* (\d\+%)$\)' + let rename = matchstr(a:line, '^ rename \zs.* => .*\ze (\d\+%)$') + if len(rename) + let rename = rename =~# '{.* => .*}' ? rename : '{' . rename . '}' + if a:state.target ==# simplify('/' . substitute(rename, '{.* => \(.*\)}', '\1', '')) + let a:state.target = simplify('/' . substitute(rename, '{\(.*\) => .*}', '\1', '')) + endif + endif + if !get(a:state, 'ignore_summary') + call add(a:state.queue, {'text': a:line}) + endif + elseif a:state.context ==# 'commit' || a:state.context ==# 'init' + call add(a:state.queue, {'text': a:line}) + endif + return [] +endfunction + +function! s:Log(type, bang, line1, count, args, legacy) abort + let dir = s:Dir() + exe s:DirCheck(dir) + let listnr = a:type =~# '^l' ? 0 : -1 + let [args, after] = s:SplitExpandChain(a:args, s:Tree(dir)) + let split = index(args, '--') + if split > 0 + let paths = args[split : -1] + let args = args[0 : split - 1] + elseif split == 0 + let paths = args + let args = [] + else + let paths = [] + endif + if a:line1 == 0 && a:count + let path = fugitive#Path(bufname(a:count), '/', dir) + elseif a:count >= 0 + let path = fugitive#Path(@%, '/', dir) + else + let path = '' + endif + let range = '' + let extra = [] + let state = {'context': 'init', 'child_found': 0, 'queue': [], 'follow': 0} + if path =~# '^/\.git\%(/\|$\)\|^$' + let path = '' + elseif a:line1 == 0 + let range = "0," . (a:count ? a:count : bufnr('')) + let extra = ['.' . path] + if (empty(paths) || paths ==# ['--']) && !s:HasOpt(args, '--no-follow') + let state.follow = 1 + if !s:HasOpt(args, '--follow') + call insert(args, '--follow') + endif + if !s:HasOpt(args, '--summary') + call insert(args, '--summary') + let state.ignore_summary = 1 + endif + endif + elseif a:count > 0 + if !s:HasOpt(args, '--merges', '--no-merges') + call insert(args, '--no-merges') + endif + call add(args, '-L' . a:line1 . ',' . a:count . ':' . path[1:-1]) + endif + if len(path) && empty(filter(copy(args), 'v:val =~# "^[^-]"')) + let owner = s:Owner(@%, dir) + if len(owner) + call add(args, owner) + endif + endif + if empty(extra) let path = '' endif - if before !~# '\s[^[:space:]-]' - let owner = s:Owner(@%) - if len(owner) - let before .= ' ' . s:shellesc(owner) - endif + if s:HasOpt(args, '-g', '--walk-reflogs') + let format = "%gd\t%H %gs" + else + let format = "%h\t%H " . g:fugitive_summary_format endif - if relative =~# '^\.git\%(/\|$\)' - let relative = '' + let cmd = ['--no-pager'] + if fugitive#GitVersion(1, 9) + call extend(cmd, ['-c', 'diff.context=0', '-c', 'diff.noprefix=false', 'log']) + else + call extend(cmd, ['log', '-U0', '--no-patch']) endif - if len(relative) && a:line2 > 0 - let before .= ' -L ' . s:shellesc(a:line1 . ',' . a:line2 . ':' . relative) - elseif len(relative) && (empty(after) || a:line2 == 0) - let after = (len(after) > 3 ? after : ' -- ') . relative + call extend(cmd, + \ ['--no-color', '--no-ext-diff', '--pretty=format:fugitive ' . format] + + \ args + paths + extra) + let state.target = path + let title = (listnr < 0 ? ':Gclog ' : ':Gllog ') . s:fnameescape(args + paths) + if empty(paths + extra) && a:legacy && len(s:Relative('/')) + let after = '|echohl WarningMsg|echo ' . string('Use :0Glog or :0Gclog for old behavior of targeting current file') . '|echohl NONE' . after endif - let grepformat = &grepformat - let grepprg = &grepprg - try - let cdback = s:Cd(s:Tree()) - let format = before =~# ' -g\| --walk-reflogs' ? '%gD %gs' : g:fugitive_summary_format - let &grepprg = escape(s:UserCommand() . ' --no-pager log --no-color ' . - \ s:shellesc('--pretty=format:fugitive://'.s:Dir().'//%H'.path.'::'.format), '%#') - let &grepformat = '%Cdiff %.%#,%C--- %.%#,%C+++ %.%#,%Z@@ -%\d%\+\,%\d%\+ +%l\,%\d%\+ @@,%-G-%.%#,%-G+%.%#,%-G %.%#,%A%f::%m,%-G%.%#' - exe a:cmd . (a:bang ? '! ' : ' ') . s:ShellExpand(before . after) - if len(path) && a:line2 == -1 - redraw - echohl WarningMsg - echo ':Glog will soon default to all files. Use :0Glog to target current file' - echohl NONE - endif - finally - let &grepformat = grepformat - let &grepprg = grepprg - execute cdback - endtry + return s:QuickfixStream(listnr, title, s:UserCommandList(dir) + cmd, !a:bang, s:function('s:LogParse'), state, dir) . after endfunction +call s:command("-bang -nargs=? -range=-1 -addr=windows -complete=customlist,s:GrepComplete Ggrep", "grep") +call s:command("-bang -nargs=? -complete=customlist,s:GrepComplete Gcgrep :execute s:GrepSubcommand(-1, -1, 0, <bang>0, '<mods>', <q-args>)") +call s:command("-bang -nargs=? -complete=customlist,s:GrepComplete Glgrep :execute s:GrepSubcommand(0, 0, 0, <bang>0, '<mods>', <q-args>)") +call s:command("-bang -nargs=? -range=-1 -addr=other -complete=customlist,s:LogComplete Glog :exe s:Log('c',<bang>0,<line1>,<count>,<q-args>, 1)") +call s:command("-bang -nargs=? -range=-1 -addr=other -complete=customlist,s:LogComplete Gclog :exe s:Log('c',<bang>0,<line1>,<count>,<q-args>, 0)") +call s:command("-bang -nargs=? -range=-1 -addr=other -complete=customlist,s:LogComplete Gllog :exe s:Log('l',<bang>0,<line1>,<count>,<q-args>, 0)") + " Section: :Gedit, :Gpedit, :Gsplit, :Gvsplit, :Gtabedit, :Gread function! s:UsableWin(nr) abort - return a:nr && !getwinvar(a:nr, '&previewwindow') && + return a:nr && !getwinvar(a:nr, '&previewwindow') && !getwinvar(a:nr, '&winfixwidth') && \ (empty(getwinvar(a:nr, 'fugitive_status')) || getbufvar(winbufnr(a:nr), 'fugitive_type') !=# 'index') && \ index(['gitrebase', 'gitcommit'], getbufvar(winbufnr(a:nr), '&filetype')) < 0 && \ index(['nofile','help','quickfix'], getbufvar(winbufnr(a:nr), '&buftype')) < 0 @@ -3123,6 +3946,20 @@ function! s:OpenParse(args) abort return [s:Expand(file), join(pre)] endfunction +function! s:DiffClose() abort + let mywinnr = winnr() + for winnr in [winnr('#')] + range(winnr('$'),1,-1) + if winnr != mywinnr && getwinvar(winnr,'&diff') + execute winnr.'wincmd w' + close + if winnr('$') > 1 + wincmd p + endif + endif + endfor + diffoff! +endfunction + function! s:BlurStatus() abort if (&previewwindow || exists('w:fugitive_status')) && get(b:,'fugitive_type', '') ==# 'index' let winnrs = filter([winnr('#')] + range(1, winnr('$')), 's:UsableWin(v:val)') @@ -3132,50 +3969,53 @@ function! s:BlurStatus() abort belowright new endif if &diff - let mywinnr = winnr() - for winnr in range(winnr('$'),1,-1) - if winnr != mywinnr && getwinvar(winnr,'&diff') - execute winnr.'wincmd w' - close - if winnr('$') > 1 - wincmd p - endif - endif - endfor - diffoff! + call s:DiffClose() endif endif endfunction -function! s:Open(cmd, bang, mods, arg, args) abort - let mods = a:mods ==# '<mods>' ? '' : a:mods - - if a:bang - let temp = tempname() - try - let cdback = s:Cd(s:Tree()) - let git = s:UserCommand() - let args = s:ShellExpand(a:arg) - silent! execute '!' . escape(git . ' --no-pager ' . args, '!#%') . - \ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1') - finally - execute cdback - endtry - let temp = s:Resolve(temp) - let s:temp_files[s:cpath(temp)] = { 'dir': s:Dir(), 'filetype': 'git' } - if a:cmd ==# 'edit' - call s:BlurStatus() - endif - silent execute mods a:cmd temp - call fugitive#ReloadStatus() - return 'redraw|echo ' . string(':!' . git . ' ' . args) +function! s:OpenExec(cmd, mods, args, ...) abort + let dir = a:0 ? s:Dir(a:1) : s:Dir() + let temp = tempname() + let columns = get(g:, 'fugitive_columns', 80) + if columns <= 0 + let env = '' + elseif s:winshell() + let env = 'set COLUMNS=' . columns . '& ' + else + let env = 'env COLUMNS=' . columns . ' ' endif + silent! execute '!' . escape(env . s:UserCommand(dir, ['--no-pager'] + a:args), '!#%') . + \ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1') + redraw! + let temp = s:Resolve(temp) + let first = join(readfile(temp, '', 2), "\n") + if first =~# '\<\([[:upper:][:digit:]_-]\+(\d\+)\).*\1' + let filetype = 'man' + else + let filetype = 'git' + endif + let s:temp_files[s:cpath(temp)] = { 'dir': dir, 'filetype': filetype, 'modifiable': first =~# '^diff ' } + if a:cmd ==# 'edit' + call s:BlurStatus() + endif + silent execute s:Mods(a:mods) . a:cmd temp + call fugitive#ReloadStatus(dir, 1) + return 'echo ' . string(':!' . s:UserCommand(dir, a:args)) +endfunction - let [file, pre] = s:OpenParse(a:args) +function! s:Open(cmd, bang, mods, arg, args) abort + if a:bang + return s:OpenExec(a:cmd, a:mods, s:SplitExpand(a:arg, s:Tree())) + endif + exe s:DirCheck() + + let mods = s:Mods(a:mods) try + let [file, pre] = s:OpenParse(a:args) let file = s:Generate(file) catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry if file !~# '^\a\a\+:' let file = s:sub(file, '/$', '') @@ -3183,46 +4023,42 @@ function! s:Open(cmd, bang, mods, arg, args) abort if a:cmd ==# 'edit' call s:BlurStatus() endif - return mods . ' ' . a:cmd . pre . ' ' . s:fnameescape(file) + return mods . a:cmd . pre . ' ' . s:fnameescape(file) endfunction function! s:ReadCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort - let mods = a:mods ==# '<mods>' ? '' : a:mods - let after = a:line2 + let mods = s:Mods(a:mods) + let after = a:count if a:count < 0 let delete = 'silent 1,' . line('$') . 'delete_|' let after = line('$') elseif a:range == 2 - let delete = 'silent ' . a:line1 . ',' . a:line2 . 'delete_|' + let delete = 'silent ' . a:line1 . ',' . a:count . 'delete_|' else let delete = '' endif if a:bang - try - let cdback = s:Cd(s:Tree()) - let git = s:UserCommand() - let args = s:ShellExpand(a:arg) - silent execute mods after.'read!' escape(git . ' --no-pager ' . args, '!#%') - finally - execute cdback - endtry + let dir = s:Dir() + let args = s:SplitExpand(a:arg, s:Tree(dir)) + silent execute mods . after . 'read!' escape(s:UserCommand(dir, ['--no-pager'] + args), '!#%') execute delete . 'diffupdate' call fugitive#ReloadStatus() - return 'redraw|echo '.string(':!'.git.' '.args) + return 'redraw|echo '.string(':!'.s:UserCommand(dir, args)) endif - let [file, pre] = s:OpenParse(a:args) + exe s:DirCheck() try + let [file, pre] = s:OpenParse(a:args) let file = s:Generate(file) catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry if file =~# '^fugitive:' && after is# 0 - return 'exe ' .string(mods . ' ' . fugitive#FileReadCmd(file, 0, pre)) . '|diffupdate' + return 'exe ' .string(mods . fugitive#FileReadCmd(file, 0, pre)) . '|diffupdate' endif if foldlevel(after) exe after . 'foldopen!' endif - return mods . ' ' . after . 'read' . pre . ' ' . s:fnameescape(file) . '|' . delete . 'diffupdate' . (a:count < 0 ? '|' . line('.') : '') + return mods . after . 'read' . pre . ' ' . s:fnameescape(file) . '|' . delete . 'diffupdate' . (a:count < 0 ? '|' . line('.') : '') endfunction function! s:ReadComplete(A,L,P) abort @@ -3238,7 +4074,7 @@ call s:command("-bar -bang -nargs=* -complete=customlist,fugitive#Comp call s:command("-bar -bang -nargs=* -complete=customlist,s:ReadComplete Gpedit execute s:Open('pedit', <bang>0, '<mods>', <q-args>, [<f-args>])") call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:ReadComplete Gsplit execute s:Open((<count> > 0 ? <count> : '').(<count> ? 'split' : 'edit'), <bang>0, '<mods>', <q-args>, [<f-args>])") call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:ReadComplete Gvsplit execute s:Open((<count> > 0 ? <count> : '').(<count> ? 'vsplit' : 'edit!'), <bang>0, '<mods>', <q-args>, [<f-args>])") -call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:ReadComplete" . (has('patch-7.4.542') ? ' -addr=tabs' : '') . " Gtabedit execute s:Open((<count> >= 0 ? <count> : '').'tabedit', <bang>0, '<mods>', <q-args>, [<f-args>])") +call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:ReadComplete -addr=tabs Gtabedit execute s:Open((<count> >= 0 ? <count> : '').'tabedit', <bang>0, '<mods>', <q-args>, [<f-args>])") call s:command("-bar -bang -nargs=* -range=-1 -complete=customlist,s:ReadComplete Gread", "Read") " Section: :Gwrite, :Gwq @@ -3248,6 +4084,7 @@ call s:command("-bar -bang -nargs=* -complete=customlist,fugitive#CompleteObject call s:command("-bar -bang -nargs=* -complete=customlist,fugitive#CompleteObject Gwq", "Wq") function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort + exe s:DirCheck() if exists('b:fugitive_commit_arguments') return 'write|bdelete' elseif expand('%:t') == 'COMMIT_EDITMSG' && $GIT_INDEX_FILE != '' @@ -3260,13 +4097,15 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) silent write setlocal buftype=nowrite if matchstr(getline(2),'index [[:xdigit:]]\+\.\.\zs[[:xdigit:]]\{7\}') ==# fugitive#RevParse(':0:'.filename)[0:6] - let err = s:TreeChomp('apply', '--cached', '--reverse', '--', expand('%:p')) + let [message, exec_error] = s:ChompError(['apply', '--cached', '--reverse', '--', expand('%:p')]) else - let err = s:TreeChomp('apply', '--cached', '--', expand('%:p')) + let [message, exec_error] = s:ChompError(['apply', '--cached', '--', expand('%:p')]) endif - if err !=# '' - let v:errmsg = split(err,"\n")[0] - return 'echoerr v:errmsg' + if exec_error + echohl ErrorMsg + echo message + echohl NONE + return '' elseif a:bang return 'bdelete' else @@ -3275,14 +4114,18 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) endif let mytab = tabpagenr() let mybufnr = bufnr('') - let file = len(a:args) ? s:Generate(s:Expand(join(a:args, ' '))) : fugitive#Real(@%) + try + let file = len(a:args) ? s:Generate(s:Expand(join(a:args, ' '))) : fugitive#Real(@%) + catch /^fugitive:/ + return 'echoerr ' . string(v:exception) + endtry if empty(file) return 'echoerr '.string('fugitive: cannot determine file path') endif if file =~# '^fugitive:' return 'write' . (a:bang ? '! ' : ' ') . s:fnameescape(file) endif - let always_permitted = s:cpath(fugitive#Real(@%), file) && s:DirCommitFile(@%)[1] =~# '^0\=$' + let always_permitted = s:cpath(fugitive#Real(@%), file) && empty(s:DirCommitFile(@%)[1]) if !always_permitted && !a:bang && (len(s:TreeChomp('diff', '--name-status', 'HEAD', '--', file)) || len(s:TreeChomp('ls-files', '--others', '--', file))) let v:errmsg = 'fugitive: file has uncommitted changes (use ! to override)' return 'echoerr v:errmsg' @@ -3296,7 +4139,7 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) if treebufnr > 0 && treebufnr != bufnr('') let temp = tempname() - silent execute '%write '.temp + silent execute 'keepalt %write '.temp for tab in [mytab] + range(1,tabpagenr('$')) for winnr in range(1,tabpagewinnr(tab,'$')) if tabpagebuflist(tab)[winnr-1] == treebufnr @@ -3312,6 +4155,7 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) silent execute '1,'.last.'delete_' silent write! silent execute lnum + diffupdate let did = 1 finally if exists('restorewinnr') @@ -3319,6 +4163,7 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) endif execute 'tabnext '.mytab endtry + break endif endfor endfor @@ -3330,11 +4175,11 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) endif if a:bang - let error = s:TreeChomp('add', '--force', '--', file) + let [error, exec_error] = s:ChompError(['add', '--force', '--', file]) else - let error = s:TreeChomp('add', '--', file) + let [error, exec_error] = s:ChompError(['add', '--', file]) endif - if v:shell_error + if exec_error let v:errmsg = 'fugitive: '.error return 'echoerr v:errmsg' endif @@ -3354,7 +4199,7 @@ function! s:WriteCommand(line1, line2, range, count, bang, mods, reg, arg, args) unlet! restorewinnr let zero = s:Generate(':0:'.file) - silent execute 'doautocmd BufWritePost' s:fnameescape(zero) + silent execute 'doautocmd' s:nomodeline 'BufWritePost' s:fnameescape(zero) for tab in range(1,tabpagenr('$')) for winnr in range(1,tabpagewinnr(tab,'$')) let bufnr = tabpagebuflist(tab)[winnr-1] @@ -3402,41 +4247,76 @@ endfunction augroup fugitive_commit autocmd! - autocmd VimLeavePre,BufDelete COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE') + autocmd VimLeavePre,BufDelete COMMIT_EDITMSG execute substitute(s:FinishCommit(), '\C^echoerr \(''[^'']*''\)*', 'redraw|echohl ErrorMsg|echo \1|echohl NONE', '') augroup END " Section: :Gpush, :Gfetch -call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpush execute s:Dispatch('<bang>', 'push '.<q-args>)") -call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gfetch execute s:Dispatch('<bang>', 'fetch '.<q-args>)") +function! s:PushComplete(A, L, P) abort + return s:CompleteSub('push', a:A, a:L, a:P, function('s:CompleteRemote')) +endfunction -function! s:Dispatch(bang, args) +function! s:FetchComplete(A, L, P) abort + return s:CompleteSub('fetch', a:A, a:L, a:P, function('s:CompleteRemote')) +endfunction + +function! s:AskPassArgs(dir) abort + if (len($DISPLAY) || len($TERM_PROGRAM) || has('gui_running')) && fugitive#GitVersion(1, 8) && + \ empty($GIT_ASKPASS) && empty($SSH_ASKPASS) && empty(fugitive#Config('core.askPass', a:dir)) + if s:executable(s:ExecPath() . '/git-gui--askpass') + return ['-c', 'core.askPass=' . s:ExecPath() . '/git-gui--askpass'] + elseif s:executable('ssh-askpass') + return ['-c', 'core.askPass=ssh-askpass'] + endif + endif + return [] +endfunction + +function! s:Dispatch(bang, cmd, args) abort + let dir = s:Dir() let [mp, efm, cc] = [&l:mp, &l:efm, get(b:, 'current_compiler', '')] try - let cdback = s:Cd(s:Tree()) let b:current_compiler = 'git' let &l:errorformat = s:common_efm - let &l:makeprg = substitute(s:UserCommand() . ' ' . a:args, '\s\+$', '', '') + let &l:makeprg = s:UserCommand(dir, s:AskPassArgs(dir) + [a:cmd] + a:args) if exists(':Make') == 2 Make + return '' else + if !has('patch-8.1.0334') && has('terminal') && &autowrite + let autowrite_was_set = 1 + set noautowrite + silent! wall + endif silent noautocmd make! redraw! return 'call fugitive#Cwindow()|call fugitive#ReloadStatus()' endif - return '' finally let [&l:mp, &l:efm, b:current_compiler] = [mp, efm, cc] if empty(cc) | unlet! b:current_compiler | endif - execute cdback + if exists('autowrite_was_set') + set autowrite + endif endtry endfunction +function! s:PushSubcommand(line1, line2, range, bang, mods, args) abort + return s:Dispatch(a:bang ? '!' : '', 'push', a:args) +endfunction + +function! s:FetchSubcommand(line1, line2, range, bang, mods, args) abort + return s:Dispatch(a:bang ? '!' : '', 'fetch', a:args) +endfunction + +call s:command("-nargs=? -bang -complete=customlist,s:PushComplete Gpush", "push") +call s:command("-nargs=? -bang -complete=customlist,s:FetchComplete Gfetch", "fetch") + " Section: :Gdiff -call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Gdiff :execute s:Diff('',<bang>0,<f-args>)") -call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Gvdiff :execute s:Diff('keepalt vert ',<bang>0,<f-args>)") -call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Gsdiff :execute s:Diff('keepalt ',<bang>0,<f-args>)") +call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Gdiffsplit :execute s:Diff(1, <bang>0, '<mods>', <f-args>)") +call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Gvdiffsplit :execute s:Diff(0, <bang>0, 'vertical <mods>', <f-args>)") +call s:command("-bang -bar -nargs=* -complete=customlist,fugitive#CompleteObject Ghdiffsplit :execute s:Diff(0, <bang>0, '<mods>', <f-args>)") augroup fugitive_diff autocmd! @@ -3463,13 +4343,13 @@ endfunction function! s:diff_modifier(count) abort let fdc = matchstr(&diffopt, 'foldcolumn:\zs\d\+') if &diffopt =~# 'horizontal' && &diffopt !~# 'vertical' - return 'keepalt ' + return '' elseif &diffopt =~# 'vertical' - return 'keepalt vert ' + return 'vertical ' elseif winwidth(0) <= a:count * ((&tw ? &tw : 80) + (empty(fdc) ? 2 : fdc)) - return 'keepalt ' + return '' else - return 'keepalt vert ' + return 'vertical ' endif endfunction @@ -3550,85 +4430,124 @@ function! s:CompareAge(mine, theirs) abort return my_time < their_time ? -1 : my_time != their_time endfunction -function! s:Diff(vert,keepfocus,...) abort +function! s:IsConflicted() abort + return len(@%) && !empty(s:ChompDefault('', 'ls-files', '--unmerged', '--', expand('%:p'))) +endfunction + +function! s:Diff(autodir, keepfocus, mods, ...) abort + if exists(':DiffGitCached') && !a:0 + return s:Mods(a:mods) . 'DiffGitCached' + endif + exe s:DirCheck() let args = copy(a:000) let post = '' if get(args, 0) =~# '^+' let post = remove(args, 0)[1:-1] endif - let vert = empty(a:vert) ? s:diff_modifier(2) : a:vert let commit = s:DirCommitFile(@%)[1] - let back = exists('*win_getid') ? 'call win_gotoid(' . win_getid() . ')' : 'wincmd p' - if exists(':DiffGitCached') - return 'DiffGitCached' - elseif (empty(args) || args[0] ==# ':') && commit =~# '^[0-1]\=$' && !empty(s:TreeChomp('ls-files', '--unmerged', '--', expand('%:p'))) - if v:shell_error - return 'echoerr ' . string("fugitive: error determining merge status of the current buffer") - endif - let vert = empty(a:vert) ? s:diff_modifier(3) : a:vert - let nr = bufnr('') - execute 'leftabove '.vert.'split' s:fnameescape(s:Generate(s:Relative(':2:'))) - execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>' - let nr2 = bufnr('') - call s:diffthis() - exe back - execute 'rightbelow '.vert.'split' s:fnameescape(s:Generate(s:Relative(':3:'))) - execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>' - let nr3 = bufnr('') - call s:diffthis() - exe back - call s:diffthis() - execute 'nnoremap <buffer> <silent> d2o :diffget '.nr2.'<Bar>diffupdate<CR>' - execute 'nnoremap <buffer> <silent> d3o :diffget '.nr3.'<Bar>diffupdate<CR>' - return post - elseif len(args) - let arg = join(args, ' ') - if arg ==# '' - return post - elseif arg ==# '/' - let file = s:Relative() - elseif arg ==# ':' - let file = s:Relative(':0:') - elseif arg =~# '^:/.' - try - let file = fugitive#RevParse(arg).s:Relative(':') - catch /^fugitive:/ - return 'echoerr v:errmsg' - endtry - else - let file = s:Expand(arg) - endif - if file !~# ':' && file !~# '^/' && s:TreeChomp('cat-file','-t',file) =~# '^\%(tag\|commit\)$' - let file = file.s:Relative(':') - endif + if a:mods =~# '\<tab\>' + let mods = substitute(a:mods, '\<tab\>', '', 'g') + tab split else - let file = empty(commit) ? s:Relative(':0:') : s:Relative() + let mods = 'keepalt ' . a:mods + endif + let back = exists('*win_getid') ? 'call win_gotoid(' . win_getid() . ')' : 'wincmd p' + if (empty(args) || args[0] ==# ':') && a:keepfocus + if empty(commit) && s:IsConflicted() + let parents = [s:Relative(':2:'), s:Relative(':3:')] + elseif empty(commit) + let parents = [s:Relative(':0:')] + elseif commit =~# '^\d\=$' + let parents = [s:Relative('HEAD:')] + elseif commit =~# '^\x\x\+$' + let parents = s:LinesError(['rev-parse', commit . '^@'])[0] + call map(parents, 's:Relative(v:val . ":")') + endif endif try - let spec = s:Generate(file) - let restore = s:diff_restore() - if exists('+cursorbind') - setlocal cursorbind + if exists('parents') && len(parents) > 1 + let mods = (a:autodir ? s:diff_modifier(len(parents) + 1) : '') . s:Mods(mods, 'leftabove') + let nr = bufnr('') + execute mods 'split' s:fnameescape(s:Generate(parents[0])) + call s:Map('n', 'dp', ':diffput '.nr.'<Bar>diffupdate<CR>', '<silent>') + let nr2 = bufnr('') + call s:diffthis() + exe back + call s:Map('n', 'd2o', ':diffget '.nr2.'<Bar>diffupdate<CR>', '<silent>') + let mods = substitute(mods, '\Cleftabove\|rightbelow\|aboveleft\|belowright', '\=submatch(0) =~# "f" ? "rightbelow" : "leftabove"', '') + for i in range(len(parents)-1, 1, -1) + execute mods 'split' s:fnameescape(s:Generate(parents[i])) + call s:Map('n', 'dp', ':diffput '.nr.'<Bar>diffupdate<CR>', '<silent>') + let nrx = bufnr('') + call s:diffthis() + exe back + call s:Map('n', 'd' . (i + 2) . 'o', ':diffget '.nrx.'<Bar>diffupdate<CR>', '<silent>') + endfor + call s:diffthis() + if len(parents) > 1 + wincmd = + endif + return post + elseif len(args) + let arg = join(args, ' ') + if arg ==# '' + return post + elseif arg ==# '/' + let file = s:Relative() + elseif arg ==# ':' + let file = s:Relative(':0:') + elseif arg =~# '^:\d$' + let file = s:Relative(arg . ':') + else + try + let file = arg =~# '^:/.' ? fugitive#RevParse(arg) . s:Relative(':') : s:Expand(arg) + catch /^fugitive:/ + return 'echoerr ' . string(v:exception) + endtry + endif + elseif exists('parents') && len(parents) + let file = parents[-1] + elseif len(commit) + let file = s:Relative() + elseif s:IsConflicted() + let file = s:Relative(':1:') + let post = 'echohl WarningMsg|echo "Use :Gdiffsplit! for 3 way diff"|echohl NONE|' . post + else + let file = s:Relative(':0:') endif + let spec = s:Generate(file) + if spec =~# '^fugitive:' && empty(s:DirCommitFile(spec)[2]) + let spec = FugitiveVimPath(spec . s:Relative('/')) + endif + let restore = s:diff_restore() let w:fugitive_diff_restore = restore if s:CompareAge(commit, s:DirCommitFile(spec)[1]) < 0 - execute 'rightbelow '.vert.'diffsplit '.s:fnameescape(spec) + let mods = s:Mods(mods, 'rightbelow') else - execute 'leftabove '.vert.'diffsplit '.s:fnameescape(spec) + let mods = s:Mods(mods, 'leftabove') endif + let mods = (a:autodir ? s:diff_modifier(2) : '') . mods + if &diffopt =~# 'vertical' + let diffopt = &diffopt + set diffopt-=vertical + endif + execute mods 'diffsplit' s:fnameescape(spec) let &l:readonly = &l:readonly redraw let w:fugitive_diff_restore = restore let winnr = winnr() if getwinvar('#', '&diff') - exe back - if !a:keepfocus - call feedkeys(winnr."\<C-W>w", 'n') + if a:keepfocus + exe back endif endif return post catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) + finally + if exists('diffopt') + let &diffopt = diffopt + endif endtry endfunction @@ -3654,8 +4573,8 @@ function! s:Move(force, rename, destination) abort if isdirectory(@%) setlocal noswapfile endif - let message = call('s:TreeChomp', ['mv'] + (a:force ? ['-f'] : []) + ['--', expand('%:p'), destination]) - if v:shell_error + let [message, exec_error] = s:ChompError(['mv'] + (a:force ? ['-f'] : []) + ['--', expand('%:p'), destination]) + if exec_error let v:errmsg = 'fugitive: '.message return 'echoerr v:errmsg' endif @@ -3695,8 +4614,8 @@ function! s:Remove(after, force) abort if a:force let cmd += ['--force'] endif - let message = call('s:TreeChomp', cmd + ['--', expand('%:p')]) - if v:shell_error + let [message, exec_error] = s:ChompError(cmd + ['--', expand('%:p')]) + if exec_error let v:errmsg = 'fugitive: '.s:sub(message,'error:.*\zs\n\(.*-f.*',' (add ! to force)') return 'echoerr '.string(v:errmsg) else @@ -3726,18 +4645,6 @@ function! s:Keywordprg() abort endif endfunction -augroup fugitive_blame - autocmd! - autocmd FileType fugitiveblame setlocal nomodeline | if len(s:Dir()) | let &l:keywordprg = s:Keywordprg() | endif - autocmd Syntax fugitiveblame call s:BlameSyntax() - autocmd User Fugitive - \ if get(b:, 'fugitive_type') =~# '^\%(file\|blob\|blame\)$' || filereadable(@%) | - \ exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:BlameCommand(<line1>,<line2>,+'<range>',<count>,<bang>0,'<mods>',<q-reg>,<q-args>,[<f-args>])" | - \ endif - autocmd ColorScheme,GUIEnter * call s:RehighlightBlame() - autocmd BufWinLeave * execute getwinvar(+bufwinnr(+expand('<abuf>')), 'fugitive_leave') -augroup END - function! s:linechars(pattern) abort let chars = strlen(s:gsub(matchstr(getline('.'), a:pattern), '.', '.')) if exists('*synconcealed') && &conceallevel > 1 @@ -3748,60 +4655,216 @@ function! s:linechars(pattern) abort return chars endfunction -function! s:BlameCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort - if exists('b:fugitive_blamed_bufnr') +function! s:BlameBufnr(...) abort + let state = s:TempState(bufname(a:0 ? a:1 : '')) + if get(state, 'filetype', '') ==# 'fugitiveblame' + return get(state, 'bufnr', -1) + else + return -1 + endif +endfunction + +function! s:BlameCommitFileLnum(...) abort + let line = a:0 ? a:1 : getline('.') + let state = a:0 ? a:2 : s:TempState() + let commit = matchstr(line, '^\^\=\zs\x\+') + if commit =~# '^0\+$' + let commit = '' + elseif line !~# '^\^' && has_key(state, 'blame_reverse_end') + let commit = get(s:LinesError('rev-list', '--ancestry-path', '--reverse', commit . '..' . state.blame_reverse_end)[0], 0, '') + endif + let lnum = +matchstr(line, ' \zs\d\+\ze \%((\| *\d\+)\)') + let path = matchstr(line, '^\^\=\x* \+\%(\d\+ \+\d\+ \+\)\=\zs.\{-\}\ze\s\+\%(\%( \d\+ \)\@<!([^()]*\w \d\+)\|\d\+ \)') + if empty(path) && lnum + let path = get(state, 'blame_file', '') + endif + return [commit, path, lnum] +endfunction + +function! s:BlameLeave() abort + let bufwinnr = bufwinnr(s:BlameBufnr()) + if bufwinnr > 0 + let bufnr = bufnr('') + exe bufwinnr . 'wincmd w' + return bufnr . 'bdelete' + endif + return '' +endfunction + +function! s:BlameQuit() abort + let cmd = s:BlameLeave() + if empty(cmd) return 'bdelete' + elseif len(s:DirCommitFile(@%)[1]) + return cmd . '|Gedit' + else + return cmd + endif +endfunction + +function! s:BlameComplete(A, L, P) abort + return s:CompleteSub('blame', a:A, a:L, a:P) +endfunction + +function! s:BlameSubcommand(line1, count, range, bang, mods, args) abort + exe s:DirCheck() + let flags = copy(a:args) + let i = 0 + let raw = 0 + let commits = [] + let files = [] + let ranges = [] + if a:line1 > 0 && a:count > 0 && a:range != 1 + call extend(ranges, ['-L', a:line1 . ',' . a:count]) + endif + while i < len(flags) + let match = matchlist(flags[i], '^\(-[a-zABDFH-KN-RT-Z]\)\ze\(.*\)') + if len(match) && len(match[2]) + call insert(flags, match[1]) + let flags[i+1] = '-' . match[2] + continue + endif + let arg = flags[i] + if arg =~# '^-p$\|^--\%(help\|porcelain\|line-porcelain\|incremental\)$' + let raw = 1 + elseif arg ==# '--contents' && i + 1 < len(flags) + call extend(commits, remove(flags, i, i+1)) + continue + elseif arg ==# '-L' && i + 1 < len(flags) + call extend(ranges, remove(flags, i, i+1)) + continue + elseif arg =~# '^--contents=' + call add(commits, remove(flags, i)) + continue + elseif arg =~# '^-L.' + call add(ranges, remove(flags, i)) + continue + elseif arg =~# '^-[GLS]$\|^--\%(date\|encoding\|contents\)$' + let i += 1 + if i == len(flags) + echohl ErrorMsg + echo s:ChompError(['blame', arg])[0] + echohl NONE + return '' + endif + elseif arg ==# '--' + if i + 1 < len(flags) + call extend(files, remove(flags, i + 1, -1)) + endif + call remove(flags, i) + break + elseif arg !~# '^-' && (s:HasOpt(flags, '--not') || arg !~# '^\^') + if index(flags, '--') >= 0 + call add(commits, remove(flags, i)) + continue + endif + if arg =~# '\.\.' && arg !~# '^\.\.\=\%(/\|$\)' && empty(commits) + call add(commits, remove(flags, i)) + continue + endif + try + let dcf = s:DirCommitFile(fugitive#Find(arg)) + if len(dcf[1]) && empty(dcf[2]) + call add(commits, remove(flags, i)) + continue + endif + catch /^fugitive:/ + endtry + call add(files, remove(flags, i)) + continue + endif + let i += 1 + endwhile + if empty(ranges + commits + files) && has_key(s:TempState(), 'blame_flags') + return substitute(s:BlameLeave(), '^$', 'bdelete', '') + endif + let file = substitute(get(files, 0, get(s:TempState(), 'blame_file', s:Relative('./'))), '^\.\%(/\|$\)', '', '') + if empty(commits) && len(files) > 1 + call add(commits, remove(files, 1)) endif try - if empty(s:Relative('/')) - call s:throw('file or blob required') + let cmd = ['--no-pager', '-c', 'blame.coloring=none', '-c', 'blame.blankBoundary=false', 'blame', '--show-number'] + call extend(cmd, filter(copy(flags), 'v:val !~# "\\v^%(-b|--%(no-)=color-.*|--progress)$"')) + if a:count > 0 && empty(ranges) + let cmd += ['-L', (a:line1 ? a:line1 : line('.')) . ',' . (a:line1 ? a:line1 : line('.'))] endif - if filter(copy(a:args),'v:val !~# "^\\%(--abbrev=\\d*\\|--relative-date\\|--first-parent\\|--root\\|--show-name\\|-\\=\\%([ltfnsew]\\|[MC]\\d*\\)\\+\\)$"') != [] - call s:throw('unsupported option') - endif - call map(a:args,'s:sub(v:val,"^\\ze[^-]","-")') - let cmd = ['--no-pager', 'blame', '--show-number'] - if a:count - let cmd += ['-L', a:line1 . ',' . a:line1] - endif - let cmd += a:args - if s:DirCommitFile(@%)[1] =~# '\D\|..' - let cmd += [s:DirCommitFile(@%)[1]] - else + call extend(cmd, ranges) + if len(commits) + let cmd += commits + elseif empty(files) && len(matchstr(s:DirCommitFile(@%)[1], '^\x\x\+$')) + let cmd += [matchstr(s:DirCommitFile(@%)[1], '^\x\x\+$')] + elseif empty(files) && !s:HasOpt(flags, '--reverse') let cmd += ['--contents', '-'] endif - let cmd += ['--', expand('%:p')] - let basecmd = escape(fugitive#Prepare(cmd), '!#%') - try - let cdback = s:Cd(s:Tree()) - let error = tempname() - let temp = error.'.fugitiveblame' - if &shell =~# 'csh' - silent! execute '%write !('.basecmd.' > '.temp.') >& '.error - else - silent! execute '%write !'.basecmd.' > '.temp.' 2> '.error - endif - finally - execute cdback - endtry + let basecmd = escape(fugitive#Prepare(cmd) . ' -- ' . s:shellesc(len(files) ? files : file), '!#%') + let tempname = tempname() + let error = tempname . '.err' + let temp = tempname . (raw ? '' : '.fugitiveblame') + if &shell =~# 'csh' + silent! execute '%write !('.basecmd.' > '.temp.') >& '.error + else + silent! execute '%write !'.basecmd.' > '.temp.' 2> '.error + endif + redraw try if v:shell_error - call s:throw(join(readfile(error),"\n")) + let lines = readfile(error) + if empty(lines) + let lines = readfile(temp) + endif + for i in range(len(lines)) + if lines[i] =~# '^error: \|^fatal: ' + echohl ErrorMsg + echon lines[i] + echohl NONE + break + else + echon lines[i] + endif + if i != len(lines) - 1 + echon "\n" + endif + endfor + return '' endif - if a:count - let edit = substitute(a:mods, '^<mods>$', '', '') . get(['edit', 'split', 'pedit'], a:line2 - a:line1, ' split') - return s:BlameCommit(edit, get(readfile(temp), 0, '')) + let temp_state = {'dir': s:Dir(), 'filetype': (raw ? '' : 'fugitiveblame'), 'blame_flags': flags, 'blame_file': file, 'modifiable': 0} + if s:HasOpt(flags, '--reverse') + let temp_state.blame_reverse_end = matchstr(get(commits, 0, ''), '\.\.\zs.*') + endif + if (a:line1 == 0 || a:range == 1) && a:count > 0 + let edit = s:Mods(a:mods) . get(['edit', 'split', 'pedit', 'vsplit', 'tabedit'], a:count - (a:line1 ? a:line1 : 1), 'split') + return s:BlameCommit(edit, get(readfile(temp), 0, ''), temp_state) else + let temp = s:Resolve(temp) + let s:temp_files[s:cpath(temp)] = temp_state + if len(ranges + commits + files) || raw + let mods = s:Mods(a:mods) + if a:count != 0 + exe 'silent keepalt' mods 'split' s:fnameescape(temp) + elseif !&modified || a:bang || &bufhidden ==# 'hide' || (empty(&bufhidden) && &hidden) + exe 'silent' mods 'edit' . (a:bang ? '! ' : ' ') . s:fnameescape(temp) + else + return mods . 'edit ' . s:fnameescape(temp) + endif + return '' + endif + if a:mods =~# '\<tab\>' + silent tabedit % + endif + let mods = substitute(a:mods, '\<tab\>', '', 'g') for winnr in range(winnr('$'),1,-1) - call setwinvar(winnr, '&scrollbind', 0) - if exists('+cursorbind') + if getwinvar(winnr, '&scrollbind') + call setwinvar(winnr, '&scrollbind', 0) + endif + if exists('+cursorbind') && getwinvar(winnr, '&cursorbind') call setwinvar(winnr, '&cursorbind', 0) endif - if getbufvar(winbufnr(winnr), 'fugitive_blamed_bufnr') + if s:BlameBufnr(winbufnr(winnr)) > 0 execute winbufnr(winnr).'bdelete' endif endfor let bufnr = bufnr('') + let temp_state.bufnr = bufnr let restore = 'call setwinvar(bufwinnr('.bufnr.'),"&scrollbind",0)' if exists('+cursorbind') let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&cursorbind",0)' @@ -3818,77 +4881,63 @@ function! s:BlameCommand(line1, line2, range, count, bang, mods, reg, arg, args) endif let top = line('w0') + &scrolloff let current = line('.') - let temp = s:Resolve(temp) - let s:temp_files[s:cpath(temp)] = { 'dir': s:Dir(), 'filetype': 'fugitiveblame', 'args': cmd, 'bufnr': bufnr } - exe 'keepalt leftabove vsplit '.temp - let b:fugitive_blamed_bufnr = bufnr - let b:fugitive_type = 'blame' + exe 'silent keepalt' (a:bang ? s:Mods(mods) . 'split' : s:Mods(mods, 'leftabove') . 'vsplit') s:fnameescape(temp) let w:fugitive_leave = restore - let b:fugitive_blame_arguments = join(a:args,' ') execute top normal! zt execute current if exists('+cursorbind') setlocal cursorbind endif - setlocal nomodified nomodifiable nonumber scrollbind nowrap foldcolumn=0 nofoldenable winfixwidth filetype=fugitiveblame buftype=nowrite - if exists('+concealcursor') - setlocal concealcursor=nc conceallevel=2 - endif + setlocal nonumber scrollbind nowrap foldcolumn=0 nofoldenable winfixwidth if exists('+relativenumber') setlocal norelativenumber endif execute "vertical resize ".(s:linechars('.\{-\}\ze\s\+\d\+)')+1) - let nowait = v:version >= 704 ? '<nowait>' : '' - nnoremap <buffer> <silent> <F1> :help fugitive-:Gblame<CR> - nnoremap <buffer> <silent> g? :help fugitive-:Gblame<CR> - nnoremap <buffer> <silent> q :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w<Bar>'.bufnr('').'bdelete','^-1','','')<CR> - exe 'nnoremap <buffer> <silent>' nowait "gq :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w<Bar>'.bufnr('').'bdelete<Bar>if expand(''%:p'') =~# ''^fugitive:[\\/][\\/]''<Bar>Gedit<Bar>endif','^-1','','')<CR>" - nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>BlameCommit("exe 'norm q'<Bar>edit")<CR> - nnoremap <buffer> <silent> - :<C-U>exe <SID>BlameJump('')<CR> - nnoremap <buffer> <silent> P :<C-U>exe <SID>BlameJump('^'.v:count1)<CR> - nnoremap <buffer> <silent> ~ :<C-U>exe <SID>BlameJump('~'.v:count1)<CR> - nnoremap <buffer> <silent> i :<C-U>exe <SID>BlameCommit("exe 'norm q'<Bar>edit")<CR> - nnoremap <buffer> <silent> o :<C-U>exe <SID>BlameCommit((&splitbelow ? "botright" : "topleft")." split")<CR> - nnoremap <buffer> <silent> O :<C-U>exe <SID>BlameCommit("tabedit")<CR> - nnoremap <buffer> <silent> p :<C-U>exe <SID>Open((&splitbelow ? "botright" : "topleft").' pedit', 0, '', matchstr(getline('.'), '\x\+'), [matchstr(getline('.'), '\x\+')])<CR> - nnoremap <buffer> <silent> A :<C-u>exe "vertical resize ".(<SID>linechars('.\{-\}\ze [0-9:/+-][0-9:/+ -]* \d\+)')+1+v:count)<CR> - nnoremap <buffer> <silent> C :<C-u>exe "vertical resize ".(<SID>linechars('^\S\+')+1+v:count)<CR> - nnoremap <buffer> <silent> D :<C-u>exe "vertical resize ".(<SID>linechars('.\{-\}\ze\d\ze\s\+\d\+)')+1-v:count)<CR> + call s:Map('n', 'A', ":<C-u>exe 'vertical resize '.(<SID>linechars('.\\{-\\}\\ze [0-9:/+-][0-9:/+ -]* \\d\\+)')+1+v:count)<CR>", '<silent>') + call s:Map('n', 'C', ":<C-u>exe 'vertical resize '.(<SID>linechars('^\\S\\+')+1+v:count)<CR>", '<silent>') + call s:Map('n', 'D', ":<C-u>exe 'vertical resize '.(<SID>linechars('.\\{-\\}\\ze\\d\\ze\\s\\+\\d\\+)')+1-v:count)<CR>", '<silent>') redraw syncbind endif endtry return '' catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry endfunction function! s:BlameCommit(cmd, ...) abort let line = a:0 ? a:1 : getline('.') - if line =~# '^0\{4,40\} ' - return 'echoerr ' . string('Not Committed Yet') + let state = a:0 ? a:2 : s:TempState() + let sigil = has_key(state, 'blame_reverse_end') ? '-' : '+' + let mods = (s:BlameBufnr() < 0 ? '' : &splitbelow ? "botright " : "topleft ") + let [commit, path, lnum] = s:BlameCommitFileLnum(line, state) + if empty(commit) && len(path) && has_key(state, 'blame_reverse_end') + let path = (len(state.blame_reverse_end) ? state.blame_reverse_end . ':' : ':(top)') . path + return s:Open(mods . a:cmd, 0, '', '+' . lnum . ' ' . s:fnameescape(path), ['+' . lnum, path]) endif - let cmd = s:Open(a:cmd, 0, '', matchstr(line, '\x\+'), [matchstr(line, '\x\+')]) + if commit =~# '^0*$' + return 'echoerr ' . string('fugitive: no commit') + endif + if line =~# '^\^' && !has_key(state, 'blame_reverse_end') + let path = commit . ':' . path + return s:Open(mods . a:cmd, 0, '', '+' . lnum . ' ' . s:fnameescape(path), ['+' . lnum, path]) + endif + let cmd = s:Open(mods . a:cmd, 0, '', commit, [commit]) if cmd =~# '^echoerr' return cmd endif - let lnum = matchstr(line, ' \zs\d\+\ze\s\+[([:digit:]]') - let path = matchstr(line, '^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') - if path ==# '' - let path = fugitive#Path(a:0 ? @% : bufname(b:fugitive_blamed_bufnr), '') - endif execute cmd - if a:cmd ==# 'pedit' + if a:cmd ==# 'pedit' || empty(path) return '' endif if search('^diff .* b/\M'.escape(path,'\').'$','W') call search('^+++') let head = line('.') while search('^@@ \|^diff ') && getline('.') =~# '^@@ ' - let top = +matchstr(getline('.'),' +\zs\d\+') - let len = +matchstr(getline('.'),' +\d\+,\zs\d\+') + let top = +matchstr(getline('.'),' ' . sigil .'\zs\d\+') + let len = +matchstr(getline('.'),' ' . sigil . '\d\+,\zs\d\+') if lnum >= top && lnum <= top + len let offset = lnum - top if &scrolloff @@ -3900,7 +4949,7 @@ function! s:BlameCommit(cmd, ...) abort endif while offset > 0 && line('.') < line('$') + - if getline('.') =~# '^[ +]' + if getline('.') =~# '^[ ' . sigil . ']' let offset -= 1 endif endwhile @@ -3913,32 +4962,51 @@ function! s:BlameCommit(cmd, ...) abort return '' endfunction -function! s:BlameJump(suffix) abort - let commit = matchstr(getline('.'),'^\^\=\zs\x\+') +function! s:BlameJump(suffix, ...) abort let suffix = a:suffix - if commit =~# '^0\+$' + let [commit, path, lnum] = s:BlameCommitFileLnum() + if empty(path) + return 'echoerr ' . string('fugitive: could not determine filename for blame') + endif + if commit =~# '^0*$' let commit = 'HEAD' let suffix = '' endif - let lnum = matchstr(getline('.'),' \zs\d\+\ze\s\+[([:digit:]]') - let path = matchstr(getline('.'),'^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') - if path ==# '' - let path = fugitive#Path(bufname(b:fugitive_blamed_bufnr), '') - endif - let args = b:fugitive_blame_arguments let offset = line('.') - line('w0') - let bufnr = bufnr('%') - let winnr = bufwinnr(b:fugitive_blamed_bufnr) - if winnr > 0 - exe winnr.'wincmd w' + let flags = get(s:TempState(), 'blame_flags', []) + if a:0 && a:1 + if s:HasOpt(flags, '--reverse') + call remove(flags, '--reverse') + else + call add(flags, '--reverse') + endif endif - execute 'Gedit' s:fnameescape(commit . suffix . ':' . path) - execute lnum - if winnr > 0 - exe bufnr.'bdelete' + let blame_bufnr = s:BlameBufnr() + if blame_bufnr > 0 + let bufnr = bufnr('') + let winnr = bufwinnr(blame_bufnr) + if winnr > 0 + exe winnr.'wincmd w' + endif + execute 'Gedit' s:fnameescape(commit . suffix . ':' . path) + execute lnum + if winnr > 0 + exe bufnr.'bdelete' + endif endif if exists(':Gblame') - execute 'Gblame '.args + let my_bufnr = bufnr('') + if blame_bufnr < 0 + let blame_args = flags + [commit . suffix, '--', path] + let result = s:BlameSubcommand(0, 0, 0, 0, '', blame_args) + else + let blame_args = flags + let result = s:BlameSubcommand(-1, -1, 0, 0, '', blame_args) + endif + if bufnr('') == my_bufnr + return result + endif + execute result execute lnum let delta = line('.') - line('w0') - offset if delta > 0 @@ -3946,32 +5014,41 @@ function! s:BlameJump(suffix) abort elseif delta < 0 execute 'normal! '.(-delta)."\<C-Y>" endif - syncbind + keepjumps syncbind + redraw + echo ':Gblame' s:fnameescape(blame_args) endif return '' endfunction let s:hash_colors = {} -function! s:BlameSyntax() abort - let b:current_syntax = 'fugitiveblame' +function! fugitive#BlameSyntax() abort let conceal = has('conceal') ? ' conceal' : '' - let arg = exists('b:fugitive_blame_arguments') ? b:fugitive_blame_arguments : '' - syn match FugitiveblameBoundary "^\^" - syn match FugitiveblameBlank "^\s\+\s\@=" nextgroup=FugitiveblameAnnotation,fugitiveblameOriginalFile,FugitiveblameOriginalLineNumber skipwhite - syn match FugitiveblameHash "\%(^\^\=\)\@<=\<\x\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite - syn match FugitiveblameUncommitted "\%(^\^\=\)\@<=\<0\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite - syn region FugitiveblameAnnotation matchgroup=FugitiveblameDelimiter start="(" end="\%( \d\+\)\@<=)" contained keepend oneline - syn match FugitiveblameTime "[0-9:/+-][0-9:/+ -]*[0-9:/+-]\%( \+\d\+)\)\@=" contained containedin=FugitiveblameAnnotation - exec 'syn match FugitiveblameLineNumber " *\d\+)\@=" contained containedin=FugitiveblameAnnotation'.conceal - exec 'syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite'.(arg =~# 'f' ? '' : conceal) - exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite'.(arg =~# 'n' ? '' : conceal) - exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite'.(arg =~# 'n' ? '' : conceal) + let config = fugitive#Config() + let flags = get(s:TempState(), 'blame_flags', []) + syn match FugitiveblameBlank "^\s\+\s\@=" nextgroup=FugitiveblameAnnotation,FugitiveblameScoreDebug,FugitiveblameOriginalFile,FugitiveblameOriginalLineNumber skipwhite + syn match FugitiveblameHash "\%(^\^\=\)\@<=\<\x\{7,\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameScoreDebug,FugitiveblameOriginalLineNumber,FugitiveblameOriginalFile skipwhite + syn match FugitiveblameUncommitted "\%(^\^\=\)\@<=\<0\{7,\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameScoreDebug,FugitiveblameOriginalLineNumber,FugitiveblameOriginalFile skipwhite + if get(get(config, 'blame.blankboundary', ['x']), 0, 'x') =~# '^$\|^true$' || s:HasOpt(flags, '-b') + syn match FugitiveblameBoundaryIgnore "^\^\x\{7,\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameScoreDebug,FugitiveblameOriginalLineNumber,FugitiveblameOriginalFile skipwhite + else + syn match FugitiveblameBoundary "^\^" + endif + syn match FugitiveblameScoreDebug " *\d\+\s\+\d\+\s\@=" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile contained skipwhite + syn region FugitiveblameAnnotation matchgroup=FugitiveblameDelimiter start="(" end="\%(\s\d\+\)\@<=)" contained keepend oneline + syn match FugitiveblameTime "[0-9:/+-][0-9:/+ -]*[0-9:/+-]\%(\s\+\d\+)\)\@=" contained containedin=FugitiveblameAnnotation + exec 'syn match FugitiveblameLineNumber "\s*\d\+)\@=" contained containedin=FugitiveblameAnnotation' conceal + exec 'syn match FugitiveblameOriginalFile "\s\%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite' (s:HasOpt(flags, '--show-name', '-f') ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber "\s*\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite' (s:HasOpt(flags, '--show-number', '-n') ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber "\s*\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite' (s:HasOpt(flags, '--show-number', '-n') ? '' : conceal) syn match FugitiveblameShort " \d\+)" contained contains=FugitiveblameLineNumber syn match FugitiveblameNotCommittedYet "(\@<=Not Committed Yet\>" contained containedin=FugitiveblameAnnotation hi def link FugitiveblameBoundary Keyword hi def link FugitiveblameHash Identifier + hi def link FugitiveblameBoundaryIgnore Ignore hi def link FugitiveblameUncommitted Ignore + hi def link FugitiveblameScoreDebug Debug hi def link FugitiveblameTime PreProc hi def link FugitiveblameLineNumber Number hi def link FugitiveblameOriginalFile String @@ -3979,6 +5056,9 @@ function! s:BlameSyntax() abort hi def link FugitiveblameShort FugitiveblameDelimiter hi def link FugitiveblameDelimiter Delimiter hi def link FugitiveblameNotCommittedYet Comment + if !get(g:, 'fugitive_dynamic_colors', 1) && !s:HasOpt(flags, '--color-lines') || s:HasOpt(flags, '--no-color-lines') + return + endif let seen = {} for lnum in range(1, line('$')) let hash = matchstr(getline(lnum), '^\^\=\zs\x\{6\}') @@ -3999,10 +5079,10 @@ function! s:BlameSyntax() abort endif exe 'syn match FugitiveblameHash'.hash.' "\%(^\^\=\)\@<='.hash.'\x\{1,34\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite' endfor - call s:RehighlightBlame() + call s:BlameRehighlight() endfunction -function! s:RehighlightBlame() abort +function! s:BlameRehighlight() abort for [hash, cterm] in items(s:hash_colors) if !empty(cterm) || has('gui_running') || has('termguicolors') && &termguicolors exe 'hi FugitiveblameHash'.hash.' guifg=#'.hash.get(s:hash_colors, hash, '') @@ -4012,17 +5092,64 @@ function! s:RehighlightBlame() abort endfor endfunction +function! s:BlameFileType() abort + setlocal nomodeline + setlocal foldmethod=manual + if len(s:Dir()) + let &l:keywordprg = s:Keywordprg() + endif + let b:undo_ftplugin = 'setl keywordprg= foldmethod<' + if exists('+concealcursor') + setlocal concealcursor=nc conceallevel=2 + let b:undo_ftplugin .= ' concealcursor< conceallevel<' + endif + if &modifiable + return '' + endif + call s:Map('n', '<F1>', ':help fugitive-:Gblame<CR>', '<silent>') + call s:Map('n', 'g?', ':help fugitive-:Gblame<CR>', '<silent>') + if mapcheck('q', 'n') =~# '^$\|bdelete' + call s:Map('n', 'q', ':exe <SID>BlameQuit()<Bar>echohl WarningMsg<Bar>echo ":Gblame q is deprecated in favor of gq"<Bar>echohl NONE<CR>', '<silent>') + endif + call s:Map('n', 'gq', ':exe <SID>BlameQuit()<CR>', '<silent>') + call s:Map('n', '<2-LeftMouse>', ':<C-U>exe <SID>BlameCommit("exe <SID>BlameLeave()<Bar>edit")<CR>', '<silent>') + call s:Map('n', '<CR>', ':<C-U>exe <SID>BlameCommit("exe <SID>BlameLeave()<Bar>edit")<CR>', '<silent>') + call s:Map('n', '-', ':<C-U>exe <SID>BlameJump("")<CR>', '<silent>') + call s:Map('n', 'P', ':<C-U>exe <SID>BlameJump("^".v:count1)<CR>', '<silent>') + call s:Map('n', '~', ':<C-U>exe <SID>BlameJump("~".v:count1)<CR>', '<silent>') + call s:Map('n', 'i', ':<C-U>exe <SID>BlameCommit("exe <SID>BlameLeave()<Bar>edit")<CR>', '<silent>') + call s:Map('n', 'o', ':<C-U>exe <SID>BlameCommit("split")<CR>', '<silent>') + call s:Map('n', 'O', ':<C-U>exe <SID>BlameCommit("tabedit")<CR>', '<silent>') + call s:Map('n', 'p', ':<C-U>exe <SID>BlameCommit("pedit")<CR>', '<silent>') +endfunction + +augroup fugitive_blame + autocmd! + autocmd FileType fugitiveblame call s:BlameFileType() + autocmd ColorScheme,GUIEnter * call s:BlameRehighlight() + autocmd BufWinLeave * execute getwinvar(+bufwinnr(+expand('<abuf>')), 'fugitive_leave') +augroup END + +call s:command('-buffer -bang -range=-1 -nargs=? -complete=customlist,s:BlameComplete Gblame', 'blame') + " Section: :Gbrowse -call s:command("-bar -bang -range=0 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse", "Browse") +call s:command("-bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse", "Browse") let s:redirects = {} function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args) abort let dir = s:Dir() + exe s:DirCheck(dir) try let validremote = '\.\|\.\=/.*\|[[:alnum:]_-]\+\%(://.\{-\}\)\=' - if len(a:args) + if a:args ==# ['-'] + if a:count >= 0 + return 'echoerr ' . string('fugitive: ''-'' no longer required to get persistent URL if range given') + else + return 'echoerr ' . string('fugitive: use :0Gbrowse instead of :Gbrowse -') + endif + elseif len(a:args) let remote = matchstr(join(a:args, ' '),'@\zs\%('.validremote.'\)$') let rev = substitute(join(a:args, ' '),'@\%('.validremote.'\)$','','') else @@ -4037,7 +5164,7 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args else let expanded = s:Expand(rev) endif - let cdir = fugitive#CommonDir(s:Dir()) + let cdir = FugitiveVimPath(fugitive#CommonDir(s:Dir())) for subdir in ['tags/', 'heads/', 'remotes/'] if expanded !~# '^[./]' && filereadable(cdir . '/refs/' . subdir . expanded) let expanded = '.git/refs/' . subdir . expanded @@ -4075,7 +5202,7 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args endif if path =~# '^\.git/.*HEAD$' && filereadable(dir . '/' . path[5:-1]) let body = readfile(dir . '/' . path[5:-1])[0] - if body =~# '^\x\{40\}$' + if body =~# '^\x\{40,\}$' let commit = body let type = 'commit' let path = '' @@ -4122,23 +5249,23 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args let line1 = a:count > 0 ? a:line1 : 0 let line2 = a:count > 0 ? a:count : 0 if empty(commit) && path !~# '^\.git/' - if a:line1 && !a:count && !empty(merge) + if a:count < 0 && !empty(merge) let commit = merge else let commit = '' if len(merge) let owner = s:Owner(@%) - let commit = s:TreeChomp('merge-base', 'refs/remotes/' . remote . '/' . merge, empty(owner) ? 'HEAD' : owner, '--') - if v:shell_error + let [commit, exec_error] = s:ChompError(['merge-base', 'refs/remotes/' . remote . '/' . merge, empty(owner) ? 'HEAD' : owner, '--']) + if exec_error let commit = '' endif - if a:count && empty(a:args) && commit =~# '^\x\{40\}$' + if a:count > 0 && empty(a:args) && commit =~# '^\x\{40,\}$' let blame_list = tempname() call writefile([commit, ''], blame_list, 'b') let blame_in = tempname() silent exe '%write' blame_in - let blame = split(s:TreeChomp('blame', '--contents', blame_in, '-L', a:line1.','.a:count, '-S', blame_list, '-s', '--show-number', './' . path), "\n") - if !v:shell_error + let [blame, exec_error] = s:LinesError(['-c', 'blame.coloring=none', 'blame', '--contents', blame_in, '-L', a:line1.','.a:count, '-S', blame_list, '-s', '--show-number', './' . path]) + if !exec_error let blame_regex = '^\^\x\+\s\+\zs\d\+\ze\s' if get(blame, 0) =~# blame_regex && get(blame, -1) =~# blame_regex let line1 = +matchstr(blame[0], blame_regex) @@ -4151,7 +5278,7 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args endif endif if empty(commit) - let commit = readfile(dir . '/HEAD', '', 1)[0] + let commit = readfile(fugitive#Find('.git/HEAD', dir), '', 1)[0] endif let i = 0 while commit =~# '^ref: ' && i < 10 @@ -4199,7 +5326,7 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args endfor if empty(url) - call s:throw("No Gbrowse handler found for '".raw."'") + call s:throw("No Gbrowse handler installed for '".raw."'") endif let url = s:gsub(url, '[ <>]', '\="%".printf("%02X",char2nr(submatch(0)))') @@ -4221,7 +5348,7 @@ function! s:BrowseCommand(line1, line2, range, count, bang, mods, reg, arg, args endif endif catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry endfunction @@ -4232,11 +5359,11 @@ function! fugitive#MapCfile(...) abort exe 'cnoremap <buffer> <expr> <Plug><cfile>' (a:0 ? a:1 : 'fugitive#Cfile()') let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|sil! exe "cunmap <buffer> <Plug><cfile>"' if !exists('g:fugitive_no_maps') - call s:map('n', 'gf', '<SID>:find <Plug><cfile><CR>', '<silent><unique>', 1) - call s:map('n', '<C-W>f', '<SID>:sfind <Plug><cfile><CR>', '<silent><unique>', 1) - call s:map('n', '<C-W><C-F>', '<SID>:sfind <Plug><cfile><CR>', '<silent><unique>', 1) - call s:map('n', '<C-W>gf', '<SID>:tabfind <Plug><cfile><CR>', '<silent><unique>', 1) - call s:map('c', '<C-R><C-F>', '<Plug><cfile>', '<silent><unique>', 1) + call s:Map('n', 'gf', '<SID>:find <Plug><cfile><CR>', '<silent><unique>', 1) + call s:Map('n', '<C-W>f', '<SID>:sfind <Plug><cfile><CR>', '<silent><unique>', 1) + call s:Map('n', '<C-W><C-F>', '<SID>:sfind <Plug><cfile><CR>', '<silent><unique>', 1) + call s:Map('n', '<C-W>gf', '<SID>:tabfind <Plug><cfile><CR>', '<silent><unique>', 1) + call s:Map('c', '<C-R><C-F>', '<Plug><cfile>', '<silent><unique>', 1) endif endfunction @@ -4245,12 +5372,19 @@ function! s:ContainingCommit() abort return empty(commit) ? 'HEAD' : commit endfunction -function! s:SquashArgument() abort +function! s:SquashArgument(...) abort if &filetype == 'fugitive' - return matchstr(getline('.'), '^\%(\%(\x\x\x\)\@!\l\+\s\+\)\=\zs[0-9a-f]\{4,\}\ze ') + let commit = matchstr(getline('.'), '^\%(\%(\x\x\x\)\@!\l\+\s\+\)\=\zs[0-9a-f]\{4,\}\ze ') + elseif has_key(s:temp_files, s:cpath(expand('%:p'))) + let commit = matchstr(getline('.'), '\<\x\{4,\}\>') else - return s:Owner(@%) + let commit = s:Owner(@%) endif + return len(commit) && a:0 ? printf(a:1, commit) : commit +endfunction + +function! s:RebaseArgument() abort + return s:SquashArgument(' %s^') endfunction function! s:NavigateUp(count) abort @@ -4273,61 +5407,146 @@ function! s:NavigateUp(count) abort return rev endfunction +function! s:MapMotion(lhs, rhs) abort + call s:Map('n', a:lhs, ":<C-U>" . a:rhs . "<CR>", "<silent>") + call s:Map('o', a:lhs, ":<C-U>" . a:rhs . "<CR>", "<silent>") + call s:Map('x', a:lhs, ":<C-U>exe 'normal! gv'<Bar>" . a:rhs . "<CR>", "<silent>") +endfunction + function! fugitive#MapJumps(...) abort - if get(b:, 'fugitive_type', '') ==# 'blob' - nnoremap <buffer> <silent> <CR> :<C-U>.Gblame<CR> - else - nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>GF("edit")<CR> - endif if !&modifiable - let nowait = v:version >= 704 ? '<nowait>' : '' if get(b:, 'fugitive_type', '') ==# 'blob' - nnoremap <buffer> <silent> o :<C-U>.,.+1Gblame<CR> - nnoremap <buffer> <silent> S :<C-U>echoerr 'Use gO'<CR> - nnoremap <buffer> <silent> gO :<C-U>vertical .,.+1Gblame<CR> - nnoremap <buffer> <silent> O :<C-U>tab .,.+1Gblame<CR> - nnoremap <buffer> <silent> p :<C-U>.,.+2Gblame<CR> + let blame_map = 'Gblame<C-R>=v:count ? " --reverse" : ""<CR><CR>' + call s:Map('n', '<2-LeftMouse>', ':<C-U>0,1' . blame_map, '<silent>') + call s:Map('n', '<CR>', ':<C-U>0,1' . blame_map, '<silent>') + call s:Map('n', 'o', ':<C-U>0,2' . blame_map, '<silent>') + call s:Map('n', 'p', ':<C-U>0,3' . blame_map, '<silent>') + call s:Map('n', 'gO', ':<C-U>0,4' . blame_map, '<silent>') + call s:Map('n', 'O', ':<C-U>0,5' . blame_map, '<silent>') + + call s:Map('n', 'D', ":<C-U>call <SID>DiffClose()<Bar>Gdiffsplit!<Bar>redraw<Bar>echohl WarningMsg<Bar> echo ':Gstatus D is deprecated in favor of dd'<Bar>echohl NONE<CR>", '<silent>') + call s:Map('n', 'dd', ":<C-U>call <SID>DiffClose()<Bar>Gdiffsplit!<CR>", '<silent>') + call s:Map('n', 'dh', ":<C-U>call <SID>DiffClose()<Bar>Ghdiffsplit!<CR>", '<silent>') + call s:Map('n', 'ds', ":<C-U>call <SID>DiffClose()<Bar>Ghdiffsplit!<CR>", '<silent>') + call s:Map('n', 'dv', ":<C-U>call <SID>DiffClose()<Bar>Gvdiffsplit!<CR>", '<silent>') + call s:Map('n', 'd?', ":<C-U>help fugitive_d<CR>", '<silent>') + else - nnoremap <buffer> <silent> o :<C-U>exe <SID>GF("split")<CR> - nnoremap <buffer> <silent> S :<C-U>echoerr 'Use gO'<CR> - nnoremap <buffer> <silent> gO :<C-U>exe <SID>GF("vsplit")<CR> - nnoremap <buffer> <silent> O :<C-U>exe <SID>GF("tabedit")<CR> - nnoremap <buffer> <silent> p :<C-U>exe <SID>GF("pedit")<CR> + call s:Map('n', '<2-LeftMouse>', ':<C-U>exe <SID>GF("edit")<CR>', '<silent>') + call s:Map('n', '<CR>', ':<C-U>exe <SID>GF("edit")<CR>', '<silent>') + call s:Map('n', 'o', ':<C-U>exe <SID>GF("split")<CR>', '<silent>') + call s:Map('n', 'gO', ':<C-U>exe <SID>GF("vsplit")<CR>', '<silent>') + call s:Map('n', 'O', ':<C-U>exe <SID>GF("tabedit")<CR>', '<silent>') + call s:Map('n', 'p', ':<C-U>exe <SID>GF("pedit")<CR>', '<silent>') + + if !exists('g:fugitive_no_maps') + if exists(':CtrlP') && get(g:, 'ctrl_p_map') =~? '^<c-p>$' + nnoremap <buffer> <silent> <C-P> :<C-U>execute line('.') == 1 ? 'CtrlP ' . fnameescape(<SID>Tree()) : <SID>PreviousItem(v:count1)<CR> + else + nnoremap <buffer> <silent> <C-P> :<C-U>execute <SID>PreviousItem(v:count1)<CR> + endif + nnoremap <buffer> <silent> <C-N> :<C-U>execute <SID>NextItem(v:count1)<CR> + endif + call s:MapMotion('(', 'exe <SID>PreviousItem(v:count1)') + call s:MapMotion(')', 'exe <SID>NextItem(v:count1)') + call s:MapMotion('K', 'exe <SID>PreviousHunk(v:count1)') + call s:MapMotion('J', 'exe <SID>NextHunk(v:count1)') + call s:MapMotion('[c', 'exe <SID>PreviousHunk(v:count1)') + call s:MapMotion(']c', 'exe <SID>NextHunk(v:count1)') + call s:MapMotion('[/', 'exe <SID>PreviousFile(v:count1)') + call s:MapMotion(']/', 'exe <SID>NextFile(v:count1)') + call s:MapMotion('[m', 'exe <SID>PreviousFile(v:count1)') + call s:MapMotion(']m', 'exe <SID>NextFile(v:count1)') + call s:MapMotion('[[', 'exe <SID>PreviousSection(v:count1)') + call s:MapMotion(']]', 'exe <SID>NextSection(v:count1)') + call s:MapMotion('[]', 'exe <SID>PreviousSectionEnd(v:count1)') + call s:MapMotion('][', 'exe <SID>NextSectionEnd(v:count1)') + call s:Map('nxo', '*', '<SID>PatchSearchExpr(0)', '<expr>') + call s:Map('nxo', '#', '<SID>PatchSearchExpr(1)', '<expr>') endif - exe "nnoremap <buffer> <silent>" nowait "- :<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>NavigateUp(v:count1))<Bar> if getline(1) =~# '^tree \x\{40\}$' && empty(getline(2))<Bar>call search('^'.escape(expand('#:t'),'.*[]~\').'/\=$','wc')<Bar>endif<CR>" - nnoremap <buffer> <silent> P :<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit().'^'.v:count1.<SID>Relative(':'))<CR> - nnoremap <buffer> <silent> ~ :<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit().'~'.v:count1.<SID>Relative(':'))<CR> - nnoremap <buffer> <silent> C :<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR> - nnoremap <buffer> <silent> co :<C-U>echoerr 'Use CTRL-W C'<CR> - nnoremap <buffer> <silent> <C-W>C :<C-U>exe 'Gsplit ' . <SID>fnameescape(<SID>ContainingCommit())<CR> - nnoremap <buffer> <silent> cp :<C-U>echoerr 'Use gC'<CR> - nnoremap <buffer> <silent> gC :<C-U>exe 'Gpedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR> - nnoremap <buffer> <silent> gc :<C-U>exe 'Gpedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR> + call s:Map('n', 'S', ':<C-U>echoerr "Use gO"<CR>', '<silent>') + call s:Map('n', 'dq', ":<C-U>call <SID>DiffClose()<CR>", '<silent>') + call s:Map('n', '-', ":<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>NavigateUp(v:count1))<Bar> if getline(1) =~# '^tree \x\{40,\}$' && empty(getline(2))<Bar>call search('^'.escape(expand('#:t'),'.*[]~\').'/\=$','wc')<Bar>endif<CR>", '<silent>') + call s:Map('n', 'P', ":<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit().'^'.v:count1.<SID>Relative(':'))<CR>", '<silent>') + call s:Map('n', '~', ":<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit().'~'.v:count1.<SID>Relative(':'))<CR>", '<silent>') + call s:Map('n', 'C', ":<C-U>exe 'Gedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR>", '<silent>') + call s:Map('n', 'cp', ":<C-U>echoerr 'Use gC'<CR>", '<silent>') + call s:Map('n', 'gC', ":<C-U>exe 'Gpedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR>", '<silent>') + call s:Map('n', 'gc', ":<C-U>exe 'Gpedit ' . <SID>fnameescape(<SID>ContainingCommit())<CR>", '<silent>') + call s:Map('n', 'gi', ":<C-U>exe 'Gsplit' (v:count ? '.gitignore' : '.git/info/exclude')<CR>", '<silent>') + call s:Map('x', 'gi', ":<C-U>exe 'Gsplit' (v:count ? '.gitignore' : '.git/info/exclude')<CR>", '<silent>') + + nnoremap <buffer> c<Space> :Gcommit<Space> + nnoremap <buffer> c<CR> :Gcommit<CR> + nnoremap <buffer> cv<Space> :Gcommit -v<Space> + nnoremap <buffer> cv<CR> :Gcommit -v<CR> nnoremap <buffer> <silent> ca :<C-U>Gcommit --amend<CR> nnoremap <buffer> <silent> cc :<C-U>Gcommit<CR> nnoremap <buffer> <silent> ce :<C-U>Gcommit --amend --no-edit<CR> nnoremap <buffer> <silent> cw :<C-U>Gcommit --amend --only<CR> nnoremap <buffer> <silent> cva :<C-U>Gcommit -v --amend<CR> nnoremap <buffer> <silent> cvc :<C-U>Gcommit -v<CR> + nnoremap <buffer> <silent> cRa :<C-U>Gcommit --reset-author --amend<CR> + nnoremap <buffer> <silent> cRe :<C-U>Gcommit --reset-author --amend --no-edit<CR> + nnoremap <buffer> <silent> cRw :<C-U>Gcommit --reset-author --amend --only<CR> nnoremap <buffer> cf :<C-U>Gcommit --fixup=<C-R>=<SID>SquashArgument()<CR> + nnoremap <buffer> cF :<C-U><Bar>Grebase --autosquash<C-R>=<SID>RebaseArgument()<CR><Home>Gcommit --fixup=<C-R>=<SID>SquashArgument()<CR> nnoremap <buffer> cs :<C-U>Gcommit --squash=<C-R>=<SID>SquashArgument()<CR> + nnoremap <buffer> cS :<C-U><Bar>Grebase --autosquash<C-R>=<SID>RebaseArgument()<CR><Home>Gcommit --squash=<C-R>=<SID>SquashArgument()<CR> nnoremap <buffer> cA :<C-U>Gcommit --edit --squash=<C-R>=<SID>SquashArgument()<CR> - nnoremap <buffer> <silent> ri :<C-U>Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR><CR> - nnoremap <buffer> <silent> rf :<C-U>Grebase --autosquash<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR><CR> + nnoremap <buffer> <silent> c? :<C-U>help fugitive_c<CR> + + nnoremap <buffer> cr<Space> :Grevert<Space> + nnoremap <buffer> cr<CR> :Grevert<CR> + nnoremap <buffer> <silent> crc :<C-U>Grevert <C-R>=<SID>SquashArgument()<CR><CR> + nnoremap <buffer> <silent> crn :<C-U>Grevert --no-commit <C-R>=<SID>SquashArgument()<CR><CR> + nnoremap <buffer> <silent> cr? :help fugitive_cr<CR> + + nnoremap <buffer> cm<Space> :Gmerge<Space> + nnoremap <buffer> cm<CR> :Gmerge<CR> + nnoremap <buffer> <silent> cm? :help fugitive_cm<CR> + + nnoremap <buffer> cz<Space> :G stash<Space> + nnoremap <buffer> cz<CR> :G stash<CR> + nnoremap <buffer> <silent> cza :<C-U>exe <SID>EchoExec(['stash', 'apply', '--quiet', '--index', 'stash@{' . v:count . '}'])<CR> + nnoremap <buffer> <silent> czA :<C-U>exe <SID>EchoExec(['stash', 'apply', '--quiet', 'stash@{' . v:count . '}'])<CR> + nnoremap <buffer> <silent> czp :<C-U>exe <SID>EchoExec(['stash', 'pop', '--quiet', '--index', 'stash@{' . v:count . '}'])<CR> + nnoremap <buffer> <silent> czP :<C-U>exe <SID>EchoExec(['stash', 'pop', '--quiet', 'stash@{' . v:count . '}'])<CR> + nnoremap <buffer> <silent> czv :<C-U>exe 'Gedit' fugitive#RevParse('stash@{' . v:count . '}')<CR> + nnoremap <buffer> <silent> czw :<C-U>exe <SID>EchoExec(['stash', '--keep-index'] + (v:count > 1 ? ['--all'] : v:count ? ['--include-untracked'] : []))<CR> + nnoremap <buffer> <silent> czz :<C-U>exe <SID>EchoExec(['stash'] + (v:count > 1 ? ['--all'] : v:count ? ['--include-untracked'] : []))<CR> + nnoremap <buffer> <silent> cz? :<C-U>help fugitive_cz<CR> + + nnoremap <buffer> co<Space> :G checkout<Space> + nnoremap <buffer> co<CR> :G checkout<CR> + nnoremap <buffer> coo :exe <SID>EchoExec(['checkout'] + split(<SID>SquashArgument()) + ['--'])<CR> + nnoremap <buffer> co? :<C-U>help fugitive_co<CR> + + nnoremap <buffer> cb<Space> :G branch<Space> + nnoremap <buffer> cb<CR> :G branch<CR> + nnoremap <buffer> cb? :<C-U>help fugitive_cb<CR> + + nnoremap <buffer> r<Space> :Grebase<Space> + nnoremap <buffer> r<CR> :Grebase<CR> + nnoremap <buffer> <silent> ri :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><CR> + nnoremap <buffer> <silent> rf :<C-U>Grebase --autosquash<C-R>=<SID>RebaseArgument()<CR><CR> nnoremap <buffer> <silent> ru :<C-U>Grebase --interactive @{upstream}<CR> nnoremap <buffer> <silent> rp :<C-U>Grebase --interactive @{push}<CR> - nnoremap <buffer> <silent> rw :<C-U>exe 'Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR>'<Bar>s/^pick/reword/e<CR> - nnoremap <buffer> <silent> rm :<C-U>exe 'Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR>'<Bar>s/^pick/edit/e<CR> - nnoremap <buffer> <silent> rd :<C-U>exe 'Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR>'<Bar>s/^pick/drop/e<CR> - nnoremap <buffer> <silent> rk :<C-U>exe 'Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR>'<Bar>s/^pick/drop/e<CR> - nnoremap <buffer> <silent> rx :<C-U>exe 'Grebase --interactive<C-R>=substitute(<SID>SquashArgument(),'.\+',' &^','')<CR>'<Bar>s/^pick/drop/e<CR> + nnoremap <buffer> <silent> rw :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><Bar>s/^pick/reword/e<CR> + nnoremap <buffer> <silent> rm :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><Bar>s/^pick/edit/e<CR> + nnoremap <buffer> <silent> rd :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><Bar>s/^pick/drop/e<CR> + nnoremap <buffer> <silent> rk :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><Bar>s/^pick/drop/e<CR> + nnoremap <buffer> <silent> rx :<C-U>Grebase --interactive<C-R>=<SID>RebaseArgument()<CR><Bar>s/^pick/drop/e<CR> nnoremap <buffer> <silent> rr :<C-U>Grebase --continue<CR> nnoremap <buffer> <silent> rs :<C-U>Grebase --skip<CR> nnoremap <buffer> <silent> re :<C-U>Grebase --edit-todo<CR> nnoremap <buffer> <silent> ra :<C-U>Grebase --abort<CR> - nnoremap <buffer> . :<C-U> <C-R>=<SID>fnameescape(fugitive#Real(@%))<CR><Home> - xnoremap <buffer> . :<C-U> <C-R>=<SID>fnameescape(fugitive#Real(@%))<CR><Home> - nnoremap <buffer> <silent> g? :help fugitive-mappings<CR> + nnoremap <buffer> <silent> r? :<C-U>help fugitive_r<CR> + + call s:Map('n', '.', ":<C-U> <C-R>=<SID>fnameescape(fugitive#Real(@%))<CR><Home>") + call s:Map('x', '.', ":<C-U> <C-R>=<SID>fnameescape(fugitive#Real(@%))<CR><Home>") + call s:Map('n', 'g?', ":<C-U>help fugitive-mappings<CR>", '<silent>') + call s:Map('n', '<F1>', ":<C-U>help fugitive-mappings<CR>", '<silent>') endif endfunction @@ -4336,16 +5555,16 @@ function! s:StatusCfile(...) abort let lead = s:cpath(tree, getcwd()) ? './' : tree . '/' let info = s:StageInfo() let line = getline('.') - if len(info.sigil) && len(info.section) && len(info.filename) + if len(info.sigil) && len(info.section) && len(info.paths) if info.section ==# 'Unstaged' && info.sigil !=# '-' - return [lead . info.filename, info.offset, 'normal!zv'] + return [lead . info.relative[0], info.offset, 'normal!zv'] elseif info.section ==# 'Staged' && info.sigil ==# '-' - return ['@:' . info.filename, info.offset, 'normal!zv'] + return ['@:' . info.relative[0], info.offset, 'normal!zv'] else - return [':0:' . info.filename, info.offset, 'normal!zv'] + return [':0:' . info.relative[0], info.offset, 'normal!zv'] endif - elseif len(info.filename) - return [lead . info.filename] + elseif len(info.paths) + return [lead . info.relative[0]] elseif len(info.commit) return [info.commit] elseif line =~# '^\%(Head\|Merge\|Rebase\|Upstream\|Pull\|Push\): ' @@ -4406,7 +5625,7 @@ function! s:cfile() abort let treebase = substitute(s:DirCommitFile(@%)[1], '^\d$', ':&', '') . ':' . \ s:Relative('') . (s:Relative('') =~# '^$\|/$' ? '' : '/') - if getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t' + if getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40,\}\t' return [treebase . s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')] elseif showtree return [treebase . s:sub(getline('.'),'/$','')] @@ -4416,8 +5635,8 @@ function! s:cfile() abort let dcmds = [] " Index - if getline('.') =~# '^\d\{6\} \x\{40\} \d\t' - let ref = matchstr(getline('.'),'\x\{40\}') + if getline('.') =~# '^\d\{6\} \x\{40,\} \d\t' + let ref = matchstr(getline('.'),'\x\{40,\}') let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':') return [file] endif @@ -4425,12 +5644,12 @@ function! s:cfile() abort if getline('.') =~# '^ref: ' let ref = strpart(getline('.'),5) - elseif getline('.') =~# '^commit \x\{40\}\>' - let ref = matchstr(getline('.'),'\x\{40\}') + elseif getline('.') =~# '^commit \x\{40,\}\>' + let ref = matchstr(getline('.'),'\x\{40,\}') return [ref] - elseif getline('.') =~# '^parent \x\{40\}\>' - let ref = matchstr(getline('.'),'\x\{40\}') + elseif getline('.') =~# '^parent \x\{40,\}\>' + let ref = matchstr(getline('.'),'\x\{40,\}') let line = line('.') let parent = 0 while getline(line) =~# '^parent ' @@ -4439,22 +5658,22 @@ function! s:cfile() abort endwhile return [ref] - elseif getline('.') =~# '^tree \x\{40\}$' - let ref = matchstr(getline('.'),'\x\{40\}') + elseif getline('.') =~# '^tree \x\{40,\}$' + let ref = matchstr(getline('.'),'\x\{40,\}') if len(myhash) && fugitive#RevParse(myhash.':') ==# ref let ref = myhash.':' endif return [ref] - elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' - let ref = matchstr(getline('.'),'\x\{40\}') + elseif getline('.') =~# '^object \x\{40,\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' + let ref = matchstr(getline('.'),'\x\{40,\}') let type = matchstr(getline(line('.')+1),'type \zs.*') elseif getline('.') =~# '^\l\{3,8\} '.myhash.'$' let ref = s:DirRev(@%)[1] - elseif getline('.') =~# '^\l\{3,8\} \x\{40\}\>' - let ref = matchstr(getline('.'),'\x\{40\}') + elseif getline('.') =~# '^\l\{3,8\} \x\{40,\}\>' + let ref = matchstr(getline('.'),'\x\{40,\}') echoerr "warning: unknown context ".matchstr(getline('.'),'^\l*') elseif getline('.') =~# '^[+-]\{3\} [abciow12]\=/' @@ -4485,23 +5704,23 @@ function! s:cfile() abort let dref = matchstr(diff, '\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)') let ref = matchstr(diff, '\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)') - let dcmd = 'Gdiff! +'.offset + let dcmd = 'Gdiffsplit! +'.offset elseif getline('.') =~# '^diff --git \%([abciow12]/.*\|/dev/null\) \%([abciow12]/.*\|/dev/null\)' let dref = matchstr(getline('.'),'\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)') let ref = matchstr(getline('.'),'\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)') - let dcmd = 'Gdiff!' + let dcmd = 'Gdiffsplit!' elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%([abciow12]/.*\|/dev/null\) \%([abciow12]/.*\|/dev/null\)' let line = getline(line('.')-1) let dref = matchstr(line,'\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)') let ref = matchstr(line,'\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)') - let dcmd = 'Gdiff!' + let dcmd = 'Gdiffsplit!' - elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$' + elseif line('$') == 1 && getline('.') =~ '^\x\{40,\}$' let ref = getline('.') - elseif expand('<cword>') =~# '^\x\{7,40\}\>' + elseif expand('<cword>') =~# '^\x\{7,\}\>' return [expand('<cword>')] else @@ -4545,12 +5764,12 @@ function! s:GF(mode) abort try let results = &filetype ==# 'fugitive' ? s:StatusCfile() : &filetype ==# 'gitcommit' ? [s:MessageCfile()] : s:cfile() catch /^fugitive:/ - return 'echoerr v:errmsg' + return 'echoerr ' . string(v:exception) endtry if len(results) > 1 return 'G' . a:mode . - \ ' +' . escape(join(results[1:-1], '|'), '| ') . ' ' . - \ s:fnameescape(results[0]) + \ ' +' . escape(results[1], ' ') . ' ' . + \ s:fnameescape(results[0]) . join(map(results[2:-1], '"|" . v:val'), '') elseif len(results) && len(results[0]) return 'G' . a:mode . ' ' . s:fnameescape(results[0]) else @@ -4669,19 +5888,20 @@ function! fugitive#Init() abort endtry endif if !exists('g:fugitive_no_maps') - call s:map('c', '<C-R><C-G>', '<SID>fnameescape(fugitive#Object(@%))', '<expr>') - call s:map('n', 'y<C-G>', ':<C-U>call setreg(v:register, fugitive#Object(@%))<CR>', '<silent>') + call s:Map('c', '<C-R><C-G>', '<SID>fnameescape(fugitive#Object(@%))', '<expr>') + call s:Map('n', 'y<C-G>', ':<C-U>call setreg(v:register, fugitive#Object(@%))<CR>', '<silent>') endif if expand('%:p') =~# ':[\/][\/]' let &l:path = s:sub(&path, '^\.%(,|$)', '') endif let dir = s:Dir() if stridx(&tags, escape(dir, ', ')) == -1 - if filereadable(dir.'/tags') - let &l:tags = escape(dir.'/tags', ', ').','.&tags + let actualdir = fugitive#Find('.git/', dir) + if filereadable(actualdir . 'tags') + let &l:tags = escape(actualdir . 'tags', ', ').','.&tags endif - if &filetype !=# '' && filereadable(dir.'/'.&filetype.'.tags') - let &l:tags = escape(dir.'/'.&filetype.'.tags', ', ').','.&tags + if &filetype !=# '' && filereadable(actualdir . &filetype . '.tags') + let &l:tags = escape(actualdir . &filetype . '.tags', ', ').','.&tags endif endif try diff --git a/sources_non_forked/vim-fugitive/doc/fugitive.txt b/sources_non_forked/vim-fugitive/doc/fugitive.txt index 16f20f15..d4750ddc 100644 --- a/sources_non_forked/vim-fugitive/doc/fugitive.txt +++ b/sources_non_forked/vim-fugitive/doc/fugitive.txt @@ -15,13 +15,21 @@ COMMANDS *fugitive-commands* These commands are local to the buffers in which they work (generally, buffers that are part of Git repositories). + *fugitive-:G* *fugitive-:Gstatus* +:G Bring up a summary window vaguely akin to git-status. +:Gstatus Press g? or see |fugitive-mappings| for usage. + *fugitive-:Git* -:Git [args] Run an arbitrary git command. Similar to :!git [args] - but chdir to the repository tree first. +:Git {args} Run an arbitrary git command. Similar to :!git [args] +:G {args} but chdir to the repository tree first. For some + subcommands, a Fugitive command is called instead. + Invoking :Git push will call :Gpush for example. *fugitive-:Git!* -:Git! [args] Like |:Git|, but capture the output into a temp file, - and edit that temp file. +:Git! {args} Like |:Git|, but capture the output into a temp file, +:Git --no-pager {args} and |:split| that temp file. Use :0Git to +:Git -P {args} |:edit| the temp file instead. A temp file is always + used for diff and log commands. *fugitive-:Gcd* :Gcd [directory] |:cd| relative to the repository. @@ -29,20 +37,16 @@ that are part of Git repositories). *fugitive-:Glcd* :Glcd [directory] |:lcd| relative to the repository. - *fugitive-:Gstatus* *fugitive-:G* -:G Bring up a summary window vaguely akin to git-status. -:Gstatus Press g? or see |fugitive-mappings| for usage. - *fugitive-:Gcommit* :Gcommit [args] A wrapper around git-commit. Unless the arguments given would skip the invocation of an editor (e.g., -m), a split window will be used to obtain a commit message, or a new tab if -v is given. Write and close - that window (:wq or |:Gwrite|) to finish the commit. - Unlike when running the actual git-commit command, it - is possible (but unadvisable) to alter the index with - commands like git-add and git-reset while a commit - message is pending. + the window (:wq) to finish the commit. To cancel, use + an empty message. + + *fugitive-:Grevert* +:Grevert [args] A wrapper around git-revert. Similar to |:Gcommit|. *fugitive-:Gmerge* :Gmerge [args] Calls git-merge and loads errors and conflicted files @@ -68,28 +72,25 @@ that are part of Git repositories). *fugitive-:Gfetch* :Gfetch [args] Like |:Gpush|, but for git-fetch. - *fugitive-:Ggrep* + *fugitive-:Ggrep* *fugitive-:Gcgrep* :Ggrep[!] [args] |:grep|[!] with git-grep as 'grepprg'. *fugitive-:Glgrep* :Glgrep[!] [args] |:lgrep|[!] with git-grep as 'grepprg'. - *fugitive-:Glog* -:Glog [args] Load the commit history into the |quickfix| list. - Additional git-log arguments can be given (for - example, --reverse). Provide "--" in the argument - list to target all commits. Otherwise, only commits - changing the current file will be targeted. This - special casing is slated to be removed. + *fugitive-:Gclog* *fugitive-:Glog* +:Gclog[!] [args] Use git-log [args] to load the commit history into the +:Glog[!] [args] |quickfix| list. Jump to the first commit unless [!] + is given. -:{range}Glog [args] Use git-log -L to load previous revisions of the given +:{range}Gclog[!] [args] Use git-log -L to load previous revisions of the given range of the current file into the |quickfix| list. The cursor is positioned on the first line of the - first diff hunk for each commit. Use :0Glog to target - the entire file. + first diff hunk for each commit. Use :0Gclog to + target the entire file. *fugitive-:Gllog* -:Gllog [args] Like |:Glog|, but use the location list instead of the +:Gllog [args] Like |:Gclog|, but use the location list instead of the |quickfix| list. *fugitive-:Gedit* *fugitive-:Ge* @@ -109,8 +110,10 @@ that are part of Git repositories). :Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!* :Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!* -:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a -:Gpedit! [args] split, tab, or preview window. +:Gtabedit! [args] Capture the output of `git [args]` to a temp file and +:Gpedit! [args] open it in a split, tab, or preview window. Use + :0Gsplit! to suppress the split and open it in the + current window. *fugitive-:Gread* :Gread [object] Empty the buffer and |:read| a |fugitive-object|. @@ -136,7 +139,7 @@ that are part of Git repositories). :Gwrite {path} You can give |:Gwrite| an explicit path of where in the work tree to write. You can also give a path like - :0:foo.txt or even :0 to write to just that stage in + :0:foo.txt or :0:% to write to just that stage in the index. *fugitive-:Gwq* @@ -146,25 +149,31 @@ that are part of Git repositories). :Gwq! [path] Like |:Gwrite|! followed by |:quit|! if the write succeeded. - *fugitive-:Gdiff* -:Gdiff [object] Perform a |vimdiff| against the given file, or if a + *fugitive-:Gdiffsplit* +:Gdiffsplit [object] Perform a |vimdiff| against the given file, or if a commit is given, the current file in that commit. - With no argument, the version in the index is used - (which means a three-way diff during a merge conflict, - making it a git-mergetool alternative). The newer of - the two files is placed to the right or bottom, - depending on 'diffopt', and the width of the window - relative to 'textwidth'. Use |do| and |dp| and write - to the index file to simulate "git add --patch". For - the three-way diff, there is also d2o and d3o pulling - the hunk to the middle from the left or the right - window, respectively. + With no argument, the version in the index or work + tree is used. The newer of the two files is placed to + the right or bottom, depending on 'diffopt' and the + width of the window relative to 'textwidth'. Use + Vim's |do| and |dp| to stage and unstage changes. - *fugitive-:Gsdiff* -:Gsdiff [object] Like |:Gdiff|, but always split horizontally. + *fugitive-:Gdiffsplit!* +:Gdiffsplit! Diff against any and all direct ancestors, retaining + focus on the current window. During a merge conflict, + this is a three-way diff against the "ours" and + "theirs" ancestors. Additional d2o and d3o maps are + provided to to obtain the hunk from the "ours" or + "theirs" ancestor, respectively. - *fugitive-:Gvdiff* -:Gvdiff [object] Like |:Gdiff|, but always split vertically. +:Gdiffsplit! {object} Like |:Gdiffsplit|, but retain focus on the current + window. + + *fugitive-:Gvdiffsplit* +:Gvdiffsplit [object] Like |:Gdiffsplit|, but always split vertically. + + *fugitive-:Ghdiffsplit* *fugitive-:Gsdiff* +:Ghdiffsplit [object] Like |:Gdiffsplit|, but always split horizontally. *fugitive-:Gmove* :Gmove {destination} Wrapper around git-mv that renames the buffer @@ -184,26 +193,31 @@ that are part of Git repositories). :Gremove Like :Gdelete, but keep the (now empty) buffer around. *fugitive-:Gblame* -:Gblame [flags] Run git-blame on the file and open the results in a - scroll bound vertical split. You can give any of - ltfnsewMC as flags and they will be passed along to - git-blame. The following maps, which work on the - cursor line commit where sensible, are provided: +:Gblame [flags] Run git-blame [flags] on the current file and open the + results in a scroll-bound vertical split. The + following maps, which work on the cursor line commit + where sensible, are provided: g? show this help A resize to end of author column C resize to end of commit column D resize to end of date/time column - q close blame and return to blamed window - gq q, then |:Gedit| to return to work tree version - <CR> q, then open commit - o open commit in horizontal split - O open commit in new tab - p open commit in preview window + gq close blame, then |:Gedit| to return to work + tree version + <CR> close blame, and jump to patch that added line + (or directly to blob for boundary commit) + o jump to patch or blob in horizontal split + O jump to patch or blob in new tab + p jump to patch or blob in preview window - reblame at commit ~ reblame at [count]th first grandparent P reblame at [count]th parent (like HEAD^[count]) +:[range]Gblame [flags] If a range is given, just that part of the file will +:Gblame [flags] {file} be blamed, and a horizontal split without + scrollbinding is used. You can also give an arbitrary + filename. + *fugitive-:Gbrowse* :Gbrowse Open the current file, blob, tree, commit, or tag in your browser at the upstream hosting provider. @@ -238,7 +252,7 @@ operate on the file or hunk under the cursor are generally available in visual mode to operate on multiple files or partial hunks. *fugitive-staging-mappings* -Staging and resetting mappings ~ +Staging/unstaging mappings ~ *fugitive_s* s Stage (add) the file or hunk under the cursor. @@ -249,11 +263,8 @@ u Unstage (reset) the file or hunk under the cursor. *fugitive_-* - Stage or unstage the file or hunk under the cursor. - *fugitive_CTRL-N* -<C-N> Skip to the next file or hunk. - - *fugitive_CTRL-P* -<C-P> Skip to the previous file or hunk. + *fugitive_U* +U Unstage everything. *fugitive_X* X Discard the change under the cursor. This uses @@ -267,39 +278,53 @@ X Discard the change under the cursor. This uses *fugitive_=* = Toggle an inline diff of the file under the cursor. - *fugitive_<* -< Insert an inline diff of the file under the cursor. - *fugitive_>* -> Remove the inline diff of the file under the cursor. +> Insert an inline diff of the file under the cursor. - *fugitive_i* -i On untracked files, call |:Git| add --intent-to-add. - Otherwise, move to next hunk, expanding inline diffs - automatically. + *fugitive_<* +< Remove the inline diff of the file under the cursor. - *fugitive_dd* -dd Perform a |:Gdiff| on the file under the cursor. + *fugitive_gI* +gI Open .git/info/exclude in a split and add the file + under the cursor. Use a count to open .gitignore. - *fugitive_ds* -ds Perform a |:Gsdiff| on the file under the cursor. - - *fugitive_dv* -dv Perform a |:Gvdiff| on the file under the cursor. + *fugitive_I* +I Invoke |:Git| add --patch or reset --patch on the file +P under the cursor. On untracked files, this instead + calls |:Git| add --intent-to-add. + *fugitive_d* +Diff mappings ~ *fugitive_dp* dp Invoke |:Git!| diff on the file under the cursor. - Deprecated in favor of inline diffs. On untracked - files, this instead calls |:Git| add --intent-to-add. + Deprecated in favor of inline diffs. -P Invoke |:Git| add --patch or reset --patch on the file - under the cursor. + *fugitive_dd* +dd Perform a |:Gdiffsplit| on the file under the cursor. + + *fugitive_dv* +dv Perform a |:Gvdiffsplit| on the file under the cursor. + + *fugitive_ds* *fugitive_dh* +ds Perform a |:Ghdiffsplit| on the file under the cursor. +dh + *fugitive_dq* +dq Close all but one diff buffer, and |:diffoff|! the + last one. + + *fugitive_d?* +d? Show this help. *fugitive-navigation-mappings* Navigation mappings ~ *fugitive_<CR>* <CR> Open the file or |fugitive-object| under the cursor. + in a blob, this and similar maps jump to the patch + from the diff where this was added, or where it was + removed if a count was given. If the line is still in + the work tree version, passing a count takes you to + it. *fugitive_o* o Open the file or |fugitive-object| under the cursor in @@ -313,6 +338,11 @@ gO Open the file or |fugitive-object| under the cursor in O Open the file or |fugitive-object| under the cursor in a new tab. + *fugitive_p* +p Open the file or |fugitive-object| under the cursor in + a preview window. In the status buffer, 1p is + required to bypass the legacy usage instructions. + *fugitive_~* ~ Open the current file in the [count]th first ancestor. @@ -322,9 +352,78 @@ P Open the current file in the [count]th parent. *fugitive_C* C Open the commit containing the current file. - *fugitive_CTRL-W_C* -<C-W>C Open the commit containing the current file in a new - split. + *fugitive_CTRL-P* *fugitive_(* +( Jump to the previous file, hunk, or revision. + + *fugitive_CTRL-N* *fugitive_)* +) Jump to the next file, hunk, or revision. + + *fugitive_[c* +[c Jump to previous hunk, expanding inline diffs + automatically. (This shadows the Vim built-in |[c| + that provides a similar operation in |diff| mode.) + + *fugitive_]c* +]c Jump to next hunk, expanding inline diffs + automatically. (This shadows the Vim built-in |]c| + that provides a similar operation in |diff| mode.) + + *fugitive_[/* *fugitive_[m* +[/ Jump to previous file, collapsing inline diffs +[m automatically. (Mnemonic: "/" appears in filenames, + "m" appears in "filenames".) + + *fugitive_]/* *fugitive_]m* +]/ Jump to next file, collapsing inline diffs +]m automatically. (Mnemonic: "/" appears in filenames, + "m" appears in "filenames".) + + *fugitive_i* +i Jump to the next file or hunk, expanding inline diffs + automatically. + + *fugitive_[[* +[[ Jump [count] sections backward. + + *fugitive_]]* +]] Jump [count] sections forward. + + *fugitive_[]* +[] Jump [count] section ends backward. + + *fugitive_][* +][ Jump [count] section ends forward. + + *fugitive_star* +* One the first column of a + or - diff line, search for + the corresponding - or + line. Otherwise, defer to + built-in |star|. + + *fugitive_#* +# Same as "*", but search backward. + + *fugitive_gu* +gu Jump to file [count] in the "Untracked" or "Unstaged" + section. + + *fugitive_gU* +gU Jump to file [count] in the "Unstaged" section. + + *fugitive_gs* +gs Jump to file [count] in the "Staged" section. + + *fugitive_gp* +gp Jump to file [count] in the "Unpushed" section. + + *fugitive_gP* +gP Jump to file [count] in the "Unpulled" section. + + *fugitive_gr* +gr Jump to file [count] in the "Rebasing" section. + + *fugitive_gi* +gi Open .git/info/exclude in a split. Use a count to + open .gitignore. *fugitive_c* Commit mappings ~ @@ -344,17 +443,74 @@ cva Amend the last commit with -v cf Create a `fixup!` commit for the commit under the cursor. +cF Create a `fixup!` commit for the commit under the + cursor and immediately rebase it. + cs Create a `squash!` commit for the commit under the cursor. +cS Create a `squash!` commit for the commit under the + cursor and immediately rebase it. + cA Create a `squash!` commit for the commit under the cursor and edit the message. +c<Space> Populate command line with ":Gcommit ". + + *fugitive_cr* +crc Revert the commit under the cursor. + +crn Revert the commit under the cursor in the index and + work tree, but do not actually commit the changes. + +cr<Space> Populate command line with ":Grevert ". + + *fugitive_cm* +cm<Space> Populate command line with ":Gmerge ". + +c? Show this help. + + *fugitive_cb* + *fugitive_co* +Checkout/branch mappings ~ + +coo Check out the commit under the cursor. + +cb<Space> Populate command line with ":G branch ". + +co<Space> Populate command line with ":G checkout ". + +cb? Show this help. +co? + + *fugitive_cz* +Stash mappings ~ + +czz Push stash. Pass a [count] of 1 to add + `--include-untracked` or 2 to add `--all`. + +czw Push stash of worktree. Like `czz` with + `--include-index`. + +czA Apply topmost stash, or stash@{count}. + +cza Apply topmost stash, or stash@{count}, preserving the + index. + +czP Pop topmost stash, or stash@{count}. + +czp Pop topmost stash, or stash@{count}, preserving the + index. + +cz<Space> Populate command line with ":G stash ". + +cz? Show this help. + *fugitive_r* Rebase mappings ~ ri Perform an interactive rebase. Uses ancestor of - commit under cursor as upstream if available. +u commit under cursor as upstream if available. rf Perform an autosquash rebase without editing the todo list. Uses ancestor of commit under cursor as @@ -382,21 +538,22 @@ rm Perform an interactive rebase with the commit under rd Perform an interactive rebase with the commit under the cursor set to `drop`. +r<Space> Populate command line with ":Grebase ". + +r? Show this help. + *fugitive-misc-mappings* Miscellaneous mappings ~ *fugitive_gq* *fugitive_q* gq Close the status buffer. - *fugitive_R* -R Reload the status buffer. - *fugitive_.* . Start a |:| command line with the file under the cursor prepopulated. *fugitive_g?* -g? Open this help. +g? Show help for |fugitive-mappings|. *fugitive-global-mappings* Global mappings ~ @@ -418,12 +575,13 @@ optional object, the default is the file in the index for work tree files and the work tree file for everything else. Example objects follow. Object Meaning ~ -HEAD .git/HEAD -refs/heads/x .git/refs/heads/x (in "common dir" if present) @ The commit referenced by @ aka HEAD +master The commit referenced by master master^ The parent of the commit referenced by master +master...other The merge base of master and other master: The tree referenced by master ./master The file named master in the working directory +:(top)master The file named master in the the work tree Makefile The file named Makefile in the work tree @^:Makefile The file named Makefile in the parent of HEAD :Makefile The file named Makefile in the index (writable) @@ -457,6 +615,6 @@ ABOUT *fugitive-about* Grab the latest version or report a bug on GitHub: -http://github.com/tpope/vim-fugitive +https://github.com/tpope/vim-fugitive vim:tw=78:et:ft=help:norl: diff --git a/sources_non_forked/vim-fugitive/plugin/fugitive.vim b/sources_non_forked/vim-fugitive/plugin/fugitive.vim index 9d23a7dd..b7d191fd 100644 --- a/sources_non_forked/vim-fugitive/plugin/fugitive.vim +++ b/sources_non_forked/vim-fugitive/plugin/fugitive.vim @@ -1,6 +1,6 @@ " fugitive.vim - A Git wrapper so awesome, it should be illegal " Maintainer: Tim Pope <http://tpo.pe/> -" Version: 2.5 +" Version: 3.0 " GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim if exists('g:loaded_fugitive') @@ -20,18 +20,14 @@ function! FugitiveGitDir(...) abort endif endfunction -function! FugitiveCommonDir(...) abort - let dir = FugitiveGitDir(a:0 ? a:1 : -1) - if empty(dir) - return '' - endif - return fugitive#CommonDir(dir) -endfunction - -function! FugitiveWorkTree(...) abort - return s:Tree(FugitiveGitDir(a:0 ? a:1 : -1)) -endfunction - +" FugitiveReal() takes a fugitive:// URL and returns the corresponding path in +" the work tree. This may be useful to get a cleaner path for inclusion in +" the statusline, for example. Note that the file and its parent directories +" are not guaranteed to exist. +" +" This is intended as an abstract API to be used on any "virtual" path. For a +" buffer named foo://bar, check for a function named FooReal(), and if it +" exists, call FooReal("foo://bar"). function! FugitiveReal(...) abort let file = a:0 ? a:1 : @% if file =~# '^\a\a\+:' || a:0 > 1 @@ -43,6 +39,13 @@ function! FugitiveReal(...) abort endif endfunction +" FugitiveFind() takes a Fugitive object and returns the appropriate Vim +" buffer name. You can use this to generate Fugitive URLs ("HEAD:README") or +" to get the absolute path to a file in the Git dir (".git/HEAD"), the common +" dir (".git/config"), or the work tree (":(top)Makefile"). +" +" An optional second argument provides the Git dir, or the buffer number of a +" buffer with a Git dir. The default is the current buffer. function! FugitiveFind(...) abort return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1)) endfunction @@ -55,12 +58,15 @@ function! FugitivePath(...) abort endif endfunction +" FugitiveParse() takes a fugitive:// URL and returns a 2 element list +" containing the Git dir and an object name ("commit:file"). It's effectively +" then inverse of FugitiveFind(). function! FugitiveParse(...) abort let path = s:Slash(a:0 ? a:1 : @%) if path !~# '^fugitive:' return ['', ''] endif - let vals = matchlist(path, '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40\}\|[0-3]\)\(/.*\)\=$') + let vals = matchlist(path, '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40,\}\|[0-3]\)\(/.*\)\=$') if len(vals) return [(vals[2] =~# '^.$' ? ':' : '') . vals[2] . substitute(vals[3], '^/', ':', ''), vals[1]] endif @@ -68,6 +74,14 @@ function! FugitiveParse(...) abort throw v:errmsg endfunction +" FugitivePrepare() constructs a Git command string which can be executed with +" functions like system() and commands like :!. Integer arguments will be +" treated as buffer numbers, and the appropriate relative path inserted in +" their place. +" +" If the first argument is a string that looks like a path or an empty string, +" it will be used as the Git dir. If it's a buffer number, the Git dir for +" that buffer will be used. The default is the current buffer. function! FugitivePrepare(...) abort return call('fugitive#Prepare', a:000) endfunction @@ -101,9 +115,21 @@ function! FugitiveStatusline(...) abort return fugitive#Statusline() endfunction +function! FugitiveCommonDir(...) abort + let dir = FugitiveGitDir(a:0 ? a:1 : -1) + if empty(dir) + return '' + endif + return fugitive#CommonDir(dir) +endfunction + +function! FugitiveWorkTree(...) abort + return s:Tree(FugitiveGitDir(a:0 ? a:1 : -1)) +endfunction + function! FugitiveIsGitDir(path) abort let path = substitute(a:path, '[\/]$', '', '') . '/' - return getfsize(path.'HEAD') > 10 && ( + return len(a:path) && getfsize(path.'HEAD') > 10 && ( \ isdirectory(path.'objects') && isdirectory(path.'refs') || \ getftype(path.'commondir') ==# 'file') endfunction @@ -124,10 +150,10 @@ function! s:Tree(path) abort let config = readfile(config_file,'',10) call filter(config,'v:val =~# "^\\s*worktree *="') if len(config) == 1 - let worktree = matchstr(config[0], '= *\zs.*') + let worktree = s:Slash(FugitiveVimPath(matchstr(config[0], '= *\zs.*'))) endif elseif filereadable(dir . '/gitdir') - let worktree = fnamemodify(readfile(dir . '/gitdir')[0], ':h') + let worktree = s:Slash(fnamemodify(FugitiveVimPath(readfile(dir . '/gitdir')[0]), ':h')) if worktree ==# '.' unlet! worktree endif @@ -159,9 +185,11 @@ function! FugitiveExtractGitDir(path) abort endif let root = resolve(path) if root !=# path - silent! exe haslocaldir() ? 'lcd .' : 'cd .' + silent! exe (haslocaldir() ? 'lcd' : exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd') '.' endif let previous = "" + let env_git_dir = len($GIT_DIR) ? s:Slash(simplify(fnamemodify(FugitiveVimPath($GIT_DIR), ':p:s?[\/]$??'))) : '' + call s:Tree(env_git_dir) while root !=# previous if root =~# '\v^//%([^/]+/?)?$' break @@ -169,14 +197,10 @@ function! FugitiveExtractGitDir(path) abort if index(split($GIT_CEILING_DIRECTORIES, ':'), root) >= 0 break endif - if root ==# $GIT_WORK_TREE && FugitiveIsGitDir($GIT_DIR) - return simplify(fnamemodify($GIT_DIR, ':p:s?[\/]$??')) - endif - if FugitiveIsGitDir($GIT_DIR) - call s:Tree(simplify(fnamemodify($GIT_DIR, ':p:s?[\/]$??'))) - if has_key(s:dir_for_worktree, root) - return s:dir_for_worktree[root] - endif + if root ==# $GIT_WORK_TREE && FugitiveIsGitDir(env_git_dir) + return env_git_dir + elseif has_key(s:dir_for_worktree, root) + return s:dir_for_worktree[root] endif let dir = substitute(root, '[\/]$', '', '') . '/.git' let type = getftype(dir) @@ -186,10 +210,11 @@ function! FugitiveExtractGitDir(path) abort return resolve(dir) elseif type !=# '' && filereadable(dir) let line = get(readfile(dir, '', 1), 0, '') - if line =~# '^gitdir: \.' && FugitiveIsGitDir(root.'/'.line[8:-1]) - return simplify(root.'/'.line[8:-1]) - elseif line =~# '^gitdir: ' && FugitiveIsGitDir(line[8:-1]) - return line[8:-1] + let file_dir = s:Slash(FugitiveVimPath(matchstr(line, '^gitdir: \zs.*'))) + if file_dir !~# '^/\|^\a:' && FugitiveIsGitDir(root . '/' . file_dir) + return simplify(root . '/' . file_dir) + elseif len(file_dir) && FugitiveIsGitDir(file_dir) + return file_dir endif elseif FugitiveIsGitDir(root) return root @@ -215,6 +240,18 @@ function! FugitiveDetect(path) abort endif endfunction +function! FugitiveVimPath(path) abort + if exists('+shellslash') && !&shellslash + return tr(a:path, '/', '\') + else + return a:path + endif +endfunction + +function! FugitiveGitPath(path) abort + return s:Slash(a:path) +endfunction + function! s:Slash(path) abort if exists('+shellslash') return tr(a:path, '\', '/') @@ -234,7 +271,10 @@ function! s:ProjectionistDetect() abort if exists('+shellslash') && !&shellslash let base = tr(base, '/', '\') endif - call projectionist#append(base, FugitiveCommonDir(dir) . '/info/projections.json') + let file = FugitiveCommonDir(dir) . '/info/projections.json' + if filereadable(file) + call projectionist#append(base, file) + endif endif endfunction @@ -266,7 +306,7 @@ augroup fugitive autocmd FileType gitrebase \ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' | \ if len(FugitiveGitDir()) | - \ let &l:includeexpr = 'v:fname =~# ''^\x\{4,40\}$'' ? FugitiveFind(v:fname) : ' . + \ let &l:includeexpr = 'v:fname =~# ''^\x\{4,\}$'' ? FugitiveFind(v:fname) : ' . \ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') | \ endif | \ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc=' @@ -296,3 +336,20 @@ augroup fugitive autocmd User ProjectionistDetect call s:ProjectionistDetect() augroup END + +let g:io_fugitive = { + \ 'simplify': function('fugitive#simplify'), + \ 'resolve': function('fugitive#resolve'), + \ 'getftime': function('fugitive#getftime'), + \ 'getfsize': function('fugitive#getfsize'), + \ 'getftype': function('fugitive#getftype'), + \ 'filereadable': function('fugitive#filereadable'), + \ 'filewritable': function('fugitive#filewritable'), + \ 'isdirectory': function('fugitive#isdirectory'), + \ 'getfperm': function('fugitive#getfperm'), + \ 'setfperm': function('fugitive#setfperm'), + \ 'readfile': function('fugitive#readfile'), + \ 'writefile': function('fugitive#writefile'), + \ 'glob': function('fugitive#glob'), + \ 'delete': function('fugitive#delete'), + \ 'Real': function('FugitiveReal')} diff --git a/sources_non_forked/vim-fugitive/syntax/fugitive.vim b/sources_non_forked/vim-fugitive/syntax/fugitive.vim index e2389b5c..afc0c0bc 100644 --- a/sources_non_forked/vim-fugitive/syntax/fugitive.vim +++ b/sources_non_forked/vim-fugitive/syntax/fugitive.vim @@ -9,24 +9,39 @@ syn include @fugitiveDiff syntax/diff.vim syn match fugitiveHeader /^[A-Z][a-z][^:]*:/ nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite -syn region fugitiveSection start=/^\%(.*(\d\+)$\)\@=/ contains=fugitiveHeading end=/^$\@=/ +syn region fugitiveSection start=/^\%(.*(\d\+)$\)\@=/ contains=fugitiveHeading end=/^$/ +syn cluster fugitiveSection contains=fugitiveSection syn match fugitiveHeading /^[A-Z][a-z][^:]*\ze (\d\+)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite syn match fugitiveCount /(\d\+)/hs=s+1,he=e-1 contained syn match fugitivePreposition /\<\%([io]nto\|from\|to\|Rebasing\%( detached\)\=\)\>/ transparent contained nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite -syn match fugitiveInstruction /^\l\l\+\>/ contained containedin=fugitiveSection nextgroup=fugitiveHash skipwhite -syn match fugitiveDone /^done\>/ contained containedin=fugitiveSection nextgroup=fugitiveHash skipwhite -syn match fugitiveStop /^stop\>/ contained containedin=fugitiveSection nextgroup=fugitiveHash skipwhite -syn match fugitiveModifier /^[MADRCU?]\{1,2} / contained containedin=fugitiveSection -syn match FugitiveSymbolicRef /\.\@!\%(\.\.\@!\|[^[:space:][:cntrl:]\:.]\)\+\.\@<!/ contained -syn match fugitiveHash /^\x\{4,\}\>/ contained containedin=fugitiveSection +syn match fugitiveInstruction /^\l\l\+\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite +syn match fugitiveDone /^done\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite +syn match fugitiveStop /^stop\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite +syn match fugitiveModifier /^[MADRCU?]\{1,2} / contained containedin=@fugitiveSection +syn match fugitiveSymbolicRef /\.\@!\%(\.\.\@!\|[^[:space:][:cntrl:]\:.]\)\+\.\@<!/ contained +syn match fugitiveHash /^\x\{4,\}\>/ contained containedin=@fugitiveSection syn match fugitiveHash /\<\x\{4,\}\>/ contained -syn region fugitiveHunk start=/^\%(@@ -\)\@=/ end=/^\%([A-Za-z?@]\|$\)\@=/ contains=@fugitiveDiff containedin=fugitiveSection fold +syn region fugitiveHunk start=/^\%(@@\+ -\)\@=/ end=/^\%([A-Za-z?@]\|$\)\@=/ contains=@fugitiveDiff containedin=@fugitiveSection fold + +for s:section in ['Untracked', 'Unstaged', 'Staged'] + exe 'syn region fugitive' . s:section . 'Section start=/^\%(' . s:section . ' .*(\d\+)$\)\@=/ contains=fugitive' . s:section . 'Heading end=/^$/' + exe 'syn match fugitive' . s:section . 'Modifier /^[MADRCU?] / contained containedin=fugitive' . s:section . 'Section' + exe 'syn cluster fugitiveSection add=fugitive' . s:section . 'Section' + exe 'syn match fugitive' . s:section . 'Heading /^[A-Z][a-z][^:]*\ze (\d\+)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite' +endfor +unlet s:section hi def link fugitiveHeader Label hi def link fugitiveHeading PreProc +hi def link fugitiveUntrackedHeading PreCondit +hi def link fugitiveUnstagedHeading Macro +hi def link fugitiveStagedHeading Include hi def link fugitiveModifier Type +hi def link fugitiveUntrackedModifier StorageClass +hi def link fugitiveUnstagedModifier Structure +hi def link fugitiveStagedModifier Typedef hi def link fugitiveInstruction Type hi def link fugitiveStop Function hi def link fugitiveHash Identifier diff --git a/sources_non_forked/vim-fugitive/syntax/fugitiveblame.vim b/sources_non_forked/vim-fugitive/syntax/fugitiveblame.vim new file mode 100644 index 00000000..c06d19e0 --- /dev/null +++ b/sources_non_forked/vim-fugitive/syntax/fugitiveblame.vim @@ -0,0 +1,7 @@ +if exists("b:current_syntax") + finish +endif + +call fugitive#BlameSyntax() + +let b:current_syntax = "fugitiveblame" diff --git a/sources_non_forked/vim-gitgutter/.github/issue_template.md b/sources_non_forked/vim-gitgutter/.github/issue_template.md index 732d22ef..d700ce98 100644 --- a/sources_non_forked/vim-gitgutter/.github/issue_template.md +++ b/sources_non_forked/vim-gitgutter/.github/issue_template.md @@ -2,7 +2,3 @@ > What vim/nvim version are you on? -> If no signs are showing at all, what does `:echo b:gitgutter.path` give? - -> If no signs are showing at all, and the `path` value is a path and not `-2`, does it work with `let g:gitgutter_grep=''`? - diff --git a/sources_non_forked/vim-gitgutter/README.mkd b/sources_non_forked/vim-gitgutter/README.mkd index a08507b0..3261f905 100644 --- a/sources_non_forked/vim-gitgutter/README.mkd +++ b/sources_non_forked/vim-gitgutter/README.mkd @@ -12,12 +12,14 @@ Features: * Never saves the buffer. * Quick jumping between blocks of changed lines ("hunks"). * Stage/undo/preview individual hunks. +* Stage partial hunks. * Provides a hunk text object. * Diffs against index (default) or any commit. * Allows folding all unchanged text. * Handles line endings correctly, even with repos that do CRLF conversion. * Optional line highlighting. -* Fully customisable (signs, sign column, line highlights, mappings, extra git-diff arguments, etc). +* Optional line number highlighting. (Only available in Neovim 0.3.2 or higher) +* Fully customisable (signs, sign column, line (number) highlights, mappings, extra git-diff arguments, etc). * Can be toggled on/off, globally or per buffer. * Preserves signs from other plugins. * Easy to integrate diff stats into status line; built-in integration with [vim-airline](https://github.com/bling/vim-airline/). @@ -26,7 +28,7 @@ Features: Constraints: * Supports git only. If you work with other version control systems, I recommend [vim-signify](https://github.com/mhinz/vim-signify). -* Relies on the `FocusGained` event. If your terminal doesn't report focus events, either use something like [Terminus][] or set `let g:gitgutter_terminal_reports_focus=0`. +* Relies on the `FocusGained` event. If your terminal doesn't report focus events, either use something like [Terminus][] or set `let g:gitgutter_terminal_reports_focus=0`. For tmux, `set -g focus-events on` in your tmux.conf. ### Screenshot @@ -103,6 +105,17 @@ cp -r vim-gitgutter/* ~/.vim/ See `:help add-global-plugin`. +### Windows + +I recommend configuring vim-gitgutter with the full path to your git executable. For example: + +```viml +let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe' +``` + +This is to avoid a problem which occurs if you have file named `git.*` (i.e. with any extension in `PATHEXT`) in your current folder. `cmd.exe` prioritises the current folder over folders in `PATH` and will try to execute your file instead of the `git` binary. + + ### Getting started When you make a change to a file tracked by git, the diff markers should appear automatically. The delay is governed by vim's `updatetime` option; the default value is `4000`, i.e. 4 seconds, but I suggest reducing it to around 100ms (add `set updatetime=100` to your vimrc). @@ -138,9 +151,15 @@ And you can turn line highlighting on and off (defaults to off): * turn off with `:GitGutterLineHighlightsDisable` * toggle with `:GitGutterLineHighlightsToggle`. +With Neovim 0.3.2 or higher, you can turn line number highlighting on and off (defaults to off): + +* turn on with `:GitGutterLineNrHighlightsEnable` +* turn off with `:GitGutterLineNrHighlightsDisable` +* toggle with `:GitGutterLineNrHighlightsToggle`. + Note that if you have line highlighting on and signs off, you will have an empty sign column – more accurately, a sign column with invisible signs. This is because line highlighting requires signs and Vim always shows the sign column even if the signs are invisible. -If you switch off both line highlighting and signs, you won't see the sign column. That is unless you configure the sign column always to be there (see Sign Column section). +If you switch off both line highlighting and signs, you won't see the sign column. To keep your Vim snappy, vim-gitgutter will suppress the signs when a file has more than 500 changes. As soon as the number of changes falls below the limit vim-gitgutter will show the signs again. You can configure the threshold with: @@ -169,6 +188,18 @@ You can stage or undo an individual hunk when your cursor is in it: * stage the hunk with `<Leader>hs` or * undo it with `<Leader>hu`. +To stage part of an additions-only hunk by: + +* either visually selecting the part you want and staging with your mapping, e.g. `<Leader>hs`; +* or using a range with the `GitGutterStageHunk` command, e.g. `:42,45GitGutterStageHunk`. + +To stage part of any hunk: + +* preview the hunk, e.g. `<Leader>hp`; +* move to the preview window, e.g. `:wincmd P`; +* delete the lines you do not want to stage; +* stage the remaining lines: either write (`:w`) the window or stage via `<Leader>hs` or `:GitGutterStageHunk`. + See the FAQ if you want to unstage staged changes. The `.` command will work with both these if you install [repeat.vim](https://github.com/tpope/vim-repeat). @@ -180,7 +211,7 @@ nmap <Leader>ha <Plug>GitGutterStageHunk nmap <Leader>hr <Plug>GitGutterUndoHunk ``` -And you can preview a hunk's changes with `<Leader>hp`. You can of course change this mapping, e.g: +And you can preview a hunk's changes with `<Leader>hp`. The location of the preview window is configured with `g:gitgutter_preview_win_location` (default `'bo'`). You can of course change this mapping, e.g: ```viml nmap <Leader>hv <Plug>GitGutterPreviewHunk @@ -224,18 +255,20 @@ You can customise: * The sign column's colours * Whether or not the sign column is shown when there aren't any signs (defaults to no) +* How to handle non-gitgutter signs * The signs' colours and symbols * Line highlights * The base of the diff * Extra arguments for `git` when running `git diff` * Extra arguments for `git diff` * Key mappings -* Whether or not vim-gitgutter is on initially (defaults to on) -* Whether or not signs are shown (defaults to yes) -* Whether or not line highlighting is on initially (defaults to off) -* Whether or not vim-gitgutter runs in "realtime" (defaults to yes) -* Whether or not vim-gitgutter runs eagerly (defaults to yes) -* Whether or not vim-gitgutter runs asynchronously (defaults to yes) +* Whether vim-gitgutter is on initially (defaults to on) +* Whether signs are shown (defaults to yes) +* Whether line highlighting is on initially (defaults to off) +* Whether line number highlighting is on initially (defaults to off) +* Whether vim-gitgutter runs asynchronously (defaults to yes) +* Whether to clobber or preserve non-gitgutter signs +* The priority of gitgutter's signs. Please note that vim-gitgutter won't override any colours or highlights you've set in your colorscheme. @@ -260,11 +293,14 @@ highlight SignColumn guibg=whatever " gVim/MacVim By default the sign column will appear when there are signs to show and disappear when there aren't. To always have the sign column, add to your vimrc: ```viml -if exists('&signcolumn') " Vim 7.4.2201 - set signcolumn=yes -else - let g:gitgutter_sign_column_always = 1 -endif +" Vim 7.4.2201 +set signcolumn=yes +``` + +GitGutter can preserve or ignore non-gitgutter signs. For Vim v8.1.0614 and later you can set gitgutter's signs' priorities with `g:gitgutter_sign_priority`, so gitgutter defaults to clobbering other signs. For Neovim v0.4.0 and later you can set an expanding sign column so gitgutter again defaults to clobbering other signs. Otherwise, gitgutter defaults to preserving other signs. You can configure this with: + +```viml +let g:gitgutter_sign_allow_clobber = 1 ``` @@ -324,6 +360,26 @@ highlight link GitGutterChangeLine DiffText ``` +#### Line number highlights + +NOTE: This feature requires Neovim 0.3.2 or higher. + +Similarly to the signs' colours, set up the following highlight groups in your colorscheme or `~/.vimrc`: + +```viml +GitGutterAddLineNr " default: links to CursorLineNr +GitGutterChangeLineNr " default: links to CursorLineNr +GitGutterDeleteLineNr " default: links to CursorLineNr +GitGutterChangeDeleteLineNr " default: links to CursorLineNr +``` + +Maybe you think `CursorLineNr` is a bit annoying. For example, you could use `Underlined` for this: + +```viml +highlight link GitGutterChangeLineNr Underlined +``` + + #### The base of the diff By default buffers are diffed against the index. However you can diff against any commit by setting: @@ -384,6 +440,11 @@ Add `let g:gitgutter_signs = 0` to your `~/.vimrc`. Add `let g:gitgutter_highlight_lines = 1` to your `~/.vimrc`. +#### To turn on line number highlighting by default + +Add `let g:gitgutter_highlight_linenrs = 1` to your `~/.vimrc`. + + #### To turn off asynchronous updates By default diffs are run asynchronously. To run diffs synchronously instead: @@ -532,7 +593,7 @@ Your colorscheme is configuring the `SignColumn` highlight group weirdly. Pleas > What happens if I also use another plugin which uses signs (e.g. Syntastic)? -Vim only allows one sign per line. Before adding a sign to a line, vim-gitgutter checks whether a sign has already been added by somebody else. If so it doesn't do anything. In other words vim-gitgutter won't overwrite another plugin's signs. It also won't remove another plugin's signs. +You can configure whether GitGutter preserves or clobbers other signs using `g:gitgutter_sign_allow_clobber`. Set to `1` to clobber other signs (default on Vim >= 8.1.0614 and NeoVim >= 0.4.0) or `0` to preserve them. ### Troubleshooting @@ -557,7 +618,7 @@ Here are some things you can check: #### When signs don't update after focusing Vim -* Your terminal probably isn't reporting focus events. Either try installing [Terminus][] or set `let g:gitgutter_terminal_reports_focus=0`. +* Your terminal probably isn't reporting focus events. Either try installing [Terminus][] or set `let g:gitgutter_terminal_reports_focus=0`. For tmux, try `set -g focus-events on` in your tmux.conf. ### Shameless Plug diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim index 2e17fdb8..98188713 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim @@ -10,7 +10,6 @@ function! gitgutter#all(force) abort let file = expand('#'.bufnr.':p') if !empty(file) if index(visible, bufnr) != -1 - call gitgutter#init_buffer(bufnr) call gitgutter#process_buffer(bufnr, a:force) elseif a:force call s:reset_tick(bufnr) @@ -21,22 +20,21 @@ function! gitgutter#all(force) abort endfunction -" Finds the file's path relative to the repo root. -function! gitgutter#init_buffer(bufnr) - if gitgutter#utility#is_active(a:bufnr) - let p = gitgutter#utility#repo_path(a:bufnr, 0) - if type(p) != s:t_string || empty(p) - call gitgutter#utility#set_repo_path(a:bufnr) - call s:setup_maps() - endif - endif -endfunction - - function! gitgutter#process_buffer(bufnr, force) abort " NOTE a:bufnr is not necessarily the current buffer. if gitgutter#utility#is_active(a:bufnr) + + if has('patch-7.4.1559') + let l:Callback = function('gitgutter#process_buffer', [a:bufnr, a:force]) + else + let l:Callback = {'function': 'gitgutter#process_buffer', 'arguments': [a:bufnr, a:force]} + endif + let how = s:setup_path(a:bufnr, l:Callback) + if [how] == ['async'] " avoid string-to-number conversion if how is a number + return + endif + if a:force || s:has_fresh_changes(a:bufnr) let diff = '' @@ -108,11 +106,19 @@ endfunction " }}} -function! s:setup_maps() +function! gitgutter#setup_maps() if !g:gitgutter_map_keys return endif + " Note hasmapto() and maparg() operate on the current buffer. + + let bufnr = bufnr('') + + if gitgutter#utility#getbufvar(bufnr, 'mapped', 0) + return + endif + if !hasmapto('<Plug>GitGutterPrevHunk') && maparg('[c', 'n') ==# '' nmap <buffer> [c <Plug>GitGutterPrevHunk endif @@ -120,7 +126,10 @@ function! s:setup_maps() nmap <buffer> ]c <Plug>GitGutterNextHunk endif - if !hasmapto('<Plug>GitGutterStageHunk') && maparg('<Leader>hs', 'n') ==# '' + if !hasmapto('<Plug>GitGutterStageHunk', 'v') && maparg('<Leader>hs', 'x') ==# '' + xmap <buffer> <Leader>hs <Plug>GitGutterStageHunk + endif + if !hasmapto('<Plug>GitGutterStageHunk', 'n') && maparg('<Leader>hs', 'n') ==# '' nmap <buffer> <Leader>hs <Plug>GitGutterStageHunk endif if !hasmapto('<Plug>GitGutterUndoHunk') && maparg('<Leader>hu', 'n') ==# '' @@ -142,6 +151,18 @@ function! s:setup_maps() if !hasmapto('<Plug>GitGutterTextObjectOuterVisual') && maparg('ac', 'x') ==# '' xmap <buffer> ac <Plug>GitGutterTextObjectOuterVisual endif + + call gitgutter#utility#setbufvar(bufnr, 'mapped', 1) +endfunction + +function! s:setup_path(bufnr, continuation) + let p = gitgutter#utility#repo_path(a:bufnr, 0) + + if type(p) == s:t_string && !empty(p) " if path is known + return + endif + + return gitgutter#utility#set_repo_path(a:bufnr, a:continuation) endfunction function! s:has_fresh_changes(bufnr) abort @@ -154,7 +175,7 @@ endfunction function! s:clear(bufnr) call gitgutter#sign#clear_signs(a:bufnr) - call gitgutter#sign#remove_dummy_sign(a:bufnr, 1) call gitgutter#hunk#reset(a:bufnr) call s:reset_tick(a:bufnr) + call gitgutter#utility#setbufvar(a:bufnr, 'path', '') endfunction diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim index b270db73..99861cca 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim @@ -4,7 +4,7 @@ let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@' " True for git v1.7.2+. function! s:git_supports_command_line_config_override() abort - call system(g:gitgutter_git_executable.' -c foo.bar=baz --version') + call system(g:gitgutter_git_executable.' '.g:gitgutter_git_args.' -c foo.bar=baz --version') return !v:shell_error endfunction @@ -68,9 +68,9 @@ let s:counter = 0 " the hunk headers (@@ -x,y +m,n @@); only possible if " grep is available. function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort - while gitgutter#utility#repo_path(a:bufnr, 0) == -1 - sleep 5m - endwhile + if gitgutter#utility#repo_path(a:bufnr, 0) == -1 + throw 'gitgutter author fail' + endif if gitgutter#utility#repo_path(a:bufnr, 0) == -2 throw 'gitgutter not tracked' @@ -119,14 +119,14 @@ function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort " Write file from index to temporary file. let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1) - let cmd .= g:gitgutter_git_executable.' --no-pager show '.index_name.' > '.from_file.' && ' + let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager show '.index_name.' > '.from_file.' && ' elseif a:from ==# 'working_tree' let from_file = gitgutter#utility#repo_path(a:bufnr, 1) endif " Call git-diff. - let cmd .= g:gitgutter_git_executable.' --no-pager '.g:gitgutter_git_args + let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager '.g:gitgutter_git_args if s:c_flag let cmd .= ' -c "diff.autorefreshindex=0"' let cmd .= ' -c "diff.noprefix=false"' diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim index 160856f7..5b14fc30 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim @@ -4,7 +4,6 @@ function! gitgutter#highlight#line_disable() abort if !g:gitgutter_signs call gitgutter#sign#clear_signs(bufnr('')) - call gitgutter#sign#remove_dummy_sign(bufnr(''), 0) endif redraw! @@ -31,6 +30,38 @@ function! gitgutter#highlight#line_toggle() abort endif endfunction +function! gitgutter#highlight#linenr_disable() abort + let g:gitgutter_highlight_linenrs = 0 + call s:define_sign_linenr_highlights() + + if !g:gitgutter_signs + call gitgutter#sign#clear_signs(bufnr('')) + endif + + redraw! +endfunction + +function! gitgutter#highlight#linenr_enable() abort + let old_highlight_lines = g:gitgutter_highlight_linenrs + + let g:gitgutter_highlight_linenrs = 1 + call s:define_sign_linenr_highlights() + + if !old_highlight_lines && !g:gitgutter_signs + call gitgutter#all(1) + endif + + redraw! +endfunction + +function! gitgutter#highlight#linenr_toggle() abort + if g:gitgutter_highlight_linenrs + call gitgutter#highlight#linenr_disable() + else + call gitgutter#highlight#linenr_enable() + endif +endfunction + function! gitgutter#highlight#define_sign_column_highlight() abort if g:gitgutter_override_sign_column_highlight @@ -66,6 +97,11 @@ function! gitgutter#highlight#define_highlights() abort highlight default link GitGutterChangeLine DiffChange highlight default link GitGutterDeleteLine DiffDelete highlight default link GitGutterChangeDeleteLine GitGutterChangeLine + + highlight default link GitGutterAddLineNr CursorLineNr + highlight default link GitGutterChangeLineNr CursorLineNr + highlight default link GitGutterDeleteLineNr CursorLineNr + highlight default link GitGutterChangeDeleteLineNr CursorLineNr endfunction function! gitgutter#highlight#define_signs() abort @@ -75,11 +111,11 @@ function! gitgutter#highlight#define_signs() abort sign define GitGutterLineRemovedFirstLine sign define GitGutterLineRemovedAboveAndBelow sign define GitGutterLineModifiedRemoved - sign define GitGutterDummy call s:define_sign_text() call gitgutter#highlight#define_sign_text_highlights() call s:define_sign_line_highlights() + call s:define_sign_linenr_highlights() endfunction function! s:define_sign_text() abort @@ -131,40 +167,45 @@ function! s:define_sign_line_highlights() abort endif endfunction -function! s:get_foreground_colors(group) abort - redir => highlight - silent execute 'silent highlight ' . a:group - redir END - - let link_matches = matchlist(highlight, 'links to \(\S\+\)') - if len(link_matches) > 0 " follow the link - return s:get_foreground_colors(link_matches[1]) +function! s:define_sign_linenr_highlights() abort + if has('nvim-0.3.2') + try + if g:gitgutter_highlight_linenrs + sign define GitGutterLineAdded numhl=GitGutterAddLineNr + sign define GitGutterLineModified numhl=GitGutterChangeLineNr + sign define GitGutterLineRemoved numhl=GitGutterDeleteLineNr + sign define GitGutterLineRemovedFirstLine numhl=GitGutterDeleteLineNr + sign define GitGutterLineRemovedAboveAndBelow numhl=GitGutterDeleteLineNr + sign define GitGutterLineModifiedRemoved numhl=GitGutterChangeDeleteLineNr + else + sign define GitGutterLineAdded numhl= + sign define GitGutterLineModified numhl= + sign define GitGutterLineRemoved numhl= + sign define GitGutterLineRemovedFirstLine numhl= + sign define GitGutterLineRemovedAboveAndBelow numhl= + sign define GitGutterLineModifiedRemoved numhl= + endif + catch /E475/ + endtry endif +endfunction - let ctermfg = s:match_highlight(highlight, 'ctermfg=\([0-9A-Za-z]\+\)') - let guifg = s:match_highlight(highlight, 'guifg=\([#0-9A-Za-z]\+\)') +function! s:get_hl(group, what, mode) abort + let r = synIDattr(synIDtrans(hlID(a:group)), a:what, a:mode) + if empty(r) || r == -1 + return 'NONE' + endif + return r +endfunction + +function! s:get_foreground_colors(group) abort + let ctermfg = s:get_hl(a:group, 'fg', 'cterm') + let guifg = s:get_hl(a:group, 'fg', 'gui') return [guifg, ctermfg] endfunction function! s:get_background_colors(group) abort - redir => highlight - silent execute 'silent highlight ' . a:group - redir END - - let link_matches = matchlist(highlight, 'links to \(\S\+\)') - if len(link_matches) > 0 " follow the link - return s:get_background_colors(link_matches[1]) - endif - - let ctermbg = s:match_highlight(highlight, 'ctermbg=\([0-9A-Za-z]\+\)') - let guibg = s:match_highlight(highlight, 'guibg=\([#0-9A-Za-z]\+\)') + let ctermbg = s:get_hl(a:group, 'bg', 'cterm') + let guibg = s:get_hl(a:group, 'bg', 'gui') return [guibg, ctermbg] endfunction - -function! s:match_highlight(highlight, pattern) abort - let matches = matchlist(a:highlight, a:pattern) - if len(matches) == 0 - return 'NONE' - endif - return matches[1] -endfunction diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim index c5111f89..6f4a6ffd 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim @@ -169,8 +169,12 @@ function! gitgutter#hunk#text_object(inner) abort endfunction -function! gitgutter#hunk#stage() abort - call s:hunk_op(function('s:stage')) +function! gitgutter#hunk#stage(...) abort + if a:0 && (a:1 != 1 || a:2 != line('$')) + call s:hunk_op(function('s:stage'), a:1, a:2) + else + call s:hunk_op(function('s:stage')) + endif silent! call repeat#set("\<Plug>GitGutterStageHunk", -1) endfunction @@ -185,9 +189,39 @@ function! gitgutter#hunk#preview() abort endfunction -function! s:hunk_op(op) +function! s:hunk_op(op, ...) let bufnr = bufnr('') + if &previewwindow + if string(a:op) =~ '_stage' + " combine hunk-body in preview window with updated hunk-header + let hunk_body = getline(1, '$') + + let [removed, added] = [0, 0] + for line in hunk_body + if line[0] == '-' + let removed += 1 + elseif line[0] == '+' + let added += 1 + endif + endfor + + let hunk_header = b:hunk_header + " from count + let hunk_header[4] = substitute(hunk_header[4], '\(-\d\+\)\(,\d\+\)\?', '\=submatch(1).",".removed', '') + " to count + let hunk_header[4] = substitute(hunk_header[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".added', '') + + let hunk_diff = join(hunk_header + hunk_body, "\n")."\n" + + wincmd p + pclose + call s:stage(hunk_diff) + endif + + return + endif + if gitgutter#utility#is_active(bufnr) " Get a (synchronous) diff. let [async, g:gitgutter_async] = [g:gitgutter_async, 0] @@ -210,7 +244,14 @@ function! s:hunk_op(op) call gitgutter#utility#warn('did not recognise your choice') endif else - call a:op(gitgutter#diff#hunk_diff(bufnr, diff)) + let hunk_diff = gitgutter#diff#hunk_diff(bufnr, diff) + + if a:0 + let hunk_first_line = s:current_hunk()[2] + let hunk_diff = s:part_of_diff(hunk_diff, a:1-hunk_first_line, a:2-hunk_first_line) + endif + + call a:op(hunk_diff) endif endif endfunction @@ -221,8 +262,11 @@ function! s:stage(hunk_diff) let diff = s:adjust_header(bufnr, a:hunk_diff) " Apply patch to index. call gitgutter#utility#system( - \ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' apply --cached --unidiff-zero - '), + \ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '), \ diff) + if v:shell_error + call gitgutter#utility#warn('patch does not apply') + endif " Refresh gitgutter's view of buffer. call gitgutter#process_buffer(bufnr, 1) @@ -240,37 +284,58 @@ function! s:undo(hunk_diff) if removed_only call append(lnum, lines) elseif added_only - execute lnum .','. (lnum+len(lines)-1) .'d' + execute lnum .','. (lnum+len(lines)-1) .'d _' else call append(lnum-1, lines[0:hunk[1]]) - execute (lnum+hunk[1]) .','. (lnum+hunk[1]+hunk[3]) .'d' + execute (lnum+hunk[1]) .','. (lnum+hunk[1]+hunk[3]) .'d _' endif endfunction function! s:preview(hunk_diff) - let hunk_lines = split(s:discard_header(a:hunk_diff), "\n") - let hunk_lines_length = len(hunk_lines) - let previewheight = min([hunk_lines_length, &previewheight]) + let lines = split(a:hunk_diff, '\n') + let header = lines[0:4] + let body = lines[5:] + + let body_length = len(body) + let previewheight = min([body_length, &previewheight]) silent! wincmd P if !&previewwindow - noautocmd execute 'bo' previewheight 'new' + noautocmd execute g:gitgutter_preview_win_location previewheight 'new' set previewwindow else execute 'resize' previewheight endif + let b:hunk_header = header + setlocal noreadonly modifiable filetype=diff buftype=nofile bufhidden=delete noswapfile execute "%delete_" - call append(0, hunk_lines) + call setline(1, body) normal! gg - setlocal readonly nomodifiable + + cnoreabbrev <buffer> <expr> w getcmdtype() == ':' && getcmdline() == 'w' ? 'GitGutterStageHunk' : 'w' + " Staging hunk from the preview window closes the window anyway. + cnoreabbrev <buffer> <expr> wq getcmdtype() == ':' && getcmdline() == 'wq' ? 'GitGutterStageHunk' : 'wq' noautocmd wincmd p endfunction +" Returns a new hunk diff using the specified lines from the given one. +" Assumes all lines are additions. +" a:first, a:last - 0-based indexes into the body of the hunk. +function! s:part_of_diff(hunk_diff, first, last) + let diff_lines = split(a:hunk_diff, '\n', 1) + + " adjust 'to' line count in header + let diff_lines[4] = substitute(diff_lines[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".(a:last-a:first+1)', '') + + return join(diff_lines[0:4] + diff_lines[5+a:first:5+a:last], "\n")."\n" +endfunction + + function! s:adjust_header(bufnr, hunk_diff) let filepath = gitgutter#utility#repo_path(a:bufnr, 0) return s:adjust_hunk_summary(s:fix_file_references(filepath, a:hunk_diff)) @@ -305,16 +370,11 @@ endif function! s:adjust_hunk_summary(hunk_diff) abort let line_adjustment = s:line_adjustment_for_current_hunk() let diff = split(a:hunk_diff, '\n', 1) - let diff[4] = substitute(diff[4], '+\@<=\(\d\+\)', '\=submatch(1)+line_adjustment', '') + let diff[4] = substitute(diff[4], '+\zs\(\d\+\)', '\=submatch(1)+line_adjustment', '') return join(diff, "\n") endfunction -function! s:discard_header(hunk_diff) - return join(split(a:hunk_diff, '\n', 1)[5:], "\n") -endfunction - - " Returns the number of lines the current hunk is offset from where it would " be if any changes above it in the file didn't exist. function! s:line_adjustment_for_current_hunk() abort diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim index 4c23dbe0..1ee305a7 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim @@ -1,11 +1,6 @@ -" Vim doesn't namespace sign ids so every plugin shares the same -" namespace. Sign ids are simply integers so to avoid clashes with other -" signs we guess at a clear run. -" -" Note also we currently never reset s:next_sign_id. +" For older Vims without sign_place() the plugin has to manaage the sign ids. let s:first_sign_id = 3000 let s:next_sign_id = s:first_sign_id -let s:dummy_sign_id = s:first_sign_id - 1 " Remove-all-signs optimisation requires Vim 7.3.596+. let s:supports_star = v:version > 703 || (v:version == 703 && has("patch596")) @@ -27,7 +22,6 @@ function! gitgutter#sign#disable() abort if !g:gitgutter_highlight_lines call gitgutter#sign#clear_signs(bufnr('')) - call gitgutter#sign#remove_dummy_sign(bufnr(''), 0) endif endfunction @@ -40,8 +34,14 @@ function! gitgutter#sign#toggle() abort endfunction -" Removes gitgutter's signs (excluding dummy sign) from the buffer being processed. +" Removes gitgutter's signs from the buffer being processed. function! gitgutter#sign#clear_signs(bufnr) abort + if exists('*sign_unplace') + call sign_unplace('gitgutter', {'buffer': a:bufnr}) + return + endif + + call s:find_current_signs(a:bufnr) let sign_ids = map(values(gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')), 'v:val.id') @@ -55,37 +55,42 @@ endfunction " modified_lines: list of [<line_number (number)>, <name (string)>] " where name = 'added|removed|modified|modified_removed' function! gitgutter#sign#update_signs(bufnr, modified_lines) abort + if exists('*sign_unplace') + " Vim is (hopefully) now quick enough to remove all signs then place new ones. + call sign_unplace('gitgutter', {'buffer': a:bufnr}) + + let modified_lines = s:handle_double_hunk(a:modified_lines) + let signs = map(copy(modified_lines), '{'. + \ '"buffer": a:bufnr,'. + \ '"group": "gitgutter",'. + \ '"name": s:highlight_name_for_change(v:val[1]),'. + \ '"lnum": v:val[0],'. + \ '"priority": g:gitgutter_sign_priority'. + \ '}') + + if exists('*sign_placelist') + call sign_placelist(signs) + return + endif + + for sign in signs + call sign_place(0, sign.group, sign.name, sign.buffer, {'lnum': sign.lnum, 'priority': sign.priority}) + endfor + return + endif + + + " Derive a delta between the current signs and the ones we want. + " Remove signs from lines that no longer need a sign. + " Upsert the remaining signs. + call s:find_current_signs(a:bufnr) let new_gitgutter_signs_line_numbers = map(copy(a:modified_lines), 'v:val[0]') let obsolete_signs = s:obsolete_gitgutter_signs_to_remove(a:bufnr, new_gitgutter_signs_line_numbers) - let flicker_possible = s:remove_all_old_signs && !empty(a:modified_lines) - if flicker_possible - call s:add_dummy_sign(a:bufnr) - endif - call s:remove_signs(a:bufnr, obsolete_signs, s:remove_all_old_signs) call s:upsert_new_gitgutter_signs(a:bufnr, a:modified_lines) - - if flicker_possible - call gitgutter#sign#remove_dummy_sign(a:bufnr, 0) - endif -endfunction - - -function! s:add_dummy_sign(bufnr) abort - if !gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign') - execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr - call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 1) - endif -endfunction - -function! gitgutter#sign#remove_dummy_sign(bufnr, force) abort - if gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign') && (a:force || !g:gitgutter_sign_column_always) - execute "sign unplace" s:dummy_sign_id "buffer=" . a:bufnr - call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 0) - endif endfunction @@ -96,40 +101,52 @@ endfunction function! s:find_current_signs(bufnr) abort let gitgutter_signs = {} " <line_number (string)>: {'id': <id (number)>, 'name': <name (string)>} - let other_signs = [] " [<line_number (number),...] - let dummy_sign_placed = 0 + if !g:gitgutter_sign_allow_clobber + let other_signs = [] " [<line_number (number),...] + endif - redir => signs - silent execute "sign place buffer=" . a:bufnr - redir END + if exists('*getbufinfo') + let bufinfo = getbufinfo(a:bufnr)[0] + let signs = has_key(bufinfo, 'signs') ? bufinfo.signs : [] + else + let signs = [] - for sign_line in filter(split(signs, '\n')[2:], 'v:val =~# "="') - " Typical sign line: line=88 id=1234 name=GitGutterLineAdded - " We assume splitting is faster than a regexp. - let components = split(sign_line) - let name = split(components[2], '=')[1] - if name =~# 'GitGutterDummy' - let dummy_sign_placed = 1 - else - let line_number = str2nr(split(components[0], '=')[1]) - if name =~# 'GitGutter' - let id = str2nr(split(components[1], '=')[1]) - " Remove orphaned signs (signs placed on lines which have been deleted). - " (When a line is deleted its sign lingers. Subsequent lines' signs' - " line numbers are decremented appropriately.) - if has_key(gitgutter_signs, line_number) - execute "sign unplace" gitgutter_signs[line_number].id - endif - let gitgutter_signs[line_number] = {'id': id, 'name': name} - else - call add(other_signs, line_number) + redir => signlines + silent execute "sign place buffer=" . a:bufnr + redir END + + for signline in filter(split(signlines, '\n')[2:], 'v:val =~# "="') + " Typical sign line before v8.1.0614: line=88 id=1234 name=GitGutterLineAdded + " We assume splitting is faster than a regexp. + let components = split(signline) + call add(signs, { + \ 'lnum': str2nr(split(components[0], '=')[1]), + \ 'id': str2nr(split(components[1], '=')[1]), + \ 'name': split(components[2], '=')[1] + \ }) + endfor + endif + + for sign in signs + if sign.name =~# 'GitGutter' + " Remove orphaned signs (signs placed on lines which have been deleted). + " (When a line is deleted its sign lingers. Subsequent lines' signs' + " line numbers are decremented appropriately.) + if has_key(gitgutter_signs, sign.lnum) + execute "sign unplace" gitgutter_signs[sign.lnum].id endif - end + let gitgutter_signs[sign.lnum] = {'id': sign.id, 'name': sign.name} + else + if !g:gitgutter_sign_allow_clobber + call add(other_signs, sign.lnum) + endif + endif endfor - call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', dummy_sign_placed) call gitgutter#utility#setbufvar(a:bufnr, 'gitgutter_signs', gitgutter_signs) - call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs) + if !g:gitgutter_sign_allow_clobber + call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs) + endif endfunction @@ -152,12 +169,8 @@ endfunction function! s:remove_signs(bufnr, sign_ids, all_signs) abort - if a:all_signs && s:supports_star && empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs')) - let dummy_sign_present = gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign') + if a:all_signs && s:supports_star && (g:gitgutter_sign_allow_clobber || empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs'))) execute "sign unplace * buffer=" . a:bufnr - if dummy_sign_present - execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr - endif else for id in a:sign_ids execute "sign unplace" id @@ -167,21 +180,16 @@ endfunction function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort - let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs') + if !g:gitgutter_sign_allow_clobber + let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs') + endif let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs') - " Handle special case where the first line is the site of two hunks: - " lines deleted above at the start of the file, and lines deleted - " immediately below. - if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']] - let modified_lines = [[1, 'removed_above_and_below']] + a:modified_lines[2:] - else - let modified_lines = a:modified_lines - endif + let modified_lines = s:handle_double_hunk(a:modified_lines) for line in modified_lines let line_number = line[0] " <number> - if index(other_signs, line_number) == -1 " don't clobber others' signs + if g:gitgutter_sign_allow_clobber || index(other_signs, line_number) == -1 " don't clobber others' signs let name = s:highlight_name_for_change(line[1]) if !has_key(old_gitgutter_signs, line_number) " insert let id = s:next_sign_id() @@ -198,6 +206,18 @@ function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort endfunction +" Handle special case where the first line is the site of two hunks: +" lines deleted above at the start of the file, and lines deleted +" immediately below. +function! s:handle_double_hunk(modified_lines) + if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']] + return [[1, 'removed_above_and_below']] + a:modified_lines[2:] + endif + + return a:modified_lines +endfunction + + function! s:next_sign_id() abort let next_id = s:next_sign_id let s:next_sign_id += 1 diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim index 470f2229..3f533ba4 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim @@ -22,14 +22,16 @@ function! gitgutter#utility#setbufvar(buffer, varname, val) endfunction function! gitgutter#utility#getbufvar(buffer, varname, ...) - let dict = get(getbufvar(a:buffer, ''), 'gitgutter', {}) - if has_key(dict, a:varname) - return dict[a:varname] - else - if a:0 - return a:1 + let bvars = getbufvar(a:buffer, '') + if !empty(bvars) + let dict = get(bvars, 'gitgutter', {}) + if has_key(dict, a:varname) + return dict[a:varname] endif endif + if a:0 + return a:1 + endif endfunction function! gitgutter#utility#warn(message) abort @@ -114,58 +116,52 @@ function! gitgutter#utility#repo_path(bufnr, shellesc) abort return a:shellesc ? gitgutter#utility#shellescape(p) : p endfunction -function! gitgutter#utility#set_repo_path(bufnr) abort + +let s:set_path_handler = {} + +function! s:set_path_handler.out(buffer, path) abort + let path = s:strip_trailing_new_line(a:path) + call gitgutter#utility#setbufvar(a:buffer, 'path', path) + + if type(self.continuation) == type(function('tr')) + call self.continuation() + else + call call(self.continuation.function, self.continuation.arguments) + endif +endfunction + +function! s:set_path_handler.err(buffer) abort + call gitgutter#utility#setbufvar(a:buffer, 'path', -2) +endfunction + + +" continuation - a funcref or hash to call after setting the repo path asynchronously. +" +" Returns 'async' if the the path is set asynchronously, 0 otherwise. +function! gitgutter#utility#set_repo_path(bufnr, continuation) abort " Values of path: " * non-empty string - path " * -1 - pending " * -2 - not tracked by git call gitgutter#utility#setbufvar(a:bufnr, 'path', -1) - let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr))) + let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr))) - if g:gitgutter_async && gitgutter#async#available() - if has('lambda') - call gitgutter#async#execute(cmd, a:bufnr, { - \ 'out': {bufnr, path -> gitgutter#utility#setbufvar(bufnr, 'path', s:strip_trailing_new_line(path))}, - \ 'err': {bufnr -> gitgutter#utility#setbufvar(bufnr, 'path', -2)}, - \ }) - else - if has('nvim') && !has('nvim-0.2.0') - call gitgutter#async#execute(cmd, a:bufnr, { - \ 'out': function('s:set_path'), - \ 'err': function('s:not_tracked_by_git') - \ }) - else - call gitgutter#async#execute(cmd, a:bufnr, { - \ 'out': function('s:set_path'), - \ 'err': function('s:set_path', [-2]) - \ }) - endif - endif + if g:gitgutter_async && gitgutter#async#available() && !has('vim_starting') + let handler = copy(s:set_path_handler) + let handler.continuation = a:continuation + call gitgutter#async#execute(cmd, a:bufnr, handler) + return 'async' + endif + + let path = gitgutter#utility#system(cmd) + if v:shell_error + call gitgutter#utility#setbufvar(a:bufnr, 'path', -2) else - let path = gitgutter#utility#system(cmd) - if v:shell_error - call gitgutter#utility#setbufvar(a:bufnr, 'path', -2) - else - call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path)) - endif + call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path)) endif endfunction -if has('nvim') && !has('nvim-0.2.0') - function! s:not_tracked_by_git(bufnr) - call s:set_path(a:bufnr, -2) - endfunction -endif - -function! s:set_path(bufnr, path) - if a:bufnr == -2 - let [bufnr, path] = [a:path, a:bufnr] - call gitgutter#utility#setbufvar(bufnr, 'path', path) - else - call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(a:path)) - endif -endfunction function! gitgutter#utility#cd_cmd(bufnr, cmd) abort let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() ? 'cd /d' : 'cd') diff --git a/sources_non_forked/vim-gitgutter/doc/gitgutter.txt b/sources_non_forked/vim-gitgutter/doc/gitgutter.txt index 87825da1..5dafcbbf 100644 --- a/sources_non_forked/vim-gitgutter/doc/gitgutter.txt +++ b/sources_non_forked/vim-gitgutter/doc/gitgutter.txt @@ -79,6 +79,19 @@ Copy vim-gitgutter's subdirectories into your vim configuration directory: See |add-global-plugin|. +WINDOWS *gitgutter-windows* + +I recommend configuring vim-gitgutter with the full path to your git executable. +For example: +> + let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe' +< +This is to avoid a problem which occurs if you have file named "git.*" (i.e. +with any extension in "PATHEXT") in your current folder. "cmd.exe" prioritises +the current folder over folders in 'PATH' and will try to execute your file +instead of the "git" binary. + + =============================================================================== COMMANDS *gitgutter-commands* @@ -126,6 +139,19 @@ Commands for turning line highlighting on and off (defaults to off):~ :GitGutterLineHighlightsToggle Turn line highlighting on or off. +Commands for turning line number highlighting on and off (defaults to off):~ +NOTE: This feature requires Neovim 0.3.2 or higher. + + *gitgutter-:GitGutterLineNrHighlightsEnable* +:GitGutterLineNrHighlightsEnable Turn on line highlighting. + + *gitgutter-:GitGutterLineNrHighlightsDisable* +:GitGutterLineNrHighlightsDisable Turn off line highlighting. + + *gitgutter-:GitGutterLineNrHighlightsToggle* +:GitGutterLineNrHighlightsToggle Turn line highlighting on or off. + + Commands for jumping between hunks:~ *gitgutter-:GitGutterNextHunk* @@ -138,7 +164,14 @@ Commands for jumping between hunks:~ Commands for operating on a hunk:~ *gitgutter-:GitGutterStageHunk* -:GitGutterStageHunk Stage the hunk the cursor is in. +:GitGutterStageHunk Stage the hunk the cursor is in. Use a visual selection + to stage part of an (additions-only) hunk; or use a + range. + + To stage part of any hunk, first |GitGutterPreviewHunk| + it, then move to the preview window, delete the lines + you do not want to stage, and |write| or + |GitGutterStageHunk|. *gitgutter-:GitGutterUndoHunk* :GitGutterUndoHunk Undo the hunk the cursor is in. @@ -148,6 +181,10 @@ Commands for operating on a hunk:~ Use |:pclose| or |CTRL-W_CTRL-Z| to close the preview window. + To stage part of the hunk, move to the preview window, + delete any lines you do not want to stage, and + |GitGutterStageHunk|. + Commands for folds:~ *gitgutter-:GitGutterFold* @@ -249,13 +286,15 @@ Signs:~ |g:gitgutter_signs| |g:gitgutter_highlight_lines| + |g:gitgutter_highlight_linenrs| |g:gitgutter_max_signs| + |g:gitgutter_sign_priority| + |g:gitgutter_sign_allow_clobber| |g:gitgutter_sign_added| |g:gitgutter_sign_modified| |g:gitgutter_sign_removed| |g:gitgutter_sign_removed_first_line| |g:gitgutter_sign_modified_removed| - |g:gitgutter_sign_column_always| |g:gitgutter_override_sign_column_highlight| Terminal:~ @@ -270,6 +309,13 @@ General:~ |g:gitgutter_log| + *g:gitgutter_preview_win_location* +Default: 'bo' + +This option determines where the preview window pops up as a result of the +:GitGutterPreviewHunk command. Other plausible values are 'to', 'bel', 'abo'. +See the end of the |opening-window| docs. + *g:gitgutter_git_executable* Default: 'git' @@ -329,6 +375,11 @@ Default: 0 Determines whether or not to show line highlights. + *g:gitgutter_highlight_linenrs* +Default: 0 + +Determines whether or not to show line number highlights. + *g:gitgutter_max_signs* Default: 500 @@ -337,6 +388,18 @@ signs, so to avoid slowing down the GUI the number of signs is capped. When the number of changed lines exceeds this value, the plugin removes all signs and displays a warning message. + *g:gitgutter_sign_priority* +Default: 10 + +Sets the |sign-priority| gitgutter assigns to its signs. + + *g:gitgutter_sign_allow_clobber* +Default: 0 (Vim < 8.1.0614, Neovim < 0.4.0) + 1 (otherwise) + +Determines whether gitgutter preserves non-gitgutter signs. When 1, gitgutter +will not preserve non-gitgutter signs. + *g:gitgutter_sign_added* *g:gitgutter_sign_modified* *g:gitgutter_sign_removed* @@ -353,17 +416,6 @@ Defaults: You can use unicode characters but not images. Signs must not take up more than 2 columns. - *g:gitgutter_sign_column_always* -Default: 0 - -This legacy option controls whether the sign column should always be shown, even -if there are no signs to display. - -From Vim 7.4.2201, use 'signcolumn' instead: -> - set signcolumn=yes -< - *g:gitgutter_override_sign_column_highlight* Default: 1 @@ -396,6 +448,11 @@ If this applies to you, either install something like Terminus (https://github.com/wincent/terminus) to make |FocusGained| work or set this option to 0. +If you use tmux, try this in your tmux.conf: +> + set -g focus-events on +< + When this option is 0, the plugin force-updates the buffer on |BufEnter| (instead of only updating if the buffer's contents has changed since the last update). @@ -452,7 +509,19 @@ colorscheme or |vimrc|: For example, to use |hl-DiffText| instead of |hl-DiffChange|: > - highlight link GitGutterChangeLine DiffChange + highlight link GitGutterChangeLine DiffText +< +To change the line number highlights, set up the following highlight groups in +your colorscheme or |vimrc|: +> + GitGutterAddLineNr " default: links to CursorLineNr + GitGutterChangeLineNr " default: links to CursorLineNr + GitGutterDeleteLineNr " default: links to CursorLineNr + GitGutterChangeDeleteLineNr " default: links to CursorLineNr +< +For example, to use |hl-Underlined| instead of |hl-CursorLineNr|: +> + highlight link GitGutterChangeLineNr Underlined < diff --git a/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim b/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim index 9ca45afd..0901f0b1 100644 --- a/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim @@ -22,17 +22,19 @@ function! s:set(var, default) abort endif endfunction +call s:set('g:gitgutter_preview_win_location', 'bo') call s:set('g:gitgutter_enabled', 1) call s:set('g:gitgutter_max_signs', 500) call s:set('g:gitgutter_signs', 1) call s:set('g:gitgutter_highlight_lines', 0) -call s:set('g:gitgutter_sign_column_always', 0) -if g:gitgutter_sign_column_always && exists('&signcolumn') - " Vim 7.4.2201. - set signcolumn=yes - let g:gitgutter_sign_column_always = 0 - call gitgutter#utility#warn('please replace "let g:gitgutter_sign_column_always=1" with "set signcolumn=yes"') +call s:set('g:gitgutter_highlight_linenrs', 0) +call s:set('g:gitgutter_sign_priority', 10) +" Nvim 0.4.0 has an expanding sign column +" The sign_place() function supports sign priority. +if (has('nvim-0.4.0') || exists('*sign_place')) && !exists('g:gitgutter_sign_allow_clobber') + let g:gitgutter_sign_allow_clobber = 1 endif +call s:set('g:gitgutter_sign_allow_clobber', 0) call s:set('g:gitgutter_override_sign_column_highlight', 1) call s:set('g:gitgutter_sign_added', '+') call s:set('g:gitgutter_sign_modified', '~') @@ -111,6 +113,12 @@ command! -bar GitGutterLineHighlightsToggle call gitgutter#highlight#line_toggl " }}} +" 'number' column highlights {{{ +command! -bar GitGutterLineNrHighlightsDisable call gitgutter#highlight#linenr_disable() +command! -bar GitGutterLineNrHighlightsEnable call gitgutter#highlight#linenr_enable() +command! -bar GitGutterLineNrHighlightsToggle call gitgutter#highlight#linenr_toggle() +" }}} + " Signs {{{ command! -bar GitGutterSignsEnable call gitgutter#sign#enable() @@ -124,7 +132,7 @@ command! -bar GitGutterSignsToggle call gitgutter#sign#toggle() command! -bar -count=1 GitGutterNextHunk call gitgutter#hunk#next_hunk(<count>) command! -bar -count=1 GitGutterPrevHunk call gitgutter#hunk#prev_hunk(<count>) -command! -bar GitGutterStageHunk call gitgutter#hunk#stage() +command! -bar -range=% GitGutterStageHunk call gitgutter#hunk#stage(<line1>,<line2>) command! -bar GitGutterUndoHunk call gitgutter#hunk#undo() command! -bar GitGutterPreviewHunk call gitgutter#hunk#preview() @@ -179,6 +187,7 @@ command! -bar GitGutterDebug call gitgutter#debug#debug() nnoremap <silent> <expr> <Plug>GitGutterNextHunk &diff ? ']c' : ":\<C-U>execute v:count1 . 'GitGutterNextHunk'\<CR>" nnoremap <silent> <expr> <Plug>GitGutterPrevHunk &diff ? '[c' : ":\<C-U>execute v:count1 . 'GitGutterPrevHunk'\<CR>" +xnoremap <silent> <Plug>GitGutterStageHunk :GitGutterStageHunk<CR> nnoremap <silent> <Plug>GitGutterStageHunk :GitGutterStageHunk<CR> nnoremap <silent> <Plug>GitGutterUndoHunk :GitGutterUndoHunk<CR> nnoremap <silent> <Plug>GitGutterPreviewHunk :GitGutterPreviewHunk<CR> @@ -186,11 +195,12 @@ nnoremap <silent> <Plug>GitGutterPreviewHunk :GitGutterPreviewHunk<CR> " }}} function! s:on_bufenter() + call gitgutter#setup_maps() + if exists('t:gitgutter_didtabenter') && t:gitgutter_didtabenter let t:gitgutter_didtabenter = 0 call gitgutter#all(!g:gitgutter_terminal_reports_focus) else - call gitgutter#init_buffer(bufnr('')) call gitgutter#process_buffer(bufnr(''), !g:gitgutter_terminal_reports_focus) endif endfunction @@ -215,6 +225,11 @@ augroup gitgutter autocmd ShellCmdPost * call gitgutter#all(1) autocmd BufLeave term://* call gitgutter#all(1) + autocmd BufWritePost fugitive://*//0/* call gitgutter#all(1) + + autocmd BufFilePre * GitGutterBufferDisable + autocmd BufFilePost * GitGutterBufferEnable + " 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. diff --git a/sources_non_forked/vim-gitgutter/test/test b/sources_non_forked/vim-gitgutter/test/test index 4daf052f..cffe9273 100644 --- a/sources_non_forked/vim-gitgutter/test/test +++ b/sources_non_forked/vim-gitgutter/test/test @@ -10,7 +10,7 @@ $VIM -u NONE -U NONE -N \ --cmd 'source ../plugin/gitgutter.vim' \ -S runner.vim \ test_*.vim \ - $* + "$@" cat messages.log diff --git a/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim b/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim index 855eca3d..10ad56ab 100644 --- a/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim @@ -6,21 +6,27 @@ let s:bufnr = bufnr('') " Helpers " -function s:signs(filename) - redir => signs - silent execute 'sign place' - redir END +" Ignores unexpected keys. +" +" expected - list of signs +function s:assert_signs(expected, filename) + if empty(a:expected) + call assert_equal(a:expected, []) + return + endif - let signs = split(signs, '\n') + let expected_keys = keys(a:expected[0]) + let actual = sign_getplaced(a:filename, {'group': 'gitgutter'})[0].signs - " filter out signs for this test file - " assumes a:filename's signs are last set listed - let i = index(signs, 'Signs for '.a:filename.':') - let signs = (i > -1 ? signs[i+1:] : []) + for sign in actual + for k in keys(sign) + if index(expected_keys, k) == -1 + call remove(sign, k) + endif + endfor + endfor - call map(signs, {_, v -> substitute(v, ' ', '', '')}) - - return signs + call assert_equal(a:expected, actual) endfunction function s:git_diff() @@ -71,8 +77,8 @@ function Test_add_lines() normal ggo* call s:trigger_gitgutter() - let expected = ["line=2 id=3000 name=GitGutterLineAdded"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded', 'group': 'gitgutter', 'priority': 10}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -83,8 +89,8 @@ function Test_add_lines_fish() normal ggo* call s:trigger_gitgutter() - let expected = ["line=2 id=3000 name=GitGutterLineAdded"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded'}] + call s:assert_signs(expected, 'fixture.txt') let &shell = _shell endfunction @@ -94,8 +100,8 @@ function Test_modify_lines() normal ggi* call s:trigger_gitgutter() - let expected = ["line=1 id=3000 name=GitGutterLineModified"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 1, 'name': 'GitGutterLineModified'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -103,8 +109,8 @@ function Test_remove_lines() execute '5d' call s:trigger_gitgutter() - let expected = ["line=4 id=3000 name=GitGutterLineRemoved"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 4, 'name': 'GitGutterLineRemoved'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -112,8 +118,20 @@ function Test_remove_first_lines() execute '1d' call s:trigger_gitgutter() - let expected = ["line=1 id=3000 name=GitGutterLineRemovedFirstLine"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedFirstLine'}] + call s:assert_signs(expected, 'fixture.txt') +endfunction + + +function Test_priority() + let g:gitgutter_sign_priority = 5 + + execute '1d' + call s:trigger_gitgutter() + + call s:assert_signs([{'priority': 5}], 'fixture.txt') + + let g:gitgutter_sign_priority = 10 endfunction @@ -122,8 +140,8 @@ function Test_overlapping_hunks() execute '1d' call s:trigger_gitgutter() - let expected = ["line=1 id=3000 name=GitGutterLineRemovedAboveAndBelow"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedAboveAndBelow'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -132,8 +150,8 @@ function Test_edit_file_with_same_name_as_a_branch() call system('git checkout -b fixture.txt') call s:trigger_gitgutter() - let expected = ["line=5 id=3000 name=GitGutterLineModified"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 5, 'name': 'GitGutterLineModified'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -144,8 +162,8 @@ function Test_file_added_to_git() normal ihello call s:trigger_gitgutter() - let expected = ["line=1 id=3000 name=GitGutterLineAdded"] - call assert_equal(expected, s:signs('fileAddedToGit.tmp')) + let expected = [{'lnum': 1, 'name': 'GitGutterLineAdded'}] + call s:assert_signs(expected, 'fileAddedToGit.tmp') endfunction @@ -156,10 +174,10 @@ function Test_filename_with_equals() call s:trigger_gitgutter() let expected = [ - \ 'line=1 id=3000 name=GitGutterLineAdded', - \ 'line=2 id=3001 name=GitGutterLineAdded' + \ {'lnum': 1, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 2, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('=fixture=.txt')) + call s:assert_signs(expected, '=fixture=.txt') endfunction @@ -170,10 +188,10 @@ function Test_filename_with_square_brackets() call s:trigger_gitgutter() let expected = [ - \ 'line=1 id=3000 name=GitGutterLineAdded', - \ 'line=2 id=3001 name=GitGutterLineAdded' + \ {'lnum': 1, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 2, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('fix[tu]re.txt')) + call s:assert_signs(expected, 'fix[tu]re.txt') endfunction @@ -184,10 +202,10 @@ function Test_filename_leading_dash() call s:trigger_gitgutter() let expected = [ - \ 'line=1 id=3000 name=GitGutterLineAdded', - \ 'line=2 id=3001 name=GitGutterLineAdded' + \ {'lnum': 1, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 2, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('-fixture.txt')) + call s:assert_signs(expected, '-fixture.txt') endfunction @@ -198,10 +216,10 @@ function Test_filename_umlaut() call s:trigger_gitgutter() let expected = [ - \ 'line=1 id=3000 name=GitGutterLineAdded', - \ 'line=2 id=3001 name=GitGutterLineAdded' + \ {'lnum': 1, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 2, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('fixtüre.txt')) + call s:assert_signs(expected, 'fixtüre.txt') endfunction @@ -213,8 +231,8 @@ function Test_follow_symlink() 6d call s:trigger_gitgutter() - let expected = ['line=5 id=3000 name=GitGutterLineRemoved'] - call assert_equal(expected, s:signs('symlink')) + let expected = [{'lnum': 5, 'name': 'GitGutterLineRemoved'}] + call s:assert_signs(expected, 'symlink') endfunction @@ -255,7 +273,7 @@ endfunction function Test_no_modifications() - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') endfunction @@ -265,8 +283,8 @@ function Test_orphaned_signs() 6d call s:trigger_gitgutter() - let expected = ['line=6 id=3001 name=GitGutterLineAdded'] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 6, 'name': 'GitGutterLineAdded'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -275,7 +293,7 @@ function Test_untracked_file_outside_repo() call system('touch '.tmp) execute 'edit '.tmp - call assert_equal([], s:signs(tmp)) + call s:assert_signs([], tmp) endfunction @@ -286,7 +304,7 @@ function Test_untracked_file_within_repo() normal ggo* call s:trigger_gitgutter() - call assert_equal([], s:signs(tmp)) + call s:assert_signs([], tmp) call assert_equal(-2, b:gitgutter.path) call system('rm '.tmp) @@ -300,23 +318,23 @@ function Test_untracked_file_square_brackets_within_repo() normal ggo* call s:trigger_gitgutter() - call assert_equal([], s:signs(tmp)) + call s:assert_signs([], tmp) call system('rm '.tmp) endfunction function Test_hunk_outside_noop() - normal 5G + 5 GitGutterStageHunk - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') call assert_equal([], s:git_diff()) call assert_equal([], s:git_diff_staged()) GitGutterUndoHunk - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') call assert_equal([], s:git_diff()) call assert_equal([], s:git_diff_staged()) endfunction @@ -332,7 +350,7 @@ function Test_hunk_stage() call assert_equal('foo', &shell) let &shell = _shell - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') " Buffer is unsaved let expected = [ @@ -372,11 +390,11 @@ function Test_hunk_stage_nearby_hunk() GitGutterStageHunk let expected = [ - \ 'line=3 id=3000 name=GitGutterLineAdded', - \ 'line=4 id=3001 name=GitGutterLineAdded', - \ 'line=5 id=3002 name=GitGutterLineAdded' + \ {'lnum': 3, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 4, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 5, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('fixture.txt')) + call s:assert_signs(expected, 'fixture.txt') " Buffer is unsaved let expected = [ @@ -417,6 +435,203 @@ function Test_hunk_stage_nearby_hunk() endfunction +function Test_hunk_stage_partial_visual_added() + call append(5, ['A','B','C','D']) + execute "normal 7GVj:GitGutterStageHunk\<CR>" + + let expected = [ + \ {'lnum': 6, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 9, 'name': 'GitGutterLineAdded'}, + \ ] + call s:assert_signs(expected, 'fixture.txt') + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index 8a7026e..f5c6aff 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -6,2 +5,0 @@ e', + \ '-B', + \ '-C', + \ ] + call assert_equal(expected, s:git_diff()) + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..8a7026e 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5,0 +6,2 @@ e', + \ '+B', + \ '+C', + \ ] + call assert_equal(expected, s:git_diff_staged()) +endfunction + + +function Test_hunk_stage_partial_cmd_added() + call append(5, ['A','B','C','D']) + 6 + 7,8GitGutterStageHunk + + let expected = [ + \ {'lnum': 6, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 9, 'name': 'GitGutterLineAdded'}, + \ ] + call s:assert_signs(expected, 'fixture.txt') + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index 8a7026e..f5c6aff 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -6,2 +5,0 @@ e', + \ '-B', + \ '-C', + \ ] + call assert_equal(expected, s:git_diff()) + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..8a7026e 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5,0 +6,2 @@ e', + \ '+B', + \ '+C', + \ ] + call assert_equal(expected, s:git_diff_staged()) +endfunction + + +function Test_hunk_stage_partial_preview_added() + call append(5, ['A','B','C','D']) + 6 + GitGutterPreviewHunk + wincmd P + + " remove C and A so we stage B and D + 3delete + 1delete + + GitGutterStageHunk + write + + let expected = [ + \ {'lnum': 6, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 8, 'name': 'GitGutterLineAdded'}, + \ ] + call s:assert_signs(expected, 'fixture.txt') + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index 975852f..3dd23a3 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5,0 +6 @@ e', + \ '+A', + \ '@@ -6,0 +8 @@ B', + \ '+C', + \ ] + call assert_equal(expected, s:git_diff()) + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..975852f 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5,0 +6,2 @@ e', + \ '+B', + \ '+D', + \ ] + call assert_equal(expected, s:git_diff_staged()) +endfunction + + +function Test_hunk_stage_preview_write() + call append(5, ['A','B','C','D']) + 6 + GitGutterPreviewHunk + wincmd P + + " preview window + call feedkeys(":w\<CR>", 'tx') + " original window + write + + call s:assert_signs([], 'fixture.txt') + + call assert_equal([], s:git_diff()) + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..3dd23a3 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5,0 +6,4 @@ e', + \ '+A', + \ '+B', + \ '+C', + \ '+D', + \ ] + call assert_equal(expected, s:git_diff_staged()) +endfunction + + +function Test_hunk_stage_partial_preview_added_removed() + 4,5delete + call append(3, ['A','B','C','D']) + 4 + GitGutterPreviewHunk + wincmd P + + " -d + " -e + " +A + " +B + " +C + " +D + + " remove D and d so they do not get staged + 6delete + 1delete + + GitGutterStageHunk + write + + let expected = [ + \ {'lnum': 3, 'name': 'GitGutterLineRemoved'}, + \ {'lnum': 7, 'name': 'GitGutterLineAdded'}, + \ ] + call s:assert_signs(expected, 'fixture.txt') + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index 9a19589..e63fb0a 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -4 +3,0 @@ c', + \ '-d', + \ '@@ -7,0 +7 @@ C', + \ '+D', + \ ] + call assert_equal(expected, s:git_diff()) + + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..9a19589 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5 +5,3 @@ d', + \ '-e', + \ '+A', + \ '+B', + \ '+C', + \ ] + call assert_equal(expected, s:git_diff_staged()) +endfunction + + function Test_hunk_undo() let _shell = &shell set shell=foo @@ -427,7 +642,7 @@ function Test_hunk_undo() call assert_equal('foo', &shell) let &shell = _shell - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') call assert_equal([], s:git_diff()) call assert_equal([], s:git_diff_staged()) endfunction @@ -442,11 +657,11 @@ function Test_undo_nearby_hunk() call s:trigger_gitgutter() let expected = [ - \ 'line=3 id=3000 name=GitGutterLineAdded', - \ 'line=4 id=3001 name=GitGutterLineAdded', - \ 'line=5 id=3002 name=GitGutterLineAdded' + \ {'lnum': 3, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 4, 'name': 'GitGutterLineAdded'}, + \ {'lnum': 5, 'name': 'GitGutterLineAdded'} \ ] - call assert_equal(expected, s:signs('fixture.txt')) + call s:assert_signs(expected, 'fixture.txt') call assert_equal([], s:git_diff()) @@ -485,10 +700,8 @@ function Test_overlapping_hunk_op() GitGutterUndoHunk call s:trigger_gitgutter() - let expected = [ - \ 'line=2 id=3000 name=GitGutterLineRemoved', - \ ] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 2, 'name': 'GitGutterLineRemoved'}] + call s:assert_signs(expected, 'fixture.txt') " Undo lower @@ -499,10 +712,8 @@ function Test_overlapping_hunk_op() GitGutterUndoHunk call s:trigger_gitgutter() - let expected = [ - \ 'line=1 id=3000 name=GitGutterLineRemovedFirstLine', - \ ] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedFirstLine'}] + call s:assert_signs(expected, 'fixture.txt') endfunction @@ -512,8 +723,8 @@ function Test_write_option() normal ggo* call s:trigger_gitgutter() - let expected = ["line=2 id=3000 name=GitGutterLineAdded"] - call assert_equal(expected, s:signs('fixture.txt')) + let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded'}] + call s:assert_signs(expected, 'fixture.txt') set write endfunction @@ -525,7 +736,7 @@ function Test_inner_text_object() normal dic call s:trigger_gitgutter() - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') call assert_equal(readfile('fixture.txt'), getline(1,'$')) " Excludes trailing lines @@ -543,7 +754,7 @@ function Test_around_text_object() normal dac call s:trigger_gitgutter() - call assert_equal([], s:signs('fixture.txt')) + call s:assert_signs([], 'fixture.txt') call assert_equal(readfile('fixture.txt'), getline(1,'$')) " Includes trailing lines @@ -646,7 +857,7 @@ function Test_encoding() call s:trigger_gitgutter() - call assert_equal([], s:signs('cp932.txt')) + call s:assert_signs([], 'cp932.txt') endfunction @@ -656,7 +867,7 @@ function Test_empty_file() edit empty.txt call s:trigger_gitgutter() - call assert_equal([], s:signs('empty.txt')) + call s:assert_signs([], 'empty.txt') " File consisting only of a newline @@ -664,7 +875,7 @@ function Test_empty_file() edit newline.txt call s:trigger_gitgutter() - call assert_equal([], s:signs('newline.txt')) + call s:assert_signs([], 'newline.txt') " 1 line file without newline @@ -674,7 +885,7 @@ function Test_empty_file() edit! oneline.txt call s:trigger_gitgutter() - call assert_equal([], s:signs('oneline.txt')) + call s:assert_signs([], 'oneline.txt') set eol fixeol endfunction diff --git a/sources_non_forked/vim-go/.github/FUNDING.yml b/sources_non_forked/vim-go/.github/FUNDING.yml new file mode 100644 index 00000000..060026ef --- /dev/null +++ b/sources_non_forked/vim-go/.github/FUNDING.yml @@ -0,0 +1 @@ +patreon: bhcleek diff --git a/sources_non_forked/vim-go/.github/ISSUE_TEMPLATE.md b/sources_non_forked/vim-go/.github/ISSUE_TEMPLATE.md index b01238f0..7d584256 100644 --- a/sources_non_forked/vim-go/.github/ISSUE_TEMPLATE.md +++ b/sources_non_forked/vim-go/.github/ISSUE_TEMPLATE.md @@ -6,10 +6,8 @@ If possible, please provide clear steps for reproducing the problem. ### What did you expect to happen? - ### What happened instead? - ### Configuration (**MUST** fill this out): #### vim-go version: @@ -20,10 +18,13 @@ If possible, please provide clear steps for reproducing the problem. </pre></details> #### Vim version (first three lines from `:version`): +<!-- :version --> -#### Go version (`go version`): +#### Go version (`go version`): +<!-- go version --> #### Go environment <details><summary><code>go env</code> Output:</summary><br><pre> +<!-- go env --> </pre></details> diff --git a/sources_non_forked/vim-go/CHANGELOG.md b/sources_non_forked/vim-go/CHANGELOG.md index 53c72cfd..bb027f7c 100644 --- a/sources_non_forked/vim-go/CHANGELOG.md +++ b/sources_non_forked/vim-go/CHANGELOG.md @@ -1,5 +1,9 @@ ## unplanned +BACKWARDS INCOMPATABILITIES: +* `g:go_metalinter_disabled` has been removed. + [[GH-2375]](https://github.com/fatih/vim-go/pull/2117) + IMPROVEMENTS: * Add a new option, `g:go_code_completion_enabled`, to control whether omnifunc is set. @@ -8,6 +12,53 @@ IMPROVEMENTS: [[GH-2261]](https://github.com/fatih/vim-go/pull/2261) * Allow debugging of packages outside of GOPATH without a go.mod file. [[GH-2269]](https://github.com/fatih/vim-go/pull/2269) +* Show which example failed when Example tests fail + [[GH-2277]](https://github.com/fatih/vim-go/pull/2277) +* Show function signature and return types in preview window when autocompleting functions and methods. + [[GH-2289]](https://github.com/fatih/vim-go/pull/2289) +* Improve the user experience when using null modules. + [[GH-2300]](https://github.com/fatih/vim-go/pull/2300) +* Modify `:GoReportGitHubIssue` to include vim-go configuration values + [[GH-2323]](https://github.com/fatih/vim-go/pull/2323) +* Respect `g:go_info_mode='gopls'` in go#complete#GetInfo. + [[GH-2313]](https://github.com/fatih/vim-go/pull/2313) +* Allow `:GoLint`, `:GoErrCheck`, and `:GoDebug` to work in null modules. + [[GH-2335]](https://github.com/fatih/vim-go/pull/2335) +* Change default value for `g:go_info_mode` and `g:go_def_mode` to `'gopls'`. + [[GH-2329]](https://github.com/fatih/vim-go/pull/2329) +* Add a new option, `g:go_doc_popup_window` to optionally use a popup window + for godoc in Vim 8.1.1513 and later. + [[GH-2347]](https://github.com/fatih/vim-go/pull/2347) +* Add `:GoAddWorkspace` function to support multiple workspaces with gopls. + [[GH-2356]](https://github.com/fatih/vim-go/pull/2356) +* Install gopls from its stable package. + [[GH-2360]](https://github.com/fatih/vim-go/pull/2360) +* Disambiguate progress message when initializing gopls. + [[GH-2369]](https://github.com/fatih/vim-go/pull/2369) +* Calculate LSP position correctly when on a line that contains multi-byte + characters before the position. + [[GH-2389]](https://github.com/fatih/vim-go/pull/2389) +* Calculate Vim position correctly from LSP text position. + [[GH-2395]](https://github.com/fatih/vim-go/pull/2395) +* Use the statusline to display gopls initialization status messages and only + echo the statuses when `g:go_echo_command_info` is set. + [[GH-2422]](https://github.com/fatih/vim-go/pull/2422) +* Send configuration to gopls so that build tags will be considered and hover + content won't have documentation. + [[GH-2429]](https://github.com/fatih/vim-go/pull/2429) +* Add a new option, `g:go_term_close_on_exit`, to control whether jobs run in a + terminal window will close the terminal window when the job exits. + [[GH-2409]](https://github.com/fatih/vim-go/pull/2409) +* Allow `g:go_template_file` and `g:go_template_test_files` to reside outside + of vim-go's template directory. + [[GH-2434]](https://github.com/fatih/vim-go/pull/2434) +* Add a new command, `:GoLSPDebugBrowser`, to open a browser to gopls debugging + view. + [[GH-2436]](https://github.com/fatih/vim-go/pull/2436) +* Restart gopls automatically when it is updated via `:GoUpdateBinaries`. + [[GH-2453]](https://github.com/fatih/vim-go/pull/2453) +* Reset `'more'` while installing binaries to avoid unnecessary more prompts. + [[GH-2457]](https://github.com/fatih/vim-go/pull/2457) BUG FIXES: * display info about function and function types whose parameters are @@ -26,6 +77,44 @@ BUG FIXES: [[GH-2268]](https://github.com/fatih/vim-go/pull/2268) * Set the anchor for method documentation correctly. [[GH-2276]](https://github.com/fatih/vim-go/pull/2276) +* Respect the LSP information for determining where candidate matches start. + [[GH-2291]](https://github.com/fatih/vim-go/pull/2291) +* Restore environment variables with backslashes correctly. + [[GH-2292]](https://github.com/fatih/vim-go/pull/2292) +* Modify handling of gopls output for `:GoInfo` to ensure the value will be + displayed. + [[GH-2311]](https://github.com/fatih/vim-go/pull/2311) +* Run `:GoLint` successfully in null modules. + [[GH-2318]](https://github.com/fatih/vim-go/pull/2318) +* Ensure actions on save work in new buffers that have not yet been persisted to disk. + [[GH-2319]](https://github.com/fatih/vim-go/pull/2319) +* Restore population of information in `:GoReportGitHubIssue`. + [[GH-2312]](https://github.com/fatih/vim-go/pull/2312) +* Do not jump back to the originating window when jumping to definitions with + `g:go_def_mode='gopls'`. + [[GH-2327]](https://github.com/fatih/vim-go/pull/2327) +* Fix getting information about a valid identifier for which gopls returns no + information (e.g. calling `:GoInfo` on a package identifier). + [[GH-2339]](https://github.com/fatih/vim-go/pull/2339) +* Fix tab completion of package names on the cmdline in null modules. + [[GH-2342]](https://github.com/fatih/vim-go/pull/2342) +* Display identifier info correctly when the identifier has no godoc. + [[GH-2373]](https://github.com/fatih/vim-go/pull/2373) +* Fix false positives when saving a buffer and `g:go_metalinter_command` is + `golangci-lint`. + [[GH-2367]](https://github.com/fatih/vim-go/pull/2367) +* Fix `:GoDebugRestart`. + [[GH-2390]](https://github.com/fatih/vim-go/pull/2390) +* Do not execute tests twice in terminal mode. + [[GH-2397]](https://github.com/fatih/vim-go/pull/2397) +* Do not open a new buffer in Neovim when there are compilation errors and + terminal mode is enabled. + [[GH-2401]](https://github.com/fatih/vim-go/pull/2401) +* Fix error due to typo in implementation of `:GoAddWorkspace`. + [[GH-2415]](https://github.com/fatih/vim-go/pull/2401) +* Do not format the file automatically when `g:go_format_autosave` is set and + the file being written is not the current file. + [[GH-2442]](https://github.com/fatih/vim-go/pull/2401) ## 1.20 - (April 22, 2019) diff --git a/sources_non_forked/vim-go/README.md b/sources_non_forked/vim-go/README.md index c47c8f35..877f9646 100644 --- a/sources_non_forked/vim-go/README.md +++ b/sources_non_forked/vim-go/README.md @@ -68,7 +68,16 @@ Depending on your installation method, you may have to generate the plugin's [`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags) manually (e.g. `:helptags ALL`). -We also have an [official vim-go tutorial](https://github.com/fatih/vim-go-tutorial). +We also have an [official vim-go tutorial](https://github.com/fatih/vim-go/wiki). + +## FAQ and troubleshooting + +The FAQ and troubleshooting tips are in the documentation and can be quickly +accessed using `:help go-troubleshooting`. If you believe you've found a bug or +shortcoming in vim-go that is neither addressed by help nor in [existing +issues](https://github.com/fatih/vim-go/issues), please open an issue with +clear reproduction steps. `:GoReportGitHubIssue` can be used pre-populate a lot +of the information needed when creating a new issue. ## License diff --git a/sources_non_forked/vim-go/autoload/go/auto.vim b/sources_non_forked/vim-go/autoload/go/auto.vim index 11748585..620df1cf 100644 --- a/sources_non_forked/vim-go/autoload/go/auto.vim +++ b/sources_non_forked/vim-go/autoload/go/auto.vim @@ -33,7 +33,7 @@ function! go#auto#echo_go_info() endfunction function! go#auto#auto_type_info() - if !go#config#AutoTypeInfo() || !filereadable(expand('%:p')) + if !go#config#AutoTypeInfo() || !isdirectory(expand('%:p:h')) return endif @@ -42,7 +42,7 @@ function! go#auto#auto_type_info() endfunction function! go#auto#auto_sameids() - if !go#config#AutoSameids() || !filereadable(expand('%:p')) + if !go#config#AutoSameids() || !isdirectory(expand('%:p:h')) return endif @@ -51,7 +51,7 @@ function! go#auto#auto_sameids() endfunction function! go#auto#fmt_autosave() - if !go#config#FmtAutosave() || !filereadable(expand('%:p')) + if !(go#config#FmtAutosave() && isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p')) return endif @@ -60,7 +60,7 @@ function! go#auto#fmt_autosave() endfunction function! go#auto#metalinter_autosave() - if !go#config#MetalinterAutosave() || !filereadable(expand('%:p')) + if !go#config#MetalinterAutosave() || !isdirectory(expand('%:p:h')) return endif @@ -69,7 +69,7 @@ function! go#auto#metalinter_autosave() endfunction function! go#auto#modfmt_autosave() - if !go#config#ModFmtAutosave() || !filereadable(expand('%:p')) + if !(go#config#ModFmtAutosave() && isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p')) return endif @@ -78,7 +78,7 @@ function! go#auto#modfmt_autosave() endfunction function! go#auto#asmfmt_autosave() - if !go#config#AsmfmtAutosave() || !filereadable(expand('%:p')) + if !(go#config#AsmfmtAutosave() && isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p')) return endif diff --git a/sources_non_forked/vim-go/autoload/go/cmd.vim b/sources_non_forked/vim-go/autoload/go/cmd.vim index fdf22990..95e6fd31 100644 --- a/sources_non_forked/vim-go/autoload/go/cmd.vim +++ b/sources_non_forked/vim-go/autoload/go/cmd.vim @@ -9,8 +9,8 @@ function! go#cmd#autowrite() abort for l:nr in range(0, bufnr('$')) if buflisted(l:nr) && getbufvar(l:nr, '&modified') " Sleep one second to make sure people see the message. Otherwise it is - " often immediacy overwritten by the async messages (which also don't - " invoke the "hit ENTER" prompt). + " often immediately overwritten by the async messages (which also + " doesn't invoke the "hit ENTER" prompt). call go#util#EchoWarning('[No write since last change]') sleep 1 return diff --git a/sources_non_forked/vim-go/autoload/go/complete.vim b/sources_non_forked/vim-go/autoload/go/complete.vim index 072153ea..869cf71b 100644 --- a/sources_non_forked/vim-go/autoload/go/complete.vim +++ b/sources_non_forked/vim-go/autoload/go/complete.vim @@ -79,7 +79,12 @@ endfunction " go#complete#GoInfo returns the description of the identifier under the " cursor. function! go#complete#GetInfo() abort - return s:sync_info(0) + let l:mode = go#config#InfoMode() + if l:mode == 'gopls' && go#util#has_job() + return go#lsp#GetInfo() + else + return s:sync_info(0) + endif endfunction function! go#complete#Info(showstatus) abort @@ -216,6 +221,7 @@ function! s:info_complete(echo, result) abort endfunction function! s:trim_bracket(val) abort + echom a:val let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '') return a:val endfunction @@ -240,37 +246,44 @@ function! go#complete#GocodeComplete(findstart, base) abort else let s = getline(".")[col('.') - 1] if s =~ '[(){}\{\}]' - return map(copy(s:completions[1]), 's:trim_bracket(v:val)') + return map(copy(s:completions), 's:trim_bracket(v:val)') endif return s:completions endif endfunction function! go#complete#Complete(findstart, base) abort - let l:state = {'done': 0, 'matches': []} + let l:state = {'done': 0, 'matches': [], 'start': -1} - function! s:handler(state, matches) abort dict + function! s:handler(state, start, matches) abort dict + let a:state.start = a:start 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])) + let [l:line, l:col] = getpos('.')[1:2] + let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col) + let l:completion = go#lsp#Completion(expand('%:p'), l:line, l:col, funcref('s:handler', [l:state])) + if l:completion + return -3 + endif 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('.') + let s:completions = l:state.matches + + return go#lsp#lsp#PositionOf(getline(l:line+1), l:state.start-1) + else "findstart = 0 when we need to return the list of completions return s:completions endif diff --git a/sources_non_forked/vim-go/autoload/go/complete_test.vim b/sources_non_forked/vim-go/autoload/go/complete_test.vim index 43971421..1c9a091f 100644 --- a/sources_non_forked/vim-go/autoload/go/complete_test.vim +++ b/sources_non_forked/vim-go/autoload/go/complete_test.vim @@ -2,23 +2,33 @@ let s:cpo_save = &cpo set cpo&vim -func! Test_GetInfo() +func! Test_GetInfo_gocode() + let g:go_info_mode = 'gocode' + call s:getinfo() + unlet g:go_info_mode +endfunction + +func! Test_GetInfo_guru() + let g:go_info_mode = 'guru' + call s:getinfo() + unlet g:go_info_mode +endfunction + +func! Test_GetInfo_gopls() + let g:go_info_mode = 'gopls' + call s:getinfo() + unlet g:go_info_mode +endfunction + +func! s:getinfo() let l:filename = 'complete/complete.go' let l:tmp = gotest#load_fixture(l:filename) call cursor(8, 3) - let g:go_info_mode = 'gocode' let expected = 'func Example(s string)' let actual = go#complete#GetInfo() call assert_equal(expected, actual) - - let g:go_info_mode = 'guru' - call go#config#InfoMode() - let actual = go#complete#GetInfo() - call assert_equal(expected, actual) - - unlet g:go_info_mode endfunction " restore Vi compatibility settings diff --git a/sources_non_forked/vim-go/autoload/go/config.vim b/sources_non_forked/vim-go/autoload/go/config.vim index b325c29e..5c035693 100644 --- a/sources_non_forked/vim-go/autoload/go/config.vim +++ b/sources_non_forked/vim-go/autoload/go/config.vim @@ -21,10 +21,12 @@ endfunction function! go#config#SetBuildTags(value) abort if a:value is '' silent! unlet g:go_build_tags + call go#lsp#ResetWorkspaceDirectories() return endif let g:go_build_tags = a:value + call go#lsp#ResetWorkspaceDirectories() endfunction function! go#config#TestTimeout() abort @@ -47,6 +49,14 @@ function! go#config#TermMode() abort return get(g:, 'go_term_mode', 'vsplit') endfunction +function! go#config#TermCloseOnExit() abort + return get(g:, 'go_term_close_on_exit', 1) +endfunction + +function! go#config#SetTermCloseOnExit(value) abort + let g:go_term_close_on_exit = a:value +endfunction + function! go#config#TermEnabled() abort return has('nvim') && get(g:, 'go_term_enabled', 0) endfunction @@ -114,7 +124,7 @@ function! go#config#ListAutoclose() abort endfunction function! go#config#InfoMode() abort - return get(g:, 'go_info_mode', 'gocode') + return get(g:, 'go_info_mode', 'gopls') endfunction function! go#config#GuruScope() abort @@ -174,12 +184,15 @@ function! go#config#DocUrl() abort return godoc_url endfunction +function! go#config#DocPopupWindow() abort + return get(g:, 'go_doc_popup_window', 0) +endfunction function! go#config#DefReuseBuffer() abort return get(g:, 'go_def_reuse_buffer', 0) endfunction function! go#config#DefMode() abort - return get(g:, 'go_def_mode', 'guru') + return get(g:, 'go_def_mode', 'gopls') endfunction function! go#config#DeclsIncludes() abort @@ -268,10 +281,6 @@ function! go#config#MetalinterEnabled() abort return get(g:, "go_metalinter_enabled", default_enabled) endfunction -function! go#config#MetalinterDisabled() abort - return get(g:, "go_metalinter_disabled", []) -endfunction - function! go#config#GolintBin() abort return get(g:, "go_golint_bin", "golint") endfunction diff --git a/sources_non_forked/vim-go/autoload/go/debug.vim b/sources_non_forked/vim-go/autoload/go/debug.vim index e2d0b9fa..bb14cf0a 100644 --- a/sources_non_forked/vim-go/autoload/go/debug.vim +++ b/sources_non_forked/vim-go/autoload/go/debug.vim @@ -576,7 +576,7 @@ function! go#debug#Start(is_test, ...) abort return s:state['job'] endif - let s:start_args = a:000 + let s:start_args = [a:is_test] + a:000 if go#util#HasDebug('debugger-state') call go#config#SetDebugDiag(s:state) @@ -595,10 +595,23 @@ function! go#debug#Start(is_test, ...) abort " append the package when it's given. if len(a:000) > 0 - let l:pkgname = go#package#FromPath(a:1) - if l:pkgname is -1 - call go#util#EchoError('could not determine package name') - return + let l:pkgname = a:1 + if l:pkgname[0] == '.' + let l:pkgabspath = fnamemodify(l:pkgname, ':p') + + let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let l:dir = getcwd() + execute l:cd fnameescape(expand('%:p:h')) + + try + let l:pkgname = go#package#FromPath(l:pkgabspath) + if type(l:pkgname) == type(0) + call go#util#EchoError('could not determine package name') + return + endif + finally + execute l:cd fnameescape(l:dir) + endtry endif let l:cmd += [l:pkgname] diff --git a/sources_non_forked/vim-go/autoload/go/debug_test.vim b/sources_non_forked/vim-go/autoload/go/debug_test.vim index f5572e51..b9aeb2a8 100644 --- a/sources_non_forked/vim-go/autoload/go/debug_test.vim +++ b/sources_non_forked/vim-go/autoload/go/debug_test.vim @@ -10,6 +10,10 @@ function! Test_GoDebugStart_RelativePackage() abort call s:debug('./debug/debugmain') endfunction +function! Test_GoDebugStart_RelativePackage_NullModule() abort + call s:debug('./debug/debugmain', 1) +endfunction + function! Test_GoDebugStart_Package() abort call s:debug('debug/debugmain') endfunction @@ -52,14 +56,22 @@ function! Test_GoDebugStart_Errors() abort endtry endfunction +" s:debug takes 2 optional arguments. The first is a package to debug. The +" second is a flag to indicate whether to reset GOPATH after +" gotest#load_fixture is called in order to test behavior outside of GOPATH. function! s:debug(...) abort if !go#util#has_job() return endif try + let $oldgopath = $GOPATH let l:tmp = gotest#load_fixture('debug/debugmain/debugmain.go') + if a:0 > 1 && a:2 == 1 + let $GOPATH = $oldgopath + endif + call go#debug#Breakpoint(6) call assert_false(exists(':GoDebugStop')) diff --git a/sources_non_forked/vim-go/autoload/go/def.vim b/sources_non_forked/vim-go/autoload/go/def.vim index 5fa11414..becd7bb5 100644 --- a/sources_non_forked/vim-go/autoload/go/def.vim +++ b/sources_non_forked/vim-go/autoload/go/def.vim @@ -6,7 +6,7 @@ let s:go_stack = [] let s:go_stack_level = 0 function! go#def#Jump(mode, type) abort - let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') + let l:fname = fnamemodify(expand("%"), ':p:gs?\\?/?') " so guru right now is slow for some people. previously we were using " godef which also has it's own quirks. But this issue come up so many @@ -66,7 +66,7 @@ function! go#def#Jump(mode, type) abort let [l:out, l:err] = go#util#ExecInDir(l:cmd) endif elseif bin_name == 'gopls' - let [l:line, l:col] = getpos('.')[1:2] + let [l:line, l:col] = go#lsp#lsp#Position() " delegate to gopls, with an empty job object and an exit status of 0 " (they're irrelevant for gopls). if a:type diff --git a/sources_non_forked/vim-go/autoload/go/def_test.vim b/sources_non_forked/vim-go/autoload/go/def_test.vim index a054471c..6a855417 100644 --- a/sources_non_forked/vim-go/autoload/go/def_test.vim +++ b/sources_non_forked/vim-go/autoload/go/def_test.vim @@ -2,19 +2,21 @@ let s:cpo_save = &cpo set cpo&vim +scriptencoding utf-8 + func! Test_jump_to_declaration_guru() abort try let l:filename = 'def/jump.go' - let lnum = 5 - let col = 6 + let l:lnum = 5 + let l:col = 6 let l:tmp = gotest#load_fixture(l:filename) - let guru_out = printf("%s:%d:%d: defined here as func main", filename, lnum, col) - call go#def#jump_to_declaration(guru_out, "", 'guru') + let l:guru_out = printf("%s:%d:%d: defined here as func main", l:filename, l:lnum, l:col) + call go#def#jump_to_declaration(l:guru_out, "", 'guru') - call assert_equal(filename, bufname("%")) - call assert_equal(lnum, getcurpos()[1]) - call assert_equal(col, getcurpos()[2]) + call assert_equal(l:filename, bufname("%")) + call assert_equal(l:lnum, getcurpos()[1]) + call assert_equal(l:col, getcurpos()[2]) finally call delete(l:tmp, 'rf') endtry @@ -22,17 +24,17 @@ endfunc func! Test_jump_to_declaration_godef() abort try - let filename = 'def/jump.go' - let lnum = 5 - let col = 6 + let l:filename = 'def/jump.go' + let l:lnum = 5 + let l:col = 6 let l:tmp = gotest#load_fixture(l:filename) - let godef_out = printf("%s:%d:%d\ndefined here as func main", filename, lnum, col) + let l:godef_out = printf("%s:%d:%d\ndefined here as func main", l:filename, l:lnum, l:col) call go#def#jump_to_declaration(godef_out, "", 'godef') - call assert_equal(filename, bufname("%")) - call assert_equal(lnum, getcurpos()[1]) - call assert_equal(col, getcurpos()[2]) + call assert_equal(l:filename, bufname("%")) + call assert_equal(l:lnum, getcurpos()[1]) + call assert_equal(l:col, getcurpos()[2]) finally call delete(l:tmp, 'rf') endtry @@ -40,33 +42,180 @@ endfunc func! Test_Jump_leaves_lists() abort try - let filename = 'def/jump.go' + let l:filename = 'def/jump.go' let l:tmp = gotest#load_fixture(l:filename) - let expected = [{'lnum': 10, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'quux'}] + let l:expected = [{'lnum': 10, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'quux'}] - call setloclist(winnr(), copy(expected), 'r' ) - call setqflist(copy(expected), 'r' ) + call setloclist(winnr(), copy(l:expected), 'r' ) + call setqflist(copy(l:expected), 'r' ) let l:bufnr = bufnr('%') call cursor(6, 7) + + if !go#util#has_job() + let g:go_def_mode='godef' + endif call go#def#Jump('', 0) - let start = reltime() - while bufnr('%') == l:bufnr && reltimefloat(reltime(start)) < 10 + if !go#util#has_job() + unlet g:go_def_mode + endif + + let l:start = reltime() + while bufnr('%') == l:bufnr && reltimefloat(reltime(l:start)) < 10 sleep 100m endwhile - let actual = getloclist(winnr()) - call gotest#assert_quickfix(actual, expected) + let l:actual = getloclist(winnr()) + call gotest#assert_quickfix(l:actual, l:expected) - let actual = getqflist() - call gotest#assert_quickfix(actual, expected) + let l:actual = getqflist() + call gotest#assert_quickfix(l:actual, l:expected) finally call delete(l:tmp, 'rf') endtry endfunc +func! Test_DefJump_gopls_simple_first() abort + if !go#util#has_job() + return + endif + + try + let g:go_def_mode = 'gopls' + + let l:tmp = gotest#write_file('simple/firstposition/firstposition.go', [ + \ 'package firstposition', + \ '', + \ 'func Example() {', + \ "\tid := " . '"foo"', + \ "\tprintln(" . '"id:", id)', + \ '}', + \ ] ) + + let l:expected = [0, 4, 2, 0] + + call assert_notequal(l:expected, getpos('.')) + + call go#def#Jump('', 0) + + let l:start = reltime() + while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10 + sleep 100m + endwhile + + call assert_equal(l:expected, getpos('.')) + finally + call delete(l:tmp, 'rf') + unlet g:go_def_mode + endtry +endfunc + +func! Test_DefJump_gopls_simple_last() abort + if !go#util#has_job() + return + endif + + try + let g:go_def_mode = 'gopls' + + let l:tmp = gotest#write_file('simple/lastposition/lastposition.go', [ + \ 'package lastposition', + \ '', + \ 'func Example() {', + \ "\tid := " . '"foo"', + \ "\tprintln(" . '"id:", id)', + \ '}', + \ ] ) + + let l:expected = [0, 4, 2, 0] + + call assert_notequal(l:expected, getpos('.')) + + call go#def#Jump('', 0) + + let l:start = reltime() + while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10 + sleep 100m + endwhile + + call assert_equal(l:expected, getpos('.')) + finally + call delete(l:tmp, 'rf') + unlet g:go_def_mode + endtry +endfunc + +func! Test_DefJump_gopls_MultipleCodeUnit_first() abort + if !go#util#has_job() + return + endif + + try + let g:go_def_mode = 'gopls' + + let l:tmp = gotest#write_file('multiplecodeunit/firstposition/firstposition.go', [ + \ 'package firstposition', + \ '', + \ 'func Example() {', + \ "\t𐐀, id := " . '"foo", "bar"', + \ "\tprintln(" . '"(𐐀, id):", 𐐀, id)', + \ '}', + \ ] ) + + let l:expected = [0, 4, 8, 0] + call assert_notequal(l:expected, getpos('.')) + + call go#def#Jump('', 0) + + let l:start = reltime() + while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10 + sleep 100m + endwhile + + call assert_equal(l:expected, getpos('.')) + finally + call delete(l:tmp, 'rf') + unlet g:go_def_mode + endtry +endfunc + + +func! Test_DefJump_gopls_MultipleCodeUnit_last() abort + if !go#util#has_job() + return + endif + + try + let g:go_def_mode = 'gopls' + + let l:tmp = gotest#write_file('multiplecodeunit/lastposition/lastposition.go', [ + \ 'package lastposition', + \ '', + \ 'func Example() {', + \ "\t𐐀, id := " . '"foo", "bar"', + \ "\tprintln(" . '"(𐐀, id):", 𐐀, id)', + \ '}', + \ ] ) + + let l:expected = [0, 4, 8, 0] + call assert_notequal(l:expected, getpos('.')) + + call go#def#Jump('', 0) + + let l:start = reltime() + while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10 + sleep 100m + endwhile + + call assert_equal(l:expected, getpos('.')) + finally + call delete(l:tmp, 'rf') + unlet g:go_def_mode + endtry +endfunc + " restore Vi compatibility settings let &cpo = s:cpo_save unlet s:cpo_save diff --git a/sources_non_forked/vim-go/autoload/go/doc.vim b/sources_non_forked/vim-go/autoload/go/doc.vim index 3960a1be..cf2493ea 100644 --- a/sources_non_forked/vim-go/autoload/go/doc.vim +++ b/sources_non_forked/vim-go/autoload/go/doc.vim @@ -76,6 +76,18 @@ function! go#doc#Open(newmode, mode, ...) abort endfunction function! s:GodocView(newposition, position, content) abort + " popup window + if go#config#DocPopupWindow() && exists('*popup_atcursor') && exists('*popup_clear') + call popup_clear() + + call popup_atcursor(split(a:content, '\n'), { + \ 'padding': [1, 1, 1, 1], + \ 'borderchars': ['-','|','-','|','+','+','+','+'], + \ "border": [1, 1, 1, 1], + \ }) + return + endif + " reuse existing buffer window if it exists otherwise create a new one let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1 if !bufexists(s:buf_nr) diff --git a/sources_non_forked/vim-go/autoload/go/issue.vim b/sources_non_forked/vim-go/autoload/go/issue.vim index 65db9d80..c76df7f4 100644 --- a/sources_non_forked/vim-go/autoload/go/issue.vim +++ b/sources_non_forked/vim-go/autoload/go/issue.vim @@ -18,20 +18,30 @@ function! s:issuebody() abort for l in lines let body = add(body, l) - if l =~ '^\* Vim version' + if l =~ '^<!-- :version' redir => out silent version redir END let body = extend(body, split(out, "\n")[0:2]) - elseif l =~ '^\* Go version' + elseif l =~ '^<!-- go version -->' let [out, err] = go#util#Exec(['go', 'version']) let body = add(body, substitute(l:out, rtrimpat, '', '')) - elseif l =~ '^\* Go environment' + elseif l =~ '^<!-- go env -->' let [out, err] = go#util#Exec(['go', 'env']) let body = add(body, substitute(l:out, rtrimpat, '', '')) endif endfor + let body = add(body, "#### vim-go configuration:\n<details><summary>vim-go configuration</summary><br><pre>") + + for k in keys(g:) + if k =~ '^go_' + let body = add(body, 'g:' . k . ' = ' . string(get(g:, k))) + endif + endfor + + let body = add(body, '</pre></details>') + return join(body, "\n") endfunction diff --git a/sources_non_forked/vim-go/autoload/go/lint.vim b/sources_non_forked/vim-go/autoload/go/lint.vim index d56f3da8..322cc674 100644 --- a/sources_non_forked/vim-go/autoload/go/lint.vim +++ b/sources_non_forked/vim-go/autoload/go/lint.vim @@ -22,10 +22,6 @@ function! go#lint#Gometa(bang, autosave, ...) abort for linter in linters let cmd += ["--enable=".linter] endfor - - for linter in go#config#MetalinterDisabled() - let cmd += ["--disable=".linter] - endfor else " the user wants something else, let us use it. let cmd = split(go#config#MetalinterCommand(), " ") @@ -44,7 +40,7 @@ function! go#lint#Gometa(bang, autosave, ...) abort endif let cmd += include elseif l:metalinter == "golangci-lint" - let goargs[0] = expand('%:p') + let goargs[0] = expand('%:p:h') endif endif @@ -88,7 +84,13 @@ function! go#lint#Gometa(bang, autosave, ...) abort else let l:winid = win_getid(winnr()) " Parse and populate our location list - call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter') + + let l:messages = split(out, "\n") + + if a:autosave + call s:metalinterautosavecomplete(fnamemodify(expand('%:p'), ":."), 0, 1, l:messages) + endif + call go#list#ParseFormat(l:listtype, errformat, l:messages, 'GoMetaLinter') let errors = go#list#Get(l:listtype) call go#list#Window(l:listtype, len(errors)) @@ -105,7 +107,7 @@ endfunction " the location list function! go#lint#Golint(bang, ...) abort if a:0 == 0 - let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), go#package#ImportPath()]) + let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), expand('%:p:h')]) else let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000) endif @@ -141,7 +143,7 @@ function! go#lint#Vet(bang, ...) abort if a:0 == 0 let [l:out, l:err] = go#util#Exec(['go', 'vet', go#package#ImportPath()]) else - let [l:out, l:err] = go#util#Exec(['go', 'tool', 'vet'] + a:000) + let [l:out, l:err] = go#util#ExecInDir(['go', 'tool', 'vet'] + a:000) endif let l:listtype = go#list#Type("GoVet") @@ -230,6 +232,7 @@ function! s:lint_job(args, bang, autosave) if a:autosave let l:opts.for = "GoMetaLinterAutoSave" + let l:opts.complete = funcref('s:metalinterautosavecomplete', [expand('%:p:t')]) endif " autowrite is not enabled for jobs @@ -279,6 +282,21 @@ function! s:golangcilintcmd(bin_path) return cmd endfunction +function! s:metalinterautosavecomplete(filepath, job, exit_code, messages) + if len(a:messages) == 0 + return + endif + + let l:file = expand('%:p:t') + let l:idx = len(a:messages) - 1 + while l:idx >= 0 + if a:messages[l:idx] !~# '^' . a:filepath . ':' + call remove(a:messages, l:idx) + endif + let l:idx -= 1 + endwhile +endfunction + " restore Vi compatibility settings let &cpo = s:cpo_save unlet s:cpo_save diff --git a/sources_non_forked/vim-go/autoload/go/lint_test.vim b/sources_non_forked/vim-go/autoload/go/lint_test.vim index dccc138a..e75b0595 100644 --- a/sources_non_forked/vim-go/autoload/go/lint_test.vim +++ b/sources_non_forked/vim-go/autoload/go/lint_test.vim @@ -3,7 +3,7 @@ let s:cpo_save = &cpo set cpo&vim func! Test_Gometa() abort - call s:gometa('gometaliner') + call s:gometa('gometalinter') endfunc func! Test_GometaGolangciLint() abort @@ -11,14 +11,19 @@ func! Test_GometaGolangciLint() abort endfunc func! s:gometa(metalinter) abort - let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' + let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint') silent exe 'e ' . $GOPATH . '/src/lint/lint.go' try - let g:go_metalinter_comand = a:metalinter + let g:go_metalinter_command = 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)'} \ ] + if a:metalinter == 'golangci-lint' + let expected = [ + \ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function `MissingFooDoc` should have comment or be unexported (golint)'} + \ ] + endif " clear the quickfix lists call setqflist([], 'r') @@ -36,48 +41,11 @@ func! s:gometa(metalinter) abort call gotest#assert_quickfix(actual, expected) finally + call call(RestoreGOPATH, []) 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)'} - \ ] - - " clear the quickfix lists - call setqflist([], 'r') - - let g:go_metalinter_disabled = ['vet'] - - call go#lint#Gometa(0, 0, $GOPATH . '/src/foo') - - let actual = getqflist() - let start = reltime() - while len(actual) == 0 && reltimefloat(reltime(start)) < 10 - sleep 100m - let actual = getqflist() - endwhile - - call gotest#assert_quickfix(actual, expected) - finally - unlet g:go_metalinter_disabled - endtry -endfunc - func! Test_GometaAutoSave() abort call s:gometaautosave('gometalinter') endfunc @@ -87,14 +55,19 @@ func! Test_GometaAutoSaveGolangciLint() abort endfunc func! s:gometaautosave(metalinter) abort - let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' + let RestoreGOPATH = go#util#SetEnv('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 g:go_metalinter_command = 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)'} \ ] + if a:metalinter == 'golangci-lint' + let expected = [ + \ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function `MissingDoc` should have comment or be unexported (golint)'} + \ ] + endif let winnr = winnr() @@ -114,18 +87,50 @@ func! s:gometaautosave(metalinter) abort call gotest#assert_quickfix(actual, expected) finally + call call(RestoreGOPATH, []) unlet g:go_metalinter_autosave_enabled endtry endfunc func! Test_Vet() abort - let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' - silent exe 'e ' . $GOPATH . '/src/vet/vet.go' + let l:tmp = gotest#load_fixture('lint/src/vet/vet.go') + + try + + let expected = [ + \ {'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'} + \ ] + + let winnr = winnr() + + " clear the location lists + call setqflist([], 'r') + + call go#lint#Vet(1) + + let actual = getqflist() + let start = reltime() + while len(actual) == 0 && reltimefloat(reltime(start)) < 10 + sleep 100m + let actual = getqflist() + endwhile + + call gotest#assert_quickfix(actual, expected) + finally + call delete(l:tmp, 'rf') + endtry +endfunc + +func! Test_Lint_GOPATH() abort + let RestoreGOPATH = go#util#SetEnv('GOPATH', fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint') + + silent exe 'e ' . $GOPATH . '/src/lint/lint.go' compiler go let expected = [ - \ {'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'} + \ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported'}, + \ {'lnum': 5, 'bufnr': 6, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function AlsoMissingDoc should have comment or be unexported'} \ ] let winnr = winnr() @@ -133,7 +138,35 @@ func! Test_Vet() abort " clear the location lists call setqflist([], 'r') - call go#lint#Vet(1) + call go#lint#Golint(1) + + let actual = getqflist() + let start = reltime() + while len(actual) == 0 && reltimefloat(reltime(start)) < 10 + sleep 100m + let actual = getqflist() + endwhile + + call gotest#assert_quickfix(actual, expected) + + call call(RestoreGOPATH, []) +endfunc + +func! Test_Lint_NullModule() abort + silent exe 'e ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint/src/lint/lint.go' + compiler go + + let expected = [ + \ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported'}, + \ {'lnum': 5, 'bufnr': 6, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function AlsoMissingDoc should have comment or be unexported'} + \ ] + + let winnr = winnr() + + " clear the location lists + call setqflist([], 'r') + + call go#lint#Golint(1) let actual = getqflist() let start = reltime() diff --git a/sources_non_forked/vim-go/autoload/go/lsp.vim b/sources_non_forked/vim-go/autoload/go/lsp.vim index 47205759..bb41a7d8 100644 --- a/sources_non_forked/vim-go/autoload/go/lsp.vim +++ b/sources_non_forked/vim-go/autoload/go/lsp.vim @@ -7,7 +7,7 @@ scriptencoding utf-8 let s:lspfactory = {} function! s:lspfactory.get() dict abort - if !has_key(self, 'current') || empty(self.current) + if empty(get(self, 'current', {})) || empty(get(self.current, 'job', {})) let self.current = s:newlsp() endif @@ -22,9 +22,16 @@ endfunction function! s:newlsp() abort 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 + let l:oldshortmess=&shortmess + if has('nvim') + set shortmess-=F + endif + call go#util#EchoWarning('Features that rely on gopls will not work without either Vim 8.0.0087 or newer with +job or Neovim') + " Sleep one second to make sure people see the message. Otherwise it is + " often immediately overwritten by an async message. + sleep 1 + let &shortmess=l:oldshortmess + return {'sendMessage': funcref('s:noop')} endif " job is the job used to talk to the backing instance of gopls. @@ -47,6 +54,8 @@ function! s:newlsp() abort \ 'last_request_id': 0, \ 'buf': '', \ 'handlers': {}, + \ 'workspaceDirectories': [], + \ 'wd' : '', \ } function! l:lsp.readMessage(data) dict abort @@ -75,19 +84,17 @@ function! s:newlsp() abort endif " get the start of the rest - let l:rest_start_idx = l:body_start_idx + str2nr(l:length_match[1]) + let l:next_start_idx = l:body_start_idx + str2nr(l:length_match[1]) - if len(l:rest) < l:rest_start_idx + if len(l:rest) < l:next_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 + call s:debug('received', l:rest[:l:next_start_idx - 1]) - let l:body = l:rest[l:body_start_idx : l:rest_start_idx - 1] - let l:rest = l:rest[l:rest_start_idx :] + let l:body = l:rest[l:body_start_idx : l:next_start_idx - 1] + let l:rest = l:rest[l:next_start_idx :] try " add the json body to the list. @@ -105,46 +112,99 @@ function! s:newlsp() abort function! l:lsp.handleMessage(ch, data) dict abort let self.buf .= a:data - let [self.buf, l:responses] = self.readMessage(self.buf) + let [self.buf, l:messages] = 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] - - let l:winid = win_getid(winnr()) - " Always set the active window to the window that was active when - " the request was sent. Among other things, this makes sure that - " the correct window's location list will be populated when the - " list type is 'location' and the user has moved windows since - " sending the reques. - call win_gotoid(l:handler.winid) - - if has_key(l:response, 'error') - call l:handler.requestComplete(0) - if has_key(l:handler, 'error') - call call(l:handler.error, [l:response.error.message]) - else - call go#util#EchoError(l:response.error.message) - endif - call win_gotoid(l:winid) - return - endif - call l:handler.requestComplete(1) - call call(l:handler.handleResult, [l:response.result]) - call win_gotoid(l:winid) - finally - call remove(self.handlers, l:response.id) - endtry + for l:message in l:messages + if has_key(l:message, 'method') + if has_key(l:message, 'id') + call self.handleRequest(l:message) + else + call self.handleNotification(l:message) + endif + elseif has_key(l:message, 'result') || has_key(l:message, 'error') + call self.handleResponse(l:message) endif endfor endfunction + function! l:lsp.handleRequest(req) dict abort + if a:req.method == 'workspace/workspaceFolders' + let l:resp = go#lsp#message#WorkspaceFoldersResult(self.workspaceDirectories) + elseif a:req.method == 'workspace/configuration' && has_key(a:req, 'params') && has_key(a:req.params, 'items') + let l:resp = go#lsp#message#ConfigurationResult(a:req.params.items) + elseif a:req.method == 'client/registerCapability' && has_key(a:req, 'params') && has_key(a:req.params, 'registrations') + let l:resp = v:null + else + return + endif + + if get(self, 'exited', 0) + return + endif + + let l:msg = self.newResponse(a:req.id, l:resp) + call self.write(l:msg) + endfunction + + function! l:lsp.handleNotification(req) dict abort + " TODO(bc): handle notifications (e.g. window/showMessage). + endfunction + + function! l:lsp.handleResponse(resp) dict abort + if has_key(a:resp, 'id') && has_key(self.handlers, a:resp.id) + try + let l:handler = self.handlers[a:resp.id] + + let l:winid = win_getid(winnr()) + " Always set the active window to the window that was active when + " the request was sent. Among other things, this makes sure that + " the correct window's location list will be populated when the + " list type is 'location' and the user has moved windows since + " sending the request. + call win_gotoid(l:handler.winid) + + if has_key(a:resp, 'error') + call l:handler.requestComplete(0) + if has_key(l:handler, 'error') + call call(l:handler.error, [a:resp.error.message]) + else + call go#util#EchoError(a:resp.error.message) + endif + call win_gotoid(l:winid) + return + endif + call l:handler.requestComplete(1) + + let l:winidBeforeHandler = l:handler.winid + call call(l:handler.handleResult, [a:resp.result]) + + " change the window back to the window that was active when + " starting to handle the message _only_ if the handler didn't + " update the winid, so that handlers can set the winid if needed + " (e.g. :GoDef). + if l:handler.winid == l:winidBeforeHandler + call win_gotoid(l:winid) + endif + finally + call remove(self.handlers, a:resp.id) + endtry + endif + endfunction + function! l:lsp.handleInitializeResult(result) dict abort + if go#config#EchoCommandInfo() + call go#util#EchoProgress("initialized gopls") + endif + let status = { + \ 'desc': '', + \ 'type': 'gopls', + \ 'state': 'initialized', + \ } + call go#statusline#Update(self.wd, status) + let self.ready = 1 - " TODO(bc): send initialized message to the server? + let l:msg = self.newMessage(go#lsp#message#Initialized()) + call self.write(l:msg) " send messages queued while waiting for ready. for l:item in self.queue @@ -157,22 +217,34 @@ function! s:newlsp() abort 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:wd = go#util#ModuleRoot() if l:wd == -1 call go#util#EchoError('could not determine appropriate working directory for gopls') - return + return -1 endif if l:wd == '' let l:wd = getcwd() endif + let self.wd = l:wd + if go#config#EchoCommandInfo() + call go#util#EchoProgress("initializing gopls") + endif + + let l:status = { + \ 'desc': '', + \ 'type': 'gopls', + \ 'state': 'initializing', + \ } + call go#statusline#Update(l:wd, l:status) + + let self.workspaceDirectories = add(self.workspaceDirectories, l:wd) let l:msg = self.newMessage(go#lsp#message#Initialize(l:wd)) let l:state = s:newHandlerState('') let l:state.handleResult = funcref('self.handleInitializeResult', [], l:self) + let self.handlers[l:msg.id] = l:state call l:state.start() @@ -199,7 +271,7 @@ function! s:newlsp() abort let l:msg = { \ 'method': a:data.method, \ 'jsonrpc': '2.0', - \ } + \ } if !a:data.notification let self.last_request_id += 1 @@ -213,13 +285,21 @@ function! s:newlsp() abort 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 + function l:lsp.newResponse(id, result) dict abort + let l:msg = { + \ 'jsonrpc': '2.0', + \ 'id': a:id, + \ 'result': a:result, + \ } - if go#util#HasDebug('lsp') - let g:go_lsp_log = add(go#config#LspLog(), "->\n" . l:data) - 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 + + call s:debug('sent', l:data) if has('nvim') call chansend(self.job, l:data) @@ -229,19 +309,39 @@ function! s:newlsp() abort call ch_sendraw(self.job, l:data) endfunction - function! l:lsp.exit_cb(job, exit_status) dict abort + function! l:lsp.exit_cb(job, exit_status) dict + let self.exited = 1 + if !get(self, 'restarting', 0) + return + endif + + let l:queue = self.queue + + let l:workspaces = self.workspaceDirectories + call s:lspfactory.reset() + let l:lsp = s:lspfactory.get() + + " restore workspaces + call call('go#lsp#AddWorkspaceDirectory', l:workspaces) + " * send DidOpen messages for all buffers that have b:did_lsp_open set + " TODO(bc): check modifiable and filetype, too? + bufdo if get(b:, 'go_lsp_did_open', 0) | if &modified | call go#lsp#DidOpen(expand('%:p')) | else | call go#lsp#DidChange(expand('%:p')) | endif | endif + let l:lsp.queue = extend(l:lsp.queue, l:queue) + return 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? + " TODO(bc): remove the buffer variables that indicate that gopls has been + " informed that the file is open 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) + if a:msg =~ '^\tPort = \d\+$' && !get(self, 'debugport', 0) + let self.debugport = substitute(a:msg, '^\tPort = \(\d\+\).*$', '\1', '') endif + + call s:debug('stderr', a:msg) endfunction " explicitly bind callbacks to l:lsp so that within it, self will always refer @@ -263,11 +363,13 @@ function! s:newlsp() abort 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) + let l:cmd = [l:bin_path] + if go#util#HasDebug('lsp') + let l:cmd = extend(l:cmd, ['-debug', 'localhost:0']) + endif + + let l:lsp.job = go#job#Start(l:cmd, l:opts) - " TODO(bc): send the initialize message now? return l:lsp endfunction @@ -327,16 +429,17 @@ function! s:requestComplete(ok) abort dict 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() + if self.statustype == '' + return + endif + let status = { + \ 'desc': 'current status', + \ 'type': self.statustype, + \ 'state': "started", + \ } + + call go#statusline#Update(self.jobdir, status) endfunction " go#lsp#Definition calls gopls to get the definition of the identifier at @@ -351,13 +454,13 @@ function! go#lsp#Definition(fname, line, col, handler) abort 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) + return 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')]] + let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, go#lsp#lsp#PositionOf(getline(l:msg.range.start.line+1), l:msg.range.start.character), 'lsp does not supply a description')]] call call(a:next, l:args) endfunction @@ -373,13 +476,13 @@ function! go#lsp#TypeDef(fname, line, col, handler) abort 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) + return 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')]] + let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, go#lsp#lsp#PositionOf(getline(l:msg.range.start.line+1), l:msg.range.start.character), 'lsp does not supply a description')]] call call(a:next, l:args) endfunction @@ -396,9 +499,13 @@ function! go#lsp#DidOpen(fname) abort let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n") let l:state = s:newHandlerState('') let l:state.handleResult = funcref('s:noop') - call l:lsp.sendMessage(l:msg, l:state) + " TODO(bc): setting a buffer level variable here assumes that a:fname is the + " current buffer. Change to a:fname first before setting it and then change + " back to active buffer. let b:go_lsp_did_open = 1 + + return l:lsp.sendMessage(l:msg, l:state) endfunction function! go#lsp#DidChange(fname) abort @@ -409,17 +516,17 @@ function! go#lsp#DidChange(fname) abort return endif - call go#lsp#DidOpen(a:fname) - if !filereadable(a:fname) return endif + call go#lsp#DidOpen(a:fname) + 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) + return l:lsp.sendMessage(l:msg, l:state) endfunction function! go#lsp#DidClose(fname) abort @@ -435,9 +542,12 @@ function! go#lsp#DidClose(fname) abort 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) - + " TODO(bc): setting a buffer level variable here assumes that a:fname is the + " current buffer. Change to a:fname first before setting it and then change + " back to active buffer. let b:go_lsp_did_open = 0 + + return l:lsp.sendMessage(l:msg, l:state) endfunction function! go#lsp#Completion(fname, line, col, handler) abort @@ -448,16 +558,33 @@ function! go#lsp#Completion(fname, line, col, handler) abort 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) + return l:lsp.sendMessage(l:msg, l:state) endfunction function! s:completionHandler(next, msg) abort dict " gopls returns a CompletionList. let l:matches = [] + let l:start = -1 + for l:item in a:msg.items + let l:start = l:item.textEdit.range.start.character + 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:match.info = l:item.detail + let l:match.menu = l:item.detail + if go#lsp#completionitemkind#IsFunction(l:item.kind) || go#lsp#completionitemkind#IsMethod(l:item.kind) + let l:match.info = printf('%s %s', l:item.label, l:item.detail) + + " The detail provided by gopls hasn't always provided the the full + " signature including the return value. The label used to be the + " function signature and the detail was the return value. Handle + " that case for backward compatibility. This can be removed in the + " future once it's likely that the majority of users are on a recent + " version of gopls. + if l:item.detail !~ '^func' + let l:match.info = printf('func %s %s', l:item.label, l:item.detail) + endif + endif endif if has_key(l:item, 'documentation') @@ -466,12 +593,12 @@ function! s:completionHandler(next, msg) abort dict let l:matches = add(l:matches, l:match) endfor - let l:args = [l:matches] + let l:args = [l:start, l:matches] call call(a:next, l:args) endfunction function! s:completionErrorHandler(next, error) abort dict - call call(a:next, [[]]) + call call(a:next, [-1, []]) endfunction function! go#lsp#Hover(fname, line, col, handler) abort @@ -482,7 +609,7 @@ function! go#lsp#Hover(fname, line, col, handler) abort let l:state = s:newHandlerState('') let l:state.handleResult = funcref('s:hoverHandler', [function(a:handler, [], l:state)], l:state) let l:state.error = funcref('s:noop') - call l:lsp.sendMessage(l:msg, l:state) + return l:lsp.sendMessage(l:msg, l:state) endfunction function! s:hoverHandler(next, msg) abort dict @@ -499,7 +626,7 @@ endfunction function! go#lsp#Info(showstatus) let l:fname = expand('%:p') - let [l:line, l:col] = getpos('.')[1:2] + let [l:line, l:col] = go#lsp#lsp#Position() call go#lsp#DidChange(l:fname) @@ -511,10 +638,29 @@ function! go#lsp#Info(showstatus) let l:state = s:newHandlerState('') endif - let l:state.handleResult = funcref('s:infoDefinitionHandler', [function('s:info', []), a:showstatus], l:state) + let l:state.handleResult = funcref('s:infoDefinitionHandler', [function('s:info', [1], l:state), a:showstatus], l:state) + let l:state.error = funcref('s:noop') + let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col) + return l:lsp.sendMessage(l:msg, l:state) +endfunction + +function! go#lsp#GetInfo() + let l:fname = expand('%:p') + let [l:line, l:col] = go#lsp#lsp#Position() + + call go#lsp#DidChange(l:fname) + + let l:lsp = s:lspfactory.get() + + let l:state = s:newHandlerState('') + + let l:info = go#promise#New(function('s:info', [0], l:state), 10000, '') + + let l:state.handleResult = funcref('s:infoDefinitionHandler', [l:info.wrapper, 0], l:state) let l:state.error = funcref('s:noop') let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col) call l:lsp.sendMessage(l:msg, l:state) + return l:info.await() endfunction function! s:infoDefinitionHandler(next, showstatus, msg) abort dict @@ -522,8 +668,8 @@ function! s:infoDefinitionHandler(next, showstatus, msg) abort dict let l:msg = a:msg[0] let l:fname = go#path#FromURI(l:msg.uri) - let l:line = l:msg.range.start.line+1 - let l:col = l:msg.range.start.character+1 + let l:line = l:msg.range.start.line + let l:col = l:msg.range.start.character let l:lsp = s:lspfactory.get() let l:msg = go#lsp#message#Hover(l:fname, l:line, l:col) @@ -534,18 +680,166 @@ function! s:infoDefinitionHandler(next, showstatus, msg) abort dict let l:state = s:newHandlerState('') endif - let l:state.handleResult = funcref('s:hoverHandler', [function('s:info', [], l:state)], l:state) + let l:state.handleResult = funcref('s:hoverHandler', [a:next], l:state) let l:state.error = funcref('s:noop') - call l:lsp.sendMessage(l:msg, l:state) + return l:lsp.sendMessage(l:msg, l:state) endfunction -function! s:info(content) abort dict +function! s:info(show, content) abort dict + let l:content = s:infoFromHoverContent(a:content) + + if a:show + call go#util#ShowInfo(l:content) + endif + + return l:content +endfunction + +function! s:infoFromHoverContent(content) abort + if len(a:content) < 1 + return '' + endif + let l:content = a:content[0] + " strip off the method set and fields of structs and interfaces. - if l:content =~# '^type [^ ]\+ \(struct\|interface\)' + if l:content =~# '^\(type \)\?[^ ]\+ \(struct\|interface\)' let l:content = substitute(l:content, '{.*', '', '') endif - call go#util#ShowInfo(l:content) + + return l:content +endfunction + +function! go#lsp#AddWorkspaceDirectory(...) abort + if a:0 == 0 + return + endif + + call go#lsp#CleanWorkspaces() + + let l:workspaces = [] + for l:dir in a:000 + let l:dir = fnamemodify(l:dir, ':p') + if !isdirectory(l:dir) + continue + endif + + let l:workspaces = add(l:workspaces, l:dir) + endfor + + let l:lsp = s:lspfactory.get() + let l:state = s:newHandlerState('') + let l:state.handleResult = funcref('s:noop') + let l:lsp.workspaceDirectories = extend(l:lsp.workspaceDirectories, l:workspaces) + let l:msg = go#lsp#message#ChangeWorkspaceFolders(l:workspaces, []) + call l:lsp.sendMessage(l:msg, l:state) + + return 0 +endfunction + +function! go#lsp#CleanWorkspaces() abort + let l:workspaces = [] + + let l:lsp = s:lspfactory.get() + + let l:i = 0 + let l:missing = [] + for l:dir in l:lsp.workspaceDirectories + if !isdirectory(l:dir) + let l:dir = add(l:missing, l:dir) + call remove(l:lsp.workspaceDirectories, l:i) + continue + endif + let l:i += 1 + endfor + + let l:state = s:newHandlerState('') + let l:state.handleResult = funcref('s:noop') + let l:msg = go#lsp#message#ChangeWorkspaceFolders([], l:missing) + call l:lsp.sendMessage(l:msg, l:state) + + return 0 +endfunction + +" go#lsp#ResetWorkspaceDiretories removes and then re-adds all workspace +" folders to cause gopls to send configuration requests for all of them again. +" This is useful, for instance, when build tags have been added and gopls +" needs to use them. +function! go#lsp#ResetWorkspaceDirectories() abort + call go#lsp#CleanWorkspaces() + + let l:lsp = s:lspfactory.get() + + let l:state = s:newHandlerState('') + let l:state.handleResult = funcref('s:noop') + let l:msg = go#lsp#message#ChangeWorkspaceFolders(l:lsp.workspaceDirectories, l:lsp.workspaceDirectories) + call l:lsp.sendMessage(l:msg, l:state) + + return 0 +endfunction + +function! go#lsp#DebugBrowser() abort + let l:lsp = s:lspfactory.get() + let l:port = get(l:lsp, 'debugport', 0) + if !l:port + call go#util#EchoError("gopls was not started with debugging enabled. See :help g:go_debug.") + return + endif + + call go#util#OpenBrowser(printf('http://localhost:%d', l:port)) +endfunction + +function! go#lsp#Restart() abort + if !go#util#has_job() || len(s:lspfactory) == 0 || !has_key(s:lspfactory, 'current') + return + endif + + let l:lsp = s:lspfactory.get() + + let l:lsp.restarting = 1 + + let l:state = s:newHandlerState('exit') + + let l:msg = go#lsp#message#Shutdown() + let l:state.handleResult = funcref('s:noop') + let l:retval = l:lsp.sendMessage(l:msg, l:state) + + let l:msg = go#lsp#message#Exit() + let l:retval = l:lsp.sendMessage(l:msg, l:state) + + return l:retval +endfunction + +function! s:debug(event, data) abort + if !go#util#HasDebug('lsp') + return + endif + + let l:winid = win_getid() + + let l:name = '__GOLSP_LOG__' + let l:log_winid = bufwinid(l:name) + if l:log_winid == -1 + silent keepalt botright 10new + silent file `='__GOLSP_LOG__'` + setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline + setlocal filetype=golsplog + else + call win_gotoid(l:log_winid) + endif + + try + setlocal modifiable + if getline(1) == '' + call setline('$', printf('%s: %s', a:event, a:data)) + else + call append('$', printf('%s: %s', a:event, a:data)) + endif + normal! G + setlocal nomodifiable + finally + call win_gotoid(l:winid) + endtry endfunction " restore Vi compatibility settings diff --git a/sources_non_forked/vim-go/autoload/go/lsp/completionitemkind.vim b/sources_non_forked/vim-go/autoload/go/lsp/completionitemkind.vim index 37c00a88..0202bd26 100644 --- a/sources_non_forked/vim-go/autoload/go/lsp/completionitemkind.vim +++ b/sources_non_forked/vim-go/autoload/go/lsp/completionitemkind.vim @@ -28,7 +28,7 @@ let s:Event = 23 let s:Operator = 24 let s:TypeParameter = 25 -function! go#lsp#completionitemkind#Vim(kind) +function! go#lsp#completionitemkind#Vim(kind) abort if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor return 'f' elseif a:kind == s:Variable || a:kind == s:Constant @@ -40,6 +40,22 @@ function! go#lsp#completionitemkind#Vim(kind) endif endfunction +function! go#lsp#completionitemkind#IsFunction(kind) abort + if a:kind == s:Function + return 1 + endif + + return 0 +endfunction + +function! go#lsp#completionitemkind#IsMethod(kind) abort + if a:kind == s:Method + return 1 + endif + + return 0 +endfunction + " restore Vi compatibility settings let &cpo = s:cpo_save unlet s:cpo_save diff --git a/sources_non_forked/vim-go/autoload/go/lsp/lsp.vim b/sources_non_forked/vim-go/autoload/go/lsp/lsp.vim new file mode 100644 index 00000000..56a2da4c --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/lsp/lsp.vim @@ -0,0 +1,58 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +" go#lsp#lsp#Position returns the LSP text position. If no arguments are +" provided, the cursor position is assumed. Otherwise, there should be two +" arguments: the line and the column. +function! go#lsp#lsp#Position(...) + if a:0 < 2 + let [l:line, l:col] = getpos('.')[1:2] + else + let l:line = a:1 + let l:col = a:2 + endif + let l:content = getline(l:line) + + " LSP uses 0-based lines. + return [l:line - 1, s:character(l:line, l:col-1)] +endfunction + +function! s:strlen(str) abort + let l:runes = split(a:str, '\zs') + return len(l:runes) + len(filter(l:runes, 'char2nr(v:val)>=0x10000')) +endfunction + +function! s:character(line, col) abort + return s:strlen(getline(a:line)[:col([a:line, a:col - 1])]) +endfunction + +" go#lsp#PositionOf returns len(content[0:units]) where units is utf-16 code +" units. This is mostly useful for converting LSP text position to vim +" position. +function! go#lsp#lsp#PositionOf(content, units) abort + if a:units == 0 + return 1 + endif + + let l:remaining = a:units + let l:str = "" + for l:rune in split(a:content, '\zs') + if l:remaining < 0 + break + endif + let l:remaining -= 1 + if char2nr(l:rune) >= 0x10000 + let l:remaining -= 1 + endif + let l:str = l:str . l:rune + endfor + + return len(l:str) +endfunction + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/lsp/lsp_test.vim b/sources_non_forked/vim-go/autoload/go/lsp/lsp_test.vim new file mode 100644 index 00000000..24a2a747 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/lsp/lsp_test.vim @@ -0,0 +1,32 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +scriptencoding utf-8 + +function! Test_PositionOf_Simple() + let l:actual = go#lsp#lsp#PositionOf("just ascii", 3) + call assert_equal(4, l:actual) +endfunc + + +function! Test_PositionOf_MultiByte() + " ⌘ is U+2318, which encodes to three bytes in utf-8 and 1 code unit in + " utf-16. + let l:actual = go#lsp#lsp#PositionOf("⌘⌘ foo", 3) + call assert_equal(8, l:actual) +endfunc + +function! Test_PositionOf_MultipleCodeUnit() + " 𐐀 is U+10400, which encodes to 4 bytes in utf-8 and 2 code units in + " utf-16. + let l:actual = go#lsp#lsp#PositionOf("𐐀 bar", 3) + call assert_equal(6, l:actual) +endfunction + + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/lsp/message.vim b/sources_non_forked/vim-go/autoload/go/lsp/message.vim index 63981854..318a3d8d 100644 --- a/sources_non_forked/vim-go/autoload/go/lsp/message.vim +++ b/sources_non_forked/vim-go/autoload/go/lsp/message.vim @@ -10,17 +10,50 @@ function! go#lsp#message#Initialize(wd) abort \ 'processId': getpid(), \ 'rootUri': go#path#ToURI(a:wd), \ 'capabilities': { - \ 'workspace': {}, + \ 'workspace': { + \ 'workspaceFolders': v:true, + \ 'didChangeConfiguration': { + \ 'dynamicRegistration': v:true, + \ }, + \ 'configuration': v:true, + \ }, \ 'textDocument': { \ 'hover': { \ 'contentFormat': ['plaintext'], \ }, \ } - \ } + \ }, + \ 'workspaceFolders': [s:workspaceFolder(0, a:wd)], \ } \ } endfunction +function! go#lsp#message#Initialized() abort + return { + \ 'notification': 1, + \ 'method': 'initialized', + \ 'params': {}, + \ } +endfunction + +function! go#lsp#message#Shutdown() abort + return { + \ 'notification': 0, + \ 'method': 'shutdown', + \ } +endfunction + +function! go#lsp#message#Exit() abort + return { + \ 'notification': 1, + \ 'method': 'exit', + \ } +endfunction + +function! go#lsp#message#WorkspaceFoldersResult(dirs) abort + return map(copy(a:dirs), function('s:workspaceFolder', [])) +endfunction + function! go#lsp#message#Definition(file, line, col) abort return { \ 'notification': 0, @@ -116,8 +149,49 @@ function! go#lsp#message#Hover(file, line, col) abort \ } endfunction +function! go#lsp#message#ChangeWorkspaceFolders(add, remove) abort + let l:addDirs = map(copy(a:add), function('s:workspaceFolder', [])) + let l:removeDirs = map(copy(a:add), function('s:workspaceFolder', [])) + + return { + \ 'notification': 1, + \ 'method': 'workspace/didChangeWorkspaceFolders', + \ 'params': { + \ 'event': { + \ 'removed': l:removeDirs, + \ 'added': l:addDirs, + \ }, + \ } + \ } + +endfunction + +function! go#lsp#message#ConfigurationResult(items) abort + let l:result = [] + + " results must be in the same order as the items + for l:item in a:items + let l:config = { + \ 'buildFlags': [], + \ 'hoverKind': 'NoDocumentation', + \ } + let l:buildtags = go#config#BuildTags() + if buildtags isnot '' + let l:config.buildFlags = extend(l:config.buildFlags, ['-tags', go#config#BuildTags()]) + endif + + let l:result = add(l:result, l:config) + endfor + + return l:result +endfunction + +function s:workspaceFolder(key, val) abort + return {'uri': go#path#ToURI(a:val), 'name': a:val} +endfunction + function! s:position(line, col) abort - return {'line': a:line - 1, 'character': a:col-1} + return {'line': a:line, 'character': a:col} endfunction " restore Vi compatibility settings diff --git a/sources_non_forked/vim-go/autoload/go/lsp_test.vim b/sources_non_forked/vim-go/autoload/go/lsp_test.vim new file mode 100644 index 00000000..b475bdb4 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/lsp_test.vim @@ -0,0 +1,49 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +scriptencoding utf-8 + +function! Test_GetSimpleTextPosition() + call s:getinfo('lsp text position should align with cursor position after ascii only', 'ascii') +endfunction + +function! Test_GetMultiByteTextPosition() + call s:getinfo('lsp text position should align with cursor position after two place of interest symbols ⌘⌘', 'multi-byte') +endfunction + +function! Test_GetMultipleCodeUnitTextPosition() + call s:getinfo('lsp text position should align with cursor position after Deseret Capital Letter Long I 𐐀', 'multi-code-units') +endfunction + +function! s:getinfo(str, name) + if !go#util#has_job() + return + endif + + try + let g:go_info_mode = 'gopls' + + let l:tmp = gotest#write_file(a:name . '/position/position.go', [ + \ 'package position', + \ '', + \ 'func Example() {', + \ "\tid := " . '"foo"', + \ "\tprintln(" .'"' . a:str . '", id)', + \ '}', + \ ] ) + + let l:expected = 'var id string' + let l:actual = go#lsp#GetInfo() + call assert_equal(l:expected, l:actual) + finally + "call delete(l:tmp, 'rf') + unlet g:go_info_mode + endtry +endfunction + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/mod.vim b/sources_non_forked/vim-go/autoload/go/mod.vim index ab36d0b5..6a7a456d 100644 --- a/sources_non_forked/vim-go/autoload/go/mod.vim +++ b/sources_non_forked/vim-go/autoload/go/mod.vim @@ -8,10 +8,14 @@ function! go#mod#Format() abort " go mod only exists in `v1.11` if empty(s:go_major_version) let tokens = matchlist(go#util#Exec(['go', 'version']), '\d\+.\(\d\+\)\(\.\d\+\)\? ') - let s:go_major_version = str2nr(tokens[1]) + if len(tokens) > 0 + let s:go_major_version = str2nr(tokens[1]) + else + let s:go_major_version = "" + endif endif - if s:go_major_version < "11" + if !empty(s:go_major_version) && s:go_major_version < "11" call go#util#EchoError("Go v1.11 is required to format go.mod file") return endif diff --git a/sources_non_forked/vim-go/autoload/go/package.vim b/sources_non_forked/vim-go/autoload/go/package.vim index 796f62d7..21b2d166 100644 --- a/sources_non_forked/vim-go/autoload/go/package.vim +++ b/sources_non_forked/vim-go/autoload/go/package.vim @@ -82,6 +82,10 @@ function! s:vendordirs() abort if l:err != 0 return [] endif + if empty(l:root) + return [] + endif + let l:root = split(l:root, '\n')[0] . go#util#PathSep() . 'src' let [l:dir, l:err] = go#util#ExecInDir(['go', 'list', '-f', '{{.Dir}}']) @@ -111,57 +115,77 @@ function! s:vendordirs() abort endfunction let s:import_paths = {} -" ImportPath returns the import path of the package for current buffer. +" ImportPath returns the import path of the package for current buffer. It +" returns -1 if the import path cannot be determined. function! go#package#ImportPath() abort - let dir = expand("%:p:h") + let l:dir = expand("%:p:h") if has_key(s:import_paths, dir) - return s:import_paths[dir] + return s:import_paths[l:dir] endif - let [l:out, l:err] = go#util#ExecInDir(['go', 'list']) - if l:err != 0 + let l:importpath = go#package#FromPath(l:dir) + if type(l:importpath) == type(0) return -1 endif - let l:importpath = split(out, '\n')[0] - - " go list returns '_CURRENTDIRECTORY' if the directory is not inside GOPATH. - " Check it and retun an error if that is the case - if l:importpath[0] ==# '_' - return -1 - endif - - let s:import_paths[dir] = l:importpath + let s:import_paths[l:dir] = l:importpath return l:importpath endfunction - " go#package#FromPath returns the import path of arg. -1 is returned when arg " does not specify a package. -2 is returned when arg is a relative path -" outside of GOPATH and not in a module. +" outside of GOPATH, not in a module, and not below the current working +" directory. A relative path is returned when in a null module at or below the +" current working directory.. function! go#package#FromPath(arg) abort let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' let l:dir = getcwd() - let l:path = a:arg + let l:path = fnamemodify(a:arg, ':p') if !isdirectory(l:path) let l:path = fnamemodify(l:path, ':h') endif execute l:cd fnameescape(l:path) - let [l:out, l:err] = go#util#Exec(['go', 'list']) - execute l:cd fnameescape(l:dir) - if l:err != 0 - return -1 - endif + try + if glob("*.go") == "" + " There's no Go code in this directory. We might be in a module directory + " which doesn't have any code at this level. To avoid `go list` making a + " bunch of HTTP requests to fetch dependencies, short-circuit `go list` + " and return -1 immediately. + if !empty(s:module()) + return -1 + endif + endif + let [l:out, l:err] = go#util#Exec(['go', 'list']) + if l:err != 0 + return -1 + endif - let l:importpath = split(l:out, '\n')[0] + let l:importpath = split(l:out, '\n')[0] + finally + execute l:cd fnameescape(l:dir) + endtry - " go list returns '_CURRENTDIRECTORY' if the directory is neither in GOPATH - " nor in a module. Check it and retun an error if that is the case + " go list returns '_CURRENTDIRECTORY' if the directory is in a null module + " (i.e. neither in GOPATH nor in a module). Return a relative import path + " if possible or an error if that is the case. if l:importpath[0] ==# '_' - return -2 + let l:relativeimportpath = fnamemodify(l:importpath[1:], ':.') + if go#util#IsWin() + let l:relativeimportpath = substitute(l:relativeimportpath, '\\', '/', 'g') + endif + + if l:relativeimportpath == l:importpath[1:] + return '.' + endif + + if l:relativeimportpath[0] == '/' + return -2 + endif + + let l:importpath= printf('./%s', l:relativeimportpath) endif return l:importpath diff --git a/sources_non_forked/vim-go/autoload/go/promise.vim b/sources_non_forked/vim-go/autoload/go/promise.vim new file mode 100644 index 00000000..76c2f7c3 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/promise.vim @@ -0,0 +1,50 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +scriptencoding utf-8 + +" New returns a promise. A promise's primary purpose is to make async jobs +" synchronous by awaiting fn. +" +" A promise is a dictionary with two keys: +" 'wrapper': +" A function that wraps fn. It can be used in place of fn. +" 'await': +" A function that waits for wrapper to be called and returns the value +" returned by fn. Returns default if timeout expires. +function! go#promise#New(fn, timeout, default) abort + let l:state = {} + + " explicitly bind to state so that within l:promise's methods, self will + " always refer to state. See :help Partial for more information. + return { + \ 'wrapper': function('s:wrapper', [a:fn], l:state), + \ 'await': function('s:await', [a:timeout, a:default], l:state), + \ } +endfunction + +function! s:wrapper(fn, ...) dict + let self.retval = call(a:fn, a:000) + return self.retval +endfunction + +function! s:await(timeout, default) dict + let l:timer = timer_start(a:timeout, function('s:setretval', [a:default], self)) + while !has_key(self, 'retval') + sleep 50m + endwhile + call timer_stop(l:timer) + + return self.retval +endfunction + +function! s:setretval(val, timer) dict + let self.retval = a:val +endfunction + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/promise_test.vim b/sources_non_forked/vim-go/autoload/go/promise_test.vim new file mode 100644 index 00000000..f4473fe6 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/promise_test.vim @@ -0,0 +1,41 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +func! Test_PromiseNew() abort + let l:sut = go#promise#New(function('s:work', []), 100, -1) + call assert_true(has_key(l:sut, 'wrapper')) + call assert_true(has_key(l:sut, 'await')) +endfunc + +func! Test_PromiseAwait() abort + let l:expected = 1 + let l:default = -1 + let l:sut = go#promise#New(function('s:work', [l:expected]), 100, l:default) + + call timer_start(10, l:sut.wrapper) + + let l:actual = call(l:sut.await, []) + call assert_equal(l:expected, l:actual) +endfunc + +func! Test_PromiseAwait_Timeout() abort + let l:desired = 1 + let l:expected = -1 + let l:sut = go#promise#New(function('s:work', [l:desired]), 10, l:expected) + + call timer_start(100, l:sut.wrapper) + + let l:actual = call(l:sut.await, []) + call assert_equal(l:expected, l:actual) +endfunc + +func! s:work(val, timer) + return a:val +endfunc + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/statusline.vim b/sources_non_forked/vim-go/autoload/go/statusline.vim index f0ec5cd0..9779d763 100644 --- a/sources_non_forked/vim-go/autoload/go/statusline.vim +++ b/sources_non_forked/vim-go/autoload/go/statusline.vim @@ -27,9 +27,8 @@ let s:last_status = "" " if not it returns an empty string. This function should be plugged directly " into the statusline. function! go#statusline#Show() abort - " lazy initialiation of the cleaner + " lazy initialization of the cleaner if !s:timer_id - " clean every 60 seconds all statuses let interval = go#config#StatuslineDuration() let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1}) endif @@ -57,9 +56,9 @@ function! go#statusline#Show() abort " only update highlight if status has changed. if status_text != s:last_status - if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass" + if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass" || status.state =~ 'initialized' hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 guibg=#5fd700 guifg=#005f00 - elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling" + elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling" || status.state =~ 'initializing' hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 guibg=#ff8700 guifg=#870000 elseif status.state =~ "failed" hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 guibg=#ff0000 guifg=#5f0000 @@ -83,10 +82,11 @@ function! go#statusline#Update(status_dir, status) abort " before we stop the timer, check if we have any previous jobs to be cleaned " up. Otherwise every job will reset the timer when this function is called " and thus old jobs will never be cleaned - call go#statusline#Clear(0) + call s:clear() " also reset the timer, so the user has time to see it in the statusline. - " Setting the timer_id to 0 will trigger a new cleaner routine. + " Setting the timer_id to 0 will cause a new timer to be created the next + " time the go#statusline#Show() is called. call timer_stop(s:timer_id) let s:timer_id = 0 endfunction @@ -94,6 +94,10 @@ endfunction " Clear clears all currently stored statusline data. The timer_id argument is " just a placeholder so we can pass it to a timer_start() function if needed. function! go#statusline#Clear(timer_id) abort + call s:clear() +endfunction + +function! s:clear() for [status_dir, status] in items(s:statuses) let elapsed_time = reltimestr(reltime(status.created_at)) " strip whitespace diff --git a/sources_non_forked/vim-go/autoload/go/template.vim b/sources_non_forked/vim-go/autoload/go/template.vim index 3f5e5381..404047ae 100644 --- a/sources_non_forked/vim-go/autoload/go/template.vim +++ b/sources_non_forked/vim-go/autoload/go/template.vim @@ -24,8 +24,13 @@ function! go#template#create() abort else let l:template_file = go#config#TemplateFile() endif - let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file) - silent exe 'keepalt 0r ' . fnameescape(l:template_path) + " If template_file is an absolute path, use it as-is. This is to support + " overrides pointing to templates outside of the vim-go plugin dir + if fnamemodify(l:template_file, ':p') != l:template_file + let l:template_file = go#util#Join(l:root_dir, "templates", l:template_file) + endif + + silent exe 'keepalt 0r ' . fnameescape(l:template_file) endif else let l:content = printf("package %s", l:package_name) diff --git a/sources_non_forked/vim-go/autoload/go/term.vim b/sources_non_forked/vim-go/autoload/go/term.vim index d7a463eb..9352be5d 100644 --- a/sources_non_forked/vim-go/autoload/go/term.vim +++ b/sources_non_forked/vim-go/autoload/go/term.vim @@ -96,6 +96,13 @@ function! s:on_stdout(job_id, data, event) dict abort endfunction function! s:on_exit(job_id, exit_status, event) dict abort + " change to directory where test were run. if we do not do this + " the quickfix items will have the incorrect paths. + " see: https://github.com/fatih/vim-go/issues/2400 + let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let l:dir = getcwd() + execute l:cd . fnameescape(expand("%:p:h")) + let l:winid = win_getid(winnr()) call win_gotoid(self.winid) let l:listtype = go#list#Type("_term") @@ -130,8 +137,10 @@ function! s:on_exit(job_id, exit_status, event) dict abort endif " close terminal; we don't need it anymore - call win_gotoid(self.termwinid) - close! + if go#config#TermCloseOnExit() + call win_gotoid(self.termwinid) + close! + endif if self.bang call win_gotoid(l:winid) @@ -140,6 +149,21 @@ function! s:on_exit(job_id, exit_status, event) dict abort call win_gotoid(self.winid) call go#list#JumpToFirst(l:listtype) + + " change back to original working directory + execute l:cd l:dir +endfunction + +function! go#term#ToggleCloseOnExit() abort + if go#config#TermCloseOnExit() + call go#config#SetTermCloseOnExit(0) + call go#util#EchoProgress("term close on exit disabled") + return + endif + + call go#config#SetTermCloseOnExit(1) + call go#util#EchoProgress("term close on exit enabled") + return endfunction " restore Vi compatibility settings diff --git a/sources_non_forked/vim-go/autoload/go/term_test.vim b/sources_non_forked/vim-go/autoload/go/term_test.vim index 40f0a52a..0d5d1d94 100644 --- a/sources_non_forked/vim-go/autoload/go/term_test.vim +++ b/sources_non_forked/vim-go/autoload/go/term_test.vim @@ -22,6 +22,7 @@ func! Test_GoTermNewMode() call assert_equal(actual, l:expected) finally + sleep 50m call delete(l:tmp, 'rf') endtry endfunc @@ -46,6 +47,7 @@ func! Test_GoTermNewMode_SplitRight() call assert_equal(actual, l:expected) finally + sleep 50m call delete(l:tmp, 'rf') set nosplitright endtry diff --git a/sources_non_forked/vim-go/autoload/go/test-fixtures/test/src/example/example_test.go b/sources_non_forked/vim-go/autoload/go/test-fixtures/test/src/example/example_test.go new file mode 100644 index 00000000..bdcc2e10 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/test-fixtures/test/src/example/example_test.go @@ -0,0 +1,10 @@ +package main + +import ( + "fmt" +) + +func ExampleHelloWorld() { + fmt.Println("Hello, World") + // Output: What's shakin +} diff --git a/sources_non_forked/vim-go/autoload/go/test.vim b/sources_non_forked/vim-go/autoload/go/test.vim index f33d7d94..ff15c8da 100644 --- a/sources_non_forked/vim-go/autoload/go/test.vim +++ b/sources_non_forked/vim-go/autoload/go/test.vim @@ -32,6 +32,7 @@ function! go#test#Test(bang, compile, ...) abort if go#config#TermEnabled() call go#term#new(a:bang, ["go"] + args, s:errorformat()) + return endif if go#util#has_job() @@ -166,9 +167,17 @@ function! s:errorformat() abort let format .= ",%-G" . indent . "%#--- PASS: %.%#" " Match failure lines. - " + + " Example failures start with '--- FAIL: ', followed by the example name + " followed by a space , followed by the duration of the example in + " parantheses. They aren't nested, though, so don't check for indentation. + " The errors from them also aren't indented and don't report file location + " or line numbers, so those won't show up. This will at least let the user + " know which example failed, though. + let format .= ',%G--- FAIL: %\\%(Example%\\)%\\@=%m (%.%#)' + " Test failures start with '--- FAIL: ', followed by the test name followed - " by a space the duration of the test in parentheses + " by a space, followed by the duration of the test in parentheses. " " e.g.: " '--- FAIL: TestSomething (0.00s)' diff --git a/sources_non_forked/vim-go/autoload/go/test_test.vim b/sources_non_forked/vim-go/autoload/go/test_test.vim index 28d7993c..322abed6 100644 --- a/sources_non_forked/vim-go/autoload/go/test_test.vim +++ b/sources_non_forked/vim-go/autoload/go/test_test.vim @@ -66,9 +66,9 @@ endfunc func! Test_GoTestShowName() abort let expected = [ \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'}, - \ {'lnum': 6, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'}, + \ {'lnum': 6, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'}, \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'}, - \ {'lnum': 9, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'}, + \ {'lnum': 9, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'}, \ ] let g:go_test_show_name=1 @@ -78,20 +78,27 @@ endfunc func! Test_GoTestVet() abort let expected = [ - \ {'lnum': 6, 'bufnr': 10, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'}, + \ {'lnum': 6, 'bufnr': 11, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'}, \ ] call s:test('veterror/veterror.go', expected) endfunc func! Test_GoTestTestCompilerError() abort let expected = [ - \ {'lnum': 10, 'bufnr': 8, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'}, + \ {'lnum': 10, 'bufnr': 9, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'}, \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'} \ ] call s:test('testcompilerror/testcompilerror_test.go', expected) endfunc +func! Test_GoTestExample() abort + let expected = [ + \ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'ExampleHelloWorld'} + \ ] + call s:test('example/example_test.go', expected) +endfunc + func! s:test(file, expected, ...) abort let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test' silent exe 'e ' . $GOPATH . '/src/' . a:file diff --git a/sources_non_forked/vim-go/autoload/go/tool.vim b/sources_non_forked/vim-go/autoload/go/tool.vim index fdeaaf12..41380abd 100644 --- a/sources_non_forked/vim-go/autoload/go/tool.vim +++ b/sources_non_forked/vim-go/autoload/go/tool.vim @@ -115,7 +115,15 @@ endfunction function! go#tool#DescribeBalloon() let l:fname = fnamemodify(bufname(v:beval_bufnr), ':p') - call go#lsp#Hover(l:fname, v:beval_lnum, v:beval_col, funcref('s:balloon', [])) + + let l:winid = win_getid() + + call win_gotoid(bufwinid(v:beval_bufnr)) + + let [l:line, l:col] = go#lsp#lsp#Position(v:beval_lnum, v:beval_col) + call go#lsp#Hover(l:fname, l:line, l:col, funcref('s:balloon', [])) + + call win_gotoid(l:winid) return '' endfunction diff --git a/sources_non_forked/vim-go/autoload/go/util.vim b/sources_non_forked/vim-go/autoload/go/util.vim index 965f1e8b..15324220 100644 --- a/sources_non_forked/vim-go/autoload/go/util.vim +++ b/sources_non_forked/vim-go/autoload/go/util.vim @@ -36,15 +36,9 @@ function! go#util#Join(...) abort endfunction " IsWin returns 1 if current OS is Windows or 0 otherwise +" Note that has('win32') is always 1 when has('win64') is 1, so has('win32') is enough. function! go#util#IsWin() abort - let win = ['win16', 'win32', 'win64', 'win95'] - for w in win - if (has(w)) - return 1 - endif - endfor - - return 0 + return has('win32') endfunction " IsMac returns 1 if current OS is macOS or 0 otherwise. @@ -468,7 +462,7 @@ function! go#util#tempdir(prefix) abort endif " Not great randomness, but "good enough" for our purpose here. - let l:rnd = sha256(printf('%s%s', localtime(), fnamemodify(bufname(''), ":p"))) + let l:rnd = sha256(printf('%s%s', reltimestr(reltime()), fnamemodify(bufname(''), ":p"))) let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd) call mkdir(l:tmp, 'p', 0700) return l:tmp @@ -557,7 +551,9 @@ function! go#util#SetEnv(name, value) abort let l:remove = 1 endif - call execute('let $' . a:name . ' = "' . a:value . '"') + " wrap the value in single quotes so that it will work on windows when there + " are backslashes present in the value (e.g. $PATH). + call execute('let $' . a:name . " = '" . a:value . "'") if l:remove function! s:remove(name) abort diff --git a/sources_non_forked/vim-go/autoload/gotest.vim b/sources_non_forked/vim-go/autoload/gotest.vim index e010d52b..7fae8152 100644 --- a/sources_non_forked/vim-go/autoload/gotest.vim +++ b/sources_non_forked/vim-go/autoload/gotest.vim @@ -12,6 +12,9 @@ set cpo&vim " The full path to the created directory is returned, it is the caller's " responsibility to clean that up! fun! gotest#write_file(path, contents) abort + if go#util#has_job() + call go#lsp#CleanWorkspaces() + endif let l:dir = go#util#tempdir("vim-go-test/testrun/") let $GOPATH .= ':' . l:dir let l:full_path = l:dir . '/src/' . a:path @@ -19,15 +22,23 @@ fun! gotest#write_file(path, contents) abort call mkdir(fnamemodify(l:full_path, ':h'), 'p') call writefile(a:contents, l:full_path) exe 'cd ' . l:dir . '/src' + + if go#util#has_job() + call go#lsp#AddWorkspaceDirectory(fnamemodify(l:full_path, ':p:h')) + endif + silent exe 'e! ' . a:path " Set cursor. let l:lnum = 1 for l:line in a:contents - let l:m = match(l:line, "\x1f") + let l:m = stridx(l:line, "\x1f") if l:m > -1 - call setpos('.', [0, l:lnum, l:m, 0]) + let l:byte = line2byte(l:lnum) + l:m + exe 'goto '. l:byte call setline('.', substitute(getline('.'), "\x1f", '', '')) + silent noautocmd w! + break endif @@ -42,6 +53,9 @@ endfun " The file will be copied to a new GOPATH-compliant temporary directory and " loaded as the current buffer. fun! gotest#load_fixture(path) abort + if go#util#has_job() + call go#lsp#CleanWorkspaces() + endif let l:dir = go#util#tempdir("vim-go-test/testrun/") let $GOPATH .= ':' . l:dir let l:full_path = l:dir . '/src/' . a:path @@ -51,6 +65,9 @@ fun! gotest#load_fixture(path) abort silent exe 'noautocmd e ' . a:path silent exe printf('read %s/test-fixtures/%s', g:vim_go_root, a:path) silent noautocmd w! + if go#util#has_job() + call go#lsp#AddWorkspaceDirectory(fnamemodify(l:full_path, ':p:h')) + endif return l:dir endfun diff --git a/sources_non_forked/vim-go/doc/vim-go.txt b/sources_non_forked/vim-go/doc/vim-go.txt index 8715995e..4100b176 100644 --- a/sources_non_forked/vim-go/doc/vim-go.txt +++ b/sources_non_forked/vim-go/doc/vim-go.txt @@ -94,26 +94,26 @@ For Pathogen or Vim |packages|, just clone the repo. For other plugin managers you may also need to add the lines to your vimrc to execute the plugin manager's install command. -* Vim 8 |packages| -> +* Vim 8 |packages| > + git clone https://github.com/fatih/vim-go.git \ ~/.vim/pack/plugins/start/vim-go - +< * https://github.com/tpope/vim-pathogen > git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go < * https://github.com/junegunn/vim-plug > - Plug 'fatih/vim-go' - + Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' } +< * https://github.com/Shougo/neobundle.vim > NeoBundle 'fatih/vim-go' < * https://github.com/gmarik/vundle > - Plugin 'fatih/vim-go', { 'do': ':GoUpdateBinaries' } + Plugin 'fatih/vim-go' < * Manual (not recommended) > @@ -376,8 +376,8 @@ CTRL-t :GoInfo Show type information about the identifier under the cursor. For example putting it above a function call is going to show the full function - signature. By default it uses `gocode` to get the type informations. To - change the underlying tool from `gocode` to another tool, see + signature. By default it uses `gopls` to get the type informations. To + change the underlying tool from `gopls` to another tool, see |'g:go_info_mode'|. @@ -536,7 +536,7 @@ CTRL-t *:GoGuruScope* -:GoGuruScope [pattern] [pattern2] ... [patternN] +:GoGuruScope [pattern] ... Changes the custom |'g:go_guru_scope'| setting and overrides it with the given package patterns. The custom scope is cleared (unset) if `""` is @@ -906,6 +906,16 @@ CTRL-t tries to preserve cursor position and avoids replacing the buffer with stderr output. + *:GoAddWorkspace* +:GoAddWorkspace [dir] ... + + Add directories to the `gopls` workspace. + + *:GoLSPDebugBrowser* +:GoLSPDebugBrowser + + Open a browser to see gopls debugging information. + ============================================================================== MAPPINGS *go-mappings* @@ -1204,6 +1214,14 @@ balloonexpr`. ============================================================================== SETTINGS *go-settings* + *'g:go_version_warning'* + +Enable warning when using an unsupported version of Vim. By default it is +enabled. +> + let g:go_version_warning = 1 +< + *'g:go_code_completion_enabled'* Enable code completion with |'omnifunc'|. By default it is enabled. @@ -1228,9 +1246,9 @@ set to 10 seconds . > < *'g:go_play_browser_command'* -Browser to use for |:GoPlay| or |:GoDocBrowser|. The url must be added with -`%URL%`, and it's advisable to include `&` to make sure the shell returns. For -example: +Browser to use for |:GoPlay|, |:GoDocBrowser|, and |:GoLSPDebugBrowser|. The +url must be added with `%URL%`, and it's advisable to include `&` to make sure +the shell returns. For example: > let g:go_play_browser_command = 'firefox-developer %URL% &' < @@ -1259,11 +1277,11 @@ updated. By default it's disabled. The delay can be configured with the *'g:go_info_mode'* Use this option to define the command to be used for |:GoInfo|. By default -`gocode` is being used as it's the fastest option. But one might also use -`gopls` or `guru` as they cover more cases and are more accurate. Current -valid options are: `[gocode, guru, gopls]` > - - let g:go_info_mode = 'gocode' +`gopls` is used, because it is the fastest and is known to be highly accurate. +One might also use `guru` for its accuracy or `gocode` for its performance. +Valid options are `gocode`, `gopls`, and `guru`. +> + let g:go_info_mode = 'gopls' < *'g:go_auto_sameids'* @@ -1375,10 +1393,11 @@ a private internal service. Default is 'https://godoc.org'. *'g:go_def_mode'* 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, gopls]` > - - let g:go_def_mode = 'guru' +`gopls` is used, because it is the fastest. One might also use `guru` for its +accuracy or `godef` for its performance. Valid options are `godef`, `gopls`, +and `guru`. +> + let g:go_def_mode = 'gopls' < *'g:go_def_mapping_enabled'* @@ -1621,6 +1640,13 @@ according to |'g:go_term_mode'|, otherwise it will run them in the background just like `:GoBuild`. By default it is disabled. > let g:go_term_enabled = 0 +< + *'g:go_term_close_on_exit'* + +This option is Neovim only. If set to 1 it closes the terminal after the +command run in it exits. By default it is enabled. +> + let g:go_term_close_on_exit = 1 < *'g:go_alternate_mode'* @@ -1676,7 +1702,8 @@ Specifies whether `gocode` should use a different socket type. By default When a new Go file is created, vim-go automatically fills the buffer content with a Go code template. By default, the templates under the `templates` folder are used. This can be changed with the |'g:go_template_file'| and -|'g:go_template_test_file'| settings. +|'g:go_template_test_file'| settings to either use a different file in the +same `templates` folder, or to use a file stored elsewhere. If the new file is created in an already prepopulated package (with other Go files), in this case a Go code template with only the Go package declaration @@ -1691,17 +1718,23 @@ By default it is enabled. < *'g:go_template_file'* -Specifies the file under the `templates` folder that is used if a new Go file -is created. Checkout |'g:go_template_autocreate'| for more info. By default -the `hello_world.go` file is used. +Specifies either the file under the `templates` folder that is used if a new +Go file is created. Checkout |'g:go_template_autocreate'| for more info. By +default the `hello_world.go` file is used. + +This variable can be set to an absolute path, so the template files don't have +to be stored inside the vim-go directory structure. Useful when you want to +use different templates for different projects. > let g:go_template_file = "hello_world.go" < *'g:go_template_test_file'* -Specifies the file under the `templates` folder that is used if a new Go test -file is created. Checkout |'g:go_template_autocreate'| for more info. By -default the `hello_world_test.go` file is used. +Like with |'g:go_template_file'|, this specifies the file to use for test +tempaltes. The template file should be under the `templates` folder, +alternatively absolute paths can be used, too. Checkout +|'g:go_template_autocreate'| for more info. By default, the +`hello_world_test.go` file is used. > let g:go_template_test_file = "hello_world_test.go" < @@ -1788,7 +1821,10 @@ 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. + lsp Echo communication between vim-go and `gopls`. All + communication is shown in a dedicated window. When + enabled before gopls is started, |:GoLSPDebugBrowser| can + be used to open a browser window to help debug gopls. > let g:go_debug = [] < @@ -2027,8 +2063,7 @@ rest of the commands and mappings become available after starting debug mode. * Make the `:GoDebug*` commands and `(go-debug-*)` mappings available. The directory of the current buffer is used if [pkg] is empty. Any other - arguments will be passed to the program. When [pkg] is relative, it will - be interpreted relative to the directory of the current buffer. + arguments will be passed to the program. Use |:GoDebugStop| to stop `dlv` and exit debugging mode. @@ -2183,6 +2218,22 @@ Highlight the current line and breakpoints in the debugger. ============================================================================== FAQ TROUBLESHOOTING *go-troubleshooting* +How do I troubleshoot problems?~ + +One of the best ways to understand what vim-go is doing and the output from +the tools to which it delegates is to use leverage the features described in +|'g:go_debug'|. + +Completion and other functions that use `gopls` don't work~ + +Vim-go is heavily reliant on `gopls` for completion and other functionality. +Many of the features that use `gopls` (e.g. completion, jumping to +definitions, showing identifier information, et al.) can be configured to +delegate to other tools. e.g. completion via |'omnifunc'|, |'g:go_info_mode'| +and |'g:go_def_mode'| can be set to use other tools for now (though some of +the alternatives to `gopls` are effectively at their end of life and support +for them from within vim-go may be removed soon). + I get "Unknown function: go#config#..." error when I open a Go file.~ This often happens to vim-polyglot users when new config options are added to diff --git a/sources_non_forked/vim-go/ftplugin/go/commands.vim b/sources_non_forked/vim-go/ftplugin/go/commands.vim index 726b944c..716b49da 100644 --- a/sources_non_forked/vim-go/ftplugin/go/commands.vim +++ b/sources_non_forked/vim-go/ftplugin/go/commands.vim @@ -116,4 +116,11 @@ command! -nargs=0 GoReportGitHubIssue call go#issue#New() " -- iferr command! -nargs=0 GoIfErr call go#iferr#Generate() +" -- lsp +command! -nargs=+ -complete=dir GoAddWorkspace call go#lsp#AddWorkspaceDirectory(<f-args>) +command! -nargs=0 GoLSPDebugBrowser call go#lsp#DebugBrowser() + +" -- term +command! GoToggleTermCloseOnExit call go#term#ToggleCloseOnExit() + " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets b/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets index 0a9b7ae4..3acf9cf3 100644 --- a/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets +++ b/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets @@ -151,7 +151,7 @@ if err := ${1:condition}; err != nil { endsnippet # error snippet -snippet errn "Error return " !b +snippet errn "Error return" !b if err != nil { return err } @@ -326,7 +326,7 @@ endsnippet # struct snippet st "type T struct { ... }" type ${1:Type} struct { -${0} + ${0} } endsnippet diff --git a/sources_non_forked/vim-go/plugin/go.vim b/sources_non_forked/vim-go/plugin/go.vim index 7b3832d3..0546f499 100644 --- a/sources_non_forked/vim-go/plugin/go.vim +++ b/sources_non_forked/vim-go/plugin/go.vim @@ -20,19 +20,19 @@ function! s:checkVersion() abort let l:unsupported = 0 if go#config#VersionWarning() != 0 if has('nvim') - let l:unsupported = !has('nvim-0.3.1') + let l:unsupported = !has('nvim-0.3.2') else let l:unsupported = (v:version < 704 || (v:version == 704 && !has('patch2009'))) endif if l:unsupported == 1 echohl Error - echom "vim-go requires Vim 7.4.2009 or Neovim 0.3.1, but you're using an older version." + echom "vim-go requires Vim 7.4.2009 or Neovim 0.3.2, but you're using an older version." echom "Please update your Vim for the best vim-go experience." echom "If you really want to continue you can set this to make the error go away:" echom " let g:go_version_warning = 0" echom "Note that some features may error out or behave incorrectly." - echom "Please do not report bugs unless you're using Vim 7.4.2009 or newer or Neovim 0.3.1." + echom "Please do not report bugs unless you're using Vim 7.4.2009 or newer or Neovim 0.3.2." echohl None " Make sure people see this. @@ -56,7 +56,7 @@ 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'], + \ 'gopls': ['golang.org/x/tools/gopls@latest', {}, {'after': function('go#lsp#Restart', [])}], \ 'gometalinter': ['github.com/alecthomas/gometalinter'], \ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint'], \ 'gomodifytags': ['github.com/fatih/gomodifytags'], @@ -104,9 +104,6 @@ function! s:GoInstallBinaries(updateBinaries, ...) " vim's executable path is looking in PATH so add our go_bin path to it let Restore_path = go#util#SetEnv('PATH', go_bin_path . go#util#PathListSep() . $PATH) - " GO111MODULE must be off to install golanci-lint and gometalinter - let Restore_modules = go#util#SetEnv('GO111MODULE', 'off') - " when shellslash is set on MS-* systems, shellescape puts single quotes " around the output string. cmd on Windows does not handle single quotes " correctly. Unsetting shellslash forces shellescape to use double quotes @@ -117,10 +114,7 @@ function! s:GoInstallBinaries(updateBinaries, ...) set noshellslash endif - let l:dl_cmd = ['go', 'get', '-v', '-d'] - if get(g:, "go_get_update", 1) != 0 - let l:dl_cmd += ['-u'] - endif + let l:get_base_cmd = ['go', 'get', '-v'] " Filter packages from arguments (if any). let l:packages = {} @@ -142,51 +136,93 @@ function! s:GoInstallBinaries(updateBinaries, ...) let l:platform = 'windows' endif - for [binary, pkg] in items(l:packages) - let l:importPath = pkg[0] + let l:oldmore = &more + let &more = 0 - let l:run_cmd = copy(l:dl_cmd) - if len(l:pkg) > 1 && get(l:pkg[1], l:platform, '') isnot '' - let l:run_cmd += get(l:pkg[1], l:platform, '') - endif + for [l:binary, l:pkg] in items(l:packages) + let l:importPath = l:pkg[0] - let bin_setting_name = "go_" . binary . "_bin" + " TODO(bc): how to support this with modules? Do we have to clone and then + " install manually? Probably not. I suspect that we can just use GOPATH + " mode and then do the legacy method. + let bin_setting_name = "go_" . l:binary . "_bin" if exists("g:{bin_setting_name}") let bin = g:{bin_setting_name} else if go#util#IsWin() - let bin = binary . '.exe' + let bin = l:binary . '.exe' else - let bin = binary + let bin = l:binary endif endif if !executable(bin) || a:updateBinaries == 1 if a:updateBinaries == 1 - echo "vim-go: Updating " . binary . ". Reinstalling ". importPath . " to folder " . go_bin_path + echo "vim-go: Updating " . l:binary . ". Reinstalling ". importPath . " to folder " . go_bin_path else - echo "vim-go: ". binary ." not found. Installing ". importPath . " to folder " . go_bin_path + echo "vim-go: ". l:binary ." not found. Installing ". importPath . " to folder " . go_bin_path endif - " first download the binary - let [l:out, l:err] = go#util#Exec(l:run_cmd + [l:importPath]) - if l:err - echom "Error downloading " . l:importPath . ": " . l:out + if l:importPath =~ "@" + let Restore_modules = go#util#SetEnv('GO111MODULE', 'on') + let l:tmpdir = go#util#tempdir('vim-go') + let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let l:dir = getcwd() + try + execute l:cd . fnameescape(l:tmpdir) + let l:get_cmd = copy(l:get_base_cmd) + + " first download the binary + let [l:out, l:err] = go#util#Exec(l:get_cmd + [l:importPath]) + if l:err + echom "Error installing " . l:importPath . ": " . l:out + endif + + call call(Restore_modules, []) + finally + execute l:cd . fnameescape(l:dir) + endtry + call call(Restore_modules, []) + else + let l:get_cmd = copy(l:get_base_cmd) + let l:get_cmd += ['-d'] + if get(g:, "go_get_update", 1) != 0 + let l:get_cmd += ['-u'] + endif + + " GO111MODULE must be off to install gometalinter. + let Restore_modules = go#util#SetEnv('GO111MODULE', 'off') + + " first download the binary + let [l:out, l:err] = go#util#Exec(l:get_cmd + [l:importPath]) + if l:err + echom "Error downloading " . l:importPath . ": " . l:out + endif + + " and then build and install it + let l:build_cmd = ['go', 'build', '-o', go_bin_path . go#util#PathSep() . bin, l:importPath] + if len(l:pkg) > 1 && get(l:pkg[1], l:platform, '') isnot '' + let l:build_cmd += get(l:pkg[1], l:platform, '') + endif + + let [l:out, l:err] = go#util#Exec(l:build_cmd) + if l:err + echom "Error installing " . l:importPath . ": " . l:out + endif + + + call call(Restore_modules, []) endif - " and then build and install it - let l:build_cmd = ['go', 'build', '-o', go_bin_path . go#util#PathSep() . bin, l:importPath] - let [l:out, l:err] = go#util#Exec(l:build_cmd) - if l:err - echom "Error installing " . l:importPath . ": " . l:out + if len(l:pkg) > 2 + call call(get(l:pkg[2], 'after', function('s:noop', [])), []) endif endif endfor " restore back! call call(Restore_path, []) - call call(Restore_modules, []) if resetshellslash set shellslash @@ -197,6 +233,8 @@ function! s:GoInstallBinaries(updateBinaries, ...) else call go#util#EchoInfo('installing finished!') endif + + let &more = l:oldmore endfunction " CheckBinaries checks if the necessary binaries to install the Go tool diff --git a/sources_non_forked/vim-go/scripts/install-vim b/sources_non_forked/vim-go/scripts/install-vim index 709fccaa..f383d371 100644 --- a/sources_non_forked/vim-go/scripts/install-vim +++ b/sources_non_forked/vim-go/scripts/install-vim @@ -30,7 +30,7 @@ case "$vim" in "nvim") # Use latest stable version. - tag="v0.3.1" + tag="v0.3.2" giturl="https://github.com/neovim/neovim" ;; @@ -62,7 +62,7 @@ cd "$srcdir" if [ "$1" = "nvim" ]; then # TODO: Use macOS binaries on macOS - curl -Ls https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz | + curl -Ls https://github.com/neovim/neovim/releases/download/$tag/nvim-linux64.tar.gz | tar xzf - -C /tmp/vim-go-test/ mv /tmp/vim-go-test/nvim-linux64 /tmp/vim-go-test/nvim-install mkdir -p "$installdir/share/nvim/runtime/pack/vim-go/start" diff --git a/sources_non_forked/vim-go/scripts/runtest.vim b/sources_non_forked/vim-go/scripts/runtest.vim index 9d20b76a..168de9ca 100644 --- a/sources_non_forked/vim-go/scripts/runtest.vim +++ b/sources_non_forked/vim-go/scripts/runtest.vim @@ -64,6 +64,12 @@ for s:test in sort(s:tests) endif try exe 'call ' . s:test + " sleep to give events a chance to be processed. This is especially + " important for the LSP code to have a chance to run before Vim exits, in + " order to avoid errors trying to write to the gopls channels since Vim + " would otherwise stop gopls before the event handlers were run and result + " in 'stream closed' errors when the events were run _after_ gopls exited. + sleep 50m catch let v:errors += [v:exception] endtry @@ -76,17 +82,17 @@ for s:test in sort(s:tests) let s:elapsed_time = substitute(reltimestr(reltime(s:started)), '^\s*\(.\{-}\)\s*$', '\1', '') let s:done += 1 - call s:logmessages() - if len(v:errors) > 0 let s:fail += 1 call add(s:logs, printf("--- FAIL %s (%ss)", s:test[:-3], s:elapsed_time)) + call s:logmessages() call extend(s:logs, map(v:errors, '" ". v:val')) " Reset so we can capture failures of the next test. let v:errors = [] else if g:test_verbose is 1 + call s:logmessages() call add(s:logs, printf("--- PASS %s (%ss)", s:test[:-3], s:elapsed_time)) endif endif diff --git a/sources_non_forked/vim-markdown/Makefile b/sources_non_forked/vim-markdown/Makefile index c9d11550..0b287e26 100644 --- a/sources_non_forked/vim-markdown/Makefile +++ b/sources_non_forked/vim-markdown/Makefile @@ -66,6 +66,12 @@ doc: build/html2vimdoc build/vim-tools -e "s/^- '([^']{1,2})':.*/ \*vim-markdown-\1\*/" -e "# short command" \ -e ":a" -e "s/^(.{1,78})$$/ \1/" -e "ta" -e "# align right" \ -e "G" -e "# append the matched line after the command reference" \ + -e "}" \ + -e "/^- 'g:vim_markdown_[[:alnum:]_]*'$$/ {" \ + -e "h" -e "# save the matched line to the hold space" \ + -e "s/^- '([^']*)'$$/ \*\1\*/" -e "# make global variable reference" \ + -e ":g" -e "s/^(.{1,78})$$/ \1/" -e "tg" -e "# align right" \ + -e "G" -e "# append the matched line after the global variable reference" \ -e "}" > doc/vim-markdown.txt && rm -f doc/tmp.md .PHONY: doc diff --git a/sources_non_forked/vim-markdown/README.md b/sources_non_forked/vim-markdown/README.md index b67917a7..fd3be687 100644 --- a/sources_non_forked/vim-markdown/README.md +++ b/sources_non_forked/vim-markdown/README.md @@ -88,154 +88,152 @@ Try `:help concealcursor` and `:help conceallevel` for details. ### Disable Folding -Add the following line to your `.vimrc` to disable the folding configuration: +- `g:vim_markdown_folding_disabled` -```vim -let g:vim_markdown_folding_disabled = 1 -``` + Add the following line to your `.vimrc` to disable the folding configuration: -This option only controls Vim Markdown specific folding configuration. + let g:vim_markdown_folding_disabled = 1 -To enable/disable folding use Vim's standard folding configuration. + This option only controls Vim Markdown specific folding configuration. -```vim -set [no]foldenable -``` + To enable/disable folding use Vim's standard folding configuration. + + set [no]foldenable ### Change fold style -To fold in a style like [python-mode](https://github.com/klen/python-mode), add the following to your `.vimrc`: +- `g:vim_markdown_folding_style_pythonic` -```vim -let g:vim_markdown_folding_style_pythonic = 1 -``` + To fold in a style like [python-mode](https://github.com/klen/python-mode), add the following to your `.vimrc`: -Level 1 heading which is served as a document title is not folded. -`g:vim_markdown_folding_level` setting is not active with this fold style. + let g:vim_markdown_folding_style_pythonic = 1 -To prevent foldtext from being set add the following to your `.vimrc`: + `g:vim_markdown_folding_level` setting (default 1) is set to `foldlevel`. + Thus level 1 heading which is served as a document title is expanded by default. -```vim -let g:vim_markdown_override_foldtext = 0 -``` +- `g:vim_markdown_override_foldtext` + + To prevent foldtext from being set add the following to your `.vimrc`: + + let g:vim_markdown_override_foldtext = 0 ### Set header folding level -Folding level is a number between 1 and 6. By default, if not specified, it is set to 1. +- `g:vim_markdown_folding_level` -```vim -let g:vim_markdown_folding_level = 6 -``` + Folding level is a number between 1 and 6. By default, if not specified, it is set to 1. -Tip: it can be changed on the fly with: + let g:vim_markdown_folding_level = 6 -```vim -:let g:vim_markdown_folding_level = 1 -:edit -``` + Tip: it can be changed on the fly with: + + :let g:vim_markdown_folding_level = 1 + :edit ### Disable Default Key Mappings -Add the following line to your `.vimrc` to disable default key mappings: +- `g:vim_markdown_no_default_key_mappings` -```vim -let g:vim_markdown_no_default_key_mappings = 1 -``` + Add the following line to your `.vimrc` to disable default key mappings: -You can also map them by yourself with `<Plug>` mappings. + let g:vim_markdown_no_default_key_mappings = 1 + + You can also map them by yourself with `<Plug>` mappings. ### Enable TOC window auto-fit -Allow for the TOC window to auto-fit when it's possible for it to shrink. -It never increases its default size (half screen), it only shrinks. +- `g:vim_markdown_toc_autofit` -```vim -let g:vim_markdown_toc_autofit = 1 -``` + Allow for the TOC window to auto-fit when it's possible for it to shrink. + It never increases its default size (half screen), it only shrinks. + + let g:vim_markdown_toc_autofit = 1 ### Text emphasis restriction to single-lines -By default text emphasis works across multiple lines until a closing token is found. However, it's possible to restrict text emphasis to a single line (i.e., for it to be applied a closing token must be found on the same line). To do so: +- `g:vim_markdown_emphasis_multiline` -```vim -let g:vim_markdown_emphasis_multiline = 0 -``` + By default text emphasis works across multiple lines until a closing token is found. However, it's possible to restrict text emphasis to a single line (i.e., for it to be applied a closing token must be found on the same line). To do so: + + let g:vim_markdown_emphasis_multiline = 0 ### Syntax Concealing -Concealing is set for some syntax. +- `g:vim_markdown_conceal` -For example, conceal `[link text](link url)` as just `link text`. -Also, `_italic_` and `*italic*` will conceal to just _italic_. -Similarly `__bold__`, `**bold**`, `___italic bold___`, and `***italic bold***` -will conceal to just __bold__, **bold**, ___italic bold___, and ***italic bold*** respectively. + Concealing is set for some syntax. -To enable conceal use Vim's standard conceal configuration. + For example, conceal `[link text](link url)` as just `link text`. + Also, `_italic_` and `*italic*` will conceal to just _italic_. + Similarly `__bold__`, `**bold**`, `___italic bold___`, and `***italic bold***` + will conceal to just __bold__, **bold**, ___italic bold___, and ***italic bold*** respectively. -```vim -set conceallevel=2 -``` + To enable conceal use Vim's standard conceal configuration. -To disable conceal regardless of `conceallevel` setting, add the following to your `.vimrc`: + set conceallevel=2 -```vim -let g:vim_markdown_conceal = 0 -``` + To disable conceal regardless of `conceallevel` setting, add the following to your `.vimrc`: -To disable math conceal with LaTeX math syntax enabled, add the following to your `.vimrc`: + let g:vim_markdown_conceal = 0 -```vim -let g:tex_conceal = "" -let g:vim_markdown_math = 1 -``` + To disable math conceal with LaTeX math syntax enabled, add the following to your `.vimrc`: + + let g:tex_conceal = "" + let g:vim_markdown_math = 1 + +- `g:vim_markdown_conceal_code_blocks` + + Disabling conceal for code fences requires an additional setting: + + let g:vim_markdown_conceal_code_blocks = 0 ### Fenced code block languages -You can use filetype name as fenced code block languages for syntax highlighting. -If you want to use different name from filetype, you can add it in your `.vimrc` like so: +- `g:vim_markdown_fenced_languages` -```vim -let g:vim_markdown_fenced_languages = ['csharp=cs'] -``` + You can use filetype name as fenced code block languages for syntax highlighting. + If you want to use different name from filetype, you can add it in your `.vimrc` like so: -This will cause the following to be highlighted using the `cs` filetype syntax. + let g:vim_markdown_fenced_languages = ['csharp=cs'] - ```csharp - ... - ``` + This will cause the following to be highlighted using the `cs` filetype syntax. -Default is `['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']`. + ```csharp + ... + ``` + + Default is `['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']`. ### Follow named anchors -This feature allows the `ge` command to follow named anchors in links of the form -`file#anchor` or just `#anchor`, where file may omit the `.md` extension as -usual. Two variables control its operation: +- `g:vim_markdown_follow_anchor` -```vim -let g:vim_markdown_follow_anchor = 1 -``` + This feature allows the `ge` command to follow named anchors in links of the form + `file#anchor` or just `#anchor`, where file may omit the `.md` extension as + usual. Two variables control its operation: -This tells vim-markdown whether to attempt to follow a named anchor in a link or -not. When it is 1, and only if a link can be split in two parts by the pattern -'#', then the first part is interpreted as the file and the second one as the -named anchor. This also includes urls of the form `#anchor`, for which the first -part is considered empty, meaning that the target file is the current one. After -the file is opened, the anchor will be searched. + let g:vim_markdown_follow_anchor = 1 -Default is `0`. + This tells vim-markdown whether to attempt to follow a named anchor in a link or + not. When it is 1, and only if a link can be split in two parts by the pattern + '#', then the first part is interpreted as the file and the second one as the + named anchor. This also includes urls of the form `#anchor`, for which the first + part is considered empty, meaning that the target file is the current one. After + the file is opened, the anchor will be searched. -```vim -let g:vim_markdown_anchorexpr = "'<<'.v:anchor.'>>'" -``` + Default is `0`. -This expression will be evaluated substituting `v:anchor` with a quoted string -that contains the anchor to visit. The result of the evaluation will become the -real anchor to search in the target file. This is useful in order to convert -anchors of the form, say, `my-section-title` to searches of the form `My Section -Title` or `<<my-section-title>>`. +- `g:vim_markdown_anchorexpr` -Default is `''`. + let g:vim_markdown_anchorexpr = "'<<'.v:anchor.'>>'" + + This expression will be evaluated substituting `v:anchor` with a quoted string + that contains the anchor to visit. The result of the evaluation will become the + real anchor to search in the target file. This is useful in order to convert + anchors of the form, say, `my-section-title` to searches of the form `My Section + Title` or `<<my-section-title>>`. + + Default is `''`. ### Syntax extensions @@ -243,119 +241,114 @@ The following options control which syntax extensions will be turned on. They ar #### LaTeX math -Used as `$x^2$`, `$$x^2$$`, escapable as `\$x\$` and `\$\$x\$\$`. +- `g:vim_markdown_math` -```vim -let g:vim_markdown_math = 1 -``` + Used as `$x^2$`, `$$x^2$$`, escapable as `\$x\$` and `\$\$x\$\$`. + + let g:vim_markdown_math = 1 #### YAML Front Matter -Highlight YAML front matter as used by Jekyll or [Hugo](https://gohugo.io/content/front-matter/). +- `g:vim_markdown_frontmatter` -```vim -let g:vim_markdown_frontmatter = 1 -``` + Highlight YAML front matter as used by Jekyll or [Hugo](https://gohugo.io/content/front-matter/). + + let g:vim_markdown_frontmatter = 1 #### TOML Front Matter -Highlight TOML front matter as used by [Hugo](https://gohugo.io/content/front-matter/). +- `g:vim_markdown_toml_frontmatter` -TOML syntax highlight requires [vim-toml](https://github.com/cespare/vim-toml). + Highlight TOML front matter as used by [Hugo](https://gohugo.io/content/front-matter/). -```vim -let g:vim_markdown_toml_frontmatter = 1 -``` + TOML syntax highlight requires [vim-toml](https://github.com/cespare/vim-toml). + + let g:vim_markdown_toml_frontmatter = 1 #### JSON Front Matter -Highlight JSON front matter as used by [Hugo](https://gohugo.io/content/front-matter/). +- `g:vim_markdown_json_frontmatter` -JSON syntax highlight requires [vim-json](https://github.com/elzr/vim-json). + Highlight JSON front matter as used by [Hugo](https://gohugo.io/content/front-matter/). -```vim -let g:vim_markdown_json_frontmatter = 1 -``` + JSON syntax highlight requires [vim-json](https://github.com/elzr/vim-json). + + let g:vim_markdown_json_frontmatter = 1 #### Strikethrough -Strikethrough uses two tildes. `~~Scratch this.~~` +- `g:vim_markdown_strikethrough` -```vim -let g:vim_markdown_strikethrough = 1 -``` + Strikethrough uses two tildes. `~~Scratch this.~~` + + let g:vim_markdown_strikethrough = 1 ### Adjust new list item indent -You can adjust a new list indent. For example, you insert a single line like below: +- `g:vim_markdown_new_list_item_indent` -``` -* item1 -``` + You can adjust a new list indent. For example, you insert a single line like below: -Then if you type `o` to insert new line in vim and type `* item2`, the result will be: + * item1 -``` -* item1 - * item2 -``` + Then if you type `o` to insert new line in vim and type `* item2`, the result will be: -vim-markdown automatically insert the indent. By default, the number of spaces of indent is 4. If you'd like to change the number as 2, just write: + * item1 + * item2 -```vim -let g:vim_markdown_new_list_item_indent = 2 -``` + vim-markdown automatically insert the indent. By default, the number of spaces of indent is 4. If you'd like to change the number as 2, just write: + + let g:vim_markdown_new_list_item_indent = 2 ### Do not require .md extensions for Markdown links -If you want to have a link like this `[link text](link-url)` and follow it for editing in vim using the `ge` command, but have it open the file "link-url.md" instead of the file "link-url", then use this option: +- `g:vim_markdown_no_extensions_in_markdown` -```vim -let g:vim_markdown_no_extensions_in_markdown = 1 -``` -This is super useful for GitLab and GitHub wiki repositories. + If you want to have a link like this `[link text](link-url)` and follow it for editing in vim using the `ge` command, but have it open the file "link-url.md" instead of the file "link-url", then use this option: -Normal behaviour would be that vim-markup required you to do this `[link text](link-url.md)`, but this is not how the Gitlab and GitHub wiki repositories work. So this option adds some consistency between the two. + let g:vim_markdown_no_extensions_in_markdown = 1 + + This is super useful for GitLab and GitHub wiki repositories. + + Normal behaviour would be that vim-markup required you to do this `[link text](link-url.md)`, but this is not how the Gitlab and GitHub wiki repositories work. So this option adds some consistency between the two. ### Auto-write when following link -If you follow a link like this `[link text](link-url)` using the `ge` shortcut, this option will automatically save any edits you made before moving you: +- `g:vim_markdown_autowrite` -```vim -let g:vim_markdown_autowrite = 1 -``` + If you follow a link like this `[link text](link-url)` using the `ge` shortcut, this option will automatically save any edits you made before moving you: + + let g:vim_markdown_autowrite = 1 ### Change default file extension -If you would like to use a file extension other than `.md` you may do so using the `vim_markdown_auto_extension_ext` variable: +- `g:vim_markdown_auto_extension_ext` -```vim -let g:vim_markdown_auto_extension_ext = 'txt' -``` + If you would like to use a file extension other than `.md` you may do so using the `vim_markdown_auto_extension_ext` variable: + + let g:vim_markdown_auto_extension_ext = 'txt' ### Do not automatically insert bulletpoints -Automatically inserting bulletpoints can lead to problems when wrapping text -(see issue #232 for details), so it can be disabled: +- `g:vim_markdown_auto_insert_bullets` -```vim -let g:vim_markdown_auto_insert_bullets = 0 -``` + Automatically inserting bulletpoints can lead to problems when wrapping text + (see issue #232 for details), so it can be disabled: -In that case, you probably also want to set the new list item indent to 0 as -well, or you will have to remove an indent each time you add a new list item: + let g:vim_markdown_auto_insert_bullets = 0 -```vim -let g:vim_markdown_new_list_item_indent = 0 -``` + In that case, you probably also want to set the new list item indent to 0 as + well, or you will have to remove an indent each time you add a new list item: + + let g:vim_markdown_new_list_item_indent = 0 ### Change how to open new files -By default when following a link the target file will be opened in your current buffer. This behavior can change if you prefer using splits or tabs by using the `vim_markdown_edit_url_in` variable. Possible values are `tab`, `vsplit`, `hsplit`, `current` opening in a new tab, vertical split, horizontal split, and current buffer respectively. Defaults to current buffer if not set: +- `g:vim_markdown_edit_url_in` -```vim -let g:vim_markdown_edit_url_in = 'tab' -``` + By default when following a link the target file will be opened in your current buffer. This behavior can change if you prefer using splits or tabs by using the `vim_markdown_edit_url_in` variable. Possible values are `tab`, `vsplit`, `hsplit`, `current` opening in a new tab, vertical split, horizontal split, and current buffer respectively. Defaults to current buffer if not set: + + let g:vim_markdown_edit_url_in = 'tab' ## Mappings diff --git a/sources_non_forked/vim-markdown/after/ftplugin/markdown.vim b/sources_non_forked/vim-markdown/after/ftplugin/markdown.vim index 41dfd944..8be6ff91 100644 --- a/sources_non_forked/vim-markdown/after/ftplugin/markdown.vim +++ b/sources_non_forked/vim-markdown/after/ftplugin/markdown.vim @@ -1,3 +1,4 @@ +" vim: ts=4 sw=4: " folding for Markdown headers, both styles (atx- and setex-) " http://daringfireball.net/projects/markdown/syntax#header " @@ -14,26 +15,36 @@ endfunction if get(g:, "vim_markdown_folding_style_pythonic", 0) function! Foldexpr_markdown(lnum) let l1 = getline(a:lnum) - " keep track of fenced code blocks + "~~~~~ keep track of fenced code blocks ~~~~~ + "If we hit a code block fence if l1 =~ '````*' || l1 =~ '\~\~\~\~*' + " toggle the variable that says if we're in a code block if b:fenced_block == 0 let b:fenced_block = 1 elseif b:fenced_block == 1 let b:fenced_block = 0 endif + " else, if we're caring about front matter elseif g:vim_markdown_frontmatter == 1 + " if we're in front matter and not on line 1 if b:front_matter == 1 && a:lnum > 2 let l0 = getline(a:lnum-1) + " if the previous line fenced front matter if l0 == '---' + " we must not be in front matter let b:front_matter = 0 endif + " else, if we're on line one elseif a:lnum == 1 + " if we hit a front matter fence if l1 == '---' + " we're in the front matter let b:front_matter = 1 endif endif endif + " if we're in a code block or front matter if b:fenced_block == 1 || b:front_matter == 1 if a:lnum == 1 " fold any 'preamble' @@ -45,17 +56,25 @@ if get(g:, "vim_markdown_folding_style_pythonic", 0) endif let l2 = getline(a:lnum+1) + " if the next line starts with two or more '=' + " and is not code if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1) " next line is underlined (level 1) return '>0' + " else, if the nex line starts with two or more '-' + " and is not code elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1) " next line is underlined (level 2) return '>1' endif + "if we're on a non-code line starting with a pound sign if l1 =~ '^#' && !s:is_mkdCode(a:lnum) - " current line starts with hashes - return '>'.(matchend(l1, '^#\+') - 1) + " set the fold level to the number of hashes -1 + " return '>'.(matchend(l1, '^#\+') - 1) + " set the fold level to the number of hashes + return '>'.(matchend(l1, '^#\+')) + " else, if we're on line 1 elseif a:lnum == 1 " fold any 'preamble' return '>1' @@ -76,7 +95,7 @@ if get(g:, "vim_markdown_folding_style_pythonic", 0) let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1 return line . ' ' . repeat("-", fillcharcount) . ' ' . foldedlinecount endfunction -else +else " vim_markdown_folding_style_pythonic == 0 function! Foldexpr_markdown(lnum) if (a:lnum == 1) let l0 = '' @@ -152,15 +171,27 @@ let b:front_matter = 0 let s:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1) 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 + if !get(g:, "vim_markdown_folding_disabled", 0) + if get(g:, "vim_markdown_folding_style_pythonic", 0) + if get(g:, "vim_markdown_override_foldtext", 1) + setlocal foldtext=Foldtext_markdown() + endif + endif + setlocal foldexpr=Foldexpr_markdown(v:lnum) + setlocal foldmethod=expr + endif endfunction + +function! s:MarkdownSetupFoldLevel() + if get(g:, "vim_markdown_folding_style_pythonic", 0) + " set default foldlevel + execute "setlocal foldlevel=".s:vim_markdown_folding_level + endif +endfunction + +call s:MarkdownSetupFoldLevel() call s:MarkdownSetupFolding() + augroup Mkd " These autocmds need to be kept in sync with the autocmds calling " s:MarkdownRefreshSyntax in ftplugin/markdown.vim. diff --git a/sources_non_forked/vim-markdown/doc/vim-markdown.txt b/sources_non_forked/vim-markdown/doc/vim-markdown.txt index 4e1c487e..4d731293 100644 --- a/sources_non_forked/vim-markdown/doc/vim-markdown.txt +++ b/sources_non_forked/vim-markdown/doc/vim-markdown.txt @@ -52,7 +52,7 @@ and extensions. *vim-markdown-installation* Installation ~ -If you use Vundle [2], add the following line to your '~/.vimrc': +If you use Vundle [2], add the following lines to your '~/.vimrc': > Plugin 'godlygeek/tabular' Plugin 'plasticboy/vim-markdown' @@ -133,159 +133,195 @@ Options ~ ------------------------------------------------------------------------------- *vim-markdown-disable-folding* - *g:vim_markdown_folding_disabled* Disable Folding ~ -Add the following line to your '.vimrc' to disable the folding configuration: + *g:vim_markdown_folding_disabled* +- 'g:vim_markdown_folding_disabled' + + Add the following line to your '.vimrc' to disable the folding + configuration: > let g:vim_markdown_folding_disabled = 1 < -This option only controls Vim Markdown specific folding configuration. + This option only controls Vim Markdown specific folding configuration. -To enable/disable folding use Vim's standard folding configuration. + To enable/disable folding use Vim's standard folding configuration. > set [no]foldenable < ------------------------------------------------------------------------------- *vim-markdown-change-fold-style* - *g:vim_markdown_folding_style_pythonic* - *g:vim_markdown_override_foldtext* Change fold style ~ -To fold in a style like python-mode [6], add the following to your '.vimrc': + *g:vim_markdown_folding_style_pythonic* +- 'g:vim_markdown_folding_style_pythonic' + + To fold in a style like python-mode [6], add the following to your + '.vimrc': > let g:vim_markdown_folding_style_pythonic = 1 < -Level 1 heading which is served as a document title is not folded. -'g:vim_markdown_folding_level' setting is not active with this fold style. + 'g:vim_markdown_folding_level' setting (default 1) is set to 'foldlevel'. + Thus level 1 heading which is served as a document title is expanded by + default. -To prevent foldtext from being set add the following to your '.vimrc': + *g:vim_markdown_override_foldtext* +- 'g:vim_markdown_override_foldtext' + + To prevent foldtext from being set add the following to your '.vimrc': > let g:vim_markdown_override_foldtext = 0 < ------------------------------------------------------------------------------- *vim-markdown-set-header-folding-level* - *g:vim_markdown_folding_level* Set header folding level ~ -Folding level is a number between 1 and 6. By default, if not specified, it is -set to 1. + *g:vim_markdown_folding_level* +- 'g:vim_markdown_folding_level' + + Folding level is a number between 1 and 6. By default, if not specified, it + is set to 1. > let g:vim_markdown_folding_level = 6 < -Tip: it can be changed on the fly with: + Tip: it can be changed on the fly with: > :let g:vim_markdown_folding_level = 1 :edit < ------------------------------------------------------------------------------- *vim-markdown-disable-default-key-mappings* - *g:vim_markdown_no_default_key_mappings* Disable Default Key Mappings ~ -Add the following line to your '.vimrc' to disable default key mappings: + *g:vim_markdown_no_default_key_mappings* +- 'g:vim_markdown_no_default_key_mappings' + + Add the following line to your '.vimrc' to disable default key mappings: > let g:vim_markdown_no_default_key_mappings = 1 < -You can also map them by yourself with '<Plug>' mappings. + You can also map them by yourself with '<Plug>' mappings. ------------------------------------------------------------------------------- *vim-markdown-enable-toc-window-auto-fit* - *g:vim_markdown_toc_autofit* Enable TOC window auto-fit ~ -Allow for the TOC window to auto-fit when it's possible for it to shrink. It -never increases its default size (half screen), it only shrinks. + *g:vim_markdown_toc_autofit* +- 'g:vim_markdown_toc_autofit' + + Allow for the TOC window to auto-fit when it's possible for it to shrink. + It never increases its default size (half screen), it only shrinks. > let g:vim_markdown_toc_autofit = 1 < ------------------------------------------------------------------------------- *vim-markdown-text-emphasis-restriction-to-single-lines* - *g:vim_markdown_emphasis_multiline* Text emphasis restriction to single-lines ~ -By default text emphasis works across multiple lines until a closing token is -found. However, it's possible to restrict text emphasis to a single line (i.e., -for it to be applied a closing token must be found on the same line). To do so: + *g:vim_markdown_emphasis_multiline* +- 'g:vim_markdown_emphasis_multiline' + + By default text emphasis works across multiple lines until a closing token + is found. However, it's possible to restrict text emphasis to a single line + (i.e., for it to be applied a closing token must be found on the same + line). To do so: > let g:vim_markdown_emphasis_multiline = 0 < ------------------------------------------------------------------------------- *vim-markdown-syntax-concealing* - *g:vim_markdown_conceal* Syntax Concealing ~ -Concealing is set for some syntax. + *g:vim_markdown_conceal* +- 'g:vim_markdown_conceal' -For example, conceal '[link text](link url)' as just 'link text'. Also, -'_italic_' and '*italic*' will conceal to just _italic_. Similarly '__bold__', -'**bold**', '___italic bold___', and '***italic bold***' will conceal to just -**bold**, **bold**, **_italic bold_**, and **_italic bold_** respectively. + Concealing is set for some syntax. -To enable conceal use Vim's standard conceal configuration. + For example, conceal '[link text](link url)' as just 'link text'. Also, + '_italic_' and '*italic*' will conceal to just _italic_. Similarly + '__bold__', '**bold**', '___italic bold___', and '***italic bold***' will + conceal to just **bold**, **bold**, **_italic bold_**, and **_italic + bold_** respectively. + + To enable conceal use Vim's standard conceal configuration. > set conceallevel=2 < -To disable conceal regardless of 'conceallevel' setting, add the following to -your '.vimrc': + To disable conceal regardless of 'conceallevel' setting, add the following + to your '.vimrc': > let g:vim_markdown_conceal = 0 < -To disable math conceal with LaTeX math syntax enabled, add the following to -your '.vimrc': + To disable math conceal with LaTeX math syntax enabled, add the following + to your '.vimrc': > let g:tex_conceal = "" let g:vim_markdown_math = 1 +< + *g:vim_markdown_conceal_code_blocks* +- 'g:vim_markdown_conceal_code_blocks' + + Disabling conceal for code fences requires an additional setting: +> + let g:vim_markdown_conceal_code_blocks = 0 < ------------------------------------------------------------------------------- *vim-markdown-fenced-code-block-languages* - *g:vim_markdown_fenced_languages* Fenced code block languages ~ -You can use filetype name as fenced code block languages for syntax -highlighting. If you want to use different name from filetype, you can add it -in your '.vimrc' like so: + *g:vim_markdown_fenced_languages* +- 'g:vim_markdown_fenced_languages' + + You can use filetype name as fenced code block languages for syntax + highlighting. If you want to use different name from filetype, you can add + it in your '.vimrc' like so: > let g:vim_markdown_fenced_languages = ['csharp=cs'] < -This will cause the following to be highlighted using the 'cs' filetype syntax. + This will cause the following to be highlighted using the 'cs' filetype + syntax. > ```csharp ... ``` < -Default is "['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']". + Default is "['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']". ------------------------------------------------------------------------------- *vim-markdown-follow-named-anchors* - *g:vim_markdown_follow_anchor* - *g:vim_markdown_anchorexpr* Follow named anchors ~ -This feature allows the 'ge' command to follow named anchors in links of the -form 'file#anchor' or just '#anchor', where file may omit the '.md' extension -as usual. Two variables control its operation: + *g:vim_markdown_follow_anchor* +- 'g:vim_markdown_follow_anchor' + + This feature allows the 'ge' command to follow named anchors in links of + the form 'file#anchor' or just '#anchor', where file may omit the '.md' + extension as usual. Two variables control its operation: > let g:vim_markdown_follow_anchor = 1 < -This tells vim-markdown whether to attempt to follow a named anchor in a link -or not. When it is 1, and only if a link can be split in two parts by the -pattern '#', then the first part is interpreted as the file and the second one -as the named anchor. This also includes urls of the form '#anchor', for which -the first part is considered empty, meaning that the target file is the current -one. After the file is opened, the anchor will be searched. + This tells vim-markdown whether to attempt to follow a named anchor in a + link or not. When it is 1, and only if a link can be split in two parts by + the pattern '#', then the first part is interpreted as the file and the + second one as the named anchor. This also includes urls of the form + '#anchor', for which the first part is considered empty, meaning that the + target file is the current one. After the file is opened, the anchor will + be searched. -Default is '0'. + Default is '0'. + + *g:vim_markdown_anchorexpr* +- 'g:vim_markdown_anchorexpr' > let g:vim_markdown_anchorexpr = "'<<'.v:anchor.'>>'" < -This expression will be evaluated substituting 'v:anchor' with a quoted string -that contains the anchor to visit. The result of the evaluation will become the -real anchor to search in the target file. This is useful in order to convert -anchors of the form, say, 'my-section-title' to searches of the form 'My -Section Title' or '<<my-section-title>>'. + This expression will be evaluated substituting 'v:anchor' with a quoted + string that contains the anchor to visit. The result of the evaluation will + become the real anchor to search in the target file. This is useful in + order to convert anchors of the form, say, 'my-section-title' to searches + of the form 'My Section Title' or '<<my-section-title>>'. -Default is "''". + Default is "''". ------------------------------------------------------------------------------- *vim-markdown-syntax-extensions* @@ -296,136 +332,161 @@ are off by default. ------------------------------------------------------------------------------- *vim-markdown-latex-math* - *g:vim_markdown_math* LaTeX math ~ -Used as '$x^2$', '$$x^2$$', escapable as '\$x\$' and '\$\$x\$\$'. + *g:vim_markdown_math* +- 'g:vim_markdown_math' + + Used as '$x^2$', '$$x^2$$', escapable as '\$x\$' and '\$\$x\$\$'. > let g:vim_markdown_math = 1 < ------------------------------------------------------------------------------- *vim-markdown-yaml-front-matter* - *g:vim_markdown_frontmatter* YAML Front Matter ~ -Highlight YAML front matter as used by Jekyll or Hugo [7]. + *g:vim_markdown_frontmatter* +- 'g:vim_markdown_frontmatter' + + Highlight YAML front matter as used by Jekyll or Hugo [7]. > let g:vim_markdown_frontmatter = 1 < ------------------------------------------------------------------------------- *vim-markdown-toml-front-matter* - *g:vim_markdown_toml_frontmatter* TOML Front Matter ~ -Highlight TOML front matter as used by Hugo [7]. + *g:vim_markdown_toml_frontmatter* +- 'g:vim_markdown_toml_frontmatter' -TOML syntax highlight requires vim-toml [8]. + Highlight TOML front matter as used by Hugo [7]. + + TOML syntax highlight requires vim-toml [8]. > let g:vim_markdown_toml_frontmatter = 1 < ------------------------------------------------------------------------------- *vim-markdown-json-front-matter* - *g:vim_markdown_json_frontmatter* JSON Front Matter ~ -Highlight JSON front matter as used by Hugo [7]. + *g:vim_markdown_json_frontmatter* +- 'g:vim_markdown_json_frontmatter' -JSON syntax highlight requires vim-json [9]. + Highlight JSON front matter as used by Hugo [7]. + + JSON syntax highlight requires vim-json [9]. > let g:vim_markdown_json_frontmatter = 1 < ------------------------------------------------------------------------------- *vim-markdown-strikethrough* - *g:vim_markdown_strikethrough* Strikethrough ~ -Strikethrough uses two tildes. '~~Scratch this.~~' + *g:vim_markdown_strikethrough* +- 'g:vim_markdown_strikethrough' + + Strikethrough uses two tildes. '~~Scratch this.~~' > let g:vim_markdown_strikethrough = 1 < ------------------------------------------------------------------------------- *vim-markdown-adjust-new-list-item-indent* - *g:vim_markdown_new_list_item_indent* Adjust new list item indent ~ -You can adjust a new list indent. For example, you insert a single line like -below: + *g:vim_markdown_new_list_item_indent* +- 'g:vim_markdown_new_list_item_indent' + + You can adjust a new list indent. For example, you insert a single line + like below: > * item1 < -Then if you type 'o' to insert new line in vim and type '* item2', the result -will be: + Then if you type 'o' to insert new line in vim and type '* item2', the + result will be: > * item1 * item2 < -vim-markdown automatically insert the indent. By default, the number of spaces -of indent is 4. If you'd like to change the number as 2, just write: + vim-markdown automatically insert the indent. By default, the number of + spaces of indent is 4. If you'd like to change the number as 2, just write: > let g:vim_markdown_new_list_item_indent = 2 < ------------------------------------------------------------------------------- *vim-markdown-do-not-require-.md-extensions-for-markdown-links* - *g:vim_markdown_no_extensions_in_markdown* Do not require .md extensions for Markdown links ~ -If you want to have a link like this '[link text](link-url)' and follow it for -editing in vim using the 'ge' command, but have it open the file "link-url.md" -instead of the file "link-url", then use this option: + *g:vim_markdown_no_extensions_in_markdown* +- 'g:vim_markdown_no_extensions_in_markdown' + + If you want to have a link like this '[link text](link-url)' and follow it + for editing in vim using the 'ge' command, but have it open the file "link- + url.md" instead of the file "link-url", then use this option: > let g:vim_markdown_no_extensions_in_markdown = 1 < -This is super useful for GitLab and GitHub wiki repositories. + This is super useful for GitLab and GitHub wiki repositories. -Normal behaviour would be that vim-markup required you to do this '[link text -](link-url.md)', but this is not how the Gitlab and GitHub wiki repositories -work. So this option adds some consistency between the two. + Normal behaviour would be that vim-markup required you to do this '[link + text](link-url.md)', but this is not how the Gitlab and GitHub wiki + repositories work. So this option adds some consistency between the two. ------------------------------------------------------------------------------- *vim-markdown-auto-write-when-following-link* - *g:vim_markdown_autowrite* Auto-write when following link ~ -If you follow a link like this '[link text](link-url)' using the 'ge' shortcut, -this option will automatically save any edits you made before moving you: + *g:vim_markdown_autowrite* +- 'g:vim_markdown_autowrite' + + If you follow a link like this '[link text](link-url)' using the 'ge' + shortcut, this option will automatically save any edits you made before + moving you: > let g:vim_markdown_autowrite = 1 < ------------------------------------------------------------------------------- *vim-markdown-change-default-file-extension* - *g:vim_markdown_auto_extension_ext* Change default file extension ~ -If you would like to use a file extension other than '.md' you may do so using -the 'vim_markdown_auto_extension_ext' variable: + *g:vim_markdown_auto_extension_ext* +- 'g:vim_markdown_auto_extension_ext' + + If you would like to use a file extension other than '.md' you may do so + using the 'vim_markdown_auto_extension_ext' variable: > let g:vim_markdown_auto_extension_ext = 'txt' < ------------------------------------------------------------------------------- *vim-markdown-do-not-automatically-insert-bulletpoints* - *g:vim_markdown_auto_insert_bullets* Do not automatically insert bulletpoints ~ -Automatically inserting bulletpoints can lead to problems when wrapping text -(see issue #232 for details), so it can be disabled: + *g:vim_markdown_auto_insert_bullets* +- 'g:vim_markdown_auto_insert_bullets' + + Automatically inserting bulletpoints can lead to problems when wrapping + text (see issue #232 for details), so it can be disabled: > let g:vim_markdown_auto_insert_bullets = 0 < -In that case, you probably also want to set the new list item indent to 0 as -well, or you will have to remove an indent each time you add a new list item: + In that case, you probably also want to set the new list item indent to 0 + as well, or you will have to remove an indent each time you add a new list + item: > let g:vim_markdown_new_list_item_indent = 0 < ------------------------------------------------------------------------------- *vim-markdown-change-how-to-open-new-files* - *g:vim_markdown_edit_url_in* Change how to open new files ~ -By default when following a link the target file will be opened in your current -buffer. This behavior can change if you prefer using splits or tabs by using -the 'vim_markdown_edit_url_in' variable. Possible values are 'tab', 'vsplit', -'hsplit', 'current' opening in a new tab, vertical split, horizontal split, and -current buffer respectively. Defaults to current buffer if not set: + *g:vim_markdown_edit_url_in* +- 'g:vim_markdown_edit_url_in' + + By default when following a link the target file will be opened in your + current buffer. This behavior can change if you prefer using splits or tabs + by using the 'vim_markdown_edit_url_in' variable. Possible values are + 'tab', 'vsplit', 'hsplit', 'current' opening in a new tab, vertical split, + horizontal split, and current buffer respectively. Defaults to current + buffer if not set: > let g:vim_markdown_edit_url_in = 'tab' < diff --git a/sources_non_forked/vim-markdown/syntax/markdown.vim b/sources_non_forked/vim-markdown/syntax/markdown.vim index d8d34ea1..c1a2b2ca 100644 --- a/sources_non_forked/vim-markdown/syntax/markdown.vim +++ b/sources_non_forked/vim-markdown/syntax/markdown.vim @@ -151,11 +151,11 @@ endif " Strike through if get(g:, 'vim_markdown_strikethrough', 0) - syn region mkdStrike matchgroup=mkdStrike start="\%(\~\~\)" end="\%(\~\~\)" + execute 'syn region mkdStrike matchgroup=htmlStrike start="\%(\~\~\)" end="\%(\~\~\)"' . s:concealends HtmlHiLink mkdStrike htmlStrike endif -syn cluster mkdNonListItem contains=@htmlTop,htmlItalic,htmlBold,htmlBoldItalic,mkdFootnotes,mkdInlineURL,mkdLink,mkdLinkDef,mkdLineBreak,mkdBlockquote,mkdCode,mkdRule,htmlH1,htmlH2,htmlH3,htmlH4,htmlH5,htmlH6,mkdMath,htmlStrike +syn cluster mkdNonListItem contains=@htmlTop,htmlItalic,htmlBold,htmlBoldItalic,mkdFootnotes,mkdInlineURL,mkdLink,mkdLinkDef,mkdLineBreak,mkdBlockquote,mkdCode,mkdRule,htmlH1,htmlH2,htmlH3,htmlH4,htmlH5,htmlH6,mkdMath,mkdStrike "highlighting for Markdown groups HtmlHiLink mkdString String diff --git a/sources_non_forked/vim-markdown/test/python-folding.vader b/sources_non_forked/vim-markdown/test/python-folding.vader index 91fc9e27..9196ea60 100644 --- a/sources_non_forked/vim-markdown/test/python-folding.vader +++ b/sources_non_forked/vim-markdown/test/python-folding.vader @@ -21,17 +21,16 @@ This is code block foobar Execute (fold level # in code block): - AssertEqual foldlevel(1), 0, '# Title' - AssertEqual foldlevel(3), 1, '## Chapter 1' - AssertEqual foldlevel(7), 1, '# This is just a comment' - AssertEqual foldlevel(8), 1, '```' - AssertEqual foldlevel(10), 1, '## Chapter 2' - AssertEqual foldlevel(12), 1, 'foobar' + AssertEqual foldlevel(1), 1, '# Title' + AssertEqual foldlevel(3), 2, '## Chapter 1' + AssertEqual foldlevel(7), 2, '# This is just a comment' + AssertEqual foldlevel(8), 2, '```' + AssertEqual foldlevel(10), 2, '## Chapter 2' + AssertEqual foldlevel(12), 2, 'foobar' Execute (fold text of chapters): let b:width = winwidth(0) let b:hyphen = repeat('-', b:width - 18 > 2 ? b:width - 18 : b:width - 9 > 0 ? 3 : 2) - AssertEqual foldtextresult(3), strpart('## Chapter 1', 0, b:width - 9) . ' ' . b:hyphen . ' 6' AssertEqual foldtextresult(10), strpart('## Chapter 2', 0, b:width - 9) . ' ' . b:hyphen . ' 2' Given markdown; @@ -59,7 +58,7 @@ foobar Execute (fold any preamble): AssertEqual foldlevel(1), 1, 'Headline' AssertEqual foldlevel(3), 1, 'foobar' - AssertEqual foldlevel(5), 0, '# Title' + AssertEqual foldlevel(5), 1, '# Title' Given markdown; --- diff --git a/sources_non_forked/vim-markdown/test/toc.vader b/sources_non_forked/vim-markdown/test/toc.vader index 2510edc7..51269526 100644 --- a/sources_non_forked/vim-markdown/test/toc.vader +++ b/sources_non_forked/vim-markdown/test/toc.vader @@ -175,10 +175,6 @@ Given markdown; ### header 3 Execute (Toc cursor on the current header): - normal! 4G - :Toc - AssertEqual line('.'), 2 - :lclose normal! G :Toc AssertEqual line('.'), 3 diff --git a/sources_non_forked/vim-multiple-cursors/README.md b/sources_non_forked/vim-multiple-cursors/README.md index ac5093e3..1f7e1be7 100644 --- a/sources_non_forked/vim-multiple-cursors/README.md +++ b/sources_non_forked/vim-multiple-cursors/README.md @@ -61,10 +61,10 @@ call plug#end() * next: `<C-n>` add a new _virtual cursor + selection_ on the next match * skip: `<C-x>` skip the next match * prev: `<C-p>` remove current _virtual cursor + selection_ and go back on previous match - * select all: `<A-n>` start muticursor and directly select all matches + * select all: `<A-n>` start multicursor and directly select all matches -You can now change the _virtual cursors + selection_ with **visual mode** commands. -For instance: `c`, `s`, `I`, `A` work without any issues. +You can now change the _virtual cursors + selection_ with **visual mode** commands. +For instance: `c`, `s`, `I`, `A` work without any issues. You could also go to **normal mode** by pressing `v` and use normal commands there. At any time, you can press `<Esc>` to exit back to regular Vim. @@ -74,11 +74,11 @@ At any time, you can press `<Esc>` to exit back to regular Vim. ### visual mode when multiple lines are selected * start: `<C-n>` add _virtual cursors_ on each line -You can now change the _virtual cursors_ with **normal mode** commands. +You can now change the _virtual cursors_ with **normal mode** commands. For instance: `ciw`. ### command -The command `MultipleCursorsFind` accepts a range and a pattern (regexp), it creates a _visual cursor_ at the end of each match. +The command `MultipleCursorsFind` accepts a range and a pattern (regexp), it creates a _visual cursor_ at the end of each match. If no range is passed in, then it defaults to the entire buffer. @@ -103,20 +103,20 @@ let g:multi_cursor_quit_key = '<Esc>' ## Settings Currently there are four additional global settings one can tweak: -### ```g:multi_cursor_exit_from_visual_mode``` (Default: 1) -If set to 0, then pressing `g:multi_cursor_quit_key` in _Visual_ mode will not quit and delete all existing cursors. -Useful if you want to go back to Normal mode, and still be able to operate on all the cursors. +### ```g:multi_cursor_exit_from_visual_mode``` (Default: 0) +If set to 1, then pressing `g:multi_cursor_quit_key` in _Visual_ mode will quit and +delete all existing cursors, just skipping normal mode with multiple cursors. -### ```g:multi_cursor_exit_from_insert_mode``` (Default: 1) -If set to 0, then pressing `g:multi_cursor_quit_key` in _Insert_ mode will not quit and delete all existing cursors. -Useful if you want to go back to Normal mode, and still be able to operate on all the cursors. +### ```g:multi_cursor_exit_from_insert_mode``` (Default: 0) +If set to 1, then pressing `g:multi_cursor_quit_key` in _Insert_ mode will quit and +delete all existing cursors, just skipping normal mode with multiple cursors. ### ```g:multi_cursor_normal_maps``` (Default: see below) `{'@': 1, 'F': 1, 'T': 1, '[': 1, '\': 1, ']': 1, '!': 1, '"': 1, 'c': 1, 'd': 1, 'f': 1, 'g': 1, 'm': 1, 'q': 1, 'r': 1, 't': 1, 'y': 1, 'z': 1, '<': 1, '=': 1, '>': 1}` Any key in this map (values are ignored) will cause multi-cursor _Normal_ mode to pause for map completion just like normal vim. Otherwise keys mapped in -normal mode will "fail to replay" when multiple cursors are active. +normal mode will "fail to replay" when multiple cursors are active. For example: `{'d':1}` makes normal-mode command `dw` work in multi-cursor mode. The default list contents should work for anybody, unless they have remapped a @@ -136,7 +136,7 @@ Same principle as `g:multi_cursor_normal_maps` ### ```Multiple_cursors_before/Multiple_cursors_after``` (Default: `nothing`) -Other plugins may be incompatible in insert mode. +Other plugins may be incompatible in insert mode. That is why we provide hooks to disable those plug-ins when vim-multiple-cursors is active: For example, if you are using [Neocomplete](https://github.com/Shougo/neocomplete.vim), @@ -171,7 +171,7 @@ highlight link multiple_cursors_visual Visual ## FAQ #### **Q** <kbd>ALT</kbd>+<kbd>n</kbd> doesn't seem to work in VIM but works in gVIM, why? -**A** This is a well known terminal/Vim [issue](http://vim.wikia.com/wiki/Get_Alt_key_to_work_in_terminal), different terminal have different ways to send ```Alt+key```. +**A** This is a well known terminal/Vim [issue](http://vim.wikia.com/wiki/Get_Alt_key_to_work_in_terminal), different terminal have different ways to send ```Alt+key```. Try adding this in your `.vimrc` and **make sure to replace the string**: ```vim if !has('gui_running') diff --git a/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt index b3b26c49..219853f7 100644 --- a/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt +++ b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt @@ -94,17 +94,15 @@ otherwise you'll have a tough time quitting from multicursor mode. Currently there are four additional global settings one can tweak: -*g:multi_cursor_exit_from_visual_mode* (Default: 1) +*g:multi_cursor_exit_from_visual_mode* (Default: 0) -If set to 0, then pressing |g:multi_cursor_quit_key| in |visual-mode| will not -quit and delete all existing cursors. Useful if you want to go back to -|normal-mode|, and still be able to operate on all the cursors. +If set to 0, then pressing |g:multi_cursor_quit_key| in |visual-mode| will quit +and delete all existing cursors, skipping normal mode with multiple cursors. -*g:multi_cursor_exit_from_insert_mode* (Default: 1) +*g:multi_cursor_exit_from_insert_mode* (Default: 0) -If set to 0, then pressing |g:multi_cursor_quit_key| in |insert-mode| will not -quit and delete all existing cursors. Useful if you want to go back to Normal -mode, and still be able to operate on all the cursors. +If set to 1, then pressing |g:multi_cursor_quit_key| in |insert-mode| will quit +and delete all existing cursors, skipping normal mode with multiple cursors. *g:multi_cursor_normal_maps* (Default: see below) diff --git a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim index ef84cab5..0f6e41f4 100644 --- a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim +++ b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim @@ -27,8 +27,8 @@ endfunction " Settings let s:settings = { - \ 'exit_from_visual_mode': 1, - \ 'exit_from_insert_mode': 1, + \ 'exit_from_visual_mode': 0, + \ 'exit_from_insert_mode': 0, \ 'use_default_mapping': 1, \ 'debug_latency': 0, \ } diff --git a/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb b/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb index 1f817bfa..867e665d 100644 --- a/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb +++ b/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb @@ -175,7 +175,9 @@ describe "Multiple Cursors when using insert mappings" do let(:options) { ['set timeoutlen=10000', 'imap jj <esc>', 'imap jojo dude', - 'imap jk <esc>:%s/bla/hey/g<cr>'] } + 'imap jk <esc>:%s/bla/hey/g<cr>', + 'let g:multi_cursor_exit_from_insert_mode = 1', + 'let g:multi_cursor_exit_from_visual_mode = 1'] } specify "#mapping doing <Esc>" do before <<-EOF hello world! diff --git a/sources_non_forked/vim-repeat/README.markdown b/sources_non_forked/vim-repeat/README.markdown index f8b44699..448d2d6d 100644 --- a/sources_non_forked/vim-repeat/README.markdown +++ b/sources_non_forked/vim-repeat/README.markdown @@ -12,6 +12,7 @@ The following plugins support repeat.vim: * [speeddating.vim](https://github.com/tpope/vim-speeddating) * [unimpaired.vim](https://github.com/tpope/vim-unimpaired) * [vim-easyclip](https://github.com/svermeulen/vim-easyclip) +* [vim-radical](https://github.com/glts/vim-radical) Adding support to a plugin is generally as simple as the following command at the end of your map functions. diff --git a/sources_non_forked/vim-snippets/UltiSnips/html.snippets b/sources_non_forked/vim-snippets/UltiSnips/html.snippets index 924f02fd..a81b1d88 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/html.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/html.snippets @@ -333,6 +333,10 @@ snippet mailto "HTML <a mailto: >" w <a href="mailto:${1:joe@example.com}?subject=${2:feedback}">${3:email me}</a> endsnippet +snippet tel "HTML <a tel: >" w +<a href="tel:+${1:XX1234567890}">${2:call me}</a> +endsnippet + snippet main "<main>" <main> ${1:main content} diff --git a/sources_non_forked/vim-snippets/UltiSnips/javascript-node.snippets b/sources_non_forked/vim-snippets/UltiSnips/javascript-node.snippets index e4a64e95..a46ed7f0 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/javascript-node.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/javascript-node.snippets @@ -1,6 +1,6 @@ priority -50 -snippet #! "shebang" +snippet #! "#!/usr/bin/env node" b #!/usr/bin/env node endsnippet diff --git a/sources_non_forked/vim-snippets/UltiSnips/lua.snippets b/sources_non_forked/vim-snippets/UltiSnips/lua.snippets index b6d0c1a3..0fd5eefc 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/lua.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/lua.snippets @@ -3,7 +3,7 @@ priority -50 ################################# # Snippets for the Lua language # ################################# -snippet #! "Shebang header" b +snippet #! "#!/usr/bin/env lua" b #!/usr/bin/env lua $0 endsnippet diff --git a/sources_non_forked/vim-snippets/UltiSnips/python.snippets b/sources_non_forked/vim-snippets/UltiSnips/python.snippets index a6c7416e..cdbe517d 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/python.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/python.snippets @@ -5,8 +5,12 @@ priority -50 ########################################################################### #! header -snippet #! "Shebang header for python scripts" b +snippet #! "#!/usr/bin/env python" b #!/usr/bin/env python +$0 +endsnippet + +snippet "^# ?[uU][tT][fF]-?8" "# encoding: UTF-8" r # -*- coding: utf-8 -*- $0 endsnippet @@ -267,7 +271,7 @@ class ${1:MyClass}(${2:object}): `!p snip.rv = triple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = triple_quotes(snip)` def __init__(self$4): - `!p snip.rv = triple_quotes(snip)`${5:TODO: to be defined1.}`!p + `!p snip.rv = triple_quotes(snip)`${5:TODO: to be defined.}`!p snip.rv = "" snip >> 2 diff --git a/sources_non_forked/vim-snippets/UltiSnips/r.snippets b/sources_non_forked/vim-snippets/UltiSnips/r.snippets index f81b0c9c..773880b5 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/r.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/r.snippets @@ -15,8 +15,9 @@ FIELD_TYPES = [ 'vector'] endglobal -snippet #! "Hashbang for Rscript (#!)" b +snippet #! "#!/usr/bin/env Rscript" b #!/usr/bin/env Rscript +$0 endsnippet snippet setwd "Set workingdir" b diff --git a/sources_non_forked/vim-snippets/UltiSnips/ruby.snippets b/sources_non_forked/vim-snippets/UltiSnips/ruby.snippets index cb90a9db..7b360ffa 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/ruby.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/ruby.snippets @@ -21,7 +21,7 @@ endglobal # Snippets # -snippet "^#!" "#!/usr/bin/env ruby" r +snippet #! "#!/usr/bin/env ruby" b #!/usr/bin/env ruby $0 endsnippet diff --git a/sources_non_forked/vim-snippets/UltiSnips/sh.snippets b/sources_non_forked/vim-snippets/UltiSnips/sh.snippets index 611b1ce3..9bacc725 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/sh.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/sh.snippets @@ -25,12 +25,8 @@ endglobal ########################################################################### # TextMate Snippets # ########################################################################### -snippet #! -`!p snip.rv = '#!/bin/' + getShell() + "\n\n" ` -endsnippet - -snippet !env "#!/usr/bin/env (!env)" -`!p snip.rv = '#!/usr/bin/env ' + getShell() + "\n\n" ` +snippet #! "#!/usr/bin/env (!env)" b +`!p snip.rv = '#!/usr/bin/env ' + getShell() + "\n" ` endsnippet snippet sbash "safe bash options" diff --git a/sources_non_forked/vim-snippets/UltiSnips/tex.snippets b/sources_non_forked/vim-snippets/UltiSnips/tex.snippets index b3383aec..355d9e46 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/tex.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/tex.snippets @@ -85,7 +85,7 @@ snippet fig "Figure environment" b \begin{figure}[${2:htpb}] \centering \includegraphics[width=${3:0.8}\linewidth]{${4:name.ext}} - \caption{${4/(\w+)\.\w+/\u$1/}$0} + \caption{${4/(\w+)\.\w+/\u$1/}$0}% \label{fig:${4/(\w+)\.\w+/$1/}} \end{figure} endsnippet diff --git a/sources_non_forked/vim-snippets/UltiSnips/zsh.snippets b/sources_non_forked/vim-snippets/UltiSnips/zsh.snippets index f7986ea5..678fbd19 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/zsh.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/zsh.snippets @@ -4,14 +4,9 @@ extends sh priority -49 -snippet #! "shebang" b -#!/bin/zsh - -endsnippet - -snippet !env "#!/usr/bin/env (!env)" b +snippet #! "#!/usr/bin/env zsh" b #!/usr/bin/env zsh - +$0 endsnippet # vim:ft=snippets: diff --git a/sources_non_forked/vim-snippets/snippets/cpp.snippets b/sources_non_forked/vim-snippets/snippets/cpp.snippets index f47a6834..f39d743e 100644 --- a/sources_non_forked/vim-snippets/snippets/cpp.snippets +++ b/sources_non_forked/vim-snippets/snippets/cpp.snippets @@ -62,9 +62,13 @@ snippet pqueue # std::shared_ptr snippet msp std::shared_ptr<${1:T}> ${2} = std::make_shared<$1>(${3}); +snippet amsp + auto ${1} = std::make_shared<${2:T}>(${3}); # std::unique_ptr snippet mup std::unique_ptr<${1:T}> ${2} = std::make_unique<$1>(${3}); +snippet amup + auto ${1} = std::make_unique<${2:T}>(${3}); ## ## Access Modifiers # private diff --git a/sources_non_forked/vim-snippets/snippets/css.snippets b/sources_non_forked/vim-snippets/snippets/css.snippets index dd688cbe..54b529ae 100644 --- a/sources_non_forked/vim-snippets/snippets/css.snippets +++ b/sources_non_forked/vim-snippets/snippets/css.snippets @@ -36,45 +36,71 @@ snippet @m "@media mediatype { }" ${2:${VISUAL}} }${0} snippet ac - align-content: ${0:stretch}; + align-content: ${1:stretch}; +snippet ac:s + align-content: start; +snippet ac:e + align-content: end; snippet ac:c align-content: center; -snippet ac:fe - align-content: flex-end; snippet ac:fs align-content: flex-start; -snippet ac:sa - align-content: space-around; +snippet ac:fe + align-content: flex-end; snippet ac:sb align-content: space-between; -snippet ac:s +snippet ac:sa + align-content: space-around; +snippet ac:se + align-content: space-evenly; +snippet ac:st align-content: stretch; +snippet ac:b + align-content: baseline; +snippet ac:fb + align-content: first baseline; +snippet ac:lb + align-content: last baseline; snippet ai - align-items: ${0:stretch}; -snippet ai:b - align-items: baseline; + align-items: ${1:stretch}; +snippet ai:s + align-items: start; +snippet ai:e + align-items: end; snippet ai:c align-items: center; -snippet ai:fe - align-items: flex-end; snippet ai:fs align-items: flex-start; -snippet ai:s +snippet ai:fe + align-items: flex-end; +snippet ai:st align-items: stretch; +snippet ai:b + align-items: baseline; +snippet ai:fb + align-items: first baseline; +snippet ai:lb + align-items: last baseline; snippet as - align-self: ${0}; -snippet as:a - align-self: auto; -snippet as:b - align-self: baseline; + align-self: ${1:stretch}; +snippet as:s + align-self: start; +snippet as:e + align-self: end; snippet as:c align-self: center; -snippet as:fe - align-self: flex-end; +snippet as:st + align-self: stretch; snippet as:fs align-self: flex-start; -snippet as:s - align-self: stretch; +snippet as:fe + align-self: flex-end; +snippet as:b + align-self: baseline; +snippet as:fb + align-self: first baseline; +snippet as:lb + align-self: last baseline; snippet bg+ background: #${1:fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};${0} snippet bga @@ -423,6 +449,8 @@ snippet d:b display: block; snippet d:cp display: compact; +snippet d:g + display: grid; snippet d:f display: flex; snippet d:ib @@ -605,24 +633,122 @@ snippet fw:n font-weight: normal; snippet f font: ${1};${0} +snippet g + grid: ${1}; +snippet gaf + grid-auto-flow: ${1:row}; +snippet gaf+ + grid-auto-flow: ${1:row} ${2:dense}; +snippet gaf:r + grid-auto-flow: row; +snippet gaf:c + grid-auto-flow: column; +snippet gaf:d + grid-auto-flow: dense; +snippet gaf:rd + grid-auto-flow: row dense; +snippet gaf:cd + grid-auto-flow: column dense; +snippet gar + grid-auto-rows: ${1}; +snippet gar:a + grid-auto-rows: auto +snippet gar:mac + grid-auto-rows: max-content; +snippet gar:mic + grid-auto-rows: min-content; +snippet gac + grid-auto-columns: ${1}; +snippet gac:a + grid-auto-columns: auto +snippet gac:mac + grid-auto-columns: max-content; +snippet gac:mic + grid-auto-columns: min-content; +snippet gt + grid-template: ${1}; +snippet gt+ + grid-template: ${1} / ${2}; +snippet gtr + grid-template-rows: ${1}; +snippet gtc + grid-template-columns: ${1}; +snippet gta + grid-template-areas: ${1}; +snippet gg + grid-gap: ${1}; +snippet gg+ + grid-gap: ${1} ${2}; +snippet gg:0 + grid-gap: 0; +snippet grg + grid-row-gap: ${1}; +snippet grg:0 + grid-row-gap: 0; +snippet gcg + grid-column-gap: ${1}; +snippet gcg:0 + grid-column-gap: 0; +snippet gr + grid-row: ${1} / ${2}; +snippet grs + grid-row-start: ${1}; +snippet gre + grid-row-end: ${1}; +snippet gc + grid-column: ${1} / ${2}; +snippet gcs + grid-column-start: ${1}; +snippet gce + grid-column-end: ${1}; snippet h height: ${1};${0} snippet h:a height: auto; snippet jc - justify-content: ${0:flex-start}; + justify-content: ${1}; +snippet jc:s + justify-content: start; +snippet jc:e + justify-content: end; snippet jc:c justify-content: center; -snippet jc:fe - justify-content: flex-end; snippet jc:fs justify-content: flex-start; -snippet jc:sa - justify-content: space-around; +snippet jc:fe + justify-content: flex-end; snippet jc:sb justify-content: space-between; +snippet jc:sa + justify-content: space-around; snippet jc:se justify-content: space-evenly; +snippet jc:st + justify-content: space-evenly; +snippet jc:l + justify-content: left; +snippet jc:r + justify-content: right; +snippet ji + justify-items: ${1:stretch}; +snippet ji:s + justify-items: start; +snippet ji:e + justify-items: end; +snippet ji:c + justify-items: center; +snippet ji:st + justify-items: stretch; +snippet js + justify-self: ${1:stretch}; +snippet js:s + justify-self: start; +snippet js:e + justify-self: end; +snippet js:c + justify-self: center; +snippet js:st + justify-self: stretch; snippet l left: ${1};${0} snippet l:a @@ -789,6 +915,28 @@ snippet p:2 padding: ${1:0} ${2:0};${0} snippet p:0 padding: 0; +snippet pc + place-content: ${1}; +snippet pc+ + place-content: ${1} ${2}; +snippet pc:s + place-content: start; +snippet pc:e + place-content: end; +snippet pc:c + place-content: center; +snippet pc:fs + place-content: flex-start; +snippet pc:fe + place-content: flex-end; +snippet pc:sb + place-content: space-between; +snippet pc:sa + place-content: space-around; +snippet pc:se + place-content: space-evenly; +snippet pc:st + place-content: stretch; snippet pgba page-break-after: ${1};${0} snippet pgba:aw @@ -815,6 +963,17 @@ snippet pgbi:a page-break-inside: auto; snippet pgbi:av page-break-inside: avoid; +snippet pi + place-items: ${1:stretch}; +snippet pi+ + place-items: ${1:stretch} ${2:stretch}; +snippet pi:s + place-items: start; +snippet pi:e + place-items: end; +snippet pi:c + place-items: center; +snippet pi:st snippet pos position: ${1};${0} snippet pos:a @@ -825,6 +984,18 @@ snippet pos:r position: relative; snippet pos:s position: static; +snippet ps + place-self: ${1:stretch}; +snippet ps+ + place-self: ${1:stretch} ${2:stretch}; +snippet ps:s + place-self: start; +snippet ps:e + place-self: end; +snippet ps:c + place-self: center; +snippet ps:st + place-self: stretch; snippet q quotes: ${1};${0} snippet q:en diff --git a/sources_non_forked/vim-snippets/snippets/eelixir.snippets b/sources_non_forked/vim-snippets/snippets/eelixir.snippets index 9910975a..456bed51 100644 --- a/sources_non_forked/vim-snippets/snippets/eelixir.snippets +++ b/sources_non_forked/vim-snippets/snippets/eelixir.snippets @@ -1,9 +1,11 @@ extends html -snippet % +snippet % <% %> <% ${0} %> -snippet = +snippet = <%= %> <%= ${0} %> +snippet # <%# %> + <%# ${0} %> snippet end <% end %> snippet for @@ -20,13 +22,35 @@ snippet ife <% else %> ${0} <% end %> -snippet ft +snippet cond + <%= cond do %> + <% ${1} -> %> + ${2:${VISUAL}} + + <% true -> %> + ${0} + <% end %> +snippet unless + <%= unless ${1} do %> + ${0:${VISUAL}} + <% end %> +snippet ft form_tag <%= form_tag(${1:"/users"}, method: ${2::post}) %> ${0} </form> -snippet lin +snippet et error_tag + <%= error_tag ${1:f}, :${2:field} %> +snippet ti text_input + <%= text_input ${1:f}, :${2:field} %> +snippet la label + <%= label ${1:f}, :${2:field}, "${3:Label}" %> +snippet pi password_input + <%= password_input ${1:f}, :${2:password} %> +snippet render + <%= render "${1:index}.html", ${2:var: @var} %> +snippet lin link <%= link "${1:Submit}", to: ${2:"/users"}, method: ${3::delete} %> -snippet ff +snippet ff form_for <%= form_for @changeset, ${1:"/users"}, fn f -> %> ${0} diff --git a/sources_non_forked/vim-snippets/snippets/go.snippets b/sources_non_forked/vim-snippets/snippets/go.snippets index 7cbbf5e2..bd7f541a 100644 --- a/sources_non_forked/vim-snippets/snippets/go.snippets +++ b/sources_non_forked/vim-snippets/snippets/go.snippets @@ -31,9 +31,6 @@ snippet cs "case" case ${1:value}: ${0:${VISUAL}} -snippet c "const" - const ${1:NAME} = ${0:0} - snippet co "constants with iota" const ( ${1:NAME1} = iota @@ -53,9 +50,6 @@ snippet dfr "defer recover" } }() -snippet i "int" - int - snippet im "import" import ( "${1:package}" diff --git a/sources_non_forked/vim-snippets/snippets/javascript/javascript-react.snippets b/sources_non_forked/vim-snippets/snippets/javascript/javascript-react.snippets index 011c5c1f..0e8d3602 100644 --- a/sources_non_forked/vim-snippets/snippets/javascript/javascript-react.snippets +++ b/sources_non_forked/vim-snippets/snippets/javascript/javascript-react.snippets @@ -1,7 +1,7 @@ snippet ir import React from 'react'; snippet irc - import React, {Component} from 'react'; + import React, { Component } from 'react'; snippet ird import ReactDOM from 'react-dom'; snippet cdm @@ -42,11 +42,24 @@ snippet pt static propTypes = { ${1}: React.PropTypes.${2:type}, } +snippet rfc + const ${1:ComponentName} = (${2:props}) => { + return ( + <div> + $1 + </div> + ); + } snippet rcc class ${1:ClassName} extends React.Component { + state = { + + } render() { return ( - ${0:<div />} + <div> + $1 + </div> ); } } diff --git a/sources_non_forked/vim-snippets/snippets/javascript/javascript-redux.snippets b/sources_non_forked/vim-snippets/snippets/javascript/javascript-redux.snippets new file mode 100644 index 00000000..e13253c3 --- /dev/null +++ b/sources_non_forked/vim-snippets/snippets/javascript/javascript-redux.snippets @@ -0,0 +1,37 @@ +snippet ist + import { createStore } from 'redux'; +snippet con + connect(${1:mapStateToProps}, ${2:mapDispatchToProps})(<${3:VISUAL}/>); +snippet act + const ${1:actionName} = (${2:arg}) => { + return { + type: ${3:VISUAL}, + $2 + }; + }; +snippet rdc + const ${1:reducerName} = (state={}, action) => { + switch(action.type) { + case ${1:action}: + return { + ...state, + $2 + }; + default: + return state; + }; + }; +snippet mstp + const mapStateToProps = (state) => { + return { + ${1:propName}: state.$1, + }; + }; +snippet mdtp + const mapDispatchToProps = (dispatch) => { + return { + ${1:propName}: () => { + dispatch(${2:actionName}()); + }, + }; + }; diff --git a/sources_non_forked/vim-snippets/snippets/javascript/javascript.es6.snippets b/sources_non_forked/vim-snippets/snippets/javascript/javascript.es6.snippets deleted file mode 100644 index 7e885e6e..00000000 --- a/sources_non_forked/vim-snippets/snippets/javascript/javascript.es6.snippets +++ /dev/null @@ -1,55 +0,0 @@ -snippet const - const ${1} = ${0}; -snippet let - let ${1} = ${0}; -snippet im "import xyz from 'xyz'" - import ${1} from '${2:$1}'; -snippet imas "import * as xyz from 'xyz'" - import * as ${1} from '${2:$1}'; -snippet imm "import { member } from 'xyz'" - import { ${1} } from '${2}'; -snippet cla - class ${1} { - ${0:${VISUAL}} - } -snippet clax - class ${1} extends ${2} { - ${0:${VISUAL}} - } -snippet clac - class ${1} { - constructor(${2}) { - ${0:${VISUAL}} - } - } -snippet foro "for (const prop of object}) { ... }" - for (const ${1:prop} of ${2:object}) { - ${0:$1} - } -# Generator -snippet fun* - function* ${1:function_name}(${2}) { - ${0:${VISUAL}} - } -snippet c=> - const ${1:function_name} = (${2}) => { - ${0:${VISUAL}} - } -snippet caf - const ${1:function_name} = (${2}) => { - ${0:${VISUAL}} - } -snippet => - (${1}) => { - ${0:${VISUAL}} - } -snippet af - (${1}) => { - ${0:${VISUAL}} - } -snippet sym - const ${1} = Symbol('${0}'); -snippet ed - export default ${0} -snippet ${ - ${${1}}${0} diff --git a/sources_non_forked/vim-snippets/snippets/javascript/javascript.snippets b/sources_non_forked/vim-snippets/snippets/javascript/javascript.snippets index 0dc5783e..8cf7c6e0 100644 --- a/sources_non_forked/vim-snippets/snippets/javascript/javascript.snippets +++ b/sources_non_forked/vim-snippets/snippets/javascript/javascript.snippets @@ -5,10 +5,14 @@ snippet proto ${0:${VISUAL}} }; # Function -snippet fun +snippet fun "function" function ${1:function_name}(${2}) { ${0:${VISUAL}} } +snippet fun "async function" + async function ${1:function_name}(${2}) { + ${0:${VISUAL}} + } # Anonymous Function snippet anf "" w function(${1}) { @@ -202,8 +206,6 @@ snippet @par @param {${1:type}} ${2:name} ${0:description} snippet @ret @return {${1:type}} ${0:description} -# JSON - # JSON.parse snippet jsonp JSON.parse(${0:jstr}); @@ -273,9 +275,64 @@ snippet cprof "console.profile" snippet ctable "console.table" console.table(${1:"${2:value}"}); # Misc -# 'use strict'; snippet us 'use strict'; # setTimeout function snippet timeout setTimeout(function () {${0}}${2}, ${1:10}); +snippet const + const ${1} = ${0}; +snippet let + let ${1} = ${0}; +snippet im "import xyz from 'xyz'" + import ${1} from '${2:$1}'; +snippet imas "import * as xyz from 'xyz'" + import * as ${1} from '${2:$1}'; +snippet imm "import { member } from 'xyz'" + import { ${1} } from '${2}'; +snippet cla + class ${1} { + ${0:${VISUAL}} + } +snippet clax + class ${1} extends ${2} { + ${0:${VISUAL}} + } +snippet clac + class ${1} { + constructor(${2}) { + ${0:${VISUAL}} + } + } +snippet foro "for (const prop of object}) { ... }" + for (const ${1:prop} of ${2:object}) { + ${0:$1} + } +snippet fun* + function* ${1:function_name}(${2}) { + ${0:${VISUAL}} + } +snippet c=> + const ${1:function_name} = (${2}) => { + ${0:${VISUAL}} + } +snippet caf + const ${1:function_name} = (${2}) => { + ${0:${VISUAL}} + } +snippet => + (${1}) => { + ${0:${VISUAL}} + } +snippet af + (${1}) => { + ${0:${VISUAL}} + } +snippet sym + const ${1} = Symbol('${0}'); +snippet ed + export default ${0} +snippet ${ + ${${1}}${0} +snippet aw "await" + await ${0:${VISUAL}} diff --git a/sources_non_forked/vim-snippets/snippets/sass.snippets b/sources_non_forked/vim-snippets/snippets/sass.snippets index 3e84c20e..5bef5937 100644 --- a/sources_non_forked/vim-snippets/snippets/sass.snippets +++ b/sources_non_forked/vim-snippets/snippets/sass.snippets @@ -34,6 +34,72 @@ snippet while ${0:${VISUAL}} snippet ! !important +snippet ac + align-content: ${0} +snippet ac:s + align-content: start +snippet ac:e + align-content: end +snippet ac:c + align-content: center +snippet ac:fs + align-content: flex-start +snippet ac:fe + align-content: flex-end +snippet ac:sb + align-content: space-between +snippet ac:sa + align-content: space-around +snippet ac:se + align-content: space-evenly +snippet ac:st + align-content: stretch +snippet ac:b + align-content: baseline +snippet ac:fb + align-content: first baseline +snippet ac:lb + align-content: last baseline +snippet ai + align-items: ${0} +snippet ai:s + align-items: start +snippet ai:e + align-items: end +snippet ai:c + align-items: center +snippet ai:fs + align-items: flex-start +snippet ai:fe + align-items: flex-end +snippet ai:st + align-items: stretch +snippet ai:b + align-items: baseline +snippet ai:fb + align-items: first baseline +snippet ai:lb + align-items: last baseline +snippet as + align-self: ${0} +snippet as:s + align-self: start +snippet as:e + align-self: end +snippet as:c + align-self: center +snippet as:st + align-self: stretch +snippet as:fs + align-self: flex-start +snippet as:fe + align-self: flex-end +snippet as:b + align-self: baseline +snippet as:fb + align-self: first baseline +snippet as:lb + align-self: last baseline snippet bdi:m+ -moz-border-image: url('${1}') ${2:0} ${3:0} ${4:0} ${5:0} ${6:stretch} ${0:stretch} snippet bdi:m @@ -411,6 +477,10 @@ snippet d:b display: block snippet d:cp display: compact +snippet d:g + display: grid +snippet d:f + display: flex snippet d:ib display: inline-block snippet d:itb @@ -561,10 +631,122 @@ snippet fw:n font-weight: normal snippet f font: ${0} +snippet g + grid: ${0} +snippet gaf + grid-auto-flow: ${0} +snippet gaf+ + grid-auto-flow: ${1:row} ${0:dense} +snippet gaf:r + grid-auto-flow: row +snippet gaf:c + grid-auto-flow: column +snippet gaf:d + grid-auto-flow: dense +snippet gaf:rd + grid-auto-flow: row dense +snippet gaf:cd + grid-auto-flow: column dense +snippet gar + grid-auto-rows: ${0} +snippet gar:a + grid-auto-rows: auto +snippet gar:mac + grid-auto-rows: max-content +snippet gar:mic + grid-auto-rows: min-content +snippet gac + grid-auto-columns: ${0} +snippet gac:a + grid-auto-columns: auto +snippet gac:mac + grid-auto-columns: max-content +snippet gac:mic + grid-auto-columns: min-content +snippet gt + grid-template: ${0} +snippet gt+ + grid-template: ${1} / ${0} +snippet gtr + grid-template-rows: ${0} +snippet gtc + grid-template-columns: ${0} +snippet gta + grid-template-areas: ${0} +snippet gg + grid-gap: ${0} +snippet gg+ + grid-gap: ${1} ${0} +snippet gg:0 + grid-gap: 0 +snippet grg + grid-row-gap: ${0} +snippet grg:0 + grid-row-gap: 0 +snippet gcg + grid-column-gap: ${0} +snippet gcg:0 + grid-column-gap: 0 +snippet gr + grid-row: ${1} / ${0} +snippet grs + grid-row-start: ${0} +snippet gre + grid-row-end: ${0} +snippet gc + grid-column: ${1} / ${0} +snippet gcs + grid-column-start: ${0} +snippet gce + grid-column-end: ${0} snippet h height: ${0} snippet h:a height: auto +snippet jc + justify-content: ${0} +snippet jc:s + justify-content: start +snippet jc:e + justify-content: end +snippet jc:c + justify-content: center +snippet jc:fs + justify-content: flex-start +snippet jc:fe + justify-content: flex-end +snippet jc:sb + justify-content: space-between +snippet jc:sa + justify-content: space-around +snippet jc:se + justify-content: space-evenly +snippet jc:st + justify-content: space-evenly +snippet jc:l + justify-content: left +snippet jc:r + justify-content: right +snippet ji + justify-items: ${0} +snippet ji:s + justify-items: start +snippet ji:e + justify-items: end +snippet ji:c + justify-items: center +snippet ji:st + justify-items: stretch +snippet js + justify-self: ${0} +snippet js:s + justify-self: start +snippet js:e + justify-self: end +snippet js:c + justify-self: center +snippet js:st + justify-self: stretch snippet l left: ${0} snippet l:a @@ -729,6 +911,28 @@ snippet p:2 padding: ${1:0} ${0:0} snippet p:0 padding: 0 +snippet pc + place-content: ${0} +snippet pc+ + place-content: ${1} ${0} +snippet pc:s + place-content: start +snippet pc:e + place-content: end +snippet pc:c + place-content: center +snippet pc:fs + place-content: flex-start +snippet pc:fe + place-content: flex-end +snippet pc:sb + place-content: space-between +snippet pc:sa + place-content: space-around +snippet pc:se + place-content: space-evenly +snippet pc:st + place-content: stretch snippet pgba page-break-after: ${0} snippet pgba:aw @@ -755,6 +959,18 @@ snippet pgbi:a page-break-inside: auto snippet pgbi:av page-break-inside: avoid +snippet pi + place-items: ${0} +snippet pi+ + place-items: ${1:stretch} ${0:stretch} +snippet pi:s + place-items: start +snippet pi:e + place-items: end +snippet pi:c + place-items: center +snippet pi:st + place-items: stretch snippet pos position: ${0} snippet pos:a @@ -765,6 +981,18 @@ snippet pos:r position: relative snippet pos:s position: static +snippet ps + place-self: ${0} +snippet ps+ + place-self: ${1:stretch} ${0:stretch} +snippet ps:s + place-self: start +snippet ps:e + place-self: end +snippet ps:c + place-self: center +snippet ps:st + place-self: stretch snippet q quotes: ${0} snippet q:en diff --git a/sources_non_forked/vim-snippets/snippets/stylus.snippets b/sources_non_forked/vim-snippets/snippets/stylus.snippets index 3ce35c26..ab703fee 100644 --- a/sources_non_forked/vim-snippets/snippets/stylus.snippets +++ b/sources_non_forked/vim-snippets/snippets/stylus.snippets @@ -1,5 +1,71 @@ snippet ! !important +snippet ac + align-content ${0} +snippet ac:s + align-content start +snippet ac:e + align-content end +snippet ac:c + align-content center +snippet ac:fs + align-content flex-start +snippet ac:fe + align-content flex-end +snippet ac:sb + align-content space-between +snippet ac:sa + align-content space-around +snippet ac:se + align-content space-evenly +snippet ac:st + align-content stretch +snippet ac:b + align-content baseline +snippet ac:fb + align-content first baseline +snippet ac:lb + align-content last baseline +snippet ai + align-items ${0} +snippet ai:s + align-items start +snippet ai:e + align-items end +snippet ai:c + align-items center +snippet ai:fs + align-items flex-start +snippet ai:fe + align-items flex-end +snippet ai:st + align-items stretch +snippet ai:b + align-items baseline +snippet ai:fb + align-items first baseline +snippet ai:lb + align-items last baseline +snippet as + align-self ${0} +snippet as:s + align-self start +snippet as:e + align-self end +snippet as:c + align-self center +snippet as:st + align-self stretch +snippet as:fs + align-self flex-start +snippet as:fe + align-self flex-end +snippet as:b + align-self baseline +snippet as:fb + align-self first baseline +snippet as:lb + align-self last baseline snippet bdi:m+ -moz-border-image url(${1}) ${2:0} ${3:0} ${4:0} ${5:0} ${6:stretch} ${0:stretch} snippet bdi:m @@ -379,10 +445,12 @@ snippet d:mis display -moz-inline-stack snippet d:b display block -snippet d:f - display flex snippet d:cp display compact +snippet d:g + display grid +snippet d:f + display flex snippet d:ib display inline-block snippet d:itb @@ -533,6 +601,74 @@ snippet fw:n font-weight normal snippet f font ${0} +snippet g + grid ${0} +snippet gaf + grid-auto-flow ${0} +snippet gaf+ + grid-auto-flow ${1:row} ${0:dense} +snippet gaf:r + grid-auto-flow row +snippet gaf:c + grid-auto-flow column +snippet gaf:d + grid-auto-flow dense +snippet gaf:rd + grid-auto-flow row dense +snippet gaf:cd + grid-auto-flow column dense +snippet gar + grid-auto-rows ${0} +snippet gar:a + grid-auto-rows auto +snippet gar:mac + grid-auto-rows max-content +snippet gar:mic + grid-auto-rows min-content +snippet gac + grid-auto-columns ${0} +snippet gac:a + grid-auto-columns auto +snippet gac:mac + grid-auto-columns max-content +snippet gac:mic + grid-auto-columns min-content +snippet gt + grid-template ${0} +snippet gt+ + grid-template ${1} / ${0} +snippet gtr + grid-template-rows ${0} +snippet gtc + grid-template-columns ${0} +snippet gta + grid-template-areas ${0} +snippet gg + grid-gap ${0} +snippet gg+ + grid-gap ${1} ${0} +snippet gg:0 + grid-gap 0 +snippet grg + grid-row-gap ${0} +snippet grg:0 + grid-row-gap 0 +snippet gcg + grid-column-gap ${0} +snippet gcg:0 + grid-column-gap 0 +snippet gr + grid-row ${1} / ${0} +snippet grs + grid-row-start ${0} +snippet gre + grid-row-end ${0} +snippet gc + grid-column ${1} / ${0} +snippet gcs + grid-column-start ${0} +snippet gce + grid-column-end ${0} snippet h height ${0} snippet h:a @@ -701,6 +837,28 @@ snippet p:2 padding ${1:0} ${0:0} snippet p:0 padding 0 +snippet pc + place-content ${0} +snippet pc+ + place-content ${1} ${0} +snippet pc:s + place-content start +snippet pc:e + place-content end +snippet pc:c + place-content center +snippet pc:fs + place-content flex-start +snippet pc:fe + place-content flex-end +snippet pc:sb + place-content space-between +snippet pc:sa + place-content space-around +snippet pc:se + place-content space-evenly +snippet pc:st + place-content stretch snippet pgba page-break-after ${0} snippet pgba:aw @@ -727,6 +885,18 @@ snippet pgbi:a page-break-inside auto snippet pgbi:av page-break-inside avoid +snippet pi + place-items ${0} +snippet pi+ + place-items ${1:stretch} ${0:stretch} +snippet pi:s + place-items start +snippet pi:e + place-items end +snippet pi:c + place-items center +snippet pi:st + place-items stretch snippet pos position ${0} snippet pos:a @@ -737,6 +907,18 @@ snippet pos:r position relative snippet pos:s position static +snippet ps + place-self ${0} +snippet ps+ + place-self ${1:stretch} ${0:stretch} +snippet ps:s + place-self start +snippet ps:e + place-self end +snippet ps:c + place-self center +snippet ps:st + place-self stretch snippet q quotes ${0} snippet q:en @@ -993,7 +1175,47 @@ snippet for for ${1:i} in ${0} snippet keyf @keyframes ${0} +snippet jc + justify-content ${0} +snippet jc:s + justify-content start +snippet jc:e + justify-content end snippet jc:c justify-content center -snippet jc - justify-content +snippet jc:fs + justify-content flex-start +snippet jc:fe + justify-content flex-end +snippet jc:sb + justify-content space-between +snippet jc:sa + justify-content space-around +snippet jc:se + justify-content space-evenly +snippet jc:st + justify-content space-evenly +snippet jc:l + justify-content left +snippet jc:r + justify-content right +snippet ji + justify-items ${0} +snippet ji:s + justify-items start +snippet ji:e + justify-items end +snippet ji:c + justify-items center +snippet ji:st + justify-items stretch +snippet js + justify-self ${0} +snippet js:s + justify-self start +snippet js:e + justify-self end +snippet js:c + justify-self center +snippet js:st + justify-self stretch diff --git a/sources_non_forked/vim-snippets/snippets/tex.snippets b/sources_non_forked/vim-snippets/snippets/tex.snippets index 895fbe57..24d4ff8a 100644 --- a/sources_non_forked/vim-snippets/snippets/tex.snippets +++ b/sources_non_forked/vim-snippets/snippets/tex.snippets @@ -248,7 +248,7 @@ snippet tikz figure environment (tikzpicture) ${2} \\end{tikzpicture} \\end{center} - \\caption{${3}} + \\caption{${3}}% \\label{fig:${4}} \\end{figure} ${0} diff --git a/sources_non_forked/vim-surround/plugin/surround.vim b/sources_non_forked/vim-surround/plugin/surround.vim index 5626f22f..59092601 100644 --- a/sources_non_forked/vim-surround/plugin/surround.vim +++ b/sources_non_forked/vim-surround/plugin/surround.vim @@ -336,7 +336,16 @@ function! s:insert(...) " {{{1 if exists("g:surround_insert_tail") call setreg('"',g:surround_insert_tail,"a".getregtype('"')) endif - if col('.') >= col('$') + if &ve != 'all' && col('.') >= col('$') + if &ve == 'insert' + let extra_cols = virtcol('.') - virtcol('$') + if extra_cols > 0 + let [regval,regtype] = [getreg('"',1,1),getregtype('"')] + call setreg('"',join(map(range(extra_cols),'" "'),''),'v') + norm! ""p + call setreg('"',regval,regtype) + endif + endif norm! ""p else norm! ""P