" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish autoload/stay/integrate/fastfold.vim [[[1 40 " FASTFOLD INTEGRATION MODULE " https://github.com/Konfekt/FastFold let s:cpoptions = &cpoptions set cpoptions&vim " - cancel integration if FastFold is not found if empty(findfile('plugin/fastfold.vim', &rtp)) let &cpoptions = s:cpoptions unlet! s:cpoptions finish endif " - register integration autocommands if FastFold plug-in is found function! stay#integrate#fastfold#setup() abort autocmd User BufStaySavePre unsilent call stay#integrate#fastfold#save_pre() autocmd User BufStaySavePost unsilent call stay#integrate#fastfold#save_post() autocmd User BufStayLoadPost,BufStaySavePost let b:isPersistent = 1 endfunction " - on User event 'BufStaySavePre': restore original 'foldmethod' function! stay#integrate#fastfold#save_pre() abort if index(split(&viewoptions, ','), 'folds') isnot -1 let [l:fdmlocal, l:fdmorig] = [&l:foldmethod, get(w:, 'lastfdm', &l:foldmethod)] if l:fdmorig isnot l:fdmlocal noautocmd silent let &l:foldmethod = l:fdmorig endif endif endfunction " - on User event 'BufStaySavePost': restore FastFold 'foldmethod' function! stay#integrate#fastfold#save_post() abort if &foldmethod isnot# 'manual' && exists('w:lastfdm') noautocmd silent let &l:foldmethod = 'manual' endif endfunction let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: autoload/stay/shim.vim [[[1 74 " STAY EVAL SHIM MODULE " Are these Vim patch levels, my dear? if v:version < 700 finish endif let s:cpoptions = &cpoptions set cpoptions&vim " Full forward and backward `globpath()` compatibility between Vim 7.0 and Vim 7.4: " - no {nosuf} argument before 7.2.051 - :h version7.txt " - no {list} argument before 7.4.279 - http://ftp.vim.org/pub/vim/patches/7.4/README if v:version < 702 || (v:version is 702 && !has('patch051')) function! stay#shim#globpath(path, glob, ...) abort let l:nosuf = get(a:, 1, 0) let l:list = get(a:, 2, 0) let l:suffixes = &suffixes let l:wildignore = &wildignore try if l:nosuf isnot 0 set suffixes= set wildignore= endif let l:result = globpath(a:path, a:glob) return l:list isnot 0 ? s:fnames2list(l:result, 0) : l:result finally let &suffixes = l:suffixes let &wildignore = l:wildignore endtry endfunction elseif v:version < 704 || (v:version is 704 && !has('patch279')) function! stay#shim#globpath(path, glob, ...) abort let l:nosuf = get(a:, 1, 0) let l:list = get(a:, 2, 0) let l:result = globpath(a:path, a:glob, l:nosuf) return l:list isnot 0 ? s:fnames2list(l:result, l:nosuf) : l:result endfunction else function! stay#shim#globpath(path, glob, ...) abort return globpath(a:path, a:glob, get(a:, 1, 0), get(a:, 2, 0)) endfunction endif " Get a List out of {fnames} without mangling file names with NL in them: " @signature: s:fnames2list({fnames:String[NL-separated]}, {setnosuf:Boolean}) " @returns: List of file system object paths in {fnames} function! s:fnames2list(fnames, setnosuf) abort let l:globcmd = a:setnosuf is 1 ? 'glob(%s, 1)' : 'glob(%s)' let l:fnames = split(a:fnames, '\n') let l:fragments = filter(copy(l:fnames), 'empty('.printf(l:globcmd, 'v:val').')') if empty(l:fragments) return l:fnames endif let l:fnames = filter(l:fnames, '!empty('.printf(l:globcmd, 'v:val').')') let l:index = 0 while l:index+1 < len(l:fragments) let l:composite = get(l:, 'composite', l:fragments[l:index])."\n".l:fragments[l:index+1] if !empty(eval(printf(l:globcmd, string(l:composite)))) call add(l:fnames, l:composite) unlet l:composite let l:index += 1 endif let l:index += 1 endwhile return sort(l:fnames, 'i') endfunction let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: autoload/stay/view.vim [[[1 96 " AUTOLOAD FUNCTION LIBRARY FOR VIM-STAY " View session handling functions let s:cpoptions = &cpoptions set cpoptions&vim " Make a persistent view for window {winnr}: " @signature: stay#view#make({winnr:Number}) " @returns: Boolean function! stay#view#make(winnr) abort if a:winnr is -1 return 0 endif try let l:lazyredraw = &lazyredraw set lazyredraw if !s:win.goto(a:winnr) return 0 endif unlet! b:stay_atpos call s:doautocmd('User', 'BufStaySavePre') mkview call s:doautocmd('User', 'BufStaySavePost') call s:win.back() return 1 finally let &lazyredraw = l:lazyredraw endtry endfunction " Load a persistent view for window {winnr}: " @signature: stay#view#load({winnr:Number}) " @returns: Boolean function! stay#view#load(winnr) abort if a:winnr is -1 || !s:win.goto(a:winnr) return 0 endif call s:doautocmd('User', 'BufStayLoadPre') try " significantly slows down buffer loads without noautocmd noautocmd silent loadview catch " silently return on errors return 0 endtry call s:doautocmd('User', 'BufStayLoadPost') call s:doautocmd('SessionLoadPost') if exists('b:stay_atpos') call cursor(b:stay_atpos[0], b:stay_atpos[1]) silent! normal! zOzz endif call s:win.back() return 1 endfunction " Private helper functions: {{{ " - window navigation stack let s:win = {'stack': []} function! s:win.activate(winnr) abort if winnr() isnot a:winnr execute 'noautocmd keepjumps keepalt silent' a:winnr.'wincmd w' endif endfunction function! s:win.goto(winnr) abort let l:oldwinnr = winnr() call self.activate(a:winnr) call add(self.stack, l:oldwinnr) return winnr() is a:winnr endfunction function! s:win.back() abort if len(self.stack) > 0 let l:towinnr = remove(self.stack, -1) call self.activate(l:towinnr) endif return exists('l:towinnr') && winnr() is l:towinnr endfunction " - apply {event} autocommands, optionally matching pattern {a:1}, " but only if there are any " 1. avoids flooding message history with "No matching autocommands" " 2. avoids re-applying modelines in Vim < 7.3.442, which doesn't honor || " see https://groups.google.com/forum/#!topic/vim_dev/DidKMDAsppw function! s:doautocmd(event, ...) abort let l:event = a:0 ? [a:event, a:1] : [a:event] if exists('#'.join(l:event, '#')) execute 'doautocmd ' join(l:event, ' ') endif endfunction " }}} let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: autoload/stay/viewdir.vim [[[1 28 " AUTOLOAD FUNCTION LIBRARY FOR VIM-STAY " 'viewdir' handling functions let s:cpoptions = &cpoptions set cpoptions&vim " Remove view session files from 'viewdir': " @signature: stay#viewdir#clean({bang:String}, [{keepdays:Number}]) " @optargs: {keepdays} keep files not older than this in days (default: 0) " @returns: List tuple of deletion candidates count, deleted files count function! stay#viewdir#clean(bang, ...) abort let l:keepsecs = max([get(a:, 1, 0) * 86400, 0]) let l:candidates = stay#shim#globpath(&viewdir, '*', 1, 1) call filter(l:candidates, 'localtime() - getftime(v:val) > l:keepsecs') let l:candcount = len(l:candidates) let l:delcount = 0 if a:bang is 1 \ || input("Type 'Y' to delete ".l:candcount." view session files: ") is# 'Y' for l:file in l:candidates let l:delcount += (delete(l:file) is 0) endfor endif return [l:candcount, l:delcount] endfunction let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: autoload/stay.vim [[[1 55 " AUTOLOAD FUNCTION LIBRARY FOR VIM-STAY " Core functions (will be loaded when first autocommand is triggered) let s:cpoptions = &cpoptions set cpoptions&vim " Check if buffer {bufnr} is persistent: " @signature: stay#ispersistent({bufnr:Number}, {volatile_ftypes:List}) " @returns: Boolean " @notes: the persistence heuristics are " - buffer must be listed " - buffer name must not be empty " - buffer must be of ordinary or "acwrite" 'buftype' " - not a preview window " - not a diff window " - buffer's 'bufhidden' must be empty or "hide" " - buffer must map to a readable file " - buffer must not be of a volatile file type " - buffer file must not be located in a known temp dir function! stay#ispersistent(bufnr, volatile_ftypes) abort let l:bufpath = expand('#'.a:bufnr.':p') return bufexists(a:bufnr) \ && !empty(l:bufpath) \ && getbufvar(a:bufnr, 'stay_ignore', 0) isnot 1 \ && getbufvar(a:bufnr, '&buflisted') is 1 \ && index(['', 'acwrite'], getbufvar(a:bufnr, '&buftype')) isnot -1 \ && getbufvar(a:bufnr, '&previewwindow') isnot 1 \ && getbufvar(a:bufnr, '&diff') isnot 1 \ && index(['', 'hide'], getbufvar(a:bufnr, '&bufhidden')) isnot -1 \ && filereadable(l:bufpath) \ && stay#isftype(a:bufnr, a:volatile_ftypes) isnot 1 \ && stay#istemp(l:bufpath) isnot 1 endfunction " Check if {fname} is in a 'backupskip' location: " @signature: stay#istemp({fname:String}) " @returns: Boolean function! stay#istemp(path) abort let l:candidates = stay#shim#globpath(&backupskip, '**/'.fnamemodify(a:path, ':t'), 1, 1) return index(l:candidates, a:path) isnot -1 endfunction " Check if one of {bufnr}'s 'filetype' parts is on the {ftypes} List: " @signature: stay#isftype({bufnr:Number}, {ftypes:List}) " @returns: Boolean " @notes: - tests individual parts of composite (dotted) 'filetype's " - comparison is always case sensitive function! stay#isftype(bufnr, ftypes) abort let l:candidates = split(getbufvar(a:bufnr, '&filetype'), '\.') return !empty(filter(l:candidates, 'index(a:ftypes, v:val) isnot -1')) endfunction let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: doc/vim-stay.txt [[[1 224 *vim-stay.txt* For Vim version 7.0 or better version 1.2.0 VIM REFERENCE for the Stay plug-in Never lose your place in a buffer again *vim-stay* 1. Introduction |vim-stay-introduction| 2. Configuration |vim-stay-configuration| 3. Commands |vim-stay-commands| 4. Position specifications |vim-stay-integration| 5. Troubleshooting |vim-stay-troubleshooting| 6. Credits and license |vim-stay-credits-license| {not available when |'compatible'| is set, or when Vim is compiled without |+autocmd| or without |+mksession|} ============================================================================== 1. Introduction *vim-stay-introduction* vim-stay adds automated |View| creation and restoration whenever editing a buffer, across Vim sessions and window life cycles. It also alleviates Vim's tendency to lose view state when cycling through buffers (via |argdo|, |bufdo| et al.). It is smart about which buffers should be persisted and which should not, making the procedure painless and invisible. ============================================================================== 2. Configuration *vim-stay-configuration* VIEW SESSION CONFIGURATION: *vim-stay-viewoptions* The following, non-standard 'viewoptions' settings are recommended: > set viewoptions=cursor,folds,slash,unix < It is recommended to clear the 'viewdir' contents after changing this option, as it is only applied when creating a view session file, not when loading it. vim-stay provides the |:CleanViewdir| command to do that. IGNORED FILE TYPES: *g:volatile_ftypes* vim-stay applies heuristics to detect buffers that should not be persisted, but in some cases non-persistent buffers slip through. Some of them are regular files that are not persistent by their very nature (like git commit messages), a few are buffers created by plug-ins that miss all indication that they are not files. These can be expressly marked as volatile (meaning buffers of this type will never be persisted) by adding their 'filetype' to the `volatile_ftypes` global |List|. Note this list is meant as a safety net for the case heuristics fail; it usually should not be necessary to modify vim-stay's defaults. If you find you need to add file types to it, make sure the plug-in has loaded, then do > let g:volatile_ftypes += ['foo', 'bar'] < ============================================================================== 3. Commands *vim-stay-commands* :CleanViewdir[!] [days] Remove all saved view sessions in 'viewdir', optionally keeping view sessions files not older than {days} days. Note: this will ask for confirmation before deleting files. Use the bang variant to bypass the confirmation prompt. :StayReload[!] Re-source the plug-in, resetting autocommands and reloading all integration modules. The bang variant will also reset global configuration variables (currently, only |g:volatile_ftypes|) to the plug-in defaults. ============================================================================== 4. Integration *vim-stay-integration* INTEGRATION WITH 3RD PARTY PLUG-INS: Out of the box, vim-stay integrates with the following plug-ins: 1. vim-fetch http://www.vim.org/scripts/script.php?script_id=5089 2. FastFold https://github.com/Konfekt/FastFold If you'd like vim-stay to integrate with other position-setting or view management plug-ins, open an issue or a PR at https://github.com/kopischke/vim-stay/issues If the plug-in in question is one you own or contribute to, see |vim-stay-plugin-api| instead. INTEGRATION API: 1. Keeping the position set by other scripts *b:stay_atpos* To make vim-stay respect a position set by an unsupported script or plug-in, set the `stay_atpos` buffer-local variable: > let b:stay_atpos = [lnum, colnum] < This position will be restored after loading the session. 2. Ignoring a file on a per-buffer basis *b:stay_ignore* To stop vim-stay making and restoring sessions for a specific buffer, do > let b:stay_ignore = 1 < See the |g:volatile_ftypes| user setting for a way to ignore all buffers of a certain file type. 3. Autocommand API *vim-stay-autocommands* vim-stray triggers two |User| autocommand events each when loading or saving state: *BufStayLoadPre* before loading a view session and *BufStayLoadPost* after loading it, *BufStaySavePre* before saving a view session and *BufStaySavePost* after. 4. Extended plug-in integration API *vim-stay-plugin-api* The mechanism vim-stay itself uses to integrate with other plug-ins is open to 3rd parties. Add a file > autoload/stay/integrate/yourplugin.vim < containing a `stay#integrate#yourplugin#setup()` |autoload| function to your plug-in. Any function with that signature found in 'runtimepath' when vim-stay loads will be executed. You can set up autocommands in there (which will automatically be added to the `stay` autocommand group), optionally leveraging vim-stay's autocommand API (|vim-stay-autocommands|), or add to the volatile 'filetype' list (|g:volatile_ftypes|). The advantage over hard-wiring support for vim-stay in your plug-in is that - the integration will be set up when your user uses vim-stay regardless of plug-in load order, but - the integration code will only be active if your user actually uses vim-stay. ============================================================================== 5. Troubleshooting *vim-stay-troubleshooting* MY CURSOR POSITION IS NOT PERSISTED You have removed "cursor" from 'viewoptions'. See the recommended setting under |vim-stay-viewoptions|. MY FOLD STATE IS NOT PERSISTED / MY CURSOR ENDS UP IN A CLOSED FOLD You have removed "folds" from 'viewoptions'. See the recommended setting under |vim-stay-viewoptions|. MY STATE IS NOT PERSISTED WHEN SWITCHING BETWEEN WINDOWS AND OTHER OS' With the default settings, 'viewoptions' uses platform specific path separators, which means stored view sessions are not portable. See the recommended setting under |vim-stay-viewoptions|. MY CURRENT WORKING DIRECTORY / MY ARGLIST CHANGES WHEN OPENING A FILE vim-stay uses |mkview| and |loadview|, which persist the local arglist and local working directory. This can be a bit disorienting at first, but it is by (Vim's) design. If this really irks you, you may be able to work around it using vim-stay's autocommand API (see |vim-stay-autocommands|). VIM-STAY MESSES UP OPTION X / BUFFER VARIABLE Y You have "options" or "localoptions" set in 'viewoptions'. See the recommended setting under |vim-stay-viewoptions|. VIM-STAY TRIES TO PERSIST STATE FOR TEMPORARY FILES - If the files are in a standard system temporary location, you should check if it listed in 'backupskip' - vim-stray will ignore files in the hierarchy of directories listed there. - Files in a temporary or cache directory not listed in 'backupskip' are not recognized as volatile, unless their 'buftype' is set to a non-file type. You can alleviate the issue by setting |b:stay_ignore| in affected buffers. VIM-STAY TRIES TO PERSIST STATE FOR OTHER VOLATILE FILES Check if the 'filetype' of the affected file is listed in |g:volatile_ftypes| and try adding it if it is not. I'd also be grateful if you reported the file type by opening a support issue (or even better, a PR) at https://github.com/kopischke/vim-stay/issues MY VIEW DIRECTORY IS A FESTERING MESS That is a consequence of Vim's view session design. To quote |loadview|: "You might want to clean up your 'viewdir' directory now and then." Use the |:CleanViewdir| command to do exactly that. MY PROBLEM ISN'T LISTED HERE You might have found a bug. Please open an issue at https://github.com/kopischke/vim-stay/issues Please do not forget to list the steps to reproduce the issue as well as your Vim version and platform. ============================================================================== 6. Credits and License *vim-stay-credits-license* vim-stay is maintained by Martin Kopischke http://martin.kopischke.net and licensed under the terms of the MIT license according to the accompanying license file (LICENSE.md). It is inspired by, but not based on, `restore_view.vim` by Zhou Yi Chao (http://www.vim.org/scripts/script.php?script_id=4021). vim:tw=78:ts=8:ft=help:norl:noet:fen:fdl=0:fdm=marker: plugin/stay.vim [[[1 78 " A LESS SIMPLISTIC TAKE ON RESTORE_VIEW.VIM " Maintainer: Martin Kopischke " License: MIT (see LICENSE.md) " Version: 1.2.0 if &compatible || !has('autocmd') || !has('mksession') || v:version < 700 finish endif let s:cpoptions = &cpoptions set cpoptions&vim " Plug-in defaults: let s:defaults = {} " - bona fide file types that should never be persisted let s:defaults.volatile_ftypes = [ \ 'gitcommit', 'gitrebase', 'gitsendmail', \ 'hgcommit', 'hgcommitmsg', 'hgstatus', 'hglog', 'hglog-changelog', 'hglog-compact', \ 'svn', 'cvs', 'cvsrc', 'bzr', \ ] " Loader for 3rd party integrations: function! s:integrate() abort let s:integrations = [] for l:file in stay#shim#globpath(&rtp, 'autoload/stay/integrate/*.vim', 1, 1) let l:name = fnamemodify(l:file, ':t:r') if index(s:integrations, l:name) is -1 try call call('stay#integrate#'.l:name.'#setup', []) catch /E117/ " no setup function found continue catch " integration setup execution errors echomsg "Skipped vim-stay integration for" l:name "due to error:" v:errmsg continue endtry call add(s:integrations, l:name) endif endfor endfunction " Set up global configuration, autocommands, commands: function! s:setup(defaults) abort " - make defaults available as individual global variables, " respecting pre-set global vars unless {defaults} is 1 for [s:key, s:val] in items(s:defaults) let g:{s:key} = a:defaults is 1 ? s:val : get(g:, s:key, s:val) unlet! s:key s:val endfor " - 'stay' autocommand group (also used by integrations) augroup stay autocmd! " default buffer handling autocmd BufLeave,BufWinLeave ?* \ if stay#ispersistent(str2nr(expand('')), g:volatile_ftypes) | \ call stay#view#make(bufwinnr(str2nr(expand('')))) | \ endif autocmd BufWinEnter ?* \ if stay#ispersistent(str2nr(expand('')), g:volatile_ftypes) | \ call stay#view#load(bufwinnr(str2nr(expand('')))) | \ endif " generic, extensible 3rd party integration call s:integrate() augroup END " - ex commands command! -bang -nargs=? CleanViewdir \ call stay#viewdir#clean(expand('') is '!', ) command! -bang -nargs=0 StayReload \ call setup(expand('') is '!') endfunction call s:setup(0) let &cpoptions = s:cpoptions unlet! s:cpoptions " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: