From 82ed35903e37c19f0598ce1204aaa23972462348 Mon Sep 17 00:00:00 2001 From: Stefan Liebl Date: Mon, 23 May 2016 22:20:55 +0200 Subject: [PATCH] GLVS Change-Id: I73fb1df3adaba7a1248c20664f1654372ad7223e --- vimfiles/GetLatest/GetLatestVimScripts.dat | 8 +- vimfiles/autoload/SrchRplcHiGrp.vim | 537 +++++++ vimfiles/autoload/diffchar.vim | 1262 +++++++++++++++++ vimfiles/autoload/merginal.vim | 1134 +-------------- vimfiles/autoload/merginal/buffers/base.vim | 229 +++ .../autoload/merginal/buffers/branchList.vim | 250 ++++ .../merginal/buffers/cherryPickConflicts.vim | 33 + .../merginal/buffers/conflictsBase.vim | 61 + .../autoload/merginal/buffers/diffFiles.vim | 116 ++ .../autoload/merginal/buffers/historyLog.vim | 128 ++ .../merginal/buffers/immutableBranchList.vim | 110 ++ .../merginal/buffers/mergeConflicts.vim | 10 + .../autoload/merginal/buffers/rebaseAmend.vim | 34 + .../merginal/buffers/rebaseConflicts.vim | 37 + vimfiles/autoload/merginal/modulelib.vim | 87 ++ vimfiles/autoload/merginal/util.vim | 89 ++ vimfiles/autoload/tcomment.vim | 374 +++-- vimfiles/doc/SrchRplcHiGrp.txt | 463 +++--- vimfiles/doc/diffchar.txt | 392 +++++ vimfiles/doc/merginal.txt | 32 +- vimfiles/doc/tags | 106 +- vimfiles/doc/tcomment.txt | 294 ++-- vimfiles/plugin/SrchRplcHiGrp.vim | 483 +------ vimfiles/plugin/diffchar.vim | 1257 +--------------- vimfiles/plugin/merginal.vim | 60 +- vimfiles/plugin/tcomment.vim | 237 ++-- 26 files changed, 4384 insertions(+), 3439 deletions(-) create mode 100644 vimfiles/autoload/SrchRplcHiGrp.vim create mode 100644 vimfiles/autoload/diffchar.vim mode change 100755 => 100644 vimfiles/autoload/merginal.vim create mode 100644 vimfiles/autoload/merginal/buffers/base.vim create mode 100644 vimfiles/autoload/merginal/buffers/branchList.vim create mode 100644 vimfiles/autoload/merginal/buffers/cherryPickConflicts.vim create mode 100644 vimfiles/autoload/merginal/buffers/conflictsBase.vim create mode 100644 vimfiles/autoload/merginal/buffers/diffFiles.vim create mode 100644 vimfiles/autoload/merginal/buffers/historyLog.vim create mode 100644 vimfiles/autoload/merginal/buffers/immutableBranchList.vim create mode 100644 vimfiles/autoload/merginal/buffers/mergeConflicts.vim create mode 100644 vimfiles/autoload/merginal/buffers/rebaseAmend.vim create mode 100644 vimfiles/autoload/merginal/buffers/rebaseConflicts.vim create mode 100644 vimfiles/autoload/merginal/modulelib.vim create mode 100644 vimfiles/autoload/merginal/util.vim create mode 100644 vimfiles/doc/diffchar.txt mode change 100755 => 100644 vimfiles/doc/merginal.txt mode change 100755 => 100644 vimfiles/plugin/merginal.vim diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat index 7d485fb..f24cfd5 100644 --- a/vimfiles/GetLatest/GetLatestVimScripts.dat +++ b/vimfiles/GetLatest/GetLatestVimScripts.dat @@ -22,11 +22,11 @@ ScriptID SourceID Filename 3745 22834 LineDiff 39 8196 matchit.vim 2092 8095 reloaded.vim (matrix colorscheme) -848 14668 SrchRplcHiGrp.vim (Search/Replace on Syntax Group) +848 23549 SrchRplcHiGrp.vim (Search/Replace on Syntax Group) 294 19633 Align.vim 479 9276 MultipleSearch.vba 1066 7618 cecutil.vim -1173 22422 tComment.vim +1173 23636 tComment.vim 2701 18988 editsrec 3280 14334 Tabbi 642 15781 getscript.vim @@ -38,6 +38,6 @@ ScriptID SourceID Filename 2975 22815 fugitive.vim 2830 22798 csv.vim 3849 22637 git-time-lapse -4932 22924 diffchar.vim -4955 22916 Merginal +4932 24088 diffchar.vim +4955 24218 Merginal 3574 16307 gitv: gitk for Vim diff --git a/vimfiles/autoload/SrchRplcHiGrp.vim b/vimfiles/autoload/SrchRplcHiGrp.vim new file mode 100644 index 0000000..06cb8ec --- /dev/null +++ b/vimfiles/autoload/SrchRplcHiGrp.vim @@ -0,0 +1,537 @@ +" SrchRplcHiGrp.vim - Search and Replace based on a highlight group +" +" Version: 7.0 +" Author: David Fishburn +" Last Changed: 2015 Aug 25 +" Created: Tue Dec 02 2003 10:11:07 PM +" Description: Search and Replace based on a syntax highlight group +" Script: http://www.vim.org/script.php?script_id=848 +" License: GPL (http://www.gnu.org/licenses/gpl.html) +" +" Command Help: {{{ +" Ensure you have updated the help system: +" :helptags $VIM/vimfiles/doc (Windows) +" :helptags $VIM/.vim/doc (*nix) +" +" :h SRHiGrp +" }}} + +" If syntax is not enabled, do not bother loading this plugin +if exists('g:loaded_srhg_auto') || !exists("syntax_on") || &cp + finish +endif +let g:loaded_srhg_auto = 7 + +" Turn on support for line continuations when creating the script +let s:cpo_save = &cpo +set cpo&vim + +" Default the highlight group to 0 +let s:srhg_group_id = 0 +let s:srhg_firstline = 0 +let s:srhg_lastline = 0 + +" SRWarningMsg: +function! SRWarningMsg(msg) "{{{ + echohl WarningMsg + echomsg a:msg + echohl None +endfunction "}}} + +" SRDispHiGrp: +" Echos the currently selected highlight group name to the screen. +" If a parameter is supplied, it will display the message in the +" colour of the group name. +function! SrchRplcHiGrp#SRDispHiGrp(...) "{{{ + if s:srhg_group_id != 0 + if s:srhg_group_id < 0 + let gid = -s:srhg_group_id + else + let gid = s:srhg_group_id + endif + + if a:0 > 0 && strlen(a:1) > 0 + let msg = a:1 + else + let msg = "SRHiGrp - Group ID: " .gid . " Name: " . synIDattr(gid,"name") + endif + + exec 'echohl ' . synIDattr(gid, "name") + exec "echomsg '" . msg . "'" + echohl None + else + echo "No highlight group has been choosen yet" + endif +endfunction "}}} + +" SRChooseHiGrp: +" Sets the script variable s:srhg_group_id to the value +" of the highlight group underneath the current cursor +" position. +function! SrchRplcHiGrp#SRChooseHiGrp(use_top_level, ...) "{{{ + if a:0 > 0 && strlen(a:1) > 0 + let cursynid = a:1 + 0 + else + if a:use_top_level == 1 + let cursynid = -synID(line("."),col("."),1) + else + let cursynid = synIDtrans(synID(line("."),col("."),1)) + endif + endif + + if cursynid == 0 + call s:SRWarningMsg( + \ 'There is no syntax group specified ' . + \ 'under the cursor' + \ ) + else + let s:srhg_group_id = cursynid + call SrchRplcHiGrp#SRDispHiGrp() + endif +endfunction "}}} + +" SRHiGrp: +" Traverses the region selected and performs all search and +" replaces over the region for the selected highlight group. +function! SrchRplcHiGrp#SRHiGrp(...) range "{{{ + + let s:srhg_firstline = a:firstline + let s:srhg_lastline = a:lastline + + if s:srhg_group_id == 0 + call s:SRWarningMsg( + \ 'You must specify a syntax group name ' . + \ 'by placing the cursor on a character ' . + \ 'that is highlighted the way you want ' . + \ 'and execute :SRChooseHiGrp or ' . + \ ':SRChooseHiGrp!' + \ ) + return + endif + + let group_name = synIDattr(s:srhg_group_id, 'name') + if group_name == '' + let group_name = synIDattr(-s:srhg_group_id, 'name') + endif + + if a:0 > 0 + if a:1 == 0 || a:1 == 1 + let match_group = a:1 + endif + else + " Default to operate on syntax groups that match + let match_group = 1 + endif + + if a:0 > 1 + let match_exp = a:2 + else + let match_exp = '\(\w\+\>\)' + let dialog_msg = "Enter match expression (default word at cursor - " . + \ match_exp . + \ "): " + let l:var_val = inputdialog(dialog_msg, match_exp) + let response = 1 + " Ok or Cancel result in an empty string + if l:var_val == "" + call s:SRWarningMsg( + \ 'You must provide a match expression which ' . + \ 'includes a submatch' + \ ) + return + endif + let match_exp = l:var_val + endif + + if a:0 > 2 + let replace_exp = a:3 + else + let replace_exp = '\U\1' + let dialog_msg = "Enter replacement expression for the submatch " . + \ "(ie capitalize word - \\U\\1): " + let l:var_val = inputdialog(dialog_msg, replace_exp) + let response = 1 + " Ok or Cancel result in an empty string + if l:var_val == "" + " If empty, check if they want to leave it empty + " of skip this variable + let response = confirm("Your value is empty!" + \ , "&Use blank\n&Cancel", response) + endif + if response == 1 + " Replace the variable with what was entered + let replace_exp = l:var_val + else + " Cancel + return + endif + endif + + " let higrpid = synIDtrans(hlID(s:srhg_group_id)) + let found = 0 + let firsttime = 1 + let lastline = line("$") + let orgline = line(".") + let orgcol = col(".") + let curline = line(".") + let curcol = col(".") + let fenkeep = &fen + let saveSearch = @/ + let saveFoldEnable = &foldenable + setlocal nofoldenable + + " Reset visual range if necessary + call s:SRSetVisualRange() + + " Restore the cursor position since resetting + " the visual area could have moved the cursor + call cursor(orgline, orgcol) + + if s:SRPositionWord(orgline,(orgcol-1), firsttime) == -1 + call s:SRWarningMsg( + \ 'Please reselect the visual area (ie gv)' + \ ) + return + endif + let firsttime = 0 + + let gid = s:srhg_group_id + if gid < 0 + let gid = -s:srhg_group_id + endif + + while line(".") <= a:lastline + let curcol = col(".") + let curline = line(".") + let cursynid = (s:srhg_group_id < 0) ? + \ -synID(line("."),col("."),1) : + \ synIDtrans(synID(line("."),col("."),1)) + let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1)) + " Useful debugging statement: + " echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".") + + if line(".") == curline + if match_group == 1 && cursynid == gid + " Perform the subtitution, but do not report an error + " if the match fails + exec 's/\%#'.match_exp.'/'.replace_exp.'/e' + " Since this command can move the cursor, put the cursor + " back to its original position + " exe 'norm! '.curline."G\".(curcol-1)."l" + call cursor(curline,curcol) + let found = 1 + elseif match_group == 0 && cursynid != gid + " Perform the subtitution, but do not report an error + " if the match fails + exec 's/\%#'.match_exp.'/'.replace_exp.'/e' + " Since this command can move the cursor, put the cursor + " back to its original position + exe 'norm! '.curline."G\".(curcol-1)."l" + let found = 1 + endif + endif + + let prvcol = curcol + let prvline = curline + if s:SRPositionWord(prvline, prvcol, firsttime) == -1 + break + endif + + endwhile + + if found == 0 + call s:SRWarningMsg('Did not find highlight group: "'.group_name.'"') + endif + + " cleanup + let &fen = fenkeep + if foldlevel(".") > 0 + norm! zO + endif + let &foldenable = saveFoldEnable + unlet curcol + " unlet higrpid + unlet lastline + let @/ = saveSearch + if exists("prvcol") + unlet prvcol + endif +endfunction "}}} + +" SRSearch: +" Finds the next occurrence of the highlight group within +" the range selected from the current cursor position. +function! SrchRplcHiGrp#SRSearch(anti, fline, lline, ...) "{{{ + if s:srhg_group_id == 0 + call s:SRWarningMsg( + \ 'You must use SRChooseHiGrp to specify a syntax group name first' + \ ) + return + endif + + let match_group = a:anti + let s:srhg_firstline = a:fline + let s:srhg_lastline = a:lline + + let group_name = synIDattr(-s:srhg_group_id, 'name') + let regex = "" + + if a:0 > 0 && strlen(a:1) > 0 + " Escape special characters in the regex + " let regex = substitute( + " \ substitute( + " \ escape(a:1 '\\/.*$^~[]'), + " \ "\n$", + " \ "", + " \ "" + " \ ), + " \ "\n", + " \ '\\_[[:return:]]', + " \ "g" + " \ ) + let regex = a:1 + endif + + " let higrpid = synIDtrans(hlID(s:srhg_group_id)) + let found = 0 + let lastline = line("$") + let orgline = line(".") + let orgcol = col(".") + let curline = line(".") + let curcol = col(".") + let fenkeep = &fen + let saveSearch = @/ + let saveFoldEnable = &foldenable + setlocal nofoldenable + " Set this to false, to force the search to move the cursor + " this prevents the user from having to manually move the + " cursor between recursive calls. + let firsttime = 0 + + " Reset visual range if necessary + call s:SRSetVisualRange() + + " Restore the cursor position since resetting + " the visual area could have moved the cursor + call cursor(orgline, orgcol) + + if s:SRPositionWord(orgline,orgcol,firsttime) == -1 + call s:SRWarningMsg( + \ 'Please reselect the visual area (ie gv)' + \ ) + return + endif + + let gid = s:srhg_group_id + if gid < 0 + let gid = -s:srhg_group_id + endif + + while line(".") <= s:srhg_lastline + let curcol = col(".") + let curline = line(".") + let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1)) + let prevsynid = (s:srhg_group_id < 0) ? synID(line("."),(col(".")-1),1) : synIDtrans(synID(line("."),(col(".")-1),1)) + " Useful debugging statement: + " echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".") + + " if line(".") == curline + " Check the current syn id against the previous columns syn id. + " If they are the same, assume we are still part of the same "string" + " and we need to continue searching until we find a gap between the + " highlight groups indicating we are actually on our next match + " (Sergio). + if line(".") == curline && (cursynid != prevsynid) + if cursynid == gid && match_group == 1 + if regex != "" + " Check if the expression matches + if strpart(getline('.'), (curcol-1)) =~ regex + let found = 1 + endif + else + let found = 1 + endif + if found == 1 + call SrchRplcHiGrp#SRDispHiGrp( "SRSearch - Match found - Group ID: " . + \ gid . " Name: " . synIDattr(gid,"name") . + \ (regex == "" ? "" : ' Regex: '.regex) + \ ) + break + endif + elseif cursynid != gid && match_group == 0 + if regex != "" + " Check if the expression matches + if strpart(getline('.'), (curcol-1)) =~ regex + let found = 1 + endif + else + let found = 1 + endif + if found == 1 + call SrchRplcHiGrp#SRDispHiGrp( "SRSearch - Match found - NOT Group ID: " . + \ gid . " Name: " . synIDattr(gid,"name") . + \ (regex == "" ? "" : ' Regex: '.regex) + \ ) + break + endif + endif + endif + + let prvcol = curcol + let prvline = curline + if s:SRPositionWord(prvline, prvcol, firsttime) == -1 + break + endif + + endwhile + + if found == 0 + call SrchRplcHiGrp#SRDispHiGrp( "SRSearch - Match NOT found - Group ID: " . + \ gid . " Name: " . synIDattr(gid,"name") + \ ) + call cursor(orgline, orgcol) + endif + + " cleanup + let &fen = fenkeep + if foldlevel(".") > 0 + norm! zO + endif + let &foldenable = saveFoldEnable + unlet curcol + " unlet higrpid + unlet lastline + let @/ = saveSearch + if exists("prvcol") + unlet prvcol + endif +endfunction "}}} + +" SRSetVisualRange: +" Redefines the visual range if the user called the functions +" with 1,5SR* +function! SRSetVisualRange() "{{{ + " If the current line position is not at the beginning + " or the end of the visual region + if line(".") != line("'<") && line(".") != line("'>") + " Visually select the rows to ensure the correct + " range is operated on. + " This handles the case that SRHiGrp was run as: + " :SRHiGrp + " :1,5SRHiGrp + " instead of: + " :'<,'>SRHiGrp + + exec 'normal! '.s:srhg_firstline."GV" + if s:srhg_lastline > s:srhg_firstline + exec "normal! " . + \ (s:srhg_lastline - s:srhg_firstline) . + \ "j" + endif + exec "normal! \" + endif + return 1 +endfunction "}}} + +" SRPositionWord: +" Places the cursor on the next match following the +" previous line and column passed in. +function! SRPositionWord(prvline, prvcol, bfirsttime) "{{{ + let prvline = a:prvline + let prvcol = a:prvcol + + " echo 'L:'. col("'<") . ' R:' . col("'>") + " echo 'Visual Mode:'. visualmode() + + if (prvline == 0) && (prvcol == 0) + call s:SRSetVisualRange() + let leftcol = col("'<") - 1 + " exe 'norm! '.s:srhg_firstline."G\".leftcol.(leftcol>0 ? 'l' : '' ) + call cursor(s:srhg_firstline,leftcol) + return 1 + endif + + while 1==1 + if visualmode() ==# 'v' + if line(".") == s:srhg_firstline + " let leftcol = col("'<") - 1 + let leftcol = col("'<") + else + let leftcol = 1 + endif + if line(".") == s:srhg_lastline + let rightcol = col("'>") + else + let rightcol = col("$") + endif + elseif visualmode() ==# 'V' + let leftcol = 1 + let rightcol = col("$") + elseif visualmode() ==# "\" + let leftcol = col("'<") - 1 + let leftcol = col("'<") + let rightcol = col("'>") + endif + + " echo 'PrvLine:'.prvline.' prvcol:'.prvcol. + " \' L:'.leftcol.' R:'.rightcol. + " \' VL:'.leftcol.' VR:'.rightcol + + " Position cursor on leftcol + " on each new line based on visual mode + if col(".") == leftcol && a:bfirsttime == 1 + " The cursor is already at it starting position, + " do not move the cursor + elseif col(".") < leftcol + " exe 'norm! '.line(".")."G\".leftcol.(leftcol>0 ? 'l' : '' ) + call cursor(line("."),leftcol) + else + normal! w + endif + + " Add additional check to see if the cursor has + " moved after the above, if not, exit. + if (col(".") == prvcol) && (line(".") == prvline && a:bfirsttime != 1) + return -1 + endif + + + if col(".") >= leftcol && + \ col(".") <= rightcol && + \ line(".") <= s:srhg_lastline + return 1 + elseif col(".") > rightcol && line(".") < s:srhg_lastline + let prvline = prvline + 1 + " Position the cursor on the next line and move + " to the start of the visual region + " exe 'norm! '.prvline."G\".leftcol.(leftcol>0 ? 'l' : '' ) + call cursor(prvline,leftcol) + break + elseif col(".") < leftcol && line(".") <= s:srhg_lastline + " outside of visual area, move to next word + continue + else + return -1 + endif + endwhile + + return 1 +endfunction "}}} + +" If a comment is found, skip it +function! SRCommentCheck( lineno, indx ) "{{{ + if getline(a:lineno) =~ '^\s*--' + return 1 + endif + return 0 + + let synid = synID(a:lineno,a:indx+1,1) + let synname = synIDattr(synIDtrans(synid),"name") + let ret= (synname == "String")? 1 : 0 + return ret +endfunction "}}} + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim:fdm=marker:nowrap:ts=4: diff --git a/vimfiles/autoload/diffchar.vim b/vimfiles/autoload/diffchar.vim new file mode 100644 index 0000000..3757c7b --- /dev/null +++ b/vimfiles/autoload/diffchar.vim @@ -0,0 +1,1262 @@ +" diffchar.vim : Highlight the exact differences, based on characters and words +" +" ____ _ ____ ____ _____ _ _ _____ ____ +" | | | || || || || | | || _ || _ | +" | _ || || __|| __|| || | | || | | || | || +" | | | || || |__ | |__ | __|| |_| || |_| || |_||_ +" | |_| || || __|| __|| | | || || __ | +" | || || | | | | |__ | _ || _ || | | | +" |____| |_||_| |_| |_____||_| |_||_| |_||_| |_| +" +" Last Change: 2016/03/09 +" Version: 6.1 +" Author: Rick Howe + +let s:save_cpo = &cpo +set cpo&vim + +function! diffchar#DiffCharExpr() + " find the fist diff trial call and return here + if readfile(v:fname_in, '', 1) == ['line1'] && + \readfile(v:fname_new, '', 1) == ['line2'] + call writefile(['1c1'], v:fname_out) + return + endif + + " get a list of diff commands and write to output file + for fn in ['ApplyInternalAlgorithm', 'ApplyDiffCommand'] + let dfcmd = s:{fn}(v:fname_in, v:fname_new) + " if empty, try next + if !empty(dfcmd) | break | endif + endfor + call writefile(dfcmd, v:fname_out) +endfunction + +function! diffchar#SetDiffModeSync() + if exists('t:DiffModeSync') ? !t:DiffModeSync : !g:DiffModeSync + return + endif + + if !exists('s:dmsync') + " a filter command (not diff) also triggers FilterWritePre but + " continueously triggers ShellFilterPost, + " prepare here to clear s:dmsync + au! dchar ShellFilterPost * call s:ClearDiffModeSync() + + let s:dmsync = {} + let s:dmsync.ebuf = [] + " find all the diff mode winnr and bufnr at the first event of + " a diff session. + let s:dmsync.dwin = s:ValidDiffModeWins(range(1, winnr('$'))) + let s:dmsync.dbuf = map(copy(s:dmsync.dwin), 'winbufnr(v:val)') + if min(s:dmsync.dbuf) == max(s:dmsync.dbuf) + call s:ClearDiffModeSync() + return + endif + endif + + " append current bufnr where the event happens + if index(s:dmsync.dbuf, bufnr('%')) != -1 + let s:dmsync.ebuf += [bufnr('%')] + endif + + if empty(filter(copy(s:dmsync.dbuf), + \'index(s:dmsync.ebuf, v:val) == -1')) + " when all the events of one diff session come, get winnr of + " the first/last buffers for v:fname_in/v:fname_new + let win = {} + let cwin = winnr() + for k in [1, 2] + let w = filter(copy(s:dmsync.dwin), 'winbufnr(v:val) == + \s:dmsync.ebuf[k == 1 ? 0 : -1]') + let win[k] = (len(w) > 1 && + \index(w, cwin) != -1) ? cwin : w[0] + endfor + + " then set diffexpr to be called soon + if !exists('s:save_dex') + let s:save_dex = &diffexpr + endif + let &diffexpr = 'diffchar#DiffModeSyncExpr(' . string(win) . ')' + + " intialize here to be prepared for the next diff session + call s:ClearDiffModeSync() + endif +endfunction + +function! s:ClearDiffModeSync() + unlet! s:dmsync + au! dchar ShellFilterPost * +endfunction + +function! diffchar#DiffModeSyncExpr(win) + " call saved diffexpr or DiffCharExpr() if empty + call eval(empty(s:save_dex) ? 'diffchar#DiffCharExpr()' : s:save_dex) + + " clear current diffchar highlights if present + if exists('t:DChar') + call s:RefreshDiffCharWID() + let cwin = winnr() + if index(values(t:DChar.win), cwin) != -1 + call diffchar#ResetDiffChar(range(1, line('$'))) + else + let save_ei = &eventignore | let &eventignore = 'all' + exec t:DChar.win[1] . 'wincmd w' + call diffchar#ResetDiffChar(range(1, line('$'))) + exec cwin . 'wincmd w' + let &eventignore = save_ei + endif + endif + + " find 'c' command and extract the line to be changed + let [c1, c2] = [[], []] + for ct in filter(readfile(v:fname_out), 'v:val =~ "^\\d.*c"') + let [p1, p2] = map(split(ct, 'c'), 'split(v:val, ",")') + let cn = min([len(p1) == 1 ? 0 : p1[1] - p1[0], + \len(p2) == 1 ? 0 : p2[1] - p2[0]]) + let [c1, c2] += [range(p1[0], p1[0] + cn), + \range(p2[0], p2[0] + cn)] + endfor + + " if there are changed lines and initialize successes + if !empty(c1) && !empty(c2) && s:InitializeDiffChar() != -1 + " change window numbers and diff lines + let t:DChar.win = a:win + let t:DChar.vdl = {1: c1, 2: c2} + + " highlight the diff changed lines + call s:MarkDiffCharWID(1) + let cwin = winnr() + if index(values(t:DChar.win), cwin) != -1 + call diffchar#ShowDiffChar(range(1, line('$'))) + else + let save_ei = &eventignore | let &eventignore = 'all' + exec t:DChar.win[1] . 'wincmd w' + call diffchar#ShowDiffChar(range(1, line('$'))) + exec cwin . 'wincmd w' + let &eventignore = save_ei + endif + endif + + " resume back to the original diffexpr + if exists('s:save_dex') + let &diffexpr = s:save_dex + unlet s:save_dex + endif +endfunction + +function! s:ApplyInternalAlgorithm(f1, f2) + " read both files to be diff traced + let [f1, f2] = [readfile(a:f1), readfile(a:f2)] + + " handle icase and iwhite diff options + let save_igc = &ignorecase + let &ignorecase = (&diffopt =~ 'icase') + if &diffopt =~ 'iwhite' + for k in [1, 2] + call map(f{k}, 'substitute(v:val, "\\s\\+", " ", "g")') + call map(f{k}, 'substitute(v:val, "\\s\\+$", "", "")') + endfor + endif + + " trace the diff lines between f1/f2 until the end time + let ses = s:TraceDiffChar(f1, f2, str2float(reltimestr(reltime())) + + \(exists('t:DiffSplitTime') ? + \t:DiffSplitTime : g:DiffSplitTime) / 1000.0) + + " restore ignorecase flag + let &ignorecase = save_igc + + " if timeout, return here with empty result + if ses == '*' | return [] | endif + + let dfcmd = [] + let [l1, l2] = [1, 1] + for ed in split(ses, '\%(=\+\|[+-]\+\)\zs') + let qn = len(ed) + if ed[0] == '=' " one or more '=' + let [l1, l2] += [qn, qn] + else " one or more '[+-]' + let q1 = len(escape(ed, '-')) - qn + let q2 = qn - q1 + let dfcmd += [ + \((q1 > 1) ? l1 . ',' : '') . (l1 + q1 - 1) . + \((q1 == 0) ? 'a' : (q2 == 0) ? 'd' : 'c') . + \((q2 > 1) ? l2 . ',' : '') . (l2 + q2 - 1)] + let [l1, l2] += [q1, q2] + endif + endfor + + return dfcmd +endfunction + +function! s:ApplyDiffCommand(f1, f2) + " execute a diff command + let opt = '-a --binary ' + if &diffopt =~ 'icase' | let opt .= '-i ' | endif + if &diffopt =~ 'iwhite' | let opt .= '-b ' | endif + if exists('g:DiffOptions') | let opt .= g:DiffOptions . ' ' | endif + " return diff commands only + return filter(split(system('diff ' . opt . a:f1 . ' ' . a:f2), '\n'), + \'v:val[0] =~ "\\d"') +endfunction + +function! s:InitializeDiffChar() + if min(tabpagebuflist()) == max(tabpagebuflist()) + echo 'Need more buffers displayed on this tab page!' + return -1 + endif + + " define a DiffChar dictionary on this tab page + let t:DChar = {} + + " select current window and next (diff mode if available) window + " whose buffer is different + let t:DChar.win = {} + let cwin = winnr() + let nwin = filter(range(cwin + 1, winnr('$')) + range(1, cwin - 1), + \'winbufnr(v:val) != winbufnr(cwin)') + let dwin = s:ValidDiffModeWins(copy(nwin)) + let [t:DChar.win[1], t:DChar.win[2]] = + \[cwin, empty(dwin) ? nwin[0] : dwin[0]] + call s:MarkDiffCharWID(1) + + " set highlight groups used for diffchar on this tab page + let t:DChar.dhl = {'A': 'DiffAdd', 'C': 'DiffChange', + \'D': 'DiffDelete', 'T': 'DiffText', 'Z': '_DiffDelPos', + \'U': has('gui_running') ? 'Cursor' : 'VertSplit'} + + " find corresponding DiffChange/DiffText lines on diff mode windows + if len(s:ValidDiffModeWins(values(t:DChar.win))) == 2 + let t:DChar.vdl = {} + let dh = [hlID(t:DChar.dhl.C), hlID(t:DChar.dhl.T)] + let save_ei = &eventignore | let &eventignore = 'all' + for k in [1, 2] + exec t:DChar.win[k] . 'wincmd w' + call diff_hlID(0, 0) " a workaround for vim defect + let t:DChar.vdl[k] = filter(range(1, line('$')), + \'index(dh, diff_hlID(v:val, 1)) != -1') + if empty(t:DChar.vdl[k]) + unlet t:DChar.vdl + break + endif + endfor + exec cwin . 'wincmd w' + let &eventignore = save_ei + endif + + " set ignorecase and ignorespace flags + let t:DChar.igc = (&diffopt =~ 'icase') + let t:DChar.igs = (&diffopt =~ 'iwhite') + + " set line and its highlight id record + let t:DChar.mid = {} + let [t:DChar.mid[1], t:DChar.mid[2]] = [{}, {}] + + " set highlighted lines and columns record + let t:DChar.hlc = {} + let [t:DChar.hlc[1], t:DChar.hlc[2]] = [{}, {}] + + " set a difference unit type on this tab page and set a split pattern + let du = exists('t:DiffUnit') ? t:DiffUnit : g:DiffUnit + if du == 'Word1' " \w\+ word and any \W character + let t:DChar.usp = t:DChar.igs ? '\%(\s\+\|\w\+\|\W\)\zs' : + \'\%(\w\+\|\W\)\zs' + elseif du == 'Word2' " non-space and space words + let t:DChar.usp = '\%(\s\+\|\S\+\)\zs' + elseif du == 'Word3' " \< or \> boundaries + let t:DChar.usp = '\<\|\>' + elseif du == 'Char' " any single character + let t:DChar.usp = t:DChar.igs ? '\%(\s\+\|.\)\zs' : '\zs' + elseif du =~ '^CSV(.\+)$' " split characters + let s = escape(du[4 : -2], '^-]') + let t:DChar.usp = '\%([^'. s . ']\+\|[' . s . ']\)\zs' + elseif du =~ '^SRE(.\+)$' " split regular expression + let t:DChar.usp = du[4 : -2] + else + let t:DChar.usp = t:DChar.igs ? '\%(\s\+\|\w\+\|\W\)\zs' : + \'\%(\w\+\|\W\)\zs' + echo 'Not a valid difference unit type. Use "Word1" instead.' + endif + + " set a difference unit updating on this tab page + " and a record of line values and number of total lines + if exists('##TextChanged') && exists('##TextChangedI') + if exists('t:DiffUpdate') ? t:DiffUpdate : g:DiffUpdate + let t:DChar.lsv = {} + let [t:DChar.lsv[1], t:DChar.lsv[2]] = [{}, {}] + endif + endif + + " Set a time length (ms) to apply the internal algorithm first + let t:DChar.slt = exists('t:DiffSplitTime') ? + \t:DiffSplitTime : g:DiffSplitTime + + " Set a diff mode synchronization flag + let t:DChar.dsy = exists('t:DiffModeSync') ? + \t:DiffModeSync : g:DiffModeSync + + " set a matching pair cursor id on this tab page + let t:DChar.pci = {} + + " set a difference matching colors on this tab page + let dc = exists('t:DiffColors') ? t:DiffColors : g:DiffColors + let t:DChar.dmc = [t:DChar.dhl.T] + if dc == 1 + let t:DChar.dmc += ['NonText', 'Search', 'VisualNOS'] + elseif dc == 2 + let t:DChar.dmc += ['NonText', 'Search', 'VisualNOS', + \'ErrorMsg', 'MoreMsg', 'TabLine', 'Title'] + elseif dc == 3 + let t:DChar.dmc += ['NonText', 'Search', 'VisualNOS', + \'ErrorMsg', 'MoreMsg', 'TabLine', 'Title', + \'StatusLine', 'WarningMsg', 'Conceal', 'SpecialKey', + \'ColorColumn', 'ModeMsg', 'SignColumn', 'Question'] + elseif dc == 100 + redir => hl | silent highlight | redir END + let h = map(filter(split(hl, '\n'), + \'v:val =~ "^\\S" && v:val =~ "="'), 'split(v:val)[0]') + for c in values(t:DChar.dhl) + let i = index(h, c) | if i != -1 | unlet h[i] | endif + endfor + while !empty(h) + let r = localtime() % len(h) + let t:DChar.dmc += [h[r]] | unlet h[r] + endwhile + endif + + " define a specific highlight group to show a position + " of a deleted unit, _DiffDelPos = DiffChange +/- underline + exec 'silent highlight clear ' . t:DChar.dhl.Z + " get current DiffChange + redir => hl | exec 'silent highlight ' . t:DChar.dhl.C | redir END + let ha = {} + for [ky, ag] in map(filter(split(hl, '\%(\n\|\s\)\+'), + \'v:val =~ "="'), 'split(v:val, "=")') + let ha[ky] = ag + endfor + " add or delete a specific attribute (underline) + let at = 'underline' + let hm = has('gui_running') ? 'gui' : &t_Co > 1 ? 'cterm' : 'term' + let ha[hm] = !exists('ha[hm]') ? at : + \match(ha[hm], at) == -1 ? ha[hm] . ',' . at : + \substitute(ha[hm], at . ',\=\|,\=' . at, '', '') + " set as a highlight + exec 'silent highlight ' . t:DChar.dhl.Z . ' ' . + \join(values(map(filter(ha, '!empty(v:val)'), + \'v:key . "=" . v:val'))) +endfunction + +function! diffchar#ShowDiffChar(lines) + " initialize when t:DChar is not defined + if !exists('t:DChar') + if s:InitializeDiffChar() == -1 | return | endif + let first = 1 + else + let first = empty(t:DChar.hlc[1]) || empty(t:DChar.hlc[2]) + endif + + " refresh window number of diffchar windows + call s:RefreshDiffCharWID() + + " return if current window is not either of diffchar windows + let cwin = winnr() + for k in [1, 2, 0] + if k == 0 | return | endif + if t:DChar.win[k] == cwin | break | endif + endfor + + " set a possible DiffChar line list among a:lines + let [d1, d2] = exists('t:DChar.vdl') ? + \s:DiffModeLines(k, a:lines) : [copy(a:lines), copy(a:lines)] + + " remove already highlighted lines and get those text + for k in [1, 2] + let hl = map(keys(t:DChar.hlc[k]), 'eval(v:val)') + call filter(d{k}, 'index(hl, v:val) == -1') + let u{k} = map(copy(d{k}), + \'getbufline(winbufnr(t:DChar.win[k]), v:val)[0]') + let n{k} = len(u{k}) + endfor + + " remove redundant lines in either window + if n1 > n2 + unlet u1[n2 - n1 :] | unlet d1[n2 - n1 :] | let n1 = n2 + elseif n1 < n2 + unlet u2[n1 - n2 :] | unlet d2[n1 - n2 :] | let n2 = n1 + endif + + " set ignorecase flag + let save_igc = &ignorecase + let &ignorecase = t:DChar.igc + + for n in range(n1 - 1, 0, -1) + if t:DChar.igs + " delete \s\+ at line end + let u1[n] = substitute(u1[n], '\s\+$', '', '') + let u2[n] = substitute(u2[n], '\s\+$', '', '') + endif + if u1[n] == u2[n] + " remove equivalent lines + unlet u1[n] | unlet d1[n] + unlet u2[n] | unlet d2[n] + let [n1, n2] -= [1, 1] + endif + endfor + if n1 == 0 + if empty(t:DChar.hlc[1]) || empty(t:DChar.hlc[2]) + call s:MarkDiffCharWID(0) + unlet t:DChar + endif + let &ignorecase = save_igc + return + endif + + " a list of actual difference units for tracing + call map(u1, 'split(v:val, t:DChar.usp)') + call map(u2, 'split(v:val, t:DChar.usp)') + + " a list of different lines and columns + let [lc1, lc2] = [{}, {}] + let cmp = 0 + for fn in ['TraceWithInternalAlgorithm', 'TraceWithDiffCommand'] + " trace with this plugin's algorithm first, + " if timeout, split to the diff command + for [ln, cx] in items(s:{fn}(u1[cmp :], u2[cmp :])) + let [lc1[d1[cmp + ln]], lc2[d2[cmp + ln]]] = + \[cx[0], cx[1]] + endfor + let cmp = len(lc1) + if cmp >= n1 | break | endif + endfor + call filter(lc1, '!empty(v:val)') + call filter(lc2, '!empty(v:val)') + + " restore ignorecase flag + let &ignorecase = save_igc + + " highlight lines and columns + let save_ei = &eventignore | let &eventignore = 'all' + for k in [1, 2] + let buf{k} = winbufnr(t:DChar.win[k]) + exec t:DChar.win[k] . 'wincmd w' + call s:HighlightDiffChar(k, lc{k}) + + if exists('t:DChar.lsv') + call extend(t:DChar.lsv[k], s:LinesValues(k, + \map(keys(lc{k}), 'eval(v:val)'))) + let t:DChar.lsv[k][0] = line('$') + endif + endfor + exec cwin . 'wincmd w' + let &eventignore = save_ei + + if empty(t:DChar.hlc[1]) || empty(t:DChar.hlc[2]) + call s:MarkDiffCharWID(0) + unlet t:DChar + return + endif + + " if not the first call in this tab page, return here + if !first | return | endif + + " set events in each buffer + for k in [1, 2] + exec 'au! dchar BufWinLeave call diffchar#ResetDiffChar(range(1, line("$")))' + if exists('##QuitPre') + exec 'au! dchar QuitPre call s:SwitchDiffChar()' + endif + endfor + if exists('t:DChar.lsv') + for k in [1, 2] + exec 'au! dchar TextChanged call s:UpdateDiffChar(' . k . ', "n")' + exec 'au! dchar TextChangedI call s:UpdateDiffChar(' . k . ', "i")' + endfor + endif + if t:DChar.dsy && exists('t:DChar.vdl') + for k in [1, 2] + exec 'au! dchar CursorHold call s:ResetSwitchDiffModeSync(' . k . ')' + endfor + if !exists('s:save_ut') && + \len(filter(map(range(1, tabpagenr('$')), + \'gettabvar(v:val, "DChar")'), + \'!empty(v:val) && v:val.dsy && + \exists("v:val.vdl")')) == 1 + let s:save_ut = &updatetime + let &updatetime = 500 + endif + endif + + if has('patch-7.4.682') + call s:ToggleDiffHL(1) + endif +endfunction + +function! s:TraceWithInternalAlgorithm(u1, u2) + " a list of commands with byte index per line + let cbx = {} + + " set an end time for diff tracing + let et = str2float(reltimestr(reltime())) + t:DChar.slt / 1000.0 + + " compare each line and trace difference units + for ln in range(len(a:u1)) + if t:DChar.igs + " convert \s\+ to a single space + let [u1, u2] = [map(copy(a:u1[ln]), 'substitute( + \v:val, "\\s\\+", " ", "g")'), + \map(copy(a:u2[ln]), 'substitute( + \v:val, "\\s\\+", " ", "g")')] + else + let [u1, u2] = [a:u1[ln], a:u2[ln]] + endif + + " get edit script + let es = s:TraceDiffChar(u1, u2, et) + + " if timeout, break here + if es == '*' | break | endif + + let cbx[ln] = s:GetComWithByteIdx(es, a:u1[ln], a:u2[ln]) + endfor + + return cbx +endfunction + +function! s:TraceWithDiffCommand(u1, u2) + " prepare 2 input files for diff + let lns = '|' + for k in [1, 2] + " add ':' at the beginning of each unit, + " enclose each line with '{' and + " '}', and insert '|' between lines + let g{k} = [] + let p = -1 | let p{k} = [] " line separator position + for n in range(len(a:u{k})) + let l = n + 1 + let g = [l . '{' . k] + + \map(copy(a:u{k}[n]), 'l . ":" . v:val') + + \[l . '}' . k] + [lns] + let g{k} += g + let p += len(g) | let p{k} += [p] + endfor + unlet g{k}[-1] + unlet p{k}[-1] + + " write to a temp file for diff command + let f{k} = tempname() | call writefile(g{k}, f{k}) + + " initialize a list of edit symbols [=+-#] for each unit + call map(g{k}, '"="') + endfor + + " call diff and get output as a list + let opt = '-a --binary ' + if t:DChar.igc | let opt .= '-i ' | endif + if t:DChar.igs | let opt .= '-b ' | endif + if exists('g:DiffOptions') | let opt .= g:DiffOptions . ' ' | endif + let dfo = split(system('diff ' . opt . f1 . ' ' . f2), '\n') + call delete(f1) | call delete(f2) + + " assign edit symbols [=+-#] to each unit + for dc in filter(dfo, 'v:val[0] =~ "\\d"') + let [se1, op, se2] = split(substitute(dc, '\a', ' & ', '')) + let [s1, e1] = (se1 =~ ',') ? split(se1, ',') : [se1, se1] + let [s2, e2] = (se2 =~ ',') ? split(se2, ',') : [se2, se2] + let [s1, e1, s2, e2] -= [1, 1, 1, 1] + if op == 'c' + let g1[s1 : e1] = repeat(['-'], e1 - s1 + 1) + let g2[s2 : e2] = repeat(['+'], e2 - s2 + 1) + elseif op == 'd' + let g1[s1 : e1] = repeat(['-'], e1 - s1 + 1) + let g2[s2] .= '#' " append add/del position mark + else "if op == 'a' + let g1[s1] .= '#' " append add/del position mark + let g2[s2 : e2] = repeat(['+'], e2 - s2 + 1) + endif + endfor + + " separate lines and divide units + for k in [1, 2] + for p in p{k} | let g{k}[p] = lns | endfor + let g{k} = map(split(join(g{k}, ''), lns), + \'split(v:val, "\\%(=\\+\\|[+-]\\+\\|#\\)\\zs")') + endfor + + " a list of commands with byte index per line + let cbx = {} + + for ln in range(len(g1)) + call map(g1[ln], 'v:val[0] == "#" ? "" : v:val') + call map(g2[ln], 'v:val[0] == "+" ? v:val : ""') + let es = join(map(g1[ln], 'v:val . g2[ln][v:key]'), '') + + " delete the first and last [+-] of line begin/end symbols + let es = substitute(es, '^[^+]*\zs+\|+\ze[^+]*$', '', 'g') + let es = substitute(es, '^[^-]*\zs-\|-\ze[^-]*$', '', 'g') + + let cbx[ln] = s:GetComWithByteIdx(es, a:u1[ln], a:u2[ln]) + endfor + + return cbx +endfunction + +function! s:GetComWithByteIdx(es, u1, u2) + let [c1, c2] = [[], []] + let [l1, l2, p1, p2] = [1, 1, 0, 0] + for ed in split(a:es, '\%(=\+\|[+-]\+\)\zs') + let qn = len(ed) + if ed[0] == '=' " one or more '=' + for k in [1, 2] + let [l{k}, p{k}] += [len(join(a:u{k}[p{k} : + \p{k} + qn - 1], '')), qn] + endfor + else " one or more '[+-]' + let q1 = len(escape(ed, '-')) - qn + let q2 = qn - q1 + for k in [1, 2] + if q{k} > 0 + let r = len(join(a:u{k}[p{k} : + \p{k} + q{k} - 1], '')) + let h{k} = [l{k}, l{k} + r - 1] + let [l{k}, p{k}] += [r, q{k}] + else + let h{k} = [l{k} - (0 < p{k} ? + \len(split(a:u{k}[p{k} - 1], + \'\zs')[-1]) : 0), + \l{k} + (p{k} < len(a:u{k}) ? + \len(split(a:u{k}[p{k}], + \'\zs')[0]) : 0) - 1] + endif + endfor + let [r1, r2] = (q1 == 0) ? ['d', 'a'] : + \(q2 == 0) ? ['a', 'd'] : ['c', 'c'] + let [c1, c2] += [[[r1, h1]], [[r2, h2]]] + endif + endfor + return [c1, c2] +endfunction + +function! diffchar#ResetDiffChar(lines) + if !exists('t:DChar') | return | endif + + " refresh window number of diffchar windows + call s:RefreshDiffCharWID() + + " return if current window is not either of diffchar windows + let cwin = winnr() + for k in [1, 2, 0] + if k == 0 | return | endif + if t:DChar.win[k] == cwin | break | endif + endfor + + " set a possible DiffChar line list among a:lines + let [d1, d2] = exists('t:DChar.vdl') ? + \s:DiffModeLines(k, a:lines) : [copy(a:lines), copy(a:lines)] + + " remove not highlighted lines + let save_ei = &eventignore | let &eventignore = 'all' + for k in [1, 2] + let hl = map(keys(t:DChar.hlc[k]), 'eval(v:val)') + call filter(d{k}, 'index(hl, v:val) != -1') + + let buf{k} = winbufnr(t:DChar.win[k]) + exec t:DChar.win[k] . 'wincmd w' + call s:ClearDiffChar(k, d{k}) + call s:ResetDiffCharPair(k) + + if exists('t:DChar.lsv') + call map(d{k}, 'remove(t:DChar.lsv[k], v:val)') + endif + endfor + exec cwin . 'wincmd w' + let &eventignore = save_ei + + if !empty(t:DChar.hlc[1]) && !empty(t:DChar.hlc[2]) + return + endif + + " reset events and all when no highlight exists + for k in [1, 2] + exec 'au! dchar BufWinLeave ' + if exists('##QuitPre') + exec 'au! dchar QuitPre ' + endif + endfor + if exists('t:DChar.lsv') + for k in [1, 2] + exec 'au! dchar TextChanged,TextChangedI ' + endfor + endif + if t:DChar.dsy && exists('t:DChar.vdl') + for k in [1, 2] + exec 'au! dchar CursorHold ' + endfor + if exists('s:save_ut') && + \len(filter(map(range(1, tabpagenr('$')), + \'gettabvar(v:val, "DChar")'), + \'!empty(v:val) && v:val.dsy && + \exists("v:val.vdl")')) == 1 + let &updatetime = s:save_ut + unlet s:save_ut + endif + endif + + if has('patch-7.4.682') + call s:ToggleDiffHL(0) + endif + call s:MarkDiffCharWID(0) + unlet t:DChar +endfunction + +function! diffchar#ToggleDiffChar(lines) + if exists('t:DChar') + call s:RefreshDiffCharWID() + for k in [1, 2, 0] + if k == 0 | return | endif + if t:DChar.win[k] == winnr() | break | endif + endfor + for hl in keys(t:DChar.hlc[k]) + if index(a:lines, eval(hl)) != -1 + call diffchar#ResetDiffChar(a:lines) + return + endif + endfor + endif + call diffchar#ShowDiffChar(a:lines) +endfunction + +function! s:SwitchDiffChar() + " if diffchar is on one of split windows and when that window quits, + " catch QuitPre and switch to the rest (diff mode first) of the windows + call s:RefreshDiffCharWID() + let cwin = winnr() + let swin = filter(range(cwin + 1, winnr('$')) + range(1, cwin - 1), + \'winbufnr(v:val) == bufnr("%")') + if !empty(swin) && index(values(t:DChar.win), cwin) != -1 + let win = t:DChar.win + call diffchar#ResetDiffChar(range(1, line('$'))) + if s:InitializeDiffChar() != -1 + let dwin = s:ValidDiffModeWins(swin) + let nwin = empty(dwin) ? swin[0] : dwin[0] + let t:DChar.win = map(win, + \'v:val == cwin ? nwin : v:val') + + call s:MarkDiffCharWID(1) + + let save_ei = &eventignore | let &eventignore = 'all' + exec nwin . 'wincmd w' + call diffchar#ShowDiffChar(range(1, line('$'))) + let &eventignore = save_ei + endif + endif +endfunction + +function! s:HighlightDiffChar(key, lec) + for [l, ec] in items(a:lec) + if has_key(t:DChar.mid[a:key], l) | continue | endif + let t:DChar.hlc[a:key][l] = ec + + " collect all the column positions per highlight group + let ap = {} + let cn = 0 + for [e, c] in ec + if e == 'c' + let hl = t:DChar.dmc[cn % len(t:DChar.dmc)] + let cn += 1 + elseif e == 'a' + let hl = t:DChar.dhl.A + elseif e == 'd' + let hl = t:DChar.dhl.Z + endif + let ap[hl] = get(ap, hl, []) + [c] + endfor + + " do highlightings on all the lines and columns + " with minimum matchaddpos() or one matchadd() call + if exists('*matchaddpos') + let t:DChar.mid[a:key][l] = + \[matchaddpos(t:DChar.dhl.C, [[l]], 0)] + for [hl, cp] in items(ap) + call map(cp, '[l, v:val[0], + \v:val[1] - v:val[0] + 1]') + while !empty(cp) + let t:DChar.mid[a:key][l] += + \[matchaddpos(hl, cp[:7], 0)] + unlet cp[:7] + endwhile + endfor + else + let dl = '\%' . l . 'l' + let t:DChar.mid[a:key][l] = + \[matchadd(t:DChar.dhl.C, dl . '.', 0)] + for [hl, cp] in items(ap) + call map(cp, '"\\%>" . (v:val[0] - 1) . + \"c\\%<" . (v:val[1] + 1) . "c"') + let dc = len(cp) > 1 ? + \'\%(' . join(cp, '\|') . '\)' : cp[0] + let t:DChar.mid[a:key][l] += + \[matchadd(hl, dl . dc, 0)] + endfor + endif + endfor +endfunction + +function! s:ClearDiffChar(key, lines) + for l in a:lines + if has_key(t:DChar.mid[a:key], l) + call map(t:DChar.mid[a:key][l], 'matchdelete(v:val)') + unlet t:DChar.mid[a:key][l] + unlet t:DChar.hlc[a:key][l] + endif + endfor +endfunction + +function! s:UpdateDiffChar(key, mode) + call s:RefreshDiffCharWID() + + let cwin = winnr() + if cwin != t:DChar.win[a:key] + let save_ei = &eventignore | let &eventignore = 'all' + exec t:DChar.win[a:key] . 'wincmd w' + endif + + " if number of lines was changed, reset all + if t:DChar.lsv[a:key][0] != line('$') + call diffchar#ResetDiffChar( + \range(1, max([t:DChar.lsv[a:key][0], line('$')]))) + else + " find changed lines which were highlighted + let chl = map(keys(t:DChar.hlc[a:key]), 'eval(v:val)') + if a:mode == 'i' + call filter(chl, 'v:val == line(".")') + endif + let lsv = s:LinesValues(a:key, chl) + call filter(chl, 'lsv[v:val] != t:DChar.lsv[a:key][v:val]') + + if !empty(chl) + " save the current t:DChar in case all hl can be reset + let sdc = deepcopy(t:DChar) + + " reset hl of changed lines + call diffchar#ResetDiffChar(chl) + + " if all hl was reset, restore saved t:DChar except hl + if !exists('t:DChar') + let [sdc.mid[1], sdc.mid[2]] = [{}, {}] + let [sdc.hlc[1], sdc.hlc[2]] = [{}, {}] + if exists('sdc.dtm') | unlet sdc.dtm | endif + if exists('sdc.lsv') + let [sdc.lsv[1], sdc.lsv[2]] = [{}, {}] + endif + let t:DChar = sdc + call s:MarkDiffCharWID(1) + endif + + " show hl of changed lines + call diffchar#ShowDiffChar(chl) + + " if hl lines are changed in diff mode, refresh diff HL + if has('patch-7.4.682') && exists('t:DChar.vdl') && + \chl != map(keys(t:DChar.hlc[a:key]), + \'eval(v:val)') + call s:RestoreDiffHL() + call s:OverwriteDiffHL() + endif + endif + endif + + if exists('save_ei') + exec cwin . 'wincmd w' + let &eventignore = save_ei + endif +endfunction + +function! s:ResetSwitchDiffModeSync(key) + " when diff mode turns off on the current window, reset it + if !empty(s:ValidDiffModeWins([winnr()])) | return | endif + + call s:RefreshDiffCharWID() + + let cwin = winnr() + if cwin != t:DChar.win[a:key] | return | endif + + let [win, vdl, dsy] = [t:DChar.win, t:DChar.vdl, t:DChar.dsy] + + call diffchar#ResetDiffChar(range(1, line('$'))) + + " if there is another diff mode window of the same buffer and + " need to contine diff mode sync, switch to that window + if dsy + let bwin = s:ValidDiffModeWins(filter(range(1, winnr('$')), + \'winbufnr(v:val) == bufnr("%")')) + if !empty(bwin) && s:InitializeDiffChar() != -1 + let t:DChar.win = + \map(win, 'v:key == a:key ? bwin[0] : v:val') + let t:DChar.vdl = vdl + + call s:MarkDiffCharWID(1) + + let save_ei = &eventignore | let &eventignore = 'all' + exec t:DChar.win[1] . 'wincmd w' + call diffchar#ShowDiffChar(range(1, line('$'))) + exec cwin . 'wincmd w' + let &eventignore = save_ei + endif + endif +endfunction + +function! s:DiffModeLines(key, lines) + " in diff mode, need to compare the different line between windows + " if current window is t:DChar.win[1], narrow a:lines within vdl[1] + " and get the corresponding lines from vdl[2] + let [d1, d2] = [copy(t:DChar.vdl[1]), copy(t:DChar.vdl[2])] + let [i, j] = (a:key == 1) ? [1, 2] : [2, 1] + call map(d{i}, 'index(a:lines, v:val) == -1 ? -1 : v:val') + call filter(d{j}, 'd{i}[v:key] != -1') + call filter(d{i}, 'v:val != -1') + return [d1, d2] +endfunction + +function! s:LinesValues(key, lines) + let bnr = winbufnr(t:DChar.win[a:key]) + return eval('{' . join(map(copy(a:lines), 'v:val . ":" . + \str2nr(sha256(getbufline(bnr, v:val)[0]), 16)'), + \',') . '}') +endfunction + +function! s:ValidDiffModeWins(wlist) + " Try to use diffput to check if the diff mode is really valid or not. + let cwin = winnr() + let save_ei = &eventignore | let &eventignore = 'all' + let vdmw = [] + for w in a:wlist + if getwinvar(w, '&diff') + exec w . 'wincmd w' + try + exec 'silent diffput 99999' + catch /^Vim(diffput):E99:/ + " &diff == 1 but invalid diff mode + catch /^Vim(diffput):/ + let vdmw += [w] + endtry + endif + endfor + exec cwin . 'wincmd w' + let &eventignore = save_ei + return vdmw +endfunction + +function! diffchar#JumpDiffChar(dir, pos) + " dir : 1 = forward, 0 = backward + " pos : 1 = start, 0 = end + if !exists('t:DChar') | return | endif + + " refresh window number of diffchar windows + call s:RefreshDiffCharWID() + + " return if current window is not either of diffchar windows + let cwin = winnr() + for k in [1, 2, 0] + if k == 0 | return | endif + if t:DChar.win[k] == cwin | break | endif + endfor + + let found = 0 + let l = line('.') + while !found && 1 <= l && l <= line('$') + if has_key(t:DChar.hlc[k], l) + if l == line('.') + let c = col('.') + if !a:pos + " end pos workaround for multibyte char + let c += len(matchstr(getbufline( + \winbufnr(cwin), l)[0], + \'.', c - 1)) - 1 + endif + else + let c = a:dir ? 0 : 99999 + endif + let hc = map(copy(t:DChar.hlc[k][l]), + \'(v:val[0] == "d") ? "" : + \v:val[1][a:pos ? 0 : 1]') + if !a:dir + let c = - c + call map(reverse(hc), + \'empty(v:val) ? "" : - v:val') + endif + for n in range(len(hc)) + if !empty(hc[n]) && c < hc[n] + let c = hc[n] + if !a:dir + let c = - c + let n = len(hc) - n - 1 + endif + call cursor(l, c) + call s:ShowDiffCharPair(k, l, n, a:pos) + let found = 1 + break + endif + endfor + endif + let l = a:dir ? l + 1 : l - 1 + endwhile +endfunction + +function! s:ShowDiffCharPair(key, line, col, pos) + " show cursor on deleted or matching unit on another window + let bkey = (a:key == 1) ? 2 : 1 + if exists('t:DChar.vdl') " diff mode + let bline = t:DChar.vdl[bkey][index(t:DChar.vdl[a:key], a:line)] + else " non-diff mode + let bline = a:line + endif + let bl = getbufline(winbufnr(t:DChar.win[bkey]), bline)[0] + let co = t:DChar.hlc[bkey][bline][a:col][1] + let dc = bl[co[0] - 1 : co[1] - 1] + + let save_ei = &eventignore | let &eventignore = 'all' + exec t:DChar.win[bkey] . 'wincmd w' + + call s:ResetDiffCharPair(bkey) + let clen = len(split(dc, '\zs')[a:pos ? 0 : -1]) + let cpos = a:pos ? co[0] : co[1] - clen + 1 + if exists('*matchaddpos') + let t:DChar.pci[bkey] = matchaddpos(t:DChar.dhl.U, + \[[bline, cpos, clen]], 0) + else + let t:DChar.pci[bkey] = matchadd(t:DChar.dhl.U, '\%' . bline . + \'l\%>' . (cpos - 1) . 'c\%<' . (cpos + clen) . 'c', 0) + endif + exec 'au! dchar WinEnter call s:ResetDiffCharPair(' . bkey . ')' + + exec t:DChar.win[a:key] . 'wincmd w' + let &eventignore = save_ei + + " echo the deleted and matching unit with its color + let [ed, co] = t:DChar.hlc[a:key][a:line][a:col] + if ed == 'a' " added unit + let bl = getbufline(winbufnr(t:DChar.win[a:key]), a:line)[0] + exec 'echohl ' . t:DChar.dhl.C + echon (1 < co[0]) ? split(bl[: co[0] - 2], '\zs')[-1] : '' + exec 'echohl ' . t:DChar.dhl.D + echon repeat('-', strwidth(bl[co[0] - 1 : co[1] - 1])) + exec 'echohl ' . t:DChar.dhl.C + echon (co[1] < len(bl)) ? split(bl[co[1] :], '\zs')[0] : '' + echohl None + elseif ed == 'c' " changed unit + exec 'echohl ' . t:DChar.dmc[(count( + \map(t:DChar.hlc[a:key][a:line][: a:col], 'v:val[0]'), + \'c') - 1) % len(t:DChar.dmc)] + echon dc + echohl None + endif +endfunction + +function! s:ResetDiffCharPair(key) + if exists('t:DChar.pci[a:key]') + call matchdelete(t:DChar.pci[a:key]) + unlet t:DChar.pci[a:key] + exec 'au! dchar WinEnter ' + echon '' + endif +endfunction + +function! s:MarkDiffCharWID(on) + " mark w:DCharWID (1/2) on diffchar windows or delete them + for wvr in map(range(1, winnr('$')), 'getwinvar(v:val, "")') + if has_key(wvr, 'DCharWID') | unlet wvr.DCharWID | endif + endfor + if a:on + call map([1, 2], + \'setwinvar(t:DChar.win[v:val], "DCharWID", v:val)') + endif +endfunction + +function! s:RefreshDiffCharWID() + " find diffchar windows and set their winnr to t:DChar.win again + let t:DChar.win = {} + for win in range(1, winnr('$')) + let id = get(getwinvar(win, ''), 'DCharWID', 0) + if id | let t:DChar.win[id] = win | endif + endfor +endfunction + +" "An O(NP) Sequence Comparison Algorithm" +" by S.Wu, U.Manber, G.Myers and W.Miller +function! s:TraceDiffChar(u1, u2, ...) + let [l1, l2] = [len(a:u1), len(a:u2)] + if l1 == 0 && l2 == 0 | return '' + elseif l1 == 0 | return repeat('+', l2) + elseif l2 == 0 | return repeat('-', l1) + endif + + " reverse to be M >= N + let [M, N, u1, u2, e1, e2] = (l1 >= l2) ? + \[l1, l2, a:u1, a:u2, '+', '-'] : + \[l2, l1, a:u2, a:u1, '-', '+'] + + let D = M - N + let fp = repeat([-1], M + N + 1) + let etree = [] " [next edit, previous p, previous k] + + " check time limit when specified the end time + let ckt = (a:0 > 0) ? 'str2float(reltimestr(reltime())) > a:1' : 0 + + let p = -1 + while fp[D] != M + " if timeout, return here with '*' + if eval(ckt) | return '*' | endif + let p += 1 + let epk = repeat([[]], p * 2 + D + 1) + for k in range(-p, D - 1, 1) + range(D + p, D, -1) + let [x, epk[k]] = (fp[k - 1] < fp[k + 1]) ? + \[fp[k + 1], [e1, k < D ? p - 1 : p, k + 1]] : + \[fp[k - 1] + 1, [e2, k > D ? p - 1 : p, k - 1]] + let y = x - k + while x < M && y < N && u1[x] == u2[y] + let epk[k][0] .= '=' + let [x, y] += [1, 1] + endwhile + let fp[k] = x + endfor + let etree += [epk] + endwhile + + " create a shortest edit script (SES) from last p and k + let ses = '' + while p != 0 || k != 0 + let [e, p, k] = etree[p][k] + let ses = e . ses + endwhile + let ses = etree[p][k][0] . ses + + return ses[1:] " remove the first entry +endfunction + +if has('patch-7.4.682') +function! s:ToggleDiffHL(on) + " no need in no-diff mode + if !exists('t:DChar.vdl') | return | endif + + let tn = len(filter(map(range(1, tabpagenr('$')), + \'gettabvar(v:val, "DChar")'), + \'!empty(v:val) && exists("v:val.dtm")')) + if a:on + if tn == 0 " set event at first ON + au! dchar TabEnter * call s:AdjustHLOption() + endif + " disable hl option and overwrite DiffChange/DiffText area + call s:DisableHLOption() + call s:OverwriteDiffHL() + else + if tn == 1 " clear event at last OFF + au! dchar TabEnter * + endif + " restore hl option and DiffChange/DiffText area + call s:RestoreHLOption() + call s:RestoreDiffHL() + endif +endfunction + +function! s:AdjustHLOption() + call eval(exists('t:DChar.vdl') ? + \'s:DisableHLOption()' : 's:RestoreHLOption()') +endfunction + +function! s:DisableHLOption() + if !exists('s:save_hl') + let s:save_hl = &highlight + let &highlight = join(map(split(s:save_hl, ','), + \'v:val[0] =~# "[CT]" ? v:val[0] . "-" : v:val'), ',') + endif +endfunction + +function! s:RestoreHLOption() + if exists('s:save_hl') + let &highlight = s:save_hl + unlet s:save_hl + endif +endfunction + +function! s:OverwriteDiffHL() + " overwrite DiffChange/DiffText area with its match + if exists('t:DChar.dtm') | return | endif + + let t:DChar.dtm = {} + + let cwin = winnr() + let save_ei = &eventignore | let &eventignore = 'all' + + for k in [1, 2] + exec t:DChar.win[k] . 'wincmd w' + + let tl = [] + if !exists('s:save_dex') + " normal case + let dt = hlID(t:DChar.dhl.T) + call diff_hlID(0, 0) " a workaround for vim defect + for l in t:DChar.vdl[k] + let t = filter(range(1, col([l, '$']) - 1), + \'diff_hlID(l, v:val) == dt') + if empty(t) | continue | endif + let [cs, ce] = [t[0], t[-1]] + let tl += [[l, cs, ce - cs + 1]] + endfor + else + " diffexpr exceptional case + for l in t:DChar.vdl[k] + let h = get(t:DChar.hlc[k], l, []) + if empty(h) | continue | endif + let cs = h[0][1][h[0][0] == 'd' ? 1 : 0] + let ce = h[-1][1][h[-1][0] == 'd' ? 0 : 1] + if cs > ce | continue | endif + let tl += [[l, cs, ce - cs + 1]] + endfor + endif + + let t:DChar.dtm[k] = [] + for hl in ['C', 'T'] + let ll = (hl == 'C') ? t:DChar.vdl[k] : tl + let p = 0 + while p < len(ll) + let t:DChar.dtm[k] += [matchaddpos( + \t:DChar.dhl[hl], ll[p : p + 7], -1)] + let p += 8 + endwhile + endfor + endfor + + exec cwin . 'wincmd w' + let &eventignore = save_ei +endfunction + +function! s:RestoreDiffHL() + " delete all the overwritten DiffChange/DiffText matches + if !exists('t:DChar.dtm') | return | endif + + let cwin = winnr() + let save_ei = &eventignore | let &eventignore = 'all' + + for k in [1, 2] + exec t:DChar.win[k] . 'wincmd w' + call map(t:DChar.dtm[k], 'matchdelete(v:val)') + endfor + + exec cwin . 'wincmd w' + let &eventignore = save_ei + + unlet t:DChar.dtm +endfunction +endif + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/vimfiles/autoload/merginal.vim b/vimfiles/autoload/merginal.vim old mode 100755 new mode 100644 index 1b26c23..97023ea --- a/vimfiles/autoload/merginal.vim +++ b/vimfiles/autoload/merginal.vim @@ -15,6 +15,21 @@ function! merginal#system(command,...) endif endfunction +function! merginal#bang(command) + if exists(':terminal') + redraw "Release 'Press ENTER or type command to continue' + let l:oldWinView = winsaveview() + botright new + call winrestview(l:oldWinView) + resize 5 + call termopen(a:command) + autocmd BufWinLeave execute winnr('#').'wincmd w' + normal! A + else + execute '!'.a:command + endif +endfunction + "Opens a file that belongs to a repo in a window that already belongs to that "repo. Creates a new window if can't find suitable window. function! merginal#openFileDecidedWindow(repo,fileName) @@ -97,23 +112,6 @@ function! merginal#getListOfDisposableWindowsOfRepo(repo) return l:result endfunction -"Get the repository that belongs to a window -function! s:getRepoOfWindow(winnr) - "Ignore bad window numbers - if a:winnr<=0 - return {} - endif - let l:currentWindow=winnr() - try - execute a:winnr.'wincmd w' - return fugitive#repo() - catch - return {} - finally - execute l:currentWindow.'wincmd w' - endtry -endfunction - "Reload the buffers function! merginal#reloadBuffers() let l:currentWindow=winnr() @@ -127,43 +125,6 @@ function! merginal#reloadBuffers() execute l:currentWindow.'wincmd w' endfunction -"Exactly what it says on tin -function! merginal#runGitCommandInTreeReturnResult(repo,command) - let l:dir=getcwd() - execute 'cd '.fnameescape(a:repo.tree()) - try - return merginal#system(a:repo.git_command().' '.a:command) - finally - execute 'cd '.fnameescape(l:dir) - endtry -endfunction - -"Like merginal#runGitCommandInTreeReturnResult but split result to lines -function! merginal#runGitCommandInTreeReturnResultLines(repo,command) - return split(merginal#runGitCommandInTreeReturnResult(a:repo, a:command), - \ '\r\n\|\n\|\r') -endfunction - -function! s:cleanup_term_codes(s) - let s = substitute(a:s, '\t', ' ', 'g') - " Remove terminal escape codes for colors (based on - " www.commandlinefu.com/commands/view/3584/). - let s = substitute(s, '\v\[([0-9]{1,3}(;[0-9]{1,3})?)?[m|K]', '', 'g') - return s -endfunction - -function! merginal#runGitCommandInTreeEcho(repo,command) - let l:lines = merginal#runGitCommandInTreeReturnResultLines(a:repo, a:command) - if len(l:lines) == 1 - " Output a single/empty line to make Vim wait for Enter. - echo ' ' - endif - for l:line in l:lines - echo "[output]" s:cleanup_term_codes(l:line) - endfor -endfunction - - "Returns 1 if there was a merginal bufffer to close function! merginal#closeMerginalBuffer() let l:merginalWindowNumber=bufwinnr('Merginal:') @@ -179,1059 +140,34 @@ function! merginal#closeMerginalBuffer() endif return 1 finally - execute l:currentWindow.'wincmd w' + "If it's the merginal window that we close, there is no window to + "return to... + if l:merginalWindowNumber != l:currentWindow + execute l:currentWindow.'wincmd w' + endif endtry end return 0 endfunction -"Returns 1 if a new buffer was opened, 0 if it already existed -function! merginal#openTuiBuffer(bufferName,inWindow) - let l:repo=fugitive#repo() - let l:tuiBufferWindow=bufwinnr(bufnr(a:bufferName)) - - if -1 (\S+))?$') - if !empty(l:remoteMatch) - let l:result.type='remote' - let l:result.isLocal=0 - let l:result.isRemote=1 - let l:result.isDetached=0 - let l:result.remote=l:remoteMatch[1] - let l:result.name=l:remoteMatch[2] - if empty(l:remoteMatch[2]) - let l:result.handle=l:remoteMatch[1] - else - let l:result.handle=l:remoteMatch[1].'/'.l:remoteMatch[2] - endif - return l:result - endif - - let l:result.type='local' - let l:result.isLocal=1 - let l:result.isRemote=0 - let l:result.isDetached=0 - let l:result.remote='' - let l:result.name=l:line - let l:result.handle=l:line - - return l:result -endfunction - -"For the file in the specified line, retrieve: -" - name: the name of the file -function! merginal#fileDetails(lineNumber) - if !exists('b:merginal_repo') - throw 'Unable to get file details outside the merginal window' - endif - if line(a:lineNumber)<=b:headerLinesCount - throw 'Unable to get branch details for the header of the merginal window' - endif - let l:line=getline(a:lineNumber) - let l:result={} - - let l:result.name=l:line - - return l:result -endfunction - -"For the commit in the specified line, retrieve it's hash -function! merginal#commitHash(lineNumber) - if !exists('b:merginal_repo') - throw 'Unable to get commit details outside the merginal window' - endif - if line(a:lineNumber)<=b:headerLinesCount - throw 'Unable to get commit details for the header of the merginal window' - endif - "echo a:lineNumber - if type(0) == type(a:lineNumber) - let l:lineNumber = a:lineNumber - else - let l:lineNumber = line(a:lineNumber) - endif - while b:headerLinesCount < l:lineNumber && !empty(getline(l:lineNumber)) - let l:lineNumber -= 1 - endwhile - let l:lineNumber += 1 - return split(getline(l:lineNumber))[0] -endfunction - -"For the commit in the specified line, retrieve: -" - fullHash -" - authorName -" - timestamp -" - subject -" - body -function! merginal#commitDetails(lineNumber) - let l:commitHash = merginal#commitHash(a:lineNumber) - let l:entryFormat = join(['%H', '%aN', '%aE', '%ai', '%B'], '%x01') - let l:commitLines = split( - \ merginal#system(b:merginal_repo.git_command('--no-pager', 'log', '-1', '--format='.l:entryFormat, l:commitHash)), - \ '\%x01') - let l:result = {} - - let l:result.fullHash = l:commitLines[0] - let l:result.authorName = l:commitLines[1] - let l:result.authorEmail = l:commitLines[2] - let l:result.timestamp = l:commitLines[3] - - let l:commitMessage = split(l:commitLines[4], '\r\n\|\n\|\r') - let l:result.subject = l:commitMessage[0] - let l:result.body = join(l:commitMessage[2 :], "\n") - - return l:result -endfunction - -function! merginal#getLocalBranchNamesThatTrackARemoteBranch(remoteBranchName) - "Get verbose list of branches - let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','-vv')),'\r\n\|\n\|\r') - - "Filter for branches that track our remote - let l:checkIfTrackingRegex='\V['.escape(a:remoteBranchName,'\').'\[\]:]' - let l:branchList=filter(l:branchList,'v:val=~l:checkIfTrackingRegex') - - "Extract the branch name from the matching lines - "let l:extractBranchNameRegex='\v^\*?\s*(\S+)' - "let l:branchList=map(l:branchList,'matchlist(v:val,l:extractBranchNameRegex)[1]') - let l:extractBranchNameRegex='\v^\*?\s*\zs\S+' - let l:branchList=map(l:branchList,'matchstr(v:val,l:extractBranchNameRegex)') - - return l:branchList -endfunction - -function! merginal#getRemoteBranchTrackedByLocalBranch(localBranchName) - let l:result=merginal#system(b:merginal_repo.git_command('branch','--list',a:localBranchName,'-vv')) - echo l:result - return matchstr(l:result,'\v\[\zs[^\[\]:]*\ze[\]:]') -endfunction - - -"Check if the current buffer's repo is in rebase mode -function! merginal#isRebaseMode() - return isdirectory(fugitive#repo().dir('rebase-apply')) -endfunction - -"Check if the current buffer's repo is in rebase amend mode -function! merginal#isRebaseAmendMode() - return isdirectory(fugitive#repo().dir('rebase-merge')) -endfunction - -"Check if the current buffer's repo is in merge mode -function! merginal#isMergeMode() - "Use glob() to check for file existence - return !empty(glob(fugitive#repo().dir('MERGE_MODE'))) -endfunction - -"Open the branch list buffer for controlling buffers -function! merginal#openBranchListBuffer(...) - if merginal#openTuiBuffer('Merginal:Branches',get(a:000,1,bufwinnr('Merginal:'))) - doautocmd User Merginal_BranchList - endif - - "At any rate, refresh the buffer: - call merginal#tryRefreshBranchListBuffer(1) -endfunction - -augroup merginal - autocmd! - autocmd User Merginal_BranchList nnoremap q q - autocmd User Merginal_BranchList nnoremap R :call merginal#tryRefreshBranchListBuffer(0) - autocmd User Merginal_BranchList nnoremap C :call checkoutBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap cc :call checkoutBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap ct :call trackBranchUnderCursor(0) - autocmd User Merginal_BranchList nnoremap cT :call trackBranchUnderCursor(1) - autocmd User Merginal_BranchList nnoremap A :call promptToCreateNewBranch() - autocmd User Merginal_BranchList nnoremap aa :call promptToCreateNewBranch() - autocmd User Merginal_BranchList nnoremap D :call deleteBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap dd :call deleteBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap M :call mergeBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap mm :call mergeBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap mf :call mergeBranchUnderCursorUsingFugitive() - autocmd User Merginal_BranchList nnoremap rb :call rebaseBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap ps :call remoteActionForBranchUnderCursor('push',[]) - autocmd User Merginal_BranchList nnoremap pS :call remoteActionForBranchUnderCursor('push',['--force']) - autocmd User Merginal_BranchList nnoremap pl :call remoteActionForBranchUnderCursor('pull',[]) - autocmd User Merginal_BranchList nnoremap pr :call remoteActionForBranchUnderCursor('pull',['--rebase']) - autocmd User Merginal_BranchList nnoremap pf :call remoteActionForBranchUnderCursor('fetch',[]) - autocmd User Merginal_BranchList nnoremap gd :call diffWithBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap rn :call renameBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap gl :call historyLogForBranchUnderCursor() -augroup END - -"If the current buffer is a branch list buffer - refresh it! -function! merginal#tryRefreshBranchListBuffer(jumpToCurrentBranch) - if 'Merginal:Branches'==bufname('') - let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','--all')),'\r\n\|\n\|\r') - let l:currentLine=line('.') - - setlocal modifiable - "Clear the buffer: - silent normal! gg"_dG - "Write the branch list: - call setline(1,l:branchList) - setlocal nomodifiable - - if a:jumpToCurrentBranch - "Find the current branch's index - let l:currentBranchIndex=-1 - for i in range(len(l:branchList)) - if '*'==l:branchList[i][0] - let l:currentBranchIndex=i - break - endif - endfor - if -1 q q - autocmd User Merginal_MergeConflicts nnoremap R :call merginal#tryRefreshMergeConflictsBuffer(0) - autocmd User Merginal_MergeConflicts nnoremap :call openMergeConflictUnderCursor() - autocmd User Merginal_MergeConflicts nnoremap A :call addConflictedFileToStagingArea() - autocmd User Merginal_MergeConflicts nnoremap aa :call addConflictedFileToStagingArea() -augroup END - -"Returns 1 if all merges are done -function! s:refreshConflictsBuffer(fileToJumpTo,headerLines) - "Get the list of unmerged files: - let l:conflicts=split(merginal#system(b:merginal_repo.git_command('ls-files','--unmerged')),'\r\n\|\n\|\r') - "Split by tab - the first part is info, the second is the file name - let l:conflicts=map(l:conflicts,'split(v:val,"\t")') - "Only take the stage 1 files - stage 2 and 3 are the same files with - "different hash, and we don't care about the hash here - let l:conflicts=filter(l:conflicts,'v:val[0] =~ "\\v 1$"') - "Take the file name - we no longer care about the info - let l:conflicts=map(l:conflicts,'v:val[1]') - "If the working copy is not the current dir, we can get wrong paths. - "We need to resulve that: - let l:conflicts=map(l:conflicts,'b:merginal_repo.tree(v:val)') - "Make the paths as short as possible: - let l:conflicts=map(l:conflicts,'fnamemodify(v:val,":~:.")') - - - let l:currentLine=line('.')-b:headerLinesCount - - setlocal modifiable - "Clear the buffer: - silent normal! gg"_dG - "Write the branch list: - call setline(1,a:headerLines+l:conflicts) - let b:headerLinesCount=len(a:headerLines) - let l:currentLine=l:currentLine+b:headerLinesCount - setlocal nomodifiable - if empty(l:conflicts) - return 1 - endif - - if empty(a:fileToJumpTo) - if 0 q q - autocmd User Merginal_DiffFiles nnoremap R :call merginal#tryRefreshDiffFilesBuffer() - autocmd User Merginal_DiffFiles nnoremap :call openDiffFileUnderCursor() - autocmd User Merginal_DiffFiles nnoremap ds :call openDiffFileUnderCursorAndDiff('s') - autocmd User Merginal_DiffFiles nnoremap dv :call openDiffFileUnderCursorAndDiff('v') - autocmd User Merginal_DiffFiles nnoremap co :call checkoutDiffFileUnderCursor() -augroup END - - -"For the diff file in the specified line, retrieve: -" - type: 'added', 'deleted' or 'modified' -" - isAdded, isDeleted, isModified -" - fileInTree: the path of the file relative to the repo -" - fileFullPath: the full path to the file -function! merginal#diffFileDetails(lineNumber) - if !exists('b:merginal_repo') - throw 'Unable to get diff file details outside the merginal window' - endif - let l:line=getline(a:lineNumber) - let l:result={} - - let l:matches=matchlist(l:line,'\v([ADM])\t(.*)$') - - if empty(l:matches) - throw 'Unable to get diff files details for `'.l:line.'`' - endif - - let l:result.isAdded=0 - let l:result.isDeleted=0 - let l:result.isModified=0 - if 'A'==l:matches[1] - let l:result.type='added' - let l:result.isAdded=1 - elseif 'D'==l:matches[1] - let l:result.type='deleted' - let l:result.isDeleted=1 - else - let l:result.type='modified' - let l:result.isModified=1 - endif - - let l:result.fileInTree=l:matches[2] - let l:result.fileFullPath=b:merginal_repo.tree(l:matches[2]) - - return l:result -endfunction - -"If the current buffer is a diff files buffer - refresh it! -function! merginal#tryRefreshDiffFilesBuffer() - if 'Merginal:Diff'==bufname('') - let l:diffTarget=b:merginal_diffTarget - let l:diffFiles=merginal#runGitCommandInTreeReturnResultLines(b:merginal_repo,'diff --name-status '.shellescape(l:diffTarget)) - let l:currentLine=line('.') - - setlocal modifiable - "Clear the buffer: - silent normal! gg"_dG - "Write the diff files list: - call setline(1,l:diffFiles) - setlocal nomodifiable - - execute l:currentLine - endif -endfunction - -"Exactly what it says on tin -function! s:openDiffFileUnderCursor() - if 'Merginal:Diff'==bufname('') - let l:diffFile=merginal#diffFileDetails('.') - - if l:diffFile.isDeleted - throw 'File does not exist in current buffer' - endif - - call merginal#openFileDecidedWindow(b:merginal_repo,l:diffFile.fileFullPath) - endif -endfunction - -"Exactly what it says on tin -function! s:openDiffFileUnderCursorAndDiff(diffType) - if a:diffType!='s' && a:diffType!='v' - throw 'Bad diff type' - endif - if 'Merginal:Diff'==bufname('') - let l:diffFile=merginal#diffFileDetails('.') - - if l:diffFile.isAdded - throw 'File does not exist in other buffer' - endif - - let l:repo=b:merginal_repo - let l:diffTarget=b:merginal_diffTarget - - "Close currently open git diffs - let l:currentWindowBuffer=winbufnr('.') - try - windo if 'blob'==get(b:,'fugitive_type','') && exists('w:fugitive_diff_restore') - \| bdelete - \| endif - catch - "do nothing - finally - execute bufwinnr(l:currentWindowBuffer).'wincmd w' - endtry - - call merginal#openFileDecidedWindow(l:repo,l:diffFile.fileFullPath) - - execute ':G'.a:diffType.'diff '.fnameescape(l:diffTarget) - endif -endfunction - -"Checks out the file from the diff target to the current branch -function! s:checkoutDiffFileUnderCursor() - if 'Merginal:Diff'==bufname('') - let l:diffFile=merginal#diffFileDetails('.') - - if l:diffFile.isAdded - throw 'File does not exist in diffed buffer' - endif - - let l:answer=1 - if !empty(glob(l:diffFile.fileFullPath)) - let l:answer='yes'==input('Override `'.l:diffFile.fileInTree.'`? (type "yes" to confirm) ') - endif - if l:answer - call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout '.shellescape(b:merginal_diffTarget) - \.' -- '.shellescape(l:diffFile.fileFullPath)) - call merginal#reloadBuffers() - call merginal#tryRefreshDiffFilesBuffer() - else - echo - echom 'File checkout canceled by user.' - endif - endif -endfunction - - -"Open the rebase conflicts buffer for resolving rebase conflicts -function! merginal#openRebaseConflictsBuffer(...) - let l:currentFile=expand('%:~:.') - if merginal#openTuiBuffer('Merginal:Rebase',get(a:000,1,bufwinnr('Merginal:'))) - doautocmd User Merginal_RebaseConflicts - endif - - "At any rate, refresh the buffer: - call merginal#tryRefreshRebaseConflictsBuffer(l:currentFile) -endfunction - -augroup merginal - autocmd User Merginal_RebaseConflicts nnoremap q q - autocmd User Merginal_RebaseConflicts nnoremap R :call merginal#tryRefreshRebaseConflictsBuffer(0) - autocmd User Merginal_RebaseConflicts nnoremap :call openMergeConflictUnderCursor() - autocmd User Merginal_RebaseConflicts nnoremap A :call addConflictedFileToStagingArea() - autocmd User Merginal_RebaseConflicts nnoremap aa :call addConflictedFileToStagingArea() - autocmd User Merginal_RebaseConflicts nnoremap ra :call rebaseAction('abort') - autocmd User Merginal_RebaseConflicts nnoremap rs :call rebaseAction('skip') - autocmd User Merginal_RebaseConflicts nnoremap rc :call rebaseAction('continue') -augroup END - -"Returns 1 if all rebase conflicts are done -function! merginal#tryRefreshRebaseConflictsBuffer(fileToJumpTo) - if 'Merginal:Rebase'==bufname('') - let l:currentCommitMessageLines=readfile(b:merginal_repo.dir('rebase-apply','msg-clean')) - call insert(l:currentCommitMessageLines,'=== Reapplying: ===') - call add(l:currentCommitMessageLines,'===================') - call add(l:currentCommitMessageLines,'') - return s:refreshConflictsBuffer(a:fileToJumpTo,l:currentCommitMessageLines) - endif - return 0 -endfunction - -"Run various rebase actions -function! s:rebaseAction(remoteAction) - if 'Merginal:Rebase'==bufname('') - \|| 'Merginal:RebaseAmend'==bufname('') - call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager rebase --'.a:remoteAction) - call merginal#reloadBuffers() - if merginal#isRebaseMode() - call merginal#tryRefreshRebaseConflictsBuffer(0) - elseif merginal#isRebaseAmendMode() - call merginal#tryRefreshRebaseAmendBuffer() - else - "If we finished rebasing - close the rebase conflicts buffer - wincmd q - endif - endif -endfunction - - - -"Open the rebase amend buffer -function! merginal#openRebaseAmendBuffer(...) - let l:currentFile=expand('%:~:.') - if merginal#openTuiBuffer('Merginal:RebaseAmend',get(a:000,1,bufwinnr('Merginal:'))) - doautocmd User Merginal_RebaseAmend - endif - - "At any rate, refresh the buffer: - call merginal#tryRefreshRebaseAmendBuffer() -endfunction - -augroup merginal - autocmd User Merginal_RebaseAmend nnoremap q q - autocmd User Merginal_RebaseAmend nnoremap R :call merginal#tryRefreshRebaseAmendBuffer() - autocmd User Merginal_RebaseAmend nnoremap ra :call rebaseAction('abort') - autocmd User Merginal_RebaseAmend nnoremap rs :call rebaseAction('skip') - autocmd User Merginal_RebaseAmend nnoremap rc :call rebaseAction('continue') - autocmd User Merginal_RebaseAmend nnoremap gd :call diffWithBranchUnderCursor() - autocmd User Merginal_RebaseAmend nnoremap gl :call historyLogForBranchUnderCursor() -augroup END - -function! merginal#tryRefreshRebaseAmendBuffer() - if 'Merginal:RebaseAmend'==bufname('') - let l:currentLine=line('.') - let l:newBufferLines=[] - let l:amendedCommit=readfile(b:merginal_repo.dir('rebase-merge','amend')) - let l:amendedCommitShort=merginal#system(b:merginal_repo.git_command('rev-parse','--short',l:amendedCommit[0])) - let l:amendedCommitShort=substitute(l:amendedCommitShort,'\v[\r\n]','','g') - let l:amendedCommitMessage=readfile(b:merginal_repo.dir('rebase-merge','message')) - call add(l:newBufferLines,'=== Amending '.l:amendedCommitShort.' ===') - let l:newBufferLines+=l:amendedCommitMessage - call add(l:newBufferLines,repeat('=',len(l:newBufferLines[0]))) - call add(l:newBufferLines,'') - - let b:headerLinesCount=len(l:newBufferLines)+1 - - let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','--all')),'\r\n\|\n\|\r') - "The first line is a reminder that we are rebasing - "call remove(l:branchList,0) - let l:newBufferLines+=l:branchList - - - setlocal modifiable - "Clear the buffer: - silent normal! gg"_dG - "Write the new buffer lines: - call setline(1,l:newBufferLines) - "call setline(1,l:branchList) - setlocal nomodifiable - endif - return 0 -endfunction - - - - - -"Open the history log buffer -function! merginal#openHistoryLogBuffer(logBranch,...) - let l:currentFile=expand('%:~:.') - if merginal#openTuiBuffer('Merginal:HistoryLog',get(a:000,1,bufwinnr('Merginal:'))) - doautocmd User Merginal_HistoryLog - endif - - let b:merginal_branch=a:logBranch - - "At any rate, refresh the buffer: - call merginal#tryRefreshHistoryLogBuffer() -endfunction - -augroup merginal - autocmd User Merginal_HistoryLog nnoremap q q - autocmd User Merginal_HistoryLog nnoremap R :call merginal#tryRefreshHistoryLogBuffer() - autocmd User Merginal_HistoryLog nnoremap :call moveToNextOrPreviousCommit(-1) - autocmd User Merginal_HistoryLog nnoremap :call moveToNextOrPreviousCommit(1) - autocmd User Merginal_HistoryLog nnoremap S :call printCommitUnderCurosr('fuller') - autocmd User Merginal_HistoryLog nnoremap ss :call printCommitUnderCurosr('fuller') - autocmd User Merginal_HistoryLog nnoremap C :call checkoutCommitUnderCurosr() - autocmd User Merginal_HistoryLog nnoremap cc :call checkoutCommitUnderCurosr() - autocmd User Merginal_HistoryLog nnoremap gd :call diffWithCommitUnderCursor() -augroup END - -function! merginal#tryRefreshHistoryLogBuffer() - if 'Merginal:HistoryLog'==bufname('') - let l:entryFormat = '%h %aN%n%ai%n%s%n' - let l:logLines = split( - \ merginal#system(b:merginal_repo.git_command( - \ '--no-pager', 'log', '--format='.l:entryFormat, b:merginal_branch.handle)), - \ '\r\n\|\n\|\r') - if empty(l:logLines[len(l:logLines) - 1]) - call remove(l:logLines, len(l:logLines) - 1) - endif - let l:currentLine=line('.') - - setlocal modifiable - "Clear the buffer: - silent normal! gg"_dG - "Write the log lines: - call setline(1,l:logLines) - setlocal nomodifiable - - execute l:currentLine - endif - return 0 -endfunction - -"Exactly what it says on tin -function! s:printCommitUnderCurosr(format) - if 'Merginal:HistoryLog'==bufname('') - let l:commitHash = merginal#commitHash('.') - "Not using merginal#runGitCommandInTreeEcho because we are insterested - "in the result as more than just git command output. Also - using - "git-log with -1 instead of git-show because for some reason git-show - "ignores the --format flag... - echo merginal#system(b:merginal_repo.git_command('--no-pager', 'log', '-1', '--format='.a:format, l:commitHash)) - endif -endfunction - -"Exactly what it says on tin -function! s:checkoutCommitUnderCurosr() - if 'Merginal:HistoryLog'==bufname('') - let l:commitHash = merginal#commitHash('.') - call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout '.shellescape(l:commitHash)) - call merginal#reloadBuffers() - call merginal#tryRefreshBranchListBuffer(0) - endif -endfunction - -"Opens the diff files buffer -function! s:diffWithCommitUnderCursor() - if 'Merginal:HistoryLog'==bufname('') - let l:commitHash = merginal#commitHash('.') - call merginal#openDiffFilesBuffer(l:commitHash) - endif -endfunction - -function! s:moveToNextOrPreviousCommit(direction) - if 'Merginal:HistoryLog'==bufname('') - let l:line = line('.') - - "Find the first line of the current commit - while !empty(getline(l:line - 1)) - let l:line -= 1 - endwhile - - "Find the first line of the next/prev commit - let l:line += a:direction - while !empty(getline(l:line - 1)) - let l:line += a:direction - endwhile - - if l:line <= 0 || line('$') <= l:line - "We reached past the first/last commit - go back! - let l:line -= a:direction - while !empty(getline(l:line - 1)) - let l:line -= a:direction - endwhile - endif - execute l:line - endif -endfunction - diff --git a/vimfiles/autoload/merginal/buffers/base.vim b/vimfiles/autoload/merginal/buffers/base.vim new file mode 100644 index 0000000..a9b63be --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/base.vim @@ -0,0 +1,229 @@ +call merginal#modulelib#makeModule(s:, 'base', '') + +let s:f.helpVisible = 0 +let s:f.filter = '' + +function! s:f.generateHelp() dict abort + let l:result = [] + let l:columnWidths = [4, winwidth(0) - 5] + echo l:columnWidths + for l:meta in self._meta + if has_key(l:meta, 'doc') + if !empty(l:meta.keymaps) + let l:result += merginal#util#makeColumns(l:columnWidths, [l:meta.keymaps[0], l:meta.doc]) + for l:keymap in l:meta.keymaps[1:] + let l:result += merginal#util#makeColumns(l:columnWidths, [l:keymap, 'same as '.l:meta.keymaps[0]]) + endfor + endif + endif + endfor + return l:result +endfunction + +function! s:f.generateHeader() dict abort + return [] +endfunction + +function! s:f.generateBody() dict abort + throw 'generateBody() Not implemented for '.self.name +endfunction + +function! s:f.bufferName() dict abort + return 'Merginal:'.self.name +endfunction + +function! s:f.existingWindowNumber() dict abort + return bufwinnr(bufnr(self.bufferName())) +endfunction + +function! s:f.gitRun(...) dict abort + let l:dir = getcwd() + execute 'cd '.fnameescape(self.repo.tree()) + try + let l:gitCommand = call(self.repo.git_command, ['--no-pager'] + a:000, self.repo) + return merginal#system(l:gitCommand) + finally + execute 'cd '.fnameescape(l:dir) + endtry +endfunction + +function! s:f.gitLines(...) dict abort + return split(call(self.gitRun, a:000, self), '\r\n\|\n\|\r') +endfunction + +function! s:f.gitEcho(...) dict abort + let l:lines = call(self.gitLines, a:000, self) + if len(l:lines) == 1 + " Output a single/empty line to make Vim wait for Enter. + echo ' ' + endif + for l:line in l:lines + let l:line = substitute(l:line, '\t', repeat(' ', &tabstop), 'g') + " Remove terminal escape codes for colors (based on + " www.commandlinefu.com/commands/view/3584/). + let l:line = substitute(l:line, '\v\[([0-9]{1,3}(;[0-9]{1,3})?)?[m|K]', '', 'g') + echo "[output]" l:line + endfor +endfunction + +function! s:f.gitBang(...) dict abort + let l:dir = getcwd() + execute 'cd '.fnameescape(self.repo.tree()) + try + let l:gitCommand = call(self.repo.git_command, ['--no-pager'] + a:000, self.repo) + call merginal#bang(l:gitCommand) + finally + execute 'cd '.fnameescape(l:dir) + endtry +endfunction + + +"Returns 1 if a new buffer was opened, 0 if it already existed +function! s:f.openTuiBuffer(targetWindow) dict abort + let self.repo = fugitive#repo() + + if -1 < a:targetWindow + let l:tuiBufferWindow = -1 + else + let l:tuiBufferWindow = self.existingWindowNumber() + endif + + if -1 < l:tuiBufferWindow "Jump to the already open buffer + execute l:tuiBufferWindow.'wincmd w' + else "Open a new buffer + if -1 < a:targetWindow + else + 40vnew + endif + setlocal buftype=nofile + setlocal bufhidden=wipe + setlocal nomodifiable + setlocal winfixwidth + setlocal winfixheight + setlocal nonumber + setlocal norelativenumber + execute 'silent file '.self.bufferName() + call fugitive#detect(self.repo.dir()) + + for l:meta in self._meta + for l:keymap in l:meta.keymaps + execute 'nnoremap '.l:keymap.' :'.l:meta.execute.'' + endfor + + if has_key(l:meta, 'command') + execute 'command! -buffer -nargs=0 '.l:meta.command.' '.l:meta.execute + endif + endfor + + call self.refresh() + if has_key(self, 'jumpToCurrentItem') + call self.jumpToCurrentItem() + endif + endif + + let b:merginal = self + + "Check and return if a new buffer was created + return -1 == l:tuiBufferWindow +endfunction + +function! s:f.gotoBuffer(bufferModuleName, ...) dict abort + let l:newBufferObject = merginal#modulelib#createObject(a:bufferModuleName) + if has_key(l:newBufferObject, 'init') + call call(l:newBufferObject.init, a:000, l:newBufferObject) + elseif 0 < a:0 + throw 'gotoBuffer called with arguments but '.a:bufferModuleName.' has no "init" method' + endif + call l:newBufferObject.openTuiBuffer(winnr()) + return l:newBufferObject +endfunction + +function! s:f._getSpecialMode() dict abort + return merginal#getSpecialMode(self.repo) +endfunction + +"Returns the buffer moved to +function! s:f.gotoSpecialModeBuffer() dict abort + let l:mode = self._getSpecialMode() + if empty(l:mode) || l:mode == self.name + return 0 + endif + let l:newBufferObject = self.gotoBuffer(l:mode) + return l:newBufferObject +endfunction + +function! s:f.isLineInBody(lineNumber) dict abort + if type(a:lineNumber) == type(0) + let l:line = a:lineNumber + else + let l:line = line(a:lineNumber) + endif + return len(self.header) < l:line +endfunction + +function! s:f.verifyLineInBody(lineNumber) dict abort + if !self.isLineInBody(a:lineNumber) + throw 'In the header section of the merginal buffer' + endif +endfunction + +function! s:f.jumpToIndexInBody(index) dict abort + execute a:index + len(self.header) + 1 +endfunction + +function! s:f.isStillInSpecialMode() dict abort + let l:mode = self._getSpecialMode() + return l:mode == self.name +endfunction + + +function! s:f.getFilteredBody() dict abort + return filter(copy(self.body), '0 <= match(v:val, self.filter)') +endfunction + + +function! s:f.refresh() dict abort + let self.header = [] + if self.helpVisible + call extend(self.header, self.generateHelp()) + else + call add(self.header, 'Press ? for help') + endif + call add(self.header, '') + call extend(self.header, self.generateHeader()) + let self.body = self.generateBody() + + let l:currentLine = line('.') - len(self.header) + let l:currentColumn = col('.') + + setlocal modifiable + "Clear the buffer: + silent normal! gg"_dG + "Write the buffer + call setline(1, self.header + self.getFilteredBody()) + let l:currentLine = l:currentLine + len(self.header) + setlocal nomodifiable + + execute l:currentLine + execute 'normal! '.l:currentColumn.'|' +endfunction +call s:f.addCommand('refresh', [], 'MerginalRefresh', 'R', 'Refresh the buffer') + +function! s:f.quit() + bdelete +endfunction +call s:f.addCommand('quit', [], 0, 'q', 'Close the buffer') + +function! s:f.toggleHelp() dict abort + let self.helpVisible = !self.helpVisible + call self.refresh() +endfunction +call s:f.addCommand('toggleHelp', [], 0, '?', 'Toggle this help message') + +function! s:f.promptForFilter() dict abort + let l:newFilter = input('&/') + let self.filter = l:newFilter + call self.refresh() +endfunction +call s:f.addCommand('promptForFilter', [], 0, '&', 'Set filter') + diff --git a/vimfiles/autoload/merginal/buffers/branchList.vim b/vimfiles/autoload/merginal/buffers/branchList.vim new file mode 100644 index 0000000..b9f66ac --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/branchList.vim @@ -0,0 +1,250 @@ +call merginal#modulelib#makeModule(s:, 'branchList', 'immutableBranchList') + + + +function! s:f.checkoutBranch() dict abort + let l:branch = self.branchDetails('.') + call self.gitEcho('checkout', l:branch.handle) + call self.refresh() + call self.jumpToCurrentItem() + call merginal#reloadBuffers() +endfunction +call s:f.addCommand('checkoutBranch', [], 'MerginalCheckout', ['cc', 'C'], 'Checkout the branch under the cursor') + + +function! s:f.trackBranch(promptForName) dict abort + let l:branch = self.branchDetails('.') + if !l:branch.isRemote + throw 'Can not track - branch is not remote' + endif + let l:newBranchName = l:branch.name + if a:promptForName + let l:newBranchName = input('Track `'.l:branch.handle.'` as: ', l:newBranchName) + if empty(l:newBranchName) + echo ' ' + echom 'Branch tracking canceled by user.' + return + endif + endif + call self.gitEcho('checkout', '-b', l:newBranchName, '--track', l:branch.handle) + if !v:shell_error + call merginal#reloadBuffers() + endif + call self.refresh() + call self.jumpToCurrentItem() +endfunction +call s:f.addCommand('trackBranch', [0], 'MerginalTrack', 'ct', 'Track the remote branch under the cursor') +call s:f.addCommand('trackBranch', [1], 'MerginalTrackPrompt', 'cT', 'Track the remote branch under the cursor, prompting for a name') + +function! s:f.promptToCreateNewBranch() dict abort + let l:newBranchName = input('Branch `'.self.repo.head().'` to: ') + if empty(l:newBranchName) + echo ' ' + echom 'Branch creation canceled by user.' + return + endif + call self.gitEcho('checkout', '-b', l:newBranchName) + call merginal#reloadBuffers() + + call self.refresh() + call self.jumpToCurrentItem() +endfunction +call s:f.addCommand('promptToCreateNewBranch', [], 'MerginalNewBranch', ['aa', 'A'], 'Create a new branch') + +function! s:f.deleteBranchUnderCursor() dict abort + let l:branch = self.branchDetails('.') + let l:answer = 0 + if l:branch.isLocal + let l:answer = 'yes' == input('Delete branch `'.l:branch.handle.'`? (type "yes" to confirm) ') + elseif l:branch.isRemote + "Deleting remote branches needs a special warning + let l:answer = 'yes-remote' == input('Delete remote(!) branch `'.l:branch.handle.'`? (type "yes-remote" to confirm) ') + endif + if l:answer + if l:branch.isLocal + call self.gitEcho('branch', '-D', l:branch.handle) + else + call self.gitBang('push', l:branch.remote, '--delete', l:branch.name) + endif + call self.refresh() + else + echo ' ' + echom 'Branch deletion canceled by user.' + endif +endfunction +call s:f.addCommand('deleteBranchUnderCursor', [], 'MerginalDelete', ['dd', 'D'], 'Delete the branch under the cursor') + +function! s:f.mergeBranchUnderCursor(...) dict abort + let l:branch = self.branchDetails('.') + let l:gitArgs = ['merge', '--no-commit', l:branch.handle] + call extend(l:gitArgs, a:000) + call call(self.gitEcho, l:gitArgs, self) + let l:confilctsBuffer = self.gotoSpecialModeBuffer() + if empty(l:confilctsBuffer) + call self.refresh() + else + if empty(l:confilctsBuffer.body) + "If we are in merge mode without actual conflicts, this means + "there are not conflicts and the user can be prompted to enter a + "merge message. + Gstatus + call merginal#closeMerginalBuffer() + endif + endif + call merginal#reloadBuffers() +endfunction +call s:f.addCommand('mergeBranchUnderCursor', [], 'MerginalMerge', ['mm', 'M'], 'Merge the branch under the cursor') +call s:f.addCommand('mergeBranchUnderCursor', ['--no-ff'], 'MerginalMergeNoFF', ['mn'], 'Merge the branch under the cursor using --no-ff') + +function! s:f.mergeBranchUnderCursorUsingFugitive() dict abort + let l:branch = self.branchDetails('.') + execute ':Gmerge '.l:branch.handle +endfunction +call s:f.addCommand('mergeBranchUnderCursorUsingFugitive', [], 'MerginalMergeUsingFugitive', ['mf'], 'Merge the branch under the cursor using fugitive') + +function! s:f.rebaseBranchUnderCursor() dict abort + let l:branch = self.branchDetails('.') + call self.gitEcho('rebase', l:branch.handle) + call merginal#reloadBuffers() + call self.gotoSpecialModeBuffer() +endfunction +call s:f.addCommand('rebaseBranchUnderCursor', [], 'MerginalRebase', 'rb', 'Rebase the branch under the cursor') + +function! s:f.remoteActionForBranchUnderCursor(action, ...) dict abort + let l:branch = self.branchDetails('.') + if l:branch.isLocal + let l:remotes = self.gitLines('remote') + if empty(l:remotes) + throw 'Can not '.a:action.' - no remotes defined' + endif + + let l:chosenRemoteIndex=0 + if 1 < len(l:remotes) + ""Choose the correct text accoring to the action: + let l:prompt = 'Choose remote to '.a:action.' `'.l:branch.handle.'`' + if 'push' == a:action + let l:prompt .= ' to:' + else + let l:prompt .= ' from:' + endif + let l:chosenRemoteIndex = merginal#util#inputList(l:prompt, l:remotes, 'MORE') + "Check that the chosen index is in range + if l:chosenRemoteIndex <= 0 || len(l:remotes) < l:chosenRemoteIndex + return + endif + endif + + let l:localBranchName = l:branch.name + let l:chosenRemote = l:remotes[l:chosenRemoteIndex] + + let l:remoteBranchNameCanadidate = self.getRemoteBranchTrackedByLocalBranch(l:branch.name) + if !empty(l:remoteBranchNameCanadidate) + "Check that this is the same remote: + if l:remoteBranchNameCanadidate =~ '\V\^'.escape(l:chosenRemote, '\').'/' + "Remove the remote repository name + let l:remoteBranchName = l:remoteBranchNameCanadidate[len(l:chosenRemote) + 1:(-1)] + endif + endif + elseif l:branch.isRemote + let l:chosenRemote = l:branch.remote + if 'push' == a:action + "For push, we want to specify the remote branch name + let l:remoteBranchName = l:branch.name + + let l:locals = self.getLocalBranchNamesThatTrackARemoteBranch(l:branch.handle) + + if empty(l:locals) + let l:localBranchName = l:branch.name + elseif 1 == len(l:locals) + let l:localBranchName = l:locals[0] + else + let l:chosenLocalIndex = merginal#util#inputList('Choose local branch to push `'.l:branch.handle.'` from:', l:locals, 'MORE') + + "Check that the chosen index is in range + if l:chosenLocalIndex <= 0 || len(l:locals) < l:chosenLocalIndex + return + endif + + let l:localBranchName = l:locals[l:chosenLocalIndex] + endif + else + "For pull and fetch, git automatically resolves the tracking + "branch based on the remote branch. + let l:localBranchName = l:branch.name + endif + endif + + if exists('l:remoteBranchName') && empty(l:remoteBranchName) + unlet l:remoteBranchName + endif + + let l:gitCommandWithArgs = [a:action] + for l:flag in a:000 + call add(l:gitCommandWithArgs, l:flag) + endfor + + let l:reloadBuffers = 0 + + "Pulling requires the --no-commit flag + if 'pull' == a:action + if exists('l:remoteBranchName') + let l:remoteBranchNameAsPrefix = l:remoteBranchName + else + let l:remoteBranchNameAsPrefix = '' + endif + let l:remoteBranchEscapedName = l:remoteBranchNameAsPrefix.l:localBranchName + call add(l:gitCommandWithArgs, '--no-commit') + let l:reloadBuffers = 1 + + elseif 'push' == a:action + if exists('l:remoteBranchName') + let l:remoteBranchNameAsSuffix = ':'.l:remoteBranchName + else + let l:remoteBranchNameAsSuffix = '' + endif + let l:remoteBranchEscapedName = l:localBranchName.l:remoteBranchNameAsSuffix + + elseif 'fetch' == a:action + if exists('l:remoteBranchName') + let l:targetBranchName = l:remoteBranchName + else + let l:targetBranchName = l:localBranchName + endif + let l:remoteBranchEscapedName = l:targetBranchName + endif + + call add(l:gitCommandWithArgs, l:chosenRemote) + call add(l:gitCommandWithArgs, l:remoteBranchEscapedName) + + call call(self.gitBang, l:gitCommandWithArgs, self) + "if l:reloadBuffers + "call merginal#reloadBuffers() + "endif + "call self.refresh() +endfunction +call s:f.addCommand('remoteActionForBranchUnderCursor', ['push'], 'MerginalPush', ['ps'], 'Prompt to choose a remote to push the branch under the cursor.') +call s:f.addCommand('remoteActionForBranchUnderCursor', ['push', '--force'], 'MerginalPushForce', ['pS'], 'Prompt to choose a remote to force push the branch under the cursor.') +call s:f.addCommand('remoteActionForBranchUnderCursor', ['pull'], 'MerginalPull', ['pl'], 'Prompt to choose a remote to pull the branch under the cursor.') +call s:f.addCommand('remoteActionForBranchUnderCursor', ['pull', '--rebase'], 'MerginalPullRebase', ['pr'], 'Prompt to choose a remote to pull-rebase the branch under the cursor.') +call s:f.addCommand('remoteActionForBranchUnderCursor', ['fetch'], 'MerginalFetch', ['pf'], 'Prompt to choose a remote to fetch the branch under the cursor.') + +function! s:f.renameBranchUnderCursor() dict abort + let l:branch = self.branchDetails('.') + if !l:branch.isLocal + throw 'Can not rename - not a local branch' + endif + let l:newName = input('Rename `'.l:branch.handle.'` to: ', l:branch.name) + echo ' ' + if empty(l:newName) + echom 'Branch rename canceled by user.' + return + elseif l:newName==l:branch.name + echom 'Branch name was not modified.' + return + endif + + call self.gitEcho('branch', '-m', l:branch.name, l:newName) + call self.refresh() +endfunction +call s:f.addCommand('renameBranchUnderCursor', [], 'MerginalRenameBranch', 'rn', 'Prompt to rename the branch under the cursor.') + diff --git a/vimfiles/autoload/merginal/buffers/cherryPickConflicts.vim b/vimfiles/autoload/merginal/buffers/cherryPickConflicts.vim new file mode 100644 index 0000000..f89b8a0 --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/cherryPickConflicts.vim @@ -0,0 +1,33 @@ +call merginal#modulelib#makeModule(s:, 'cherryPickConflicts', 'conflictsBase') + +function! s:f.generateHeader() dict abort + let l:currentCommit = readfile(self.repo.dir('ORIG_HEAD'))[0] + let l:currentCommitMessageLines = self.gitLines('log', '--format=%s', '-n1', l:currentCommit) + call insert(l:currentCommitMessageLines, '=== Reapplying: ===') + call add(l:currentCommitMessageLines, '===================') + call add(l:currentCommitMessageLines, '') + return l:currentCommitMessageLines +endfunction + +function! s:f.lastFileAdded() dict abort + let l:cherryPickConflictsBuffer = bufnr('') + Gstatus + let l:gitStatusBuffer = bufnr('') + execute bufwinnr(l:cherryPickConflictsBuffer).'wincmd w' + wincmd q + execute bufwinnr(l:gitStatusBuffer).'wincmd w' +endfunction + + +function! s:f.cherryPickAction(action) dict abort + call self.gitEcho('cherry-pick', '--'.a:action) + call merginal#reloadBuffers() + if self._getSpecialMode() == self.name + call self.refresh() + else + ""If we finished cherry-picking - close the cherry-pick conflicts buffer + wincmd q + endif +endfunction +call s:f.addCommand('cherryPickAction', ['abort'], 'MerginalAbort', 'ca', 'Abort the cherry-pick.') +call s:f.addCommand('cherryPickAction', ['continue'], 'MerginalContinue', 'cc', 'Continue to the next patch.') diff --git a/vimfiles/autoload/merginal/buffers/conflictsBase.vim b/vimfiles/autoload/merginal/buffers/conflictsBase.vim new file mode 100644 index 0000000..4b33a11 --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/conflictsBase.vim @@ -0,0 +1,61 @@ +call merginal#modulelib#makeModule(s:, 'conflictsBase', 'base') + +function! s:f.generateBody() dict abort + "Get the list of unmerged files: + let l:conflicts = self.gitLines('ls-files', '--unmerged') + + "Split by tab - the first part is info, the second is the file name + let l:conflicts = map(l:conflicts, 'split(v:val, "\t")') + + "Only take the stage 1 files - stage 2 and 3 are the same files with + "different hash, and we don't care about the hash here + let l:conflicts = filter(l:conflicts, 'v:val[0] =~ "\\v 1$"') + + "Take the file name - we no longer care about the info + let l:conflicts = map(l:conflicts, 'v:val[1]') + + "If the working copy is not the current dir, we can get wrong paths. + "We need to resolve that: + let l:conflicts = map(l:conflicts, 'self.repo.tree(v:val)') + + "Make the paths as short as possible: + let l:conflicts = map(l:conflicts, 'fnamemodify(v:val, ":~:.")') + + return l:conflicts +endfunction + +function! s:f.fileDetails(lineNumber) dict abort + call self.verifyLineInBody(a:lineNumber) + + let l:line = getline(a:lineNumber) + let l:result = {} + + let l:result.name = l:line + + return l:result +endfunction + + +function! s:f.openConflictedFileUnderCursor() dict abort + let l:file = self.fileDetails('.') + if empty(l:file.name) + return + endif + call merginal#openFileDecidedWindow(self.repo, l:file.name) +endfunction +call s:f.addCommand('openConflictedFileUnderCursor', [], 'MerginalOpen', '', 'Open the conflicted file under the cursor.') + +function! s:f.addConflictedFileToStagingArea() dict abort + let l:file = self.fileDetails('.') + if empty(l:file.name) + return + endif + + call self.gitEcho('add', fnamemodify(l:file.name, ':p')) + call self.refresh() + + if empty(self.body) "This means that was the last file + call self.lastFileAdded() + endif +endfunction +call s:f.addCommand('addConflictedFileToStagingArea', [], 'MerginalAddConflictedFileToStagingArea', ['aa' ,'A'], 'Add the conflicted file under the cursor to the staging area.') diff --git a/vimfiles/autoload/merginal/buffers/diffFiles.vim b/vimfiles/autoload/merginal/buffers/diffFiles.vim new file mode 100644 index 0000000..9f6507e --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/diffFiles.vim @@ -0,0 +1,116 @@ +call merginal#modulelib#makeModule(s:, 'diffFiles', 'base') + +function! s:f.init(diffTarget) dict abort + let self.diffTarget = a:diffTarget +endfunction + +function! s:f.generateHeader() dict abort + return [ + \ '=== Diffing With: ===', + \ self.diffTarget, + \ '=====================', + \ ''] +endfunction + +function! s:f.generateBody() dict abort + let l:diffFiles = self.gitLines('diff', '--name-status', self.diffTarget) + return l:diffFiles +endfunction + +function! s:f.diffFileDetails(lineNumber) dict abort + call self.verifyLineInBody(a:lineNumber) + + let l:line = getline(a:lineNumber) + let l:result = {} + + let l:matches = matchlist(l:line, '\v([ADM])\t(.*)$') + + if empty(l:matches) + throw 'Unable to get diff files details for `'.l:line.'`' + endif + + let l:result.isAdded = 0 + let l:result.isDeleted = 0 + let l:result.isModified = 0 + if 'A' == l:matches[1] + let l:result.type = 'added' + let l:result.isAdded = 1 + elseif 'D' == l:matches[1] + let l:result.type = 'deleted' + let l:result.isDeleted = 1 + else + let l:result.type = 'modified' + let l:result.isModified = 1 + endif + + let l:result.fileInTree = l:matches[2] + let l:result.fileFullPath = self.repo.tree(l:matches[2]) + + return l:result +endfunction + + +function! s:f.openDiffFileUnderCursor() dict abort + let l:diffFile = self.diffFileDetails('.') + + if l:diffFile.isDeleted + throw 'File does not exist in current buffer' + endif + + call merginal#openFileDecidedWindow(self.repo, l:diffFile.fileFullPath) +endfunction +call s:f.addCommand('openDiffFileUnderCursor', [], 'MerginalOpen', '', 'Open the file under the cursor (if it exists in the currently checked out branch).') + + +function! s:f.openDiffFileUnderCursorAndDiff(diffType) dict abort + if a:diffType!='s' && a:diffType!='v' + throw 'Bad diff type' + endif + + let l:diffFile = self.diffFileDetails('.') + + if l:diffFile.isAdded + throw 'File does not exist in other buffer' + endif + + "Close currently open git diffs + let l:currentWindowBuffer = winbufnr('.') + try + windo if 'blob' == get(b:,'fugitive_type','') && exists('w:fugitive_diff_restore') + \| bdelete + \| endif + catch + "do nothing + finally + execute bufwinnr(l:currentWindowBuffer).'wincmd w' + endtry + + call merginal#openFileDecidedWindow(self.repo, l:diffFile.fileFullPath) + + execute ':G'.a:diffType.'diff '.fnameescape(self.diffTarget) +endfunction +call s:f.addCommand('openDiffFileUnderCursorAndDiff', ['s'], 'MerginalDiff', 'ds', 'Split-diff against the file under the cursor (if it exists in the other branch)') +call s:f.addCommand('openDiffFileUnderCursorAndDiff', ['v'], 'MerginalVDiff', 'dv', 'VSplit-diff against the file under the cursor (if it exists in the other branch)') + + +function! s:f.checkoutDiffFileUnderCursor() dict abort + let l:diffFile = self.diffFileDetails('.') + + if l:diffFile.isAdded + throw 'File does not exist in diffed buffer' + endif + + let l:answer = 1 + if !empty(glob(l:diffFile.fileFullPath)) + let l:answer = 'yes' == input('Override `'.l:diffFile.fileInTree.'`? (type "yes" to confirm) ') + endif + if l:answer + call self.gitEcho('checkout', self.diffTarget, '--', l:diffFile.fileFullPath) + call merginal#reloadBuffers() + call self.refresh() + else + echo + echom 'File checkout canceled by user.' + endif +endfunction +call s:f.addCommand('checkoutDiffFileUnderCursor', [], 'MerginalCheckoutDiffFile', 'co', 'Check out the file under the cursor (if it exists in the other branch) into the current branch.') diff --git a/vimfiles/autoload/merginal/buffers/historyLog.vim b/vimfiles/autoload/merginal/buffers/historyLog.vim new file mode 100644 index 0000000..00bf409 --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/historyLog.vim @@ -0,0 +1,128 @@ +call merginal#modulelib#makeModule(s:, 'historyLog', 'base') + +function! s:f.init(branch) dict abort + let self.branch = a:branch +endfunction + +function! s:f.generateHeader() dict abort + return [ + \ '=== Showing History For: ===', + \ self.branch, + \ '============================', + \ ''] +endfunction + +function! s:f.generateBody() dict abort + let l:logLines = self.gitLines('log', '--format=%h %aN%n%ai%n%s%n', self.branch) + if empty(l:logLines[len(l:logLines) - 1]) + call remove(l:logLines, len(l:logLines) - 1) + endif + return l:logLines +endfunction + +function! s:f.getFilteredBody() dict abort + if empty(self.filter) + return copy(self.body) + endif + let l:result = [] + let l:lastBunch = [] + for l:line in self.body + if empty(l:line) + if 0 <= match(l:lastBunch, self.filter) + call extend(l:result, l:lastBunch) + endif + let l:lastBunch = [] + endif + call add(l:lastBunch, l:line) + endfor + if 0 <= match(l:lastBunch, self.filter) + call extend(l:result, l:lastBunch) + endif + if !empty(l:result) && l:result[0] == '' + call remove(l:result, 0) + endif + return l:result +endfunction + +function! s:f.commitHash(lineNumber) dict abort + call self.verifyLineInBody(a:lineNumber) + if type(0) == type(a:lineNumber) + let l:lineNumber = a:lineNumber + else + let l:lineNumber = line(a:lineNumber) + endif + while self.isLineInBody(l:lineNumber) && !empty(getline(l:lineNumber)) + let l:lineNumber -= 1 + endwhile + let l:lineNumber += 1 + return split(getline(l:lineNumber))[0] +endfunction + + +function! s:f.moveToNextOrPreviousCommit(direction) dict abort + let l:line = line('.') + + "Find the first line of the current commit + while !empty(getline(l:line - 1)) + let l:line -= 1 + endwhile + + "Find the first line of the next/prev commit + let l:line += a:direction + while !empty(getline(l:line - 1)) + let l:line += a:direction + endwhile + + if l:line <= 0 || line('$') <= l:line + "We reached past the first/last commit - go back! + let l:line -= a:direction + while !empty(getline(l:line - 1)) + let l:line -= a:direction + endwhile + endif + if self.isLineInBody(l:line) + execute l:line + endif +endfunction +call s:f.addCommand('moveToNextOrPreviousCommit', [-1], '', '', 'Move the cursor to the previous commit.') +call s:f.addCommand('moveToNextOrPreviousCommit', [1], '', '', 'Move the cursor to the next commit.') + +function! s:f.printCommitUnderCurosr(format) dict abort + let l:commitHash = self.commitHash('.') + "Not using self.gitEcho() because we are insterested in the result as more + "than just git command output. Also - using git-log with -1 instead of + "git-show because for some reason git-show ignores the --format flag... + echo join(self.gitLines('log', '-1', '--format='.a:format, l:commitHash), "\n") +endfunction +call s:f.addCommand('printCommitUnderCurosr', ['fuller'], 'MerginalShow', ['ss', 'S'], "Echo the commit details(using git's --format=fuller)") + +function! s:f.checkoutCommitUnderCurosr() dict abort + let l:commitHash = self.commitHash('.') + call self.gitEcho('checkout', l:commitHash) + call merginal#reloadBuffers() +endfunction +call s:f.addCommand('checkoutCommitUnderCurosr', [], 'MerginalCheckout', ['cc', 'C'], 'Checkout the commit under the cursor.') + +function! s:f.diffWithCommitUnderCursor() dict abort + let l:commitHash = self.commitHash('.') + call self.gotoBuffer('diffFiles', l:commitHash) +endfunction +call s:f.addCommand('diffWithCommitUnderCursor', [], 'MerginalDiff', 'gd', 'Open diff files buffer to diff against the commit under the cursor.') + +function! s:f.cherryPickCommitUnderCursor() dict abort + let l:commitHash = self.commitHash('.') + call self.gitEcho('cherry-pick', l:commitHash) + let l:confilctsBuffer = self.gotoSpecialModeBuffer() + if empty(l:confilctsBuffer) + call self.refresh() + else + if empty(l:confilctsBuffer.body) + "If we are in cherry-pick mode without actual conflicts, this + "means there are not conflicts and the user can be prompted to + "enter a cherry-pick message. + Gstatus + call merginal#closeMerginalBuffer() + endif + endif +endfunction +call s:f.addCommand('cherryPickCommitUnderCursor', [], 'MerginalCherryPick', 'cp', 'Cherry-pick the commit under the cursor') diff --git a/vimfiles/autoload/merginal/buffers/immutableBranchList.vim b/vimfiles/autoload/merginal/buffers/immutableBranchList.vim new file mode 100644 index 0000000..f0193b9 --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/immutableBranchList.vim @@ -0,0 +1,110 @@ +call merginal#modulelib#makeModule(s:, 'immutableBranchList', 'base') + +function! s:f.generateBody() dict abort + return self.gitLines('branch', '--all') +endfunction + +function! s:f.branchDetails(lineNumber) dict abort + call self.verifyLineInBody(a:lineNumber) + + let l:line = getline(a:lineNumber) + let l:result = {} + + "Check if this branch is the currently selected one + let l:result.isCurrent = ('*' == l:line[0]) + let l:line = l:line[2:] + + let l:detachedMatch = matchlist(l:line, '\v^\(detached from ([^/]+)%(/(.*))?\)$') + if !empty(l:detachedMatch) + let l:result.type = 'detached' + let l:result.isLocal = 0 + let l:result.isRemote = 0 + let l:result.isDetached = 1 + let l:result.remote = l:detachedMatch[1] + let l:result.name = l:detachedMatch[2] + if empty(l:detachedMatch[2]) + let l:result.handle = l:detachedMatch[1] + else + let l:result.handle = l:detachedMatch[1].'/'.l:detachedMatch[2] + endif + return l:result + endif + + let l:remoteMatch = matchlist(l:line,'\v^remotes/([^/]+)%(/(\S*))%( \-\> (\S+))?$') + if !empty(l:remoteMatch) + let l:result.type = 'remote' + let l:result.isLocal = 0 + let l:result.isRemote = 1 + let l:result.isDetached = 0 + let l:result.remote = l:remoteMatch[1] + let l:result.name = l:remoteMatch[2] + if empty(l:remoteMatch[2]) + let l:result.handle = l:remoteMatch[1] + else + let l:result.handle = l:remoteMatch[1].'/'.l:remoteMatch[2] + endif + return l:result + endif + + let l:result.type = 'local' + let l:result.isLocal = 1 + let l:result.isRemote = 0 + let l:result.isDetached = 0 + let l:result.remote = '' + let l:result.name = l:line + let l:result.handle = l:line + + return l:result +endfunction + +function! s:f.jumpToCurrentItem() dict abort + "Find the current branch's index + let l:currentBranchIndex = -1 + for l:i in range(len(self.body)) + if '*' == self.body[i][0] + let l:currentBranchIndex = l:i + break + endif + endfor + if -1 < l:currentBranchIndex + "Jump to the current branch's line + call self.jumpToIndexInBody(l:currentBranchIndex) + endif +endfunction + +function! s:f.getRemoteBranchTrackedByLocalBranch(localBranchName) dict abort + let l:result = self.gitLines('branch','--list',a:localBranchName,'-vv') + return matchstr(l:result, '\v\[\zs[^\[\]:]*\ze[\]:]') +endfunction + +function! s:f.getLocalBranchNamesThatTrackARemoteBranch(remoteBranchName) dict abort + "Get verbose list of branches + let l:branchList = self.gitLines('branch', '-vv') + + "Filter for branches that track our remote + let l:checkIfTrackingRegex = '\V['.escape(a:remoteBranchName, '\').'\[\]:]' + let l:branchList = filter(l:branchList, 'v:val =~ l:checkIfTrackingRegex') + + "Extract the branch name from the matching lines + let l:extractBranchNameRegex = '\v^\*?\s*\zs\S+' + let l:branchList = map(l:branchList, 'matchstr(v:val, l:extractBranchNameRegex)') + + return l:branchList +endfunction + + + + + +function! s:f.diffWithBranchUnderCursor() dict abort + let l:branch = self.branchDetails('.') + call self.gotoBuffer('diffFiles', l:branch.handle) +endfunction +call s:f.addCommand('diffWithBranchUnderCursor', [], 'MerginalDiff', 'gd', 'Open diff files buffer to diff against the branch under the cursor.') + +function! s:f.historyLogForBranchUnderCursor() dict abort + let l:branch = self.branchDetails('.') + call self.gotoBuffer('historyLog', l:branch.handle) +endfunction +call s:f.addCommand('historyLogForBranchUnderCursor', [], 'MerginalHistoryLog', 'gl', 'Open history log buffer to view the history of the branch under the cursor.') + diff --git a/vimfiles/autoload/merginal/buffers/mergeConflicts.vim b/vimfiles/autoload/merginal/buffers/mergeConflicts.vim new file mode 100644 index 0000000..5a6423e --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/mergeConflicts.vim @@ -0,0 +1,10 @@ +call merginal#modulelib#makeModule(s:, 'mergeConflicts', 'conflictsBase') + +function! s:f.lastFileAdded() dict abort + let l:mergeConflictsBuffer = bufnr('') + Gstatus + let l:gitStatusBuffer = bufnr('') + execute bufwinnr(l:mergeConflictsBuffer).'wincmd w' + wincmd q + execute bufwinnr(l:gitStatusBuffer).'wincmd w' +endfunction diff --git a/vimfiles/autoload/merginal/buffers/rebaseAmend.vim b/vimfiles/autoload/merginal/buffers/rebaseAmend.vim new file mode 100644 index 0000000..5a5713d --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/rebaseAmend.vim @@ -0,0 +1,34 @@ +call merginal#modulelib#makeModule(s:, 'rebaseAmend', 'immutableBranchList') + +function! s:f.generateHeader() dict abort + let l:amendedCommit = readfile(self.repo.dir('rebase-merge', 'amend')) + let l:amendedCommitShort = self.gitRun('rev-parse', '--short', l:amendedCommit[0]) + let l:amendedCommitShort = substitute(l:amendedCommitShort,'\v[\r\n]','','g') + let l:header = ['=== Amending '.l:amendedCommitShort.' ==='] + + let l:amendedCommitMessage=readfile(self.repo.dir('rebase-merge', 'message')) + let l:header += l:amendedCommitMessage + + call add(l:header,repeat('=', len(l:header[0]))) + call add(l:header, '') + + return l:header +endfunction + + +function! s:f.rebaseAction(action) dict abort + call self.gitEcho('rebase', '--'.a:action) + call merginal#reloadBuffers() + let l:mode = self._getSpecialMode() + if l:mode == self.name + call self.refresh() + elseif empty(l:mode) + "If we finished rebasing - close the rebase amend buffer + wincmd q + else + call self.gotoBuffer(l:mode) + endif +endfunction +call s:f.addCommand('rebaseAction', ['abort'], 'MerginalAbort', 'ra', 'Abort the rebase.') +call s:f.addCommand('rebaseAction', ['skip'], 'MerginalSkip', 'rs', 'Continue to the next patch.') +call s:f.addCommand('rebaseAction', ['continue'], 'MerginalContinue', 'rc', 'Skip the current patch') diff --git a/vimfiles/autoload/merginal/buffers/rebaseConflicts.vim b/vimfiles/autoload/merginal/buffers/rebaseConflicts.vim new file mode 100644 index 0000000..a22f086 --- /dev/null +++ b/vimfiles/autoload/merginal/buffers/rebaseConflicts.vim @@ -0,0 +1,37 @@ +call merginal#modulelib#makeModule(s:, 'rebaseConflicts', 'conflictsBase') + +function! s:f.generateHeader() dict abort + let l:currentCommit = readfile(self.repo.dir('ORIG_HEAD'))[0] + let l:currentCommitMessageLines = self.gitLines('log', '--format=%s', '-n1', l:currentCommit) + call insert(l:currentCommitMessageLines, '=== Reapplying: ===') + call add(l:currentCommitMessageLines, '===================') + call add(l:currentCommitMessageLines, '') + return l:currentCommitMessageLines +endfunction + +function! s:f.lastFileAdded() dict abort + echo 'Added the last file of this patch.' + echo 'Continue to the next patch (y/N)?' + let l:answer = getchar() + if char2nr('y') == l:answer || char2nr('Y') == l:answer + call self.rebaseAction('continue') + endif +endfunction + + +function! s:f.rebaseAction(action) dict abort + call self.gitEcho('rebase', '--'.a:action) + call merginal#reloadBuffers() + let l:mode = self._getSpecialMode() + if l:mode == self.name + call self.refresh() + elseif empty(l:mode) + "If we finished rebasing - close the rebase conflicts buffer + wincmd q + else + call self.gotoBuffer(l:mode) + endif +endfunction +call s:f.addCommand('rebaseAction', ['abort'], 'MerginalAbort', 'ra', 'Abort the rebase.') +call s:f.addCommand('rebaseAction', ['skip'], 'MerginalSkip', 'rs', 'Continue to the next patch.') +call s:f.addCommand('rebaseAction', ['continue'], 'MerginalContinue', 'rc', 'Skip the current patch') diff --git a/vimfiles/autoload/merginal/modulelib.vim b/vimfiles/autoload/merginal/modulelib.vim new file mode 100644 index 0000000..879aa3a --- /dev/null +++ b/vimfiles/autoload/merginal/modulelib.vim @@ -0,0 +1,87 @@ + +let s:f = {} +let s:modules = {} + +function! merginal#modulelib#makeModule(namespace, name, parent) + let s:modules[a:name] = a:namespace + let a:namespace.f = merginal#modulelib#prototype() + let a:namespace.moduleName = a:name + let a:namespace.parent = a:parent +endfunction + +function! s:populate(object, moduleName) + try + let l:module = s:modules[a:moduleName] + catch /Key not present in Dictionary/ + execute 'runtime autoload/merginal/buffers/'.a:moduleName.'.vim' + let l:module = s:modules[a:moduleName] + endtry + + if !empty(l:module.parent) + call s:populate(a:object, l:module.parent) + endif + + let l:f = l:module.f + + for l:k in keys(l:f) + if l:k != '_meta' && !has_key(s:f, l:k) + let a:object[l:k] = l:f[l:k] + endif + endfor + + call extend(a:object._meta, l:f._meta) +endfunction + +function! merginal#modulelib#createObject(moduleName) + let l:obj = {} + let l:obj.name = a:moduleName + let l:obj._meta = [] + call s:populate(l:obj, a:moduleName) + return l:obj +endfunction + +function! merginal#modulelib#prototype() + let l:prototype = copy(s:f) + let l:prototype._meta = [] + return l:prototype +endfunction + +function! s:f.new() dict abort + let l:obj = {} + for l:k in keys(self) + if !has_key(s:f, l:k) + let l:obj[l:k] = self[l:k] + endif + endfor + + return l:obj +endfunction + +function! s:f.addCommand(functionName, args, command, keymaps, doc) dict abort + let l:meta = {} + + let l:args = [] + for l:arg in a:args + call add(l:args, string(l:arg)) + endfor + let l:meta.execute = 'call b:merginal.'.a:functionName.'('.join(l:args, ', ').')' + + if !empty(a:command) + let l:meta.command = a:command + endif + + if empty(a:keymaps) + elseif type(a:keymaps) == type([]) + let l:meta.keymaps = a:keymaps + else + let l:meta.keymaps = [a:keymaps] + endif + + if !empty(a:doc) + let l:meta.doc = a:doc + endif + + "let self._meta[a:functionName] = l:meta + call add(self._meta, l:meta) +endfunction + diff --git a/vimfiles/autoload/merginal/util.vim b/vimfiles/autoload/merginal/util.vim new file mode 100644 index 0000000..dd012b6 --- /dev/null +++ b/vimfiles/autoload/merginal/util.vim @@ -0,0 +1,89 @@ +"Similar to Vim's inputlist, but adds numbers and a 'more' option for huge +"lists. If no options selected, returns -1(not 0 like inputlist!) +function! merginal#util#inputList(prompt, options, morePrompt) abort + let l:takeFrom = 0 + while l:takeFrom < len(a:options) + let l:takeThisTime = &lines - 2 + if l:takeFrom + l:takeThisTime < len(a:options) + let l:more = l:takeThisTime + let l:takeThisTime -= 1 + else + let l:more = 0 + endif + + let l:options = [a:prompt] + + for l:i in range(min([l:takeThisTime, len(a:options) - l:takeFrom])) + call add(l:options, printf('%i) %s', 1 + l:i, a:options[l:takeFrom + l:i])) + endfor + if l:more + call add(l:options, printf('%i) %s', l:more, a:morePrompt)) + endif + let l:selected = inputlist(l:options) + if l:selected <= 0 || len(l:options) <= l:selected + return -1 + elseif l:more && l:selected < l:more + return l:takeFrom + l:selected - 1 + elseif !l:more && l:selected < len(l:options) + return l:takeFrom + l:selected - 1 + endif + + "Create a new line for the next inputlist's prompt + echo ' ' + + let l:takeFrom += l:takeThisTime + endwhile +endfunction + +function! merginal#util#makeColumns(widths, texts) abort + let l:brokenToLines = [] + for l:i in range(len(a:texts)) + let l:text = a:texts[l:i] + let l:width = a:widths[l:i] + let l:lines = [] + let l:line = '' + let l:words = split(l:text, ' ') + for l:word in l:words + if l:width < len(l:line) + 1 + len(l:word) + if !empty(l:line) + call add(l:lines, l:line) + endif + while l:width < len(l:word) + call add(l:lines, l:word[:l:width - 1]) + let l:word = l:word[l:width :] + endwhile + let l:line = '' + endif + if !empty(l:line) + let l:line .= ' ' + endif + let l:line .= l:word + endfor + if !empty(l:line) + call add(l:lines, l:line) + endif + call add(l:brokenToLines, l:lines) + endfor + + let l:maxLength = max(map(copy(l:brokenToLines), 'len(v:val)')) + for l:lines in l:brokenToLines + while len(l:lines) < l:maxLength + call add(l:lines, '') + endwhile + endfor + + let l:result = [] + for l:i in range(l:maxLength) + let l:resultLine = '' + for l:j in range(len(l:brokenToLines)) + let l:width = a:widths[l:j] + let l:line = l:brokenToLines[l:j][l:i] + let l:resultLine .= l:line.repeat(' ', l:width - len(l:line)) + let l:resultLine .= ' ' + endfor + let l:resultLine = substitute(l:resultLine, '\v\s*$', '', '') + call add(l:result, l:resultLine) + endfor + + return l:result +endfunction diff --git a/vimfiles/autoload/tcomment.vim b/vimfiles/autoload/tcomment.vim index 34ff1e0..fa22231 100644 --- a/vimfiles/autoload/tcomment.vim +++ b/vimfiles/autoload/tcomment.vim @@ -2,8 +2,8 @@ " @Website: http://www.vim.org/account/profile.php?user_id=4037 " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 2007-09-17. -" @Last Change: 2014-06-25. -" @Revision: 1656 +" @Last Change: 2015-09-30. +" @Revision: 1781 " call tlog#Log('Load: '. expand('')) " vimtlib-sfile @@ -40,10 +40,14 @@ endif if !exists('g:tcommentOptions') " Other key-value options used by |tcomment#Comment()|. " - " Example: If you want to put the opening comment marker always in - " the first column regardless of the block's indentation, put this - " into your |vimrc| file: > + " Examples: + " Put the opening comment marker always in the first column + " regardless of the block's indentation, put this into your |vimrc| + " file: > " let g:tcommentOptions = {'col': 1} + " + " Indent uncommented lines: > + " let g:tcommentOptions = {'postprocess_uncomment': 'norm! %sgg=%sgg'} let g:tcommentOptions = {} "{{{2 endif @@ -111,9 +115,15 @@ endif if !exists("g:tcommentGuessFileType_eruby") let g:tcommentGuessFileType_eruby = 1 "{{{2 endif +if !exists("g:tcommentGuessFileType_jinja") + let g:tcommentGuessFileType_jinja = 'html' "{{{2 +endif if !exists("g:tcommentGuessFileType_smarty") let g:tcommentGuessFileType_smarty = 1 "{{{2 endif +if !exists("g:tcommentGuessFileType_rnoweb") + let g:tcommentGuessFileType_rnoweb = 'r' "{{{2 +endif if !exists("g:tcommentIgnoreTypes_php") " In php files, some syntax regions are wrongly highlighted as sql @@ -181,10 +191,10 @@ if !exists('g:tcomment#replacements_c') \ } endif -if !exists("g:tcommentInlineC") - " Generic c-like comments. - " :read: let g:tcommentInlineC = {...} "{{{2 - let g:tcommentInlineC = { +if !exists("g:tcommentLineC_fmt") + " Generic c-like block comments. + let g:tcommentLineC_fmt = { + \ 'commentstring_rx': '\%%(// %s\|/* %s */\)', \ 'commentstring': '/* %s */', \ 'rxbeg': '\*\+', \ 'rxend': '', @@ -192,10 +202,24 @@ if !exists("g:tcommentInlineC") \ 'replacements': g:tcomment#replacements_c \ } endif -if !exists("g:tcommentLineC") - " Generic c-like block comments. - let g:tcommentLineC = g:tcommentInlineC + + +function! tcomment#GetLineC(...) + let cmt = deepcopy(g:tcommentLineC_fmt) + if a:0 >= 1 + let cmt.commentstring = a:1 + endif + return cmt +endf + + +if !exists("g:tcommentInlineC") + " Generic c-like comments. + " :read: let g:tcommentInlineC = {...} "{{{2 + let g:tcommentInlineC = tcomment#GetLineC() endif + + if !exists("g:tcommentBlockC") let g:tcommentBlockC = { \ 'commentstring': '/*%s */', @@ -345,14 +369,18 @@ endf call tcomment#DefineType('aap', '# %s' ) call tcomment#DefineType('ada', '-- %s' ) +call tcomment#DefineType('autohotkey', '; %s' ) call tcomment#DefineType('apache', '# %s' ) +call tcomment#DefineType('applescript', '(* %s *)' ) +call tcomment#DefineType('applescript_block',"(*%s*)\n" ) +call tcomment#DefineType('applescript_inline','(* %s *)' ) call tcomment#DefineType('asciidoc', '// %s' ) call tcomment#DefineType('asm', '; %s' ) call tcomment#DefineType('asterisk', '; %s' ) call tcomment#DefineType('blade', '{{-- %s --}}' ) call tcomment#DefineType('blade_block', '{{-- %s --}}' ) call tcomment#DefineType('blade_inline', '{{-- %s --}}' ) -call tcomment#DefineType('c', g:tcommentLineC ) +call tcomment#DefineType('c', tcomment#GetLineC()) call tcomment#DefineType('c_block', g:tcommentBlockC ) call tcomment#DefineType('c_inline', g:tcommentInlineC ) call tcomment#DefineType('catalog', '-- %s --' ) @@ -368,9 +396,10 @@ call tcomment#DefineType('coffee', '# %s' ) call tcomment#DefineType('conf', '# %s' ) call tcomment#DefineType('context', '%% %s' ) call tcomment#DefineType('conkyrc', '# %s' ) -call tcomment#DefineType('cpp', '// %s' ) +call tcomment#DefineType('cpp', tcomment#GetLineC('// %s')) call tcomment#DefineType('cpp_block', g:tcommentBlockC ) call tcomment#DefineType('cpp_inline', g:tcommentInlineC ) +call tcomment#DefineType('cram', {'col': 1, 'commentstring': '# %s' }) call tcomment#DefineType('crontab', '# %s' ) call tcomment#DefineType('cs', '// %s' ) call tcomment#DefineType('cs_block', g:tcommentBlockC ) @@ -396,15 +425,17 @@ call tcomment#DefineType('erlang', '%%%% %s' ) call tcomment#DefineType('eruby', '<%%# %s' ) call tcomment#DefineType('esmtprc', '# %s' ) call tcomment#DefineType('expect', '# %s' ) +call tcomment#DefineType('fish', '# %s' ) call tcomment#DefineType('form', {'commentstring': '* %s', 'col': 1}) call tcomment#DefineType('fstab', '# %s' ) +call tcomment#DefineType('gitconfig', '# %s' ) call tcomment#DefineType('gitcommit', '# %s' ) call tcomment#DefineType('gitignore', '# %s' ) call tcomment#DefineType('gnuplot', '# %s' ) call tcomment#DefineType('go', '// %s' ) call tcomment#DefineType('go_block', g:tcommentBlockC ) call tcomment#DefineType('go_inline', g:tcommentInlineC ) -call tcomment#DefineType('groovy', '// %s' ) +call tcomment#DefineType('groovy', tcomment#GetLineC('// %s')) call tcomment#DefineType('groovy_block', g:tcommentBlockC ) call tcomment#DefineType('groovy_doc_block', g:tcommentBlockC2 ) call tcomment#DefineType('groovy_inline', g:tcommentInlineC ) @@ -425,24 +456,34 @@ call tcomment#DefineType('ini', '; %s' ) " php ini (/et call tcomment#DefineType('io', '// %s' ) call tcomment#DefineType('jade', '// %s' ) call tcomment#DefineType('jasmine', '# %s' ) -call tcomment#DefineType('java', '/* %s */' ) +call tcomment#DefineType('java', tcomment#GetLineC('// %s')) call tcomment#DefineType('java_block', g:tcommentBlockC ) call tcomment#DefineType('java_doc_block', g:tcommentBlockC2 ) call tcomment#DefineType('java_inline', g:tcommentInlineC ) -" call tcomment#DefineType('javaScript', '// %s' ) -" call tcomment#DefineType('javaScript_block', g:tcommentBlockC ) -" call tcomment#DefineType('javaScript_inline', g:tcommentInlineC ) -call tcomment#DefineType('javascript', '// %s' ) +call tcomment#DefineType('javascript', tcomment#GetLineC('// %s')) call tcomment#DefineType('javascript_block', g:tcommentBlockC ) call tcomment#DefineType('javascript_inline', g:tcommentInlineC ) +call tcomment#DefineType('jsx', '{/* %s */}') +call tcomment#DefineType('jsx_block', '{/* %s */}') +call tcomment#DefineType('jsx_inline', '{/* %s */}') +call tcomment#DefineType('jinja', '{# %s #}' ) +call tcomment#DefineType('jinja_block', "{%% comment %%}%s{%% endcomment %%}\n ") call tcomment#DefineType('jproperties', '# %s' ) +call tcomment#DefineType('lilypond', '%% %s' ) call tcomment#DefineType('lisp', '; %s' ) +call tcomment#DefineType('liquid', g:tcommentInlineXML) +call tcomment#DefineType('liquid_block', g:tcommentBlockXML ) +call tcomment#DefineType('liquid_inline', g:tcommentInlineXML) call tcomment#DefineType('lua', '-- %s' ) call tcomment#DefineType('lua_block', "--[[%s--]]\n" ) call tcomment#DefineType('lua_inline', '--[[%s --]]' ) call tcomment#DefineType('lynx', '# %s' ) call tcomment#DefineType('m4', 'dnl %s' ) call tcomment#DefineType('mail', '> %s' ) +call tcomment#DefineType('make', '# %s' ) +call tcomment#DefineType('markdown_block', "\n " ) +call tcomment#DefineType('markdown.pandoc', '' ) +call tcomment#DefineType('markdown.pandoc_block', "\n ") call tcomment#DefineType('matlab', '%% %s' ) call tcomment#DefineType('monkey', ''' %s' ) call tcomment#DefineType('msidl', '// %s' ) @@ -484,7 +525,10 @@ call tcomment#DefineType('rc', '// %s' ) call tcomment#DefineType('readline', '# %s' ) call tcomment#DefineType('remind', {'commentstring_rx': '\[;#] %s', 'commentstring': '# %s'}) call tcomment#DefineType('resolv', '# %s' ) +call tcomment#DefineType('robot', {'col': 1, 'commentstring': '# %s'}) call tcomment#DefineType('robots', '# %s' ) +call tcomment#DefineType('rust', tcomment#GetLineC('// %s')) +call tcomment#DefineType('rust_block', g:tcommentBlockC ) call tcomment#DefineType('ruby', '# %s' ) call tcomment#DefineType('ruby_3', '### %s' ) call tcomment#DefineType('ruby_block', "=begin rdoc%s=end") @@ -519,9 +563,12 @@ call tcomment#DefineType('sshdconfig', '# %s' ) call tcomment#DefineType('st', '" %s "' ) call tcomment#DefineType('tcl', '# %s' ) call tcomment#DefineType('tex', '%% %s' ) +call tcomment#DefineType('toml', '# %s' ) call tcomment#DefineType('tpl', '' ) +call tcomment#DefineType('tup', '# %s' ) call tcomment#DefineType('typoscript', '# %s' ) call tcomment#DefineType('upstart', '# %s' ) +call tcomment#DefineType('vader', {'col': 1, 'commentstring': '" %s' }) call tcomment#DefineType('vhdl', '-- %s' ) call tcomment#DefineType('verilog', '// %s' ) call tcomment#DefineType('verilog_inline', g:tcommentInlineC ) @@ -569,6 +616,21 @@ function! s:DefaultValue(option) endf +function! s:Count(string, rx) + return len(split(a:string, a:rx, 1)) - 1 +endf + + +function! s:Printf1(fmt, expr) + let n = s:Count(a:fmt, '%\@= 1 ? a:1 : 'G'), g:tcommentModeExtra, a:beg, a:end) let comment_mode = comment_mode0 let comment_anyway = a:0 >= 2 ? (a:2 == '!') : 0 - " TLogVAR a:beg, a:end, comment_mode, comment_anyway + " TLogVAR a:beg, a:end, comment_mode, comment_anyway, a:000 " save the cursor position if exists('w:tcomment_pos') let s:current_pos = copy(w:tcomment_pos) @@ -656,11 +722,7 @@ function! tcomment#Comment(beg, end, ...) let [lbeg, cbeg, lend, cend] = s:GetStartEnd(a:beg, a:end, comment_mode) " TLogVAR lbeg, cbeg, lend, cend, virtcol('$') if comment_mode ==? 'I' && comment_mode0 =~# 'i' && lbeg == lend && cend >= virtcol('$') - 1 - if cbeg <= 1 - let comment_mode = 'G' - else - let comment_mode = 'R' - endif + let comment_mode = substitute(comment_mode, '\CI', cbeg <= 1 ? 'G' : 'R', 'g') " TLogVAR comment_mode endif let mode_extra = s:GetTempOption('mode_extra', '') @@ -696,7 +758,8 @@ function! tcomment#Comment(beg, end, ...) endif " TLogVAR ax, a:0, a:000 if a:0 >= ax - let cdef = extend(cdef, s:ParseArgs(lbeg, lend, comment_mode, a:000[ax - 1 : -1])) + " let cdef = extend(cdef, s:ParseArgs(lbeg, lend, comment_mode, a:000[ax - 1 : -1])) + let cdef = s:ExtendCDef(lbeg, lend, comment_mode, cdef, s:ParseArgs(lbeg, lend, comment_mode, a:000[ax - 1 : -1])) " TLogVAR 5, cdef endif if !empty(get(cdef, 'begin', '')) || !empty(get(cdef, 'end', '')) @@ -734,26 +797,39 @@ function! tcomment#Comment(beg, end, ...) let cmt_check = substitute(cms0, '\([ ]\)', '\1\\?', 'g') "" turn commentstring into a search pattern " TLogVAR cmt_check - let cmt_check = printf(cmt_check, '\(\_.\{-}\)') + let cmt_check = s:Printf1(cmt_check, '\(\_.\{-}\)') " TLogVAR cdef, cmt_check let s:cdef = cdef " set comment_mode + " TLogVAR comment_mode let [lbeg, lend, uncomment] = s:CommentDef(lbeg, lend, cmt_check, comment_mode, cbeg, cend) - " TLogVAR lbeg, lend, cbeg, cend, uncomment - " echom "DBG" string(s:cdef) - let cbeg = get(s:cdef, 'col', cbeg) - " TLogVAR cbeg - if mode_extra =~# 'U' - let uncomment = 1 - elseif mode_extra =~# 'C' || comment_anyway - let uncomment = 0 + " TLogVAR lbeg, lend, cbeg, cend, uncomment, comment_mode, comment_anyway + if uncomment + if comment_mode =~# 'C' || comment_anyway + let comment_do = 'c' + else + let comment_do = 'u' + endif + else + if comment_mode =~# 'U' + let comment_do = 'u' + elseif comment_mode =~# 'K' + let comment_do = 'k' + else + let comment_do = 'c' + endif endif - " TLogVAR comment_anyway, mode_extra, uncomment + " TLogVAR comment_anyway, comment_mode, mode_extra, comment_do + " " echom "DBG" string(s:cdef) + if comment_do ==# 'c' + let cbeg = get(s:cdef, 'col', cbeg) + endif + " TLogVAR cbeg " go " TLogVAR comment_mode if comment_mode =~# 'B' " We want a comment block - call s:CommentBlock(lbeg, lend, cbeg, cend, comment_mode, uncomment, cmt_check, s:cdef) + call s:CommentBlock(lbeg, lend, cbeg, cend, comment_mode, comment_do, cmt_check, s:cdef) else " We want commented lines " final search pattern for uncommenting @@ -791,18 +867,28 @@ function! tcomment#Comment(beg, end, ...) endif endif if !empty(lmatch) - let part1 = s:ProcessLine(uncomment, lmatch[2], cmt_check, cmt_replace) - " TLogVAR part1 - let line1 = lmatch[1] . part1 . lmatch[4] - if uncomment && g:tcomment#rstrip_on_uncomment > 0 - if g:tcomment#rstrip_on_uncomment == 2 || line1 !~ '\S' - let line1 = substitute(line1, '\s\+$', '', '') + let [part1, ok] = s:ProcessLine(comment_do, lmatch[2], cmt_check, cmt_replace) + " TLogVAR part1, ok + if ok + let line1 = lmatch[1] . part1 . lmatch[4] + if comment_do ==# 'u' + if g:tcomment#rstrip_on_uncomment > 0 + if g:tcomment#rstrip_on_uncomment == 2 || line1 !~ '\S' + let line1 = substitute(line1, '\s\+$', '', '') + endif + endif endif + " TLogVAR line1 + call setline(lnum, line1) endif - " TLogVAR line1 - call setline(lnum, line1) endif endfor + if comment_do ==# 'u' + let postprocess_uncomment = get(cdef, 'postprocess_uncomment', '') + if !empty(postprocess_uncomment) + exec printf(postprocess_uncomment, lbeg, lend) + endif + endif endif " reposition cursor " TLogVAR 3, comment_mode @@ -839,6 +925,20 @@ else endif +function! tcomment#MaybeReuseOptions(name) "{{{3 + if exists('s:options_cache') && get(s:options_cache, 'name', '') == a:name + if exists('s:temp_options') + let s:temp_options = extend(deepcopy(s:options_cache.options), s:temp_options) + let s:options_cache = {'name': a:name, 'options': s:temp_options} + else + let s:temp_options = deepcopy(s:options_cache.options) + endif + elseif exists('s:temp_options') + let s:options_cache = {'name': a:name, 'options': s:temp_options} + endif +endf + + function! s:GetTempOption(name, default) "{{{3 if exists('s:temp_options') && has_key(s:temp_options, a:name) return s:temp_options[a:name] @@ -848,6 +948,11 @@ function! s:GetTempOption(name, default) "{{{3 endf +function! tcomment#ResetOption() "{{{3 + unlet! s:temp_options s:options_cache +endf + + function! tcomment#SetOption(name, arg) "{{{3 " TLogVAR a:name, a:arg if !exists('s:temp_options') @@ -1012,15 +1117,27 @@ endf function! s:ExtendCDef(beg, end, comment_mode, cdef, args) for [key, value] in items(a:args) + " TLogVAR key, value if key == 'as' call extend(a:cdef, s:GetCommentDefinitionForType(a:beg, a:end, a:comment_mode, value)) elseif key == 'mode' - let a:cdef[key] = a:comment_mode . value + " let a:cdef[key] = a:comment_mode . value + let a:cdef.mode = s:AddModeExtra(a:comment_mode, value, a:beg, a:end) + elseif key == 'mode_extra' + if has_key(a:cdef, 'mode') + let mode = s:AddModeExtra(a:comment_mode, a:cdef.mode, a:beg, a:end) + " TLogVAR 'mode', mode + else + let mode = a:comment_mode + " TLogVAR 'mode == comment_mode', mode + endif + let a:cdef.mode = s:AddModeExtra(mode, value, a:beg, a:end) elseif key == 'count' let a:cdef[key] = str2nr(value) else let a:cdef[key] = value endif + " TLogVAR get(a:cdef, 'comment_mode', '') endfor return a:cdef endf @@ -1228,7 +1345,7 @@ endf " s:GetCommentDefinition(beg, end, comment_mode, ?filetype="") function! s:GetCommentDefinition(beg, end, comment_mode, ...) let ft = a:0 >= 1 ? a:1 : '' - " TLogVAR ft + " TLogVAR a:comment_mode, ft if ft != '' let cdef = s:GuessCustomCommentString(ft, a:comment_mode) else @@ -1342,75 +1459,97 @@ function! s:CommentDef(beg, end, checkRx, comment_mode, cbeg, cend) " TLogVAR a:beg, a:end, a:checkRx, a:comment_mode, a:cbeg, a:cend let beg = a:beg let end = a:end - if get(s:cdef, 'mixedindent', 1) - let mdrx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) .'\s\*' - let mdrx .= s:StartColRx(a:comment_mode, a:cbeg + 1, 0) .'\s\*' + if a:comment_mode =~# 'U' + let uncomment = 1 + elseif a:comment_mode =~# '[CK]' + let uncomment = 0 else - let mdrx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) .'\s\*' - endif - let mdrx .= a:checkRx .'\s\*'. s:EndColRx(a:comment_mode, a:end, 0) - " let mdrx = '\V'. s:StartPosRx(a:comment_mode, beg, a:cbeg) .'\s\*'. a:checkRx .'\s\*'. s:EndPosRx(a:comment_mode, end, 0) - " TLogVAR mdrx - let line = getline(beg) - if a:cbeg != 0 && a:cend != 0 - let line = strpart(line, 0, a:cend - 1) - endif - let uncomment = (line =~ mdrx) - " TLogVAR 1, uncomment, line - let n = beg + 1 - if a:comment_mode =~# 'G' - if uncomment - while n <= end - if getline(n) =~ '\S' - if !(getline(n) =~ mdrx) - let uncomment = 0 - " TLogVAR 2, uncomment - break + if get(s:cdef, 'mixedindent', 1) + let mdrx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) .'\s\*' + let mdrx .= s:StartColRx(a:comment_mode, a:cbeg + 1, 0) .'\s\*' + else + let mdrx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) .'\s\*' + endif + let mdrx .= a:checkRx .'\s\*'. s:EndColRx(a:comment_mode, a:end, 0) + " let mdrx = '\V'. s:StartPosRx(a:comment_mode, beg, a:cbeg) .'\s\*'. a:checkRx .'\s\*'. s:EndPosRx(a:comment_mode, end, 0) + " TLogVAR mdrx + let line = getline(beg) + if a:cbeg != 0 && a:cend != 0 + let line = strpart(line, 0, a:cend - 1) + endif + let uncomment = (line =~ mdrx) + " TLogVAR 1, uncomment, line + let n = beg + 1 + if a:comment_mode =~# 'G' + if uncomment + while n <= end + if getline(n) =~ '\S' + if !(getline(n) =~ mdrx) + let uncomment = 0 + " TLogVAR 2, uncomment + break + endif + endif + let n = n + 1 + endwh + endif + elseif a:comment_mode =~# 'B' + let t = @t + try + silent exec 'norm! '. beg.'G1|v'.end.'G$"ty' + if &selection == 'inclusive' && @t =~ '\n$' && len(@t) > 1 + let @t = @t[0 : -2] + endif + " TLogVAR @t, mdrx + let uncomment = (@t =~ mdrx) + " TLogVAR 3, uncomment + if !uncomment && a:comment_mode =~ 'o' + let mdrx1 = substitute(mdrx, '\\$$', '\\n\\$', '') + " TLogVAR mdrx1 + if @t =~ mdrx1 + let uncomment = 1 + " TLogVAR 4, uncomment endif endif - let n = n + 1 - endwh + finally + let @t = t + endtry endif - elseif a:comment_mode =~# 'B' - let t = @t - try - silent exec 'norm! '. beg.'G1|v'.end.'G$"ty' - if &selection == 'inclusive' && @t =~ '\n$' && len(@t) > 1 - let @t = @t[0 : -2] - endif - " TLogVAR @t, mdrx - let uncomment = (@t =~ mdrx) - " TLogVAR 3, uncomment - if !uncomment && a:comment_mode =~ 'o' - let mdrx1 = substitute(mdrx, '\\$$', '\\n\\$', '') - " TLogVAR mdrx1 - if @t =~ mdrx1 - let uncomment = 1 - " TLogVAR 4, uncomment - endif - endif - finally - let @t = t - endtry endif - " TLogVAR 5, uncomment + " TLogVAR 5, beg, end, uncomment return [beg, end, uncomment] endf -function! s:ProcessLine(uncomment, match, checkRx, replace) - " TLogVAR a:uncomment, a:match, a:checkRx, a:replace +function! s:ProcessLine(comment_do, match, checkRx, replace) + " TLogVAR a:comment_do, a:match, a:checkRx, a:replace try if !(g:tcomment#blank_lines > 0 || a:match =~ '\S') return a:match endif - if a:uncomment - let rv = substitute(a:match, a:checkRx, '\1\2', '') + if a:comment_do ==# 'k' + if a:match =~ a:checkRx + return ['', 0] + endif + endif + if a:comment_do ==# 'u' + let m = matchlist(a:match, a:checkRx) + if !empty(m) + for irx in range(2, s:Count(a:checkRx, '\\\@= 1 && a:1 != '' let cdef = s:GuessCustomCommentString(a:1, a:comment_mode) @@ -1727,10 +1865,12 @@ function! s:GuessFileType(beg, end, comment_mode, filetype, ...) let n = beg " TLogVAR n, beg, end while n <= end - let m = indent(n) + 1 let text = getline(n) - let le = len(text) - " TLogVAR m, le + let indentstring = matchstr(text, '^\s*') + let m = strwidth(indentstring) + " let m = indent(n) + 1 + let le = strwidth(text) + " TLogVAR n, m, le while m <= le let syntax_name = s:GetSyntaxName(n, m) " TLogVAR syntax_name, n, m @@ -1805,6 +1945,7 @@ endf function! s:AddModeExtra(comment_mode, extra, beg, end) "{{{3 + " TLogVAR a:comment_mode, a:extra if a:beg == a:end let extra = substitute(a:extra, '\C[B]', '', 'g') else @@ -1817,6 +1958,9 @@ function! s:AddModeExtra(comment_mode, extra, beg, end) "{{{3 if extra =~# '[IR]' let comment_mode = substitute(comment_mode, '\c[gb]', '', 'g') endif + if extra =~# '[BLIRK]' && comment_mode =~# 'G' + let comment_mode = substitute(comment_mode, '\c[G]', '', 'g') + endif let rv = comment_mode . extra " TLogVAR a:comment_mode, a:extra, comment_mode, extra, rv return rv @@ -1825,20 +1969,20 @@ endf function! s:GuessCommentMode(comment_mode, supported_comment_modes) "{{{3 " TLogVAR a:comment_mode, a:supported_comment_modes + let special = substitute(a:comment_mode, '\c[^ukc]', '', 'g') let cmode = tolower(a:comment_mode) let ccmodes = split(tolower(a:supported_comment_modes), '\zs') let ccmodes = filter(ccmodes, 'stridx(cmode, v:val) != -1') let guess = substitute(a:comment_mode, '\w\+', 'G', 'g') " TLogVAR ccmodes, guess if a:comment_mode =~# '[BR]' - return !empty(ccmodes) ? a:comment_mode : guess + let rv = !empty(ccmodes) ? a:comment_mode : guess elseif a:comment_mode =~# '[I]' - return !empty(ccmodes) ? a:comment_mode : '' - " elseif a:comment_mode =~# '[R]' && !empty(ccmodes) - " return a:comment_mode + let rv = !empty(ccmodes) ? a:comment_mode : '' else - return guess + let rv = guess endif + return s:AddModeExtra(rv, special, 0, 1) endf diff --git a/vimfiles/doc/SrchRplcHiGrp.txt b/vimfiles/doc/SrchRplcHiGrp.txt index 081d3ec..4d4fc9d 100644 --- a/vimfiles/doc/SrchRplcHiGrp.txt +++ b/vimfiles/doc/SrchRplcHiGrp.txt @@ -1,209 +1,254 @@ -*SrchRplcHiGrp.txt* Search and Replace Restricted to a Highlighting Group - -Author: David Fishburn January 1, 2011 - - -============================================================================== -1. Contents *srchrplchigrp* *srchrplchigrp-contents* - - 1. Contents......................: |srchrplchigrp-contents| - 2. Commands......................: |srchrplchigrp-commands| - SR............................: |SR| - SRDispHiGrp...................: |SRDispHiGrp| - SRChooseHiGrp.................: |SRChooseHiGrp| - SRHiGrp.......................: |SRHiGrp| - 3. Examples......................: |srchrplchigrp-examples| - - -============================================================================== -2. Commands *srchrplchigrp-commands* - - SR = Search and Replace *SR* - - SRDispHiGrp *SRDispHiGrp* - Displays the syntax id and name the of the syntax group - which has been chosen. - - SRChooseHiGrp[!] *SRChooseHiGrp* - Before you can run the search and replace command (:SRHiGrp), - you must choose which syntax group id you want to operate on. - The top level syntax id of the current cursor position is - chosen (ie. the top-level one versus the final one). - - The optional bang lets SRChooseHiGrp use the translated - syntax ID. This is final one versus the top-level one. - - Assuming we were using a SQL file and placed the cursor on the - FROM word, then using the SyntaxAttr plugin - (http://vim.sourceforge.net/script.php?script_id=383) - it displays both the top-level and translated - (or final) highlight group as follows: > - group: sqlKeyword->Statement guifg=#ffff00(#ffff00) -< - - Examples: > - :SRChooseHiGrp -< Will operate on only sqlKeyword syntax groups -> - :SRChooseHiGrp! -< Will operate on all Statement syntax groups. Based on - |group-name|, the Statement group will highlight the - same color for the following highlight groups: - Conditional - Repeat - Label - Operator - Keyword - Exception - Therefore SRChooseHiGrp! will operate over all of the - above syntax groups. - - SRSearch *SRSearch* - This command will perform a forward search starting at the current - cursor position for a specified highlight group name. The range defaults - to the entire file. It supports all visual modes, characterwise (v), - linewise (V) and blockwise (). - - It optionally takes takes one parameter. You can supply a hightlight - group name: > - :SRSearch Statement -< - The command supports highlight group name completion. > - :SRSearch C -< Depending on which syntax groups are defined (given your filetype and - various plugins) this will cycle through all highlight group names - beginning with the letter 'C'. - - Alternatively, you can use the SRChooseHiGrp or SRChooseHiGrp! - command to select the highlight group. Running SRSearch - without a parameter will check if a valid group name was - selected via SRChooseHiGrp and begin the search. If no valid - group name was specified, an error message will be reported. - - Running SRSearch a second time will ensure the cursor is - positioned on the next separate highlight matched text. - There must be a gap between the two groups. - - SRHiGrp[!] *SRHiGrp* - This command will perform a search and replace over a visual - range. It works in all visual modes, characterwise (v), - linewise (V) and blockwise (). - - It optionally takes takes 2 parameters. - - Parameter 1 controls what characters are matched. The default - for this value is \(\w\+\>\). This expression is appended to - the \%# which starts the match from the current cursor - position. This expression must specify a submatch \(...\). - - Parameter 2 controls what to do with the matched string. The - default for this value is \U\1. This expression will cause - the matched string to be UPPER cased. The \1 refers to the - submatch from the first parameter. - - If the parameters are not supplied, the user will be prompted - to enter the expression(s). - - The optional bang (!) works the same as SRHiGrp, but will - operate on all syntax groups that are NOT the chosen one - (SRChooseHiGrp). - - Syntax: > - [range]SRHiGrp[!] 'from-pattern','to-string' -< -============================================================================== -3. Examples *srchrplchigrp-examples* - - SRHiGrp - ------- - - First place your cursor on an item that is syntax colored the way - you want. Notice the command takes an optional !. If your first - search and replace doesn't work, you can undo the change and reselect - the group using the ! and try again. -> - :SRChooseHiGrp - SRHiGrp - Group ID: 562 Name: sqlStatement - or - :SRChooseHiGrp! - SRHiGrp - Group ID: 51 Name: Statement -< - Next, visually select a block of text - (all visual modes are supported) -> - :SRHiGrp - or - :SRHiGrp '\(\w\+\>\)' - or - :SRHiGrp '\(\w\+\>\)', '\U\1' -< - If you had the following in a SQL file: -> - if exists( select 1 - from sys.sysprocedure sp - key join sys.sysuserperm sup - where sp.proc_name = 'sp_http_course_detail' - and sup.user_name = user_name() ) then - drop procedure sp_http_course_detail; - end if; -< - Where the keywords (if, exists, select, from ...) are all - highlighted yellow (based on my colorscheme). After I visually - select the area and run the command taking default prompts: -> - :'<,'>SRHiGrp -< - The result is: -> - IF EXISTS( SELECT 1 - FROM sys.sysprocedure sp - KEY JOIN sys.sysuserperm sup - WHERE sp.proc_name = 'sp_http_course_detail' - AND sup.user_name = user_name() ) THEN - DROP PROCEDURE sp_http_course_detail; - END IF; -< - Where the keywords (if, exists, select, from ...) are all - highlighted yellow (based on my colorscheme). After I visually - select the area and run the command taking default prompts: > - - :'<,'>SRHiGrp! -< - The result is: -> - if exists( select 1 - from SYS.SYSPROCEDURE SP - key join SYS.SYSUSERPERM SUP - where SP.PROC_NAME = 'SP_HTTP_COURSE_DETAIL' - and SUP.USER_NAME = USER_NAME() ) then - drop procedure SP_HTTP_COURSE_DETAIL; - end if; -< - - SRSearch - -------- - - SRSearch simply does a forward search for the specified highlight - group. A few examples: > - :SRSearch sqlKeyword - :1,5SRSearch sqlKeyword - :'<,'>SRSearch sqlKeyword -< - Optionally, you can first choose the hightlight group by placing your - cursor on the highlight you want and: > - :SRChooseHiGrp - :SRSearch -< - Using Vim's tab completion you can also: > - :SRSearch s -< - Each time you press tab, it will cycle through the currently defined - syntax highlight groups beginning with the letter 's'. - - The results of the search is displayed in the command line and is - highlighted in the color of the syntax group. This will remind you - which group was searched for. > - SRSearch - Match found - Group ID: 171 Name: sqlKeyword - SRSearch - Match NOT found - Group ID: 171 Name: sqlKeyword -< -vim:tw=78:ts=8:ft=help:norl: +*SrchRplcHiGrp.txt* Search and Replace Restricted to a Highlighting Group + +Author: David Fishburn August 25, 2015 + + +============================================================================== +1. Contents *srchrplchigrp* *srchrplchigrp-contents* + + 1. Contents......................: |srchrplchigrp-contents| + 2. Commands......................: |srchrplchigrp-commands| + SR............................: |SR| + SRDispHiGrp...................: |SRDispHiGrp| + SRChooseHiGrp.................: |SRChooseHiGrp| + SRHiGrp.......................: |SRHiGrp| + 3. Examples......................: |srchrplchigrp-examples| + 4. History.......................: |srchrplchigrp-history| + + +============================================================================== +2. Commands *srchrplchigrp-commands* + + SR = Search and Replace *SR* + + SRDispHiGrp *SRDispHiGrp* + Displays the syntax id and name the of the syntax group + which has been chosen. + + SRChooseHiGrp[!][id] *SRChooseHiGrp* + Before you can run the search and replace command (:SRHiGrp), + you must choose which syntax group id you want to operate on. + The top level syntax id of the current cursor position is + chosen (ie. the top-level one versus the final one). + + The optional bang lets SRChooseHiGrp use the translated + syntax ID. This is final one versus the top-level one. + + Assuming we were using a SQL file and placed the cursor on any + word in a Comment section. Typically SQL comments can use any + of these formats: + -- This is a comment + + // This is also a comment + + /* + * This is a multi + * line comment + */ + + + Examples: > + :SRChooseHiGrp +< SRHiGrp - Group ID: 497 Name: sqlDashComment + + Will operate on only sqlDashComment syntax groups +> + :SRChooseHiGrp! +< SRHiGrp - Group ID: 46 Name: Comment + + Will operate on all Comment syntax groups. Looking + at the syntax file for this we see: > + hi def link sqlDashComment Comment + hi def link sqlSlashComment Comment + hi def link sqlMultiComment Comment +< + Therefore SRChooseHiGrp! will operate over all of the + above syntax groups: > + sqlDashComment + sqlSlashComment + sqlMultiComment +> + :SRChooseHiGrp 46 +< SRHiGrp - Group ID: 46 Name: Comment + + Instead of choosing the syntax group the cursor is on + this allows you to programmatically choose the exact + group id you want. + + SRSearch[!] *SRSearch* + This command will perform a forward search starting at the current + cursor position for text in the specified highlight group + name. The range defaults to the entire file. It supports all + visual modes, characterwise (v), linewise (V) and blockwise + (). First choose a highlight group using SRChooseHiGrp. + Providing no arguments will search until it finds text + highlighted in that syntax. > + :SRSearch +< + Using the bang (!) it will search for the next text that is + not using the syntax group: > + :SRSearch! +< + It optionally takes takes a regex parameter. You can supply a hightlight + group name: > + :SRSearch some text + :SRSearch \(first\|second\|word\) +< + Running SRSearch a second time will ensure the cursor is + positioned on the next separate highlight matched text. + There must be a gap between the two groups. + + SRHiGrp[!] *SRHiGrp* + This command will perform a search and replace over a range. + The range defaults to the entire file. It works in all visual + modes, characterwise (v), linewise (V) and blockwise (). + + It optionally takes takes 2 parameters. + + Parameter 1 controls what characters are matched. The default + for this value is \(\w\+\>\). This expression is appended to + the \%# which starts the match from the current cursor + position. This expression must specify a submatch \(...\). + + Parameter 2 controls what to do with the matched string. The + default for this value is \U\1. This expression will cause + the matched string to be UPPER cased. The \1 refers to the + submatch from the first parameter. + + If the parameters are not supplied, the user will be prompted + to enter the expression(s). + + The optional bang (!) works the same as SRHiGrp, but will + operate on all syntax groups that are NOT the chosen one + (SRChooseHiGrp). + + Syntax: > + [range]SRHiGrp[!] 'from-pattern','to-string' +< +============================================================================== +3. Examples *srchrplchigrp-examples* + + SRHiGrp + ------- + + First place your cursor on an item that is syntax colored the way + you want. Notice the command takes an optional !. If your first + search and replace doesn't work, you can undo the change and reselect + the group using the ! and try again. +> + :SRChooseHiGrp + SRHiGrp - Group ID: 562 Name: sqlStatement + or + :SRChooseHiGrp! + SRHiGrp - Group ID: 51 Name: Statement +< + Next, visually select a block of text + (all visual modes are supported) +> + :SRHiGrp + or + :SRHiGrp '\(\w\+\>\)' + or + :SRHiGrp '\(\w\+\>\)', '\U\1' +< + If you had the following in a SQL file: +> + if exists( select 1 + from sys.sysprocedure sp + key join sys.sysuserperm sup + where sp.proc_name = 'sp_http_course_detail' + and sup.user_name = user_name() ) then + drop procedure sp_http_course_detail; + end if; +< + Where the keywords (if, exists, select, from ...) are all + highlighted yellow (based on my colorscheme). After I visually + select the area and run the command taking default prompts: +> + :'<,'>SRHiGrp +< + The result is: +> + IF EXISTS( SELECT 1 + FROM sys.sysprocedure sp + KEY JOIN sys.sysuserperm sup + WHERE sp.proc_name = 'sp_http_course_detail' + AND sup.user_name = user_name() ) THEN + DROP PROCEDURE sp_http_course_detail; + END IF; +< + Where the keywords (if, exists, select, from ...) are all + highlighted yellow (based on my colorscheme). After I visually + select the area and run the command taking default prompts: > + + :'<,'>SRHiGrp! +< + The result is: +> + if exists( select 1 + from SYS.SYSPROCEDURE SP + key join SYS.SYSUSERPERM SUP + where SP.PROC_NAME = 'SP_HTTP_COURSE_DETAIL' + and SUP.USER_NAME = USER_NAME() ) then + drop procedure SP_HTTP_COURSE_DETAIL; + end if; +< + + SRSearch + -------- + + SRSearch simply does a forward search for the specified highlight + group. You must first use SRChooseHiGrp to choose a highlight group. + Find the next item highlighted as that syntax group: > + :SRSearch + :1,5SRSearch + :'<,'>SRSearch +< + Find the next item highlighted that is NOT that syntax group: > + :SRSearch! + :1,5SRSearch! + :'<,'>SRSearch! +< + Find the next item highlighted as that syntax group and matches + the regular expression supplied: > + :SRSearch something + :SRSearch \(first\|second\|word\) +< + Find the next item highlighted that is NOT that syntax group and + matches the regular expression supplied: > + :SRSearch! \(first\|second\|word\) +< + The results of the search is displayed in the command line and is + highlighted in the color of the syntax group. This will remind you + which group was searched for. > + SRSearch - Match found - Group ID: 171 Name: sqlKeyword + SRSearch - Match NOT found - Group ID: 171 Name: sqlKeyword + SRSearch - Match found - Group ID: 171 Name: sqlKeyword Regex: \(first\|second\|word\) + SRSearch - Match NOT found - Group ID: 171 Name: sqlKeyword Regex \(first\|second\|word\) +< +============================================================================== +4. History *srchrplchigrp-history* + + Version 7 (August 25, 2015) + - Changed SRSeach. It will first look for the next item that has + the syntax group chosen via SRChooseHiGrp. + It will also take an optional regular expression and not only find + that syntax group, but also match the regular expression. + Added SRSearch!, which will find the next item that is NOT what + was chosen via SRChooseHiGrp. Same applied with the regular + expression, so if I put my cursor on a comment and :SRChooseHiGrp. + Then ran :SRSearch! something, it will find the word "something" + that is NOT in a comment. + + + + Version 6 (July 27, 2015) + - Changed to save and restore cp options on load + - Changed to use Vim's autoload mechanism to load only when + required (speeds Vim's load time and memory usage) + - When using SRHiGrp! (operate over non-matching areas) the plugin + always reported "Did not find highlight group" (Mathieu Westphal) + - SRHiGrp now defaults the range to the entire file, instead of the + current row + +vim:tw=78:ts=8:ft=help:norl: diff --git a/vimfiles/doc/diffchar.txt b/vimfiles/doc/diffchar.txt new file mode 100644 index 0000000..8b9bb06 --- /dev/null +++ b/vimfiles/doc/diffchar.txt @@ -0,0 +1,392 @@ +*diffchar.txt* Highlight the exact differences, based on characters and words +> + ____ _ ____ ____ _____ _ _ _____ ____ + | | | || || || || | | || _ || _ | + | _ || || __|| __|| || | | || | | || | || + | | | || || |__ | |__ | __|| |_| || |_| || |_||_ + | |_| || || __|| __|| | | || || __ | + | || || | | | | |__ | _ || _ || | | | + |____| |_||_| |_| |_____||_| |_||_| |_||_| |_| +< +Last Change: 2016/03/09 +Version: 6.1 +Author: Rick Howe + +----------------------------------------------------------------------------- +INTRODUCTION *diffchar* + +This plugin has been developed in order to make diff mode more useful. Vim +highlights all the text in between the first and last different characters on +a changed line. But this plugin will find the exact differences between them, +character by character - so called DiffChar. + +For example, in diff mode: ( [DiffText], ) +> + (window A) The [quick brown fox jumps over the lazy] dog. + (window B) The [lazy fox jumps over the quick brown] dog. +< +this plugin will exactly show the changed and added units: +> + (window A) The [quick] fox jumps over the [lazy] dog. + (window B) The [lazy] fox jumps over the [quick] dog. +< +This plugin will synchronously show/reset the highlights of the exact +differences as soon as the diff mode starts/ends since a |g:DiffModeSync| is +enabled as a default. It synchronously works as well on your custom diff tool +(e.g. git-diff) when you have specified it to the 'diffexpr' option. + +In non-diff mode or when the |g:DiffModeSync| is disabled, you can toggle to +show/reset the diff highlights by pressing or or using |:TDChar| +command. To show or reset them, use |:SDChar| or |:RDChar| command. + +In diff mode, the corresponding changed lines are compared between two +windows. In non-diff mode, the same lines are compared among them. You can +set a matching color to a |g:DiffColors| to make it easy to recognize the +corresponding changed units between two windows. As a default, all the +changed units are highlighted with DiffText. In addition, DiffAdd is always +used for the added units and both the previous and next character of the +deleted units are underlined. + +This plugin traces the differences based on a |g:DiffUnit|. Its default is +'Word1' and it handles a \w\+ word and a \W character as a difference unit. +There are other types of word provided and you can also set 'Char' to compare +character by character. + +While showing the exact differences, you can use ]b or ]e to jump cursor to +the start or end position of the next difference unit, and [b or [e to the +start or end position of the previous unit. Then this plugin echoes the +corresponding difference unit with the assigned color as a message. Those +keymaps, and are configurable in your vimrc and so on. + +This plugin attempts to keep the exact differences updated while editing since +a |g:DiffUpdate| is enabled as a default. However, a total number of lines are +changed (after some lines are added/deleted), all the diff highlights will +be cleared and you will need to manually show them again to update. + +This plugin has been using "An O(NP) Sequence Comparison Algorithm" developed +by S.Wu, et al., which always finds an optimum sequence quickly. But for +longer lines and less-similar files, it takes time to complete the diff +tracing. To make it more efficient, this plugin splits the tracing with the +external diff command. Firstly applies the internal O(NP) algorithm. If not +completed within the time specified by a |g:DiffSplitTime|, continuously +switches to the diff command at that point, and then joins both results. This +approach provides a stable performance and reasonable accuracy, because the +diff command effectively optimizes between them. Its default is 100 ms, which +would be useful for smaller files. If prefer to always apply the internal +algorithm for accuracy (or the diff command for performance), set some large +value (or 0) to it. + +This plugin sets the DiffCharExpr() to the 'diffexpr' option, if it is empty. +It also uses the |g:DiffSplitTime| and splits the tracing between the +internal algorithm and the external diff command. If prefer to leave the +'diffexpr' option as empty, set 0 to a |g:DiffExpr|. + +This plugin works on each tab page individually. You can use a tab page +variable (t:), instead of a global one (g:), to specify different options on +each tab page. + +This plugin has been always positively supporting mulltibyte characters. + +----------------------------------------------------------------------------- +COMMANDS *diffchar-commands* + +:[range]SDChar - Show the highlights of difference units for [range] +:[range]RDChar - Reset the highlights of difference units for [range] +:[range]TDChar - Toggle to show/reset the highlights for [range] + +----------------------------------------------------------------------------- +KEYMAPS *diffchar-keymaps* + +ToggleDiffCharAllLines (default: ) + Toggle to show/reset the highlights for all/selected lines + +ToggleDiffCharCurrentLine (default: ) + Toggle to show/reset the highlights for current/selected lines + +JumpDiffCharPrevStart (default: [b) + Jump cursor to the start position of the previous difference unit + +JumpDiffCharNextStart (default: ]b) + Jump cursor to the start position of the next difference unit + +JumpDiffCharPrevEnd (default: [e) + Jump cursor to the end position of the previous difference unit + +JumpDiffCharNextEnd (default: ]e) + Jump cursor to the end position of the next difference unit + +----------------------------------------------------------------------------- +OPTIONS *diffchar-options* + +|g:DiffUnit|, |t:DiffUnit| + Type of difference unit + 'Word1' : \w\+ word and any \W single character (default) + 'Word2' : non-space and space words + 'Word3' : \< or \> character class boundaries + 'Char' : any single character + 'CSV(,)' : separated by characters such as ',', ';', and '\t' + +|g:DiffColors|, |t:DiffColors| + Matching colors for changed unit pairs (always DiffAdd for added units) + 0 : always DiffText (default) + 1 : 4 colors in fixed order + 2 : 8 colors in fixed order + 3 : 16 colors in fixed order + 100 : all available colors in dynamic random order + +|g:DiffUpdate|, |t:DiffUpdate| (available on vim 7.4) + Interactively updating the diff highlights while editing + 1 : enable (default) + 0 : disable + +|g:DiffSplitTime|, |t:DiffSplitTime| + A time length (ms) to apply the internal algorithm first + 0 ~ : (100 as default) + +|g:DiffModeSync|, |t:DiffModeSync| + Synchronously show/reset with diff mode + 1 : enable (default) + 0 : disable + +|g:DiffExpr| + Set DiffCharExpr() to the 'diffexpr' option + 1 : enable (default) + 0 : disable + +----------------------------------------------------------------------------- +CHANGE HISTORY *diffchar-history* + +Update : 6.1 +* Improved a workaround for vim 7.4.682 (at update 5.1) not to disappear vim's + DiffChange/DiffText highlights in other tab pages. +* Improved to handle diff tracing only once in one diff session when more than + 2 buffers become diff mode and DiffModeSync is enabled. +* Fixed to correctly reset diffchar highlights on a split window when the + window is closed. + +Update : 6.0 +* Defined a new :TDChar command to toggle the highlights for specified range, + and make it possible to select a block of lines in visual mode and toggle + them by using . +* Changed the default value of g:DiffUnit from 'Char' to 'Word1', where \w\+ + is handled as a single difference unit, to make more sense to usual case. +* Changed the default value of g:DiffSplitTime from 500 to 100 to switch more + quickly and changed to check the time more often (unit-by-unit, not + line-by-line) to detect the time limit earlier. +* Changed to use the g:DiffSplitTime, instead of the number of lines as an + argument, in the DiffCharExpr() to switch to the diff command as accurately + as specified. +* Improved the way to analyze the output of the diff command quickly. +* Enhanced to interactively update the highlights faster while editing when + g:DiffUpdate is enabled. +* Changed the position of a pair cursor for a deleted unit on either its + previous or next character instead of both. +* Fixed to ignore white spaces at line end when iwhite is specified in the + 'diffopt' option. +* Fixed to enable to use a t:DiffModeSync tab page variable as well as its + global one. + +Update : 5.5 +* Introduced g:DiffModeSync to synchronously show/reset the highlights as the + diff mode starts/ends, which also works on your custom diff tool. +* Changed to enable g:DiffUpdate as a default and then interactively update + the highlights while editing. +* Enhanced to draw and delete the highlights faster by specifying as many + position parameters as possible in one matchaddpos() and matchadd() call. +* Changed to select current window and next diff mode window (if present) + whose buffer is different at initialize. +* Fixed: + - caused an error on getwinvar() in vim 7.3. + - in non-gVim, did not show a matching pair cursor when jumping the cursor + by using [e or ]b, depending on a color scheme. + - sometimes failed to toggle the highlights when using or in diff + mode windows. + - did not interactively update the highlight of all the lines when multiple + lines were changed at once if g:DiffUpdate = 1. + +Update : 5.4 +* Enhanced to show a position of a deleted unit with underline on its + previous and next characters. This position is where a unit is added + between those characters in another diffchar window. +* Improved to be able to change this plugin's global variables anytime. +* Changed to select current window and then the next (wincmd w) window whose + buffer is different. + +Update : 5.3 +* Performance improved for long lines and some defects fixed when the diff + command is used for the diff tracing. + +Update : 5.2 +* Enhanced to provide a stable performance even for less-similar long files. + The new approach applies this plugin's algorithm first, and if not + completed within the specified time, continuously splits the tracing with + the diff command, and join both results. +* Fixed: when diff command does not choose minimal algorithm and it shows the + equivalent lines as "changed", this plugin sometimes makes an error. +* Fixed: if file encoding is not same as buffer encoding, a difference may + not be correctly detected in DiffCharExpr(). + +Update : 5.1 +* Since vim 7.4.682, it has become impossible to overwrite the vim's diff + highlights with this plugin. Then, for example, DiffText bold typeface will + be left in all the diff highlighted lines (for more info, see + https://groups.google.com/forum/?hl=en_US#!topic/vim_use/1jQnbTva2fY). This + update provides a workaround to reduce its effect and to show the + differences mostly same as before. + +Update : 5.0 +* Significantly improved the way to trace and show the differences and make + them 1.5 ~ 2.0 times faster. +* Introduced g:DiffMaxRatio (and t:DiffMaxRatio), a maximum difference ratio + to trace (100% as default). Once exceeds, the diff tracing is recursively + split and helps to keep performance instead of diff accuracy. +* Discontinued other difference algorithms (OND and Basic) than the ONP, then + g:DiffAlgorithm no longer supported. +* Improved to allow to specify one or more characters for 'CSV(c)' in + g:DiffUnit (and t:DiffUnit). For example, 'CSV(,:\t)' will split the units + by a comma, colon, and tab. Use '\\' for a backslash. + +Update : 4.9 +* Fixed DiffCharExpr() to check the number of total lines, not different + lines only, of both windows and apply either internal algorithm or external + diff command, in order to keep the appropriate performance for large files. + +Update : 4.81 +* Enhanced to make DiffCharExpr() a bit faster by using uniq() or so. + +Update : 4.8 +* Enhanced to set the threshold value on DiffCharExpr() to check how many + differences and then apply either of internal algorithm or external diff + command. The default for 'diffexpr' option using DiffCharExpr() is changed to + use this threshold, 200 - apply internal if less than 200 differences, + apply external if more. +* Changed the way to select windows when more than 2 windows in the page. + - automatically select the diff mode's next (wincmd w) window, if any, in + addition to the current window + - can select any of split windows as vim can do for diff + +Update : 4.7 +* Enhanced to set DiffCharExpr() to the 'diffexpr' option, if it is empty. When + diff mode begins, vim calls this function which finds differences by this + plugin's internal diff algorithm (default) and then initially shows the + exact differences (default). You can also explicitly set this function to + the option with different arguments. +* Enhanced to make the key mappings configurable. + For example, the default can be modified by: + nmap your_favorite_key ToggleDiffCharAllLines +* Fixed to correctly adjust the position of difference units when 'diffopt' + iwhite option is enabled. + +Update : 4.6 +* Fixed to correctly show the colors of changed units in one-by-one defined + order of g:DiffColors. Since an added unit was improperly counted as + changed one, some colors were skipped and not shown. The first changed unit + is now always highlighted with DiffText in any color mode. + +Update : 4.5 +* Fixed to trace the differences until the end of the units. Previously the + last same units were skipped, so last added units were sometimes shown as + changed ones (eg: the last "swift brown" on above were shown as changed + units but now shows "brown" as added ones). +* Enhanced to use your global variables if defined in vimrc. + +Update : 4.4 +* Enhanced to follow 'diffopt' icase and iwhite options for both diff and + non-diff modes (ignorecase option is not used). Previously, it has been + always case and space/tab sensitive. +* Implemented to highlight the difference units using a new matchaddpos() + function, introduced in 7.4.330, when available to draw faster. + +Update : 4.3 +* Enhanced to differently show added/deleted/changed difference units with + original diff highlightings. + - added units will be always highlighted with DiffAdd. + - changed units will be highlighted based on the g:DiffColors (and + t:DiffColors) variable, but DiffText is always used for the first changed + unit. + - when jumping cursor by [b/]b or [e/]e on the added unit, it highlights + around the corresponding deleted units with a cursor-type color in + another window, and echoes a diff-delete filler with DiffDelete, along + with common characters on both sides (e.g. a-----b). + +Update : 4.2 +* Enhanced to update the highlighted DiffChar units while editing. A + g:DiffUpdate (and t:DiffUpdate) variable enables and disables (default) + this update behavior. If a text line was added/deleted, reset all the + highlightings. This feature is available on vim 7.4. + +Update : 4.1 +* Implemented to echo a matching difference unit with its color when jumping + cursor by [b/]b or [e/]e. +* Fixed defects: not using the new uniq() function introduced in vim 7.4. + +Update : 4.0 +* Enhanced to easily find a corresponding pair of each difference unit. + - each unit pair will be shown in individual same color on both windows. A + g:DiffColors (and t:DiffColors) variable is a type of matching colors, 0 + (default) for always 1 color as before, 1/2/3 for 4/8/16 colors in fixed + order, and 100 for all available colors in dynamic random order. + - when jumping cursor by [b/]b or [e/]e in either window, the start or end + position of a matching unit will be highlighted with a cursor-type color + in another window. + +Update : 3.6 +* Added two g:DiffUnit (and t:DiffUnit) types. 'Word3' will split at the \< + or \> boundaries, which can separate based on the character class like CJK, + Hiragana, Katakana, Hangul, full width symbols and so on. And 'CSV(c)' will + split the units by a specified character 'c'. For example, 'CSV(,)' and + 'CSV(\t)' can be used for comma and tab separated text. + +Update : 3.5 +* Fixed defects: DiffChar highlighting units do not override/hide hlsearch. + +Update : 3.4 +* Enhanced to support individual DiffChar handling on each tab page. + Difference unit and algorithm can also be set page by page using tab page + local variables, t:DiffUnit and t:DiffAlgorithm. + +Update : 3.3 +* Enhanced to jump cursor to the DiffChar highlighting units. Sample keymaps + ]b and [b will move cursor forwards to the next and backwards to the + previous start positions. And ]e and [e will move to the end positions. + +Update : 3.2 +* Enhanced to follow diff mode without any limitations. Compare between the + corresponding DiffChange lines on both windows and properly handle DiffAdd + and DiffDelete lines. + +Update : 3.1 +* Enhanced to show/reset/toggle DiffChar highlightings on individual line by + line. +* Implemented the window layout handling. + - the DiffChar'ed windows will remain the highlightings even if the window + position is rotated/replaced/moved and another new window opens. + - if either DiffChar'ed window is closed, reset all the DiffChar + highlightings on another window. +* Removed limitations: + - when more than 2 windows exist, current and next (wincmd w) windows will + be selected. + - if the specified numbers of lines are different in both windows, ignore + the redundant lines and continue to compare the text on the same lines. + - RDChar sample command has a range attribute (e.g. %RDChar). +* Fixed defects: + - reset just DiffChar highlightings only and remain others. + +Update : 3.0 +* Implemented word by word differences. A g:DiffUnit variable is a type of a + difference unit. Its default is 'Char', which will trace character by + character as before. 'Word1' will split into \w\+ words and any \W single + characters. And 'Word2' will separate the units at the \s\+ space + boundaries. +* Improved the performance around 10%. + +Update : 2.1 +* Coding changes in the O(NP) function for readability. + +Update : 2.0 +* Implemented the O(NP) and O(ND) Difference algorithms to improve the + performance. This update uses the O(NP) by default, and can be changed to + the O(ND) if necessary, or to the basic algorithm implemented in the + initial version. + + vim:tw=78:ts=8:ft=help:norl: diff --git a/vimfiles/doc/merginal.txt b/vimfiles/doc/merginal.txt old mode 100755 new mode 100644 index db48c7b..2a4c783 --- a/vimfiles/doc/merginal.txt +++ b/vimfiles/doc/merginal.txt @@ -4,7 +4,7 @@ Author: Idan Arye License: Same terms as Vim itself (see |license|) -Version: 1.5.0 +Version: 2.0.1 INTRODUCTION *merginal* @@ -54,6 +54,7 @@ following keymaps to interact with the branches: q Close the branch list. R Refresh the branch list. +& Filter the branch list. cc Checkout the branch under the cursor. ct Track the remote branch under the cursor. cT Track the remote branch under the cursor, prompting for a name. @@ -69,6 +70,9 @@ mm Merge the branch under the cursor into the currently checked out M Same as mm. mf Merge the branch under the cursor into the currently checked out branch using Fugitive's |:Gmerge| command. +mn Merge the branch under the cursor using the --no-ff flag, forcing the + creation of a merge commit even when the merge resolves as a + fast-forward. rb Rebase the currently checked out branch against the branch under the cursor. If there are rebase conflicts, the |merginal-rebase-conflicts| buffer will open in place of @@ -92,6 +96,7 @@ files that have merge conflicts and offers the following keymaps: q Close the merge conflicts list. R Refresh the merge conflicts list. +& Filter the merge conflicts list. Open the conflicted file under the cursor. aa Add the conflicted file under the cursor to the staging area. If that was the last conflicted file, the merge conflicts buffer will close and @@ -106,6 +111,7 @@ currently applied commit message and all the files that have rebase conflicts, and offers the following keymaps: R Refresh the rebase conflicts list. +& Filter the rebase conflicts list. Open the conflicted file under the cursor. aa Add the conflicted file under the cursor to the staging area. If that was the last conflicted file, prompt the user to continue to the next @@ -125,6 +131,7 @@ keymaps: q Close the rebase amend buffer. R Refresh the rebase amend buffer. +& Filter the rebase amend buffer. gd Open |merginal-diff-files| buffer to diff against the branch under the cursor. gl Open |merginal-history-log| buffer to view the history of the branch @@ -142,6 +149,7 @@ opened against, and offers the following keymaps: q Close the diff files list. R Refresh the diff files list. +& Filter the diff files list. Open the file under the cursor (if it exists in the currently checked out branch). ds Split-diff against the file under the cursor (if it exists in the other @@ -160,6 +168,7 @@ offers the following keymaps: q Close the history log buffer. R Refresh the history log buffer. +& Filter the history log buffer. Move the cursor to the previous commit. Move the cursor to the next commit. ss Echo the commit details(using git's --format=fuller). @@ -168,3 +177,24 @@ cc Checkout the commit under the cursor. C Same as cc. gd Open |merginal-diff-files| buffer to diff against the commit under the cursor. +cp Cherry-pick the commit under the cursor into the currently checked out + branch. If there are cherry-pick conflicts, the + |merginal-cherry-pick-conflicts| buffer will open in place of the + history log buffer. + + +CHERRY-PICK CONFLICTS *merginal-cherry-pick-conflicts* + +The cherry-pick conflicts buffer is used to solve cherry-pick conflicts. It +shows the cherry-picked commit message and all the files that have cherry-pick +conflicts, and offers the following keymaps: + +R Refresh the cherry-pick conflicts list. +& Filter the cherry-pick conflicts list. + Open the conflicted file under the cursor. +aa Add the conflicted file under the cursor to the staging area. If that + was the last conflicted file, prompt the user to continue to the next + patch. +A Same as aa. +ra Abort the cherry-pick. +rc Continue to the next patch. diff --git a/vimfiles/doc/tags b/vimfiles/doc/tags index b506eb3..18d395d 100644 --- a/vimfiles/doc/tags +++ b/vimfiles/doc/tags @@ -13,7 +13,7 @@ :CSVHeader ft-csv.txt /*:CSVHeader* :CSVHeaderToggle ft-csv.txt /*:CSVHeaderToggle* :CSVHiColumn ft-csv.txt /*:CSVHiColumn* -:CSVInitCSV ft-csv.txt /*:CSVInitCSV* +:CSVInit ft-csv.txt /*:CSVInit* :CSVMoveCol ft-csv.txt /*:CSVMoveCol* :CSVNewDelimiter ft-csv.txt /*:CSVNewDelimiter* :CSVNewRecord ft-csv.txt /*:CSVNewRecord* @@ -115,26 +115,26 @@ :VCSVimDiff vcscommand.txt /*:VCSVimDiff* :Vexplore pi_netrw.txt /*:Vexplore* :VimballList pi_vimball.txt /*:VimballList* -TComment-_ tcomment.txt /*TComment-_* -TComment-__ tcomment.txt /*TComment-__* -TComment-_a tcomment.txt /*TComment-_a* -TComment-_b tcomment.txt /*TComment-_b* -TComment-_n tcomment.txt /*TComment-_n* -TComment-_p tcomment.txt /*TComment-_p* -TComment-_r tcomment.txt /*TComment-_r* -TComment-_s tcomment.txt /*TComment-_s* -TComment- tcomment.txt /*TComment-* -TComment- tcomment.txt /*TComment-* -TComment-a tcomment.txt /*TComment-a* -TComment-b tcomment.txt /*TComment-b* -TComment-ca tcomment.txt /*TComment-ca* -TComment-cc tcomment.txt /*TComment-cc* -TComment-i tcomment.txt /*TComment-i* -TComment-n tcomment.txt /*TComment-n* -TComment-p tcomment.txt /*TComment-p* -TComment-r tcomment.txt /*TComment-r* -TComment-s tcomment.txt /*TComment-s* -TComment-ic tcomment.txt /*TComment-ic* +TComment__ tcomment.txt /*TComment__* +TComment___ tcomment.txt /*TComment___* +TComment__a tcomment.txt /*TComment__a* +TComment__b tcomment.txt /*TComment__b* +TComment__n tcomment.txt /*TComment__n* +TComment__p tcomment.txt /*TComment__p* +TComment__r tcomment.txt /*TComment__r* +TComment__s tcomment.txt /*TComment__s* +TComment_ tcomment.txt /*TComment_* +TComment_ tcomment.txt /*TComment_* +TComment_a tcomment.txt /*TComment_a* +TComment_b tcomment.txt /*TComment_b* +TComment_ca tcomment.txt /*TComment_ca* +TComment_cc tcomment.txt /*TComment_cc* +TComment_i tcomment.txt /*TComment_i* +TComment_n tcomment.txt /*TComment_n* +TComment_p tcomment.txt /*TComment_p* +TComment_r tcomment.txt /*TComment_r* +TComment_s tcomment.txt /*TComment_s* +TComment_ic tcomment.txt /*TComment_ic* AddColumn_CSV ft-csv.txt /*AddColumn_CSV* Align-copyright Align.txt /*Align-copyright* Analyze_CSV ft-csv.txt /*Analyze_CSV* @@ -142,13 +142,17 @@ ArrangeColumn_CSV ft-csv.txt /*ArrangeColumn_CSV* C-Reference crefvim.txt /*C-Reference* CSV-Functions ft-csv.txt /*CSV-Functions* CSVCol() ft-csv.txt /*CSVCol()* +CSVCount() ft-csv.txt /*CSVCount()* CSVField() ft-csv.txt /*CSVField()* CSVFixed ft-csv.txt /*CSVFixed* +CSVMax() ft-csv.txt /*CSVMax()* +CSVMin() ft-csv.txt /*CSVMin()* CSVPat() ft-csv.txt /*CSVPat()* CSVSum() ft-csv.txt /*CSVSum()* CSV_WCol() ft-csv.txt /*CSV_WCol()* ConvertData_CSV ft-csv.txt /*ConvertData_CSV* Copy_CSV ft-csv.txt /*Copy_CSV* +CountCol_CSV ft-csv.txt /*CountCol_CSV* DeleteColumn_CSV ft-csv.txt /*DeleteColumn_CSV* DirDiff dirdiff.txt /*DirDiff* Duplicate_CSV ft-csv.txt /*Duplicate_CSV* @@ -171,10 +175,11 @@ HiColumn_CSV ft-csv.txt /*HiColumn_CSV* IDMY visincr.txt /*IDMY* IMDY visincr.txt /*IMDY* IYMD visincr.txt /*IYMD* -InitCSV ft-csv.txt /*InitCSV* LogiPat() LogiPat.txt /*LogiPat()* LogiPat-flags LogiPat.txt /*LogiPat-flags* MatchError matchit.txt /*MatchError* +MaxCol_CSV ft-csv.txt /*MaxCol_CSV* +MinCol_CSV ft-csv.txt /*MinCol_CSV* MoveCol_CSV ft-csv.txt /*MoveCol_CSV* MultipleSearch MultipleSearch.txt /*MultipleSearch* MultipleSearch-commands MultipleSearch.txt /*MultipleSearch-commands* @@ -1607,6 +1612,7 @@ csv-strict ft-csv.txt /*csv-strict* csv-syntax ft-csv.txt /*csv-syntax* csv-syntax-error ft-csv.txt /*csv-syntax-error* csv-tabularize ft-csv.txt /*csv-tabularize* +csv-textobjects ft-csv.txt /*csv-textobjects* csv-tips ft-csv.txt /*csv-tips* csv-toc ft-csv.txt /*csv-toc* csv-transpose ft-csv.txt /*csv-transpose* @@ -1614,6 +1620,12 @@ csv-vertfold ft-csv.txt /*csv-vertfold* cvscommand-changes vcscommand.txt /*cvscommand-changes* dav pi_netrw.txt /*dav* davs pi_netrw.txt /*davs* +diffchar diffchar.txt /*diffchar* +diffchar-commands diffchar.txt /*diffchar-commands* +diffchar-history diffchar.txt /*diffchar-history* +diffchar-keymaps diffchar.txt /*diffchar-keymaps* +diffchar-options diffchar.txt /*diffchar-options* +diffchar.txt diffchar.txt /*diffchar.txt* dirdiff dirdiff.txt /*dirdiff* dirdiff-a dirdiff.txt /*dirdiff-a* dirdiff-enter dirdiff.txt /*dirdiff-enter* @@ -1823,7 +1835,9 @@ g:tcommentGuessFileType_django tcomment.txt /*g:tcommentGuessFileType_django* g:tcommentGuessFileType_dsl tcomment.txt /*g:tcommentGuessFileType_dsl* g:tcommentGuessFileType_eruby tcomment.txt /*g:tcommentGuessFileType_eruby* g:tcommentGuessFileType_html tcomment.txt /*g:tcommentGuessFileType_html* +g:tcommentGuessFileType_jinja tcomment.txt /*g:tcommentGuessFileType_jinja* g:tcommentGuessFileType_php tcomment.txt /*g:tcommentGuessFileType_php* +g:tcommentGuessFileType_rnoweb tcomment.txt /*g:tcommentGuessFileType_rnoweb* g:tcommentGuessFileType_smarty tcomment.txt /*g:tcommentGuessFileType_smarty* g:tcommentGuessFileType_tskeleton tcomment.txt /*g:tcommentGuessFileType_tskeleton* g:tcommentGuessFileType_vim tcomment.txt /*g:tcommentGuessFileType_vim* @@ -1890,15 +1904,15 @@ gundo_right gundo.txt /*gundo_right* gundo_tree_statusline gundo.txt /*gundo_tree_statusline* gundo_width gundo.txt /*gundo_width* http pi_netrw.txt /*http* -i_TComment- tcomment.txt /*i_TComment-* -i_TComment- tcomment.txt /*i_TComment-* -i_TComment-a tcomment.txt /*i_TComment-a* -i_TComment-b tcomment.txt /*i_TComment-b* -i_TComment-i tcomment.txt /*i_TComment-i* -i_TComment-n tcomment.txt /*i_TComment-n* -i_TComment-p tcomment.txt /*i_TComment-p* -i_TComment-r tcomment.txt /*i_TComment-r* -i_TComment-s tcomment.txt /*i_TComment-s* +i_TComment_ tcomment.txt /*i_TComment_* +i_TComment_ tcomment.txt /*i_TComment_* +i_TComment_a tcomment.txt /*i_TComment_a* +i_TComment_b tcomment.txt /*i_TComment_b* +i_TComment_i tcomment.txt /*i_TComment_i* +i_TComment_n tcomment.txt /*i_TComment_n* +i_TComment_p tcomment.txt /*i_TComment_p* +i_TComment_r tcomment.txt /*i_TComment_r* +i_TComment_s tcomment.txt /*i_TComment_s* linediff linediff.txt /*linediff* linediff-commands linediff.txt /*linediff-commands* linediff-contents linediff.txt /*linediff-contents* @@ -1950,6 +1964,7 @@ matchit.txt matchit.txt /*matchit.txt* matchit.vim matchit.txt /*matchit.vim* merginal merginal.txt /*merginal* merginal-branch-list merginal.txt /*merginal-branch-list* +merginal-cherry-pick-conflicts merginal.txt /*merginal-cherry-pick-conflicts* merginal-diff-files merginal.txt /*merginal-diff-files* merginal-history-log merginal.txt /*merginal-history-log* merginal-merge-conflicts merginal.txt /*merginal-merge-conflicts* @@ -1958,15 +1973,6 @@ merginal-rebase-conflicts merginal.txt /*merginal-rebase-conflicts* merginal-requirements merginal.txt /*merginal-requirements* merginal-usage merginal.txt /*merginal-usage* merginal.txt merginal.txt /*merginal.txt* -n_TComment-Comment tcomment.txt /*n_TComment-Comment* -n_TComment-Commentb tcomment.txt /*n_TComment-Commentb* -n_TComment-Commentc tcomment.txt /*n_TComment-Commentc* -n_TComment-Uncomment tcomment.txt /*n_TComment-Uncomment* -n_TComment-Uncommentb tcomment.txt /*n_TComment-Uncommentb* -n_TComment-Uncommentc tcomment.txt /*n_TComment-Uncommentc* -n_TComment-gc tcomment.txt /*n_TComment-gc* -n_TComment-gcb tcomment.txt /*n_TComment-gcb* -n_TComment-gcc tcomment.txt /*n_TComment-gcc* netreadfixup pi_netrw.txt /*netreadfixup* netrw pi_netrw.txt /*netrw* netrw-% pi_netrw.txt /*netrw-%* @@ -2174,23 +2180,27 @@ srchrplchigrp SrchRplcHiGrp.txt /*srchrplchigrp* srchrplchigrp-commands SrchRplcHiGrp.txt /*srchrplchigrp-commands* srchrplchigrp-contents SrchRplcHiGrp.txt /*srchrplchigrp-contents* srchrplchigrp-examples SrchRplcHiGrp.txt /*srchrplchigrp-examples* +srchrplchigrp-history SrchRplcHiGrp.txt /*srchrplchigrp-history* tcomment#Comment() tcomment.txt /*tcomment#Comment()* tcomment#CommentAs() tcomment.txt /*tcomment#CommentAs()* tcomment#DefineType() tcomment.txt /*tcomment#DefineType()* tcomment#GetCommentDef() tcomment.txt /*tcomment#GetCommentDef()* +tcomment#GetLineC() tcomment.txt /*tcomment#GetLineC()* tcomment#GuessCommentType() tcomment.txt /*tcomment#GuessCommentType()* +tcomment#MaybeReuseOptions() tcomment.txt /*tcomment#MaybeReuseOptions()* tcomment#Operator() tcomment.txt /*tcomment#Operator()* tcomment#OperatorAnyway() tcomment.txt /*tcomment#OperatorAnyway()* tcomment#OperatorLine() tcomment.txt /*tcomment#OperatorLine()* tcomment#OperatorLineAnyway() tcomment.txt /*tcomment#OperatorLineAnyway()* +tcomment#ResetOption() tcomment.txt /*tcomment#ResetOption()* tcomment#SetOption() tcomment.txt /*tcomment#SetOption()* tcomment#TextObjectInlineComment() tcomment.txt /*tcomment#TextObjectInlineComment()* tcomment-maps tcomment.txt /*tcomment-maps* tcomment-operator tcomment.txt /*tcomment-operator* tcomment.txt tcomment.txt /*tcomment.txt* -v_TComment- tcomment.txt /*v_TComment-* -v_TComment-i tcomment.txt /*v_TComment-i* -v_TComment-ic tcomment.txt /*v_TComment-ic* +v_TComment_ tcomment.txt /*v_TComment_* +v_TComment_i tcomment.txt /*v_TComment_i* +v_TComment_ic tcomment.txt /*v_TComment_ic* v_[% matchit.txt /*v_[%* v_]% matchit.txt /*v_]%* v_a% matchit.txt /*v_a%* @@ -2269,11 +2279,11 @@ visincr-raggedright visincr.txt /*visincr-raggedright* visincr-restrict visincr.txt /*visincr-restrict* visincr-usage visincr.txt /*visincr-usage* visincr.txt visincr.txt /*visincr.txt* -x_TComment-__ tcomment.txt /*x_TComment-__* -x_TComment-_i tcomment.txt /*x_TComment-_i* -x_TComment-Comment tcomment.txt /*x_TComment-Comment* -x_TComment-Uncomment tcomment.txt /*x_TComment-Uncomment* -x_TComment-gc tcomment.txt /*x_TComment-gc* +x_TComment___ tcomment.txt /*x_TComment___* +x_TComment__i tcomment.txt /*x_TComment__i* +x_TComment_Comment tcomment.txt /*x_TComment_Comment* +x_TComment_Uncomment tcomment.txt /*x_TComment_Uncomment* +x_TComment_gc tcomment.txt /*x_TComment_gc* xml-plugin-callbacks xml-plugin.txt /*xml-plugin-callbacks* xml-plugin-html xml-plugin.txt /*xml-plugin-html* xml-plugin-mappings xml-plugin.txt /*xml-plugin-mappings* diff --git a/vimfiles/doc/tcomment.txt b/vimfiles/doc/tcomment.txt index 0917d60..d8e5274 100644 --- a/vimfiles/doc/tcomment.txt +++ b/vimfiles/doc/tcomment.txt @@ -54,7 +54,7 @@ Explicit commenting/uncommenting: In visual mode: gc :: Toggle comments - gC :: Comment selected text + g> :: Comment selected text CAVEAT: If you visually select text within a line, the visual mode map will comment out the selected text. If you selected text across several lines, the @@ -145,52 +145,43 @@ Contents~ :TCommentBlock ................................ |:TCommentBlock| :TCommentInline ............................... |:TCommentInline| :TCommentMaybeInline .......................... |:TCommentMaybeInline| - TComment- ..................... |TComment-| - v_TComment- ................... |v_TComment-| - i_TComment- ................... |i_TComment-| - TComment-p ......................... |TComment-p| - i_TComment-p ....................... |i_TComment-p| - TComment- ................... |TComment-| - i_TComment- ................. |i_TComment-| - i_TComment-r ....................... |i_TComment-r| - TComment-r ......................... |TComment-r| - v_TComment-i ....................... |v_TComment-i| - TComment-i ......................... |TComment-i| - i_TComment-i ....................... |i_TComment-i| - TComment-b ......................... |TComment-b| - i_TComment-b ....................... |i_TComment-b| - TComment-a ......................... |TComment-a| - i_TComment-a ....................... |i_TComment-a| - TComment-n ......................... |TComment-n| - i_TComment-n ....................... |i_TComment-n| - TComment-s ......................... |TComment-s| - i_TComment-s ....................... |i_TComment-s| - TComment-cc ........................ |TComment-cc| - TComment-ca ........................ |TComment-ca| - TComment-__ ..................... |TComment-__| - x_TComment-__ ................... |x_TComment-__| - TComment-_p ..................... |TComment-_p| - TComment-_ ............... |TComment-_| - x_TComment-_i ................... |x_TComment-_i| - TComment-_r ..................... |TComment-_r| - TComment-_b ..................... |TComment-_b| - TComment-_a ..................... |TComment-_a| - TComment-_n ..................... |TComment-_n| - TComment-_s ..................... |TComment-_s| - n_TComment-Uncomment .................... |n_TComment-Uncomment| - n_TComment-Uncommentc ................... |n_TComment-Uncommentc| - n_TComment-Uncommentb ................... |n_TComment-Uncommentb| - x_TComment-Uncomment .................... |x_TComment-Uncomment| - n_TComment-Comment ...................... |n_TComment-Comment| - n_TComment-Commentc ..................... |n_TComment-Commentc| - n_TComment-Commentb ..................... |n_TComment-Commentb| - x_TComment-Comment ...................... |x_TComment-Comment| - v_TComment-ic ........................... |v_TComment-ic| - TComment-ic ............................. |TComment-ic| - n_TComment-gcc .......................... |n_TComment-gcc| - n_TComment-gcb .......................... |n_TComment-gcb| - x_TComment-gc ........................... |x_TComment-gc| - n_TComment-gc ........................... |n_TComment-gc| + TComment_ ..................... |TComment_| + v_TComment_ ................... |v_TComment_| + i_TComment_ ................... |i_TComment_| + TComment_p ......................... |TComment_p| + i_TComment_p ....................... |i_TComment_p| + TComment_ ................... |TComment_| + i_TComment_ ................. |i_TComment_| + i_TComment_r ....................... |i_TComment_r| + TComment_r ......................... |TComment_r| + v_TComment_i ....................... |v_TComment_i| + TComment_i ......................... |TComment_i| + i_TComment_i ....................... |i_TComment_i| + TComment_b ......................... |TComment_b| + i_TComment_b ....................... |i_TComment_b| + TComment_a ......................... |TComment_a| + i_TComment_a ....................... |i_TComment_a| + TComment_n ......................... |TComment_n| + i_TComment_n ....................... |i_TComment_n| + TComment_s ......................... |TComment_s| + i_TComment_s ....................... |i_TComment_s| + TComment_cc ........................ |TComment_cc| + TComment_ca ........................ |TComment_ca| + TComment___ ..................... |TComment___| + x_TComment___ ................... |x_TComment___| + TComment__p ..................... |TComment__p| + TComment__ ............... |TComment__| + x_TComment__i ................... |x_TComment__i| + TComment__r ..................... |TComment__r| + TComment__b ..................... |TComment__b| + TComment__a ..................... |TComment__a| + TComment__n ..................... |TComment__n| + TComment__s ..................... |TComment__s| + x_TComment_Uncomment .................... |x_TComment_Uncomment| + x_TComment_Comment ...................... |x_TComment_Comment| + v_TComment_ic ........................... |v_TComment_ic| + TComment_ic ............................. |TComment_ic| + x_TComment_gc ........................... |x_TComment_gc| g:tcomment#blank_lines ........................ |g:tcomment#blank_lines| g:tcomment#rstrip_on_uncomment ................ |g:tcomment#rstrip_on_uncomment| g:tcommentModeExtra ........................... |g:tcommentModeExtra| @@ -208,11 +199,14 @@ Contents~ g:tcommentGuessFileType_vim ................... |g:tcommentGuessFileType_vim| g:tcommentGuessFileType_django ................ |g:tcommentGuessFileType_django| g:tcommentGuessFileType_eruby ................. |g:tcommentGuessFileType_eruby| + g:tcommentGuessFileType_jinja ................. |g:tcommentGuessFileType_jinja| g:tcommentGuessFileType_smarty ................ |g:tcommentGuessFileType_smarty| + g:tcommentGuessFileType_rnoweb ................ |g:tcommentGuessFileType_rnoweb| g:tcommentIgnoreTypes_php ..................... |g:tcommentIgnoreTypes_php| g:tcomment#syntax_substitute .................. |g:tcomment#syntax_substitute| g:tcommentSyntaxMap ........................... |g:tcommentSyntaxMap| g:tcomment#replacements_c ..................... |g:tcomment#replacements_c| + tcomment#GetLineC ............................. |tcomment#GetLineC()| g:tcommentInlineC ............................. |g:tcommentInlineC| g:tcommentBlockC2 ............................. |g:tcommentBlockC2| g:tcomment#replacements_xml ................... |g:tcomment#replacements_xml| @@ -224,6 +218,8 @@ Contents~ tcomment#GetCommentDef ........................ |tcomment#GetCommentDef()| g:tcomment_types .............................. |g:tcomment_types| tcomment#Comment .............................. |tcomment#Comment()| + tcomment#MaybeReuseOptions .................... |tcomment#MaybeReuseOptions()| + tcomment#ResetOption .......................... |tcomment#ResetOption()| tcomment#SetOption ............................ |tcomment#SetOption()| tcomment#Operator ............................. |tcomment#Operator()| tcomment#OperatorLine ......................... |tcomment#OperatorLine()| @@ -324,143 +320,116 @@ g:tcommentTextObjectInlineComment (default: 'ic') 1. a list of key=value pairs 2. 1-2 values for: ?commentBegin, ?commentEnd - *TComment-* -TComment- ... :TComment + *TComment_* +TComment_ ... :TComment - *v_TComment-* -v_TComment- ... :TCommentMaybeInline + *v_TComment_* +v_TComment_ ... :TCommentMaybeInline - *i_TComment-* -i_TComment- ... :TComment + *i_TComment_* +i_TComment_ ... :TComment - *TComment-p* -TComment-p ... m`vip:TComment`` + *TComment_p* +TComment_p ... m`vip:TComment`` - *i_TComment-p* -i_TComment-p ... :norm! m`vip:TComment`` + *i_TComment_p* +i_TComment_p ... :norm! m`vip:TComment`` - *TComment-* -TComment- ... :TComment + *TComment_* +TComment_ ... :TComment - *i_TComment-* -i_TComment- ... :TComment + *i_TComment_* +i_TComment_ ... :TComment - *i_TComment-r* -i_TComment-r ... :TCommentRight + *i_TComment_r* +i_TComment_r ... :TCommentRight - *TComment-r* -TComment-r ... :TCommentRight + *TComment_r* +TComment_r ... :TCommentRight - *v_TComment-i* -v_TComment-i ... :TCommentInline + *v_TComment_i* +v_TComment_i ... :TCommentInline - *TComment-i* -TComment-i ... v:TCommentInline mode=I# + *TComment_i* +TComment_i ... v:TCommentInline mode=I# - *i_TComment-i* -i_TComment-i ... v:TCommentInline mode=# + *i_TComment_i* +i_TComment_i ... v:TCommentInline mode=# - *TComment-b* -TComment-b ... :TCommentBlock + *TComment_b* +TComment_b ... :TCommentBlock - *i_TComment-b* -i_TComment-b ... :TCommentBlock mode=# + *i_TComment_b* +i_TComment_b ... :TCommentBlock mode=# - *TComment-a* -TComment-a ... :TCommentAs + *TComment_a* +TComment_a ... :TCommentAs - *i_TComment-a* -i_TComment-a ... :TCommentAs + *i_TComment_a* +i_TComment_a ... :TCommentAs - *TComment-n* -TComment-n ... :TCommentAs =&ft + *TComment_n* +TComment_n ... :TCommentAs =&ft - *i_TComment-n* -i_TComment-n ... :TCommentAs =&ft + *i_TComment_n* +i_TComment_n ... :TCommentAs =&ft - *TComment-s* -TComment-s ... :TCommentAs =&ft_ + *TComment_s* +TComment_s ... :TCommentAs =&ft_ - *i_TComment-s* -i_TComment-s ... :TCommentAs =&ft_ + *i_TComment_s* +i_TComment_s ... :TCommentAs =&ft_ - *TComment-cc* -TComment-cc ... :call tcomment#SetOption("count", v:count1) + *TComment_cc* +TComment_cc ... :call tcomment#SetOption("count", v:count1) - *TComment-ca* -TComment-ca ... :call tcomment#SetOption("as", input("Comment as: ", &filetype, "customlist,tcomment#Complete")) + *TComment_ca* +TComment_ca ... :call tcomment#SetOption("as", input("Comment as: ", &filetype, "customlist,tcomment#Complete")) - *TComment-__* -TComment-__ ... :TComment + *TComment___* +TComment___ ... :TComment - *x_TComment-__* -x_TComment-__ ... :TCommentMaybeInline + *x_TComment___* +x_TComment___ ... :TCommentMaybeInline - *TComment-_p* -TComment-_p ... vip:TComment + *TComment__p* +TComment__p ... vip:TComment - *TComment-_* -TComment-_ ... :TComment + *TComment__* +TComment__ ... :TComment - *x_TComment-_i* -x_TComment-_i ... :TCommentInline + *x_TComment__i* +x_TComment__i ... :TCommentInline - *TComment-_r* -TComment-_r ... :TCommentRight + *TComment__r* +TComment__r ... :TCommentRight - *TComment-_b* -TComment-_b ... :TCommentBlock + *TComment__b* +TComment__b ... :TCommentBlock - *TComment-_a* -TComment-_a ... :TCommentAs + *TComment__a* +TComment__a ... :TCommentAs - *TComment-_n* -TComment-_n ... :TCommentAs =&ft + *TComment__n* +TComment__n ... :TCommentAs =&ft - *TComment-_s* -TComment-_s ... :TCommentAs =&ft_ + *TComment__s* +TComment__s ... :TCommentAs =&ft_ - *n_TComment-Uncomment* -n_TComment-Uncomment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ + *x_TComment_Uncomment* +x_TComment_Uncomment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline - *n_TComment-Uncommentc* -n_TComment-Uncommentc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ + *x_TComment_Comment* +x_TComment_Comment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! - *n_TComment-Uncommentb* -n_TComment-Uncommentb ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "UB") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ + *v_TComment_ic* +v_TComment_ic ... :call tcomment#TextObjectInlineComment() - *x_TComment-Uncomment* -x_TComment-Uncomment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline + *TComment_ic* +TComment_ic ... :call tcomment#TextObjectInlineComment() - *n_TComment-Comment* -n_TComment-Comment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ - - *n_TComment-Commentc* -n_TComment-Commentc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ - - *n_TComment-Commentb* -n_TComment-Commentb ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "B") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ - - *x_TComment-Comment* -x_TComment-Comment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! - - *v_TComment-ic* -v_TComment-ic ... :call tcomment#TextObjectInlineComment() - - *TComment-ic* -TComment-ic ... :call tcomment#TextObjectInlineComment() - - *n_TComment-gcc* -n_TComment-gcc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@$ - - *n_TComment-gcb* -n_TComment-gcb ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| call tcomment#SetOption("mode_extra", "B") \| set opfunc=tcomment#OperatorLineg@ - - *x_TComment-gc* -x_TComment-gc ... :TCommentMaybeInline - - *n_TComment-gc* -n_TComment-gc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#Operatorg@ + *x_TComment_gc* +x_TComment_gc ... :TCommentMaybeInline ======================================================================== @@ -496,10 +465,14 @@ g:tcommentOpModeExtra (default: '') g:tcommentOptions (default: {}) Other key-value options used by |tcomment#Comment()|. - Example: If you want to put the opening comment marker always in - the first column regardless of the block's indentation, put this - into your |vimrc| file: > + Examples: + Put the opening comment marker always in the first column + regardless of the block's indentation, put this into your |vimrc| + file: > let g:tcommentOptions = {'col': 1} + +< Indent uncommented lines: > + let g:tcommentOptions = {'postprocess_uncomment': 'norm! %sgg=%sgg'} < *g:tcomment#options_comments* @@ -563,9 +536,15 @@ g:tcommentGuessFileType_django (default: 1) *g:tcommentGuessFileType_eruby* g:tcommentGuessFileType_eruby (default: 1) + *g:tcommentGuessFileType_jinja* +g:tcommentGuessFileType_jinja (default: 'html') + *g:tcommentGuessFileType_smarty* g:tcommentGuessFileType_smarty (default: 1) + *g:tcommentGuessFileType_rnoweb* +g:tcommentGuessFileType_rnoweb (default: 'r') + *g:tcommentIgnoreTypes_php* g:tcommentIgnoreTypes_php (default: 'sql') In php files, some syntax regions are wrongly highlighted as sql @@ -586,6 +565,9 @@ g:tcommentSyntaxMap (default: {...}) g:tcomment#replacements_c (default: {...}) Replacements for c filetype. + *tcomment#GetLineC()* +tcomment#GetLineC(...) + *g:tcommentInlineC* g:tcommentInlineC (default: {...}) Generic c-like comments. @@ -710,6 +692,9 @@ tcomment#Comment(beg, end, ...) (default), strip from empty lines only, if 2, always strip whitespace; if 0, don't strip any whitespace + postprocess_uncomment .. Run a |printf()| expression with 2 + placeholders on uncommented lines, e.g. + 'norm! %sgg=%sgg'. 2. 1-2 values for: ?commentPrefix, ?commentPostfix 3. a dictionary (internal use only) @@ -723,10 +708,17 @@ tcomment#Comment(beg, end, ...) v ... visual o ... operator C ... force comment + K ... comment only uncommented lines U ... force uncomment (if U and C are present, U wins) By default, each line in range will be commented by adding the comment prefix and postfix. + *tcomment#MaybeReuseOptions()* +tcomment#MaybeReuseOptions(name) + + *tcomment#ResetOption()* +tcomment#ResetOption() + *tcomment#SetOption()* tcomment#SetOption(name, arg) diff --git a/vimfiles/plugin/SrchRplcHiGrp.vim b/vimfiles/plugin/SrchRplcHiGrp.vim index f28e4c1..2b9667c 100644 --- a/vimfiles/plugin/SrchRplcHiGrp.vim +++ b/vimfiles/plugin/SrchRplcHiGrp.vim @@ -1,8 +1,8 @@ " SrchRplcHiGrp.vim - Search and Replace based on a highlight group " -" Version: 5.0 +" Version: 7.0 " Author: David Fishburn -" Last Changed: 2011 Jan 01 +" Last Changed: 2015 Aug 25 " Created: Tue Dec 02 2003 10:11:07 PM " Description: Search and Replace based on a syntax highlight group " Script: http://www.vim.org/script.php?script_id=848 @@ -17,476 +17,23 @@ " }}} " If syntax is not enabled, do not bother loading this plugin -if exists('g:loaded_srhg') || &cp || !exists("syntax_on") +if exists('g:loaded_srhg') || !exists("syntax_on") finish endif -let g:loaded_srhg = 5 +let g:loaded_srhg = 7 -" Default the highlight group to 0 -let s:srhg_group_id = 0 -let s:srhg_firstline = 0 -let s:srhg_lastline = 0 +" Turn on support for line continuations when creating the script +let s:cpo_save = &cpo +set cpo&vim -" Functions: "{{{ +" Commands: {{{ +command! -range=% -nargs=* -bang SRHiGrp ,call SrchRplcHiGrp#SRHiGrp(1,) +command! -nargs=* -bang SRChooseHiGrp :call SrchRplcHiGrp#SRChooseHiGrp(1,) +command! -nargs=* SRDispHiGrp :call SrchRplcHiGrp#SRDispHiGrp() +command! -range=% -nargs=? -bang SRSearch call SrchRplcHiGrp#SRSearch(1,,,) +"}}} -" SRWarningMsg: -function! SRWarningMsg(msg) "{{{ - echohl WarningMsg - echomsg a:msg - echohl None -endfunction "}}} - -" SRDispHiGrp: -" Echos the currently selected highlight group name to the screen. -" If a parameter is supplied, it will display the message in the -" colour of the group name. -function! SRDispHiGrp(...) "{{{ - if s:srhg_group_id != 0 - if s:srhg_group_id < 0 - let gid = -s:srhg_group_id - else - let gid = s:srhg_group_id - endif - - if a:0 > 0 && strlen(a:1) > 0 - let msg = a:1 - else - let msg = "SRHiGrp - Group ID: " .gid . " Name: " . synIDattr(gid,"name") - endif - - exec 'echohl ' . synIDattr(gid, "name") - exec "echomsg '" . msg . "'" - echohl None - else - echo "No highlight group has been choosen yet" - endif -endfunction "}}} - -" SRChooseHiGrp: -" Sets the script variable s:srhg_group_id to the value -" of the highlight group underneath the current cursor -" position. -function! SRChooseHiGrp(use_top_level) "{{{ - if(a:use_top_level == 1) - let cursynid = -synID(line("."),col("."),1) - else - let cursynid = synIDtrans(synID(line("."),col("."),1)) - endif - - if cursynid == 0 - call s:SRWarningMsg( - \ 'There is no syntax group specified ' . - \ 'under the cursor' - \ ) - else - let s:srhg_group_id = cursynid - call s:SRDispHiGrp() - endif -endfunction "}}} - -" SRSetVisualRange: -" Redefines the visual range if the user called the functions -" with 1,5SR* -function! SRSetVisualRange() "{{{ - " If the current line position is not at the beginning - " or the end of the visual region - if line(".") != line("'<") && line(".") != line("'>") - " Visually select the rows to ensure the correct - " range is operated on. - " This handles the case that SRHiGrp was run as: - " :SRHiGrp - " :1,5SRHiGrp - " instead of: - " :'<,'>SRHiGrp - - exec 'normal! '.s:srhg_firstline."GV" - if s:srhg_lastline > s:srhg_firstline - exec "normal! " . - \ (s:srhg_lastline - s:srhg_firstline) . - \ "j" - endif - exec "normal! \" - endif - return 1 -endfunction "}}} - -" SRPositionWord: -" Places the cursor on the next match following the -" previous line and column passed in. -function! SRPositionWord(prvline, prvcol, bfirsttime) "{{{ - let prvline = a:prvline - let prvcol = a:prvcol - - " echo 'L:'. col("'<") . ' R:' . col("'>") - " echo 'Visual Mode:'. visualmode() - - if (prvline == 0) && (prvcol == 0) - call s:SRSetVisualRange() - let leftcol = col("'<") - 1 - " exe 'norm! '.s:srhg_firstline."G\".leftcol.(leftcol>0 ? 'l' : '' ) - call cursor(s:srhg_firstline,leftcol) - return 1 - endif - - while 1==1 - if visualmode() ==# 'v' - if line(".") == s:srhg_firstline - " let leftcol = col("'<") - 1 - let leftcol = col("'<") - else - let leftcol = 1 - endif - if line(".") == s:srhg_lastline - let rightcol = col("'>") - else - let rightcol = col("$") - endif - elseif visualmode() ==# 'V' - let leftcol = 1 - let rightcol = col("$") - elseif visualmode() ==# "\" - let leftcol = col("'<") - 1 - let leftcol = col("'<") - let rightcol = col("'>") - endif - - " echo 'PrvLine:'.prvline.' prvcol:'.prvcol. - " \' L:'.leftcol.' R:'.rightcol. - " \' VL:'.leftcol.' VR:'.rightcol - - " Position cursor on leftcol - " on each new line based on visual mode - if col(".") == leftcol && a:bfirsttime == 1 - " The cursor is already at it starting position, - " do not move the cursor - elseif col(".") < leftcol - " exe 'norm! '.line(".")."G\".leftcol.(leftcol>0 ? 'l' : '' ) - call cursor(line("."),leftcol) - else - normal! w - endif - - " Add additional check to see if the cursor has - " moved after the above, if not, exit. - if (col(".") == prvcol) && (line(".") == prvline && a:bfirsttime != 1) - return -1 - endif - - - if col(".") >= leftcol && - \ col(".") <= rightcol && - \ line(".") <= s:srhg_lastline - return 1 - elseif col(".") > rightcol && line(".") < s:srhg_lastline - let prvline = prvline + 1 - " Position the cursor on the next line and move - " to the start of the visual region - " exe 'norm! '.prvline."G\".leftcol.(leftcol>0 ? 'l' : '' ) - call cursor(prvline,leftcol) - break - elseif col(".") < leftcol && line(".") <= s:srhg_lastline - " outside of visual area, move to next word - continue - else - return -1 - endif - endwhile - - return 1 -endfunction "}}} - -" SRHiGrp: -" Traverses the region selected and performs all search and -" replaces over the region for the selected highlight group. -function! SRHiGrp(...) range "{{{ - - let s:srhg_firstline = a:firstline - let s:srhg_lastline = a:lastline - - if s:srhg_group_id == 0 - call s:SRWarningMsg( - \ 'You must specify a syntax group name ' . - \ 'by placing the cursor on a character ' . - \ 'that is highlighted the way you want ' . - \ 'and execute :SRChooseHiGrp or ' . - \ ':SRChooseHiGrp!' - \ ) - return - endif - - let group_name = synIDattr(s:srhg_group_id, 'name') - if group_name == '' - let group_name = synIDattr(-s:srhg_group_id, 'name') - endif - - if(a:0 > 0) - if( a:1 == 0 || a:1 == 1) - let match_group = a:1 - endif - else - " Default to operate on syntax groups that match - let match_group = 1 - endif - - if(a:0 > 1) - let match_exp = a:2 - else - let match_exp = '\(\w\+\>\)' - let dialog_msg = "Enter match expression (default word at cursor - " . - \ match_exp . - \ "): " - let l:var_val = inputdialog(dialog_msg, match_exp) - let response = 1 - " Ok or Cancel result in an empty string - if l:var_val == "" - call s:SRWarningMsg( - \ 'You must provide a match expression which ' . - \ 'includes a submatch' - \ ) - return - endif - let match_exp = l:var_val - endif - - if(a:0 > 2) - let replace_exp = a:3 - else - let replace_exp = '\U\1' - let dialog_msg = "Enter replacement expression for the submatch " . - \ "(ie capitalize word - \\U\\1): " - let l:var_val = inputdialog(dialog_msg, replace_exp) - let response = 1 - " Ok or Cancel result in an empty string - if l:var_val == "" - " If empty, check if they want to leave it empty - " of skip this variable - let response = confirm("Your value is empty!" - \ , "&Use blank\n&Cancel", response) - endif - if response == 1 - " Replace the variable with what was entered - let replace_exp = l:var_val - else - " Cancel - return - endif - endif - - " let higrpid = synIDtrans(hlID(s:srhg_group_id)) - let found = 0 - let firsttime = 1 - let lastline = line("$") - let orgline = line(".") - let orgcol = col(".") - let curline = line(".") - let curcol = col(".") - let fenkeep = &fen - let saveSearch = @/ - let saveFoldEnable = &foldenable - setlocal nofoldenable - - " Reset visual range if necessary - call s:SRSetVisualRange() - - " Restore the cursor position since resetting - " the visual area could have moved the cursor - call cursor(orgline, orgcol) - - if s:SRPositionWord(orgline,(orgcol-1), firsttime) == -1 - call s:SRWarningMsg( - \ 'Please reselect the visual area (ie gv)' - \ ) - return - endif - let firsttime = 0 - - let gid = s:srhg_group_id - if(gid < 0) - let gid = -s:srhg_group_id - endif - - while line(".") <= a:lastline - let curcol = col(".") - let curline = line(".") - let cursynid = (s:srhg_group_id < 0) ? - \ -synID(line("."),col("."),1) : - \ synIDtrans(synID(line("."),col("."),1)) - let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1)) - " Useful debugging statement: - " echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".") - - if line(".") == curline - if match_group == 1 && cursynid == gid - " Perform the subtitution, but do not report an error - " if the match fails - exec 's/\%#'.match_exp.'/'.replace_exp.'/e' - " Since this command can move the cursor, put the cursor - " back to its original position - " exe 'norm! '.curline."G\".(curcol-1)."l" - call cursor(curline,curcol) - let found = 1 - elseif match_group == 0 && cursynid != gid - " Perform the subtitution, but do not report an error - " if the match fails - exec 's/\%#'.match_exp.'/'.replace_exp.'/e' - " Since this command can move the cursor, put the cursor - " back to its original position - exe 'norm! '.curline."G\".(curcol-1)."l" - endif - endif - - let prvcol = curcol - let prvline = curline - if s:SRPositionWord(prvline, prvcol, firsttime) == -1 - break - endif - - endwhile - - if found == 0 - call s:SRWarningMsg('Did not find highlight group: "'.group_name.'"') - endif - - " cleanup - let &fen = fenkeep - if foldlevel(".") > 0 - norm! zO - endif - let &foldenable = saveFoldEnable - unlet curcol - " unlet higrpid - unlet lastline - let @/ = saveSearch - if exists("prvcol") - unlet prvcol - endif -endfunction "}}} - -"}}} - -" SRSearch: -" Finds the next occurrence of the highlight group within -" the range selected from the current cursor position. -function! SRSearch(fline, lline, ...) "{{{ - - let s:srhg_firstline = a:fline - let s:srhg_lastline = a:lline - - if a:0 > 0 && strlen(a:1) > 0 - let s:srhg_group_id = -hlID(a:1) - let group_name = a:1 - else - let group_name = synIDattr(-s:srhg_group_id, 'name') - endif - - if s:srhg_group_id == 0 - call s:SRWarningMsg( - \ 'You must specify a syntax group name ' . - \ 'on the command line ( to complete) ' . - \ 'or by placing the cursor on a character ' . - \ 'that is highlighted the way you want ' . - \ 'and execute :SRChooseHiGrp or ' . - \ ':SRChooseHiGrp!' - \ ) - return - endif - - " let higrpid = synIDtrans(hlID(s:srhg_group_id)) - let found = 0 - let lastline = line("$") - let orgline = line(".") - let orgcol = col(".") - let curline = line(".") - let curcol = col(".") - let fenkeep = &fen - let saveSearch = @/ - let saveFoldEnable = &foldenable - setlocal nofoldenable - " Set this to false, to force the search to move the cursor - " this prevents the user from having to manually move the - " cursor between recursive calls. - let firsttime = 0 - - " Reset visual range if necessary - call s:SRSetVisualRange() - - " Restore the cursor position since resetting - " the visual area could have moved the cursor - call cursor(orgline, orgcol) - - if s:SRPositionWord(orgline,orgcol,firsttime) == -1 - call s:SRWarningMsg( - \ 'Please reselect the visual area (ie gv)' - \ ) - return - endif - - let gid = s:srhg_group_id - if(gid < 0) - let gid = -s:srhg_group_id - endif - - while line(".") <= s:srhg_lastline - let curcol = col(".") - let curline = line(".") - let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1)) - let prevsynid = (s:srhg_group_id < 0) ? synID(line("."),(col(".")-1),1) : synIDtrans(synID(line("."),(col(".")-1),1)) - " Useful debugging statement: - " echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".") - - " if line(".") == curline - " Check the current syn id against the previous columns syn id. - " If they are the same, assume we are still part of the same "string" - " and we need to continue searching until we find a gap between the - " highlight groups indicating we are actually on our next match - " (Sergio). - if line(".") == curline && (cursynid != prevsynid) - if cursynid == gid - call s:SRDispHiGrp( "SRSearch - Match found - Group ID: " . - \ gid . " Name: " . synIDattr(gid,"name") - \ ) - let found = 1 - break - endif - endif - - let prvcol = curcol - let prvline = curline - if s:SRPositionWord(prvline, prvcol, firsttime) == -1 - break - endif - - endwhile - - if found == 0 - call s:SRDispHiGrp( "SRSearch - Match NOT found - Group ID: " . - \ gid . " Name: " . synIDattr(gid,"name") - \ ) - call cursor(orgline, orgcol) - endif - - " cleanup - let &fen = fenkeep - if foldlevel(".") > 0 - norm! zO - endif - let &foldenable = saveFoldEnable - unlet curcol - " unlet higrpid - unlet lastline - let @/ = saveSearch - if exists("prvcol") - unlet prvcol - endif -endfunction "}}} - -"}}} - -" Commands: {{{ -command! -range -bang -nargs=* SRHiGrp ,call s:SRHiGrp(1,) -command! -bang -nargs=0 SRChooseHiGrp :call s:SRChooseHiGrp(1) -command! -nargs=0 SRDispHiGrp :call s:SRDispHiGrp() -command! -range=% -nargs=? -complete=highlight SRSearch call s:SRSearch(,,) -"}}} +let &cpo = s:cpo_save +unlet s:cpo_save " vim:fdm=marker:nowrap:ts=4: diff --git a/vimfiles/plugin/diffchar.vim b/vimfiles/plugin/diffchar.vim index 64411b1..1cf62f2 100644 --- a/vimfiles/plugin/diffchar.vim +++ b/vimfiles/plugin/diffchar.vim @@ -1,255 +1,46 @@ -" diffchar.vim - Highlight the exact differences, based on characters and words +" diffchar.vim : Highlight the exact differences, based on characters and words " -" This plugin has been developed in order to make diff mode more useful. -" DiffText does not show the exact difference, but this plugin will -" highlight its difference, character by character - so called DiffChar. +" ____ _ ____ ____ _____ _ _ _____ ____ +" | | | || || || || | | || _ || _ | +" | _ || || __|| __|| || | | || | | || | || +" | | | || || |__ | |__ | __|| |_| || |_| || |_||_ +" | |_| || || __|| __|| | | || || __ | +" | || || | | | | |__ | _ || _ || | | | +" |____| |_||_| |_| |_____||_| |_||_| |_||_| |_| " -" Use this plugin just after diff command. DiffText area will be narrowed -" down to show the DiffChar. You can use this plugin in non-diff usual -" mode as well. -" -" For example, diff command shows: (<|DiffText area|>) -" -" (file A) The <|swift brown fox jumped over the lazy|> dog. -" (file B) The <|lazy fox jumped over the swift brown|> dog. -" -" then this plugin will narrow down the DiffText area: -" -" (file A) The <|swift brown|> fox jumped over the <|lazy|> dog. -" (file B) The <|lazy|> fox jumped over the <|swift brown|> dog. -" -" Since update 4.7, vim is able to automatically show the exact differences -" on diff mode. -" -" This plugin has been always positively supporting mulltibyte characters. -" -" Sample commands -" :[range]SDChar - Highlight difference units for [range] -" :[range]RDChar - Reset the highlight of difference units for [range] -" -" Configurable sample keymaps -" ToggleDiffCharAllLines (default: ) -" toggle the highlight/reset of difference units for all lines -" ToggleDiffCharCurrentLine (default: ) -" toggle the highlight/reset of difference units for current line -" JumpDiffCharPrevStart (default: [b) -" jump cursor to the start position of the previous difference unit -" JumpDiffCharNextStart (default: ]b) -" jump cursor to the start position of the next difference unit -" JumpDiffCharPrevEnd (default: [e) -" jump cursor to the end position of the previous difference unit -" JumpDiffCharNextEnd (default: ]e) -" jump cursor to the end position of the next difference unit -" -" Global variables (and tab local variables when using t:) -" g:DiffUnit - type of difference unit -" "Char" : any single character (default) -" "Word1" : \w\+ word and any \W single character -" "Word2" : non-space and space words -" "Word3" : \< or \> character class boundaries -" "CSV(,)" : separated by a character such as ',', ';', and '\t' -" g:DiffColors - matching colors for changed unit pairs -" 0 : always DiffText (default) -" 1 : 4 colors in fixed order -" 2 : 8 colors in fixed order -" 3 : 16 colors in fixed order -" 100 : all available colors in dynamic random order -" (notes : always DiffAdd for added units) -" g:DiffUpdate - interactively updating of highlightings while editing -" 0 : disable (default) -" 1 : enable -" (notes : available on vim 7.4) -" g:DiffAlgorithm - difference algorithm -" "ONP" : S.Wu, U.Manber, G.Myers and W.Miller, -" "An O(NP) Sequence Comparison Algorithm" (default) -" "OND" : E.W.Myers, "An O(ND) Difference Algorithm and Its Variations" -" "Basic" : basic algorithm using edit graph and shortest edit distance -" -" DiffCharExpr(mxi, exd) function for the diffexpr option -" mxi: the maximum number of total lines of both windows to apply internal -" algorithm, apply external diff command when more lines -" exd: 1 = initially show exact differences, 0 = vim original ones -" -" Update : 4.9 -" * Fixed DiffCharExpr() to check the number of total lines, not different -" lines only, of both windows and apply either internal algorithm or -" external diff command, in order to keep the appropriate performance -" for large files. -" -" Update : 4.81 -" * Enhanced to make DiffCharExpr() a bit faster by using uniq() or so. -" -" Update : 4.8 -" * Enhanced to set the threshold value on DiffCharExpr() to check how many -" differences and then apply either of internal algorithm or external diff -" command. The default for diffexpr option using DiffCharExpr() is changed -" to use this threshold, 200 - apply internal if less than 200 differences, -" apply external if more. -" * Changed the way to select windows when more than 2 windows in the page. -" - automatically select the diff mode's next (wincmd w) window, if any, -" in addition to the current window -" - can select any of splitted windows as vim can do for diff -" -" Update : 4.7 -" * Enhanced to set DiffCharExpr() to the diffexpr option, if it is empty. -" When diff mode begins, vim calls this function which finds differences by -" this plugin's internal diff algorithm (default) and then initially shows -" the exact differences (default). You can also explicitly set this function -" to the option with different arguments. -" * Enhanced to make the key mappings configurable. -" For example, the default can be modified by: -" nmap "your favorite key" ToggleDiffCharAllLines -" * Fixed to correctly adjust the position of difference units when diffopt's -" iwhite option is enabled. -" -" Update : 4.6 -" * Fixed to correctly show the colors of changed units in one-by-one defined -" order of g:DiffColors. Since an added unit was improperly counted as -" changed one, some colors were skipped and not shown. The first changed -" unit is now always highlighted with DiffText in any color mode. -" -" Update : 4.5 -" * Fixed to trace the differences until the end of the units. Previously -" the last same units were skipped, so last added units were sometimes shown -" as changed ones (eg: the last "swift brown" on above were shown as changed -" units but now shows "brown" as added ones). -" * Enhanced to use your global variables if defined in vimrc. -" -" Update : 4.4 -" * Enhanced to follow diffopt's icase and iwhite options for both diff and -" non-diff modes (ignorecase option is not used). Previously, it has been -" always case and space/tab sensitive. -" * Implemented to highlight the difference units using a new matchaddpos() -" function, introduced in 7.4.330, when available to draw faster. -" -" Update : 4.3 -" * Enhanced to differently show added/deleted/changed difference units -" with original diff highlightings. -" - added units will be always highlighted with DiffAdd. -" - changed units will be highlighted based on the g:DiffColors (and -" t:DiffColors) variable, but DiffText is always used for the first -" changed unit. -" - when jumping cursor by "[b"/"]b" or "[e"/"]e" on the added unit, it -" highlights around the corresponding deleted units with a cursor-type color -" in another window, and echoes a diff-delete filler with DiffDelete, -" along with common characters on both sides (e.g. a-----b). -" -" Update : 4.2 -" * Enhanced to update the highlighted DiffChar units while editing. -" A g:DiffUpdate (and t:DiffUpdate) variable enables and disables (default) -" this update behavior. If a text line was added/deleted, reset all the -" highlightings. This feature is available on vim 7.4. -" -" Update : 4.1 -" * Implemented to echo a matching difference unit with its color when jumping -" cursor by "[b"/"]b" or "[e"/"]e". -" * Fixed defects: not using the new uniq() function introduced in vim 7.4. -" -" Update : 4.0 -" * Enhanced to easily find a corresponding pair of each difference unit. -" - each unit pair will be shown in individual same color on both windows. -" A g:DiffColors (and t:DiffColors) variable is a type of matching colors, -" 0 (default) for always 1 color as before, 1/2/3 for 4/8/16 colors in -" fixed order, and 100 for all available colors in dynamic random order. -" - when jumping cursor by "[b"/"]b" or "[e"/"]e" in either window, -" the start or end position of a matching unit will be highlighted with -" a cursor-type color in another window. -" -" Update : 3.6 -" * Added two g:DiffUnit (and t:DiffUnit) types. "Word3" will split at the -" \< or \> boundaries, which can separate based on the character class like -" CJK, Hiragana, Katakana, Hangul, full width symbols and so on. And "CSV(c)" -" will split the units by a specified character "c". For example, "CSV(,)" -" and "CSV(\t)" can be used for comma and tab separated text. -" -" Update : 3.5 -" * Fixed defects: DiffChar highlighting units do not override/hide hlsearch. -" -" Update : 3.4 -" * Enhanced to support individual DiffChar handling on each tab page. -" Difference unit and algorithm can also be set page by page using -" tab page local variables, t:DiffUnit and t:DiffAlgorithm. -" -" Update : 3.3 -" * Enhanced to jump cursor to the DiffChar highlighting units. Sample keymaps -" "]b" and "[b" will move cursor forwards to the next and backwards to the -" previous start positions. And "]e" and "[e" will move to the end positions. -" -" Update : 3.2 -" * Enhanced to follow diff mode without any limitations. Compare between -" the corresponding DiffChange lines on both windows and properly handle -" DiffAdd and DiffDelete lines. -" -" Update : 3.1 -" * Enhanced to show/reset/toggle DiffChar highlightings on individual line -" by line. -" * Implemented the window layout handling. -" - the DiffChar'ed windows will remain the highlightings even if the -" window position is rotated/replaced/moved and another new window opens. -" - if either DiffChar'ed window is closed, reset all the DiffChar -" highlightings on another window. -" * Removed limitations: -" - when more than 2 windows exist, current and next (wincmd w) windows -" will be selected. -" - if the specified numbers of lines are different in both windows, ignore -" the redundant lines and continue to compare the text on the same lines. -" - RDChar sample command has a range attribute (e.g. %RDChar). -" * Fixed defects: -" - reset just DiffChar highlightings only and remain others. -" -" Update : 3.0 -" * Implemented word by word differences. A g:DiffUnit variable is a type of -" a difference unit. Its default is "Char", which will trace character -" by character as before. "Word1" will split into \w\+ words and -" any \W single characters. And "Word2" will separate the units at the -" \s\+ space boundaries. -" * Improved the performance around 10%. -" -" Update : 2.1 -" * Coding changes in the O(NP) function for readability. -" -" Update : 2.0 -" * Implemented the O(NP) and O(ND) Difference algorithms to improve the -" performance. This update uses the O(NP) by default, and can be changed -" to the O(ND) if necessary, or to the basic algorithm implemented in -" the initial version. -" -" Author: Rick Howe -" Last Change: 2015/02/18 -" Created: -" Requires: -" Version: 4.9 +" Last Change: 2016/03/09 +" Version: 6.1 +" Author: Rick Howe -if exists("g:loaded_diffchar") +if exists('g:loaded_diffchar') finish endif -let g:loaded_diffchar = 4.9 +let g:loaded_diffchar = 6.1 let s:save_cpo = &cpo set cpo&vim -" Sample commands -command! -range SDChar call s:ShowDiffChar(, ) -command! -range RDChar call s:ResetDiffChar(, ) +" Commands +command! -range SDChar call diffchar#ShowDiffChar(range(, )) +command! -range RDChar call diffchar#ResetDiffChar(range(, )) +command! -range TDChar call diffchar#ToggleDiffChar(range(, )) -" Sample keymaps -nnoremap ToggleDiffCharAllLines - \ :call ToggleDiffChar(1, line('$')) -nnoremap ToggleDiffCharCurrentLine - \ :call ToggleDiffChar(line('.')) +" Configurable Keymaps +noremap ToggleDiffCharAllLines :%TDChar +noremap ToggleDiffCharCurrentLine :TDChar nnoremap JumpDiffCharPrevStart - \ :call JumpDiffChar(0, 1) + \ :call diffchar#JumpDiffChar(0, 1) nnoremap JumpDiffCharNextStart - \ :call JumpDiffChar(1, 1) + \ :call diffchar#JumpDiffChar(1, 1) nnoremap JumpDiffCharPrevEnd - \ :call JumpDiffChar(0, 0) + \ :call diffchar#JumpDiffChar(0, 0) nnoremap JumpDiffCharNextEnd - \ :call JumpDiffChar(1, 0) -if !hasmapto('ToggleDiffCharAllLines', 'n') - nmap ToggleDiffCharAllLines + \ :call diffchar#JumpDiffChar(1, 0) +if !hasmapto('ToggleDiffCharAllLines', 'nv') + map ToggleDiffCharAllLines endif -if !hasmapto('ToggleDiffCharCurrentLine', 'n') - nmap ToggleDiffCharCurrentLine +if !hasmapto('ToggleDiffCharCurrentLine', 'nv') + map ToggleDiffCharCurrentLine endif if !hasmapto('JumpDiffCharPrevStart', 'n') nmap [b JumpDiffCharPrevStart @@ -265,16 +56,16 @@ if !hasmapto('JumpDiffCharNextEnd', 'n') endif " Set a difference unit type -if !exists("g:DiffUnit") -let g:DiffUnit = "Char" " any single character -" let g:DiffUnit = "Word1" " \w\+ word and any \W single character -" let g:DiffUnit = "Word2" " non-space and space words -" let g:DiffUnit = "Word3" " \< or \> character class boundaries -" let g:DiffUnit = "CSV(,)" " character separated by (,;\t) +if !exists('g:DiffUnit') +let g:DiffUnit = 'Word1' " \w\+ word and any \W single character +" let g:DiffUnit = 'Word2' " non-space and space words +" let g:DiffUnit = 'Word3' " \< or \> character class boundaries +" let g:DiffUnit = 'Char' " any single character +" let g:DiffUnit = 'CSV(,)' " split characters endif " Set a difference unit matching colors -if !exists("g:DiffColors") +if !exists(':DiffColors') let g:DiffColors = 0 " always 1 color " let g:DiffColors = 1 " 4 colors in fixed order " let g:DiffColors = 2 " 8 colors in fixed order @@ -283,965 +74,37 @@ let g:DiffColors = 0 " always 1 color endif " Set a difference unit updating while editing -if !exists("g:DiffUpdate") -if exists("##TextChanged") && exists("##TextChangedI") -let g:DiffUpdate = 0 " disable -" let g:DiffUpdate = 1 " enable -endif +if !exists('g:DiffUpdate') +let g:DiffUpdate = 1 " enable +" let g:DiffUpdate = 0 " disable endif -" Set a difference algorithm -if !exists("g:DiffAlgorithm") -let g:DiffAlgorithm = "ONP" -" let g:DiffAlgorithm = "OND" -" let g:DiffAlgorithm = "Basic" +" Set a time length (ms) to apply this plugin's internal algorithm first +if !exists('g:DiffSplitTime') +let g:DiffSplitTime = 100 " when timeout, split to diff command +" let g:DiffSplitTime = 0 " always apply diff command only endif -" Set a diff expression -if !exists("g:DiffExpr") || g:DiffExpr -if empty(&diffexpr) -let &diffexpr = "DiffCharExpr(200, 1)" " set # of lines and show exact diffs -" let &diffexpr = "DiffCharExpr(0, 0)" " apply ext cmd and show vim original -endif +" Set a diff mode synchronization to show/reset exact differences +if !exists('g:DiffModeSync') +let g:DiffModeSync = 1 " enable +" let g:DiffModeSync = 0 " disable endif -function! DiffCharExpr(mxi, exd) - " read both files to be diff traced - let [f1, f2] = [readfile(v:fname_in), readfile(v:fname_new)] - - " find the fist diff trial call and return here - if [f1, f2] == [["line1"], ["line2"]] - call writefile(["1c1"], v:fname_out) - return - endif - - " get a list of diff commands - let dfcmd = (len(f1 + f2) <= a:mxi) ? - \s:ApplyIntDiffAlgorithm(f1, f2) : s:ApplyExtDiffCommand() - - " write to output file - call writefile(dfcmd, v:fname_out) - - " return if no need to show exact differences - if exists("t:DChar") || !a:exd | return | endif - - " find 'c' command and extract the line to be replaced - let [r1, r2] = [[], []] - let cpt = '^\(\d\+\)\%(,\(\d\+\)\)\=c\(\d\+\)\%(,\(\d\+\)\)\=$' - let rep = '\1 \2 \3 \4' - for ct in filter(dfcmd, 'v:val =~ "c"') - let cl = split(substitute(ct, cpt, rep, ''), ' ', 1) - let nr = min([empty(cl[1]) ? 0 : cl[1] - cl[0], - \empty(cl[3]) ? 0 : cl[3] - cl[2]]) - let [r1, r2] += [range(cl[0], cl[0] + nr), - \range(cl[2], cl[2] + nr)] - endfor - - " return if no replaced lines - if empty(r1) | return | endif - - " initialize diffchar - if s:InitializeDiffChar() == -1 | return | endif - - " check which window is v:fname_in/v:fname_new and - " set those window numbers and replaced lines - let t:DChar.win = {} - let t:DChar.vdl = {} - for w in range(1, winnr('$')) - if !getwinvar(w, "&diff") | continue | endif - if getbufline(winbufnr(w), r1[0]) ==# [f1[r1[0] - 1]] - let [t:DChar.win[1], t:DChar.vdl[1]] = [w, r1] - elseif getbufline(winbufnr(w), r2[0]) ==# [f2[r2[0] - 1]] - let [t:DChar.win[2], t:DChar.vdl[2]] = [w, r2] - endif - endfor - - " highlight the exact differences on the replaced lines - if exists("t:DChar.win[1]") && exists("t:DChar.win[2]") - call s:MarkDiffCharID(1) - call s:ShowDiffChar(1, line('$')) - else - unlet t:DChar - endif -endfunction - -function! s:ApplyIntDiffAlgorithm(f1, f2) - " handle icase and iwhite diff options - let save_igc = &ignorecase - let &ignorecase = (&diffopt =~ "icase") - if &diffopt =~ "iwhite" - for k in [1, 2] - let f{k} = copy(a:f{k}) - call map(f{k}, 'substitute(v:val, "\\s\\+", " ", "g")') - call map(f{k}, 'substitute(v:val, "\\s\\+$", "", "")') - endfor - else - let [f1, f2] = [a:f1, a:f2] - endif - - " trace the diff lines between f1/f2 - let dfcmd = [] - let [d1, d2, l1, l2] = [[], [], 1, 1] - let [ex, nu] = ['', 0] - for [ed, ut] in s:TraceDiffChar{g:DiffAlgorithm}(f1, f2) - \+ [['=', ''], ['', '']] - if ex == ed | let nu += 1 | continue | endif - if ex == '=' - let ee = [empty(d1), empty(d2)] - if ee == [0, 0] - let dfcmd += [((d1[0] == d1[-1]) ? - \d1[0] : d1[0] . ',' . d1[-1]) . 'c' . - \((d2[0] == d2[-1]) ? - \d2[0] : d2[0] . ',' . d2[-1])] - elseif ee == [0, 1] - let dfcmd += [((d1[0] == d1[-1]) ? - \d1[0] : d1[0] . ',' . d1[-1]) - \. 'd' . (l2 - 1)] - elseif ee == [1, 0] - let dfcmd += [(l1 - 1) . 'a' . - \((d2[0] == d2[-1]) ? - \d2[0] : d2[0] . ',' . d2[-1])] - endif - let [d1, d2] = [[], []] - let [l1, l2] += [nu + 1, nu + 1] - elseif ex == '-' - let [d1, l1] += [[l1, l1 + nu], nu + 1] - elseif ex == '+' - let [d2, l2] += [[l2, l2 + nu], nu + 1] - endif - let [ex, nu] = [ed, 0] - endfor - - " restore ignorecase flag - let &ignorecase = save_igc - - return dfcmd -endfunction - -function! s:ApplyExtDiffCommand() - " execute a diff command - let opt = "-a --binary " - if &diffopt =~ "icase" | let opt .= "-i " | endif - if &diffopt =~ "iwhite" | let opt .= "-b " | endif - let dfout = system("diff " . opt . v:fname_in . " " . v:fname_new) - - " return diff commands only - return filter(split(dfout, '\n'), 'v:val =~ "^\\d"') -endfunction - -function! s:InitializeDiffChar() - if winnr('$') < 2 - echo "Need more windows on this tab page!" - return -1 - endif - - " define a DiffChar dictionary on this tab page - let t:DChar = {} - - " select current window and next diff mode window if possible - let t:DChar.win = {} - let cwin = winnr() - let w = 0 - while 1 - let nwin = (cwin + w) % winnr('$') + 1 - if nwin == cwin - let nwin = cwin % winnr('$') + 1 - break - endif - if getwinvar(nwin, "&diff") | break | endif - let w += 1 - endwhile - let [t:DChar.win[1], t:DChar.win[2]] = [cwin, nwin] - call s:MarkDiffCharID(1) - - " find corresponding DiffChange/DiffText lines on diff mode windows - let t:DChar.vdl = {} - let dh = [hlID("DiffChange"), hlID("DiffText")] - for k in [1, 2] - if getwinvar(t:DChar.win[k], "&diff") - exec t:DChar.win[k] . "wincmd w" - let t:DChar.vdl[k] = [] - for l in range(1, line('$')) - if index(dh, diff_hlID(l, 1)) != -1 - let t:DChar.vdl[k] += [l] - endif - endfor - else - unlet t:DChar.vdl - break - endif - endfor - exec cwin . "wincmd w" - - " set ignorecase and ignorespace flags - let t:DChar.igc = (&diffopt =~ "icase") - let t:DChar.igs = (&diffopt =~ "iwhite") - - " set line and its highlight id record - let t:DChar.mid = {} - let [t:DChar.mid[1], t:DChar.mid[2]] = [{}, {}] - - " set highlighted lines and columns record - let t:DChar.hlc = {} - let [t:DChar.hlc[1], t:DChar.hlc[2]] = [{}, {}] - - " set a difference unit type on this tab page and set a split pattern - if !exists("t:DiffUnit") - let t:DiffUnit = g:DiffUnit - endif - if t:DiffUnit == "Char" " any single character - let t:DChar.spt = t:DChar.igs ? '\(\s\+\|.\)\zs' : '\zs' - elseif t:DiffUnit == "Word1" " \w\+ word and any \W character - let t:DChar.spt = t:DChar.igs ? '\(\s\+\|\w\+\|\W\)\zs' : - \'\(\w\+\|\W\)\zs' - elseif t:DiffUnit == "Word2" " non-space and space words - let t:DChar.spt = '\(\s\+\|\S\+\)\zs' - elseif t:DiffUnit == "Word3" " \< or \> boundaries - let t:DChar.spt = '\<\|\>' - elseif t:DiffUnit =~ '^CSV(.\+)$' " character separated - let s = substitute(t:DiffUnit, '^CSV(\(.\+\))$', '\1', '') - let t:DChar.spt = '\(\([^\'. s . ']\+\)\|\' . s . '\)\zs' - else - let t:DChar.spt = t:DChar.igs ? '\(\s\+\|.\)\zs' : '\zs' - echo 'Not a valid difference unit type. Use "Char" instead.' - endif - - " set a difference algorithm on this tab page - if !exists("t:DiffAlgorithm") - let t:DiffAlgorithm = g:DiffAlgorithm - endif - - " set a matching pair cursor id on this tab page - let t:DChar.mpc = {} - - " set a difference matching colors on this tab page - if !exists("t:DiffColors") - let t:DiffColors = g:DiffColors - endif - - " set types of difference matching colors from available highlights - let t:DChar.dmc = ["DiffText"] - if t:DiffColors == 1 - let t:DChar.dmc += ["NonText", "Search", "VisualNOS"] - elseif t:DiffColors == 2 - let t:DChar.dmc += ["NonText", "Search", "VisualNOS", - \"ErrorMsg", "MoreMsg", "TabLine", "Title"] - elseif t:DiffColors == 3 - let t:DChar.dmc += ["NonText", "Search", "VisualNOS", - \"ErrorMsg", "MoreMsg", "TabLine", "Title", - \"StatusLine", "WarningMsg", "Conceal", "SpecialKey", - \"ColorColumn", "ModeMsg", "SignColumn", "CursorLineNr"] - elseif t:DiffColors == 100 - redir => hl | silent highlight | redir END - let h = map(filter(split(hl, '\n'), - \'v:val =~ "^\\S" && v:val =~ "="'), 'split(v:val)[0]') - unlet h[index(h, "DiffAdd")] - unlet h[index(h, "DiffDelete")] - unlet h[index(h, "DiffChange")] - unlet h[index(h, "DiffText")] - unlet h[index(h, hlexists("Cursor") ? "Cursor" : "MatchParen")] - while !empty(h) - let r = localtime() % len(h) - let t:DChar.dmc += [h[r]] | unlet h[r] - endwhile - endif - - " set a difference unit updating on this tab page - " and a record of line string values - if exists("##TextChanged") && exists("##TextChangedI") - if !exists("t:DiffUpdate") - let t:DiffUpdate = g:DiffUpdate - endif - if t:DiffUpdate - let t:DChar.lsv = {} - endif - endif -endfunction - -function! s:ShowDiffChar(sl, el) - " initialize when t:DChar is not defined - if !exists("t:DChar") && s:InitializeDiffChar() == -1 | return | endif - - call s:RefreshDiffCharWin() - - let cwin = winnr() - if cwin == t:DChar.win[1] | let k = 1 - elseif cwin == t:DChar.win[2] | let k = 2 - else | return | endif - - " set a possible DiffChar line list between sl and el - if exists("t:DChar.vdl") " diff mode - let [d1, d2] = s:GetDiffModeLines(k, a:sl, a:el) - else " non-diff mode - let [d1, d2] = [range(a:sl, a:el), range(a:sl, a:el)] - endif - - " remove already highlighted lines and get those text - for k in [1, 2] - let hl = map(keys(t:DChar.hlc[k]), 'eval(v:val)') - for n in range(len(d{k})) - if index(hl, d{k}[n]) != -1 - let d{k}[n] = -1 - endif - endfor - call filter(d{k}, 'v:val != -1') - - let t{k} = [] - for d in d{k} - let t{k} += getbufline(winbufnr(t:DChar.win[k]), d) - endfor - let n{k} = len(t{k}) - endfor - - " remove redundant lines in either window - if n1 > n2 - unlet t1[n2 - n1 :] - unlet d1[n2 - n1 :] - let n1 = n2 - elseif n1 < n2 - unlet t2[n1 - n2 :] - unlet d2[n1 - n2 :] - let n2 = n1 - endif - - " set ignorecase flag - let save_igc = &ignorecase - let &ignorecase = t:DChar.igc - - " a list of different lines and columns - let [lc1, lc2] = [{}, {}] - - " compare each line and trace difference units - for n in range(n1) - " split each line to the difference units - let [u1, u2] = - \[split(t1[n], t:DChar.spt), split(t2[n], t:DChar.spt)] - - " set unit lists for tracing - let [u1t, u2t] = [copy(u1), copy(u2)] - if t:DChar.igs - " convert \s\+ to a single space and - " remove/unlet the last \s\+$ on ignorespace mode - for k in [1, 2] - if !empty(u{k}t) - call map(u{k}t, 'substitute - \(v:val, "\\s\\+", " ", "g")') - let u{k}t[-1] = substitute - \(u{k}t[-1], '\s\+$', '', '') - if empty(u{k}t[-1]) - unlet u{k}t[-1] - endif - endif - endfor - endif - if u1t == u2t | continue | endif - - " get first same units out to trace - let ns = min([len(u1t), len(u2t)]) - let fu = 0 - while fu < ns && u1t[fu] == u2t[fu] - let fu += 1 - endwhile - let [u1t, u2t] = [u1t[fu :], u2t[fu :]] - - " trace the actual diffference units - let [c1, c2, h1, h2, p1, p2] = [[], [], [], [], fu, fu] - let [l1, l2] = (fu == 0) ? [0, 0] : - \[len(join(u1[: fu - 1], '')), - \len(join(u2[: fu - 1], ''))] - let [nc, na] = [0, 0] " changed and added counts - let [ex, nu] = ['', 0] - for [ed, ut] in s:TraceDiffChar{t:DiffAlgorithm}(u1t, u2t) - \+ [['=', ''], ['', '']] - if ex == ed | let nu += 1 | continue | endif - if ex == '=' - let ee = [empty(h1), empty(h2)] - if ee == [0, 0] - let [c1, c2] += [ - \[['c', nc, [h1[0], h1[-1]]]], - \[['c', nc, [h2[0], h2[-1]]]]] - let nc += 1 - elseif ee == [0, 1] - let [c1, c2] += [ - \[['a', na, [h1[0], h1[-1]]]], - \[['d', na, [l2, l2 + 1]]]] - let na += 1 - elseif ee == [1, 0] - let [c1, c2] += [ - \[['d', na, [l1, l1 + 1]]], - \[['a', na, [h2[0], h2[-1]]]]] - let na += 1 - endif - let [h1, h2] = [[], []] - let [l1, l2, p1, p2] += [ - \len(join(u1[p1 : p1 + nu], '')), - \len(join(u2[p2 : p2 + nu], '')), - \nu + 1, nu + 1] - elseif ex == '-' - let ul = len(join(u1[p1 : p1 + nu], '')) - let [h1, l1, p1] += - \[[l1 + 1, l1 + ul], ul, nu + 1] - elseif ex == '+' - let ul = len(join(u2[p2 : p2 + nu], '')) - let [h2, l2, p2] += - \[[l2 + 1, l2 + ul], ul, nu + 1] - endif - let [ex, nu] = [ed, 0] - endfor - - " add different lines and columns to the list - if !empty(c1) || !empty(c2) - let [lc1[d1[n]], lc2[d2[n]]] = [c1, c2] - endif - endfor - - " restore ignorecase flag - let &ignorecase = save_igc - - " highlight lines and columns and set events - for k in [1, 2] - exec t:DChar.win[k] . "wincmd w" - call s:HighlightDiffChar(k, lc{k}) - if empty(t:DChar.hlc[k]) | continue | endif - let buf = winbufnr(t:DChar.win[k]) - if !exists("#BufWinLeave#") - exec "au BufWinLeave call s:ResetDiffChar(1, line('$'))" - endif - if exists("t:DChar.lsv") - if !exists("#TextChanged#") - exec "au TextChanged call s:UpdateDiffChar(" . k . ")" - endif - if !exists("#TextChangedI#") - exec "au TextChangedI call s:UpdateDiffChar(" . k . ")" - endif - let t:DChar.lsv[k] = s:GetLineStrValues(k) - endif - endfor - exec cwin . "wincmd w" - - " reset t:DChar when no DiffChar highlightings in either buffer - if empty(t:DChar.hlc[1]) || empty(t:DChar.hlc[2]) - call s:MarkDiffCharID(0) - unlet t:DChar - endif -endfunction - -function! s:ResetDiffChar(sl, el) - if !exists("t:DChar") | return | endif - - call s:RefreshDiffCharWin() - - let cwin = winnr() - if cwin == t:DChar.win[1] | let k = 1 - elseif cwin == t:DChar.win[2] | let k = 2 - else | return | endif - - " set a possible DiffChar line list between sl and el - if exists("t:DChar.vdl") " diff mode - let [d1, d2] = s:GetDiffModeLines(k, a:sl, a:el) - else " non-diff mode - let [d1, d2] = [range(a:sl, a:el), range(a:sl, a:el)] - endif - - for k in [1, 2] - " remove not highlighted lines - let hl = map(keys(t:DChar.hlc[k]), 'eval(v:val)') - for n in range(len(d{k})) - if index(hl, d{k}[n]) == -1 - let d{k}[n] = -1 - endif - endfor - call filter(d{k}, 'v:val != -1') - - exec t:DChar.win[k] . "wincmd w" - call s:ClearDiffChar(k, d{k}) - - " when no highlight exists, reset events - if empty(t:DChar.hlc[k]) - let buf = winbufnr(t:DChar.win[k]) - exec "au! BufWinLeave " - if exists("t:DChar.lsv") - exec "au! TextChanged " - exec "au! TextChangedI " - unlet t:DChar.lsv[k] - endif - call s:ResetDiffCharPair(k) - endif - endfor - exec cwin . "wincmd w" - - " reset t:DChar when no DiffChar highlightings in either buffer - if empty(t:DChar.hlc[1]) || empty(t:DChar.hlc[2]) - call s:MarkDiffCharID(0) - unlet t:DChar - endif -endfunction - -function! s:ToggleDiffChar(...) - if a:0 == 1 | let sl = a:1 | let el = a:1 - elseif a:0 == 2 | let sl = a:1 | let el = a:2 - else | return | endif - - if exists("t:DChar") - for l in range(sl, el) - if has_key(t:DChar.hlc[1], l) || - \has_key(t:DChar.hlc[2], l) - call s:ResetDiffChar(sl, el) - return - endif - endfor - endif - call s:ShowDiffChar(sl, el) -endfunction - -function! s:HighlightDiffChar(key, lnecol) - for [l, enc] in items(a:lnecol) - if has_key(t:DChar.mid[a:key], l) | continue | endif - if exists("*matchaddpos") - let mid = [matchaddpos("DiffChange", [[l]], 0)] - else - let dl = '\%' . l . 'l' - let mid = [matchadd("DiffChange", dl . '.', 0)] - endif - for [e, n, c] in enc - if e == 'd' | continue | endif - let hl = (e == 'a') ? - \"DiffAdd" : t:DChar.dmc[n % len(t:DChar.dmc)] - if exists("*matchaddpos") - let mid += [matchaddpos(hl, - \[[l, c[0], c[-1] - c[0] + 1]], 0)] - else - let dc = '\%>' . (c[0] - 1) . 'c\%<' . - \(c[-1] + 1) . 'c' - let mid += [matchadd(hl, dl . dc, 0)] - endif - endfor - let [t:DChar.mid[a:key][l], t:DChar.hlc[a:key][l]] = [mid, enc] - endfor -endfunction - -function! s:ClearDiffChar(key, lines) - for l in a:lines - if has_key(t:DChar.mid[a:key], l) - for id in t:DChar.mid[a:key][l] - call matchdelete(id) - endfor - unlet t:DChar.mid[a:key][l] - unlet t:DChar.hlc[a:key][l] - endif - endfor -endfunction - -function! s:UpdateDiffChar(key) - " if number of lines was changed, reset all - if len(t:DChar.lsv[a:key]) != line('$') - call s:ResetDiffChar(1, line('$')) - return - endif - - " save the current t:DChar settings except highlightings - let sdc = deepcopy(t:DChar) - let [sdc.mid[1], sdc.mid[2]] = [{}, {}] - let [sdc.hlc[1], sdc.hlc[2]] = [{}, {}] - - " update only highlighted and current changed lines - let lsv = s:GetLineStrValues(a:key) - for l in map(keys(t:DChar.hlc[a:key]), 'eval(v:val)') - if lsv[l - 1] != t:DChar.lsv[a:key][l - 1] - call s:ResetDiffChar(l, l) - if !exists("t:DChar") | let t:DChar = sdc | endif - call s:MarkDiffCharID(1) - call s:ShowDiffChar(l, l) - endif - endfor -endfunction - -function! s:GetDiffModeLines(key, sl, el) - " in diff mode, need to compare the different line between windows - " if current window is t:DChar.win[1], narrow sl <= t:DChar.vdl[1] - " <= el and get the corresponding lines from t:DChar.vdl[2] - let [i, j] = (a:key == 1) ? [1, 2] : [2, 1] - let [d1, d2] = [copy(t:DChar.vdl[1]), copy(t:DChar.vdl[2])] - for l in range(len(d{i})) - if d{i}[l] < a:sl || a:el < d{i}[l] - let [d{i}[l], d{j}[l]] = [-1, -1] - endif - endfor - call filter(d1, 'v:val != -1') - call filter(d2, 'v:val != -1') - return [d1, d2] -endfunction - -function! s:GetLineStrValues(key) - let hl = map(keys(t:DChar.hlc[a:key]), 'eval(v:val)') - let lsv = [] - for l in range(1, line('$')) - if index(hl, l) != -1 - let str = getbufline(winbufnr(t:DChar.win[a:key]), l)[0] - let val = 0 - for n in range(len(str)) - let val += char2nr(str[n]) * (n + 1) - endfor - let lsv += [val] - else - let lsv += [-1] - endif - endfor - return lsv -endfunction - -function! s:JumpDiffChar(dir, pos) - " dir : 1 = forward, else = backward - " pos : 1 = start, else = end - if !exists("t:DChar") | return | endif - - call s:RefreshDiffCharWin() - - let cwin = winnr() - if cwin == t:DChar.win[1] | let k = 1 - elseif cwin == t:DChar.win[2] | let k = 2 - else | return | endif - - let found = 0 - let l = line('.') - while !found && 1 <= l && l <= line('$') - if has_key(t:DChar.hlc[k], l) - if l == line('.') - let c = col('.') - if !a:pos - " end pos workaround for multibyte char - let c += len(matchstr(getbufline( - \winbufnr(cwin), l)[0], - \'.', c - 1)) - 1 - endif - else - let c = a:dir ? 0 : 99999 - endif - let hc = map(copy(t:DChar.hlc[k][l]), - \'(v:val[0] == "d") ? - \"" : v:val[2][a:pos ? 0 : -1]') - if !a:dir - let c = - c - call map(reverse(hc), - \'empty(v:val) ? "" : - v:val') - endif - for n in range(len(hc)) - if !empty(hc[n]) && c < hc[n] - let c = hc[n] - if !a:dir - let c = - c - let n = len(hc) - n - 1 - endif - call cursor(l, c) - call s:ShowDiffCharPair(k, l, n, a:pos) - let found = 1 - break - endif - endfor - endif - let l = a:dir ? l + 1 : l - 1 - endwhile -endfunction - -function! s:ShowDiffCharPair(key, line, icol, pos) - let m = (a:key == 1) ? 2 : 1 - if exists("t:DChar.vdl") " diff mode - let line = t:DChar.vdl[m][index(t:DChar.vdl[a:key], a:line)] - else " non-diff mode - let line = a:line - endif - let bl = getbufline(winbufnr(t:DChar.win[m]), line)[0] - - let [e, n, c] = t:DChar.hlc[m][line][a:icol] - if e == 'd' - " deleted unit - let pc = (0 < c[0]) ? split(bl[ : c[0] - 1], '\zs')[-1] : "" - let nc = (c[0] < len(bl)) ? split(bl[c[0] : ], '\zs')[0] : "" - " echo a-----b with DiffChange/DiffDelete - echohl DiffChange - echon pc - echohl DiffDelete - let col = t:DChar.hlc[a:key][a:line][a:icol][2] - echon repeat('-', strwidth( - \getbufline(winbufnr(t:DChar.win[a:key]), a:line)[0] - \[col[0] - 1 : col[-1] - 1])) - echohl DiffChange - echon nc - echohl None - " set position/length for both side of deleted unit - let clen = len(pc . nc) - let cpos = c[0] - len(pc) + 1 - else - " changed unit - let dc = bl[c[0] - 1 : c[-1] - 1] - " echo the matching unit with its color - exec "echohl " . t:DChar.dmc[n % len(t:DChar.dmc)] - echon dc - echohl None - " set position/length for matching unit - let clen = len(split(dc, '\zs')[a:pos ? 0 : -1]) - let cpos = a:pos ? c[0] : c[-1] - clen + 1 - endif - - " show cursor on deleted unit or matching unit on another window - exec t:DChar.win[m] . "wincmd w" - call s:ResetDiffCharPair(m) - if exists("*matchaddpos") - let t:DChar.mpc[m] = matchaddpos( - \hlexists("Cursor") ? "Cursor" : "MatchParen", - \[[line, cpos, clen]], 0) - else - let t:DChar.mpc[m] = matchadd( - \hlexists("Cursor") ? "Cursor" : "MatchParen", - \'\%' . line . 'l\%>' . (cpos - 1) . 'c\%<' . - \(cpos + clen) . 'c', 0) - endif - if !exists("#WinEnter#") - exec "au WinEnter call s:ResetDiffCharPair(" . m . ")" - endif - exec t:DChar.win[a:key] . "wincmd w" -endfunction - -function! s:ResetDiffCharPair(key) - if exists("t:DChar.mpc[a:key]") - call matchdelete(t:DChar.mpc[a:key]) - unlet t:DChar.mpc[a:key] - exec "au! WinEnter " - echon "" - endif -endfunction - -function! s:MarkDiffCharID(on) - " mark w:DCharID (0/1/2) on all windows, on : 1 = set, 0 = clear - for win in range(1, winnr('$')) - call setwinvar(win, "DCharID", - \(win == t:DChar.win[1]) ? a:on * 1 : - \(win == t:DChar.win[2]) ? a:on * 2 : 0) - endfor -endfunction - -function! s:RefreshDiffCharWin() - " find diffchar windows and set their winnr to t:DChar.win again - let t:DChar.win = {} - for win in range(1, winnr('$')) - let id = getwinvar(win, "DCharID", 0) - if id | let t:DChar.win[id] = win | endif - endfor -endfunction - -" O(NP) Difference algorithm -function! s:TraceDiffCharONP(u1, u2) - let [n1, n2] = [len(a:u1), len(a:u2)] - if n1 == 0 && n2 == 0 | return [] | endif - - " reverse to be N <= M, u2 <= u1 - let rev = (n1 > n2) ? 0 : (n1 < n2) ? 1 : - \(join(a:u1, '') >= join(a:u2, '')) ? 0 : 1 - let [u1, u2, M, N] = rev ? [a:u2, a:u1, n2, n1] : [a:u1, a:u2, n1, n2] - - let fp = repeat([-1], M + N + 3) - let offset = N + 1 - let delta = M - N - let etree = [] " [next edit, previous p, previous k] - - let p = -1 - while fp[delta + offset] != M - let p += 1 - let etree += [repeat([['', 0, 0]], p * 2 + delta + 1)] - for [k, r] in map(range(-p, delta - 1, 1), '[v:val, "A"]') - \+ map(range(delta + p, delta + 1, -1), '[v:val, "C"]') - \+ [[delta, "B"]] - let [x, ed, pp, pk] = - \(fp[k - 1 + offset] < fp[k + 1 + offset]) ? - \[fp[k + 1 + offset], - \'+', (r == 'A') ? p - 1 : p, k + 1] : - \[fp[k - 1 + offset] + 1, - \'-', (r == 'C') ? p - 1 : p, k - 1] - let y = x - k - while x < M && y < N && u1[x] == u2[y] - let ed .= '=' - let [x, y] += [1, 1] - endwhile - let fp[k + offset] = x - " add [ed, pp, pk] for current p and k - let etree[p][p + k] = [ed, pp, pk] - endfor - endwhile - - " create an edit sequence back from last p and k - let eseq = '' - while p >= 0 && p + k >= 0 - let [e, p, k] = etree[p][p + k] - let eseq = e . eseq - endwhile - let eseq = eseq[1:] " delete the first entry - - " trace the edit sequence starting from [0, 0] and - " create a shortest edit script (SES) - let ses = [] " ['+/-/=', unit] - let [i1, i2] = [0, 0] - for n in range(len(eseq)) - let ed = eseq[n] - if ed == '=' - let ses += [[ed, u1[i1]]] - let [i1, i2] += [1, 1] - elseif ed == '-' - let ses += [[ed, u1[i1]]] - let i1 += 1 - elseif ed == '+' - let ses += [[ed, u2[i2]]] - let i2 += 1 - endif - endfor - if rev " reverse the edit - call map(ses, '[tr(v:val[0], "+-", "-+"), v:val[1]]') - endif - - return ses -endfunction - -" O(ND) Difference algorithm -function! s:TraceDiffCharOND(u1, u2) - let [n1, n2] = [len(a:u1), len(a:u2)] - if n1 == 0 && n2 == 0 | return [] | endif - - " reverse to be u2 <= u1 - let rev = (n1 > n2) ? 0 : (n1 < n2) ? 1 : - \(join(a:u1, '') >= join(a:u2, '')) ? 0 : 1 - let [u1, u2, M, N] = rev ? [a:u2, a:u1, n2, n1] : [a:u1, a:u2, n1, n2] - - let offset = M + N - let V = repeat([0], offset * 2 + 1) - let etree = [] " [next edit, previous K's position] - let found = 0 - - for D in range(offset + 1) - let etree += [[]] " add a list for each D - for k in range(-D, D, 2) - let [x, ed, pk] = (k == -D || k != D && - \V[k - 1 + offset] < V[k + 1 + offset]) ? - \[V[k + 1 + offset], '+', k + 1] : - \[V[k - 1 + offset] + 1, '-', k - 1] - let y = x - k - while x < M && y < N && u1[x] == u2[y] - let ed .= '=' - let [x, y] += [1, 1] - endwhile - let V[k + offset] = x - " add [ed, pk] of k for [-D], [-D+2], ..., [D-2], [D] - let etree[D] += [[ed, (pk + D - 1)/2]] - " find the goal? - if x >= M && y >= N | let found = 1 | break | endif - endfor - if found | break | endif " break loop - endfor - - " create an edit sequence back from last D - let eseq = '' - let pk = -1 - for d in range(D, 0, -1) - let [ed, pk] = etree[d][pk] - let eseq = ed . eseq - endfor - let eseq = eseq[1:] " delete the first entry - - " trace the edit sequence starting from [0, 0] and - " create a shortest edit script (SES) - let ses = [] " ['+/-/=', unit] - let [i1, i2] = [0, 0] - for n in range(len(eseq)) - let ed = eseq[n] - if ed == '=' - let ses += [[ed, u1[i1]]] - let [i1, i2] += [1, 1] - elseif ed == '-' - let ses += [[ed, u1[i1]]] - let i1 += 1 - elseif ed == '+' - let ses += [[ed, u2[i2]]] - let i2 += 1 - endif - endfor - if rev " reverse the edit - call map(ses, '[tr(v:val[0], "+-", "-+"), v:val[1]]') - endif - - return ses -endfunction - -" Basic Difference algorithm -function! s:TraceDiffCharBasic(u1, u2) - let [n1, n2] = [len(a:u1), len(a:u2)] - if n1 == 0 && n2 == 0 | return [] | endif - - " reverse to be u2 <= u1 - let rev = (n1 > n2) ? 0 : (n1 < n2) ? 1 : - \(join(a:u1, '') >= join(a:u2, '')) ? 0 : 1 - let [u1, u2, n1, n2] = rev ? [a:u2, a:u1, n2, n1] : [a:u1, a:u2, n1, n2] - - " initialize an edit graph [next edit, # of steps to goal] - let egph = [] - for i1 in range(n1 + 1) - let egph += [repeat([['', 0]], n2 + 1)] - endfor - - " assign values in egph[] based on u1 and u2 - let egph[n1][n2] = ['*', 0] " last point = goal - for i1 in range(n1) " last column's points - let egph[i1][n2] = ['-', n1 - i1] - endfor - for i2 in range(n2) " last row's points - let egph[n1][i2] = ['+', n2 - i2] - endfor - for i1 in range(n1 - 1, 0, -1) " other points from goal - for i2 in range(n2 - 1, 0, -1) - if u1[i1] == u2[i2] - let egph[i1][i2] = - \['=', egph[i1 + 1][i2 + 1][1]] - else - let [i1p, i2p] = - \[egph[i1 + 1][i2], egph[i1][i2 + 1]] - let egph[i1][i2] = - \(i1p[1] < i2p[1]) ? ['-', i1p[1] + 1] : - \(i1p[1] > i2p[1]) ? ['+', i2p[1] + 1] : - \(i1p[0] == '=') ? ['-', i1p[1] + 1] : - \(i2p[0] == '=') ? ['+', i2p[1] + 1] : - \(i1p[0] == '-' && i2p[0] == '-') ? - \['+', i2p[1] + 1] : ['-', i1p[1] + 1] - endif - endfor - endfor - - " trace the next edit starting from [0, 0] and - " create a shortest edit script (SES) - let ses = [] " ['+/-/=', unit] - let [i1, i2] = [0, 0] - while 1 - let ed = egph[i1][i2][0] - if ed == '=' - let ses += [[ed, u1[i1]]] - let [i1, i2] += [1, 1] - elseif ed == '-' - let ses += [[ed, u1[i1]]] - let i1 += 1 - elseif ed == '+' - let ses += [[ed, u2[i2]]] - let i2 += 1 - elseif ed == '*' - break - endif - endwhile - if rev " reverse the edit - call map(ses, '[tr(v:val[0], "+-", "-+"), v:val[1]]') - endif - - return ses -endfunction +" Set this plugin's DiffCharExpr() to the diffexpr option if empty +if !exists('g:DiffExpr') +let g:DiffExpr = 1 " enable +" let g:DiffExpr = 0 " disable +endif +if g:DiffExpr && empty(&diffexpr) +let &diffexpr = 'diffchar#DiffCharExpr()' +endif + +" Set an event group of this plugin +augroup dchar +au! +au! FilterWritePre * call diffchar#SetDiffModeSync() +augroup END let &cpo = s:save_cpo unlet s:save_cpo diff --git a/vimfiles/plugin/merginal.vim b/vimfiles/plugin/merginal.vim old mode 100755 new mode 100644 index 1cda509..7125be9 --- a/vimfiles/plugin/merginal.vim +++ b/vimfiles/plugin/merginal.vim @@ -1,51 +1,23 @@ -function! s:openBasedOnMergeMode() abort - if merginal#isRebaseMode() - call merginal#openRebaseConflictsBuffer() - elseif merginal#isRebaseAmendMode() - call merginal#openRebaseAmendBuffer() - elseif merginal#isMergeMode() - call merginal#openMergeConflictsBuffer() - else - call merginal#openBranchListBuffer() - endif -endfunction - function! s:toggleBasedOnMergeMode() abort - let l:repo=fugitive#repo() - let l:merginalWindowNumber=bufwinnr('Merginal:') - if 0<=l:merginalWindowNumber - let l:merginalBufferNumber=winbufnr(l:merginalWindowNumber) - let l:merginalBufferName=bufname(l:merginalBufferNumber) - - "If we are not on the same dir we need to reload the merginal buffer - "anyways: - if getbufvar(l:merginalBufferNumber,'merginal_repo').dir()==l:repo.dir() - if merginal#isRebaseMode() - if 'Merginal:Rebase'==l:merginalBufferName - call merginal#closeMerginalBuffer() - return - endif - elseif merginal#isRebaseAmendMode() - if 'Merginal:RebaseAmend'==l:merginalBufferName - call merginal#closeMerginalBuffer() - return - endif - elseif merginal#isMergeMode() - if 'Merginal:Conflicts'==l:merginalBufferName - call merginal#closeMerginalBuffer() - return - endif - else - if 'Merginal:Branches'==l:merginalBufferName - call merginal#closeMerginalBuffer() - return - endif - end + let l:merginalWindowNumber = bufwinnr('Merginal:') + if 0 <= l:merginalWindowNumber + let l:merginalBufferNumber = winbufnr(l:merginalWindowNumber) + let l:bufferObject = getbufvar(l:merginalBufferNumber, 'merginal') + let l:mode = l:bufferObject._getSpecialMode() + if l:mode == '' + let l:mode = 'branchList' endif + if l:bufferObject.name == l:mode + call merginal#closeMerginalBuffer() + return + else + call l:bufferObject.gotoBuffer(l:mode) + endif + else + call merginal#openMerginalBuffer() endif - call s:openBasedOnMergeMode() endfunction -autocmd User Fugitive command! -buffer -nargs=0 Merginal call s:openBasedOnMergeMode() +autocmd User Fugitive command! -buffer -nargs=0 Merginal call merginal#openMerginalBuffer() autocmd User Fugitive command! -buffer -nargs=0 MerginalToggle call s:toggleBasedOnMergeMode() autocmd User Fugitive command! -buffer -nargs=0 MerginalClose call merginal#closeMerginalBuffer() diff --git a/vimfiles/plugin/tcomment.vim b/vimfiles/plugin/tcomment.vim index 4d095ad..f86bf10 100644 --- a/vimfiles/plugin/tcomment.vim +++ b/vimfiles/plugin/tcomment.vim @@ -2,14 +2,14 @@ " @Author: Tom Link (micathom AT gmail com) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 27-Dez-2004. -" @Last Change: 2014-06-30. -" @Revision: 840 +" @Last Change: 2015-04-26. +" @Revision: 964 " GetLatestVimScripts: 1173 1 tcomment.vim if &cp || exists('loaded_tcomment') finish endif -let loaded_tcomment = 304 +let loaded_tcomment = 307 let s:save_cpo = &cpo set cpo&vim @@ -117,138 +117,169 @@ command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs T \ keepjumps call tcomment#Comment(, , 'i', "", ) -noremap TComment- :TComment -vnoremap TComment- :TCommentMaybeInline -inoremap TComment- :TComment -noremap TComment-p m`vip:TComment`` -inoremap TComment-p :norm! m`vip:TComment`` -noremap TComment- :TComment -inoremap TComment- :TComment -inoremap TComment-r :TCommentRight -noremap TComment-r :TCommentRight -vnoremap TComment-i :TCommentInline -noremap TComment-i v:TCommentInline mode=I# -inoremap TComment-i v:TCommentInline mode=# -noremap TComment-b :TCommentBlock -inoremap TComment-b :TCommentBlock mode=# -noremap TComment-a :TCommentAs -inoremap TComment-a :TCommentAs -noremap TComment-n :TCommentAs =&ft -inoremap TComment-n :TCommentAs =&ft -noremap TComment-s :TCommentAs =&ft_ -inoremap TComment-s :TCommentAs =&ft_ -noremap TComment-cc :call tcomment#SetOption("count", v:count1) -noremap TComment-ca :call tcomment#SetOption("as", input("Comment as: ", &filetype, "customlist,tcomment#Complete")) +" command! -range TCommentMap call tcomment#ResetOption() | -noremap TComment-__ :TComment -xnoremap TComment-__ :TCommentMaybeInline -noremap TComment-_p vip:TComment -noremap TComment-_ :TComment -xnoremap TComment-_i :TCommentInline -noremap TComment-_r :TCommentRight -noremap TComment-_b :TCommentBlock -noremap TComment-_a :TCommentAs -noremap TComment-_n :TCommentAs =&ft -noremap TComment-_s :TCommentAs =&ft_ +noremap TComment_ :TComment +vnoremap TComment_ :TCommentMaybeInline +inoremap TComment_ :TComment +noremap TComment_p m`vip:TComment`` +inoremap TComment_p :norm! m`vip:TComment`` +noremap TComment_ :TComment +inoremap TComment_ :TComment +inoremap TComment_r :TCommentRight +noremap TComment_r :TCommentRight +vnoremap TComment_i :TCommentInline +noremap TComment_i v:TCommentInline mode=I# +inoremap TComment_i v:TCommentInline mode=# +noremap TComment_b :TCommentBlock +inoremap TComment_b :TCommentBlock mode=# +noremap TComment_a :TCommentAs +inoremap TComment_a :TCommentAs +noremap TComment_n :TCommentAs =&ft +inoremap TComment_n :TCommentAs =&ft +noremap TComment_s :TCommentAs =&ft_ +inoremap TComment_s :TCommentAs =&ft_ +noremap TComment_cc :call tcomment#SetOption("count", v:count1) +noremap TComment_ca :call tcomment#SetOption("as", input("Comment as: ", &filetype, "customlist,tcomment#Complete")) -nnoremap TComment-Uncomment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ -nnoremap TComment-Uncommentc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ -nnoremap TComment-Uncommentb :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "UB") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ -xnoremap TComment-Uncomment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline +noremap TComment___ :TComment +xnoremap TComment___ :TCommentMaybeInline +noremap TComment__p vip:TComment +noremap TComment__ :TComment +xnoremap TComment__i :TCommentInline +noremap TComment__r :TCommentRight +noremap TComment__b :TCommentBlock +noremap TComment__a :TCommentAs +noremap TComment__n :TCommentAs =&ft +noremap TComment__s :TCommentAs =&ft_ -nnoremap TComment-Comment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ -nnoremap TComment-Commentc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ -nnoremap TComment-Commentb :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "B") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ -xnoremap TComment-Comment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! -vnoremap TComment-ic :call tcomment#TextObjectInlineComment() -noremap TComment-ic :call tcomment#TextObjectInlineComment() +" function! TCommentOp(type) "{{{3 +" " TLogVAR a:type, v:count +" " echom "DBG TCommentOp" g:tcomment_ex +" " echom "DBG TCommentOp" g:tcomment_op +" exec g:tcomment_ex +" call call(g:tcomment_op, [a:type]) +" endf -nnoremap TComment-gcc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@$ -nnoremap TComment-gcb :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| call tcomment#SetOption("mode_extra", "B") \| set opfunc=tcomment#OperatorLineg@ -xnoremap TComment-gc :TCommentMaybeInline +function! s:MapOp(name, extra, op, invoke) "{{{3 + let opfunc = 'TCommentOpFunc_'. substitute(a:name, '[^a-zA-Z0-9_]', '_', 'G') + let fn = [ + \ 'function! '. opfunc .'(...)', + \ 'call tcomment#MaybeReuseOptions('. string(opfunc) .')', + \ a:extra, + \ 'return call('. string(a:op) .', a:000)', + \ 'endf' + \ ] + exec join(fn, "\n") + exec printf('nnoremap TComment_%s '. + \ ':call tcomment#ResetOption() \| if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \|'. + \ 'set opfunc=%s%s', + \ a:name, opfunc, a:invoke) +endf -nnoremap TComment-gc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#Operatorg@ + +call s:MapOp('Uncomment', 'call tcomment#SetOption("mode_extra", "U")', 'tcomment#Operator', 'g@') +call s:MapOp('Uncommentc', 'call tcomment#SetOption("mode_extra", "U")', 'tcomment#OperatorLine', 'g@$') +call s:MapOp('Uncommentb', 'call tcomment#SetOption("mode_extra", "UB")', 'tcomment#OperatorLine', 'g@') +xnoremap TComment_Uncomment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline + +call s:MapOp('Comment', '', 'tcomment#OperatorAnyway', 'g@') +call s:MapOp('Commentc', '', 'tcomment#OperatorLineAnyway', 'g@$') +call s:MapOp('Commentb', 'call tcomment#SetOption("mode_extra", "B")', 'tcomment#OperatorLine', 'g@') +xnoremap TComment_Comment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! + +vnoremap TComment_ic :call tcomment#TextObjectInlineComment() +noremap TComment_ic :call tcomment#TextObjectInlineComment() + +call s:MapOp('gcc', '', 'tcomment#OperatorLine', 'g@$') +call s:MapOp('gcb', 'call tcomment#SetOption("mode_extra", "B")', 'tcomment#OperatorLine', 'g@') +xnoremap TComment_gc :TCommentMaybeInline + +call s:MapOp('gc', '', 'tcomment#Operator', 'g@') for s:i in range(1, 9) - exec 'noremap TComment-' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' - exec 'inoremap TComment-' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' - exec 'vnoremap TComment-' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' + exec 'noremap TComment_' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' + exec 'inoremap TComment_' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' + exec 'vnoremap TComment_' . s:i . ' :call tcomment#SetOption("count", '. s:i .')' endfor for s:i in range(1, 9) - exec 'nnoremap TComment-gc' . s:i .'c :let w:tcommentPos = getpos(".") \| call tcomment#SetOption("count", '. s:i .') \| set opfunc=tcomment#Operatorg@' + call s:MapOp('gc' . s:i .'c', 'call tcomment#SetOption("count", '. s:i .')', 'tcomment#Operator', 'g@') endfor unlet s:i +delfun s:MapOp + if g:tcommentMaps if g:tcommentMapLeader1 != '' - exec 'map '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment-' - exec 'vmap '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment-' - exec 'imap '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment-' - exec 'map '. g:tcommentMapLeader1 .'p TComment-p' - exec 'imap '. g:tcommentMapLeader1 .'p TComment-p' - exec 'map '. g:tcommentMapLeader1 .' TComment-' - exec 'imap '. g:tcommentMapLeader1 .' TComment-' - exec 'imap '. g:tcommentMapLeader1 .'r TComment-r' - exec 'map '. g:tcommentMapLeader1 .'r TComment-r' - exec 'vmap '. g:tcommentMapLeader1 .'i TComment-i' - exec 'map '. g:tcommentMapLeader1 .'i TComment-i' - exec 'imap '. g:tcommentMapLeader1 .'i TComment-i' - exec 'map '. g:tcommentMapLeader1 .'b TComment-b' - exec 'imap '. g:tcommentMapLeader1 .'b TComment-b' - exec 'map '. g:tcommentMapLeader1 .'a TComment-a' - exec 'imap '. g:tcommentMapLeader1 .'a TComment-a' - exec 'map '. g:tcommentMapLeader1 .'n TComment-n' - exec 'imap '. g:tcommentMapLeader1 .'n TComment-n' - exec 'map '. g:tcommentMapLeader1 .'s TComment-s' - exec 'imap '. g:tcommentMapLeader1 .'s TComment-s' - exec 'map '. g:tcommentMapLeader1 .'cc TComment-cc' - exec 'map '. g:tcommentMapLeader1 .'ca TComment-ca' + exec 'map '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment_' + exec 'vmap '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment_' + exec 'imap '. g:tcommentMapLeader1 . g:tcommentMapLeader1 .' TComment_' + exec 'map '. g:tcommentMapLeader1 .'p TComment_p' + exec 'imap '. g:tcommentMapLeader1 .'p TComment_p' + exec 'map '. g:tcommentMapLeader1 .' TComment_' + exec 'imap '. g:tcommentMapLeader1 .' TComment_' + exec 'imap '. g:tcommentMapLeader1 .'r TComment_r' + exec 'map '. g:tcommentMapLeader1 .'r TComment_r' + exec 'vmap '. g:tcommentMapLeader1 .'i TComment_i' + exec 'map '. g:tcommentMapLeader1 .'i TComment_i' + exec 'imap '. g:tcommentMapLeader1 .'i TComment_i' + exec 'map '. g:tcommentMapLeader1 .'b TComment_b' + exec 'imap '. g:tcommentMapLeader1 .'b TComment_b' + exec 'map '. g:tcommentMapLeader1 .'a TComment_a' + exec 'imap '. g:tcommentMapLeader1 .'a TComment_a' + exec 'map '. g:tcommentMapLeader1 .'n TComment_n' + exec 'imap '. g:tcommentMapLeader1 .'n TComment_n' + exec 'map '. g:tcommentMapLeader1 .'s TComment_s' + exec 'imap '. g:tcommentMapLeader1 .'s TComment_s' + exec 'map '. g:tcommentMapLeader1 .'cc TComment_cc' + exec 'map '. g:tcommentMapLeader1 .'ca TComment_ca' for s:i in range(1, 9) - exec 'map '. g:tcommentMapLeader1 . s:i .' TComment-'.s:i - exec 'imap '. g:tcommentMapLeader1 . s:i .' TComment-'.s:i - exec 'vmap '. g:tcommentMapLeader1 . s:i .' TComment-'.s:i + exec 'map '. g:tcommentMapLeader1 . s:i .' TComment_'.s:i + exec 'imap '. g:tcommentMapLeader1 . s:i .' TComment_'.s:i + exec 'vmap '. g:tcommentMapLeader1 . s:i .' TComment_'.s:i endfor unlet s:i endif if g:tcommentMapLeader2 != '' - exec 'map '. g:tcommentMapLeader2 .'_ TComment-__' - exec 'xmap '. g:tcommentMapLeader2 .'_ TComment-__' - exec 'map '. g:tcommentMapLeader2 .'p TComment-_p' - exec 'map '. g:tcommentMapLeader2 .' TComment-_' - exec 'xmap '. g:tcommentMapLeader2 .'i TComment-_i' - exec 'map '. g:tcommentMapLeader2 .'r TComment-_r' - exec 'map '. g:tcommentMapLeader2 .'b TComment-_b' - exec 'map '. g:tcommentMapLeader2 .'a TComment-_a' - exec 'map '. g:tcommentMapLeader2 .'n TComment-_n' - exec 'map '. g:tcommentMapLeader2 .'s TComment-_s' + exec 'map '. g:tcommentMapLeader2 .'_ TComment___' + exec 'xmap '. g:tcommentMapLeader2 .'_ TComment___' + exec 'map '. g:tcommentMapLeader2 .'p TComment__p' + exec 'map '. g:tcommentMapLeader2 .' TComment__' + exec 'xmap '. g:tcommentMapLeader2 .'i TComment__i' + exec 'map '. g:tcommentMapLeader2 .'r TComment__r' + exec 'map '. g:tcommentMapLeader2 .'b TComment__b' + exec 'map '. g:tcommentMapLeader2 .'a TComment__a' + exec 'map '. g:tcommentMapLeader2 .'n TComment__n' + exec 'map '. g:tcommentMapLeader2 .'s TComment__s' endif if g:tcommentMapLeaderOp1 != '' - exec 'nmap '. g:tcommentMapLeaderOp1 .' TComment-gc' + exec 'nmap '. g:tcommentMapLeaderOp1 .' TComment_gc' for s:i in range(1, 9) - exec 'nmap '. g:tcommentMapLeaderOp1 . s:i .' TComment-gc'.s:i + exec 'nmap '. g:tcommentMapLeaderOp1 . s:i .' TComment_gc'.s:i + exec 'nmap '. g:tcommentMapLeaderOp1 . s:i .'c TComment_gc'.s:i.'c' endfor unlet s:i - exec 'nmap '. g:tcommentMapLeaderOp1 .'c TComment-gcc' - exec 'nmap '. g:tcommentMapLeaderOp1 .'b TComment-gcb' - exec 'xmap '. g:tcommentMapLeaderOp1 .' TComment-gc' + exec 'nmap '. g:tcommentMapLeaderOp1 .'c TComment_gcc' + exec 'nmap '. g:tcommentMapLeaderOp1 .'b TComment_gcb' + exec 'xmap '. g:tcommentMapLeaderOp1 .' TComment_gc' endif if g:tcommentMapLeaderUncommentAnyway != '' - exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .' TComment-Uncomment' - exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'c TComment-Uncommentc' - exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'b TComment-Uncommentb' - exec 'xmap '. g:tcommentMapLeaderUncommentAnyway .' TComment-Uncomment' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .' TComment_Uncomment' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'c TComment_Uncommentc' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'b TComment_Uncommentb' + exec 'xmap '. g:tcommentMapLeaderUncommentAnyway .' TComment_Uncomment' endif if g:tcommentMapLeaderCommentAnyway != '' - exec 'nmap '. g:tcommentMapLeaderCommentAnyway .' TComment-Comment' - exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'c TComment-Commentc' - exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'b TComment-Commentb' - exec 'xmap '. g:tcommentMapLeaderCommentAnyway .' TComment-Comment' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .' TComment_Comment' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'c TComment_Commentc' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'b TComment_Commentb' + exec 'xmap '. g:tcommentMapLeaderCommentAnyway .' TComment_Comment' endif if g:tcommentTextObjectInlineComment != '' - exec 'vmap' g:tcommentTextObjectInlineComment ' TComment-ic' - exec 'omap' g:tcommentTextObjectInlineComment ' TComment-ic' + exec 'vmap' g:tcommentTextObjectInlineComment ' TComment_ic' + exec 'omap' g:tcommentTextObjectInlineComment ' TComment_ic' endif endif