diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 764ffff..378b53b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,49 +1,105 @@ -# Bug reports / Github issues +# CONTRIBUTING +- - - +1\. [Bug reports / GitHub issues](#bugreps) +2\. [Submitting a patch](#patches) +3\. [General style notes](#generalstyle) +4\. [Syntax checker notes](#checkerstyle) +- - - -When reporting a bug make sure you search the existing github issues for the -same/similar issues. If you find one, feel free to add a `+1` comment with any -additional information that may help us solve the issue. + + +## 1. Bug reports / GitHub issues + +Please note that the preferred channel for posting bug reports is the +[issue tracker at GitHub][0]. Reports posted elsewhere are less likely +to be seen by the core team. + +When reporting a bug make sure you search the existing GitHub issues +for the same/similar issues. If you find one, feel free to add a `+1` +comment with any additional information that may help us solve the +issue. When creating a new issue be sure to state the following: -* Steps to reproduce the bug. -* The version of vim you are using. -* The version of syntastic you are using. +* steps to reproduce the bug; +* the version of Vim you are using (run `:ver` to find out); +* the version of syntastic you are using (see `:SyntasticInfo`). + +For syntax checker bugs also state the version of the checker executable +that you are using. Adding debugging information is typically useful +too: + +* open a file handled by your checker; +* set `g:syntastic_debug` to 1 or 3; +* run the checker; +* copy the output of `:mes`. + + + +## 2. Submitting a patch -For syntax checker bugs also state the version of the checker executable that you are using. +Before you consider adding features to syntastic, _please_ spend a few +minutes (re-)reading the latest version of the [manual][1]. Syntastic +is changing rapidly at times, and it's quite possible that some of the +features you want to add exist already. -# Submitting a patch +To submit a patch: -* Fork the repo on github -* Make a [topic branch](https://github.com/dchelimsky/rspec/wiki/Topic-Branches#using-topic-branches-when-contributing-patches) and start hacking -* Submit a pull request based off your topic branch +* fork the [repo][2] on GitHub; +* make a [topic branch][3] and start hacking; +* submit a pull request based off your topic branch. -Small focused patches are preferred. +Small, focused patches are preferred. -Large changes to the code should be discussed with the core team first. Create an issue and explain your plan and see what we say. +Large changes to the code should be discussed with the core team first. +Create an issue and explain your plan and see what we say. -# General style notes +Also make sure to update the manual whenever applicable. Nobody can use +features that aren't documented. -Following the coding conventions/styles used in the syntastic core: + -* Use 4 space indents. -* Don't use abbreviated keywords - e.g. use `endfunction`, not `endfun` (there's always room for more fun!). -* Don't use `l:` prefixes for variables unless actually required (i.e. almost never). -* Code for maintainability. We would rather a function be a couple of lines longer and have (for example) some [explaining variables](http://www.refactoring.com/catalog/introduceExplainingVariable.html) to aid readability. +## 3. General style notes -# Syntax checker style notes +Follow the coding conventions/styles used in the syntastic core: -The preferred style for error format strings is one "clause" per line. E.g. -(from the coffeelint checker): +* use 4 space indents; +* don't use abbreviated keywords - e.g. use `endfunction`, not `endfun` +(there's always room for more fun!); +* don't use `l:` prefixes for variables unless actually required (i.e. +almost never); +* code for maintainability; we would rather a function be a couple of +lines longer and have (for example) some [explaining variables][4] to +aid readability. -```viml -let errorformat = '%E%f:%l:%c: %trror: %m,' . - \ 'Syntax%trror: In %f\, %m on line %l,' . - \ '%EError: In %f\, Parse error on line %l: %m,' . - \ '%EError: In %f\, %m on line %l,' . - \ '%W%f(%l): lint warning: %m,' . - \ '%W%f(%l): warning: %m,' . - \ '%E%f(%l): SyntaxError: %m,' . - \ '%-Z%p^,' . - \ '%-G%.%#' + + +## 4. Syntax checker notes + +Make sure to read the [guide][5] if you plan to add new syntax checkers. + +Use the existing checkers as templates, rather than writing everything +from scratch. + +The preferred style for error format strings is one "clause" per line. +E.g. (from the `coffee` checker): + +```vim +let errorformat = + \ '%E%f:%l:%c: %trror: %m,' . + \ 'Syntax%trror: In %f\, %m on line %l,' . + \ '%EError: In %f\, Parse error on line %l: %m,' . + \ '%EError: In %f\, %m on line %l,' . + \ '%W%f(%l): lint warning: %m,' . + \ '%W%f(%l): warning: %m,' . + \ '%E%f(%l): SyntaxError: %m,' . + \ '%-Z%p^,' . + \ '%-G%.%#' ``` + +[0]: https://github.com/scrooloose/syntastic/issues +[1]: https://github.com/scrooloose/syntastic/blob/master/doc/syntastic.txt +[2]: https://github.com/scrooloose/syntastic +[3]: https://github.com/dchelimsky/rspec/wiki/Topic-Branches#using-topic-branches-when-contributing-patches +[4]: http://www.refactoring.com/catalog/extractVariable.html +[5]: https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide diff --git a/README.markdown b/README.markdown index 04effa5..4d03421 100644 --- a/README.markdown +++ b/README.markdown @@ -18,32 +18,51 @@ - - - -1\. [Introduction](#introduction) -2\. [Installation](#installation) -3\. [FAQ](#faq) -4\. [Other resources](#otherresources) +1. [Introduction](#introduction) +2. [Installation](#installation) +2.1. [Requirements](#requirements) +2.2. [Installing syntastic with Pathogen](#installpathogen) +3. [Recommended settings](#settings) +4. [FAQ](#faq) +4.1. [I installed syntastic but it isn't reporting any errors...](#faqinfo) +4.2. [The `python` checker complains about syntactically valid Python 3 constructs...](#faqpython3) +4.3. [Are there any local checkers for HTML5 that I can use with syntastic?](#faqhtml5) +4.4. [The `perl` checker has stopped working...](#faqperl) +4.5. [What happened to the `rustc` checker?](#faqrust) +4.6. [I run a checker and the location list is not updated...](#faqloclist) +4.6. [I run`:lopen` or `:lwindow` and the error window is empty...](#faqloclist) +4.7. [How can I pass additional arguments to a checker?](#faqargs) +4.8. [Syntastic supports several checkers for my filetype - how do I tell which one(s) to use?](#faqcheckers) +4.9. [What is the difference between syntax checkers and style checkers?](#faqstyle) +4.10. [I have enabled multiple checkers for the current filetype. How can I display all of the errors from all of the checkers together?](#faqaggregate) +4.11. [How can I jump between the different errors without using the location list at the bottom of the window?](#faqlnext) +4.12. [The error window is closed automatically when I :quit the current buffer but not when I :bdelete it?](#faqbdelete) +5. [Resources](#otherresources) + - - - ## 1\. Introduction -Syntastic is a syntax checking plugin for Vim that runs files through external -syntax checkers and displays any resulting errors to the user. This can be done -on demand, or automatically as files are saved. If syntax errors are detected, -the user is notified and is happy because they didn't have to compile their -code or execute their script to find them. +Syntastic is a syntax checking plugin for [Vim][13] that runs files through +external syntax checkers and displays any resulting errors to the user. This +can be done on demand, or automatically as files are saved. If syntax errors +are detected, the user is notified and is happy because they didn't have to +compile their code or execute their script to find them. At the time of this writing, syntax checking plugins exist for ActionScript, -Ada, AppleScript, AsciiDoc, ASM, BEMHTML, Bourne shell, C, C++, C#, Chef, -CoffeeScript, Coco, Coq, CSS, Cucumber, CUDA, D, Dart, DocBook, Dust, Elixir, -Erlang, eRuby, Fortran, Gentoo metadata, GLSL, Go, Haml, Haskell, Haxe, -Handlebars, HSS, HTML, Java, JavaScript, JSON, LESS, Lex, Limbo, LISP, -LLVM intermediate language, Lua, MATLAB, NASM, Objective-C, Objective-C++, -OCaml, Perl, Perl POD, PHP, gettext Portable Object, Puppet, Python, Racket, -reStructuredText, Ruby, Rust, SASS/SCSS, Scala, Slim, Tcl, TeX, Texinfo, Twig, -TypeScript, Vala, Verilog, VHDL, VimL, xHtml, XML, XSLT, YACC, YAML, z80, Zope -page templates, zsh. +Ada, AppleScript, AsciiDoc, ASM, BEMHTML, Bro, Bourne shell, C, C++, C#, Cabal, +Chef, CoffeeScript, Coco, Coq, CSS, Cucumber, CUDA, D, Dart, DocBook, Dust, +Elixir, Erlang, eRuby, Fortran, Gentoo metadata, GLSL, Go, Haml, Haskell, +Haxe, Handlebars, HSS, HTML, Java, JavaScript, JSON, JSX, LESS, Lex, Limbo, +LISP, LLVM intermediate language, Lua, Markdown, MATLAB, NASM, Objective-C, +Objective-C++, OCaml, Perl, Perl POD, PHP, gettext Portable Object, OS X and +iOS property lists, Puppet, Python, R, Racket, Relax NG, reStructuredText, RPM +spec, Ruby, SASS/SCSS, Scala, Slim, Tcl, TeX, Texinfo, Twig, TypeScript, Vala, +Verilog, VHDL, VimL, xHtml, XML, XSLT, YACC, YAML, z80, Zope page templates, +and zsh. See the [wiki][3] for details about the corresponding supported +checkers. Below is a screenshot showing the methods that Syntastic uses to display syntax errors. Note that, in practise, you will only have a subset of these methods @@ -62,155 +81,292 @@ enabled. ## 2\. Installation -Installing syntastic is easy but first you need to have the pathogen plugin installed. If you already -have pathogen working then skip Step 1 and go to Step 2. + - +### 2.1\. Requirements -### 2.1\. Step 1: Install pathogen.vim +Syntastic itself has rather relaxed requirements: it doesn't have any external +dependencies, and it needs a version of [Vim][13] compiled with a few common +features: `autocmd`, `eval`, `file_in_path`, `modify_fname`, `quickfix`, +`reltime`, and `user_commands`. Not all possible combinations of features that +include the ones above make equal sense on all operating systems, but Vim +version 7 or later with the "normal", "big", or "huge" feature sets should be +fine. -First I'll show you how to install tpope's [pathogen.vim][1] so that it's -easy to install syntastic. Do this in your Terminal so that you get the -pathogen.vim file and the directories it needs: +Syntastic should work with any modern plugin managers for Vim, such as +[NeoBundle][14], [Pathogen][1], [Vim-Addon-Manager][15], [Vim-Plug][16], or +[Vundle][17]. Instructions for installing syntastic with [Pathogen][1] are +included below for completeness. - mkdir -p ~/.vim/autoload ~/.vim/bundle; \ - curl -so ~/.vim/autoload/pathogen.vim \ - https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim +Last but not least: syntastic doesn't know how to do any syntax checks by +itself. In order to get meaningful results you need to install external +checkers corresponding to the types of files you use. Please consult the +[wiki][3] for a list of supported checkers. -Next you *need to add this* to your ~/.vimrc: + - execute pathogen#infect() +### 2.2\. Installing syntastic with Pathogen - +If you already have [Pathogen][1] working then skip [Step 1](#step1) and go to +[Step 2](#step2). -### 2.2\. Step 2: Install syntastic as a pathogen bundle + -You now have pathogen installed and can put syntastic into ~/.vim/bundle like this: - +#### 2.2.1\. Step 1: Install pathogen.vim - cd ~/.vim/bundle - git clone https://github.com/scrooloose/syntastic.git +First I'll show you how to install Tim Pope's [Pathogen][1] so that it's easy to +install syntastic. Do this in your terminal so that you get the `pathogen.vim` +file and the directories it needs: +```sh +mkdir -p ~/.vim/autoload ~/.vim/bundle && \ +curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim +``` +Next you *need* to add this to your `~/.vimrc`: +```vim +execute pathogen#infect() +``` -Quit vim and start it back up to reload it, then type: + - :Helptags +#### 2.2.2\. Step 2: Install syntastic as a Pathogen bundle -If you get an error when you do this, then you probably didn't install pathogen right. Go back to -step 1 and make sure you did the following: +You now have pathogen installed and can put syntastic into `~/.vim/bundle` like +this: +```sh +cd ~/.vim/bundle && \ +git clone https://github.com/scrooloose/syntastic.git +``` +Quit vim and start it back up to reload it, then type: +```vim +:Helptags +``` +If you get an error when you do this, then you probably didn't install +[Pathogen][1] right. Go back to [Step 1](#step1) and make sure you did the +following: -1. Created both the ~/.vim/autoload and ~/.vim/bundle directories. -2. Added the "call pathogen#infect()" line to your ~/.vimrc file -3. Did the git clone of syntastic inside ~/.vim/bundle +1. Created both the `~/.vim/autoload` and `~/.vim/bundle` directories. +2. Added the `execute pathogen#infect()` line to your `~/.vimrc` file +3. Did the `git clone` of syntastic inside `~/.vim/bundle` 4. Have permissions to access all of these directories. + + +## 3\. Recommended settings + +Syntastic has a large number of options that can be configured, and the +defaults are not particularly well suitable for new users. It is recommended +that you start by adding the following lines to your `vimrc` file, and return +to them after reading the manual (see `:help syntastic` in Vim): +```vim +set statusline+=%#warningmsg# +set statusline+=%{SyntasticStatuslineFlag()} +set statusline+=%* + +let g:syntastic_always_populate_loc_list = 1 +let g:syntastic_auto_loc_list = 1 +let g:syntastic_check_on_open = 1 +let g:syntastic_check_on_wq = 0 +``` -## 3\. FAQ +## 4\. FAQ + + -__Q. I installed syntastic but it isn't reporting any errors...__ +__4.1. Q. I installed syntastic but it isn't reporting any errors...__ A. The most likely reason is that none of the syntax checkers that it requires -is installed. For example: python requires either `flake8`, `pyflakes` -or `pylint` to be installed and in `$PATH`. To see which executables are -supported, just look in `syntax_checkers//*.vim`. Note that aliases -do not work; the actual executable must be available in your `$PATH`. Symbolic -links are okay. You can see syntastic's idea of available checkers by running -`:SyntasticInfo`. +is installed. For example: by default, python requires either `flake8` or +`pylint` to be installed and in your `$PATH`. To see which executables are +supported, look at the [wiki][3]. Note that aliases do not work; the actual +executables must be available in your `$PATH`. Symbolic links are okay though. +You can see syntastic's idea of available checkers by running `:SyntasticInfo`. Another reason it could fail is that either the command line options or the error output for a syntax checker may have changed. In this case, make sure you have the latest version of the syntax checker installed. If it still fails then create an issue - or better yet, create a pull request. -__Q. Recently some of my syntax checker options have stopped working...__ + -A. The options are still there, they have just been renamed. Recently, -almost all syntax checkers were refactored to use the new `makeprgBuild()` -function. This made a lot of the old explicit options redundant - as they are -now implied. The new implied options usually have slightly different names to -the old options. +__4.2. Q. The `python` checker complains about syntactically valid Python 3 constructs...__ -e.g. Previously there was `g:syntastic_phpcs_conf`, now you must use -`g:syntastic_php_phpcs_args`. This completely overrides the arguments of -the checker, including any defaults, so you may need to look up the default -arguments of the checker and add these in. +A. Configure the `python` checker to call a Python 3 interpreter rather than +Python 2, e.g: +```vim +let g:syntastic_python_python_exec = '/path/to/python3' +``` -See `:help syntastic-checker-options` for more information. + + +__4.3. Q. Are there any local checkers for HTML5 that I can use with syntastic?__ + +[HTML Tidy][18] has a fork named [HTML Tidy for HTML5][19]. It's a drop +in replacement, and syntastic can use it without changes. Just install it +somewhere and point `g:syntastic_html_tidy_exec` to its executable. + +Alternatively, you can install [vnu.jar][21] from the [validator.nu][20] +project and run it as a [HTTP server][23]: +```sh +$ java -Xss512k -cp /path/to/vnu.jar nu.validator.servlet.Main 8888 +``` +Then you can [configure][22] syntastic to use it: +```vim +let g:syntastic_html_validator_api = 'http://localhost:8888/' +``` + + -__Q. I run a checker and the location list is not updated...__ +__4.4. Q. The `perl` checker has stopped working...__ -A. By default, the location list is changed only when you run the `:Errors` +A. The `perl` checker runs `perl -c` against your file, which in turn +__executes__ any `BEGIN`, `UNITCHECK`, and `CHECK` blocks, and any `use` +statements in your file (cf. [perlrun][10]). This is probably fine if you +wrote the file yourself, but it's a security problem if you're checking third +party files. Since there is currently no way to disable this behaviour while +still producing useful results, the checker is now disabled by default. To +(re-)enable it, make sure the `g:syntastic_perl_checkers` list includes `perl`, +and set `g:syntastic_enable_perl_checker` to 1 in your `vimrc`: +```vim +let g:syntastic_enable_perl_checker = 1 +``` + + + +__4.5. Q. What happened to the `rustc` checker?__ + +A. It has been included in the [Rust compiler package][12]. If you have +a recent version of the Rust compiler, the checker should be picked up +automatically by syntastic. + + + +__4.6. Q. I run a checker and the location list is not updated...__ +__4.6. Q. I run`:lopen` or `:lwindow` and the error window is empty...__ + +A. By default the location list is changed only when you run the `:Errors` command, in order to minimise conflicts with other plugins. If you want the location list to always be updated when you run the checkers, add this line to -your vimrc: +your `vimrc`: ```vim -let g:syntastic_always_populate_loc_list=1 +let g:syntastic_always_populate_loc_list = 1 ``` -__Q. How can I pass additional arguments to a checker?__ + + +__4.7. Q. How can I pass additional arguments to a checker?__ A. Almost all syntax checkers use the `makeprgBuild()` function. Those checkers that do can be configured using global variables. The general form of the -global args variables are: -```vim -syntastic___args -``` +global `args` variables is `syntastic___args`. -So, If you wanted to pass "--my --args --here" to the ruby mri checker you -would add this line to your vimrc: +So, If you wanted to pass `--my --args --here` to the ruby mri checker you +would add this line to your `vimrc`: ```vim -let g:syntastic_ruby_mri_args="--my --args --here" +let g:syntastic_ruby_mri_args = "--my --args --here" ``` See `:help syntastic-checker-options` for more information. -__Q. Syntastic supports several checkers for my filetype - how do I tell it + + +__4.8. Q. Syntastic supports several checkers for my filetype - how do I tell it which one(s) to use?__ -A. Stick a line like this in your vimrc: +A. Stick a line like this in your `vimrc`: ```vim -let g:syntastic__checkers=[''] +let g:syntastic__checkers = [''] ``` -To see the list of checkers for your filetype, look in -`syntax_checkers//`. +To see the list of supported checkers for your filetype look at the +[wiki][3]. -e.g. Python has the following checkers: `flake8`, `pyflakes`, `pylint` and a -native `python` checker. +e.g. Python has the following checkers, among others: `flake8`, `pyflakes`, +`pylint` and a native `python` checker. To tell syntastic to use `pylint`, you would use this setting: ```vim -let g:syntastic_python_checkers=['pylint'] +let g:syntastic_python_checkers = ['pylint'] ``` -Some filetypes, like PHP, have style checkers as well as syntax checkers. These -can be chained together like this: +Checkers can be chained together like this: ```vim -let g:syntastic_php_checkers=['php', 'phpcs', 'phpmd'] +let g:syntastic_php_checkers = ['php', 'phpcs', 'phpmd'] ``` This is telling syntastic to run the `php` checker first, and if no errors are found, run `phpcs`, and then `phpmd`. -__Q. How can I jump between the different errors without using the location +You can also run checkers explicitly by calling `:SyntasticCheck `. + +e.g. to run `phpcs` and `phpmd`: +```vim +:SyntasticCheck phpcs phpmd +``` + +This works for any checkers available for the current filetype, even if they +aren't listed in `g:syntastic__checkers`. You can't run checkers for +"foreign" filetypes though (e.g. you can't run, say, a Python checker if the +filetype of the current file is `php`). + + + +__4.9. Q. What is the difference between syntax checkers and style checkers?__ + +A. The errors and warnings they produce are highlighted differently and can +be filtered by different rules, but otherwise the distinction is pretty much +arbitrary. There is an ongoing effort to keep things consistent, so you can +_generally_ expect messages produced by syntax checkers to be _mostly_ related +to syntax, and messages produced by style checkers to be _mostly_ about style. +But there can be no formal guarantee that, say, a style checker that runs into +a syntax error wouldn't die with a fatal message, nor that a syntax checker +wouldn't give you warnings against using some constructs as being bad practice. +There is also no guarantee that messages marked as "style" are less severe than +the ones marked as "syntax" (whatever that might mean). And there are even a +few Frankenstein checkers (for example `flake8` and `pylama`) that, by their +nature, produce both kinds of messages. Syntastic is not smart enough to be +able to sort out these things by itself. + +In fact it's more useful to look at this from the perspective of filtering +unwanted messages, rather than as an indicator of severity levels. The +distinction between syntax and style is orthogonal to the distinction between +errors and warnings, and thus you can turn off messages based on level, on +type, or both. + +e.g. To disable all style messages: +```vim +let g:syntastic_quiet_messages = { "type": "style" } +``` +See `:help syntastic_quiet_messages` for details. + + + +__4.10. Q. I have enabled multiple checkers for the current filetype. How can I +display all of the errors from all of the checkers together?__ + +A. Set `g:syntastic_aggregate_errors` to 1 in your `vimrc`: +```vim +let g:syntastic_aggregate_errors = 1 +``` + +See `:help syntastic-aggregating-errors` for more details. + + + +__4.11. Q. How can I jump between the different errors without using the location list at the bottom of the window?__ -A. Vim provides several built in commands for this. See `:help :lnext` and -`:help :lprev`. +A. Vim provides several built-in commands for this. See `:help :lnext` and +`:help :lprevious`. If you use these commands a lot then you may want to add shortcut mappings to -your vimrc, or install something like [unimpaired][2], which provides such +your `vimrc`, or install something like [unimpaired][2], which provides such mappings (among other things). -__Q. A syntax checker is giving me unwanted/strange style tips?__ - -A. Some filetypes (e.g. php) have style checkers as well as syntax -checkers. You can usually configure the options that are passed to the style -checkers, or just disable them. Take a look at the [wiki][3] to see what -options are available. + -__Q. The error window is closed automatically when I :quit the current buffer +__4.12. Q. The error window is closed automatically when I :quit the current buffer but not when I :bdelete it?__ A. There is no safe way to handle that situation automatically, but you can @@ -221,14 +377,15 @@ nnoremap :lclose:bdelete cabbrev bd lclose\|bdelete ``` - -## 4\. Other resources +## 5\. Resources The preferred place for posting suggestions, reporting bugs, and general -discussions related to syntastic is the [issue tracker at GitHub][4]. There -are also a [google group][5], and a [syntastic tag at StackOverflow][6]. +discussions related to syntastic is the [issue tracker at GitHub][4]. +A guide for writing syntax checkers can be found in the [wiki][11]. +There are also a dedicated [google group][5], and a +[syntastic tag at StackOverflow][6]. Syntastic aims to provide a common interface to syntax checkers for as many languages as possible. For particular languages, there are, of course, other @@ -244,4 +401,22 @@ a look at [jedi-vim][7], [python-mode][8], or [YouCompleteMe][9]. [6]: http://stackoverflow.com/questions/tagged/syntastic [7]: https://github.com/davidhalter/jedi-vim [8]: https://github.com/klen/python-mode -[9]: https://github.com/Valloric/YouCompleteMe +[9]: http://valloric.github.io/YouCompleteMe/ +[10]: http://perldoc.perl.org/perlrun.html#*-c* +[11]: https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide +[12]: https://github.com/rust-lang/rust/ +[13]: http://www.vim.org/ +[14]: https://github.com/Shougo/neobundle.vim +[15]: https://github.com/MarcWeber/vim-addon-manager +[16]: https://github.com/junegunn/vim-plug/ +[17]: https://github.com/gmarik/Vundle.vim +[18]: http://tidy.sourceforge.net/ +[19]: http://w3c.github.io/tidy-html5/ +[20]: http://about.validator.nu/ +[21]: https://github.com/validator/validator/releases/latest +[22]: https://github.com/scrooloose/syntastic/wiki/HTML%3A---validator +[23]: http://validator.github.io/validator/#standalone + + diff --git a/autoload/syntastic/c.vim b/autoload/syntastic/c.vim index 82f4c70..44279d1 100644 --- a/autoload/syntastic/c.vim +++ b/autoload/syntastic/c.vim @@ -1,4 +1,4 @@ -if exists("g:loaded_syntastic_c_autoload") +if exists("g:loaded_syntastic_c_autoload") || !exists("g:loaded_syntastic_plugin") finish endif let g:loaded_syntastic_c_autoload = 1 @@ -10,17 +10,25 @@ set cpo&vim " convenience function to determine the 'null device' parameter " based on the current operating system -function! syntastic#c#NullOutput() +function! syntastic#c#NullOutput() " {{{2 let known_os = has('unix') || has('mac') || syntastic#util#isRunningWindows() return known_os ? '-o ' . syntastic#util#DevNull() : '' -endfunction +endfunction " }}}2 " read additional compiler flags from the given configuration file " the file format and its parsing mechanism is inspired by clang_complete -function! syntastic#c#ReadConfig(file) - " search in the current file's directory upwards +function! syntastic#c#ReadConfig(file) " {{{2 + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: looking for', a:file) + + " search upwards from the current file's directory let config = findfile(a:file, '.;') - if config == '' || !filereadable(config) + if config == '' + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: file not found') + return '' + endif + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: config file:', config) + if !filereadable(config) + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: file unreadable') return '' endif @@ -30,7 +38,8 @@ function! syntastic#c#ReadConfig(file) " try to read config file try let lines = readfile(config) - catch /^Vim\%((\a\+)\)\=:E48[45]/ + catch /\m^Vim\%((\a\+)\)\=:E48[45]/ + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: error reading file') return '' endtry @@ -57,12 +66,12 @@ function! syntastic#c#ReadConfig(file) endfor return join(map(parameters, 'syntastic#util#shescape(v:val)')) -endfunction +endfunction " }}}2 " GetLocList() for C-like compilers -function! syntastic#c#GetLocList(filetype, subchecker, options) +function! syntastic#c#GetLocList(filetype, subchecker, options) " {{{2 try - let flags = s:GetCflags(a:filetype, a:subchecker, a:options) + let flags = s:_get_cflags(a:filetype, a:subchecker, a:options) catch /\m\C^Syntastic: skip checks$/ return [] endtry @@ -70,9 +79,9 @@ function! syntastic#c#GetLocList(filetype, subchecker, options) let makeprg = syntastic#util#shexpand(g:syntastic_{a:filetype}_compiler) . \ ' ' . flags . ' ' . syntastic#util#shexpand('%') - let errorformat = s:GetCheckerVar('g', a:filetype, a:subchecker, 'errorformat', a:options['errorformat']) + let errorformat = s:_get_checker_var('g', a:filetype, a:subchecker, 'errorformat', a:options['errorformat']) - let postprocess = s:GetCheckerVar('g', a:filetype, a:subchecker, 'remove_include_errors', 0) ? + let postprocess = s:_get_checker_var('g', a:filetype, a:subchecker, 'remove_include_errors', 0) ? \ ['filterForeignErrors'] : [] " process makeprg @@ -80,34 +89,112 @@ function! syntastic#c#GetLocList(filetype, subchecker, options) \ 'makeprg': makeprg, \ 'errorformat': errorformat, \ 'postprocess': postprocess }) -endfunction +endfunction " }}}2 + +" }}}1 " Private functions {{{1 " initialize c/cpp syntax checker handlers -function! s:Init() +function! s:_init() " {{{2 let s:handlers = [] let s:cflags = {} - call s:RegHandler('\m\', 'syntastic#c#CheckPhp', []) - call s:RegHandler('\m\', 'syntastic#c#CheckPython', []) - call s:RegHandler('\m\', 's:_checkPhp', []) + call s:_registerHandler('\m\', 's:_checkPython', []) + call s:_registerHandler('\m\" echohl ErrorMsg echomsg "syntastic: error: " . a:msg echohl None -endfunction +endfunction " }}}2 -function! syntastic#log#deprecationWarn(msg) - if index(s:deprecation_notices_issued, a:msg) >= 0 +function! syntastic#log#oneTimeWarn(msg) " {{{2 + if index(s:one_time_notices_issued, a:msg) >= 0 return endif - call add(s:deprecation_notices_issued, a:msg) + call add(s:one_time_notices_issued, a:msg) call syntastic#log#warn(a:msg) -endfunction +endfunction " }}}2 + +" @vimlint(EVL102, 1, l:OLD_VAR) +function! syntastic#log#deprecationWarn(old, new, ...) " {{{2 + if exists('g:syntastic_' . a:old) && !exists('g:syntastic_' . a:new) + let msg = 'variable g:syntastic_' . a:old . ' is deprecated, please use ' + + if a:0 + let OLD_VAR = g:syntastic_{a:old} + try + let NEW_VAR = eval(a:1) + let msg .= 'in its stead: let g:syntastic_' . a:new . ' = ' . string(NEW_VAR) + let g:syntastic_{a:new} = NEW_VAR + catch + let msg .= 'g:syntastic_' . a:new . ' instead' + endtry + else + let msg .= 'g:syntastic_' . a:new . ' instead' + let g:syntastic_{a:new} = g:syntastic_{a:old} + endif -function! syntastic#log#debug(level, msg, ...) - if !s:isDebugEnabled(a:level) + call syntastic#log#oneTimeWarn(msg) + endif +endfunction " }}}2 +" @vimlint(EVL102, 0, l:OLD_VAR) + +function! syntastic#log#debug(level, msg, ...) " {{{2 + if !s:_isDebugEnabled(a:level) return endif - let leader = s:logTimestamp() - call s:logRedirect(1) + let leader = s:_log_timestamp() + call s:_logRedirect(1) if a:0 > 0 " filter out dictionary functions @@ -83,68 +77,74 @@ function! syntastic#log#debug(level, msg, ...) echomsg leader . a:msg endif - call s:logRedirect(0) -endfunction + call s:_logRedirect(0) +endfunction " }}}2 -function! syntastic#log#debugShowOptions(level, names) - if !s:isDebugEnabled(a:level) +function! syntastic#log#debugShowOptions(level, names) " {{{2 + if !s:_isDebugEnabled(a:level) return endif - let leader = s:logTimestamp() - call s:logRedirect(1) + let leader = s:_log_timestamp() + call s:_logRedirect(1) - let vlist = type(a:names) == type("") ? [a:names] : a:names + let vlist = copy(type(a:names) == type("") ? [a:names] : a:names) if !empty(vlist) - call map(copy(vlist), "'&' . v:val . ' = ' . strtrans(string(eval('&' . v:val)))") + call map(vlist, "'&' . v:val . ' = ' . strtrans(string(eval('&' . v:val)))") echomsg leader . join(vlist, ', ') endif - call s:logRedirect(0) -endfunction + call s:_logRedirect(0) +endfunction " }}}2 -function! syntastic#log#debugShowVariables(level, names) - if !s:isDebugEnabled(a:level) +function! syntastic#log#debugShowVariables(level, names) " {{{2 + if !s:_isDebugEnabled(a:level) return endif - let leader = s:logTimestamp() - call s:logRedirect(1) + let leader = s:_log_timestamp() + call s:_logRedirect(1) let vlist = type(a:names) == type("") ? [a:names] : a:names for name in vlist - echomsg leader . s:formatVariable(name) + let msg = s:_format_variable(name) + if msg != '' + echomsg leader . msg + endif endfor - call s:logRedirect(0) -endfunction + call s:_logRedirect(0) +endfunction " }}}2 -function! syntastic#log#debugDump(level) - if !s:isDebugEnabled(a:level) +function! syntastic#log#debugDump(level) " {{{2 + if !s:_isDebugEnabled(a:level) return endif - call syntastic#log#debugShowVariables(a:level, s:global_options) -endfunction + call syntastic#log#debugShowVariables( a:level, sort(keys(g:_SYNTASTIC_DEFAULTS)) ) +endfunction " }}}2 + +" }}}1 " Private functions {{{1 -function! s:isDebugEnabled_smart(level) +function! s:_isDebugEnabled_smart(level) " {{{2 return and(g:syntastic_debug, a:level) -endfunction +endfunction " }}}2 -function! s:isDebugEnabled_dumb(level) +function! s:_isDebugEnabled_dumb(level) " {{{2 " poor man's bit test for bit N, assuming a:level == 2**N return (g:syntastic_debug / a:level) % 2 -endfunction +endfunction " }}}2 -let s:isDebugEnabled = function(exists('*and') ? 's:isDebugEnabled_smart' : 's:isDebugEnabled_dumb') +let s:_isDebugEnabled = function(exists('*and') ? 's:_isDebugEnabled_smart' : 's:_isDebugEnabled_dumb') +lockvar s:_isDebugEnabled -function! s:logRedirect(on) +function! s:_logRedirect(on) " {{{2 if exists("g:syntastic_debug_file") if a:on try - execute 'redir >> ' . fnameescape(expand(g:syntastic_debug_file)) - catch /^Vim\%((\a\+)\)\=:/ + execute 'redir >> ' . fnameescape(expand(g:syntastic_debug_file, 1)) + catch /\m^Vim\%((\a\+)\)\=:/ silent! redir END unlet g:syntastic_debug_file endtry @@ -152,30 +152,31 @@ function! s:logRedirect(on) silent! redir END endif endif -endfunction +endfunction " }}}2 -function! s:logTimestamp_smart() - return 'syntastic: ' . split(reltimestr(reltime(g:syntastic_start)))[0] . ': ' -endfunction +" }}}1 -function! s:logTimestamp_dumb() - return 'syntastic: debug: ' -endfunction +" Utilities {{{1 -let s:logTimestamp = function(has('reltime') ? 's:logTimestamp_smart' : 's:logTimestamp_dumb') +function! s:_log_timestamp() " {{{2 + return 'syntastic: ' . split(reltimestr(reltime(g:_SYNTASTIC_START)))[0] . ': ' +endfunction " }}}2 -function! s:formatVariable(name) +function! s:_format_variable(name) " {{{2 let vals = [] - if exists('g:' . a:name) - call add(vals, 'g:' . a:name . ' = ' . strtrans(string(g:{a:name}))) + if exists('g:syntastic_' . a:name) + call add(vals, 'g:syntastic_' . a:name . ' = ' . strtrans(string(g:syntastic_{a:name}))) endif - if exists('b:' . a:name) - call add(vals, 'b:' . a:name . ' = ' . strtrans(string(b:{a:name}))) + if exists('b:syntastic_' . a:name) + call add(vals, 'b:syntastic_' . a:name . ' = ' . strtrans(string(b:syntastic_{a:name}))) endif return join(vals, ', ') -endfunction +endfunction " }}}2 + +" }}}1 let &cpo = s:save_cpo unlet s:save_cpo -" vim: set et sts=4 sw=4 fdm=marker: + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/autoload/syntastic/postprocess.vim b/autoload/syntastic/postprocess.vim index 877bb50..80fd7cf 100644 --- a/autoload/syntastic/postprocess.vim +++ b/autoload/syntastic/postprocess.vim @@ -1,4 +1,4 @@ -if exists("g:loaded_syntastic_postprocess_autoload") +if exists("g:loaded_syntastic_postprocess_autoload") || !exists("g:loaded_syntastic_plugin") finish endif let g:loaded_syntastic_postprocess_autoload = 1 @@ -6,38 +6,23 @@ let g:loaded_syntastic_postprocess_autoload = 1 let s:save_cpo = &cpo set cpo&vim -function! s:compareErrorItems(a, b) - if a:a['bufnr'] != a:b['bufnr'] - " group by files - return a:a['bufnr'] - a:b['bufnr'] - elseif a:a['lnum'] != a:b['lnum'] - return a:a['lnum'] - a:b['lnum'] - elseif a:a['type'] !=? a:b['type'] - " errors take precedence over warnings - return a:a['type'] ==? 'e' ? -1 : 1 - else - return get(a:a, 'col', 0) - get(a:b, 'col', 0) - endif -endfunction - -" natural sort -function! syntastic#postprocess#sort(errors) - return sort(copy(a:errors), 's:compareErrorItems') -endfunction +" Public functions {{{1 " merge consecutive blanks -function! syntastic#postprocess#compressWhitespace(errors) +function! syntastic#postprocess#compressWhitespace(errors) " {{{2 for e in a:errors let e['text'] = substitute(e['text'], "\001", '', 'g') let e['text'] = substitute(e['text'], '\n', ' ', 'g') let e['text'] = substitute(e['text'], '\m\s\{2,}', ' ', 'g') + let e['text'] = substitute(e['text'], '\m^\s\+', '', '') + let e['text'] = substitute(e['text'], '\m\s\+$', '', '') endfor return a:errors -endfunction +endfunction " }}}2 " remove spurious CR under Cygwin -function! syntastic#postprocess#cygwinRemoveCR(errors) +function! syntastic#postprocess#cygwinRemoveCR(errors) " {{{2 if has('win32unix') for e in a:errors let e['text'] = substitute(e['text'], '\r', '', 'g') @@ -45,23 +30,44 @@ function! syntastic#postprocess#cygwinRemoveCR(errors) endif return a:errors -endfunction +endfunction " }}}2 " decode XML entities -function! syntastic#postprocess#decodeXMLEntities(errors) +function! syntastic#postprocess#decodeXMLEntities(errors) " {{{2 for e in a:errors let e['text'] = syntastic#util#decodeXMLEntities(e['text']) endfor return a:errors -endfunction +endfunction " }}}2 " filter out errors referencing other files -function! syntastic#postprocess#filterForeignErrors(errors) +function! syntastic#postprocess#filterForeignErrors(errors) " {{{2 return filter(copy(a:errors), 'get(v:val, "bufnr") == ' . bufnr('')) -endfunction +endfunction " }}}2 + +" make sure line numbers are not past end of buffers +" XXX: this loads all referenced buffers in memory +function! syntastic#postprocess#guards(errors) " {{{2 + let buffers = syntastic#util#unique(map(filter(copy(a:errors), 'v:val["valid"]'), 'str2nr(v:val["bufnr"])')) + + let guards = {} + for b in buffers + let guards[b] = len(getbufline(b, 1, '$')) + endfor + + for e in a:errors + if e['valid'] && e['lnum'] > guards[e['bufnr']] + let e['lnum'] = guards[e['bufnr']] + endif + endfor + + return a:errors +endfunction " }}}2 + +" }}}1 let &cpo = s:save_cpo unlet s:save_cpo -" vim: set et sts=4 sw=4: +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/autoload/syntastic/preprocess.vim b/autoload/syntastic/preprocess.vim new file mode 100644 index 0000000..85d5981 --- /dev/null +++ b/autoload/syntastic/preprocess.vim @@ -0,0 +1,262 @@ +if exists("g:loaded_syntastic_preprocess_autoload") || !exists("g:loaded_syntastic_plugin") + finish +endif +let g:loaded_syntastic_preprocess_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +" Public functions {{{1 + +function! syntastic#preprocess#cabal(errors) " {{{2 + let out = [] + let star = 0 + for err in a:errors + if star + if err == '' + let star = 0 + else + let out[-1] .= ' ' . err + endif + else + call add(out, err) + if err =~ '\m^*\s' + let star = 1 + endif + endif + endfor + return out +endfunction " }}}2 + +function! syntastic#preprocess#checkstyle(errors) " {{{2 + let out = [] + let fname = expand('%', 1) + for err in a:errors + if match(err, '\m') > -1 + let line = str2nr(matchstr(err, '\m\ \[[^]]+\])+\ze:'', "", "")') +endfunction " }}}2 + +" @vimlint(EVL102, 1, l:true) +" @vimlint(EVL102, 1, l:false) +" @vimlint(EVL102, 1, l:null) +function! syntastic#preprocess#flow(errors) " {{{2 + " JSON artifacts + let true = 1 + let false = 0 + let null = '' + + " A hat tip to Marc Weber for this trick + " http://stackoverflow.com/questions/17751186/iterating-over-a-string-in-vimscript-or-parse-a-json-file/19105763#19105763 + try + let errs = eval(join(a:errors, '')) + catch + let errs = {} + endtry + + let out = [] + if type(errs) == type({}) && has_key(errs, 'errors') && type(errs['errors']) == type([]) + for e in errs['errors'] + if type(e) == type({}) && has_key(e, 'message') && type(e['message']) == type([]) && len(e['message']) + let m = e['message'][0] + let t = e['message'][1:] + + try + let msg = + \ m['path'] . ':' . + \ m['line'] . ':' . + \ m['start'] . ':' . + \ (m['line'] ==# m['endline'] ? m['end'] . ':' : '') . + \ ' ' . m['descr'] + + if len(t) + let msg .= ' ' . join(map(t, + \ 'v:val["descr"] . " (" . v:val["path"] . ":" . v:val["line"] . ":" . v:val["start"] . ' . + \ '"," . (v:val["line"] !=# v:val["endline"] ? v:val["endline"] . ":" : "") . ' . + \ 'v:val["end"] . ")"')) + endif + + let msg = substitute(msg, '\r', '', 'g') + let msg = substitute(msg, '\n', ' ', 'g') + + call add(out, msg) + catch /\m^Vim\%((\a\+)\)\=:E716/ + call syntastic#log#warn('checker javascript/flow: unknown error format') + let out = [] + break + endtry + else + call syntastic#log#warn('checker javascript/flow: unknown error format') + let out = [] + break + endif + endfor + else + call syntastic#log#warn('checker javascript/flow: unknown error format') + endif + + return out +endfunction " }}}2 +" @vimlint(EVL102, 0, l:true) +" @vimlint(EVL102, 0, l:false) +" @vimlint(EVL102, 0, l:null) + +function! syntastic#preprocess#killEmpty(errors) " {{{2 + return filter(copy(a:errors), 'v:val != ""') +endfunction " }}}2 + +function! syntastic#preprocess#perl(errors) " {{{2 + let out = [] + + for e in a:errors + let parts = matchlist(e, '\v^(.*)\sat\s(.{-})\sline\s(\d+)(.*)$') + if !empty(parts) + call add(out, parts[2] . ':' . parts[3] . ':' . parts[1] . parts[4]) + endif + endfor + + return syntastic#util#unique(out) +endfunction " }}}2 + +" @vimlint(EVL102, 1, l:true) +" @vimlint(EVL102, 1, l:false) +" @vimlint(EVL102, 1, l:null) +function! syntastic#preprocess#prospector(errors) " {{{2 + " JSON artifacts + let true = 1 + let false = 0 + let null = '' + + " A hat tip to Marc Weber for this trick + " http://stackoverflow.com/questions/17751186/iterating-over-a-string-in-vimscript-or-parse-a-json-file/19105763#19105763 + try + let errs = eval(join(a:errors, '')) + catch + let errs = {} + endtry + + let out = [] + if type(errs) == type({}) && has_key(errs, 'messages') && type(errs['messages']) == type([]) + for e in errs['messages'] + if type(e) == type({}) + try + if e['source'] ==# 'pylint' + let e['location']['character'] += 1 + endif + + let msg = + \ e['location']['path'] . ':' . + \ e['location']['line'] . ':' . + \ e['location']['character'] . ': ' . + \ e['code'] . ' ' . + \ e['message'] . ' ' . + \ '[' . e['source'] . ']' + + call add(out, msg) + catch /\m^Vim\%((\a\+)\)\=:E716/ + call syntastic#log#warn('checker python/prospector: unknown error format') + let out = [] + break + endtry + else + call syntastic#log#warn('checker python/prospector: unknown error format') + let out = [] + break + endif + endfor + else + call syntastic#log#warn('checker python/prospector: unknown error format') + endif + + return out +endfunction " }}}2 +" @vimlint(EVL102, 0, l:true) +" @vimlint(EVL102, 0, l:false) +" @vimlint(EVL102, 0, l:null) + +function! syntastic#preprocess#rparse(errors) " {{{2 + let errlist = copy(a:errors) + + " remove uninteresting lines and handle continuations + let i = 0 + while i < len(errlist) + if i > 0 && errlist[i][:1] == ' ' && errlist[i] !~ '\m\s\+\^$' + let errlist[i-1] .= errlist[i][1:] + call remove(errlist, i) + elseif errlist[i] !~ '\m^\(Lint:\|Lint checking:\|Error in\) ' + call remove(errlist, i) + else + let i += 1 + endif + endwhile + + let out = [] + let fname = '' + for e in errlist + if match(e, '\m^Lint: ') == 0 + let parts = matchlist(e, '\m^Lint: \(.*\): found on lines \([0-9, ]\+\)\(+\(\d\+\) more\)\=') + if len(parts) >= 3 + for line in split(parts[2], '\m,\s*') + call add(out, 'E:' . fname . ':' . line . ': ' . parts[1]) + endfor + endif + if len(parts) >= 5 && parts[4] != '' + call add(out, 'E:' . fname . ':0: ' . parts[1] . ' - ' . parts[4] . ' messages not shown') + endif + elseif match(e, '\m^Lint checking: ') == 0 + let fname = matchstr(e, '\m^Lint checking: \zs.*') + elseif match(e, '\m^Error in ') == 0 + call add(out, substitute(e, '\m^Error in .\+ : .\+\ze:\d\+:\d\+: ', 'E:' . fname, '')) + endif + endfor + + return out +endfunction " }}}2 + +function! syntastic#preprocess#tslint(errors) " {{{2 + return map(copy(a:errors), 'substitute(v:val, ''\m^\(([^)]\+)\)\s\(.\+\)$'', ''\2 \1'', "")') +endfunction " }}}2 + +function! syntastic#preprocess#validator(errors) " {{{2 + let out = [] + for e in a:errors + let parts = matchlist(e, '\v^"([^"]+)"(.+)') + if len(parts) >= 3 + " URL decode, except leave alone any "+" + let parts[1] = substitute(parts[1], '\m%\(\x\x\)', '\=nr2char("0x".submatch(1))', 'g') + let parts[1] = substitute(parts[1], '\m\\"', '"', 'g') + let parts[1] = substitute(parts[1], '\m\\\\', '\\', 'g') + call add(out, '"' . parts[1] . '"' . parts[2]) + endif + endfor + return out +endfunction " }}}2 + +" }}}1 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/autoload/syntastic/util.vim b/autoload/syntastic/util.vim index 1ab837a..a87e2e2 100644 --- a/autoload/syntastic/util.vim +++ b/autoload/syntastic/util.vim @@ -1,4 +1,4 @@ -if exists('g:loaded_syntastic_util_autoload') +if exists('g:loaded_syntastic_util_autoload') || !exists("g:loaded_syntastic_plugin") finish endif let g:loaded_syntastic_util_autoload = 1 @@ -6,27 +6,83 @@ let g:loaded_syntastic_util_autoload = 1 let s:save_cpo = &cpo set cpo&vim -" strwidth() was added in Vim 7.3; if it doesn't exist, we use strlen() -" and hope for the best :) -let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen') - " Public functions {{{1 -function! syntastic#util#isRunningWindows() +function! syntastic#util#isRunningWindows() " {{{2 return has('win16') || has('win32') || has('win64') -endfunction +endfunction " }}}2 -function! syntastic#util#DevNull() +function! syntastic#util#DevNull() " {{{2 if syntastic#util#isRunningWindows() return 'NUL' endif return '/dev/null' -endfunction +endfunction " }}}2 " Get directory separator -function! syntastic#util#Slash() abort +function! syntastic#util#Slash() abort " {{{2 return (!exists("+shellslash") || &shellslash) ? '/' : '\' -endfunction +endfunction " }}}2 + +" Create a temporary directory +function! syntastic#util#tmpdir() " {{{2 + let tempdir = '' + + if (has('unix') || has('mac')) && executable('mktemp') + " TODO: option "-t" to mktemp(1) is not portable + let tmp = $TMPDIR != '' ? $TMPDIR : $TMP != '' ? $TMP : '/tmp' + let out = split(system('mktemp -q -d ' . tmp . '/vim-syntastic-' . getpid() . '-XXXXXXXX'), "\n") + if v:shell_error == 0 && len(out) == 1 + let tempdir = out[0] + endif + endif + + if tempdir == '' + if has('win32') || has('win64') + let tempdir = $TEMP . syntastic#util#Slash() . 'vim-syntastic-' . getpid() + elseif has('win32unix') + let tempdir = s:CygwinPath('/tmp/vim-syntastic-' . getpid()) + elseif $TMPDIR != '' + let tempdir = $TMPDIR . '/vim-syntastic-' . getpid() + else + let tempdir = '/tmp/vim-syntastic-' . getpid() + endif + + try + call mkdir(tempdir, 'p', 0700) + catch /\m^Vim\%((\a\+)\)\=:E739/ + call syntastic#log#error(v:exception) + let tempdir = '.' + endtry + endif + + return tempdir +endfunction " }}}2 + +" Recursively remove a directory +function! syntastic#util#rmrf(what) " {{{2 + " try to make sure we don't delete directories we didn't create + if a:what !~? 'vim-syntastic-' + return + endif + + if getftype(a:what) ==# 'dir' + if !exists('s:rmrf') + let s:rmrf = + \ has('unix') || has('mac') ? 'rm -rf' : + \ has('win32') || has('win64') ? 'rmdir /S /Q' : + \ has('win16') || has('win95') || has('dos16') || has('dos32') ? 'deltree /Y' : '' + endif + + if s:rmrf != '' + silent! call system(s:rmrf . ' ' . syntastic#util#shescape(a:what)) + else + call s:_rmrf(a:what) + endif + else + silent! call delete(a:what) + endif +endfunction " }}}2 "search the first 5 lines of the file for a magic number and return a map "containing the args and the executable @@ -38,37 +94,32 @@ endfunction "returns " "{'exe': '/usr/bin/perl', 'args': ['-f', '-bar']} -function! syntastic#util#parseShebang() - for lnum in range(1,5) +function! syntastic#util#parseShebang() " {{{2 + for lnum in range(1, 5) let line = getline(lnum) - if line =~ '^#!' - let exe = matchstr(line, '\m^#!\s*\zs[^ \t]*') - let args = split(matchstr(line, '\m^#!\s*[^ \t]*\zs.*')) + let line = substitute(line, '\v^#!\s*(\S+/env(\s+-\S+)*\s+)?', '', '') + let exe = matchstr(line, '\m^\S*\ze') + let args = split(matchstr(line, '\m^\S*\zs.*')) return { 'exe': exe, 'args': args } endif endfor return { 'exe': '', 'args': [] } -endfunction +endfunction " }}}2 " Get the value of a variable. Allow local variables to override global ones. -function! syntastic#util#var(name) +function! syntastic#util#var(name, ...) " {{{2 return \ exists('b:syntastic_' . a:name) ? b:syntastic_{a:name} : - \ exists('g:syntastic_' . a:name) ? g:syntastic_{a:name} : '' -endfunction + \ exists('g:syntastic_' . a:name) ? g:syntastic_{a:name} : + \ a:0 > 0 ? a:1 : '' +endfunction " }}}2 " Parse a version string. Return an array of version components. -function! syntastic#util#parseVersion(version) - return split(matchstr( a:version, '\v^\D*\zs\d+(\.\d+)+\ze' ), '\m\.') -endfunction - -" Run 'command' in a shell and parse output as a version string. -" Returns an array of version components. -function! syntastic#util#getVersion(command) - return syntastic#util#parseVersion(system(a:command)) -endfunction +function! syntastic#util#parseVersion(version) " {{{2 + return map(split(matchstr( a:version, '\v^\D*\zs\d+(\.\d+)+\ze' ), '\m\.'), 'str2nr(v:val)') +endfunction " }}}2 " Verify that the 'installed' version is at least the 'required' version. " @@ -76,20 +127,41 @@ endfunction " the "missing" elements will be assumed to be 0 for the purposes of checking. " " See http://semver.org for info about version numbers. -function! syntastic#util#versionIsAtLeast(installed, required) - for idx in range(max([len(a:installed), len(a:required)])) - let installed_element = get(a:installed, idx, 0) - let required_element = get(a:required, idx, 0) - if installed_element != required_element - return installed_element > required_element +function! syntastic#util#versionIsAtLeast(installed, required) " {{{2 + return syntastic#util#compareLexi(a:installed, a:required) >= 0 +endfunction " }}}2 + +" Almost lexicographic comparison of two lists of integers. :) If lists +" have different lengths, the "missing" elements are assumed to be 0. +function! syntastic#util#compareLexi(a, b) " {{{2 + for idx in range(max([len(a:a), len(a:b)])) + let a_element = str2nr(get(a:a, idx, 0)) + let b_element = str2nr(get(a:b, idx, 0)) + if a_element != b_element + return a_element > b_element ? 1 : -1 endif endfor " Everything matched, so it is at least the required version. - return 1 -endfunction + return 0 +endfunction " }}}2 + +" strwidth() was added in Vim 7.3; if it doesn't exist, we use strlen() +" and hope for the best :) +let s:_width = function(exists('*strwidth') ? 'strwidth' : 'strlen') +lockvar s:_width + +function! syntastic#util#screenWidth(str, tabstop) " {{{2 + let chunks = split(a:str, "\t", 1) + let width = s:_width(chunks[-1]) + for c in chunks[:-2] + let cwidth = s:_width(c) + let width += cwidth + a:tabstop - cwidth % a:tabstop + endfor + return width +endfunction " }}}2 "print as much of a:msg as possible without "Press Enter" prompt appearing -function! syntastic#util#wideMsg(msg) +function! syntastic#util#wideMsg(msg) " {{{2 let old_ruler = &ruler let old_showcmd = &showcmd @@ -100,7 +172,7 @@ function! syntastic#util#wideMsg(msg) "convert tabs to spaces so that the tabs count towards the window "width as the proper amount of characters let chunks = split(msg, "\t", 1) - let msg = join(map(chunks[:-2], 'v:val . repeat(" ", &ts - s:width(v:val) % &ts)'), '') . chunks[-1] + let msg = join(map(chunks[:-2], 'v:val . repeat(" ", &tabstop - s:_width(v:val) % &tabstop)'), '') . chunks[-1] let msg = strpart(msg, 0, &columns - 1) set noruler noshowcmd @@ -110,10 +182,10 @@ function! syntastic#util#wideMsg(msg) let &ruler = old_ruler let &showcmd = old_showcmd -endfunction +endfunction " }}}2 " Check whether a buffer is loaded, listed, and not hidden -function! syntastic#util#bufIsActive(buffer) +function! syntastic#util#bufIsActive(buffer) " {{{2 " convert to number, or hell breaks loose let buf = str2nr(a:buffer) @@ -129,11 +201,11 @@ function! syntastic#util#bufIsActive(buffer) endfor return 0 -endfunction +endfunction " }}}2 " start in directory a:where and walk up the parent folders until it " finds a file matching a:what; return path to that file -function! syntastic#util#findInParent(what, where) +function! syntastic#util#findInParent(what, where) " {{{2 let here = fnamemodify(a:where, ':p') let root = syntastic#util#Slash() @@ -146,7 +218,7 @@ function! syntastic#util#findInParent(what, where) let old = '' while here != '' - let p = split(globpath(here, a:what), '\n') + let p = split(globpath(here, a:what, 1), '\n') if !empty(p) return fnamemodify(p[0], ':p') @@ -162,10 +234,10 @@ function! syntastic#util#findInParent(what, where) endwhile return '' -endfunction +endfunction " }}}2 " Returns unique elements in a list -function! syntastic#util#unique(list) +function! syntastic#util#unique(list) " {{{2 let seen = {} let uniques = [] for e in a:list @@ -175,20 +247,31 @@ function! syntastic#util#unique(list) endif endfor return uniques -endfunction +endfunction " }}}2 " A less noisy shellescape() -function! syntastic#util#shescape(string) +function! syntastic#util#shescape(string) " {{{2 return a:string =~ '\m^[A-Za-z0-9_/.-]\+$' ? a:string : shellescape(a:string) -endfunction +endfunction " }}}2 " A less noisy shellescape(expand()) -function! syntastic#util#shexpand(string) - return syntastic#util#shescape(expand(a:string)) -endfunction +function! syntastic#util#shexpand(string, ...) " {{{2 + return syntastic#util#shescape(a:0 ? expand(a:string, a:1) : expand(a:string, 1)) +endfunction " }}}2 + +" Escape arguments +function! syntastic#util#argsescape(opt) " {{{2 + if type(a:opt) == type('') && a:opt != '' + return [a:opt] + elseif type(a:opt) == type([]) + return map(copy(a:opt), 'syntastic#util#shescape(v:val)') + endif + + return [] +endfunction " }}}2 " decode XML entities -function! syntastic#util#decodeXMLEntities(string) +function! syntastic#util#decodeXMLEntities(string) " {{{2 let str = a:string let str = substitute(str, '\m<', '<', 'g') let str = substitute(str, '\m>', '>', 'g') @@ -196,56 +279,114 @@ function! syntastic#util#decodeXMLEntities(string) let str = substitute(str, '\m'', "'", 'g') let str = substitute(str, '\m&', '\&', 'g') return str -endfunction +endfunction " }}}2 -function! syntastic#util#redraw(full) +function! syntastic#util#redraw(full) " {{{2 if a:full redraw! else redraw endif -endfunction +endfunction " }}}2 -function! syntastic#util#dictFilter(errors, filter) - let rules = s:translateFilter(a:filter) - " call syntastic#log#debug(g:SyntasticDebugFilters, "applying filter:", rules) +function! syntastic#util#dictFilter(errors, filter) " {{{2 + let rules = s:_translateFilter(a:filter) + " call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, "applying filter:", rules) try call filter(a:errors, rules) catch /\m^Vim\%((\a\+)\)\=:E/ let msg = matchstr(v:exception, '\m^Vim\%((\a\+)\)\=:\zs.*') call syntastic#log#error('quiet_messages: ' . msg) endtry -endfunction +endfunction " }}}2 + +" Return a [high, low] list of integers, representing the time +" (hopefully high resolution) since program start +" TODO: This assumes reltime() returns a list of integers. +function! syntastic#util#stamp() " {{{2 + return reltime(g:_SYNTASTIC_START) +endfunction " }}}2 + +" }}}1 " Private functions {{{1 -function! s:translateFilter(filters) +function! s:_translateFilter(filters) " {{{2 let conditions = [] for k in keys(a:filters) if type(a:filters[k]) == type([]) - call extend(conditions, map(copy(a:filters[k]), 's:translateElement(k, v:val)')) + call extend(conditions, map(copy(a:filters[k]), 's:_translateElement(k, v:val)')) else - call add(conditions, s:translateElement(k, a:filters[k])) + call add(conditions, s:_translateElement(k, a:filters[k])) endif endfor + + if conditions == [] + let conditions = ["1"] + endif return len(conditions) == 1 ? conditions[0] : join(map(conditions, '"(" . v:val . ")"'), ' && ') -endfunction - -function! s:translateElement(key, term) - if a:key ==? 'level' - let ret = 'v:val["type"] !=? ' . string(a:term[0]) - elseif a:key ==? 'type' - let ret = a:term ==? 'style' ? 'get(v:val, "subtype", "") !=? "style"' : 'has_key(v:val, "subtype")' - elseif a:key ==? 'regex' - let ret = 'v:val["text"] !~? ' . string(a:term) - elseif a:key ==? 'file' - let ret = 'bufname(str2nr(v:val["bufnr"])) !~# ' . string(a:term) +endfunction " }}}2 + +function! s:_translateElement(key, term) " {{{2 + let fkey = a:key + if fkey[0] == '!' + let fkey = fkey[1:] + let not = 1 + else + let not = 0 + endif + + if fkey ==? 'level' + let op = not ? ' ==? ' : ' !=? ' + let ret = 'v:val["type"]' . op . string(a:term[0]) + elseif fkey ==? 'type' + if a:term ==? 'style' + let op = not ? ' ==? ' : ' !=? ' + let ret = 'get(v:val, "subtype", "")' . op . '"style"' + else + let op = not ? '!' : '' + let ret = op . 'has_key(v:val, "subtype")' + endif + elseif fkey ==? 'regex' + let op = not ? ' =~? ' : ' !~? ' + let ret = 'v:val["text"]' . op . string(a:term) + elseif fkey ==? 'file' || fkey[:4] ==? 'file:' + let op = not ? ' =~# ' : ' !~# ' + let ret = 'bufname(str2nr(v:val["bufnr"]))' + let mod = fkey[4:] + if mod != '' + let ret = 'fnamemodify(' . ret . ', ' . string(mod) . ')' + endif + let ret .= op . string(a:term) else + call syntastic#log#warn('quiet_messages: ignoring invalid key ' . strtrans(string(fkey))) let ret = "1" endif return ret -endfunction +endfunction " }}}2 + +function! s:_rmrf(what) " {{{2 + if !exists('s:rmdir') + let s:rmdir = syntastic#util#shescape(get(g:, 'netrw_localrmdir', 'rmdir')) + endif + + if getftype(a:what) ==# 'dir' + if filewritable(a:what) != 2 + return + endif + + for f in split(globpath(a:what, '*', 1), "\n") + call s:_rmrf(f) + endfor + silent! call system(s:rmdir . ' ' . syntastic#util#shescape(a:what)) + else + silent! call delete(a:what) + endif +endfunction " }}}2 + +" }}}1 let &cpo = s:save_cpo unlet s:save_cpo -" vim: set et sts=4 sw=4 fdm=marker: + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/doc/syntastic.txt b/doc/syntastic.txt index 4d04bee..423bd7d 100644 --- a/doc/syntastic.txt +++ b/doc/syntastic.txt @@ -21,6 +21,7 @@ CONTENTS *syntastic-contents* 1.Intro........................................|syntastic-intro| 1.1.Quick start............................|syntastic-quickstart| + 1.2.Recommended settings...................|syntastic-recommended| 2.Functionality provided.......................|syntastic-functionality| 2.1.The statusline flag....................|syntastic-statusline-flag| 2.2.Error signs............................|syntastic-error-signs| @@ -34,11 +35,18 @@ CONTENTS *syntastic-contents* 5.1.Choosing which checkers to use.........|syntastic-filetype-checkers| 5.2.Choosing the executable................|syntastic-config-exec| 5.3.Configuring specific checkers..........|syntastic-config-makeprg| + 5.4.Sorting errors.........................|syntastic-config-sort| 6.Notes........................................|syntastic-notes| 6.1.Handling of composite filetypes........|syntastic-composite| - 6.2.Interaction with python-mode...........|syntastic-pymode| - 6.3.Interaction with the fish shell........|syntastic-fish| - 6.4.Using syntastic with the fizsh shell...|syntastic-fizsh| + 6.2.Editing files over network.............|syntastic-netrw| + 6.3.Interaction with python-mode...........|syntastic-pymode| + 6.4.Interaction with YouCompleteMe.........|syntastic-ycm| + 6.5.Interaction with the fish shell........|syntastic-fish| + 6.6.Interaction with PowerShell............|syntastic-powershell| + 6.7.Using syntastic with the fizsh shell...|syntastic-fizsh| + 6.8.Interaction with Eclim.................|syntastic-eclim| + 6.9.Interaction with vim-virtualenv........|syntastic-vim-virtualenv| + 6.10.Interaction with vim-auto-save........|syntastic-vim-auto-save| 7.About........................................|syntastic-about| 8.License......................................|syntastic-license| @@ -62,7 +70,7 @@ Take a look at the wiki for a list of supported filetypes and checkers: https://github.com/scrooloose/syntastic/wiki/Syntax-Checkers Note: This doc only deals with using syntastic. To learn how to write syntax -checker integrations, see the guide on the github wiki: +checker integrations, see the guide on the GitHub wiki: https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide @@ -73,17 +81,40 @@ Syntastic comes preconfigured with a default list of enabled checkers per filetype. This list is kept reasonably short to prevent slowing down Vim or trying to use conflicting checkers. -You can see the list checkers available for the current filetype with the +You can see the list of checkers available for the current filetype with the |:SyntasticInfo| command. -If you want to override the configured list of checkers for a filetype then -see |syntastic-checker-options| for details. You can also change the arguments -passed to a specific checker as well. +You probably want to override the configured list of checkers for the +filetypes you use, and also change the arguments passed to specific checkers +to suit your needs. See |syntastic-checker-options| below for details. -Use |:SyntasticCheck| to manually check right now. Use |:SyntasticToggleMode| -to switch between active (checking on writting the buffer) and passive (manual) -checking. +Use |:SyntasticCheck| to manually check right now. Use |:Errors| to open the +|location-list| window, and |:lclose| to close it. You can clear the error +list with |:SyntasticReset|, and you can use |:SyntasticToggleMode| to switch +between active (checking on writing the buffer) and passive (manual) checking. +You don't have to switch focus to the |location-list| window to jump to the +different errors. Vim provides several built-in commands for this, for +example |:lnext| and |:lprevious|. You may want to add shortcut mappings for +these commands, or perhaps install a plugin such as Tim Pope's 'unimpaired' +(see https://github.com/tpope/vim-unimpaired) that provides such mappings. + +------------------------------------------------------------------------------ +1.2. Recommended settings *syntastic-recommended* + +Syntastic has a large number of options that can be configured, and the +defaults are not particularly well suitable for new users. It is recommended +that you start by adding the following lines to your vimrc, and return to them +later as needed: > + set statusline+=%#warningmsg# + set statusline+=%{SyntasticStatuslineFlag()} + set statusline+=%* + + let g:syntastic_always_populate_loc_list = 1 + let g:syntastic_auto_loc_list = 1 + let g:syntastic_check_on_open = 1 + let g:syntastic_check_on_wq = 0 +< ============================================================================== 2. Functionality provided *syntastic-functionality* @@ -91,7 +122,7 @@ Syntax checking can be done automatically or on demand (see |'syntastic_mode_map'| and |:SyntasticToggleMode| for configuring this). When syntax checking is done, the features below can be used to notify the -user of errors. See |syntastic-options| for how to configure and +user of errors. See |syntastic-global-options| for how to configure and activate/deactivate these features. * A statusline flag @@ -150,13 +181,22 @@ Example: > highlight SyntasticErrorLine guibg=#2f0000 < ------------------------------------------------------------------------------ -2.3. The error window *:Errors* *syntastic-error-window* +2.3. The error window *syntastic-error-window* -You can use the :Errors command to display the errors for the current buffer +You can use the |:Errors| command to display the errors for the current buffer in the |location-list|. -Note that when you use :Errors, the current location list is overwritten with -Syntastic's own location list. +Note that when you use |:Errors| the current location list is overwritten with +Syntastic's own location list. The location list is also overwritten when +|syntastic_auto_jump| is non-zero and the cursor has to jump to an issue. + +By default syntastic doesn't fill the |location-list| with the errors found by +the checkers, in order to reduce clashes with other plugins. Consequently, if +you run |:lopen| or |:lwindow| rather than |:Errors| to open the error window you +wouldn't see syntastic's list of errors. If you insist on using |:lopen| or +|:lwindow| you should either run |:SyntasticSetLoclist| after running the checks, +or set |syntastic_always_populate_loc_list| which tells syntastic to update the +|location-list| automatically. ------------------------------------------------------------------------------ 2.4. Error highlighting *syntastic-highlighting* @@ -167,6 +207,8 @@ and the SpellCap group is used for warnings. If you wish to customize the colors for highlighting you can use the following groups: SyntasticError - Links to 'SpellBad' by default SyntasticWarning - Links to 'SpellCap' by default + SyntasticStyleError - Links to SyntasticError by default + SyntasticStyleWarning - Links to SyntasticWarning by default Example: > highlight SyntasticError guibg=#2f0000 @@ -186,7 +228,13 @@ If |'syntastic_aggregate_errors'| is set, syntastic runs all checkers that apply (still cf. |syntastic-filetype-checkers|), then aggregates errors found by all checkers in a single list, and notifies you. In this mode each error message is labeled with the name of the checker that generated it, but you can -disable these labels by unsetting '|syntastic_id_checkers|'. +disable generation of these labels by turning off '|syntastic_id_checkers|'. + +If |'syntastic_sort_aggregated_errors'| is set (which is the default), messages +in the aggregated list are grouped by file, then sorted by line number, then +type, then column number. Otherwise messages produced by the same checker are +grouped together, and sorting within each group is decided by the variables +|'syntastic___sort'|. ------------------------------------------------------------------------------ 2.6 Filtering errors *syntastic-filtering-errors* @@ -200,11 +248,14 @@ See also: |'syntastic___quiet_messages'|. ============================================================================== 3. Commands *syntastic-commands* -:Errors *:SyntasticErrors* +:Errors *:Errors* When errors have been detected, use this command to pop up the |location-list| and display the error messages. +Please note that the |:Errors| command overwrites the current location list with +syntastic's own location list. + :SyntasticToggleMode *:SyntasticToggleMode* Toggles syntastic between active and passive mode. See |'syntastic_mode_map'| @@ -227,7 +278,7 @@ the order specified. The rules of |syntastic_aggregate_errors| still apply. Example: > :SyntasticCheck flake8 pylint < -:SyntasticInfo *:SyntasticInfo* +:SyntasticInfo *:SyntasticInfo* The command takes an optional argument, and outputs information about the checkers available for the filetype named by said argument, or for the current @@ -278,12 +329,35 @@ a file with a composite filetype), it might not be immediately obvious which checker has produced a given error message. This variable instructs syntastic to label error messages with the names of the checkers that created them. > let g:syntastic_id_checkers = 0 +< + *'syntastic_sort_aggregated_errors'* +Default: 1 +By default, when results from multiple checkers are aggregated in a single +error list (that is either when |syntastic_aggregate_errors| is enabled, or +when checking a file with a composite filetype), errors are grouped by file, +then sorted by line number, then grouped by type (namely errors take precedence +over warnings), then they are sorted by column number. If you want to leave +messages grouped by checker output, set this variable to 0. > + let g:syntastic_sort_aggregated_errors = 0 < *'syntastic_echo_current_error'* Default: 1 -If enabled, syntastic will echo the error associated with the current line to -the command window. If multiple errors are found, the first will be used. > +If enabled, syntastic will echo current error to the command window. If +multiple errors are found on the same line, |syntastic_cursor_columns| is used +to decide which one is shown. > let g:syntastic_echo_current_error = 1 +< + *'syntastic_cursor_columns'* +Default: 1 +This option controls which errors are echoed to the command window if +|syntastic_echo_current_error| is set and multiple errors are found on the same +line. When the option is enabled, the first error corresponding to the current +column is show. Otherwise, the first error on the current line is echoed, +regardless of the cursor position on the current line. + +When dealing with very large lists of errors, disabling this option can speed +up navigation significantly: > + let g:syntastic_cursor_column = 0 < *'syntastic_enable_signs'* Default: 1 @@ -301,8 +375,8 @@ error symbols can be customized: syntastic_style_warning_symbol - For style warnings, defaults to 'S>' Example: > - let g:syntastic_error_symbol = '✗' - let g:syntastic_warning_symbol = '⚠' + let g:syntastic_error_symbol = "✗" + let g:syntastic_warning_symbol = "⚠" < *'syntastic_enable_balloons'* Default: 1 @@ -332,12 +406,17 @@ when saving or opening a file. When set to 0 the cursor won't jump automatically. > let g:syntastic_auto_jump = 0 < -When set to 1 the cursor will always jump to the first issue detected. > +When set to 1 the cursor will always jump to the first issue detected, +regardless of type. > let g:syntastic_auto_jump = 1 < When set to 2 the cursor will jump to the first issue detected, but only if this issue is an error. > let g:syntastic_auto_jump = 2 +< +When set to 3 the cursor will jump to the first error detected, if any. If +all issues detected are warnings, the cursor won't jump. > + let g:syntastic_auto_jump = 3 < *'syntastic_auto_loc_list'* Default: 2 @@ -374,71 +453,106 @@ Default: {} Use this option to map non-standard filetypes to standard ones. Corresponding checkers are mapped accordingly, which allows syntastic to check files with non-standard filetypes: > - let g:syntastic_filetype_map = { 'latex': 'tex', - \ 'gentoo-metadata': 'xml' } + let g:syntastic_filetype_map = { + \ "latex": "tex", + \ "gentoo-metadata": "xml" } < Composite filetypes can also be mapped to simple types, which disables the default behaviour of running both checkers against the input file: > - let g:syntastic_filetype_map = { 'handlebars.html': 'handlebars' } + let g:syntastic_filetype_map = { "handlebars.html": "handlebars" } < *'syntastic_mode_map'* Default: { "mode": "active", "active_filetypes": [], "passive_filetypes": [] } - Use this option to fine tune when automatic syntax checking is done (or not done). The option should be set to something like: > - let g:syntastic_mode_map = { 'mode': 'active', - \ 'active_filetypes': ['ruby', 'php'], - \ 'passive_filetypes': ['puppet'] } + let g:syntastic_mode_map = { + \ "mode": "active", + \ "active_filetypes": ["ruby", "php"], + \ "passive_filetypes": ["puppet"] } < -"mode" can be mapped to one of two values - "active" or "passive". When set to -active, syntastic does automatic checking whenever a buffer is saved or +"mode" can be mapped to one of two values - "active" or "passive". When set +to "active", syntastic does automatic checking whenever a buffer is saved or initially opened. When set to "passive" syntastic only checks when the user calls |:SyntasticCheck|. The exceptions to these rules are defined with "active_filetypes" and -"passive_filetypes". In passive mode, automatic checks are still done -for all filetypes in the "active_filetypes" array. In active mode, -automatic checks are not done for any filetypes in the -"passive_filetypes" array. +"passive_filetypes". In passive mode, automatic checks are still done for +filetypes in the "active_filetypes" array (and "passive_filetypes" is +ignored). In active mode, automatic checks are not done for any filetypes in +the "passive_filetypes" array ("active_filetypes" is ignored). + +If any of "mode", "active_filetypes", or "passive_filetypes" are left +unspecified, they default to values above. + +If local variable |'b:syntastic_mode'| is defined its value takes precedence +over all calculations involving |'syntastic_mode_map'| for the corresponding +buffer. At runtime, the |:SyntasticToggleMode| command can be used to switch between -active and passive mode. +active and passive modes. -If any of "mode", "active_filetypes", or "passive_filetypes" are not specified -then they will default to their default value as above. + *'b:syntastic_mode'* +Default: unset +Only the local form |'b:syntastic_mode'| is used. When set to either "active" +or "passive", it takes precedence over |'syntastic_mode_map'| when deciding +whether the corresponding buffer should be checked automatically. *'syntastic_quiet_messages'* Default: {} - Use this option to filter out some of the messages produced by checkers. The option should be set to something like: > - - let g:syntastic_quiet_messages = { "level": "warnings", - \ "type": "style", - \ "regex": '\m\[C03\d\d\]', - \ "file": ['\m^/usr/include/', '\m\c\.h$'] } + let g:syntastic_quiet_messages = { + \ "!level": "errors", + \ "type": "style", + \ "regex": '\m\[C03\d\d\]', + \ "file:p": ['\m^/usr/include/', '\m\c\.h$'] } < - Each element turns off messages matching the patterns specified by the corresponding value. Values are lists, but if a list consist of a single -element you can omit adding the brackets (e.g. you can write "style" instead of -["style"]). +element you may omit the brackets (e.g. you may write "style" instead of +["style"]). Elements with values [] or '' are ignored (this is useful for +overriding filters, cf. |filter-overrides|). "level" - takes one of two values, "warnings" or "errors" "type" - can be either "syntax" or "style" "regex" - is matched against the messages' text as a case insensitive |regular-expression| - "file" - is matched against the filename the error refers to, as a case - sensitive |regular-expression|. + "file" - is matched against the filenames the messages refer to, as a + case sensitive |regular-expression|. + +If a key is prefixed by an exclamation mark "!", the corresponding filter is +negated (i.e. the above example silences all messages that are NOT errors). + +The "file" key may be followed by one or more filename modifiers (see +|filename-modifiers|). The modifiers are applied to the filenames the messages +refer to before matching against the value (i.e. in the above example the full +path of the issues are matched against '\m^/usr/include/' and '\m\c\.h$'). + +If |'syntastic_id_checkers'| is set, filters are applied before error messages +are labeled with the names of the checkers that created them. There are also checker-specific variants of this option, providing finer control. They are named |'syntastic___quiet_messages'|. +For a particular checker, if both a |'syntastic_quiet_messages'| filter and +a checker-specific filter are present, they are both applied (to the list of +errors produced by the said checker). In case of conflicting values for the +same keys, the values of the checker-specific filters take precedence. + + *filter-overrides* +Since filter elements with values [] or '' are ignored, you can disable global +filters for particular checkers, by setting the values of the corresponding +elements in |'syntastic___quiet_messages'| to [] or ''. For +example, the following setting will silence all warnings, except for the +ones produced by "pylint": > + let g:syntastic_quiet_messages = { "level": "warnings" } + let g:syntastic_python_pylint_quiet_messages = { "level" : [] } +< *'syntastic_stl_format'* Default: [Syntax: line:%F (%t)] Use this option to control what the syntastic statusline text contains. Several @@ -467,6 +581,12 @@ statusline: > < If the buffer had 2 warnings, starting on line 5 then this would appear: > [Warn: 5 #2] +< + *'b:syntastic_skip_checks'* +Default: unset +Only the local form |'b:syntastic_skip_checks'| is used. When set to a true +value, no checks are run against the corresponding buffer. Example: > + let b:syntastic_skip_checks = 1 < *'syntastic_full_redraws'* Default: 0 in GUI Vim and MacVim, 1 otherwise @@ -475,16 +595,24 @@ Changing it can in principle make screen redraws smoother, but it can also cause screen to flicker, or cause ghost characters. Leaving it to the default should be safe. + *'syntastic_exit_checks'* +Default: 0 when running under "cmd.exe" on Windows, 1 otherwise +Syntastic attempts to catch abnormal termination conditions from checkers by +looking at their exit codes. The "cmd.exe" shell on Windows make these checks +meaningless, by returning 1 to Vim when the checkers exit with non-zero codes. +The above variable can be used to disable exit code checks in syntastic. + *'syntastic_debug'* Default: 0 Set this to the sum of one or more of the following flags to enable debugging: - 1 - trace checker calls + 1 - trace general workflow 2 - dump location lists 4 - trace notifiers 8 - trace autocommands 16 - dump options + 32 - trace running of specific checkers Example: > let g:syntastic_debug = 1 @@ -504,7 +632,7 @@ List of filetypes handled by checkers external to syntastic. If you have a Vim plugin that adds a checker for syntastic, and if the said checker deals with a filetype that is unknown to syntastic, you might consider adding that filetype to this list: > - let g:syntastic_extra_filetypes = [ 'make', 'gitcommit' ] + let g:syntastic_extra_filetypes = [ "make", "gitcommit" ] < This will allow |:SyntasticInfo| to do proper tab completion for the new filetypes. @@ -518,14 +646,14 @@ filetypes. *'g:syntastic__checkers'* You can tell syntastic which checkers to run for a given filetype by setting a variable 'g:syntastic__checkers' to a list of checkers, e.g. > - let g:syntastic_php_checkers = ['php', 'phpcs', 'phpmd'] + let g:syntastic_php_checkers = ["php", "phpcs", "phpmd"] < *'b:syntastic_checkers'* There is also a per-buffer version of this setting, 'b:syntastic_checkers'. When set, it takes precedence over |'g:syntastic__checkers'|. You can use this in an autocmd to configure specific checkers for particular paths: > - autocmd FileType python if stridx(expand('%:p'), '/some/path/') == 0 | - \ let b:syntastic_checkers = ['pylint'] | endif + autocmd FileType python if stridx(expand("%:p"), "/some/path/") == 0 | + \ let b:syntastic_checkers = ["pylint"] | endif < If neither |'g:syntastic__checkers'| nor |'b:syntastic_checkers'| is set, a default list of checker is used. Beware however that this list @@ -541,48 +669,61 @@ Use |:SyntasticInfo| to see which checkers are available for a given filetype. ------------------------------------------------------------------------------ 5.2 Choosing the executable *syntastic-config-exec* - *'syntastic___exec'* -The executable used by a checker is normally defined automatically, when the -checkers is registered. You can however override it by setting the variable -'g:syntastic___exec': > + *'syntastic___exec'* +The executable run by a checker is normally defined automatically, when the +checker is registered. You can however override it, by setting the variable +'g:syntastic___exec': > let g:syntastic_ruby_mri_exec = '~/bin/ruby2' < +This variable has a local version, 'b:syntastic___exec', +which takes precedence over the global one in the corresponding buffer. + + *'b:syntastic__exec'* +And there is also a local variable named 'b:syntastic__exec', which +takes precedence over both 'b:syntastic___exec' and +'g:syntastic___exec' in the buffers where it is defined. + ------------------------------------------------------------------------------ 5.3 Configuring specific checkers *syntastic-config-makeprg* Most checkers use the 'makeprgBuild()' function and provide many options by default - in fact you can customise every part of the command that gets called. - *'syntastic___