" Vimball Archiver by Charles E. Campbell UseVimball finish plugin/gitTools.vim [[[1 252 " Script Name: gitTools.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, git " " NOTES: " " Version: 0.0.2 " Changes: " 0.0.2 Fry, 08 Jul 22. JPuigdevall " - New: Gitvdf, do not open new tab when asking for vimdiff of current file. " - Fix: Gitvdf always shows file is not modified. " - New: remove from disk command GitRM. " - New: git move command Gitmv. " - New: remove from disk command Gitrm. " - New: git restore command Gitr. " - New: git unstage command Gitu. " - New: git add command Gita. " - Fix: call again ChooseBranchMenu(), when no branch choosen. " - New: Gitm (git merge) command to show on vimdiff the files with " conflicts. " - Fix: Gitvd... and GitVD... commands not showing merge issues. " 0.0.1 Tue, 19 Apr 22. JPuigdevall " - Initial realease. " Adapt plugin svnTools to use git instead of subversion. if exists('g:loaded_gittools') finish endif let g:loaded_gittools = 1 let s:save_cpo = &cpo set cpo&vim let g:gitTools_version = "0.0.2" "- configuration -------------------------------------------------------------- let g:gitTools_gitCmd = get(g:, 'gitTools_gitCmd', "git") let g:gitTools_userAndPsswd = get(g:, 'gitTools_userAndPsswd', 0) let g:gitTools_gitUser = get(g:, 'gitTools_gitUser', "") let g:gitTools_storeGitPsswd = get(g:, 'gitTools_storeGitPsswd', 1) let g:gitTools_runInBackground = get(g:, 'gitTools_runInBackground', 1) let g:gitTools_gotoWindowOnEnd = get(g:, 'gitTools_gotoWindowOnEnd', 1) let g:gitTools_lastCommits = get(g:, 'gitTools_lastCommits', 3000) let g:gitTools_mode = get(g:, 'gitTools_mode', 3) " On vimdiff window (commands: Gitvd, Gitvdp, Gitvda, Gitvdd, Gitvdf...) resize the right most window " multiplying current width with this value. let g:gitTools_vimdiffWinWidthMultiplyValue = get(g:, 'gitTools_vimdiffWinWidthMultiplyValue', 1.3) "- commands ------------------------------------------------------------------- " GIT INFO: command! -nargs=0 Giti call gitTools#info#Info() command! -nargs=0 Gitb call gitTools#info#ShowBranches() " GIT STATUS COMMANDS: command! -nargs=? -range Gita ,call gitTools#commands#Add("") command! -nargs=? -range Gitu ,call gitTools#commands#Unstage() command! -nargs=? -range GitR ,call gitTools#commands#Restore() command! -nargs=? -range Gitrm ,call gitTools#commands#Remove() command! -nargs=* -range Gitmv call gitTools#commands#Move() command! -nargs=? -range GitRM ,call gitTools#commands#DiskRemove() " GIT STATUS: command! -nargs=1 -complete=dir Gitstp call gitTools#status#GetStatus(, "-uno") command! -nargs=0 Gitst call gitTools#status#GetStatus(getcwd(), "-uno") command! -nargs=0 Gitsta call gitTools#status#GetStatus(getcwd(), "") command! -nargs=0 Gitstf call gitTools#status#GetStatus(expand('%'), "-uno") command! -nargs=0 Gitstd call gitTools#status#GetStatus(expand('%:h'), "-uno") command! -nargs=1 -complete=dir GitStp call gitTools#status#GetStatus(, "-suno") command! -nargs=0 GitSt call gitTools#status#GetStatus(getcwd(), "-suno") command! -nargs=0 GitSta call gitTools#status#GetStatus(getcwd(), "-s") command! -nargs=0 GitStf call gitTools#status#GetStatus(expand('%'), "-suno") command! -nargs=0 GitStd call gitTools#status#GetStatus(expand('%:h'), "-suno") command! -nargs=0 GitSth call gitTools#help#StatusHelp() " GIT DIFF: " Simple diff command! -nargs=1 -complete=dir Gitd call gitTools#diff#Diff() command! -nargs=0 Gitdf call gitTools#diff#Diff(expand('%')) command! -nargs=0 Gitdd call gitTools#diff#Diff(expand('%:h')) command! -nargs=0 Gitda call gitTools#diff#Diff(getcwd()) " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " +KeepPattern : pattern used to keep files with names matching. " -SkipPattern : pattern used to skip files with names not matching. command! -nargs=* -complete=dir GitD call gitTools#diff#DiffAdv() command! -nargs=* GitDD call gitTools#diff#DiffAdv(expand('%:h'), ) command! -nargs=* GitDA call gitTools#diff#DiffAdv(getcwd(), ) " GIT DIFF WITH VIMDIF: command! -nargs=0 Gitvdf call gitTools#vimdiff#File(expand('%')) command! -nargs=1 -complete=dir Gitvd call gitTools#vimdiff#Path() command! -nargs=0 Gitvdd call gitTools#vimdiff#Path(expand('%:h')) command! -nargs=0 Gitvda call gitTools#vimdiff#Path(getcwd()) " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " +KeepPattern : pattern used to keep files with names matching. " -SkipPattern : pattern used to skip files with names not matching. command! -nargs=* -complete=dir GitVD call gitTools#vimdiff#PathAdv() command! -nargs=* GitVDD call gitTools#vimdiff#PathAdv(expand('%:h'), ) command! -nargs=* GitVDA call gitTools#vimdiff#PathAdv(getcwd(), ) " DIFF FILES BETWEEN DIRECTORIES: " Allowed options: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only . " SE: skip equal files (default). " C1: use only git changes on path1. " C2: use only git changes on path2. "command! -nargs=* -complete=dir Gitdc call gitTools#directory#CompareChanges("diff", ) "command! -nargs=* -complete=dir Gitvdc call gitTools#directory#CompareChanges("vimdiff", ) " Open with vimdiff all files modified on a revsion or between two different revisions " Gitvdr REV1 " Gitvdr REV1 REV2 " When no revision number provided as argument, try get word under cursor as the revision number. "command! -nargs=* Gitvdr call gitTools#vimdiff#RevisionsCompare() " DIFF FILE TOOLS: " When placed on buffer with a diff file opened. "command! -nargs=0 Gitdvdr call gitTools#diffFile#OpenVimDiffOnEachFileAndRevision() " Show vimdiff of each modified file "command! -nargs=* GitDiffVdr call gitTools#diffFile#OpenVimDiffOnAllFiles() " When placed on a line starting with 'Index' or '---' or " '+++' " Show vimdiff of current modified file "command! -nargs=* GitDiffVdrf call gitTools#diffFile#OpenVimDiffGetFileAndRevisionFromCurrentLine() " GIT LOG: command! -nargs=? Gitl call gitTools#log#GetRevision() command! -nargs=1 Gitls call gitTools#log#SearchPattern() command! -nargs=* Gitlf call gitTools#log#GetHistory(expand("%"), ) command! -nargs=* Gitld call gitTools#log#GetHistory(getcwd(), ) command! -nargs=* Gitlp call gitTools#log#GetHistory() command! -nargs=0 Gitrl call gitTools#log#GetRefLog() " Pending: adapt for git. "command! -nargs=? Gitlr call gitTools#log#GetRevDiff("") " Get log and diff from selected revision. command! -nargs=? Gitr call gitTools#log#GetLogAndDiff() " GIT SHOW: show file on its state on another revisio. command! -nargs=1 Gitsh call gitTools#show#Revision() " GIT BLAME: command! -nargs=0 Gitbl call gitTools#blame#Blame("") " GIT CONFLICTS: command! -nargs=0 Gitm call gitTools#conflict#Merge(getcwd()) command! -nargs=0 Gitmf call gitTools#conflict#Merge(expand('%')) command! -nargs=* Gitmp call gitTools#conflict#Merge() " Other: command! -nargs=0 Gith call gitTools#help#Help() " Toogle background/foreground execution of the git commands. command! -nargs=? Gitbg call gitTools#gitTools#BackgroundMode("") command! -nargs=? Gitv call gitTools#tools#Verbose("") " Release functions: command! -nargs=0 Gitvba call gitTools#gitTools#NewVimballRelease() " Edit plugin files: command! -nargs=0 Gitedit call gitTools#gitTools#Edit() " Git user and password functions: "command! -nargs=0 Gitpwd call gitTools#tools#SetUserAndPsswd() "- abbreviations ------------------------------------------------------------------- " DEBUG functions: reload plugin cnoreabbrev _gitrl =gitTools#gitTools#Reload() "- menus ------------------------------------------------------------------- if has("gui_running") call gitTools#gitTools#CreateMenus('cn' , '.&Info' , ':Giti' , 'Working dir info' , ':Giti') call gitTools#gitTools#CreateMenus('cn' , '.&Info' , ':Gitb' , 'Show branches info' , ':Gita') call gitTools#gitTools#CreateMenus('cn' , '.&Blame' , ':Gitbl' , 'Get file blame' , ':Gitbl') call gitTools#gitTools#CreateMenus('cn' , '.&Log' , ':Gitl' , 'Show log (num of commits)' , ':Gitl [NUM]') call gitTools#gitTools#CreateMenus('cn' , '.&Log' , ':Gitls' , 'Log search (num of commits)' , ':Gitls PATTERN [NUM]') "call gitTools#gitTools#CreateMenus('cn' , '.&Log' , ':Gitlr' , 'On git log file, get each revision diff' , ':Gitlr') call gitTools#gitTools#CreateMenus('cn' , '.&Diff' , ':Gitd' , 'Get file/path diff' , ':GitD PATH') call gitTools#gitTools#CreateMenus('cn' , '.&Diff' , ':Gitdf' , 'Get file diff' , ':GitDf') call gitTools#gitTools#CreateMenus('cn' , '.&Diff' , ':Gitdd' , 'Get dir diff' , ':GitDd') call gitTools#gitTools#CreateMenus('cn' , '.&Diff' , ':Gitda' , 'Get working dir changes diff' , ':GitDa') call gitTools#gitTools#CreateMenus('cn' , '.&DiffFilt' , ':GitD' , 'Get (filtered) file/path diff' , ':GitD PATH [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&DiffFilt' , ':GitDD' , 'Get (filtered) dir changes diff' , ':GitDD [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&DiffFilt' , ':GitDA' , 'Get (filtered) working dir diff' , ':GitDA [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&Vimdiff' , ':Gitvd' , 'Get current file/path changes using vimdiff' , ':Gitvd') call gitTools#gitTools#CreateMenus('cn' , '.&Vimdiff' , ':Gitvdf' , 'Get current file changes using vimdiff' , ':Gitvdf') call gitTools#gitTools#CreateMenus('cn' , '.&Vimdiff' , ':Gitvdd' , 'Get current dir changes using vimdiff' , ':Gitvdd') call gitTools#gitTools#CreateMenus('cn' , '.&Vimdiff' , ':Gitvda' , 'Get working dir with changes using vimdiff' , ':Gitvda') call gitTools#gitTools#CreateMenus('cn' , '.&VimdiffFilt' , ':GitvD' , 'Get current (filtered) file/path changes using vimdiff' , ':GitvD PATH [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&VimdiffFilt' , ':GitvDD' , 'Get current (filtered) dir changes using vimdiff' , ':GitvDD [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&VimdiffFilt' , ':GitvDA' , 'Get working (filtered) dir with changes using vimdiff' , ':GitvDA [FLAGS]') "call gitTools#gitTools#CreateMenus('cn' , '.&DirCompare' , ':Gitdc' , 'Get diff between changes on both paths' , ':Gitdc PATH1 PATH2 [FLAGS]') "call gitTools#gitTools#CreateMenus('cn' , '.&DirCompare' , ':Gitvdc' , 'Get vimdiff between changes on both paths' , ':Gitvdc PATH1 PATH2 [FLAGS]') "call gitTools#gitTools#CreateMenus('cn' , '.&MyDirCompare' , ':Gitdmc' , 'Get diff with files changed on current path' , ':Gitdc PATH [FLAGS]') "call gitTools#gitTools#CreateMenus('cn' , '.&MyDirCompare' , ':Gitvdmc' , 'Get vimdiff with files changed on current path' , ':Gitvdmc PATH [FLAGS]') call gitTools#gitTools#CreateMenus('cn' , '.&Revision' , ':Gitr' , 'Get revision log and diff' , ':Gitr REV') call gitTools#gitTools#CreateMenus('cn' , '.&Revision' , ':Gitshr' , 'Get revision files' , ':Gitcr REV') call gitTools#gitTools#CreateMenus('cn' , '.&Revision' , ':Gitvdr' , 'Get vimdiff on revision' , ':Gitvdr [REV1] [REV2]') call gitTools#gitTools#CreateMenus('cn' , '.&Conflicts' , ':Gitm' , 'Merge all files in conflict' , ':Gitm [LAYOUT]') call gitTools#gitTools#CreateMenus('cn' , '.&Conflicts' , ':Gitmf' , 'Merge file in conflict' , ':Gitmf FILE [LAYOUT]') call gitTools#gitTools#CreateMenus('cn' , '.&Conflicts' , ':Gitmp' , 'Merge file in conflict' , ':Gitmf FILE [LAYOUT]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitsta' , 'Show git status for all files' , ':Gitsta') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitstd' , 'Show git status for current directoty' , ':Gitstd') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitstf' , 'Show git status for current file' , ':Gitstf') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitstf' , 'Show git status for path' , ':Gitstp PATH') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gita' , 'Add file to git stage' , ':Gita [FILEPATH]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitu' , 'Unstage file' , ':Gitu [FILEPATH]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':GitR' , 'Restore file' , ':Gitr [FILEPATH]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitrm' , 'Remove file/dir' , ':Gitrm [FILEPATH]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':Gitmv' , 'Move file/dir' , ':Gitmv [FILEPATH]') call gitTools#gitTools#CreateMenus('cn' , '.&Status' , ':GitRM' , 'Remove file/dir from disk' , ':GitRM [FILEPATH]') "call gitTools#gitTools#CreateMenus('cn' , '.&FileCompare' , ':Vdf' , 'Compare [current] file with same one on different dir' , ':Vdf [PATH1] PATH2') "call gitTools#gitTools#CreateMenus('cn' , '.&FileCompare' , ':Vdd' , 'Compare all files between directories' , ':Vdd [PATH1] PATH2 [FLAGS]') "call gitTools#gitTools#CreateMenus('cn' , '' , ':Gitpwd' , 'Set git user and password' , ':Gitpwd') call gitTools#gitTools#CreateMenus('cn' , '' , ':Gitbg' , 'Run foreground/background' , ':Gitbg') call gitTools#gitTools#CreateMenus('cn' , '' , ':Gith ' , 'Show command help' , ':Gith') endif let &cpo = s:save_cpo unlet s:save_cpo autoload/gitTools/blame.vim [[[1 117 " Script Name: gitTools/blame.vim "Description: " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " " "- functions ------------------------------------------------------------------- " Git blame " Commands: Gitbl. function! gitTools#blame#Blame(opt) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif let file = expand("%") let name = expand("%:t") let path = expand("%:h") let pos = line('.') let ext = gitTools#tools#GetSyntax() let path = gitTools#tools#GetPathAsFilename(l:path) let name = "_gitBlame_".l:path.".".l:ext let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let command = l:gitCmd." blame ".a:opt." ".l:file let callback = ["gitTools#blame#BlameEnd", l:pos, l:ext, l:name] call gitTools#tools#WindowSplitMenu(2) call gitTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! gitTools#blame#BlameEnd(pos,ext,name,resfile) if exists('a:resfile') && !empty(glob(a:resfile)) " On vertical split synchronize scroll if exists('w:split') if w:split == 2 | set crb! | endif endif silent exec("normal zz") let l:split = w:split let l:winh = winheight(0) if l:split == 1 || split == 2 " synchronize scroll and cursor set cursorbind set scrollbind endif call gitTools#tools#WindowSplit() put = readfile(a:resfile) silent! exec("normal ggdd") " Set syntax highlight silent exec("set ft=".a:ext) " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) call gitTools#tools#WindowSplitEnd() if l:split == 1 || split == 2 " synchronize scroll and cursor set cursorbind set scrollbind " Autocommand to reset cursor and scroll sync on buffer exit. silent exec("silent! autocmd! BufLeave ".a:name." call s:BlameExit()") endif " Restore previous position silent exec("normal ".a:pos."G") silent exec("normal zz") if l:split == 1 " Horizontal split: " Resize to half original window: silent exe "resize ".l:winh/2 elseif l:split == 2 " Vertical split: " Resize window: " Check resize widht: "silent normal 0f) silent normal 05W let l:width = col('.')+2 " whant to show on screen. let l:winw = winwidth(0) if l:winw > l:width echom "resize to ".l:width silent exe "vertical resize ".l:width endif silent normal 0 endif redraw else call gitTools#tools#Warn("Git blame empty") endif endfunction " Reset cursor and scroll bind on buffer exit. function! s:BlameExit() windo set noscb windo set nocrb endfunction autoload/gitTools/commands.vim [[[1 518 " Script Name: commands.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " " NOTES: " "- functions ------------------------------------------------------------------- " Add file to stage. " Arg1: [filepath], get Word under cursor if empty. " Commands: Gita function! gitTools#commands#Add(filepath) range " Save window position let l:winview = winsaveview() let l:linesList = [] if a:filepath != "" let l:linesList += [ a:filepath ] else let l:linesNum = a:lastline - a:firstline if l:linesNum != 0 let l:n = str2nr(a:firstline) while l:n <= str2nr(a:lastline) let l:linesList += [ gitTools#tools#TrimString(getline(l:n)) ] let l:n += 1 endwhile else let l:linesList += [ gitTools#tools#TrimString(getline(".")) ] endif endif "echom "linesList: "l:linesList if len(l:linesList) > 1 let l:header = "" else let l:header = "[gitTools.vim] " endif let l:n = 0 for l:line in l:linesList for l:filepath in split(l:line, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif if filereadable(l:filepath) call system("git add ".l:filepath) echo l:header."git add ".l:filepath."... done" let l:n += 1 elseif isdirectory(l:filepath) call confirm("Confirm to add directory: ".l:filepath) call system("git add ".l:filepath) echo l:header."git add ".l:filepath."... done" let l:n += 1 else call gitTools#tools#Error("ERROR: '".l:filepath."' path not found.") endif endfor endfor if len(l:linesList) > 1 echo "[gitTools.vim] ".l:n." paths added." endif if len(l:linesList) > 0 && l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif endif endfunction " Remove file from stage. " Arg1: [filepath], get Word under cursor if empty. " Commands: Gitu function! gitTools#commands#Unstage(filepath) range " Save window position let l:winview = winsaveview() let l:linesList = [] if a:filepath != "" let l:linesList += [ a:filepath ] else let l:linesNum = a:lastline - a:firstline if l:linesNum != 0 let l:n = str2nr(a:firstline) while l:n <= str2nr(a:lastline) let l:linesList += [ gitTools#tools#TrimString(getline(l:n)) ] let l:n += 1 endwhile else let l:linesList += [ gitTools#tools#TrimString(getline(".")) ] endif endif "echo "linesList: "l:linesList if len(l:linesList) > 1 let l:header = "" else let l:header = "[gitTools.vim] " endif let l:n = 0 for l:line in l:linesList if a:filepath == "" && s:isGitFileStatusLine(l:line) == 0 let l:mssg = "WARNING: not a status line: '".l:line."'. Status tags expected (new file/modified/deleted/unmerged...)" call gitTools#tools#Warn(l:mssg) continue endif for l:filepath in split(l:line, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif if filereadable(l:filepath) call system("git restore --staged ".l:filepath) echo l:header."git restore --staged ".l:filepath."... done" let l:n += 1 elseif isdirectory(l:filepath) call confirm("Confirm to unstage directory: ".l:filepath) call system("git restore --staged ".l:filepath) echo l:header."git restore --staged ".l:filepath."... done" let l:n += 1 else call gitTools#tools#Warn("WARNING: '".l:filepath."' path not found.") call system("git restore --staged ".l:filepath) echo l:header."git restore --staged ".l:filepath."... " let l:n += 1 endif endfor endfor if len(l:linesList) > 1 echo "[gitTools.vim] ".l:n." paths unstaged." endif if len(l:linesList) > 0 && l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif endif endfunction " Restore file changes. " Arg1: [filepath], get Word under cursor if empty. " Commands: GitR function! gitTools#commands#Restore(filepath) range " Save window position let l:winview = winsaveview() let l:linesList = [] if a:filepath != "" let l:linesList += [ a:filepath ] else let l:linesNum = a:lastline - a:firstline if l:linesNum != 0 let l:n = str2nr(a:firstline) while l:n <= str2nr(a:lastline) let l:linesList += [ gitTools#tools#TrimString(getline(l:n)) ] let l:n += 1 endwhile else let l:linesList += [ gitTools#tools#TrimString(getline(".")) ] endif endif "echo "linesList: "l:linesList if len(l:linesList) > 1 let l:header = "" else let l:header = "[gitTools.vim] " endif let l:n = 0 for l:line in l:linesList if a:filepath == "" && s:isGitFileStatusLine(l:line) == 0 let l:mssg = "WARNING: not a status line: '".l:line."'. Status tags expected (new file/modified/deleted/unmerged...)" call gitTools#tools#Warn(l:mssg) continue endif for l:filepath in split(l:line, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif redraw if filereadable(l:filepath) || isdirectory(l:filepath) if confirm("Restore?", "&yes\n&no", 2) != 2 call system("git restore ".l:filepath) let res = system("git restore ".l:filepath) echo l:res redraw echo l:header."git restore ".l:filepath."... done" let l:n += 1 endif else call gitTools#tools#Error("ERROR: '".l:filepath."' path not found.") endif endfor endfor if len(l:linesList) > 1 redraw echo "[gitTools.vim] ".l:n." paths restored." endif if len(l:linesList) > 0 && l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif endif endfunction " Remove files from disk. " Arg1: [filepath], get Word under cursor if empty. " Commands: Gitrm function! gitTools#commands#Remove(filepath) range " Save window position let l:winview = winsaveview() let l:linesList = [] if a:filepath != "" let l:linesList += [ a:filepath ] else let l:linesNum = a:lastline - a:firstline if l:linesNum != 0 let l:n = str2nr(a:firstline) while l:n <= str2nr(a:lastline) let l:linesList += [ gitTools#tools#TrimString(getline(l:n)) ] let l:n += 1 endwhile else let l:linesList += [ gitTools#tools#TrimString(getline(".")) ] endif endif "echo "linesList: "l:linesList if len(l:linesList) > 1 let l:header = "" else let l:header = "[gitTools.vim] " endif let l:n = 0 for l:line in l:linesList if a:filepath == "" && s:isGitFileStatusLine(l:line) == 0 let l:mssg = "WARNING: not a status line: '".l:line."'. Status tags expected (new file/modified/deleted/unmerged...)" call gitTools#tools#Warn(l:mssg) continue endif for l:filepath in split(l:line, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif let l:cmd = "git rm ".l:filepath if !filereadable(l:filepath) && !isdirectory(l:filepath) call gitTools#tools#Warn("WARNING: '".l:filepath."' path not found on disk.") else let l:options = "" if confirm("Remove from disk too?", "&yes\n&no", 2) == 2 let l:options += "--cached " endif if isdirectory(l:filepath) if confirm("Remove from git?", "&yes\n&no", 2) != 2 let l:cmd = "git rm ".l:options.l:filepath."/*" endif else let l:cmd = "git rm ".l:options.l:filepath endif endif "if filereadable(l:filepath) || isdirectory(l:filepath) "let l:options = "" "if confirm("Remove from disk too?", "&yes\n&no", 2) == 2 "let l:options += "--cached " "endif "endif "let l:cmd = "" "if isdirectory(l:filepath) "if confirm("Remove from git?", "&yes\n&no", 2) != 2 "let l:cmd = "git rm ".l:options.l:filepath."/*" "endif "endif "if filereadable(l:filepath) "if confirm("Remove from git?", "&yes\n&no", 2) != 2 "let l:cmd = "git rm ".l:options.l:filepath "endif "endif if l:cmd != "" call system(l:cmd) "redraw echo l:header.l:cmd." ... done" let l:n += 1 endif endfor endfor if len(l:linesList) > 1 "redraw echo "[gitTools.vim] ".l:n." paths removed." endif if len(l:linesList) > 0 && l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif endif endfunction " Remove files from disk. " Arg1: [filepath], get Word under cursor if empty. " Commands: GitRM function! gitTools#commands#DiskRemove(filepath) range " Save window position let l:winview = winsaveview() let l:linesList = [] if a:filepath != "" let l:linesList += [ a:filepath ] else let l:linesNum = a:lastline - a:firstline if l:linesNum != 0 let l:n = str2nr(a:firstline) while l:n <= str2nr(a:lastline) let l:linesList += [ gitTools#tools#TrimString(getline(l:n)) ] let l:n += 1 endwhile else let l:linesList += [ gitTools#tools#TrimString(getline(".")) ] endif endif "echo "linesList: "l:linesList if len(l:linesList) > 1 let l:header = "" else let l:header = "[gitTools.vim] " endif let l:n = 0 for l:line in l:linesList for l:filepath in split(l:line, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif if !filereadable(l:filepath) && !isdirectory(l:filepath) call gitTools#tools#Error("ERROR: '".l:filepath."' path not found.") continue endif if isdirectory(l:filepath) if confirm("Remove from disk?", "&yes\n&no", 2) != 2 call system("rm -r ".l:filepath) redraw echo l:header."rm -r ".l:filepath."... done" let l:n += 1 endif endif if filereadable(l:filepath) if confirm("Remove from disk?", "&yes\n&no", 2) != 2 call system("rm ".l:filepath) redraw echo l:header."rm ".l:filepath."... done" let l:n += 1 endif endif endfor endfor if len(l:linesList) > 1 redraw echo "[gitTools.vim] ".l:n." paths removed." endif if len(l:linesList) > 0 && l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif endif endfunction " Git rename files. " Arg1: [file/path], get Word under cursor if empty. " Arg2: file/path, get Word under cursor if empty. " Commands: Gitmv function! gitTools#commands#Move(...) " Save window position let l:winview = winsaveview() let l:path0 = "" let l:path1 = "" if a:0 == 0 let l:path0 = gitTools#tools#TrimString(getline(".")) echo "Move ".l:path0 let l:path1 = input("Enter new file name: ") elseif a:0 == 1 if filereadable(l:path) || isdirectory(l:path) let l:path0 = gitTools#tools#TrimString(getline(".")) echo "Move ".l:path0 let l:path1 = input("Enter new file name: ") else echo "New name ".l:path1 let l:path0 = input("Enter current file name: ") endif elseif a:0 >= 1 let l:path0 = a:1 let l:path1 = a:2 echo "Move ".l:path0." to ".l:path1 endif if l:path0 == "" call gitTools#tools#Error("ERROR: current file/path name missing.") return endif if l:path1 == "" call gitTools#tools#Error("ERROR: new file/path name missing.") return endif let l:n = 0 for l:path in split(l:path0, " ") if l:filepath == "" | continue | endif if s:isGitStatusReservedWord(l:filepath) == 1 | continue | endif if filereadable(l:path) || isdirectory(l:path) if confirm("Git move ".l:path." to ".l:path1, "&yes\n&no", 2) != 2 call system("git mv ".l:path." ".l:path1) redraw echo "[gitTools.vim] git mv ".l:path." ".l:path1."... done" let l:n += 1 else call gitTools#tools#Error("ERROR: '".l:filepath."' path not found.") return endif endif endfor if l:n > 0 if confirm("Update git status?", "&yes\n&no", 2) != 2 call gitTools#status#GetStatus(getcwd(), "") " Restore window position call winrestview(l:winview) endif else call gitTools#tools#Error("ERROR: move error.") endif endfunction function! s:isGitStatusReservedWord(word) if a:word == "new" | return 1 | endif if a:word == "file:" | return 1 | endif if a:word == "modified:" | return 1 | endif if a:word == "unmerged:" | return 1 | endif if a:word == "deleted:" | return 1 | endif if a:word == "renamed:" | return 1 | endif if a:word == "typechange:" | return 1 | endif if a:word == " " | return 1 | endif if a:word == "" | return 1 | endif return 0 endfunction function! s:isGitFileStatusLine(line) if a:line =~ "new file:" | return 1 | endif if a:line =~ "modified:" | return 1 | endif if a:line =~ "unmerged:" | return 1 | endif if a:line =~ "deleted:" | return 1 | endif if a:line =~ "renamed:" | return 1 | endif if a:line =~ "typechange:" | return 1 | endif return 0 endfunction autoload/gitTools/conflict.vim [[[1 64 " svnipt Name: gitTools/conflict.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Merge all file conflicts. " Open every file in conflict on a new tab and split vertical showing left, " working and right conflic files. " Arg1: path. " Commands: Gitm, Gitmf, Gitmd. function! gitTools#conflict#Merge(path) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif echo "Search files with conflicts. In progress..." let l:list = gitTools#status#GetListOfFilesUnmerged(a:path) let len = len(l:list) if len(l:list) == 0 call gitTools#tools#Warn("No conflicts found") return endif redraw echo "Files in conflict:" for file in l:list echo "- ".l:file endfor call input("Open all with merge tool?") echo " " let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile redraw echo "This may take a while ..." echo "" " Perform git diff on each selected file. " Open each file with vimdiff on new tab let l:n = 0 for l:file in l:list echo "- ".l:file call gitTools#diffTools#VimDiffFileBranch(l:file,l:branch) let l:n += 1 endfor redraw echo " " echo "[gitTools.vim] Show git merge conflicts on ".a:path." using vimdiff. ".l:n." files." endfunction autoload/gitTools/diff.vim [[[1 188 " Script Name: gitTools/diff.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, git. " " "- functions ------------------------------------------------------------------- " Git diff file/path " Command: Gitd, Gitdf, Gitda, Gitdd function! gitTools#diff#Diff(path) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile let path = gitTools#tools#GetPathAsFilename(a:path) let name = "_gitDiff_".l:path.".diff" let l:gitCmd = g:gitTools_gitCmd "let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() "let command = l:gitCmd." diff ".a:path let command = l:gitCmd." diff --unified=4 --no-prefix ".l:branch." ".a:path "echom "Cmd: ".l:command | return let callback = ["gitTools#diff#GitDiffEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(command,callback,1) redraw endfunction function! gitTools#diff#GitDiffEnd(name,resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call gitTools#tools#Warn("Git diff empty") endif call gitTools#tools#WindowSplit() put = readfile(a:resfile) silent exec("set syntax=diff") " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) normal gg let @/ = '^+ \|^- ' call gitTools#tools#WindowSplitEnd() redraw endfunction " Git diff file/path with advanced options " Arg: PATH. Path to check for changed files. " Arg: [FLAGS]: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern: keep files matching pattern. " -SkipPattern: skip files matching pattern. " Command: GitD, GitDA, GitDD. function! gitTools#diff#DiffAdv(...) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif if a:0 == 0 || join(a:000) =~# "help" echo "Get diff changes on the selected path." echo "Arguments: PATH [FLAGS]" echo "- FLAGS: " echo " B (show binaries)." echo " +keepFilePattern" echo " -skipFilePattern" if join(a:000) !~# "help" call gitTools#tools#Error("Missing arguments: PATH") endif return endif let l:equals = "skip" let l:path = "" for l:arg in a:000 if l:arg ==? "BO" || l:arg ==? "SB" || l:arg[0] == '+' || l:arg[0] == '-' " Arguments meant for: gitTools#misc#FilterFilesListWithArgsList elseif l:arg ==? "ALL" let l:equals = "" elseif l:arg ==? "EO" let l:equals = "only" elseif l:arg ==? "SE" let l:equals = "skip" elseif !empty(glob(l:arg)) let l:path .= l:arg." " let l:path = substitute(l:path,'^\s\+','','g') let l:path = substitute(l:path,'\s\+$','','g') else call gitTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if empty(glob(l:path)) call gitTools#tools#Error("Path not found ".l:path) return endif let name = "_gitDiff_".l:path.".diff" echo "" "---------------------------------------- " Get files modified on subversion: "---------------------------------------- echo "Getting modified files on ".l:path."..." let l:filesList = gitTools#status#GetListOfFilesAddedModifiedDeletedUnmerged(l:path) if len(l:filesList) == 0 call gitTools#tools#Warn("[gitTools.vim] No modifications found") return endif redraw echo "Modified Files:" for l:file in l:filesList echo "- ".l:file endfor echo " " echo "Found ".len(l:filesList)." modified files" "call confirm("Perform diff on this ".len(l:filesList)." files?") call confirm("continue?") redraw "---------------------------------------- " Filter files: " Filter acording to flags on arguments list, keep/skip binaries/equal-files/match-patterns. " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern: keep files matching pattern. " -SkipPattern: skip files matching pattern. "---------------------------------------- redraw echo "[gitTools.vim] Filter files on: '".l:path let l:filesList = gitTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path, "") echo "Files to open compare with head revision: ".len(l:filesList) call confirm("Perform diff on this ".len(l:filesList)." files?") "---------------------------------------- " Get the git diff for all files. "---------------------------------------- echo "Getting every file diff..." let l:gitCmd = g:gitTools_gitCmd "let command = l:gitCmd." diff --diff-cmd=diff ".join(l:filesList) let command = l:gitCmd." diff ".join(l:filesList) let callback = ["gitTools#diff#GitDiffEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(command,callback,1) redraw echo "[gitTools.vim] Show git changes on ".l:path." using diff. ".len(l:filesList)." files found." endfunction autoload/gitTools/diffFile.vim [[[1 332 " Script Name: gitTools/diffFile.vim "Description: " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " "- functions ------------------------------------------------------------------- " When placed on a diff file, for each modified file, get its name and filepath. " Return: list containing all modified file paths. function! gitTools#diffFile#GetModifiedFilesList() let list = [] let @z="" silent g/^Index: /y Z silent new silent put=@Z silent! %s/^$//g silent %s/Index: //g if line('$') == 1 && getline(".") == "" " Empty file else let @z="" silent normal ggVG"zy let files = @z let list = split(l:files, "\n") endif quit return l:list endfunction " When placed on a diff file. Extract all modified file names and path. " Perform vimdiff on this files for revision2 with the same files on revision1 " When no revision number provided as argument, try get word under cursor as the " revision number. " When REV2 not provided set REV2=REV1, and dreacrese REV1. " Arg1: [optional] revision1 " Arg2: [optional] revision2 " Cmd: GitDiffVdr function! gitTools#diffFile#OpenVimDiffGetFilesAndRevisionsEveryIndexLine(...) if &filetype !=# 'diff' call gitTools#tools#Warn("Attention, file type is not diff!") call input("") endif let rev1 = "" let rev2 = "" if a:0 >= 2 let rev1 = a:1 let rev2 = a:2 elseif a:0 == 1 let rev2 = a:1 else let rev2 = expand("") endif if l:rev2 == "" call gitTools#tools#Error("Missing revision number") return endif let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') if l:rev2 == "" call gitTools#tools#Error("Wrong revision number ". l:rev2) return endif if l:rev1 == "" let l:rev1 = l:rev2 -1 else let rev1 = substitute(l:rev1, '[^0-9]*', '', 'g') if l:rev1 == "" call gitTools#tools#Error("Wrong revision number ". l:rev1) return endif endif " Save window position let l:winview = winsaveview() " Extract from diff file, the list of modified files. let l:list = gitTools#diffFile#GetModifiedFilesList() " Restore window position call winrestview(l:winview) redraw for file in l:list echo l:file endfor call confirm(len(l:list) ." modified files found. Continue?") " Perform vimdiff for each file and revision. redraw echo "Opening ". l:rev1 .":". l:rev2 ."modifications with vimdiff:" for file in l:list echo "- ". l:file silent call gitTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) setl nomodifiable endfor endfunction " When placed on a log diff file (exmple: _r29456.diff) " Extract all files modified and perform vimdiff from the revision " Cmd: Gitdvdr function! gitTools#diffFile#OpenVimDiffOnEachFileAndRevision() if expand("%") !~ "_r[1-9].*\.diff" echo "First launch commands: Gitr, to get the revision diff." call gitTools#tools#Warn("Current file is not an git diff file!") call confirm("Go ahead with current file?") "return endif " Extract from log file, the revision number. let l:list = gitTools#log#GitLogFileGetCommitNumberList() if len(l:list) != 1 call gitTools#tools#Error("Could't find the revision number!") return endif let l:rev = substitute(l:list[0], '[^0-9]*', '', 'g') let rev2 = str2nr(l:rev) let rev1 = l:rev2 - 1 " Extract from diff file, the list of modified files. let l:list = gitTools#diffFile#GetModifiedFilesList() redraw echo "Files modified: " for file in l:list echo " ".l:file endfor echo "Number of files modified: ".len(l:list) call confirm("Perform vimdiff on each file for between revision: ".l:rev1." and".l:rev2.". Continue?") " Perform vimdiff for each file and revision. redraw echo "Opening ". l:rev1 .":". l:rev2 ." modifications with vimdiff:" for file in l:list echo "- ". l:file silent call gitTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) endfor endfunction " When placed on a diff file. Extract all lines staring with words:'+++ ' and " retrieve the file path an revision number. " Perform vimdiff on this files for the selected revision. " Cmd: GitDiffVdr function! gitTools#diffFile#OpenVimDiffOnAllFiles(...) let l:file = expand("%") let fileDelete = "" if empty(glob(l:file)) " Buffer not saved on file, dump content to a new tmp file let file = tempname() let fileDelete = l:file silent exec(":w! ".l:file) endif " Parse the config file redir! > readfile.out let l:file = readfile(l:file) let l:all = 0 for l:line in l:file if l:line[0:3] == "+++ " let l:list = split(l:line) let l:fileList += [ l:list[1] ] let l:fileRevList += [ l:list[1]." ".l:list[2] ] let l:linesList += [ l:lline ] endif endfor redir END " Clean tmp file used for searching on buffers not saved if l:fileDelete != "" | call delete(l:fileDelete) | endif for l:file in l:fileRevList echo l:file endfor echo "" if confirm("Perform vimdiff all files? ", "&yes\n&no") == 2 let l:n = 0 for l:file in l:fileRevList echo l:file if confirm("Vimdiff file: ".l:file, "&yes\n&no") == 2 let l:linesList[l:n] = "" endif let l:n += 1 endfor endif for l:line in l:linesList if l:line[0:3] == "+++ " if l:line =~ "(working copy)" let l:list = split(l:line) let l:file = l:list[1] call gitTools#vimdiff#File(l:file) else call gitTools#diffFile#OpenVimDiffGetFileAndRevisionFromCurrentLine() endif endif endfor endfunction " When placed on a diff file. Extract current line modified file name and path. " Perform vimdiff on this files for revision2 with the same files on revision1 " When no revision number provided as argument, try get the revision from (revision xxxxxx) at line end. " revision number. " When REV2 not provided set REV2=REV1, and dreacrese REV1. " Arg1: [optional] revision1 " Arg2: [optional] revision2 " Cmd: GitDiffVdrf function! gitTools#diffFile#OpenVimDiffGetFileAndRevisionFromCurrentLine(...) if &filetype !=# 'diff' call gitTools#tools#Warn("Attention, file type is not diff! (Press key to continue)") endif let rev1 = "" let rev2 = "" let file = "" if a:0 >= 3 let file = a:3 endif if a:0 >= 2 let rev1 = a:1 let rev2 = a:2 elseif a:0 == 1 let rev2 = a:1 else " Verify current line type. normal $bbviW"zy let l:check = @z if l:check != "(revision" call gitTools#tools#Error("Verify cursor line position. Place on line ending with: '(revision xxxx)'.") return endif " Extract revision number normal $bviw"zy let l:rev2 = @z endif if l:rev2 == "" call gitTools#tools#Error("Missing revision number") return endif let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') if l:rev2 == "" call gitTools#tools#Error("Wrong revision number ". l:rev2) return endif if l:rev1 == "" let l:rev1 = l:rev2 -1 else let rev1 = substitute(l:rev1, '[^0-9]*', '', 'g') if l:rev1 == "" call gitTools#tools#Error("Wrong revision number ". l:rev1) return endif endif if file == "" " Get file path from current line. " Save window position let l:winview = winsaveview() " Verify current line type. normal 0lllvl"zy let l:tag0 = @z normal 0viW"zy let l:tag1 = @z if l:tag0 =~ "[A-Z] " " Log line with path normal 0wwviW"zy let l:file = @z elseif l:tag1 == "Index:" || l:tag1 == "---" || l:tag1 == "+++" " Diff line with path normal 0wviW"zy let l:file = @z else echo "Place cursor on diff line starting with: 'Index: PATH', '--- PATH', '+++ PATH'." echo "Place cursor on log changed path line starting with: ' [A-Z] PATH'." call gitTools#tools#Error("Line format error. Verify cursor line position.") return endif " Restore window position call winrestview(l:winview) endif " Extract from diff file, the file name and path. if l:file == "" call gitTools#tools#Error("File path not found on current file. Check cursor line position") return endif "call confirm("Vimdiff file: ". l:file ." rev: ". l:rev1 .":". l:rev2) if confirm("Vimdiff file: ". l:file ." rev: ". l:rev1 .":". l:rev2, "&yes\n&no") != 1 return endif " Perform vimdiff for file and revision. redraw echo "Opening ". l:file ." ". l:rev1 .":". l:rev2 ." with vimdiff..." silent call gitTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) setl nomodifiable endfunction autoload/gitTools/diffTools.vim [[[1 409 " Perform diff between same files on different directories/sandboxes " Arg1: file to check on both paths " Arg2: sandbox 1 path " Arg3: sandbox 2 path function! gitTools#diffTools#DiffFiles(file,path1,path2) let l:file1 = a:path1."/".a:file let l:file2 = a:path2."/".a:file return system("diff -ua ".l:file1." ".l:file2) endfunction " Perform vimdiff between same files on different directories/sandboxes " Arg: list with all files to compare function! gitTools#diffTools#VimDiffFilePathsList(pathsList, filesList, setNoModifiable) let l:ext = fnamemodify(a:filesList[0], ":e") for fileName in a:filesList "echo "fileName: ".l:fileName tabnew let l:n = 0 for path in a:pathsList "echo "Path: ".l:path let l:file = l:path."/".l:fileName "echo "File: ".l:file if l:n == 0 " Open first file if !filereadable(l:file) call gitTools#tools#Warn("File not found:".l:file) "silent exec("new ".l:file) else silent exec("e ".l:file) endif else if !filereadable(l:file) call gitTools#tools#Warn("File not found:".l:file) silent exec("vert new".l:file) else silent exec("vert new") silent exec("e ".l:file) endif endif call gitTools#tools#SetSyntax(l:ext) " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") let l:n += 1 if a:setNoModifiable == 1 setl nomodifiable setl buflisted setl bufhidden=delete setl buftype=nofile endif endfor silent exec("windo diffthis") highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey endfor endfunction " Perform vimdiff between same files on different directories/sandboxes " Arg1: sandbox 1 path " Arg2: sandbox 2 path function! gitTools#diffTools#VimDiffFilePaths(file1,file2) let l:isModifiable = 1 call gitTools#diffTools#VimDiffFilePaths_setModifiable(a:file1, a:file2, l:isModifiable, l:isModifiable) endfunction " Perform vimdiff between same files on different directories/sandboxes " Arg1: sandbox 1 path " Arg2: sandbox 2 path function! gitTools#diffTools#VimDiffFilePaths_setModifiable(file1,file2,isModifiable1,isModifiable2) let l:ext = fnamemodify(a:file1, ":e") let l:file1 = a:file1 let l:file2 = a:file2 "Open new tab tabnew " Open file1 if !filereadable(l:file1) call gitTools#tools#Warn("File not found:".l:file1) silent exec("new ".l:file1) else silent exec("e ".l:file1) endif call gitTools#tools#SetSyntax(l:ext) if a:isModifiable1 == 1 silent exec("set modifiable") else silent exec("set nomodifiable") endif silent exec("diffthis") " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") " Open file2 " New vertical split if !filereadable(l:file2) call gitTools#tools#Warn("File not found:".l:file2) silent exec("vert new".l:file2) else silent exec("vert new") silent exec("e ".l:file2) endif silent exec("diffthis") call gitTools#tools#SetSyntax(l:ext) if a:isModifiable2 == 1 silent exec("set modifiable") else silent exec("set nomodifiable") endif " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey endfunction " Perform vimdiff between same files on different directories/sandboxes " Arg1: file to check on both paths " Arg2: sandbox 1 path " Arg3: sandbox 2 path function! gitTools#diffTools#VimDiffFiles(file,path1,path2) let l:ext = fnamemodify(a:file, ":e") let l:file1 = a:path1."/".a:file let l:file2 = a:path2."/".a:file "call s:VimDiffFilePaths(file1,file2) call gitTools#diffTools#VimDiffFilePaths(file1,file2) return "Open new tab tabnew " Open file1 if !filereadable(l:file1) call gitTools#tools#Warn("File not found:".l:file1) silent exec("new ".l:file1) else silent exec("e ".l:file1) endif call gitTools#tools#SetSyntax(l:ext) silent exec("diffthis") " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") " Open file2 " New vertical split if !filereadable(l:file2) call gitTools#tools#Warn("File not found:".l:file2) silent exec("vert new".l:file2) else silent exec("vert new") silent exec("e ".l:file2) endif silent exec("diffthis") call gitTools#tools#SetSyntax(l:ext) " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey endfunction " Perform vimdiff between two revisions or last git revision and current one. " Arg1: rev0 to download from git and compare, if empty use last revision. " Arg2: rev1 to download from git and compare, if empty use current file on disk " Arg3: directory to save git file into. function! gitTools#diffTools#VimDiffFileRev(file,branch,rev0,rev1,saveDir) "Open new tab tabnew let path = fnamemodify(a:file,":p:h") let name = fnamemodify(a:file,":t:r") let ext = fnamemodify(a:file,":e") let nameExt = fnamemodify(a:file,":t") let file = a:file " Remove working directory from path let path1 = substitute(l:path, getcwd(), '', 'g') " Replace each / with _ let path1 = substitute(l:path1, '/', '_', 'g') " Replace duplicated _ let path1 = substitute(l:path1, "__", "_", "") let l:rev0 = "" let l:rev1 = "" if a:rev0 != "" let l:rev0 = "-r ".a:rev0." " endif if a:rev1 != "" let l:rev1 = "-r ".a:rev1." " endif " Get original file echo "This may take a while ..." if a:saveDir != "" let l:tmp = a:saveDir."/".l:path1."_".l:name."_r".a:rev0.".".l:ext else let l:tmp = l:path1."_".l:name."_r".a:rev0.".".l:ext endif if !filereadable(l:tmp) let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() echo "git cat ".l:rev0.a:file silent exec("r !".l:gitCmd." show ".a:branch.":".a:file) silent exec("0file") silent! exec("file ".l:tmp) setl nomodifiable setl buflisted setl bufhidden=delete setl buftype=nofile if a:saveDir != "" echo "Save ".l:tmp silent! exec("w! ".l:tmp) endif else echo "File1 found:".l:tmp silent exec("e ".l:tmp) endif call gitTools#tools#SetSyntax(l:ext) " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") if a:rev1 != "" if a:saveDir != "" let l:tmp = a:saveDir."/".l:path1."_".l:name."_r".a:rev1.".".l:ext else let l:tmp = l:path1."_".l:name."_r".a:rev1.".".l:ext endif " Perform vertical vimdiff on two selected revisions of the file " Make this window part of the diff silent exec("diffthis") " New vertical split silent exec("vert new") " Resize "silent exec("resize ".l:neWidth) if !filereadable(l:tmp) let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() echo "git cat ".l:rev1.a:file silent exec "edit ".a:file silent exec("0file") silent! exec("file ".l:tmp) if a:saveDir != "" silent! exec("w! ".l:tmp) endif else echo "File2 found:".l:tmp silent exec("e ".l:tmp) endif silent exec("diffthis") call gitTools#tools#SetSyntax(l:ext) else " Perform vertical vimdiff between selected revision and current one. " WindowSplitMenu tab in a vimdiff manner silent exec("vert diffsplit ".l:file) endif call gitTools#tools#SetSyntax(l:ext) highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey endfunction " Perform vimdiff of file between two git branches. " Arg1: file, file on curren tbranch to compare. " Arg2: branch, branch to compare thie files with current one. function! gitTools#diffTools#VimDiffFileBranch(file,branch) tabnew let path = fnamemodify(a:file,":p:h") let name = fnamemodify(a:file,":t:r") let ext = fnamemodify(a:file,":e") let nameExt = fnamemodify(a:file,":t") let file = a:file " Remove working directory from path let path1 = substitute(l:path, getcwd(), '', 'g') " Replace each / with _ let path1 = substitute(l:path1, '/', '_', 'g') " Replace duplicated _ let path1 = substitute(l:path1, "__", "_", "") " Get the branch file: let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() echo "git show "a:branch.":".a:file silent exec("r !".l:gitCmd." show ".a:branch.":".a:file) silent normal ggdd let l:tmpFileName = "_branch:".a:branch."_".l:path1."_".l:name.".".l:ext silent exec("0file") silent! exec("file ".l:tmpFileName) setl nomodifiable setl buflisted setl bufhidden=delete setl buftype=nofile call gitTools#tools#SetSyntax(l:ext) " Perform vertical vimdiff between selected revision and current one. silent exec("vert diffsplit ".l:file) call gitTools#tools#SetSyntax(l:ext) highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey " Resize the right window: if g:gitTools_vimdiffWinWidthMultiplyValue <= 0 || g:gitTools_vimdiffWinWidthMultiplyValue >= 2 call gitTools#tools#Error("Wrong variable g:gitTools_vimdiffWinWidthMultiplyValue must be lower than 2 and greater than 0.") else let l:newwidth = winwidth(0) * g:gitTools_vimdiffWinWidthMultiplyValue let l:newwidth = round(l:newwidth) let l:newwidth = string(l:newwidth) silent exec("vertical resize ".l:newwidth) endif endfunction " Perform vimdiff of file between current filea and " Arg1: file, file on current branch to compare. " Arg2: branch, branch to compare thie files with current one. function! gitTools#diffTools#VimDiffThisFileBranch(file,branch) vertical new wincmd H let path = fnamemodify(a:file,":p:h") let name = fnamemodify(a:file,":t:r") let ext = fnamemodify(a:file,":e") let nameExt = fnamemodify(a:file,":t") let file = a:file " Remove working directory from path let path1 = substitute(l:path, getcwd(), '', 'g') " Replace each / with _ let path1 = substitute(l:path1, '/', '_', 'g') " Replace duplicated _ let path1 = substitute(l:path1, "__", "_", "") " Get the branch file: let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() echo "git show "a:branch.":".a:file silent exec("r !".l:gitCmd." show ".a:branch.":".a:file) silent normal ggdd let l:tmpFileName = "_branch:".a:branch."_".l:path1."_".l:name.".".l:ext silent exec("0file") silent! exec("file ".l:tmpFileName) setl nomodifiable setl buflisted setl bufhidden=delete setl buftype=nofile call gitTools#tools#SetSyntax(l:ext) " Perform vertical vimdiff between selected revision and current one. diffthis wincmd l diffthis call gitTools#tools#SetSyntax(l:ext) highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey " Resize the right window: if g:gitTools_vimdiffWinWidthMultiplyValue <= 0 || g:gitTools_vimdiffWinWidthMultiplyValue >= 2 call gitTools#tools#Error("Wrong variable g:gitTools_vimdiffWinWidthMultiplyValue must be lower than 2 and greater than 0.") else let l:newwidth = winwidth(0) * g:gitTools_vimdiffWinWidthMultiplyValue let l:newwidth = round(l:newwidth) let l:newwidth = string(l:newwidth) silent exec("vertical resize ".l:newwidth) endif endfunction autoload/gitTools/directory.vim [[[1 287 " Script Name: gitTools/directory.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " "- functions ------------------------------------------------------------------- " Using git st get the files changed/added/removed on path1 and path2 " Perform vimdiff on all files changed/added/remove between both paths. " Arg: MODE. diff or vimdiff. " Arg: [PATH1]. primary file/path to check for changes, if empty use current WD. " Arg: PATH2 secondary sandbox path to compare changes. " Arg: [FLAGS]: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " C1: compare only with git changes on path1. " C2: compare only with git changes on path2. " Commands: Gitdc, Gitvdc. function! gitTools#directory#CompareChanges(...) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif if a:0 < 2 || join(a:000) =~# "help" echo "Get all the files changed on the provided directories and compare them." echo "Handy to compare two sandboxes." echo "Arguments: MODE [PATH1] PATH2 [FLAGS]" echo "- MODE: diff or vimdiff." echo "- FLAGS: ALL (open all files, even equal or binaries)" echo " EO (show equal files only), BO (show binaries only), SB (skip binaries) SE (skip equal)" echo " C1 (check only path1 changes), C2 (check only path2 changes)" if join(a:000) !~# "help" call gitTools#tools#Error("Missing arguments: PATH") endif return endif let l:mode = "diff" let l:path1 = "" let l:path2 = "" let l:path1Changes = "yes" let l:path2Changes = "yes" for l:arg in a:000 if l:arg ==? "ALL" || l:arg ==? "BO" || l:arg ==? "SB" || l:arg ==? "EO" || l:arg ==? "SE" || l:arg[0] == '+' || l:arg[0] == '-' " Arguments meant for: gitTools#misc#FilterFilesListWithArgsList elseif l:arg ==? "C1" let l:path1Changes = "yes" let l:path2Changes = "no" elseif l:arg ==? "C2" let l:path1Changes = "no" let l:path2Changes = "yes" elseif l:arg == 'diff' let l:mode = "diff" elseif l:arg == 'vimdiff' let l:mode = "vimdiff" elseif !empty(glob(l:arg)) if l:path1 == "" let l:path1 = l:arg let l:path1 = substitute(l:path1,'^\s\+','','g') let l:path1 = substitute(l:path1,'\s\+$','','g') else if l:path2 == "" let l:path2 = l:arg let l:path2 = substitute(l:path2,'^\s\+','','g') let l:path2 = substitute(l:path2,'\s\+$','','g') else call gitTools#tools#Warn("Path1 and Path2 already set. Skipping path: ".l:arg) call confirm("Continue?") endif endif else call gitTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if l:path1 == "./" let l:path1 = getcwd() endif if l:path2 == "./" let l:path2 = getcwd() endif if l:path1 != "" && l:path2 == "" let l:path2 = l:path1 let l:path1 = getcwd() echohl DiffChange echo "Argument path2 missing. Using CWD ".l:path1." as path1." echohl None endif if l:path1 == "" || empty(glob(l:path1)) call gitTools#tools#Error("Path1 not found ".l:path1) return endif if l:path2 == "" || empty(glob(l:path2)) call gitTools#tools#Error("Path2 not found ".l:path2) return endif "---------------------------------------- " Get path1 and/or path2 git changes "---------------------------------------- let l:tmpList = [] echo "Comparing changes between: '".l:path1."' and: '".l:path2."' " if l:path1Changes == "yes" && l:path2Changes == "no" echo " * C1: search only files changed on path1: ".l:path1 elseif l:path1Changes == "no" && l:path2Changes == "yes" echo " * C2: search only files changed on path2: ".l:path2 endif if l:path1Changes != "yes" && l:path2Changes != "yes" call gitTools#tools#Error("No path selected") return endif if l:path1Changes == "yes" echo " " echo "Searching files modified on: ".l:path1 echo "This may take a while ..." " Get files changed on git for path1 "let l:st1 = gitTools#status#GetStatusFilesString(l:path1, '^M\|^A\|^D') let l:st1 = join(gitTools#status#GetListOfFilesAddedModifiedDeleted(l:path1)) if l:st1 == "" echo "Files modified: none (".l:path1.")" else let l:st1 = substitute(l:st1, l:path1."/", '', 'g') let l:st1 = substitute(l:st1, l:path1, '', 'g') let l:tmpList1 = split(l:st1," ") let l:tmpList += l:tmpList1 call gitTools#tools#LogLevel(1, expand(''), "Dir1: ".l:path1) call gitTools#tools#LogLevel(2, expand(''), "Files: ".l:st1) call gitTools#tools#LogLevel(2, expand(''), "") if len(l:tmpList1) == 0 echo "Files modified: none (".l:path1.")" else echo "Files modified: ".len(l:tmpList1)." (".l:path1.")" endif endif endif if l:path2Changes == "yes" echo " " echo "Searching files modified on: ".l:path2 echo "This may take a while ..." " Get files changed on git for path2 "let l:st2 = gitTools#status#GetStatusFilesString(l:path2, '^M\|^A\|^D') let l:st2 = join(gitTools#status#GetListOfFilesAddedModifiedDeleted(l:path2)) if l:st2 == "" echo "Files modified: none (".l:path2.")" else let l:st2 = substitute(l:st2, l:path2."/", '', 'g') let l:st2 = substitute(l:st2, l:path2, '', 'g') let l:tmpList2 = split(l:st2," ") let l:tmpList += l:tmpList2 call gitTools#tools#LogLevel(1, expand(''), "Dir2: ".l:path2) call gitTools#tools#LogLevel(2, expand(''), "Files: ".l:st2) call gitTools#tools#LogLevel(2, expand(''), "") if len(l:tmpList2) == 0 echo "Files modified: none (".l:path2.")" else echo "Files modified: ".len(l:tmpList2)." (".l:path2.")" endif endif endif echo " " if len(l:tmpList) == 0 echo "" call gitTools#tools#Warn("[gitTools.vim] No modifications found") call input("") return endif if l:path1Changes == "yes" && l:path2Changes == "yes" " Remove duplicated files " Sort files let l:sortedList = sort(copy(l:tmpList)) call gitTools#tools#LogLevel(2, expand(''), "Files sorted: ".join(l:sortedList)) call gitTools#tools#LogLevel(2, expand(''), "") " Uniq files let l:filesList = filter(copy(l:sortedList), 'index(l:sortedList, v:val, v:key+1)==-1') call gitTools#tools#LogLevel(2, expand(''), "Files uniq: ".join(l:filesList)) call gitTools#tools#LogLevel(2, expand(''), "") else let l:filesList = l:tmpList endif "---------------------------------------- " "---------------------------------------- echo "Final files to be checked:" let l:n = 1 for l:file in l:filesList echo " - File ".l:n." ".l:file let l:n += 1 endfor echo " " echo "Found ".len(l:filesList)." files with changes." call confirm("continue?") "---------------------------------------- " Filter files: " Filter acording to flags on arguments list, keep/skip binaries/equal-files/match-patterns. " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern : pattern used to keep files with names matching. " -SkipPattern : pattern used to skip files with names not matching. "---------------------------------------- echo "[gitTools.vim] Comparing changes between: '".l:path1."' and: '".l:path2."' " let l:filesList = gitTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path1, l:path2) if len(l:filesList) == 0 echo "" call gitTools#tools#Warn("[gitTools.vim] No modifications found") call input("") return endif echo "Files to open: ".len(l:filesList) call confirm("Perform ".l:mode." on this ".len(l:filesList)." files?") "---------------------------------------- " Perform diff/vimdiff between both paths for the same file. "---------------------------------------- let l:diffText = "" let l:n = 0 for file in l:filesList let l:n += 1 if l:mode == "vimdiff" echo "Vimdiff ".l:n.": ".l:file call gitTools#diffTools#VimDiffFiles(l:file, l:path2, l:path1) else echo "Diff ".l:n.": ".l:file let l:diffText .= gitTools#diffTools#DiffFiles(l:file, l:path2, l:path1) endif endfor if l:mode == "diff" call gitTools#tools#WindowSplitMenu(3) call gitTools#tools#WindowSplit() let @a = l:diffText silent put! a normal gg0 silent exec("0file") silent! exec("file _dirDiff.diff") set ft=diff endif call gitTools#tools#WindowSplitEnd() redraw echo " " echo "[gitTools.vim] Compare git changes between directories ".l:path1." and ".l:path2." with vimdiff. ".len(l:filesList)." files." endfunction autoload/gitTools/gitTools.vim [[[1 180 " Script Name: gitTools.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " " NOTES: " "- functions ------------------------------------------------------------------- " Get the plugin reload command function! gitTools#gitTools#Reload() let l:pluginPath = substitute(s:plugin_path, "autoload/gitTools", "plugin", "") let s:initialized = 0 let l:cmd = "" let l:cmd .= "unlet g:loaded_gittools " let l:cmd .= " | so ".s:plugin_path."/blame.vim" let l:cmd .= " | so ".s:plugin_path."/commands.vim" let l:cmd .= " | so ".s:plugin_path."/conflict.vim" let l:cmd .= " | so ".s:plugin_path."/diff.vim" let l:cmd .= " | so ".s:plugin_path."/diffFile.vim" let l:cmd .= " | so ".s:plugin_path."/diffTools.vim" let l:cmd .= " | so ".s:plugin_path."/directory.vim" let l:cmd .= " | so ".s:plugin_path."/gitTools.vim" let l:cmd .= " | so ".s:plugin_path."/help.vim" let l:cmd .= " | so ".s:plugin_path."/info.vim" let l:cmd .= " | so ".s:plugin_path."/log.vim" let l:cmd .= " | so ".s:plugin_path."/misc.vim" let l:cmd .= " | so ".s:plugin_path."/show.vim" let l:cmd .= " | so ".s:plugin_path."/status.vim" let l:cmd .= " | so ".s:plugin_path."/tools.vim" let l:cmd .= " | so ".s:plugin_path."/utils.vim" let l:cmd .= " | so ".s:plugin_path."/vimdiff.vim" let l:cmd .= " | so ".l:pluginPath."/gitTools.vim" let l:cmd .= " | let g:loaded_gittools = 1" return l:cmd endfunction " Edit plugin files " Cmd: Gitedit function! gitTools#gitTools#Edit() let l:plugin = substitute(s:plugin_path, "autoload/gitTools", "plugin", "") silent exec("tabnew ".s:plugin) silent exec("vnew ".l:plugin."/".s:plugin_name) endfunction function! s:Initialize() "call gitTools#tools#SetLogLevel(0) let s:jobsRunningDict = {} endfunction " Change background/foreground execution of the git commands. " Arg1: [options]. " - Change current mode when aragument is b/f (f:foreground, b:background). " - Show current mode when aragument is '?'. " - Toogle the background/foregraund execution mode when no argument provided. " Commands: Gitbg function! gitTools#gitTools#BackgroundMode(options) if a:options =~ "b" || a:options =~ "f" if a:options =~ "f" let g:gitTools_runInBackground = 0 else let g:gitTools_runInBackground = 1 endif elseif a:options == "" if g:gitTools_runInBackground == 1 let g:gitTools_runInBackground = 0 else let g:gitTools_runInBackground = 1 endif endif if g:gitTools_runInBackground == 1 let l:mode = "background" else let l:mode = "foreground" endif echo "[".s:plugin_name."] run commands in ".l:mode."." endfunction "- GUI menu ------------------------------------------------------------ " " Create menu items for the specified modes. function! gitTools#gitTools#CreateMenus(modes, submenu, target, desc, cmd) " Build up a map command like let plug = a:target let plug_start = 'noremap ' . ' :call GitTools("' let plug_end = '", "' . a:target . '")' " Build up a menu command like let menuRoot = get(['', 'GitTools', '&GitTools', "&Plugin.&GitTools".a:submenu], 3, '') let menu_command = 'menu ' . l:menuRoot . '.' . escape(a:desc, ' ') if strlen(a:cmd) let menu_command .= '' . a:cmd endif let menu_command .= ' ' . (strlen(a:cmd) ? plug : a:target) call gitTools#tools#LogLevel(1, expand(''), l:menu_command) " Execute the commands built above for each requested mode. for mode in (a:modes == '') ? [''] : split(a:modes, '\zs') if strlen(a:cmd) execute mode . plug_start . mode . plug_end call gitTools#tools#LogLevel(1, expand(''), "execute ". mode . plug_start . mode . plug_end) endif " Check if the user wants the menu to be displayed. if g:gitTools_mode != 0 call gitTools#tools#LogLevel(1, expand(''), "execute " . mode . menu_command) execute mode . menu_command endif endfor endfunction "- Release tools ------------------------------------------------------------ " " Create a vimball release with the plugin files. " Commands: Gitvba function! gitTools#gitTools#NewVimballRelease() let text = "" let l:text .= "plugin/gitTools.vim\n" let l:text .= "autoload/gitTools/blame.vim\n" let l:text .= "autoload/gitTools/commands.vim\n" let l:text .= "autoload/gitTools/conflict.vim\n" let l:text .= "autoload/gitTools/diff.vim\n" let l:text .= "autoload/gitTools/diffFile.vim\n" let l:text .= "autoload/gitTools/diffTools.vim\n" let l:text .= "autoload/gitTools/directory.vim\n" let l:text .= "autoload/gitTools/gitTools.vim\n" let l:text .= "autoload/gitTools/help.vim\n" let l:text .= "autoload/gitTools/info.vim\n" let l:text .= "autoload/gitTools/log.vim\n" let l:text .= "autoload/gitTools/misc.vim\n" let l:text .= "autoload/gitTools/show.vim\n" let l:text .= "autoload/gitTools/status.vim\n" let l:text .= "autoload/gitTools/tools.vim\n" let l:text .= "autoload/gitTools/utils.vim\n" let l:text .= "autoload/gitTools/vimdiff.vim\n" let l:text .= "plugin/jobs.vim\n" let l:text .= "autoload/jobs.vim\n" silent tabedit silent put = l:text silent! exec '0file | file vimball_files' silent normal ggdd let l:plugin_name = substitute(s:plugin_name, ".vim", "", "g") let l:releaseName = l:plugin_name."_".g:gitTools_version.".vmb" let l:workingDir = getcwd() silent cd ~/.vim silent exec "1,$MkVimball! ".l:releaseName." ./" silent exec "vertical new ".l:releaseName silent exec "cd ".l:workingDir "call gitTools#tools#WindowSplitEnd() endfunction "- initializations ------------------------------------------------------------ " let s:plugin = expand('') let s:plugin_path = expand(':p:h') let s:plugin_name = expand(':t') call s:Initialize() autoload/gitTools/help.vim [[[1 265 " Script Name: gitTools/help.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " "- Help functions ----------------------------------------------------------- function! gitTools#help#StatusHelp() let text = "[GitTools.vim] help (v".g:gitTools_version."):\n" let text .= "\n" let text .= "Git status help:\n" let text .= "\n" let text .= "Symbols:\n" let text .= " ' ' = unmodified\n" let text .= " M = modified\n" let text .= " T = file type changed (regular file, symbolic link or submodule)\n" let text .= " A = added\n" let text .= " D = deleted\n" let text .= " R = renamed\n" let text .= " C = copied (if config option status.renames is set to \"copies\")\n" let text .= " U = updated but unmerged\n" let text .= "\n" let text .= "Table of states:\n" let text .= " X Y Meaning\n" let text .= " -------------------------------------------------\n" let text .= " [AMD] not updated\n" let text .= " M [ MTD] updated in index\n" let text .= " T [ MTD] type changed in index\n" let text .= " A [ MTD] added to index\n" let text .= " D deleted from index\n" let text .= " R [ MTD] renamed in index\n" let text .= " C [ MTD] copied in index\n" let text .= " [MTARC] index and work tree matches\n" let text .= " [ MTARC] M work tree changed since index\n" let text .= " [ MTARC] T type changed in work tree since index\n" let text .= " [ MTARC] D deleted in work tree\n" let text .= " R renamed in work tree\n" let text .= " C copied in work tree\n" let text .= " -------------------------------------------------\n" let text .= " D D unmerged, both deleted\n" let text .= " A U unmerged, added by us\n" let text .= " U D unmerged, deleted by them\n" let text .= " U A unmerged, added by them\n" let text .= " D U unmerged, deleted by us\n" let text .= " A A unmerged, both added\n" let text .= " U U unmerged, both modified\n" let text .= " -------------------------------------------------\n" let text .= " ? ? untracked\n" let text .= " ! ! ignored\n" let text .= " -------------------------------------------------\n" call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#WindowSplit() call gitTools#tools#WindowSplitEnd() setl nowrap set buflisted set bufhidden=delete set buftype=nofile setl noswapfile silent put = l:text silent! exec '0file | file gitTools.vim_git_status_help' normal ggdd endfunction function! gitTools#help#Help() if g:gitTools_runInBackground == 1 let l:job = "foreground" else let l:job = "background" endif let l:text = "[gitTools.vim] help (v".g:gitTools_version."):\n" let l:text .= "\n" let l:text .= "Abridged command help:\n" let l:text .= "\n" let l:text .= "- Info:\n" let l:text .= " :Giti : get current revision info.\n" let l:text .= " :Gita : show branch info.\n" let l:text .= "\n" let l:text .= "- Blame:\n" let l:text .= " :Gitbl : get blame of current file.\n" let l:text .= "\n" let l:text .= "- Status: show status screen\n" let l:text .= " :Gitst : show file's status (conceal symbols: X and ?).\n" let l:text .= " :Gitsta : show status files (show all symbols).\n" let l:text .= " :Gitstf : show current file status.\n" let l:text .= " :Gitstd : show current directory status.\n" let l:text .= " :Gitsth : show the git status symbols' help.\n" let l:text .= "\n" let l:text .= "- Short Status:\n" let l:text .= " :GitSt : show file's status (conceal symbols: X and ?).\n" let l:text .= " :GitSta : show status files (show all symbols).\n" let l:text .= " :GitStf : show current file status.\n" let l:text .= " :GitStd : show current directory status.\n" let l:text .= " :GitSth : show the git status symbols' help.\n" let l:text .= "\n" let l:text .= "- Status commands:\n" let l:text .= " Can be lanuched from within status screen when cursor placed on git file or directory.\n" let l:text .= " :Gita [FILEPATH] : add file to git stage.\n" let l:text .= " :Gitu [FILEPATH] : unstage file.\n" let l:text .= " :GitR [FILEPATH] : restore file.\n" let l:text .= " :Gitrm [FILEPATH] : remove file/dir from repository.\n" let l:text .= " :Gitmv [FILEPATH] : move file/dir path.\n" let l:text .= " :GitRM [FILEPATH] : Remove from disk.\n" let l:text .= "\n" let l:text .= "- Log:\n" let l:text .= " :Gitl [NUM] : get subversion log (num. commits, defaults to ".g:gitTools_lastCommits.").\n" let l:text .= " :Gitls PATTERN [NUM] : log search pattern (num. commits, defaults to ".g:gitTools_lastCommits.").\n" "let l:text .= " :Gitlf FILEPATH : show file log.\n" "let l:text .= " :Gitlr [NUM] : when placed on a git log file, get the log and diff of each revison.\n" "let l:text .= " NUM: given a number, only first number of changes will be get.\n" let l:text .= "\n" let l:text .= "- Diff:\n" let l:text .= " Basic:\n" let l:text .= " :Gitd PATH : get diff of changes on the selected path.\n" let l:text .= " :Gitdf : get diff of changes on current file.\n" let l:text .= " :Gitdd : get diff of changes on current file's directory.\n" let l:text .= " :Gitda : get diff of (all) changes on current workind directory.\n" let l:text .= " Advanced: allows to filter files and binaries.\n" let l:text .= " :GitD PATH [FLAGS] : get diff of changes on selected path.\n" let l:text .= " :GitDD [FLAGS] : get diff of changes on current file's directory.\n" let l:text .= " :GitDA [FLAGS] : get diff of (all) changes on workind directory.\n" let l:text .= " Gitdvdr : when placed on a git log and diff file (after Gitr/Gitdd/Gitdf/Gitda)\n" let l:text .= " get each file changes vimdiff.\n" let l:text .= "\n" let l:text .= "- Vimdiff:\n" let l:text .= " Basic:\n" let l:text .= " :Gitvdf : get vimdiff of current file changes.\n" let l:text .= " :Gitvd PATH : get vimdiff of (all) changes on working dir.\n" let l:text .= " :Gitvdd : get vimdiff of current file's directory changes.\n" let l:text .= " :Gitvda : get vimdiff of (all) files with changes on working dir.\n" let l:text .= " Advanced: allows to filter files and binaries.\n" let l:text .= " :GitvD PATH [FLAGS] : get vimdiff of the files with changes on the selected path.\n" let l:text .= " :GitvDD [FLAGS] : get vimdiff of the files with changes on current file's directory.\n" let l:text .= " :GitvDA [FLAGS] : get vimdiff of the files with changes on working directory.\n" let l:text .= " FLAGS:\n" let l:text .= " B: show binaries.\n" let l:text .= " NB: skip binaries (default).\n" let l:text .= " EQ: show equal (default).\n" let l:text .= " NEQ: skip equal.\n" let l:text .= " +pattern (keep only files with pattern).\n" let l:text .= " -pattern (skip all files with pattern).\n" let l:text .= " Gitvdr REV : get revision log and open the selected revision changes with vimdiff.\n" let l:text .= "\n" "let l:text .= "- Directory compare (sandbox compare):\n" "let l:text .= " Compare files with changes on both paths:\n" "let l:text .= " :Gitdc [PATH1] PATH2 [FLAG] : get diff on all changes.\n" "let l:text .= " :Gitvdc [PATH1] PATH2 [FLAG] : get vimdiff on all changes.\n" "let l:text .= " FLAG:\n" "let l:text .= " ALL: show all files.\n" "let l:text .= " EO: equal files only.\n" "let l:text .= " SE: skip equal files (default).\n" "let l:text .= " BO: binary files only. \n" "let l:text .= " SB: skip binary files (default).\n" "let l:text .= " C1: check only git changes on path1.\n" "let l:text .= " C2: check only git changes on path2.\n" "let l:text .= "\n" let l:text .= "- Revision:\n" let l:text .= " :Gitr REV : get diff of selected revision number.\n" let l:text .= " :Gitsh REV : show the file on the requested revision number\n" let l:text .= "\n" let l:text .= "- Conflicts:\n" "let l:text .= " :Gitm [LAYOUT] : merge all conflicts with vimdiff. Layouts: ".g:gitTools_mergeLayouts." (default layout: ".g:gitTools_mergeLayout.").\n" "let l:text .= " :Gitmf [LAYOUT] : merge current file conflict with vimdiff. Layouts: ".g:gitTools_mergeLayouts." (default layout: ".g:gitTools_mergeLayout.").\n" "let l:text .= " :Gitmp PATH [LAYOUT] : merge selected path conflicts with vimdiff. Layouts: ".g:gitTools_mergeLayouts." (default layout: ".g:gitTools_mergeLayout.").\n" let l:text .= " :Gitm [LAYOUT] : merge all conflicts with vimdiff.\n" let l:text .= " :Gitmf [LAYOUT] : merge current file conflict with vimdiff.\n" let l:text .= " :Gitmp PATH [LAYOUT] : merge selected path conflicts with vimdiff.\n" let l:text .= "\n" "let l:text .= "- Password:\n" "let l:text .= " :Gitpwd : set git user and password.\n" "let l:text .= " Custom .vimrc config:\n" "let l:text .= " let g:gitTools_userAndPsswd = 1\n" "let l:text .= " let g:gitTools_gitUser = 'MY_USER'\n" "let l:text .= "\n" let l:text .= "- Tools:\n" let l:text .= " :Gitbg : toogle git job run on ".l:job."\n" let l:text .= "\n" let l:text .= "\n" let l:text .= "-------------------------------------------------------------------------\n" let l:text .= "\n" let l:text .= "EXAMPLES:\n" let l:text .= "\n" let l:text .= "- Get diff of all modified files:\n" let l:text .= " :Gitda\n" let l:text .= "\n" let l:text .= "- Get diff off all changes on selected path (show equal and binary files):\n" let l:text .= " :GitD project1/source ALL\n" let l:text .= "\n" let l:text .= "- Get diff off all changes on selected path, only cpp files:\n" let l:text .= " :GitD project1/source +cpp\n" let l:text .= "\n" let l:text .= "- Get diff off all changes on all cpp files:\n" let l:text .= " :GitDA +cpp\n" let l:text .= "\n" let l:text .= "- Get diff off all changes on all cpp and xml files, skip config files:\n" let l:text .= " :GitDA +cpp +xml -config\n" let l:text .= "\n" let l:text .= "- Get vimdiff off each cpp file with changes on the selected path\n" let l:text .= " :GitVD project1/source +cpp\n" let l:text .= "\n" let l:text .= "- Get vimdiff off every file changed:\n" let l:text .= " :Gitvda\n" let l:text .= "\n" let l:text .= "- Get vimdiff off each cpp and xml, but not config file with changes:\n" let l:text .= " :GitVDA +cpp +xml -config\n" let l:text .= "\n" "let l:text .= "- Compare the files changed on two directories (omitt binaries and equal files):\n" "let l:text .= " :Gitvdc /home/jp/sandbox1 /home/jp/sandbox2/\n" "let l:text .= "\n" "let l:text .= "- Compare the files changed on two directories (show equal and binary files):\n" "let l:text .= " :Gitvdc /home/jp/sandbox1 /home/jp/sandbox2/ ALL\n" "let l:text .= "\n" "let l:text .= "- Compare the files changed on current directory (flag C1) with its counterpart on another directory:\n" "let l:text .= " (equal files and binaries omitted by default)\n" "let l:text .= " :Gitvdc /home/jp/sandbox2/ C1\n" "let l:text .= "\n" call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#WindowSplit() call gitTools#tools#WindowSplitEnd() setl nowrap set buflisted set bufhidden=delete set buftype=nofile setl noswapfile silent put = l:text silent! exec '0file | file gitTools_plugin_help' normal ggdd endfunction " Test git status colors: "A unmerged, added by us "A unmerged, added by us "AA unmerged, added by us "D unmerged, added by us "D unmerged, added by us "DD unmerged, added by us "M unmerged, added by us "M unmerged, added by us "MM unmerged, added by us "T unmerged, added by us "T unmerged, added by us "TT unmerged, added by us "R unmerged, added by us "R unmerged, added by us "RR unmerged, added by us "C unmerged, added by us "C unmerged, added by us "CC unmerged, added by us "AD unmerged, added by us "DD unmerged, both deleted "AU unmerged, added by us "UD unmerged, deleted by them "UA unmerged, added by them "DU unmerged, deleted by us "AA unmerged, both added "UU unmerged, both modified autoload/gitTools/info.vim [[[1 148 " Script Name: gitTools/info.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " " "- functions ------------------------------------------------------------------- " Get git info " Return: list with all branches. " Cmd: Giti function! gitTools#info#Info() let l:header = "[gitTools.vim] Git info:" let l:gitCmd = g:gitTools_gitCmd let l:rev = "Revision: ".system(l:gitCmd. " rev-list --count HEAD") let l:desc = "Describe: ".system(l:gitCmd." describe --always --tags --dirty") let l:branch = "Branch: ".gitTools#info#GetCurrentBranch() echo l:header echo l:rev echo l:desc echo l:branch endfunction " Get the git branch configured. " Return: string with git branch name. function! gitTools#info#GetCurrentBranch() let l:list = [] let l:gitCmd = g:gitTools_gitCmd let text = system(l:gitCmd." branch ") if l:text == "" return "" endif if line('$') == 1 && getline(".") == "" " Empty file return "" else for l:line in split(l:text, "\n") let l:fieldsList = split(l:line, " ") if l:fieldsList[0] == "*" && len(l:fieldsList) > 1 return l:fieldsList[1] endif endfor endif endfunction " Show all available branches: " Cmd: Gitb function! gitTools#info#ShowBranches() let l:list = [] let l:gitCmd = g:gitTools_gitCmd let text = system(l:gitCmd." branch ") if l:text == "" return endif if line('$') == 1 && getline(".") == "" " Empty file else echo "[gitTools.vim] Git branches:" for branch in split(l:text, "\n") echo l:branch endfor endif endfunction " Get all available branches: " Return: list with all branches. function! gitTools#info#Branches() let l:list = [] let l:gitCmd = g:gitTools_gitCmd let text = system(l:gitCmd." branch ") if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd silent exec "g/^$/d" if line('$') == 1 && getline(".") == "" " Empty file else " Get last column. File paths. silent normal gg0wG$"zy let files = @z "echom "Files: ".l:files let list = split(l:files, "\n") if len(l:list) == 0 " Only one file. let list = [ l:files ] endif "echom "Git status list: "l:list endif silent quit! return l:list endfunction function! gitTools#info#ChooseBranchMenu() let l:branchList = ["origin"] let l:branchList += gitTools#info#Branches() if len(l:branchList) == 0 call gitTools#tools#Warn("[gitTools.vim] No branch found") endif let l:i = 1 for l:branch in l:branchList echo l:i.") ".l:branch let l:i += 1 endfor let l:I = input("Choose branch: ") echo " " if l:I <= 0 || l:I > len(l:branchList) "call gitTools#tools#Warn("[gitTools.vim] Wrong branch number ".l:I) "return "" let l:default = gitTools#info#GetCurrentBranch() echo "Use default branch: ".l:default return l:default endif let l:branch = l:branchList[l:I-1] echo "Use branch: ".l:branch return l:branch endfunction autoload/gitTools/log.vim [[[1 405 " Script Name: gitTools/log.vim "Description: " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " " "- functions ------------------------------------------------------------------- " Get the git log history for the selected path. " Arg1: path. " Arg2: [optional] options ex: -v, --verbose. " Commands: Gitlf function! gitTools#log#GetHistory(...) let l:options = "" if len(a:000) == 0 let l:filepath = expand("%") elseif len(a:000) >= 1 let l:filepath = substitute(a:1, getcwd(), "", "g") elseif len(a:000) >= 1 let l:options = a:2 ." " endif let file = substitute(l:filepath, "\/", "_", "g") let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let name = "_gitLog_". l:file .".log" let command = l:gitCmd." log ". l:options . l:filepath let callback = ["gitTools#log#GitLogFileEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! gitTools#log#GitLogFileEnd(name, resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call gitTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) silent put = readfile(a:resfile) silent exec("normal gg") call delete(a:resfile) normal gg call gitTools#tools#WindowSplitEnd() redraw call s:SetSyntaxAndHighlighting("") else call gitTools#tools#Warn("Git log search empty") endif endfunction " When placed on a git log file, get each commit number. " Return: list containing all commit numbers. function! gitTools#log#GitLogFileGetCommitNumberList() let list = [] let @z="" silent g/^r.*\|.*(.*).*lines/y Z silent new silent put=@Z silent! g/^$/d silent! %s/ |.*$//g "silent bd! if line('$') == 1 && getline(".") == "" " Empty file else let @z="" silent normal ggVG"zy let revNum = @z let list = split(l:revNum, "\n") endif quit return l:list endfunction " Get git log and git diff from the given revision number. " Arg1: rev. Revision number: r34567 or 34567. " Arg2: mode. Use new_tab to open each revison on new tab. function! s:GitLogFileGetRevisionDiff(rev, mode) let l:rev = substitute(a:rev, '[^0-9]*', '', 'g') let prev = l:rev - 1 let name = "_r".l:rev.".diff" let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let command = l:gitCmd." log -vr ".l:rev." --diff" "let command = "git log -vr ".l:rev." --diff" let text = system(l:command) if l:text == "" echo "Failed" return 1 endif if a:mode == "new_tab" silent tabnew normal ggO silent put=l:text normal ggdd " Rename buffer silent! exec("0file") silent! exec("bd! ".l:name) silent! exec("file! ".l:name) silent exec("set syntax=diff") silent exec("normal gg") else normal GO silent put=l:text endif endfunction " When placed on the git log file open all revisions. " Commands: Gitlr " PENDING: adapt for git function! gitTools#log#GetRevDiff(num) if expand("%") !~ "_gitLog_.*\.log" echo "First launch one of following commands: Gitl, Gitls, Gitlf, Gitld or Gitlp, to get the revision log." call gitTools#tools#Error("Current file is not an git log file!") return endif let l:filename = expand("%") " Get all revision numbers let l:list = gitTools#log#GitLogFileGetCommitNumberList() if len(l:list) == 0 call gitTools#tools#Error("No revision number found on current buffer!") return endif redraw echo "Number of commits: ".len(l:list) echo "Commits found: ".join(l:list) if a:num != "" call confirm("Open the first ".a:num." revisions. Continue?") let max = str2nr(a:num) else call confirm("Open each revision diff. Continue?") let max = len(l:list) endif if confirm("Open each revision on new tab?", "&yes\n&no", 1) == 2 let l:mode = "same_tab" silent tabnew " Rename buffer let l:newname = substitute(l:filename, 'gitLog', 'gitLogRevDiff_'.l:max.'Rev_', "g") if l:newname != "" silent! exec("0file") silent! exec("bd! ".l:newname) silent! exec("file! ".l:newname) endif else let l:mode = "new_tab" endif redraw " Perform git log and git diff for each revision. let n=1 for rev in l:list echo l:n."/".l:max.") Getting ".l:rev." log and diff..." call s:GitLogFileGetRevisionDiff(l:rev, l:mode) let n+=1 if a:num != "" && l:n > l:max | break | endif endfor endfunction " Search the git log for commit number " Arg1: [commitNum] number of commits to search " Commands: Gitl function! gitTools#log#GetRevision(commitNum) echo "Get log changes." let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() " Get git log from last x commits let l:command = l:gitCmd." log " echo "This may take a while ..." let l:name = "_gitLog.log" let callback = ["gitTools#log#GetRevisionEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! gitTools#log#GetRevisionEnd(name,resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call gitTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) silent put = readfile(a:resfile) silent exec("normal gg") call delete(a:resfile) normal gg call gitTools#tools#WindowSplitEnd() redraw call s:SetSyntaxAndHighlighting("") else call gitTools#tools#Warn("Git log search empty") endif endfunction " Search the git log for pattern " Arg1: pattern to search. " Commands: Gitls function! gitTools#log#SearchPattern(pattern) let l:pattern = a:pattern if l:pattern == "" call gitTools#tools#Warn("Argument 1: search pattern not found.") return endif echo "Search pattern: ".l:pattern echo "git log --grep=\" ".l:pattern."\"" let l:name = "_gitLogGrep_".l:pattern.".log" let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let command = l:gitCmd." log --grep=\"".l:pattern."\"" let callback = ["gitTools#log#GitLogSearchPatternEnd", l:name] call gitTools#tools#WindowSplitMenu(4) echo "This may take a while ..." call gitTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! gitTools#log#GitLogSearchPatternEnd(name,resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call gitTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) put = readfile(a:resfile) call s:SetSyntaxAndHighlighting("") silent exec("normal gg") call delete(a:resfile) normal gg call gitTools#tools#WindowSplitEnd() redraw else call gitTools#tools#Warn("Git log search pattern empty") endif endfunction " Get log and diff from the selected revision. " Arg1: revision number to search. " Command: Gitr function! gitTools#log#GetLogAndDiff(rev) if a:rev == "" let l:rev = expand("") else let l:rev = a:rev endif " CHeck revision number lenght: if len(l:rev) < 11 call gitTools#tools#Error("Wrong revision number lenght ".l:rev." (expected lenght >= 12)") return endif " Check contains both numbers and letters: let l:numbers = substitute(l:rev, '[^0-9]*', '', 'g') let l:letters = substitute(l:rev, '[^a-zA-Z]*', '', 'g') if l:numbers == "" || l:letters == "" call gitTools#tools#Warn("Found a weird revision number ".l:rev) call confirm("Proceed?") endif let name = "_gitShowRev_".l:rev.".diff" echo "Getting ".l:rev." log and diff" let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let command = l:gitCmd." show ".l:rev let callback = ["gitTools#log#GetLogAndDiffEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! gitTools#log#GetLogAndDiffEnd(name,resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call gitTools#tools#Warn("Git log and diff empty") return endif call gitTools#tools#WindowSplit() call gitTools#tools#LogLevel(1, expand(''), "name=".a:name) " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) put = readfile(a:resfile) call s:SetSyntaxAndHighlighting("diff") silent exec("normal gg") call delete(a:resfile) call gitTools#tools#WindowSplitEnd() redraw endfunction " Set file type and if hi.vim plugin is available: apply a color highlighting. " Arg1: syntax, file syntax (c, cpp, py, sh, diff...). " Leave empty ("") to not apply any file type syntax. function! s:SetSyntaxAndHighlighting(syntax) if exists('g:HiLoaded') let g:HiCheckPatternAvailable = 0 silent! call hi#config#PatternColorize("commit " , "w*") silent! call hi#config#PatternColorize("Author: ", "c*") silent! call hi#config#PatternColorize("Date: " , "o2*") silent! call hi#config#PatternColorize("Merge: " , "o*") silent! call hi#config#PatternColorize("http>>:>>\ ", "b_&") let g:HiCheckPatternAvailable = 1 endif if a:syntax != "" silent exec("set ft=".a:syntax) if exists('g:HiLoaded') call hi#hi#Refresh() endif endif endfunction " Get the git reflog. " Commands: Gitrl function! gitTools#log#GetRefLog() let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let name = "_gitRefLog.log" let command = l:gitCmd." reflog " let callback = ["gitTools#log#GitRefLogEnd", l:name] call gitTools#tools#WindowSplitMenu(4) call gitTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! gitTools#log#GitRefLogEnd(name, resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call gitTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) silent put = readfile(a:resfile) silent exec("normal gg") call delete(a:resfile) normal gg call gitTools#tools#WindowSplitEnd() redraw "call s:SetSyntaxAndHighlighting("") if exists('g:HiLoaded') let g:HiCheckPatternAvailable = 0 silent! call hi#config#PatternColorize(": commit: " , "c") silent! call hi#config#PatternColorize(": commit (merge): ", "c") silent! call hi#config#PatternColorize(": pull.*: .*" , "v") silent! call hi#config#PatternColorize(": reset.*: .*" , "o2") silent! call hi#config#PatternColorize(": checkout.*: .*", "b1") silent! call hi#config#PatternColorize(": clone.*: .*" , "w") let g:HiCheckPatternAvailable = 1 endif else call gitTools#tools#Warn("Git ref log search empty") endif endfunction autoload/gitTools/misc.vim [[[1 315 " Script Name: gitTools/misc.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: diff, wc. " " "- functions ------------------------------------------------------------------- " Filter a files list acording to the arguments list. " Remove binary files if required. " Remove files not matching patterns if required. " Keep only files matching patterns if required. " Arg1: arsList. List of arguments containing the filter options. " Arg2: filesList. List of filepaths. " Arg3: [path1]. Primary path. Use "" to skip. Used to remove unwanted path form files on the filesList. " Arg4: [path2]. Secondary path. Use "" to skip. Used to get same files on filesList on different directory. " Return: filtered files' list. " Used by: GitD, GitDA, GitDD, GitVD, GitVDA, GitVDD, Gitdc, Gitvdc, Vdd. function! gitTools#misc#FilterFilesListWithArgsList(argsList, filesList, path1, path2) "echom "gitTools#misc#FilterFilesListWithArgsList("a:argsList.", "a:filesList.", ".a:path1.", ".a:path2.")" let l:equals = "skip" let l:binaries = "skip" let l:keepStr = "" let l:filterStr = "" for l:arg in a:argsList if l:arg ==? "ALL" let l:equals = "" let l:binaries = "" elseif l:arg ==? "EO" let l:equals = "only" elseif l:arg ==? "SE" let l:equals = "skip" elseif l:arg ==? "BO" let l:binaries = "only" elseif l:arg ==? "SB" let l:binaries = "skip" elseif l:arg[0] == '+' let l:keepStr .= l:arg[1:]." " elseif l:arg[0] == '-' let l:filterStr .= l:arg[1:]." " endif endfor if l:equals.l:binaries.l:filterStr.l:keepStr != "" echon " Flags: " if l:equals == "skip" echon "skip_equal_files " elseif l:equals == "only" echon "show_equal_files_only " endif if l:binaries == "skip" echon "skip_binaries " elseif l:binaries == "only" echon "show_binaries_only " endif if l:keepStr != "" echon "KeepOnly: ".l:keepStr." " endif if l:filterStr != "" echon "Skip: ".l:filterStr." " endif endif echo " " return gitTools#misc#FilterFilesListWithOptions(a:filesList, l:equals, l:binaries, l:keepStr, l:filterStr, a:path1, a:path2) endfunction " Filter a files list acording to the options selected. " Remove binary files if required. " Remove files not matching patterns if required. " Keep only files matching patterns if required. " Arg1: filesList. List of filepaths. " Arg2: binSkip. Skip binary files if not empty. " Arg3: keepStr. Pattern to match with filename to keep it. " Arg4: filterStr. Pattern to match with filename to skip it. " Arg5: [path1]. Primary path. Use "" to skip. Used to remove unwanted path form files on the filesList. " Arg6: [path2]. Secondary path. Use "" to skip. Used to get same files on filesList on different directory. " Return: filtered files' list. " Used by: GitD, GitDA, GitDD, GitVD, GitVDA, GitVDD, Gitdc, Gitvdc, Vdd. function! gitTools#misc#FilterFilesListWithOptions(filesList, equals, binaries, keepStr, filterStr, path1, path2) "---------------------------------------- " Check all files: "---------------------------------------- let l:filesList = [] let l:n = 0 let l:openNum = 0 let l:equalNum = 0 let l:binNum = 0 let l:skipNum = 0 let l:changesNum = 0 let l:file2 = "" if a:equals != "" && !executable('diff') call gitTools#tools#Warn("Warning. diff executable not found. Can't check if files differ!") endif for l:file1 in a:filesList "echom "File1:".l:file1 "echom "File2:".l:file2 " " Check if file is binary: let l:isBinary = 0 let l:skipFile = 0 let res = system("file ".l:file1) "echom l:file1." ".l:res if l:res =~ " cannot open" echohl Title echo " - File ".l:n.": ".l:file1." (error: cannot open)" echohl None continue elseif l:res =~ " directory" continue elseif l:res !~ " text" && l:res !~ " link" let l:isBinary = 1 endif if !filereadable(l:file1) echohl Error echo " - File ".l:n.": ".l:file1." (error: not found)" echohl None continue endif let l:n += 1 if a:binaries == "skip" && l:isBinary == 1 let l:skipFile = 1 let l:text = "" elseif a:binaries == "only" && l:isBinary == 0 let l:skipFile = 1 let l:text = "not " endif if l:skipFile == 1 echohl DiffText echo " - File ".l:n.": ".l:file1." (skip, file is ".l:text."binary)" echohl None let l:binNum += 1 continue endif if a:path2 != "" let l:file2 = a:path2 let l:file2 .= substitute(l:file1, a:path1, "", "") if !filereadable(l:file2) echohl Error echo " - File ".l:n.": ".l:file2." (error: not found)" echohl None continue endif endif " Check if file must be skipped if a:filterStr != "" let skip = 0 for l:filter in split(a:filterStr, '') "echom "Check ".l:file1." with filter:-".l:filter if l:file1 =~? l:filter echohl Conceal echo " - File ".l:n.": ".l:file1." (skip, matching ".l:filter.")" echohl None let l:skipNum += 1 let skip = 1 break endif endfor if l:skip == 1 | continue | endif endif " Check if file must be keeped if a:keepStr != "" let keep = 0 for l:filter in split(a:keepStr, ' ') "echom "Check ".l:file1." with filter:+".l:filter if l:file1 =~? l:filter let l:keep = 1 break endif endfor if l:keep == 0 echohl Conceal echo " - File ".l:n.": ".l:file1." (skip, not matching ".l:filter.")" echohl None let l:skipNum += 1 continue endif endif if l:file2 != "" && executable('diff') " Check if files are equal: let l:areEqual = 0 let l:skipFile = 0 let l:diffNumTxt = "" if system("diff -qa ".l:file1." ".l:file2) == "" let l:areEqual = 1 else if executable('wc') let l:diffNum = system("diff --suppress-common-lines --speed-large-files -y ".l:file1." ".l:file2." | wc -l") let l:diffNum = substitute(l:diffNum, '\n', '', 'g') let l:changesNum += str2nr(l:diffNum) let l:diffNumTxt = " ".l:diffNum endif endif if a:equals == "skip" && l:areEqual == 1 let l:skipFile = 1 let l:text = "" elseif a:equals == "only" && l:areEqual == 0 let l:skipFile = 1 let l:text = "not " endif if l:skipFile == 1 "echohl Conceal "echohl SpecialKey echohl DiffChange echo " - File ".l:n.": ".l:file1." and ".l:file2." (skip, files are ".l:text."equal)" echohl None let l:equalNum += 1 continue endif endif " Found file to be opened. let l:filesList += [ l:file1 ] let l:openNum += 1 if l:file2 != "" echohl DiffAdd echo " - File ".l:n.": ".l:file1." and ".l:file2." (differ".l:diffNumTxt.")" echohl None else echo " - File ".l:n.": ".l:file1 endif endfor " Show results: echo " " echo "Checked: ".l:n." files" if a:equals == "skip" echon ", ".l:equalNum." are equal" endif if a:binaries == "skip" echon ", ".l:binNum." are binaries" endif if a:equals == "only" echon ", ".l:equalNum." are not equal" endif if a:binaries == "only" echon ", ".l:binNum." are not binaries" endif if a:keepStr.a:filterStr != "" echon ", ".l:skipNum." skipped" endif echo "" echon "Changes: ".l:openNum." files" if l:changesNum != "" echon ", ".l:changesNum." lines" endif if l:openNum == 0 return [] endif call confirm("Continue?") let l:handPick = 0 if a:keepStr.a:filterStr == "" if confirm("Pick files manually?", "&yes\n&no", 2) == 1 let l:handPick = 1 endif endif " SHow all files: let l:tmpList = [] let l:n = 1 for l:file1 in l:filesList if l:file2 != "" let l:file2 = substitute(l:file1, a:path1, a:path2, "") echo " - File ".l:n.": ".l:file1." and ".l:file2 else echo " - File ".l:n.": ".l:file1 endif if l:handPick == 1 if confirm("Open file?", "&yes\n&no", 2) == 1 let l:tmpList += [ l:file1 ] endif endif let l:n += 1 endfor if l:handPick == 1 let l:filesList = l:tmpList endif return l:filesList endfunction autoload/gitTools/show.vim [[[1 96 " Script Name: gitTools/show.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " "- functions ------------------------------------------------------------------- " Get the current file's selected git revision. " Arg1: revision number to search. " Commands: Gitsh " PENDING: make use of jobs.vim to launch the command on background. function! gitTools#show#Revision(rev) let l:file = expand("%") let l:filePathToName = substitute(l:file,"/","_","g") let l:ext = expand("%:e") let l:name = expand("%:t") if a:rev == "" let l:rev = substitute(expand(""), 'r', '', '') else let l:rev = substitute(a:rev, 'r', '', '') endif if l:rev == "" call gitTools#tools#Warn("Argument 1: revision number not found.") return endif " CHeck revision number lenght: if len(l:rev) < 12 call gitTools#tools#Error("Wrong revision number lenght ".l:rev." (expected lenght >= 12)") return endif " Check contains both numbers and letters: let l:numbers = substitute(l:rev, '[^0-9]*', '', 'g') let l:letters = substitute(l:rev, '[^a-zA-Z]*', '', 'g') if l:numbers == "" || l:letters == "" call gitTools#tools#Warn("Found a weird revision number ".l:rev) call confirm("Proceed?") endif let filepath = expand("%") let filename = expand("%:t:r") echo "Get file: ".l:filename." revision: ".l:rev echo " " let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile call gitTools#tools#WindowSplitMenu(3) call gitTools#tools#WindowSplit() let l:gitCmd = g:gitTools_gitCmd echo l:gitCmd." show ".l:branch.":".l:file echo "This may take a while ..." let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() silent exec("r !".l:gitCmd." show ".l:branch.":".l:file) if line('$') == 1 call gitTools#tools#WindowSplitEnd() call gitTools#tools#Warn("Not found") return endif call gitTools#tools#SetSyntax(l:ext) silent exec("0file") silent! exec("file _gitShowRev_".l:rev."_".l:filePathToName) setl nomodifiable setl buflisted setl bufhidden=delete setl buftype=nofile call gitTools#tools#WindowSplitEnd() redraw endfunction autoload/gitTools/status.vim [[[1 423 " Script Name: gitTools/status.vim "Description: save/restore/compare the file changes. " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " " NOTES: " " Show on a new window the git status lines matching the selected filter " pattern. " Arg1: path, file or path to check with git status " Arg2: git commmand options (-uno --branch --show-stash...). " Commands: Gitst, Gitsta, Gitstf, Gitstd. function! gitTools#status#GetStatus(path, options) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let l:gitOptions = "--branch --show-stash ".a:options let command = l:gitCmd." status ".l:gitOptions." ".a:path let callback = ["gitTools#status#GetStatusEnd", a:path, a:options] call gitTools#tools#WindowSplitMenu(1) call gitTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! gitTools#status#GetStatusEnd(path, options, resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call gitTools#tools#Warn("Git status ". a:path .". No modifications found.") return endif call gitTools#tools#WindowSplit() put = readfile(a:resfile) call delete(a:resfile) " Rename window let l:flatpath = gitTools#tools#GetPathAsFilename(a:path) let l:filename = "_gitStatus_".l:flatpath.".txt" silent exec("0file") silent! exec("file ".l:filename) " Add header on top let l:textList = [] let l:textList += [ " [gitTools.vim]" ] let l:textList += [ " git status ".a:path."" ] let l:textList += [ " ==========================================================" ] let l:textList += [ " Available commands:" ] let l:textList += [ " Place cursor on line showing git file's status then:" ] let l:textList += [ " - Use :Gita to add to the staging area." ] let l:textList += [ " - Use :Gitu to remove from staging area." ] let l:textList += [ " - Use :GitR to restore discarding the changes." ] let l:textList += [ " - Use :Gitrm to remove from repository." ] let l:textList += [ " - Use :Gitmv to change the path." ] let l:textList += [ " - Use :GitRM to remove from disk." ] let l:text = gitTools#tools#EncloseOnRectangle(l:textList, "bold", "") normal ggO put=l:text normal ggdd " Resize window to fit content. call gitTools#tools#WindowSplitEnd() redraw if a:options =~ "s" call s:ApplyShortStatusColorHighlighting() else call s:ApplyStatusColorHighlighting() endif endfunction " Show on a new window the git status lines matching the selected filter " pattern. " Arg1: path, file or path to check with git status " Arg2: filter keep pattern. " Keep only files in conflict: "^C ". " Keep only modified files: "^M ". " Keep only modified, added or deleted files: "^M \|^A \|^D ". " Arg3: filter remove pattern. " Remove only files not added to the repository: "^? ". " Remove only files with modified permissions: "^X ". " Remove both files not added and permission changes: "^? \|^X ". " Arg4: git commmand options (-uno --branch --show-stash...). " Commands: Gitst, Gitsta, Gitstf, Gitstd. function! gitTools#status#GetStatusFilter(path, filter, remove, options) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let l:gitOptions = "-s --branch --show-stash ".a:options "let command = l:gitCmd." status -s --branch --show-stash ".a:path let command = l:gitCmd." status ".l:gitOptions." ".a:path let callback = ["gitTools#status#GetStatusFilterEnd", a:path, a:filter, a:remove] call gitTools#tools#WindowSplitMenu(1) call gitTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! gitTools#status#GetStatusFilterEnd(path, filter, remove, resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call gitTools#tools#Warn("Git status ". a:path .". No modifications found.") return endif call gitTools#tools#WindowSplit() put = readfile(a:resfile) " Filter window content. if a:filter != "" silent exec "g!/". a:filter ."/d" let l:filter0 = a:filter else let l:filter = "" let l:filter0 = "none" endif " Filter window content. if a:remove != "" silent exec "g/". a:remove ."/d" endif let noResults = 0 if line('$') == 1 && getline(".") == "" let noResults = 1 endif if line('$') == 2 && getline(1) == "" && getline(2) == "" let noResults = 1 endif " Close window if empty if l:noResults == 1 if a:filter == "" && a:remove == "" call gitTools#tools#Warn("Git status ". a:path .". No modifications found.") else call gitTools#tools#Warn("Git status ". a:path .". No modifications found. (Keep: ". a:filter .". Remove: ". a:remove.")" ) endif quit return endif let l:lines0 = line('$') call delete(a:resfile) " Rename window let l:flatpath = gitTools#tools#GetPathAsFilename(a:path) let l:filename = "_gitStatusFiltered_".l:flatpath.".txt" silent exec("0file") silent! exec("file ".l:filename) " Add header on top normal ggO if a:filter == "" && a:remove == "" let text = "[gitTools.vim] git status '".a:path."' (".l:lines0." results)" else let text = "[gitTools.vim] git status '".a:path."' Filter: keep:'".l:filter0."', remove:'".a:remove."' (".l:lines0." results)" endif put=l:text normal ggdd " Resize window to fit content. call gitTools#tools#WindowSplitEnd() redraw call s:ApplyShortStatusColorHighlighting() au BufLeave bdelete g:scratch_buffer call CreateScratchWindow() endfunction " Get a list of files added modified or deleted on the repository. " Arg1: path to be checked with git status. " Return: list with the required files. function! gitTools#status#GetListOfFilesAddedModifiedDeleted(path) return gitTools#status#GetStatusFilesList(a:path, '^[MAD]\|^[A-Z?! ][MAD]') endfunction " Get a list of files added modified, deleted or unmerged on the repository. " Arg1: path to be checked with git status. " Return: list with the required files. function! gitTools#status#GetListOfFilesAddedModifiedDeletedUnmerged(path) return gitTools#status#GetStatusFilesList(a:path, '^[UMAD]\|^[A-Z?! ][UMAD]') endfunction " Get a list of unmerged files on the repository. " Arg1: path to be checked with git status. " Return: list with the required files. function! gitTools#status#GetListOfFilesUnmerged(path) "return gitTools#status#GetStatusFilesList(a:path, "^U\|[A-Z?! ]U\|^AA\|^DD") return gitTools#status#GetStatusFilesList(a:path, 'DD\|AU\|UD\|UA\|DU\|AA\|UU') endfunction " Get files from git status that match the selected filter pattern. " Arg1: path to be checked with git status. " Arg2: pattern to keep from the result: " Keep only files in conflict: "^C ". " Keep only modified files: "^M ". " Keep only modified, added or deleted files: "^M \|^A \|^D ". " Return: list with all files. function! gitTools#status#GetStatusFilesList(path, filter) let l:list = [] let l:gitCmd = g:gitTools_gitCmd let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() let text = system(l:gitCmd." status -s ". a:path) "echom "Git status: ".l:text if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd if a:filter != "" "echom "Filter: ".a:filter silent exec "v/".a:filter."/d" endif silent exec "g/^$/d" if line('$') == 1 && getline(".") != "" " Only one file let @z = "" silent normal 0lwviW"zy let files = @z "echom "File: ".l:files let list = [ l:files ] else " Get last column. File paths. let @z = "" silent normal gg0lwG$"zy let l:files = @z "echom "files:".l:files let l:list = split(l:files, "\n") endif "echom "Git status list: "l:list silent quit! return l:list endfunction " Get files from git status that match the selected filter pattern. " Arg1: filter pattern. " Keep only files in conflict: "^C ". " Keep only modified files: "^M ". " Keep only modified, added or deleted files: "^M \|^A \|^D ". " Return: string with all files. "function! gitTools#status#GetStatusFilesString(path, filter) "let l:list = [] "let l:gitCmd = g:gitTools_gitCmd "let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() "" Short format (-s). Get only modified files (-uno). "" Use porcelain 1, guaranteed not to change in a backwards-incompatible way between Git versions. "let text = system(l:gitCmd." status -suno --porcelain=1 ".a:path) "if l:text == "" "return "" "endif "silent new "normal ggO "silent put=l:text "normal ggdd "if a:filter != "" "silent exec "g!/". a:filter ."/d" "endif "silent exec "g/^$/d" "if line('$') == 1 && getline(".") == "" "" Empty file "let l:res = "" "else ""silent normal gg0WG$"zy ""silent normal gg0f/bG$"zy "silent normal gg0lwG$"zy "let files = @z "let l:res = substitute(l:files, "\n", " ", "g") "if l:res =~ "not a working copy" "call gitTools#tools#Error("Not a git working copy") "return "" "endif "endif "silent exec("bd!") "return l:res "endfunction " " function! s:ApplyShortStatusColorHighlighting() if exists('g:HiLoaded') let g:HiCheckPatternAvailable = 0 silent! call hi#config#PatternColorize("#.*]", "w") silent! call hi#config#PatternColorize("ahead.*,", "g") silent! call hi#config#PatternColorize("behind.*]", "r") "silent! call hi#config#PatternColorize(" C ", "m*") " Conflicted "silent! call hi#config#PatternColorize("?.*left", "m2*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*right", "m3*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*working", "m1*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*mine", "m1*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*original","m1*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*second", "m3*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("?.*first", "m2*") " Conflicted. Merge file. "silent! call hi#config#PatternColorize("! ", "r4@") " Ignored "silent! call hi#config#PatternColorize("\\~ ", "v2@") " Obstructed by some item of different kind " " Added to staging area silent! call hi#config#PatternColorize("A[MICRT? ] ","g") silent! call hi#config#PatternColorize("[MICRT? ]A ","g") silent! call hi#config#PatternColorize("AA ", "m1*") " Unmerged silent! call hi#config#PatternColorize(" A ", "g*") silent! call hi#config#PatternColorize("A ", "g*") " Copied silent! call hi#config#PatternColorize("C[A-Z? ] ", "y3") silent! call hi#config#PatternColorize("[A-Z? ]C ", "y3") silent! call hi#config#PatternColorize("CC ", "y3*") silent! call hi#config#PatternColorize(" C ", "y3*") silent! call hi#config#PatternColorize("C ", "y3*") " Deleted silent! call hi#config#PatternColorize("D[A-Z? ] ", "o") silent! call hi#config#PatternColorize("[A-Z? ]D ", "o") silent! call hi#config#PatternColorize("DD ", "m1*") " Unmerged silent! call hi#config#PatternColorize(" D ", "o*") silent! call hi#config#PatternColorize("D ", "o*") " Ignored silent! call hi#config#PatternColorize("I[A-Z?] ", "y") silent! call hi#config#PatternColorize("[A-Z?]I ", "y") silent! call hi#config#PatternColorize("II ", "y*") silent! call hi#config#PatternColorize(" I ", "y*") silent! call hi#config#PatternColorize("I ", "y*") " Modified silent! call hi#config#PatternColorize("M[A-Z?] ", "b") silent! call hi#config#PatternColorize("[A-Z?]M ", "b") silent! call hi#config#PatternColorize("MM ", "b*") silent! call hi#config#PatternColorize(" M ", "b*") silent! call hi#config#PatternColorize("M ", "b*") " Renamed silent! call hi#config#PatternColorize("R[A-Z?] ", "y") silent! call hi#config#PatternColorize("[A-Z?]R ", "y") silent! call hi#config#PatternColorize("RR ", "y*") silent! call hi#config#PatternColorize(" R ", "y*") silent! call hi#config#PatternColorize("R ", "y*") " File type changed silent! call hi#config#PatternColorize("T[A-Z?] ", "y2") silent! call hi#config#PatternColorize("[A-Z?]T ", "y2") silent! call hi#config#PatternColorize("TT ", "y2*") silent! call hi#config#PatternColorize("T ", "y2*") silent! call hi#config#PatternColorize(" T ", "y2*") " Updated but unmerged silent! call hi#config#PatternColorize("U[A-Z?] ", "m1*") silent! call hi#config#PatternColorize("[A-Z?]U ", "m1*") silent! call hi#config#PatternColorize("UU ", "m1*") silent! call hi#config#PatternColorize("U ", "m1*") silent! call hi#config#PatternColorize(" U ", "m1*") " Unversioned directory silent! call hi#config#PatternColorize("X[A-Z?] ", "w7") silent! call hi#config#PatternColorize("[A-Z?]X ", "w7") silent! call hi#config#PatternColorize("XX ", "w7*") silent! call hi#config#PatternColorize("X ", "w7*") silent! call hi#config#PatternColorize(" X ", "w7*") " Unversioned file silent! call hi#config#PatternColorize("?[A-Z? ] ", "w8") silent! call hi#config#PatternColorize("[A-Z? ]? ", "w8") silent! call hi#config#PatternColorize("?? ", "w8*") silent! call hi#config#PatternColorize("? ", "w8*") silent! call hi#config#PatternColorize(" ? ", "w8*") " Ignored file silent! call hi#config#PatternColorize("![A-Z? ] ", "w6") silent! call hi#config#PatternColorize("[A-Z? ]! ", "w6") silent! call hi#config#PatternColorize("!! ", "w6*") silent! call hi#config#PatternColorize("! ", "w6*") silent! call hi#config#PatternColorize(" ! ", "w6*") let g:HiCheckPatternAvailable = 1 endif endfunction function! s:ApplyStatusColorHighlighting() if exists('g:HiLoaded') let g:HiCheckPatternAvailable = 0 silent! call hi#config#PatternColorize("#.*]", "w") silent! call hi#config#PatternColorize("ahead.*,", "g") silent! call hi#config#PatternColorize("behind.*]", "r") " silent! call hi#config#PatternColorize("modified: ", "b*") silent! call hi#config#PatternColorize("new file:" , "g*") silent! call hi#config#PatternColorize("unmerged " , "m1*") silent! call hi#config#PatternColorize("deleted:" , "r1*") silent! call hi#config#PatternColorize("renamed:" , "y*") silent! call hi#config#PatternColorize("typechange:", "y1*") let g:HiCheckPatternAvailable = 1 endif endfunction autoload/gitTools/tools.vim [[[1 355 " Script Name: gitTools.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, git " " NOTES: " "- functions ------------------------------------------------------------------- " Check if the repository is available " Return: 1 if available otherwhise return 0. function! gitTools#tools#isGitAvailable() let l:gitCmd = g:gitTools_gitCmd let l:desc = system(l:gitCmd." describe --always --tags --dirty") let l:desc = substitute(l:desc,' ','','g') let l:desc = substitute(l:desc,'\n','','g') if l:desc == "" || l:desc =~ "fatal: " return l:desc else return 1 endif endfunction function! gitTools#tools#CheckGitUserAndPsswd() if g:gitTools_userAndPsswd != 1 return "" endif " Get git user: if g:gitTools_gitUser == "" let g:gitTools_gitUser = input("Git user: ") endif if g:gitTools_gitUser == "" call gitTools#tools#Error("Not valid git user.") return "" endif " Get git password: let l:tmp = "" if exists("g:gitTools_tmp") if g:gitTools_tmp != "" let l:tmp = g:gitTools_tmp endif endif " Set git password: if l:tmp == "" let l:tmp = inputsecret("Git user: ".g:gitTools_gitUser.". Enter password: ") if g:gitTools_storeGitPsswd == 1 echo "" echo "" echo "[gitTools.vim] Git password set for current session." let g:gitTools_tmp = l:tmp endif endif if l:tmp == "" call gitTools#tools#Error("Not valid git password.") return "" endif return " --non-interactive --no-auth-cache --username ".g:gitTools_gitUser." --password ".l:tmp endfunction " Set upser and password " Command: Gitpwd function! gitTools#tools#SetUserAndPsswd() if g:gitTools_gitUser != "" if confirm("Change git user: ".g:gitTools_gitUser."?", "&yes\n&no", 2) == 1 let g:gitTools_gitUser = "" endif echo "" echo "" endif silent! unlet g:gitTools_tmp call gitTools#tools#CheckGitUserAndPsswd() endfunction function! gitTools#tools#Error(mssg) echohl ErrorMsg | echom "[GitTools] ".a:mssg | echohl None endfunction function! gitTools#tools#Warn(mssg) echohl WarningMsg | echom a:mssg | echohl None endfunction function! gitTools#tools#LowWarn(mssg) echohl WarningMsg | echon "WARNING: " | echohl None "echon a:mssg echo printf("%s\n", a:mssg) endfunction function! gitTools#tools#SetLogLevel(level) let s:LogLevel = a:level endfunction " Debug function. Log message function! gitTools#tools#LogLevel(level,func,mssg) if s:LogLevel >= a:level echom "[GitTools : ".a:func."] ".a:mssg endif endfunction " Debug function. Log message and wait user key function! gitTools#tools#LogLevelStop(level,func,mssg) if s:LogLevel >= a:level call input("[GitTools : ".a:func."] ".a:mssg." (press key)") endif endfunction func! gitTools#tools#Verbose(level) if a:level == "" call s:LogLevel(0, expand(''), "Verbose level: ".s:LogLevel) return endif let s:LogLevel = a:level call gitTools#tools#LogLevel(0, expand(''), "Set verbose level: ".s:LogLevel) endfun function! gitTools#tools#SetSyntax(ext) if a:ext == "h" let l:ext = "cpp" elseif a:ext == "hpp" let l:ext = "cpp" else let l:ext = a:ext endif "silent exec("set syntax=".l:ext) silent exec("set ft=".l:ext) endfunction function! gitTools#tools#GetSyntax() let l:ext = expand("%:e") if l:ext == "h" return "cpp" elseif l:ext == "hpp" return "cpp" else return l:ext endif endfunction function! gitTools#tools#WindowSplitMenu(default) let w:winSize = winheight(0) "echo "w:winSize:".w:winSize | call input("continue") let text = "split hor&izontal\n&split vertical\nnew &tab\ncurrent &window" let w:split = confirm("", l:text, a:default) redraw call gitTools#tools#LogLevel(1, expand(''), "Choosed split:".w:split) endfunction function! gitTools#tools#WindowSplit() if !exists('w:split') return endif let l:split = w:split let l:winSize = w:winSize call gitTools#tools#LogLevel(1, expand(''), "New split:".w:split) if w:split == 1 silent exec("sp! | enew") elseif w:split == 2 silent exec("vnew") elseif w:split == 3 silent exec("tabnew") elseif w:split == 4 silent exec("enew") endif let w:split = l:split let w:winSize = l:winSize endfunction function! gitTools#tools#WindowSplitEnd() if exists('w:split') if w:split == 1 if exists('w:winSize') "echo "w:winSize:".w:winSize | call input("continue") let lines = line('$') + 2 if l:lines <= w:winSize "echo "resize:".l:lines | call input("continue") exe "resize ".l:lines else "echo "resize:".w:winSize | call input("continue") exe "resize ".w:winSize endif endif exe "normal! gg" endif endif silent! unlet w:winSize silent! unlet w:split endfunction "function! gitTools#tools#PathToFile(path) "return gitTools#tools#GetPathAsFilename(a:path) "endfunction " Turn a path to a filename showing the path and file. " Return: for input /dir1/dir2/dir3/filename.ext return dir1_dir2_dir3_filename.ext function! gitTools#tools#GetPathAsFilename(path) if a:path == "" return "" endif let path = a:path let path = substitute(path, getcwd(), '', 'g') let path = substitute(path, '/', '_', 'g') let path = substitute(path, '-$', '', '') let path = substitute(path, '_-', '', '') let path = substitute(path, '-_', '', '') return l:path endfunction "function! gitTools#tools#SystemCmd0(command,callback,async) "if !exists("g:loaded_jobs") "call gitTools#tools#Error("Plugin jobs.vim not loaded.") "return "endif "let jobName = "gitTools" "if g:gitTools_runInBackground == 0 || a:async == 0 "let l:async = 0 "else "let l:async = 1 "endif "if g:gitTools_userAndPsswd != 1 "let cmd = "let @a = \"".a:command."\" \| normal G! \| exec(\"put a\")" "call histadd(':', l:cmd) "endif "call jobs#RunCmd(a:command,a:callback,l:async,l:jobName) "endfunction function! gitTools#tools#SystemCmd0(command,callbackList,async) if !exists("g:loaded_jobs") call gitTools#tools#Error("Plugin jobs.vim not loaded.") return endif let jobName = "gitTools" if g:gitTools_runInBackground == 0 || a:async == 0 let l:async = 0 else let l:async = 1 endif " Do not add command with user password from history if g:gitTools_userAndPsswd != 1 let cmd = "let @a = \"".a:command."\" \| normal G! \| exec(\"put a\")" call histadd(':', l:cmd) endif call jobs#RunCmd0(a:command,a:callbackList,l:async,l:jobName) endfunction " Remove leading and trailing spaces. " Remove end of line characters. " Return: string without leading trailing white spaces. func! gitTools#tools#TrimString(string) let l:tmp = a:string let l:tmp = substitute(l:tmp,'^\s\+','','g') let l:tmp = substitute(l:tmp,'\s\+$','','g') let l:tmp = substitute(l:tmp,' ','','g') let l:tmp = substitute(l:tmp,'\n','','g') return l:tmp endfunc " Enclose the given lines on list on a rectangle. " Arg1: linesList, list with every line to be enclosed inside the rectangle. " Arg2: rectangleType, bold, hashtag, equals, normal. " Bold: ┏━━━━━━━┓ " ┃ ┃ " ┗━━━━━━━┛ " Hashtag: ######### " # # " ######### " Equals: ========= " || || " ========= " Normal: ┌───────┐ " │ │ " └───────┘ " Arg3: [OPTIONAL] len, force minimum rectangle length to this value. " Return: string with the text enclosed on rectangle. function! gitTools#tools#EncloseOnRectangle(linesList,rectangleType,len) if a:rectangleType == "bold" let l:cornerTL='┏' | let l:cornerTR='┓' | let l:vertical='┃' | let l:horizontal='━' | let l:cornerBL='┗' | let l:cornerBR='┛' elseif a:rectangleType == "hashtag" let l:cornerTL='#' | let l:cornerTR='#' | let l:vertical='#' | let l:horizontal='#' | let l:cornerBL='#' | let l:cornerBR='#' elseif a:rectangleType == "equals" let l:cornerTL='=' | let l:cornerTR='=' | let l:vertical='||' | let l:horizontal='=' | let l:cornerBL='=' | let l:cornerBR='=' else let l:cornerTL="┌" | let l:cornerTR="┐" | let l:vertical="│" | let l:horizontal='─' | let l:cornerBL='└' | let l:cornerBR='┘' endif if a:len != "" let maxlen = a:len else let maxlen = 0 for line in a:linesList let len = strlen(l:line) if l:len > l:maxlen | let l:maxlen = l:len | endif endfor endif let config = l:cornerTL let config .= repeat(l:horizontal,l:maxlen) let config .= l:cornerTR."\n" for line in a:linesList let config .= l:vertical.l:line let len = l:maxlen - strlen(l:line) let config .= repeat(' ', l:len) let config .= l:vertical."\n" endfor let config .= l:cornerBL let config .= repeat(l:horizontal,l:maxlen) let config .= l:cornerBR."\n" return l:config endfunction "- initializations ------------------------------------------------------------ let s:LogLevel = 0 autoload/gitTools/utils.vim [[[1 196 " Script Name: gitTools/utils.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " " "- functions ------------------------------------------------------------------- " Compare with vimdiff file on current buffer with same one on a different " working directory. " Handy to open and compare quickly, same files on different sandboxes. " Arg1: CMD, new/vnew. " Arg2: [PATH1], pattern to be replaced on current files's path. " Arg3: path2, string to replace the found pattern. "Cmd: Vdf and Vdfv func! gitTools#utils#DiffSameFileOnPath(...) if a:0 == 2 let l:filepath1 = expand("%:p") let l:file0 = substitute(l:filepath1, getcwd(), "", "") let l:path2 = a:2 let l:filepath2 = l:path2."/".l:file0 elseif a:0 == 3 let l:filepath1 = a:1 let l:filepath2 = substitute(expand("%:p"), a:2, a:3, "g") echo l:filepath2 else echohl ErrorMsg | echo "Arguments: [PATH1] PATH2" | echohl None return endif if l:filepath1 == l:filepath2 echohl ErrorMsg | echo "Same path not allowed: ".l:filepath1." ".l:filepath2 | echohl None return endif if !filereadable(l:filepath2) echohl ErrorMsg | echo "File not found ".l:filepath2 | echohl None return endif redraw echo "[GitTools.vim] Vimdiff: ".l:filepath1." and ".l:filepath2 silent exec(l:filepath1) silent exec("edit ".l:filepath2) windo diffthis endfunc " Compare all files between two directories: " Arg: [PATH1]. primary file/path. " Arg: PATH2. secondary sandbox path to compare files. " Arg: [FLAGS]: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern: keep files matching pattern. " -SkipPattern: skip files matching pattern. " Cmd: Vdd1. func! gitTools#utils#VimdiffAll(...) if a:0 < 1 call gitTools#tools#Error("Arguments error. Missing paths. Arguments: [PATH1] PATH2 [FLAGS]") return endif let l:mode = "diff" let l:path1 = "" let l:path2 = "" let l:equals = "skip" let l:binaries = "skip" let l:keepStr = "" let l:filterStr = "" for l:arg in a:000 if l:arg ==? "ALL" || l:arg ==? "BO" || l:arg ==? "SB" || l:arg ==? "EO" || l:arg ==? "SE" || l:arg[0] == '+' || l:arg[0] == '-' elseif l:arg[0] == '-' let l:filterStr .= l:arg[1:]." " elseif !empty(glob(l:arg)) if l:path1 == "" let l:path1 = l:arg let l:path1 = substitute(l:path1,'^\s\+','','g') let l:path1 = substitute(l:path1,'\s\+$','','g') else if l:path2 == "" let l:path2 = l:arg let l:path2 = substitute(l:path2,'^\s\+','','g') let l:path2 = substitute(l:path2,'\s\+$','','g') else call gitTools#tools#Warn("Path1 and Path2 already set. Skipping path: ".l:arg) call confirm("Continue?") endif endif else call gitTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if l:path2 == "" let l:dirs = substitute(expand("%:h"), getcwd(), "", "") let l:path2 = l:path1."/".l:dirs let l:path1 = expand("%:h") endif if empty(glob(l:path2)) call gitTools#tools#Error("Path2 not found ".l:path2) return endif if empty(glob(l:path1)) call gitTools#tools#Error("Path1 not found ".l:path1) return endif if l:path1 == l:path2 call gitTools#tools#Error("Paths must be different ".l:path1." ".l:path2) return endif "---------------------------------------- " Get all files on the directory (recursive): "---------------------------------------- "echom "Path1:".l:path1 let l:filesStr = globpath(l:path1, "**") let l:filesList = split(l:filesStr, "\n") "echom "FilesStr:".l:filesStr "echom "FilesList:"l:filesList "---------------------------------------- " Filter Files: " Filter acording to flags on arguments list, keep/skip binaries/equal-files/match-patterns. " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). "---------------------------------------- redraw echo "[gitTools.vim] Diff files between: ".l:path1." and ".l:path2 let l:filesList = gitTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path1, l:path2) if len(l:filesList) == 0 echo "" call gitTools#tools#Warn("No modifications found") call input("") return endif echo "Files to open: ".len(l:filesList) call confirm("Perform ".l:mode." on this ".len(l:filesList)." files?") "---------------------------------------- " Open vimdiff for all files: "---------------------------------------- let l:n = 1 for l:file1 in l:filesList let l:file2 = substitute(l:file1, l:path1, l:path2, "") echo " - Opening vimdiff ".l:n.": ".l:file1." and ".l:file2 silent exec("tabedit ".l:file1) " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") silent diffthis silent vnew silent exec("edit ".l:file2) " Visually show tabs and spaces silent exec("set invlist") silent exec("set listchars=tab:>.,trail:_,extends:\#,nbsp:_") silent diffthis let l:n += 1 endfor redraw echo " " echo " " echo "[gitTools.vim] Compare files on: ".l:path1." and ".l:path2." Differing files:".l:n endfunc autoload/gitTools/vimdiff.vim [[[1 594 " Script Name: gitTools/vimdiff.vim "Description: " " Copyright: (C) 2022-2023 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, git, diff " " "- functions ------------------------------------------------------------------- " Vimdiff single file. " Arg1: file to check, if empty use current file. " Commands: Gitvdf function! gitTools#vimdiff#File(file) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif let l:list = gitTools#status#GetListOfFilesAddedModifiedDeletedUnmerged(a:file) "echom "Git status list: "l:list if len(l:list) == 0 redraw call gitTools#tools#Warn("[gitTools.vim] No modifications found.") endif let name = fnamemodify(a:file,":t:r") if join(l:list) =~ l:name redraw call gitTools#tools#Warn("[gitTools.vim] No modifications found on file ".a:file) endif let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile echo "This may take a while ..." if expand("%") != a:file " Open new tab to open both vimdiff files. call gitTools#diffTools#VimDiffFileBranch(a:file, l:branch) else " Use current buffer as left split for vertical vimddiff. call gitTools#diffTools#VimDiffThisFileBranch(a:file, l:branch) endif redraw endfunction " Simple Vimdiff on path " Arg1: file to check, if empty use current file. " Commands: Gitvd, Gitvda, Gitvdd, GitvdA. function! gitTools#vimdiff#Path(path) let l:res = gitTools#tools#isGitAvailable() if l:res != 1 call gitTools#tools#Error("ERROR: ".l:res) return endif echo "Getting modified files on ".a:path."..." let l:list = gitTools#status#GetListOfFilesAddedModifiedDeletedUnmerged(a:path) let l:n = len(l:list) if l:n == 0 redraw call gitTools#tools#Warn("[gitTools.vim] No modifications found") return endif let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile redraw if l:n == 1 " Only ONE file modified " Open vimdiff without asking user echo "This may take a while ..." call gitTools#diffTools#VimDiffFileBranch(l:list[0],l:branch) redraw return else " Show the final list with the files to open with vimdiff. redraw echo "Modified Files:" for file in l:list echo "- ".l:file endfor echo "" echo " " echo "This may take a while ..." echo "" " Perform git diff on each selected file. " Open each file with vimdiff on new tab let l:n = 0 for l:file in l:list echo "- ".l:file call gitTools#diffTools#VimDiffFileBranch(l:file,l:branch) let l:n += 1 endfor redraw echo " " echo "[gitTools.vim] Show git changes on ".a:path." using vimdiff. ".l:n." files." endif endfunction " Vimdiff path with advanced options " Arg: PATH. Path to check for changed files. " Arg: [FLAGS]: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern: keep files matching pattern. " -SkipPattern: skip files matching pattern. " Commands: GitVD, GitVDA, GitVDD. function! gitTools#vimdiff#PathAdv(...) if gitTools#tools#isGitAvailable() == 0 call gitTools#tools#Error("No git repository found on path ".getcwd()) return endif if a:0 == 0 || join(a:000) =~# "help" echo "Get vimdiff changes on the selected path." echo "Arguments: PATH [FLAGS]" echo "- FLAGS: " echo " B (show binaries)." echo " +keepFilePattern" echo " -skipFilePattern" if join(a:000) !~# "help" call gitTools#tools#Error("Missing arguments: PATH") endif return endif let l:path = "" let l:equals = "skip" for l:arg in a:000 if l:arg ==? "BO" || l:arg ==? "SB" || l:arg[0] == '+' || l:arg[0] == '-' " Arguments meant for: gitTools#misc#FilterFilesListWithArgsList elseif l:arg ==? "ALL" let l:equals = "" elseif l:arg ==? "EO" let l:equals = "only" elseif l:arg ==? "SE" let l:equals = "skip" elseif !empty(glob(l:arg)) let l:path .= l:arg." " let l:path = substitute(l:path,'^\s\+','','g') let l:path = substitute(l:path,'\s\+$','','g') else call gitTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if empty(glob(l:path) ) call gitTools#tools#Error("Path not found ".l:path) return endif "---------------------------------------- " Get files modified on subversion: "---------------------------------------- echo "Getting modified files on ".l:path."..." let l:filesList = gitTools#status#GetListOfFilesAddedModifiedDeletedUnmerged(l:path) if len(l:filesList) == 0 redraw call gitTools#tools#Warn("[gitTools.vim] No modifications found") return [] endif echo "Modified Files:" for l:file in l:filesList echo "- ".l:file endfor echo " " if len(l:filesList) == 0 call gitTools#tools#Warn("No files found.") return endif echo "Found ".len(l:filesList)." modified files" call confirm("continue?") "---------------------------------------- " Filter files: " Filter acording to flags on arguments list, keep/skip binaries/equal-files/match-patterns. " Flags: " ALL:show all files modified. " BO: show binaries only. " SB: skip binaries (default). " EO: show equal files only. " SE: skip equal files (default). " +KeepPattern: keep files matching pattern. " -SkipPattern: skip files matching pattern. "---------------------------------------- "redraw echo "[gitTools.vim] Filter files on: '".l:path let l:filesList = gitTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path, "") echo "Files to open compare with head revision: ".len(l:filesList) call confirm("Perform vimdiff on this ".len(l:filesList)." files?") "---------------------------------------- " Get the subversion file and perform vimdiff with current one. "---------------------------------------- let l:branch = "" while l:branch == "" echo " " let l:branch = gitTools#info#ChooseBranchMenu() endwhile echo " " echo "Getting every file vimdiff..." let l:n = 0 for l:file in l:filesList echo "- ".l:file." vimdiff" call gitTools#diffTools#VimDiffFileBranch(l:file,l:branch) let l:n += 1 endfor "redraw echo " " echom "[gitTools.vim] Show git changes on ".l:path." using vimdiff. ".l:n." files found." endfunction " Vimdiff current file with the selected revision " Arg1: revision number " Arg2: file to check, if empty use current file. "function! s:VimdiffRev(branch,rev,file) "let l:confirm = "" "if a:file == "" "let l:file = expand('%') "else "let l:file = a:file "endif "if l:file == "" "call gitTools#tools#Warn("File path not found") "return "endif "if a:rev == "" "let l:rev = expand('') "let l:confirm = "yes" "else "let l:rev = a:rev "endif "if l:rev == "" "call gitTools#tools#Warn("Revision number not found") "return "endif "if l:confirm != "" "if confirm("Check file: ".l:file,"Rev: ".l:rev."? &yes\n&no\n",2) == 2 "return "endif "endif "echo "This may take a while ..." "call gitTools#tools#WindowSplitMenu(3) "call gitTools#tools#WindowSplit() "call gitTools#diffTools#VimDiffFileRev(l:file,l:branch,l:rev,"","") "call gitTools#tools#WindowSplitEnd() "endfunction " Vimdiff current file with the selected revision " Arg1: revision number " Arg2: file to check, if empty use current file. "function! s:VimdiffRev(branch,rev,file) "let l:confirm = "" "if a:file == "" "let l:file = expand('%') "else "let l:file = a:file "endif "if l:file == "" "call gitTools#tools#Warn("File path not found") "return "endif "if a:rev == "" "let l:rev = expand('') "let l:confirm = "yes" "else "let l:rev = a:rev "endif "if l:rev == "" "call gitTools#tools#Warn("Revision number not found") "return "endif "if l:confirm != "" "if confirm("Check file: ".l:file,"Rev: ".l:rev."? &yes\n&no\n",2) == 2 "return "endif "endif "echo "This may take a while ..." "call gitTools#tools#WindowSplitMenu(3) "call gitTools#tools#WindowSplit() "call gitTools#diffTools#VimDiffFileRev(l:file,a:branch,l:rev,"","") "call gitTools#tools#WindowSplitEnd() "endfunction " On a unified diff file. Extract file path and revision number " Parse the file and perform diff between the paths found starting with " string: --- or string: +++. " Diff line format expected: " Ex: " --- path/file.cpp (revision 188593) " +++ path/file.cpp (revision 188594) "let s:DiffFile = "" "let s:DiffRev = "" "function! s:DiffGetFileRev() "let s:DiffFile = "" "let s:DiffRev = "" "normal 0yiW "let l:tmp = @" "if l:tmp != "---" && l:tmp != "+++" "call gitTools#tools#Warn("Diff line format '".l:tmp."' unknown") "return 1 "endif "if l:tmp =~ "revision" | return 1 | endif "normal wyiW "if @" == "" | return 1 | endif "let s:DiffFile = @" "normal Wwwyiw "if @" == "" || @" == ")" || @" == "copy" | return 1 | endif "let s:DiffRev = @" "return 0 "endfunction "" On a unified diff file and current line with format Ex: "" --- path/file.cpp (revision 188593) "" or "" +++ path/file.cpp (revision 188594) "" "" Open vimdiff with file path and revision number "function! s:VimdiffRevDiffFile() "let l:rev0 = "" "let l:rev1 = "" "if s:DiffGetFileRev() == 1 "call gitTools#tools#Warn("Revision number not found") "return 1 "endif "let match = matchstr(getline('.'), '.*--- ') " regex match "if(!empty(match)) "let l:rev0 = s:DiffRev "normal j "else "let l:rev1 = s:DiffRev "normal k "endif "if s:DiffGetFileRev() == 1 "call gitTools#tools#Warn("Revision number not found") "return 1 "endif "let match = matchstr(getline('.'), '.*+++ ') " regex match "if(!empty(match)) "let l:rev1 = s:DiffRev "else "let l:rev0 = s:DiffRev "endif "if confirm("Vimdiff file: ".s:DiffFile,"Rev: ".l:rev0.":".l:rev1."? &yes\n&no\n",2) == 2 "return "endif "call gitTools#diffTools#VimDiffFileRev(s:DiffFile,l:branch,l:rev0,l:rev1,"") "return 0 "endfunction "" On a unified diff file. Search all lines starting on --- and get the "" filename and revision number, then perform vimdiff. "" Ex: line format: "" --- path/file.cpp (revision 188593) "function! s:VimdiffRevDiffAll() "echo "Perform vimdiff on each modified file:" "let l:list = [ ] "if l:dir = "" "let file = readfile(expand("%:p")) " read current file "let cmd = "" | let File = "" | let rev = "" "for line in file "let match = matchstr(line, '.*--- ') " regex match "if(!empty(match)) "if l:cmd != "" "echo " - Diff: ".l:cmd "call insert(l:list, l:cmd) "let File = "" "let rev = "" "endif "new "setlocal bt=nofile "let @a = l:line "put! a "normal gg0 "if s:DiffGetFileRev() == 0 "let cmd = s:DiffFile." ".s:DiffRev "let File = s:DiffFile "let rev = s:DiffRev "endif "silent! execute 'bd!' "endif "let match = matchstr(line, '.*+++ ') " regex match "if(!empty(match)) "new "setlocal bt=nofile "let @a = l:line "put! a "normal gg0 "if s:DiffGetFileRev() == 0 "if l:rev != "" && l:File == s:DiffFile "let cmd .= " ".s:DiffRev "let dir = s:DiffRev "endif "endif "silent! execute 'bd!' "endif "endfor "if l:cmd != "" "echo " - Diff: ".l:cmd "call insert(l:list, l:cmd) "endif "if len(l:list) <= 0 "call gitTools#tools#Warn("[gitTools.vim] No modifications found") "return "endif "let l:saveDir = "" "if l:dir != "" "if confirm("","Save/get dir: _r".l:dir."? &yes\n&no\n",2) == 1 "" Create new directory named after with revision number "let l:saveDir = "_r".l:dir "if !isdirectory(l:saveDir) "call mkdir(l:saveDir) "endif "endif "endif "let l:open = 1 "for cmd in l:list "let args = split(l:cmd, " ") "let file = get(l:args, 0, "") "let rev0 = get(l:args, 1, "") "let rev1 = get(l:args, 2, "") "if l:open != 3 "echo "" "let l:open = confirm("Vimdiff: ".l:file,"Rev: ".l:rev0."/".l:rev1."? &yes\n&no\nopen &all\n",1) "if l:open == 2 | continue | endif "endif ""call gitTools#diffTools#VimDiffFileRev(l:file,l:rev0,l:rev1,l:saveDir) "let l:branch = gitTools#info#ChooseBranchMenu() "if l:branch == "" | return | endif "call gitTools#diffTools#VimDiffFileBranch(l:file,l:branch) "endfor "if l:saveDir != "" "" Save current vim session "exec("mksession! ".l:saveDir."/vdiff.vim") "endif "endfunction " Perform vimdiff on all modified files on revision2 with the same files on revision1 " When no revision number provided as argument, try get word under cursor as the " revision number. " When REV2 not provided set REV2=REV1, and dreacrese REV1. " Arg1: [optional] revision1 " Arg2: [optional] revision2 " Cmd: Gitvdr "function! gitTools#vimdiff#RevisionsCompare(...) "let rev1 = "" "let rev2 = "" "if a:0 >= 2 "let rev1 = a:1 "let rev2 = a:2 "elseif a:0 == 1 "let rev2 = a:1 "else "let rev2 = expand("") "endif "if l:rev2 == "" "call gitTools#tools#Error("Missing revision number") "return "endif "let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') "if l:rev2 == "" "call gitTools#tools#Error("Wrong revision number ". l:rev2) "return "endif "if l:rev1 == "" "let l:rev1 = l:rev2 -1 "else "let rev1 = substitute(l:rev1, '[^0-9]*', '', 'g') "if l:rev1 == "" "call gitTools#tools#Error("Wrong revision number ". l:rev1) "return "endif "endif "" Get diff file "echo "Getting r". l:rev2 ." log and diff..." "let l:gitCmd = g:gitTools_gitCmd "let l:gitCmd .= gitTools#tools#CheckGitUserAndPsswd() "" On Subversion versions after 1.7: "let command = l:gitCmd." log -vr ".l:rev2." --diff" ""let command = "git log -vr ".l:rev2." --diff" "let text = system(l:command) "" Extract from diff file, the list of modified files. "tabnew "put=l:text "normal ggdd "let l:list = gitTools#diffFile#GetModifiedFilesList() ""quit "silent! exec("0file") "silent! exec("file! _r". l:rev2 .".diff") "set ft=diff "normal gg "redraw "for file in l:list "echo l:file "endfor "call confirm(len(l:list) ." modified files found. Continue?") ""let l:branch = gitTools#info#ChooseBranchMenu() ""if l:branch == "" | return | endif "" Perform vimdiff for each file and revision. "redraw "echo "Opening ". l:rev1 .":". l:rev2 ." modifications with vimdiff:" "for file in l:list "echo "- ". l:file "silent call gitTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) ""call gitTools#diffTools#VimDiffFileBranch(l:file,l:branch) "endfor "endfunction plugin/jobs.vim [[[1 139 " Script Name: jobs.vim " Description: run system commands in background. " Tool to be used on other plugins to launch system commands in background. " Includes several commands to check the commands in progress (Jobsl). " Stop all commands in background (Jobska) " Choose wich commands in background to stop (Jobsk) " Showw all commands in background related to current vim window (Jobshw) " Showw all commands history (Jobshy) " " Example: " function! svnTools#Blame() " let file = expand("%") " let name = expand("%:t") " let pos = line('.') " let ext = s:GetSyntax() " " let command = "svn blame -v ".l:file " let callback = ["svnTools#SvnBlameEnd", l:pos, l:ext, l:name] " let l:async = 1 " " call jobs#RunCmd(a:command, a:callback, l:async, "svn") " endfunction " " function! svnTools#SvnBlameEnd(pos,ext,name,resfile) " if exists('a:resfile') && !empty(glob(a:resfile)) " " Process the svn blame file " else " echo "ERROR. Svn blame empty" " endif " endfunction " " Copyright: (C) 2017-2020 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jpLib.vim (optional) " " NOTES: " " Version: 0.1.1 " Changes: " 0.1.1 Fry, 28 May 21. JPuigdevall " - New: hide passwords, prevent showing command passwords on the command " line, instead replace the password with * characters. Use option: g:jobs_hidePsswd " to dissable it. " 0.1.0 Wed, 15 Jul 20. JPuigdevall " - Change the callback variable to a list conatining the function name and " arguments. " 0.0.1 Fry, 22 Jun 20. JPuigdevall if exists('g:loaded_jobs') finish endif let g:loaded_jobs = 1 let s:save_cpo = &cpo set cpo&vim let g:jobs_version = "0.1.1" "- configuration -------------------------------------------------------------- let g:jobs_version = get(g:, 'jobs_version', "0.1.0") let g:jobs_run_in_background = get(g:, 'jobs_run_in_background', 1) let g:jobs_return_to_base_window = get(g:, 'jobs_return_to_base_window', 1) " Do not show the password on the commands, replace with ******* let g:jobs_hidePsswd = get(g:, 'jobs_hidePsswd', 1) if (v:version < 800 || !has("job")) " +job option needed for job_start, job_stop, job_status functions. " Dissable running job in background let g:jobs_run_in_background = 0 endif let g:jobs_mode = get(g:, 'jobs_mode', 3) "- commands ------------------------------------------------------------------- command! -nargs=0 JobsKill call jobs#Stop() command! -nargs=0 Jobsk call jobs#Stop() command! -nargs=0 JobsList call jobs#Status() command! -nargs=0 Jobsl call jobs#Status() command! -nargs=0 JobsHist call jobs#History() command! -nargs=0 Jobshy call jobs#History() command! -nargs=0 JobsListWin call jobs#StatusCurrentWindow() command! -nargs=0 Jobsw call jobs#StatusCurrentWindow() command! -nargs=0 JobsKillAll call jobs#StopAll() command! -nargs=0 Jobska call jobs#StopAll() command! -nargs=0 Jobsh call jobs#Help() command! -nargs=? Jobsv call jobs#Verbose("") command! -nargs=* Jobs call jobs#Menu() " Release functions: command! -nargs=0 Jobsvba call jobs#NewVimballRelease() " Edit plugin: command! -nargs=0 Jobsedit call jobs#Edit() "- mappings ------------------------------------------------------------------- " if !hasmapto('Jobsl', 'n') nmap jl :Jobsl endif "- abbreviations ------------------------------------------------------------------- " DEBUG functions: reload plugin cnoreabbrev _jobsrl =jobs#Reload() "- menus ------------------------------------------------------------------- if has("gui_running") call jobs#CreateMenus('cn' , '' , ':Jobsl ' , 'Show all running jobs' , ':Jobsl') call jobs#CreateMenus('cn' , '' , ':Jobsw ' , 'Show all jobs running for current window' , ':Jobsw') call jobs#CreateMenus('cn' , '' , ':Jobshy' , 'Show all jobs history' , ':Jobshy') call jobs#CreateMenus('cn' , '' , ':' , '-Sep-' , '') call jobs#CreateMenus('cn' , '' , ':Jobsk ' , 'Show the running jobs. Choose job to kill' , ':Jobsk') call jobs#CreateMenus('cn' , '' , ':Jobska' , 'Kill all running jobs' , ':Jobska') call jobs#CreateMenus('cn' , '' , ':' , '-Sep2-' , '') call jobs#CreateMenus('cn' , '' , ':Jobsv ' , 'Change verbosity level' , ':Jobsv') endif let &cpo = s:save_cpo unlet s:save_cpo autoload/jobs.vim [[[1 728 " Script Name: jobs.vim "Description: run system commands in background. " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jpLib.vim (optional) " " NOTES: " " Get the plugin reload command function! jobs#Reload() let l:pluginPath = substitute(s:plugin_path, "autoload", "plugin", "") let l:autoloadFile = s:plugin_path."/".s:plugin_name let l:pluginFile = l:pluginPath."/".s:plugin_name return "silent! unlet g:loaded_jobs | so ".l:autoloadFile." | so ".l:pluginFile endfunction " Edit plugin files " Cmd: Jobsedit function! jobs#Edit() let l:plugin = substitute(s:plugin_path, "autoload", "plugin", "") silent exec("tabnew ".s:plugin) silent exec("vnew ".l:plugin."/".s:plugin_name) endfunction function! s:Initialize() let s:LogLevel = 0 let s:jobsRunningDict = {} let s:jobsHistoryDict = {} endfunction function! s:Error(mssg) echohl ErrorMsg | echom s:plugin.": ".a:mssg | echohl None endfunction function! s:Warn(mssg) echohl WarningMsg | echom a:mssg | echohl None endfunction " Debug function. Log message function! s:LogLevel(level,func,mssg) if s:LogLevel >= a:level echom "["s:plugin_name." : ".a:func." ] ".a:mssg endif endfunction " Debug function. Log message and wait user key function! s:LogLevelStop(level,func,mssg) if s:LogLevel >= a:level call input("[".s:plugin_name." : ".a:func." ] ".a:mssg." (press key)") endif endfunction func! jobs#Verbose(level) if a:level == "" call s:LogLevel(0, expand(''), "Verbose level: ".s:LogLevel) return endif let s:LogLevel = a:level call s:LogLevel(0, expand(''), "Set verbose level: ".s:LogLevel) endfun function! s:JobHistList(jobsDict) if empty(a:jobsDict) call s:Warn("No jobs history found.") return 1 endif let jobIdList = [] let n = 1 let format = "%' '-3s) %' '-11s %s " let format1 = "%' '-3d) %' '-11s \"%s\" " echo printf(l:format, "Pos", "Time", "Cmd") " for jobList in items(a:jobsDict) let jobId = l:jobList[0] let jobCmd = l:jobList[1][0] let starTime = l:jobList[1][5] let endTime = l:jobList[1][8] let timeList = reltime([l:starTime, l:endTime]) let time = l:timeList[0] if l:time >= 3600 let l:time = l:time / 3600.0 let timeStr = printf("%.1f", l:time)." h" elseif l:time >= 60 let l:time = l:time / 60.0 let timeStr = printf("%.1f", l:time)." m" else let timeStr = printf("%.f", l:time)." s" endif echo printf(l:format1, l:n, l:timeStr, l:jobCmd) let n += 1 endfor return 0 endfunction function! s:JobList(jobsDict,winId) if empty(a:jobsDict) call s:Warn("No jobs found running in background.") return endif let jobIdList = [] let n = 1 let format = "%' '-3s) %' '-8s %' '-6s %' '-11s %s " let format1 = "%' '-3d) %' '-8s %' '-6s %' '-11s \"%s\" " echo printf(l:format, "Pos", "JobId", "Status", "Time", "Cmd") " for jobList in items(a:jobsDict) let jobId = l:jobList[0] let jobCmd = l:jobList[1][0] let winId = l:jobList[1][1] let starTime = l:jobList[1][5] let job = l:jobList[1][7] if a:winId != "" && a:winId != l:winId continue endif let status = job_status(l:job) let timeList = reltime([l:starTime, localtime()]) let time = l:timeList[0] if l:time >= 60 let timeStr = printf("%.1f", l:time / 60.0)." m" else let timeStr = printf("%.f", l:time)." s" endif if l:status == "dead" | echohl ErrorMsg | endif echo printf(l:format1, l:n, l:jobId, l:status, l:timeStr, l:jobCmd) if l:status == "dead" echohl None call s:JobCancel(l:job) else let jobIdList += [ l:jobId ] endif let n += 1 endfor return l:jobIdList endfunction function! s:JobCancel(jobId) if empty(s:jobsRunningDict) call s:Warn("No jobs running in backgraund.") return endif if !has_key(s:jobsRunningDict, a:jobId) return 1 endif let jobCfgList = s:jobsRunningDict[a:jobId] let winId = l:jobCfgList[1] let result = l:jobCfgList[4] let script = l:jobCfgList[5] let name = l:jobCfgList[6] let job = l:jobCfgList[7] " Add to jobs history list let l:jobCfgList += [ localtime() ] " Add end time call extend(s:jobsHistoryDict, { a:jobId : l:jobCfgList }) " Remove from the running jobs list call remove(s:jobsRunningDict, a:jobId) call delete(l:script) call delete(l:result) if exists("w:jobsWinList") let n = index(w:jobsWinList, l:name) if l:n >= 0 call remove(w:jobsWinList, l:n) endif endif if exists("w:jobsTabList") let n = index(w:jobsTabList, l:name) if l:n >= 0 call remove(w:jobsTabList, l:n) endif endif silent! call job_stop(l:job) call s:Warn("Cancel job ".l:job) endfunction " Check if there's a job already running on background for this window " If name is not empty, search only for jors in bg with the " provided name runngin on current window. function! jobs#IsOnWindow(name) if !exists("w:jobsWinList") return 0 endif if a:name == "" && len(w:jobsWinList) > 0 return 1 endif let l:n = index(w:jobsWinList, a:name) call s:LogLevel(1, expand(''), "position:".l:n) if (l:n > 0) return 1 endif return 0 endfunction " Check if job already running in background on thi tab " If name is not empty, search only for jors in bg with the " provided name runngin on current tab. function! jobs#IsOnTab(name) if !exists("w:jobsTabList") return 0 endif if a:name == "" && len(w:jobsTabdDict) > 0 return 1 endif if (index(w:jobsTabList, a:name) >= 0) return 1 endif return 0 endfunction function! s:MountCallbackCall(list, resfile) if len(a:list) == 0 call s:LogLevel(1, expand(''), "Callback: empty") return "" endif let n = 0 for arg in a:list silent! call s:LogLevel(2, expand(''), "arg". l:n .": ". l:arg) if l:n == 0 let l:callback = l:arg ."(" else let l:callback .= "\"". l:arg ."\", " endif let n += 1 silent! call s:LogLevel(2, expand(''), "Callback: ". l:callback) endfor let l:callback .= "\"". a:resfile ."\")" call s:LogLevel(1, expand(''), "Callback: ". l:callback) return l:callback endfunction " Run system command. " Arg1: system command. " Arg2: callback function to process the system results. " Arg3: if true run the system call on backgraund. " Arg4: command name, used to search for commands of the same type already running on background. function! jobs#RunCmd0(command,callbackList,async,name) " Make sure we're running VIM version 8 or higher. if g:jobs_run_in_background == 0 || a:async == 0 echo a:command." (fg)" " Launch command in foreground let l:result = tempname() let command = a:command." > ".l:result echo "This may take a while..." call system(l:command) if len(a:callbackList) != 0 execute "call ". s:MountCallbackCall(a:callbackList,l:result) endif call delete(l:result) else if g:jobs_hidePsswd == 1 " Hide passwords from command line. " Admitted formats: "password MY_PASSWORD", "password=MY_PASSWORD". let l:modifiedJobCmd = substitute(a:command, "password[ =]\\([a-zA-Z0-9\-\.\*\/?,;':\"~!@#$%^&*()_+='|]\\)*", "password ********", "") " DEBUG: Test substitute command on vim's command line: " echo substitute("cmd --password mypass./*,:12 --option1 --option2", "password[ =]\\([a-zA-Z0-9\-\.\*\/?,;':\"~!@#$%^&*()_+='|]\\)*", "password ********", "") " echo substitute("cmd --password=mypass./*,:12 --option1 --option2", "password[ =]\\([a-zA-Z0-9\-\.\*\/?,;':\"~!@#$%^&*()_+='|]\\)*", "password ********", "") " echo substitute("cmd --password mypass./*,:12", "password[ =]\\([a-zA-Z0-9\-\.\*\/?,;':\"~!@#$%^&*()_+='|]\\)*", "password ********", "") " echo substitute("cmd --password=mypass./*,:12", "password[ =]\\([a-zA-Z0-9\-\.\*\/?,;':\"~!@#$%^&*()_+='|]\\)*", "password ********", "") echo l:modifiedJobCmd." (bg)" else echo a:command." (bg)" let l:modifiedJobCmd = a:command endif let result = tempname() let script = tempname() let command = "( ".a:command." ) 2>&1" call system("echo '".l:command."' > ".l:script) call system("chmod 744 ".l:script) call s:LogLevel(1, expand(''), l:script) call s:LogLevel(1, expand(''), system("cat ".l:script)) let l:callback = s:MountCallbackCall(a:callbackList, l:result) "echom "callback: ".l:callback call s:LogLevel(1, expand(''), "Job start: ".l:modifiedJobCmd." Cmd: ".l:script." File: ".l:result) " Launch the job. let jobCfgList = [ l:modifiedJobCmd, win_getid(), l:callback, l:result, l:script, localtime(), a:name ] call s:LogLevel(1, expand(''), "Job start: ".l:modifiedJobCmd." Cmd: ".l:script." File: ".l:result) let job = job_start(l:script, {'exit_cb': 'jobs#SystemCmdCallback0', 'out_io': 'file', 'out_name': l:result}) let l:jobCfgList += [ l:job ] let jobId = split(job,' ')[1] call extend(s:jobsRunningDict, { l:jobId : l:jobCfgList }) "sleep 500ms sleep if job_status(l:job) != "dead" && a:name != "" if !exists("w:jobsWinList") let w:jobsWinList = [] endif if !exists("w:jobsTabList") let w:jobsTabList = [] endif let w:jobsWinList += [ a:name ] let w:jobsTabList += [ a:name ] "else "call s:Error("Job ".a:name." failed (".a:command.")") endif endif endfunction " Check the system command status, launch the callback function on finish. function! jobs#SystemCmdCallback0(job,message) call s:LogLevelStop(1, expand(''), "job1:".a:job." mssg:".a:message) if job_status(a:job) ==# "run" "call s:Error("Job ".a:job." failed. ".a:message) return endif let jobId = split(a:job,' ')[1] call s:LogLevelStop(1, expand(''), "jobId1:".l:jobId) if !has_key(s:jobsRunningDict, l:jobId) "call s:Error("Job ".a:job." failed. ".a:message) return 1 endif let jobCfgList = s:jobsRunningDict[l:jobId] let command = l:jobCfgList[0] let winId = l:jobCfgList[1] let callback = l:jobCfgList[2] let result = l:jobCfgList[3] let script = l:jobCfgList[4] let time = l:jobCfgList[5] let jobName = l:jobCfgList[6] let baseWinId = win_getid() if l:winId != "" cal s:LogLevelStop(1, expand(''), "Goto window:".l:winId) if win_gotoid(l:winId) != 1 call s:Error("Can't find the window associated to this job") return 1 endif endif echom "callback: ".l:callback if l:callback != "" cal s:LogLevelStop(1, expand(''), "Launch callback:".l:callback) execute "call ".l:callback endif " Add to jobs history list let l:jobCfgList += [ localtime() ] " Add end time call extend(s:jobsHistoryDict, { l:jobId : l:jobCfgList }) call delete(l:script) call delete(l:result) " Remove from the running jobs list call remove(s:jobsRunningDict, l:jobId) if exists("w:jobsWinList") let n = index(w:jobsWinList, l:jobName) if l:n >= 0 cal s:LogLevel(1, expand(''), "Remove job:".l:n." from win list") call remove(w:jobsWinList, l:n) endif endif if exists("w:jobsTabList") let n = index(w:jobsTabList, l:jobName) if l:n >= 0 cal s:LogLevel(1, expand(''), "Remove job:".l:n." from tab list") call remove(w:jobsTabList, l:n) endif endif return 1 endfunction " Run system command. " Arg1: system command. " Arg2: callback function to process the system results. " Arg3: if true run the system call on backgraund. " Arg4: command name, used to search for commands of the same type already running on background. function! jobs#RunCmd(command,callback,async,name) " Make sure we're running VIM version 8 or higher. if g:jobs_run_in_background == 0 || a:async == 0 echo a:command." (fg)" " Launch command in foreground let l:result = tempname() let command = a:command." > ".l:result echo "This may take a while..." call system(l:command) if a:callback != "" "echomsg "Launch callback:"s:callback."\"".l:result."\")" execute "call ".a:callback."\"".l:result."\")" endif call delete(l:result) else echo a:command." (bg)" let result = tempname() let script = tempname() let command = "( ".a:command." ) 2>&1" call system("echo '".l:command."' > ".l:script) call system("chmod 744 ".l:script) call s:LogLevel(1, expand(''), l:script) call s:LogLevel(1, expand(''), system("cat ".l:script)) " Launch the job. let jobCfgList = [ a:command, win_getid(), a:callback , l:result, l:script, localtime(), a:name ] call s:LogLevel(1, expand(''), "Job start: ".a:command." Cmd: ".l:script." File: ".l:result) let job = job_start(l:script, {'exit_cb': 'jobs#SystemCmdCallback', 'out_io': 'file', 'out_name': l:result}) let l:jobCfgList += [ l:job ] let jobId = split(job,' ')[1] call extend(s:jobsRunningDict, { l:jobId : l:jobCfgList }) "sleep 500ms sleep if job_status(l:job) != "dead" && a:name != "" if !exists("w:jobsWinList") let w:jobsWinList = [] endif if !exists("w:jobsTabList") let w:jobsTabList = [] endif let w:jobsWinList += [ a:name ] let w:jobsTabList += [ a:name ] "else "call s:Error("Job ".a:name." failed (".a:command.")") endif endif endfunction " Check the system command status, launch the callback function on finish. function! jobs#SystemCmdCallback(job,message) call s:LogLevelStop(1, expand(''), "job1:".a:job." mssg:".a:message) if job_status(a:job) ==# "run" "call s:Error("Job ".a:job." failed. ".a:message) return endif let jobId = split(a:job,' ')[1] call s:LogLevelStop(1, expand(''), "jobId1:".l:jobId) if !has_key(s:jobsRunningDict, l:jobId) "call s:Error("Job ".a:job." failed. ".a:message) return 1 endif let jobCfgList = s:jobsRunningDict[l:jobId] let command = l:jobCfgList[0] let winId = l:jobCfgList[1] let callback = l:jobCfgList[2] let result = l:jobCfgList[3] let script = l:jobCfgList[4] let time = l:jobCfgList[5] let jobName = l:jobCfgList[6] let baseWinId = win_getid() if l:winId != "" cal s:LogLevelStop(1, expand(''), "Goto window:".l:winId) if win_gotoid(l:winId) != 1 call s:Error("Can't find the window associated to this job") return 1 endif endif if l:callback != "" cal s:LogLevelStop(1, expand(''), "Launch callback:".l:callback."\"".l:result."\")") execute "call ".l:callback."\"".l:result."\")" endif " Add to jobs history list let l:jobCfgList += [ localtime() ] " Add end time call extend(s:jobsHistoryDict, { l:jobId : l:jobCfgList }) call delete(l:script) call delete(l:result) " Remove from the running jobs list call remove(s:jobsRunningDict, l:jobId) if exists("w:jobsWinList") let n = index(w:jobsWinList, l:jobName) if l:n >= 0 cal s:LogLevel(1, expand(''), "Remove job:".l:n." from win list") call remove(w:jobsWinList, l:n) endif endif if exists("w:jobsTabList") let n = index(w:jobsTabList, l:jobName) if l:n >= 0 cal s:LogLevel(1, expand(''), "Remove job:".l:n." from tab list") call remove(w:jobsTabList, l:n) endif endif return 1 endfunction " Show list with all jobs running in background. " Stop the selected job. function! jobs#Stop() if empty(s:jobsRunningDict) call s:Warn("No jobs running in backgraund.") return endif let jobIdList = s:JobList(s:jobsRunningDict,"") let pos = input("Remove position: ") echo " " for n in split(l:pos) if l:n != "" && l:n <= len(l:jobIdList) let n -= 1 call s:JobCancel(l:jobIdList[l:n]) endif endfor return endfunction " Show list with all jobs running in background. function! jobs#Status() if empty(s:jobsRunningDict) call s:Warn("No jobs running in backgraund.") return endif let jobIdList = s:JobList(s:jobsRunningDict,"") call input("") endfunction " Show list with all jobs running in background on currnet window function! jobs#StatusCurrentWindow() if empty(s:jobsRunningDict) call s:Warn("No jobs running in backgraund.") return endif let jobIdList = s:JobList(s:jobsRunningDict,win_getid()) call input("") endfunction " Show job history function! jobs#History() if empty(s:jobsHistoryDict) call s:Warn("No jobs history found.") return endif let jobIdList = s:JobHistList(s:jobsHistoryDict) call input("") endfunction " Stop all jobs running in background function! jobs#StopAll() let n = 0 if !empty(s:jobsRunningDict) for jobList in items(s:jobsRunningDict) call s:JobCancel(l:jobList[0]) let n += 1 endfor endif let s:jobsRunningDict = {} let w:jobsWinList = [] echo "Jobs stopped:".l:n endfunction function! jobs#Help() echo "jobs.vim" echo " " echo " Jobsl : show all jobs running." echo " Jobsw : show all jobs running on current window." echo " Jobshy : show jobs history." echo " Jobsk : show all jobs running, kill selected one." echo " Jobska : kill all running jobs." echo " Jobsv : change verbosity level (0 is default)." echo " " call input("(Press key)") endfunction function! jobs#Menu(...) " Check jpLib.vim plugin installed if empty(glob(s:plugin_path."/jpLib.vim")) call s:Error("missing plugin jpLib.vim (".s:plugin_path."/jpLib.vim".")") call input("") endif let l:selection = "" if a:0 >= 1 let l:selection = a:1 endif let l:options = [] let l:options += [ [ "#jobs.vim commands:" , "" , "" ] ] let l:options += [ [ "Show all jobs running (Jobsl)" , "Jobsl " , "" ] ] let l:options += [ [ "Show all jobs running on current window (Jobsw)", "Jobsw " , "" ] ] let l:options += [ [ "Show jobs history (Jobshy)" , "Jobshy ", "" ] ] let l:options += [ [ "Show all jobs running kill selected one (Jobsk)", "Jobsk " , "" ] ] let l:options += [ [ "Kill all running jobs (Jobska)" , "Jobska ", "" ] ] let l:options += [ [ "Change verbosity level. 0 is default (Jobsv)" , "Jobsv" , "" ] ] call jpLib#OptionsMenu(l:options, l:selection) endfunction " Create menu items for the specified modes. function! jobs#CreateMenus(modes, submenu, target, desc, cmd) "let s:LogLevel = 4 " Build up a map command like let plug = a:target let plug_start = 'noremap ' . ' :call JobsMenu("' let plug_end = '", "' . a:target . '")' " Build up a menu command like let menuRoot = get(['', 'JobsMenu', '&JobsUtils', "&Plugin.&JobsUtils".a:submenu], 3, '') let menu_command = 'menu ' . l:menuRoot . '.' . escape(a:desc, ' ') if strlen(a:cmd) let menu_command .= '' . a:cmd endif let menu_command .= ' ' . (strlen(a:cmd) ? plug : a:target) "let menu_command .= ' ' . (strlen(a:cmd) ? a:target) call s:LogLevel(1, expand(''), "menu_command :".l:menu_command) " Execute the commands built above for each requested mode. for mode in (a:modes == '') ? [''] : split(a:modes, '\zs') if strlen(a:cmd) execute mode . plug_start . mode . plug_end call s:LogLevel(1, expand(''), "execute ". mode . plug_start . mode . plug_end) endif " Check if the user wants the menu to be displayed. if g:jobs_mode != 0 call s:LogLevel(1, expand(''), "execute " . mode . menu_command) execute mode . menu_command endif endfor "let s:LogLevel = 0 endfunction "- Release tools ------------------------------------------------------------ " " Create a vimball release with the plugin files. " Commands: Jobsvba function! jobs#NewVimballRelease() let text = "" let text .= "plugin/jobs.vim\n" let text .= "autoload/jobs.vim\n" silent tabedit silent put = l:text silent! exec '0file | file vimball_files' silent normal ggdd let l:plugin_name = substitute(s:plugin_name, ".vim", "", "g") let l:releaseName = l:plugin_name."_".g:jobs_version.".vmb" let l:workingDir = getcwd() silent cd ~/.vim silent exec "1,$MkVimball! ".l:releaseName." ./" silent exec "vertical new ".l:releaseName silent exec "cd ".l:workingDir endfunction "- initializations ------------------------------------------------------------ let s:plugin = expand('') let s:plugin_path = expand(':p:h') let s:plugin_name = expand(':t') if !exists("s:initialized") call s:Initialize() let s:initialized = 1 endif