" Vimball Archiver by Charles E. Campbell UseVimball finish plugin/svnTools.vim [[[1 343 " Script Name: svnTools.vim "Description: " " Copyright: (C) 2017-2022 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, jpLib.vim(optional) " " NOTES: " " Version: 2.0.1 " Changes: " 2.0.1 Fri, Feb 25. JPuigdevall " - New: command Vdd, compare with vimdiff all files found on different directories. " allows to filter files (flags: +fileX, -fileY), " skip/keep-only binaries (flags: SB, BO) and/or " skip/keep-only equal files (flags: SE, EO). " - New: command Vdf, compare current file with same file on a different directory. " When the structure paths are the same in both sides, passing as argument the other working directory is enough. " ex: 'Vdf ~/Projects/dir2/' " When comparing directories on the same path, only need to change the directory name. " ex: compare same file on sandbox1 with dir2: 'Vdf sandbox1 dir2' " When comparing directories on the same path, only need to change the directory part to be replaced. " ex: compare same file on dir1 with dir2: 'Vdf 1 2' " - New: commands SvnD, SvnDD and SvnDA. Advanced diff on path, allows to filter files (flags: +fileX, -fileY), " and skip/keep-only binaries (flags: SB, BO). " - New: commands SvnVD, SvnVDD and SvnVDA. Advanced vimdiff on path, allows to filter files (flags: +fileX -fileY), " and skip/keep-only binaries (flags: SB, BO). " - New: Svndc and Svnvdc admit flags SE and SB to skip equal files and binary files. " use falgs C1 or C2 to check only changes on path1 or path2. " - Del: remove commands SvndA, SvnvdA, SvndC, SvnvdC, already covered on " Svndc and Svnvdc modifying the flags argument. " - Fix: Svnst color highlighting on ^C tagged files. " - Fix: Svnres command. Missing files in conflict not correctly fetched from snv st output. " - Fix: Svnm command. Missing files in conflict not correctly fetched from snv st output. " reverse previous changes on svnTools#status#GetStatusFilesList launch filter field. " - Fix: Svnm command. Missing list variable definition. " - Fix: Svnvdr. error on OpenVimDiffOnEachFileAndRevision. " 2.0.0 Fri, 21 Jan 22. JPuigdevall " - new: menu to alow SvnvdC to skip or keep only the files matching the required patterns. " - Fix: Svnc VimDiffFilePaths not found. " - Fix: Svnvdf command, not showing any result. " - New: Svnedit command, not showing the plugint/svnTools.vim file. " - Fix: Svnvdf command, not showing any result. " - Fix: svnTools#status#GetStatusFilesList calls, use "^M \|^D \|^A " instead of "^[M|D|A] ". " - Fix: svnTools#status#GetStatusFilesList list returns empty when only one file modified found. " - Fix: Svnvdr command. " - REFACTORING of the plugin to divide in different files. " New autoload/svnTools/ folder to save the plugin files. " - New: save and restore changes' functions: Svncsv, Svncvd, Svncvdd, Svncr. " Allowing to save, compare and restore changes. " Every time we save changes a new directory is created: _svnTools_changes_YYMMDD_HHMMSS/ " Every modified file is saved as: dir1___dir2___dir3__filename.ext " - New: Svnpwd command, enter user and password. " - New: on Svndvda, Svnvdd commands: allow user to select the files to perform the vimdiff. " - New: on Svndvda, Svnvdd commands: allow user to filter files adding splace separated filter patterns. " 1.0.6 Fri, 28 May 21. JPuigdevall " - New: Svndvdr command, when placed on an svn log and diff file (obtained from Svnr, Svnda, Svndd or Svndf), for each file " open the vimdiff of the current log's file revision. " - New configuration option g:svnTools_userAndPsswd to use non interactive snv and send user and password in the " same command: let g:svnTools_userAndPsswd = 1 " - New options to manage svn user and password: g:svnTools_svnUser, g:svnTool_storeSvnPsswd. " 1.0.5 Fri, 26 Feb 21. JPuigdevall " - New: Svnlr command, when placed on an svn log file, for each revision " number get its log and diff changes. " - Fix Svnm command, treat status ' C ' as file in conflict. " - Fix Svnm command, treat status !.*C as file in conflict. " - Fix Svnm command, do not try opening merge tool when file in confict is not found. " - Fix GetStatusFilesList function, file path is last column not second one. " - New Svnvmb command, development command to create a vimball release of the plugin. " 1.0.4 Wed, 16 Dec 20. JPuigdevall " - Fix bug on Svnvda, Svnvdd, Svnvdf, SvnvdA. " - New on Svnda, Svndd, Svndf: do not allow to modify or save the revision file on vimdiff. " - New Svndc command, show diff between files with changes on two different directories. " - New Svndc command, show diff between files with changes on two different directories, skip binary files. " - New Svnmh command: show merge layout help. " 1.0.3 Thu, 10 Dec 20. JPuigdevall " - New SvnvdA command. For every modifed file, allows user to get vimdiff, skip (this/all/none) file, " skip (this/all/none) binaries. " - New on Svnvdf/Svnvdd/Svnvda check if file is binary, ask user to skip binary files. " - New on Svnvdc will now show only files with differecnes, omitt any files that do not differ. " - New Svnvdca command to show all changes between directories. " - Fix GetStatusFilesString issue affecting svnTools#VimDiffCompareDirChanges. " 1.0.2 Fry, 10 Jul 20. JPuigdevall " - Add Svnm command to merge commit upon conflict. " - Add Svnrv command to resolve commit conflicts. " - Add Svnst commands to show svn status. " - Adapt to jobs.vim 0.1.0 " - Add Svnvdr command to show vimdiff on files modified on selected revision. " 1.0.1 Fry, 22 Jun 20. JPuigdevall " 1.0.0 Wed, 13 Feb 19. JPuigdevall " 0.0.1 Sun, 10 Feb 18. JPuigdevall " - Initial realease. if exists('g:loaded_svntools') finish endif let g:loaded_svntools = 1 let s:save_cpo = &cpo set cpo&vim let g:svnTools_version = "2.0.1" "- configuration -------------------------------------------------------------- let g:svnTools_svnCmd = get(g:, 'svnTools_svnCmd', "svn") let g:svnTools_userAndPsswd = get(g:, 'svnTools_userAndPsswd', 0) let g:svnTools_svnUser = get(g:, 'svnTools_svnUser', "") let g:svnTools_storeSvnPsswd = get(g:, 'svnTools_storeSvnPsswd', 1) let g:svnTools_runInBackground = get(g:, 'svnTools_runInBackground', 1) let g:svnTools_gotoWindowOnEnd = get(g:, 'svnTools_gotoWindowOnEnd', 1) let g:svnTools_lastCommits = get(g:, 'svnTools_lastCommits', 3000) let g:svnTools_mode = get(g:, 'svnTools_mode', 3) " Merge Layout: " Layout 2: " -------------------------- " | | | " | Current | Right | " | | | " -------------------------- " " Layout 3: " -------------------------- " | | | | " | Left | Current | Right | " | | | | " -------------------------- " " Layout 4: " -------------------------- " | | | | " | Left | Working | Right | " | | | | " -------------------------- " | Current | " -------------------------- " let g:svnTools_mergeLayout = get(g:, 'svnTools_mergeLayout', "4") let g:svnTools_mergeLayouts = get(g:, 'svnTools_mergeLayouts', "2 3 4") "- commands ------------------------------------------------------------------- " SVN INFO: command! -nargs=0 Svni call svnTools#svnTools#Info(getcwd()) command! -nargs=0 Svnif call svnTools#svnTools#Info(getcwd()) " SVN STATUS: command! -nargs=0 Svnst call svnTools#status#GetStatus(getcwd(), "^[A-Z!] ", "^[?X] ") command! -nargs=0 Svnsta call svnTools#status#GetStatus(getcwd(), "", "") command! -nargs=0 Svnstf call svnTools#status#GetStatus(expand('%'), "", "") command! -nargs=0 Svnstd call svnTools#status#GetStatus(expand('%:h'), "", "") command! -nargs=0 Svnsth call svnTools#help#StatusHelp() " SVN DIFF: " Simple diff command! -nargs=1 -complete=dir Svnd call svnTools#diff#Diff() command! -nargs=0 Svndf call svnTools#diff#Diff(expand('%')) command! -nargs=0 Svndd call svnTools#diff#Diff(expand('%:h')) command! -nargs=0 Svnda call svnTools#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 SvnD call svnTools#diff#DiffAdv() command! -nargs=* SvnDD call svnTools#diff#DiffAdv(expand('%:h'), ) command! -nargs=* SvnDA call svnTools#diff#DiffAdv(getcwd(), ) " SVN DIFF WITH VIMDIF: command! -nargs=0 Svnvdf call svnTools#vimdiff#File(expand('%')) command! -nargs=1 -complete=dir Svnvd call svnTools#vimdiff#Path() command! -nargs=0 Svnvdd call svnTools#vimdiff#Path(expand('%:h')) command! -nargs=0 Svnvda call svnTools#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 SvnVD call svnTools#vimdiff#PathAdv() command! -nargs=* SvnVDD call svnTools#vimdiff#PathAdv(expand('%:h'), ) command! -nargs=* SvnVDA call svnTools#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 svn changes on path1. " C2: use only svn changes on path2. command! -nargs=* -complete=dir Svndc call svnTools#directory#CompareChanges("diff", ) command! -nargs=* -complete=dir Svnvdc call svnTools#directory#CompareChanges("vimdiff", ) " Open with vimdiff all files modified on a revsion or between two different revisions " Svnvdr REV1 " Svnvdr REV1 REV2 " When no revision number provided as argument, try get word under cursor as the revision number. command! -nargs=* Svnvdr call svnTools#vimdiff#RevisionsCompare() " DIFF FILE TOOLS: " When placed on buffer with a diff file opened. command! -nargs=0 Svndvdr call svnTools#diffFile#OpenVimDiffOnEachFileAndRevision() " Show vimdiff of each modified file command! -nargs=* SvnDiffVdr call svnTools#diffFile#OpenVimDiffOnAllFiles() " When placed on a line starting with 'Index' or '---' or " '+++' " Show vimdiff of current modified file command! -nargs=* SvnDiffVdrf call svnTools#diffFile#OpenVimDiffGetFileAndRevisionFromCurrentLine() " SVN LOG: command! -nargs=? Svnl call svnTools#log#GetRevision() command! -nargs=* Svnls call svnTools#log#SearchPattern() command! -nargs=* Svnlf call svnTools#log#GetHistory(expand("%"), ) command! -nargs=* Svnld call svnTools#log#GetHistory(getcwd(), ) command! -nargs=* Svnlp call svnTools#log#GetHistory() command! -nargs=? Svnlr call svnTools#log#GetRevDiff("") " Get log and diff from selected revision. command! -nargs=? Svnr call svnTools#log#GetLogAndDiff() " SVN CAT: command! -nargs=1 Svncr call svnTools#cat#GetRevision() " SVN BLAME: command! -nargs=0 Svnbl call svnTools#blame#Blame("") command! -nargs=0 Svnblv call svnTools#blame#Blame("-v") " SVN CONFLICTS: command! -nargs=* Svnm call svnTools#conflict#Merge(getcwd(), ) command! -nargs=* Svnmf call svnTools#conflict#Merge(expand('%'), ) command! -nargs=* Svnmp call svnTools#conflict#Merge() command! -nargs=* Svnmh call svnTools#help#MergeLayoutHelp() command! -nargs=* Svnres call svnTools#conflict#Resolve(getcwd(), ) command! -nargs=* Svnresp call svnTools#conflict#Resolve() " Other: command! -nargs=0 Svnh call svnTools#help#Help() " Toogle background/foreground execution of the svn commands. command! -nargs=? Svnbg call svnTools#svnTools#BackgroundMode("") command! -nargs=? Svnv call svnTools#tools#Verbose("") " Release functions: command! -nargs=0 Svnvba call svnTools#svnTools#NewVimballRelease() " Edit plugin files: command! -nargs=0 Svnedit call svnTools#svnTools#Edit() " Svn user and password functions: command! -nargs=0 Svnpwd call svnTools#tools#SetUserAndPsswd() " Save/restore changes from disk: command! -nargs=0 Svnc call svnTools#changes#Show() command! -nargs=0 Svncsv call svnTools#changes#Save() command! -nargs=0 Svncvd call svnTools#changes#VimdiffCurrentAndSaved() command! -nargs=0 Svncvdd call svnTools#changes#VimdiffSaved() command! -nargs=0 Svncr call svnTools#changes#Restore() " Diff: " Compare with vimdiff same file on different base directory. " Vim Diff File (vertical split) command! -nargs=* -complete=dir Vdf call svnTools#utils#DiffSameFileOnPath("vnew", ) " Compare with vimdiff (each file on) two diferent directories " Vim Diff Directories command! -nargs=* -complete=dir Vdd call svnTools#utils#VimdiffAll() "- abbreviations ------------------------------------------------------------------- " DEBUG functions: reload plugin cnoreabbrev _svnrl =svnTools#svnTools#Reload() "- menus ------------------------------------------------------------------- if has("gui_running") call svnTools#svnTools#CreateMenus('cn' , '.&Info' , ':Svni' , 'Working dir info' , ':Svni') call svnTools#svnTools#CreateMenus('cn' , '.&Info' , ':Svnif' , 'File info' , ':Svnif') call svnTools#svnTools#CreateMenus('cn' , '.&Blame' , ':Svnbl' , 'Get file blame' , ':Svnbl') call svnTools#svnTools#CreateMenus('cn' , '.&Blame' , ':Svnblv' , 'Get file blame verbose' , ':Svnblv') call svnTools#svnTools#CreateMenus('cn' , '.&Log' , ':Svnl' , 'Show log (num of commits)' , ':Svnl [NUM]') call svnTools#svnTools#CreateMenus('cn' , '.&Log' , ':Svnls' , 'Log search (num of commits)' , ':Svnls PATTERN [NUM]') call svnTools#svnTools#CreateMenus('cn' , '.&Log' , ':Svnlr' , 'On svn log file, get each revision diff' , ':Svnlr') call svnTools#svnTools#CreateMenus('cn' , '.&Log' , ':Svnlvdr' , 'On svn log and diff file, get each file vimdiff' , ':Svnlvdr') call svnTools#svnTools#CreateMenus('cn' , '.&Diff' , ':Svnd' , 'Get file/path diff' , ':SvnD PATH') call svnTools#svnTools#CreateMenus('cn' , '.&Diff' , ':Svndf' , 'Get file diff' , ':SvnDf') call svnTools#svnTools#CreateMenus('cn' , '.&Diff' , ':Svndd' , 'Get dir diff' , ':SvnDd') call svnTools#svnTools#CreateMenus('cn' , '.&Diff' , ':Svnda' , 'Get working dir changes diff' , ':SvnDa') call svnTools#svnTools#CreateMenus('cn' , '.&DiffFilt' , ':SvnD' , 'Get (filtered) file/path diff' , ':SvnD PATH [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&DiffFilt' , ':SvnDD' , 'Get (filtered) dir changes diff' , ':SvnDD [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&DiffFilt' , ':SvnDA' , 'Get (filtered) working dir diff' , ':SvnDA [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&Vimdiff' , ':Svnvd' , 'Get current file/path changes using vimdiff' , ':Svnvd') call svnTools#svnTools#CreateMenus('cn' , '.&Vimdiff' , ':Svnvdf' , 'Get current file changes using vimdiff' , ':Svnvdf') call svnTools#svnTools#CreateMenus('cn' , '.&Vimdiff' , ':Svnvdd' , 'Get current dir changes using vimdiff' , ':Svnvdd') call svnTools#svnTools#CreateMenus('cn' , '.&Vimdiff' , ':Svnvda' , 'Get working dir with changes using vimdiff' , ':Svnvda') call svnTools#svnTools#CreateMenus('cn' , '.&VimdiffFilt' , ':SvnvD' , 'Get current (filtered) file/path changes using vimdiff' , ':SvnvD PATH [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&VimdiffFilt' , ':SvnvDD' , 'Get current (filtered) dir changes using vimdiff' , ':SvnvDD [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&VimdiffFilt' , ':SvnvDA' , 'Get working (filtered) dir with changes using vimdiff' , ':SvnvDA [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&DirCompare' , ':Svndc' , 'Get diff between changes on both paths' , ':Svndc PATH1 PATH2 [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&DirCompare' , ':Svnvdc' , 'Get vimdiff between changes on both paths' , ':Svnvdc PATH1 PATH2 [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&MyDirCompare' , ':Svndmc' , 'Get diff with files changed on current path' , ':Svndc PATH [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&MyDirCompare' , ':Svnvdmc' , 'Get vimdiff with files changed on current path' , ':Svnvdmc PATH [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '.&Revision' , ':Svnr' , 'Get revision log and diff' , ':Svnr REV') call svnTools#svnTools#CreateMenus('cn' , '.&Revision' , ':Svncr' , 'Get revision files' , ':Svncr REV') call svnTools#svnTools#CreateMenus('cn' , '.&Revision' , ':Svnvdr' , 'Get vimdiff on revision' , ':Svnvdr [REV1] [REV2]') call svnTools#svnTools#CreateMenus('cn' , '.&Conflicts' , ':Svnm' , 'Merge all files in conflict' , ':Svnm [LAYOUT]') call svnTools#svnTools#CreateMenus('cn' , '.&Conflicts' , ':Svnmf' , 'Merge file in conflict' , ':Svnmf FILE [LAYOUT]') call svnTools#svnTools#CreateMenus('cn' , '.&Conflicts' , ':Svnmp' , 'Merge file in conflict' , ':Svnmf FILE [LAYOUT]') call svnTools#svnTools#CreateMenus('cn' , '.&Conflicts' , ':Svnres' , 'Resolve conflicts' , ':Svnres [all/file]') call svnTools#svnTools#CreateMenus('cn' , '.&Conflicts' , ':Svnmh' , 'Show merge layout help' , ':Svnmh') call svnTools#svnTools#CreateMenus('cn' , '.&Changes' , ':Svnc' , 'Show saved changes' , ':Svnc') call svnTools#svnTools#CreateMenus('cn' , '.&Changes' , ':Svncsv' , 'Save current changes' , ':Svncsv') call svnTools#svnTools#CreateMenus('cn' , '.&Changes' , ':Svncvd' , 'Show selected changes and vimdiff' , ':Svncvd') call svnTools#svnTools#CreateMenus('cn' , '.&Changes' , ':Svncr' , 'Restore selected changes' , ':Svncr') call svnTools#svnTools#CreateMenus('cn' , '.&FileCompare' , ':Vdf' , 'Compare [current] file with same one on different dir' , ':Vdf [PATH1] PATH2') call svnTools#svnTools#CreateMenus('cn' , '.&FileCompare' , ':Vdd' , 'Compare all files between directories' , ':Vdd [PATH1] PATH2 [FLAGS]') call svnTools#svnTools#CreateMenus('cn' , '' , ':Svnpwd' , 'Set svn user and password' , ':Svnpwd') call svnTools#svnTools#CreateMenus('cn' , '' , ':Svnbg' , 'Run foreground/background' , ':Svnbg') call svnTools#svnTools#CreateMenus('cn' , '' , ':Svnh ' , 'Show command help' , ':Svnh') endif let &cpo = s:save_cpo unlet s:save_cpo autoload/svnTools/blame.vim [[[1 76 " Script Name: svnTools/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 ------------------------------------------------------------------- " Svn blame and Svn blame -v " Commands: SvnBlame, Svnbl, Svnblv. function! svnTools#blame#Blame(opt) let file = expand("%") let name = expand("%:t") let path = expand("%:h") let pos = line('.') let ext = svnTools#tools#GetSyntax() let path = svnTools#tools#PathToFile(l:path) let name = "_svnBlame_".l:path.".".l:ext let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let command = l:svnCmd." blame ".a:opt." ".l:file "let command = g:svnTools_svnCmd." blame ".a:opt." ".l:file let callback = ["svnTools#blame#BlameEnd", l:pos, l:ext, l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! svnTools#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 call svnTools#tools#WindowSplit() put = readfile(a:resfile) " Set syntax highlight silent exec("set ft=".a:ext) " Restore previous position silent exec("normal ".a:pos."G") silent exec("normal zz") " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) call svnTools#tools#WindowSplitEnd() " On vertical split synchronize scroll if exists('w:split') if w:split == 2 set crb! vertical resize 70 endif endif else call svnTools#tools#Warn("Svn blame empty") endif endfunction autoload/svnTools/cat.vim [[[1 67 " Script Name: svnTools/cat.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 current file's selected svn revision. " Arg1: revision number to search. " Commands: SvnCatRev, Svncr. function! svnTools#cat#GetRevision(rev) let l:file = expand("%") 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 svnTools#tools#Warn("Argument 1: revision number not found.") return endif let file = "r".l:rev.".diff" let filepath = expand("%") let filename = expand("%:t:r") echo "Get file: ".l:filename." revision: ".l:rev call svnTools#tools#WindowSplitMenu(3) call svnTools#tools#WindowSplit() echo "svn cat -r ".l:rev." ".l:filepath echo "This may take a while ..." let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() exec("r! ".l:svnCmd." cat -r ".l:rev." ".l:filepath) "exec("r! svn cat -r ".l:rev." ".l:filepath) if line('$') == 1 call svnTools#tools#WindowSplitEnd() call svnTools#tools#Warn("Not found") return endif call svnTools#tools#SetSyntax(l:ext) silent exec("0file") silent! exec("file _svnCat_".l:name."_r".l:rev.".".l:ext) call svnTools#tools#WindowSplitEnd() endfunction autoload/svnTools/changes.vim [[[1 313 " Script Name: changes.vim "Description: save/restore/compare the file changes. " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " " NOTES: " "- Changes Save/restore functions --------------------------------------------------- " Show saved changes. " Commands: Svnc function! svnTools#changes#Show() let l:savedDatesList = s:GetSavedChangesDatesList() if len(l:savedDatesList) == 0 call svnTools#tools#Warn("No saved changes found") return endif echo "Saved changes:" let n = 1 for date in l:savedDatesList if l:date == "" | continue | endif echo " ".l:n.") ".l:date let l:n += 1 endfor endfunction " Save current changes. " Commands: Svncsv function! svnTools#changes#Save() echo "Getting changed files at ".getcwd()."..." "let l:list = svnTools#status#GetStatusFilesList(getcwd(), '^[MAD] ') let l:list = svnTools#status#GetStatusFilesList(getcwd(), '^M \|^A \|^D ') if len(l:list) == 0 call svnTools#tools#Warn("No changes found") return endif redraw let l:dir = "_svnTools_changes_" . strftime("%y%m%d_%H%M%S") echo "Save changes as: ". l:dir if system("mkdir ".l:dir) != 0 call svnTools#tools#Warn("Mkdir error for: ".l:dir) endif echo "Modified Files:" let n = 0 for file in l:list echo "- ".l:file let l:file = substitute(l:file, getcwd()."/", "", "") let l:newfile = substitute(l:file, "/", "___", "g") if system("cp ".l:file." ".l:dir."/".l:newfile) != 0 call svnTools#tools#Warn("Copy error on: ".l:file." to ".l:newfile) endif "echo "cp ".l:file." ".l:dir."/".l:newfile endfor call input("(press key)") endfunction " View the saved changes, compare choosen date them with current changes using vimdiff. " Commands: Svncvd function! svnTools#changes#VimdiffCurrentAndSaved() let l:changeDate = s:ChooseSavedDate(0) if l:changeDate == "" | return | endif echo "Getting changed files at ".getcwd()."..." "let l:changedFilesList = svnTools#status#GetStatusFilesList(getcwd(), '^[MAD] ') let l:changedFilesList = svnTools#status#GetStatusFilesList(getcwd(), '^M \|^A \|^D ') redraw let l:modifiable = 1 let l:NOmodifiable = 0 if len(l:changedFilesList) == 0 call svnTools#tools#Warn("No changes found") let l:savedFilesList = s:GetSavedChangesFilesList(changeDate) if len(l:savedFilesList) == 0 call svnTools#tools#Warn("No file changes found for saved date: ".l:changeDate) else for savedFile in l:savedFilesList let l:savedFile = fnamemodify(l:savedFile, ":t") let l:originalFile = substitute(l:savedFile, "___", "/", "g") echo "Vimdiff>> saved:".l:savedFile." and original:".l:originalFile call svnTools#diffTools#VimDiffFilePaths_setModifiable(l:savedFile, l:originalFile, l:NOmodifiable, l:modifiable) endfor endif else for changedFile in l:changedFilesList let l:savedFile = substitute(l:changedFile, getcwd()."/", "", "g") let l:savedFile = substitute(l:savedFile, "/", "___", "g") let l:savedFilePath = "_svnTools_changes_".l:changeDate."/".l:savedFile echo "Vimdiff saved: [".l:savedFilePath."] and changed: [".l:changedFile."]" call svnTools#diffTools#VimDiffFilePaths_setModifiable(l:savedFilePath, l:changedFile, l:NOmodifiable, l:modifiable) endfor endif endfunction " View the saved changes, compare using vimdiff a pair of chosen dates. " Commands: Svncvdd function! svnTools#changes#VimdiffSaved() let l:datesList = [] let l:date = s:ChooseSavedDate(1) while l:date != "" let l:datesList += [ l:date ] echo "(Press enter to stop selecting dates)" echo " " let l:date = s:ChooseSavedDate(1) endwhile if len(l:datesList) == 0 call svnTools#tools#Warn("No date selected") endif if len(l:datesList) < 2 call svnTools#tools#Warn("Two dates needed.") endif let l:filesList = s:GetSavedChangesListFilesList(l:datesList) if len(l:filesList) == 0 call svnTools#tools#Warn("No file changes found") endif let l:pathsList = [] for date in l:datesList let l:pathsList += [ "_svnTools_changes_".l:date."/" ] endfor redraw let l:setNoModifiable = 1 call svnTools#diffTools#VimDiffFilePathsList(l:pathsList, l:filesList, l:setNoModifiable) endfunction " Restore previous changes saved with Svnsv " Commands: Svncr function! svnTools#changes#Restore() let l:changeDate = s:ChooseSavedDate(0) if l:changeDate == "" | return | endif let l:savedFilesList = s:GetSavedChangesFilesList(changeDate) if len(l:savedFilesList) == 0 call svnTools#tools#Warn("No file changes found for saved date: ".l:changeDate) return endif call svnTools#tools#Warn("ATTENTION: you are about to replace current files with saved ones") if confirm("Restore ".l:changeDate." changes?", "&yes\n&no", 2) != 1 return endif for savedFile in l:savedFilesList if l:savedFile == "" | continue | endif let l:savedFile = fnamemodify(l:savedFile, ":t") let l:originalFile = substitute(l:savedFile, "___", "/", "g") let l:savedFilePath = "_svnTools_changes_".l:changeDate."/".l:savedFile echo "Restored [".l:savedFilePath."] to [".l:originalFile."]" if system("cp ".l:savedFilePath." ".l:originalFile) != 0 call svnTools#tools#Warn("Copy error on: ".l:savedFile." to ".l:originalFile) endif endfor call input("(press key)") endfunction " Return: date where the changes where saved. function! s:ChooseSavedDate(flagAll) let l:savedDatesList = s:GetSavedChangesDatesList() if len(l:savedDatesList) == 0 call svnTools#tools#Warn("No saved changes found") return "" endif echo "Saved changes:" let n = 1 for date in l:savedDatesList if l:date == "" | continue | endif echo " ".l:n.") ".l:date let l:n += 1 endfor "if flagAll != "" "echo l:n.") all" "endif let l:selection = input(" Select date: ") if l:selection == "" return "" endif let l:selection -= 1 echo " " echo " " let l:changeDate = l:savedDatesList[l:selection] return l:changeDate endfunction " Return: list with all changes' dates. function! s:GetSavedChangesDatesList() let l:list = [] let text = system("ls -d _svnTools_changes*") if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd silent exec "silent! %s/_svnTools_changes_//g" if line('$') == 1 && getline(".") == "" " Empty file else silent normal gg0VG$"zy let l:files = @z let l:list = split(l:files, "\n") endif quit return l:list endfunction " Return: list with all files on the selected changes directory function! s:GetSavedChangesFilesList(changeDate) let l:list = [] let text = system("ls -d _svnTools_changes_".a:changeDate."/*") if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd silent exec "silent! %s#_svnTools_changes_".a:changeDate."/##g" if line('$') == 1 && getline(".") == "" " Empty file else silent normal gg0VG$"zy let l:files = @z let l:list = split(l:files, "\n") endif quit return l:list endfunction " Return: list with all files on the selected changes dates function! s:GetSavedChangesListFilesList(changeDateList) let l:list = [] let l:cmd = "ls " for date in a:changeDateList let cmd .= "_svnTools_changes_".l:date."/* " endfor "echo "cmd: ".l:cmd let text = system(l:cmd) if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd for date in a:changeDateList silent exec "silent! %s#_svnTools_changes_".l:date."/##g" endfor silent! %sort u if line('$') == 1 && getline(".") == "" " Empty file else silent normal gg0VG$"zy let l:files = @z let l:list = split(l:files, "\n") endif quit return l:list endfunction autoload/svnTools/conflict.vim [[[1 509 " Script Name: svnTools/conflict.vim "Description: " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Merge window layout 2. " Window layout 2: " -------------------------- " | | | " | Current | Right | " | | | " -------------------------- function! MergeLayout2(list) let fileNum = len(a:list) if l:fileNum < 4 call svnTools#tools#Error("Merge file list not compleat. Only ". l:fileNum ." files provided.") return endif let fileCenter = a:list[1] let fileRight = a:list[3] tabnew let n = 0 if !empty(glob(l:fileCenter)) silent exec("edit ". l:fileCenter) if line('$') == 1 && getline(".") == "" quit else if expand('%') == l:fileCenter let n += 1 else call svnTools#tools#Warn("missing file: ". l:fileCenter) quit endif endif else call svnTools#tools#Warn("missing file: ". l:fileCenter) endif if !empty(glob(l:fileRight)) if l:n != 0 silent exec("vert new") endif silent exec("edit ". l:fileRight) if line('$') == 1 && getline(".") == "" quit else if expand('%') != l:fileRight call svnTools#tools#Warn("missing file: ". l:fileRight) quit else let n += 1 endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileRight) endif if l:n == 0 silent! tabclose elseif l:n > 1 silent exec("windo diffthis") endif endfunction " Merge window layout 3. " Window layout 3: " -------------------------- " | | | | " | Left | Current | Right | " | | | | " -------------------------- function! MergeLayout3(list) let fileNum = len(a:list) if l:fileNum < 4 call svnTools#tools#Error("Merge file list not compleat. Only ". l:fileNum ." files provided.") return endif let fileCenter = a:list[1] let fileLeft = a:list[2] let fileRight = a:list[3] tabnew let n = 0 if !empty(glob(l:fileLeft)) silent exec("edit ". l:fileLeft) if line('$') == 1 && getline(".") == "" quit else if expand('%') != l:fileLeft call svnTools#tools#Warn("missing file: ". l:fileLeft) quit else let n += 1 endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileLeft) endif if !empty(glob(l:fileCenter)) if l:n != 0 silent exec("vert new") endif silent exec("edit ". l:fileCenter) if line('$') == 1 && getline(".") == "" quit else if expand('%') == l:fileCenter let n += 1 else call svnTools#tools#Warn("missing file: ". l:fileCenter) quit endif endif else call svnTools#tools#Warn("missing file: ". l:fileCenter) endif if !empty(glob(l:fileRight)) if l:n != 0 silent exec("vert new") endif silent exec("edit ". l:fileRight) if line('$') == 1 && getline(".") == "" quit else if expand('%') != l:fileRight call svnTools#tools#Warn("missing file: ". l:fileRight) quit else let n += 1 endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileRight) endif if l:n == 0 silent! tabclose elseif l:n > 1 silent exec("windo diffthis") endif endfunction " Merge window layout 4. " Window layout 4: " -------------------------- " | | | | " | Left | Working | Right | " | | | | " -------------------------- " | Current | " -------------------------- function! MergeLayout4(list) let fileNum = len(a:list) if l:fileNum < 4 call svnTools#tools#Error("Merge file list not compleat. Only ". l:fileNum ." files provided.") return endif let fileDown = a:list[0] let fileCenter = a:list[1] let fileLeft = a:list[2] let fileRight = a:list[3] "echom "MergeLayout4: ".a:list[0]. " ".a:list[1]. " ".a:list[2]. " ".a:list[3] tabnew let n = 0 if !empty(glob(l:fileLeft)) silent exec("edit ". l:fileLeft) if line('$') == 1 && getline(".") == "" quit else let fileName = fnamemodify(l:fileLeft, ':t') if expand('%:t') == l:fileName let n += 1 else call svnTools#tools#Warn("Missing file (left): ". l:fileLeft.", found: ".expand('%')) quit endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileLeft) endif if !empty(glob(l:fileCenter)) if l:n != 0 silent exec("vert new") endif silent exec("edit ". l:fileCenter) if line('$') == 1 && getline(".") == "" quit else let fileName = fnamemodify(l:fileCenter, ':t') if expand('%:t') == l:fileName let n += 1 else call svnTools#tools#Warn("Missing file (center): ". l:fileCenter.", found: ".expand('%')) quit endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileCenter) endif if !empty(glob(l:fileRight)) if l:n != 0 silent exec("vert new") endif silent exec("edit ". l:fileRight) if line('$') == 1 && getline(".") == "" quit else let fileName = fnamemodify(l:fileRight, ':t') if expand('%:t') == l:fileName let n += 1 else call svnTools#tools#Warn("Missing file (right): ". l:fileRight.", found: ".expand('%')) quit endif endif else call svnTools#tools#Warn("Missing or empty file: ". l:fileRight) endif if l:n == 0 silent! tabclose elseif l:n > 1 silent exec("windo diffthis") endif if !empty(glob(l:fileDown)) if l:n != 0 silent exec("new") silent wincmd J silent resize 20 endif silent exec("edit ". l:fileDown) let fileName = fnamemodify(l:fileDown, ':t') if expand('%:t') == l:fileName let n += 1 else call svnTools#tools#Warn("Missing file (down): ".l:fileName.", found: ".expand('%:t')) quit endif else call svnTools#tools#Warn("Missing or empty file (down): ".l:fileDown) endif if l:n == 0 silent! tabclose endif endfunction " Reorder the files related to the merge in the order to be displayed on " screen. " Arg1: list with files related to the merge (file.mine, file.working, " file.rxxxxx, file.left, file.right). " Return: list with the files ordered, first the one to display on the left, " center, right and down. function! s:MergeFilesArrange(list) let l:list = ["", "", "", ""] let revFlag = 0 for file in sort(a:list) call svnTools#tools#LogLevel(2, expand(''), "Check file: ". l:file) if l:file =~ ".working" let l:list[1] = l:file call svnTools#tools#LogLevel(2, expand(''), "working") elseif l:file =~ ".mine" let l:list[1] = l:file call svnTools#tools#LogLevel(2, expand(''), "mine") elseif l:file =~ ".merge.left.r[0-9]" let l:list[2] = l:file call svnTools#tools#LogLevel(2, expand(''), ".merge.left.r") elseif l:file =~ ".merge.right.r[0-9]" let l:list[3] = l:file call svnTools#tools#LogLevel(2, expand(''), ".merge.right.r") elseif l:file =~ "left.r[0-9]" let l:list[2] = l:file call svnTools#tools#LogLevel(2, expand(''), "left.r") elseif l:file =~ "right.r[0-9]" let l:list[3] = l:file call svnTools#tools#LogLevel(0, expand(''), "right.r") elseif l:file =~ ".r[0-9]" if l:revFlag == 1 let l:list[3] = l:file call svnTools#tools#LogLevel(2, expand(''), ".r second") else let l:list[2] = l:file call svnTools#tools#LogLevel(2, expand(''), ".r first") endif let revFlag = 1 else let l:list[0] = l:file call svnTools#tools#LogLevel(0, expand(''), "original") endif endfor call svnTools#tools#LogLevel(1, expand(''), "Original: ". l:list[0]) call svnTools#tools#LogLevel(1, expand(''), "Center: ". l:list[1]) call svnTools#tools#LogLevel(1, expand(''), "Left: ". l:list[2]) call svnTools#tools#LogLevelStop(1, expand(''), "Right: ". l:list[3]) return l:list endfunction " 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. " Arg2: [optional] window layout configuration. " Commands: Svnm, Svnmf, Svnmd. function! svnTools#conflict#Merge(path, layout) let l:mergeLayout = g:svnTools_mergeLayout if a:layout != "" if a:layout =~ g:svnTools_mergeLayouts let l:mergeLayout = a:layout else call svnTools#tools#Error("Selected layout ". a:layout ." not found on layout list: ". g:svnTools_mergeLayouts) return endif endif echo "Search files with conflicts. In progress..." let list = svnTools#status#GetStatusFilesList(a:path, "^[C!]") let list += svnTools#status#GetStatusFilesList(a:path, " C ") let len = len(l:list) if len(l:list) == 0 call svnTools#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?") redraw for file in l:list if !filereadable(l:file) call svnTools#tools#Warn("File not found: ".l:file) else echo "Open ".l:file." on merge tool. Files: " let list1 = svnTools#status#GetStatusFilesList(l:file."*", "^[C!?]") let list1 += svnTools#status#GetStatusFilesList(l:file."*", " C ") let l:listArranged = s:MergeFilesArrange(l:list1) if len(l:listArranged) <= 0 call svnTools#tools#Warn("File not found: ".l:file) endif for file2 in l:listArranged | echo " ".l:file2 | endfor | echo "" exec "call MergeLayout". l:mergeLayout ."(l:listArranged)" endif endfor endfunction " Ask user how to resolve the conflict. " Return: user selected option. function! s:UserDialogResolve() while 1 let l:opt = confirm("Resolve, accept: ", "&base\n&working\n&mine\n&theirs\n&help\n&cancel", 10) if l:opt == 1 return "--accept base" elseif l:opt == 2 return = "--accept working" elseif l:opt == 3 return "--accept theirs-full" elseif l:opt == 4 return "--accept theirs-full" elseif l:opt == 5 echo "" echo "base:" echo " Choose the file that was the BASE revision before you updated your working copy. That is, the file that you checked out before you made your latest edits." echo "working:" echo " Assuming that you've manually handled the conflict resolution, choose the version of the file as it currently stands in your working copy." echo "mine-full:" echo " Resolve all conflicted files with copies of the files as they stood immediately before you ran svn update." echo "theirs-full:" echo " Resolve all conflicted files with copies of the files that were fetched from the server when you ran svn update." echo "" else return "" endif endwhile endfunction " Resolve the conflicts " Commands: Svnres, Svnresf, Svnresd " Arg1: path. " Arg2: [optional] use 'all' to resolve all conflicts. File path to resolve " single file in conflict. function! svnTools#conflict#Resolve(path, option) "let l:file = "" if a:option != "all" && a:option != "" call svnTools#tools#Error("Unknown option ". a:option) endif " Perform svn st and extract all files in conflict echo "Search files with conflicts. In progress..." let list = svnTools#status#GetStatusFilesList(a:path, "^[C!]") "let list = svnTools#status#GetStatusFilesList(a:path, "^C\|^!") let list += svnTools#status#GetStatusFilesList(a:path, " C ") if len(l:list) == 0 call svnTools#tools#Warn("No conflicts found ". a:path) return endif redraw echo "Files in conflict:" "echo l:text for file in l:list echo "C ". l:file endfor call confirm("Open resolve tool?") redraw let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() if a:option == "all" if confirm("ATTENTION! This will resolve all conflicts?", "&yes\n&no", 2) == 2 return endif redraw echo "Resolve all conflicts" let l:cmd = s:UserDialogResolve() if l:cmd == "" | return | endif "echo "base" "echo " Choose the file that was the BASE revision before you updated your working copy. That is, the file that you checked out before you made your latest edits." "echo "working "echo " Assuming that you've manually handled the conflict resolution, choose the version of the file as it currently stands in your working copy." "echo "mine-full" "echo " Resolve all conflicted files with copies of the files as they stood immediately before you ran svn update." "echo "theirs-full" "echo " Resolve all conflicted files with copies of the files that were fetched from the server when you ran svn update." "let l:opt = confirm("Resolve ", "&base\n&working\n&mine\n&theirs\n&cancel", 10) "if l:opt == 1 "let l:cmd = "--accept base" "elseif l:opt == 2 "let l:cmd = "--accept working" "elseif l:opt == 3 "let l:cmd = "--accept theirs-full" "elseif l:opt == 4 "let l:cmd = "--accept theirs-full" "else "return "endif call system(l:svnCmd." resolve -R ". l:cmd) "call system("svn resolve -R ". l:cmd) else " Iterate on all files found with conflict. for file in l:list echo "File: ". l:file let l:cmd = s:UserDialogResolve() if l:cmd == "" | continue | endif "let l:opt = confirm("Resolve ", "&mine\n&theirs\n&cancel", 3) "if l:opt == 1 "let l:cmd = "--accept mine-full" "elseif l:opt == 2 "let l:cmd = "--accept theirs-full" "else "continue "endif call system(l:svnCmd." resolve ". l:cmd ." ". l:file) call system("svn resolve ". l:cmd ." ". l:file) echo "" endfor endif endfunction autoload/svnTools/diff.vim [[[1 166 " Script Name: svnTools/diff.vim "Description: " " Copyright: (C) 2017-2022 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim, svn. " " "- functions ------------------------------------------------------------------- " Svn diff file/path " Command: Svnd, Svndf, Svnda, Svndd, SvndA function! svnTools#diff#Diff(path) let path = svnTools#tools#PathToFile(a:path) let name = "_svnDiff_".l:path.".diff" let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let command = l:svnCmd." --non-interactive diff --diff-cmd=diff ".a:path "let command = g:svnTools_svnCmd." --non-interactive diff --diff-cmd=diff ".a:path let callback = ["svnTools#diff#SvnDiffEnd", l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(command,callback,1) redraw endfunction function! svnTools#diff#SvnDiffEnd(name,resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call svnTools#tools#Warn("Svn diff empty") endif call svnTools#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 svnTools#tools#WindowSplitEnd() endfunction " Svn 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: SvnD, SvnDA, SvnDD. function! svnTools#diff#DiffAdv(...) 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 svnTools#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: svnTools#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 svnTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if empty(glob(l:path)) call svnTools#tools#Error("Path not found ".l:path) return endif let name = "_svnDiff_".l:path.".diff" echo "" "---------------------------------------- " Get files modified on subversion: "---------------------------------------- echo "Getting modified files on ".l:path."..." let l:filesList = svnTools#status#GetStatusFilesList(l:path, '^[MAD] ') if len(l:filesList) == 0 call svnTools#tools#Warn("[svnTools.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 "[svnTools.vim] Filter files on: '".l:path let l:filesList = svnTools#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 svn diff for all files. "---------------------------------------- echo "Getting every file diff..." let l:svnCmd = g:svnTools_svnCmd let command = l:svnCmd." --non-interactive diff --diff-cmd=diff ".join(l:filesList) let callback = ["svnTools#diff#SvnDiffEnd", l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(command,callback,1) redraw echo "[svnTools.vim] Show svn changes on ".l:path." using diff. ".len(l:filesList)." files found." endfunction autoload/svnTools/diffFile.vim [[[1 332 " Script Name: svnTools/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! svnTools#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: SvnDiffVdr function! svnTools#diffFile#OpenVimDiffGetFilesAndRevisionsEveryIndexLine(...) if &filetype !=# 'diff' call svnTools#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 svnTools#tools#Error("Missing revision number") return endif let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') if l:rev2 == "" call svnTools#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 svnTools#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 = svnTools#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 svnTools#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: Svndvdr function! svnTools#diffFile#OpenVimDiffOnEachFileAndRevision() if expand("%") !~ "_r[1-9].*\.diff" echo "First launch commands: Svnr, to get the revision diff." call svnTools#tools#Warn("Current file is not an svn diff file!") call confirm("Go ahead with current file?") "return endif " Extract from log file, the revision number. let l:list = svnTools#log#SvnLogFileGetCommitNumberList() if len(l:list) != 1 call svnTools#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 = svnTools#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 svnTools#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: SvnDiffVdr function! svnTools#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 svnTools#vimdiff#File(l:file) else call svnTools#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: SvnDiffVdrf function! svnTools#diffFile#OpenVimDiffGetFileAndRevisionFromCurrentLine(...) if &filetype !=# 'diff' call svnTools#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 svnTools#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 svnTools#tools#Error("Missing revision number") return endif let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') if l:rev2 == "" call svnTools#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 svnTools#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 svnTools#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 svnTools#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 svnTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) setl nomodifiable endfunction autoload/svnTools/diffTools.vim [[[1 299 " 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! svnTools#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! svnTools#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 svnTools#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 svnTools#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 svnTools#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! svnTools#diffTools#VimDiffFilePaths(file1,file2) let l:isModifiable = 1 call svnTools#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! svnTools#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 svnTools#tools#Warn("File not found:".l:file1) silent exec("new ".l:file1) else silent exec("e ".l:file1) endif call svnTools#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 svnTools#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 svnTools#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! svnTools#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 svnTools#diffTools#VimDiffFilePaths(file1,file2) return "Open new tab tabnew " Open file1 if !filereadable(l:file1) call svnTools#tools#Warn("File not found:".l:file1) silent exec("new ".l:file1) else silent exec("e ".l:file1) endif call svnTools#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 svnTools#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 svnTools#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 svn revision and current one. " Arg1: rev0 to download from svn and compare, if empty use last revision. " Arg2: rev1 to download from svn and compare, if empty use current file on disk " Arg3: directory to save svn file into. function! svnTools#diffTools#VimDiffFileRev(file,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:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() echo "svn cat ".l:rev0.a:file silent exec("r !".l:svnCmd." cat ".l:rev0.a:file) "silent exec("r !svn cat ".l:rev0.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 svnTools#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") if !filereadable(l:tmp) let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() echo "svn cat ".l:rev1.a:file silent exec("r !.".l:svnCmd." cat ".l:rev1.a:file) "silent exec("r !svn cat ".l:rev1.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 svnTools#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 svnTools#tools#SetSyntax(l:ext) highlight DiffText cterm=BOLD ctermfg=Red ctermbg=DarkGrey endfunction autoload/svnTools/directory.vim [[[1 271 " Script Name: svnTools/directory.vim "Description: " " Copyright: (C) 2017-2022 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " "- functions ------------------------------------------------------------------- " Using svn 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 svn changes on path1. " C2: compare only with svn changes on path2. " Commands: Svndc, Svnvdc. function! svnTools#directory#CompareChanges(...) 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 svnTools#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: svnTools#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 svnTools#tools#Warn("Path1 and Path2 already set. Skipping path: ".l:arg) call confirm("Continue?") endif endif else call svnTools#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 svnTools#tools#Error("Path1 not found ".l:path1) return endif if l:path2 == "" || empty(glob(l:path2)) call svnTools#tools#Error("Path2 not found ".l:path2) return endif "---------------------------------------- " Get path1 and/or path2 svn changes "---------------------------------------- let l:tmpList = [] echo "Comparing changes between: '".l:path1."' and: '".l:path2."' " if l:path1Changes == "yes" && l:path2Changes == "no" echo " * Compare only changes on path1: ".l:path1 elseif l:path1Changes == "no" && l:path2Changes == "yes" echo " * Compare only changes on path2: ".l:path2 endif if l:path1Changes != "yes" && l:path2Changes != "yes" call svnTools#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 svn for path1 let l:st1 = svnTools#status#GetStatusFilesString(l:path1, '^M\|^A\|^D') 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 svnTools#tools#LogLevel(1, expand(''), "Dir1: ".l:path1) call svnTools#tools#LogLevel(2, expand(''), "Files: ".l:st1) call svnTools#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 if l:path2Changes == "yes" echo " " echo "Searching files modified on: ".l:path2 echo "This may take a while ..." " Get files changed on svn for path2 let l:st2 = svnTools#status#GetStatusFilesString(l:path2, '^M\|^A\|^D') 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 svnTools#tools#LogLevel(1, expand(''), "Dir2: ".l:path2) call svnTools#tools#LogLevel(2, expand(''), "Files: ".l:st2) call svnTools#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 echo " " if len(l:tmpList) == 0 echo "" call svnTools#tools#Warn("[svnTools.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 svnTools#tools#LogLevel(2, expand(''), "Files sorted: ".join(l:sortedList)) call svnTools#tools#LogLevel(2, expand(''), "") " Uniq files let l:filesList = filter(copy(l:sortedList), 'index(l:sortedList, v:val, v:key+1)==-1') call svnTools#tools#LogLevel(2, expand(''), "Files uniq: ".join(l:filesList)) call svnTools#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 "[svnTools.vim] Comparing changes between: '".l:path1."' and: '".l:path2."' " let l:filesList = svnTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path1, l:path2) if len(l:filesList) == 0 echo "" call svnTools#tools#Warn("[svnTools.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 svnTools#diffTools#VimDiffFiles(l:file, l:path2, l:path1) else echo "Diff ".l:n.": ".l:file let l:diffText .= svnTools#diffTools#DiffFiles(l:file, l:path2, l:path1) endif endfor if l:mode == "diff" call svnTools#tools#WindowSplitMenu(3) call svnTools#tools#WindowSplit() let @a = l:diffText silent put! a normal gg0 silent exec("0file") silent! exec("file _dirDiff.diff") set ft=diff endif call svnTools#tools#WindowSplitEnd() redraw echo " " echo "[svnTools.vim] Compare svn changes between directories ".l:path1." and ".l:path2." with vimdiff. ".len(l:filesList)." files." endfunction autoload/svnTools/help.vim [[[1 303 " Script Name: svnTools/help.vim "Description: " " Copyright: (C) 2017-2022 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " "- Help functions ----------------------------------------------------------- function! svnTools#help#StatusHelp() let text = "[SvnTools.vim] help (v".g:svnTools_version."):\n" let text .= "\n" let text .= "Svn status' symbols help:\n" let text .= "\n" let text .= "- First column: Says if item was added, deleted, or otherwise changed\n" let text .= " ' ' no modifications\n" let text .= " 'A' Added\n" let text .= " 'C' Conflicted\n" let text .= " 'D' Deleted\n" let text .= " 'I' Ignored\n" let text .= " 'M' Modified\n" let text .= " 'R' Replaced\n" let text .= " 'X' an unversioned directory created by an externals definition\n" let text .= " '?' item is not under version control\n" let text .= " '!' item is missing (removed by non-svn command) or incomplete\n" let text .= " '~' versioned item obstructed by some item of a different kind\n" let text .= "\n" let text .= "- Second column: Modifications of a file's or directory's properties\n" let text .= " ' ' no modifications\n" let text .= " 'C' Conflicted\n" let text .= " 'M' Modified\n" let text .= "\n" let text .= "- Third column: Whether the working copy directory is locked\n" let text .= " ' ' not locked\n" let text .= " 'L' locked\n" let text .= "\n" let text .= "- Fourth column: Scheduled commit will contain addition-with-history\n" let text .= " ' ' no history scheduled with commit\n" let text .= " '+' history scheduled with commit\n" let text .= "\n" let text .= " Fifth column: Whether the item is switched or a file external\n" let text .= " ' ' normal\n" let text .= " 'S' the item has a Switched URL relative to the parent\n" let text .= " 'X' a versioned file created by an eXternals definition\n" let text .= "\n" let text .= "- Sixth column: Repository lock token\n" let text .= " (without -u)\n" let text .= " ' ' no lock token\n" let text .= " 'K' lock token present\n" let text .= " (with -u)\n" let text .= " ' ' not locked in repository, no lock token\n" let text .= " 'K' locked in repository, lock toKen present\n" let text .= " 'O' locked in repository, lock token in some Other working copy\n" let text .= " 'T' locked in repository, lock token present but sTolen\n" let text .= " 'B' not locked in repository, lock token present but Broken\n" let text .= "\n" let text .= "- Seventh column: Whether the item is the victim of a tree conflict\n" let text .= " ' ' normal\n" let text .= " 'C' tree-Conflicted\n" call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#WindowSplit() call svnTools#tools#WindowSplitEnd() setl nowrap set buflisted set bufhidden=delete set buftype=nofile setl noswapfile silent put = l:text silent! exec '0file | file svnTools_plugin_svn_status_help' normal ggdd endfunction function! svnTools#help#MergeLayoutHelp() let text = "[SvnTools.vim] help (v".g:svnTools_version."):\n" let text .= "\n" let text .= "Svn merge's layout help:\n" let text .= "\n" let text .= "Layout 2:\n" let text .= "--------------------------\n" let text .= "| | |\n" let text .= "| Current | Right |\n" let text .= "| | |\n" let text .= "--------------------------\n" let text .= "\n" let text .= "Layout 3:\n" let text .= "--------------------------\n" let text .= "| | | |\n" let text .= "| Left | Current | Right |\n" let text .= "| | | |\n" let text .= "--------------------------\n" let text .= "\n" let text .= "Layout 4:\n" let text .= "--------------------------\n" let text .= "| | | |\n" let text .= "| Left | Working | Right |\n" let text .= "| | | |\n" let text .= "--------------------------\n" let text .= "| Current |\n" let text .= "--------------------------\n" let text .= "\n" let text .= "Default layout: ".g:svnTools_mergeLayout."\n" let text .= "\n" call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#WindowSplit() call svnTools#tools#WindowSplitEnd() setl nowrap set buflisted set bufhidden=delete set buftype=nofile setl noswapfile silent put = l:text silent! exec '0file | file svnTools_plugin_svn_merge_layout_help' normal ggdd endfunction function! svnTools#help#Help() if g:svnTools_runInBackground == 1 let l:job = "foreground" else let l:job = "background" endif let l:text = "[svnTools.vim] help (v".g:svnTools_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 .= " :Svni : get current revision info.\n" let l:text .= " :Svnif : get current file revision info.\n" let l:text .= "\n" let l:text .= "- Blame:\n" let l:text .= " :Svnbl : get blame of current file.\n" let l:text .= " :Svnblv : get verbose blame of current file.\n" let l:text .= "\n" let l:text .= "- Status:\n" let l:text .= " :Svnst : show file's status (conceal symbols: X and ?).\n" let l:text .= " :Svnsta : show status files (show all symbols).\n" let l:text .= " :Svnstf : show current file status.\n" let l:text .= " :Svnstd : show current directory status.\n" let l:text .= " :Svnsth : show the svn status symbols' help.\n" let l:text .= "\n" let l:text .= "- Log:\n" let l:text .= " :Svnl [NUM] : get subversion log (num. commits, defaults to ".g:svnTools_lastCommits.").\n" let l:text .= " :Svnls PATTERN [NUM] : log search pattern (num. commits, defaults to ".g:svnTools_lastCommits.").\n" let l:text .= " :Svnlf FILEPATH : show file log.\n" let l:text .= " :Svnlr [NUM] : when placed on a svn 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 .= " :Svnd PATH : get diff of changes on the selected path.\n" let l:text .= " :Svndf : get diff of changes on current file.\n" let l:text .= " :Svndd : get diff of changes on current file's directory.\n" let l:text .= " :Svnda : get diff of (all) changes on current workind directory.\n" let l:text .= " Advanced: allows to filter files and binaries.\n" let l:text .= " :SvnD PATH [FLAGS] : get diff of changes on selected path.\n" let l:text .= " :SvnDD [FLAGS] : get diff of changes on current file's directory.\n" let l:text .= " :SvnDA [FLAGS] : get diff of (all) changes on workind directory.\n" let l:text .= " Svndvdr : when placed on a svn log and diff file (after Svnr/Svndd/Svndf/Svnda)\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 .= " :Svnvdf : get vimdiff of current file changes.\n" let l:text .= " :Svnvd PATH : get vimdiff of (all) changes on working dir.\n" let l:text .= " :Svnvdd : get vimdiff of current file's directory changes.\n" let l:text .= " :Svnvda : 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 .= " :SvnvD PATH [FLAGS] : get vimdiff of the files with changes on the selected path.\n" let l:text .= " :SvnvDD [FLAGS] : get vimdiff of the files with changes on current file's directory.\n" let l:text .= " :SvnvDA [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 .= " Svnvdr 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 .= " :Svndc [PATH1] PATH2 [FLAG] : get diff on all changes.\n" let l:text .= " :Svnvdc [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 svn changes on path1.\n" let l:text .= " C2: check only svn changes on path2.\n" let l:text .= "\n" let l:text .= "- Revision:\n" let l:text .= " :Svnr REV : get diff of selected revision number.\n" let l:text .= " :Svncr REV : cat revision number\n" let l:text .= "\n" let l:text .= "- Conflicts:\n" let l:text .= " :Svnm [LAYOUT] : merge all conflicts with vimdiff. Layouts: ".g:svnTools_mergeLayouts." (default layout: ".g:svnTools_mergeLayout.").\n" let l:text .= " :Svnmf [LAYOUT] : merge current file conflict with vimdiff. Layouts: ".g:svnTools_mergeLayouts." (default layout: ".g:svnTools_mergeLayout.").\n" let l:text .= " :Svnmp PATH [LAYOUT] : merge selected path conflicts with vimdiff. Layouts: ".g:svnTools_mergeLayouts." (default layout: ".g:svnTools_mergeLayout.").\n" let l:text .= " :Svnres [all] : perform svn resolve. Use 'all' to resolve all conflicts.\n" let l:text .= " :Svnmh : show merge layout help.\n" let l:text .= "\n" let l:text .= "- Changes on disk (save/restore/show):\n" let l:text .= " :Svnc : show saved changes.\n" let l:text .= " :Svncsv : save current changes.\n" let l:text .= " :Svncvd : perform vimdiff between saved changes and current changes.\n" let l:text .= " :Svncvdd : perform vimdiff between saved changes.\n" let l:text .= " :Svncr : restore saved changes.\n" let l:text .= "\n" let l:text .= "- Compare same files on different base directories:\n" let l:text .= " :Vdf [PATH1] PATH2 : compare (vimdiff) current file with same one on path2.\n" let l:text .= " :Vdd [PATH1] PATH2 [FLAGS] : compare (vimdiff) files between directories. Perform vertical diff.\n" let l:text .= " FLAGS:\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: compare only with svn changes on path1.\n" let l:text .= " C2: compare only with svn changes on path2. \n" let l:text .= " +pattern (keep only files with pattern).\n" let l:text .= " -pattern (skip all files with pattern).\n" let l:text .= "\n" let l:text .= "- Password:\n" let l:text .= " :Svnpwd : set svn user and password.\n" let l:text .= " Custom .vimrc config:\n" let l:text .= " let g:svnTools_userAndPsswd = 1\n" let l:text .= " let g:svnTools_svnUser = 'MY_USER'\n" let l:text .= "\n" let l:text .= "- Tools:\n" let l:text .= " :Svnbg : toogle svn 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 off all changes on selected path (show equal and binary files):\n" let l:text .= " :SvnD 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 .= " :SvnD project1/source +cpp\n" let l:text .= "\n" let l:text .= "- Get diff off all changes on all cpp files:\n" let l:text .= " :SvnDA +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 .= " :SvnDA +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 .= " :SvnvD project1/source +cpp\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 .= " :SvnVDA +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 .= " :Svnvdc /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 .= " :Svnvdc /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 .= " :Svnvdc /home/jp/sandbox2/ C1\n" let l:text .= "\n" let l:text .= "- Compare current file open with same file on different working directory:\n" let l:text .= " (split vertical)\n" let l:text .= " :Vdf /home/jp/sandbox2/\n" let l:text .= "\n" let l:text .= "- Compare current file open with same file on different working directory:\n" let l:text .= " (From current file path, replace sandbox1 with sandbox2, to open the file to diff.\n" let l:text .= " :Vdf 1 2\n" let l:text .= "\n" let l:text .= "- Compare files on different directories:\n" let l:text .= " :Vdd /home/jp/sandbox1/config/ /home/jp/sandbox2/config/\n" let l:text .= "\n" let l:text .= "- Compare only 'conf' files on different directories, skip 'xml' files:\n" let l:text .= " :Vdd /home/jp/sandbox1/config/ /home/jp/sandbox2/config/ +conf -xml\n" let l:text .= "\n" call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#WindowSplit() call svnTools#tools#WindowSplitEnd() setl nowrap set buflisted set bufhidden=delete set buftype=nofile setl noswapfile silent put = l:text silent! exec '0file | file svnTools_plugin_help' normal ggdd endfunction autoload/svnTools/info.vim [[[1 0 autoload/svnTools/log.vim [[[1 357 " Script Name: svnTools/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 svn log history for the selected path. " Arg1: path. " Arg2: [optional] options ex: -v, --verbose. " Commands: Svnlf function! svnTools#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:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let name = "_svnLog_". l:file .".log" let command = l:svnCmd." log ". l:options . l:filepath "let command = "svn log ". l:options . l:filepath "let command = "svn log ". l:filepath let callback = ["svnTools#log#SvnLogFileEnd", l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! svnTools#log#SvnLogFileEnd(name, resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call svnTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) put = readfile(a:resfile) silent exec("normal gg") call delete(a:resfile) normal gg call svnTools#tools#WindowSplitEnd() else call svnTools#tools#Warn("Svn log file search empty") endif endfunction " When placed on a svn log file, get each commit number. " Return: list containing all commit numbers. function! svnTools#log#SvnLogFileGetCommitNumberList() 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 svn log and svn 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:SvnLogFileGetRevisionDiff(rev, mode) let l:rev = substitute(a:rev, '[^0-9]*', '', 'g') let prev = l:rev - 1 let name = "_r".l:rev.".diff" let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let command = l:svnCmd." log -vr ".l:rev." --diff" "let command = "svn 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 svn log file open all revisions. " Commands: Svnlr. function! svnTools#log#GetRevDiff(num) if expand("%") !~ "_svnLog_.*\.log" echo "First launch one of following commands: Svnl, Svnls, Svnlf, Svnld or Svnlp, to get the revision log." call svnTools#tools#Error("Current file is not an svn log file!") return endif let l:filename = expand("%") " Get all revision numbers let l:list = svnTools#log#SvnLogFileGetCommitNumberList() if len(l:list) == 0 call svnTools#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, 'svnLog', 'svnLogRevDiff_'.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 svn log and svn 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:SvnLogFileGetRevisionDiff(l:rev, l:mode) let n+=1 if a:num != "" && l:n > l:max | break | endif endfor endfunction " Search the svn log for commit number " Svn log -v -g " Arg1: number of commits to search " Commands: SvnLog, Svnl. function! svnTools#log#GetRevision(commitNumb) let lastCommits = "" let numbCommits = "All" if a:commitNumb != "" let lastCommits = " -l ".a:commitNumb let numbCommits = a:commitNumb endif echo "Get log changes (include trunk, branches and tags). Commit numb:".l:numbCommits.")" let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() " Get URL, remove trunk word let l:url = system(l:svnCmd." info \| grep URL \| awk 'NR==1 {print $2}' \| sed 's/trunk//'") "let l:url = system("svn info \| grep URL \| awk 'NR==1 {print $2}' \| sed 's/trunk//'") " Get svn log from last x commits echo "svn log -v -g ".l:lastCommits." ".l:url echo "This may take a while ..." let l:name = "_svnSearch".l:numbCommits.".log" let command = l:svnCmd." log -v -g ".l:lastCommits." ".l:url "let command = "svn log -v -g ".l:lastCommits." ".l:url let callback = ["svnTools#log#GetRevisionEnd", l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! svnTools#log#GetRevisionEnd(name,resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call svnTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) put = readfile(a:resfile) silent exec("normal gg") call delete(a:resfile) normal gg call svnTools#tools#WindowSplitEnd() else call svnTools#tools#Warn("Svn log search empty") endif endfunction " Search the svn log for pattern " Svn log -v --search " Arg1: pattern to search. " Arg2: number of commits to search. " Commands: SvnLogSearch, Svnls. function! svnTools#log#SearchPattern(...) let lastCommits = g:svnTools_lastCommits if a:0 >= 2 let lastCommits = a:2 endif if a:0 < 1 let pattern = substitute(expand(""), 'r', '', '') if l:pattern == "" let l:pattern = expand('%:t') endif else let pattern = a:1 endif if l:pattern == "" call svnTools#tools#Warn("Argument 1: search pattern not found.") return endif echo "Search pattern: ".l:pattern." on last ".lastCommits." commits..." echo "svn log -v --search ".l:pattern." -l ".l:lastCommits let l:name = "_svnSearch".l:lastCommits."_".l:pattern.".log" let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let command = l:svnCmd." log -v --search ".l:pattern." -l ".l:lastCommits "let command = "svn log -v --search ".l:pattern." -l ".l:lastCommits let callback = ["svnTools#log#SvnLogSearchPatternEnd", l:name] call svnTools#tools#WindowSplitMenu(4) echo "This may take a while ..." call svnTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! svnTools#log#SvnLogSearchPatternEnd(name,resfile) if exists('a:resfile') && !empty(glob(a:resfile)) call svnTools#tools#WindowSplit() " Rename buffer silent! exec("0file") silent! exec("bd! ".a:name) silent! exec("file! ".a:name) put = readfile(a:resfile) silent exec("set syntax=diff") silent exec("normal gg") call delete(a:resfile) normal gg call svnTools#tools#WindowSplitEnd() else call svnTools#tools#Warn("Svn log search pattern empty") endif endfunction " Get log and diff from the selected revision. " Arg1: revision number to search. " Command: Svnr function! svnTools#log#GetLogAndDiff(rev) if a:rev == "" let l:rev = expand("") else let l:rev = a:rev endif let rev = substitute(l:rev, '[^0-9]*', '', 'g') if l:rev == "" call svnTools#tools#Error("Revision number not found.") return endif let prev = l:rev - 1 let name = "_r".l:rev.".diff" echo "Getting ".l:rev." log and diff" let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() "On Subversion versions after 1.7: let command = l:svnCmd." log -vr ".l:rev." --diff" "let command = "svn log -vr ".l:rev." --diff" let callback = ["svnTools#log#GetLogAndDiffEnd", l:name] call svnTools#tools#WindowSplitMenu(4) call svnTools#tools#SystemCmd0(l:command,l:callback,1) endfunction function! svnTools#log#GetLogAndDiffEnd(name,resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call svnTools#tools#Warn("Svn log and diff empty") return endif call svnTools#tools#WindowSplit() call svnTools#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) silent exec("set syntax=diff") silent exec("normal gg") call delete(a:resfile) call svnTools#tools#WindowSplitEnd() endfunction autoload/svnTools/misc.vim [[[1 315 " Script Name: svnTools/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: SvnD, SvnDA, SvnDD, SvnVD, SvnVDA, SvnVDD, Svndc, Svnvdc, Vdd. function! svnTools#misc#FilterFilesListWithArgsList(argsList, filesList, path1, path2) "echom "svnTools#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 svnTools#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: SvnD, SvnDA, SvnDD, SvnVD, SvnVDA, SvnVDD, Svndc, Svnvdc, Vdd. function! svnTools#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 svnTools#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/svnTools/status.vim [[[1 222 " Script Name: svnTools/status.vim "Description: save/restore/compare the file changes. " " Copyright: (C) 2017-2021 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: " " NOTES: " " Show on a new window the svn status lines matching the selected filter " pattern. " Arg1: filter keep pattern. " Keep only files in conflict: "^C ". " Keep only modified files: "^M ". " Keep only modified, added or deleted files: "^M \|^A \|^D ". " Arg2: 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 ". " Commands: Svnst, Svnsta, Svnstf, Svnstd. function! svnTools#status#GetStatus(path, filter, remove) let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let command = l:svnCmd." st ".a:path "let command = "svn st ".a:path let callback = ["svnTools#status#GetStatusEnd", a:path, a:filter, a:remove] call svnTools#tools#WindowSplitMenu(1) call svnTools#tools#SystemCmd0(l:command, l:callback, 1) endfunction function! svnTools#status#GetStatusEnd(path, filter, remove, resfile) if !exists('a:resfile') || empty(glob(a:resfile)) call svnTools#tools#Warn("Svn st ". a:path .". No modifications found.") return endif call svnTools#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 svnTools#tools#Warn("Svn st ". a:path .". No modifications found.") else call svnTools#tools#Warn("Svn st ". 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 silent exec("0file") silent! exec("file _svnSt.txt") " Add header on top normal ggO if a:filter == "" && a:remove == "" let text = "[svnTools.vim] svn st '".a:path."' (".l:lines0." results)" else let text = "[svnTools.vim] svn st '".a:path."' Filter: keep:'".l:filter0."', remove:'".a:remove."' (".l:lines0." results)" endif put=l:text normal ggdd " Resize window to fit content. call svnTools#tools#WindowSplitEnd() " Highlight lines in different colors. If hi.vim plugin available. if exists('g:HiLoaded') let g:HiCheckPatternAvailable = 0 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@") " Missing silent! call hi#config#PatternColorize("\\~ ", "v2@") " Obstructed by some item of different kind silent! call hi#config#PatternColorize("A ", "g*") " Added silent! call hi#config#PatternColorize("C ", "m*") " Conflicted silent! call hi#config#PatternColorize("D ", "o*") " Deleted silent! call hi#config#PatternColorize("I ", "n*") " Ignored silent! call hi#config#PatternColorize("M ", "b*") " Modified silent! call hi#config#PatternColorize("R ", "y*") " Replaced silent! call hi#config#PatternColorize("X ", "w7*-") " Unversioned directory silent! call hi#config#PatternColorize("? ", "w7*-") " Unversioned file let g:HiCheckPatternAvailable = 1 endif endfunction " Get files from svn status that match the selected filter pattern. " Arg1: 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! svnTools#status#GetStatusFilesList(path, filter) let l:list = [] let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let text = system(l:svnCmd." st ". a:path) "echom "Svn status: ".l:text if l:text == "" return l:list endif silent new normal ggO silent put=l:text normal ggdd if a:filter != "" "silent exec "g!/". a:filter ."/d" silent exec "v/". a:filter ."/d" endif silent exec "g/^$/d" if line('$') == 1 && getline(".") == "" " Empty file else " Get last column. File paths. silent normal gg0f/G$"zy let files = @z "echo "Files: ".l:i let list = split(l:files, "\n") if len(l:list) == 0 " Only one file. let list = [ l:files ] endif "echom "Svn status list: "l:list endif silent quit! return l:list endfunction " Get files from svn 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! svnTools#status#GetStatusFilesString(path, filter) let l:list = [] let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() "echom "GetStatusFilesString: ".l:svnCmd let text = system(l:svnCmd." st ". a:path) if l:text == "" return l:list 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 "normal VGww"z silent normal gg0WG$"zy let files = @z let l:res = substitute(l:files, "\n", " ", "g") if l:res =~ "not a working copy" call svnTools#tools#Error("Not a svn working copy") return [] endif endif silent exec("bd!") return l:res endfunction autoload/svnTools/svnTools.vim [[[1 197 " Script Name: svnTools.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, jpLib.vim(optional) " " NOTES: " "- functions ------------------------------------------------------------------- " Get the plugin reload command function! svnTools#svnTools#Reload() let l:pluginPath = substitute(s:plugin_path, "autoload/svnTools", "plugin", "") let s:initialized = 0 let l:cmd = "" let l:cmd .= "unlet g:loaded_svntools " let l:cmd .= " | so ".s:plugin_path."/blame.vim" let l:cmd .= " | so ".s:plugin_path."/cat.vim" let l:cmd .= " | so ".s:plugin_path."/changes.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."/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."/status.vim" let l:cmd .= " | so ".s:plugin_path."/svnTools.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."/svnTools.vim" let l:cmd .= " | let g:loaded_svntools = 1" return l:cmd endfunction " Edit plugin files " Cmd: Svnedit function! svnTools#svnTools#Edit() let l:plugin = substitute(s:plugin_path, "autoload/svnTools", "plugin", "") silent exec("tabnew ".s:plugin) silent exec("vnew ".l:plugin."/".s:plugin_name) endfunction function! s:Initialize() "call svnTools#tools#SetLogLevel(0) let s:jobsRunningDict = {} endfunction " Svn info " Command: SvnInfo, Svni function! svnTools#svnTools#Info(path) let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() let info = system(l:svnCmd." info ".a:path." \| egrep -i 'rev:|date' \| awk '{$1=$2=\"\";print}'") "let info = system("svn info ".a:path." \| egrep -i 'rev:|date' \| awk '{$1=$2=\"\";print}'") let list = split(l:info,"\n") "echo "".l:fileFullPath for file in l:list echo "".l:file endfor call input("") endfunction " Change background/foreground execution of the svn 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: Svnbg function! svnTools#svnTools#BackgroundMode(options) if a:options =~ "b" || a:options =~ "f" if a:options =~ "f" let g:svnTools_runInBackground = 0 else let g:svnTools_runInBackground = 1 endif elseif a:options == "" if g:svnTools_runInBackground == 1 let g:svnTools_runInBackground = 0 else let g:svnTools_runInBackground = 1 endif endif if g:svnTools_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! svnTools#svnTools#CreateMenus(modes, submenu, target, desc, cmd) " Build up a map command like let plug = a:target let plug_start = 'noremap ' . ' :call SvnTools("' let plug_end = '", "' . a:target . '")' " Build up a menu command like let menuRoot = get(['', 'SvnTools', '&SvnTools', "&Plugin.&SvnTools".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 svnTools#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 svnTools#tools#LogLevel(1, expand(''), "execute ". mode . plug_start . mode . plug_end) endif " Check if the user wants the menu to be displayed. if g:svnTools_mode != 0 call svnTools#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: Svnvba function! svnTools#svnTools#NewVimballRelease() let text = "" let l:text .= "plugin/svnTools.vim\n" let l:text .= "autoload/svnTools/blame.vim\n" let l:text .= "autoload/svnTools/cat.vim\n" let l:text .= "autoload/svnTools/changes.vim\n" let l:text .= "autoload/svnTools/conflict.vim\n" let l:text .= "autoload/svnTools/diff.vim\n" let l:text .= "autoload/svnTools/diffFile.vim\n" let l:text .= "autoload/svnTools/diffTools.vim\n" let l:text .= "autoload/svnTools/directory.vim\n" let l:text .= "autoload/svnTools/help.vim\n" let l:text .= "autoload/svnTools/info.vim\n" let l:text .= "autoload/svnTools/log.vim\n" let l:text .= "autoload/svnTools/misc.vim\n" let l:text .= "autoload/svnTools/status.vim\n" let l:text .= "autoload/svnTools/svnTools.vim\n" let l:text .= "autoload/svnTools/tools.vim\n" let l:text .= "autoload/svnTools/utils.vim\n" let l:text .= "autoload/svnTools/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:svnTools_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 svnTools#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/svnTools/tools.vim [[[1 257 " Script Name: svnTools.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, jpLib.vim(optional) " " NOTES: " "- functions ------------------------------------------------------------------- function! svnTools#tools#CheckSvnUserAndPsswd() if g:svnTools_userAndPsswd == 0 return endif " Get svn user: if g:svnTools_svnUser == "" let g:svnTools_svnUser = input("Svn user: ") endif if g:svnTools_svnUser == "" call svnTools#tools#Error("Not valid svn user.") return endif " Get svn password: let l:tmp = "" if exists("g:svnTools_tmp") if g:svnTools_tmp != "" let l:tmp = g:svnTools_tmp endif endif " Set svn password: if l:tmp == "" let l:tmp = inputsecret("Svn user: ".g:svnTools_svnUser.". Enter password: ") if g:svnTools_storeSvnPsswd == 1 echo "" echo "" echo "[svnTools.vim] Svn password set for current session." let g:svnTools_tmp = l:tmp endif endif if l:tmp == "" call svnTools#tools#Error("Not valid svn password.") return endif return " --non-interactive --no-auth-cache --username ".g:svnTools_svnUser." --password ".l:tmp endfunction " Set upser and password " Command: Svnpwd function! svnTools#tools#SetUserAndPsswd() if g:svnTools_svnUser != "" if confirm("Change svn user: ".g:svnTools_svnUser."?", "&yes\n&no", 2) == 1 let g:svnTools_svnUser = "" endif echo "" echo "" endif silent! unlet g:svnTools_tmp call svnTools#tools#CheckSvnUserAndPsswd() endfunction function! svnTools#tools#Error(mssg) echohl ErrorMsg | echom "[SvnTools] ".a:mssg | echohl None endfunction function! svnTools#tools#Warn(mssg) echohl WarningMsg | echom a:mssg | echohl None endfunction function! svnTools#tools#SetLogLevel(level) let s:LogLevel = a:level endfunction " Debug function. Log message function! svnTools#tools#LogLevel(level,func,mssg) if s:LogLevel >= a:level echom "[SvnTools : ".a:func."] ".a:mssg endif endfunction " Debug function. Log message and wait user key function! svnTools#tools#LogLevelStop(level,func,mssg) if s:LogLevel >= a:level call input("[SvnTools : ".a:func."] ".a:mssg." (press key)") endif endfunction func! svnTools#tools#Verbose(level) if a:level == "" call s:LogLevel(0, expand(''), "Verbose level: ".s:LogLevel) return endif let s:LogLevel = a:level call svnTools#tools#LogLevel(0, expand(''), "Set verbose level: ".s:LogLevel) endfun function! svnTools#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! svnTools#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! svnTools#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 svnTools#tools#LogLevel(1, expand(''), "Choosed split:".w:split) endfunction function! svnTools#tools#WindowSplit() if !exists('w:split') return endif let l:split = w:split let l:winSize = w:winSize call svnTools#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! svnTools#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! svnTools#tools#PathToFile(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! svnTools#tools#SystemCmd0(command,callback,async) if !exists("g:loaded_jobs") call svnTools#tools#Error("Plugin jobs.vim not loaded.") return endif let jobName = "svnTools" if g:svnTools_runInBackground == 0 || a:async == 0 let l:async = 0 else let l:async = 1 endif if g:svnTools_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! svnTools#tools#SystemCmd0(command,callbackList,async) if !exists("g:loaded_jobs") call svnTools#tools#Error("Plugin jobs.vim not loaded.") return endif let jobName = "svnTools" if g:svnTools_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:svnTools_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 "- initializations ------------------------------------------------------------ let s:LogLevel = 0 autoload/svnTools/utils.vim [[[1 196 " Script Name: svnTools/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! svnTools#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 "[SvnTools.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! svnTools#utils#VimdiffAll(...) if a:0 < 1 call svnTools#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 svnTools#tools#Warn("Path1 and Path2 already set. Skipping path: ".l:arg) call confirm("Continue?") endif endif else call svnTools#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 svnTools#tools#Error("Path2 not found ".l:path2) return endif if empty(glob(l:path1)) call svnTools#tools#Error("Path1 not found ".l:path1) return endif if l:path1 == l:path2 call svnTools#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 "[svnTools.vim] Diff files between: ".l:path1." and ".l:path2 let l:filesList = svnTools#misc#FilterFilesListWithArgsList(a:000, l:filesList, l:path1, l:path2) if len(l:filesList) == 0 echo "" call svnTools#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 "[svnTools.vim] Compare files on: ".l:path1." and ".l:path2." Differing files:".l:n endfunc autoload/svnTools/vimdiff.vim [[[1 551 " Script Name: svnTools/vimdiff.vim "Description: " " Copyright: (C) 2017-2022 Javier Puigdevall " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Javier Puigdevall " Contributors: " " Dependencies: jobs.vim " " "- functions ------------------------------------------------------------------- " Vimdiff single file. " Arg1: file to check, if empty use current file. " Commands: Svnvdf function! svnTools#vimdiff#File(file) "let l:list = svnTools#status#GetStatusFilesList(a:file, '^[MAD] ') let l:list = svnTools#status#GetStatusFilesList(a:file, '^M \|^A \|^D ') if len(l:list) == 0 call svnTools#tools#Warn("[svnTools.vim] No modifications found.") return endif echo "This may take a while ..." silent! call svnTools#diffTools#VimDiffFileRev(a:file,"","","") redraw endfunction " Simple Vimdiff on path " Arg1: file to check, if empty use current file. " Commands: Svnvd, Svnvda, Svnvdd, SvnvdA. function! svnTools#vimdiff#Path(path) echo "Getting modified files on ".a:path."..." let l:list = svnTools#status#GetStatusFilesList(a:path, '^[MAD] ') let l:n = len(l:list) if l:n == 0 call svnTools#tools#Warn("[svnTools.vim] No modifications found") return elseif l:n > 1 " 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 "" else " Only ONE file modified " Open vimdiff without asking user call svnTools#tools#WindowSplitMenu(3) call svnTools#tools#WindowSplit() echo "This may take a while ..." silent! call svnTools#diffTools#VimDiffFileRev(l:list[0],"","","") call svnTools#tools#WindowSplitEnd() return endif echo " " echo "Getting every file vimdiff..." echo "" " Perform svn 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 silent! call svnTools#diffTools#VimDiffFileRev(l:file,"","","") let l:n += 1 endfor redraw echo " " echo "[svnTools.vim] Show svn changes on ".a:path." using vimdiff. ".l:n." files." 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: SvnvD, SvnvDA, SvnvDD. function! svnTools#vimdiff#PathAdv(...) 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 svnTools#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: svnTools#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 svnTools#tools#Warn("Unknown argument: ".l:arg) call confirm("Continue?") endif endfor if empty(glob(l:path) ) call svnTools#tools#Error("Path not found ".l:path) return endif "---------------------------------------- " Get files modified on subversion: "---------------------------------------- echo "Getting modified files on ".l:path."..." let l:filesList = svnTools#status#GetStatusFilesList(l:path, '^[MAD] ') if len(l:filesList) == 0 call svnTools#tools#Warn("[svnTools.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 svnTools#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 "[svnTools.vim] Filter files on: '".l:path let l:filesList = svnTools#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. "---------------------------------------- echo "Getting every file vimdiff..." let l:n = 0 for l:file in l:filesList echo "- ".l:file." vimdiff" silent! call svnTools#diffTools#VimDiffFileRev(l:file,"","","") " Check if there are differences between both windows. "if foldclosed('.') != -1 && foldclosedend('.') != -1 "let l:filesEqual = 1 "else "let l:filesEqual = 0 "endif "if l:equals == "skip" && l:fileEqual == 1 "call svnTools#tools#Warn("Closing: ".expand("%").". No changes found.") "tabclose "endif "if l:equals == "only" && l:fileEqual == 0 "call svnTools#tools#Warn("Closing: ".expand("%").". Changes found.") "tabclose "endif let l:n += 1 endfor "redraw echo " " echom "[svnTools.vim] Show svn 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(rev,file) let l:confirm = "" if a:file == "" let l:file = expand('%') else let l:file = a:file endif if l:file == "" call svnTools#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 svnTools#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 svnTools#tools#WindowSplitMenu(3) call svnTools#tools#WindowSplit() call svnTools#diffTools#VimDiffFileRev(l:file,l:rev,"","") call svnTools#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(rev,file) let l:confirm = "" if a:file == "" let l:file = expand('%') else let l:file = a:file endif if l:file == "" call svnTools#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 svnTools#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 svnTools#tools#WindowSplitMenu(3) call svnTools#tools#WindowSplit() call svnTools#diffTools#VimDiffFileRev(l:file,l:rev,"","") call svnTools#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 svnTools#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 svnTools#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 svnTools#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 svnTools#diffTools#VimDiffFileRev(s:DiffFile,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 svnTools#tools#Warn("[svnTools.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 svnTools#diffTools#VimDiffFileRev(l:file,l:rev0,l:rev1,l:saveDir) 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: Svnvdr function! svnTools#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 svnTools#tools#Error("Missing revision number") return endif let rev2 = substitute(l:rev2, '[^0-9]*', '', 'g') if l:rev2 == "" call svnTools#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 svnTools#tools#Error("Wrong revision number ". l:rev1) return endif endif " Get diff file echo "Getting r". l:rev2 ." log and diff..." let l:svnCmd = g:svnTools_svnCmd let l:svnCmd .= svnTools#tools#CheckSvnUserAndPsswd() " On Subversion versions after 1.7: let command = l:svnCmd." log -vr ".l:rev2." --diff" "let command = "svn 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 = svnTools#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?") " 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 svnTools#diffTools#VimDiffFileRev(l:file, l:rev1, l:rev2, 0) 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 725 " 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) " 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 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