mirror of
https://github.com/preservim/tagbar.git
synced 2025-02-13 19:22:45 +08:00
Improved s:EscapeCtagsCmd() for windows cmd.exe to eliminate issues when
a:ctags_bin calls a batch file that uses %~dp0. Changes include: - Enable ctags_args to be a list - Changed default ctags_args to be a list to improve robustness of s:EscapeCtagsCmd() - Do not escape 0th argument of ctags_cmd for cmd.exe when it is not necessary because otherwise batch files may not return expected value for %~dp0 - Updated tagbar documentation about string and list value types for ctags_args See https://github.com/majutsushi/tagbar/issues/133
This commit is contained in:
parent
dec1f840fb
commit
d0df97040b
|
@ -982,7 +982,7 @@ function! s:CreateAutocommands() abort
|
|||
endfunction
|
||||
|
||||
" s:PauseAutocommands() {{{2
|
||||
" Toggle autocommands
|
||||
" Toggle autocommands
|
||||
function! s:PauseAutocommands() abort
|
||||
if s:autocommands_enabled == 1
|
||||
autocmd! TagbarAutoCmds
|
||||
|
@ -2029,19 +2029,31 @@ function! s:ExecuteCtagsOnFile(fname, realfname, ftype) abort
|
|||
|
||||
let typeinfo = s:known_types[a:ftype]
|
||||
|
||||
if has_key(typeinfo, 'ctagsargs')
|
||||
if has_key(typeinfo, 'ctagsargs') && type(typeinfo.ctagsargs)==type(' ')
|
||||
"if ctagsargs is a string, prepend and append space seperators
|
||||
let ctags_args = ' ' . typeinfo.ctagsargs . ' '
|
||||
elseif has_key(typeinfo, 'ctagsargs') && type(typeinfo.ctagsargs)==type([])
|
||||
let ctags_args = typeinfo.ctagsargs
|
||||
"otherwise ctagsargs is not defined or not defined as a valid type
|
||||
else
|
||||
let ctags_args = ' -f - '
|
||||
let ctags_args .= ' --format=2 '
|
||||
let ctags_args .= ' --excmd=pattern '
|
||||
let ctags_args .= ' --fields=nksSa '
|
||||
let ctags_args .= ' --extra= '
|
||||
let ctags_args .= ' --sort=yes '
|
||||
"Prefer constructing ctags_args as a list rather than a string
|
||||
"See s:EscapeCtagsCmd() - It's a best practice to shellescape()
|
||||
"each arg separately because in special cases where space is
|
||||
"intended to be in an argument, spaces in a single ctag_args
|
||||
"string would be ambiguous. Is the space an argument separator
|
||||
"or to be included in the argument
|
||||
let ctags_args = [ '-f',
|
||||
\ '-',
|
||||
\ '--format=2',
|
||||
\ '--excmd=pattern',
|
||||
\ '--fields=nksSa',
|
||||
\ '--extra=',
|
||||
\ '--sort=yes'
|
||||
\ ]
|
||||
|
||||
" Include extra type definitions
|
||||
if has_key(typeinfo, 'deffile')
|
||||
let ctags_args .= ' --options=' . typeinfo.deffile . ' '
|
||||
let ctags_args += ['--options=' . typeinfo.deffile]
|
||||
endif
|
||||
|
||||
let ctags_type = typeinfo.ctagstype
|
||||
|
@ -2051,8 +2063,8 @@ function! s:ExecuteCtagsOnFile(fname, realfname, ftype) abort
|
|||
let ctags_kinds .= kind.short
|
||||
endfor
|
||||
|
||||
let ctags_args .= ' --language-force=' . ctags_type .
|
||||
\ ' --' . ctags_type . '-kinds=' . ctags_kinds . ' '
|
||||
let ctags_args += ['--language-force=' . ctags_type]
|
||||
let ctags_args += ['--' . ctags_type . '-kinds=' . ctags_kinds]
|
||||
endif
|
||||
|
||||
if has_key(typeinfo, 'ctagsbin')
|
||||
|
@ -3194,32 +3206,79 @@ endfunction
|
|||
" Assemble the ctags command line in a way that all problematic characters are
|
||||
" properly escaped and converted to the system's encoding
|
||||
" Optional third parameter is a file name to run ctags on
|
||||
" Note: The second parameter (a:args) can be a list of args or
|
||||
" a single string of the args.
|
||||
" When a:args is a list, each argument in the list will be escaped for the
|
||||
" current &shell type.
|
||||
" When a:args is a string, all arguments should be escaped appropriately
|
||||
" (if required). In most use cases no escaping is required so a string
|
||||
" is acceptable. But in cases where arguments may need to be escaped
|
||||
" differently for each &shell type, then pass a list of arguments.
|
||||
function! s:EscapeCtagsCmd(ctags_bin, args, ...) abort
|
||||
call s:LogDebugMessage('EscapeCtagsCmd called')
|
||||
call s:LogDebugMessage('ctags_bin: ' . a:ctags_bin)
|
||||
call s:LogDebugMessage('ctags_args: ' . a:args)
|
||||
if type(a:args)==type('')
|
||||
call s:LogDebugMessage('ctags_args (is a string): ' . a:args)
|
||||
elseif type(a:args)==type([])
|
||||
call s:LogDebugMessage('ctags_args (is a list): ' . string(a:args))
|
||||
endif
|
||||
|
||||
if exists('+shellslash')
|
||||
let shellslash_save = &shellslash
|
||||
set noshellslash
|
||||
endif
|
||||
|
||||
if a:0 == 1
|
||||
let fname = shellescape(a:1)
|
||||
"Set up 0th argument of ctags_cmd
|
||||
"a:ctags_bin may have special characters that require escaping.
|
||||
if &shell =~ 'cmd\.exe$' && a:ctags_bin !~ '\s'
|
||||
"For windows cmd.exe, escaping the 0th argument can cause
|
||||
"problems if it references a batch file and the batch file uses %~dp0.
|
||||
"So for windows cmd.exe, only escape the 0th argument iff necessary.
|
||||
"Only known necessary case is when ctags_bin executable filename has
|
||||
"whitespace character(s).
|
||||
|
||||
" Example: If 0th argument is wrapped in double quotes AND it is not
|
||||
" an absolute path to ctags_bin, but rather an executable in %PATH%,
|
||||
" then %~dp0 resolves to the current working directory rather than
|
||||
" the batch file's directory. Batch files like this generally exepect
|
||||
" and depend on %~dp0 to resolve the batch file's directory.
|
||||
" Note: Documentation such as `help cmd.exe` and
|
||||
" http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true
|
||||
" suggest other special characters that require escaping for command
|
||||
" line completion. But tagbar.vim does not use the command line
|
||||
" completion feature of cmd.exe and testing shows that the only special
|
||||
" character that needs to be escaped for tagbar.vim is <space> for
|
||||
" windows cmd.exe.
|
||||
let ctags_cmd = a:ctags_bin
|
||||
else
|
||||
let fname = ''
|
||||
let ctags_cmd = shellescape(a:ctags_bin)
|
||||
endif
|
||||
|
||||
let ctags_cmd = shellescape(a:ctags_bin) . ' ' . a:args . ' ' . fname
|
||||
"Add additional arguments to ctags_cmd
|
||||
if type(a:args)==type('')
|
||||
"When a:args is a string, append the arguments
|
||||
"Note: In this case, do not attempt to shell escape a:args string.
|
||||
"This function expects the string to already be escaped properly for
|
||||
"the shell type. Why not escape? Because it could be ambiguous about
|
||||
"whether a space is an argument separator or included in the argument.
|
||||
"Since escaping rules vary from shell to shell, it is better to pass a
|
||||
"list of arguments to a:args. With a list, each argument is clearly
|
||||
"separated, so shellescape() can calculate the appropriate escaping
|
||||
"for each argument for the current &shell.
|
||||
let ctags_cmd .= ' ' . a:args
|
||||
elseif type(a:args)==type([])
|
||||
"When a:args is a list, shellescape() each argument and append ctags_cmd
|
||||
"Note: It's a better practice to shellescape() each argument separately so that
|
||||
"spaces used as a separator between arguments can be distinguished with
|
||||
"spaces used inside a single argument.
|
||||
for arg in a:args
|
||||
let ctags_cmd .= ' ' . shellescape(arg)
|
||||
endfor
|
||||
endif
|
||||
|
||||
" Stupid cmd.exe quoting
|
||||
if &shell =~ 'cmd\.exe'
|
||||
let reserved_chars = '&()@^'
|
||||
" not allowed in filenames, but escape anyway just in case
|
||||
let reserved_chars .= '<>|'
|
||||
let pattern = join(split(reserved_chars, '\zs'), '\|')
|
||||
let ctags_cmd = substitute(ctags_cmd, '\V\(' . pattern . '\)',
|
||||
\ '^\0', 'g')
|
||||
"if a filename was specified, add filename as final argument to ctags_cmd.
|
||||
if a:0 == 1
|
||||
let ctags_cmd .= ' ' . shellescape(a:1)
|
||||
endif
|
||||
|
||||
if exists('+shellslash')
|
||||
|
@ -3588,7 +3647,7 @@ function! tagbar#RestoreSession() abort
|
|||
endfunction
|
||||
|
||||
function! tagbar#PauseAutocommands() abort
|
||||
call s:PauseAutocommands()
|
||||
call s:PauseAutocommands()
|
||||
endfunction
|
||||
|
||||
" }}}2
|
||||
|
|
|
@ -268,7 +268,7 @@ COMMANDS *tagbar-commands*
|
|||
an alias for ":TagbarOpen fjc".
|
||||
|
||||
:TagbarTogglePause *:TagbarTogglePause*
|
||||
Freezes/Unfreezes the Tagbar window. Stops the contents of the window
|
||||
Freezes/Unfreezes the Tagbar window. Stops the contents of the window
|
||||
from changing when a different source file is selected.
|
||||
|
||||
:TagbarSetFoldlevel[!] {number} *:TagbarSetFoldlevel*
|
||||
|
@ -793,6 +793,25 @@ ctagsargs: The arguments to be passed to the filetype-specific ctags program
|
|||
program output its data on stdout. Not used for the normal ctags
|
||||
program.
|
||||
|
||||
The value of ctagsargs may be a |List| of strings (a string for
|
||||
each argument), or a single string (|expr-string|) of all the
|
||||
arguments.
|
||||
|
||||
When the value of ctagsargs is a list, tagbar.vim takes care of
|
||||
escaping each argument in the list as required for the current
|
||||
|'shell'| type.
|
||||
|
||||
When the value of ctagsargs is a string, it must be properly
|
||||
escaped (if required by the current shell type). The reason
|
||||
tagbar.vim does not attempt to escape the string in this case is
|
||||
because if there is a space, it is ambiguous as to whether the
|
||||
space is delimiting an argument or included in the argument. To
|
||||
avoid this amiguity, tagbar.vim expects the string to be already
|
||||
escaped as required.
|
||||
|
||||
If special escaping is required for different OS shell types or if
|
||||
in doubt, then it is recommended to define ctagsargs with a List.
|
||||
|
||||
|
||||
You then have to assign this dictionary to a variable in your vimrc with the
|
||||
name
|
||||
|
|
Loading…
Reference in New Issue
Block a user