From 02572caa95bd577200834f6df54d6bd54caa1f40 Mon Sep 17 00:00:00 2001 From: Amir Salihefendic Date: Sat, 31 Mar 2018 11:56:26 -0300 Subject: [PATCH] Updated plugins --- README.md | 2 +- sources_non_forked/ack.vim/autoload/ack.vim | 4 +- .../ctrlp.vim/autoload/ctrlp.vim | 8 +- sources_non_forked/ctrlp.vim/doc/ctrlp.cnx | 2 +- sources_non_forked/ctrlp.vim/doc/ctrlp.txt | 2 +- sources_non_forked/gruvbox/colors/gruvbox.vim | 4 +- .../nerdtree/.github/ISSUE_TEMPLATE.md | 47 +- sources_non_forked/nerdtree/doc/NERDTree.txt | 10 + .../nerdtree/lib/nerdtree/creator.vim | 2 +- .../nerdtree/lib/nerdtree/path.vim | 12 +- .../autoload/glob_linux.vim | 42 + .../vim-coffee-script/syntax/coffee.vim | 2 +- .../vim-fugitive/CONTRIBUTING.markdown | 10 +- .../vim-gitgutter/.github/issue_template.md | 8 + sources_non_forked/vim-gitgutter/README.mkd | 117 +-- .../vim-gitgutter/autoload/gitgutter.vim | 272 ++---- .../autoload/gitgutter/async.vim | 58 +- .../autoload/gitgutter/debug.vim | 62 +- .../vim-gitgutter/autoload/gitgutter/diff.vim | 368 +++---- .../autoload/gitgutter/highlight.vim | 54 +- .../vim-gitgutter/autoload/gitgutter/hunk.vim | 224 ++++- .../vim-gitgutter/autoload/gitgutter/sign.vim | 136 ++- .../autoload/gitgutter/utility.vim | 293 +++--- .../vim-gitgutter/doc/gitgutter.txt | 610 +++++++----- .../vim-gitgutter/plugin/gitgutter.vim | 120 +-- .../vim-gitgutter/test/cp932.txt | 8 + sources_non_forked/vim-gitgutter/test/test | 2 + .../vim-gitgutter/test/test_gitgutter.vim | 261 ++++- sources_non_forked/vim-gitgutter/unplace.vim | 27 + sources_non_forked/vim-go/.codecov.yml | 12 + sources_non_forked/vim-go/CHANGELOG.md | 37 +- sources_non_forked/vim-go/README.md | 7 +- sources_non_forked/vim-go/autoload/go/cmd.vim | 2 +- .../vim-go/autoload/go/cmd_test.vim | 30 + .../vim-go/autoload/go/complete.vim | 273 ++++-- .../vim-go/autoload/go/coverage.vim | 2 +- .../vim-go/autoload/go/debug.vim | 904 ++++++++++++++++++ sources_non_forked/vim-go/autoload/go/fmt.vim | 1 - .../vim-go/autoload/go/guru.vim | 113 ++- sources_non_forked/vim-go/autoload/go/job.vim | 102 +- .../vim-go/autoload/go/jobcontrol.vim | 8 +- .../vim-go/autoload/go/lint.vim | 93 +- .../vim-go/autoload/go/lint_test.vim | 32 +- .../vim-go/autoload/go/list.vim | 39 +- .../vim-go/autoload/go/package.vim | 8 + .../vim-go/autoload/go/rename.vim | 49 +- .../vim-go/autoload/go/template.vim | 2 +- .../vim-go/autoload/go/term.vim | 105 +- .../vim-go/autoload/go/term_test.vim | 50 + .../autoload/go/test-fixtures/cmd/bad.go | 5 + .../go/test-fixtures/lint/src/vet/vet.go | 8 + .../autoload/go/test-fixtures/term/term.go | 5 + .../vim-go/autoload/go/test.vim | 63 +- .../vim-go/autoload/go/textobj.vim | 52 +- .../vim-go/autoload/go/util.vim | 9 +- sources_non_forked/vim-go/doc/vim-go.txt | 238 ++++- .../vim-go/ftplugin/go/commands.vim | 7 + .../vim-go/ftplugin/go/snippets.vim | 2 +- .../vim-go/gosnippets/UltiSnips/go.snippets | 5 + .../vim-go/gosnippets/snippets/go.snip | 4 + sources_non_forked/vim-go/plugin/go.vim | 1 + sources_non_forked/vim-go/syntax/go.vim | 2 +- .../vim-go/syntax/godebugoutput.vim | 13 + .../vim-go/syntax/godebugstacktrace.vim | 11 + .../vim-go/syntax/godebugvariables.vim | 23 + sources_non_forked/vim-markdown/README.md | 4 +- .../vim-markdown/ftplugin/markdown.vim | 12 +- .../vim-multiple-cursors/README.md | 15 +- .../autoload/multiple_cursors.vim | 67 +- .../doc/multiple_cursors.txt | 10 - .../plugin/multiple_cursors.vim | 3 - .../spec/multiple_cursors_spec.rb | 123 ++- .../vim-snippets/UltiSnips/all.snippets | 7 + .../vim-snippets/UltiSnips/cpp.snippets | 2 +- .../vim-snippets/UltiSnips/plsql.snippets | 733 ++++++++++++++ .../vim-snippets/UltiSnips/robot.snippets | 19 +- .../vim-snippets/UltiSnips/tex.snippets | 20 +- .../vim-snippets/snippets/cpp.snippets | 12 +- .../vim-snippets/snippets/ps1.snippets | 76 +- .../vim-snippets/snippets/puppet.snippets | 95 +- .../vim-snippets/snippets/python.snippets | 6 +- .../vim-snippets/snippets/rails.snippets | 16 +- .../vim-snippets/snippets/tex.snippets | 10 +- vimrcs/plugins_config.vim | 23 +- 84 files changed, 4588 insertions(+), 1749 deletions(-) create mode 100644 sources_non_forked/vim-addon-mw-utils/autoload/glob_linux.vim create mode 100644 sources_non_forked/vim-gitgutter/.github/issue_template.md create mode 100644 sources_non_forked/vim-gitgutter/test/cp932.txt create mode 100644 sources_non_forked/vim-gitgutter/unplace.vim create mode 100644 sources_non_forked/vim-go/.codecov.yml create mode 100644 sources_non_forked/vim-go/autoload/go/cmd_test.vim create mode 100644 sources_non_forked/vim-go/autoload/go/debug.vim create mode 100644 sources_non_forked/vim-go/autoload/go/term_test.vim create mode 100644 sources_non_forked/vim-go/autoload/go/test-fixtures/cmd/bad.go create mode 100644 sources_non_forked/vim-go/autoload/go/test-fixtures/lint/src/vet/vet.go create mode 100644 sources_non_forked/vim-go/autoload/go/test-fixtures/term/term.go create mode 100644 sources_non_forked/vim-go/syntax/godebugoutput.vim create mode 100644 sources_non_forked/vim-go/syntax/godebugstacktrace.vim create mode 100644 sources_non_forked/vim-go/syntax/godebugvariables.vim create mode 100644 sources_non_forked/vim-snippets/UltiSnips/plsql.snippets diff --git a/README.md b/README.md index e3f7ae1d..77000f23 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ I recommend reading the docs of these plugins to understand them better. Each pl * [open_file_under_cursor.vim](https://github.com/amix/open_file_under_cursor.vim): Open file under cursor when pressing `gf` * [pathogen.vim](https://github.com/tpope/vim-pathogen): Manage your vim runtimepath * [snipmate.vim](https://github.com/garbas/vim-snipmate): snipmate.vim aims to be a concise vim script that implements some of TextMate's snippets features in Vim -* [syntastic](https://github.com/scrooloose/syntastic): Syntax checking hacks for vim +* [ale](https://github.com/w0rp/ale): Syntax and lint checking for vim (async) * [vim-commentary](https://github.com/tpope/vim-commentary): Comment stuff out. Use `gcc` to comment out a line (takes a count), `gc` to comment out the target of a motion. `gcu` uncomments a set of adjacent commented lines. * [vim-expand-region](https://github.com/terryma/vim-expand-region): Allows you to visually select increasingly larger regions of text using the same key combination * [vim-fugitive](https://github.com/tpope/vim-fugitive): A Git wrapper so awesome, it should be illegal diff --git a/sources_non_forked/ack.vim/autoload/ack.vim b/sources_non_forked/ack.vim/autoload/ack.vim index dbf84572..b6afdba4 100644 --- a/sources_non_forked/ack.vim/autoload/ack.vim +++ b/sources_non_forked/ack.vim/autoload/ack.vim @@ -130,8 +130,8 @@ function! s:ApplyMappings() "{{{ endif if exists("g:ackpreview") " if auto preview in on, remap j and k keys - nnoremap j j - nnoremap k k + nnoremap j j + nnoremap k k nmap j nmap k endif diff --git a/sources_non_forked/ctrlp.vim/autoload/ctrlp.vim b/sources_non_forked/ctrlp.vim/autoload/ctrlp.vim index 4968e785..e0c55c75 100644 --- a/sources_non_forked/ctrlp.vim/autoload/ctrlp.vim +++ b/sources_non_forked/ctrlp.vim/autoload/ctrlp.vim @@ -540,7 +540,7 @@ fu! s:bufparts(bufnr) endf fu! ctrlp#buffers(...) let ids = sort(filter(range(1, bufnr('$')), '(empty(getbufvar(v:val, "&bt"))' - \ .' || s:isneovimterminal(v:val)) && getbufvar(v:val, "&bl")'), 's:compmreb') + \ .' || s:isterminal(v:val)) && getbufvar(v:val, "&bl")'), 's:compmreb') if a:0 && a:1 == 'id' retu ids el @@ -2031,7 +2031,7 @@ fu! ctrlp#normcmd(cmd, ...) let buftypes = [ 'quickfix', 'help' ] if a:0 < 2 && s:nosplit() | retu a:cmd | en let norwins = filter(range(1, winnr('$')), - \ 'index(buftypes, getbufvar(winbufnr(v:val), "&bt")) == -1 || s:isneovimterminal(winbufnr(v:val))') + \ 'index(buftypes, getbufvar(winbufnr(v:val), "&bt")) == -1 || s:isterminal(winbufnr(v:val))') for each in norwins let bufnr = winbufnr(each) if empty(bufname(bufnr)) && empty(getbufvar(bufnr, '&ft')) @@ -2305,8 +2305,8 @@ fu! s:delbuf() cal s:PrtClearCache() endf -fu! s:isneovimterminal(buf) - retu has('nvim') && getbufvar(a:buf, "&bt") == "terminal" +fu! s:isterminal(buf) + retu getbufvar(a:buf, "&bt") == "terminal" endf " Entering & Exiting {{{2 fu! s:getenv() diff --git a/sources_non_forked/ctrlp.vim/doc/ctrlp.cnx b/sources_non_forked/ctrlp.vim/doc/ctrlp.cnx index 1f8a2ee6..d99c4c6c 100644 --- a/sources_non_forked/ctrlp.vim/doc/ctrlp.cnx +++ b/sources_non_forked/ctrlp.vim/doc/ctrlp.cnx @@ -1,4 +1,4 @@ -*ctrlp.txt* 支持模糊匹配的 文件, 缓冲区, 最近最多使用, 标签, ... 检索. v1.79 +*ctrlp.txt* 支持模糊匹配的 文件, 缓冲区, 最近最多使用, 标签, ... 检索. v1.80 *CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'* =============================================================================== # # diff --git a/sources_non_forked/ctrlp.vim/doc/ctrlp.txt b/sources_non_forked/ctrlp.vim/doc/ctrlp.txt index 4dc2e4ec..4090e836 100644 --- a/sources_non_forked/ctrlp.vim/doc/ctrlp.txt +++ b/sources_non_forked/ctrlp.vim/doc/ctrlp.txt @@ -1,4 +1,4 @@ -*ctrlp.txt* Fuzzy file, buffer, mru, tag, ... finder. v1.79 +*ctrlp.txt* Fuzzy file, buffer, mru, tag, ... finder. v1.80 *CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'* =============================================================================== # # diff --git a/sources_non_forked/gruvbox/colors/gruvbox.vim b/sources_non_forked/gruvbox/colors/gruvbox.vim index 33e5763d..a0c2c0ba 100644 --- a/sources_non_forked/gruvbox/colors/gruvbox.vim +++ b/sources_non_forked/gruvbox/colors/gruvbox.vim @@ -688,8 +688,8 @@ hi! link EasyMotionShade Comment " }}} " Sneak: {{{ -autocmd ColorScheme gruvbox hi! link Sneak Search -autocmd ColorScheme gruvbox hi! link SneakLabel Search +hi! link Sneak Search +hi! link SneakLabel Search " }}} " Indent Guides: {{{ diff --git a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md index 69aa7d9b..c3ca5eff 100644 --- a/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md +++ b/sources_non_forked/nerdtree/.github/ISSUE_TEMPLATE.md @@ -1,37 +1,28 @@ -_To assist in resolving your issue, provide as much information as possible, in place of the ellipses (`…`) below._ + ---- -**Environment:** _Describe your Vim/NERDTree setup._ +### Environment + ->* Operating System: … ->* Vim version `:version`: … ->* NERDTree version `git rev-parse --short HEAD`: … ->* NERDTree settings applied in your vimrc, if any: -> -> ``` -> … -> ``` +* 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._ +### Process + ->1. … +1. -**Current Result:** _Describe what you you currently experience from this process._ +### Current Result + ->… +### Expected Result + -**Expected Result:** _Describe what you would expect to have resulted from this process._ +### Screenshot(s) ->… - ---- -**Optional** - -**Screenshot(s):** - ->… - -**Possible Fix:** _(Have you poked around in the code?)_ - ->… +### Possible Fix + diff --git a/sources_non_forked/nerdtree/doc/NERDTree.txt b/sources_non_forked/nerdtree/doc/NERDTree.txt index 828032cc..a83c4e15 100644 --- a/sources_non_forked/nerdtree/doc/NERDTree.txt +++ b/sources_non_forked/nerdtree/doc/NERDTree.txt @@ -694,6 +694,16 @@ NERD tree. These options should be set in your vimrc. |'NERDTreeCreatePrefix'| Specify a prefix to be used when creating the NERDTree window. +|'NERDTreeRemoveFileCmd'| Specify a custom shell command to be used when + deleting files. Note that it should include + one space character at the end of the command + and it applies only to files. + +|'NERDTreeRemoveDirCmd'| Specify a custom shell command to be used when + deleting directories. Note that it should + include one space character at the end of the + command and it applies only to directories. + ------------------------------------------------------------------------------ 3.2. Customisation details *NERDTreeOptionDetails* diff --git a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim index 047939fa..fb5adfd0 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim @@ -185,7 +185,7 @@ function! s:Creator._createTreeWin() let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " let splitSize = g:NERDTreeWinSize - if !exists('t:NERDTreeBufName') + if !g:NERDTree.ExistsForTab() let t:NERDTreeBufName = self._nextBufferName() silent! exec splitLocation . 'vertical ' . splitSize . ' new' silent! exec "edit " . t:NERDTreeBufName diff --git a/sources_non_forked/nerdtree/lib/nerdtree/path.vim b/sources_non_forked/nerdtree/lib/nerdtree/path.vim index 65cd5ca8..7fc726ed 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/path.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/path.vim @@ -246,7 +246,13 @@ function! s:Path.delete() throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'" endif else - let success = delete(self.str()) + if exists('g:NERDTreeRemoveFileCmd') + let cmd = g:NERDTreeRemoveFileCmd . self.str({'escape': 1}) + let success = system(cmd) + else + let success = delete(self.str()) + endif + if success != 0 throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'" endif @@ -409,7 +415,7 @@ endfunction " FUNCTION: Path.isHiddenUnder(path) {{{1 function! s:Path.isHiddenUnder(path) - + if !self.isUnder(a:path) return 0 endif @@ -418,7 +424,7 @@ function! s:Path.isHiddenUnder(path) let l:segments = self.pathSegments[l:startIndex : ] for l:segment in l:segments - + if l:segment =~# '^\.' return 1 endif diff --git a/sources_non_forked/vim-addon-mw-utils/autoload/glob_linux.vim b/sources_non_forked/vim-addon-mw-utils/autoload/glob_linux.vim new file mode 100644 index 00000000..6fd3f044 --- /dev/null +++ b/sources_non_forked/vim-addon-mw-utils/autoload/glob_linux.vim @@ -0,0 +1,42 @@ + +" TODO refactor: create glob function +" noremap \og :callglob_linux#FileByGlobCurrentDir('**/*'.input('glob open '),"\\.git\\\\.hg\\node_modules\\\\.pyc" ) +" noremap \og :callglob_linux#FileByGlobCurrentDir('**/*'.input('glob open '),"default" ) +function! glob_linux#FileByGlobCurrentDir(glob, exclude_pattern) + if a:exclude_pattern == "default" + let exclude_pattern = '\.git\|\.hg\|node_modules\|\.pyc' + else + let exclude_pattern = a:exclude_pattern + endif + + " let files = split(glob(a:glob),"\n") + let g = a:glob + let replace = {'**': '.*','*': '[^/\]*','.': '\.'} + let g = substitute(g, '\(\*\*\|\*\|\.\)', '\='.string(replace).'[submatch(1)]','g') + + let exclude = exclude_pattern == '' ? '' : ' | grep -v -e '.shellescape(exclude_pattern) + + let cmd = 'find | grep -e '.shellescape(g).exclude + let files = split(system(cmd),"\n") + " for nom in a:excludes + " call filter(files,nom) + " endfor + if len(files) > 1000 + echoe "more than ".2000." files - would be too slow. Open the file in another way" + else + if empty(files) + echoe "no file found" + elseif len(files) == 1 + exec 'e '.fnameescape(files[0]) + else + let g:abc=7 + call tovl#ui#filter_list#ListView({ + \ 'number' : 1, + \ 'selectByIdOrFilter' : 1, + \ 'Continuation' : funcref#Function('exec "e ".fnameescape(ARGS[0])'), + \ 'items' : files, + \ 'cmds' : ['wincmd J'] + \ }) + endif + endif +endfunction diff --git a/sources_non_forked/vim-coffee-script/syntax/coffee.vim b/sources_non_forked/vim-coffee-script/syntax/coffee.vim index 58d13268..bd8de587 100644 --- a/sources_non_forked/vim-coffee-script/syntax/coffee.vim +++ b/sources_non_forked/vim-coffee-script/syntax/coffee.vim @@ -32,7 +32,7 @@ hi def link coffeeConditional Conditional syn match coffeeException /\<\%(try\|catch\|finally\)\>/ display hi def link coffeeException Exception -syn match coffeeKeyword /\<\%(new\|in\|of\|by\|and\|or\|not\|is\|isnt\|class\|extends\|super\|do\|yield\|debugger\|import\|export\|default\|await\)\>/ +syn match coffeeKeyword /\<\%(new\|in\|of\|from\|by\|and\|or\|not\|is\|isnt\|class\|extends\|super\|do\|yield\|debugger\|import\|export\|default\|await\)\>/ \ display " The `own` keyword is only a keyword after `for`. syn match coffeeKeyword /\/ contained containedin=coffeeRepeat diff --git a/sources_non_forked/vim-fugitive/CONTRIBUTING.markdown b/sources_non_forked/vim-fugitive/CONTRIBUTING.markdown index e651dcae..843bbe6b 100644 --- a/sources_non_forked/vim-fugitive/CONTRIBUTING.markdown +++ b/sources_non_forked/vim-fugitive/CONTRIBUTING.markdown @@ -8,8 +8,14 @@ platform issues, and interactions with other plugins. I end up bisecting a lot more than other projects, and thus I'm especially meticulous here about maintaining a clean, readable, history. Squash and force push any requested changes to a pull request. And if your [commit message -sucks](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), -I'm not going to accept it. Period. +sucks](https://commit.style), I'm not going to accept it. Period. + +If your contribution involves adding a configuration option, you are going to +need a very compelling justification for it. Options add a maintenance +burden, support burden, and documentation bloat, and oftentimes can be +achieved much more simply with a custom map or autocommand. If your option +controls an underlying Git command, ask yourself why Git itself does not offer +such configuration. Beyond that, don't be shy about asking before patching. What takes you hours might take me minutes simply because I have both domain knowledge and a diff --git a/sources_non_forked/vim-gitgutter/.github/issue_template.md b/sources_non_forked/vim-gitgutter/.github/issue_template.md new file mode 100644 index 00000000..732d22ef --- /dev/null +++ b/sources_non_forked/vim-gitgutter/.github/issue_template.md @@ -0,0 +1,8 @@ +> What is the latest commit SHA in your installed vim-gitgutter? + +> 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 83f10c20..520e1cc8 100644 --- a/sources_non_forked/vim-gitgutter/README.mkd +++ b/sources_non_forked/vim-gitgutter/README.mkd @@ -1,12 +1,14 @@ ## vim-gitgutter -A Vim plugin which shows a git diff in the 'gutter' (sign column). It shows whether each line has been added, modified, and where lines have been removed. You can also stage and undo individual hunks. +A Vim plugin which shows a git diff in the 'gutter' (sign column). It shows which lines have been added, modified, or removed. You can also preview, stage, and undo individual hunks. The plugin also provides a hunk text object. + +The signs are always up to date and the plugin never saves your buffer. Features: * Shows signs for added, modified, and removed lines. -* Runs the diffs asynchronously in terminal Vim/MacVim (7.4.1826+), gVim (7.4.1850+), MacVim GUI (7.4.1832+), and NeoVim. -* Ensures signs are always as up to date as possible (but without running more than necessary). +* Runs the diffs asynchronously where possible. +* Ensures signs are always up to date. * Quick jumping between blocks of changed lines ("hunks"). * Stage/undo/preview individual hunks. * Provides a hunk text object. @@ -21,9 +23,8 @@ Features: Constraints: -* Supports git only. - -If you work with other version control systems, I recommend [vim-signify](https://github.com/mhinz/vim-signify). +* 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`. ### Screenshot @@ -39,7 +40,7 @@ In the screenshot above you can see: ### Installation -Before installation, please check your Vim supports signs by running `:echo has('signs')`. `1` means you're all set; `0` means you need to install a Vim with signs support. If you're compiling Vim yourself you need the 'big' or 'huge' feature set. [MacVim][] supports signs. +Before installation, please check your Vim supports signs by running `:echo has('signs')`. `1` means you're all set; `0` means you need to install a Vim with signs support. If you're compiling Vim yourself you need the 'big' or 'huge' feature set. MacVim supports signs. You install vim-gitgutter like any other vim plugin. @@ -100,16 +101,13 @@ cp -r vim-gitgutter/* ~/.vim/ See `:help add-global-plugin`. -If you are on Windows you may find the command prompt pops up briefly every time vim-gitgutter runs. You can avoid this by installing both [vim-misc](https://github.com/xolox/vim-misc) and [vim-shell](https://github.com/xolox/vim-shell). If you have those two plugins but don't want vim-gitgutter to use them, you can opt out with `let g:gitgutter_avoid_cmd_prompt_on_windows = 0` in your `~/.vimrc`. - - ### 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 4 seconds but I suggest reducing it to around 250ms (add `set updatetime=250` to your vimrc). +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). You can jump between hunks with `[c` and `]c`. You can preview, stage, and undo hunks with `hp`, `hs`, and `hu` respectively. -You cannot currently unstage a staged hunk. +You cannot unstage a staged hunk. #### Activation @@ -136,7 +134,7 @@ Note that if you have line highlighting on and signs off, you will have an empty 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). -To keep your Vim snappy, vim-gitgutter will suppress itself 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: +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: ```viml let g:gitgutter_max_signs = 500 " default value @@ -205,33 +203,6 @@ Finally, you can force vim-gitgutter to update its signs across all visible buff See the customisation section below for how to change the defaults. -### When are the signs updated? - -By default the signs are updated as follows: - -| Event | Reason for update | Configuration | -|---------------------------|--------------------------------------|------------------------| -| Stop typing | So the signs are real time | `g:gitgutter_realtime` | -| Switch buffer | To notice change to git index | `g:gitgutter_eager` | -| Switch tab | To notice change to git index | `g:gitgutter_eager` | -| Focus the GUI | To notice change to git index | `g:gitgutter_eager` (not gVim on Windows) | -| After shell command | To notice change to git index | `g:gitgutter_eager` | -| Read a file into a buffer | To display initial signs | [always] | -| Save a buffer | So non-realtime signs are up to date | [always] | -| Change a file outside Vim | To notice `git stash` | [always] | - -The length of time Vim waits after you stop typing before it triggers the plugin is governed by the setting `updatetime`. This defaults to `4000` milliseconds which is rather too long. I recommend around `250` milliseconds but it depends on your system and your preferences. Note that in terminal Vim pre-7.4.427 an `updatetime` of less than approximately `1000` milliseconds can lead to random highlighting glitches; the lower the `updatetime`, the more glitches. - -If you experience a lag, you can trade speed for accuracy: - -```viml -let g:gitgutter_realtime = 0 -let g:gitgutter_eager = 0 -``` - -Note the realtime updating requires Vim 7.3.105 or higher. - - ### Customisation You can customise: @@ -351,7 +322,7 @@ If you use an alternative to grep, you can tell vim-gitgutter to use it here. ```viml " Default: -let g:gitgutter_grep_command = 'grep' +let g:gitgutter_grep = 'grep' ``` #### To turn off vim-gitgutter by default @@ -490,57 +461,53 @@ nmap [c :call PrevHunkAllBuffers() ### FAQ +> How can I turn off realtime updates? + +Add this to your vim configuration (in an `/after/plugin` directory): + +```viml +" .vim/after/plugin/gitgutter.vim +autocmd! gitgutter CursorHold,CursorHoldI +``` + + > Why can't I unstage staged changes? -Unstaging staged hunks is feasible but not quite as easy as it sounds. There are three relevant versions of a file at any one time: - -1. The version at HEAD in the repo. -2. The version staged in the index. -3. The version in the working tree, in your vim buffer. - -`git-diff` without arguments shows you how 3 and 2 differ; this is what vim-gitgutter shows too. - -`git-diff --staged` shows you how 2 and 1 differ. - -Let's say you are looking at a file in vim which has some unstaged changes. Now you stage a hunk, either via vim-gitgutter or another means. The hunk is no longer marked in vim-gitgutter because it is the same in 3 and 2. - -Now you want to unstage that hunk. To see it, you need the difference between 2 and 1. For vim-gitgutter to show those differences, it would need to show you 2 instead of 3 in your vim buffer. But 2 is virtual so vim-gitgutter would need to handle it without touching 3. - -I intend to implement this but I can't commit to any deadline. +This plugin is for showing changes between the working tree and the index (and staging/undoing those changes). Unstaging a staged hunk would require showing changes between the index and HEAD, which is out of scope. > Why are the colours in the sign column weird? Your colorscheme is configuring the `SignColumn` highlight group weirdly. Please see the section above on customising the sign column. -> There's a noticeable lag when vim-gitter runs; how can I avoid it? - -By default vim-gitgutter runs often so the signs are as accurate as possible. The delay is governed by `updatetime`; see [above](#when-are-the-signs-updated) for more information. - -If you don't want realtime updates and would like to trade a little accuracy for speed, add this to your `~/.vimrc`: - -```viml -let g:gitgutter_realtime = 0 -let g:gitgutter_eager = 0 -``` - > 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. -> Why aren't any signs showing at all? + +### Troubleshooting + +#### When no signs are showing at all Here are some things you can check: -* `:echo system("git --version")` succeeds. -* Your git config is compatible with the version of git returned by the command above. -* Your Vim supports signs (`:echo has('signs')` should give `1`). -* Your file is being tracked by git and has unstaged changes. -* If you have aliased or configured `grep` to use any flags, add `let g:gitgutter_grep_command = 'grep'` to your `~/.vimrc`. +* Try adding `let g:gitgutter_grep=''` to your vimrc. If it works, the problem is grep producing non-plain output; e.g. ANSI escape codes or colours. +* Verify `:echo system("git --version")` succeeds. +* Verify your git config is compatible with the version of git returned by the command above. +* Verify your Vim supports signs (`:echo has('signs')` should give `1`). +* Verify your file is being tracked by git and has unstaged changes. -> Why is the whole file marked as added when I edit it? +#### When the whole file is marked as added * If you use zsh, and you set `CDPATH`, make sure `CDPATH` doesn't include the current directory. +#### When signs take a few seconds to appear + +* Try reducing `updatetime`, e.g. `set updatetime=100`. + +#### 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`. + ### Shameless Plug @@ -561,4 +528,4 @@ Copyright Andrew Stewart, AirBlade Software Ltd. Released under the MIT licence [pathogen]: https://github.com/tpope/vim-pathogen [siv]: http://pluralsight.com/training/Courses/TableOfContents/smash-into-vim [airblade]: http://airbladesoftware.com/peepcode-vim - [macvim]: http://code.google.com/p/macvim/ + [terminus]: https://github.com/wincent/terminus diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim index 6e8ca57d..d095cd74 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter.vim @@ -1,67 +1,54 @@ -let s:nomodeline = (v:version > 703 || (v:version == 703 && has('patch442'))) ? '' : '' +let s:t_string = type('') " Primary functions {{{ -function! gitgutter#all() abort - for buffer_id in gitgutter#utility#dedup(tabpagebuflist()) - let file = expand('#' . buffer_id . ':p') +function! gitgutter#all(force) abort + for bufnr in s:uniq(tabpagebuflist()) + let file = expand('#'.bufnr.':p') if !empty(file) - call gitgutter#process_buffer(buffer_id, 0) + call gitgutter#init_buffer(bufnr) + call gitgutter#process_buffer(bufnr, a:force) endif endfor endfunction -" bufnr: (integer) the buffer to process. -" realtime: (boolean) when truthy, do a realtime diff; otherwise do a disk-based diff. -function! gitgutter#process_buffer(bufnr, realtime) abort - call gitgutter#utility#use_known_shell() - call gitgutter#utility#set_buffer(a:bufnr) - if gitgutter#utility#is_active() - if g:gitgutter_sign_column_always - call gitgutter#sign#add_dummy_sign() +" 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) endif - try - if !a:realtime || gitgutter#utility#has_fresh_changes() - let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(), 0) - if diff != 'async' - call gitgutter#handle_diff(diff) - 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 a:force || s:has_fresh_changes(a:bufnr) + + let diff = '' + try + let diff = gitgutter#diff#run_diff(a:bufnr, 0) + catch /gitgutter not tracked/ + call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr)) + catch /gitgutter diff failed/ + call gitgutter#debug#log('Diff failed: '.gitgutter#utility#file(a:bufnr)) + call gitgutter#hunk#reset(a:bufnr) + endtry + + if diff != 'async' + call gitgutter#diff#handler(a:bufnr, diff) endif - catch /diff failed/ - call gitgutter#debug#log('diff failed') - call gitgutter#hunk#reset() - endtry - execute "silent doautocmd" s:nomodeline "User GitGutter" - else - call gitgutter#hunk#reset() - endif - call gitgutter#utility#restore_shell() + endif + endif endfunction -function! gitgutter#handle_diff(diff) abort - call gitgutter#debug#log(a:diff) - - call gitgutter#utility#setbufvar(gitgutter#utility#bufnr(), 'tracked', 1) - - call gitgutter#hunk#set_hunks(gitgutter#diff#parse_diff(a:diff)) - let modified_lines = gitgutter#diff#process_hunks(gitgutter#hunk#hunks()) - - if len(modified_lines) > g:gitgutter_max_signs - call gitgutter#utility#warn_once('exceeded maximum number of signs (configured by g:gitgutter_max_signs).', 'max_signs') - call gitgutter#sign#clear_signs() - return - endif - - if g:gitgutter_signs || g:gitgutter_highlight_lines - call gitgutter#sign#update_signs(modified_lines) - endif - - call gitgutter#utility#save_last_seen_change() -endfunction - function! gitgutter#disable() abort " get list of all buffers (across all tabs) let buflist = [] @@ -69,13 +56,10 @@ function! gitgutter#disable() abort call extend(buflist, tabpagebuflist(i + 1)) endfor - for buffer_id in gitgutter#utility#dedup(buflist) - let file = expand('#' . buffer_id . ':p') + for bufnr in s:uniq(buflist) + let file = expand('#'.bufnr.':p') if !empty(file) - call gitgutter#utility#set_buffer(buffer_id) - call gitgutter#sign#clear_signs() - call gitgutter#sign#remove_dummy_sign(1) - call gitgutter#hunk#reset() + call s:clear(bufnr) endif endfor @@ -84,7 +68,7 @@ endfunction function! gitgutter#enable() abort let g:gitgutter_enabled = 1 - call gitgutter#all() + call gitgutter#all(1) endfunction function! gitgutter#toggle() abort @@ -97,163 +81,33 @@ endfunction " }}} -" Line highlights {{{ - -function! gitgutter#line_highlights_disable() abort - let g:gitgutter_highlight_lines = 0 - call gitgutter#highlight#define_sign_line_highlights() - - if !g:gitgutter_signs - call gitgutter#sign#clear_signs() - call gitgutter#sign#remove_dummy_sign(0) - endif - - redraw! +function! s:has_fresh_changes(bufnr) abort + return getbufvar(a:bufnr, 'changedtick') != gitgutter#utility#getbufvar(a:bufnr, 'tick') endfunction -function! gitgutter#line_highlights_enable() abort - let old_highlight_lines = g:gitgutter_highlight_lines - - let g:gitgutter_highlight_lines = 1 - call gitgutter#highlight#define_sign_line_highlights() - - if !old_highlight_lines && !g:gitgutter_signs - call gitgutter#all() - endif - - redraw! +function! s:reset_tick(bufnr) abort + call gitgutter#utility#setbufvar(a:bufnr, 'tick', 0) endfunction -function! gitgutter#line_highlights_toggle() abort - if g:gitgutter_highlight_lines - call gitgutter#line_highlights_disable() - else - call gitgutter#line_highlights_enable() - endif +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) endfunction -" }}} - -" Signs {{{ - -function! gitgutter#signs_enable() abort - let old_signs = g:gitgutter_signs - - let g:gitgutter_signs = 1 - call gitgutter#highlight#define_sign_text_highlights() - - if !old_signs && !g:gitgutter_highlight_lines - call gitgutter#all() - endif -endfunction - -function! gitgutter#signs_disable() abort - let g:gitgutter_signs = 0 - call gitgutter#highlight#define_sign_text_highlights() - - if !g:gitgutter_highlight_lines - call gitgutter#sign#clear_signs() - call gitgutter#sign#remove_dummy_sign(0) - endif -endfunction - -function! gitgutter#signs_toggle() abort - if g:gitgutter_signs - call gitgutter#signs_disable() - else - call gitgutter#signs_enable() - endif -endfunction - -" }}} - -" Hunks {{{ - -function! gitgutter#stage_hunk() abort - call gitgutter#utility#use_known_shell() - if gitgutter#utility#is_active() - " Ensure the working copy of the file is up to date. - " It doesn't make sense to stage a hunk otherwise. - noautocmd silent write - let diff = gitgutter#diff#run_diff(0, 1) - call gitgutter#handle_diff(diff) - - if empty(gitgutter#hunk#current_hunk()) - call gitgutter#utility#warn('cursor is not in a hunk') - else - let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(diff, 'stage') - call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file(g:gitgutter_git_executable.' apply --cached --unidiff-zero - '), diff_for_hunk) - - " refresh gitgutter's view of buffer - silent execute "GitGutter" - endif - - silent! call repeat#set("\GitGutterStageHunk", -1) - endif - call gitgutter#utility#restore_shell() -endfunction - -function! gitgutter#undo_hunk() abort - call gitgutter#utility#use_known_shell() - if gitgutter#utility#is_active() - " Ensure the working copy of the file is up to date. - " It doesn't make sense to stage a hunk otherwise. - noautocmd silent write - let diff = gitgutter#diff#run_diff(0, 1) - call gitgutter#handle_diff(diff) - - if empty(gitgutter#hunk#current_hunk()) - call gitgutter#utility#warn('cursor is not in a hunk') - else - let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(diff, 'undo') - call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file(g:gitgutter_git_executable.' apply --reverse --unidiff-zero - '), diff_for_hunk) - - " reload file preserving screen line position - " CTRL-Y and CTRL-E treat negative counts as positive counts. - let x = line('w0') - silent edit - let y = line('w0') - let z = x - y - if z > 0 - execute "normal! ".z."\" - else - execute "normal! ".z."\" +if exists('*uniq') " Vim 7.4.218 + function! s:uniq(list) + return uniq(sort(a:list)) + endfunction +else + function! s:uniq(list) + let processed = [] + for e in a:list + if index(processed, e) == -1 + call add(processed, e) endif - endif - - silent! call repeat#set("\GitGutterUndoHunk", -1) - endif - call gitgutter#utility#restore_shell() -endfunction - -function! gitgutter#preview_hunk() abort - call gitgutter#utility#use_known_shell() - if gitgutter#utility#is_active() - " Ensure the working copy of the file is up to date. - " It doesn't make sense to stage a hunk otherwise. - noautocmd silent write - let diff = gitgutter#diff#run_diff(0, 1) - call gitgutter#handle_diff(diff) - - if empty(gitgutter#hunk#current_hunk()) - call gitgutter#utility#warn('cursor is not in a hunk') - else - let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(diff, 'preview') - - silent! wincmd P - if !&previewwindow - noautocmd execute 'bo' &previewheight 'new' - set previewwindow - endif - - setlocal noro modifiable filetype=diff buftype=nofile bufhidden=delete noswapfile - execute "%delete_" - call append(0, split(diff_for_hunk, "\n")) - - noautocmd wincmd p - endif - endif - call gitgutter#utility#restore_shell() -endfunction - -" }}} + endfor + return processed + endfunction +endif diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/async.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/async.vim index 070e00f8..7413930d 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/async.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/async.vim @@ -11,10 +11,13 @@ function! gitgutter#async#available() endfunction -function! gitgutter#async#execute(cmd) abort +function! gitgutter#async#execute(cmd, bufnr, handler) abort + call gitgutter#debug#log('[async] '.a:cmd) + let options = { \ 'stdoutbuffer': [], - \ 'buffer': gitgutter#utility#bufnr() + \ 'buffer': a:bufnr, + \ 'handler': a:handler \ } let command = s:build_command(a:cmd) @@ -58,33 +61,13 @@ function! s:on_stdout_nvim(_job_id, data, _event) dict abort endfunction function! s:on_stderr_nvim(_job_id, _data, _event) dict abort - " Backward compatibility for nvim < 0.2.0 - if !has('nvim-0.2.0') - let current_buffer = gitgutter#utility#bufnr() - call gitgutter#utility#set_buffer(self.buffer) - if gitgutter#utility#is_active() - call gitgutter#hunk#reset() - endif - call gitgutter#utility#set_buffer(current_buffer) - return - endif - - call s:buffer_exec(self.buffer, function('gitgutter#hunk#reset')) + call self.handler.err(self.buffer) endfunction -function! s:on_exit_nvim(_job_id, _data, _event) dict abort - " Backward compatibility for nvim < 0.2.0 - if !has('nvim-0.2.0') - let current_buffer = gitgutter#utility#bufnr() - call gitgutter#utility#set_buffer(self.buffer) - if gitgutter#utility#is_active() - call gitgutter#handle_diff(gitgutter#utility#stringify(self.stdoutbuffer)) - endif - call gitgutter#utility#set_buffer(current_buffer) - return +function! s:on_exit_nvim(_job_id, exit_code, _event) dict abort + if !a:exit_code + call self.handler.out(self.buffer, join(self.stdoutbuffer, "\n")) endif - - call s:buffer_exec(self.buffer, function('gitgutter#handle_diff', [gitgutter#utility#stringify(self.stdoutbuffer)])) endfunction @@ -92,22 +75,15 @@ function! s:on_stdout_vim(_channel, data) dict abort call add(self.stdoutbuffer, a:data) endfunction -function! s:on_stderr_vim(_channel, _data) dict abort - call s:buffer_exec(self.buffer, function('gitgutter#hunk#reset')) +function! s:on_stderr_vim(channel, _data) dict abort + call self.handler.err(self.buffer) + try + call ch_close(a:channel) " so close_cb and its 'out' handler are not triggered + catch /E906/ + " noop + endtry endfunction function! s:on_exit_vim(_channel) dict abort - call s:buffer_exec(self.buffer, function('gitgutter#handle_diff', [gitgutter#utility#stringify(self.stdoutbuffer)])) -endfunction - - -function! s:buffer_exec(buffer, fn) - let current_buffer = gitgutter#utility#bufnr() - call gitgutter#utility#set_buffer(a:buffer) - - if gitgutter#utility#is_active() - call a:fn() - endif - - call gitgutter#utility#set_buffer(current_buffer) + call self.handler.out(self.buffer, join(self.stdoutbuffer, "\n")) endfunction diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/debug.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/debug.vim index 594f044b..79d197ec 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/debug.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/debug.vim @@ -12,67 +12,67 @@ function! gitgutter#debug#debug() setlocal bufhidden=delete setlocal noswapfile - call gitgutter#debug#vim_version() - call gitgutter#debug#separator() + call s:vim_version() + call s:separator() - call gitgutter#debug#git_version() - call gitgutter#debug#separator() + call s:git_version() + call s:separator() - call gitgutter#debug#grep_version() - call gitgutter#debug#separator() + call s:grep_version() + call s:separator() - call gitgutter#debug#option('updatetime') - call gitgutter#debug#option('shell') - call gitgutter#debug#option('shellcmdflag') - call gitgutter#debug#option('shellpipe') - call gitgutter#debug#option('shellquote') - call gitgutter#debug#option('shellredir') - call gitgutter#debug#option('shellslash') - call gitgutter#debug#option('shelltemp') - call gitgutter#debug#option('shelltype') - call gitgutter#debug#option('shellxescape') - call gitgutter#debug#option('shellxquote') + call s:option('updatetime') + call s:option('shell') + call s:option('shellcmdflag') + call s:option('shellpipe') + call s:option('shellquote') + call s:option('shellredir') + call s:option('shellslash') + call s:option('shelltemp') + call s:option('shelltype') + call s:option('shellxescape') + call s:option('shellxquote') endfunction -function! gitgutter#debug#separator() - call gitgutter#debug#output('') +function! s:separator() + call s:output('') endfunction -function! gitgutter#debug#vim_version() +function! s:vim_version() redir => version_info silent execute 'version' redir END - call gitgutter#debug#output(split(version_info, '\n')[0:2]) + call s:output(split(version_info, '\n')[0:2]) endfunction -function! gitgutter#debug#git_version() +function! s:git_version() let v = system(g:gitgutter_git_executable.' --version') - call gitgutter#debug#output( substitute(v, '\n$', '', '') ) + call s:output( substitute(v, '\n$', '', '') ) endfunction -function! gitgutter#debug#grep_version() +function! s:grep_version() let v = system('grep --version') - call gitgutter#debug#output( substitute(v, '\n$', '', '') ) + call s:output( substitute(v, '\n$', '', '') ) let v = system('grep --help') - call gitgutter#debug#output( substitute(v, '\%x00', '', 'g') ) + call s:output( substitute(v, '\%x00', '', 'g') ) endfunction -function! gitgutter#debug#option(name) +function! s:option(name) if exists('+' . a:name) let v = eval('&' . a:name) - call gitgutter#debug#output(a:name . '=' . v) + call s:output(a:name . '=' . v) " redir => output " silent execute "verbose set " . a:name . "?" " redir END - " call gitgutter#debug#output(a:name . '=' . output) + " call s:output(a:name . '=' . output) else - call gitgutter#debug#output(a:name . ' [n/a]') + call s:output(a:name . ' [n/a]') end endfunction -function! gitgutter#debug#output(text) +function! s:output(text) call append(line('$'), a:text) endfunction diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim index 7ecb8afd..d9f44199 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/diff.vim @@ -1,152 +1,176 @@ -if exists('g:gitgutter_grep_command') - let s:grep_available = 1 - let s:grep_command = g:gitgutter_grep_command -else - let s:grep_available = executable('grep') - if s:grep_available - let s:grep_command = 'grep' - if $GREP_OPTIONS =~# '--color=always' - let s:grep_command .= ' --color=never' - endif - endif -endif +let s:nomodeline = (v:version > 703 || (v:version == 703 && has('patch442'))) ? '' : '' + let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@' -let s:c_flag = gitgutter#utility#git_supports_command_line_config_override() +" 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') + return !v:shell_error +endfunction + +let s:c_flag = s:git_supports_command_line_config_override() + let s:temp_index = tempname() let s:temp_buffer = tempname() " Returns a diff of the buffer. " -" The way to get the diff depends on whether the buffer is saved or unsaved. +" The buffer contents is not the same as the file on disk so we need to pass +" two instances of the file to git-diff: " -" * Saved: the buffer contents is the same as the file on disk in the working -" tree so we simply do: +" git diff myfileA myfileB " -" git diff myfile +" where myfileA comes from " -" * Unsaved: the buffer contents is not the same as the file on disk so we -" need to pass two instances of the file to git-diff: +" git show :myfile > myfileA " -" git diff myfileA myfileB -" -" The first instance is the file in the index which we obtain with: -" -" git show :myfile > myfileA -" -" The second instance is the buffer contents. Ideally we would pass this to -" git-diff on stdin via the second argument to vim's system() function. -" Unfortunately git-diff does not do CRLF conversion for input received on -" stdin, and git-show never performs CRLF conversion, so repos with CRLF -" conversion report that every line is modified due to mismatching EOLs. -" -" Instead, we write the buffer contents to a temporary file - myfileB in this -" example. Note the file extension must be preserved for the CRLF -" conversion to work. -" -" Before diffing a buffer for the first time, we check whether git knows about -" the file: -" -" git ls-files --error-unmatch myfile +" and myfileB is the buffer contents. " " After running the diff we pass it through grep where available to reduce " subsequent processing by the plugin. If grep is not available the plugin " does the filtering instead. -function! gitgutter#diff#run_diff(realtime, preserve_full_diff) abort +" +" +" Regarding line endings: +" +" git-show does not convert line endings. +" git-diff FILE FILE does convert line endings for the given files. +" +" If a file has CRLF line endings and git's core.autocrlf is true, +" the file in git's object store will have LF line endings. Writing +" it out via git-show will produce a file with LF line endings. +" +" If this last file is one of the files passed to git-diff, git-diff will +" convert its line endings to CRLF before diffing -- which is what we want -- +" but also by default output a warning on stderr. +" +" warning: LF will be replace by CRLF in . +" The file will have its original line endings in your working directory. +" +" When running the diff asynchronously, the warning message triggers the stderr +" callbacks which assume the overall command has failed and reset all the +" signs. As this is not what we want, and we can safely ignore the warning, +" we turn it off by passing the '-c "core.safecrlf=false"' argument to +" git-diff. +" +" When writing the temporary files we preserve the original file's extension +" so that repos using .gitattributes to control EOL conversion continue to +" convert correctly. +function! gitgutter#diff#run_diff(bufnr, preserve_full_diff) abort + while gitgutter#utility#repo_path(a:bufnr, 0) == -1 + sleep 5m + endwhile + + if gitgutter#utility#repo_path(a:bufnr, 0) == -2 + throw 'gitgutter not tracked' + endif + + " Wrap compound commands in parentheses to make Windows happy. " bash doesn't mind the parentheses. let cmd = '(' - let bufnr = gitgutter#utility#bufnr() - let tracked = gitgutter#utility#getbufvar(bufnr, 'tracked', 0) " i.e. tracked by git - if !tracked - " Don't bother trying to realtime-diff an untracked file. - " NOTE: perhaps we should pull this guard up to the caller? - if a:realtime - throw 'diff failed' - else - let cmd .= g:gitgutter_git_executable.' ls-files --error-unmatch '.gitgutter#utility#shellescape(gitgutter#utility#filename()).' && (' - endif + " Append buffer number to avoid race conditions between writing and reading + " the files when asynchronously processing multiple buffers. + " + " Without the buffer number, index_file would have a race in the shell + " between the second process writing it (with git-show) and the first + " reading it (with git-diff). + let index_file = s:temp_index.'.'.a:bufnr + + " Without the buffer number, buff_file would have a race between the + " second gitgutter#process_buffer() writing the file (synchronously, below) + " and the first gitgutter#process_buffer()'s async job reading it (with + " git-diff). + let buff_file = s:temp_buffer.'.'.a:bufnr + + let extension = gitgutter#utility#extension(a:bufnr) + if !empty(extension) + let index_file .= '.'.extension + let buff_file .= '.'.extension endif - if a:realtime - let blob_name = g:gitgutter_diff_base.':'.gitgutter#utility#shellescape(gitgutter#utility#file_relative_to_repo_root()) - let blob_file = s:temp_index - let buff_file = s:temp_buffer - let extension = gitgutter#utility#extension() - if !empty(extension) - let blob_file .= '.'.extension - let buff_file .= '.'.extension - endif - let cmd .= g:gitgutter_git_executable.' show '.blob_name.' > '.blob_file.' && ' + " Write file from index to temporary file. + let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1) + let cmd .= g:gitgutter_git_executable.' --no-pager show '.index_name.' > '.index_file.' && ' - " Writing the whole buffer resets the '[ and '] marks and also the - " 'modified' flag (if &cpoptions includes '+'). These are unwanted - " side-effects so we save and restore the values ourselves. - let modified = getbufvar(bufnr, "&mod") - let op_mark_start = getpos("'[") - let op_mark_end = getpos("']") + " Write buffer to temporary file. + " Note: this is synchronous. + call s:write_buffer(a:bufnr, buff_file) - let current_buffer = bufnr('') - execute 'buffer '.bufnr - execute 'keepalt noautocmd silent write!' buff_file - execute 'buffer '.current_buffer - - call setbufvar(bufnr, "&mod", modified) - call setpos("'[", op_mark_start) - call setpos("']", op_mark_end) - endif - - let cmd .= g:gitgutter_git_executable + " Call git-diff with the temporary files. + let cmd .= g:gitgutter_git_executable.' --no-pager' if s:c_flag let cmd .= ' -c "diff.autorefreshindex=0"' let cmd .= ' -c "diff.noprefix=false"' + let cmd .= ' -c "core.safecrlf=false"' endif - let cmd .= ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args.' ' + let cmd .= ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args.' -- '.index_file.' '.buff_file - if a:realtime - let cmd .= ' -- '.blob_file.' '.buff_file - else - let cmd .= g:gitgutter_diff_base.' -- '.gitgutter#utility#shellescape(gitgutter#utility#filename()) + " Pipe git-diff output into grep. + if !a:preserve_full_diff && !empty(g:gitgutter_grep) + let cmd .= ' | '.g:gitgutter_grep.' '.gitgutter#utility#shellescape('^@@ ') endif - if !a:preserve_full_diff && s:grep_available - let cmd .= ' | '.s:grep_command.' '.gitgutter#utility#shellescape('^@@ ') - endif - - if (!a:preserve_full_diff && s:grep_available) || a:realtime - " grep exits with 1 when no matches are found; diff exits with 1 when - " differences are found. However we want to treat non-matches and - " differences as non-erroneous behaviour; so we OR the command with one - " which always exits with success (0). - let cmd .= ' || exit 0' - endif + " grep exits with 1 when no matches are found; git-diff exits with 1 when + " differences are found. However we want to treat non-matches and + " differences as non-erroneous behaviour; so we OR the command with one + " which always exits with success (0). + let cmd .= ' || exit 0' let cmd .= ')' - if !tracked - let cmd .= ')' - endif + let cmd = gitgutter#utility#cd_cmd(a:bufnr, cmd) - let cmd = gitgutter#utility#command_in_directory_of_file(cmd) - - if g:gitgutter_async && gitgutter#async#available() && !a:preserve_full_diff - call gitgutter#async#execute(cmd) + if g:gitgutter_async && gitgutter#async#available() + call gitgutter#async#execute(cmd, a:bufnr, { + \ 'out': function('gitgutter#diff#handler'), + \ 'err': function('gitgutter#hunk#reset'), + \ }) return 'async' else let diff = gitgutter#utility#system(cmd) - if gitgutter#utility#shell_error() - " A shell error indicates the file is not tracked by git (unless something bizarre is going on). - throw 'diff failed' + if v:shell_error + call gitgutter#debug#log(diff) + throw 'gitgutter diff failed' endif return diff endif endfunction + +function! gitgutter#diff#handler(bufnr, diff) abort + call gitgutter#debug#log(a:diff) + + call gitgutter#hunk#set_hunks(a:bufnr, gitgutter#diff#parse_diff(a:diff)) + let modified_lines = gitgutter#diff#process_hunks(a:bufnr, gitgutter#hunk#hunks(a:bufnr)) + + let signs_count = len(modified_lines) + if signs_count > g:gitgutter_max_signs + call gitgutter#utility#warn_once(a:bufnr, printf( + \ 'exceeded maximum number of signs (%d > %d, configured by g:gitgutter_max_signs).', + \ signs_count, g:gitgutter_max_signs), 'max_signs') + call gitgutter#sign#clear_signs(a:bufnr) + + else + if g:gitgutter_signs || g:gitgutter_highlight_lines + call gitgutter#sign#update_signs(a:bufnr, modified_lines) + endif + endif + + call s:save_last_seen_change(a:bufnr) + if exists('#User#GitGutter') + let g:gitgutter_hook_context = {'bufnr': a:bufnr} + execute 'doautocmd' s:nomodeline 'User GitGutter' + unlet g:gitgutter_hook_context + endif +endfunction + + function! gitgutter#diff#parse_diff(diff) abort let hunks = [] for line in split(a:diff, '\n') @@ -171,69 +195,71 @@ function! gitgutter#diff#parse_hunk(line) abort end endfunction -function! gitgutter#diff#process_hunks(hunks) abort +" This function is public so it may be used by other plugins +" e.g. vim-signature. +function! gitgutter#diff#process_hunks(bufnr, hunks) abort let modified_lines = [] for hunk in a:hunks - call extend(modified_lines, gitgutter#diff#process_hunk(hunk)) + call extend(modified_lines, s:process_hunk(a:bufnr, hunk)) endfor return modified_lines endfunction " Returns [ [, ], ...] -function! gitgutter#diff#process_hunk(hunk) abort +function! s:process_hunk(bufnr, hunk) abort let modifications = [] let from_line = a:hunk[0] let from_count = a:hunk[1] let to_line = a:hunk[2] let to_count = a:hunk[3] - if gitgutter#diff#is_added(from_count, to_count) - call gitgutter#diff#process_added(modifications, from_count, to_count, to_line) - call gitgutter#hunk#increment_lines_added(to_count) + if s:is_added(from_count, to_count) + call s:process_added(modifications, from_count, to_count, to_line) + call gitgutter#hunk#increment_lines_added(a:bufnr, to_count) - elseif gitgutter#diff#is_removed(from_count, to_count) - call gitgutter#diff#process_removed(modifications, from_count, to_count, to_line) - call gitgutter#hunk#increment_lines_removed(from_count) + elseif s:is_removed(from_count, to_count) + call s:process_removed(modifications, from_count, to_count, to_line) + call gitgutter#hunk#increment_lines_removed(a:bufnr, from_count) - elseif gitgutter#diff#is_modified(from_count, to_count) - call gitgutter#diff#process_modified(modifications, from_count, to_count, to_line) - call gitgutter#hunk#increment_lines_modified(to_count) + elseif s:is_modified(from_count, to_count) + call s:process_modified(modifications, from_count, to_count, to_line) + call gitgutter#hunk#increment_lines_modified(a:bufnr, to_count) - elseif gitgutter#diff#is_modified_and_added(from_count, to_count) - call gitgutter#diff#process_modified_and_added(modifications, from_count, to_count, to_line) - call gitgutter#hunk#increment_lines_added(to_count - from_count) - call gitgutter#hunk#increment_lines_modified(from_count) + elseif s:is_modified_and_added(from_count, to_count) + call s:process_modified_and_added(modifications, from_count, to_count, to_line) + call gitgutter#hunk#increment_lines_added(a:bufnr, to_count - from_count) + call gitgutter#hunk#increment_lines_modified(a:bufnr, from_count) - elseif gitgutter#diff#is_modified_and_removed(from_count, to_count) - call gitgutter#diff#process_modified_and_removed(modifications, from_count, to_count, to_line) - call gitgutter#hunk#increment_lines_modified(to_count) - call gitgutter#hunk#increment_lines_removed(from_count - to_count) + elseif s:is_modified_and_removed(from_count, to_count) + call s:process_modified_and_removed(modifications, from_count, to_count, to_line) + call gitgutter#hunk#increment_lines_modified(a:bufnr, to_count) + call gitgutter#hunk#increment_lines_removed(a:bufnr, from_count - to_count) endif return modifications endfunction -function! gitgutter#diff#is_added(from_count, to_count) abort +function! s:is_added(from_count, to_count) abort return a:from_count == 0 && a:to_count > 0 endfunction -function! gitgutter#diff#is_removed(from_count, to_count) abort +function! s:is_removed(from_count, to_count) abort return a:from_count > 0 && a:to_count == 0 endfunction -function! gitgutter#diff#is_modified(from_count, to_count) abort +function! s:is_modified(from_count, to_count) abort return a:from_count > 0 && a:to_count > 0 && a:from_count == a:to_count endfunction -function! gitgutter#diff#is_modified_and_added(from_count, to_count) abort +function! s:is_modified_and_added(from_count, to_count) abort return a:from_count > 0 && a:to_count > 0 && a:from_count < a:to_count endfunction -function! gitgutter#diff#is_modified_and_removed(from_count, to_count) abort +function! s:is_modified_and_removed(from_count, to_count) abort return a:from_count > 0 && a:to_count > 0 && a:from_count > a:to_count endfunction -function! gitgutter#diff#process_added(modifications, from_count, to_count, to_line) abort +function! s:process_added(modifications, from_count, to_count, to_line) abort let offset = 0 while offset < a:to_count let line_number = a:to_line + offset @@ -242,7 +268,7 @@ function! gitgutter#diff#process_added(modifications, from_count, to_count, to_l endwhile endfunction -function! gitgutter#diff#process_removed(modifications, from_count, to_count, to_line) abort +function! s:process_removed(modifications, from_count, to_count, to_line) abort if a:to_line == 0 call add(a:modifications, [1, 'removed_first_line']) else @@ -250,7 +276,7 @@ function! gitgutter#diff#process_removed(modifications, from_count, to_count, to endif endfunction -function! gitgutter#diff#process_modified(modifications, from_count, to_count, to_line) abort +function! s:process_modified(modifications, from_count, to_count, to_line) abort let offset = 0 while offset < a:to_count let line_number = a:to_line + offset @@ -259,7 +285,7 @@ function! gitgutter#diff#process_modified(modifications, from_count, to_count, t endwhile endfunction -function! gitgutter#diff#process_modified_and_added(modifications, from_count, to_count, to_line) abort +function! s:process_modified_and_added(modifications, from_count, to_count, to_line) abort let offset = 0 while offset < a:from_count let line_number = a:to_line + offset @@ -273,7 +299,7 @@ function! gitgutter#diff#process_modified_and_added(modifications, from_count, t endwhile endfunction -function! gitgutter#diff#process_modified_and_removed(modifications, from_count, to_count, to_line) abort +function! s:process_modified_and_removed(modifications, from_count, to_count, to_line) abort let offset = 0 while offset < a:to_count let line_number = a:to_line + offset @@ -283,28 +309,14 @@ function! gitgutter#diff#process_modified_and_removed(modifications, from_count, let a:modifications[-1] = [a:to_line + offset - 1, 'modified_removed'] endfunction -" Generates a zero-context diff for the current hunk. -" -" diff - the full diff for the buffer -" type - stage | undo | preview -function! gitgutter#diff#generate_diff_for_hunk(diff, type) abort - let diff_for_hunk = gitgutter#diff#discard_hunks(a:diff, a:type == 'stage' || a:type == 'undo') - if a:type == 'stage' || a:type == 'undo' - let diff_for_hunk = gitgutter#diff#adjust_hunk_summary(diff_for_hunk, a:type == 'stage') - endif - - return diff_for_hunk -endfunction - -" Returns the diff with all hunks discarded except the current. -" -" diff - the diff to process -" keep_header - truthy to keep the diff header and hunk summary, falsy to discard it -function! gitgutter#diff#discard_hunks(diff, keep_header) abort +" Returns a diff for the current hunk. +function! gitgutter#diff#hunk_diff(bufnr, full_diff) let modified_diff = [] - let keep_line = a:keep_header - for line in split(a:diff, '\n') + let keep_line = 1 + " Don't keepempty when splitting because the diff we want may not be the + " final one. Instead add trailing NL at end of function. + for line in split(a:full_diff, '\n') let hunk_info = gitgutter#diff#parse_hunk(line) if len(hunk_info) == 4 " start of new hunk let keep_line = gitgutter#hunk#cursor_in_hunk(hunk_info) @@ -313,36 +325,32 @@ function! gitgutter#diff#discard_hunks(diff, keep_header) abort call add(modified_diff, line) endif endfor + return join(modified_diff, "\n")."\n" +endfunction - if a:keep_header - return gitgutter#utility#stringify(modified_diff) - else - " Discard hunk summary too. - return gitgutter#utility#stringify(modified_diff[1:]) + +function! s:write_buffer(bufnr, file) + let bufcontents = getbufline(a:bufnr, 1, '$') + + if getbufvar(a:bufnr, '&fileformat') ==# 'dos' + call map(bufcontents, 'v:val."\r"') endif + + let fenc = getbufvar(a:bufnr, '&fileencoding') + if fenc !=# &encoding + call map(bufcontents, 'iconv(v:val, &encoding, "'.fenc.'")') + endif + + if getbufvar(a:bufnr, '&bomb') + let bufcontents[0]=''.bufcontents[0] + endif + + call writefile(bufcontents, a:file) endfunction -" Adjust hunk summary (from's / to's line number) to ignore changes above/before this one. -" -" diff_for_hunk - a diff containing only the hunk of interest -" staging - truthy if the hunk is to be staged, falsy if it is to be undone -" -" TODO: push this down to #discard_hunks? -function! gitgutter#diff#adjust_hunk_summary(diff_for_hunk, staging) abort - let line_adjustment = gitgutter#hunk#line_adjustment_for_current_hunk() - let adj_diff = [] - for line in split(a:diff_for_hunk, '\n') - if match(line, s:hunk_re) != -1 - if a:staging - " increment 'to' line number - let line = substitute(line, '+\@<=\(\d\+\)', '\=submatch(1)+line_adjustment', '') - else - " decrement 'from' line number - let line = substitute(line, '-\@<=\(\d\+\)', '\=submatch(1)-line_adjustment', '') - endif - endif - call add(adj_diff, line) - endfor - return gitgutter#utility#stringify(adj_diff) + +function! s:save_last_seen_change(bufnr) abort + call gitgutter#utility#setbufvar(a:bufnr, 'tick', getbufvar(a:bufnr, 'changedtick')) endfunction + diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim index 61b0f307..3fa4a91b 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/highlight.vim @@ -1,3 +1,37 @@ +function! gitgutter#highlight#line_disable() abort + let g:gitgutter_highlight_lines = 0 + call s:define_sign_line_highlights() + + if !g:gitgutter_signs + call gitgutter#sign#clear_signs(bufnr('')) + call gitgutter#sign#remove_dummy_sign(bufnr(''), 0) + endif + + redraw! +endfunction + +function! gitgutter#highlight#line_enable() abort + let old_highlight_lines = g:gitgutter_highlight_lines + + let g:gitgutter_highlight_lines = 1 + call s:define_sign_line_highlights() + + if !old_highlight_lines && !g:gitgutter_signs + call gitgutter#all(1) + endif + + redraw! +endfunction + +function! gitgutter#highlight#line_toggle() abort + if g:gitgutter_highlight_lines + call gitgutter#highlight#line_disable() + else + call gitgutter#highlight#line_enable() + endif +endfunction + + function! gitgutter#highlight#define_sign_column_highlight() abort if g:gitgutter_override_sign_column_highlight highlight! link SignColumn LineNr @@ -7,7 +41,7 @@ function! gitgutter#highlight#define_sign_column_highlight() abort endfunction function! gitgutter#highlight#define_highlights() abort - let [guibg, ctermbg] = gitgutter#highlight#get_background_colors('SignColumn') + let [guibg, ctermbg] = s:get_background_colors('SignColumn') " Highlights used by the signs. @@ -42,12 +76,12 @@ function! gitgutter#highlight#define_signs() abort sign define GitGutterLineModifiedRemoved sign define GitGutterDummy - call gitgutter#highlight#define_sign_text() + call s:define_sign_text() call gitgutter#highlight#define_sign_text_highlights() - call gitgutter#highlight#define_sign_line_highlights() + call s:define_sign_line_highlights() endfunction -function! gitgutter#highlight#define_sign_text() abort +function! s:define_sign_text() abort execute "sign define GitGutterLineAdded text=" . g:gitgutter_sign_added execute "sign define GitGutterLineModified text=" . g:gitgutter_sign_modified execute "sign define GitGutterLineRemoved text=" . g:gitgutter_sign_removed @@ -75,7 +109,7 @@ function! gitgutter#highlight#define_sign_text_highlights() abort endif endfunction -function! gitgutter#highlight#define_sign_line_highlights() abort +function! s:define_sign_line_highlights() abort if g:gitgutter_highlight_lines sign define GitGutterLineAdded linehl=GitGutterAddLine sign define GitGutterLineModified linehl=GitGutterChangeLine @@ -91,22 +125,22 @@ function! gitgutter#highlight#define_sign_line_highlights() abort endif endfunction -function! gitgutter#highlight#get_background_colors(group) abort +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 gitgutter#highlight#get_background_colors(link_matches[1]) + return s:get_background_colors(link_matches[1]) endif - let ctermbg = gitgutter#highlight#match_highlight(highlight, 'ctermbg=\([0-9A-Za-z]\+\)') - let guibg = gitgutter#highlight#match_highlight(highlight, 'guibg=\([#0-9A-Za-z]\+\)') + let ctermbg = s:match_highlight(highlight, 'ctermbg=\([0-9A-Za-z]\+\)') + let guibg = s:match_highlight(highlight, 'guibg=\([#0-9A-Za-z]\+\)') return [guibg, ctermbg] endfunction -function! gitgutter#highlight#match_highlight(highlight, pattern) abort +function! s:match_highlight(highlight, pattern) abort let matches = matchlist(a:highlight, a:pattern) if len(matches) == 0 return 'NONE' diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim index 5875e0a7..d3e55bbd 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/hunk.vim @@ -1,15 +1,15 @@ -function! gitgutter#hunk#set_hunks(hunks) abort - call gitgutter#utility#setbufvar(gitgutter#utility#bufnr(), 'hunks', a:hunks) - call s:reset_summary() +function! gitgutter#hunk#set_hunks(bufnr, hunks) abort + call gitgutter#utility#setbufvar(a:bufnr, 'hunks', a:hunks) + call s:reset_summary(a:bufnr) endfunction -function! gitgutter#hunk#hunks() abort - return gitgutter#utility#getbufvar(gitgutter#utility#bufnr(), 'hunks', []) +function! gitgutter#hunk#hunks(bufnr) abort + return gitgutter#utility#getbufvar(a:bufnr, 'hunks', []) endfunction -function! gitgutter#hunk#reset() abort - call gitgutter#utility#setbufvar(gitgutter#utility#bufnr(), 'hunks', []) - call s:reset_summary() +function! gitgutter#hunk#reset(bufnr) abort + call gitgutter#utility#setbufvar(a:bufnr, 'hunks', []) + call s:reset_summary(a:bufnr) endfunction @@ -17,37 +17,35 @@ function! gitgutter#hunk#summary(bufnr) abort return gitgutter#utility#getbufvar(a:bufnr, 'summary', [0,0,0]) endfunction -function! s:reset_summary() abort - call gitgutter#utility#setbufvar(gitgutter#utility#bufnr(), 'summary', [0,0,0]) +function! s:reset_summary(bufnr) abort + call gitgutter#utility#setbufvar(a:bufnr, 'summary', [0,0,0]) endfunction -function! gitgutter#hunk#increment_lines_added(count) abort - let bufnr = gitgutter#utility#bufnr() - let summary = gitgutter#hunk#summary(bufnr) +function! gitgutter#hunk#increment_lines_added(bufnr, count) abort + let summary = gitgutter#hunk#summary(a:bufnr) let summary[0] += a:count - call gitgutter#utility#setbufvar(bufnr, 'summary', summary) + call gitgutter#utility#setbufvar(a:bufnr, 'summary', summary) endfunction -function! gitgutter#hunk#increment_lines_modified(count) abort - let bufnr = gitgutter#utility#bufnr() - let summary = gitgutter#hunk#summary(bufnr) +function! gitgutter#hunk#increment_lines_modified(bufnr, count) abort + let summary = gitgutter#hunk#summary(a:bufnr) let summary[1] += a:count - call gitgutter#utility#setbufvar(bufnr, 'summary', summary) + call gitgutter#utility#setbufvar(a:bufnr, 'summary', summary) endfunction -function! gitgutter#hunk#increment_lines_removed(count) abort - let bufnr = gitgutter#utility#bufnr() - let summary = gitgutter#hunk#summary(bufnr) +function! gitgutter#hunk#increment_lines_removed(bufnr, count) abort + let summary = gitgutter#hunk#summary(a:bufnr) let summary[2] += a:count - call gitgutter#utility#setbufvar(bufnr, 'summary', summary) + call gitgutter#utility#setbufvar(a:bufnr, 'summary', summary) endfunction function! gitgutter#hunk#next_hunk(count) abort - if gitgutter#utility#is_active() + let bufnr = bufnr('') + if gitgutter#utility#is_active(bufnr) let current_line = line('.') let hunk_count = 0 - for hunk in gitgutter#hunk#hunks() + for hunk in gitgutter#hunk#hunks(bufnr) if hunk[2] > current_line let hunk_count += 1 if hunk_count == a:count @@ -61,10 +59,11 @@ function! gitgutter#hunk#next_hunk(count) abort endfunction function! gitgutter#hunk#prev_hunk(count) abort - if gitgutter#utility#is_active() + let bufnr = bufnr('') + if gitgutter#utility#is_active(bufnr) let current_line = line('.') let hunk_count = 0 - for hunk in reverse(copy(gitgutter#hunk#hunks())) + for hunk in reverse(copy(gitgutter#hunk#hunks(bufnr))) if hunk[2] < current_line let hunk_count += 1 if hunk_count == a:count @@ -80,10 +79,11 @@ endfunction " Returns the hunk the cursor is currently in or an empty list if the cursor " isn't in a hunk. -function! gitgutter#hunk#current_hunk() abort +function! s:current_hunk() abort + let bufnr = bufnr('') let current_hunk = [] - for hunk in gitgutter#hunk#hunks() + for hunk in gitgutter#hunk#hunks(bufnr) if gitgutter#hunk#cursor_in_hunk(hunk) let current_hunk = hunk break @@ -107,22 +107,8 @@ function! gitgutter#hunk#cursor_in_hunk(hunk) abort return 0 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! gitgutter#hunk#line_adjustment_for_current_hunk() abort - let adj = 0 - for hunk in gitgutter#hunk#hunks() - if gitgutter#hunk#cursor_in_hunk(hunk) - break - else - let adj += hunk[1] - hunk[3] - endif - endfor - return adj -endfunction - function! gitgutter#hunk#text_object(inner) abort - let hunk = gitgutter#hunk#current_hunk() + let hunk = s:current_hunk() if empty(hunk) return @@ -141,3 +127,155 @@ function! gitgutter#hunk#text_object(inner) abort execute 'normal! 'first_line.'GV'.last_line.'G' endfunction + + +function! gitgutter#hunk#stage() abort + call s:hunk_op(function('s:stage')) + silent! call repeat#set("\GitGutterStageHunk", -1) +endfunction + +function! gitgutter#hunk#undo() abort + call s:hunk_op(function('s:undo')) + silent! call repeat#set("\GitGutterUndoHunk", -1) +endfunction + +function! gitgutter#hunk#preview() abort + call s:hunk_op(function('s:preview')) + silent! call repeat#set("\GitGutterPreviewHunk", -1) +endfunction + + +function! s:hunk_op(op) + let bufnr = bufnr('') + + if gitgutter#utility#is_active(bufnr) + " Get a (synchronous) diff. + let [async, g:gitgutter_async] = [g:gitgutter_async, 0] + let diff = gitgutter#diff#run_diff(bufnr, 1) + let g:gitgutter_async = async + + call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff)) + + if empty(s:current_hunk()) + call gitgutter#utility#warn('cursor is not in a hunk') + else + call a:op(gitgutter#diff#hunk_diff(bufnr, diff)) + endif + endif +endfunction + + +function! s:stage(hunk_diff) + let bufnr = bufnr('') + 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 - '), + \ diff) + + " Refresh gitgutter's view of buffer. + call gitgutter#process_buffer(bufnr, 1) +endfunction + + +function! s:undo(hunk_diff) + " Apply reverse patch to buffer. + let hunk = gitgutter#diff#parse_hunk(split(a:hunk_diff, '\n')[4]) + let lines = map(split(a:hunk_diff, '\n')[5:], 'v:val[1:]') + let lnum = hunk[2] + let added_only = hunk[1] == 0 && hunk[3] > 0 + let removed_only = hunk[1] > 0 && hunk[3] == 0 + + if removed_only + call append(lnum, lines) + elseif added_only + 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' + 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]) + + silent! wincmd P + if !&previewwindow + noautocmd execute 'bo' previewheight 'new' + set previewwindow + else + execute 'resize' previewheight + endif + + setlocal noreadonly modifiable filetype=diff buftype=nofile bufhidden=delete noswapfile + execute "%delete_" + call append(0, hunk_lines) + normal! gg + setlocal readonly nomodifiable + + noautocmd wincmd p +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)) +endfunction + + +" Replaces references to temp files with the actual file. +function! s:fix_file_references(filepath, hunk_diff) + let lines = split(a:hunk_diff, '\n') + + let left_prefix = matchstr(lines[2], '[abciow12]').'/' + let right_prefix = matchstr(lines[3], '[abciow12]').'/' + let quote = lines[0][11] == '"' ? '"' : '' + + let left_file = quote.left_prefix.a:filepath.quote + let right_file = quote.right_prefix.a:filepath.quote + + let lines[0] = 'diff --git '.left_file.' '.right_file + let lines[2] = '--- '.left_file + let lines[3] = '+++ '.right_file + + return join(lines, "\n")."\n" +endfunction + +if $VIM_GITGUTTER_TEST + function! gitgutter#hunk#fix_file_references(filepath, hunk_diff) + return s:fix_file_references(a:filepath, a:hunk_diff) + endfunction +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', '') + 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 + let bufnr = bufnr('') + let adj = 0 + for hunk in gitgutter#hunk#hunks(bufnr) + if gitgutter#hunk#cursor_in_hunk(hunk) + break + else + let adj += hunk[1] - hunk[3] + endif + endfor + return adj +endfunction + diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim index cab3d65b..b65563d3 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/sign.vim @@ -10,14 +10,43 @@ let s:dummy_sign_id = s:first_sign_id - 1 let s:supports_star = v:version > 703 || (v:version == 703 && has("patch596")) -" Removes gitgutter's signs (excluding dummy sign) from the buffer being processed. -function! gitgutter#sign#clear_signs() abort - let bufnr = gitgutter#utility#bufnr() - call gitgutter#sign#find_current_signs() +function! gitgutter#sign#enable() abort + let old_signs = g:gitgutter_signs - let sign_ids = map(values(gitgutter#utility#getbufvar(bufnr, 'gitgutter_signs')), 'v:val.id') - call gitgutter#sign#remove_signs(sign_ids, 1) - call gitgutter#utility#setbufvar(bufnr, 'gitgutter_signs', {}) + let g:gitgutter_signs = 1 + call gitgutter#highlight#define_sign_text_highlights() + + if !old_signs && !g:gitgutter_highlight_lines + call gitgutter#all(1) + endif +endfunction + +function! gitgutter#sign#disable() abort + let g:gitgutter_signs = 0 + call gitgutter#highlight#define_sign_text_highlights() + + if !g:gitgutter_highlight_lines + call gitgutter#sign#clear_signs(bufnr('')) + call gitgutter#sign#remove_dummy_sign(bufnr(''), 0) + endif +endfunction + +function! gitgutter#sign#toggle() abort + if g:gitgutter_signs + call gitgutter#sign#disable() + else + call gitgutter#sign#enable() + endif +endfunction + + +" Removes gitgutter's signs (excluding dummy sign) from the buffer being processed. +function! gitgutter#sign#clear_signs(bufnr) abort + call s:find_current_signs(a:bufnr) + + let sign_ids = map(values(gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')), 'v:val.id') + call s:remove_signs(a:bufnr, sign_ids, 1) + call gitgutter#utility#setbufvar(a:bufnr, 'gitgutter_signs', {}) endfunction @@ -25,39 +54,37 @@ endfunction " " modified_lines: list of [, ] " where name = 'added|removed|modified|modified_removed' -function! gitgutter#sign#update_signs(modified_lines) abort - call gitgutter#sign#find_current_signs() +function! gitgutter#sign#update_signs(bufnr, modified_lines) abort + call s:find_current_signs(a:bufnr) let new_gitgutter_signs_line_numbers = map(copy(a:modified_lines), 'v:val[0]') - let obsolete_signs = gitgutter#sign#obsolete_gitgutter_signs_to_remove(new_gitgutter_signs_line_numbers) + 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 gitgutter#sign#add_dummy_sign() + call s:add_dummy_sign(a:bufnr) endif - call gitgutter#sign#remove_signs(obsolete_signs, s:remove_all_old_signs) - call gitgutter#sign#upsert_new_gitgutter_signs(a:modified_lines) + 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(0) + call gitgutter#sign#remove_dummy_sign(a:bufnr, 0) endif endfunction -function! gitgutter#sign#add_dummy_sign() abort - let bufnr = gitgutter#utility#bufnr() - if !gitgutter#utility#getbufvar(bufnr, 'dummy_sign') - execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . bufnr - call gitgutter#utility#setbufvar(bufnr, 'dummy_sign', 1) +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(force) abort - let bufnr = gitgutter#utility#bufnr() - if gitgutter#utility#getbufvar(bufnr, 'dummy_sign') && (a:force || !g:gitgutter_sign_column_always) - execute "sign unplace" s:dummy_sign_id "buffer=" . bufnr - call gitgutter#utility#setbufvar(bufnr, 'dummy_sign', 0) +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 @@ -67,14 +94,13 @@ endfunction " -function! gitgutter#sign#find_current_signs() abort - let bufnr = gitgutter#utility#bufnr() +function! s:find_current_signs(bufnr) abort let gitgutter_signs = {} " : {'id': , 'name': } let other_signs = [] " [ signs - silent execute "sign place buffer=" . bufnr + silent execute "sign place buffer=" . a:bufnr redir END for sign_line in filter(split(signs, '\n')[2:], 'v:val =~# "="') @@ -101,19 +127,18 @@ function! gitgutter#sign#find_current_signs() abort end endfor - call gitgutter#utility#setbufvar(bufnr, 'dummy_sign', dummy_sign_placed) - call gitgutter#utility#setbufvar(bufnr, 'gitgutter_signs', gitgutter_signs) - call gitgutter#utility#setbufvar(bufnr, 'other_signs', other_signs) + 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) endfunction " Returns a list of [, ...] " Sets `s:remove_all_old_signs` as a side-effect. -function! gitgutter#sign#obsolete_gitgutter_signs_to_remove(new_gitgutter_signs_line_numbers) abort - let bufnr = gitgutter#utility#bufnr() +function! s:obsolete_gitgutter_signs_to_remove(bufnr, new_gitgutter_signs_line_numbers) abort let signs_to_remove = [] " list of [, ...] let remove_all_signs = 1 - let old_gitgutter_signs = gitgutter#utility#getbufvar(bufnr, 'gitgutter_signs') + let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs') for line_number in keys(old_gitgutter_signs) if index(a:new_gitgutter_signs_line_numbers, str2nr(line_number)) == -1 call add(signs_to_remove, old_gitgutter_signs[line_number].id) @@ -126,13 +151,12 @@ function! gitgutter#sign#obsolete_gitgutter_signs_to_remove(new_gitgutter_signs_ endfunction -function! gitgutter#sign#remove_signs(sign_ids, all_signs) abort - let bufnr = gitgutter#utility#bufnr() - if a:all_signs && s:supports_star && empty(gitgutter#utility#getbufvar(bufnr, 'other_signs')) - let dummy_sign_present = gitgutter#utility#getbufvar(bufnr, 'dummy_sign') - execute "sign unplace * buffer=" . bufnr +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') + execute "sign unplace * buffer=" . a:bufnr if dummy_sign_present - execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . bufnr + execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr endif else for id in a:sign_ids @@ -142,22 +166,21 @@ function! gitgutter#sign#remove_signs(sign_ids, all_signs) abort endfunction -function! gitgutter#sign#upsert_new_gitgutter_signs(modified_lines) abort - let bufnr = gitgutter#utility#bufnr() - let other_signs = gitgutter#utility#getbufvar(bufnr, 'other_signs') - let old_gitgutter_signs = gitgutter#utility#getbufvar(bufnr, 'gitgutter_signs') +function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort + let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs') + let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs') for line in a:modified_lines let line_number = line[0] " if index(other_signs, line_number) == -1 " don't clobber others' signs - let name = gitgutter#utility#highlight_name_for_change(line[1]) + let name = s:highlight_name_for_change(line[1]) if !has_key(old_gitgutter_signs, line_number) " insert - let id = gitgutter#sign#next_sign_id() - execute "sign place" id "line=" . line_number "name=" . name "buffer=" . bufnr + let id = s:next_sign_id() + execute "sign place" id "line=" . line_number "name=" . name "buffer=" . a:bufnr else " update if sign has changed let old_sign = old_gitgutter_signs[line_number] if old_sign.name !=# name - execute "sign place" old_sign.id "name=" . name "buffer=" . bufnr + execute "sign place" old_sign.id "name=" . name "buffer=" . a:bufnr end endif endif @@ -166,7 +189,7 @@ function! gitgutter#sign#upsert_new_gitgutter_signs(modified_lines) abort endfunction -function! gitgutter#sign#next_sign_id() abort +function! s:next_sign_id() abort let next_id = s:next_sign_id let s:next_sign_id += 1 return next_id @@ -177,3 +200,20 @@ endfunction function! gitgutter#sign#reset() let s:next_sign_id = s:first_sign_id endfunction + + +function! s:highlight_name_for_change(text) abort + if a:text ==# 'added' + return 'GitGutterLineAdded' + elseif a:text ==# 'removed' + return 'GitGutterLineRemoved' + elseif a:text ==# 'removed_first_line' + return 'GitGutterLineRemovedFirstLine' + elseif a:text ==# 'modified' + return 'GitGutterLineModified' + elseif a:text ==# 'modified_removed' + return 'GitGutterLineModifiedRemoved' + endif +endfunction + + diff --git a/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim b/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim index e4bc774d..bacbf228 100644 --- a/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim +++ b/sources_non_forked/vim-gitgutter/autoload/gitgutter/utility.vim @@ -1,11 +1,18 @@ -let s:file = '' -let s:using_xolox_shell = -1 -let s:exit_code = 0 +function! gitgutter#utility#supports_overscore_sign() + if s:windows() + return &encoding ==? 'utf-8' + else + return &termencoding ==? &encoding || &termencoding == '' + endif +endfunction function! gitgutter#utility#setbufvar(buffer, varname, val) let dict = get(getbufvar(a:buffer, ''), 'gitgutter', {}) + let needs_setting = empty(dict) let dict[a:varname] = a:val - call setbufvar(a:buffer, 'gitgutter', dict) + if needs_setting + call setbufvar(a:buffer, 'gitgutter', dict) + endif endfunction function! gitgutter#utility#getbufvar(buffer, varname, ...) @@ -26,11 +33,11 @@ function! gitgutter#utility#warn(message) abort let v:warningmsg = a:message endfunction -function! gitgutter#utility#warn_once(message, key) abort - if empty(gitgutter#utility#getbufvar(s:bufnr, a:key)) - call gitgutter#utility#setbufvar(s:bufnr, a:key, '1') +function! gitgutter#utility#warn_once(bufnr, message, key) abort + if empty(gitgutter#utility#getbufvar(a:bufnr, a:key)) + call gitgutter#utility#setbufvar(a:bufnr, a:key, '1') echohl WarningMsg - redraw | echo 'vim-gitgutter: ' . a:message + redraw | echom 'vim-gitgutter: ' . a:message echohl None let v:warningmsg = a:message endif @@ -38,188 +45,166 @@ endfunction " Returns truthy when the buffer's file should be processed; and falsey when it shouldn't. " This function does not and should not make any system calls. -function! gitgutter#utility#is_active() abort +function! gitgutter#utility#is_active(bufnr) abort return g:gitgutter_enabled && \ !pumvisible() && - \ gitgutter#utility#is_file_buffer() && - \ gitgutter#utility#exists_file() && - \ gitgutter#utility#not_git_dir() + \ s:is_file_buffer(a:bufnr) && + \ s:exists_file(a:bufnr) && + \ s:not_git_dir(a:bufnr) endfunction -function! gitgutter#utility#not_git_dir() abort - return gitgutter#utility#full_path_to_directory_of_file() !~ '[/\\]\.git\($\|[/\\]\)' +function! s:not_git_dir(bufnr) abort + return s:dir(a:bufnr) !~ '[/\\]\.git\($\|[/\\]\)' endfunction -function! gitgutter#utility#is_file_buffer() abort - return empty(getbufvar(s:bufnr, '&buftype')) +function! s:is_file_buffer(bufnr) abort + return empty(getbufvar(a:bufnr, '&buftype')) endfunction -" A replacement for the built-in `shellescape(arg)`. -" -" Recent versions of Vim handle shell escaping pretty well. However older -" versions aren't as good. This attempts to do the right thing. -" -" See: -" https://github.com/tpope/vim-fugitive/blob/8f0b8edfbd246c0026b7a2388e1d883d579ac7f6/plugin/fugitive.vim#L29-L37 +" From tpope/vim-fugitive +function! s:winshell() + return &shell =~? 'cmd' || exists('+shellslash') && !&shellslash +endfunction + +" From tpope/vim-fugitive function! gitgutter#utility#shellescape(arg) abort if a:arg =~ '^[A-Za-z0-9_/.-]\+$' return a:arg - elseif &shell =~# 'cmd' || gitgutter#utility#using_xolox_shell() + elseif s:winshell() return '"' . substitute(substitute(a:arg, '"', '""', 'g'), '%', '"%"', 'g') . '"' else return shellescape(a:arg) endif endfunction -function! gitgutter#utility#set_buffer(bufnr) abort - let s:bufnr = a:bufnr - let s:file = resolve(bufname(a:bufnr)) +function! gitgutter#utility#file(bufnr) + return s:abs_path(a:bufnr, 1) endfunction -function! gitgutter#utility#bufnr() - return s:bufnr -endfunction - -function! gitgutter#utility#file() - return s:file -endfunction - -function! gitgutter#utility#filename() abort - return fnamemodify(s:file, ':t') -endfunction - -function! gitgutter#utility#extension() abort - return fnamemodify(s:file, ':e') -endfunction - -function! gitgutter#utility#full_path_to_directory_of_file() abort - return fnamemodify(s:file, ':p:h') -endfunction - -function! gitgutter#utility#directory_of_file() abort - return fnamemodify(s:file, ':h') -endfunction - -function! gitgutter#utility#exists_file() abort - return filereadable(s:file) -endfunction - -function! gitgutter#utility#has_unsaved_changes() abort - return getbufvar(s:bufnr, "&mod") -endfunction - -function! gitgutter#utility#has_fresh_changes() abort - return getbufvar(s:bufnr, 'changedtick') != gitgutter#utility#getbufvar(s:bufnr, 'last_tick') -endfunction - -function! gitgutter#utility#save_last_seen_change() abort - call gitgutter#utility#setbufvar(s:bufnr, 'last_tick', getbufvar(s:bufnr, 'changedtick')) -endfunction - -function! gitgutter#utility#shell_error() abort - return gitgutter#utility#using_xolox_shell() ? s:exit_code : v:shell_error -endfunction - -function! gitgutter#utility#using_xolox_shell() abort - if s:using_xolox_shell == -1 - if !g:gitgutter_avoid_cmd_prompt_on_windows - let s:using_xolox_shell = 0 - " Although xolox/vim-shell works on both windows and unix we only want to use - " it on windows. - elseif has('win32') || has('win64') || has('win32unix') - let s:using_xolox_shell = exists('g:xolox#misc#version') && exists('g:xolox#shell#version') - else - let s:using_xolox_shell = 0 - endif - endif - return s:using_xolox_shell +" Not shellescaped +function! gitgutter#utility#extension(bufnr) abort + return fnamemodify(s:abs_path(a:bufnr, 0), ':e') endfunction function! gitgutter#utility#system(cmd, ...) abort call gitgutter#debug#log(a:cmd, a:000) - if gitgutter#utility#using_xolox_shell() - let options = {'command': a:cmd, 'check': 0} - if a:0 > 0 - let options['stdin'] = a:1 - endif - let ret = xolox#misc#os#exec(options) - let output = join(ret.stdout, "\n") - let s:exit_code = ret.exit_code - else - silent let output = (a:0 == 0) ? system(a:cmd) : system(a:cmd, a:1) - endif + call s:use_known_shell() + silent let output = (a:0 == 0) ? system(a:cmd) : system(a:cmd, a:1) + call s:restore_shell() + return output endfunction -function! gitgutter#utility#file_relative_to_repo_root() abort - let file_path_relative_to_repo_root = gitgutter#utility#getbufvar(s:bufnr, 'repo_relative_path') - if empty(file_path_relative_to_repo_root) - let dir_path_relative_to_repo_root = gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file(g:gitgutter_git_executable.' rev-parse --show-prefix')) - let dir_path_relative_to_repo_root = gitgutter#utility#strip_trailing_new_line(dir_path_relative_to_repo_root) - let file_path_relative_to_repo_root = dir_path_relative_to_repo_root . gitgutter#utility#filename() - call gitgutter#utility#setbufvar(s:bufnr, 'repo_relative_path', file_path_relative_to_repo_root) - endif - return file_path_relative_to_repo_root +" Path of file relative to repo root. +" +" * empty string - not set +" * non-empty string - path +" * -1 - pending +" * -2 - not tracked by git +function! gitgutter#utility#repo_path(bufnr, shellesc) abort + let p = gitgutter#utility#getbufvar(a:bufnr, 'path') + return a:shellesc ? gitgutter#utility#shellescape(p) : p endfunction -function! gitgutter#utility#command_in_directory_of_file(cmd) abort - return 'cd '.gitgutter#utility#shellescape(gitgutter#utility#directory_of_file()).' && '.a:cmd -endfunction +function! gitgutter#utility#set_repo_path(bufnr) abort + " Values of path: + " * non-empty string - path + " * -1 - pending + " * -2 - not tracked by git -function! gitgutter#utility#highlight_name_for_change(text) abort - if a:text ==# 'added' - return 'GitGutterLineAdded' - elseif a:text ==# 'removed' - return 'GitGutterLineRemoved' - elseif a:text ==# 'removed_first_line' - return 'GitGutterLineRemovedFirstLine' - elseif a:text ==# 'modified' - return 'GitGutterLineModified' - elseif a:text ==# 'modified_removed' - return 'GitGutterLineModifiedRemoved' + 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 '.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 + 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 endif endfunction -" Dedups list in-place. -" Assumes list has no empty entries. -function! gitgutter#utility#dedup(list) - return filter(sort(a:list), 'index(a:list, v:val, v:key + 1) == -1') +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#strip_trailing_new_line(line) abort +function! gitgutter#utility#cd_cmd(bufnr, cmd) abort + let cd = s:unc_path(a:bufnr) ? 'pushd' : (s:windows() ? 'cd /d' : 'cd') + return cd.' '.s:dir(a:bufnr).' && '.a:cmd +endfunction + +function! s:unc_path(bufnr) + return s:abs_path(a:bufnr, 0) =~ '^\\\\' +endfunction + +function! s:use_known_shell() abort + if has('unix') && &shell !=# 'sh' + let [s:shell, s:shellcmdflag, s:shellredir] = [&shell, &shellcmdflag, &shellredir] + let &shell = 'sh' + set shellcmdflag=-c shellredir=>%s\ 2>&1 + endif +endfunction + +function! s:restore_shell() abort + if has('unix') && exists('s:shell') + let [&shell, &shellcmdflag, &shellredir] = [s:shell, s:shellcmdflag, s:shellredir] + endif +endfunction + +function! s:abs_path(bufnr, shellesc) + let p = resolve(expand('#'.a:bufnr.':p')) + return a:shellesc ? gitgutter#utility#shellescape(p) : p +endfunction + +function! s:dir(bufnr) abort + return gitgutter#utility#shellescape(fnamemodify(s:abs_path(a:bufnr, 0), ':h')) +endfunction + +" Not shellescaped. +function! s:filename(bufnr) abort + return fnamemodify(s:abs_path(a:bufnr, 0), ':t') +endfunction + +function! s:exists_file(bufnr) abort + return filereadable(s:abs_path(a:bufnr, 0)) +endfunction + +function! s:strip_trailing_new_line(line) abort return substitute(a:line, '\n$', '', '') endfunction -" True for git v1.7.2+. -function! gitgutter#utility#git_supports_command_line_config_override() abort - call system(g:gitgutter_git_executable.' -c foo.bar=baz --version') - return !v:shell_error -endfunction - -function! gitgutter#utility#stringify(list) abort - return join(a:list, "\n")."\n" -endfunction - -function! gitgutter#utility#use_known_shell() abort - if has('unix') - if &shell !=# 'sh' - let s:shell = &shell - let s:shellcmdflag = &shellcmdflag - let s:shellredir = &shellredir - let &shell = 'sh' - set shellcmdflag=-c - set shellredir=>%s\ 2>&1 - endif - endif -endfunction - -function! gitgutter#utility#restore_shell() abort - if has('unix') - if exists('s:shell') - let &shell = s:shell - let &shellcmdflag = s:shellcmdflag - let &shellredir = s:shellredir - endif - endif +function! s:windows() + return has('win64') || has('win32') || has('win16') endfunction diff --git a/sources_non_forked/vim-gitgutter/doc/gitgutter.txt b/sources_non_forked/vim-gitgutter/doc/gitgutter.txt index 0065d098..8cf62b97 100644 --- a/sources_non_forked/vim-gitgutter/doc/gitgutter.txt +++ b/sources_non_forked/vim-gitgutter/doc/gitgutter.txt @@ -4,45 +4,50 @@ Vim Git Gutter -Author: Andy Stewart +Author: Andy Stewart Plugin Homepage: -=============================================================================== -CONTENTS *GitGutterContents* - - 1. Introduction ................. |GitGutterIntroduction| - 2. Installation ................. |GitGutterInstallation| - 3. Usage ........................ |GitGutterUsage| - 4. Commands ..................... |GitGutterCommands| - 5. Autocommand .................. |GitGutterAutocmd| - 6. CUSTOMISATION................. |GitGutterCustomisation| - 7. FAQ .......................... |GitGutterFAQ| =============================================================================== -1. INTRODUCTION *GitGutterIntroduction* - *GitGutter* +CONTENTS *gitgutter* -Vim Git Gutter is a Vim plugin which shows a git diff in the 'gutter' (sign -column). It shows whether each line has been added, modified, and where lines -have been removed. + Introduction ................. |gitgutter-introduction| + Installation ................. |gitgutter-installation| + Commands ..................... |gitgutter-commands| + Mappings ..................... |gitgutter-mappings| + Autocommand .................. |gitgutter-autocommand| + Options ...................... |gitgutter-options| + Highlights ................... |gitgutter-highlights| + FAQ .......................... |gitgutter-faq| + TROUBLESHOOTING .............. |gitgutter-troubleshooting| -This is a port of the Git Gutter plugin for Sublime Text 2. =============================================================================== -2. INSTALLATION *GitGutterInstallation* +INTRODUCTION *gitgutter-introduction* -* Pathogen: +GitGutter is a Vim plugin which shows a git diff in the 'gutter' (sign column). +It shows which lines have been added, modified, or removed. You can also +preview, stage, and undo individual hunks. The plugin also provides a hunk +text object. + +The signs are always up to date and the plugin never saves your buffer. + + +=============================================================================== +INSTALLATION *gitgutter-installation* + +Pathogen:~ > cd ~/.vim/bundle git clone git://github.com/airblade/vim-gitgutter.git < -* Voom: +Voom:~ Edit your plugin manifest (`voom edit`) and add: > airblade/vim-gitgutter < -* VimPlug: +VimPlug:~ Place this in your .vimrc: > @@ -53,7 +58,7 @@ Then run the following in Vim: :source % :PlugInstall < -* NeoBundle: +NeoBundle:~ Place this in your .vimrc: > @@ -64,7 +69,7 @@ Then run the following in Vim: :source % :NeoBundleInstall < -* No plugin manager: +No plugin manager:~ Copy vim-gitgutter's subdirectories into your vim configuration directory: > @@ -73,133 +78,346 @@ Copy vim-gitgutter's subdirectories into your vim configuration directory: < See |add-global-plugin|. -=============================================================================== -3. USAGE *GitGutterUsage* - -You don't have to do anything: it just works. =============================================================================== -4. COMMANDS *GitGutterCommands* +COMMANDS *gitgutter-commands* -Commands for turning Git Gutter on and off: +Commands for turning vim-gitgutter on and off:~ - :GitGutterDisable *:GitGutterDisable* - Explicitly turn Git Gutter off. + *gitgutter-:GitGutterDisable* +:GitGutterDisable Turn vim-gitgutter off for all buffers. - :GitGutterEnable *:GitGutterEnable* - Explicitly turn Git Gutter on. + *gitgutter-:GitGutterEnable* +:GitGutterEnable Turn vim-gitgutter on for all buffers. - :GitGutterToggle *:GitGutterToggle* - Explicitly turn Git Gutter on if it was off and vice versa. + *gitgutter-:GitGutterToggle* +:GitGutterToggle Toggle vim-gitgutter on or off for all buffers. - :GitGutter *:GitGutter* - Update signs for the current buffer. + *gitgutter-:GitGutter* +:GitGutter Update signs for the current buffer. You shouldn't + need to run this. - :GitGutterAll *:GitGutterAll* - Update signs across all buffers. + *gitgutter-:GitGutterAll* +:GitGutterAll Update signs for all buffers. You shouldn't need to + run this. -Commands for turning signs on and off (defaults to on): - :GitGutterSignsEnable *:GitGutterSignsEnable* - Explicitly turn line signs on. +Commands for turning signs on and off (defaults to on):~ - :GitGutterSignsDisable *:GitGutterSignsDisable* - Explicitly turn line signs off. + *gitgutter-:GitGutterSignsEnable* +:GitGutterSignsEnable Show signs for the diff. - :GitGutterSignsToggle *:GitGutterSignsToggle* - Explicitly turn line signs on if it was off and vice versa. + *gitgutter-:GitGutterSignsDisable* +:GitGutterSignsDisable Do not show signs for the diff. -Commands for turning line highlighting on and off (defaults to off): + *gitgutter-:GitGutterSignsToggle* +:GitGutterSignsToggle Toggle signs on or off. - :GitGutterLineHighlightsEnable *:GitGutterLineHighlightsEnable* - Explicitly turn line highlighting on. - :GitGutterLineHighlightsDisable *:GitGutterLineHighlightsDisable* - Explicitly turn line highlighting off. +Commands for turning line highlighting on and off (defaults to off):~ - :GitGutterLineHighlightsToggle *:GitGutterLineHighlightsToggle* - Explicitly turn line highlighting on if it was off and vice versa. + *gitgutter-:GitGutterLineHighlightsEnable* +:GitGutterLineHighlightsEnable Turn on line highlighting. -Commands for jumping between marked hunks: + *gitgutter-:GitGutterLineHighlightsDisable* +:GitGutterLineHighlightsDisable Turn off line highlighting. - :GitGutterNextHunk *:GitGutterNextHunk* - Jump to the next marked hunk. Takes a count. + *gitgutter-:GitGutterLineHighlightsToggle* +:GitGutterLineHighlightsToggle Turn line highlighting on or off. - :GitGutterPrevHunk *:GitGutterPrevHunk* - Jump to the previous marked hunk. Takes a count. -Commands for staging or undoing individual hunks: +Commands for jumping between hunks:~ - :GitGutterStageHunk *:GitGutterStageHunk* - Stage the hunk the cursor is in. + *gitgutter-:GitGutterNextHunk* +:GitGutterNextHunk Jump to the next [count] hunk. - :GitGutterUndoHunk *:GitGutterUndoHunk* - Undo the hunk the cursor is in. + *gitgutter-:GitGutterPrevHunk* +:GitGutterPrevHunk Jump to the previous [count] hunk. + + +Commands for operating on a hunk:~ + + *gitgutter-:GitGutterStageHunk* +:GitGutterStageHunk Stage the hunk the cursor is in. + + *gitgutter-:GitGutterUndoHunk* +:GitGutterUndoHunk Undo the hunk the cursor is in. + + *gitgutter-:GitGutterPreviewHunk* +:GitGutterPreviewHunk Preview the hunk the cursor is in. + Use |:pclose| or |CTRL-W_CTRL-Z| to close the preview + window. - :GitGutterPreviewHunk *:GitGutterPreviewHunk* - Preview the hunk the cursor is in. - Use |:pclose| or |CTRL-W_CTRL-Z| to close the preview window. =============================================================================== -5. AUTOCOMMAND *GitGutterAutocmd* +AUTOCOMMAND *gitgutter-autocommand* + +User GitGutter~ After updating a buffer's signs vim-gitgutter fires a |User| |autocmd| with the event GitGutter. You can listen for this event, for example: > autocmd User GitGutter call updateMyStatusLine() < +A dictionary `g:gitgutter_hook_context` is made available during its execution, +which contains an entry `bufnr` that contains the buffer number being updated. + =============================================================================== -6. CUSTOMISATION *GitGutterCustomisation* +MAPPINGS *gitgutter-mappings* -You can customise: +You can disable all these mappings with: +> + let g:gitgutter_map_keys = 0 +< -- The sign column's colours -- The signs' colours and symbols -- Line highlights -- The base of the diff -- Extra arguments for git-diff -- Key mappings -- The grep executable used -- 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) +Hunk operations:~ -Please note that vim-gitgutter won't override any colours or highlights you've -set in your colorscheme. +These can be repeated with `.` if you have vim-repeat installed. -SIGN COLUMN + *gitgutter-hp* +hp Preview the hunk under the cursor. -By default vim-gitgutter will make the sign column look like the line number -column (i.e. the |hl-LineNr| highlight group). + *gitgutter-hs* +hs Stage the hunk under the cursor. + + *gitgutter-hu* +hu Undo the hunk under the cursor. + +You can change these mappings like this: +> + nmap ghp GitGutterPreviewHunk + nmap ghs GitGutterStageHunk + nmap ghu GitGutterUndoHunk +< + +Hunk jumping:~ + + *gitgutter-]c* +]c Jump to the next [count] hunk. + + *gitgutter-[c* +[c Jump to the previous [count] hunk. + +You can change these mappings like this: +> + nmap [c GitGutterPrevHunk + nmap ]c GitGutterNextHunk +< + +Hunk text object:~ + + *gitgutter-ic* *gitgutter-ac* *gitgutter-text-object* +"ic" operates on the current hunk's lines. "ac" does the same but also includes +trailing empty lines. +> + omap ic GitGutterTextObjectInnerPending + omap ac GitGutterTextObjectOuterPending + xmap ic GitGutterTextObjectInnerVisual + xmap ac GitGutterTextObjectOuterVisual +< + + +=============================================================================== +OPTIONS *gitgutter-options* + +The most important option is 'updatetime' which determines how long (in +milliseconds) the plugin will wait after you stop typing before it updates the +signs. Vim's default is 4000. I recommend 100. + +Most important option:~ + + 'updatetime' + +Git:~ + + |g:gitgutter_git_executable| + |g:gitgutter_diff_args| + |g:gitgutter_diff_base| + +Grep:~ + + |g:gitgutter_grep| + +Signs:~ + + |g:gitgutter_signs| + |g:gitgutter_highlight_lines| + |g:gitgutter_max_signs| + |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:~ + + |g:gitgutter_terminal_reports_focus| + +General:~ + + |g:gitgutter_enabled| + |g:gitgutter_map_keys| + |g:gitgutter_async| + |g:gitgutter_log| + + + *g:gitgutter_git_executable* +Default: 'git' + +This option determines what git binary to use. Set this if git is not on your +path. + + *g:gitgutter_diff_args* +Default: empty + +Use this option to pass any extra arguments to git-diff. For example: +> + let g:gitgutter_diff_args = '-w' +< + + *g:gitgutter_diff_base* +Default: empty + +By default buffers are diffed against the index. Use this option to diff against +a revision instead. For example: +> + let g:gitgutter_diff_base = '' +< + + *g:gitgutter_grep* +Default: 'grep' + +The plugin pipes the output of git-diff into grep to minimise the amount of data +vim has to process. Set this option if grep is not on your path. + +grep must produce plain-text output without any ANSI escape codes or colours. +Use this option to turn off colours if necessary. +> + let g:gitgutter_grep = 'grep --color=never' +< +If you do not want to use grep at all (perhaps to debug why signs are not +showing), set this option to an empty string: +> + let g:gitgutter_grep = '' +< + + *g:gitgutter_signs* +Default: 1 + +Determines whether or not to show signs. + + *g:gitgutter_highlight_lines* +Default: 0 + +Determines whether or not to show line highlights. + + *g:gitgutter_max_signs* +Default: 500 + +Sets the maximum number of signs to show in a buffer. Vim is slow at updating +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_added* + *g:gitgutter_sign_modified* + *g:gitgutter_sign_removed* + *g:gitgutter_sign_removed_first_line* + *g:gitgutter_sign_modified_removed* +Defaults: +> + let g:gitgutter_sign_added = '+' + let g:gitgutter_sign_modified = '~' + let g:gitgutter_sign_removed = '_' + let g:gitgutter_sign_removed_first_line = '‾' + let g:gitgutter_sign_modified_removed = '~_' +< +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 + +Controls whether to make the sign column look like the line-number column (i.e. +the |hl-LineNr| highlight group). To customise your sign column's background color, first tell vim-gitgutter to leave it alone: > - let g:gitgutter_override_sign_column_highlight = 0 + let g:gitgutter_override_sign_column_highlight = 0 < And then either update your colorscheme's |hlSignColumn| highlight group or set it in your |vimrc|: Desired appearance Command ~ - Same as line number column highlight clear SignColumn + Same as line-number column highlight clear SignColumn User-defined (terminal Vim) highlight SignColumn ctermbg={whatever} User-defined (graphical Vim) highlight SignColumn guibg={whatever} -SIGNS' COLOURS AND SYMBOLS -To customise the colours, set up the following highlight groups in your + *g:gitgutter_terminal_reports_focus* +Default: 1 + +Normally the plugin uses |FocusGained| to force-update all buffers when Vim +receives focus. However some terminals do not report focus events and so the +|FocusGained| autocommand never fires. + +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. + +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). + + *g:gitgutter_enabled* +Default: 1 + +Controls whether or not the plugin is on at startup. + + *g:gitgutter_map_keys* +Default: 1 + +Controls whether or not the plugin provides mappings. See |gitgutter-mapppings|. + + *g:gitgutter_async* +Default: 1 + +Controls whether or not diffs are run in the background. This has no effect if +your Vim does not support background jobs. + + *g:gitgutter_log* +Default: 0 + +When switched on, the plugin logs to gitgutter.log in the directory where it is +installed. Additionally it logs channel activity to channel.log. + + +=============================================================================== +HIGHLIGHTS *gitgutter-highlights* + +To change the signs' colours, set up the following highlight groups in your colorscheme or |vimrc|: - > - GitGutterAdd " an added line - GitGutterChange " a changed line - GitGutterDelete " at least one removed line - GitGutterChangeDelete " a changed line followed by at least one removed line + GitGutterAdd " an added line + GitGutterChange " a changed line + GitGutterDelete " at least one removed line + GitGutterChangeDelete " a changed line followed by at least one removed line < You can either set these with `highlight GitGutterAdd {key}={arg}...` or link @@ -208,134 +426,94 @@ them to existing highlight groups with, say: highlight link GitGutterAdd DiffAdd < -To customise the symbols, add the following to your |vimrc|: -> - let g:gitgutter_sign_added = 'xx' - let g:gitgutter_sign_modified = 'yy' - let g:gitgutter_sign_removed = 'zz' - let g:gitgutter_sign_modified_removed = 'ww' -< - -LINE HIGHLIGHTS - -Similarly to the signs' colours, set up the following highlight groups in your +To change the line highlights, set up the following highlight groups in your colorscheme or |vimrc|: > - GitGutterAddLine " default: links to DiffAdd - GitGutterChangeLine " default: links to DiffChange - GitGutterDeleteLine " default: links to DiffDelete - GitGutterChangeDeleteLine " default: links to GitGutterChangeLineDefault + GitGutterAddLine " default: links to DiffAdd + GitGutterChangeLine " default: links to DiffChange + GitGutterDeleteLine " default: links to DiffDelete + GitGutterChangeDeleteLine " default: links to GitGutterChangeLineDefault < -THE BASE OF THE DIFF - -By default buffers are diffed against the index. To diff against a commit -instead: -> - let g:gitgutter_diff_base = '' -< - -EXTRA ARGUMENTS FOR GIT-DIFF - -To pass extra arguments to git-diff, add this to your |vimrc|: -> - let g:gitgutter_diff_args = '-w' -< - -KEY MAPPINGS - -To disable all key maps: -> - let g:gitgutter_map_keys = 0 -< - -To change the hunk-jumping maps (defaults shown): -> - nmap [c GitGutterPrevHunk - nmap ]c GitGutterNextHunk -< - -To change the hunk-staging/undoing/previewing maps (defaults shown): -> - nmap hs GitGutterStageHunk - nmap hu GitGutterUndoHunk - nmap hp GitGutterPreviewHunk -< - -To change the hunk text object maps (defaults shown): -> - omap ic GitGutterTextObjectInnerPending - omap ac GitGutterTextObjectOuterPending - xmap ic GitGutterTextObjectInnerVisual - xmap ac GitGutterTextObjectOuterVisual -< - -TO USE A CUSTOM GREP COMMAND - -To use a custom invocation for grep, use this: -> - let g:gitgutter_grep_command = 'grep' -< - -TO TURN OFF VIM-GITGUTTER BY DEFAULT - -Add to your |vimrc| -> - let g:gitgutter_enabled = 0 -< - -TO TURN OFF SIGNS BY DEFAULT - -Add to your |vimrc| -> - let g:gitgutter_signs = 0 -< - -Note that the sign column will still be present if you have line highlighting -switched on. - -TO TURN ON LINE HIGHLIGHTING BY DEFAULT - -Add to your |vimrc| -> - let g:gitgutter_highlight_lines = 1 -< - -TO STOP VIM-GITGUTTER RUNNING IN REALTIME - -Add to your |vimrc| -> - let g:gitgutter_realtime = 0 -< - -TO STOP VIM-GITGUTTER RUNNING EAGERLY - -Add to your |vimrc| -> - let g:gitgutter_eager = 0 -< - -TO TURN OFF ASYNCHRONOUS UPDATES - -By default diffs are run asynchronously. To run diffs synchronously -instead: - -Add to your |vimrc| -> -let g:gitgutter_async = 0 -< =============================================================================== -7. FAQ *GitGutterFAQ* +FAQ *gitgutter-faq* -a. Why are the colours in the sign column weird? +a. How do I turn off realtime updates? + + Add this to your vim configuration in an |after-directory|: +> + autocmd! gitgutter CursorHold,CursorHoldI +< +b. Why can't I unstage staged changes? + + This plugin is for showing changes between the working tree and the index + (and staging/undoing those changes). Unstaging a staged hunk would require + showing changes between the index and HEAD, which is out of scope. + +c. Why are the colours in the sign column weird? Your colorscheme is configuring the |hl-SignColumn| highlight group weirdly. - Please see |GitGutterCustomisation| on customising the sign column. + Please see |g:gitgutter_override_sign_column_highlight| on customising the + sign column. -b. What happens if I also use another plugin which uses signs (e.g. Syntastic)? +d. What happens if I also use another plugin which uses signs (e.g. Syntastic)? + + Vim only allows one sign per line. Vim-gitgutter will not interfere with + signs it did not add. + + +=============================================================================== +TROUBLESHOOTING *gitgutter-troubleshooting* + +When no signs are showing at all:~ + +1. Try bypassing grep with: +> + let g:gitgutter_grep = '' +< + If it works, the problem is grep outputting ANSI escape codes. Use this + option to pass arguments to grep to turn off the escape codes. + +2. Verify git is on your path: +> + :echo system('git --version') +< + +3. Verify your git config is compatible with the version of git return by the + command above. + +4. Verify your Vim supports signs. The following should give 1: +> + :echo has('signs') +< + +5. Check whether the plugin thinks git knows about your file: +> + :echo getbufvar('','gitgutter').path +< + If the result is -2, the plugin thinks your file is not tracked by git. + + +When the whole file is marked as added:~ + +If you use zsh, and you set "CDPATH", make sure "CDPATH" does not include the +current directory. + + +When signs take a few seconds to appear:~ + +Try reducing 'updatetime': +> + set updatetime=100 +< + + +When signs don't update after focusing Vim:~ + +Your terminal probably isn't reporting focus events. Either try installing +Terminus (https://github.com/wincent/terminus) or set: +> + let g:gitgutter_terminal_reports_focus = 0 +< - 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. diff --git a/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim b/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim index ad39bc17..3d64514b 100644 --- a/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/plugin/gitgutter.vim @@ -7,14 +7,9 @@ let g:loaded_gitgutter = 1 " Initialisation {{{ -" Realtime sign updates require Vim 7.3.105+. if v:version < 703 || (v:version == 703 && !has("patch105")) - let g:gitgutter_realtime = 0 -endif - -" Eager updates require gettabvar()/settabvar(). -if !exists("*gettabvar") - let g:gitgutter_eager = 0 + call gitgutter#utility#warn('requires Vim 7.3.105') + finish endif function! s:set(var, default) abort @@ -33,35 +28,50 @@ 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"') endif call s:set('g:gitgutter_override_sign_column_highlight', 1) -call s:set('g:gitgutter_realtime', 1) -call s:set('g:gitgutter_eager', 1) call s:set('g:gitgutter_sign_added', '+') call s:set('g:gitgutter_sign_modified', '~') call s:set('g:gitgutter_sign_removed', '_') -try + +if gitgutter#utility#supports_overscore_sign() call s:set('g:gitgutter_sign_removed_first_line', '‾') -catch /E239/ - let g:gitgutter_sign_removed_first_line = '_^' -endtry +else + call s:set('g:gitgutter_sign_removed_first_line', '_^') +endif call s:set('g:gitgutter_sign_modified_removed', '~_') call s:set('g:gitgutter_diff_args', '') call s:set('g:gitgutter_diff_base', '') call s:set('g:gitgutter_map_keys', 1) -call s:set('g:gitgutter_avoid_cmd_prompt_on_windows', 1) +call s:set('g:gitgutter_terminal_reports_focus', 1) call s:set('g:gitgutter_async', 1) call s:set('g:gitgutter_log', 0) -call s:set('g:gitgutter_git_executable', 'git') +call s:set('g:gitgutter_git_executable', 'git') if !executable(g:gitgutter_git_executable) call gitgutter#utility#warn('cannot find git. Please set g:gitgutter_git_executable.') endif +let default_grep = 'grep' +call s:set('g:gitgutter_grep', default_grep) +if !empty(g:gitgutter_grep) + if executable(split(g:gitgutter_grep)[0]) + if $GREP_OPTIONS =~# '--color=always' + let g:gitgutter_grep .= ' --color=never' + endif + else + if g:gitgutter_grep !=# default_grep + call gitgutter#utility#warn('cannot find '.g:gitgutter_grep.'. Please check g:gitgutter_grep.') + endif + let g:gitgutter_grep = '' + endif +endif + call gitgutter#highlight#define_sign_column_highlight() call gitgutter#highlight#define_highlights() call gitgutter#highlight#define_signs() @@ -70,40 +80,39 @@ call gitgutter#highlight#define_signs() " Primary functions {{{ -command -bar GitGutterAll call gitgutter#all() -command -bar GitGutter call gitgutter#process_buffer(bufnr(''), 0) +command! -bar GitGutterAll call gitgutter#all(1) +command! -bar GitGutter call gitgutter#process_buffer(bufnr(''), 1) -command -bar GitGutterDisable call gitgutter#disable() -command -bar GitGutterEnable call gitgutter#enable() -command -bar GitGutterToggle call gitgutter#toggle() +command! -bar GitGutterDisable call gitgutter#disable() +command! -bar GitGutterEnable call gitgutter#enable() +command! -bar GitGutterToggle call gitgutter#toggle() " }}} " Line highlights {{{ -command -bar GitGutterLineHighlightsDisable call gitgutter#line_highlights_disable() -command -bar GitGutterLineHighlightsEnable call gitgutter#line_highlights_enable() -command -bar GitGutterLineHighlightsToggle call gitgutter#line_highlights_toggle() +command! -bar GitGutterLineHighlightsDisable call gitgutter#highlight#line_disable() +command! -bar GitGutterLineHighlightsEnable call gitgutter#highlight#line_enable() +command! -bar GitGutterLineHighlightsToggle call gitgutter#highlight#line_toggle() " }}} " Signs {{{ -command -bar GitGutterSignsEnable call gitgutter#signs_enable() -command -bar GitGutterSignsDisable call gitgutter#signs_disable() -command -bar GitGutterSignsToggle call gitgutter#signs_toggle() +command! -bar GitGutterSignsEnable call gitgutter#sign#enable() +command! -bar GitGutterSignsDisable call gitgutter#sign#disable() +command! -bar GitGutterSignsToggle call gitgutter#sign#toggle() " }}} " Hunks {{{ -command -bar -count=1 GitGutterNextHunk call gitgutter#hunk#next_hunk() -command -bar -count=1 GitGutterPrevHunk call gitgutter#hunk#prev_hunk() +command! -bar -count=1 GitGutterNextHunk call gitgutter#hunk#next_hunk() +command! -bar -count=1 GitGutterPrevHunk call gitgutter#hunk#prev_hunk() -command -bar GitGutterStageHunk call gitgutter#stage_hunk() -command -bar GitGutterUndoHunk call gitgutter#undo_hunk() -command -bar GitGutterRevertHunk echomsg 'GitGutterRevertHunk is deprecated. Use GitGutterUndoHunk'call gitgutter#undo_hunk() -command -bar GitGutterPreviewHunk call gitgutter#preview_hunk() +command! -bar GitGutterStageHunk call gitgutter#hunk#stage() +command! -bar GitGutterUndoHunk call gitgutter#hunk#undo() +command! -bar GitGutterPreviewHunk call gitgutter#hunk#preview() " Hunk text object onoremap GitGutterTextObjectInnerPending :call gitgutter#hunk#text_object(1) @@ -130,7 +139,8 @@ xnoremap GitGutterTextObjectOuterVisual :call gitgutter#hun " `line` - refers to the line number where the change starts " `count` - refers to the number of lines the change covers function! GitGutterGetHunks() - return gitgutter#utility#is_active() ? gitgutter#hunk#hunks() : [] + let bufnr = bufnr('') + return gitgutter#utility#is_active(bufnr) ? gitgutter#hunk#hunks(bufnr) : [] endfunction " Returns an array that contains a summary of the hunk status for the current @@ -142,7 +152,7 @@ endfunction " }}} -command -bar GitGutterDebug call gitgutter#debug#debug() +command! -bar GitGutterDebug call gitgutter#debug#debug() " Maps {{{ @@ -169,7 +179,6 @@ if g:gitgutter_map_keys endif if !hasmapto('GitGutterUndoHunk') && maparg('hu', 'n') ==# '' nmap hu GitGutterUndoHunk - nmap hr GitGutterUndoHunk:echomsg 'hr is deprecated. Use hu' endif if !hasmapto('GitGutterPreviewHunk') && maparg('hp', 'n') ==# '' nmap hp GitGutterPreviewHunk @@ -196,35 +205,26 @@ endif augroup gitgutter autocmd! - if g:gitgutter_realtime - autocmd CursorHold,CursorHoldI * call gitgutter#process_buffer(bufnr(''), 1) - endif + autocmd TabEnter * let t:gitgutter_didtabenter = 1 - if g:gitgutter_eager - autocmd BufWritePost,FileChangedShellPost,ShellCmdPost * call gitgutter#process_buffer(bufnr(''), 0) + autocmd BufEnter * + \ 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 - autocmd BufEnter * - \ if gettabvar(tabpagenr(), 'gitgutter_didtabenter') | - \ call settabvar(tabpagenr(), 'gitgutter_didtabenter', 0) | - \ call gitgutter#all() | - \ else | - \ call gitgutter#process_buffer(bufnr(''), 0) | - \ endif + autocmd CursorHold,CursorHoldI * call gitgutter#process_buffer(bufnr(''), 0) + autocmd FileChangedShellPost,ShellCmdPost * call gitgutter#process_buffer(bufnr(''), 1) - autocmd TabEnter * call settabvar(tabpagenr(), 'gitgutter_didtabenter', 1) + " Ensure that all buffers are processed when opening vim with multiple files, e.g.: + " + " vim -o file1 file2 + autocmd VimEnter * if winnr() != winnr('$') | call gitgutter#all(0) | endif - " Ensure that all buffers are processed when opening vim with multiple files, e.g.: - " - " vim -o file1 file2 - autocmd VimEnter * if winnr() != winnr('$') | :GitGutterAll | endif - - if !has('gui_win32') - autocmd FocusGained * call gitgutter#all() - endif - - else - autocmd BufRead,BufWritePost,FileChangedShellPost * call gitgutter#process_buffer(bufnr(''), 0) - endif + autocmd FocusGained * call gitgutter#all(1) autocmd ColorScheme * call gitgutter#highlight#define_sign_column_highlight() | call gitgutter#highlight#define_highlights() diff --git a/sources_non_forked/vim-gitgutter/test/cp932.txt b/sources_non_forked/vim-gitgutter/test/cp932.txt new file mode 100644 index 00000000..80cb10bf --- /dev/null +++ b/sources_non_forked/vim-gitgutter/test/cp932.txt @@ -0,0 +1,8 @@ +The quick brown fox jumps +over the lazy dog + +͂ɂقւƂʂ +킩悽ꂻ‚˂Ȃ +̂܂ӂ +߂݂Ђ + diff --git a/sources_non_forked/vim-gitgutter/test/test b/sources_non_forked/vim-gitgutter/test/test index 6247a058..4daf052f 100644 --- a/sources_non_forked/vim-gitgutter/test/test +++ b/sources_non_forked/vim-gitgutter/test/test @@ -2,6 +2,8 @@ VIM="/Applications/MacVim.app/Contents/MacOS/Vim -v" +export VIM_GITGUTTER_TEST=1 + $VIM -u NONE -U NONE -N \ --cmd 'set rtp+=../' \ --cmd 'let g:gitgutter_async=0' \ diff --git a/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim b/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim index 1a65ed8a..4cf82c5e 100644 --- a/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim +++ b/sources_non_forked/vim-gitgutter/test/test_gitgutter.vim @@ -31,6 +31,10 @@ function s:git_diff_staged() return split(system('git diff -U0 --staged fixture.txt'), '\n') endfunction +function s:trigger_gitgutter() + doautocmd CursorHold +endfunction + " " SetUp / TearDown @@ -40,7 +44,8 @@ function SetUp() call system("git init ".s:test_repo. \ " && cd ".s:test_repo. \ " && cp ../fixture.txt .". - \ " && git add . && git commit -m 'initial'") + \ " && git add . && git commit -m 'initial'". + \ " && git config diff.mnemonicPrefix false") execute ':cd' s:test_repo edit! fixture.txt call gitgutter#sign#reset() @@ -64,7 +69,7 @@ endfunction function Test_add_lines() normal ggo* - write + call s:trigger_gitgutter() let expected = ["line=2 id=3000 name=GitGutterLineAdded"] call assert_equal(expected, s:signs('fixture.txt')) @@ -76,7 +81,7 @@ function Test_add_lines_fish() set shell=/usr/local/bin/fish normal ggo* - write + call s:trigger_gitgutter() let expected = ["line=2 id=3000 name=GitGutterLineAdded"] call assert_equal(expected, s:signs('fixture.txt')) @@ -87,7 +92,7 @@ endfunction function Test_modify_lines() normal ggi* - write + call s:trigger_gitgutter() let expected = ["line=1 id=3000 name=GitGutterLineModified"] call assert_equal(expected, s:signs('fixture.txt')) @@ -96,7 +101,7 @@ endfunction function Test_remove_lines() execute '5d' - write + call s:trigger_gitgutter() let expected = ["line=4 id=3000 name=GitGutterLineRemoved"] call assert_equal(expected, s:signs('fixture.txt')) @@ -105,7 +110,7 @@ endfunction function Test_remove_first_lines() execute '1d' - write + call s:trigger_gitgutter() let expected = ["line=1 id=3000 name=GitGutterLineRemovedFirstLine"] call assert_equal(expected, s:signs('fixture.txt')) @@ -115,7 +120,7 @@ endfunction function Test_edit_file_with_same_name_as_a_branch() normal 5Gi* call system('git checkout -b fixture.txt') - write + call s:trigger_gitgutter() let expected = ["line=5 id=3000 name=GitGutterLineModified"] call assert_equal(expected, s:signs('fixture.txt')) @@ -127,7 +132,7 @@ function Test_file_added_to_git() call system('touch '.tmpfile.' && git add '.tmpfile) execute 'edit '.tmpfile normal ihello - write + call s:trigger_gitgutter() let expected = ["line=1 id=3000 name=GitGutterLineAdded"] call assert_equal(expected, s:signs('fileAddedToGit.tmp')) @@ -138,7 +143,7 @@ function Test_filename_with_equals() call system('touch =fixture=.txt && git add =fixture=.txt') edit =fixture=.txt normal ggo* - write + call s:trigger_gitgutter() let expected = [ \ 'line=1 id=3000 name=GitGutterLineAdded', @@ -152,7 +157,7 @@ function Test_filename_with_square_brackets() call system('touch fix[tu]re.txt && git add fix[tu]re.txt') edit fix[tu]re.txt normal ggo* - write + call s:trigger_gitgutter() let expected = [ \ 'line=1 id=3000 name=GitGutterLineAdded', @@ -168,7 +173,7 @@ function Test_follow_symlink() call system('ln -nfs fixture.txt '.tmp) execute 'edit '.tmp 6d - write + call s:trigger_gitgutter() let expected = ['line=5 id=3000 name=GitGutterLineRemoved'] call assert_equal(expected, s:signs('symlink')) @@ -183,7 +188,7 @@ function Test_keep_alt() call assert_equal('', bufname('#')) normal ggx - doautocmd CursorHold + call s:trigger_gitgutter() call assert_equal('', bufname('#')) endfunction @@ -193,7 +198,7 @@ function Test_keep_modified() normal 5Go* call assert_equal(1, getbufvar('', '&modified')) - doautocmd CursorHold + call s:trigger_gitgutter() call assert_equal(1, getbufvar('', '&modified')) endfunction @@ -204,7 +209,7 @@ function Test_keep_op_marks() call assert_equal([0,6,1,0], getpos("'[")) call assert_equal([0,6,2,0], getpos("']")) - doautocmd CursorHold + call s:trigger_gitgutter() call assert_equal([0,6,1,0], getpos("'[")) call assert_equal([0,6,2,0], getpos("']")) @@ -218,26 +223,15 @@ endfunction function Test_orphaned_signs() execute "normal 5GoX\Y" - write + call s:trigger_gitgutter() 6d - write + call s:trigger_gitgutter() let expected = ['line=6 id=3001 name=GitGutterLineAdded'] call assert_equal(expected, s:signs('fixture.txt')) endfunction -function Test_sign_column_always() - let g:gitgutter_sign_column_always=1 - write - - let expected = ['line=9999 id=2999 name=GitGutterDummy'] - call assert_equal(expected, s:signs('fixture.txt')) - - let g:gitgutter_sign_column_always=0 -endfunction - - function Test_untracked_file_outside_repo() let tmp = tempname() call system('touch '.tmp) @@ -252,7 +246,7 @@ function Test_untracked_file_within_repo() call system('touch '.tmp) execute 'edit '.tmp normal ggo* - doautocmd CursorHold + call s:trigger_gitgutter() call assert_equal([], s:signs(tmp)) @@ -265,7 +259,7 @@ function Test_untracked_file_square_brackets_within_repo() call system('touch '.tmp) execute 'edit '.tmp normal ggo* - doautocmd CursorHold + call s:trigger_gitgutter() call assert_equal([], s:signs(tmp)) @@ -301,8 +295,19 @@ function Test_hunk_stage() call assert_equal([], s:signs('fixture.txt')) - call assert_equal([], s:git_diff()) + " Buffer is unsaved + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index ae8e546..f5c6aff 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -5 +5 @@ d', + \ '-*e', + \ '+e' + \ ] + call assert_equal(expected, s:git_diff()) + " Index has been updated let expected = [ \ 'diff --git a/fixture.txt b/fixture.txt', \ 'index f5c6aff..ae8e546 100644', @@ -313,6 +318,11 @@ function Test_hunk_stage() \ '+*e' \ ] call assert_equal(expected, s:git_diff_staged()) + + " Save the buffer + write + + call assert_equal([], s:git_diff()) endfunction @@ -329,6 +339,31 @@ function Test_hunk_stage_nearby_hunk() \ ] call assert_equal(expected, s:signs('fixture.txt')) + " Buffer is unsaved + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index 53b13df..f5c6aff 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -3,0 +4 @@ c', + \ '+d', + \ ] + call assert_equal(expected, s:git_diff()) + + " Index has been updated + let expected = [ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..53b13df 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -4 +3,0 @@ c', + \ '-d', + \ ] + call assert_equal(expected, s:git_diff_staged()) + + " Save the buffer + write + let expected = [ \ 'diff --git a/fixture.txt b/fixture.txt', \ 'index 53b13df..8fdfda7 100644', @@ -340,16 +375,6 @@ function Test_hunk_stage_nearby_hunk() \ '+z', \ ] call assert_equal(expected, s:git_diff()) - - let expected = [ - \ 'diff --git a/fixture.txt b/fixture.txt', - \ 'index f5c6aff..53b13df 100644', - \ '--- a/fixture.txt', - \ '+++ b/fixture.txt', - \ '@@ -4 +3,0 @@ c', - \ '-d', - \ ] - call assert_equal(expected, s:git_diff_staged()) endfunction @@ -359,7 +384,6 @@ function Test_hunk_undo() normal 5Gi* GitGutterUndoHunk - write " write file so we can verify git diff (--staged) call assert_equal('foo', &shell) let &shell = _shell @@ -374,8 +398,9 @@ function Test_undo_nearby_hunk() execute "normal! 2Gox\y\z" normal 2jdd normal k + call s:trigger_gitgutter() GitGutterUndoHunk - write " write file so we can verify git diff (--staged) + call s:trigger_gitgutter() let expected = [ \ 'line=3 id=3000 name=GitGutterLineAdded', @@ -384,6 +409,13 @@ function Test_undo_nearby_hunk() \ ] call assert_equal(expected, s:signs('fixture.txt')) + call assert_equal([], s:git_diff()) + + call assert_equal([], s:git_diff_staged()) + + " Save the buffer + write + let expected = [ \ 'diff --git a/fixture.txt b/fixture.txt', \ 'index f5c6aff..3fbde56 100644', @@ -396,5 +428,148 @@ function Test_undo_nearby_hunk() \ ] call assert_equal(expected, s:git_diff()) - call assert_equal([], s:git_diff_staged()) +endfunction + + +function Test_write_option() + set nowrite + + normal ggo* + call s:trigger_gitgutter() + + let expected = ["line=2 id=3000 name=GitGutterLineAdded"] + call assert_equal(expected, s:signs('fixture.txt')) + + set write +endfunction + + +function Test_inner_text_object() + execute "normal! 2Gox\y\z\\" + call s:trigger_gitgutter() + normal dic + call s:trigger_gitgutter() + + call assert_equal([], s:signs('fixture.txt')) + call assert_equal(readfile('fixture.txt'), getline(1,'$')) + + " Excludes trailing lines + normal 9Gi* + normal 10Gi* + call s:trigger_gitgutter() + execute "normal vic\" + call assert_equal([9, 10], [line("'<"), line("'>")]) +endfunction + + +function Test_around_text_object() + execute "normal! 2Gox\y\z\\" + call s:trigger_gitgutter() + normal dac + call s:trigger_gitgutter() + + call assert_equal([], s:signs('fixture.txt')) + call assert_equal(readfile('fixture.txt'), getline(1,'$')) + + " Includes trailing lines + normal 9Gi* + normal 10Gi* + call s:trigger_gitgutter() + execute "normal vac\" + call assert_equal([9, 11], [line("'<"), line("'>")]) +endfunction + + +function Test_user_autocmd() + autocmd User GitGutter let s:autocmd_user = g:gitgutter_hook_context.bufnr + + " Verify not fired when nothing changed. + let s:autocmd_user = 0 + call s:trigger_gitgutter() + call assert_equal(0, s:autocmd_user) + + " Verify fired when there was a change. + normal ggo* + let bufnr = bufnr('') + call s:trigger_gitgutter() + call assert_equal(bufnr, s:autocmd_user) +endfunction + + +function Test_fix_file_references() + " No special characters + let hunk_diff = join([ + \ 'diff --git a/fixture.txt b/fixture.txt', + \ 'index f5c6aff..3fbde56 100644', + \ '--- a/fixture.txt', + \ '+++ b/fixture.txt', + \ '@@ -2,0 +3,1 @@ b', + \ '+x' + \ ], "\n")."\n" + let filepath = 'blah.txt' + + let expected = join([ + \ 'diff --git a/blah.txt b/blah.txt', + \ 'index f5c6aff..3fbde56 100644', + \ '--- a/blah.txt', + \ '+++ b/blah.txt', + \ '@@ -2,0 +3,1 @@ b', + \ '+x' + \ ], "\n")."\n" + + call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff)) + + " diff.mnemonicPrefix; spaces in filename + let hunk_diff = join([ + \ 'diff --git i/x/cat dog w/x/cat dog', + \ 'index f5c6aff..3fbde56 100644', + \ '--- i/x/cat dog', + \ '+++ w/x/cat dog', + \ '@@ -2,0 +3,1 @@ b', + \ '+x' + \ ], "\n")."\n" + let filepath = 'blah.txt' + + let expected = join([ + \ 'diff --git i/blah.txt w/blah.txt', + \ 'index f5c6aff..3fbde56 100644', + \ '--- i/blah.txt', + \ '+++ w/blah.txt', + \ '@@ -2,0 +3,1 @@ b', + \ '+x' + \ ], "\n")."\n" + + call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff)) + + " Backslashes in filename; quotation marks + let hunk_diff = join([ + \ 'diff --git "a/C:\\Users\\FOO~1.PAR\\AppData\\Local\\Temp\\nvimJcmSv9\\11.1.vim" "b/C:\\Users\\FOO~1.PAR\\AppData\\Local\\Temp\\nvimJcmSv9\\12.1.vim"', + \ 'index f42aeb0..4930403 100644', + \ '--- "a/C:\\Users\\FOO~1.PAR\\AppData\\Local\\Temp\\nvimJcmSv9\\11.1.vim"', + \ '+++ "b/C:\\Users\\FOO~1.PAR\\AppData\\Local\\Temp\\nvimJcmSv9\\12.1.vim"', + \ '@@ -172,0 +173 @@ stuff', + \ '+x' + \ ], "\n")."\n" + let filepath = 'init.vim' + + let expected = join([ + \ 'diff --git "a/init.vim" "b/init.vim"', + \ 'index f42aeb0..4930403 100644', + \ '--- "a/init.vim"', + \ '+++ "b/init.vim"', + \ '@@ -172,0 +173 @@ stuff', + \ '+x' + \ ], "\n")."\n" + + call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff)) +endfunction + + +function Test_encoding() + call system('cp ../cp932.txt . && git add cp932.txt') + edit ++enc=cp932 cp932.txt + + call s:trigger_gitgutter() + + call assert_equal([], s:signs('cp932.txt')) endfunction diff --git a/sources_non_forked/vim-gitgutter/unplace.vim b/sources_non_forked/vim-gitgutter/unplace.vim new file mode 100644 index 00000000..a97993d9 --- /dev/null +++ b/sources_non_forked/vim-gitgutter/unplace.vim @@ -0,0 +1,27 @@ +" Measure how long it takes to unplace signs. +" +" Source this file with `:source %` or `vim -S unplace.vim` + + +let num = 500 +sign define Foo text=* + +new + +call append(0, range(1, num)) + +for i in range(1, num) + execute "sign place ".i." line=".i." name=Foo buffer=".bufnr('') +endfor + +let start = reltime() +for i in range(1, num) + execute "sign unplace ".i +endfor +let elapsed = reltime(start) + +bdelete! + +echom split(reltimestr(elapsed))[0]."s to remove ".num." signs" +echom string(reltimefloat(elapsed) * 1000 / num).' ms/sign' +echom string(float2nr(num / reltimefloat(elapsed))).' sign/s' diff --git a/sources_non_forked/vim-go/.codecov.yml b/sources_non_forked/vim-go/.codecov.yml new file mode 100644 index 00000000..e9062d50 --- /dev/null +++ b/sources_non_forked/vim-go/.codecov.yml @@ -0,0 +1,12 @@ +--- +coverage: + status: + project: + default: + target: auto + threshold: 1 + base: auto +comment: false +ignore: + - "!autoload/go/*.vim$" + - "autoload/go/*_test.vim$" diff --git a/sources_non_forked/vim-go/CHANGELOG.md b/sources_non_forked/vim-go/CHANGELOG.md index 0e3303e3..ac5d8d12 100644 --- a/sources_non_forked/vim-go/CHANGELOG.md +++ b/sources_non_forked/vim-go/CHANGELOG.md @@ -1,5 +1,15 @@ ## unplanned +## 1.17 - (March 27, 2018) + +FEATURES: + +* **Debugger support!** Add integrated support for the + [`delve`](https://github.com/derekparker/delve) debugger. Use + `:GoInstallBinaries` to install `dlv`, and see `:help go-debug` to get + started. + [[GH-1390]](https://github.com/fatih/vim-go/pull/1390) + IMPROVEMENTS: * Add descriptions to neosnippet abbrevations. @@ -8,6 +18,16 @@ IMPROVEMENTS: `gometalinter` is run automatically when saving a buffer. Whether the location list or quickfix list is used can be customized in the usual ways. [[GH-1652]](https://github.com/fatih/vim-go/pull/1652) +* Redraw the screen before executing blocking calls to gocode. + [[GH-1671]](https://github.com/fatih/vim-go/pull/1671) +* Add `fe` -> `fmt.Errorf()` snippet for NeoSnippet and UltiSnippets. + [[GH-1677]](https://github.com/fatih/vim-go/pull/1677) +* Use the async api when calling guru from neovim. + [[GH-1678]](https://github.com/fatih/vim-go/pull/1678) +* Use the async api when calling gocode to get type info. + [[GH-1697]](https://github.com/fatih/vim-go/pull/1697) +* Cache import path lookups to improve responsiveness. + [[GH-1713]](https://github.com/fatih/vim-go/pull/1713) BUG FIXES: @@ -47,7 +67,17 @@ BUG FIXES: * Show the file location of test errors when the message is empty or begins with a newline. [[GH-1664]](https://github.com/fatih/vim-go/pull/1664) - +* Fix minisnip on Windows. + [[GH-1698]](https://github.com/fatih/vim-go/pull/1698) +* Keep alternate filename when loading an autocreate template. + [[GH-1675]](https://github.com/fatih/vim-go/pull/1675) +* Parse the column number in errors correctly in vim8 and neovim. + [[GH-1716]](https://github.com/fatih/vim-go/pull/1716) +* Fix race conditions in the terminal handling for neovim. + [[GH-1721]](https://github.com/fatih/vim-go/pull/1721) +* Put the user back in the original window regardless of the value of + `splitright` after starting a neovim terminal window. + [[GH-1725]](https://github.com/fatih/vim-go/pull/1725) BACKWARDS INCOMPATIBILITIES: @@ -57,7 +87,7 @@ BACKWARDS INCOMPATIBILITIES: * `go_highlight_methods` - in favor of the following settings and changes: + in favor of the following settings and changes: * `go_highlight_functions`: This highlights now all function and method declarations (whereas previously it would also highlight function and @@ -67,6 +97,9 @@ BACKWARDS INCOMPATIBILITIES: [[GH-1557]](https://github.com/fatih/vim-go/pull/1557) * Rename g`g:go_metalinter_excludes` to `g:go_metalinter_disabled`. [[GH-1648]](https://github.com/fatih/vim-go/pull/1648) +* `:GoBuild` doesn't append the `-i` flag anymore due the recent Go 1.10 + changes that introduced a build cache. + [[GH-1701]](https://github.com/fatih/vim-go/pull/1701) ## 1.16 - (December 29, 2017) diff --git a/sources_non_forked/vim-go/README.md b/sources_non_forked/vim-go/README.md index 8566224a..30c15ac1 100644 --- a/sources_non_forked/vim-go/README.md +++ b/sources_non_forked/vim-go/README.md @@ -9,16 +9,16 @@ This plugin adds Go language support for Vim, with the following main features: * Compile your package with `:GoBuild`, install it with `:GoInstall` or test it - with `:GoTest`. Run a single tests with `:GoTestFunc`). + with `:GoTest`. Run a single test with `:GoTestFunc`). * Quickly execute your current file(s) with `:GoRun`. * Improved syntax highlighting and folding. +* Debug programs with integrated `delve` support with `:GoDebugStart`. * Completion support via `gocode`. * `gofmt` or `goimports` on save keeps the cursor position and undo history. * Go to symbol/declaration with `:GoDef`. * Look up documentation with `:GoDoc` or `:GoDocBrowser`. * Easily import packages via `:GoImport`, remove them via `:GoDrop`. -* Automatic `GOPATH` detection which works with `gb` and `godep`. Change or - display `GOPATH` with `:GoPath`. +* Precise type-safe renaming of identifiers with `:GoRename`. * See which code is covered by tests with `:GoCoverage`. * Add or remove tags on struct fields with `:GoAddTags` and `:GoRemoveTags`. * Call `gometalinter` with `:GoMetaLinter` to invoke all possible linters @@ -28,7 +28,6 @@ This plugin adds Go language support for Vim, with the following main features: errors, or make sure errors are checked with `:GoErrCheck`. * Advanced source analysis tools utilizing `guru`, such as `:GoImplements`, `:GoCallees`, and `:GoReferrers`. -* Precise type-safe renaming of identifiers with `:GoRename`. * ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more information. diff --git a/sources_non_forked/vim-go/autoload/go/cmd.vim b/sources_non_forked/vim-go/autoload/go/cmd.vim index 863a8de8..569572d5 100644 --- a/sources_non_forked/vim-go/autoload/go/cmd.vim +++ b/sources_non_forked/vim-go/autoload/go/cmd.vim @@ -17,7 +17,7 @@ function! go#cmd#Build(bang, ...) abort let args = \ ["build"] + \ map(copy(a:000), "expand(v:val)") + - \ ["-i", ".", "errors"] + \ [".", "errors"] " Vim async. if go#util#has_job() diff --git a/sources_non_forked/vim-go/autoload/go/cmd_test.vim b/sources_non_forked/vim-go/autoload/go/cmd_test.vim new file mode 100644 index 00000000..ef391100 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/cmd_test.vim @@ -0,0 +1,30 @@ +func! Test_GoBuildErrors() + try + let l:filename = 'cmd/bad.go' + let l:tmp = gotest#load_fixture(l:filename) + exe 'cd ' . l:tmp . '/src/cmd' + + " set the compiler type so that the errorformat option will be set + " correctly. + compiler go + + let expected = [{'lnum': 4, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'undefined: notafunc'}] + " clear the quickfix lists + call setqflist([], 'r') + + call go#cmd#Build(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, l:expected) + finally + call delete(l:tmp, 'rf') + endtry +endfunc + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/complete.vim b/sources_non_forked/vim-go/autoload/go/complete.vim index 32ac360e..8013f000 100644 --- a/sources_non_forked/vim-go/autoload/go/complete.vim +++ b/sources_non_forked/vim-go/autoload/go/complete.vim @@ -1,58 +1,51 @@ let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix' -function! s:gocodeCurrentBuffer() abort - let file = tempname() - call writefile(go#util#GetLines(), file) - return file -endfunction - -function! s:gocodeCommand(cmd, preargs, args) abort - for i in range(0, len(a:args) - 1) - let a:args[i] = go#util#Shellescape(a:args[i]) - endfor - for i in range(0, len(a:preargs) - 1) - let a:preargs[i] = go#util#Shellescape(a:preargs[i]) - endfor - +function! s:gocodeCommand(cmd, args) abort let bin_path = go#path#CheckBinPath("gocode") if empty(bin_path) - return + return [] endif + let socket_type = get(g:, 'go_gocode_socket_type', s:sock_type) + + let cmd = [bin_path] + let cmd = extend(cmd, ['-sock', socket_type]) + let cmd = extend(cmd, ['-f', 'vim']) + let cmd = extend(cmd, [a:cmd]) + let cmd = extend(cmd, a:args) + + return cmd +endfunction + +function! s:sync_gocode(cmd, args, input) abort " We might hit cache problems, as gocode doesn't handle different GOPATHs " well. See: https://github.com/nsf/gocode/issues/239 let old_goroot = $GOROOT let $GOROOT = go#util#env("goroot") try - let socket_type = get(g:, 'go_gocode_socket_type', s:sock_type) - let cmd = printf('%s -sock %s %s %s %s', - \ go#util#Shellescape(bin_path), - \ socket_type, - \ join(a:preargs), - \ go#util#Shellescape(a:cmd), - \ join(a:args) - \ ) + let cmd = s:gocodeCommand(a:cmd, a:args) + " gocode can sometimes be slow, so redraw now to avoid waiting for gocode + " to return before redrawing automatically. + redraw - let result = go#util#System(cmd) + let [l:result, l:err] = go#util#Exec(cmd, a:input) finally let $GOROOT = old_goroot endtry - if go#util#ShellError() != 0 - return "[\"0\", []]" - else - if &encoding != 'utf-8' - let result = iconv(result, 'utf-8', &encoding) - endif - return result + if l:err != 0 + return "[0, []]" endif + + if &encoding != 'utf-8' + let l:result = iconv(l:result, 'utf-8', &encoding) + endif + + return l:result endfunction -function! s:gocodeCurrentBufferOpt(filename) abort - return '-in=' . a:filename -endfunction - +" TODO(bc): reset when gocode isn't running let s:optionsEnabled = 0 function! s:gocodeEnableOptions() abort if s:optionsEnabled @@ -78,62 +71,161 @@ endfunction function! s:gocodeAutocomplete() abort call s:gocodeEnableOptions() - let filename = s:gocodeCurrentBuffer() - let result = s:gocodeCommand('autocomplete', - \ [s:gocodeCurrentBufferOpt(filename), '-f=vim'], - \ [expand('%:p'), go#util#OffsetCursor()]) - call delete(filename) - return result + " use the offset as is, because the cursor position is the position for + " which autocomplete candidates are needed. + return s:sync_gocode('autocomplete', + \ [expand('%:p'), go#util#OffsetCursor()], + \ go#util#GetLines()) endfunction +" go#complete#GoInfo returns the description of the identifier under the +" cursor. function! go#complete#GetInfo() abort - let offset = go#util#OffsetCursor()+1 - let filename = s:gocodeCurrentBuffer() - let result = s:gocodeCommand('autocomplete', - \ [s:gocodeCurrentBufferOpt(filename), '-f=godit'], - \ [expand('%:p'), offset]) - call delete(filename) - - " first line is: Charcount,,NumberOfCandidates, i.e: 8,,1 - " following lines are candiates, i.e: func foo(name string),,foo( - let out = split(result, '\n') - - " no candidates are found - if len(out) == 1 - return "" - endif - - " only one candidate is found - if len(out) == 2 - return split(out[1], ',,')[0] - endif - - " to many candidates are available, pick one that maches the word under the - " cursor - let infos = [] - for info in out[1:] - call add(infos, split(info, ',,')[0]) - endfor - - let wordMatch = '\<' . expand("") . '\>' - " escape single quotes in wordMatch before passing it to filter - let wordMatch = substitute(wordMatch, "'", "''", "g") - let filtered = filter(infos, "v:val =~ '".wordMatch."'") - - if len(filtered) == 1 - return filtered[0] - endif - - return "" + return s:sync_info(0) endfunction function! go#complete#Info(auto) abort + if go#util#has_job() + return s:async_info(a:auto) + else + return s:sync_info(a:auto) + endif +endfunction + +function! s:async_info(auto) + if exists("s:async_info_job") + call job_stop(s:async_info_job) + unlet s:async_info_job + endif + + let state = { + \ 'exited': 0, + \ 'exit_status': 0, + \ 'closed': 0, + \ 'messages': [], + \ 'auto': a:auto + \ } + + function! s:callback(chan, msg) dict + let l:msg = a:msg + if &encoding != 'utf-8' + let l:msg = iconv(l:msg, 'utf-8', &encoding) + endif + call add(self.messages, l:msg) + endfunction + + function! s:exit_cb(job, exitval) dict + let self.exit_status = a:exitval + let self.exited = 1 + + if self.closed + call self.complete() + endif + endfunction + + function! s:close_cb(ch) dict + let self.closed = 1 + if self.exited + call self.complete() + endif + endfunction + + function state.complete() dict + if self.exit_status != 0 + return + endif + + let result = s:info_filter(self.auto, join(self.messages, "\n")) + call s:info_complete(self.auto, result) + endfunction + + " add 1 to the offset, so that the position at the cursor will be included + " in gocode's search + let offset = go#util#OffsetCursor()+1 + + " We might hit cache problems, as gocode doesn't handle different GOPATHs + " well. See: https://github.com/nsf/gocode/issues/239 + let env = { + \ "GOROOT": go#util#env("goroot") + \ } + + let cmd = s:gocodeCommand('autocomplete', + \ [expand('%:p'), offset]) + + " TODO(bc): Don't write the buffer to a file; pass the buffer directrly to + " gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name: + " s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')} + " should work. + let options = { + \ 'env': env, + \ 'in_io': 'file', + \ 'in_name': s:gocodeFile(), + \ 'callback': funcref("s:callback", [], state), + \ 'exit_cb': funcref("s:exit_cb", [], state), + \ 'close_cb': funcref("s:close_cb", [], state) + \ } + + let s:async_info_job = job_start(cmd, options) +endfunction + +function! s:gocodeFile() + let file = tempname() + call writefile(go#util#GetLines(), file) + return file +endfunction + +function! s:sync_info(auto) " auto is true if we were called by g:go_auto_type_info's autocmd - let result = go#complete#GetInfo() - if !empty(result) - " if auto, and the result is a PANIC by gocode, hide it - if a:auto && result ==# 'PANIC PANIC PANIC' | return | endif - echo "vim-go: " | echohl Function | echon result | echohl None + + " add 1 to the offset, so that the position at the cursor will be included + " in gocode's search + let offset = go#util#OffsetCursor()+1 + + let result = s:sync_gocode('autocomplete', + \ [expand('%:p'), offset], + \ go#util#GetLines()) + + let result = s:info_filter(a:auto, result) + call s:info_complete(a:auto, result) +endfunction + +function! s:info_filter(auto, result) abort + if empty(a:result) + return "" + endif + + let l:result = eval(a:result) + if len(l:result) != 2 + return "" + endif + + let l:candidates = l:result[1] + if len(l:candidates) == 1 + " When gocode panics in vim mode, it returns + " [0, [{'word': 'PANIC', 'abbr': 'PANIC PANIC PANIC', 'info': 'PANIC PANIC PANIC'}]] + if a:auto && l:candidates[0].info ==# "PANIC PANIC PANIC" + return "" + endif + + return l:candidates[0].info + endif + + let filtered = [] + let wordMatch = '\<' . expand("") . '\>' + " escape single quotes in wordMatch before passing it to filter + let wordMatch = substitute(wordMatch, "'", "''", "g") + let filtered = filter(l:candidates, "v:val.info =~ '".wordMatch."'") + + if len(l:filtered) != 1 + return "" + endif + + return l:filtered[0].info +endfunction + +function! s:info_complete(auto, result) abort + if !empty(a:result) + echo "vim-go: " | echohl Function | echon a:result | echohl None endif endfunction @@ -142,20 +234,22 @@ function! s:trim_bracket(val) abort return a:val endfunction +let s:completions = "" function! go#complete#Complete(findstart, base) abort "findstart = 1 when we need to get the text length if a:findstart == 1 - execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() - return col('.') - g:gocomplete_completions[0] - 1 + execute "silent let s:completions = " . s:gocodeAutocomplete() + return col('.') - s:completions[0] - 1 "findstart = 0 when we need to return the list of completions else let s = getline(".")[col('.') - 1] if s =~ '[(){}\{\}]' - return map(copy(g:gocomplete_completions[1]), 's:trim_bracket(v:val)') + return map(copy(s:completions[1]), 's:trim_bracket(v:val)') endif - return g:gocomplete_completions[1] + + return s:completions[1] endif -endf +endfunction function! go#complete#ToggleAutoTypeInfo() abort if get(g:, "go_auto_type_info", 0) @@ -168,5 +262,4 @@ function! go#complete#ToggleAutoTypeInfo() abort call go#util#EchoProgress("auto type info enabled") endfunction - " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/coverage.vim b/sources_non_forked/vim-go/autoload/go/coverage.vim index 428039cb..7f362cae 100644 --- a/sources_non_forked/vim-go/autoload/go/coverage.vim +++ b/sources_non_forked/vim-go/autoload/go/coverage.vim @@ -45,7 +45,7 @@ function! go#coverage#Buffer(bang, ...) abort let l:tmpname = tempname() if get(g:, 'go_echo_command_info', 1) - echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None + call go#util#EchoProgress("testing...") endif if go#util#has_job() diff --git a/sources_non_forked/vim-go/autoload/go/debug.vim b/sources_non_forked/vim-go/autoload/go/debug.vim new file mode 100644 index 00000000..64e4f8de --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/debug.vim @@ -0,0 +1,904 @@ +scriptencoding utf-8 + +if !exists('g:go_debug_windows') + let g:go_debug_windows = { + \ 'stack': 'leftabove 20vnew', + \ 'out': 'botright 10new', + \ 'vars': 'leftabove 30vnew', + \ } +endif + +if !exists('g:go_debug_address') + let g:go_debug_address = '127.0.0.1:8181' +endif + +if !exists('s:state') + let s:state = { + \ 'rpcid': 1, + \ 'running': 0, + \ 'breakpoint': {}, + \ 'currentThread': {}, + \ 'localVars': {}, + \ 'functionArgs': {}, + \ 'message': [], + \ 'is_test': 0, + \} + + if go#util#HasDebug('debugger-state') + let g:go_debug_diag = s:state + endif +endif + +if !exists('s:start_args') + let s:start_args = [] +endif + +function! s:groutineID() abort + return s:state['currentThread'].goroutineID +endfunction + +function! s:exit(job, status) abort + if has_key(s:state, 'job') + call remove(s:state, 'job') + endif + call s:clearState() + if a:status > 0 + call go#util#EchoError(s:state['message']) + endif +endfunction + +function! s:logger(prefix, ch, msg) abort + let l:cur_win = bufwinnr('') + let l:log_win = bufwinnr(bufnr('__GODEBUG_OUTPUT__')) + if l:log_win == -1 + return + endif + exe l:log_win 'wincmd w' + + try + setlocal modifiable + if getline(1) == '' + call setline('$', a:prefix . a:msg) + else + call append('$', a:prefix . a:msg) + endif + normal! G + setlocal nomodifiable + finally + exe l:cur_win 'wincmd w' + endtry +endfunction + +function! s:call_jsonrpc(method, ...) abort + if go#util#HasDebug('debugger-commands') + if !exists('g:go_debug_commands') + let g:go_debug_commands = [] + endif + echom 'sending to dlv ' . a:method + endif + + if len(a:000) > 0 && type(a:000[0]) == v:t_func + let Cb = a:000[0] + let args = a:000[1:] + else + let Cb = v:none + let args = a:000 + endif + let s:state['rpcid'] += 1 + let req_json = json_encode({ + \ 'id': s:state['rpcid'], + \ 'method': a:method, + \ 'params': args, + \}) + + try + " Use callback + if type(Cb) == v:t_func + let s:ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'callback': Cb}) + call ch_sendraw(s:ch, req_json) + + if go#util#HasDebug('debugger-commands') + let g:go_debug_commands = add(g:go_debug_commands, { + \ 'request': req_json, + \ 'response': Cb, + \ }) + endif + return + endif + + let ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'timeout': 20000}) + call ch_sendraw(ch, req_json) + let resp_json = ch_readraw(ch) + + if go#util#HasDebug('debugger-commands') + let g:go_debug_commands = add(g:go_debug_commands, { + \ 'request': req_json, + \ 'response': resp_json, + \ }) + endif + + let obj = json_decode(resp_json) + if type(obj) == v:t_dict && has_key(obj, 'error') && !empty(obj.error) + throw obj.error + endif + return obj + catch + throw substitute(v:exception, '^Vim', '', '') + endtry +endfunction + +" Update the location of the current breakpoint or line we're halted on based on +" response from dlv. +function! s:update_breakpoint(res) abort + if type(a:res) ==# v:t_none + return + endif + + let state = a:res.result.State + if !has_key(state, 'currentThread') + return + endif + + let s:state['currentThread'] = state.currentThread + let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"') + if len(bufs) == 0 + return + endif + + exe bufs[0][0] 'wincmd w' + let filename = state.currentThread.file + let linenr = state.currentThread.line + let oldfile = fnamemodify(expand('%'), ':p:gs!\\!/!') + if oldfile != filename + silent! exe 'edit' filename + endif + silent! exe 'norm!' linenr.'G' + silent! normal! zvzz + silent! sign unplace 9999 + silent! exe 'sign place 9999 line=' . linenr . ' name=godebugcurline file=' . filename +endfunction + +" Populate the stacktrace window. +function! s:show_stacktrace(res) abort + if !has_key(a:res, 'result') + return + endif + + let l:stack_win = bufwinnr(bufnr('__GODEBUG_STACKTRACE__')) + if l:stack_win == -1 + return + endif + + let l:cur_win = bufwinnr('') + exe l:stack_win 'wincmd w' + + try + setlocal modifiable + silent %delete _ + for i in range(len(a:res.result.Locations)) + let loc = a:res.result.Locations[i] + call setline(i+1, printf('%s - %s:%d', loc.function.name, fnamemodify(loc.file, ':p'), loc.line)) + endfor + finally + setlocal nomodifiable + exe l:cur_win 'wincmd w' + endtry +endfunction + +" Populate the variable window. +function! s:show_variables() abort + let l:var_win = bufwinnr(bufnr('__GODEBUG_VARIABLES__')) + if l:var_win == -1 + return + endif + + let l:cur_win = bufwinnr('') + exe l:var_win 'wincmd w' + + try + setlocal modifiable + silent %delete _ + + let v = [] + let v += ['# Local Variables'] + if type(get(s:state, 'localVars', [])) is type([]) + for c in s:state['localVars'] + let v += split(s:eval_tree(c, 0), "\n") + endfor + endif + + let v += [''] + let v += ['# Function Arguments'] + if type(get(s:state, 'functionArgs', [])) is type([]) + for c in s:state['functionArgs'] + let v += split(s:eval_tree(c, 0), "\n") + endfor + endif + + call setline(1, v) + finally + setlocal nomodifiable + exe l:cur_win 'wincmd w' + endtry +endfunction + +function! s:clearState() abort + let s:state['currentThread'] = {} + let s:state['localVars'] = {} + let s:state['functionArgs'] = {} + let s:state['message'] = [] + silent! sign unplace 9999 +endfunction + +function! s:stop() abort + call s:clearState() + if has_key(s:state, 'job') + call job_stop(s:state['job']) + call remove(s:state, 'job') + endif +endfunction + +function! go#debug#Stop() abort + " Remove signs. + for k in keys(s:state['breakpoint']) + let bt = s:state['breakpoint'][k] + if bt.id >= 0 + silent exe 'sign unplace ' . bt.id + endif + endfor + + " Remove all commands and add back the default commands. + for k in map(split(execute('command GoDebug'), "\n")[1:], 'matchstr(v:val, "^\\s*\\zs\\S\\+")') + exe 'delcommand' k + endfor + command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start(0, ) + command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start(1, ) + command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint() + + " Remove all mappings. + for k in map(split(execute('map (go-debug-'), "\n")[1:], 'matchstr(v:val, "^n\\s\\+\\zs\\S\\+")') + exe 'unmap' k + endfor + + call s:stop() + + let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"') + if len(bufs) > 0 + exe bufs[0][0] 'wincmd w' + else + wincmd p + endif + silent! exe bufwinnr(bufnr('__GODEBUG_STACKTRACE__')) 'wincmd c' + silent! exe bufwinnr(bufnr('__GODEBUG_VARIABLES__')) 'wincmd c' + silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c' + + set noballooneval + set balloonexpr= +endfunction + +function! s:goto_file() abort + let m = matchlist(getline('.'), ' - \(.*\):\([0-9]\+\)$') + if m[1] == '' + return + endif + let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"') + if len(bufs) == 0 + return + endif + exe bufs[0][0] 'wincmd w' + let filename = m[1] + let linenr = m[2] + let oldfile = fnamemodify(expand('%'), ':p:gs!\\!/!') + if oldfile != filename + silent! exe 'edit' filename + endif + silent! exe 'norm!' linenr.'G' + silent! normal! zvzz +endfunction + +function! s:delete_expands() + let nr = line('.') + while 1 + let l = getline(nr+1) + if empty(l) || l =~ '^\S' + return + endif + silent! exe (nr+1) . 'd _' + endwhile + silent! exe 'norm!' nr.'G' +endfunction + +function! s:expand_var() abort + " Get name from struct line. + let name = matchstr(getline('.'), '^[^:]\+\ze: [a-zA-Z0-9\.·]\+{\.\.\.}$') + " Anonymous struct + if name == '' + let name = matchstr(getline('.'), '^[^:]\+\ze: struct {.\{-}}$') + endif + + if name != '' + setlocal modifiable + let not_open = getline(line('.')+1) !~ '^ ' + let l = line('.') + call s:delete_expands() + + if not_open + call append(l, split(s:eval(name), "\n")[1:]) + endif + silent! exe 'norm!' l.'G' + setlocal nomodifiable + return + endif + + " Expand maps + let m = matchlist(getline('.'), '^[^:]\+\ze: map.\{-}\[\(\d\+\)\]$') + if len(m) > 0 && m[1] != '' + setlocal modifiable + let not_open = getline(line('.')+1) !~ '^ ' + let l = line('.') + call s:delete_expands() + if not_open + " TODO: Not sure how to do this yet... Need to get keys of the map. + " let vs = '' + " for i in range(0, min([10, m[1]-1])) + " let vs .= ' ' . s:eval(printf("%s[%s]", m[0], )) + " endfor + " call append(l, split(vs, "\n")) + endif + + silent! exe 'norm!' l.'G' + setlocal nomodifiable + return + endif + + " Expand string. + let m = matchlist(getline('.'), '^\([^:]\+\)\ze: \(string\)\[\([0-9]\+\)\]\(: .\{-}\)\?$') + if len(m) > 0 && m[1] != '' + setlocal modifiable + let not_open = getline(line('.')+1) !~ '^ ' + let l = line('.') + call s:delete_expands() + + if not_open + let vs = '' + for i in range(0, min([10, m[3]-1])) + let vs .= ' ' . s:eval(m[1] . '[' . i . ']') + endfor + call append(l, split(vs, "\n")) + endif + + silent! exe 'norm!' l.'G' + setlocal nomodifiable + return + endif + + " Expand slice. + let m = matchlist(getline('.'), '^\([^:]\+\)\ze: \(\[\]\w\{-}\)\[\([0-9]\+\)\]$') + if len(m) > 0 && m[1] != '' + setlocal modifiable + let not_open = getline(line('.')+1) !~ '^ ' + let l = line('.') + call s:delete_expands() + + if not_open + let vs = '' + for i in range(0, min([10, m[3]-1])) + let vs .= ' ' . s:eval(m[1] . '[' . i . ']') + endfor + call append(l, split(vs, "\n")) + endif + silent! exe 'norm!' l.'G' + setlocal nomodifiable + return + endif +endfunction + +function! s:start_cb(ch, json) abort + let res = json_decode(a:json) + if type(res) == v:t_dict && has_key(res, 'error') && !empty(res.error) + throw res.error + endif + if empty(res) || !has_key(res, 'result') + return + endif + for bt in res.result.Breakpoints + if bt.id >= 0 + let s:state['breakpoint'][bt.id] = bt + exe 'sign place '. bt.id .' line=' . bt.line . ' name=godebugbreakpoint file=' . bt.file + endif + endfor + + let oldbuf = bufnr('%') + silent! only! + + let winnum = bufwinnr(bufnr('__GODEBUG_STACKTRACE__')) + if winnum != -1 + return + endif + + if exists('g:go_debug_windows["stack"]') && g:go_debug_windows['stack'] != '' + exe 'silent ' . g:go_debug_windows['stack'] + silent file `='__GODEBUG_STACKTRACE__'` + setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline + setlocal filetype=godebugstacktrace + nmap :call goto_file() + nmap q (go-debug-stop) + endif + + if exists('g:go_debug_windows["out"]') && g:go_debug_windows['out'] != '' + exe 'silent ' . g:go_debug_windows['out'] + silent file `='__GODEBUG_OUTPUT__'` + setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline + setlocal filetype=godebugoutput + nmap q (go-debug-stop) + endif + + if exists('g:go_debug_windows["vars"]') && g:go_debug_windows['vars'] != '' + exe 'silent ' . g:go_debug_windows['vars'] + silent file `='__GODEBUG_VARIABLES__'` + setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline + setlocal filetype=godebugvariables + call append(0, ["# Local Variables", "", "# Function Arguments"]) + nmap :call expand_var() + nmap q (go-debug-stop) + endif + + silent! delcommand GoDebugStart + silent! delcommand GoDebugTest + command! -nargs=0 GoDebugContinue call go#debug#Stack('continue') + command! -nargs=0 GoDebugNext call go#debug#Stack('next') + command! -nargs=0 GoDebugStep call go#debug#Stack('step') + command! -nargs=0 GoDebugStepOut call go#debug#Stack('stepOut') + command! -nargs=0 GoDebugRestart call go#debug#Restart() + command! -nargs=0 GoDebugStop call go#debug#Stop() + command! -nargs=* GoDebugSet call go#debug#Set() + command! -nargs=1 GoDebugPrint call go#debug#Print() + + nnoremap (go-debug-breakpoint) :call go#debug#Breakpoint() + nnoremap (go-debug-next) :call go#debug#Stack('next') + nnoremap (go-debug-step) :call go#debug#Stack('step') + nnoremap (go-debug-stepout) :call go#debug#Stack('stepout') + nnoremap (go-debug-continue) :call go#debug#Stack('continue') + nnoremap (go-debug-stop) :call go#debug#Stop() + nnoremap (go-debug-print) :call go#debug#Print(expand('')) + + nmap (go-debug-continue) + nmap (go-debug-print) + nmap (go-debug-breakpoint) + nmap (go-debug-next) + nmap (go-debug-step) + + set balloonexpr=go#debug#BalloonExpr() + set ballooneval + + exe bufwinnr(oldbuf) 'wincmd w' +endfunction + +function! s:err_cb(ch, msg) abort + call go#util#EchoError(a:msg) + let s:state['message'] += [a:msg] +endfunction + +function! s:out_cb(ch, msg) abort + call go#util#EchoProgress(a:msg) + let s:state['message'] += [a:msg] + + " TODO: why do this in this callback? + if stridx(a:msg, g:go_debug_address) != -1 + call ch_setoptions(a:ch, { + \ 'out_cb': function('s:logger', ['OUT: ']), + \ 'err_cb': function('s:logger', ['ERR: ']), + \}) + + " Tell dlv about the breakpoints that the user added before delve started. + let l:breaks = copy(s:state.breakpoint) + let s:state['breakpoint'] = {} + for l:bt in values(l:breaks) + call go#debug#Breakpoint(bt.line) + endfor + + call s:call_jsonrpc('RPCServer.ListBreakpoints', function('s:start_cb')) + endif +endfunction + +" Start the debug mode. The first argument is the package name to compile and +" debug, anything else will be passed to the running program. +function! go#debug#Start(is_test, ...) abort + if has('nvim') + call go#util#EchoError('This feature only works in Vim for now; Neovim is not (yet) supported. Sorry :-(') + return + endif + if !go#util#has_job() + call go#util#EchoError('This feature requires Vim 8.0.0087 or newer with +job.') + return + endif + + " It's already running. + if has_key(s:state, 'job') && job_status(s:state['job']) == 'run' + return + endif + + let s:start_args = a:000 + + if go#util#HasDebug('debugger-state') + let g:go_debug_diag = s:state + endif + + " cd in to test directory; this is also what running "go test" does. + if a:is_test + lcd %:p:h + endif + + let s:state.is_test = a:is_test + + let dlv = go#path#CheckBinPath("dlv") + if empty(dlv) + return + endif + + try + if len(a:000) > 0 + let l:pkgname = a:1 + " Expand .; otherwise this won't work from a tmp dir. + if l:pkgname[0] == '.' + let l:pkgname = go#package#FromPath(getcwd()) . l:pkgname[1:] + endif + else + let l:pkgname = go#package#FromPath(getcwd()) + endif + + let l:args = [] + if len(a:000) > 1 + let l:args = ['--'] + a:000[1:] + endif + + let l:cmd = [ + \ dlv, + \ (a:is_test ? 'test' : 'debug'), + \ '--output', tempname(), + \ '--headless', + \ '--api-version', '2', + \ '--log', + \ '--listen', g:go_debug_address, + \ '--accept-multiclient', + \] + if get(g:, 'go_build_tags', '') isnot '' + let l:cmd += ['--build-flags', '--tags=' . g:go_build_tags] + endif + let l:cmd += l:args + + call go#util#EchoProgress('Starting GoDebug...') + let s:state['message'] = [] + let s:state['job'] = job_start(l:cmd, { + \ 'out_cb': function('s:out_cb'), + \ 'err_cb': function('s:err_cb'), + \ 'exit_cb': function('s:exit'), + \ 'stoponexit': 'kill', + \}) + catch + call go#util#EchoError(v:exception) + endtry +endfunction + +" Translate a reflect kind constant to a human string. +function! s:reflect_kind(k) + " Kind constants from Go's reflect package. + return [ + \ 'Invalid Kind', + \ 'Bool', + \ 'Int', + \ 'Int8', + \ 'Int16', + \ 'Int32', + \ 'Int64', + \ 'Uint', + \ 'Uint8', + \ 'Uint16', + \ 'Uint32', + \ 'Uint64', + \ 'Uintptr', + \ 'Float32', + \ 'Float64', + \ 'Complex64', + \ 'Complex128', + \ 'Array', + \ 'Chan', + \ 'Func', + \ 'Interface', + \ 'Map', + \ 'Ptr', + \ 'Slice', + \ 'String', + \ 'Struct', + \ 'UnsafePointer', + \ ][a:k] +endfunction + +function! s:eval_tree(var, nest) abort + if a:var.name =~ '^\~' + return '' + endif + let nest = a:nest + let v = '' + let kind = s:reflect_kind(a:var.kind) + if !empty(a:var.name) + let v .= repeat(' ', nest) . a:var.name . ': ' + + if kind == 'Bool' + let v .= printf("%s\n", a:var.value) + + elseif kind == 'Struct' + " Anonymous struct + if a:var.type[:8] == 'struct { ' + let v .= printf("%s\n", a:var.type) + else + let v .= printf("%s{...}\n", a:var.type) + endif + + elseif kind == 'String' + let v .= printf("%s[%d]%s\n", a:var.type, a:var.len, + \ len(a:var.value) > 0 ? ': ' . a:var.value : '') + + elseif kind == 'Slice' || kind == 'String' || kind == 'Map' || kind == 'Array' + let v .= printf("%s[%d]\n", a:var.type, a:var.len) + + elseif kind == 'Chan' || kind == 'Func' || kind == 'Interface' + let v .= printf("%s\n", a:var.type) + + elseif kind == 'Ptr' + " TODO: We can do something more useful here. + let v .= printf("%s\n", a:var.type) + + elseif kind == 'Complex64' || kind == 'Complex128' + let v .= printf("%s%s\n", a:var.type, a:var.value) + + " Int, Float + else + let v .= printf("%s(%s)\n", a:var.type, a:var.value) + endif + else + let nest -= 1 + endif + + if index(['Chan', 'Complex64', 'Complex128'], kind) == -1 && a:var.type != 'error' + for c in a:var.children + let v .= s:eval_tree(c, nest+1) + endfor + endif + return v +endfunction + +function! s:eval(arg) abort + try + let res = s:call_jsonrpc('RPCServer.State') + let goroutineID = res.result.State.currentThread.goroutineID + let res = s:call_jsonrpc('RPCServer.Eval', { + \ 'expr': a:arg, + \ 'scope': {'GoroutineID': goroutineID} + \ }) + return s:eval_tree(res.result.Variable, 0) + catch + call go#util#EchoError(v:exception) + return '' + endtry +endfunction + +function! go#debug#BalloonExpr() abort + silent! let l:v = s:eval(v:beval_text) + return l:v +endfunction + +function! go#debug#Print(arg) abort + try + echo substitute(s:eval(a:arg), "\n$", "", 0) + catch + call go#util#EchoError(v:exception) + endtry +endfunction + +function! s:update_variables() abort + " FollowPointers requests pointers to be automatically dereferenced. + " MaxVariableRecurse is how far to recurse when evaluating nested types. + " MaxStringLen is the maximum number of bytes read from a string + " MaxArrayValues is the maximum number of elements read from an array, a slice or a map. + " MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields. + let l:cfg = { + \ 'scope': {'GoroutineID': s:groutineID()}, + \ 'cfg': {'MaxStringLen': 20, 'MaxArrayValues': 20} + \ } + + try + let res = s:call_jsonrpc('RPCServer.ListLocalVars', l:cfg) + let s:state['localVars'] = res.result['Variables'] + catch + call go#util#EchoError(v:exception) + endtry + + try + let res = s:call_jsonrpc('RPCServer.ListFunctionArgs', l:cfg) + let s:state['functionArgs'] = res.result['Args'] + catch + call go#util#EchoError(v:exception) + endtry + + call s:show_variables() +endfunction + +function! go#debug#Set(symbol, value) abort + try + let res = s:call_jsonrpc('RPCServer.State') + let goroutineID = res.result.State.currentThread.goroutineID + call s:call_jsonrpc('RPCServer.Set', { + \ 'symbol': a:symbol, + \ 'value': a:value, + \ 'scope': {'GoroutineID': goroutineID} + \ }) + catch + call go#util#EchoError(v:exception) + endtry + + call s:update_variables() +endfunction + +function! s:update_stacktrace() abort + try + let res = s:call_jsonrpc('RPCServer.Stacktrace', {'id': s:groutineID(), 'depth': 5}) + call s:show_stacktrace(res) + catch + call go#util#EchoError(v:exception) + endtry +endfunction + +function! s:stack_cb(ch, json) abort + let s:stack_name = '' + let res = json_decode(a:json) + if type(res) == v:t_dict && has_key(res, 'error') && !empty(res.error) + call go#util#EchoError(res.error) + call s:clearState() + call go#debug#Restart() + return + endif + + if empty(res) || !has_key(res, 'result') + return + endif + call s:update_breakpoint(res) + call s:update_stacktrace() + call s:update_variables() +endfunction + +" Send a command to change the cursor location to Delve. +" +" a:name must be one of continue, next, step, or stepOut. +function! go#debug#Stack(name) abort + let l:name = a:name + + " Run continue if the program hasn't started yet. + if s:state.running is 0 + let s:state.running = 1 + let l:name = 'continue' + endif + + " Add a breakpoint to the main.Main if the user didn't define any. + if len(s:state['breakpoint']) is 0 + if go#debug#Breakpoint() isnot 0 + let s:state.running = 0 + return + endif + endif + + try + " TODO: document why this is needed. + if l:name is# 'next' && get(s:, 'stack_name', '') is# 'next' + call s:call_jsonrpc('RPCServer.CancelNext') + endif + let s:stack_name = l:name + call s:call_jsonrpc('RPCServer.Command', function('s:stack_cb'), {'name': l:name}) + catch + call go#util#EchoError(v:exception) + endtry +endfunction + +function! go#debug#Restart() abort + try + call job_stop(s:state['job']) + while has_key(s:state, 'job') && job_status(s:state['job']) is# 'run' + sleep 50m + endwhile + + let l:breaks = s:state['breakpoint'] + let s:state = { + \ 'rpcid': 1, + \ 'running': 0, + \ 'breakpoint': {}, + \ 'currentThread': {}, + \ 'localVars': {}, + \ 'functionArgs': {}, + \ 'message': [], + \} + + " Preserve breakpoints. + for bt in values(l:breaks) + " TODO: should use correct filename + exe 'sign unplace '. bt.id .' file=' . bt.file + call go#debug#Breakpoint(bt.line) + endfor + call call('go#debug#Start', s:start_args) + catch + call go#util#EchoError(v:exception) + endtry +endfunction + +" Report if debugger mode is active. +function! s:isActive() + return len(s:state['message']) > 0 +endfunction + +" Toggle breakpoint. Returns 0 on success and 1 on failure. +function! go#debug#Breakpoint(...) abort + let l:filename = fnamemodify(expand('%'), ':p:gs!\\!/!') + + " Get line number from argument. + if len(a:000) > 0 + let linenr = str2nr(a:1) + if linenr is 0 + call go#util#EchoError('not a number: ' . a:1) + return 0 + endif + else + let linenr = line('.') + endif + + try + " Check if we already have a breakpoint for this line. + let found = v:none + for k in keys(s:state.breakpoint) + let bt = s:state.breakpoint[k] + if bt.file == l:filename && bt.line == linenr + let found = bt + break + endif + endfor + + " Remove breakpoint. + if type(found) == v:t_dict + call remove(s:state['breakpoint'], bt.id) + exe 'sign unplace '. found.id .' file=' . found.file + if s:isActive() + let res = s:call_jsonrpc('RPCServer.ClearBreakpoint', {'id': found.id}) + endif + " Add breakpoint. + else + if s:isActive() + let res = s:call_jsonrpc('RPCServer.CreateBreakpoint', {'Breakpoint': {'file': l:filename, 'line': linenr}}) + let bt = res.result.Breakpoint + exe 'sign place '. bt.id .' line=' . bt.line . ' name=godebugbreakpoint file=' . bt.file + let s:state['breakpoint'][bt.id] = bt + else + let id = len(s:state['breakpoint']) + 1 + let s:state['breakpoint'][id] = {'id': id, 'file': l:filename, 'line': linenr} + exe 'sign place '. id .' line=' . linenr . ' name=godebugbreakpoint file=' . l:filename + endif + endif + catch + call go#util#EchoError(v:exception) + return 1 + endtry + + return 0 +endfunction + +sign define godebugbreakpoint text=> texthl=GoDebugBreakpoint +sign define godebugcurline text== linehl=GoDebugCurrent texthl=GoDebugCurrent + +fun! s:hi() + hi GoDebugBreakpoint term=standout ctermbg=117 ctermfg=0 guibg=#BAD4F5 guifg=Black + hi GoDebugCurrent term=reverse ctermbg=12 ctermfg=7 guibg=DarkBlue guifg=White +endfun +augroup vim-go-breakpoint + autocmd! + autocmd ColorScheme * call s:hi() +augroup end +call s:hi() + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/fmt.vim b/sources_non_forked/vim-go/autoload/go/fmt.vim index 42d04191..08fc3b3e 100644 --- a/sources_non_forked/vim-go/autoload/go/fmt.vim +++ b/sources_non_forked/vim-go/autoload/go/fmt.vim @@ -148,7 +148,6 @@ function! go#fmt#update_file(source, target) if has_key(l:list_title, "title") && l:list_title['title'] == "Format" call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) endif endfunction diff --git a/sources_non_forked/vim-go/autoload/go/guru.vim b/sources_non_forked/vim-go/autoload/go/guru.vim index e8640325..3e735ec1 100644 --- a/sources_non_forked/vim-go/autoload/go/guru.vim +++ b/sources_non_forked/vim-go/autoload/go/guru.vim @@ -78,7 +78,7 @@ function! s:guru_cmd(args) range abort let scopes = go#util#StripTrailingSlash(scopes) " create shell-safe entries of the list - if !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif + if !has("nvim") && !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif " guru expect a comma-separated list of patterns, construct it let l:scope = join(scopes, ",") @@ -129,7 +129,7 @@ function! s:sync_guru(args) abort endif if has_key(a:args, 'custom_parse') - call a:args.custom_parse(go#util#ShellError(), out) + call a:args.custom_parse(go#util#ShellError(), out, a:args.mode) else call s:parse_guru_output(go#util#ShellError(), out, a:args.mode) endif @@ -137,6 +137,33 @@ function! s:sync_guru(args) abort return out endfunc +" use vim or neovim job api as appropriate +function! s:job_start(cmd, start_options) abort + if go#util#has_job() + return job_start(a:cmd, a:start_options) + endif + + let opts = {'stdout_buffered': v:true, 'stderr_buffered': v:true} + function opts.on_stdout(job_id, data, event) closure + call a:start_options.callback(a:job_id, join(a:data, "\n")) + endfunction + function opts.on_stderr(job_id, data, event) closure + call a:start_options.callback(a:job_id, join(a:data, "\n")) + endfunction + function opts.on_exit(job_id, exit_code, event) closure + call a:start_options.exit_cb(a:job_id, a:exit_code) + call a:start_options.close_cb(a:job_id) + endfunction + + " use a shell for input redirection if needed + let cmd = a:cmd + if has_key(a:start_options, 'in_io') && a:start_options.in_io ==# 'file' && !empty(a:start_options.in_name) + let cmd = ['/bin/sh', '-c', join(a:cmd, ' ') . ' <' . a:start_options.in_name] + endif + + return jobstart(cmd, opts) +endfunction + " async_guru runs guru in async mode with the given arguments function! s:async_guru(args) abort let result = s:guru_cmd(a:args) @@ -145,8 +172,6 @@ function! s:async_guru(args) abort return endif - let status_dir = expand('%:p:h') - let statusline_type = printf("%s", a:args.mode) if !has_key(a:args, 'disable_progress') if a:args.needs_scope @@ -155,60 +180,64 @@ function! s:async_guru(args) abort endif endif - let messages = [] - function! s:callback(chan, msg) closure - call add(messages, a:msg) + let state = { + \ 'status_dir': expand('%:p:h'), + \ 'statusline_type': printf("%s", a:args.mode), + \ 'mode': a:args.mode, + \ 'status': {}, + \ 'exitval': 0, + \ 'closed': 0, + \ 'exited': 0, + \ 'messages': [], + \ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output")) + \ } + + function! s:callback(chan, msg) dict + call add(self.messages, a:msg) endfunction - let status = {} - let exitval = 0 - let closed = 0 - let exited = 0 - - function! s:exit_cb(job, exitval) closure - let exited = 1 + function! s:exit_cb(job, exitval) dict + let self.exited = 1 let status = { \ 'desc': 'last status', - \ 'type': statusline_type, + \ 'type': self.statusline_type, \ 'state': "finished", \ } if a:exitval - let exitval = a:exitval + let self.exitval = a:exitval let status.state = "failed" endif - call go#statusline#Update(status_dir, status) + call go#statusline#Update(self.status_dir, status) - if closed - call s:complete() + if self.closed + call self.complete() endif endfunction - function! s:close_cb(ch) closure - let closed = 1 + function! s:close_cb(ch) dict + let self.closed = 1 - if exited - call s:complete() + if self.exited + call self.complete() endif endfunction - function! s:complete() closure - let out = join(messages, "\n") + function state.complete() dict + let out = join(self.messages, "\n") - if has_key(a:args, 'custom_parse') - call a:args.custom_parse(exitval, out) - else - call s:parse_guru_output(exitval, out, a:args.mode) - endif + call self.parse(self.exitval, out, self.mode) endfunction + " explicitly bind the callbacks to state so that self within them always + " refers to state. See :help Partial for more information. let start_options = { - \ 'callback': funcref("s:callback"), - \ 'exit_cb': funcref("s:exit_cb"), - \ 'close_cb': funcref("s:close_cb"), - \ } + \ 'callback': function('s:callback', [], state), + \ 'exit_cb': function('s:exit_cb', [], state), + \ 'close_cb': function('s:close_cb', [], state) + \ } if has_key(result, 'stdin_content') let l:tmpname = tempname() @@ -217,18 +246,18 @@ function! s:async_guru(args) abort let l:start_options.in_name = l:tmpname endif - call go#statusline#Update(status_dir, { + call go#statusline#Update(state.status_dir, { \ 'desc': "current status", - \ 'type': statusline_type, + \ 'type': state.statusline_type, \ 'state': "analysing", \}) - return job_start(result.cmd, start_options) + return s:job_start(result.cmd, start_options) endfunc " run_guru runs the given guru argument function! s:run_guru(args) abort - if go#util#has_job() + if has('nvim') || go#util#has_job() let res = s:async_guru(a:args) else let res = s:sync_guru(a:args) @@ -289,7 +318,7 @@ function! go#guru#DescribeInfo() abort return endif - function! s:info(exit_val, output) + function! s:info(exit_val, output, mode) if a:exit_val != 0 return endif @@ -464,10 +493,6 @@ function! go#guru#Referrers(selected) abort call s:run_guru(args) endfunction -function! go#guru#SameIdsTimer() abort - call timer_start(200, function('go#guru#SameIds'), {'repeat': -1}) -endfunction - function! go#guru#SameIds() abort " we use matchaddpos() which was introduce with 7.4.330, be sure we have " it: http://ftp.vim.org/vim/patches/7.4/7.4.330 @@ -495,7 +520,7 @@ function! go#guru#SameIds() abort call s:run_guru(args) endfunction -function! s:same_ids_highlight(exit_val, output) abort +function! s:same_ids_highlight(exit_val, output, mode) abort call go#guru#ClearSameIds() " run after calling guru to reduce flicker. if a:output[0] !=# '{' diff --git a/sources_non_forked/vim-go/autoload/go/job.vim b/sources_non_forked/vim-go/autoload/go/job.vim index 987c0ec1..62214b41 100644 --- a/sources_non_forked/vim-go/autoload/go/job.vim +++ b/sources_non_forked/vim-go/autoload/go/job.vim @@ -19,10 +19,6 @@ " list of messages received from the channel. The default value will " process the messages and manage the error list after the job exits and " the channel is closed. -" 'callback': -" A function to call when there is a message to read from the job's -" channel. The function will be passed two arguments: the channel and a -" message. See job-callback. " The return value is a dictionary with these keys: " 'callback': @@ -36,43 +32,46 @@ " job-close_cb. function go#job#Spawn(args) let cbs = {} - - let winnr = winnr() - let dir = getcwd() - let jobdir = fnameescape(expand("%:p:h")) - let messages = [] - let args = a:args.cmd - let bang = 0 - let for = "_job" + let state = { + \ 'winnr': winnr(), + \ 'dir': getcwd(), + \ 'jobdir': fnameescape(expand("%:p:h")), + \ 'messages': [], + \ 'args': a:args.cmd, + \ 'bang': 0, + \ 'for': "_job", + \ 'exited': 0, + \ 'exit_status': 0, + \ 'closed': 0, + \ 'errorformat': &errorformat + \ } if has_key(a:args, 'bang') - let l:bang = a:args.bang + let state.bang = a:args.bang endif if has_key(a:args, 'for') - let l:for = a:args.for + let state.for = a:args.for endif - let l:exited = 0 - let l:exit_status = 0 - let l:closed = 0 - - function! s:NopComplete(job, exit_status, data) + " do nothing in state.complete by default. + function state.complete(job, exit_status, data) endfunction - let Complete = funcref('s:NopComplete') - if has_key(a:args, 'complete') - let Complete = a:args.complete + let state.complete = a:args.complete endif - function cbs.callback(chan, msg) dict closure - call add(messages, a:msg) + function! s:callback(chan, msg) dict + call add(self.messages, a:msg) endfunction + " explicitly bind callback to state so that within it, self will + " always refer to state. See :help Partial for more information. + let cbs.callback = function('s:callback', [], state) - function cbs.exit_cb(job, exitval) dict closure - let exit_status = a:exitval - let exited = 1 + function! s:exit_cb(job, exitval) dict + let self.exit_status = a:exitval + let self.exited = 1 if get(g:, 'go_echo_command_info', 1) if a:exitval == 0 @@ -82,56 +81,63 @@ function go#job#Spawn(args) endif endif - if closed - call Complete(a:job, exit_status, messages) - call s:show_errors(a:job, exit_status, messages) + if self.closed + call self.complete(a:job, self.exit_status, self.messages) + call self.show_errors(a:job, self.exit_status, self.messages) endif endfunction + " explicitly bind exit_cb to state so that within it, self will always refer + " to state. See :help Partial for more information. + let cbs.exit_cb = function('s:exit_cb', [], state) - function cbs.close_cb(ch) dict closure - let closed = 1 + function! s:close_cb(ch) dict + let self.closed = 1 - if exited + if self.exited let job = ch_getjob(a:ch) - call Complete(job, exit_status, messages) - call s:show_errors(job, exit_status, messages) + call self.complete(job, self.exit_status, self.messages) + call self.show_errors(job, self.exit_status, self.messages) endif endfunction + " explicitly bind close_cb to state so that within it, self will + " always refer to state. See :help Partial for more information. + let cbs.close_cb = function('s:close_cb', [], state) - function! s:show_errors(job, exit_status, data) closure - let l:listtype = go#list#Type(for) + function state.show_errors(job, exit_status, data) + let l:listtype = go#list#Type(self.for) if a:exit_status == 0 call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) return endif - let l:listtype = go#list#Type(for) + let l:listtype = go#list#Type(self.for) if len(a:data) == 0 call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) return endif + let out = join(self.messages, "\n") + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' try - execute cd jobdir - let errors = go#tool#ParseErrors(a:data) - let errors = go#tool#FilterValids(errors) + " parse the errors relative to self.jobdir + execute cd self.jobdir + call go#list#ParseFormat(l:listtype, self.errorformat, out, self.for) + let errors = go#list#Get(l:listtype) finally - execute cd . fnameescape(dir) + execute cd . fnameescape(self.dir) endtry + if empty(errors) " failed to parse errors, output the original content - call go#util#EchoError(messages + [dir]) + call go#util#EchoError(self.messages + [self.dir]) return endif - if winnr == winnr() - call go#list#Populate(l:listtype, errors, join(args)) + if self.winnr == winnr() call go#list#Window(l:listtype, len(errors)) - if !bang + if !self.bang call go#list#JumpToFirst(l:listtype) endif endif diff --git a/sources_non_forked/vim-go/autoload/go/jobcontrol.vim b/sources_non_forked/vim-go/autoload/go/jobcontrol.vim index 57eab32c..25505812 100644 --- a/sources_non_forked/vim-go/autoload/go/jobcontrol.vim +++ b/sources_non_forked/vim-go/autoload/go/jobcontrol.vim @@ -62,6 +62,7 @@ function! s:spawn(bang, desc, for, args) abort \ 'status_dir' : status_dir, \ 'started_at' : started_at, \ 'for' : a:for, + \ 'errorformat': &errorformat, \ } " execute go build in the files directory @@ -125,7 +126,6 @@ function! s:on_exit(job_id, exit_status, event) dict abort let l:listtype = go#list#Type(self.for) if a:exit_status == 0 call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) let self.state = "SUCCESS" @@ -143,8 +143,9 @@ function! s:on_exit(job_id, exit_status, event) dict abort call go#util#EchoError("[" . self.status_type . "] FAILED") endif - let errors = go#tool#ParseErrors(std_combined) - let errors = go#tool#FilterValids(errors) + " parse the errors relative to self.jobdir + call go#list#ParseFormat(l:listtype, self.errorformat, std_combined, self.for) + let errors = go#list#Get(l:listtype) execute cd . fnameescape(dir) @@ -156,7 +157,6 @@ function! s:on_exit(job_id, exit_status, event) dict abort " if we are still in the same windows show the list if self.winnr == winnr() - call go#list#Populate(l:listtype, errors, self.desc) call go#list#Window(l:listtype, len(errors)) if !empty(errors) && !self.bang call go#list#JumpToFirst(l:listtype) diff --git a/sources_non_forked/vim-go/autoload/go/lint.vim b/sources_non_forked/vim-go/autoload/go/lint.vim index f810237e..42046946 100644 --- a/sources_non_forked/vim-go/autoload/go/lint.vim +++ b/sources_non_forked/vim-go/autoload/go/lint.vim @@ -105,7 +105,6 @@ function! go#lint#Gometa(autosave, ...) abort if l:err == 0 call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None else " GoMetaLinter can output one of the two, so we look for both: @@ -147,7 +146,7 @@ function! go#lint#Golint(...) abort endif let l:listtype = go#list#Type("GoLint") - call go#list#Parse(l:listtype, out) + call go#list#Parse(l:listtype, out, "GoLint") let errors = go#list#Get(l:listtype) call go#list#Window(l:listtype, len(errors)) call go#list#JumpToFirst(l:listtype) @@ -166,8 +165,9 @@ function! go#lint#Vet(bang, ...) abort let l:listtype = go#list#Type("GoVet") if go#util#ShellError() != 0 - let errors = go#tool#ParseErrors(split(out, '\n')) - call go#list#Populate(l:listtype, errors, 'Vet') + let errorformat="%-Gexit status %\\d%\\+," . &errorformat + call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet") + let errors = go#list#Get(l:listtype) call go#list#Window(l:listtype, len(errors)) if !empty(errors) && !a:bang call go#list#JumpToFirst(l:listtype) @@ -175,7 +175,6 @@ function! go#lint#Vet(bang, ...) abort echon "vim-go: " | echohl ErrorMsg | echon "[vet] FAIL" | echohl None else call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) redraw | echon "vim-go: " | echohl Function | echon "[vet] PASS" | echohl None endif endfunction @@ -228,7 +227,6 @@ function! go#lint#Errcheck(...) abort endif else call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) echon "vim-go: " | echohl Function | echon "[errcheck] PASS" | echohl None endif @@ -246,10 +244,18 @@ function! go#lint#ToggleMetaLinterAutoSave() abort endfunction function! s:lint_job(args, autosave) - let status_dir = expand('%:p:h') - let started_at = reltime() + let state = { + \ 'status_dir': expand('%:p:h'), + \ 'started_at': reltime(), + \ 'messages': [], + \ 'exited': 0, + \ 'closed': 0, + \ 'exit_status': 0, + \ 'winnr': winnr(), + \ 'autosave': a:autosave + \ } - call go#statusline#Update(status_dir, { + call go#statusline#Update(state.status_dir, { \ 'desc': "current status", \ 'type': "gometalinter", \ 'state': "analysing", @@ -259,26 +265,18 @@ function! s:lint_job(args, autosave) call go#cmd#autowrite() if a:autosave - let l:listtype = go#list#Type("GoMetaLinterAutoSave") + let state.listtype = go#list#Type("GoMetaLinterAutoSave") else - let l:listtype = go#list#Type("GoMetaLinter") + let state.listtype = go#list#Type("GoMetaLinter") endif - let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m' - - let l:messages = [] - let l:exited = 0 - let l:closed = 0 - let l:exit_status = 0 - let l:winnr = winnr() - - function! s:callback(chan, msg) closure - call add(messages, a:msg) + function! s:callback(chan, msg) dict closure + call add(self.messages, a:msg) endfunction - function! s:exit_cb(job, exitval) closure - let exited = 1 - let exit_status = a:exitval + function! s:exit_cb(job, exitval) dict + let self.exited = 1 + let self.exit_status = a:exitval let status = { \ 'desc': 'last status', @@ -290,50 +288,63 @@ function! s:lint_job(args, autosave) let status.state = "failed" endif - let elapsed_time = reltimestr(reltime(started_at)) + let elapsed_time = reltimestr(reltime(self.started_at)) " strip whitespace let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') let status.state .= printf(" (%ss)", elapsed_time) - call go#statusline#Update(status_dir, status) + call go#statusline#Update(self.status_dir, status) - if closed - call s:show_errors() + if self.closed + call self.show_errors() endif endfunction - function! s:close_cb(ch) closure - let closed = 1 + function! s:close_cb(ch) dict + let self.closed = 1 - if exited - call s:show_errors() + if self.exited + call self.show_errors() endif endfunction - function! s:show_errors() closure + function state.show_errors() + let l:winnr = winnr() + " make sure the current window is the window from which gometalinter was " run when the listtype is locationlist so that the location list for the " correct window will be populated. - if l:listtype == 'locationlist' - exe l:winnr . "wincmd w" + if self.listtype == 'locationlist' + exe self.winnr . "wincmd w" endif let l:errorformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m' - call go#list#ParseFormat(l:listtype, l:errorformat, messages, 'GoMetaLinter') + call go#list#ParseFormat(self.listtype, l:errorformat, self.messages, 'GoMetaLinter') - let errors = go#list#Get(l:listtype) - call go#list#Window(l:listtype, len(errors)) + let errors = go#list#Get(self.listtype) + call go#list#Window(self.listtype, len(errors)) + + " move to the window that was active before processing the errors, because + " the user may have moved around within the window or even moved to a + " different window since saving. Moving back to current window as of the + " start of this function avoids the perception that the quickfix window + " steals focus when linting takes a while. + if self.autosave + exe l:winnr . "wincmd w" + endif if get(g:, 'go_echo_command_info', 1) call go#util#EchoSuccess("linting finished") endif endfunction + " explicitly bind the callbacks to state so that self within them always + " refers to state. See :help Partial for more information. let start_options = { - \ 'callback': funcref("s:callback"), - \ 'exit_cb': funcref("s:exit_cb"), - \ 'close_cb': funcref("s:close_cb"), + \ 'callback': funcref("s:callback", [], state), + \ 'exit_cb': funcref("s:exit_cb", [], state), + \ 'close_cb': funcref("s:close_cb", [], state), \ } call job_start(a:args.cmd, start_options) 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 06c48785..141d57c0 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 @@ func! Test_Gometa() abort silent exe 'e ' . $GOPATH . '/src/lint/lint.go' let expected = [ - \ {'lnum': 5, 'bufnr': 3, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} + \ {'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 @@ -37,7 +37,7 @@ func! Test_GometaWithDisabled() abort silent exe 'e ' . $GOPATH . '/src/lint/lint.go' let expected = [ - \ {'lnum': 5, 'bufnr': 3, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} + \ {'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 @@ -71,7 +71,7 @@ func! Test_GometaAutoSave() abort silent exe 'e ' . $GOPATH . '/src/lint/lint.go' let expected = [ - \ {'lnum': 5, 'bufnr': 2, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'} + \ {'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)'} \ ] let winnr = winnr() @@ -102,4 +102,30 @@ func! Test_GometaAutoSave() abort let g:go_metalinter_autosave_enabled = orig_go_metalinter_autosave_enabled endfunc +func! Test_Vet() + let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' + silent exe 'e ' . $GOPATH . '/src/vet/vet.go' + compiler go + + let expected = [ + \ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'arg str for printf verb %d 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) +endfunc + " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/list.vim b/sources_non_forked/vim-go/autoload/go/list.vim index 38a65faf..23b0cbd5 100644 --- a/sources_non_forked/vim-go/autoload/go/list.vim +++ b/sources_non_forked/vim-go/autoload/go/list.vim @@ -18,14 +18,7 @@ function! go#list#Window(listtype, ...) abort " location list increases/decreases, cwindow will not resize when a new " updated height is passed. lopen in the other hand resizes the screen. if !a:0 || a:1 == 0 - let autoclose_window = get(g:, 'go_list_autoclose', 1) - if autoclose_window - if a:listtype == "locationlist" - lclose - else - cclose - endif - endif + call go#list#Close(a:listtype) return endif @@ -79,13 +72,7 @@ function! go#list#ParseFormat(listtype, errformat, items, title) abort " parse and populate the location list let &errorformat = a:errformat try - if a:listtype == "locationlist" - lgetexpr a:items - if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif - else - cgetexpr a:items - if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif - endif + call go#list#Parse(a:listtype, a:items, a:title) finally "restore back let &errorformat = old_errorformat @@ -94,11 +81,13 @@ endfunction " Parse parses the given items based on the global errorformat and " populates the list. -function! go#list#Parse(listtype, items) abort +function! go#list#Parse(listtype, items, title) abort if a:listtype == "locationlist" lgetexpr a:items + if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif else cgetexpr a:items + if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif endif endfunction @@ -111,13 +100,29 @@ function! go#list#JumpToFirst(listtype) abort endif endfunction -" Clean cleans the location list +" Clean cleans and closes the location list function! go#list#Clean(listtype) abort if a:listtype == "locationlist" lex [] else cex [] endif + + call go#list#Close(a:listtype) +endfunction + +" Close closes the location list +function! go#list#Close(listtype) abort + let autoclose_window = get(g:, 'go_list_autoclose', 1) + if !autoclose_window + return + endif + + if a:listtype == "locationlist" + lclose + else + cclose + endif endfunction function! s:listtype(listtype) abort diff --git a/sources_non_forked/vim-go/autoload/go/package.vim b/sources_non_forked/vim-go/autoload/go/package.vim index 940423f0..7cf7c5c0 100644 --- a/sources_non_forked/vim-go/autoload/go/package.vim +++ b/sources_non_forked/vim-go/autoload/go/package.vim @@ -54,8 +54,14 @@ function! go#package#Paths() abort return dirs endfunction +let s:import_paths = {} " ImportPath returns the import path in the current directory it was executed function! go#package#ImportPath() abort + let dir = expand("%:p:h") + if has_key(s:import_paths, dir) + return s:import_paths[dir] + endif + let out = go#tool#ExecuteInDir("go list") if go#util#ShellError() != 0 return -1 @@ -69,6 +75,8 @@ function! go#package#ImportPath() abort return -1 endif + let s:import_paths[dir] = import_path + return import_path endfunction diff --git a/sources_non_forked/vim-go/autoload/go/rename.vim b/sources_non_forked/vim-go/autoload/go/rename.vim index 6b61751c..095462f8 100644 --- a/sources_non_forked/vim-go/autoload/go/rename.vim +++ b/sources_non_forked/vim-go/autoload/go/rename.vim @@ -72,20 +72,22 @@ function! go#rename#Rename(bang, ...) abort endfunction function s:rename_job(args) - let exited = 0 - let closed = 0 - let exitval = 0 - let messages = [] + let state = { + \ 'exited': 0, + \ 'closed': 0, + \ 'exitval': 0, + \ 'messages': [], + \ 'status_dir': expand('%:p:h'), + \ 'bang': a:args.bang + \ } - function! s:callback(chan, msg) closure - call add(messages, a:msg) + function! s:callback(chan, msg) dict + call add(self.messages, a:msg) endfunction - let status_dir = expand('%:p:h') - - function! s:exit_cb(job, exitval) closure - let exited = 1 - let exitval = a:exitval + function! s:exit_cb(job, exitval) dict + let self.exited = 1 + let self.exitval = a:exitval let status = { \ 'desc': 'last status', @@ -97,28 +99,30 @@ function s:rename_job(args) let status.state = "failed" endif - call go#statusline#Update(status_dir, status) + call go#statusline#Update(self.status_dir, status) - if closed - call s:parse_errors(a:exitval, a:args.bang, messages) + if self.closed + call s:parse_errors(self.exitval, self.bang, self.messages) endif endfunction - function! s:close_cb(ch) closure - let closed = 1 + function! s:close_cb(ch) dict + let self.closed = 1 - if exited - call s:parse_errors(exitval, a:args.bang, messages) + if self.exited + call s:parse_errors(self.exitval, self.bang, self.messages) endif endfunction + " explicitly bind the callbacks to state so that self within them always + " refers to state. See :help Partial for more information. let start_options = { - \ 'callback': funcref("s:callback"), - \ 'exit_cb': funcref("s:exit_cb"), - \ 'close_cb': funcref("s:close_cb"), + \ 'callback': funcref("s:callback", [], state), + \ 'exit_cb': funcref("s:exit_cb", [], state), + \ 'close_cb': funcref("s:close_cb", [], state), \ } - call go#statusline#Update(status_dir, { + call go#statusline#Update(state.status_dir, { \ 'desc': "current status", \ 'type': "gorename", \ 'state': "started", @@ -156,7 +160,6 @@ function s:parse_errors(exit_val, bang, out) " strip out newline on the end that gorename puts. If we don't remove, it " will trigger the 'Hit ENTER to continue' prompt call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) call go#util#EchoSuccess(a:out[0]) " refresh the buffer so we can see the new content diff --git a/sources_non_forked/vim-go/autoload/go/template.vim b/sources_non_forked/vim-go/autoload/go/template.vim index 11a91aef..edb26a60 100644 --- a/sources_non_forked/vim-go/autoload/go/template.vim +++ b/sources_non_forked/vim-go/autoload/go/template.vim @@ -24,7 +24,7 @@ function! go#template#create() abort let l:template_file = get(g:, 'go_template_file', "hello_world.go") endif let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file) - silent exe '0r ' . fnameescape(l:template_path) + silent exe 'keepalt 0r ' . fnameescape(l:template_path) elseif l:package_name == -1 && l:go_template_use_pkg == 1 " cwd is now the dir of the package let l:path = fnamemodify(getcwd(), ':t') diff --git a/sources_non_forked/vim-go/autoload/go/term.vim b/sources_non_forked/vim-go/autoload/go/term.vim index 23ee18c4..1e085a38 100644 --- a/sources_non_forked/vim-go/autoload/go/term.vim +++ b/sources_non_forked/vim-go/autoload/go/term.vim @@ -2,9 +2,6 @@ if has('nvim') && !exists("g:go_term_mode") let g:go_term_mode = 'vsplit' endif -" s:jobs is a global reference to all jobs started with new() -let s:jobs = {} - " new creates a new terminal with the given command. Mode is set based on the " global variable g:go_term_mode, which is by default set to :vsplit function! go#term#new(bang, cmd) abort @@ -18,8 +15,14 @@ function! go#term#newmode(bang, cmd, mode) abort let mode = g:go_term_mode endif + let state = { + \ 'cmd': a:cmd, + \ 'bang' : a:bang, + \ 'winid': win_getid(winnr()), + \ 'stdout': [] + \ } + " execute go build in the files directory - let l:winnr = winnr() let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let dir = getcwd() @@ -33,30 +36,27 @@ function! go#term#newmode(bang, cmd, mode) abort setlocal noswapfile setlocal nobuflisted + " explicitly bind callbacks to state so that within them, self will always + " refer to state. See :help Partial for more information. + " + " Don't set an on_stderr, because it will be passed the same data as + " on_stdout. See https://github.com/neovim/neovim/issues/2836 let job = { - \ 'stderr' : [], - \ 'stdout' : [], - \ 'bang' : a:bang, - \ 'on_stdout': function('s:on_stdout'), - \ 'on_stderr': function('s:on_stderr'), - \ 'on_exit' : function('s:on_exit'), - \ } + \ 'on_stdout': function('s:on_stdout', [], state), + \ 'on_exit' : function('s:on_exit', [], state), + \ } - let id = termopen(a:cmd, job) + let state.id = termopen(a:cmd, job) + let state.termwinid = win_getid(winnr()) execute cd . fnameescape(dir) - let job.id = id - let job.cmd = a:cmd - startinsert - " resize new term if needed. let height = get(g:, 'go_term_height', winheight(0)) let width = get(g:, 'go_term_width', winwidth(0)) - " we are careful how to resize. for example it's vsplit we don't change - " the height. The below command resizes the buffer - + " Adjust the window width or height depending on whether it's a vertical or + " horizontal split. if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew" exe 'vertical resize ' . width elseif mode =~ "split" || mode =~ "new" @@ -64,77 +64,56 @@ function! go#term#newmode(bang, cmd, mode) abort endif " we also need to resize the pty, so there you go... - call jobresize(id, width, height) + call jobresize(state.id, width, height) - let s:jobs[id] = job - stopinsert + call win_gotoid(state.winid) - if l:winnr !=# winnr() - exe l:winnr . "wincmd w" - endif - - return id + return state.id endfunction function! s:on_stdout(job_id, data, event) dict abort - if !has_key(s:jobs, a:job_id) - return - endif - let job = s:jobs[a:job_id] - - call extend(job.stdout, a:data) -endfunction - -function! s:on_stderr(job_id, data, event) dict abort - if !has_key(s:jobs, a:job_id) - return - endif - let job = s:jobs[a:job_id] - - call extend(job.stderr, a:data) + call extend(self.stdout, a:data) endfunction function! s:on_exit(job_id, exit_status, event) dict abort - if !has_key(s:jobs, a:job_id) - return - endif - let job = s:jobs[a:job_id] - let l:listtype = go#list#Type("_term") " usually there is always output so never branch into this clause - if empty(job.stdout) - call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) - unlet s:jobs[a:job_id] + if empty(self.stdout) + call s:cleanlist(self.winid, l:listtype) return endif - let errors = go#tool#ParseErrors(job.stdout) + let errors = go#tool#ParseErrors(self.stdout) let errors = go#tool#FilterValids(errors) if !empty(errors) - " close terminal we don't need it anymore + " close terminal; we don't need it anymore + call win_gotoid(self.termwinid) close - call go#list#Populate(l:listtype, errors, job.cmd) + call win_gotoid(self.winid) + + call go#list#Populate(l:listtype, errors, self.cmd) call go#list#Window(l:listtype, len(errors)) if !self.bang call go#list#JumpToFirst(l:listtype) endif - unlet s:jobs[a:job_id] + return endif - " tests are passing clean the list and close the list. But we only can - " close them from a normal view, so jump back, close the list and then - " again jump back to the terminal - wincmd p - call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) - wincmd p + call s:cleanlist(self.winid, l:listtype) +endfunction - unlet s:jobs[a:job_id] +function! s:cleanlist(winid, listtype) abort + " There are no errors. Clean and close the list. Jump to the window to which + " the location list is attached, close the list, and then jump back to the + " current window. + let winid = win_getid(winnr()) + call win_gotoid(a:winid) + call go#list#Clean(a:listtype) + call win_gotoid(l:winid) endfunction " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/term_test.vim b/sources_non_forked/vim-go/autoload/go/term_test.vim new file mode 100644 index 00000000..7a630eef --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/term_test.vim @@ -0,0 +1,50 @@ +func! Test_GoTermNewMode() + if !has('nvim') + return + endif + + try + let l:filename = 'term/term.go' + let l:tmp = gotest#load_fixture(l:filename) + exe 'cd ' . l:tmp . '/src/term' + + let expected = expand('%:p') + + let cmd = "go run ". go#util#Shelljoin(go#tool#Files()) + + set nosplitright + call go#term#newmode(0, cmd, '') + let actual = expand('%:p') + call assert_equal(actual, l:expected) + + finally + call delete(l:tmp, 'rf') + endtry +endfunc + +func! Test_GoTermNewMode_SplitRight() + if !has('nvim') + return + endif + + try + let l:filename = 'term/term.go' + let l:tmp = gotest#load_fixture(l:filename) + exe 'cd ' . l:tmp . '/src/term' + + let expected = expand('%:p') + + let cmd = "go run ". go#util#Shelljoin(go#tool#Files()) + + set splitright + call go#term#newmode(0, cmd, '') + let actual = expand('%:p') + call assert_equal(actual, l:expected) + + finally + call delete(l:tmp, 'rf') + set nosplitright + endtry +endfunc + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/autoload/go/test-fixtures/cmd/bad.go b/sources_non_forked/vim-go/autoload/go/test-fixtures/cmd/bad.go new file mode 100644 index 00000000..a1cc46ea --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/test-fixtures/cmd/bad.go @@ -0,0 +1,5 @@ +package main + +func main() { + notafunc() +} diff --git a/sources_non_forked/vim-go/autoload/go/test-fixtures/lint/src/vet/vet.go b/sources_non_forked/vim-go/autoload/go/test-fixtures/lint/src/vet/vet.go new file mode 100644 index 00000000..d3a8e04e --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/test-fixtures/lint/src/vet/vet.go @@ -0,0 +1,8 @@ +package main + +import "fmt" + +func main() { + str := "hello world!" + fmt.Printf("%d\n", str) +} diff --git a/sources_non_forked/vim-go/autoload/go/test-fixtures/term/term.go b/sources_non_forked/vim-go/autoload/go/test-fixtures/term/term.go new file mode 100644 index 00000000..73d83e64 --- /dev/null +++ b/sources_non_forked/vim-go/autoload/go/test-fixtures/term/term.go @@ -0,0 +1,5 @@ +package main + +func main() { + println("hello, world") +} diff --git a/sources_non_forked/vim-go/autoload/go/test.vim b/sources_non_forked/vim-go/autoload/go/test.vim index ee36bc01..c62f508f 100644 --- a/sources_non_forked/vim-go/autoload/go/test.vim +++ b/sources_non_forked/vim-go/autoload/go/test.vim @@ -94,7 +94,6 @@ function! go#test#Test(bang, compile, ...) abort call go#util#EchoError("[test] FAIL") else call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) if a:compile call go#util#EchoSuccess("[test] SUCCESS") @@ -139,9 +138,6 @@ function! go#test#Func(bang, ...) abort endfunction function! s:test_job(args) abort - let status_dir = expand('%:p:h') - let started_at = reltime() - let status = { \ 'desc': 'current status', \ 'type': "test", @@ -152,23 +148,29 @@ function! s:test_job(args) abort let status.state = "compiling" endif - call go#statusline#Update(status_dir, status) - " autowrite is not enabled for jobs call go#cmd#autowrite() - let l:exited = 0 - let l:closed = 0 - let l:exitval = 0 - let messages = [] + let state = { + \ 'exited': 0, + \ 'closed': 0, + \ 'exitval': 0, + \ 'messages': [], + \ 'args': a:args, + \ 'compile_test': a:args.compile_test, + \ 'status_dir': expand('%:p:h'), + \ 'started_at': reltime() + \ } - function! s:callback(chan, msg) closure - call add(messages, a:msg) + call go#statusline#Update(state.status_dir, status) + + function! s:callback(chan, msg) dict + call add(self.messages, a:msg) endfunction - function! s:exit_cb(job, exitval) closure - let exited = 1 - let exitval = a:exitval + function! s:exit_cb(job, exitval) dict + let self.exited = 1 + let self.exitval = a:exitval let status = { \ 'desc': 'last status', @@ -176,7 +178,7 @@ function! s:test_job(args) abort \ 'state': "pass", \ } - if a:args.compile_test + if self.compile_test let status.state = "success" endif @@ -186,7 +188,7 @@ function! s:test_job(args) abort if get(g:, 'go_echo_command_info', 1) if a:exitval == 0 - if a:args.compile_test + if self.compile_test call go#util#EchoSuccess("[test] SUCCESS") else call go#util#EchoSuccess("[test] PASS") @@ -196,31 +198,33 @@ function! s:test_job(args) abort endif endif - let elapsed_time = reltimestr(reltime(started_at)) + let elapsed_time = reltimestr(reltime(self.started_at)) " strip whitespace let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') let status.state .= printf(" (%ss)", elapsed_time) - call go#statusline#Update(status_dir, status) + call go#statusline#Update(self.status_dir, status) - if closed - call s:show_errors(a:args, l:exitval, messages) + if self.closed + call s:show_errors(self.args, self.exitval, self.messages) endif endfunction - function! s:close_cb(ch) closure - let closed = 1 + function! s:close_cb(ch) dict + let self.closed = 1 - if exited - call s:show_errors(a:args, l:exitval, messages) + if self.exited + call s:show_errors(self.args, self.exitval, self.messages) endif endfunction + " explicitly bind the callbacks to state so that self within them always + " refers to state. See :help Partial for more information. let start_options = { - \ 'callback': funcref("s:callback"), - \ 'exit_cb': funcref("s:exit_cb"), - \ 'close_cb': funcref("s:close_cb"), - \ } + \ 'callback': funcref("s:callback", [], state), + \ 'exit_cb': funcref("s:exit_cb", [], state), + \ 'close_cb': funcref("s:close_cb", [], state) + \ } " pre start let dir = getcwd() @@ -241,7 +245,6 @@ function! s:show_errors(args, exit_val, messages) abort let l:listtype = go#list#Type("GoTest") if a:exit_val == 0 call go#list#Clean(l:listtype) - call go#list#Window(l:listtype) return endif diff --git a/sources_non_forked/vim-go/autoload/go/textobj.vim b/sources_non_forked/vim-go/autoload/go/textobj.vim index 62a70427..e8a23d31 100644 --- a/sources_non_forked/vim-go/autoload/go/textobj.vim +++ b/sources_non_forked/vim-go/autoload/go/textobj.vim @@ -17,6 +17,7 @@ endif " < > " t for tag +" Select a function in visual mode. function! go#textobj#Function(mode) abort let offset = go#util#OffsetCursor() @@ -98,23 +99,8 @@ function! go#textobj#Function(mode) abort call cursor(info.rbrace.line-1, 1) endfunction -function! go#textobj#FunctionJump(mode, direction) abort - " get count of the motion. This should be done before all the normal - " expressions below as those reset this value(because they have zero - " count!). We abstract -1 because the index starts from 0 in motion. - let l:cnt = v:count1 - 1 - - " set context mark so we can jump back with '' or `` - normal! m' - - " select already previously selected visual content and continue from there. - " If it's the first time starts with the visual mode. This is needed so - " after selecting something in visual mode, every consecutive motion - " continues. - if a:mode == 'v' - normal! gv - endif - +" Get the location of the previous or next function. +function! go#textobj#FunctionLocation(direction, cnt) abort let offset = go#util#OffsetCursor() let fname = shellescape(expand("%:p")) @@ -131,7 +117,7 @@ function! go#textobj#FunctionJump(mode, direction) abort endif let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset) - let command .= ' -shift ' . l:cnt + let command .= ' -shift ' . a:cnt if a:direction == 'next' let command .= ' -mode next' @@ -154,9 +140,33 @@ function! go#textobj#FunctionJump(mode, direction) abort call delete(l:tmpname) endif - " convert our string dict representation into native Vim dictionary type - let result = eval(out) - if type(result) != 4 || !has_key(result, 'fn') + let l:result = json_decode(out) + if type(l:result) != 4 || !has_key(l:result, 'fn') + return 0 + endif + + return l:result +endfunction + +function! go#textobj#FunctionJump(mode, direction) abort + " get count of the motion. This should be done before all the normal + " expressions below as those reset this value(because they have zero + " count!). We abstract -1 because the index starts from 0 in motion. + let l:cnt = v:count1 - 1 + + " set context mark so we can jump back with '' or `` + normal! m' + + " select already previously selected visual content and continue from there. + " If it's the first time starts with the visual mode. This is needed so + " after selecting something in visual mode, every consecutive motion + " continues. + if a:mode == 'v' + normal! gv + endif + + let l:result = go#textobj#FunctionLocation(a:direction, l:cnt) + if l:result is 0 return endif diff --git a/sources_non_forked/vim-go/autoload/go/util.vim b/sources_non_forked/vim-go/autoload/go/util.vim index bf72dadd..7b434601 100644 --- a/sources_non_forked/vim-go/autoload/go/util.vim +++ b/sources_non_forked/vim-go/autoload/go/util.vim @@ -330,6 +330,7 @@ function! go#util#EchoWarning(msg) call s:echo(a:msg, 'WarningMsg') endfunction function! go#util#EchoProgress(msg) + redraw call s:echo(a:msg, 'Identifier') endfunction function! go#util#EchoInfo(msg) @@ -362,7 +363,6 @@ function! go#util#archive() return expand("%:p:gs!\\!/!") . "\n" . strlen(l:buffer) . "\n" . l:buffer endfunction - " Make a named temporary directory which starts with "prefix". " " Unfortunately Vim's tempname() is not portable enough across various systems; @@ -384,7 +384,7 @@ function! go#util#tempdir(prefix) abort endfor if l:dir == '' - echoerr 'Unable to find directory to store temporary directory in' + call go#util#EchoError('Unable to find directory to store temporary directory in') return endif @@ -395,4 +395,9 @@ function! go#util#tempdir(prefix) abort return l:tmp endfunction +" Report if the user enabled a debug flag in g:go_debug. +function! go#util#HasDebug(flag) + return index(get(g:, 'go_debug', []), a:flag) >= 0 +endfunction + " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/doc/vim-go.txt b/sources_non_forked/vim-go/doc/vim-go.txt index f2bedc95..7d8f2ff3 100644 --- a/sources_non_forked/vim-go/doc/vim-go.txt +++ b/sources_non_forked/vim-go/doc/vim-go.txt @@ -22,10 +22,11 @@ CONTENTS *go-contents* 6. Functions....................................|go-functions| 7. Settings.....................................|go-settings| 8. Syntax highlighting..........................|go-syntax| - 9. FAQ/Troubleshooting..........................|go-troubleshooting| - 10. Development..................................|go-development| - 11. Donation.....................................|go-donation| - 12. Credits......................................|go-credits| + 9. Debugger.....................................|go-debug| + 10. FAQ/Troubleshooting..........................|go-troubleshooting| + 11. Development..................................|go-development| + 12. Donation.....................................|go-donation| + 13. Credits......................................|go-credits| ============================================================================== INTRO *go-intro* @@ -37,16 +38,16 @@ and individual features can be toggled easily. vim-go leverages a number of tools developed by the Go community to provide a seamless Vim experience. * Compile your package with |:GoBuild|, install it with |:GoInstall| or - test it with |:GoTest|. Run a single tests with |:GoTestFunc|). + test it with |:GoTest|. Run a single test with |:GoTestFunc|). * Quickly execute your current file(s) with |:GoRun|. * Improved syntax highlighting and folding. + * Debug programs with integrated `delve` support with |:GoDebugStart|. * Completion support via `gocode`. * `gofmt` or `goimports` on save keeps the cursor position and undo history. * Go to symbol/declaration with |:GoDef|. * Look up documentation with |:GoDoc| or |:GoDocBrowser|. * Easily import packages via |:GoImport|, remove them via |:GoDrop|. - * Automatic `GOPATH` detection which works with `gb` and `godep`. Change or - display `GOPATH` with |:GoPath|. + * Precise type-safe renaming of identifiers with |:GoRename|. * See which code is covered by tests with |:GoCoverage|. * Add or remove tags on struct fields with |:GoAddTags| and |:GoRemoveTags|. * Call `gometalinter` with |:GoMetaLinter| to invoke all possible linters @@ -56,7 +57,8 @@ tools developed by the Go community to provide a seamless Vim experience. static errors, or make sure errors are checked with |:GoErrCheck|. * Advanced source analysis tools utilizing `guru`, such as |:GoImplements|, |:GoCallees|, and |:GoReferrers|. - * Precise type-safe renaming of identifiers with |:GoRename|. + * Automatic `GOPATH` detection which works with `gb` and `godep`. Change or + display `GOPATH` with |:GoPath|. * Integrated and improved snippets, supporting `ultisnips`, `neosnippet`, and `vim-minisnip`. * Share your current code to play.golang.org with |:GoPlay|. @@ -1100,7 +1102,7 @@ cleaned for each package after `60` seconds. This can be changed with the *go#complete#GetInfo()* Returns the description of the identifer under the cursor. Can be used to plug -into the statusline. This function is also used for |'g:go_auto_type_info'|. +into the statusline. ============================================================================== SETTINGS *go-settings* @@ -1658,6 +1660,18 @@ By default "snakecase" is used. Current values are: ["snakecase", > let g:go_addtags_transform = 'snakecase' < + *'g:go_debug'* + +A list of options to debug; useful for development and/or reporting bugs. + +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`. +> + let g:go_debug = [] +< ============================================================================== SYNTAX HIGHLIGHTING *ft-go-syntax* *go-syntax* @@ -1815,6 +1829,212 @@ The `gohtmltmpl` filetype is automatically set for `*.tmpl` files; the `gotexttmpl` is never automatically set and needs to be set manually. +============================================================================== +DEBUGGER *go-debug* + +Vim-go comes with a special "debugger mode". This starts a `dlv` process in +the background and provides various commands to communicate with it. + +This debugger is similar to Visual Studio or Eclipse and has the following +features: + + * Show stack trace and jumps. + * List local variables. + * List function arguments. + * Expand values of struct or array/slice. + * Show balloon on the symbol. + * Show output of stdout/stderr. + * Toggle breakpoint. + * Stack operation continue/next/step out. + +This feature requires Vim 8.0.0087 or newer with the |+job| feature. Neovim +does _not_ work (yet). +This requires Delve 1.0.0 or newer, and it is recommended to use Go 1.10 or +newer, as its new caching will speed up recompiles. + + *go-debug-intro* +GETTING STARTED WITH THE DEBUGGER~ + +Use |:GoDebugStart| or |:GoDebugTest| to start the debugger. The first +argument is the package name, and any arguments after that will be passed on +to the program; for example: +> + :GoDebugStart . -someflag value +< +This may take few seconds. After the code is compiled you'll see three new +windows: the stack trace on left side, the variable list on the bottom-left, +and program output at the bottom. + +You can add breakpoints with |:GoDebugBreakpoint| () and run your program +with |:GoDebugContinue| (). + +The program will halt on the breakpoint, at which point you can inspect the +program state. You can go to the next line with |:GoDebugNext| () or step +in with |:GoDebugStep| (). + +The variable window in the bottom left (`GODEBUG_VARIABLES`) will display all +local variables. Struct values are displayed as `{...}`, array/slices as +`[4]`. Use on the variable name to expand the values. + +The `GODEBUG_OUTPUT` window displays output from the program and the Delve +debugger. + +The `GODEBUG_STACKTRACE` window can be used to jump to different places in the +call stack. + +When you're done use |:GoDebugStop| to close the debugging windows and halt +the `dlv` process, or |:GoDebugRestart| to recompile the code. + + *go-debug-commands* +DEBUGGER COMMANDS~ + +Only |:GoDebugStart| and |:GoDebugBreakpoint| are available by default; the +rest of the commands and mappings become available after starting debug mode. + + *:GoDebugStart* +:GoDebugStart [pkg] [program-args] + + Start the debug mode for [pkg]; this does several things: + + * Setup the debug windows according to |'g:go_debug_windows'|. + * Make the `:GoDebug*` commands and `(go-debug-*)` mappings available. + + The current directory is used if [pkg] is empty. Any other arguments will + be passed to the program. + + Use |:GoDebugStop| to stop `dlv` and exit debugging mode. + + *:GoDebugTest* +:GoDebugTest [pkg] [program-args] + + Behaves the same as |:GoDebugStart| but runs `dlv test` instead of + `dlv debug` so you can debug tests. + + Use `-test.flag` to pass flags to `go test` when debugging a test; for + example `-test.v` or `-test.run TestFoo` + + + *:GoDebugRestart* +:GoDebugRestart + + Stop the program (if running) and restart `dlv` to recompile the package. + The current window layout and breakpoints will be left intact. + + *:GoDebugStop* + *(go-debug-stop)* +:GoDebugStop + + Stop `dlv` and remove all debug-specific commands, mappings, and windows. + + *:GoDebugBreakpoint* + *(go-debug-breakpoint)* +:GoDebugBreakpoint [linenr] + + Toggle breakpoint for the [linenr]. [linenr] defaults to the current line + if it is omitted. A line with a breakpoint will have the + {godebugbreakpoint} |:sign| placed on it. The line the program is + currently halted on will have the {godebugcurline} sign. + + *hl-GoDebugCurrent* *hl-GoDebugBreakpoint* + A line with a breakpoint will be highlighted with the {GoDebugBreakpoint} + group; the line the program is currently halted on will be highlighted + with {GoDebugCurrent}. + + Mapped to by default. + + *:GoDebugContinue* + *(go-debug-continue)* +:GoDebugContinue + + Continue execution until breakpoint or program termination. It will start + the program if it hasn't been started yet. + + Mapped to by default. + + *:GoDebugNext* + *(go-debug-next)* +:GoDebugNext + + Advance execution by one line, also called "step over" by some other + debuggers. + It will behave as |:GoDebugContinue| if the program isn't started. + + Mapped to by default. + + *:GoDebugStep* + *(go-debug-step)* +:GoDebugStep + + Advance execution by one step, stopping at the next line of code that will + be executed (regardless of location). + It will behave as |:GoDebugContinue| if the program isn't started. + + Mapped to by default. + + *:GoDebugStepOut* + *(go-debug-stepout)* + +:GoDebugStepOut + + Run all the code in the current function and halt when the function + returns ("step out of the current function"). + It will behave as |:GoDebugContinue| if the program isn't started. + + *:GoDebugSet* +:GoDebugSet {var} {value} + + Set the variable {var} to {value}. Example: +> + :GoDebugSet truth 42 +< + This only works for `float`, `int` and variants, `uint` and variants, + `bool`, and pointers (this is a `delve` limitation, not a vim-go + limitation). + + *:GoDebugPrint* + *(go-debug-print)* +:GoDebugPrint {expr} + + Print the result of a Go expression. +> + :GoDebugPrint truth == 42 + truth == 42 true +< + Mapped to by default, which will evaluate the under the + cursor. + + *go-debug-settings* +DEBUGGER SETTINGS~ + + *'g:go_debug_windows'* + +Controls the window layout for debugging mode. This is a |dict| with three +possible keys: "stack", "out", and "vars"; the windows will created in that +order with the commands in the value. +A window will not be created if a key is missing or empty. + +Defaults: +> + let g:go_debug_windows = { + \ 'stack': 'leftabove 20vnew', + \ 'out': 'botright 10new', + \ 'vars': 'leftabove 30vnew', + \ } +< +Show only variables on the right-hand side: > + + let g:go_debug_windows = { + \ 'vars': 'rightbelow 60vnew', + \ } +< + *'g:go_debug_address'* + +Server address `dlv` will listen on; must be in `hostname:port` format. +Defaults to `127.0.0.1:8181`: +> + let g:go_debug_address = '127.0.0.1:8181' +< + ============================================================================== FAQ TROUBLESHOOTING *go-troubleshooting* diff --git a/sources_non_forked/vim-go/ftplugin/go/commands.vim b/sources_non_forked/vim-go/ftplugin/go/commands.vim index 9b983ef5..8b74ba66 100644 --- a/sources_non_forked/vim-go/ftplugin/go/commands.vim +++ b/sources_non_forked/vim-go/ftplugin/go/commands.vim @@ -98,4 +98,11 @@ command! -nargs=0 GoKeyify call go#keyify#Keyify() " -- fillstruct command! -nargs=0 GoFillStruct call go#fillstruct#FillStruct() +" -- debug +if !exists(':GoDebugStart') + command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start(0, ) + command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start(1, ) + command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint() +endif + " vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/ftplugin/go/snippets.vim b/sources_non_forked/vim-go/ftplugin/go/snippets.vim index 33a3cd5a..f53de41c 100644 --- a/sources_non_forked/vim-go/ftplugin/go/snippets.vim +++ b/sources_non_forked/vim-go/ftplugin/go/snippets.vim @@ -40,7 +40,7 @@ function! s:GoMinisnip() abort endif if exists('g:minisnip_dir') - let g:minisnip_dir .= ':' . globpath(&rtp, 'gosnippets/minisnip') + let g:minisnip_dir .= go#util#PathListSep() . globpath(&rtp, 'gosnippets/minisnip') else let g:minisnip_dir = globpath(&rtp, 'gosnippets/minisnip') endif diff --git a/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets b/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets index 1a78a04d..9a9f546d 100644 --- a/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets +++ b/sources_non_forked/vim-go/gosnippets/UltiSnips/go.snippets @@ -252,6 +252,11 @@ snippet fn "fmt.Println(...)" fmt.Println("${1:${VISUAL}}") endsnippet +# Fmt Errorf debug +snippet fe "fmt.Errorf(...)" +fmt.Errorf("${1:${VISUAL}}") +endsnippet + # log printf snippet lf "log.Printf(...)" log.Printf("${1:${VISUAL}} = %+v\n", $1) diff --git a/sources_non_forked/vim-go/gosnippets/snippets/go.snip b/sources_non_forked/vim-go/gosnippets/snippets/go.snip index 40e6fe3e..7a22cd24 100644 --- a/sources_non_forked/vim-go/gosnippets/snippets/go.snip +++ b/sources_non_forked/vim-go/gosnippets/snippets/go.snip @@ -219,6 +219,10 @@ abbr fmt.Printf(...) snippet fn abbr fmt.Println(...) fmt.Println("${1}") +# Fmt Errorf +snippet fe +abbr fmt.Errorf(...) + fmt.Errorf("${1}") # log printf snippet lf abbr log.Printf(...) diff --git a/sources_non_forked/vim-go/plugin/go.vim b/sources_non_forked/vim-go/plugin/go.vim index bb88608f..513ce366 100644 --- a/sources_non_forked/vim-go/plugin/go.vim +++ b/sources_non_forked/vim-go/plugin/go.vim @@ -31,6 +31,7 @@ endif " needed by the user with GoInstallBinaries let s:packages = { \ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt'], + \ 'dlv': ['github.com/derekparker/delve/cmd/dlv'], \ 'errcheck': ['github.com/kisielk/errcheck'], \ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'], \ 'gocode': ['github.com/nsf/gocode', {'windows': '-ldflags -H=windowsgui'}], diff --git a/sources_non_forked/vim-go/syntax/go.vim b/sources_non_forked/vim-go/syntax/go.vim index 31fe9612..8769dffb 100644 --- a/sources_non_forked/vim-go/syntax/go.vim +++ b/sources_non_forked/vim-go/syntax/go.vim @@ -453,7 +453,7 @@ if g:go_highlight_build_constraints != 0 || s:fold_package_comment \ . ' contains=@goCommentGroup,@Spell' \ . (s:fold_package_comment ? ' fold' : '') exe 'syn region goPackageComment start=/\v\/\*.*\n(.*\n)*\s*\*\/\npackage/' - \ . ' end=/\v\n\s*package/he=e-7,me=e-7,re=e-7' + \ . ' end=/\v\*\/\n\s*package/he=e-7,me=e-7,re=e-7' \ . ' contains=@goCommentGroup,@Spell' \ . (s:fold_package_comment ? ' fold' : '') hi def link goPackageComment Comment diff --git a/sources_non_forked/vim-go/syntax/godebugoutput.vim b/sources_non_forked/vim-go/syntax/godebugoutput.vim new file mode 100644 index 00000000..b8e6f5ff --- /dev/null +++ b/sources_non_forked/vim-go/syntax/godebugoutput.vim @@ -0,0 +1,13 @@ +if exists("b:current_syntax") + finish +endif + +syn match godebugOutputErr '^ERR:.*' +syn match godebugOutputOut '^OUT:.*' + +let b:current_syntax = "godebugoutput" + +hi def link godebugOutputErr Comment +hi def link godebugOutputOut Normal + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/syntax/godebugstacktrace.vim b/sources_non_forked/vim-go/syntax/godebugstacktrace.vim new file mode 100644 index 00000000..b0c53725 --- /dev/null +++ b/sources_non_forked/vim-go/syntax/godebugstacktrace.vim @@ -0,0 +1,11 @@ +if exists("b:current_syntax") + finish +endif + +syn match godebugStacktrace '^\S\+' + +let b:current_syntax = "godebugoutput" + +hi def link godebugStacktrace SpecialKey + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-go/syntax/godebugvariables.vim b/sources_non_forked/vim-go/syntax/godebugvariables.vim new file mode 100644 index 00000000..791705ba --- /dev/null +++ b/sources_non_forked/vim-go/syntax/godebugvariables.vim @@ -0,0 +1,23 @@ +if exists("b:current_syntax") + finish +endif + +syn match godebugTitle '^#.*' +syn match godebugVariables '^\s*\S\+\ze:' + +syn keyword goType chan map bool string error +syn keyword goSignedInts int int8 int16 int32 int64 rune +syn keyword goUnsignedInts byte uint uint8 uint16 uint32 uint64 uintptr +syn keyword goFloats float32 float64 +syn keyword goComplexes complex64 complex128 + +syn keyword goBoolean true false + +let b:current_syntax = "godebugvariables" + +hi def link godebugTitle Underlined +hi def link godebugVariables Statement +hi def link goType Type +hi def link goBoolean Boolean + +" vim: sw=2 ts=2 et diff --git a/sources_non_forked/vim-markdown/README.md b/sources_non_forked/vim-markdown/README.md index 67d473cc..8c056ce0 100644 --- a/sources_non_forked/vim-markdown/README.md +++ b/sources_non_forked/vim-markdown/README.md @@ -123,7 +123,7 @@ 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 (ie, for it to be applied a closing token must be found on the same line). To do so: +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: ```vim let g:vim_markdown_emphasis_multiline = 0 @@ -176,7 +176,7 @@ Default is `['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']`. ### Follow named anchors -This feature allows ge to follow named anchors in links of the form +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: diff --git a/sources_non_forked/vim-markdown/ftplugin/markdown.vim b/sources_non_forked/vim-markdown/ftplugin/markdown.vim index 1078f3da..1aa3494f 100644 --- a/sources_non_forked/vim-markdown/ftplugin/markdown.vim +++ b/sources_non_forked/vim-markdown/ftplugin/markdown.vim @@ -764,10 +764,10 @@ function! s:MarkdownClearSyntaxVariables() endfunction augroup Mkd - autocmd! - au BufWinEnter * call s:MarkdownRefreshSyntax(1) - au BufUnload * call s:MarkdownClearSyntaxVariables() - au BufWritePost * call s:MarkdownRefreshSyntax(0) - au InsertEnter,InsertLeave * call s:MarkdownRefreshSyntax(0) - au CursorHold,CursorHoldI * call s:MarkdownRefreshSyntax(0) + autocmd! * + autocmd BufWinEnter call s:MarkdownRefreshSyntax(1) + autocmd BufUnload call s:MarkdownClearSyntaxVariables() + autocmd BufWritePost call s:MarkdownRefreshSyntax(0) + autocmd InsertEnter,InsertLeave call s:MarkdownRefreshSyntax(0) + autocmd CursorHold,CursorHoldI call s:MarkdownRefreshSyntax(0) augroup END diff --git a/sources_non_forked/vim-multiple-cursors/README.md b/sources_non_forked/vim-multiple-cursors/README.md index 8ed8c113..ab52b535 100644 --- a/sources_non_forked/vim-multiple-cursors/README.md +++ b/sources_non_forked/vim-multiple-cursors/README.md @@ -35,7 +35,7 @@ Vim command sequence: `2Gfpcname` ### Add a cursor to each line of your visual selection ![Example2](assets/example2.gif?raw=true) -Vim command sequence: `2Gvipi"",vipJ$r]Idays = [` +Vim command sequence: `2Gvipi"",vipgJ$r]Idays = [` ### Do it backwards too! This is not just a replay of the above gif :) ![Example3](assets/example3.gif?raw=true) @@ -51,8 +51,8 @@ To see what keystrokes are used for the above examples, see [the wiki page](http - Live update in Insert mode - One key to rule it all! See [Quick Start](#quick-start) on what the key does in different scenarios - Works in Normal, Insert, and Visual mode for any commands (including - multi-key commands, assuming you set `g:multicursor_insert_maps` and - `g:multicursor_normal_maps`; see Settings below for details) + multi-key commands, assuming you set `g:multicursor_normal_maps`; + see Settings below for details) ## Installation Install using [Pathogen], [Vundle], [Neobundle], or your favorite Vim package manager. @@ -123,15 +123,6 @@ If set to 0, then pressing `g:multi_cursor_quit_key` in _Visual_ mode will not q ### ```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. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. -### ```g:multi_cursor_insert_maps``` (Default: `{}`) -Any key in this map (values are ignored) will cause multi-cursor _Insert_ mode -to pause for `timeoutlen` waiting for map completion just like normal vim. -Otherwise keys mapped in insert mode are ignored when multiple cursors are -active. For example, setting it to `{'\':1}` will make insert-mode mappings -beginning with the default leader key work in multi-cursor mode. You have to -manually set this because vim doesn't provide a way to see which keys _start_ -mappings. - ### ```g:multi_cursor_normal_maps``` (Default: see below) Default value: `{'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1}` diff --git a/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim b/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim index 36d267ff..1b8935a3 100644 --- a/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim +++ b/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim @@ -103,7 +103,7 @@ endfunction function! s:fire_pre_triggers() if !s:before_function_called - doautocmd User MultipleCursorsPre + silent doautocmd User MultipleCursorsPre if exists('*Multiple_cursors_before') exe "call Multiple_cursors_before()" endif @@ -445,7 +445,7 @@ function! s:CursorManager.reset(restore_view, restore_setting, ...) dict if exists('*Multiple_cursors_after') exe "call Multiple_cursors_after()" endif - doautocmd User MultipleCursorsPost + silent doautocmd User MultipleCursorsPost let s:before_function_called = 0 endif endfunction @@ -516,7 +516,6 @@ function! s:CursorManager.update_current() dict if s:to_mode ==# 'V' exec "normal! gvv\" endif - " Sets the cursor at the right place exec "normal! gv\" call cur.update_visual_selection(s:get_visual_region(s:pos('.'))) @@ -525,17 +524,18 @@ function! s:CursorManager.update_current() dict " This should be executed after user input is processed, when unnamed " register already contains the text. call cur.save_unnamed_register() - call cur.remove_visual_selection() - elseif s:from_mode ==# 'i' && s:to_mode ==# 'n' && self.current_index != self.size() - 1 + elseif s:from_mode ==# 'i' && s:to_mode ==# 'n' && self.current_index != 0 normal! h elseif s:from_mode ==# 'n' " Save contents of unnamed register after each operation in Normal mode. call cur.save_unnamed_register() endif - let vdelta = line('$') - s:saved_linecount + let pos = s:pos('.') + " If the total number of lines changed in the buffer, we need to potentially " adjust other cursor locations + let vdelta = line('$') - s:saved_linecount if vdelta != 0 if self.current_index != self.size() - 1 let cur_column_offset = (cur.column() - col('.')) * -1 @@ -547,7 +547,7 @@ function! s:CursorManager.update_current() dict let c = self.get(i) " If there're other cursors on the same line, we need to adjust their " columns. This needs to happen before we adjust their line! - if cur.line() == c.line() + if cur.line() == c.line() || cur.position == pos if vdelta > 0 " Added a line let hdelta = cur_column_offset @@ -583,7 +583,6 @@ function! s:CursorManager.update_current() dict endif endif - let pos = s:pos('.') if cur.position == pos return 0 endif @@ -598,7 +597,8 @@ endfunction " Start tracking cursor updates function! s:CursorManager.start_loop() dict - let self.starting_index = self.current_index + let self.current_index = 0 + let self.starting_index = 0 endfunction " Returns true if we're cycled through all the cursors @@ -1210,28 +1210,51 @@ function! s:wait_for_user_input(mode) let s:saved_keys = "" endif - if s:from_mode ==# 'i' && has_key(g:multi_cursor_insert_maps, s:last_char()) - let c = getchar(0) - let char_type = type(c) + " ambiguous mappings are note supported; e.g.: + " imap jj JJ + " imap jjj JJJ + " will always trigger the 'jj' mapping + if s:from_mode ==# 'i' && mapcheck(s:char, "i") != "" let poll_count = 0 - while char_type == 0 && c == 0 && poll_count < &timeoutlen - sleep 1m + let map_dict = {} + while poll_count < &timeoutlen let c = getchar(0) let char_type = type(c) - let poll_count += 1 + let poll_count += 1.5 + if char_type == 0 && c != 0 + let s:char .= nr2char(c) + elseif char_type == 1 " char with more than 8 bits (as string) + let s:char .= c + endif + let map_dict = maparg(s:char, "i", 0, 1) + " break if chars exactly match mapping or if chars don't match beging of mapping anymore + if map_dict != {} || mapcheck(s:char, "i") == "" + if get(map_dict, 'expr', 0) + " handle case where {rhs} is a function + exec 'let char_mapping = ' . map_dict['rhs'] + else + let char_mapping = get(map_dict, 'rhs', s:char) + endif + " handle case where mapping is + exec 'let s:char = "'.substitute(char_mapping, '<', '\\<', 'g').'"' + break + endif + sleep 1m endwhile - - if char_type == 0 && c != 0 - let s:char .= nr2char(c) - elseif char_type == 1 " char with more than 8 bits (as string) - let s:char .= c - endif elseif s:from_mode !=# 'i' && s:char[0] ==# ":" call feedkeys(s:char) call s:cm.reset(1, 1) return - elseif s:from_mode ==# 'n' + elseif s:from_mode ==# 'n' || s:from_mode =~# 'v\|V' while match(s:last_char(), "\\d") == 0 + if match(s:char, '\(^\|\a\)0') == 0 + " fixes an edge case concerning the `0` key. + " The 0 key behaves differently from [1-9]. + " It's consumed immediately when it is the + " first key typed while we're waiting for input. + " References: issue #152, pull #241 + break + endif let s:char .= s:get_char() endwhile endif 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 422d5cf7..31896cf0 100644 --- a/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt +++ b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt @@ -157,16 +157,6 @@ quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. -*g:multi_cursor_insert_maps* (Default: `{}`) - -Any key in this map (values are ignored) will cause multi-cursor _Insert_ mode -to pause for `timeoutlen` waiting for map completion just like normal vim. -Otherwise keys mapped in insert mode are ignored when multiple cursors are -active. For example, setting it to `{'\':1}` will make insert-mode mappings -beginning with the default leader key work in multi-cursor mode. You have to -manually set this because vim doesn't provide a way to see which keys _start_ -mappings. - *g:multi_cursor_normal_maps* (Default: see below) Default value: `{'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1}` 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 6595bc35..cfc22e5b 100644 --- a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim +++ b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim @@ -40,12 +40,9 @@ let s:settings_if_default = { \ 'skip_key': '', \ } -let s:default_insert_maps = {} let s:default_normal_maps = {'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1} let s:default_visual_maps = {'i':1, 'a':1, 'f':1, 'F':1, 't':1, 'T':1} -let g:multi_cursor_insert_maps = - \ get(g:, 'multi_cursor_insert_maps', s:default_insert_maps) let g:multi_cursor_normal_maps = \ get(g:, 'multi_cursor_normal_maps', s:default_normal_maps) let g:multi_cursor_visual_maps = 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 2d92e5a2..18ca32bb 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 @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- require 'spec_helper' def set_file_content(string) @@ -136,6 +136,79 @@ describe "Multiple Cursors op pending & exit from insert|visual mode" do EOF end + specify "#normal mode '0': goes to 1st char of line" do + before <<-EOF + hello jan world + hello feb world + hello mar world + EOF + + type 'vw0dw' + + after <<-EOF + jan world + feb world + mar world + EOF + end + + specify "#normal mode 'd0': deletes backward to 1st char of line" do + before <<-EOF + hello jan world + hello feb world + hello mar world + EOF + + type 'vwd0' + + after <<-EOF + jan world + feb world + mar world + EOF + end + +end + +describe "Multiple Cursors when using insert mapings" do + let(:filename) { 'test.txt' } + let(:options) { ['imap jj ', 'imap jojo dude'] } + specify "#mapping doing " do + before <<-EOF + hello world! + hello world! + bla bla bla + bla bla bla + EOF + + type 'wcjjidude' + + after <<-EOF + hello dude! + hello ! + bla bla bla + bla bla bla + EOF + end + + specify "#mapping using more than 2 characters" do + before <<-EOF + hello + hello + bla bla bla + bla bla bla + EOF + + type 'A jojo' + + after <<-EOF + hello dude + hello dude + bla bla bla + bla bla bla + EOF + end + end describe "Multiple Cursors when normal_maps is empty" do @@ -190,7 +263,53 @@ describe "Multiple Cursors when visual_maps is empty" do end -describe "Multiple Cursors" do +describe "Multiple Cursors when changing the line count" do + let(:filename) { 'test.txt' } + let(:options) { ['set backspace=indent,eol,start'] } + + specify "#backspace on first char of the line, then carriage return" do + before <<-EOF + madec + + antoine + andre + joseph + EOF + + type 'Gvipi' + + after <<-EOF + madec + + antoine + andre + joseph + EOF + end + + specify "#del at EOL, then carriage return" do + before <<-EOF + madec + antoine + joseph + + andre + EOF + + type 'vipA' + + after <<-EOF + madec + antoine + joseph + + andre + EOF + end + +end + +describe "Multiple Cursors misc" do let(:filename) { 'test.txt' } let(:options) { ['set autoindent'] } diff --git a/sources_non_forked/vim-snippets/UltiSnips/all.snippets b/sources_non_forked/vim-snippets/UltiSnips/all.snippets index 6d77cc59..d956e0e8 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/all.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/all.snippets @@ -100,4 +100,11 @@ snippet todo "TODO comment" bw `!p snip.rv=get_comment_format()[0]` ${2:TODO}: $0${3: <${4:`!v strftime('%d-%m-%y')`}${5:, `!v g:snips_author`}>} `!p snip.rv=get_comment_format()[2]` endsnippet +########## +# Misc # +########## +snippet uuid "Random UUID" w +`!p if not snip.c: import uuid; snip.rv = uuid.uuid4()` +endsnippet + # vim:ft=snippets: diff --git a/sources_non_forked/vim-snippets/UltiSnips/cpp.snippets b/sources_non_forked/vim-snippets/UltiSnips/cpp.snippets index bb79a0e1..1abd5096 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/cpp.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/cpp.snippets @@ -104,7 +104,7 @@ snippet fnc "Basic c++ doxygen function template" b */ ${1:ReturnType} ${2:FunctionName}(${3:param}) { - ${0:FunctionBody} + ${0:FunctionBody} } endsnippet # vim:ft=snippets: diff --git a/sources_non_forked/vim-snippets/UltiSnips/plsql.snippets b/sources_non_forked/vim-snippets/UltiSnips/plsql.snippets new file mode 100644 index 00000000..4bc7d7b6 --- /dev/null +++ b/sources_non_forked/vim-snippets/UltiSnips/plsql.snippets @@ -0,0 +1,733 @@ +########################################################################### +# PLSQL SNIPPETS # +########################################################################### + +global !p +# Import package +import datetime + +# Return the doc string for PLSQL script +def docstring_plsql(params): + comment = "" + if params: + comment = "/** Parameters\n" + # Split the arguments + args = [arg.strip() for arg in params.split(',')] + for arg in args: + comment += "* {0:30} : \n".format(arg.split(' ')[0].upper()) + comment += "*/\n" + # Return the comment string + return comment + +def hdr_params(params, level=0, gap=" "): + line = level * gap + "-- -----------------------------------------------" + comment = line + if params: + # Split the arguments + args = [arg.strip() for arg in params.split(',')] + for arg in args: + comment += "\n" + level * gap + "-- {0:20} : ".format(arg.split(' ')[0].upper()) + # comment += line + # Return the comment string + return comment + +def dyear(): + """ Returns the current Year in YYYY format + """ + now = datetime.datetime.now() + rv=now.year + return rv + +def today(): + """ Returns the current Date in DD-MON-YYYY format + """ + now = datetime.datetime.now() + rv=now.strftime("%d-%b-%Y") + return rv + +def param(var): + """ Returns the string name wrapped value """ + return "'" + var + " : ' || " + +endglobal + +######################################## +# SQL Snippets # +######################################## +snippet doc "Document comment" + /* + * ${0: comment ...} + */ +endsnippet + +snippet hdr "Header Documentation" +-- ############################################################################# +-- # Copyright (c) `!p snip.rv = dyear()` ${1:company} +-- # All rights reserved +-- # +-- ############################################################################ +-- # Application : ${2:schema} +-- # File Name: : ${3:`!p snip.rv=snip.fn`} +-- # Type : Table +-- # Exec Method : PL/SQL File +-- # Description : This script ${5:create} under the schema $2 +-- # +-- # Change History +-- # ----------------------------------------------------------------------- +-- # Version Date Author Remarks +-- # ======= =========== ================ ============================ +-- # 1.0 `!p snip.rv = today()` Amit Maindola Initial Version +-- ############################################################################# + +endsnippet + +snippet pkggbl "Package Global variables" + -- Declare Global Variables + g_sysdate DATE := SYSDATE; + g_delimiter VARCHAR2( 30 ) := ' '; + g_err_length_limit NUMBER := 1500; + g_package_name CONSTANT VARCHAR2(30) := '${0}'; + g_proc_name VARCHAR2(100) := NULL; + excp_custom EXCEPTION; + + -- Declare User Global Types + +endsnippet + +snippet flushca "Flush Cache" +ALTER SYSTEM FLUSH BUFFER_CACHE; +endsnippet + +snippet flushsp "Flush Shared Pool" +ALTER SYSTEM FLUSH SHARED_POOL; +endsnippet + +snippet err + show errors; +endsnippet + +snippet sel "Select statement" +SELECT ${0:*} FROM ${1} WHERE 1 = 1; +endsnippet + +snippet selc "Select statement" +SELECT COUNT(1) FROM ${1} WHERE ${0}; +endsnippet + +snippet wrn "Where ROWNNUM" +WHERE ROWNUM <= 10 ${0:AND} +endsnippet + +snippet arn "AND ROWNNUM" +AND ROWNUM <= 10 ${0:;} +endsnippet + +snippet ppram "Retuns param in wrapped format" + ||`!p snip.rv = param(t[1].upper())`$1 $0 +endsnippet + +snippet dbo "Show output " + DBMS_OUTPUT.put_line('${0}'); +endsnippet + +snippet dbop "Show Parameter output " + DBMS_OUTPUT.put_line(`!p snip.rv = param(t[1].upper())`$1 $0); +endsnippet + +snippet dbl "Log message in Log Table, Change procedure as defined by you" + DEBUG_LOG_PKG.WRITE_LOG(${1:'Test'},${2:$1} ,$0 ); +endsnippet + +snippet plog "Print Log output " + printlog(`!p snip.rv = param(t[1].upper())`$1 $0); +endsnippet + +snippet dut "DBMS_OUTPUT.put_line" + DBMS_UTILITY.get_time; +endsnippet + +snippet bc "Bulk collect into" + bulk collect into ${0} +endsnippet + +snippet ei "Execute Immediate" + EXECUTE IMMEDIATE '${0:statement}' ; +endsnippet + +snippet eitt "Execute Immediate TRUNCATE Table" + EXECUTE IMMEDIATE( 'TRUNCATE TABLE ${0:table}'); +endsnippet + +snippet eitp "Execute Immediate ALTER Table Truncate partition" + EXECUTE IMMEDIATE( 'ALTER TABLE ${1:table} TRUNCATE PARTITION ${0:partition}'); +endsnippet + +snippet prmpt "Prompt message" +PROMPT ${1:Creating }... +endsnippet + +snippet crseq "Create Sequence" +DROP SEQUENCE ${1:schema}.${2:name}_s; + +CREATE SEQUENCE $1.$2_s + START WITH ${3:1} + MAXVALUE 999999999999999999999999999 + MINVALUE 1 + NOCYCLE + NOCACHE + NOORDER; +endsnippet + +snippet crsyn "Create Synonym" + +CREATE OR REPLACE SYNONYM ${1:schema}.${2:name} FOR ${3:target}.${0}; + +endsnippet + +snippet crind "Create Index" +DROP INDEX $1.$4; + +CREATE INDEX $1.${4:$2_${5}} +ON ${1:schema}.${2:table}(${3}) ${6:TABLESPACE ${0} }; +endsnippet + +######################################## +# Table Operation # +######################################## + +snippet drtab "Drop Table" +DROP TABLE ${1:schema}.${2:name} CASCADE CONSTRAINTS ${3:PURGE}; + +endsnippet + +snippet crtab "Create Table" + +DROP TABLE ${1:schema}.${2:name} CASCADE CONSTRAINTS PURGE; + +CREATE TABLE $1.$2 +( + ${0} +) +${3:TABLESPACE ${4}} +; +endsnippet + +snippet ccol "Add VARCHAR2 column to table" + ${1:,} ${2:name} VARCHAR2(${0:100}) +endsnippet + +snippet dcol "Add DATE column to table" + ${1:,} ${0:name} DATE +endsnippet + +snippet ncol "Add NUMBER column to table" + ${1:,} ${0:name} NUMBER +endsnippet + +snippet at "Alter Table" + ALTER TABLE ${1:table} ${0} +endsnippet + + +######################################### +# Declare Types and local variable # +######################################### + +snippet tr "Type record" + TYPE t_${1:rec} IS RECORD (${0:/* columns */} ); +endsnippet + +snippet tt "Type Table" + TYPE t_${1:tbl} IS TABLE OF ${0:table_name}%ROWTYPE INDEX BY BINARY_INTEGER; +endsnippet + +snippet tc "Type Cursor" + TYPE t_${1:tbl} IS TABLE OF ${0:cur}%ROWTYPE INDEX BY BINARY_INTEGER; +endsnippet + +snippet pn + p_${1} ${2:IN} NUMBER ${3:DEFAULT ${0:NULL}} +endsnippet + +snippet pd + p_${1} ${2:IN} DATE ${3:DEFAULT ${0:SYSDATE}} +endsnippet + +snippet pc + P_${1} ${2:IN} VARCHAR2 ${3:DEFAULT ${0:NULL}} +endsnippet + +snippet ln + l_${1} NUMBER ${2: := ${3} }; +endsnippet + +snippet ld + l_${1} DATE ${2: := ${3} }; +endsnippet + +snippet lc + l_${1} VARCHAR2(${2:100}) ${3: := ${4} }; +endsnippet + +snippet gn + g_${1} NUMBER ${2: := ${3:10} }; +endsnippet + +snippet gd + g_${1} DATE ${2: := ${3:SYSDATE} }; +endsnippet + +snippet gc + g_${1} VARCHAR2(${2:100}) ${3: := ${4} }; +endsnippet + +snippet ltbl + l_tbl_${1} ${0}; +endsnippet + +snippet lrec + l_rec_${1} ${0}; +endsnippet + +######################################### +# Condition, Loops # +######################################### +snippet if "If Condition" + IF(${1}) THEN + ${0}; + END IF; +endsnippet + +snippet ife "IF-Else Condition" + IF(${1}) THEN + ${2}; + ELSIF + ${0}; + END IF; +endsnippet + +snippet els "Else Condition" + ELSIF ${1:condition} THEN + ${0}; +endsnippet + +snippet case "Case statement" + CASE WHEN (${1}) THEN + ${2} + WHEN (${3}) THEN + ${4} + ${0:ELSE} + END +endsnippet + +snippet while "While Loop" + WHILE ${1:a} ${2:condition} ${3:b} LOOP + ${0}; + END LOOP; +endsnippet + +snippet fori "For Loop" + FOR ${1:indx} in ${2:1}..${3:10} LOOP + ${4}; + END LOOP; +endsnippet + +snippet fort "Table For Loop" + FOR ${1:indx} in 1..${2:ttb}.count LOOP + ${0}; + END LOOP; +endsnippet + +snippet loop "Loop statement" + LOOP + ${0}; + END LOOP; +endsnippet + +snippet fora "For All Loop" + IF ( ${1:ttbl}.COUNT > 0 ) THEN + BEGIN + FORALL ${2:indx} IN 1 .. $1.COUNT + -- Insert/Update + ${0} + EXCEPTION --Exception Block + WHEN OTHERS THEN + l_errmsg := 'Error while Bulk updating, Error : ' || SQLERRM; + RAISE excp_custom; + END; + END IF; +endsnippet + +snippet forc "For Cursor Loop" + FOR $1_rec IN ${1:cur} ${2:(${3:param})} + LOOP + ${0} + END LOOP; -- End $1 +endsnippet + +######################################### +# Cursor Operations # +######################################### +snippet dcur "Cursor declaration" + CURSOR ${1:cur} IS + SELECT ${0} + FROM $1 + WHERE 1 = 1; +endsnippet + +snippet copen "Open Cursor" + OPEN ${1:cursor} ${2:( ${3:param} )}; + FETCH $1 + INTO ${4:record}; + ${0} + IF ( $1 %NOTFOUND ) THEN + CLOSE $1; + l_errmsg := 'No records fetched in cursor : $1.'; + RAISE excp_custom; + END IF; + CLOSE $1; +endsnippet + +snippet copenbc "Open Cursor Bulk collect" + OPEN ${1:cursor} ${2:( ${3:param} )}; + FETCH $1 + BULK COLLECT INTO ${4:ttbl}; + CLOSE $1; + + IF ( $4.count = 0 ) THEN + l_errmsg := 'No records fetched in cursor : $1.'; + RAISE excp_custom;{0} + END IF; +endsnippet + +######################################### +# BEGIN/DECLARE Blocks # +######################################### +snippet decl "Declare Begin block" +DECLARE + ${1} +BEGIN + ${0:null} +EXCEPTION --Exception Block + WHEN NO_DATA_FOUND THEN + dbms_output.put_line('No Data Found'); + WHEN OTHERS THEN + dbms_output.put_line('Error while . Error : '||sqlerrm); +END; +endsnippet + +snippet begin "Begin block" +BEGIN + ${0} +EXCEPTION --Exception Block + WHEN NO_DATA_FOUND THEN + printlog('No Data Found'); + WHEN OTHERS THEN + printlog('Error while . Error : '||sqlerrm); +END; +endsnippet + +snippet excp "Exception Block" + EXCEPTION --Exception Block + ${0} + WHEN OTHERS THEN + ${1}; + END; +endsnippet + +snippet rae "Raise Application Error" +RAISE_APPLICATION_ERROR(${1:-20000},${0:''}); +endsnippet + +######################################### +# Procedure/Function calling # +######################################### +snippet crjob "Submit DBMS Job" +-- Submit the job to get the output +BEGIN + DECLARE + vjob INTEGER; + BEGIN + DBMS_JOB.submit( vjob, '${1:procedure}${0:('''')};', SYSDATE ); + DBMS_OUTPUT.put_line( 'Job id : ' || vjob ); + COMMIT; + END; +END; +endsnippet + +snippet whilejob "Submit DBMS Job with While Loop" +-- Submit the job to get the output + +BEGIN + DECLARE + vjob INTEGER; + BEGIN + DBMS_JOB.submit ( vjob , ' +DECLARE + l_start_date DATE := ''${1:01-Jan-2017}''; +BEGIN + WHILE l_start_date < ''${2:01-Jan-2017}'' + LOOP + ${3:Procedure}${0:( to_char(l_start_date,''YYYYMMDD'') )}; + l_start_date := TRUNC( l_start_date + 1 ); + END LOOP; +EXCEPTION --Exception Block + WHEN OTHERS THEN + DBMS_OUTPUT.put_line( ''Error while . Error : '' || SQLERRM ); +END; + ' + , SYSDATE + ); + DBMS_OUTPUT.put_line( 'Job id : ' || vjob ); + COMMIT; + END; +END; +endsnippet + + +######################################### +# Function creation scripts # +######################################### +snippet crprintlog "Create Printlog Procedure" + ------------------------------------------------------------------------------------------------ + -- PROCEDURE : PRINTLOG + -- Description : This procedure is used to print log messages in Log file, Table and Console + ------------------------------------------------------------------------------------------------ + PROCEDURE printlog (p_message IN VARCHAR2) + IS + l_errmsg VARCHAR2 (10000); + BEGIN + l_errmsg := SUBSTR ( p_message, 1, g_err_length_limit); + fnd_file.put_line ( fnd_file.LOG, l_errmsg); -- Debug log file + DBMS_OUTPUT.put_line (l_errmsg); -- Console output + DEBUG_LOG_PKG.WRITE_LOG(g_package_name,g_proc_name,p_message); -- Debug table + END printlog; +endsnippet + +snippet crgeterr "Create get_errmsg function" + -- Form the error message for when others + FUNCTION get_errmsg( p_message IN VARCHAR2 DEFAULT NULL ) + RETURN VARCHAR2 + IS + BEGIN + RETURN 'Error occured in ' || g_package_name || '.' || g_proc_name || '. ' || NVL( p_message, '' ) || ' Error : ' || SQLERRM; + EXCEPTION --Exception Block + WHEN OTHERS THEN + printlog( 'Error while forming messgage. Error : ' || SQLERRM ); + RETURN NULL; + END; +endsnippet + +snippet crpksfunc "Create package specification function" +------------------------------------------------------------------------------------------------ +-- Function : `!p snip.rv = t[1].upper()` +-- Description : This Function will ${4:description}. +`!p snip.rv=hdr_params(t[3]) ` +------------------------------------------------------------------------------------------------ +FUNCTION ${1:func} ${2:(${3:params})} + RETURN ${0}; +endsnippet + +snippet crpksproc "Create package specification procedure" +------------------------------------------------------------------------------------------------ +-- PROCEDURE : `!p snip.rv = t[1].upper()` +-- Description : This Procedure will ${4:description}. +`!p snip.rv=hdr_params(t[3],0) ` +------------------------------------------------------------------------------------------------ +PROCEDURE ${1:proc} ${2:(${3:params})} ; +endsnippet + +snippet crpkbfunc "Create package body function" + ------------------------------------------------------------------------------------------------ + -- Function : `!p snip.rv = t[1].upper()` + -- Description : This Function will ${8:description}. + `!p snip.rv=hdr_params(t[3],2) ` + ------------------------------------------------------------------------------------------------ + FUNCTION ${1:func} ${2:(${3:params})} + RETURN ${4} + IS + -- Declare Cursors + -- Declare Variables + ${5:l_} $4 ${6:( ${7:length} )}; + BEGIN + -- Initialize + g_proc_name := '`!p snip.rv = t[1].upper()`'; + ${0} + -- Return value + RETURN $5 ; + EXCEPTION + WHEN OTHERS + THEN + RETURN NULL; + END $1; +endsnippet + +snippet crpkbproc "Create package body procedure" + +------------------------------------------------------------------------------------------------ +-- PROCEDURE : `!p snip.rv = t[1].upper()` +-- Description : This Procedure will ${4:description}. +`!p snip.rv=hdr_params(t[3]) ` +------------------------------------------------------------------------------------------------ +PROCEDURE ${1:proc} ${2:(${3:params})} +IS + -- Declare cursors + -- Declare Out and exception variables + l_errmsg VARCHAR2( 10000 ) := null; + excp_skip EXCEPTION; +-- Declare Varibales + +BEGIN + -- Initializing out parameters + g_proc_name := '`!p snip.rv = t[1].upper()`'; + + ${0} +EXCEPTION -- Exception block of Procedure + WHEN excp_custom THEN + ROLLBACK; + printlog( l_errmsg ); + WHEN OTHERS THEN + ROLLBACK; + l_errmsg := get_errmsg; + printlog( l_errmsg ); +END $1; + +endsnippet + +snippet crpks "Create Package specification" +CREATE OR REPLACE PACKAGE ${1}.${2} +AS +-- ############################################################################# +-- # Copyright (c) `!p snip.rv = dyear()` ${3} +-- # All rights reserved +-- # +-- ############################################################################ +-- # +-- # Application : $1 +-- # File Name: : `!p snip.rv = t[2].upper()`.pks +-- # Exec Method : PL/SQL Stored - Procedure +-- # Description : Package used for ${4} +-- # +-- # Change History +-- # ----------------------------------------------------------------------- +-- # Version Date Author Remarks +-- # ======= =========== ============= ============================ +-- # 1.0 `!p snip.rv = today()` Amit Maindola Initial Version +-- # +-- # +-- ############################################################################ + ${0} +END $2; +/ + +SHOW ERROR +/ +endsnippet + +snippet crpkb "Create package body" +CREATE OR REPLACE PACKAGE BODY ${1}.${2} +IS +-- ############################################################################# +-- # Copyright (c) `!p snip.rv = dyear()` ${3} +-- # All rights reserved +-- # +-- ############################################################################ +-- # +-- # Application : $1 +-- # File Name: : `!p snip.rv = t[2].upper()`.pkb +-- # Exec Method : PL/SQL Stored - Procedure +-- # Description : Package used for ${4} +-- # +-- # Change History +-- # ----------------------------------------------------------------------- +-- # Version Date Author Remarks +-- # ======= =========== ============= ============================ +-- # 1.0 `!p snip.rv = today()` Amit Maindola Initial Version +-- # +-- # +-- ############################################################################ + -- Declare Global Variables + g_sysdate DATE := SYSDATE; + g_delimiter VARCHAR2( 30 ) := ' '; + g_err_length_limit NUMBER := 1500; + g_package_name CONSTANT VARCHAR2(30) := '`!p snip.rv = t[2].upper()`'; + g_proc_name VARCHAR2(100) := NULL; + excp_custom EXCEPTION; + + -- Declare User Global Types + + ------------------------------------------------------------------------------------------------ + -- PROCEDURE : PRINTLOG + -- Description : This procedure is used to print log messages + ------------------------------------------------------------------------------------------------ + PROCEDURE printlog( p_message IN VARCHAR2 ) + IS + BEGIN + DBMS_OUTPUT.PUT_LINE( p_message ); + DEBUG_LOG_PKG.WRITE_LOG(g_package_name,g_proc_name,p_message); + END printlog; + + -- Form the error message for when others + FUNCTION get_errmsg( p_message IN VARCHAR2 DEFAULT NULL ) + RETURN VARCHAR2 + IS + BEGIN + RETURN 'Error occured in ' || g_package_name || '.' || g_proc_name || '. ' || NVL( p_message, '' ) || ' Error : ' || SQLERRM; + EXCEPTION --Exception Block + WHEN OTHERS THEN + printlog( 'Error while forming messgage. Error : ' || SQLERRM ); + RETURN NULL; + END; + +END $2; +/ + +SHOW ERROR +/ + +endsnippet + +snippet crproc "Create procedure" + +CREATE OR REPLACE PROCEDURE ${1:schema}.${2:name} ${3:( ${4:prams} )} +-- ############################################################################# +-- # Copyright (c) `!p snip.rv = dyear()` ${5} +-- # All rights reserved +-- # +-- ############################################################################ +-- # +-- # Application : $1 +-- # File Name: : `!p snip.rv = t[2].upper()`.prc +-- # Exec Method : PL/SQL Stored - Procedure +-- # Description : Package used for ${6} +-- # +-- # Change History +-- # ----------------------------------------------------------------------- +-- # Version Date Author Remarks +-- # ======= =========== ============= ============================ +-- # 1.0 `!p snip.rv = today()` Amit Maindola Initial Version +-- # +-- # +-- ############################################################################ +is + g_proc_name VARCHAR2(30) := '`!p snip.rv = t[2].upper()`'; + l_errmsg VARCHAR2( 10000 ) := null; + excp_custom EXCEPTION; + -- Declare cursors + -- Declare Varibales +BEGIN + -- Initializing out parameters + + ${0} +EXCEPTION -- Exception block of Procedure + WHEN excp_custom THEN + ROLLBACK; + DEBUG_LOG_PKG.WRITE_LOG(g_proc_name,g_proc_name ,l_errmsg ); + WHEN OTHERS THEN + ROLLBACK; + l_errmsg := 'Exception in procedure. '||SQLERRM; + DEBUG_LOG_PKG.WRITE_LOG(g_proc_name,g_proc_name ,l_errmsg ); +END $2; + +endsnippet + diff --git a/sources_non_forked/vim-snippets/UltiSnips/robot.snippets b/sources_non_forked/vim-snippets/UltiSnips/robot.snippets index cc3c8663..955ecdd6 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/robot.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/robot.snippets @@ -29,7 +29,7 @@ Return From Keyword ${1:${optional return value}} endsnippet snippet rfki "Return From Keyword If" -Return From Keyword If ${1:${condition}} ${2:${optional return value}} +Return From Keyword If '\${${1:rc}}' != '${2:abc}' ${3:${optional return value}} endsnippet snippet rk "Run Keyword" @@ -54,7 +54,7 @@ Run Keyword And Return ${1:${kw}} ${2:${args}} endsnippet snippet rkari "Run Keyword And Return If" -Run Keyword And Return If ${1:{condition}} ${2:${kw}} ${3:${args}} +Run Keyword And Return If '\${${1:rc}}' != '${2:abc}' ${3:${kw}} ${4:${args}} endsnippet snippet rkars "Run Keyword And Return Status" @@ -62,9 +62,12 @@ snippet rkars "Run Keyword And Return Status" endsnippet snippet rki "Run Keyword If" -Run Keyword If ${1:${rc} < 0} ${2:${VISUAL:Some keyword returning a value}} -... ELSE IF ${3:'${str}' == 'abc'} ${4:Another keyword} -... ELSE ${5:Final keyword} +Run Keyword If '\${${1:rc}}' != '${2:abc}' +... ${3:${VISUAL:Some keyword returning a value}} +... ELSE IF '\${${4:str}}' != '${5:def}' +... ${6:Another keyword} +... ELSE +... ${7:Final keyword} endsnippet snippet rkiactf "Run Keyword If Any Critical Tests Failed" @@ -102,7 +105,7 @@ Run Keywords endsnippet snippet rku "Run Keyword Unless" -Run Keyword Unless ${1:${condition}} ${2:${kw}} ${3:${args}} +Run Keyword Unless '\${${1:rc}}' != '${2:abc}' ${3:${kw}} ${4:${args}} endsnippet snippet sgv "Set Global Variable" @@ -130,7 +133,9 @@ snippet sv "Set Variable" endsnippet snippet svi "Set Variable If" -\${${1:var}}= Set Variable If ${2:${condition}} ${3:${value true}} ${4:${value false}} +\${${1:var}}= Set Variable If '\${${2:rc}}' != '${3:abc}' +`!p snip.rv = '...' + ' ' * (len(t[1]) + 23)` ${4:${value true}} +`!p snip.rv = '...' + ' ' * (len(t[1]) + 23)` ${5:${value false}} endsnippet snippet wuks "Wait Until Keyword Succeeds" diff --git a/sources_non_forked/vim-snippets/UltiSnips/tex.snippets b/sources_non_forked/vim-snippets/UltiSnips/tex.snippets index d89f30bc..e54c2c72 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/tex.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/tex.snippets @@ -113,28 +113,28 @@ snippet it "Individual item" b endsnippet snippet part "Part" b -\part{${1:part name}} +\part{${1:part name}}% \label{prt:${2:${1/(\w+)|\W+/(?1:\L$0\E:_)/ga}}} $0 endsnippet snippet cha "Chapter" b -\chapter{${1:chapter name}} +\chapter{${1:chapter name}}% \label{cha:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 endsnippet snippet sec "Section" b -\section{${1:section name}} +\section{${1:section name}}% \label{sec:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 endsnippet snippet sec* "Section" b -\section*{${1:section name}} +\section*{${1:section name}}% \label{sec:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} ${0} @@ -142,42 +142,42 @@ endsnippet snippet sub "Subsection" b -\subsection{${1:subsection name}} +\subsection{${1:subsection name}}% \label{sub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 endsnippet snippet sub* "Subsection" b -\subsection*{${1:subsection name}} +\subsection*{${1:subsection name}}% \label{sub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} ${0} endsnippet snippet ssub "Subsubsection" b -\subsubsection{${1:subsubsection name}} +\subsubsection{${1:subsubsection name}}% \label{ssub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 endsnippet snippet ssub* "Subsubsection" b -\subsubsection*{${1:subsubsection name}} +\subsubsection*{${1:subsubsection name}}% \label{ssub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} ${0} endsnippet snippet par "Paragraph" b -\paragraph{${1:paragraph name}} +\paragraph{${1:paragraph name}}% \label{par:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 endsnippet snippet subp "Subparagraph" b -\subparagraph{${1:subparagraph name}} +\subparagraph{${1:subparagraph name}}% \label{par:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} $0 diff --git a/sources_non_forked/vim-snippets/snippets/cpp.snippets b/sources_non_forked/vim-snippets/snippets/cpp.snippets index a6459023..9496555e 100644 --- a/sources_non_forked/vim-snippets/snippets/cpp.snippets +++ b/sources_non_forked/vim-snippets/snippets/cpp.snippets @@ -200,10 +200,12 @@ snippet lld # snippets exception snippet try try { - + }catch(${1}) { - + } - - - +snippet af auto function + auto ${1:name}(${2}) -> ${3:void} + { + ${0} + }; diff --git a/sources_non_forked/vim-snippets/snippets/ps1.snippets b/sources_non_forked/vim-snippets/snippets/ps1.snippets index acab10cc..41099d9d 100644 --- a/sources_non_forked/vim-snippets/snippets/ps1.snippets +++ b/sources_non_forked/vim-snippets/snippets/ps1.snippets @@ -1,19 +1,19 @@ -# Snippets for +# Snippets for # Authored by Trevor Sullivan # PowerShell Class snippet class class { - [string] ${0:FirstName} + [string] ${1:FirstName} } -# PowerShell Advanced Function +# PowerShell Advanced Function snippet function - function {0:name} { + function ${1:name} { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] - [string] $Param1 + [string] ${2:Param} ) begin { @@ -29,30 +29,74 @@ snippet function # PowerShell Splatting snippet splatting $Params = @{ - ${0:Param1} = 'Value1' - ${1:Param2} = 'Value2' + ${1:Param1} = '{2:Value1}' + ${3:Param2} = '{4:Value2}' } - ${3:CommandName} + ${5:CommandName} @Params # PowerShell Enumeration snippet enum - enum ${0:name} { - ${1:item1} - ${2:item2} + enum ${1:name} { + ${2:item1} + ${3:item2} } # PowerShell if..then snippet if - if (${0:condition}) { - ${1:statement} + if (${1:condition}) { + ${2:statement} + } + +# PowerShell if..else +snippet ife + if ( ${1:condition} ) { + ${2} + } + else { + ${3} } # PowerShell While Loop snippet while - while (${0:condition}) { - ${1:statement} + while (${1:condition}) { + ${2:statement} } # PowerShell Filter..Sort snippet filtersort - ${0:command} | Where-Object -FilterScript { $PSItem.${1:property} -${2:operator} '${3:expression}' } | Sort-Object -Property ${4:sortproperty} + ${1:command} | Where-Object -FilterScript { $PSItem.${2:property} -${3:operator} '${4:expression}' } | Sort-Object -Property ${5:sortproperty} + +# PowerShell foreach +snippet foreach + foreach ( $${1:iterator} in $${2:collection} ) { + ${3:statement} + } + +# PowerShell export-csv +snippet epcsv + Export-CSV -NoTypeInformation -Path ${1:path} + +# Powershell Comment Based Help +snippet help + <# + .SYNOPSIS + ${1:Short Description} + .DESCRIPTION + ${2:Full Description} + .PARAMETER ${3:Param1} + ${4: $3 usage} + .EXAMPLE + ${5:Example} + .NOTES + ${6:notes} + .LINK + ${7:online help} + #> + +# Powershell switch statement +snippet switch + switch ( ${1:test} ){ + ${2:condition1} { ${3:action} } + ${4:condition2} { ${5:action} } + default { ${6:action} } + diff --git a/sources_non_forked/vim-snippets/snippets/puppet.snippets b/sources_non_forked/vim-snippets/snippets/puppet.snippets index 83886112..7d8e6d8a 100644 --- a/sources_non_forked/vim-snippets/snippets/puppet.snippets +++ b/sources_non_forked/vim-snippets/snippets/puppet.snippets @@ -1,87 +1,60 @@ # Snippets for use with VIM and http://www.vim.org/scripts/script.php?script_id=2540 # -# Please contact R.I.Pienaar for additions and feedback, +# Please contact Jorge Vidal for additions and feedback, # see it in action @ http://www.devco.net/archives/2009/09/22/vim_and_puppet.php +# Many thanks to the original author R.I.Pienaar -# Header to match http://docs.puppetlabs.com/guides/style_guide.html#puppet-doc +# Header using Puppet Strings (YARD tags) https://puppet.com/docs/puppet/latest/modules_documentation.html +# More info: https://github.com/puppetlabs/puppet-strings snippet classheader - # == Class: ${1:`vim_snippets#Filename(expand('%:p:s?.*modules/??:h:h'), 'name')`} + # ${1:`vim_snippets#Filename(expand('%:p:s?.*modules/??:h:h'), 'class-name')`} + # ${2:A description of what this class does} # - # ${2:Full description of class $1 here} + # @summary ${3:A short summary of the purpose of this class} # - # === Parameters + # @param ${4:parameter1} [${5:String}] + # ${6:Explanation of what this parameter affects.} # - # Document parameters here. + # @example Simple use + # class { '$1': } # - # [*parameter1*] - # Explanation of what this parameter affects and what it defaults to. - # e.g. "Specify one or more upstream ntp servers as an array." + # @example Use with params + # class { '$1': + # $$4 => '${7:undef}', + # } # - # === Variables + # @author ${8:`g:snips_author`} <${9:`g:snips_email`}> # - # Here you should define a list of variables that this module would require. + # @note Copyright `strftime("%Y")` $8 # - # [*variable1*] - # Explanation of how this variable affects the funtion of this class and - # if it has a default. e.g. "The parameter enc_ntp_servers must be set by the - # External Node Classifier as a comma separated list of hostnames." - # - # === Examples - # - # class { '$1': - # parameter1 => [ 'just', 'an', 'example', ] - # } - # - # === Authors - # - # `g:snips_author` <`g:snips_email`> - # - # === Copyright - # - # Copyright `strftime("%Y")` `g:snips_author` - # - class $1 (${3}){ - ${4} + class $1( + $$4 = undef, + ) { + ${0} } snippet defheader - # == Define: ${1:`vim_snippets#Filename(expand('%:p:s?.*modules/??:r:s?/manifests/?::?'), 'name')`} + # ${1:`vim_snippets#Filename(expand('%:p:s?.*modules/??:h:h'), 'define-name')`} + # ${2:A description of what this define does} # - # ${2:Full description of defined resource type $1 here} + # @summary ${3:A short summary of the purpose of this define} # - # === Parameters - # - # Document parameters here - # - # [*namevar*] - # If there is a parameter that defaults to the value of the title string - # when not explicitly set, you must always say so. This parameter can be - # referred to as a "namevar," since it's functionally equivalent to the - # namevar of a core resource type. - # - # [*basedir*] - # Description of this variable. For example, "This parameter sets the - # base directory for this resource type. It should not contain a trailing - # slash." - # - # === Examples - # - # Provide some examples on how to use this type: + # @param ${4:parameter1} [${5:String}] + # ${6:Explanation of what this parameter affects.} # + # @example Simple use # $1 { 'namevar': - # basedir => '/tmp/src', + # $$4 => '${7:undef}', # } # - # === Authors + # @author ${8:`g:snips_author`} <${9:`g:snips_email`}> # - # `g:snips_author` <`g:snips_email`> + # @note Copyright `strftime("%Y")` $8 # - # === Copyright - # - # Copyright `strftime("%Y")` `g:snips_author` - # - define $1(${3}) { - ${4} + define $1( + $$4 = undef, + ) { + ${0} } # Language Constructs diff --git a/sources_non_forked/vim-snippets/snippets/python.snippets b/sources_non_forked/vim-snippets/snippets/python.snippets index d0cea516..3c67125c 100644 --- a/sources_non_forked/vim-snippets/snippets/python.snippets +++ b/sources_non_forked/vim-snippets/snippets/python.snippets @@ -115,21 +115,21 @@ snippet try Try/Except ${1:${VISUAL}} except ${2:Exception} as ${3:e}: ${0:raise $3} -snippet try Try/Except/Else +snippet trye Try/Except/Else try: ${1:${VISUAL}} except ${2:Exception} as ${3:e}: ${4:raise $3} else: ${0} -snippet try Try/Except/Finally +snippet tryf Try/Except/Finally try: ${1:${VISUAL}} except ${2:Exception} as ${3:e}: ${4:raise $3} finally: ${0} -snippet try Try/Except/Else/Finally +snippet tryef Try/Except/Else/Finally try: ${1:${VISUAL}} except ${2:Exception} as ${3:e}: diff --git a/sources_non_forked/vim-snippets/snippets/rails.snippets b/sources_non_forked/vim-snippets/snippets/rails.snippets index 3742cd40..4678de92 100644 --- a/sources_non_forked/vim-snippets/snippets/rails.snippets +++ b/sources_non_forked/vim-snippets/snippets/rails.snippets @@ -42,10 +42,10 @@ snippet defcreate if @$1.save flash[:notice] = '$2 was successfully created.' format.html { redirect_to(@$1) } - format.xml { render xml: @$1, status: :created, location: @$1 } + format.json { render json: @$1, status: :created, location: @$1 } else format.html { render action: 'new' } - format.xml { render xml: @$1.errors, status: :unprocessable_entity } + format.json { render json: @$1.errors, status: :unprocessable_entity } end end end @@ -56,7 +56,7 @@ snippet defdestroy respond_to do |format| format.html { redirect_to($1s_url) } - format.xml { head :ok } + format.json { head :ok } end end snippet defedit @@ -69,7 +69,7 @@ snippet defindex respond_to do |format| format.html # index.html.erb - format.xml { render xml: @$1s } + format.json { render json: @$1s } end end snippet defnew @@ -78,7 +78,7 @@ snippet defnew respond_to do |format| format.html # new.html.erb - format.xml { render xml: @$1 } + format.json { render json: @$1 } end end snippet defshow @@ -87,7 +87,7 @@ snippet defshow respond_to do |format| format.html # show.html.erb - format.xml { render xml: @$1 } + format.json { render json: @$1 } end end snippet defupdate @@ -98,10 +98,10 @@ snippet defupdate if @$1.update($1_params) flash[:notice] = '$2 was successfully updated.' format.html { redirect_to(@$1) } - format.xml { head :ok } + format.json { head :ok } else format.html { render action: 'edit' } - format.xml { render xml: @$1.errors, status: :unprocessable_entity } + format.json { render json: @$1.errors, status: :unprocessable_entity } end end end diff --git a/sources_non_forked/vim-snippets/snippets/tex.snippets b/sources_non_forked/vim-snippets/snippets/tex.snippets index 527d0772..f304a56e 100644 --- a/sources_non_forked/vim-snippets/snippets/tex.snippets +++ b/sources_non_forked/vim-snippets/snippets/tex.snippets @@ -292,7 +292,9 @@ snippet block block environment \\begin{block}{${1:title}} ${0:${VISUAL}} \\end{block} -snippet alert alertblock environment +snippet alert alert text + \\alert{${1:${VISUAL:text}}} ${0} +snippet alertblock alertblock environment \\begin{alertblock}{${1:title}} ${0:${VISUAL}} \\end{alertblock} @@ -309,6 +311,12 @@ snippet col2 two-column environment ${0} \\end{column} \\end{columns} +snippet multicol2 two-column environment with multicol + \\begin{multicols}{2} + ${1} + \columnbreak + ${0} + \\end{multicols} snippet \{ \{ \} \\{ ${0} \\} #delimiter diff --git a/vimrcs/plugins_config.vim b/vimrcs/plugins_config.vim index 9af44a59..a7d9814e 100644 --- a/vimrcs/plugins_config.vim +++ b/vimrcs/plugins_config.vim @@ -146,24 +146,13 @@ let g:go_fmt_command = "goimports" """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " => Syntastic (syntax checker) """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Python -let g:syntastic_python_checkers=['pyflakes'] +let g:ale_linters = { +\ 'javascript': ['jshint'], +\ 'python': ['flake8'], +\ 'go': ['go', 'golint', 'errcheck'] +\} -" Javascript -let g:syntastic_javascript_checkers = ['jshint'] - -" Go -let g:syntastic_auto_loc_list = 1 -let g:syntastic_go_checkers = ['go', 'golint', 'errcheck'] - -" Custom CoffeeScript SyntasticCheck -func! SyntasticCheckCoffeescript() - let l:filename = substitute(expand("%:p"), '\(\w\+\)\.coffee', '.coffee.\1.js', '') - execute "tabedit " . l:filename - execute "SyntasticCheck" - execute "Errors" -endfunc -nnoremap c :call SyntasticCheckCoffeescript() +nmap a (ale_next_wrap) """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""