mirror of
https://github.com/junegunn/fzf.vim.git
synced 2026-09-27 22:22:22 +08:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9705771895 | ||
|
|
c228c70ee3 | ||
|
|
a5717367fc | ||
|
|
88b0ae41c8 | ||
|
|
d538da05b6 | ||
|
|
a630ef91e1 | ||
|
|
8a0068127a |
+45
-7
@@ -498,7 +498,10 @@ function! fzf#vim#paste(items) abort
|
||||
return s:warn('Cannot paste into a nomodifiable buffer')
|
||||
endif
|
||||
let line = getline('.')
|
||||
let idx = empty(line) ? 0 : col('.')
|
||||
" col('.') is the first byte of the character under the cursor. Skip the
|
||||
" whole character so that a multibyte character is not split in half.
|
||||
let cursor = col('.') - 1
|
||||
let idx = empty(line) ? 0 : cursor + strlen(matchstr(line, '.', cursor))
|
||||
let head = strpart(line, 0, idx)
|
||||
let tail = strpart(line, idx)
|
||||
let pad = (!empty(head) && head !~ '\s$') ? ' ' : ''
|
||||
@@ -531,6 +534,30 @@ function! s:execute_silent(cmd)
|
||||
silent keepjumps keepalt execute a:cmd
|
||||
endfunction
|
||||
|
||||
" A tag address can be any Ex command, and a tags file can come from an
|
||||
" untrusted source, so run it in a sandbox as a builtin tag jump does
|
||||
function! s:execute_tag_address(excmd)
|
||||
silent keepjumps keepalt sandbox execute a:excmd
|
||||
endfunction
|
||||
|
||||
" Address of a tag, given the rest of the line after the file name. Only the
|
||||
" forms a tags file is meant to hold, a line number and a search pattern,
|
||||
" chained with ';' for '--excmd=combine' and cut at the ';"' terminator as
|
||||
" Vim's find_extra() does. The last pattern can be left unterminated, as a
|
||||
" field holding a tab arrives cut short; it then runs to the end of the line,
|
||||
" taking any '|' or ';' with it, so it cannot chain a command. Returns an
|
||||
" empty string for anything else, which is then not run.
|
||||
let s:tag_address_part = '\%(\d\+\|/\%(\\.\|[^/\\]\)*/\|?\%(\\.\|[^?\\]\)*?\)'
|
||||
let s:tag_address_open = '\%(/\%(\\.\|[^/\\]\)*\|?\%(\\.\|[^?\\]\)*\)'
|
||||
function! s:tag_address(rest)
|
||||
" :BTags aligns its columns, so its field arrives padded
|
||||
let rest = s:strip(a:rest)
|
||||
let address = matchstr(rest,
|
||||
\ '^'.s:tag_address_part.'\%(;'.s:tag_address_part.'\)*\ze\%(;"\|$\)')
|
||||
return empty(address) ? matchstr(rest,
|
||||
\ '^\%('.s:tag_address_part.';\)*'.s:tag_address_open.'$') : address
|
||||
endfunction
|
||||
|
||||
" [key, [filename, [stay_on_edit: 0]]]
|
||||
function! s:action_for(key, ...)
|
||||
let Cmd = get(get(g:, 'fzf_action', s:default_action), a:key, '')
|
||||
@@ -726,7 +753,7 @@ function! s:goto_entry(winid, bufnr, dir, kind, entry) abort
|
||||
if len(parts) < 3
|
||||
return
|
||||
endif
|
||||
let excmd = matchstr(join(parts[2:-2], '')[:-2], '^.\{-}\ze;\?"\t')
|
||||
let excmd = s:tag_address(join(parts[2:-2], '')[:-2])
|
||||
let relpath = parts[1][:-2]
|
||||
let path = relpath =~ (s:is_win ? '^[A-Z]:\' : '^/')
|
||||
\ ? relpath : join([fnamemodify(parts[-1], ':h'), relpath], '/')
|
||||
@@ -735,14 +762,18 @@ function! s:goto_entry(winid, bufnr, dir, kind, entry) abort
|
||||
return
|
||||
endif
|
||||
let cmds = s:edit_cmds(a:winid, path)
|
||||
\ + ['keepjumps '.excmd, 'normal! ^zvzz']
|
||||
\ + ['sandbox keepjumps '.excmd, 'normal! ^zvzz']
|
||||
elseif a:kind ==# 'btags'
|
||||
let parts = split(entry, "\t")
|
||||
if len(parts) < 3 || !bufexists(a:bufnr)
|
||||
return
|
||||
endif
|
||||
let excmd = s:tag_address(parts[2])
|
||||
if empty(excmd)
|
||||
return
|
||||
endif
|
||||
let cmds = ['keepalt keepjumps hide buffer '.a:bufnr,
|
||||
\ 'keepjumps '.parts[2], 'normal! zvzz']
|
||||
\ 'sandbox keepjumps '.excmd, 'normal! zvzz']
|
||||
elseif a:kind ==# 'marks'
|
||||
" A lowercase mark is local to the buffer the run started on
|
||||
let mark = matchstr(entry, '^\s*\zs\S')
|
||||
@@ -1651,7 +1682,11 @@ function! s:btags_sink(from, lines)
|
||||
let qfl = []
|
||||
for line in a:lines[1:]
|
||||
let parts = split(line, "\t")
|
||||
call s:execute_silent(parts[2])
|
||||
let excmd = s:tag_address(parts[2])
|
||||
if empty(excmd)
|
||||
continue
|
||||
endif
|
||||
call s:execute_tag_address(excmd)
|
||||
call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')})
|
||||
if empty(tagname)
|
||||
let tagname = s:strip(parts[0])
|
||||
@@ -1721,7 +1756,7 @@ function! s:tags_sink(from, lines)
|
||||
for line in list
|
||||
try
|
||||
let parts = split(line, '\t\zs')
|
||||
let excmd = matchstr(join(parts[2:-2], '')[:-2], '^.\{-}\ze;\?"\t')
|
||||
let excmd = s:tag_address(join(parts[2:-2], '')[:-2])
|
||||
let base = fnamemodify(parts[-1], ':h')
|
||||
let relpath = parts[1][:-2]
|
||||
let abspath = relpath =~ (s:is_win ? '^[A-Z]:\' : '^/') ? relpath : join([base, relpath], '/')
|
||||
@@ -1731,7 +1766,10 @@ function! s:tags_sink(from, lines)
|
||||
else
|
||||
call s:open(expand(abspath, 1))
|
||||
endif
|
||||
call s:execute_silent(excmd)
|
||||
if empty(excmd)
|
||||
continue
|
||||
endif
|
||||
call s:execute_tag_address(excmd)
|
||||
call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')})
|
||||
if empty(tagname)
|
||||
let tagname = s:strip(parts[0])
|
||||
|
||||
+4
-1
@@ -30,9 +30,12 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The address comes from a tags file, which can be untrusted, and a preview
|
||||
# runs as soon as an entry is highlighted. Sandboxed as a builtin tag jump is,
|
||||
# so that it cannot run a shell command or touch a file
|
||||
CENTER="$("${VIMNAME}" -R -i NONE -u NONE -e -m -s "${FILE}" \
|
||||
-c "set nomagic" \
|
||||
-c "silent ${EXCMD}" \
|
||||
-c "silent sandbox ${EXCMD}" \
|
||||
-c 'let l=line(".") | new | put =l | print | qa!')" || exit
|
||||
|
||||
START_LINE="$(( CENTER - FZF_PREVIEW_LINES / 2 ))"
|
||||
|
||||
Reference in New Issue
Block a user