From 6716a22df194fdd6982c92feb55d11fe6c0ae0d6 Mon Sep 17 00:00:00 2001 From: alterdepp Date: Thu, 26 May 2011 14:07:42 +0000 Subject: [PATCH] + gundo git-svn-id: https://vimsuite.svn.sourceforge.net/svnroot/vimsuite/trunk@202 eb2d0018-73a3-4aeb-bfe9-1def61c9ec69 --- vimfiles/GetLatest/GetLatestVimScripts.dat | 1 + vimfiles/doc/gundo.txt | 243 ++++++ vimfiles/doc/tags | 105 +-- vimfiles/plugin/gundo.vim | 955 +++++++++++++++++++++ 4 files changed, 1217 insertions(+), 87 deletions(-) create mode 100644 vimfiles/doc/gundo.txt create mode 100644 vimfiles/plugin/gundo.vim diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat index 9270faa..804e2ba 100644 --- a/vimfiles/GetLatest/GetLatestVimScripts.dat +++ b/vimfiles/GetLatest/GetLatestVimScripts.dat @@ -33,3 +33,4 @@ ScriptID SourceID Filename 642 8136 :AutoInstall: getscript.vim 1075 15352 :AutoInstall: netrw.vim 1502 15362 :AutoInstall: vimball.vim +3304 15211 Gundo diff --git a/vimfiles/doc/gundo.txt b/vimfiles/doc/gundo.txt new file mode 100644 index 0000000..3ee2b48 --- /dev/null +++ b/vimfiles/doc/gundo.txt @@ -0,0 +1,243 @@ +*gundo.txt* Graph your undo tree so you can actually USE it. + +Making's Vim's undo tree usable by humans. + +============================================================================== +CONTENTS *Gundo-contents* + + 1. Intro .......................... |GundoIntro| + 2. Usage .......................... |GundoUsage| + 3. Configuration .................. |GundoConfig| + 3.1 gundo_width ............... |gundo_width| + 3.2 gundo_preview_height ...... |gundo_preview_height| + 3.3 gundo_preview_bottom ...... |gundo_preview_bottom| + 3.4 gundo_right ............... |gundo_right| + 3.5 gundo_help ................ |gundo_help| + 3.6 gundo_disable ............. |gundo_disable| + 3.7 gundo_map_move_older ...... |gundo_map_move_older| + gundo_map_move_newer ...... |gundo_map_move_newer| + 4. License ........................ |GundoLicense| + 5. Bugs ........................... |GundoBugs| + 6. Contributing ................... |GundoContributing| + 7. Changelog ...................... |GundoChangelog| + 8. Credits ........................ |GundoCredits| + +============================================================================== +1. Intro *GundoIntro* + +You know that Vim lets you undo changes like any text editor. What you might +not know is that it doesn't just keep a list of your changes -- it keeps +a goddamed |:undo-tree| of them. + +Say you make a change (call it X), undo that change, and then make another +change (call it Y). With most editors, change X is now gone forever. With Vim +you can get it back. + +The problem is that trying to do this in the real world is painful. Vim gives +you an |:undolist| command that shows you the leaves of the tree. Good luck +finding the change you want in that list. + +Gundo is a plugin to make browsing this ridiculously powerful undo tree less +painful. + +============================================================================== +2. Usage *GundoUsage* + +We'll get to the technical details later, but if you're a human the first +thing you need to do is add a mapping to your |:vimrc| to toggle the undo +graph: > + + nnoremap :GundoToggle + +Change the mapped key to suit your taste. We'll stick with F5 because that's +what the author uses. + +Now you can press F5 to toggle the undo graph and preview pane, which will +look something like this: > + + Undo graph File + +-----------------------------------+------------------------------------+ + | " Gundo for something.txt [1] |one | + | " j/k - move between undo states |two | + | " - revert to that state |three | + | |five | + | @ [5] 3 hours ago | | + | | | | + | | o [4] 4 hours ago | | + | | | | | + | o | [3] 4 hours ago | | + | | | | | + | o | [2] 4 hours ago | | + | |/ | | + | o [1] 4 hours ago | | + | | | | + | o [0] Original | | + +-----------------------------------+ | + | --- 3 2010-10-12 06:27:35 PM | | + | +++ 5 2010-10-12 07:38:37 PM | | + | @@ -1,3 +1,4 | | + | one | | + | two | | + | three | | + | +five | | + +-----------------------------------+------------------------------------+ + Preview pane + +Your current position in the undo tree is marked with an '@' character. Other +nodes are marked with an 'o' character. + +When you toggle open the graph Gundo will put your cursor on your current +position in the tree. You can move up and down the graph with the j and +k keys. + +You can move to the top of the graph (the newest state) with gg and to the +bottom of the graph (the oldest state) with G. + +As you move between undo states the preview pane will show you a unified diff +of the change that state made. + +Pressing enter on a state (or double clicking on it) will revert the contents +of the file to match that state. + +You can use p on a state to make the preview window show the diff between +your current state and the selected state, instead of a preview of what the +selected state changed. + +Pressing P while on a state will initiate "play to" mode targeted at that +state. This will replay all the changes between your current state and the +target, with a slight pause after each change. It's mostly useless, but can be +fun to watch and see where your editing lags -- that might be a good place to +define a new mapping to speed up your editing. + +Pressing q while in the undo graph will close it. You can also just press your +toggle mapping key. + +============================================================================== +3. Configuration *GundoConfig* + +You can tweak the behavior of Gundo by setting a few variables in your :vimrc +file. For example: > + + let g:gundo_width = 60 + let g:gundo_preview_height = 40 + let g:gundo_right = 1 + +------------------------------------------------------------------------------ +3.1 g:gundo_width *gundo_width* + +Set the horizontal width of the Gundo graph (and preview). + +Default: 45 + +------------------------------------------------------------------------------ +3.2 g:gundo_preview_height *gundo_preview_height* + +Set the vertical height of the Gundo preview. + +Default: 15 + +------------------------------------------------------------------------------ +3.3 g:gundo_preview_bottom *gundo_preview_bottom* + +Force the preview window below current windows instead of below the graph. +This gives the preview window more space to show the unified diff. + +Example: + + +--------+ +--------+ + !g! ! ! !g! + !g! ! or ! !g! + !g!______! !______!g! + !g!pppppp! !pppppp!g! + +--------+ +--------+ + +Default: 0 + +------------------------------------------------------------------------------ +3.4 g:gundo_right *gundo_right* + +Set this to 1 to make the Gundo graph (and preview) open on the right side +instead of the left. + +Default: 0 (off, open on the left side) + +------------------------------------------------------------------------------ +3.5 g:gundo_help *gundo_help* + +Set this to 0 to disable the help text in the Gundo graph window. + +Default: 1 (show the help) + +------------------------------------------------------------------------------ +3.6 g:gundo_disable *gundo_disable* + +Set this to 1 to disable Gundo entirely. + +Useful if you use the same ~/.vim folder on multiple machines, and some of +them may not have Python support. + +Default: 0 (Gundo is enabled as usual) + +------------------------------------------------------------------------------ +3.7 g:gundo_map_move_older, g:gundo_map_move_newer *gundo_map_move_older* + *gundo_map_move_newer* + +These options let you change the keys that navigate the undo graph. This is +useful if you use a Dvorak keyboard and have changed your movement keys. + +Default: gundo_map_move_older = "j" + gundo_map_move_newer = "k" + +============================================================================== +4. License *GundoLicense* + +GPLv2+. Look it up. + +============================================================================== +5. Bugs *GundoBugs* + +If you find a bug please post it on the issue tracker: +http://bitbucket.org/sjl/gundo.vim/issues?status=new&status=open + +============================================================================== +6. Contributing *GundoContributing* + +Think you can make this plugin better? Awesome. Fork it on BitBucket or GitHub +and send a pull request. + +BitBucket: http://bitbucket.org/sjl/gundo.vim/ +GitHub: http://github.com/sjl/gundo.vim/ + +============================================================================== +7. Changelog *GundoChangelog* + +v2.1.1 + * Fix a bug with the movement key mappings. +v2.1.0 + * Warnings about having an incompatible Vim and/or Python installation + are now deferred until the first time you try to use Gundo, instead + of being displayed on launch. + * The and mappings are now configurable with + g:gundo_map_move_older and g:gundo_map_move_newer. + * The o, and keys are now mapped in the Gundo pane. + * Improve and add several unit tests for Gundo. +v2.0.0 + * Make GundoToggle close the Gundo windows if they're visible but not the + current window, instead of moving to them. + * Add the g:gundo_help setting. + * Add the g:gundo_disable setting. + * Add the 'p' mapping to preview the result of reverting to the selected + state. + * Fix movement commands with counts in the graph. +v1.0.0 + * Initial stable release. + +============================================================================== +8. Credits *GundoCredits* + +The graphing code was all taken from Mercurial, hence the GPLv2+ license. + +The plugin was heavily inspired by histwin.vim, and the code for scratch.vim +helped the author get started. + +============================================================================== diff --git a/vimfiles/doc/tags b/vimfiles/doc/tags index 404f18a..44e6944 100644 --- a/vimfiles/doc/tags +++ b/vimfiles/doc/tags @@ -1,12 +1,3 @@ -:CVSEdit vcscommand.txt /*:CVSEdit* -:CVSEditors vcscommand.txt /*:CVSEditors* -:CVSUnedit vcscommand.txt /*:CVSUnedit* -:CVSWatch vcscommand.txt /*:CVSWatch* -:CVSWatchAdd vcscommand.txt /*:CVSWatchAdd* -:CVSWatchOff vcscommand.txt /*:CVSWatchOff* -:CVSWatchOn vcscommand.txt /*:CVSWatchOn* -:CVSWatchRemove vcscommand.txt /*:CVSWatchRemove* -:CVSWatchers vcscommand.txt /*:CVSWatchers* :Explore pi_netrw.txt /*:Explore* :GLVS pi_getscript.txt /*:GLVS* :GetLatestVimScripts_dat pi_getscript.txt /*:GetLatestVimScripts_dat* @@ -60,23 +51,6 @@ :TCommentRight tcomment.txt /*:TCommentRight* :Texplore pi_netrw.txt /*:Texplore* :UseVimball pi_vimball.txt /*:UseVimball* -:VCSAdd vcscommand.txt /*:VCSAdd* -:VCSAnnotate vcscommand.txt /*:VCSAnnotate* -:VCSBlame vcscommand.txt /*:VCSBlame* -:VCSCommit vcscommand.txt /*:VCSCommit* -:VCSDelete vcscommand.txt /*:VCSDelete* -:VCSDiff vcscommand.txt /*:VCSDiff* -:VCSGotoOriginal vcscommand.txt /*:VCSGotoOriginal* -:VCSInfo vcscommand.txt /*:VCSInfo* -:VCSLock vcscommand.txt /*:VCSLock* -:VCSLog vcscommand.txt /*:VCSLog* -:VCSRemove vcscommand.txt /*:VCSRemove* -:VCSRevert vcscommand.txt /*:VCSRevert* -:VCSReview vcscommand.txt /*:VCSReview* -:VCSStatus vcscommand.txt /*:VCSStatus* -:VCSUnlock vcscommand.txt /*:VCSUnlock* -:VCSUpdate vcscommand.txt /*:VCSUpdate* -:VCSVimDiff vcscommand.txt /*:VCSVimDiff* :Vexplore pi_netrw.txt /*:Vexplore* :VimballList pi_vimball.txt /*:VimballList* Align-copyright Align.txt /*Align-copyright* @@ -84,6 +58,15 @@ C-Reference crefvim.txt /*C-Reference* GetLatestVimScripts pi_getscript.txt /*GetLatestVimScripts* GetLatestVimScripts-copyright pi_getscript.txt /*GetLatestVimScripts-copyright* GetLatestVimScripts_dat pi_getscript.txt /*GetLatestVimScripts_dat* +Gundo-contents gundo.txt /*Gundo-contents* +GundoBugs gundo.txt /*GundoBugs* +GundoChangelog gundo.txt /*GundoChangelog* +GundoConfig gundo.txt /*GundoConfig* +GundoContributing gundo.txt /*GundoContributing* +GundoCredits gundo.txt /*GundoCredits* +GundoIntro gundo.txt /*GundoIntro* +GundoLicense gundo.txt /*GundoLicense* +GundoUsage gundo.txt /*GundoUsage* IDMY visincr.txt /*IDMY* IMDY visincr.txt /*IMDY* IYMD visincr.txt /*IYMD* @@ -103,26 +86,6 @@ SRHiGrp SrchRplcHiGrp.txt /*SRHiGrp* SRSearch SrchRplcHiGrp.txt /*SRSearch* SrchRplcHiGrp.txt SrchRplcHiGrp.txt /*SrchRplcHiGrp.txt* TCommentDefineType() tComment.txt /*TCommentDefineType()* -VCSCommandCVSDiffOpt vcscommand.txt /*VCSCommandCVSDiffOpt* -VCSCommandCVSExec vcscommand.txt /*VCSCommandCVSExec* -VCSCommandCommitOnWrite vcscommand.txt /*VCSCommandCommitOnWrite* -VCSCommandDeleteOnHide vcscommand.txt /*VCSCommandDeleteOnHide* -VCSCommandDiffSplit vcscommand.txt /*VCSCommandDiffSplit* -VCSCommandDisableAll vcscommand.txt /*VCSCommandDisableAll* -VCSCommandDisableExtensionMappings vcscommand.txt /*VCSCommandDisableExtensionMappings* -VCSCommandDisableMappings vcscommand.txt /*VCSCommandDisableMappings* -VCSCommandEdit vcscommand.txt /*VCSCommandEdit* -VCSCommandEnableBufferSetup vcscommand.txt /*VCSCommandEnableBufferSetup* -VCSCommandMapPrefix vcscommand.txt /*VCSCommandMapPrefix* -VCSCommandMappings vcscommand.txt /*VCSCommandMappings* -VCSCommandResultBufferNameExtension vcscommand.txt /*VCSCommandResultBufferNameExtension* -VCSCommandResultBufferNameFunction vcscommand.txt /*VCSCommandResultBufferNameFunction* -VCSCommandSVKExec vcscommand.txt /*VCSCommandSVKExec* -VCSCommandSVNDiffExt vcscommand.txt /*VCSCommandSVNDiffExt* -VCSCommandSVNDiffOpt vcscommand.txt /*VCSCommandSVNDiffOpt* -VCSCommandSVNExec vcscommand.txt /*VCSCommandSVNExec* -VCSCommandSplit vcscommand.txt /*VCSCommandSplit* -VCSCommandVCSTypeOverride vcscommand.txt /*VCSCommandVCSTypeOverride* VimPdb.txt VimPdb.txt /*VimPdb.txt* Vimball-copyright pi_vimball.txt /*Vimball-copyright* [% matchit.txt /*[%* @@ -211,10 +174,6 @@ alignmap-tt Align.txt /*alignmap-tt* alignmap-t~ Align.txt /*alignmap-t~* alignmaps Align.txt /*alignmaps* alignusage Align.txt /*alignusage* -b:VCSCommandCommand vcscommand.txt /*b:VCSCommandCommand* -b:VCSCommandOriginalBuffer vcscommand.txt /*b:VCSCommandOriginalBuffer* -b:VCSCommandSourceFile vcscommand.txt /*b:VCSCommandSourceFile* -b:VCSCommandVCSType vcscommand.txt /*b:VCSCommandVCSType* b:match_col matchit.txt /*b:match_col* b:match_debug matchit.txt /*b:match_debug* b:match_ignorecase matchit.txt /*b:match_ignorecase* @@ -1468,7 +1427,6 @@ crvdoc-licGPL crefvimdoc.txt /*crvdoc-licGPL* crvdoc-licLGPL crefvimdoc.txt /*crvdoc-licLGPL* crvdoc-limbugs crefvimdoc.txt /*crvdoc-limbugs* crvdoc-usage crefvimdoc.txt /*crvdoc-usage* -cvscommand-changes vcscommand.txt /*cvscommand-changes* dav pi_netrw.txt /*dav* davs pi_netrw.txt /*davs* drv-dtArrayInit crefvim.txt /*drv-dtArrayInit* @@ -1615,6 +1573,15 @@ glvs-install pi_getscript.txt /*glvs-install* glvs-options pi_getscript.txt /*glvs-options* glvs-plugins pi_getscript.txt /*glvs-plugins* glvs-usage pi_getscript.txt /*glvs-usage* +gundo.txt gundo.txt /*gundo.txt* +gundo_disable gundo.txt /*gundo_disable* +gundo_help gundo.txt /*gundo_help* +gundo_map_move_newer gundo.txt /*gundo_map_move_newer* +gundo_map_move_older gundo.txt /*gundo_map_move_older* +gundo_preview_bottom gundo.txt /*gundo_preview_bottom* +gundo_preview_height gundo.txt /*gundo_preview_height* +gundo_right gundo.txt /*gundo_right* +gundo_width gundo.txt /*gundo_width* http pi_netrw.txt /*http* local_markfilelist pi_netrw.txt /*local_markfilelist* logipat LogiPat.txt /*logipat* @@ -1834,14 +1801,6 @@ op-opAsRightShift crefvim.txt /*op-opAsRightShift* opAsBitAnd crefvim.txt /*opAsBitAnd* opAsBitOr crefvim.txt /*opAsBitOr* opAsBitXor crefvim.txt /*opAsBitXor* -outlook outlook.txt /*outlook* -outlook-configuration outlook.txt /*outlook-configuration* -outlook-install outlook.txt /*outlook-install* -outlook-macro outlook.txt /*outlook-macro* -outlook-new outlook.txt /*outlook-new* -outlook-overview outlook.txt /*outlook-overview* -outlook.txt outlook.txt /*outlook.txt* -outlookvim outlook.txt /*outlookvim* pi_getscript.txt pi_getscript.txt /*pi_getscript.txt* pi_netrw.txt pi_netrw.txt /*pi_netrw.txt* pi_vimball.txt pi_vimball.txt /*pi_vimball.txt* @@ -1873,29 +1832,6 @@ v_]% matchit.txt /*v_]%* v_a% matchit.txt /*v_a%* v_g% matchit.txt /*v_g%* vba pi_vimball.txt /*vba* -vcscommand vcscommand.txt /*vcscommand* -vcscommand-buffer-management vcscommand.txt /*vcscommand-buffer-management* -vcscommand-buffer-variables vcscommand.txt /*vcscommand-buffer-variables* -vcscommand-bugs vcscommand.txt /*vcscommand-bugs* -vcscommand-commands vcscommand.txt /*vcscommand-commands* -vcscommand-config vcscommand.txt /*vcscommand-config* -vcscommand-contents vcscommand.txt /*vcscommand-contents* -vcscommand-customize vcscommand.txt /*vcscommand-customize* -vcscommand-events vcscommand.txt /*vcscommand-events* -vcscommand-install vcscommand.txt /*vcscommand-install* -vcscommand-intro vcscommand.txt /*vcscommand-intro* -vcscommand-manual vcscommand.txt /*vcscommand-manual* -vcscommand-mappings vcscommand.txt /*vcscommand-mappings* -vcscommand-mappings-override vcscommand.txt /*vcscommand-mappings-override* -vcscommand-naming vcscommand.txt /*vcscommand-naming* -vcscommand-options vcscommand.txt /*vcscommand-options* -vcscommand-ssh vcscommand.txt /*vcscommand-ssh* -vcscommand-ssh-config vcscommand.txt /*vcscommand-ssh-config* -vcscommand-ssh-env vcscommand.txt /*vcscommand-ssh-env* -vcscommand-ssh-other vcscommand.txt /*vcscommand-ssh-other* -vcscommand-ssh-wrapper vcscommand.txt /*vcscommand-ssh-wrapper* -vcscommand-statusline vcscommand.txt /*vcscommand-statusline* -vcscommand.txt vcscommand.txt /*vcscommand.txt* vimball pi_vimball.txt /*vimball* vimball-contents pi_vimball.txt /*vimball-contents* vimball-extract pi_vimball.txt /*vimball-extract* @@ -1944,8 +1880,3 @@ visincr-raggedright visincr.txt /*visincr-raggedright* visincr-restrict visincr.txt /*visincr-restrict* visincr-usage visincr.txt /*visincr-usage* visincr.txt visincr.txt /*visincr.txt* -xml-plugin-callbacks xml-plugin.txt /*xml-plugin-callbacks* -xml-plugin-html xml-plugin.txt /*xml-plugin-html* -xml-plugin-mappings xml-plugin.txt /*xml-plugin-mappings* -xml-plugin-settings xml-plugin.txt /*xml-plugin-settings* -xml-plugin.txt xml-plugin.txt /*xml-plugin.txt* diff --git a/vimfiles/plugin/gundo.vim b/vimfiles/plugin/gundo.vim new file mode 100644 index 0000000..49cd83f --- /dev/null +++ b/vimfiles/plugin/gundo.vim @@ -0,0 +1,955 @@ +" ============================================================================ +" File: gundo.vim +" Description: vim global plugin to visualize your undo tree +" Maintainer: Steve Losh +" License: GPLv2+ -- look it up. +" Notes: Much of this code was thiefed from Mercurial, and the rest was +" heavily inspired by scratch.vim and histwin.vim. +" +" ============================================================================ + + +"{{{ Init + +if !exists('g:gundo_debug') && (exists('g:gundo_disable') || exists('loaded_gundo') || &cp)"{{{ + finish +endif +let loaded_gundo = 1"}}} + +if v:version < '703'"{{{ + function! s:GundoDidNotLoad() + echohl WarningMsg|echomsg "Gundo unavailable: requires Vim 7.3+"|echohl None + endfunction + command! -nargs=0 GundoToggle call s:GundoDidNotLoad() + finish +endif"}}} + +if has('python')"{{{ + let s:has_supported_python = 1 + +python << ENDPYTHON +import sys +import vim +if sys.version_info[:2] < (2, 4): + vim.command('let s:has_supported_python = 0') +ENDPYTHON +else + let s:has_supported_python = 0 +endif + +if !s:has_supported_python + function! s:GundoDidNotLoad() + echohl WarningMsg|echomsg "Gundo requires Vim to be compiled with Python 2.4+"|echohl None + endfunction + command! -nargs=0 GundoToggle call s:GundoDidNotLoad() + finish +endif"}}} + +if !exists('g:gundo_width')"{{{ + let g:gundo_width = 45 +endif"}}} +if !exists('g:gundo_preview_height')"{{{ + let g:gundo_preview_height = 15 +endif"}}} +if !exists('g:gundo_preview_bottom')"{{{ + let g:gundo_preview_bottom = 0 +endif"}}} +if !exists('g:gundo_right')"{{{ + let g:gundo_right = 0 +endif"}}} +if !exists('g:gundo_help')"{{{ + let g:gundo_help = 1 +endif"}}} +if !exists("g:gundo_map_move_older")"{{{ + let g:gundo_map_move_older = 'j' +endif"}}} +if !exists("g:gundo_map_move_newer")"{{{ + let g:gundo_map_move_newer = 'k' +endif"}}} + +"}}} + +"{{{ Mercurial's graphlog code +python << ENDPYTHON +def asciiedges(seen, rev, parents): + """adds edge info to changelog DAG walk suitable for ascii()""" + if rev not in seen: + seen.append(rev) + nodeidx = seen.index(rev) + + knownparents = [] + newparents = [] + for parent in parents: + if parent in seen: + knownparents.append(parent) + else: + newparents.append(parent) + + ncols = len(seen) + seen[nodeidx:nodeidx + 1] = newparents + edges = [(nodeidx, seen.index(p)) for p in knownparents] + + if len(newparents) > 0: + edges.append((nodeidx, nodeidx)) + if len(newparents) > 1: + edges.append((nodeidx, nodeidx + 1)) + + nmorecols = len(seen) - ncols + return nodeidx, edges, ncols, nmorecols + +def get_nodeline_edges_tail( + node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail): + if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0: + # Still going in the same non-vertical direction. + if n_columns_diff == -1: + start = max(node_index + 1, p_node_index) + tail = ["|", " "] * (start - node_index - 1) + tail.extend(["/", " "] * (n_columns - start)) + return tail + else: + return ["\\", " "] * (n_columns - node_index - 1) + else: + return ["|", " "] * (n_columns - node_index - 1) + +def draw_edges(edges, nodeline, interline): + for (start, end) in edges: + if start == end + 1: + interline[2 * end + 1] = "/" + elif start == end - 1: + interline[2 * start + 1] = "\\" + elif start == end: + interline[2 * start] = "|" + else: + nodeline[2 * end] = "+" + if start > end: + (start, end) = (end, start) + for i in range(2 * start + 1, 2 * end): + if nodeline[i] != "+": + nodeline[i] = "-" + +def fix_long_right_edges(edges): + for (i, (start, end)) in enumerate(edges): + if end > start: + edges[i] = (start, end + 1) + +def ascii(buf, state, type, char, text, coldata): + """prints an ASCII graph of the DAG + + takes the following arguments (one call per node in the graph): + + - Somewhere to keep the needed state in (init to asciistate()) + - Column of the current node in the set of ongoing edges. + - Type indicator of node data == ASCIIDATA. + - Payload: (char, lines): + - Character to use as node's symbol. + - List of lines to display as the node's text. + - Edges; a list of (col, next_col) indicating the edges between + the current node and its parents. + - Number of columns (ongoing edges) in the current revision. + - The difference between the number of columns (ongoing edges) + in the next revision and the number of columns (ongoing edges) + in the current revision. That is: -1 means one column removed; + 0 means no columns added or removed; 1 means one column added. + """ + + idx, edges, ncols, coldiff = coldata + assert -2 < coldiff < 2 + if coldiff == -1: + # Transform + # + # | | | | | | + # o | | into o---+ + # |X / |/ / + # | | | | + fix_long_right_edges(edges) + + # add_padding_line says whether to rewrite + # + # | | | | | | | | + # | o---+ into | o---+ + # | / / | | | # <--- padding line + # o | | | / / + # o | | + add_padding_line = (len(text) > 2 and coldiff == -1 and + [x for (x, y) in edges if x + 1 < y]) + + # fix_nodeline_tail says whether to rewrite + # + # | | o | | | | o | | + # | | |/ / | | |/ / + # | o | | into | o / / # <--- fixed nodeline tail + # | |/ / | |/ / + # o | | o | | + fix_nodeline_tail = len(text) <= 2 and not add_padding_line + + # nodeline is the line containing the node character (typically o) + nodeline = ["|", " "] * idx + nodeline.extend([char, " "]) + + nodeline.extend( + get_nodeline_edges_tail(idx, state[1], ncols, coldiff, + state[0], fix_nodeline_tail)) + + # shift_interline is the line containing the non-vertical + # edges between this entry and the next + shift_interline = ["|", " "] * idx + if coldiff == -1: + n_spaces = 1 + edge_ch = "/" + elif coldiff == 0: + n_spaces = 2 + edge_ch = "|" + else: + n_spaces = 3 + edge_ch = "\\" + shift_interline.extend(n_spaces * [" "]) + shift_interline.extend([edge_ch, " "] * (ncols - idx - 1)) + + # draw edges from the current node to its parents + draw_edges(edges, nodeline, shift_interline) + + # lines is the list of all graph lines to print + lines = [nodeline] + if add_padding_line: + lines.append(get_padding_line(idx, ncols, edges)) + lines.append(shift_interline) + + # make sure that there are as many graph lines as there are + # log strings + while len(text) < len(lines): + text.append("") + if len(lines) < len(text): + extra_interline = ["|", " "] * (ncols + coldiff) + while len(lines) < len(text): + lines.append(extra_interline) + + # print lines + indentation_level = max(ncols, ncols + coldiff) + for (line, logstr) in zip(lines, text): + ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr) + buf.write(ln.rstrip() + '\n') + + # ... and start over + state[0] = coldiff + state[1] = idx + +def generate(dag, edgefn, current): + seen, state = [], [0, 0] + buf = Buffer() + for node, parents in list(dag): + if node.time: + age_label = age(int(node.time)) + else: + age_label = 'Original' + line = '[%s] %s' % (node.n, age_label) + if node.n == current: + char = '@' + else: + char = 'o' + ascii(buf, state, 'C', char, [line], edgefn(seen, node, parents)) + return buf.b +ENDPYTHON +"}}} + +"{{{ Mercurial age function +python << ENDPYTHON +import time + +agescales = [("year", 3600 * 24 * 365), + ("month", 3600 * 24 * 30), + ("week", 3600 * 24 * 7), + ("day", 3600 * 24), + ("hour", 3600), + ("minute", 60), + ("second", 1)] + +def age(ts): + '''turn a timestamp into an age string.''' + + def plural(t, c): + if c == 1: + return t + return t + "s" + def fmt(t, c): + return "%d %s" % (c, plural(t, c)) + + now = time.time() + then = ts + if then > now: + return 'in the future' + + delta = max(1, int(now - then)) + if delta > agescales[0][1] * 2: + return time.strftime('%Y-%m-%d', time.gmtime(float(ts))) + + for t, s in agescales: + n = delta // s + if n >= 2 or s == 1: + return '%s ago' % fmt(t, n) +ENDPYTHON +"}}} + +"{{{ Python Vim utility functions +python << ENDPYTHON +import vim + +normal = lambda s: vim.command('normal %s' % s) + +MISSING_BUFFER = "Cannot find Gundo's target buffer (%s)" +MISSING_WINDOW = "Cannot find window (%s) for Gundo's target buffer (%s)" + +def _check_sanity(): + '''Check to make sure we're not crazy. + + Does the following things: + + * Make sure the target buffer still exists. + ''' + b = int(vim.eval('g:gundo_target_n')) + + if not vim.eval('bufloaded(%d)' % b): + vim.command('echo "%s"' % (MISSING_BUFFER % b)) + return False + + w = int(vim.eval('bufwinnr(%d)' % b)) + if w == -1: + vim.command('echo "%s"' % (MISSING_WINDOW % (w, b))) + return False + + return True + +def _goto_window_for_buffer(b): + w = int(vim.eval('bufwinnr(%d)' % int(b))) + vim.command('%dwincmd w' % w) + +def _goto_window_for_buffer_name(bn): + b = vim.eval('bufnr("%s")' % bn) + return _goto_window_for_buffer(b) + +def _undo_to(n): + n = int(n) + if n == 0: + vim.command('silent earlier %s' % (int(vim.eval('&undolevels')) + 1)) + else: + vim.command('silent undo %d' % n) + + +INLINE_HELP = '''\ +" Gundo for %s (%d) +" j/k - move between undo states +" p - preview diff of selected and current states +" - revert to selected state + +''' +ENDPYTHON +"}}} + +"{{{ Python undo tree data structures and functions +python << ENDPYTHON +import itertools + +class Buffer(object): + def __init__(self): + self.b = '' + + def write(self, s): + self.b += s + +class Node(object): + def __init__(self, n, parent, time, curhead): + self.n = int(n) + self.parent = parent + self.children = [] + self.curhead = curhead + self.time = time + +def _make_nodes(alts, nodes, parent=None): + p = parent + + for alt in alts: + curhead = 'curhead' in alt + node = Node(n=alt['seq'], parent=p, time=alt['time'], curhead=curhead) + nodes.append(node) + if alt.get('alt'): + _make_nodes(alt['alt'], nodes, p) + p = node + +def make_nodes(): + ut = vim.eval('undotree()') + entries = ut['entries'] + + root = Node(0, None, False, 0) + nodes = [] + _make_nodes(entries, nodes, root) + nodes.append(root) + nmap = dict((node.n, node) for node in nodes) + return nodes, nmap + +def changenr(nodes): + _curhead_l = list(itertools.dropwhile(lambda n: not n.curhead, nodes)) + if _curhead_l: + current = _curhead_l[0].parent.n + else: + current = int(vim.eval('changenr()')) + return current +ENDPYTHON +"}}} + +"{{{ Gundo utility functions + +function! s:GundoGetTargetState()"{{{ + let target_line = matchstr(getline("."), '\v\[[0-9]+\]') + return matchstr(target_line, '\v[0-9]+') +endfunction"}}} + +function! s:GundoGoToWindowForBufferName(name)"{{{ + if bufwinnr(bufnr(a:name)) != -1 + exe bufwinnr(bufnr(a:name)) . "wincmd w" + return 1 + else + return 0 + endif +endfunction"}}} + +function! s:GundoIsVisible()"{{{ + if bufwinnr(bufnr("__Gundo__")) != -1 || bufwinnr(bufnr("__Gundo_Preview__")) != -1 + return 1 + else + return 0 + endif +endfunction"}}} + +function! s:GundoInlineHelpLength()"{{{ + if g:gundo_help + return 6 + else + return 0 + endif +endfunction"}}} + +"}}} + +"{{{ Gundo buffer settings + +function! s:GundoMapGraph()"{{{ + exec 'nnoremap