" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish autoload/fetch.vim [[[1 143 " AUTOLOAD FUNCTION LIBRARY FOR VIM-FETCH let s:cpo = &cpo set cpo&vim " Position specs Dictionary: let s:specs = {} " - trailing colon, i.e. ':lnum[:colnum[:]]' " trigger with '?*:[0123456789]*' pattern let s:specs.colon = {'pattern': '\m\%(:\d\+\)\{1,2}:\?$'} function! s:specs.colon.parse(file) abort return [substitute(a:file, self.pattern, '', ''), \ split(matchstr(a:file, self.pattern), ':')] endfunction " - trailing parentheses, i.e. '(lnum[:colnum])' " trigger with '?*([0123456789]*)' pattern let s:specs.paren = {'pattern': '\m(\(\d\+\%(:\d\+\)\?\))$'} function! s:specs.paren.parse(file) abort return [substitute(a:file, self.pattern, '', ''), \ split(matchlist(a:file, self.pattern)[1], ':')] endfunction " - Plan 9 type line spec, i.e. '[:]#lnum' " trigger with '?*#[0123456789]*' pattern let s:specs.plan9 = {'pattern': '\m:#\(\d\+\)$'} function! s:specs.plan9.parse(file) abort return [substitute(a:file, self.pattern, '', ''), \ [matchlist(a:file, self.pattern)[1]]] endfunction " Detection methods for buffers that bypass `filereadable()`: let s:ignore = [] " - non-file buffer types call add(s:ignore, {'types': ['quickfix', 'acwrite', 'nofile']}) function! s:ignore[-1].detect(buffer) abort return index(self.types, getbufvar(a:buffer, '&buftype')) isnot -1 endfunction " - non-document file types that do not trigger the above " not needed for: Unite / VimFiler / VimShell / CtrlP / Conque-Shell call add(s:ignore, {'types': ['netrw']}) function! s:ignore[-1].detect(buffer) abort return index(self.types, getbufvar(a:buffer, '&filetype')) isnot -1 endfunction " - redirected buffers call add(s:ignore, {'bufvars': ['netrw_lastfile']}) function! s:ignore[-1].detect(buffer) abort for l:var in self.bufvars if !empty(getbufvar(a:buffer, l:var)) return 1 endif endfor return 0 endfunction " Get a copy of vim-fetch's spec matchers: " @signature: fetch#specs() " @returns: Dictionary of specs, keyed by name, " each spec Dictionary with the following keys: " - 'pattern' String to match the spec in a file name " - 'parse' Funcref taking a spec'ed file name and " returning a two item List of " {unspec'ed path:String}, {pos:List} " @notes: the autocommand match patterns are not included function! fetch#specs() abort return deepcopy(s:specs) endfunction " Edit {file}, placing the cursor at the line and column indicated by {spec}: " @signature: fetch#edit({file:String}, {spec:String}) " @returns: Boolean indicating if a spec has been succesfully resolved " @notes: - won't work from a |BufReadCmd| event as it doesn't load non-spec'ed files " - won't work from events fired before the spec'ed file is loaded into " the buffer (i.e. before '%' is set to the spec'ed file) like |BufNew| " as it won't be able to wipe the spurious new spec'ed buffer function! fetch#edit(file, spec) abort " naive early exit on obvious non-matches if filereadable(a:file) || match(a:file, s:specs[a:spec].pattern) is -1 return 0 endif " check for unspec'ed editable file let [l:file, l:pos] = s:specs[a:spec].parse(a:file) if !filereadable(l:file) return 0 " in doubt, end with invalid user input endif " processing setup let l:pre = '' " will be prefixed to edit command " if current buffer is spec'ed and invalid set it up for wiping if expand('%:p') is fnamemodify(a:file, ':p') for l:ignore in s:ignore if l:ignore.detect(bufnr('%')) is 1 return 0 endif endfor set buftype=nowrite " avoid issues voiding the buffer set bufhidden=wipe " avoid issues with |bwipeout| let l:pre .= 'keepalt ' " don't mess up alternate file on switch endif " clean up argument list if has('listcmds') let l:argidx = index(argv(), a:file) if l:argidx isnot -1 " substitute un-spec'ed file for spec'ed execute 'argdelete' fnameescape(a:file) execute l:argidx.'argadd' fnameescape(l:file) endif endif " edit on argument list if required if index(argv(), l:file) isnot -1 let l:pre .= 'arg' " set arglist index to edited file endif " open correct file and place cursor at position spec execute l:pre.'edit' fnameescape(l:file) return fetch#setpos(l:pos) endfunction " Place the current buffer's cursor at {pos}: " @signature: fetch#setpos({pos:List}) " @returns: Boolean " @notes: triggers the |User| events " - BufFetchPosPre before setting the position " - BufFetchPosPost after setting the position function! fetch#setpos(pos) abort silent doautocmd User BufFetchPosPre let b:fetch_lastpos = [max([a:pos[0], 1]), max([get(a:pos, 1, 0), 1])] call cursor(b:fetch_lastpos[0], b:fetch_lastpos[1]) silent! normal! zOzz silent doautocmd User BufFetchPosPost return getpos('.')[1:2] == b:fetch_lastpos endfunction let &cpo = s:cpo unlet! s:cpo " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: doc/vim-fetch.txt [[[1 163 *vim-fetch.txt* For Vim version 7.0 or better version 1.3.0 VIM REFERENCE for the Fetch plug-in Jump to lines and columns specified in buffer names *vim-fetch* 1. Introduction |vim-fetch-introduction| 2. Usage |vim-fetch-usage| 3. Position specifications |vim-fetch-specs| 4. Troubleshooting |vim-fetch-troubleshooting| 5. Credits and license |vim-fetch-credits-license| {not available when |'compatible'| is set} ============================================================================== 1. Introduction *vim-fetch-introduction* vim-fetch enables Vim to process line and column jump specifications in file paths as found in stack traces and similar output. When asked to open such a file, Vim with vim-fetch will jump to the specified line (and column, if given) instead of displaying an empty, new file. ============================================================================== 2. Usage *vim-fetch-usage* FROM OUTSIDE VIM: > vim path/to/file.ext:12:3 < will open `file.ext` and jump to line 12, column 3. This works for multiple files (|arglist| passing) in any mix of spec'ed and unspec'ed paths, and with all Vim |windows-opening| switches ('-o', '-O', and '-p' if compiled with |+windows|) FROM INSIDE VIM: > :e[dit] path/to/file.ext:100:12 < will open `file.ext` and jump to line 100, column 12. This works for any command that opens files with |edit| semantics, including |argedit|, |pedit| and |diffsplit| on local file systems (e.g. not for |netrw| remote editing). INTEGRATION: 1. position buffer local variable *b:fetch_lastpos* After processing a spec for a buffer, vim-spec sets a buffer-local variable, > let b:fetch_lastpos = [lnum, colnum] < You can use the presence and / or values of that variable to integrate with vim-fetch. 2. autocommand API *BufFetchPosPre* *BufFetchPosPost* vim-fetch triggers two |User| autocommand events when setting the position in a buffer: `BufFetchPosPre` before and `BufFetchPosPost` after. Notes: - BufFetchPosPost is fired if the position fetch function completes, it does not guarantee the final position of the cursor. - The events are triggered with |:silent| to avoid flooding message history with "No matching autocommands" messages. Use |:unsilent| to restore normal message processing, i.e. > autocmd User BufFetchPosPre unsilent echomsg 'Gotcha!' < ============================================================================== 3. Position specifications *vim-fetch-specs* vim-fetch understands the following position specifications: COLON SEPARATED 1. path/to/file.ext:lnum 2. path/to/file.ext:lnum: 3. path/to/file.ext:lnum:colnum 4. path/to/file.ext:lnum:colnum: PARENTHESES ENCLOSED 5. path/to/file.ext(lnum) 6. path/to/file.ext(lnum:colnum) PLAN 9 STYLE 7. path/to/file.ext:#lnum Note: `#` is the alternate file token and needs to be escaped to be used on the command line (see |cmdline-special|). OTHER SPEC TYPES If you would you like to see other specs in vim-fetch, open an issue (or even better: send a PR) for them at https://github.com/kopischke/vim-fetch ============================================================================== 4. Troubleshooting *vim-fetch-troubleshooting* I HAVE FILES WITH THE POSITION SPEC IN MY BUFFER (ARG) LIST vim-fetch uses the |BufWinEnter| event to trigger the loading; if your buffers have never actually entered a window yet, they are still listed in their spec'ed form. Correct loading will happen when you select them for editing. I CAN'T JUMP TO LINE 8 If you use an edit command with a file token like `%` or `#` with a trailing colon spec and the line number is 8, Vim will parse that as the file name modifier |%:8|. Escape the first colon or prepend a 0 to the line number to avoid the issue. I TRIED TO EDIT A FILE WITH A PLAN 9 STYLE SPEC AND GOT ANOTHER FILE (OR E194) `#` is the alternate file token; you need to escape it to use it literally: > :e path/to/file.ext:\#lnum < I CAN'T JUMP TO LINES IN REMOTE FILES VIA NETRW This is by design: vim-fetch needs to check for readable files in both spec'ed and unspec'ed form. Doing that remotely, even when possible, would add too much latency to file opening. MY PROBLEM ISN'T LISTED HERE You might have found a bug. Please open an issue at https://github.com/kopischke/vim-fetch/issues Please do not forget to list the steps to reproduce the issue as well as your Vim version and platform. ============================================================================== 5. Credits and License *vim-fetch-credits-license* vim-fetch 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, the `file_line` plug-in by Victor Bogado (https://github.com/bogado/file-line). vim:tw=78:ts=8:ft=help:norl:noet:fen:fdl=0:fdm=marker: plugin/fetch.vim [[[1 41 " SIMPLIFIED TAKE ON BOGADO/FILE-LINE (HOPEFULLY) WITHOUT THE WARTS " Maintainer: Martin Kopischke " License: MIT (see LICENSE.md) " Version: 1.3.0 if &compatible || !has('autocmd') || v:version < 700 finish endif let s:cpo = &cpo set cpo&vim " Based on |BufNewFile|, but flanked by |BufWinEnter| to correctly process all " buffers in an |arglist| passed with '-o/-O' resp. '-p' (see " |windows-starting| for some background, though that omits to mention that " |BufRead| events are also skipped, as is |BufNewFile|, that |BufWinEnter| " events *are* fired for all buffers, and relies on implicitly understanding " that the first buffer of the list is activated after loading all files, but " that the usual event sequence still is out of kilter; also note there is no " equivalent help section for '-p' though its behaviour is analogous). " " Note the use of highly spec specific file name patterns to avoid autocommand " flooding when nesting (which is needed as we switch buffers out). let s:matchers = { \ 'colon': '?*:[0123456789]*', \ 'paren': '?*([0123456789]*)', \ 'plan9': '?*#[0123456789]*', \ } augroup fetch autocmd! for [s:spec, s:pat] in items(s:matchers) execute 'autocmd BufNewFile,BufWinEnter' s:pat \ 'nested call fetch#edit(expand(""), "'.s:spec.'")' unlet! s:spec s:pat endfor augroup END let &cpo = s:cpo unlet! s:cpo " vim:set sw=2 sts=2 ts=2 et fdm=marker fmr={{{,}}}: