From 46441f08f0aff2f465b1f1d7af023218e651df24 Mon Sep 17 00:00:00 2001 From: Maxim Likhachev Date: Tue, 28 Jul 2020 12:52:45 +0300 Subject: [PATCH] vim: plugins: ++auto-git-diff --- etc/soft/nvim/+plugins/auto-git-diff/README.md | 83 +++++++++++++ .../auto-git-diff/autoload/auto_git_diff.vim | 132 +++++++++++++++++++++ .../auto-git-diff/plugin/auto-git-diff.vim | 16 +++ 3 files changed, 231 insertions(+) create mode 100644 etc/soft/nvim/+plugins/auto-git-diff/README.md create mode 100644 etc/soft/nvim/+plugins/auto-git-diff/autoload/auto_git_diff.vim create mode 100644 etc/soft/nvim/+plugins/auto-git-diff/plugin/auto-git-diff.vim diff --git a/etc/soft/nvim/+plugins/auto-git-diff/README.md b/etc/soft/nvim/+plugins/auto-git-diff/README.md new file mode 100644 index 0000000..91f928a --- /dev/null +++ b/etc/soft/nvim/+plugins/auto-git-diff/README.md @@ -0,0 +1,83 @@ +Show git diff for Git Rebase Interactive +======================================= + +`auto-git-diff` is a vim plugin which shows git diff between each commit and +its parent commit below the commit list window of git rebase interactive. + +When you move a text-cursor in `git-rebase-todo` file, `auto-git-diff` gets +a commit hash of the line where the cursor exists and update the diff window. + + +![sample_image](https://user-images.githubusercontent.com/359226/33921582-2319e7a0-e008-11e7-8be3-ba9f68a78217.gif) + +## Variables + + - `g:auto_git_diff_disable_auto_update` + +If this variable is set to 1, the diff window won't update automatically. You +can update the diff window manually with the following key mapping: +`(auto_git_diff_manual_update)`. + + - `g:auto_git_diff_show_window_at_right` + +If this variable is set to 1, the diff window will be created at right on the +commit list window. + + - `g:auto_git_diff_command_options` + +The options passed to `git diff` command. If this variable is not defined, +`--stat -p --submodule -C -C` will be used. + +## Mappings + + - `(auto_git_diff_manual_update)` + +This key mapping updates the diff window manully. + + - `(auto_git_diff_scroll_down_1)` + - `(auto_git_diff_scroll_up_1)` + - `(auto_git_diff_scroll_down_half)` + - `(auto_git_diff_scroll_up_half)` + - `(auto_git_diff_scroll_down_page)` + - `(auto_git_diff_scroll_up_page)` + +These key mappings scroll the diff window without moving the cursor into the +window. `_1` means scrolling one line (`` or ``), `_half` means +scrolling half a page (`` or ``) and `_page` means scrolling one page +(`` or ``). + +Following is an example to configure the mappings in your `vimrc`. + +```vim +function! s:setup_auto_git_diff() abort + nmap (auto_git_diff_scroll_manual_update) + nmap (auto_git_diff_scroll_down_half) + nmap (auto_git_diff_scroll_up_half) +endfunction +autocmd FileType gitrebase call setup_auto_git_diff() +``` + +## License + + The MIT License (MIT) + Copyright (c) 2015 hotwatermorning + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/etc/soft/nvim/+plugins/auto-git-diff/autoload/auto_git_diff.vim b/etc/soft/nvim/+plugins/auto-git-diff/autoload/auto_git_diff.vim new file mode 100644 index 0000000..b2d2830 --- /dev/null +++ b/etc/soft/nvim/+plugins/auto-git-diff/autoload/auto_git_diff.vim @@ -0,0 +1,132 @@ +let s:save_cpo = &cpo +let s:previous_hash_string = "" +set cpo&vim + +nnoremap (auto_git_diff_manual_update) :call auto_git_diff#show_git_diff() + +" Get commit hash from current line. +" The first colomn(pick, r, ...) can be empty. +function! s:get_git_hash() abort + return matchstr(getline('.'), '^\(\w\+\>\)\=\(\s*\)\zs\x\{4,40\}\>\ze') +endfunction + +" Find the preview window. +" If not found, return zero. +function! s:find_preview_window() abort + for nr in range(1, winnr('$')) + if getwinvar(nr, "&pvw") == 1 + " found a preview + return nr + endif + endfor + return 0 +endfunction + +" Execute git diff between hash~1 and hash with options a:opts, +" and show the result into the preview window. +function! s:show_git_diff_impl(hash, vertsplit, opts) abort + + let wn = s:find_preview_window() + + if wn == 0 + " The preview window is not found. + " => Open new window + + if a:vertsplit + rightbelow vnew + else + rightbelow new + endif + + silent! setlocal previewwindow bufhidden=delete nobackup noswf nobuflisted nowrap buftype=nofile + + let wn = bufwinnr('%') + else + " Preview window is found" + " Move to the window + silent execute wn."wincmd w" + endif + + let out = s:get_git_diff(a:hash, a:opts) + + if v:shell_error + setlocal ft= + else + setlocal ft=diff + endif + + setlocal modifiable + + silent! % delete _ + silent! $ put=out + silent! 1 delete _ + + setlocal nomodifiable + + noremap q :bw + + silent wincmd p +endfunction + +function! s:get_git_diff(hash, opts) abort + let prefix = has("win32") ? "set LANG=C & " : "env LANG=C " + + let diff_command = "git diff ".a:opts." ".a:hash."~1 ".a:hash + silent let out = system(prefix.diff_command) + if !v:shell_error + return out + endif + let save_out = out + + let empty_tree_sha1_hex = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" + let diff_command = "git diff ".a:opts." ".empty_tree_sha1_hex." ".a:hash + silent let out = system(prefix.diff_command) + if !v:shell_error + return out + endif + + return save_out +endfunction + +function! auto_git_diff#show_git_diff() abort + + let hash_string = s:get_git_hash() + if hash_string == "" || hash_string == s:previous_hash_string + return + else + let s:previous_hash_string = hash_string + endif + + call s:show_git_diff_impl( s:get_git_hash() +\ , get(g:, "auto_git_diff_show_window_at_right", 0) +\ , get(g:, "auto_git_diff_command_options", "--stat -p --submodule -C -C") +\ ) +endfunction + +" Called when text-cursor is moved. +function! auto_git_diff#auto_update_git_diff() abort + + if get(g:, "auto_git_diff_disable_auto_update", 0) + return + endif + + if mode() != "n" + return + endif + + call auto_git_diff#show_git_diff() +endfunction + +function! auto_git_diff#scroll_in_preview_window(map) abort + if s:find_preview_window() == 0 + return + endif + wincmd P + sandbox let input = eval('"\<'.a:map.'>"') + execute "normal!" input + wincmd p +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo + diff --git a/etc/soft/nvim/+plugins/auto-git-diff/plugin/auto-git-diff.vim b/etc/soft/nvim/+plugins/auto-git-diff/plugin/auto-git-diff.vim new file mode 100644 index 0000000..8be9d82 --- /dev/null +++ b/etc/soft/nvim/+plugins/auto-git-diff/plugin/auto-git-diff.vim @@ -0,0 +1,16 @@ +if exists("g:did_auto_git_diff") | finish | endif +let g:did_auto_git_diff = 1 + +augroup auto_git_diff_command_group + autocmd! + autocmd CursorMoved git-rebase-todo call auto_git_diff#auto_update_git_diff() + autocmd FileType gitrebase setlocal nowarn nowb +augroup END + +nnoremap (auto_git_diff_scroll_down_1) :call auto_git_diff#scroll_in_preview_window("C-e") +nnoremap (auto_git_diff_scroll_up_1) :call auto_git_diff#scroll_in_preview_window("C-y") +nnoremap (auto_git_diff_scroll_down_half) :call auto_git_diff#scroll_in_preview_window("C-d") +nnoremap (auto_git_diff_scroll_up_half) :call auto_git_diff#scroll_in_preview_window("C-u") +nnoremap (auto_git_diff_scroll_down_page) :call auto_git_diff#scroll_in_preview_window("C-f") +nnoremap (auto_git_diff_scroll_up_page) :call auto_git_diff#scroll_in_preview_window("C-b") +