" @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 =~? '\' 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 =~? '\' && 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 =~? '\' 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