You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1088 lines
33 KiB
VimL

" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 1393
if !exists('g:checksyntax#auto_enable_rx')
" Enable automatic checking for filetypes matching this rx.
" Set to "." to enable for all filetypes.
" This requires |g:checksyntax_auto| to be > 0.
" This variable overrules any filetype-specific settings in
" |g:checksyntax|.
let g:checksyntax#auto_enable_rx = '' "{{{2
endif
if !exists('g:checksyntax#auto_disable_rx')
" Disable automatic checking for filetypes matching this rx.
" Set to "." to disable for all filetypes.
" This requires |g:checksyntax_auto| to be > 0.
" This variable overrules any filetype-specific settings in
" |g:checksyntax|.
let g:checksyntax#auto_disable_rx = '' "{{{2
endif
if !exists('g:checksyntax#show_cmd')
" A dictionary of VIM commands that are used to display the qf/loc
" lists.
" If empty, do nothing.
let g:checksyntax#show_cmd = {'qfl': 'copen', 'loc': 'lopen'} "{{{2
endif
if !exists('g:checksyntax#lines_expr')
" A vim expression that determines the number of lines of the
" qfl/loc window. If empty, don't set the size.
" A useful value is: >
" let g:checksyntax#lines_expr = 'min([&previewheight, &lines / 2, len(getloclist(0))])'
let g:checksyntax#lines_expr = '' "{{{2
endif
if !exists('g:checksyntax#debug')
let g:checksyntax#debug = 0
endif
if !exists('g:checksyntax#preferred')
" A dictionary of 'filetype' => |regexp|.
" If only one alternative should be run (see
" |g:checksyntax#run_alternatives|), check only those syntax
" checkers whose names matches |regexp|.
let g:checksyntax#preferred = {'xml': '.'} "{{{2
endif
if !exists('g:checksyntax#async_runner')
" Supported values:
" asynccommand ... Use the AsyncCommand plugin
let g:checksyntax#async_runner = has('clientserver') && !empty(v:servername) && exists(':AsyncMake') ? 'asynccommand' : '' "{{{2
if has('clientserver') && empty(v:servername)
echohl WarningMsg
echom "CheckSyntax: Run vim with the --servername NAME command line option to enable use of AsyncCommand"
echohl NONE
endif
endif
if !empty(g:checksyntax#async_runner)
" Show status information (pending async tasks).
command! CheckSyntaxStatus call s:Status()
endif
if !exists('g:checksyntax#run_alternatives')
" How to handle alternatives. Possible values:
"
" first ... Use the first valid entry
" all ... Run all valid alternatives one after another
"
" Alternatively, the following flag can be added in order to change
" how the alternatives are run:
"
" async ... Run alternatives asynchronously (see also
" |g:checksyntax#async_runner|)
let g:checksyntax#run_alternatives = 'first' . (!empty(g:checksyntax#async_runner) ? ' async' : '') "{{{2
endif
if !exists('g:checksyntax#run_all_alternatives')
" How to run "all" alternatives -- e.g., when calling the
" |:CheckSyntax| command with a bang.
let g:checksyntax#run_all_alternatives = 'all' . (!empty(g:checksyntax#async_runner) ? ' async' : '') "{{{2
endif
if !exists('g:checksyntax#windows')
let g:checksyntax#windows = &shell !~ 'sh' && (has('win16') || has('win32') || has('win64')) "{{{2
endif
if !exists('g:checksyntax#null')
let g:checksyntax#null = g:checksyntax#windows ? 'nul' : (filereadable('/dev/null') ? '/dev/null' : '') "{{{2
endif
if !exists('g:checksyntax#cygwin_path_rx')
" If a full windows filename (with slashes instead of backslashes)
" matches this |regexp|, it is assumed to be a cygwin executable.
let g:checksyntax#cygwin_path_rx = '/cygwin/' "{{{2
endif
if !exists('g:checksyntax#cygwin_expr')
" For cygwin binaries, convert command calls using this vim
" expression.
let g:checksyntax#cygwin_expr = '"bash -c ''". escape(%s, "''\\") ."''"' "{{{2
endif
let s:cygwin = {}
function! s:CygwinBin(cmd) "{{{3
" TLogVAR a:cmd
if !g:checksyntax#windows
return 0
elseif has_key(s:cygwin, a:cmd)
let rv = s:cygwin[a:cmd]
else
if !s:Executable('cygpath', 1) || !s:Executable('which', 1)
let rv = 0
else
let which = substitute(system('which '. shellescape(a:cmd)), '\n$', '', '')
" echom "DBG which:" which
if which =~ '^/'
let filename = system('cygpath -ma '. shellescape(which))
" echom "DBG filename:" filename
let rv = filename =~ g:checksyntax#cygwin_path_rx
else
let rv = 0
endif
endif
let s:cygwin[a:cmd] = rv
endif
" TLogVAR rv
return rv
endf
let s:executables = {}
function! s:Executable(cmd, ...) "{{{3
" TLogVAR a:cmd
" echom "DBG has_key(s:executables, a:cmd)" has_key(s:executables, a:cmd)
if !has_key(s:executables, a:cmd)
let ignore_cyg = a:0 >= 1 ? a:1 : !g:checksyntax#windows
let s:executables[a:cmd] = executable(a:cmd) != 0 && (ignore_cyg || s:CygwinBin(a:cmd))
endif
" echom "DBG s:executables[a:cmd]" s:executables[a:cmd]
return s:executables[a:cmd]
endf
if !exists('g:checksyntax#check_cygpath')
" If true, check whether we have to convert a path via cyppath --
" see |checksyntax#MaybeUseCygpath|
let g:checksyntax#check_cygpath = g:checksyntax#windows && s:Executable('cygpath') "{{{2
endif
if !exists('*CheckSyntaxSucceed')
" This function is called when no syntax errors were found.
function! CheckSyntaxSucceed(type, manually)
call g:checksyntax#prototypes[a:type].Close()
if a:manually
echo
echo 'Syntax ok.'
endif
endf
endif
if !exists('*CheckSyntaxFail')
" This function is called when a syntax error was found.
function! CheckSyntaxFail(type, manually, bg)
" TLogVAR a:type, a:manually, a:bg
call g:checksyntax#prototypes[a:type].Open(a:bg)
endf
endif
if !exists('g:checksyntax#prototypes')
" Contains prototype definitions for syntax checkers that use the
" |location-list| ("loc") or the |quixfix|-list.
let g:checksyntax#prototypes = {'loc': {}, 'qfl': {}} "{{{2
endif
function! s:Open(bg, type) "{{{3
" TLogVAR a:bg
let cmd = get(g:checksyntax#show_cmd, a:type, '')
if !empty(cmd)
if !empty(g:checksyntax#lines_expr)
let lines = eval(g:checksyntax#lines_expr)
else
let lines = ''
endif
" TLogVAR lines
if empty(g:checksyntax#lines_expr) || !empty(lines)
let bufnr = bufnr('%')
let winnr = winnr()
exec cmd lines
if a:bg && bufnr != bufnr('%')
wincmd p
endif
endif
endif
endf
if empty(g:checksyntax#prototypes.loc)
function! g:checksyntax#prototypes.loc.Close() dict "{{{3
lclose
endf
function! g:checksyntax#prototypes.loc.Open(bg) dict "{{{3
call s:Open(a:bg, 'loc')
endf
function! g:checksyntax#prototypes.loc.GetExpr(args) dict "{{{3
" TLogDBG system(a:args)
return s:RunCmd('lgetexpr', 'system('. string(a:args). ')')
endf
function! g:checksyntax#prototypes.loc.Make(args) dict "{{{3
return s:RunCmd('lmake!', a:args)
endf
function! g:checksyntax#prototypes.loc.Get() dict "{{{3
return copy(getloclist(0))
endf
function! g:checksyntax#prototypes.loc.Set(list) dict "{{{3
call setloclist(0, a:list)
endf
endif
if empty(g:checksyntax#prototypes.qfl)
function! g:checksyntax#prototypes.qfl.Close() dict "{{{3
cclose
endf
function! g:checksyntax#prototypes.qfl.Open(bg) dict "{{{3
call s:Open(a:bg, 'qfl')
endf
function! g:checksyntax#prototypes.qfl.GetExpr(args) dict "{{{3
" TLogDBG system(a:args)
return s:RunCmd('cgetexpr', 'system('. string(a:args). ')')
endf
function! g:checksyntax#prototypes.qfl.Make(args) dict "{{{3
return s:RunCmd('make!', a:args)
endf
function! g:checksyntax#prototypes.qfl.Get() dict "{{{3
return copy(getqflist())
endf
function! g:checksyntax#prototypes.qfl.Set(list) dict "{{{3
call setqflist(a:list)
endf
endif
function! s:RunCmd(cmd, args) "{{{3
try
" TLogVAR a:cmd, a:args, &efm
exec 'silent' a:cmd a:args
return 1
catch
echohl Error
echom v:exception
echohl NONE
return 0
endtry
endf
let s:checkers = {}
let s:top_level_fields = ['modified', 'auto', 'run_alternatives', 'alternatives']
let s:mandatory = ['cmd', 'cmdexpr', 'compiler', 'exec']
" Define a syntax checker definition for a given filetype.
" If filetype ends with "?", add only if no checker with the given name
" is defined.
"
" A checker definition is a dictionary with the following fields:
"
" Mandatory (either one of the following):
"
" cmd ........ A shell command used as 'makeprg' to check the file.
" cmdexpr .... A vim expression that returns the cmd
" compiler ... A vim compiler that is used to check the file.
" exec ....... A vim command used to check the file (deprecated; use
" cmdexpr & process_list instead)
"
" Optional:
"
" efm ....... An 'errorformat' string.
" prepare .... An ex command that is run before doing anything.
" ignore_nr .. A list of error numbers that should be ignored.
" listtype ... Either loc (default) or qfl
" include .... Include another definition
" process_list .. Process a list of issues
" if ......... An expression to test *once* whether a syntax checker
" should be used.
" if_executable .. Test whether an application is executable.
" buffers .... Keep results only for either "current", "listed", or
" "all" buffers
" compiler_args .. Internal use
" cmd_args ... Internal use
"
" Optional top-level fields:
"
" auto ....... Run automatically when saving a file (see also
" |g:checksyntax#auto_enable_rx| and
" |g:checksyntax#auto_disable_rx|)
" modified ... The name of a pseudo-filetype that should be used if
" the buffer was modified
" run_alternatives ... A string that defines how to run
" alternatives (overrides
" |g:checksyntax#run_alternatives|).
"
" Top-level fields affect how syntax checkers for a filetype are run.
function! checksyntax#AddChecker(filetype, ...) "{{{3
if a:0 == 1 && type(a:1) == 3
let alternatives = a:1
else
let alternatives = a:000
endif
" TLogVAR alternatives
if !empty(alternatives)
let [update, filetype] = s:UpName(a:filetype)
" TLogVAR filetype, update, a:000, a:0, type(a:1)
if !has_key(s:checkers, filetype)
let s:checkers[filetype] = {'alternatives': {}, 'order': []}
endif
for make_def in alternatives
" Copy top_level_fields
for upkey in s:top_level_fields
let [kupdate, key] = s:UpName(upkey)
if has_key(make_def, key) && (kupdate || !has_key(s:checkers[filetype], key))
let s:checkers[filetype][key] = remove(make_def, key)
endif
endfor
" If there are other fields, add make_def
if !empty(make_def)
if has_key(make_def, 'cmdexpr')
let make_def.cmd = eval(make_def.cmdexpr)
endif
" TLogVAR make_def
if !has_key(make_def, 'cmd') || !empty(make_def.cmd)
let [update_name, name] = s:UpNameFromDef(make_def)
if empty(name)
throw "CheckSyntax: Name must not be empty: ". filetype .': '. string(make_def)
elseif empty(filter(copy(s:mandatory), 'has_key(make_def, v:val)'))
throw "CheckSyntax: One of ". join(s:mandatory, ', ') ." must be defined: ". filetype .': '. string(make_def)
else
let new_item = !has_key(s:checkers[filetype].alternatives, name)
if update || update_name || new_item
let s:checkers[filetype].alternatives[name] = make_def
if new_item
call add(s:checkers[filetype].order, name)
endif
endif
endif
endif
endif
endfor
endif
endf
function! checksyntax#GetChecker(filetype, ...) "{{{3
call checksyntax#Require(a:filetype)
let alts = get(get(s:checkers, a:filetype, {}), 'alternatives', {})
if a:0 == 0
return values(alts)
else
return values(filter(copy(alts), 'index(a:000, v:key) != -1'))
endif
endf
" :nodoc:
" Run |:make| based on a syntax checker definition.
function! s:RunSyncWithEFM(make_def) "{{{3
" TLogVAR a:make_def
let type = get(a:make_def, 'listtype', 'loc')
let shellpipe = &shellpipe
let errorformat = &errorformat
if has_key(a:make_def, 'shellpipe')
let &shellpipe = get(a:make_def, 'shellpipe')
" TLogVAR &shellpipe
endif
if has_key(a:make_def, 'efm')
let &errorformat = get(a:make_def, 'efm')
" TLogVAR &errorformat
endif
try
if has_key(a:make_def, 'cmd')
let cmddef = s:ExtractCompilerParams(a:make_def, '%', a:make_def.cmd)
let cmd = s:NativeCmd(cmddef.cmd)
" TLogVAR cmd
let rv = g:checksyntax#prototypes[type].GetExpr(cmd)
" TLogVAR rv, getqflist()
return rv
elseif has_key(a:make_def, 'exec')
exec a:make_def.exec
return 1
endif
finally
if &shellpipe != shellpipe
let &shellpipe = shellpipe
endif
if &errorformat != errorformat
let &errorformat = errorformat
endif
endtry
endf
let s:convert_filenames = {}
function! s:ConvertFilenames(make_def, props) "{{{3
for key in ['filename', 'altname']
let filename = a:props[key]
let convert_filename = get(a:make_def, 'convert_filename', '')
if !empty(convert_filename)
if !has_key(s:convert_filenames, convert_filename)
let s:convert_filenames[convert_filename] = {}
endif
if has_key(s:convert_filenames[convert_filename], filename)
let filename = s:convert_filenames[convert_filename][filename]
else
" TLogVAR filename, convert_filename
let cmd = printf(convert_filename, shellescape(filename))
" TLogVAR cmd
let filename = system(cmd)
let filename = substitute(filename, '\n$', '', '')
let s:convert_filenames[convert_filename][filename] = filename
endif
" TLogVAR filename
endif
let a:make_def[key] = filename
endfor
return a:make_def
endf
let s:loaded_checkers = {}
" :nodoc:
function! checksyntax#Require(filetype) "{{{3
if empty(a:filetype)
return 0
else
if !has_key(s:loaded_checkers, a:filetype)
exec 'runtime! autoload/checksyntax/defs/'. a:filetype .'.vim'
let s:loaded_checkers[a:filetype] = 1
endif
return has_key(s:checkers, a:filetype)
endif
endf
function! s:NativeCmd(cmd) "{{{3
if !empty(g:checksyntax#cygwin_expr) && s:CygwinBin(matchstr(a:cmd, '^\S\+'))
let cmd = eval(printf(g:checksyntax#cygwin_expr, string(a:cmd)))
" TLogVAR cmd
return cmd
else
return a:cmd
endif
endf
" :nodoc:
function! s:Cmd(make_def) "{{{3
if has_key(a:make_def, 'cmd')
let cmd = matchstr(a:make_def.cmd, '^\(\\\s\|\S\+\|"\([^"]\|\\"\)\+"\)\+')
else
let cmd = ''
endif
return cmd
endf
" :nodoc:
function! s:UpName(upname) "{{{3
if a:upname =~ '?$'
let update = 0
let name = substitute(a:upname, '?$', '', '')
else
let update = 1
let name = a:upname
endif
return [update, name]
endf
" :nodoc:
function! s:UpNameFromDef(make_def) "{{{3
let name = get(a:make_def, 'name', '')
if empty(name)
let name = get(a:make_def, 'compiler', '')
endif
if empty(name)
let name = s:Cmd(a:make_def)
endif
return s:UpName(name)
endf
function! s:ValidAlternative(make_def) "{{{3
" TLogVAR a:make_def
if has_key(a:make_def, 'if')
return eval(a:make_def.if)
elseif has_key(a:make_def, 'if_executable')
return s:Executable(a:make_def.if_executable)
else
return 1
endif
endf
function! s:GetValidAlternatives(filetype, run_alternatives, alternatives) "{{{3
" TLogVAR a:filetype, a:run_alternatives, a:alternatives
let valid = {}
for name in get(get(s:checkers, a:filetype, {}), 'order', [])
let alternative = a:alternatives[name]
" TLogVAR alternative
if s:ValidAlternative(alternative)
if has_key(alternative, 'cmd')
let cmd = s:Cmd(alternative)
" TLogVAR cmd
if !empty(cmd) && !s:Executable(cmd)
continue
endif
endif
let valid[name] = alternative
if a:run_alternatives =~? '\<first\>'
break
endif
endif
endfor
return valid
endf
let s:run_alternatives_all = 0
" :nodoc:
function! checksyntax#RunAlternativesMode(make_def) "{{{3
let rv = s:run_alternatives_all ? g:checksyntax#run_all_alternatives : get(a:make_def, 'run_alternatives', g:checksyntax#run_alternatives)
" TLogVAR a:make_def, rv
return rv
endf
function! s:GetDef(filetype) "{{{3
" TLogVAR a:filetype
if has_key(s:checkers, a:filetype)
let dict = s:checkers
let rv = s:checkers[a:filetype]
else
let dict = {}
let rv = {}
endif
if !empty(dict)
let alternatives = get(rv, 'alternatives', {})
" TLogVAR alternatives
if !empty(alternatives)
let alternatives = s:GetValidAlternatives(a:filetype, checksyntax#RunAlternativesMode(rv), alternatives)
" TLogVAR alternatives
if len(alternatives) == 0
let rv = {}
else
let rv = copy(rv)
let rv.alternatives = alternatives
endif
endif
endif
return rv
endf
let s:async_pending = {}
let g:checksyntax#issues = {}
function! g:checksyntax#issues.Reset() dict "{{{3
let self.issues = []
let self.type = 'loc'
endf
call g:checksyntax#issues.Reset()
function! g:checksyntax#issues.AddList(name, make_def, type) dict "{{{3
if a:type == 'qfl'
let self.type = a:type
endif
let issues = checksyntax#GetList(a:name, a:make_def, a:type)
if !empty(issues)
let self.issues += issues
endif
return issues
endf
function! g:checksyntax#issues.Display(manually, bg) dict "{{{3
if empty(self.issues)
call g:checksyntax#prototypes[self.type].Set(self.issues)
call CheckSyntaxSucceed(self.type, a:manually)
else
" TLogVAR self.issues
call sort(self.issues, 's:CompareIssues')
" TLogVAR self.issues
" TLogVAR self.type
call g:checksyntax#prototypes[self.type].Set(self.issues)
" TLogVAR self.type, a:manually, a:bg
call CheckSyntaxFail(self.type, a:manually, a:bg)
endif
endf
" :def: function! checksyntax#Check(manually, ?bang='', ?filetype=&ft, ?background=1)
" Perform a syntax check.
" If bang is not empty, run all alternatives (see
" |g:checksyntax#run_alternatives|).
" If filetype is empty, the current buffer's 'filetype' will be used.
" If background is true, display the list of issues in the background,
" i.e. the active window will keep the focus.
function! checksyntax#Check(manually, ...)
let bang = a:0 >= 1 ? !empty(a:1) : 0
let filetype = a:0 >= 2 && a:2 != '' ? a:2 : &filetype
let bg = a:0 >= 3 && a:3 != '' ? a:3 : 0
" TLogVAR a:manually, bang, filetype, bg
let s:run_alternatives_all = bang
if !&autochdir
let wd = getcwd()
exec 'lcd' fnameescape(expand('%:p'))
endif
try
let defs = s:GetDefsByFiletype(a:manually, filetype)
" TLogVAR defs
if !empty(defs.make_defs)
if !exists('b:checksyntax_runs')
let b:checksyntax_runs = 1
else
let b:checksyntax_runs += 1
endif
" TLogVAR &makeprg, &l:makeprg, &g:makeprg, &errorformat
if defs.run_alternatives =~? '\<first\>' && has_key(g:checksyntax#preferred, filetype)
let preferred_rx = g:checksyntax#preferred[filetype]
let defs.make_defs = filter(defs.make_defs, 's:UpNameFromDef(v:val)[1] =~ preferred_rx')
endif
let async = !empty(g:checksyntax#async_runner) && defs.run_alternatives =~? '\<async\>'
if !empty(s:async_pending)
if !a:manually && async
echohl WarningMsg
echo "CheckSyntax: Still waiting for async results ..."
echohl NONE
return
else
let s:async_pending = {}
endif
endif
let props = {
\ 'bg': bg,
\ 'bufnr': bufnr('%'),
\ 'filename': expand('%'),
\ 'altname': expand('#'),
\ 'manually': a:manually,
\ }
call g:checksyntax#issues.Reset()
for [name, make_def] in items(defs.make_defs)
" TLogVAR make_def, async
let make_def1 = copy(make_def)
let done = 0
if async
call extend(make_def1, props)
let make_def1 = s:ConvertFilenames(make_def1, make_def1)
let make_def1.name = name
let make_def1.job_id = name .'_'. make_def1.bufnr
let done = s:Run_async(make_def1)
endif
if !done
let make_def1 = s:ConvertFilenames(make_def1, props)
let done = s:Run_sync(name, filetype, make_def1)
endif
endfor
" echom "DBG 1" string(list)
if empty(s:async_pending)
call g:checksyntax#issues.Display(a:manually, bg)
endif
endif
finally
if !&autochdir
exec 'lcd' fnameescape(wd)
endif
let s:run_alternatives_all = 0
endtry
redraw!
endf
function! s:Status() "{{{3
if empty(s:async_pending)
echo "CheckSyntax: No pending jobs"
else
echo "CheckSyntax: Pending jobs:"
for [job_id, make_def] in items(s:async_pending)
echo printf(" %s: bufnr=%s, cmd=%s",
\ job_id,
\ make_def.bufnr,
\ make_def.name
\ )
endfor
endif
endf
function! s:GetDefsByFiletype(manually, filetype) "{{{3
" TLogVAR a:manually, a:filetype
let defs = {'mode': '', 'make_defs': {}}
call checksyntax#Require(a:filetype)
" let defs.mode = 'auto'
let make_def = a:manually ? {} : s:GetDef(a:filetype .',auto')
" TLogVAR 1, make_def
if empty(make_def)
let make_def = s:GetDef(a:filetype)
" TLogVAR 2, make_def
endif
if &modified
if has_key(make_def, 'modified')
let make_def = s:GetDef(make_def.modified)
" TLogVAR 3, make_def
else
echohl WarningMsg
echom "Buffer was modified. Please save it before calling :CheckSyntax."
echohl NONE
return
endif
endif
" TLogVAR make_def
if empty(make_def)
return defs
endif
if !empty(g:checksyntax#auto_enable_rx) && a:filetype =~ g:checksyntax#auto_enable_rx
let auto = 1
elseif !empty(g:checksyntax#auto_disable_rx) && a:filetype =~ g:checksyntax#auto_disable_rx
let auto = 0
else
let auto = get(make_def, 'auto', 0)
endif
" TLogVAR auto
if !(a:manually || auto)
return defs
endif
let defs.run_alternatives = checksyntax#RunAlternativesMode(make_def)
" TLogVAR &makeprg, &l:makeprg, &g:makeprg, &errorformat
" TLogVAR make_def
let defs.make_defs = get(make_def, 'alternatives', {'*': make_def})
return defs
endf
function! s:CompareIssues(i1, i2) "{{{3
let l1 = get(a:i1, 'lnum', 0)
let l2 = get(a:i2, 'lnum', 0)
" TLogVAR l1, l2, type(l1), type(l2)
return l1 == l2 ? 0 : l1 > l2 ? 1 : -1
endf
function! s:WithCompiler(compiler, exec, default) "{{{3
if exists('g:current_compiler')
let cc = g:current_compiler
else
let cc = ''
endif
try
exec 'compiler '. a:compiler
exec a:exec
finally
if cc != ''
let g:current_compiler = cc
exec 'compiler '. cc
endif
endtry
return a:default
endf
function! s:RunSyncChecker(filetype, make_def)
let bufnr = bufnr('%')
let pos = getpos('.')
let type = get(a:make_def, 'listtype', 'loc')
try
if has_key(a:make_def, 'compiler')
" <+TODO+> Use s:ExtractCompilerParams and run s:RunSyncWithEFM
let args = get(a:make_def, 'compiler_args', '%')
let rv = s:WithCompiler(a:make_def.compiler,
\ 'call g:checksyntax#prototypes[type].Make('. string(args) .')',
\ 1)
else
let rv = s:RunSyncWithEFM(a:make_def)
endif
" TLogVAR rv
return rv
catch
echohl Error
echom "Exception" v:exception "from" v:throwpoint
echom v:errmsg
echohl NONE
finally
" TLogVAR pos, bufnr
if bufnr != bufnr('%')
exec bufnr 'buffer'
endif
call setpos('.', pos)
endtry
return 0
endf
function! s:Run_async(make_def) "{{{3
" TLogVAR a:make_def
let make_def = a:make_def
let cmd = ''
if has_key(make_def, 'cmd')
let cmd = get(make_def, 'cmd', '')
" let cmd .= ' '. shellescape(make_def.filename)
if has_key(a:make_def, 'cmd_args')
let cmddef = s:ExtractCompilerParams(a:make_def, '', a:make_def.cmd)
let cmd = cmddef.cmd
else
let cmd .= ' '. escape(make_def.filename, '"''\ ')
endif
elseif has_key(make_def, 'compiler')
let compiler_def = s:WithCompiler(make_def.compiler,
\ 'return s:ExtractCompilerParams('. string(a:make_def) .', "")',
\ {})
" TLogVAR compiler_def
if !empty(compiler_def)
let cmd = compiler_def.cmd
let make_def.efm = compiler_def.efm
endif
endif
" TLogVAR cmd
if !empty(cmd)
try
let cmd = s:NativeCmd(cmd)
" TLogVAR cmd
let rv = checksyntax#async#{g:checksyntax#async_runner}#Run(cmd, make_def)
call checksyntax#AddJob(make_def)
return rv
catch /^Vim\%((\a\+)\)\=:E117/
echohl Error
echom 'Checksyntax: Unsupported value for g:checksyntax#async_runner: '. string(g:checksyntax#async_runner)
echohl NONE
let g:checksyntax#async_runner = ''
return 0
endtry
else
echohl WarningMsg
echom "CheckSyntax: Cannot run asynchronously: ". make_def.name
echohl NONE
return 0
endif
endf
function! s:ReplaceMakeArgs(make_def, cmd, args) "{{{3
let cmd = a:cmd
if !empty(a:args) && stridx(cmd, '$*') == -1
let cmd .= ' '. a:args
endif
let replaced = []
if stridx(cmd, '%') != -1
let cmd = substitute(cmd, '%\(\%(:[phtre]\)\+\)\?', '\=s:Filename(a:make_def, "%", submatch(1))', 'g')
call add(replaced, '%')
endif
if stridx(cmd, '$*') != -1
if index(replaced, '%') == -1
let cmd = substitute(cmd, '\V$*', a:args .' '. escape(a:make_def['filename'], '\'), 'g')
call add(replaced, '%')
else
let cmd = substitute(cmd, '\V$*', a:args, 'g')
endif
call add(replaced, '$*')
endif
if stridx(cmd, '#') != -1
let cmd = substitute(cmd, '#\(\%(:[phtre]\)\+\)\?', '\=s:Filename(a:make_def, "#", submatch(1))', 'g')
call add(replaced, '#')
endif
return cmd
endf
function! s:Filename(make_def, type, mod) "{{{3
if a:type == '%'
let filename = a:make_def.filename
elseif a:type == '#'
let filename = a:make_def.altname
else
throw "CheckSyntax/s:Filename: Internal error: type = ". a:type
endif
if !empty(a:mod)
let filename = fnamemodify(filename, a:mod)
endif
return escape(filename, '\')
endf
function! s:ExtractCompilerParams(make_def, args, ...) "{{{3
let cmd = a:0 >= 1 ? a:1 : &makeprg
let args = get(a:make_def, 'compiler_args', a:args)
let cmd = s:ReplaceMakeArgs(a:make_def, cmd, args)
let compiler_def = {
\ 'cmd': cmd,
\ 'efm': &errorformat
\ }
" TLogVAR compiler_def
return compiler_def
endf
let s:status_expr = 'checksyntax#Status()'
function! checksyntax#AddJob(make_def) "{{{3
let s:async_pending[a:make_def.job_id] = a:make_def
if exists('g:tstatus_exprs')
if index(g:tstatus_exprs, s:status_expr) == -1
call add(g:tstatus_exprs, s:status_expr)
endif
endif
endf
function! checksyntax#RemoveJob(job_id) "{{{3
let rv = has_key(s:async_pending, a:job_id)
if rv
call remove(s:async_pending, a:job_id)
if empty(s:async_pending) && exists('g:tstatus_exprs')
let idx = index(g:tstatus_exprs, s:status_expr)
if idx != -1
call remove(g:tstatus_exprs, idx)
endif
endif
endif
return rv ? len(s:async_pending) : -1
endf
function! checksyntax#Status() "{{{3
let n = len(s:async_pending)
if n == 0
return ''
else
return 'PendingChecks='. n
endif
endf
function! s:Run_sync(name, filetype, make_def) "{{{3
" TLogVAR a:name, a:filetype, a:make_def
let make_def = a:make_def
if has_key(make_def, 'include')
let include = s:GetDef(make_def.include)
if !empty(include)
let make_def = extend(copy(make_def), include, 'keep')
endif
endif
exec get(make_def, 'prepare', '')
if s:RunSyncChecker(a:filetype, make_def)
let type = get(make_def, 'listtype', 'loc')
call g:checksyntax#issues.AddList(a:name, make_def, type)
return 1
else
return 0
endif
endf
function! checksyntax#GetList(name, make_def, type) "{{{3
" TLogVAR a:type
let list = g:checksyntax#prototypes[a:type].Get()
" TLogVAR list
" TLogVAR 1, len(list), has_key(a:make_def, 'process_list')
if !empty(list) && has_key(a:make_def, 'process_list')
" TLogVAR a:make_def.process_list
let list = call(a:make_def.process_list, [list])
" TLogVAR 2, len(list)
endif
if !empty(list)
let list = filter(list, 's:FilterItem(a:make_def, v:val)')
" TLogVAR 3, len(list)
" TLogVAR a:type, list
if !empty(list)
let list = map(list, 's:CompleteItem(a:name, a:make_def, v:val)')
" TLogVAR 4, len(list)
" TLogVAR a:type, list
endif
endif
" TLogVAR "return", list
return list
endf
function! s:CompleteItem(name, make_def, val) "{{{3
" TLogVAR a:name, a:make_def, a:val
if get(a:val, 'bufnr', 0) == 0
let a:val.bufnr = bufnr('%')
endif
let text = get(a:val, 'text', '')
let a:val.text = substitute(text, '^\s\+\|\s\+$', '', 'g')
let type = get(a:val, 'type', '')
if !empty(type)
let a:val.text = printf('[%s] %s', type, a:val.text)
endif
if !empty(a:name)
let text = get(a:val, 'text', '')
if !empty(text)
let a:val.text = a:name .': '. text
endif
endif
" TLogVAR a:val
return a:val
endf
function! s:FilterItem(make_def, val) "{{{3
if a:val.lnum == 0 && a:val.pattern == ''
return 0
elseif has_key(a:val, 'nr') && has_key(a:make_def, 'ignore_nr') && index(a:make_def.ignore_nr, a:val.nr) != -1
return 0
elseif has_key(a:make_def, 'buffers')
let buffers = a:make_def.buffers
if buffers == 'listed' && !buflisted(a:val.bufnr)
return 0
elseif buffers == 'current' && a:val.bufnr != a:make_def.bufnr
return 0
endif
endif
return 1
endf
function! checksyntax#NullOutput(flag) "{{{3
if empty(g:checksyntax#null)
return ''
else
return a:flag .' '. g:checksyntax#null
endif
endf
" If cmd seems to be a cygwin executable, use cygpath to convert
" filenames. This assumes that cygwin's which command returns full
" filenames for non-cygwin executables.
function! checksyntax#MaybeUseCygpath(cmd) "{{{3
" echom "DBG" a:cmd
if g:checksyntax#check_cygpath && s:CygwinBin(a:cmd)
return 'cygpath -u %s'
endif
return ''
endf