551 changed files with 66981 additions and 0 deletions
@ -0,0 +1 @@ |
|||||
|
/pack/minpac/* |
||||
@ -0,0 +1,5 @@ |
|||||
|
setlocal expandtab |
||||
|
setlocal shiftwidth=4 |
||||
|
setlocal softtabstop=4 |
||||
|
setlocal autoindent |
||||
|
let g:rustfmt_autosave = 1 |
||||
@ -0,0 +1,18 @@ |
|||||
|
language: viml |
||||
|
sudo: required |
||||
|
dist: trusty |
||||
|
|
||||
|
install: |
||||
|
- export VIM_VERSION=master |
||||
|
- bash test/install-vim.sh |
||||
|
- export PATH=$HOME/vim/bin:$PATH |
||||
|
|
||||
|
before_script: |
||||
|
- git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis /tmp/vim-themis |
||||
|
|
||||
|
script: |
||||
|
- pip install --user --upgrade vim-vint pathlib enum34 typing |
||||
|
- python --version |
||||
|
- vim --version |
||||
|
- vint autoload |
||||
|
- /tmp/vim-themis/bin/themis --reporter dot |
||||
@ -0,0 +1,21 @@ |
|||||
|
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) 2016 Prabir Shrestha |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
||||
@ -0,0 +1,86 @@ |
|||||
|
# async.vim |
||||
|
normalize async job control api for vim and neovim |
||||
|
|
||||
|
## sample usage |
||||
|
|
||||
|
```vim |
||||
|
function! s:handler(job_id, data, event_type) |
||||
|
echo a:job_id . ' ' . a:event_type |
||||
|
echo join(a:data, "\n") |
||||
|
endfunction |
||||
|
|
||||
|
if has('win32') || has('win64') |
||||
|
let argv = ['cmd', '/c', 'dir c:\ /b'] |
||||
|
else |
||||
|
let argv = ['bash', '-c', 'ls'] |
||||
|
endif |
||||
|
|
||||
|
let jobid = async#job#start(argv, { |
||||
|
\ 'on_stdout': function('s:handler'), |
||||
|
\ 'on_stderr': function('s:handler'), |
||||
|
\ 'on_exit': function('s:handler'), |
||||
|
\ }) |
||||
|
|
||||
|
if jobid > 0 |
||||
|
echom 'job started' |
||||
|
else |
||||
|
echom 'job failed to start' |
||||
|
endif |
||||
|
|
||||
|
" If you want to get the process id of the job |
||||
|
let pid = async#job#pid(jobid) |
||||
|
|
||||
|
" If you want to wait the job: |
||||
|
call async#job#wait([jobid], 5000) " timeout: 5 sec |
||||
|
|
||||
|
" If you want to stop the job: |
||||
|
call async#job#stop(jobid) |
||||
|
``` |
||||
|
|
||||
|
## APIs |
||||
|
|
||||
|
APIs are based on neovim's job control APIs. |
||||
|
|
||||
|
* [job-control](https://neovim.io/doc/user/job_control.html#job-control) |
||||
|
* [jobsend()](https://neovim.io/doc/user/eval.html#jobsend%28%29) |
||||
|
* [jobstart()](https://neovim.io/doc/user/eval.html#jobstart%28%29) |
||||
|
* [jobstop()](https://neovim.io/doc/user/eval.html#jobstop%28%29) |
||||
|
* [jobwait()](https://neovim.io/doc/user/eval.html#jobwait%28%29) |
||||
|
* [jobpid()](https://neovim.io/doc/user/eval.html#jobpid%28%29) |
||||
|
|
||||
|
## Embedding |
||||
|
|
||||
|
Async.vim can be either embedded with other plugins or be used as an external plugin. |
||||
|
If you want to embed all you need is to change these 5 function names async#job# to what ever you want. E.g.: |
||||
|
|
||||
|
```vim |
||||
|
" public apis {{{ |
||||
|
function! yourplugin#job#start(cmd, opts) abort |
||||
|
return s:job_start(a:cmd, a:opts) |
||||
|
endfunction |
||||
|
|
||||
|
function! yourplugin#job#stop(jobid) abort |
||||
|
call s:job_stop(a:jobid) |
||||
|
endfunction |
||||
|
|
||||
|
function! yourplugin#job#send(jobid, data) abort |
||||
|
call s:job_send(a:jobid, a:data) |
||||
|
endfunction |
||||
|
|
||||
|
function! yourplugin#job#wait(jobids, ...) abort |
||||
|
let l:timeout = get(a:000, 0, -1) |
||||
|
return s:job_wait(a:jobids, l:timeout) |
||||
|
endfunction |
||||
|
|
||||
|
function! yourplugin#job#pid(jobid) abort |
||||
|
return s:job_pid(a:jobid) |
||||
|
endfunction |
||||
|
" }}} |
||||
|
``` |
||||
|
|
||||
|
## Todos |
||||
|
* Fallback to sync `system()` calls in vim that doesn't support `job` |
||||
|
* `job_stop` and `job_send` is treated as noop when using `system()` |
||||
|
* `on_stderr` doesn't work when using `system()` |
||||
|
* Fallback to python/ruby threads and vimproc instead of using `system()` for better compatibility (PRs welcome!!!) |
||||
|
|
||||
@ -0,0 +1,302 @@ |
|||||
|
" Author: Prabir Shrestha <mail at prabir dot me> |
||||
|
" Website: https://github.com/prabirshrestha/async.vim |
||||
|
" License: The MIT License {{{ |
||||
|
" The MIT License (MIT) |
||||
|
" |
||||
|
" Copyright (c) 2016 Prabir Shrestha |
||||
|
" |
||||
|
" Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
" of this software and associated documentation files (the "Software"), to deal |
||||
|
" in the Software without restriction, including without limitation the rights |
||||
|
" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
" copies of the Software, and to permit persons to whom the Software is |
||||
|
" furnished to do so, subject to the following conditions: |
||||
|
" |
||||
|
" The above copyright notice and this permission notice shall be included in all |
||||
|
" copies or substantial portions of the Software. |
||||
|
" |
||||
|
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
" SOFTWARE. |
||||
|
" }}} |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
let s:jobidseq = 0 |
||||
|
let s:jobs = {} " { job, opts, type: 'vimjob|nvimjob'} |
||||
|
let s:job_type_nvimjob = 'nvimjob' |
||||
|
let s:job_type_vimjob = 'vimjob' |
||||
|
let s:job_error_unsupported_job_type = -2 " unsupported job type |
||||
|
|
||||
|
function! s:job_supported_types() abort |
||||
|
let l:supported_types = [] |
||||
|
if has('nvim') |
||||
|
let l:supported_types += [s:job_type_nvimjob] |
||||
|
endif |
||||
|
if !has('nvim') && has('job') && has('channel') && has('lambda') |
||||
|
let l:supported_types += [s:job_type_vimjob] |
||||
|
endif |
||||
|
return l:supported_types |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_supports_type(type) abort |
||||
|
return index(s:job_supported_types(), a:type) >= 0 |
||||
|
endfunction |
||||
|
|
||||
|
function! s:out_cb(jobid, opts, job, data) abort |
||||
|
if has_key(a:opts, 'on_stdout') |
||||
|
call a:opts.on_stdout(a:jobid, split(a:data, "\n", 1), 'stdout') |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:err_cb(jobid, opts, job, data) abort |
||||
|
if has_key(a:opts, 'on_stderr') |
||||
|
call a:opts.on_stderr(a:jobid, split(a:data, "\n", 1), 'stderr') |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:exit_cb(jobid, opts, job, status) abort |
||||
|
if has_key(a:opts, 'on_exit') |
||||
|
call a:opts.on_exit(a:jobid, a:status, 'exit') |
||||
|
endif |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
call remove(s:jobs, a:jobid) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_stdout(jobid, data, event) abort |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if has_key(l:jobinfo.opts, 'on_stdout') |
||||
|
call l:jobinfo.opts.on_stdout(a:jobid, a:data, a:event) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_stderr(jobid, data, event) abort |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if has_key(l:jobinfo.opts, 'on_stderr') |
||||
|
call l:jobinfo.opts.on_stderr(a:jobid, a:data, a:event) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_exit(jobid, status, event) abort |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if has_key(l:jobinfo.opts, 'on_exit') |
||||
|
call l:jobinfo.opts.on_exit(a:jobid, a:status, a:event) |
||||
|
endif |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
call remove(s:jobs, a:jobid) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_start(cmd, opts) abort |
||||
|
let l:jobtypes = s:job_supported_types() |
||||
|
let l:jobtype = '' |
||||
|
|
||||
|
if has_key(a:opts, 'type') |
||||
|
if type(a:opts.type) == type('') |
||||
|
if !s:job_supports_type(a:opts.type) |
||||
|
return s:job_error_unsupported_job_type |
||||
|
endif |
||||
|
let l:jobtype = a:opts.type |
||||
|
else |
||||
|
let l:jobtypes = a:opts.type |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if empty(l:jobtype) |
||||
|
" find the best jobtype |
||||
|
for l:jobtype2 in l:jobtypes |
||||
|
if s:job_supports_type(l:jobtype2) |
||||
|
let l:jobtype = l:jobtype2 |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
if l:jobtype ==? '' |
||||
|
return s:job_error_unsupported_job_type |
||||
|
endif |
||||
|
|
||||
|
if l:jobtype == s:job_type_nvimjob |
||||
|
let l:job = jobstart(a:cmd, { |
||||
|
\ 'on_stdout': function('s:on_stdout'), |
||||
|
\ 'on_stderr': function('s:on_stderr'), |
||||
|
\ 'on_exit': function('s:on_exit'), |
||||
|
\}) |
||||
|
if l:job <= 0 |
||||
|
return l:job |
||||
|
endif |
||||
|
let l:jobid = l:job " nvimjobid and internal jobid is same |
||||
|
let s:jobs[l:jobid] = { |
||||
|
\ 'type': s:job_type_nvimjob, |
||||
|
\ 'opts': a:opts, |
||||
|
\ } |
||||
|
let s:jobs[l:jobid].job = l:job |
||||
|
elseif l:jobtype == s:job_type_vimjob |
||||
|
let s:jobidseq = s:jobidseq + 1 |
||||
|
let l:jobid = s:jobidseq |
||||
|
let l:jobopt = { |
||||
|
\ 'out_cb': function('s:out_cb', [l:jobid, a:opts]), |
||||
|
\ 'err_cb': function('s:err_cb', [l:jobid, a:opts]), |
||||
|
\ 'exit_cb': function('s:exit_cb', [l:jobid, a:opts]), |
||||
|
\ 'mode': 'raw', |
||||
|
\ } |
||||
|
if has('patch-8.1.889') |
||||
|
let l:jobopt['noblock'] = 1 |
||||
|
endif |
||||
|
let l:job = job_start(a:cmd, l:jobopt) |
||||
|
if job_status(l:job) !=? 'run' |
||||
|
return -1 |
||||
|
endif |
||||
|
let s:jobs[l:jobid] = { |
||||
|
\ 'type': s:job_type_vimjob, |
||||
|
\ 'opts': a:opts, |
||||
|
\ 'job': l:job, |
||||
|
\ 'channel': job_getchannel(l:job), |
||||
|
\ 'buffer': '' |
||||
|
\ } |
||||
|
else |
||||
|
return s:job_error_unsupported_job_type |
||||
|
endif |
||||
|
|
||||
|
return l:jobid |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_stop(jobid) abort |
||||
|
if has_key(s:jobs, a:jobid) |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if l:jobinfo.type == s:job_type_nvimjob |
||||
|
" See: vital-Whisky/System.Job |
||||
|
try |
||||
|
call jobstop(a:jobid) |
||||
|
catch /^Vim\%((\a\+)\)\=:E900/ |
||||
|
" NOTE: |
||||
|
" Vim does not raise exception even the job has already closed so fail |
||||
|
" silently for 'E900: Invalid job id' exception |
||||
|
endtry |
||||
|
elseif l:jobinfo.type == s:job_type_vimjob |
||||
|
call job_stop(s:jobs[a:jobid].job) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_send(jobid, data) abort |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if l:jobinfo.type == s:job_type_nvimjob |
||||
|
call jobsend(a:jobid, a:data) |
||||
|
elseif l:jobinfo.type == s:job_type_vimjob |
||||
|
if has('patch-8.1.0818') |
||||
|
call ch_sendraw(l:jobinfo.channel, a:data) |
||||
|
else |
||||
|
let l:jobinfo.buffer .= a:data |
||||
|
call s:flush_vim_sendraw(a:jobid, v:null) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:flush_vim_sendraw(jobid, timer) abort |
||||
|
" https://github.com/vim/vim/issues/2548 |
||||
|
" https://github.com/natebosch/vim-lsc/issues/67#issuecomment-357469091 |
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
sleep 1m |
||||
|
if len(l:jobinfo.buffer) <= 4096 |
||||
|
call ch_sendraw(l:jobinfo.channel, l:jobinfo.buffer) |
||||
|
let l:jobinfo.buffer = '' |
||||
|
else |
||||
|
let l:to_send = l:jobinfo.buffer[:4095] |
||||
|
let l:jobinfo.buffer = l:jobinfo.buffer[4096:] |
||||
|
call ch_sendraw(l:jobinfo.channel, l:to_send) |
||||
|
call timer_start(1, function('s:flush_vim_sendraw', [a:jobid])) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_wait_single(jobid, timeout, start) abort |
||||
|
if !has_key(s:jobs, a:jobid) |
||||
|
return -3 |
||||
|
endif |
||||
|
|
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if l:jobinfo.type == s:job_type_nvimjob |
||||
|
let l:timeout = a:timeout - reltimefloat(reltime(a:start)) * 1000 |
||||
|
return jobwait([a:jobid], float2nr(l:timeout))[0] |
||||
|
elseif l:jobinfo.type == s:job_type_vimjob |
||||
|
let l:timeout = a:timeout / 1000.0 |
||||
|
try |
||||
|
while l:timeout < 0 || reltimefloat(reltime(a:start)) < l:timeout |
||||
|
let l:info = job_info(l:jobinfo.job) |
||||
|
if l:info.status ==# 'dead' |
||||
|
return l:info.exitval |
||||
|
elseif l:info.status ==# 'fail' |
||||
|
return -3 |
||||
|
endif |
||||
|
sleep 1m |
||||
|
endwhile |
||||
|
catch /^Vim:Interrupt$/ |
||||
|
return -2 |
||||
|
endtry |
||||
|
endif |
||||
|
return -1 |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_wait(jobids, timeout) abort |
||||
|
let l:start = reltime() |
||||
|
let l:exitcode = 0 |
||||
|
let l:ret = [] |
||||
|
for l:jobid in a:jobids |
||||
|
if l:exitcode != -2 " Not interrupted. |
||||
|
let l:exitcode = s:job_wait_single(l:jobid, a:timeout, l:start) |
||||
|
endif |
||||
|
let l:ret += [l:exitcode] |
||||
|
endfor |
||||
|
return l:ret |
||||
|
endfunction |
||||
|
|
||||
|
function! s:job_pid(jobid) abort |
||||
|
if !has_key(s:jobs, a:jobid) |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
let l:jobinfo = s:jobs[a:jobid] |
||||
|
if l:jobinfo.type == s:job_type_nvimjob |
||||
|
return jobpid(a:jobid) |
||||
|
elseif l:jobinfo.type == s:job_type_vimjob |
||||
|
let l:vimjobinfo = job_info(a:jobid) |
||||
|
if type(l:vimjobinfo) == type({}) && has_key(l:vimjobinfo, 'process') |
||||
|
return l:vimjobinfo['process'] |
||||
|
endif |
||||
|
endif |
||||
|
return 0 |
||||
|
endfunction |
||||
|
|
||||
|
" public apis {{{ |
||||
|
function! async#job#start(cmd, opts) abort |
||||
|
return s:job_start(a:cmd, a:opts) |
||||
|
endfunction |
||||
|
|
||||
|
function! async#job#stop(jobid) abort |
||||
|
call s:job_stop(a:jobid) |
||||
|
endfunction |
||||
|
|
||||
|
function! async#job#send(jobid, data) abort |
||||
|
call s:job_send(a:jobid, a:data) |
||||
|
endfunction |
||||
|
|
||||
|
function! async#job#wait(jobids, ...) abort |
||||
|
let l:timeout = get(a:000, 0, -1) |
||||
|
return s:job_wait(a:jobids, l:timeout) |
||||
|
endfunction |
||||
|
|
||||
|
function! async#job#pid(jobid) abort |
||||
|
return s:job_pid(a:jobid) |
||||
|
endfunction |
||||
|
" }}} |
||||
@ -0,0 +1,2 @@ |
|||||
|
call themis#option('recursive', 1) |
||||
|
call themis#helper('command').with(themis#helper('assert')) |
||||
@ -0,0 +1,76 @@ |
|||||
|
function! s:on_stdout(ctx, id, data, event) abort |
||||
|
call add(a:ctx.output, join(a:data, '')) |
||||
|
call async#job#stop(a:id) |
||||
|
endfunction |
||||
|
|
||||
|
Describe async |
||||
|
Before |
||||
|
let scope = themis#helper('scope') |
||||
|
let vars = scope.vars('autoload/async/job.vim') |
||||
|
End |
||||
|
|
||||
|
Describe async#job#start |
||||
|
It can start cmmand and return numbered job-id |
||||
|
let job = async#job#start('vim --version', {}) |
||||
|
Assert Equals(type(job), v:t_number) |
||||
|
End |
||||
|
End |
||||
|
|
||||
|
Describe async#job#stop |
||||
|
It can stop the job specified |
||||
|
let job = async#job#start('bash -c "sleep 2 && touch i-love-vim"', {}) |
||||
|
sleep 3 |
||||
|
call async#job#stop(job) |
||||
|
Assert filereadable('i-love-vim') |
||||
|
call delete('i-love-vim') |
||||
|
|
||||
|
let job = async#job#start('bash -c "sleep 2 && touch i-love-vim"', {}) |
||||
|
sleep 1 |
||||
|
call async#job#stop(job) |
||||
|
Assert !filereadable('i-love-vim') |
||||
|
End |
||||
|
|
||||
|
It invokes 'on_exit' callback |
||||
|
let ns = { 'called': 0 } |
||||
|
let job = async#job#start('bash -c "sleep 2 && touch i-love-vim"', { |
||||
|
\ 'on_exit': { -> extend(ns, { 'called': 1 }) }, |
||||
|
\}) |
||||
|
call async#job#stop(job) |
||||
|
sleep 1m |
||||
|
Assert Equals(ns, {'called': 1}) |
||||
|
End |
||||
|
|
||||
|
It removes a corresponding job from an internal variable |
||||
|
let job1 = async#job#start('bash -c "sleep 2 && touch i-love-vim"', {}) |
||||
|
let job2 = async#job#start('bash -c "sleep 2 && touch i-love-vim"', {}) |
||||
|
Assert Equals(sort(keys(vars.jobs)), sort([string(job1), string(job2)])) |
||||
|
call async#job#stop(job1) |
||||
|
sleep 1m |
||||
|
Assert Equals(sort(keys(vars.jobs)), sort([string(job2)])) |
||||
|
sleep 3 |
||||
|
Assert Equals(sort(keys(vars.jobs)), []) |
||||
|
End |
||||
|
End |
||||
|
|
||||
|
Describe async#job#wait |
||||
|
It can wait the job specified |
||||
|
let job = async#job#start('bash -c "sleep 2"', {}) |
||||
|
let start = reltime() |
||||
|
call async#job#wait([job]) |
||||
|
let seconds = reltimefloat(reltime(start)) |
||||
|
call async#job#stop(job) |
||||
|
Assert seconds > 2 |
||||
|
End |
||||
|
End |
||||
|
|
||||
|
Describe async#job#send |
||||
|
It can send input text to the job |
||||
|
let ctx = { 'output': [] } |
||||
|
let job = async#job#start('cat', {'on_stdout': function('s:on_stdout', [ctx])}) |
||||
|
call async#job#send(job, "i-love-vim\n") |
||||
|
call async#job#wait([job]) |
||||
|
let out = join(ctx.output, '') |
||||
|
Assert Equals(out, 'i-love-vim') |
||||
|
End |
||||
|
End |
||||
|
End |
||||
@ -0,0 +1,27 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -ev |
||||
|
|
||||
|
case "${TRAVIS_OS_NAME}" in |
||||
|
linux) |
||||
|
if [[ "${VIM_VERSION}" == "" ]]; then |
||||
|
exit |
||||
|
fi |
||||
|
git clone --depth 1 --branch "${VIM_VERSION}" https://github.com/vim/vim /tmp/vim |
||||
|
cd /tmp/vim |
||||
|
./configure --prefix="${HOME}/vim" --with-features=huge --enable-pythoninterp \ |
||||
|
--enable-python3interp --enable-fail-if-missing |
||||
|
make -j2 |
||||
|
make install |
||||
|
;; |
||||
|
osx) |
||||
|
brew install macvim |
||||
|
# Instead of --with-override-system-vim, manually link the executable because |
||||
|
# it prevents MacVim installation with a bottle. |
||||
|
ln -fs "$(brew --prefix macvim)/bin/mvim" "/usr/local/bin/vim" |
||||
|
;; |
||||
|
*) |
||||
|
echo "Unknown value of \${TRAVIS_OS_NAME}: ${TRAVIS_OS_NAME}" |
||||
|
exit 65 |
||||
|
;; |
||||
|
esac |
||||
@ -0,0 +1 @@ |
|||||
|
* text=auto |
||||
@ -0,0 +1 @@ |
|||||
|
tags |
||||
@ -0,0 +1,7 @@ |
|||||
|
LSP source for asyncomplete.vim vim-lsp |
||||
|
======================================= |
||||
|
|
||||
|
Provide [Language Server Protocol](https://github.com/Microsoft/language-server-protocol) autocompletion source for [asyncomplete.vim](https://github.com/prabirshrestha/asyncomplete.vim) and [vim-lsp](https://github.com/prabirshrestha/vim-lsp). |
||||
|
|
||||
|
## Installing |
||||
|
Refer to asyncomplete.vim docs on Language Server Protocol at https://github.com/prabirshrestha/asyncomplete.vim#language-server-protocol-lsp. |
||||
@ -0,0 +1,97 @@ |
|||||
|
if exists('g:asyncomplete_lsp_loaded') |
||||
|
finish |
||||
|
endif |
||||
|
let g:asyncomplete_lsp_loaded = 1 |
||||
|
|
||||
|
let s:servers = {} " { server_name: 1 } |
||||
|
|
||||
|
au User lsp_server_init call s:server_initialized() |
||||
|
au User lsp_server_exit call s:server_exited() |
||||
|
|
||||
|
function! s:server_initialized() abort |
||||
|
let l:server_names = lsp#get_server_names() |
||||
|
for l:server_name in l:server_names |
||||
|
if !has_key(s:servers, l:server_name) |
||||
|
let l:init_capabilities = lsp#get_server_capabilities(l:server_name) |
||||
|
if has_key(l:init_capabilities, 'completionProvider') |
||||
|
let l:name = s:generate_asyncomplete_name(l:server_name) |
||||
|
let l:source_opt = { |
||||
|
\ 'name': l:name, |
||||
|
\ 'completor': function('s:completor', [l:server_name]), |
||||
|
\ } |
||||
|
if type(l:init_capabilities['completionProvider']) == type({}) && has_key(l:init_capabilities['completionProvider'], 'triggerCharacters') |
||||
|
let l:source_opt['triggers'] = { '*': l:init_capabilities['completionProvider']['triggerCharacters'] } |
||||
|
endif |
||||
|
let l:server = lsp#get_server_info(l:server_name) |
||||
|
if has_key(l:server, 'whitelist') |
||||
|
let l:source_opt['whitelist'] = l:server['whitelist'] |
||||
|
endif |
||||
|
if has_key(l:server, 'blacklist') |
||||
|
let l:source_opt['blacklist'] = l:server['blacklist'] |
||||
|
endif |
||||
|
if has_key(l:server, 'priority') |
||||
|
let l:source_opt['priority'] = l:server['priority'] |
||||
|
endif |
||||
|
call asyncomplete#register_source(l:source_opt) |
||||
|
let s:servers[l:server_name] = 1 |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction |
||||
|
|
||||
|
function! s:server_exited() abort |
||||
|
let l:server_names = lsp#get_server_names() |
||||
|
for l:server_name in l:server_names |
||||
|
if has_key(s:servers, l:server_name) |
||||
|
let l:name = s:generate_asyncomplete_name(l:server_name) |
||||
|
if s:servers[l:server_name] |
||||
|
call asyncomplete#unregister_source(l:name) |
||||
|
endif |
||||
|
unlet s:servers[l:server_name] |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction |
||||
|
|
||||
|
function! s:generate_asyncomplete_name(server_name) abort |
||||
|
return 'asyncomplete_lsp_' . a:server_name |
||||
|
endfunction |
||||
|
|
||||
|
function! s:completor(server_name, opt, ctx) abort |
||||
|
call lsp#send_request(a:server_name, { |
||||
|
\ 'method': 'textDocument/completion', |
||||
|
\ 'params': { |
||||
|
\ 'textDocument': lsp#get_text_document_identifier(), |
||||
|
\ 'position': lsp#get_position(), |
||||
|
\ }, |
||||
|
\ 'on_notification': function('s:handle_completion', [a:server_name, a:opt, a:ctx]), |
||||
|
\ }) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:handle_completion(server_name, opt, ctx, data) abort |
||||
|
if lsp#client#is_error(a:data) || !has_key(a:data, 'response') || !has_key(a:data['response'], 'result') |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let l:result = a:data['response']['result'] |
||||
|
|
||||
|
if type(l:result) == type([]) |
||||
|
let l:items = l:result |
||||
|
let l:incomplete = 0 |
||||
|
elseif type(l:result) == type({}) |
||||
|
let l:items = l:result['items'] |
||||
|
let l:incomplete = l:result['isIncomplete'] |
||||
|
else |
||||
|
let l:items = [] |
||||
|
let l:incomplete = 0 |
||||
|
endif |
||||
|
|
||||
|
call map(l:items, 'lsp#omni#get_vim_completion_item(v:val, a:server_name)') |
||||
|
|
||||
|
let l:col = a:ctx['col'] |
||||
|
let l:typed = a:ctx['typed'] |
||||
|
let l:kw = matchstr(l:typed, '\k\+$') |
||||
|
let l:kwlen = len(l:kw) |
||||
|
let l:startcol = l:col - l:kwlen |
||||
|
|
||||
|
call asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:items, l:incomplete) |
||||
|
endfunction |
||||
@ -0,0 +1 @@ |
|||||
|
* text=auto |
||||
@ -0,0 +1,12 @@ |
|||||
|
# These are supported funding model platforms |
||||
|
|
||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] |
||||
|
patreon: # Replace with a single Patreon username |
||||
|
open_collective: asyncomplete |
||||
|
ko_fi: # Replace with a single Ko-fi username |
||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel |
||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry |
||||
|
liberapay: # Replace with a single Liberapay username |
||||
|
issuehunt: # Replace with a single IssueHunt username |
||||
|
otechie: # Replace with a single Otechie username |
||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] |
||||
@ -0,0 +1 @@ |
|||||
|
tags |
||||
@ -0,0 +1,21 @@ |
|||||
|
MIT License |
||||
|
|
||||
|
Copyright (c) 2019 Prabir Shrestha |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
||||
@ -0,0 +1,226 @@ |
|||||
|
asyncomplete.vim |
||||
|
================ |
||||
|
|
||||
|
Async autocompletion for Vim 8 and Neovim with |timers|. |
||||
|
|
||||
|
This is inspired by [nvim-complete-manager](https://github.com/roxma/nvim-complete-manager) but written |
||||
|
in pure Vim Script. |
||||
|
|
||||
|
### Installing |
||||
|
|
||||
|
```viml |
||||
|
Plug 'prabirshrestha/asyncomplete.vim' |
||||
|
``` |
||||
|
|
||||
|
#### Tab completion |
||||
|
|
||||
|
```vim |
||||
|
inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>" |
||||
|
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>" |
||||
|
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<cr>" |
||||
|
``` |
||||
|
|
||||
|
### Force refresh completion |
||||
|
|
||||
|
```vim |
||||
|
imap <c-space> <Plug>(asyncomplete_force_refresh) |
||||
|
``` |
||||
|
|
||||
|
### Auto popup |
||||
|
By default asyncomplete will automatically show the autocomplete popup menu as you start typing. |
||||
|
If you would like to disable the default behavior set `g:asyncomplete_auto_popup` to 0. |
||||
|
|
||||
|
```vim |
||||
|
let g:asyncomplete_auto_popup = 0 |
||||
|
``` |
||||
|
|
||||
|
You can use the above `<Plug>(asyncomplete_force_refresh)` to show the popup |
||||
|
or can you tab to show the autocomplete. |
||||
|
|
||||
|
```vim |
||||
|
let g:asyncomplete_auto_popup = 0 |
||||
|
|
||||
|
function! s:check_back_space() abort |
||||
|
let col = col('.') - 1 |
||||
|
return !col || getline('.')[col - 1] =~ '\s' |
||||
|
endfunction |
||||
|
|
||||
|
inoremap <silent><expr> <TAB> |
||||
|
\ pumvisible() ? "\<C-n>" : |
||||
|
\ <SID>check_back_space() ? "\<TAB>" : |
||||
|
\ asyncomplete#force_refresh() |
||||
|
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>" |
||||
|
``` |
||||
|
|
||||
|
#### Preview Window |
||||
|
|
||||
|
To disable preview window: |
||||
|
|
||||
|
```vim |
||||
|
set completeopt-=preview |
||||
|
``` |
||||
|
|
||||
|
To enable preview window: |
||||
|
|
||||
|
```vim |
||||
|
set completeopt+=preview |
||||
|
``` |
||||
|
|
||||
|
To auto close preview window when completion is done. |
||||
|
|
||||
|
```vim |
||||
|
autocmd! CompleteDone * if pumvisible() == 0 | pclose | endif |
||||
|
``` |
||||
|
|
||||
|
### Sources |
||||
|
|
||||
|
asyncomplete.vim deliberately does not contain any sources. Please use one of the following sources or create your own. |
||||
|
|
||||
|
#### Language Server Protocol (LSP) |
||||
|
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol) via [vim-lsp](https://github.com/prabirshrestha/vim-lsp) and [asyncomplete-lsp.vim](https://github.com/prabirshrestha/asyncomplete-lsp.vim) |
||||
|
|
||||
|
**Please note** that vim-lsp setup for neovim requires neovim v0.2.0 or higher, since it uses lambda setup. |
||||
|
|
||||
|
```vim |
||||
|
Plug 'prabirshrestha/asyncomplete.vim' |
||||
|
Plug 'prabirshrestha/async.vim' |
||||
|
Plug 'prabirshrestha/vim-lsp' |
||||
|
Plug 'prabirshrestha/asyncomplete-lsp.vim' |
||||
|
|
||||
|
if executable('pyls') |
||||
|
" pip install python-language-server |
||||
|
au User lsp_setup call lsp#register_server({ |
||||
|
\ 'name': 'pyls', |
||||
|
\ 'cmd': {server_info->['pyls']}, |
||||
|
\ 'whitelist': ['python'], |
||||
|
\ }) |
||||
|
endif |
||||
|
``` |
||||
|
|
||||
|
**Refer to [vim-lsp wiki](https://github.com/prabirshrestha/vim-lsp/wiki/Servers) for configuring other language servers.** Besides auto-complete language server support other features such as go to definition, find references, renaming symbols, document symbols, find workspace symbols, formatting and so on. |
||||
|
|
||||
|
*in alphabetical order* |
||||
|
|
||||
|
| Languages/FileType/Source | Links | |
||||
|
|-------------------------------|----------------------------------------------------------------------------------------------------| |
||||
|
| Buffer | [asyncomplete-buffer.vim](https://github.com/prabirshrestha/asyncomplete-buffer.vim) | |
||||
|
| Emoji | [asyncomplete-emoji.vim](https://github.com/prabirshrestha/asyncomplete-emoji.vim) | |
||||
|
| Filenames / directories | [asyncomplete-file.vim](https://github.com/prabirshrestha/asyncomplete-file.vim) | |
||||
|
| [NeoInclude][neoinclude] | [asyncomplete-neoinclude.vim](https://github.com/kyouryuukunn/asyncomplete-neoinclude.vim) | |
||||
|
| Go | [asyncomplete-gocode.vim](https://github.com/prabirshrestha/asyncomplete-gocode.vim) | |
||||
|
| JavaScript (Flow) | [asyncomplete-flow.vim](https://github.com/prabirshrestha/asyncomplete-flow.vim) | |
||||
|
| [Neosnippet][neosnippet] | [asyncomplete-neosnippet.vim](https://github.com/prabirshrestha/asyncomplete-neosnippet.vim) | |
||||
|
| Omni | [asyncomplete-omni.vim](https://github.com/yami-beta/asyncomplete-omni.vim) | |
||||
|
| PivotalTracker stories | [asyncomplete-pivotaltracker.vim](https://github.com/hauleth/asyncomplete-pivotaltracker.vim) | |
||||
|
| Racer | [asyncomplete-racer.vim](https://github.com/keremc/asyncomplete-racer.vim) | |
||||
|
| [tmux complete][tmuxcomplete] | [tmux-complete.vim][tmuxcomplete] | |
||||
|
| Typescript | [asyncomplete-tscompletejob.vim](https://github.com/prabirshrestha/asyncomplete-tscompletejob.vim) | |
||||
|
| [UltiSnips][ultisnips] | [asyncomplete-ultisnips.vim](https://github.com/prabirshrestha/asyncomplete-ultisnips.vim) | |
||||
|
| Vim Syntax | [asyncomplete-necosyntax.vim](https://github.com/prabirshrestha/asyncomplete-necosyntax.vim) | |
||||
|
| Vim tags | [asyncomplete-tags.vim](https://github.com/prabirshrestha/asyncomplete-tags.vim) | |
||||
|
| Vim | [asyncomplete-necovim.vim](https://github.com/prabirshrestha/asyncomplete-necovim.vim) | |
||||
|
|
||||
|
[neosnippet]: https://github.com/Shougo/neosnippet.vim |
||||
|
[neoinclude]: https://github.com/Shougo/neoinclude.vim |
||||
|
[tmuxcomplete]: https://github.com/wellle/tmux-complete.vim |
||||
|
[ultisnips]: https://github.com/SirVer/ultisnips |
||||
|
|
||||
|
*can't find what you are looking for? write one instead an send a PR to be included here or search github topics tagged with asyncomplete at https://github.com/topics/asyncomplete.* |
||||
|
|
||||
|
#### Using existing vim plugin sources |
||||
|
|
||||
|
Rather than writing your own completion source from scratch you could also suggests other plugin authors to provide a async completion api that works for asyncomplete.vim or any other async autocomplete libraries without taking a dependency on asyncomplete.vim. The plugin can provide a function that takes a callback which returns the list of candidates and the startcol from where it must show the popup. Candidates can be list of words or vim's `complete-items`. |
||||
|
|
||||
|
```vim |
||||
|
function s:completor(opt, ctx) |
||||
|
call mylanguage#get_async_completions({candidates, startcol -> asyncomplete#complete(a:opt['name'], a:ctx, startcol, candidates) }) |
||||
|
endfunction |
||||
|
|
||||
|
au User asyncomplete_setup call asyncomplete#register_source({ |
||||
|
\ 'name': 'mylanguage', |
||||
|
\ 'whitelist': [*], |
||||
|
\ 'completor': function('s:completor'), |
||||
|
\ }) |
||||
|
``` |
||||
|
|
||||
|
### Example |
||||
|
|
||||
|
```vim |
||||
|
function! s:js_completor(opt, ctx) abort |
||||
|
let l:col = a:ctx['col'] |
||||
|
let l:typed = a:ctx['typed'] |
||||
|
|
||||
|
let l:kw = matchstr(l:typed, '\v\S+$') |
||||
|
let l:kwlen = len(l:kw) |
||||
|
|
||||
|
let l:startcol = l:col - l:kwlen |
||||
|
|
||||
|
let l:matches = [ |
||||
|
\ "do", "if", "in", "for", "let", "new", "try", "var", "case", "else", "enum", "eval", "null", "this", "true", |
||||
|
\ "void", "with", "await", "break", "catch", "class", "const", "false", "super", "throw", "while", "yield", |
||||
|
\ "delete", "export", "import", "public", "return", "static", "switch", "typeof", "default", "extends", |
||||
|
\ "finally", "package", "private", "continue", "debugger", "function", "arguments", "interface", "protected", |
||||
|
\ "implements", "instanceof" |
||||
|
\ ] |
||||
|
|
||||
|
call asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches) |
||||
|
endfunction |
||||
|
|
||||
|
au User asyncomplete_setup call asyncomplete#register_source({ |
||||
|
\ 'name': 'javascript', |
||||
|
\ 'whitelist': ['javascript'], |
||||
|
\ 'completor': function('s:js_completor'), |
||||
|
\ }) |
||||
|
``` |
||||
|
|
||||
|
The above sample shows synchronous completion. If you would like to make it async just call `asyncomplete#complete` whenever you have the results ready. |
||||
|
|
||||
|
```vim |
||||
|
call timer_start(2000, {timer-> asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches)}) |
||||
|
``` |
||||
|
|
||||
|
If you are returning incomplete results and would like to trigger completion on the next keypress pass `1` as the fifth parameter to `asyncomplete#complete` |
||||
|
which signifies the result is incomplete. |
||||
|
|
||||
|
```vim |
||||
|
call asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches, 1) |
||||
|
``` |
||||
|
|
||||
|
As a source author you do not have to worry about synchronization issues in case the server returns the async completion after the user has typed more |
||||
|
characters. asyncomplete.vim uses partial caching as well as ignores if the context changes when calling `asyncomplete#complete`. |
||||
|
This is one of the core reason why the original context must be passed when calling `asyncomplete#complete`. |
||||
|
|
||||
|
### Credits |
||||
|
All the credit goes to the following projects |
||||
|
* [https://github.com/roxma/nvim-complete-manager](https://github.com/roxma/nvim-complete-manager) |
||||
|
* [https://github.com/maralla/completor.vim](https://github.com/maralla/completor.vim) |
||||
|
|
||||
|
## Contributors |
||||
|
|
||||
|
### Code Contributors |
||||
|
|
||||
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. |
||||
|
<a href="https://github.com/prabirshrestha/asyncomplete.vim/graphs/contributors"><img src="https://opencollective.com/asyncomplete/contributors.svg?width=890&button=false" /></a> |
||||
|
|
||||
|
### Financial Contributors |
||||
|
|
||||
|
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/asyncomplete/contribute)] |
||||
|
|
||||
|
#### Individuals |
||||
|
|
||||
|
<a href="https://opencollective.com/asyncomplete"><img src="https://opencollective.com/asyncomplete/individuals.svg?width=890"></a> |
||||
|
|
||||
|
#### Organizations |
||||
|
|
||||
|
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/asyncomplete/contribute)] |
||||
|
|
||||
|
<a href="https://opencollective.com/asyncomplete/organization/0/website"><img src="https://opencollective.com/asyncomplete/organization/0/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/1/website"><img src="https://opencollective.com/asyncomplete/organization/1/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/2/website"><img src="https://opencollective.com/asyncomplete/organization/2/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/3/website"><img src="https://opencollective.com/asyncomplete/organization/3/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/4/website"><img src="https://opencollective.com/asyncomplete/organization/4/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/5/website"><img src="https://opencollective.com/asyncomplete/organization/5/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/6/website"><img src="https://opencollective.com/asyncomplete/organization/6/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/7/website"><img src="https://opencollective.com/asyncomplete/organization/7/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/8/website"><img src="https://opencollective.com/asyncomplete/organization/8/avatar.svg"></a> |
||||
|
<a href="https://opencollective.com/asyncomplete/organization/9/website"><img src="https://opencollective.com/asyncomplete/organization/9/avatar.svg"></a> |
||||
@ -0,0 +1,500 @@ |
|||||
|
function! asyncomplete#log(...) abort |
||||
|
if !empty(g:asyncomplete_log_file) |
||||
|
call writefile([json_encode(a:000)], g:asyncomplete_log_file, 'a') |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" do nothing, place it here only to avoid the message |
||||
|
augroup asyncomplete_silence_messages |
||||
|
au! |
||||
|
autocmd User asyncomplete_setup silent |
||||
|
augroup END |
||||
|
|
||||
|
if !has('timers') |
||||
|
echohl ErrorMsg |
||||
|
echomsg 'Vim/Neovim compiled with timers required for asyncomplete.vim.' |
||||
|
echohl NONE |
||||
|
if has('nvim') |
||||
|
call asyncomplete#log('neovim compiled with timers required.') |
||||
|
else |
||||
|
call asyncomplete#log('vim compiled with timers required.') |
||||
|
endif |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
let s:already_setup = 0 |
||||
|
let s:sources = {} |
||||
|
let s:matches = {} " { server_name: { incomplete: 1, startcol: 0, items: [], refresh: 0, status: 'idle|pending|success|failure', ctx: ctx } } |
||||
|
let s:has_complete_info = exists('*complete_info') |
||||
|
|
||||
|
function! s:setup_if_required() abort |
||||
|
if !s:already_setup |
||||
|
" register asyncomplete change manager |
||||
|
for l:change_manager in g:asyncomplete_change_manager |
||||
|
call asyncomplete#log('core', 'initializing asyncomplete change manager', l:change_manager) |
||||
|
if type(l:change_manager) == type('') |
||||
|
execute 'let s:on_change_manager = function("'. l:change_manager .'")()' |
||||
|
else |
||||
|
let s:on_change_manager = l:change_manager() |
||||
|
endif |
||||
|
if has_key(s:on_change_manager, 'error') |
||||
|
call asyncomplete#log('core', 'initializing asyncomplete change manager failed', s:on_change_manager['name'], s:on_change_manager['error']) |
||||
|
else |
||||
|
call s:on_change_manager.register(function('s:on_change')) |
||||
|
call asyncomplete#log('core', 'initializing asyncomplete change manager complete', s:on_change_manager['name']) |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
augroup asyncomplete |
||||
|
autocmd! |
||||
|
autocmd InsertEnter * call s:on_insert_enter() |
||||
|
autocmd InsertLeave * call s:on_insert_leave() |
||||
|
augroup END |
||||
|
|
||||
|
doautocmd User asyncomplete_setup |
||||
|
let s:already_setup = 1 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#enable_for_buffer() abort |
||||
|
call s:setup_if_required() |
||||
|
let b:asyncomplete_enable = 1 |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#disable_for_buffer() abort |
||||
|
let b:asyncomplete_enable = 0 |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#get_source_names() abort |
||||
|
return keys(s:sources) |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#get_source_info(source_name) abort |
||||
|
return s:sources[a:source_name] |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#register_source(info) abort |
||||
|
if has_key(s:sources, a:info['name']) |
||||
|
call asyncomplete#log('core', 'duplicate asyncomplete#register_source', a:info['name']) |
||||
|
return -1 |
||||
|
else |
||||
|
let s:sources[a:info['name']] = a:info |
||||
|
if has_key(a:info, 'events') && has_key(a:info, 'on_event') |
||||
|
execute 'augroup asyncomplete_source_event_' . a:info['name'] |
||||
|
for l:event in a:info['events'] |
||||
|
let l:exec = 'if get(b:,"asyncomplete_enable",0) | call s:notify_event_to_source("' . a:info['name'] . '", "'.l:event.'",asyncomplete#context()) | endif' |
||||
|
if type(l:event) == type('') |
||||
|
execute 'au ' . l:event . ' * ' . l:exec |
||||
|
elseif type(l:event) == type([]) |
||||
|
execute 'au ' . join(l:event,' ') .' ' . l:exec |
||||
|
endif |
||||
|
endfor |
||||
|
execute 'augroup end' |
||||
|
endif |
||||
|
|
||||
|
if exists('b:asyncomplete_active_sources') |
||||
|
unlet b:asyncomplete_active_sources |
||||
|
call s:get_active_sources_for_buffer() |
||||
|
endif |
||||
|
|
||||
|
if exists('b:asyncomplete_triggers') |
||||
|
unlet b:asyncomplete_triggers |
||||
|
call s:update_trigger_characters() |
||||
|
endif |
||||
|
|
||||
|
return 1 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#unregister_source(info_or_server_name) abort |
||||
|
if type(a:info_or_server_name) == type({}) |
||||
|
let l:server_name = a:info_or_server_name['name'] |
||||
|
else |
||||
|
let l:server_name = a:info_or_server_name |
||||
|
endif |
||||
|
if has_key(s:sources, l:server_name) |
||||
|
let l:server = s:sources[l:server_name] |
||||
|
if has_key(l:server, 'unregister') |
||||
|
call l:server.unregister() |
||||
|
endif |
||||
|
unlet s:sources[l:server_name] |
||||
|
return 1 |
||||
|
else |
||||
|
return -1 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#context() abort |
||||
|
let l:ret = {'bufnr':bufnr('%'), 'curpos':getcurpos(), 'changedtick':b:changedtick} |
||||
|
let l:ret['lnum'] = l:ret['curpos'][1] |
||||
|
let l:ret['col'] = l:ret['curpos'][2] |
||||
|
let l:ret['filetype'] = &filetype |
||||
|
let l:ret['filepath'] = expand('%:p') |
||||
|
let l:ret['typed'] = strpart(getline(l:ret['lnum']),0,l:ret['col']-1) |
||||
|
return l:ret |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_enter() abort |
||||
|
call s:get_active_sources_for_buffer() " call to cache |
||||
|
call s:update_trigger_characters() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_leave() abort |
||||
|
call s:disable_popup_skip() |
||||
|
let s:matches = {} |
||||
|
if exists('s:update_pum_timer') |
||||
|
call timer_stop(s:update_pum_timer) |
||||
|
unlet s:update_pum_timer |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:get_active_sources_for_buffer() abort |
||||
|
if exists('b:asyncomplete_active_sources') |
||||
|
" active sources were cached for buffer |
||||
|
return b:asyncomplete_active_sources |
||||
|
endif |
||||
|
|
||||
|
call asyncomplete#log('core', 'computing active sources for buffer', bufnr('%')) |
||||
|
let b:asyncomplete_active_sources = [] |
||||
|
for [l:name, l:info] in items(s:sources) |
||||
|
let l:blacklisted = 0 |
||||
|
|
||||
|
if has_key(l:info, 'blacklist') |
||||
|
for l:filetype in l:info['blacklist'] |
||||
|
if l:filetype == &filetype || l:filetype is# '*' |
||||
|
let l:blacklisted = 1 |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
if l:blacklisted |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
if has_key(l:info, 'whitelist') |
||||
|
for l:filetype in l:info['whitelist'] |
||||
|
if l:filetype == &filetype || l:filetype is# '*' |
||||
|
let b:asyncomplete_active_sources += [l:name] |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
call asyncomplete#log('core', 'active source for buffer', bufnr('%'), b:asyncomplete_active_sources) |
||||
|
|
||||
|
return b:asyncomplete_active_sources |
||||
|
endfunction |
||||
|
|
||||
|
function! s:update_trigger_characters() abort |
||||
|
if exists('b:asyncomplete_triggers') |
||||
|
" triggers were cached for buffer |
||||
|
return b:asyncomplete_triggers |
||||
|
endif |
||||
|
let b:asyncomplete_triggers = {} " { char: { 'sourcea': 1, 'sourceb': 2 } } |
||||
|
|
||||
|
for l:source_name in s:get_active_sources_for_buffer() |
||||
|
let l:source_info = s:sources[l:source_name] |
||||
|
if has_key(l:source_info, 'triggers') && has_key(l:source_info['triggers'], &filetype) |
||||
|
let l:triggers = l:source_info['triggers'][&filetype] |
||||
|
elseif has_key(l:source_info, 'triggers') && has_key(l:source_info['triggers'], '*') |
||||
|
let l:triggers = l:source_info['triggers']['*'] |
||||
|
elseif has_key(g:asyncomplete_triggers, &filetype) |
||||
|
let l:triggers = g:asyncomplete_triggers[&filetype] |
||||
|
elseif has_key(g:asyncomplete_triggers, '*') |
||||
|
let l:triggers = g:asyncomplete_triggers['*'] |
||||
|
else |
||||
|
let l:triggers = [] |
||||
|
endif |
||||
|
|
||||
|
for l:trigger in l:triggers |
||||
|
let l:last_char = l:trigger[len(l:trigger) -1] |
||||
|
if !has_key(b:asyncomplete_triggers, l:last_char) |
||||
|
let b:asyncomplete_triggers[l:last_char] = {} |
||||
|
endif |
||||
|
if !has_key(b:asyncomplete_triggers[l:last_char], l:source_name) |
||||
|
let b:asyncomplete_triggers[l:last_char][l:source_name] = [] |
||||
|
endif |
||||
|
call add(b:asyncomplete_triggers[l:last_char][l:source_name], l:trigger) |
||||
|
endfor |
||||
|
endfor |
||||
|
call asyncomplete#log('core', 'trigger characters for buffer', bufnr('%'), b:asyncomplete_triggers) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:enable_popup_skip() abort |
||||
|
let s:skip_popup = 1 |
||||
|
endfunction |
||||
|
|
||||
|
function! s:disable_popup_skip() abort |
||||
|
let s:skip_popup = 0 |
||||
|
endfunction |
||||
|
|
||||
|
function! s:should_skip_popup() abort |
||||
|
if get(s:, 'skip_popup', 0) |
||||
|
return 1 |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:should_skip() abort |
||||
|
if mode() isnot# 'i' || !get(b:, 'asyncomplete_enable', 0) |
||||
|
return 1 |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#close_popup() abort |
||||
|
call s:enable_popup_skip() |
||||
|
return pumvisible() ? "\<C-y>" : '' |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#cancel_popup() abort |
||||
|
call s:enable_popup_skip() |
||||
|
return pumvisible() ? "\<C-e>" : '' |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_change() abort |
||||
|
if s:should_skip() | return | endif |
||||
|
|
||||
|
if !g:asyncomplete_auto_popup |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let l:ctx = asyncomplete#context() |
||||
|
let l:startcol = l:ctx['col'] |
||||
|
let l:last_char = l:ctx['typed'][l:startcol - 2] " col is 1-indexed, but str 0-indexed |
||||
|
|
||||
|
let l:sources_to_notify = {} |
||||
|
|
||||
|
" match sources based on the last character if it is a trigger character |
||||
|
if has_key(b:asyncomplete_triggers, l:last_char) |
||||
|
" TODO: also check for multiple chars instead of just last chars for |
||||
|
" languages such as cpp which uses -> and :: |
||||
|
for l:source_name in keys(b:asyncomplete_triggers[l:last_char]) |
||||
|
if !has_key(s:matches, l:source_name) || s:matches[l:source_name]['ctx']['lnum'] != l:ctx['lnum'] || s:matches[l:source_name]['startcol'] != l:startcol |
||||
|
let l:sources_to_notify[l:source_name] = 1 |
||||
|
let s:matches[l:source_name] = { 'startcol': l:startcol, 'status': 'idle', 'items': [], 'refresh': 0, 'ctx': l:ctx } |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
" loop left and find the start of the word and set it as the startcol for the source instead of refresh_pattern |
||||
|
let l:refresh_pattern = '\(\k\+$\)' |
||||
|
let [l:_, l:startidx, l:endidx] = asyncomplete#utils#matchstrpos(l:ctx['typed'], l:refresh_pattern) |
||||
|
let l:startcol = l:startidx + 1 |
||||
|
|
||||
|
if l:startidx > -1 |
||||
|
if s:should_skip_popup() | return | endif |
||||
|
for l:source_name in b:asyncomplete_active_sources |
||||
|
if !has_key(l:sources_to_notify, l:source_name) |
||||
|
if has_key(s:matches, l:source_name) && s:matches[l:source_name]['ctx']['lnum'] ==# l:ctx['lnum'] && s:matches[l:source_name]['startcol'] ==# l:startcol |
||||
|
continue |
||||
|
endif |
||||
|
let l:sources_to_notify[l:source_name] = 1 |
||||
|
let s:matches[l:source_name] = { 'startcol': l:startcol, 'status': 'idle', 'items': [], 'refresh': 0, 'ctx': l:ctx } |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call s:disable_popup_skip() |
||||
|
endif |
||||
|
|
||||
|
call s:trigger(l:ctx) |
||||
|
call s:update_pum() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:trigger(ctx) abort |
||||
|
" send cancellation request if supported |
||||
|
for [l:source_name, l:matches] in items(s:matches) |
||||
|
call asyncomplete#log('core', 's:trigger', l:matches) |
||||
|
if l:matches['refresh'] || l:matches['status'] == 'idle' || l:matches['status'] == 'failure' |
||||
|
let l:matches['status'] = 'pending' |
||||
|
try |
||||
|
" TODO: check for min chars |
||||
|
call asyncomplete#log('core', 's:trigger.completor()', l:source_name, s:matches[l:source_name], a:ctx) |
||||
|
call s:sources[l:source_name].completor(s:sources[l:source_name], a:ctx) |
||||
|
catch |
||||
|
let l:matches['status'] = 'failure' |
||||
|
call asyncomplete#log('core', 's:trigger', 'error', v:exception) |
||||
|
continue |
||||
|
endtry |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#complete(name, ctx, startcol, items, ...) abort |
||||
|
let l:refresh = a:0 > 0 ? a:1 : 0 |
||||
|
let l:ctx = asyncomplete#context() |
||||
|
if !has_key(s:matches, a:name) || l:ctx['lnum'] != a:ctx['lnum'] " TODO: handle more context changes |
||||
|
call asyncomplete#log('core', 'asyncomplete#log', 'ignoring due to context chnages', a:name, a:ctx, a:startcol, l:refresh, a:items) |
||||
|
call s:update_pum() |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call asyncomplete#log('asyncomplete#complete', a:name, a:ctx, a:startcol, l:refresh, a:items) |
||||
|
|
||||
|
let l:matches = s:matches[a:name] |
||||
|
let l:matches['items'] = s:normalize_items(a:items) |
||||
|
let l:matches['refresh'] = l:refresh |
||||
|
let l:matches['startcol'] = a:startcol |
||||
|
let l:matches['status'] = 'success' |
||||
|
|
||||
|
call s:update_pum() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:normalize_items(items) abort |
||||
|
if len(a:items) > 0 && type(a:items[0]) ==# type('') |
||||
|
let l:items = [] |
||||
|
for l:item in a:items |
||||
|
let l:items += [{'word': l:item }] |
||||
|
endfor |
||||
|
return l:items |
||||
|
else |
||||
|
return a:items |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#force_refresh() abort |
||||
|
return asyncomplete#menu_selected() ? "\<c-y>\<c-r>=asyncomplete#_force_refresh()\<CR>" : "\<c-r>=asyncomplete#_force_refresh()\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#_force_refresh() abort |
||||
|
call s:disable_popup_skip() |
||||
|
if s:should_skip() | return | endif |
||||
|
|
||||
|
let l:ctx = asyncomplete#context() |
||||
|
let l:startcol = l:ctx['col'] |
||||
|
let l:last_char = l:ctx['typed'][l:startcol - 2] |
||||
|
|
||||
|
" loop left and find the start of the word or trigger chars and set it as the startcol for the source instead of refresh_pattern |
||||
|
let l:refresh_pattern = '\(\k\+$\)' |
||||
|
let [l:_, l:startidx, l:endidx] = asyncomplete#utils#matchstrpos(l:ctx['typed'], l:refresh_pattern) |
||||
|
" When no word here, startcol is current col |
||||
|
let l:startcol = l:startidx == -1 ? col('.') : l:startidx + 1 |
||||
|
|
||||
|
let s:matches = {} |
||||
|
|
||||
|
for l:source_name in b:asyncomplete_active_sources |
||||
|
let s:matches[l:source_name] = { 'startcol': l:startcol, 'status': 'idle', 'items': [], 'refresh': 0, 'ctx': l:ctx } |
||||
|
endfor |
||||
|
|
||||
|
call s:trigger(l:ctx) |
||||
|
call s:update_pum() |
||||
|
return '' |
||||
|
endfunction |
||||
|
|
||||
|
function! s:update_pum() abort |
||||
|
if exists('s:update_pum_timer') |
||||
|
call timer_stop(s:update_pum_timer) |
||||
|
unlet s:update_pum_timer |
||||
|
endif |
||||
|
call asyncomplete#log('core', 's:update_pum') |
||||
|
let s:update_pum_timer = timer_start(g:asyncomplete_popup_delay, function('s:recompute_pum')) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:recompute_pum(...) abort |
||||
|
if s:should_skip() | return | endif |
||||
|
if s:should_skip_popup() | return | endif |
||||
|
|
||||
|
" TODO: add support for remote recomputation of complete items, |
||||
|
" Ex: heavy computation such as fuzzy search can happen in a python thread |
||||
|
|
||||
|
call asyncomplete#log('core', 's:recompute_pum') |
||||
|
|
||||
|
if asyncomplete#menu_selected() |
||||
|
call asyncomplete#log('core', 's:recomputed_pum', 'ignorning refresh pum due to menu selection') |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let l:ctx = asyncomplete#context() |
||||
|
|
||||
|
let l:startcols = [] |
||||
|
let l:matches_to_filter = {} |
||||
|
|
||||
|
for [l:source_name, l:match] in items(s:matches) |
||||
|
let l:startcol = l:match['startcol'] |
||||
|
let l:startcols += [l:startcol] |
||||
|
let l:curitems = l:match['items'] |
||||
|
|
||||
|
if l:startcol > l:ctx['col'] |
||||
|
call asyncomplete#log('core', 's:recompute_pum', 'ignoring due to wrong start col', l:startcol, l:ctx['col']) |
||||
|
continue |
||||
|
else |
||||
|
let l:matches_to_filter[l:source_name] = l:match |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
let l:startcol = min(l:startcols) |
||||
|
let l:base = l:ctx['typed'][l:startcol - 1:] " col is 1-indexed, but str 0-indexed |
||||
|
|
||||
|
let l:filter_ctx = extend({ |
||||
|
\ 'base': l:base, |
||||
|
\ 'startcol': l:startcol, |
||||
|
\ }, l:ctx) |
||||
|
|
||||
|
let l:mode = s:has_complete_info ? complete_info(['mode'])['mode'] : 'unknown' |
||||
|
if l:mode ==# '' || l:mode ==# 'eval' || l:mode ==# 'unknown' |
||||
|
let l:Preprocessor = empty(g:asyncomplete_preprocessor) ? function('s:default_preprocessor') : g:asyncomplete_preprocessor[0] |
||||
|
call l:Preprocessor(l:filter_ctx, l:matches_to_filter) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:default_preprocessor(options, matches) abort |
||||
|
let l:items = [] |
||||
|
let l:startcols = [] |
||||
|
for [l:source_name, l:matches] in items(a:matches) |
||||
|
let l:startcol = l:matches['startcol'] |
||||
|
let l:base = a:options['typed'][l:startcol - 1:] |
||||
|
for l:item in l:matches['items'] |
||||
|
if stridx(l:item['word'], l:base) == 0 |
||||
|
let l:startcols += [l:startcol] |
||||
|
call add(l:items, l:item) |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
|
||||
|
let a:options['startcol'] = min(l:startcols) |
||||
|
|
||||
|
call asyncomplete#preprocess_complete(a:options, l:items) |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#preprocess_complete(ctx, items) |
||||
|
" TODO: handle cases where this is called asynchronsouly. Currently not supported |
||||
|
if s:should_skip() | return | endif |
||||
|
if s:should_skip_popup() | return | endif |
||||
|
|
||||
|
call asyncomplete#log('core', 'asyncomplete#preprocess_complete') |
||||
|
|
||||
|
if asyncomplete#menu_selected() |
||||
|
call asyncomplete#log('core', 'asyncomplete#preprocess_complete', 'ignorning pum update due to menu selection') |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
if (g:asyncomplete_auto_completeopt == 1) |
||||
|
setl completeopt=menuone,noinsert,noselect |
||||
|
endif |
||||
|
|
||||
|
call asyncomplete#log('core', 'asyncomplete#preprocess_complete calling complete()', a:ctx['startcol'], a:items) |
||||
|
call complete(a:ctx['startcol'], a:items) |
||||
|
endfunction |
||||
|
|
||||
|
function! asyncomplete#menu_selected() abort |
||||
|
" when the popup menu is visible, v:completed_item will be the |
||||
|
" current_selected item |
||||
|
" if v:completed_item is empty, no item is selected |
||||
|
return pumvisible() && !empty(v:completed_item) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:notify_event_to_source(name, event, ctx) abort |
||||
|
try |
||||
|
if has_key(s:sources, a:name) |
||||
|
call s:sources[a:name].on_event(s:sources[a:name], a:ctx, a:event) |
||||
|
endif |
||||
|
catch |
||||
|
call asyncomplete#log('core', 's:notify_event_to_source', 'error', v:exception) |
||||
|
return |
||||
|
endtry |
||||
|
endfunction |
||||
@ -0,0 +1,21 @@ |
|||||
|
" Find a nearest to a `path` parent directory `directoryname` by traversing the |
||||
|
" filesystem upwards |
||||
|
function! asyncomplete#utils#find_nearest_parent_directory(path, directoryname) abort |
||||
|
let l:relative_path = finddir(a:directoryname, a:path . ';') |
||||
|
|
||||
|
if !empty(l:relative_path) |
||||
|
return fnamemodify(l:relative_path, ':p') |
||||
|
else |
||||
|
return '' |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
if exists('*matchstrpos') |
||||
|
function! asyncomplete#utils#matchstrpos(expr, pattern) abort |
||||
|
return matchstrpos(a:expr, a:pattern) |
||||
|
endfunction |
||||
|
else |
||||
|
function! asyncomplete#utils#matchstrpos(expr, pattern) abort |
||||
|
return [matchstr(a:expr, a:pattern), match(a:expr, a:pattern), matchend(a:expr, a:pattern)] |
||||
|
endfunction |
||||
|
endif |
||||
@ -0,0 +1,59 @@ |
|||||
|
let s:callbacks = [] |
||||
|
|
||||
|
function! asyncomplete#utils#_on_change#textchangedp#init() abort |
||||
|
if exists('##TextChangedP') |
||||
|
call s:setup_if_required() |
||||
|
return { |
||||
|
\ 'name': 'TextChangedP', |
||||
|
\ 'register': function('s:register'), |
||||
|
\ 'unregister': function('s:unregister'), |
||||
|
\ } |
||||
|
else |
||||
|
return { 'name': 'TextChangedP', 'error': 'Requires vim with TextChangedP support' } |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:setup_if_required() abort |
||||
|
augroup asyncomplete_utils_on_change_text_changed_p |
||||
|
autocmd! |
||||
|
autocmd InsertEnter * call s:on_insert_enter() |
||||
|
autocmd InsertLeave * call s:on_insert_leave() |
||||
|
autocmd TextChangedI * call s:on_text_changed_i() |
||||
|
autocmd TextChangedP * call s:on_text_changed_p() |
||||
|
augroup END |
||||
|
endfunction |
||||
|
|
||||
|
function! s:register(cb) abort |
||||
|
call add(s:callbacks , a:cb) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:unregister(obj, cb) abort |
||||
|
" TODO: remove from s:callbacks |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_enter() abort |
||||
|
let s:previous_position = getcurpos() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_leave() abort |
||||
|
unlet s:previous_position |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_text_changed_i() abort |
||||
|
call s:maybe_notify_on_change() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_text_changed_p() abort |
||||
|
call s:maybe_notify_on_change() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:maybe_notify_on_change() abort |
||||
|
" enter to new line or backspace to previous line shouldn't cause change trigger |
||||
|
let l:previous_position = s:previous_position |
||||
|
let s:previous_position = getcurpos() |
||||
|
if l:previous_position[1] ==# getcurpos()[1] |
||||
|
for l:Cb in s:callbacks |
||||
|
call l:Cb() |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction |
||||
@ -0,0 +1,83 @@ |
|||||
|
let s:callbacks = [] |
||||
|
|
||||
|
let s:change_timer = -1 |
||||
|
let s:last_tick = [] |
||||
|
|
||||
|
function! asyncomplete#utils#_on_change#timer#init() abort |
||||
|
call s:setup_if_required() |
||||
|
return { |
||||
|
\ 'name': 'timer', |
||||
|
\ 'register': function('s:register'), |
||||
|
\ 'unregister': function('s:unregister'), |
||||
|
\ } |
||||
|
endfunction |
||||
|
|
||||
|
function! s:setup_if_required() abort |
||||
|
augroup asyncomplete_utils_on_change_timer |
||||
|
autocmd! |
||||
|
autocmd InsertEnter * call s:on_insert_enter() |
||||
|
autocmd InsertLeave * call s:on_insert_leave() |
||||
|
autocmd TextChangedI * call s:on_text_changed_i() |
||||
|
augroup END |
||||
|
endfunction |
||||
|
|
||||
|
function! s:register(cb) abort |
||||
|
call add(s:callbacks , a:cb) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:unregister(obj, cb) abort |
||||
|
" TODO: remove from s:callbacks |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_enter() abort |
||||
|
let s:previous_position = getcurpos() |
||||
|
call s:change_tick_start() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_insert_leave() abort |
||||
|
unlet s:previous_position |
||||
|
call s:change_tick_stop() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:on_text_changed_i() abort |
||||
|
call s:check_changes() |
||||
|
endfunction |
||||
|
|
||||
|
function! s:change_tick_start() abort |
||||
|
if !exists('s:change_timer') |
||||
|
let s:last_tick = s:change_tick() |
||||
|
" changes every 30ms, which is 0.03s, it should be fast enough |
||||
|
let s:change_timer = timer_start(30, function('s:check_changes'), { 'repeat': -1 }) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:change_tick_stop() abort |
||||
|
if exists('s:change_timer') |
||||
|
call timer_stop(s:change_timer) |
||||
|
unlet s:change_timer |
||||
|
let s:last_tick = [] |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:check_changes(...) abort |
||||
|
let l:tick = s:change_tick() |
||||
|
if l:tick != s:last_tick |
||||
|
let s:last_tick = l:tick |
||||
|
call s:maybe_notify_on_change() |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:maybe_notify_on_change() abort |
||||
|
" enter to new line or backspace to previous line shouldn't cause change trigger |
||||
|
let l:previous_position = s:previous_position |
||||
|
let s:previous_position = getcurpos() |
||||
|
if l:previous_position[1] ==# getcurpos()[1] |
||||
|
for l:Cb in s:callbacks |
||||
|
call l:Cb() |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:change_tick() abort |
||||
|
return [b:changedtick, getcurpos()] |
||||
|
endfunction |
||||
@ -0,0 +1,155 @@ |
|||||
|
*asyncomplete.vim.txt* Async autocompletion for Vim 8 and Neovim. |
||||
|
*asyncomplete* |
||||
|
|
||||
|
|
||||
|
=============================================================================== |
||||
|
CONTENTS *asyncomplete-contents* |
||||
|
|
||||
|
1. Introduction |asyncomplete-introduction| |
||||
|
2. Options |asyncomplete-options| |
||||
|
3. Functions |asyncomplete-functions| |
||||
|
4. Global vim configuration |asyncomplete-global-config| |
||||
|
5. Known Issues |asyncomplete-known-issues| |
||||
|
|
||||
|
=============================================================================== |
||||
|
1. Introduction *asyncomplete-introduction* |
||||
|
|
||||
|
Async autocompletion for Vim 8 and Neovim with |timers|. |
||||
|
|
||||
|
This is inspired by https://github.com/roxma/nvim-complete-manager but written |
||||
|
in pure Vim Script. |
||||
|
|
||||
|
=============================================================================== |
||||
|
2. Options *asyncomplete-options* |
||||
|
|
||||
|
|
||||
|
g:asyncomplete_auto_popup *g:asyncomplete_auto_popup* |
||||
|
|
||||
|
Type: |Number| |
||||
|
Default: `1` |
||||
|
|
||||
|
Automatically show the autocomplete popup menu as you start typing. |
||||
|
|
||||
|
g:asyncomplete_log_file *g:asyncomplete_log_file* |
||||
|
|
||||
|
Type: |String| |
||||
|
Default: null |
||||
|
|
||||
|
Path to log file. |
||||
|
|
||||
|
g:asyncomplete_popup_delay *g:asyncomplete_popup_delay* |
||||
|
|
||||
|
Type: |Number| |
||||
|
Default: 30 |
||||
|
|
||||
|
Milliseconds to wait before opening the popup menu |
||||
|
|
||||
|
g:asyncomplete_auto_completeopt *g:asyncomplete_auto_completeopt* |
||||
|
|
||||
|
Type: |Number| |
||||
|
Default: 1 |
||||
|
|
||||
|
Set default `completeopt` options. These are `menuone,noinsert,noselect`. |
||||
|
This effectively overwrites what ever the user has in their config file. |
||||
|
|
||||
|
Set to 0 to disable. |
||||
|
|
||||
|
g:asyncomplete_preprocessor *g:asyncomplete_preprocessor* |
||||
|
|
||||
|
Type: |Array| for zero or one |Function| |
||||
|
Default: [] |
||||
|
|
||||
|
Set a function to allow custom filtering or sorting. |
||||
|
Below example implements removing duplicates. |
||||
|
|
||||
|
function! s:my_asyncomplete_preprocessor(options, matches) abort |
||||
|
let l:visited = {} |
||||
|
let l:items = [] |
||||
|
for [l:source_name, l:matches] in items(a:matches) |
||||
|
for l:item in l:matches['items'] |
||||
|
if stridx(l:item['word'], a:options['base']) == 0 |
||||
|
if !has_key(l:visited, l:item['word']) |
||||
|
call add(l:items, l:item) |
||||
|
let l:visited[l:item['word']] = 1 |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
|
||||
|
call asyncomplete#preprocess_complete(a:options, l:items) |
||||
|
endfunction |
||||
|
|
||||
|
let g:asyncomplete_preprocessor = [function('s:my_asyncomplete_preprocessor')] |
||||
|
|
||||
|
Note: |
||||
|
asyncomplete#preprocess_complete() must be called synchronously. |
||||
|
Plans to support async preprocessing will be supported in the future. |
||||
|
|
||||
|
context and matches in arguments in preprecessor function should be treated |
||||
|
as immutable. |
||||
|
=============================================================================== |
||||
|
3. Functions *asyncomplete-functions* |
||||
|
|
||||
|
asyncomplete#close_popup() *asyncomplete#close_popup()* |
||||
|
|
||||
|
Insert selected candidate and close popup menu. |
||||
|
Following example prevents popup menu from re-opening after insertion. |
||||
|
> |
||||
|
inoremap <expr> <C-y> pumvisible() ? asyncomplete#close_popup() : "\<C-y>" |
||||
|
< |
||||
|
asyncomplete#cancel_popup() *asyncomplete#cancel_popup()* |
||||
|
|
||||
|
Cancel completion and close popup menu. |
||||
|
Following example prevents popup menu from re-opening after cancellation. |
||||
|
> |
||||
|
inoremap <expr> <C-e> pumvisible() ? asyncomplete#cancel_popup() : "\<C-e>" |
||||
|
< |
||||
|
asyncomplete#get_source_info({source-name}) *asyncomplete#get_source_info()* |
||||
|
|
||||
|
Get the source configuration info as dict. |
||||
|
Below example implements a priority sort function. |
||||
|
> |
||||
|
function! s:sort_by_priority_preprocessor(options, matches) abort |
||||
|
let l:items = [] |
||||
|
for [l:source_name, l:matches] in items(a:matches) |
||||
|
for l:item in l:matches['items'] |
||||
|
if stridx(l:item['word'], a:options['base']) == 0 |
||||
|
let l:item['priority'] = |
||||
|
\ get(asyncomplete#get_source_info(l:source_name),'priority',0) |
||||
|
call add(l:items, l:item) |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
|
||||
|
let l:items = sort(l:items, {a, b -> b['priority'] - a['priority']}) |
||||
|
|
||||
|
call asyncomplete#preprocess_complete(a:options, l:items) |
||||
|
endfunction |
||||
|
|
||||
|
let g:asyncomplete_preprocessor = [function('s:sort_by_priority_preprocessor')] |
||||
|
< |
||||
|
asyncomplete#get_source_names() *asyncomplete#get_source_names()* |
||||
|
|
||||
|
Get the registered source names list. |
||||
|
|
||||
|
=============================================================================== |
||||
|
4. Global vim configuration *asyncomplete-global-config* |
||||
|
|
||||
|
If you notice messages like 'Pattern not found' or 'Match 1 of <N>' printed in |
||||
|
red colour in vim command line and in `:messages` history and you are annoyed |
||||
|
with them, try setting `shortmess` vim option in your `.vimrc` like so: |
||||
|
> |
||||
|
set shortmess+=c |
||||
|
< |
||||
|
See `:help shortmess` for details and description. |
||||
|
|
||||
|
=============================================================================== |
||||
|
5. Known Issues *asyncomplete-known-issues* |
||||
|
|
||||
|
Builtin complete such as omni func, file func flickers and closes. |
||||
|
You need vim with patch v8.1.1068. |
||||
|
https://github.com/vim/vim/commit/fd133323d4e1cc9c0e61c0ce357df4d36ea148e3 |
||||
|
|
||||
|
=============================================================================== |
||||
|
|
||||
|
vim:tw=78:ts=4:sts=4:sw=4:ft=help:norl: |
||||
@ -0,0 +1,23 @@ |
|||||
|
if exists('g:asyncomplete_loaded') |
||||
|
finish |
||||
|
endif |
||||
|
let g:asyncomplete_loaded = 1 |
||||
|
|
||||
|
if get(g:, 'asyncomplete_enable_for_all', 1) |
||||
|
augroup asyncomplete_enable |
||||
|
au! |
||||
|
au BufEnter * if exists('b:asyncomplete_enable') == 0 | call asyncomplete#enable_for_buffer() | endif |
||||
|
augroup END |
||||
|
endif |
||||
|
|
||||
|
let g:asyncomplete_manager = get(g:, 'asyncomplete_manager', 'asyncomplete#managers#vim#init') |
||||
|
let g:asyncomplete_change_manager = get(g:, 'asyncomplete_change_manager', ['asyncomplete#utils#_on_change#textchangedp#init', 'asyncomplete#utils#_on_change#timer#init']) |
||||
|
let g:asyncomplete_triggers = get(g:, 'asyncomplete_triggers', {'*': ['.', '>', ':'] }) |
||||
|
|
||||
|
let g:asyncomplete_auto_completeopt = get(g:, 'asyncomplete_auto_completeopt', 1) |
||||
|
let g:asyncomplete_auto_popup = get(g:, 'asyncomplete_auto_popup', 1) |
||||
|
let g:asyncomplete_popup_delay = get(g:, 'asyncomplete_popup_delay', 30) |
||||
|
let g:asyncomplete_log_file = get(g:, 'asyncomplete_log_file', '') |
||||
|
let g:asyncomplete_preprocessor = get(g:, 'asyncomplete_preprocessor', []) |
||||
|
|
||||
|
inoremap <silent> <expr> <Plug>(asyncomplete_force_refresh) asyncomplete#force_refresh() |
||||
@ -0,0 +1 @@ |
|||||
|
/doc/tags |
||||
@ -0,0 +1,7 @@ |
|||||
|
--- |
||||
|
sudo: required |
||||
|
services: |
||||
|
- docker |
||||
|
language: generic |
||||
|
script: | |
||||
|
cd test && ./run-tests |
||||
@ -0,0 +1,10 @@ |
|||||
|
cmdargs: |
||||
|
# Checking more strictly |
||||
|
severity: style_problem |
||||
|
|
||||
|
policies: |
||||
|
# Disable a violation |
||||
|
ProhibitUnnecessaryDoubleQuote: |
||||
|
enabled: false |
||||
|
ProhibitImplicitScopeVariable: |
||||
|
enabled: false |
||||
@ -0,0 +1,27 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Hi, and thanks for reporting an issue with rust.vim. |
||||
|
|
||||
|
Details about your environment will help us assist you. |
||||
|
|
||||
|
Please edit this template! |
||||
|
|
||||
|
--> |
||||
|
|
||||
|
* rust.vim version: <!-- Describe if you use a Vim plugin manager, and you |
||||
|
can use it to tell which version of rust.vim you are running. --> |
||||
|
|
||||
|
Steps to reproduce: |
||||
|
|
||||
|
<!-- It's best to try to reproduce the issue with the master version of |
||||
|
rust.vim. The issue may already be fixed! --> |
||||
|
_?_ |
||||
|
|
||||
|
Expected vs. actual behavior: |
||||
|
|
||||
|
_?_ |
||||
|
|
||||
|
Paste debugging info from the Rust Vim plugin via _one_ of the following |
||||
|
commands: `:RustInfo`, `:RustInfoToClipboard`, or `:RustInfoToFile <filename>`. |
||||
|
|
||||
|
_?_ |
||||
@ -0,0 +1,201 @@ |
|||||
|
Apache License |
||||
|
Version 2.0, January 2004 |
||||
|
http://www.apache.org/licenses/ |
||||
|
|
||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
|
||||
|
1. Definitions. |
||||
|
|
||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
|
||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||
|
the copyright owner that is granting the License. |
||||
|
|
||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||
|
other entities that control, are controlled by, or are under common |
||||
|
control with that entity. For the purposes of this definition, |
||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||
|
direction or management of such entity, whether by contract or |
||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
|
||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||
|
exercising permissions granted by this License. |
||||
|
|
||||
|
"Source" form shall mean the preferred form for making modifications, |
||||
|
including but not limited to software source code, documentation |
||||
|
source, and configuration files. |
||||
|
|
||||
|
"Object" form shall mean any form resulting from mechanical |
||||
|
transformation or translation of a Source form, including but |
||||
|
not limited to compiled object code, generated documentation, |
||||
|
and conversions to other media types. |
||||
|
|
||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||
|
Object form, made available under the License, as indicated by a |
||||
|
copyright notice that is included in or attached to the work |
||||
|
(an example is provided in the Appendix below). |
||||
|
|
||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||
|
form, that is based on (or derived from) the Work and for which the |
||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||
|
of this License, Derivative Works shall not include works that remain |
||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||
|
the Work and Derivative Works thereof. |
||||
|
|
||||
|
"Contribution" shall mean any work of authorship, including |
||||
|
the original version of the Work and any modifications or additions |
||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||
|
means any form of electronic, verbal, or written communication sent |
||||
|
to the Licensor or its representatives, including but not limited to |
||||
|
communication on electronic mailing lists, source code control systems, |
||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||
|
excluding communication that is conspicuously marked or otherwise |
||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
|
||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||
|
subsequently incorporated within the Work. |
||||
|
|
||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||
|
Work and such Derivative Works in Source or Object form. |
||||
|
|
||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
(except as stated in this section) patent license to make, have made, |
||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
|
where such license applies only to those patent claims licensable |
||||
|
by such Contributor that are necessarily infringed by their |
||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||
|
institute patent litigation against any entity (including a |
||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
|
or a Contribution incorporated within the Work constitutes direct |
||||
|
or contributory patent infringement, then any patent licenses |
||||
|
granted to You under this License for that Work shall terminate |
||||
|
as of the date such litigation is filed. |
||||
|
|
||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||
|
Work or Derivative Works thereof in any medium, with or without |
||||
|
modifications, and in Source or Object form, provided that You |
||||
|
meet the following conditions: |
||||
|
|
||||
|
(a) You must give any other recipients of the Work or |
||||
|
Derivative Works a copy of this License; and |
||||
|
|
||||
|
(b) You must cause any modified files to carry prominent notices |
||||
|
stating that You changed the files; and |
||||
|
|
||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||
|
that You distribute, all copyright, patent, trademark, and |
||||
|
attribution notices from the Source form of the Work, |
||||
|
excluding those notices that do not pertain to any part of |
||||
|
the Derivative Works; and |
||||
|
|
||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||
|
distribution, then any Derivative Works that You distribute must |
||||
|
include a readable copy of the attribution notices contained |
||||
|
within such NOTICE file, excluding those notices that do not |
||||
|
pertain to any part of the Derivative Works, in at least one |
||||
|
of the following places: within a NOTICE text file distributed |
||||
|
as part of the Derivative Works; within the Source form or |
||||
|
documentation, if provided along with the Derivative Works; or, |
||||
|
within a display generated by the Derivative Works, if and |
||||
|
wherever such third-party notices normally appear. The contents |
||||
|
of the NOTICE file are for informational purposes only and |
||||
|
do not modify the License. You may add Your own attribution |
||||
|
notices within Derivative Works that You distribute, alongside |
||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||
|
that such additional attribution notices cannot be construed |
||||
|
as modifying the License. |
||||
|
|
||||
|
You may add Your own copyright statement to Your modifications and |
||||
|
may provide additional or different license terms and conditions |
||||
|
for use, reproduction, or distribution of Your modifications, or |
||||
|
for any such Derivative Works as a whole, provided Your use, |
||||
|
reproduction, and distribution of the Work otherwise complies with |
||||
|
the conditions stated in this License. |
||||
|
|
||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||
|
by You to the Licensor shall be under the terms and conditions of |
||||
|
this License, without any additional terms or conditions. |
||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||
|
the terms of any separate license agreement you may have executed |
||||
|
with Licensor regarding such Contributions. |
||||
|
|
||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||
|
except as required for reasonable and customary use in describing the |
||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
|
||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
|
agreed to in writing, Licensor provides the Work (and each |
||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
|
implied, including, without limitation, any warranties or conditions |
||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
|
appropriateness of using or redistributing the Work and assume any |
||||
|
risks associated with Your exercise of permissions under this License. |
||||
|
|
||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||
|
whether in tort (including negligence), contract, or otherwise, |
||||
|
unless required by applicable law (such as deliberate and grossly |
||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||
|
liable to You for damages, including any direct, indirect, special, |
||||
|
incidental, or consequential damages of any character arising as a |
||||
|
result of this License or out of the use or inability to use the |
||||
|
Work (including but not limited to damages for loss of goodwill, |
||||
|
work stoppage, computer failure or malfunction, or any and all |
||||
|
other commercial damages or losses), even if such Contributor |
||||
|
has been advised of the possibility of such damages. |
||||
|
|
||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
|
or other liability obligations and/or rights consistent with this |
||||
|
License. However, in accepting such obligations, You may act only |
||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||
|
of any other Contributor, and only if You agree to indemnify, |
||||
|
defend, and hold each Contributor harmless for any liability |
||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||
|
of your accepting any such warranty or additional liability. |
||||
|
|
||||
|
END OF TERMS AND CONDITIONS |
||||
|
|
||||
|
APPENDIX: How to apply the Apache License to your work. |
||||
|
|
||||
|
To apply the Apache License to your work, attach the following |
||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
|
replaced with your own identifying information. (Don't include |
||||
|
the brackets!) The text should be enclosed in the appropriate |
||||
|
comment syntax for the file format. We also recommend that a |
||||
|
file or class name and description of purpose be included on the |
||||
|
same "printed page" as the copyright notice for easier |
||||
|
identification within third-party archives. |
||||
|
|
||||
|
Copyright [yyyy] [name of copyright owner] |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
@ -0,0 +1,25 @@ |
|||||
|
Copyright (c) 2015 The Rust Project Developers |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any |
||||
|
person obtaining a copy of this software and associated |
||||
|
documentation files (the "Software"), to deal in the |
||||
|
Software without restriction, including without |
||||
|
limitation the rights to use, copy, modify, merge, |
||||
|
publish, distribute, sublicense, and/or sell copies of |
||||
|
the Software, and to permit persons to whom the Software |
||||
|
is furnished to do so, subject to the following |
||||
|
conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice |
||||
|
shall be included in all copies or substantial portions |
||||
|
of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
DEALINGS IN THE SOFTWARE. |
||||
@ -0,0 +1,109 @@ |
|||||
|
# rust.vim |
||||
|
|
||||
|
## Description |
||||
|
|
||||
|
This is a Vim plugin that provides [Rust][r] file detection, syntax highlighting, formatting, |
||||
|
[Syntastic][syn] integration, and more. It requires Vim 8 or higher for full functionality. |
||||
|
Some things may not work on earlier versions. |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
Use one of the following package managers: |
||||
|
|
||||
|
* [Vim8 packages][vim8pack]: |
||||
|
* `git clone https://github.com/rust-lang/rust.vim ~/.vim/pack/plugins/start/rust.vim` |
||||
|
* [Vundle][v]: |
||||
|
* Add `Plugin 'rust-lang/rust.vim'` to `~/.vimrc` |
||||
|
* `:PluginInstall` or `$ vim +PluginInstall +qall` |
||||
|
* *Note:* Vundle will not automatically detect Rust files properly if `filetype |
||||
|
on` is executed before Vundle. Please check the [quickstart][vqs] for more |
||||
|
details. Errors such as `Not an editor command: RustFmt` may occur if Vundle |
||||
|
is misconfigured with this plugin. |
||||
|
* [Pathogen][p]: |
||||
|
* `git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust.vim` |
||||
|
* [vim-plug][vp]: |
||||
|
* Add `Plug 'rust-lang/rust.vim'` to `~/.vimrc` |
||||
|
* `:PlugInstall` or `$ vim +PlugInstall +qall` |
||||
|
* [dein.vim][d]: |
||||
|
* Add `call dein#add('rust-lang/rust.vim')` to `~/.vimrc` |
||||
|
* `:call dein#install()` |
||||
|
* [NeoBundle][nb]: |
||||
|
* Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc` |
||||
|
* Re-open vim or execute `:source ~/.vimrc` |
||||
|
|
||||
|
## Features |
||||
|
|
||||
|
### Error checking with [Syntastic][syn] |
||||
|
|
||||
|
`rust.vim` automatically registers `cargo` as a syntax checker with |
||||
|
[Syntastic][syn], if nothing else is specified. See `:help rust-syntastic` |
||||
|
for more details. |
||||
|
|
||||
|
### Source browsing with [Tagbar][tgbr] |
||||
|
|
||||
|
The installation of Tagbar along with [Universal Ctags][uctags] is recommended |
||||
|
for a good Tagbar experience. For other kinds of setups, `rust.vim` tries to |
||||
|
configure Tagbar to some degree. |
||||
|
|
||||
|
### Formatting with [rustfmt][rfmt] |
||||
|
|
||||
|
The `:RustFmt` command will format your code with |
||||
|
[rustfmt][rfmt] if installed. |
||||
|
|
||||
|
Placing `let g:rustfmt_autosave = 1` in your `~/.vimrc` will |
||||
|
enable automatic running of `:RustFmt` when you save a buffer. |
||||
|
|
||||
|
Do `:help :RustFmt` for further formatting help and customization |
||||
|
options. |
||||
|
|
||||
|
### [Playpen][pp] integration |
||||
|
|
||||
|
*Note:* This feature requires [webapi-vim][wav] to be installed. |
||||
|
|
||||
|
The `:RustPlay` command will send the current selection, or if |
||||
|
nothing is selected the current buffer, to the [Rust playpen][pp]. |
||||
|
|
||||
|
If you set g:rust_clip_command RustPlay will copy the url to the clipboard. |
||||
|
|
||||
|
- Mac: |
||||
|
|
||||
|
let g:rust_clip_command = 'pbcopy' |
||||
|
|
||||
|
- Linux: |
||||
|
|
||||
|
let g:rust_clip_command = 'xclip -selection clipboard' |
||||
|
|
||||
|
### Running a test under cursor |
||||
|
|
||||
|
In cargo project, the `:RustTest` command will run a test under the cursor. |
||||
|
This is useful when your project is bigger and running all tests take longer time. |
||||
|
|
||||
|
## Help |
||||
|
|
||||
|
Further help can be found in the documentation with `:Helptags` then `:help rust`. |
||||
|
|
||||
|
Detailed help can be found in the documentation with `:help rust`. |
||||
|
Helptags (`:help helptags`) need to be generated for this plugin |
||||
|
in order to navigate the help. Most plugin managers will do this |
||||
|
automatically, but check their documentation if that is not the case. |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
Like Rust, rust.vim is primarily distributed under the terms of both the MIT |
||||
|
license and the Apache License (Version 2.0). See LICENSE-APACHE and |
||||
|
LICENSE-MIT for details. |
||||
|
|
||||
|
[r]: https://www.rust-lang.org |
||||
|
[v]: https://github.com/gmarik/vundle |
||||
|
[vqs]: https://github.com/gmarik/vundle#quick-start |
||||
|
[p]: https://github.com/tpope/vim-pathogen |
||||
|
[nb]: https://github.com/Shougo/neobundle.vim |
||||
|
[vp]: https://github.com/junegunn/vim-plug |
||||
|
[d]: https://github.com/Shougo/dein.vim |
||||
|
[rfmt]: https://github.com/rust-lang-nursery/rustfmt |
||||
|
[syn]: https://github.com/scrooloose/syntastic |
||||
|
[tgbr]: https://github.com/majutsushi/tagbar |
||||
|
[uctags]: https://ctags.io |
||||
|
[wav]: https://github.com/mattn/webapi-vim |
||||
|
[pp]: https://play.rust-lang.org/ |
||||
|
[vim8pack]: http://vimhelp.appspot.com/repeat.txt.html#packages |
||||
@ -0,0 +1,41 @@ |
|||||
|
scriptencoding utf-8 |
||||
|
|
||||
|
if !get(g:, 'rust_conceal', 0) || !has('conceal') || &encoding !=# 'utf-8' |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
" For those who don't want to see `::`... |
||||
|
if get(g:, 'rust_conceal_mod_path', 0) |
||||
|
syn match rustNiceOperator "::" conceal cchar=ㆍ |
||||
|
endif |
||||
|
|
||||
|
syn match rustRightArrowHead contained ">" conceal cchar= |
||||
|
syn match rustRightArrowTail contained "-" conceal cchar=⟶ |
||||
|
syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail |
||||
|
|
||||
|
syn match rustFatRightArrowHead contained ">" conceal cchar= |
||||
|
syn match rustFatRightArrowTail contained "=" conceal cchar=⟹ |
||||
|
syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail |
||||
|
|
||||
|
syn match rustNiceOperator /\<\@!_\(_*\>\)\@=/ conceal cchar=′ |
||||
|
|
||||
|
" For those who don't want to see `pub`... |
||||
|
if get(g:, 'rust_conceal_pub', 0) |
||||
|
syn match rustPublicSigil contained "pu" conceal cchar=* |
||||
|
syn match rustPublicRest contained "b" conceal cchar= |
||||
|
syn match rustNiceOperator "pub " contains=rustPublicSigil,rustPublicRest |
||||
|
endif |
||||
|
|
||||
|
hi link rustNiceOperator Operator |
||||
|
|
||||
|
if !get(g:, 'rust_conceal_mod_path', 0) |
||||
|
hi! link Conceal Operator |
||||
|
|
||||
|
augroup rust.vim.after |
||||
|
autocmd! |
||||
|
" And keep it after a colorscheme change |
||||
|
autocmd ColorScheme <buffer> hi! link Conceal Operator |
||||
|
augroup END |
||||
|
endif |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,125 @@ |
|||||
|
function! cargo#Load() |
||||
|
" Utility call to get this script loaded, for debugging |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#cmd(args) |
||||
|
" Trim trailing spaces. This is necessary since :terminal command parses |
||||
|
" trailing spaces as an empty argument. |
||||
|
let args = substitute(a:args, '\s\+$', '', '') |
||||
|
if has('terminal') |
||||
|
let cmd = 'terminal' |
||||
|
elseif has('nvim') |
||||
|
let cmd = 'noautocmd new | terminal' |
||||
|
else |
||||
|
let cmd = '!' |
||||
|
endif |
||||
|
execute cmd 'cargo' args |
||||
|
endfunction |
||||
|
|
||||
|
function! s:nearest_cargo(...) abort |
||||
|
" If the second argument is not specified, the first argument determines |
||||
|
" whether we will start from the current directory or the directory of the |
||||
|
" current buffer, otherwise, we start with the provided path on the |
||||
|
" second argument. |
||||
|
|
||||
|
let l:is_getcwd = get(a:, 1, 0) |
||||
|
if l:is_getcwd |
||||
|
let l:starting_path = get(a:, 2, getcwd()) |
||||
|
else |
||||
|
let l:starting_path = get(a:, 2, expand('%:p:h')) |
||||
|
endif |
||||
|
|
||||
|
return findfile('Cargo.toml', l:starting_path . ';') |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#nearestCargo(is_getcwd) abort |
||||
|
return s:nearest_cargo(a:is_getcwd) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#nearestWorkspaceCargo(is_getcwd) abort |
||||
|
let l:nearest = s:nearest_cargo(a:is_getcwd) |
||||
|
while l:nearest !=# '' |
||||
|
for l:line in readfile(l:nearest, '', 0x100) |
||||
|
if l:line =~# '\V[workspace]' |
||||
|
return l:nearest |
||||
|
endif |
||||
|
endfor |
||||
|
let l:next = fnamemodify(l:nearest, ':p:h:h') |
||||
|
let l:nearest = s:nearest_cargo(0, l:next) |
||||
|
endwhile |
||||
|
return '' |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#nearestRootCargo(is_getcwd) abort |
||||
|
" Try to find a workspace Cargo.toml, and if not found, take the nearest |
||||
|
" regular Cargo.toml |
||||
|
let l:workspace_cargo = cargo#nearestWorkspaceCargo(a:is_getcwd) |
||||
|
if l:workspace_cargo !=# '' |
||||
|
return l:workspace_cargo |
||||
|
endif |
||||
|
return s:nearest_cargo(a:is_getcwd) |
||||
|
endfunction |
||||
|
|
||||
|
|
||||
|
function! cargo#build(args) |
||||
|
call cargo#cmd("build " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#clean(args) |
||||
|
call cargo#cmd("clean " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#doc(args) |
||||
|
call cargo#cmd("doc " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#new(args) |
||||
|
call cargo#cmd("new " . a:args) |
||||
|
cd `=a:args` |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#init(args) |
||||
|
call cargo#cmd("init " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#run(args) |
||||
|
call cargo#cmd("run " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#test(args) |
||||
|
call cargo#cmd("test " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#bench(args) |
||||
|
call cargo#cmd("bench " . a:args) |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#runtarget(args) |
||||
|
let l:filename = expand('%:p') |
||||
|
let l:read_manifest = system('cargo read-manifest') |
||||
|
let l:metadata = json_decode(l:read_manifest) |
||||
|
let l:targets = get(l:metadata, 'targets', []) |
||||
|
let l:did_run = 0 |
||||
|
for l:target in l:targets |
||||
|
let l:src_path = get(l:target, 'src_path', '') |
||||
|
let l:kinds = get(l:target, 'kind', []) |
||||
|
let l:name = get(l:target, 'name', '') |
||||
|
if l:src_path == l:filename |
||||
|
if index(l:kinds, 'example') != -1 |
||||
|
let l:did_run = 1 |
||||
|
call cargo#run("--example " . shellescape(l:name) . " " . a:args) |
||||
|
return |
||||
|
elseif index(l:kinds, 'bin') != -1 |
||||
|
let l:did_run = 1 |
||||
|
call cargo#run("--bin " . shellescape(l:name) . " " . a:args) |
||||
|
return |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
if l:did_run != 1 |
||||
|
call cargo#run(a:args) |
||||
|
return |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,26 @@ |
|||||
|
function! cargo#quickfix#CmdPre() abort |
||||
|
if &filetype ==# 'rust' && get(b:, 'current_compiler', '') ==# 'cargo' |
||||
|
" Preserve the current directory, and 'lcd' to the nearest Cargo file. |
||||
|
let b:rust_compiler_cargo_qf_has_lcd = haslocaldir() |
||||
|
let b:rust_compiler_cargo_qf_prev_cd = getcwd() |
||||
|
let b:rust_compiler_cargo_qf_prev_cd_saved = 1 |
||||
|
let l:nearest = fnamemodify(cargo#nearestRootCargo(0), ':h') |
||||
|
execute 'lchdir! '.l:nearest |
||||
|
else |
||||
|
let b:rust_compiler_cargo_qf_prev_cd_saved = 0 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! cargo#quickfix#CmdPost() abort |
||||
|
if exists("b:rust_compiler_cargo_qf_prev_cd_saved") && b:rust_compiler_cargo_qf_prev_cd_saved |
||||
|
" Restore the current directory. |
||||
|
if b:rust_compiler_cargo_qf_has_lcd |
||||
|
execute 'lchdir! '.b:rust_compiler_cargo_qf_prev_cd |
||||
|
else |
||||
|
execute 'chdir! '.b:rust_compiler_cargo_qf_prev_cd |
||||
|
endif |
||||
|
let b:rust_compiler_cargo_qf_prev_cd_saved = 0 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,563 @@ |
|||||
|
" Description: Helper functions for Rust commands/mappings |
||||
|
" Last Modified: May 27, 2014 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
function! rust#Load() |
||||
|
" Utility call to get this script loaded, for debugging |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#GetConfigVar(name, default) |
||||
|
" Local buffer variable with same name takes predeence over global |
||||
|
if has_key(b:, a:name) |
||||
|
return get(b:, a:name) |
||||
|
endif |
||||
|
if has_key(g:, a:name) |
||||
|
return get(g:, a:name) |
||||
|
endif |
||||
|
return a:default |
||||
|
endfunction |
||||
|
|
||||
|
" Include expression {{{1 |
||||
|
|
||||
|
function! rust#IncludeExpr(fname) abort |
||||
|
" Remove leading 'crate::' to deal with 2018 edition style 'use' |
||||
|
" statements |
||||
|
let l:fname = substitute(a:fname, '^crate::', '', '') |
||||
|
|
||||
|
" Remove trailing colons arising from lines like |
||||
|
" |
||||
|
" use foo::{Bar, Baz}; |
||||
|
let l:fname = substitute(l:fname, ':\+$', '', '') |
||||
|
|
||||
|
" Replace '::' with '/' |
||||
|
let l:fname = substitute(l:fname, '::', '/', 'g') |
||||
|
|
||||
|
" When we have |
||||
|
" |
||||
|
" use foo::bar::baz; |
||||
|
" |
||||
|
" we can't tell whether baz is a module or a function; and we can't tell |
||||
|
" which modules correspond to files. |
||||
|
" |
||||
|
" So we work our way up, trying |
||||
|
" |
||||
|
" foo/bar/baz.rs |
||||
|
" foo/bar.rs |
||||
|
" foo.rs |
||||
|
while l:fname !=# '.' |
||||
|
let l:path = findfile(l:fname) |
||||
|
if !empty(l:path) |
||||
|
return l:fname |
||||
|
endif |
||||
|
let l:fname = fnamemodify(l:fname, ':h') |
||||
|
endwhile |
||||
|
return l:fname |
||||
|
endfunction |
||||
|
|
||||
|
" Jump {{{1 |
||||
|
|
||||
|
function! rust#Jump(mode, function) range |
||||
|
let cnt = v:count1 |
||||
|
normal! m' |
||||
|
if a:mode ==# 'v' |
||||
|
norm! gv |
||||
|
endif |
||||
|
let foldenable = &foldenable |
||||
|
set nofoldenable |
||||
|
while cnt > 0 |
||||
|
execute "call <SID>Jump_" . a:function . "()" |
||||
|
let cnt = cnt - 1 |
||||
|
endwhile |
||||
|
let &foldenable = foldenable |
||||
|
endfunction |
||||
|
|
||||
|
function! s:Jump_Back() |
||||
|
call search('{', 'b') |
||||
|
keepjumps normal! w99[{ |
||||
|
endfunction |
||||
|
|
||||
|
function! s:Jump_Forward() |
||||
|
normal! j0 |
||||
|
call search('{', 'b') |
||||
|
keepjumps normal! w99[{% |
||||
|
call search('{') |
||||
|
endfunction |
||||
|
|
||||
|
" Run {{{1 |
||||
|
|
||||
|
function! rust#Run(bang, args) |
||||
|
let args = s:ShellTokenize(a:args) |
||||
|
if a:bang |
||||
|
let idx = index(l:args, '--') |
||||
|
if idx != -1 |
||||
|
let rustc_args = idx == 0 ? [] : l:args[:idx-1] |
||||
|
let args = l:args[idx+1:] |
||||
|
else |
||||
|
let rustc_args = l:args |
||||
|
let args = [] |
||||
|
endif |
||||
|
else |
||||
|
let rustc_args = [] |
||||
|
endif |
||||
|
|
||||
|
let b:rust_last_rustc_args = l:rustc_args |
||||
|
let b:rust_last_args = l:args |
||||
|
|
||||
|
call s:WithPath(function("s:Run"), rustc_args, args) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:Run(dict, rustc_args, args) |
||||
|
let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') |
||||
|
if has('win32') |
||||
|
let exepath .= '.exe' |
||||
|
endif |
||||
|
|
||||
|
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) |
||||
|
let rustc_args = [relpath, '-o', exepath] + a:rustc_args |
||||
|
|
||||
|
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" |
||||
|
|
||||
|
let pwd = a:dict.istemp ? a:dict.tmpdir : '' |
||||
|
let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) |
||||
|
if output !=# '' |
||||
|
echohl WarningMsg |
||||
|
echo output |
||||
|
echohl None |
||||
|
endif |
||||
|
if !v:shell_error |
||||
|
exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" Expand {{{1 |
||||
|
|
||||
|
function! rust#Expand(bang, args) |
||||
|
let args = s:ShellTokenize(a:args) |
||||
|
if a:bang && !empty(l:args) |
||||
|
let pretty = remove(l:args, 0) |
||||
|
else |
||||
|
let pretty = "expanded" |
||||
|
endif |
||||
|
call s:WithPath(function("s:Expand"), pretty, args) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:Expand(dict, pretty, args) |
||||
|
try |
||||
|
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" |
||||
|
|
||||
|
if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' |
||||
|
let flag = '--xpretty' |
||||
|
else |
||||
|
let flag = '--pretty' |
||||
|
endif |
||||
|
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) |
||||
|
let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args |
||||
|
let pwd = a:dict.istemp ? a:dict.tmpdir : '' |
||||
|
let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) |
||||
|
if v:shell_error |
||||
|
echohl WarningMsg |
||||
|
echo output |
||||
|
echohl None |
||||
|
else |
||||
|
new |
||||
|
silent put =output |
||||
|
1 |
||||
|
d |
||||
|
setl filetype=rust |
||||
|
setl buftype=nofile |
||||
|
setl bufhidden=hide |
||||
|
setl noswapfile |
||||
|
" give the buffer a nice name |
||||
|
let suffix = 1 |
||||
|
let basename = fnamemodify(a:dict.path, ':t:r') |
||||
|
while 1 |
||||
|
let bufname = basename |
||||
|
if suffix > 1 | let bufname .= ' ('.suffix.')' | endif |
||||
|
let bufname .= '.pretty.rs' |
||||
|
if bufexists(bufname) |
||||
|
let suffix += 1 |
||||
|
continue |
||||
|
endif |
||||
|
exe 'silent noautocmd keepalt file' fnameescape(bufname) |
||||
|
break |
||||
|
endwhile |
||||
|
endif |
||||
|
endtry |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#CompleteExpand(lead, line, pos) |
||||
|
if a:line[: a:pos-1] =~# '^RustExpand!\s*\S*$' |
||||
|
" first argument and it has a ! |
||||
|
let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] |
||||
|
if !empty(a:lead) |
||||
|
call filter(list, "v:val[:len(a:lead)-1] == a:lead") |
||||
|
endif |
||||
|
return list |
||||
|
endif |
||||
|
|
||||
|
return glob(escape(a:lead, "*?[") . '*', 0, 1) |
||||
|
endfunction |
||||
|
|
||||
|
" Emit {{{1 |
||||
|
|
||||
|
function! rust#Emit(type, args) |
||||
|
let args = s:ShellTokenize(a:args) |
||||
|
call s:WithPath(function("s:Emit"), a:type, args) |
||||
|
endfunction |
||||
|
|
||||
|
function! s:Emit(dict, type, args) |
||||
|
try |
||||
|
let output_path = a:dict.tmpdir.'/output' |
||||
|
|
||||
|
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" |
||||
|
|
||||
|
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) |
||||
|
let args = [relpath, '--emit', a:type, '-o', output_path] + a:args |
||||
|
let pwd = a:dict.istemp ? a:dict.tmpdir : '' |
||||
|
let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) |
||||
|
if output !=# '' |
||||
|
echohl WarningMsg |
||||
|
echo output |
||||
|
echohl None |
||||
|
endif |
||||
|
if !v:shell_error |
||||
|
new |
||||
|
exe 'silent keepalt read' fnameescape(output_path) |
||||
|
1 |
||||
|
d |
||||
|
if a:type ==# "llvm-ir" |
||||
|
setl filetype=llvm |
||||
|
let extension = 'll' |
||||
|
elseif a:type ==# "asm" |
||||
|
setl filetype=asm |
||||
|
let extension = 's' |
||||
|
endif |
||||
|
setl buftype=nofile |
||||
|
setl bufhidden=hide |
||||
|
setl noswapfile |
||||
|
if exists('l:extension') |
||||
|
" give the buffer a nice name |
||||
|
let suffix = 1 |
||||
|
let basename = fnamemodify(a:dict.path, ':t:r') |
||||
|
while 1 |
||||
|
let bufname = basename |
||||
|
if suffix > 1 | let bufname .= ' ('.suffix.')' | endif |
||||
|
let bufname .= '.'.extension |
||||
|
if bufexists(bufname) |
||||
|
let suffix += 1 |
||||
|
continue |
||||
|
endif |
||||
|
exe 'silent noautocmd keepalt file' fnameescape(bufname) |
||||
|
break |
||||
|
endwhile |
||||
|
endif |
||||
|
endif |
||||
|
endtry |
||||
|
endfunction |
||||
|
|
||||
|
" Utility functions {{{1 |
||||
|
|
||||
|
" Invokes func(dict, ...) |
||||
|
" Where {dict} is a dictionary with the following keys: |
||||
|
" 'path' - The path to the file |
||||
|
" 'tmpdir' - The path to a temporary directory that will be deleted when the |
||||
|
" function returns. |
||||
|
" 'istemp' - 1 if the path is a file inside of {dict.tmpdir} or 0 otherwise. |
||||
|
" If {istemp} is 1 then an additional key is provided: |
||||
|
" 'tmpdir_relpath' - The {path} relative to the {tmpdir}. |
||||
|
" |
||||
|
" {dict.path} may be a path to a file inside of {dict.tmpdir} or it may be the |
||||
|
" existing path of the current buffer. If the path is inside of {dict.tmpdir} |
||||
|
" then it is guaranteed to have a '.rs' extension. |
||||
|
function! s:WithPath(func, ...) |
||||
|
let buf = bufnr('') |
||||
|
let saved = {} |
||||
|
let dict = {} |
||||
|
try |
||||
|
let saved.write = &write |
||||
|
set write |
||||
|
let dict.path = expand('%') |
||||
|
let pathisempty = empty(dict.path) |
||||
|
|
||||
|
" Always create a tmpdir in case the wrapped command wants it |
||||
|
let dict.tmpdir = tempname() |
||||
|
call mkdir(dict.tmpdir) |
||||
|
|
||||
|
if pathisempty || !saved.write |
||||
|
let dict.istemp = 1 |
||||
|
" if we're doing this because of nowrite, preserve the filename |
||||
|
if !pathisempty |
||||
|
let filename = expand('%:t:r').".rs" |
||||
|
else |
||||
|
let filename = 'unnamed.rs' |
||||
|
endif |
||||
|
let dict.tmpdir_relpath = filename |
||||
|
let dict.path = dict.tmpdir.'/'.filename |
||||
|
|
||||
|
let saved.mod = &modified |
||||
|
set nomodified |
||||
|
|
||||
|
silent exe 'keepalt write! ' . fnameescape(dict.path) |
||||
|
if pathisempty |
||||
|
silent keepalt 0file |
||||
|
endif |
||||
|
else |
||||
|
let dict.istemp = 0 |
||||
|
update |
||||
|
endif |
||||
|
|
||||
|
call call(a:func, [dict] + a:000) |
||||
|
finally |
||||
|
if bufexists(buf) |
||||
|
for [opt, value] in items(saved) |
||||
|
silent call setbufvar(buf, '&'.opt, value) |
||||
|
unlet value " avoid variable type mismatches |
||||
|
endfor |
||||
|
endif |
||||
|
if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif |
||||
|
endtry |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#AppendCmdLine(text) |
||||
|
call setcmdpos(getcmdpos()) |
||||
|
let cmd = getcmdline() . a:text |
||||
|
return cmd |
||||
|
endfunction |
||||
|
|
||||
|
" Tokenize the string according to sh parsing rules |
||||
|
function! s:ShellTokenize(text) |
||||
|
" states: |
||||
|
" 0: start of word |
||||
|
" 1: unquoted |
||||
|
" 2: unquoted backslash |
||||
|
" 3: double-quote |
||||
|
" 4: double-quoted backslash |
||||
|
" 5: single-quote |
||||
|
let l:state = 0 |
||||
|
let l:current = '' |
||||
|
let l:args = [] |
||||
|
for c in split(a:text, '\zs') |
||||
|
if l:state == 0 || l:state == 1 " unquoted |
||||
|
if l:c ==# ' ' |
||||
|
if l:state == 0 | continue | endif |
||||
|
call add(l:args, l:current) |
||||
|
let l:current = '' |
||||
|
let l:state = 0 |
||||
|
elseif l:c ==# '\' |
||||
|
let l:state = 2 |
||||
|
elseif l:c ==# '"' |
||||
|
let l:state = 3 |
||||
|
elseif l:c ==# "'" |
||||
|
let l:state = 5 |
||||
|
else |
||||
|
let l:current .= l:c |
||||
|
let l:state = 1 |
||||
|
endif |
||||
|
elseif l:state == 2 " unquoted backslash |
||||
|
if l:c !=# "\n" " can it even be \n? |
||||
|
let l:current .= l:c |
||||
|
endif |
||||
|
let l:state = 1 |
||||
|
elseif l:state == 3 " double-quote |
||||
|
if l:c ==# '\' |
||||
|
let l:state = 4 |
||||
|
elseif l:c ==# '"' |
||||
|
let l:state = 1 |
||||
|
else |
||||
|
let l:current .= l:c |
||||
|
endif |
||||
|
elseif l:state == 4 " double-quoted backslash |
||||
|
if stridx('$`"\', l:c) >= 0 |
||||
|
let l:current .= l:c |
||||
|
elseif l:c ==# "\n" " is this even possible? |
||||
|
" skip it |
||||
|
else |
||||
|
let l:current .= '\'.l:c |
||||
|
endif |
||||
|
let l:state = 3 |
||||
|
elseif l:state == 5 " single-quoted |
||||
|
if l:c ==# "'" |
||||
|
let l:state = 1 |
||||
|
else |
||||
|
let l:current .= l:c |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
if l:state != 0 |
||||
|
call add(l:args, l:current) |
||||
|
endif |
||||
|
return l:args |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RmDir(path) |
||||
|
" sanity check; make sure it's not empty, /, or $HOME |
||||
|
if empty(a:path) |
||||
|
echoerr 'Attempted to delete empty path' |
||||
|
return 0 |
||||
|
elseif a:path ==# '/' || a:path ==# $HOME |
||||
|
let l:path = expand(a:path) |
||||
|
if l:path ==# '/' || l:path ==# $HOME |
||||
|
echoerr 'Attempted to delete protected path: ' . a:path |
||||
|
return 0 |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if !isdirectory(a:path) |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
" delete() returns 0 when removing file successfully |
||||
|
return delete(a:path, 'rf') == 0 |
||||
|
endfunction |
||||
|
|
||||
|
" Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd. |
||||
|
" If {pwd} is the empty string then it doesn't change the cwd. |
||||
|
function! s:system(pwd, cmd) |
||||
|
let cmd = a:cmd |
||||
|
if !empty(a:pwd) |
||||
|
let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd |
||||
|
endif |
||||
|
return system(cmd) |
||||
|
endfunction |
||||
|
|
||||
|
" Playpen Support {{{1 |
||||
|
" Parts of gist.vim by Yasuhiro Matsumoto <mattn.jp@gmail.com> reused |
||||
|
" gist.vim available under the BSD license, available at |
||||
|
" http://github.com/mattn/gist-vim |
||||
|
function! s:has_webapi() |
||||
|
if !exists("*webapi#http#post") |
||||
|
try |
||||
|
call webapi#http#post() |
||||
|
catch |
||||
|
endtry |
||||
|
endif |
||||
|
return exists("*webapi#http#post") |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#Play(count, line1, line2, ...) abort |
||||
|
redraw |
||||
|
|
||||
|
let l:rust_playpen_url = get(g:, 'rust_playpen_url', 'https://play.rust-lang.org/') |
||||
|
let l:rust_shortener_url = get(g:, 'rust_shortener_url', 'https://is.gd/') |
||||
|
|
||||
|
if !s:has_webapi() |
||||
|
echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let bufname = bufname('%') |
||||
|
if a:count < 1 |
||||
|
let content = join(getline(a:line1, a:line2), "\n") |
||||
|
else |
||||
|
let save_regcont = @" |
||||
|
let save_regtype = getregtype('"') |
||||
|
silent! normal! gvy |
||||
|
let content = @" |
||||
|
call setreg('"', save_regcont, save_regtype) |
||||
|
endif |
||||
|
|
||||
|
let url = l:rust_playpen_url."?code=".webapi#http#encodeURI(content) |
||||
|
|
||||
|
if strlen(url) > 5000 |
||||
|
echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let payload = "format=simple&url=".webapi#http#encodeURI(url) |
||||
|
let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) |
||||
|
if res.status[0] ==# '2' |
||||
|
let url = res.content |
||||
|
endif |
||||
|
|
||||
|
let footer = '' |
||||
|
if exists('g:rust_clip_command') |
||||
|
call system(g:rust_clip_command, url) |
||||
|
if !v:shell_error |
||||
|
let footer = ' (copied to clipboard)' |
||||
|
endif |
||||
|
endif |
||||
|
redraw | echomsg 'Done: '.url.footer |
||||
|
endfunction |
||||
|
|
||||
|
" Run a test under the cursor or all tests {{{1 |
||||
|
|
||||
|
" Finds a test function name under the cursor. Returns empty string when a |
||||
|
" test function is not found. |
||||
|
function! s:SearchTestFunctionNameUnderCursor() abort |
||||
|
let cursor_line = line('.') |
||||
|
|
||||
|
" Find #[test] attribute |
||||
|
if search('\m\C#\[test\]', 'bcW') is 0 |
||||
|
return '' |
||||
|
endif |
||||
|
|
||||
|
" Move to an opening brace of the test function |
||||
|
let test_func_line = search('\m\C^\s*fn\s\+\h\w*\s*(.\+{$', 'eW') |
||||
|
if test_func_line is 0 |
||||
|
return '' |
||||
|
endif |
||||
|
|
||||
|
" Search the end of test function (closing brace) to ensure that the |
||||
|
" cursor position is within function definition |
||||
|
normal! % |
||||
|
if line('.') < cursor_line |
||||
|
return '' |
||||
|
endif |
||||
|
|
||||
|
return matchstr(getline(test_func_line), '\m\C^\s*fn\s\+\zs\h\w*') |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#Test(mods, winsize, all, options) abort |
||||
|
let manifest = findfile('Cargo.toml', expand('%:p:h') . ';') |
||||
|
if manifest ==# '' |
||||
|
return rust#Run(1, '--test ' . a:options) |
||||
|
endif |
||||
|
|
||||
|
" <count> defaults to 0, but we prefer an empty string |
||||
|
let winsize = a:winsize ? a:winsize : '' |
||||
|
|
||||
|
if has('terminal') |
||||
|
if has('patch-8.0.910') |
||||
|
let cmd = printf('%s noautocmd %snew | terminal ++curwin ', a:mods, winsize) |
||||
|
else |
||||
|
let cmd = printf('%s terminal ', a:mods) |
||||
|
endif |
||||
|
elseif has('nvim') |
||||
|
let cmd = printf('%s noautocmd %snew | terminal ', a:mods, winsize) |
||||
|
else |
||||
|
let cmd = '!' |
||||
|
let manifest = shellescape(manifest) |
||||
|
endif |
||||
|
|
||||
|
if a:all |
||||
|
if a:options ==# '' |
||||
|
execute cmd . 'cargo test --manifest-path' manifest |
||||
|
else |
||||
|
execute cmd . 'cargo test --manifest-path' manifest a:options |
||||
|
endif |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let saved = getpos('.') |
||||
|
try |
||||
|
let func_name = s:SearchTestFunctionNameUnderCursor() |
||||
|
if func_name ==# '' |
||||
|
echohl ErrorMsg |
||||
|
echomsg 'No test function was found under the cursor. Please add ! to command if you want to run all tests' |
||||
|
echohl None |
||||
|
return |
||||
|
endif |
||||
|
if a:options ==# '' |
||||
|
execute cmd . 'cargo test --manifest-path' manifest func_name |
||||
|
else |
||||
|
execute cmd . 'cargo test --manifest-path' manifest func_name a:options |
||||
|
endif |
||||
|
return |
||||
|
finally |
||||
|
call setpos('.', saved) |
||||
|
endtry |
||||
|
endfunction |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,103 @@ |
|||||
|
" For debugging, inspired by https://github.com/w0rp/rust/blob/master/autoload/rust/debugging.vim |
||||
|
|
||||
|
let s:global_variable_list = [ |
||||
|
\ '_rustfmt_autosave_because_of_config', |
||||
|
\ 'ftplugin_rust_source_path', |
||||
|
\ 'loaded_syntastic_rust_cargo_checker', |
||||
|
\ 'loaded_syntastic_rust_filetype', |
||||
|
\ 'loaded_syntastic_rust_rustc_checker', |
||||
|
\ 'rust_bang_comment_leader', |
||||
|
\ 'rust_cargo_avoid_whole_workspace', |
||||
|
\ 'rust_clip_command', |
||||
|
\ 'rust_conceal', |
||||
|
\ 'rust_conceal_mod_path', |
||||
|
\ 'rust_conceal_pub', |
||||
|
\ 'rust_fold', |
||||
|
\ 'rust_last_args', |
||||
|
\ 'rust_last_rustc_args', |
||||
|
\ 'rust_original_delimitMate_excluded_regions', |
||||
|
\ 'rust_playpen_url', |
||||
|
\ 'rust_prev_delimitMate_quotes', |
||||
|
\ 'rust_recent_nearest_cargo_tol', |
||||
|
\ 'rust_recent_root_cargo_toml', |
||||
|
\ 'rust_recommended_style', |
||||
|
\ 'rust_set_conceallevel', |
||||
|
\ 'rust_set_conceallevel=1', |
||||
|
\ 'rust_set_foldmethod', |
||||
|
\ 'rust_set_foldmethod=1', |
||||
|
\ 'rust_shortener_url', |
||||
|
\ 'rustc_makeprg_no_percent', |
||||
|
\ 'rustc_path', |
||||
|
\ 'rustfmt_autosave', |
||||
|
\ 'rustfmt_autosave_if_config_present', |
||||
|
\ 'rustfmt_command', |
||||
|
\ 'rustfmt_emit_files', |
||||
|
\ 'rustfmt_fail_silently', |
||||
|
\ 'rustfmt_options', |
||||
|
\ 'syntastic_extra_filetypes', |
||||
|
\ 'syntastic_rust_cargo_fname', |
||||
|
\] |
||||
|
|
||||
|
function! s:Echo(message) abort |
||||
|
execute 'echo a:message' |
||||
|
endfunction |
||||
|
|
||||
|
function! s:EchoGlobalVariables() abort |
||||
|
for l:key in s:global_variable_list |
||||
|
if l:key !~# '^_' |
||||
|
call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))) |
||||
|
endif |
||||
|
|
||||
|
if has_key(b:, l:key) |
||||
|
call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#debugging#Info() abort |
||||
|
call cargo#Load() |
||||
|
call rust#Load() |
||||
|
call rustfmt#Load() |
||||
|
call s:Echo('rust.vim Global Variables:') |
||||
|
call s:Echo('') |
||||
|
call s:EchoGlobalVariables() |
||||
|
|
||||
|
silent let l:output = system(g:rustfmt_command . ' --version') |
||||
|
echo l:output |
||||
|
|
||||
|
let l:rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" |
||||
|
silent let l:output = system(l:rustc . ' --version') |
||||
|
echo l:output |
||||
|
|
||||
|
silent let l:output = system('cargo --version') |
||||
|
echo l:output |
||||
|
|
||||
|
version |
||||
|
|
||||
|
if exists(":SyntasticInfo") |
||||
|
echo "----" |
||||
|
echo "Info from Syntastic:" |
||||
|
execute "SyntasticInfo" |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#debugging#InfoToClipboard() abort |
||||
|
redir @" |
||||
|
silent call rust#debugging#Info() |
||||
|
redir END |
||||
|
|
||||
|
call s:Echo('RustInfo copied to your clipboard') |
||||
|
endfunction |
||||
|
|
||||
|
function! rust#debugging#InfoToFile(filename) abort |
||||
|
let l:expanded_filename = expand(a:filename) |
||||
|
|
||||
|
redir => l:output |
||||
|
silent call rust#debugging#Info() |
||||
|
redir END |
||||
|
|
||||
|
call writefile(split(l:output, "\n"), l:expanded_filename) |
||||
|
call s:Echo('RustInfo written to ' . l:expanded_filename) |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,44 @@ |
|||||
|
let s:delimitMate_extra_excluded_regions = ',rustLifetimeCandidate,rustGenericLifetimeCandidate' |
||||
|
|
||||
|
" For this buffer, when delimitMate issues the `User delimitMate_map` |
||||
|
" event in the autocommand system, add the above-defined extra excluded |
||||
|
" regions to delimitMate's state, if they have not already been added. |
||||
|
function! rust#delimitmate#onMap() abort |
||||
|
if &filetype !=# 'rust' |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
if get(b:, "delimitMate_quotes") |
||||
|
let b:rust_prev_delimitMate_quotes = b:delimitMate_quotes |
||||
|
endif |
||||
|
let b:delimitMate_quotes = "\" `" |
||||
|
|
||||
|
if match(delimitMate#Get("excluded_regions"), |
||||
|
\ s:delimitMate_extra_excluded_regions) == -1 |
||||
|
call delimitMate#Set("excluded_regions", |
||||
|
\delimitMate#Get("excluded_regions").s:delimitMate_extra_excluded_regions) |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" For this buffer, when delimitMate issues the `User delimitMate_unmap` |
||||
|
" event in the autocommand system, delete the above-defined extra excluded |
||||
|
" regions from delimitMate's state (the deletion being idempotent and |
||||
|
" having no effect if the extra excluded regions are not present in the |
||||
|
" targeted part of delimitMate's state). |
||||
|
function! rust#delimitmate#onUnmap() abort |
||||
|
if &filetype !=# 'rust' |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
if get(b:, "rust_prev_delimitMate_quotes") |
||||
|
let b:delimitMate_quotes = b:rust_prev_delimitMate_quotes |
||||
|
endif |
||||
|
|
||||
|
call delimitMate#Set("excluded_regions", substitute( |
||||
|
\ delimitMate#Get("excluded_regions"), |
||||
|
\ '\C\V' . s:delimitMate_extra_excluded_regions, |
||||
|
\ '', 'g')) |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
|
|
||||
@ -0,0 +1,18 @@ |
|||||
|
" Tagbar support code, for the sake of not automatically overriding its |
||||
|
" configuration in case Universal Ctags is detected. |
||||
|
|
||||
|
let s:ctags_is_uctags = 0 |
||||
|
let s:checked_ctags = 0 |
||||
|
|
||||
|
function! rust#tags#IsUCtags() abort |
||||
|
if s:checked_ctags == 0 |
||||
|
let l:ctags_bin = get(g:, 'tagbar_ctags_bin', 'ctags') |
||||
|
if system(l:ctags_bin.' --version') =~? 'universal ctags' |
||||
|
let s:ctags_is_uctags = 1 |
||||
|
endif |
||||
|
let s:checked_ctags = 1 |
||||
|
endif |
||||
|
return s:ctags_is_uctags |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,264 @@ |
|||||
|
" Author: Stephen Sugden <stephen@stephensugden.com> |
||||
|
" |
||||
|
" Adapted from https://github.com/fatih/vim-go |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
if !exists("g:rustfmt_autosave") |
||||
|
let g:rustfmt_autosave = 0 |
||||
|
endif |
||||
|
|
||||
|
if !exists("g:rustfmt_command") |
||||
|
let g:rustfmt_command = "rustfmt" |
||||
|
endif |
||||
|
|
||||
|
if !exists("g:rustfmt_options") |
||||
|
let g:rustfmt_options = "" |
||||
|
endif |
||||
|
|
||||
|
if !exists("g:rustfmt_fail_silently") |
||||
|
let g:rustfmt_fail_silently = 0 |
||||
|
endif |
||||
|
|
||||
|
function! rustfmt#DetectVersion() |
||||
|
" Save rustfmt '--help' for feature inspection |
||||
|
silent let s:rustfmt_help = system(g:rustfmt_command . " --help") |
||||
|
let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features" |
||||
|
|
||||
|
" Build a comparable rustfmt version varible out of its `--version` output: |
||||
|
silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version") |
||||
|
let l:rustfmt_version_list = matchlist(l:rustfmt_version_full, |
||||
|
\ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)') |
||||
|
if len(l:rustfmt_version_list) < 3 |
||||
|
let s:rustfmt_version = "0" |
||||
|
else |
||||
|
let s:rustfmt_version = l:rustfmt_version_list[1] |
||||
|
endif |
||||
|
return s:rustfmt_version |
||||
|
endfunction |
||||
|
|
||||
|
call rustfmt#DetectVersion() |
||||
|
|
||||
|
if !exists("g:rustfmt_emit_files") |
||||
|
let g:rustfmt_emit_files = s:rustfmt_version >= "0.8.2" |
||||
|
endif |
||||
|
|
||||
|
if !exists("g:rustfmt_file_lines") |
||||
|
let g:rustfmt_file_lines = s:rustfmt_help =~# "--file-lines JSON" |
||||
|
endif |
||||
|
|
||||
|
let s:got_fmt_error = 0 |
||||
|
|
||||
|
function! rustfmt#Load() |
||||
|
" Utility call to get this script loaded, for debugging |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RustfmtWriteMode() |
||||
|
if g:rustfmt_emit_files |
||||
|
return "--emit=files" |
||||
|
else |
||||
|
return "--write-mode=overwrite" |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RustfmtConfig() |
||||
|
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';') |
||||
|
if l:rustfmt_toml !=# '' |
||||
|
return '--config-path '.l:rustfmt_toml |
||||
|
endif |
||||
|
|
||||
|
let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';') |
||||
|
if l:_rustfmt_toml !=# '' |
||||
|
return '--config-path '.l:_rustfmt_toml |
||||
|
endif |
||||
|
|
||||
|
return '' |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RustfmtCommandRange(filename, line1, line2) |
||||
|
if g:rustfmt_file_lines == 0 |
||||
|
echo "--file-lines is not supported in the installed `rustfmt` executable" |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} |
||||
|
let l:write_mode = s:RustfmtWriteMode() |
||||
|
let l:rustfmt_config = s:RustfmtConfig() |
||||
|
|
||||
|
" FIXME: When --file-lines gets to be stable, add version range checking |
||||
|
" accordingly. |
||||
|
let l:unstable_features = s:rustfmt_unstable_features ? '--unstable-features' : '' |
||||
|
|
||||
|
let l:cmd = printf("%s %s %s %s %s --file-lines '[%s]' %s", g:rustfmt_command, |
||||
|
\ l:write_mode, g:rustfmt_options, |
||||
|
\ l:unstable_features, l:rustfmt_config, |
||||
|
\ json_encode(l:arg), shellescape(a:filename)) |
||||
|
return l:cmd |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RustfmtCommand() |
||||
|
if g:rustfmt_emit_files |
||||
|
let l:write_mode = "--emit=stdout" |
||||
|
else |
||||
|
let l:write_mode = "--write-mode=display" |
||||
|
endif |
||||
|
" rustfmt will pick on the right config on its own due to the |
||||
|
" current directory change. |
||||
|
return g:rustfmt_command . " ". l:write_mode . " " . g:rustfmt_options |
||||
|
endfunction |
||||
|
|
||||
|
function! s:DeleteLines(start, end) abort |
||||
|
silent! execute a:start . ',' . a:end . 'delete _' |
||||
|
endfunction |
||||
|
|
||||
|
function! s:RunRustfmt(command, tmpname, from_writepre) |
||||
|
mkview! |
||||
|
|
||||
|
let l:stderr_tmpname = tempname() |
||||
|
call writefile([], l:stderr_tmpname) |
||||
|
|
||||
|
let l:command = a:command . ' 2> ' . l:stderr_tmpname |
||||
|
|
||||
|
if a:tmpname ==# '' |
||||
|
" Rustfmt in stdin/stdout mode |
||||
|
|
||||
|
" chdir to the directory of the file |
||||
|
let l:has_lcd = haslocaldir() |
||||
|
let l:prev_cd = getcwd() |
||||
|
execute 'lchdir! '.expand('%:h') |
||||
|
|
||||
|
let l:buffer = getline(1, '$') |
||||
|
if exists("*systemlist") |
||||
|
silent let out = systemlist(l:command, l:buffer) |
||||
|
else |
||||
|
silent let out = split(system(l:command, |
||||
|
\ join(l:buffer, "\n")), '\r\?\n') |
||||
|
endif |
||||
|
else |
||||
|
if exists("*systemlist") |
||||
|
silent let out = systemlist(l:command) |
||||
|
else |
||||
|
silent let out = split(system(l:command), '\r\?\n') |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
let l:stderr = readfile(l:stderr_tmpname) |
||||
|
|
||||
|
call delete(l:stderr_tmpname) |
||||
|
|
||||
|
let l:open_lwindow = 0 |
||||
|
if v:shell_error == 0 |
||||
|
if a:from_writepre |
||||
|
" remove undo point caused via BufWritePre |
||||
|
try | silent undojoin | catch | endtry |
||||
|
endif |
||||
|
|
||||
|
if a:tmpname ==# '' |
||||
|
let l:content = l:out |
||||
|
else |
||||
|
" take the tmpfile's content, this is better than rename |
||||
|
" because it preserves file modes. |
||||
|
let l:content = readfile(a:tmpname) |
||||
|
endif |
||||
|
|
||||
|
call s:DeleteLines(len(l:content), line('$')) |
||||
|
call setline(1, l:content) |
||||
|
|
||||
|
" only clear location list if it was previously filled to prevent |
||||
|
" clobbering other additions |
||||
|
if s:got_fmt_error |
||||
|
let s:got_fmt_error = 0 |
||||
|
call setloclist(0, []) |
||||
|
let l:open_lwindow = 1 |
||||
|
endif |
||||
|
elseif g:rustfmt_fail_silently == 0 && !a:from_writepre |
||||
|
" otherwise get the errors and put them in the location list |
||||
|
let l:errors = [] |
||||
|
|
||||
|
let l:prev_line = "" |
||||
|
for l:line in l:stderr |
||||
|
" error: expected one of `;` or `as`, found `extern` |
||||
|
" --> src/main.rs:2:1 |
||||
|
let tokens = matchlist(l:line, '^\s\+-->\s\(.\{-}\):\(\d\+\):\(\d\+\)$') |
||||
|
if !empty(tokens) |
||||
|
call add(l:errors, {"filename": @%, |
||||
|
\"lnum": tokens[2], |
||||
|
\"col": tokens[3], |
||||
|
\"text": l:prev_line}) |
||||
|
endif |
||||
|
let l:prev_line = l:line |
||||
|
endfor |
||||
|
|
||||
|
if !empty(l:errors) |
||||
|
call setloclist(0, l:errors, 'r') |
||||
|
echohl Error | echomsg "rustfmt returned error" | echohl None |
||||
|
else |
||||
|
echo "rust.vim: was not able to parse rustfmt messages. Here is the raw output:" |
||||
|
echo "\n" |
||||
|
for l:line in l:stderr |
||||
|
echo l:line |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
let s:got_fmt_error = 1 |
||||
|
let l:open_lwindow = 1 |
||||
|
endif |
||||
|
|
||||
|
" Restore the current directory if needed |
||||
|
if a:tmpname ==# '' |
||||
|
if l:has_lcd |
||||
|
execute 'lchdir! '.l:prev_cd |
||||
|
else |
||||
|
execute 'chdir! '.l:prev_cd |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" Open lwindow after we have changed back to the previous directory |
||||
|
if l:open_lwindow == 1 |
||||
|
lwindow |
||||
|
endif |
||||
|
|
||||
|
silent! loadview |
||||
|
endfunction |
||||
|
|
||||
|
function! rustfmt#FormatRange(line1, line2) |
||||
|
let l:tmpname = tempname() |
||||
|
call writefile(getline(1, '$'), l:tmpname) |
||||
|
let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) |
||||
|
call s:RunRustfmt(command, l:tmpname, v:false) |
||||
|
call delete(l:tmpname) |
||||
|
endfunction |
||||
|
|
||||
|
function! rustfmt#Format() |
||||
|
call s:RunRustfmt(s:RustfmtCommand(), '', v:false) |
||||
|
endfunction |
||||
|
|
||||
|
function! rustfmt#Cmd() |
||||
|
" Mainly for debugging |
||||
|
return s:RustfmtCommand() |
||||
|
endfunction |
||||
|
|
||||
|
function! rustfmt#PreWrite() |
||||
|
if !filereadable(expand("%@")) |
||||
|
return |
||||
|
endif |
||||
|
if rust#GetConfigVar('rustfmt_autosave_if_config_present', 0) |
||||
|
if findfile('rustfmt.toml', '.;') !=# '' || findfile('.rustfmt.toml', '.;') !=# '' |
||||
|
let b:rustfmt_autosave = 1 |
||||
|
let b:_rustfmt_autosave_because_of_config = 1 |
||||
|
endif |
||||
|
else |
||||
|
if has_key(b:, '_rustfmt_autosave_because_of_config') |
||||
|
unlet b:_rustfmt_autosave_because_of_config |
||||
|
unlet b:rustfmt_autosave |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if !rust#GetConfigVar("rustfmt_autosave", 0) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call s:RunRustfmt(s:RustfmtCommand(), '', v:true) |
||||
|
endfunction |
||||
|
|
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,49 @@ |
|||||
|
" Vim compiler file |
||||
|
" Compiler: Cargo Compiler |
||||
|
" Maintainer: Damien Radtke <damienradtke@gmail.com> |
||||
|
" Latest Revision: 2014 Sep 24 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
if exists('current_compiler') |
||||
|
finish |
||||
|
endif |
||||
|
runtime compiler/rustc.vim |
||||
|
let current_compiler = "cargo" |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
if exists(':CompilerSet') != 2 |
||||
|
command -nargs=* CompilerSet setlocal <args> |
||||
|
endif |
||||
|
|
||||
|
if exists('g:cargo_makeprg_params') |
||||
|
execute 'CompilerSet makeprg=cargo\ '.escape(g:cargo_makeprg_params, ' \|"').'\ $*' |
||||
|
else |
||||
|
CompilerSet makeprg=cargo\ $* |
||||
|
endif |
||||
|
|
||||
|
augroup RustCargoQuickFixHooks |
||||
|
autocmd! |
||||
|
autocmd QuickFixCmdPre make call cargo#quickfix#CmdPre() |
||||
|
autocmd QuickFixCmdPost make call cargo#quickfix#CmdPost() |
||||
|
augroup END |
||||
|
|
||||
|
" Ignore general cargo progress messages |
||||
|
CompilerSet errorformat+= |
||||
|
\%-G%\\s%#Downloading%.%#, |
||||
|
\%-G%\\s%#Compiling%.%#, |
||||
|
\%-G%\\s%#Finished%.%#, |
||||
|
\%-G%\\s%#error:\ Could\ not\ compile\ %.%#, |
||||
|
\%-G%\\s%#To\ learn\ more\\,%.%#, |
||||
|
\%-Gnote:\ Run\ with\ \`RUST_BACKTRACE=%.%#, |
||||
|
\%.%#panicked\ at\ \\'%m\\'\\,\ %f:%l:%c |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,57 @@ |
|||||
|
" Vim compiler file |
||||
|
" Compiler: Rust Compiler |
||||
|
" Maintainer: Chris Morgan <me@chrismorgan.info> |
||||
|
" Latest Revision: 2013 Jul 12 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
if exists("current_compiler") |
||||
|
finish |
||||
|
endif |
||||
|
let current_compiler = "rustc" |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
if exists(":CompilerSet") != 2 |
||||
|
command -nargs=* CompilerSet setlocal <args> |
||||
|
endif |
||||
|
|
||||
|
if get(g:, 'rustc_makeprg_no_percent', 0) |
||||
|
CompilerSet makeprg=rustc |
||||
|
else |
||||
|
if has('patch-7.4.191') |
||||
|
CompilerSet makeprg=rustc\ \%:S |
||||
|
else |
||||
|
CompilerSet makeprg=rustc\ \% |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" New errorformat (after nightly 2016/08/10) |
||||
|
CompilerSet errorformat= |
||||
|
\%-G, |
||||
|
\%-Gerror:\ aborting\ %.%#, |
||||
|
\%-Gerror:\ Could\ not\ compile\ %.%#, |
||||
|
\%Eerror:\ %m, |
||||
|
\%Eerror[E%n]:\ %m, |
||||
|
\%Wwarning:\ %m, |
||||
|
\%Inote:\ %m, |
||||
|
\%C\ %#-->\ %f:%l:%c, |
||||
|
\%E\ \ left:%m,%C\ right:%m\ %f:%l:%c,%Z |
||||
|
|
||||
|
" Old errorformat (before nightly 2016/08/10) |
||||
|
CompilerSet errorformat+= |
||||
|
\%f:%l:%c:\ %t%*[^:]:\ %m, |
||||
|
\%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m, |
||||
|
\%-G%f:%l\ %s, |
||||
|
\%-G%*[\ ]^, |
||||
|
\%-G%*[\ ]^%*[~], |
||||
|
\%-G%*[\ ]... |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,11 @@ |
|||||
|
--langdef=Rust |
||||
|
--langmap=Rust:.rs |
||||
|
--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?(static|const)[ \t]+([a-zA-Z0-9_]+)/\3/c,consts,static constants/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/ |
||||
|
--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]*<[^>]*>)?[ \t]+(([a-zA-Z0-9_:]+)[ \t]*(<[^>]*>)?[ \t]+(for)[ \t]+)?([a-zA-Z0-9_]+)/\4 \6 \7/i,impls,trait implementations/ |
||||
|
--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/ |
||||
@ -0,0 +1,475 @@ |
|||||
|
*ft_rust.txt* Filetype plugin for Rust |
||||
|
|
||||
|
============================================================================== |
||||
|
CONTENTS *rust* |
||||
|
|
||||
|
1. Introduction |rust-intro| |
||||
|
2. Settings |rust-settings| |
||||
|
3. Commands |rust-commands| |
||||
|
4. Mappings |rust-mappings| |
||||
|
|
||||
|
============================================================================== |
||||
|
INTRODUCTION *rust-intro* |
||||
|
|
||||
|
This plugin provides syntax and supporting functionality for the Rust |
||||
|
filetype. It requires Vim 8 or higher for full functionality. Some commands |
||||
|
will not work on earlier versions. |
||||
|
|
||||
|
============================================================================== |
||||
|
SETTINGS *rust-settings* |
||||
|
|
||||
|
This plugin has a few variables you can define in your vimrc that change the |
||||
|
behavior of the plugin. |
||||
|
|
||||
|
Some variables can be set buffer local (`:b` prefix), and the buffer local |
||||
|
will take precedence over the global `g:` counterpart. |
||||
|
|
||||
|
*g:rustc_path* |
||||
|
g:rustc_path~ |
||||
|
Set this option to the path to rustc for use in the |:RustRun| and |
||||
|
|:RustExpand| commands. If unset, "rustc" will be located in $PATH: > |
||||
|
let g:rustc_path = $HOME."/bin/rustc" |
||||
|
< |
||||
|
|
||||
|
*g:rustc_makeprg_no_percent* |
||||
|
g:rustc_makeprg_no_percent~ |
||||
|
Set this option to 1 to have 'makeprg' default to "rustc" instead of |
||||
|
"rustc %": > |
||||
|
let g:rustc_makeprg_no_percent = 1 |
||||
|
< |
||||
|
|
||||
|
*g:rust_conceal* |
||||
|
g:rust_conceal~ |
||||
|
Set this option to turn on the basic |conceal| support: > |
||||
|
let g:rust_conceal = 1 |
||||
|
< |
||||
|
|
||||
|
*g:rust_conceal_mod_path* |
||||
|
g:rust_conceal_mod_path~ |
||||
|
Set this option to turn on |conceal| for the path connecting token |
||||
|
"::": > |
||||
|
let g:rust_conceal_mod_path = 1 |
||||
|
< |
||||
|
|
||||
|
*g:rust_conceal_pub* |
||||
|
g:rust_conceal_pub~ |
||||
|
Set this option to turn on |conceal| for the "pub" token: > |
||||
|
let g:rust_conceal_pub = 1 |
||||
|
< |
||||
|
|
||||
|
*g:rust_recommended_style* |
||||
|
g:rust_recommended_style~ |
||||
|
Set this option to enable vim indentation and textwidth settings to |
||||
|
conform to style conventions of the rust standard library (i.e. use 4 |
||||
|
spaces for indents and sets 'textwidth' to 99). This option is enabled |
||||
|
by default. To disable it: > |
||||
|
let g:rust_recommended_style = 0 |
||||
|
< |
||||
|
|
||||
|
*g:rust_fold* |
||||
|
g:rust_fold~ |
||||
|
Set this option to turn on |folding|: > |
||||
|
let g:rust_fold = 1 |
||||
|
< |
||||
|
Value Effect ~ |
||||
|
0 No folding |
||||
|
1 Braced blocks are folded. All folds are open by |
||||
|
default. |
||||
|
2 Braced blocks are folded. 'foldlevel' is left at the |
||||
|
global value (all folds are closed by default). |
||||
|
|
||||
|
*g:rust_bang_comment_leader* |
||||
|
g:rust_bang_comment_leader~ |
||||
|
Set this option to 1 to preserve the leader on multi-line doc comments |
||||
|
using the /*! syntax: > |
||||
|
let g:rust_bang_comment_leader = 1 |
||||
|
< |
||||
|
|
||||
|
*g:rust_use_custom_ctags_defs* |
||||
|
g:rust_use_custom_ctags_defs~ |
||||
|
Set this option to 1 if you have customized ctags definitions for Rust |
||||
|
and do not wish for those included with rust.vim to be used: > |
||||
|
let g:rust_use_custom_ctags_defs = 1 |
||||
|
< |
||||
|
|
||||
|
NOTE: rust.vim's built-in definitions are only used for the Tagbar Vim |
||||
|
plugin, if you have it installed, AND if Universal Ctags is not |
||||
|
detected. This is because Universal Ctags already has built-in |
||||
|
support for Rust when used with Tagbar. |
||||
|
|
||||
|
Also, note that when using ctags other than Universal Ctags, it is not |
||||
|
automatically used when generating |tags| files that Vim can use to |
||||
|
navigate to definitions across different source files. Feel free to |
||||
|
copy `rust.vim/ctags/rust.ctags` into your own `~/.ctags` if you wish |
||||
|
to generate |tags| files. |
||||
|
|
||||
|
|
||||
|
*g:ftplugin_rust_source_path* |
||||
|
g:ftplugin_rust_source_path~ |
||||
|
Set this option to a path that should be prepended to 'path' for Rust |
||||
|
source files: > |
||||
|
let g:ftplugin_rust_source_path = $HOME.'/dev/rust' |
||||
|
< |
||||
|
|
||||
|
*g:rustfmt_command* |
||||
|
g:rustfmt_command~ |
||||
|
Set this option to the name of the 'rustfmt' executable in your $PATH. If |
||||
|
not specified it defaults to 'rustfmt' : > |
||||
|
let g:rustfmt_command = 'rustfmt' |
||||
|
< |
||||
|
*g:rustfmt_autosave* |
||||
|
g:rustfmt_autosave~ |
||||
|
Set this option to 1 to run |:RustFmt| automatically when saving a |
||||
|
buffer. If not specified it defaults to 0 : > |
||||
|
let g:rustfmt_autosave = 0 |
||||
|
< |
||||
|
There is also a buffer-local b:rustfmt_autosave that can be set for |
||||
|
the same purpose, and can override the global setting. |
||||
|
|
||||
|
*g:rustfmt_autosave_if_config_present* |
||||
|
g:rustfmt_autosave_if_config_present~ |
||||
|
Set this option to 1 to to have *b:rustfmt_autosave* be set automatically |
||||
|
if a `rustfmt.toml` file is present in any parent directly leading to |
||||
|
the file being edited. If not set, default to 0: > |
||||
|
|
||||
|
let g:rustfmt_autosave_if_config_present = 0 |
||||
|
< |
||||
|
This is useful to have `rustfmt` only execute on save, on projects |
||||
|
that have `rustfmt.toml` configuration. |
||||
|
|
||||
|
There is also a buffer-local b:rustfmt_autosave_if_config_present |
||||
|
that can be set for the same purpose, which can overrides the global |
||||
|
setting. |
||||
|
*g:rustfmt_fail_silently* |
||||
|
g:rustfmt_fail_silently~ |
||||
|
Set this option to 1 to prevent 'rustfmt' from populating the |
||||
|
|location-list| with errors. If not specified it defaults to 0: > |
||||
|
let g:rustfmt_fail_silently = 0 |
||||
|
< |
||||
|
*g:rustfmt_options* |
||||
|
g:rustfmt_options~ |
||||
|
Set this option to a string of options to pass to 'rustfmt'. The |
||||
|
write-mode is already set to 'overwrite'. If not specified it |
||||
|
defaults to '' : > |
||||
|
let g:rustfmt_options = '' |
||||
|
< |
||||
|
*g:rustfmt_emit_files* |
||||
|
g:rustfmt_emit_files~ |
||||
|
If not specified rust.vim tries to detect the right parameter to |
||||
|
pass to rustfmt based on its reported version. Otherwise, it |
||||
|
determines whether to run rustfmt with '--emit=files' (when 1 is |
||||
|
provided) instead of '--write-mode=overwrite'. > |
||||
|
let g:rustfmt_emit_files = 0 |
||||
|
|
||||
|
*g:rust_playpen_url* |
||||
|
g:rust_playpen_url~ |
||||
|
Set this option to override the url for the playpen to use: > |
||||
|
let g:rust_playpen_url = 'https://play.rust-lang.org/' |
||||
|
< |
||||
|
|
||||
|
*g:rust_shortener_url* |
||||
|
g:rust_shortener_url~ |
||||
|
Set this option to override the url for the url shortener: > |
||||
|
let g:rust_shortener_url = 'https://is.gd/' |
||||
|
< |
||||
|
|
||||
|
*g:rust_clip_command* |
||||
|
g:rust_clip_command~ |
||||
|
Set this option to the command used in your OS to copy the Rust Play |
||||
|
url to the clipboard: > |
||||
|
let g:rust_clip_command = 'xclip -selection clipboard' |
||||
|
< |
||||
|
|
||||
|
*g:cargo_makeprg_params* |
||||
|
g:cargo_makeprg_params~ |
||||
|
Set this option to the string of parameters to pass to cargo. If not |
||||
|
specified it defaults to '$*' : > |
||||
|
let g:cargo_makeprg_params = 'build' |
||||
|
< |
||||
|
|
||||
|
|
||||
|
Integration with Syntastic *rust-syntastic* |
||||
|
-------------------------- |
||||
|
|
||||
|
This plugin automatically integrates with the Syntastic checker. There are two |
||||
|
checkers provided: 'rustc', and 'cargo'. The later invokes 'Cargo' in order to |
||||
|
build code, and the former delivers a single edited '.rs' file as a compilation |
||||
|
target directly to the Rust compiler, `rustc`. |
||||
|
|
||||
|
Because Cargo is almost exclusively being used for building Rust code these |
||||
|
days, 'cargo' is the default checker. > |
||||
|
|
||||
|
let g:syntastic_rust_checkers = ['cargo'] |
||||
|
< |
||||
|
If you would like to change it, you can set `g:syntastic_rust_checkers` to a |
||||
|
different value. |
||||
|
*g:rust_cargo_avoid_whole_workspace* |
||||
|
*b:rust_cargo_avoid_whole_workspace* |
||||
|
g:rust_cargo_avoid_whole_workspace~ |
||||
|
When editing a crate that is part of a Cargo workspace, and this |
||||
|
option is set to 1 (the default), then 'cargo' will be executed |
||||
|
directly in that crate directory instead of in the workspace |
||||
|
directory. Setting 0 prevents this behavior - however be aware that if |
||||
|
you are working in large workspace, Cargo commands may take more time, |
||||
|
plus the Syntastic error list may include all the crates in the |
||||
|
workspace. > |
||||
|
let g:rust_cargo_avoid_whole_workspace = 0 |
||||
|
< |
||||
|
*g:rust_cargo_check_all_targets* |
||||
|
*b:rust_cargo_check_all_targets* |
||||
|
g:rust_cargo_check_all_targets~ |
||||
|
When set to 1, the `--all-targets` option will be passed to cargo when |
||||
|
Syntastic executes it, allowing the linting of all targets under the |
||||
|
package. |
||||
|
The default is 0. |
||||
|
|
||||
|
*g:rust_cargo_check_all_features* |
||||
|
*b:rust_cargo_check_all_features* |
||||
|
g:rust_cargo_check_all_features~ |
||||
|
When set to 1, the `--all-features` option will be passed to cargo when |
||||
|
Syntastic executes it, allowing the linting of all features of the |
||||
|
package. |
||||
|
The default is 0. |
||||
|
|
||||
|
*g:rust_cargo_check_examples* |
||||
|
*b:rust_cargo_check_examples* |
||||
|
g:rust_cargo_check_examples~ |
||||
|
When set to 1, the `--examples` option will be passed to cargo when |
||||
|
Syntastic executes it, to prevent the exclusion of examples from |
||||
|
linting. The examples are normally under the `examples/` directory of |
||||
|
the crate. |
||||
|
The default is 0. |
||||
|
|
||||
|
*g:rust_cargo_check_tests* |
||||
|
*b:rust_cargo_check_tests* |
||||
|
g:rust_cargo_check_tests~ |
||||
|
When set to 1, the `--tests` option will be passed to cargo when |
||||
|
Syntastic executes it, to prevent the exclusion of tests from linting. |
||||
|
The tests are normally under the `tests/` directory of the crate. |
||||
|
The default is 0. |
||||
|
|
||||
|
*g:rust_cargo_check_benches* |
||||
|
*b:rust_cargo_check_benches* |
||||
|
g:rust_cargo_check_benches~ |
||||
|
When set to 1, the `--benches` option will be passed to cargo when |
||||
|
Syntastic executes it. The benches are normally under the `benches/` |
||||
|
directory of the crate. |
||||
|
The default is 0. |
||||
|
|
||||
|
Integration with auto-pairs *rust-auto-pairs* |
||||
|
--------------------------- |
||||
|
|
||||
|
This plugin automatically configures the auto-pairs plugin not to duplicate |
||||
|
single quotes, which are used more often for lifetime annotations than for |
||||
|
single character literals. |
||||
|
|
||||
|
*g:rust_keep_autopairs_default* |
||||
|
g:rust_keep_autopairs_default~ |
||||
|
|
||||
|
Don't override auto-pairs default for the Rust filetype. The default |
||||
|
is 0. |
||||
|
|
||||
|
============================================================================== |
||||
|
COMMANDS *rust-commands* |
||||
|
|
||||
|
Invoking Cargo |
||||
|
-------------- |
||||
|
|
||||
|
This plug defines very simple shortcuts for invoking Cargo from with Vim. |
||||
|
|
||||
|
:Cargo <args> *:Cargo* |
||||
|
Runs 'cargo' with the provided arguments. |
||||
|
|
||||
|
:Cbuild <args> *:Cbuild* |
||||
|
Shortcut for 'cargo build`. |
||||
|
|
||||
|
:Cclean <args> *:Cclean* |
||||
|
Shortcut for 'cargo clean`. |
||||
|
|
||||
|
:Cdoc <args> *:Cdoc* |
||||
|
Shortcut for 'cargo doc`. |
||||
|
|
||||
|
:Cinit <args> *:Cinit* |
||||
|
Shortcut for 'cargo init`. |
||||
|
|
||||
|
:Crun <args> *:Crun* |
||||
|
Shortcut for 'cargo run`. |
||||
|
|
||||
|
:Ctest <args> *:Ctest* |
||||
|
Shortcut for 'cargo test`. |
||||
|
|
||||
|
:Cupdate <args> *:Cupdate* |
||||
|
Shortcut for 'cargo update`. |
||||
|
|
||||
|
:Cbench <args> *:Cbench* |
||||
|
Shortcut for 'cargo bench`. |
||||
|
|
||||
|
:Csearch <args> *:Csearch* |
||||
|
Shortcut for 'cargo search`. |
||||
|
|
||||
|
:Cpublish <args> *:Cpublish* |
||||
|
Shortcut for 'cargo publish`. |
||||
|
|
||||
|
:Cinstall <args> *:Cinstall* |
||||
|
Shortcut for 'cargo install`. |
||||
|
|
||||
|
:Cruntarget <args> *:Cruntarget* |
||||
|
Shortcut for 'cargo run --bin' or 'cargo run --example', |
||||
|
depending on the currently open buffer. |
||||
|
|
||||
|
Formatting |
||||
|
---------- |
||||
|
|
||||
|
:RustFmt *:RustFmt* |
||||
|
Runs |g:rustfmt_command| on the current buffer. If |
||||
|
|g:rustfmt_options| is set then those will be passed to the |
||||
|
executable. |
||||
|
|
||||
|
If |g:rustfmt_fail_silently| is 0 (the default) then it |
||||
|
will populate the |location-list| with the errors from |
||||
|
|g:rustfmt_command|. If |g:rustfmt_fail_silently| is set to 1 |
||||
|
then it will not populate the |location-list|. |
||||
|
|
||||
|
:RustFmtRange *:RustFmtRange* |
||||
|
Runs |g:rustfmt_command| with selected range. See |
||||
|
|:RustFmt| for any other information. |
||||
|
|
||||
|
|
||||
|
Playpen integration |
||||
|
------------------- |
||||
|
|
||||
|
:RustPlay *:RustPlay* |
||||
|
This command will only work if you have web-api.vim installed |
||||
|
(available at https://github.com/mattn/webapi-vim). It sends the |
||||
|
current selection, or if nothing is selected, the entirety of the |
||||
|
current buffer to the Rust playpen, and emits a message with the |
||||
|
shortened URL to the playpen. |
||||
|
|
||||
|
|g:rust_playpen_url| is the base URL to the playpen, by default |
||||
|
"https://play.rust-lang.org/". |
||||
|
|
||||
|
|g:rust_shortener_url| is the base url for the shorterner, by |
||||
|
default "https://is.gd/" |
||||
|
|
||||
|
|g:rust_clip_command| is the command to run to copy the |
||||
|
playpen url to the clipboard of your system. |
||||
|
|
||||
|
Evaulation of a single Rust file |
||||
|
-------------------------------- |
||||
|
|
||||
|
NOTE: These commands are useful only when working with standalone Rust files, |
||||
|
which is usually not the case for common Rust development. If you wish to |
||||
|
building Rust crates from with Vim can should use Vim's make, Syntastic, or |
||||
|
functionality from other plugins. |
||||
|
|
||||
|
|
||||
|
:RustRun [args] *:RustRun* |
||||
|
:RustRun! [rustc-args] [--] [args] |
||||
|
Compiles and runs the current file. If it has unsaved changes, |
||||
|
it will be saved first using |:update|. If the current file is |
||||
|
an unnamed buffer, it will be written to a temporary file |
||||
|
first. The compiled binary is always placed in a temporary |
||||
|
directory, but is run from the current directory. |
||||
|
|
||||
|
The arguments given to |:RustRun| will be passed to the |
||||
|
compiled binary. |
||||
|
|
||||
|
If ! is specified, the arguments are passed to rustc instead. |
||||
|
A "--" argument will separate the rustc arguments from the |
||||
|
arguments passed to the binary. |
||||
|
|
||||
|
If |g:rustc_path| is defined, it is used as the path to rustc. |
||||
|
Otherwise it is assumed rustc can be found in $PATH. |
||||
|
|
||||
|
:RustExpand [args] *:RustExpand* |
||||
|
:RustExpand! [TYPE] [args] |
||||
|
Expands the current file using --pretty and displays the |
||||
|
results in a new split. If the current file has unsaved |
||||
|
changes, it will be saved first using |:update|. If the |
||||
|
current file is an unnamed buffer, it will be written to a |
||||
|
temporary file first. |
||||
|
|
||||
|
The arguments given to |:RustExpand| will be passed to rustc. |
||||
|
This is largely intended for specifying various --cfg |
||||
|
configurations. |
||||
|
|
||||
|
If ! is specified, the first argument is the expansion type to |
||||
|
pass to rustc --pretty. Otherwise it will default to |
||||
|
"expanded". |
||||
|
|
||||
|
If |g:rustc_path| is defined, it is used as the path to rustc. |
||||
|
Otherwise it is assumed rustc can be found in $PATH. |
||||
|
|
||||
|
:RustEmitIr [args] *:RustEmitIr* |
||||
|
Compiles the current file to LLVM IR and displays the results |
||||
|
in a new split. If the current file has unsaved changes, it |
||||
|
will be saved first using |:update|. If the current file is an |
||||
|
unnamed buffer, it will be written to a temporary file first. |
||||
|
|
||||
|
The arguments given to |:RustEmitIr| will be passed to rustc. |
||||
|
|
||||
|
If |g:rustc_path| is defined, it is used as the path to rustc. |
||||
|
Otherwise it is assumed rustc can be found in $PATH. |
||||
|
|
||||
|
:RustEmitAsm [args] *:RustEmitAsm* |
||||
|
Compiles the current file to assembly and displays the results |
||||
|
in a new split. If the current file has unsaved changes, it |
||||
|
will be saved first using |:update|. If the current file is an |
||||
|
unnamed buffer, it will be written to a temporary file first. |
||||
|
|
||||
|
The arguments given to |:RustEmitAsm| will be passed to rustc. |
||||
|
|
||||
|
If |g:rustc_path| is defined, it is used as the path to rustc. |
||||
|
Otherwise it is assumed rustc can be found in $PATH. |
||||
|
|
||||
|
|
||||
|
Running test(s) |
||||
|
--------------- |
||||
|
|
||||
|
:[N]RustTest[!] [options] *:RustTest* |
||||
|
Runs a test under the cursor when the current buffer is in a |
||||
|
cargo project with "cargo test" command. If the command did |
||||
|
not find any test function under the cursor, it stops with an |
||||
|
error message. |
||||
|
|
||||
|
When N is given, adjust the size of the new window to N lines |
||||
|
or columns. |
||||
|
|
||||
|
When ! is given, runs all tests regardless of current cursor |
||||
|
position. |
||||
|
|
||||
|
When [options] is given, it is passed to "cargo" command |
||||
|
arguments. |
||||
|
|
||||
|
When the current buffer is outside cargo project, the command |
||||
|
runs "rustc --test" command instead of "cargo test" as |
||||
|
fallback. All tests are run regardless of adding ! since there |
||||
|
is no way to run specific test function with rustc. [options] |
||||
|
is passed to "rustc" command arguments in the case. |
||||
|
|
||||
|
Takes optional modifiers (see |<mods>|): > |
||||
|
:tab RustTest |
||||
|
:belowright 16RustTest |
||||
|
:leftabove vert 80RustTest |
||||
|
< |
||||
|
rust.vim Debugging |
||||
|
------------------ |
||||
|
|
||||
|
:RustInfo *:RustInfo* |
||||
|
Emits debugging info of the Vim Rust plugin. |
||||
|
|
||||
|
:RustInfoToClipboard *:RustInfoClipboard* |
||||
|
Saves debugging info of the Vim Rust plugin to the default |
||||
|
register. |
||||
|
|
||||
|
:RustInfoToFile [filename] *:RustInfoToFile* |
||||
|
Saves debugging info of the Vim Rust plugin to the the given |
||||
|
file, overwritting it. |
||||
|
|
||||
|
============================================================================== |
||||
|
MAPPINGS *rust-mappings* |
||||
|
|
||||
|
This plugin defines mappings for |[[| and |]]| to support hanging indents. |
||||
|
|
||||
|
============================================================================== |
||||
|
vim:tw=78:sw=4:noet:ts=8:ft=help:norl: |
||||
@ -0,0 +1,15 @@ |
|||||
|
" vint: -ProhibitAutocmdWithNoGroup |
||||
|
|
||||
|
autocmd BufRead,BufNewFile *.rs call s:set_rust_filetype() |
||||
|
|
||||
|
if has('patch-8.0.613') |
||||
|
autocmd BufRead,BufNewFile Cargo.toml setf FALLBACK cfg |
||||
|
endif |
||||
|
|
||||
|
function! s:set_rust_filetype() abort |
||||
|
if &filetype !=# 'rust' |
||||
|
set filetype=rust |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,200 @@ |
|||||
|
" Language: Rust |
||||
|
" Description: Vim ftplugin for Rust |
||||
|
" Maintainer: Chris Morgan <me@chrismorgan.info> |
||||
|
" Last Change: June 08, 2016 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
if exists("b:did_ftplugin") |
||||
|
finish |
||||
|
endif |
||||
|
let b:did_ftplugin = 1 |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
if get(b:, 'current_compiler', '') ==# '' |
||||
|
if strlen(findfile('Cargo.toml', '.;')) > 0 |
||||
|
compiler cargo |
||||
|
else |
||||
|
compiler rustc |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" Variables {{{1 |
||||
|
|
||||
|
" The rust source code at present seems to typically omit a leader on /*! |
||||
|
" comments, so we'll use that as our default, but make it easy to switch. |
||||
|
" This does not affect indentation at all (I tested it with and without |
||||
|
" leader), merely whether a leader is inserted by default or not. |
||||
|
if get(g:, 'rust_bang_comment_leader', 0) |
||||
|
" Why is the `,s0:/*,mb:\ ,ex:*/` there, you ask? I don't understand why, |
||||
|
" but without it, */ gets indented one space even if there were no |
||||
|
" leaders. I'm fairly sure that's a Vim bug. |
||||
|
setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,:// |
||||
|
else |
||||
|
setlocal comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// |
||||
|
endif |
||||
|
setlocal commentstring=//%s |
||||
|
setlocal formatoptions-=t formatoptions+=croqnl |
||||
|
" j was only added in 7.3.541, so stop complaints about its nonexistence |
||||
|
silent! setlocal formatoptions+=j |
||||
|
|
||||
|
" smartindent will be overridden by indentexpr if filetype indent is on, but |
||||
|
" otherwise it's better than nothing. |
||||
|
setlocal smartindent nocindent |
||||
|
|
||||
|
if get(g:, 'rust_recommended_style', 1) |
||||
|
let b:rust_set_style = 1 |
||||
|
setlocal tabstop=8 shiftwidth=4 softtabstop=4 expandtab |
||||
|
setlocal textwidth=99 |
||||
|
endif |
||||
|
|
||||
|
setlocal include=\\v^\\s*(pub\\s+)?use\\s+\\zs(\\f\|:)+ |
||||
|
setlocal includeexpr=rust#IncludeExpr(v:fname) |
||||
|
|
||||
|
setlocal suffixesadd=.rs |
||||
|
|
||||
|
if exists("g:ftplugin_rust_source_path") |
||||
|
let &l:path=g:ftplugin_rust_source_path . ',' . &l:path |
||||
|
endif |
||||
|
|
||||
|
if exists("g:loaded_delimitMate") |
||||
|
if exists("b:delimitMate_excluded_regions") |
||||
|
let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions |
||||
|
endif |
||||
|
|
||||
|
augroup rust.vim.DelimitMate |
||||
|
autocmd! |
||||
|
|
||||
|
autocmd User delimitMate_map :call rust#delimitmate#onMap() |
||||
|
autocmd User delimitMate_unmap :call rust#delimitmate#onUnmap() |
||||
|
augroup END |
||||
|
endif |
||||
|
|
||||
|
" Integration with auto-pairs (https://github.com/jiangmiao/auto-pairs) |
||||
|
if exists("g:AutoPairsLoaded") && !get(g:, 'rust_keep_autopairs_default', 0) |
||||
|
let b:AutoPairs = {'(':')', '[':']', '{':'}','"':'"', '`':'`'} |
||||
|
endif |
||||
|
|
||||
|
if has("folding") && get(g:, 'rust_fold', 0) |
||||
|
let b:rust_set_foldmethod=1 |
||||
|
setlocal foldmethod=syntax |
||||
|
if g:rust_fold == 2 |
||||
|
setlocal foldlevel< |
||||
|
else |
||||
|
setlocal foldlevel=99 |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if has('conceal') && get(g:, 'rust_conceal', 0) |
||||
|
let b:rust_set_conceallevel=1 |
||||
|
setlocal conceallevel=2 |
||||
|
endif |
||||
|
|
||||
|
" Motion Commands {{{1 |
||||
|
|
||||
|
" Bind motion commands to support hanging indents |
||||
|
nnoremap <silent> <buffer> [[ :call rust#Jump('n', 'Back')<CR> |
||||
|
nnoremap <silent> <buffer> ]] :call rust#Jump('n', 'Forward')<CR> |
||||
|
xnoremap <silent> <buffer> [[ :call rust#Jump('v', 'Back')<CR> |
||||
|
xnoremap <silent> <buffer> ]] :call rust#Jump('v', 'Forward')<CR> |
||||
|
onoremap <silent> <buffer> [[ :call rust#Jump('o', 'Back')<CR> |
||||
|
onoremap <silent> <buffer> ]] :call rust#Jump('o', 'Forward')<CR> |
||||
|
|
||||
|
" Commands {{{1 |
||||
|
|
||||
|
" See |:RustRun| for docs |
||||
|
command! -nargs=* -complete=file -bang -buffer RustRun call rust#Run(<bang>0, <q-args>) |
||||
|
|
||||
|
" See |:RustExpand| for docs |
||||
|
command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -buffer RustExpand call rust#Expand(<bang>0, <q-args>) |
||||
|
|
||||
|
" See |:RustEmitIr| for docs |
||||
|
command! -nargs=* -buffer RustEmitIr call rust#Emit("llvm-ir", <q-args>) |
||||
|
|
||||
|
" See |:RustEmitAsm| for docs |
||||
|
command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", <q-args>) |
||||
|
|
||||
|
" See |:RustPlay| for docs |
||||
|
command! -range=% RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>) |
||||
|
|
||||
|
" See |:RustFmt| for docs |
||||
|
command! -buffer RustFmt call rustfmt#Format() |
||||
|
|
||||
|
" See |:RustFmtRange| for docs |
||||
|
command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>) |
||||
|
|
||||
|
" See |:RustInfo| for docs |
||||
|
command! -bar RustInfo call rust#debugging#Info() |
||||
|
|
||||
|
" See |:RustInfoToClipboard| for docs |
||||
|
command! -bar RustInfoToClipboard call rust#debugging#InfoToClipboard() |
||||
|
|
||||
|
" See |:RustInfoToFile| for docs |
||||
|
command! -bar -nargs=1 RustInfoToFile call rust#debugging#InfoToFile(<f-args>) |
||||
|
|
||||
|
" See |:RustTest| for docs |
||||
|
command! -buffer -nargs=* -count -bang RustTest call rust#Test(<q-mods>, <count>, <bang>0, <q-args>) |
||||
|
|
||||
|
if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") |
||||
|
let b:rust_last_rustc_args = [] |
||||
|
let b:rust_last_args = [] |
||||
|
endif |
||||
|
|
||||
|
" Cleanup {{{1 |
||||
|
|
||||
|
let b:undo_ftplugin = " |
||||
|
\ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd< |
||||
|
\|if exists('b:rust_set_style') |
||||
|
\|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< |
||||
|
\|endif |
||||
|
\|if exists('b:rust_original_delimitMate_excluded_regions') |
||||
|
\|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions |
||||
|
\|unlet b:rust_original_delimitMate_excluded_regions |
||||
|
\|else |
||||
|
\|unlet! b:delimitMate_excluded_regions |
||||
|
\|endif |
||||
|
\|if exists('b:rust_set_foldmethod') |
||||
|
\|setlocal foldmethod< foldlevel< |
||||
|
\|unlet b:rust_set_foldmethod |
||||
|
\|endif |
||||
|
\|if exists('b:rust_set_conceallevel') |
||||
|
\|setlocal conceallevel< |
||||
|
\|unlet b:rust_set_conceallevel |
||||
|
\|endif |
||||
|
\|unlet! b:rust_last_rustc_args b:rust_last_args |
||||
|
\|delcommand RustRun |
||||
|
\|delcommand RustExpand |
||||
|
\|delcommand RustEmitIr |
||||
|
\|delcommand RustEmitAsm |
||||
|
\|delcommand RustPlay |
||||
|
\|nunmap <buffer> [[ |
||||
|
\|nunmap <buffer> ]] |
||||
|
\|xunmap <buffer> [[ |
||||
|
\|xunmap <buffer> ]] |
||||
|
\|ounmap <buffer> [[ |
||||
|
\|ounmap <buffer> ]] |
||||
|
\|setlocal matchpairs-=<:> |
||||
|
\|unlet b:match_skip |
||||
|
\" |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Code formatting on save |
||||
|
augroup rust.vim.PreWrite |
||||
|
autocmd! |
||||
|
autocmd BufWritePre *.rs silent! call rustfmt#PreWrite() |
||||
|
augroup END |
||||
|
|
||||
|
setlocal matchpairs+=<:> |
||||
|
" For matchit.vim (rustArrow stops `Fn() -> X` messing things up) |
||||
|
let b:match_skip = 's:comment\|string\|rustCharacter\|rustArrow' |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,40 @@ |
|||||
|
" |
||||
|
" Support for Tagbar -- https://github.com/majutsushi/tagbar |
||||
|
" |
||||
|
if !exists(':Tagbar') || rust#tags#IsUCtags() |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
if !exists('g:tagbar_type_rust') |
||||
|
let g:tagbar_type_rust = { |
||||
|
\ 'ctagstype' : 'rust', |
||||
|
\ 'kinds' : [ |
||||
|
\'T:types', |
||||
|
\'f:functions', |
||||
|
\'g:enumerations', |
||||
|
\'s:structures', |
||||
|
\'m:modules', |
||||
|
\'c:constants', |
||||
|
\'t:traits', |
||||
|
\'i:trait implementations', |
||||
|
\ ] |
||||
|
\ } |
||||
|
endif |
||||
|
|
||||
|
" In case you've updated/customized your ~/.ctags and prefer to use it. |
||||
|
if !get(g:, 'rust_use_custom_ctags_defs', 0) |
||||
|
let g:tagbar_type_rust.deffile = expand('<sfile>:p:h:h:h') . '/ctags/rust.ctags' |
||||
|
endif |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,284 @@ |
|||||
|
" Vim indent file |
||||
|
" Language: Rust |
||||
|
" Author: Chris Morgan <me@chrismorgan.info> |
||||
|
" Last Change: 2018 Jan 10 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
" Only load this indent file when no other was loaded. |
||||
|
if exists("b:did_indent") |
||||
|
finish |
||||
|
endif |
||||
|
let b:did_indent = 1 |
||||
|
|
||||
|
setlocal cindent |
||||
|
setlocal cinoptions=L0,(s,Ws,J1,j1,m1 |
||||
|
setlocal cinkeys=0{,0},!^F,o,O,0[,0],0(,0) |
||||
|
" Don't think cinwords will actually do anything at all... never mind |
||||
|
setlocal cinwords=for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern,macro |
||||
|
|
||||
|
" Some preliminary settings |
||||
|
setlocal nolisp " Make sure lisp indenting doesn't supersede us |
||||
|
setlocal autoindent " indentexpr isn't much help otherwise |
||||
|
" Also do indentkeys, otherwise # gets shoved to column 0 :-/ |
||||
|
setlocal indentkeys=0{,0},!^F,o,O,0[,0],0(,0) |
||||
|
|
||||
|
setlocal indentexpr=GetRustIndent(v:lnum) |
||||
|
|
||||
|
" Only define the function once. |
||||
|
if exists("*GetRustIndent") |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" Come here when loading the script the first time. |
||||
|
|
||||
|
function! s:get_line_trimmed(lnum) |
||||
|
" Get the line and remove a trailing comment. |
||||
|
" Use syntax highlighting attributes when possible. |
||||
|
" NOTE: this is not accurate; /* */ or a line continuation could trick it |
||||
|
let line = getline(a:lnum) |
||||
|
let line_len = strlen(line) |
||||
|
if has('syntax_items') |
||||
|
" If the last character in the line is a comment, do a binary search for |
||||
|
" the start of the comment. synID() is slow, a linear search would take |
||||
|
" too long on a long line. |
||||
|
if synIDattr(synID(a:lnum, line_len, 1), "name") =~? 'Comment\|Todo' |
||||
|
let min = 1 |
||||
|
let max = line_len |
||||
|
while min < max |
||||
|
let col = (min + max) / 2 |
||||
|
if synIDattr(synID(a:lnum, col, 1), "name") =~? 'Comment\|Todo' |
||||
|
let max = col |
||||
|
else |
||||
|
let min = col + 1 |
||||
|
endif |
||||
|
endwhile |
||||
|
let line = strpart(line, 0, min - 1) |
||||
|
endif |
||||
|
return substitute(line, "\s*$", "", "") |
||||
|
else |
||||
|
" Sorry, this is not complete, nor fully correct (e.g. string "//"). |
||||
|
" Such is life. |
||||
|
return substitute(line, "\s*//.*$", "", "") |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
function! s:is_string_comment(lnum, col) |
||||
|
if has('syntax_items') |
||||
|
for id in synstack(a:lnum, a:col) |
||||
|
let synname = synIDattr(id, "name") |
||||
|
if synname ==# "rustString" || synname =~# "^rustComment" |
||||
|
return 1 |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
" without syntax, let's not even try |
||||
|
return 0 |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
if exists('*shiftwidth') |
||||
|
function! s:shiftwidth() |
||||
|
return shiftwidth() |
||||
|
endfunc |
||||
|
else |
||||
|
function! s:shiftwidth() |
||||
|
return &shiftwidth |
||||
|
endfunc |
||||
|
endif |
||||
|
|
||||
|
function GetRustIndent(lnum) |
||||
|
" Starting assumption: cindent (called at the end) will do it right |
||||
|
" normally. We just want to fix up a few cases. |
||||
|
|
||||
|
let line = getline(a:lnum) |
||||
|
|
||||
|
if has('syntax_items') |
||||
|
let synname = synIDattr(synID(a:lnum, 1, 1), "name") |
||||
|
if synname ==# "rustString" |
||||
|
" If the start of the line is in a string, don't change the indent |
||||
|
return -1 |
||||
|
elseif synname =~? '\(Comment\|Todo\)' |
||||
|
\ && line !~# '^\s*/\*' " not /* opening line |
||||
|
if synname =~? "CommentML" " multi-line |
||||
|
if line !~# '^\s*\*' && getline(a:lnum - 1) =~# '^\s*/\*' |
||||
|
" This is (hopefully) the line after a /*, and it has no |
||||
|
" leader, so the correct indentation is that of the |
||||
|
" previous line. |
||||
|
return GetRustIndent(a:lnum - 1) |
||||
|
endif |
||||
|
endif |
||||
|
" If it's in a comment, let cindent take care of it now. This is |
||||
|
" for cases like "/*" where the next line should start " * ", not |
||||
|
" "* " as the code below would otherwise cause for module scope |
||||
|
" Fun fact: " /*\n*\n*/" takes two calls to get right! |
||||
|
return cindent(a:lnum) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" cindent gets second and subsequent match patterns/struct members wrong, |
||||
|
" as it treats the comma as indicating an unfinished statement:: |
||||
|
" |
||||
|
" match a { |
||||
|
" b => c, |
||||
|
" d => e, |
||||
|
" f => g, |
||||
|
" }; |
||||
|
|
||||
|
" Search backwards for the previous non-empty line. |
||||
|
let prevlinenum = prevnonblank(a:lnum - 1) |
||||
|
let prevline = s:get_line_trimmed(prevlinenum) |
||||
|
while prevlinenum > 1 && prevline !~# '[^[:blank:]]' |
||||
|
let prevlinenum = prevnonblank(prevlinenum - 1) |
||||
|
let prevline = s:get_line_trimmed(prevlinenum) |
||||
|
endwhile |
||||
|
|
||||
|
" A standalone '{', '}', or 'where' |
||||
|
let l:standalone_open = line =~# '\V\^\s\*{\s\*\$' |
||||
|
let l:standalone_close = line =~# '\V\^\s\*}\s\*\$' |
||||
|
let l:standalone_where = line =~# '\V\^\s\*where\s\*\$' |
||||
|
if l:standalone_open || l:standalone_close || l:standalone_where |
||||
|
" ToDo: we can search for more items than 'fn' and 'if'. |
||||
|
let [l:found_line, l:col, l:submatch] = |
||||
|
\ searchpos('\<\(fn\)\|\(if\)\>', 'bnWp') |
||||
|
if l:found_line !=# 0 |
||||
|
" Now we count the number of '{' and '}' in between the match |
||||
|
" locations and the current line (there is probably a better |
||||
|
" way to compute this). |
||||
|
let l:i = l:found_line |
||||
|
let l:search_line = strpart(getline(l:i), l:col - 1) |
||||
|
let l:opens = 0 |
||||
|
let l:closes = 0 |
||||
|
while l:i < a:lnum |
||||
|
let l:search_line2 = substitute(l:search_line, '\V{', '', 'g') |
||||
|
let l:opens += strlen(l:search_line) - strlen(l:search_line2) |
||||
|
let l:search_line3 = substitute(l:search_line2, '\V}', '', 'g') |
||||
|
let l:closes += strlen(l:search_line2) - strlen(l:search_line3) |
||||
|
let l:i += 1 |
||||
|
let l:search_line = getline(l:i) |
||||
|
endwhile |
||||
|
if l:standalone_open || l:standalone_where |
||||
|
if l:opens ==# l:closes |
||||
|
return indent(l:found_line) |
||||
|
endif |
||||
|
else |
||||
|
" Expect to find just one more close than an open |
||||
|
if l:opens ==# l:closes + 1 |
||||
|
return indent(l:found_line) |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" A standalone 'where' adds a shift. |
||||
|
let l:standalone_prevline_where = prevline =~# '\V\^\s\*where\s\*\$' |
||||
|
if l:standalone_prevline_where |
||||
|
return indent(prevlinenum) + 4 |
||||
|
endif |
||||
|
|
||||
|
" Handle where clauses nicely: subsequent values should line up nicely. |
||||
|
if prevline[len(prevline) - 1] ==# "," |
||||
|
\ && prevline =~# '^\s*where\s' |
||||
|
return indent(prevlinenum) + 6 |
||||
|
endif |
||||
|
|
||||
|
let l:last_prevline_character = prevline[len(prevline) - 1] |
||||
|
|
||||
|
" A line that ends with '.<expr>;' is probably an end of a long list |
||||
|
" of method operations. |
||||
|
if prevline =~# '\V\^\s\*.' && l:last_prevline_character ==# ';' |
||||
|
call cursor(a:lnum - 1, 1) |
||||
|
let l:scope_start = searchpair('{\|(', '', '}\|)', 'nbW', |
||||
|
\ 's:is_string_comment(line("."), col("."))') |
||||
|
if l:scope_start != 0 && l:scope_start < a:lnum |
||||
|
return indent(l:scope_start) + 4 |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if l:last_prevline_character ==# "," |
||||
|
\ && s:get_line_trimmed(a:lnum) !~# '^\s*[\[\]{})]' |
||||
|
\ && prevline !~# '^\s*fn\s' |
||||
|
\ && prevline !~# '([^()]\+,$' |
||||
|
\ && s:get_line_trimmed(a:lnum) !~# '^\s*\S\+\s*=>' |
||||
|
" Oh ho! The previous line ended in a comma! I bet cindent will try to |
||||
|
" take this too far... For now, let's normally use the previous line's |
||||
|
" indent. |
||||
|
|
||||
|
" One case where this doesn't work out is where *this* line contains |
||||
|
" square or curly brackets; then we normally *do* want to be indenting |
||||
|
" further. |
||||
|
" |
||||
|
" Another case where we don't want to is one like a function |
||||
|
" definition with arguments spread over multiple lines: |
||||
|
" |
||||
|
" fn foo(baz: Baz, |
||||
|
" baz: Baz) // <-- cindent gets this right by itself |
||||
|
" |
||||
|
" Another case is similar to the previous, except calling a function |
||||
|
" instead of defining it, or any conditional expression that leaves |
||||
|
" an open paren: |
||||
|
" |
||||
|
" foo(baz, |
||||
|
" baz); |
||||
|
" |
||||
|
" if baz && (foo || |
||||
|
" bar) { |
||||
|
" |
||||
|
" Another case is when the current line is a new match arm. |
||||
|
" |
||||
|
" There are probably other cases where we don't want to do this as |
||||
|
" well. Add them as needed. |
||||
|
return indent(prevlinenum) |
||||
|
endif |
||||
|
|
||||
|
if !has("patch-7.4.355") |
||||
|
" cindent before 7.4.355 doesn't do the module scope well at all; e.g.:: |
||||
|
" |
||||
|
" static FOO : &'static [bool] = [ |
||||
|
" true, |
||||
|
" false, |
||||
|
" false, |
||||
|
" true, |
||||
|
" ]; |
||||
|
" |
||||
|
" uh oh, next statement is indented further! |
||||
|
|
||||
|
" Note that this does *not* apply the line continuation pattern properly; |
||||
|
" that's too hard to do correctly for my liking at present, so I'll just |
||||
|
" start with these two main cases (square brackets and not returning to |
||||
|
" column zero) |
||||
|
|
||||
|
call cursor(a:lnum, 1) |
||||
|
if searchpair('{\|(', '', '}\|)', 'nbW', |
||||
|
\ 's:is_string_comment(line("."), col("."))') == 0 |
||||
|
if searchpair('\[', '', '\]', 'nbW', |
||||
|
\ 's:is_string_comment(line("."), col("."))') == 0 |
||||
|
" Global scope, should be zero |
||||
|
return 0 |
||||
|
else |
||||
|
" At the module scope, inside square brackets only |
||||
|
"if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum |
||||
|
if line =~# "^\\s*]" |
||||
|
" It's the closing line, dedent it |
||||
|
return 0 |
||||
|
else |
||||
|
return &shiftwidth |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" Fall back on cindent, which does it mostly right |
||||
|
return cindent(a:lnum) |
||||
|
endfunction |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,26 @@ |
|||||
|
if exists('g:loaded_rust_vim_plugin_cargo') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_rust_vim_plugin_cargo = 1 |
||||
|
let s:save_cpo = &cpoptions |
||||
|
set cpoptions&vim |
||||
|
|
||||
|
command! -nargs=+ Cargo call cargo#cmd(<q-args>) |
||||
|
command! -nargs=* Cbuild call cargo#build(<q-args>) |
||||
|
command! -nargs=* Cclean call cargo#clean(<q-args>) |
||||
|
command! -nargs=* Cdoc call cargo#doc(<q-args>) |
||||
|
command! -nargs=+ Cnew call cargo#new(<q-args>) |
||||
|
command! -nargs=* Cinit call cargo#init(<q-args>) |
||||
|
command! -nargs=* Crun call cargo#run(<q-args>) |
||||
|
command! -nargs=* Ctest call cargo#test(<q-args>) |
||||
|
command! -nargs=* Cbench call cargo#bench(<q-args>) |
||||
|
command! -nargs=* Cupdate call cargo#update(<q-args>) |
||||
|
command! -nargs=* Csearch call cargo#search(<q-args>) |
||||
|
command! -nargs=* Cpublish call cargo#publish(<q-args>) |
||||
|
command! -nargs=* Cinstall call cargo#install(<q-args>) |
||||
|
command! -nargs=* Cruntarget call cargo#runtarget(<q-args>) |
||||
|
|
||||
|
let &cpoptions = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,28 @@ |
|||||
|
" Vim syntastic plugin helper |
||||
|
" Language: Rust |
||||
|
" Maintainer: Andrew Gallant <jamslam@gmail.com> |
||||
|
|
||||
|
if exists('g:loaded_rust_vim') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_rust_vim = 1 |
||||
|
let s:save_cpo = &cpoptions |
||||
|
set cpoptions&vim |
||||
|
|
||||
|
" This is to let Syntastic know about the Rust filetype. |
||||
|
" It enables tab completion for the 'SyntasticInfo' command. |
||||
|
" (This does not actually register the syntax checker.) |
||||
|
if exists('g:syntastic_extra_filetypes') |
||||
|
call add(g:syntastic_extra_filetypes, 'rust') |
||||
|
else |
||||
|
let g:syntastic_extra_filetypes = ['rust'] |
||||
|
endif |
||||
|
|
||||
|
if !exists('g:syntastic_rust_checkers') |
||||
|
let g:syntastic_rust_checkers = ['cargo'] |
||||
|
endif |
||||
|
|
||||
|
let &cpoptions = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,363 @@ |
|||||
|
" Vim syntax file |
||||
|
" Language: Rust |
||||
|
" Maintainer: Patrick Walton <pcwalton@mozilla.com> |
||||
|
" Maintainer: Ben Blum <bblum@cs.cmu.edu> |
||||
|
" Maintainer: Chris Morgan <me@chrismorgan.info> |
||||
|
" Last Change: Feb 24, 2016 |
||||
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim |
||||
|
|
||||
|
if version < 600 |
||||
|
syntax clear |
||||
|
elseif exists("b:current_syntax") |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
" Syntax definitions {{{1 |
||||
|
" Basic keywords {{{2 |
||||
|
syn keyword rustConditional match if else |
||||
|
syn keyword rustRepeat loop while |
||||
|
" `:syn match` must be used to prioritize highlighting `for` keyword. |
||||
|
syn match rustRepeat /\<for\>/ |
||||
|
" Highlight `for` keyword in `impl ... for ... {}` statement. This line must |
||||
|
" be put after previous `syn match` line to overwrite it. |
||||
|
syn match rustKeyword /\%(\<impl\>.\+\)\@<=\<for\>/ |
||||
|
syn keyword rustRepeat in |
||||
|
syn keyword rustTypedef type nextgroup=rustIdentifier skipwhite skipempty |
||||
|
syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipempty |
||||
|
syn keyword rustUnion union nextgroup=rustIdentifier skipwhite skipempty contained |
||||
|
syn match rustUnionContextual /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion |
||||
|
syn keyword rustOperator as |
||||
|
syn keyword rustExistential existential nextgroup=rustTypedef skipwhite skipempty contained |
||||
|
syn match rustExistentialContextual /\<existential\_s\+type/ transparent contains=rustExistential,rustTypedef |
||||
|
|
||||
|
syn match rustAssert "\<assert\(\w\)*!" contained |
||||
|
syn match rustPanic "\<panic\(\w\)*!" contained |
||||
|
syn match rustAsync "\<async\%(\s\|\n\)\@=" |
||||
|
syn keyword rustKeyword break |
||||
|
syn keyword rustKeyword box |
||||
|
syn keyword rustKeyword continue |
||||
|
syn keyword rustKeyword crate |
||||
|
syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty |
||||
|
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty |
||||
|
syn keyword rustKeyword impl let |
||||
|
syn keyword rustKeyword macro |
||||
|
syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty |
||||
|
syn keyword rustKeyword return |
||||
|
syn keyword rustKeyword yield |
||||
|
syn keyword rustSuper super |
||||
|
syn keyword rustKeyword where |
||||
|
syn keyword rustUnsafeKeyword unsafe |
||||
|
syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty |
||||
|
" FIXME: Scoped impl's name is also fallen in this category |
||||
|
syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty |
||||
|
syn keyword rustStorage move mut ref static const |
||||
|
syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/ |
||||
|
syn keyword rustAwait await |
||||
|
syn match rustKeyword /\<try\>!\@!/ display |
||||
|
|
||||
|
syn keyword rustPubScopeCrate crate contained |
||||
|
syn match rustPubScopeDelim /[()]/ contained |
||||
|
syn match rustPubScope /([^()]*)/ contained contains=rustPubScopeDelim,rustPubScopeCrate,rustSuper,rustModPath,rustModPathSep,rustSelf transparent |
||||
|
|
||||
|
syn keyword rustExternCrate crate contained nextgroup=rustIdentifier,rustExternCrateString skipwhite skipempty |
||||
|
" This is to get the `bar` part of `extern crate "foo" as bar;` highlighting. |
||||
|
syn match rustExternCrateString /".*"\_s*as/ contained nextgroup=rustIdentifier skipwhite transparent skipempty contains=rustString,rustOperator |
||||
|
syn keyword rustObsoleteExternMod mod contained nextgroup=rustIdentifier skipwhite skipempty |
||||
|
|
||||
|
syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained |
||||
|
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained |
||||
|
|
||||
|
syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end=")" contains=TOP nextgroup=rustMacroRepeatCount |
||||
|
syn match rustMacroRepeatCount ".\?[*+]" contained |
||||
|
syn match rustMacroVariable "$\w\+" |
||||
|
|
||||
|
" Reserved (but not yet used) keywords {{{2 |
||||
|
syn keyword rustReservedKeyword become do priv typeof unsized abstract virtual final override |
||||
|
|
||||
|
" Built-in types {{{2 |
||||
|
syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32 |
||||
|
syn keyword rustType f64 i8 i16 i32 i64 i128 str Self |
||||
|
|
||||
|
" Things from the libstd v1 prelude (src/libstd/prelude/v1.rs) {{{2 |
||||
|
" This section is just straight transformation of the contents of the prelude, |
||||
|
" to make it easy to update. |
||||
|
|
||||
|
" Reexported core operators {{{3 |
||||
|
syn keyword rustTrait Copy Send Sized Sync |
||||
|
syn keyword rustTrait Drop Fn FnMut FnOnce |
||||
|
|
||||
|
" Reexported functions {{{3 |
||||
|
" There’s no point in highlighting these; when one writes drop( or drop::< it |
||||
|
" gets the same highlighting anyway, and if someone writes `let drop = …;` we |
||||
|
" don’t really want *that* drop to be highlighted. |
||||
|
"syn keyword rustFunction drop |
||||
|
|
||||
|
" Reexported types and traits {{{3 |
||||
|
syn keyword rustTrait Box |
||||
|
syn keyword rustTrait ToOwned |
||||
|
syn keyword rustTrait Clone |
||||
|
syn keyword rustTrait PartialEq PartialOrd Eq Ord |
||||
|
syn keyword rustTrait AsRef AsMut Into From |
||||
|
syn keyword rustTrait Default |
||||
|
syn keyword rustTrait Iterator Extend IntoIterator |
||||
|
syn keyword rustTrait DoubleEndedIterator ExactSizeIterator |
||||
|
syn keyword rustEnum Option |
||||
|
syn keyword rustEnumVariant Some None |
||||
|
syn keyword rustEnum Result |
||||
|
syn keyword rustEnumVariant Ok Err |
||||
|
syn keyword rustTrait SliceConcatExt |
||||
|
syn keyword rustTrait String ToString |
||||
|
syn keyword rustTrait Vec |
||||
|
|
||||
|
" Other syntax {{{2 |
||||
|
syn keyword rustSelf self |
||||
|
syn keyword rustBoolean true false |
||||
|
|
||||
|
" If foo::bar changes to foo.bar, change this ("::" to "\."). |
||||
|
" If foo::bar changes to Foo::bar, change this (first "\w" to "\u"). |
||||
|
syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3 |
||||
|
syn match rustModPathSep "::" |
||||
|
|
||||
|
syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1 |
||||
|
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>(); |
||||
|
|
||||
|
" This is merely a convention; note also the use of [A-Z], restricting it to |
||||
|
" latin identifiers rather than the full Unicode uppercase. I have not used |
||||
|
" [:upper:] as it depends upon 'noignorecase' |
||||
|
"syn match rustCapsIdent display "[A-Z]\w\(\w\)*" |
||||
|
|
||||
|
syn match rustOperator display "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?" |
||||
|
" This one isn't *quite* right, as we could have binary-& with a reference |
||||
|
syn match rustSigil display /&\s\+[&~@*][^)= \t\r\n]/he=e-1,me=e-1 |
||||
|
syn match rustSigil display /[&~@*][^)= \t\r\n]/he=e-1,me=e-1 |
||||
|
" This isn't actually correct; a closure with no arguments can be `|| { }`. |
||||
|
" Last, because the & in && isn't a sigil |
||||
|
syn match rustOperator display "&&\|||" |
||||
|
" This is rustArrowCharacter rather than rustArrow for the sake of matchparen, |
||||
|
" so it skips the ->; see http://stackoverflow.com/a/30309949 for details. |
||||
|
syn match rustArrowCharacter display "->" |
||||
|
syn match rustQuestionMark display "?\([a-zA-Z]\+\)\@!" |
||||
|
|
||||
|
syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustPanic |
||||
|
syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustPanic |
||||
|
|
||||
|
syn match rustEscapeError display contained /\\./ |
||||
|
syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ |
||||
|
syn match rustEscapeUnicode display contained /\\u{\%(\x_*\)\{1,6}}/ |
||||
|
syn match rustStringContinuation display contained /\\\n\s*/ |
||||
|
syn region rustString matchgroup=rustStringDelimiter start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation |
||||
|
syn region rustString matchgroup=rustStringDelimiter start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell |
||||
|
syn region rustString matchgroup=rustStringDelimiter start='b\?r\z(#*\)"' end='"\z1' contains=@Spell |
||||
|
|
||||
|
" Match attributes with either arbitrary syntax or special highlighting for |
||||
|
" derives. We still highlight strings and comments inside of the attribute. |
||||
|
syn region rustAttribute start="#!\?\[" end="\]" contains=@rustAttributeContents,rustAttributeParenthesizedParens,rustAttributeParenthesizedCurly,rustAttributeParenthesizedBrackets,rustDerive |
||||
|
syn region rustAttributeParenthesizedParens matchgroup=rustAttribute start="\w\%(\w\)*("rs=e end=")"re=s transparent contained contains=rustAttributeBalancedParens,@rustAttributeContents |
||||
|
syn region rustAttributeParenthesizedCurly matchgroup=rustAttribute start="\w\%(\w\)*{"rs=e end="}"re=s transparent contained contains=rustAttributeBalancedCurly,@rustAttributeContents |
||||
|
syn region rustAttributeParenthesizedBrackets matchgroup=rustAttribute start="\w\%(\w\)*\["rs=e end="\]"re=s transparent contained contains=rustAttributeBalancedBrackets,@rustAttributeContents |
||||
|
syn region rustAttributeBalancedParens matchgroup=rustAttribute start="("rs=e end=")"re=s transparent contained contains=rustAttributeBalancedParens,@rustAttributeContents |
||||
|
syn region rustAttributeBalancedCurly matchgroup=rustAttribute start="{"rs=e end="}"re=s transparent contained contains=rustAttributeBalancedCurly,@rustAttributeContents |
||||
|
syn region rustAttributeBalancedBrackets matchgroup=rustAttribute start="\["rs=e end="\]"re=s transparent contained contains=rustAttributeBalancedBrackets,@rustAttributeContents |
||||
|
syn cluster rustAttributeContents contains=rustString,rustCommentLine,rustCommentBlock,rustCommentLineDocError,rustCommentBlockDocError |
||||
|
syn region rustDerive start="derive(" end=")" contained contains=rustDeriveTrait |
||||
|
" This list comes from src/libsyntax/ext/deriving/mod.rs |
||||
|
" Some are deprecated (Encodable, Decodable) or to be removed after a new snapshot (Show). |
||||
|
syn keyword rustDeriveTrait contained Clone Hash RustcEncodable RustcDecodable Encodable Decodable PartialEq Eq PartialOrd Ord Rand Show Debug Default FromPrimitive Send Sync Copy |
||||
|
|
||||
|
" dyn keyword: It's only a keyword when used inside a type expression, so |
||||
|
" we make effort here to highlight it only when Rust identifiers follow it |
||||
|
" (not minding the case of pre-2018 Rust where a path starting with :: can |
||||
|
" follow). |
||||
|
" |
||||
|
" This is so that uses of dyn variable names such as in 'let &dyn = &2' |
||||
|
" and 'let dyn = 2' will not get highlighted as a keyword. |
||||
|
syn match rustKeyword "\<dyn\ze\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)" contains=rustDynKeyword |
||||
|
syn keyword rustDynKeyword dyn contained |
||||
|
|
||||
|
" Number literals |
||||
|
syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" |
||||
|
syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" |
||||
|
syn match rustOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" |
||||
|
syn match rustBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" |
||||
|
|
||||
|
" Special case for numbers of the form "1." which are float literals, unless followed by |
||||
|
" an identifier, which makes them integer literals with a method call or field access, |
||||
|
" or by another ".", which makes them integer literals followed by the ".." token. |
||||
|
" (This must go first so the others take precedence.) |
||||
|
syn match rustFloat display "\<[0-9][0-9_]*\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\|\.\)\@!" |
||||
|
" To mark a number as a normal float, it must have at least one of the three things integral values don't have: |
||||
|
" a decimal point and more numbers; an exponent; and a type suffix. |
||||
|
syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)\=" |
||||
|
syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\(f32\|f64\)\=" |
||||
|
syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)" |
||||
|
|
||||
|
" For the benefit of delimitMate |
||||
|
syn region rustLifetimeCandidate display start=/&'\%(\([^'\\]\|\\\(['nrt0\\\"]\|x\x\{2}\|u{\%(\x_*\)\{1,6}}\)\)'\)\@!/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime |
||||
|
syn region rustGenericRegion display start=/<\%('\|[^[:cntrl:][:space:][:punct:]]\)\@=')\S\@=/ end=/>/ contains=rustGenericLifetimeCandidate |
||||
|
syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime |
||||
|
|
||||
|
"rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting |
||||
|
syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" |
||||
|
syn match rustLabel display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*:" |
||||
|
syn match rustLabel display "\%(\<\%(break\|continue\)\s*\)\@<=\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" |
||||
|
syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/ |
||||
|
" The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII). |
||||
|
syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/ |
||||
|
syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode |
||||
|
syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u{\%(\x_*\)\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid |
||||
|
|
||||
|
syn match rustShebang /\%^#![^[].*/ |
||||
|
syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell |
||||
|
syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell |
||||
|
syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained |
||||
|
syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell |
||||
|
syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,rustCommentBlockDocRustCode,@Spell |
||||
|
syn region rustCommentBlockDocError matchgroup=rustCommentBlockDocError start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained |
||||
|
syn region rustCommentBlockNest matchgroup=rustCommentBlock start="/\*" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell contained transparent |
||||
|
syn region rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell contained transparent |
||||
|
syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained transparent |
||||
|
|
||||
|
" FIXME: this is a really ugly and not fully correct implementation. Most |
||||
|
" importantly, a case like ``/* */*`` should have the final ``*`` not being in |
||||
|
" a comment, but in practice at present it leaves comments open two levels |
||||
|
" deep. But as long as you stay away from that particular case, I *believe* |
||||
|
" the highlighting is correct. Due to the way Vim's syntax engine works |
||||
|
" (greedy for start matches, unlike Rust's tokeniser which is searching for |
||||
|
" the earliest-starting match, start or end), I believe this cannot be solved. |
||||
|
" Oh you who would fix it, don't bother with things like duplicating the Block |
||||
|
" rules and putting ``\*\@<!`` at the start of them; it makes it worse, as |
||||
|
" then you must deal with cases like ``/*/**/*/``. And don't try making it |
||||
|
" worse with ``\%(/\@<!\*\)\@<!``, either... |
||||
|
|
||||
|
syn keyword rustTodo contained TODO FIXME XXX NB NOTE |
||||
|
|
||||
|
" Folding rules {{{2 |
||||
|
" Trivial folding rules to begin with. |
||||
|
" FIXME: use the AST to make really good folding |
||||
|
syn region rustFoldBraces start="{" end="}" transparent fold |
||||
|
|
||||
|
if !exists("b:current_syntax_embed") |
||||
|
let b:current_syntax_embed = 1 |
||||
|
syntax include @RustCodeInComment <sfile>:p:h/rust.vim |
||||
|
unlet b:current_syntax_embed |
||||
|
|
||||
|
" Currently regions marked as ```<some-other-syntax> will not get |
||||
|
" highlighted at all. In the future, we can do as vim-markdown does and |
||||
|
" highlight with the other syntax. But for now, let's make sure we find |
||||
|
" the closing block marker, because the rules below won't catch it. |
||||
|
syn region rustCommentLinesDocNonRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\).\+$' end='^\z1$' keepend contains=rustCommentLineDoc |
||||
|
|
||||
|
" We borrow the rules from rust’s src/librustdoc/html/markdown.rs, so that |
||||
|
" we only highlight as Rust what it would perceive as Rust (almost; it’s |
||||
|
" possible to trick it if you try hard, and indented code blocks aren’t |
||||
|
" supported because Markdown is a menace to parse and only mad dogs and |
||||
|
" Englishmen would try to handle that case correctly in this syntax file). |
||||
|
syn region rustCommentLinesDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentLineDocLeader |
||||
|
syn region rustCommentBlockDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\%(\s*\*\)\?\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentBlockDocStar |
||||
|
" Strictly, this may or may not be correct; this code, for example, would |
||||
|
" mishighlight: |
||||
|
" |
||||
|
" /** |
||||
|
" ```rust |
||||
|
" println!("{}", 1 |
||||
|
" * 1); |
||||
|
" ``` |
||||
|
" */ |
||||
|
" |
||||
|
" … but I don’t care. Balance of probability, and all that. |
||||
|
syn match rustCommentBlockDocStar /^\s*\*\s\?/ contained |
||||
|
syn match rustCommentLineDocLeader "^\s*//\%(//\@!\|!\)" contained |
||||
|
endif |
||||
|
|
||||
|
" Default highlighting {{{1 |
||||
|
hi def link rustDecNumber rustNumber |
||||
|
hi def link rustHexNumber rustNumber |
||||
|
hi def link rustOctNumber rustNumber |
||||
|
hi def link rustBinNumber rustNumber |
||||
|
hi def link rustIdentifierPrime rustIdentifier |
||||
|
hi def link rustTrait rustType |
||||
|
hi def link rustDeriveTrait rustTrait |
||||
|
|
||||
|
hi def link rustMacroRepeatCount rustMacroRepeatDelimiters |
||||
|
hi def link rustMacroRepeatDelimiters Macro |
||||
|
hi def link rustMacroVariable Define |
||||
|
hi def link rustSigil StorageClass |
||||
|
hi def link rustEscape Special |
||||
|
hi def link rustEscapeUnicode rustEscape |
||||
|
hi def link rustEscapeError Error |
||||
|
hi def link rustStringContinuation Special |
||||
|
hi def link rustString String |
||||
|
hi def link rustStringDelimiter String |
||||
|
hi def link rustCharacterInvalid Error |
||||
|
hi def link rustCharacterInvalidUnicode rustCharacterInvalid |
||||
|
hi def link rustCharacter Character |
||||
|
hi def link rustNumber Number |
||||
|
hi def link rustBoolean Boolean |
||||
|
hi def link rustEnum rustType |
||||
|
hi def link rustEnumVariant rustConstant |
||||
|
hi def link rustConstant Constant |
||||
|
hi def link rustSelf Constant |
||||
|
hi def link rustFloat Float |
||||
|
hi def link rustArrowCharacter rustOperator |
||||
|
hi def link rustOperator Operator |
||||
|
hi def link rustKeyword Keyword |
||||
|
hi def link rustDynKeyword rustKeyword |
||||
|
hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust |
||||
|
hi def link rustStructure Keyword " More precise is Structure |
||||
|
hi def link rustUnion rustStructure |
||||
|
hi def link rustExistential rustKeyword |
||||
|
hi def link rustPubScopeDelim Delimiter |
||||
|
hi def link rustPubScopeCrate rustKeyword |
||||
|
hi def link rustSuper rustKeyword |
||||
|
hi def link rustUnsafeKeyword Exception |
||||
|
hi def link rustReservedKeyword Error |
||||
|
hi def link rustRepeat Conditional |
||||
|
hi def link rustConditional Conditional |
||||
|
hi def link rustIdentifier Identifier |
||||
|
hi def link rustCapsIdent rustIdentifier |
||||
|
hi def link rustModPath Include |
||||
|
hi def link rustModPathSep Delimiter |
||||
|
hi def link rustFunction Function |
||||
|
hi def link rustFuncName Function |
||||
|
hi def link rustFuncCall Function |
||||
|
hi def link rustShebang Comment |
||||
|
hi def link rustCommentLine Comment |
||||
|
hi def link rustCommentLineDoc SpecialComment |
||||
|
hi def link rustCommentLineDocLeader rustCommentLineDoc |
||||
|
hi def link rustCommentLineDocError Error |
||||
|
hi def link rustCommentBlock rustCommentLine |
||||
|
hi def link rustCommentBlockDoc rustCommentLineDoc |
||||
|
hi def link rustCommentBlockDocStar rustCommentBlockDoc |
||||
|
hi def link rustCommentBlockDocError Error |
||||
|
hi def link rustCommentDocCodeFence rustCommentLineDoc |
||||
|
hi def link rustAssert PreCondit |
||||
|
hi def link rustPanic PreCondit |
||||
|
hi def link rustMacro Macro |
||||
|
hi def link rustType Type |
||||
|
hi def link rustTodo Todo |
||||
|
hi def link rustAttribute PreProc |
||||
|
hi def link rustDerive PreProc |
||||
|
hi def link rustDefault StorageClass |
||||
|
hi def link rustStorage StorageClass |
||||
|
hi def link rustObsoleteStorage Error |
||||
|
hi def link rustLifetime Special |
||||
|
hi def link rustLabel Label |
||||
|
hi def link rustExternCrate rustKeyword |
||||
|
hi def link rustObsoleteExternMod Error |
||||
|
hi def link rustQuestionMark Special |
||||
|
hi def link rustAsync rustKeyword |
||||
|
hi def link rustAwait rustKeyword |
||||
|
|
||||
|
" Other Suggestions: |
||||
|
" hi rustAttribute ctermfg=cyan |
||||
|
" hi rustDerive ctermfg=cyan |
||||
|
" hi rustAssert ctermfg=yellow |
||||
|
" hi rustPanic ctermfg=red |
||||
|
" hi rustMacro ctermfg=magenta |
||||
|
|
||||
|
syn sync minlines=200 |
||||
|
syn sync maxlines=500 |
||||
|
|
||||
|
let b:current_syntax = "rust" |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,93 @@ |
|||||
|
" Vim syntastic plugin |
||||
|
" Language: Rust |
||||
|
" Maintainer: Julien Levesy <jlevesy@gmail.com> |
||||
|
" |
||||
|
" See for details on how to add an external Syntastic checker: |
||||
|
" https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide#external |
||||
|
|
||||
|
if exists("g:loaded_syntastic_rust_cargo_checker") |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
let g:loaded_syntastic_rust_cargo_checker = 1 |
||||
|
|
||||
|
" Force syntastic to call cargo without a specific file name |
||||
|
let g:syntastic_rust_cargo_fname = "" |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_rust_cargo_IsAvailable() dict |
||||
|
if exists("*syntastic#util#getVersion") |
||||
|
echom "rust.vim: version of Syntastic is too old. Needs to be at least 3.7.0." |
||||
|
return v:false |
||||
|
endif |
||||
|
|
||||
|
return executable(self.getExec()) && |
||||
|
\ syntastic#util#versionIsAtLeast(self.getVersion(), [0, 16, 0]) |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_rust_cargo_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ "args": "check" }) |
||||
|
let l:root_cargo_toml = cargo#nearestRootCargo(0) |
||||
|
let l:nearest_cargo_toml = cargo#nearestCargo(0) |
||||
|
let b:rust_recent_root_cargo_toml = l:root_cargo_toml |
||||
|
let b:rust_recent_nearest_cargo_toml = l:nearest_cargo_toml |
||||
|
|
||||
|
" All pathname prints are relative to the Cargo.toml of the workspace, if |
||||
|
" there is a workspace, otherwise they are relative to the Cargo.toml of |
||||
|
" the single crate. Where to actually execute under these varying |
||||
|
" circumtances 'cargo' is determined here, and controlled by |
||||
|
" configuration. |
||||
|
|
||||
|
if rust#GetConfigVar('rust_cargo_avoid_whole_workspace', 1) |
||||
|
if l:root_cargo_toml !=# l:nearest_cargo_toml |
||||
|
let makeprg = "cd " . fnamemodify(l:nearest_cargo_toml, ":p:h") |
||||
|
\ . " && " . makeprg |
||||
|
endif |
||||
|
else |
||||
|
let makeprg = "cd " . fnamemodify(l:root_cargo_toml, ":p:h") |
||||
|
\ . " && " . makeprg |
||||
|
endif |
||||
|
|
||||
|
let l:check_all_targets = rust#GetConfigVar('rust_cargo_check_all_targets', 0) |
||||
|
let l:check_all_features = rust#GetConfigVar('rust_cargo_check_all_features', 0) |
||||
|
let l:check_examples = rust#GetConfigVar('rust_cargo_check_examples', 0) |
||||
|
let l:check_tests = rust#GetConfigVar('rust_cargo_check_tests', 0) |
||||
|
let l:check_benches = rust#GetConfigVar('rust_cargo_check_benches', 0) |
||||
|
|
||||
|
let makeprg = makeprg. ' ' |
||||
|
\ . (l:check_all_targets ? ' --all-targets' : '') |
||||
|
\ . (l:check_all_features ? ' --all-features' : '') |
||||
|
\ . (l:check_benches ? ' --benches' : '') |
||||
|
\ . (l:check_examples ? ' --examples' : '') |
||||
|
\ . (l:check_tests ? ' --tests' : '') |
||||
|
|
||||
|
" Ignored patterns, and blank lines |
||||
|
let errorformat = |
||||
|
\ '%-G,' . |
||||
|
\ '%-Gerror: aborting %.%#,' . |
||||
|
\ '%-Gerror: Could not compile %.%#,' |
||||
|
|
||||
|
" Meaningful lines (errors, notes, warnings, contextual information) |
||||
|
let errorformat .= |
||||
|
\ '%Eerror: %m,' . |
||||
|
\ '%Eerror[E%n]: %m,' . |
||||
|
\ '%Wwarning: %m,' . |
||||
|
\ '%Inote: %m,' . |
||||
|
\ '%C %#--> %f:%l:%c' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'cwd': fnamemodify(l:root_cargo_toml, ":p:h:."), |
||||
|
\ 'errorformat': errorformat }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'rust', |
||||
|
\ 'name': 'cargo'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,54 @@ |
|||||
|
" Vim syntastic plugin |
||||
|
" Language: Rust |
||||
|
" Maintainer: Andrew Gallant <jamslam@gmail.com> |
||||
|
" |
||||
|
" See for details on how to add an external Syntastic checker: |
||||
|
" https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide#external |
||||
|
|
||||
|
if exists("g:loaded_syntastic_rust_rustc_checker") |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_rust_rustc_checker = 1 |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
function! SyntaxCheckers_rust_rustc_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({}) |
||||
|
|
||||
|
" Old errorformat (before nightly 2016/08/10) |
||||
|
let errorformat = |
||||
|
\ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' . |
||||
|
\ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' . |
||||
|
\ '%C%f:%l %m' |
||||
|
|
||||
|
" New errorformat (after nightly 2016/08/10) |
||||
|
let errorformat .= |
||||
|
\ ',' . |
||||
|
\ '%-G,' . |
||||
|
\ '%-Gerror: aborting %.%#,' . |
||||
|
\ '%-Gerror: Could not compile %.%#,' . |
||||
|
\ '%Eerror: %m,' . |
||||
|
\ '%Eerror[E%n]: %m,' . |
||||
|
\ '%-Gwarning: the option `Z` is unstable %.%#,' . |
||||
|
\ '%Wwarning: %m,' . |
||||
|
\ '%Inote: %m,' . |
||||
|
\ '%C %#--> %f:%l:%c' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'rust', |
||||
|
\ 'name': 'rustc'}) |
||||
|
|
||||
|
" vint: -ProhibitAbbreviationOption |
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
" vint: +ProhibitAbbreviationOption |
||||
|
|
||||
|
" vim: set et sw=4 sts=4 ts=8: |
||||
@ -0,0 +1,34 @@ |
|||||
|
# This is brought as reference, to be able to reproduce a new image |
||||
|
|
||||
|
FROM alonid/vim-testbed:10 |
||||
|
|
||||
|
RUN install_vim -tag v7.4.052 -name vim74-trusty -build \ |
||||
|
-tag v8.0.1850 -name vim80 -build \ |
||||
|
-tag v8.1.0105 -name vim81 -build \ |
||||
|
-tag neovim:v0.1.7 -build \ |
||||
|
-tag neovim:v0.2.2 -build |
||||
|
|
||||
|
ENV PACKAGES="\ |
||||
|
bash \ |
||||
|
git \ |
||||
|
python \ |
||||
|
python2-pip \ |
||||
|
curl \ |
||||
|
" |
||||
|
|
||||
|
RUN dnf install -y $PACKAGES |
||||
|
|
||||
|
RUN pip install vim-vint==0.3.19 |
||||
|
|
||||
|
RUN export HOME=/rust ; mkdir $HOME ; curl https://sh.rustup.rs -sSf | sh -s -- -y |
||||
|
|
||||
|
RUN chown vimtest.vimtest -R /rust |
||||
|
|
||||
|
RUN (dnf remove -y gcc \*-devel ; \ |
||||
|
dnf install -y gpm msgpack libvterm libtermkey unibilium ) || true |
||||
|
RUN dnf clean all |
||||
|
|
||||
|
RUN echo "export PATH=~/.cargo/bin:$PATH" >> ~/.bashrc |
||||
|
|
||||
|
RUN git clone https://github.com/da-x/vader.vim vader && \ |
||||
|
cd vader && git checkout v2017-12-26 |
||||
@ -0,0 +1,24 @@ |
|||||
|
Given rust (Some Rust code): |
||||
|
fn main() { |
||||
|
println!("Hello World\n") |
||||
|
} |
||||
|
|
||||
|
Execute (RustInfo - call it to see that it works): |
||||
|
redir => m |
||||
|
silent RustInfo |
||||
|
redir END |
||||
|
Log m |
||||
|
|
||||
|
Execute (RustEmitAsm - see that we actually get assembly output): |
||||
|
silent! w test.rs |
||||
|
silent! e! test.rs |
||||
|
redir => m |
||||
|
silent! RustEmitAsm |
||||
|
redir END |
||||
|
AssertEqual 'asm', &filetype |
||||
|
normal! ggVGy:q<CR> |
||||
|
AssertEqual 1,(@" =~# '\V.section') |
||||
|
bd |
||||
|
call delete('test.rs') |
||||
|
|
||||
|
# TODO: a lot more tests |
||||
@ -0,0 +1,292 @@ |
|||||
|
Given rust: |
||||
|
fn main() { |
||||
|
let a = 2; |
||||
|
println!("Hello World\n") |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (very basic indentation result): |
||||
|
fn main() { |
||||
|
let a = 2; |
||||
|
println!("Hello World\n") |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #195 |
||||
|
|
||||
|
Given rust: |
||||
|
fn main() { |
||||
|
let paths: Vec<_> = ({ |
||||
|
fs::read_dir("test_data") |
||||
|
.unwrap() |
||||
|
.cloned() |
||||
|
}) |
||||
|
.collect(); |
||||
|
|
||||
|
println!("Hello World\n"); |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
/collect\<cr> |
||||
|
ostatement();\<ESC>\<ESC> |
||||
|
|
||||
|
Expect rust (issue #195): |
||||
|
fn main() { |
||||
|
let paths: Vec<_> = ({ |
||||
|
fs::read_dir("test_data") |
||||
|
.unwrap() |
||||
|
.cloned() |
||||
|
}) |
||||
|
.collect(); |
||||
|
statement(); |
||||
|
|
||||
|
println!("Hello World\n"); |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #189 |
||||
|
|
||||
|
Given rust: |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where |
||||
|
K: Borrow<Q>, |
||||
|
Q: Ord + ?Sized, |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #189): |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where |
||||
|
K: Borrow<Q>, |
||||
|
Q: Ord + ?Sized, |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #189b |
||||
|
|
||||
|
Given rust: |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where |
||||
|
K: Borrow<Q>, |
||||
|
Q: Ord + ?Sized |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #189b): |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where |
||||
|
K: Borrow<Q>, |
||||
|
Q: Ord + ?Sized |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #189c |
||||
|
|
||||
|
Given rust: |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where K: Borrow<Q>, Q: Ord + ?Sized |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #189b): |
||||
|
impl X for { |
||||
|
pub fn get<Q>(&self, key: &Q) -> Option<Entry<K, V>> |
||||
|
where K: Borrow<Q>, Q: Ord + ?Sized |
||||
|
{ |
||||
|
self.inner.get(key).map(Entry::new) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
############################################ |
||||
|
# Issue #149 |
||||
|
|
||||
|
Given rust: |
||||
|
fn test() { |
||||
|
let t = "a |
||||
|
wah"; |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
/wah\<cr> |
||||
|
i#\<ESC>\<ESC> |
||||
|
/;\<cr>o |
||||
|
statement();\<ESC>\<ESC> |
||||
|
|
||||
|
# Disabled |
||||
|
# Expect rust (issue #149): |
||||
|
fn test() { |
||||
|
let t = "a |
||||
|
#wah"; |
||||
|
statement(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
############################################ |
||||
|
# Issue #77 |
||||
|
|
||||
|
Given rust: |
||||
|
fn test() { |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
of(x, y,\<CR>z);\<CR> |
||||
|
f((x, y),\<CR>z);\<CR> |
||||
|
|
||||
|
# Disabled |
||||
|
# Expect rust (issue #77): |
||||
|
fn test() { |
||||
|
f(x, y, |
||||
|
z); |
||||
|
f((x, y), |
||||
|
z); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #44 |
||||
|
|
||||
|
Given rust: |
||||
|
fn main() { |
||||
|
a |
||||
|
|
||||
|
let philosophers = vec![ |
||||
|
Philosopher::new("Judith Butler"), |
||||
|
Philosopher::new("Gilles Deleuze"), |
||||
|
Philosopher::new("Karl Marx"), |
||||
|
Philosopher::new("Emma Goldman"), |
||||
|
Philosopher::new("Michel Foucault"), |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
/let\<CR> |
||||
|
vip= |
||||
|
|
||||
|
# Disabled |
||||
|
# Expect rust (issue #44): |
||||
|
fn main() { |
||||
|
a |
||||
|
|
||||
|
let philosophers = vec![ |
||||
|
Philosopher::new("Judith Butler"), |
||||
|
Philosopher::new("Gilles Deleuze"), |
||||
|
Philosopher::new("Karl Marx"), |
||||
|
Philosopher::new("Emma Goldman"), |
||||
|
Philosopher::new("Michel Foucault"), |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #5 |
||||
|
|
||||
|
Given rust: |
||||
|
fn f() { |
||||
|
if x && |
||||
|
y { |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #5): |
||||
|
fn f() { |
||||
|
if x && |
||||
|
y { |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
# Issue #366 |
||||
|
|
||||
|
Given rust: |
||||
|
fn f() { |
||||
|
g(|_| { |
||||
|
h(); |
||||
|
}) |
||||
|
.unwrap(); |
||||
|
h(); |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #366): |
||||
|
fn f() { |
||||
|
g(|_| { |
||||
|
h(); |
||||
|
}) |
||||
|
.unwrap(); |
||||
|
h(); |
||||
|
} |
||||
|
|
||||
|
Given rust: |
||||
|
fn f() { |
||||
|
let a = g(|_| { |
||||
|
h(); |
||||
|
}) |
||||
|
.unwrap(); |
||||
|
h(); |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (issue #366, variation #2): |
||||
|
fn f() { |
||||
|
let a = g(|_| { |
||||
|
h(); |
||||
|
}) |
||||
|
.unwrap(); |
||||
|
h(); |
||||
|
} |
||||
|
|
||||
|
############################################ |
||||
|
|
||||
|
Given rust: |
||||
|
fn f() { |
||||
|
let mut state = State::new( |
||||
|
backend, |
||||
|
header.clone(), |
||||
|
).expect("Something"); |
||||
|
} |
||||
|
|
||||
|
Do: |
||||
|
vip= |
||||
|
|
||||
|
Expect rust (Trailing comma in call): |
||||
|
fn f() { |
||||
|
let mut state = State::new( |
||||
|
backend, |
||||
|
header.clone(), |
||||
|
).expect("Something"); |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
|
||||
|
import os |
||||
|
import sys |
||||
|
|
||||
|
REPO = "alonid/vim-testbed" |
||||
|
TAG = "10-rust.vim" |
||||
|
IMAGE = "%s:%s" % (REPO, TAG) |
||||
|
|
||||
|
class Error(Exception): |
||||
|
pass |
||||
|
|
||||
|
def system(cmd, capture=False, ok_fail=False): |
||||
|
if capture: |
||||
|
f = os.popen(cmd) |
||||
|
d = f.read() |
||||
|
return d |
||||
|
|
||||
|
res = os.system(cmd) |
||||
|
if res != 0: |
||||
|
if ok_fail: |
||||
|
return res |
||||
|
|
||||
|
raise Error("Error executing: %s" % (cmd, )) |
||||
|
return 0 |
||||
|
|
||||
|
def root(): |
||||
|
return os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
||||
|
|
||||
|
def prep(): |
||||
|
d = os.path.join(root(), "test") |
||||
|
for i in [".cargo", ".rustup", ".multirust"]: |
||||
|
l = os.path.join(d, i) |
||||
|
if not os.path.lexists(l): |
||||
|
os.symlink("/rust/" + i, l) |
||||
|
|
||||
|
l = os.path.join(root(), "test/.vimrc") |
||||
|
if not os.path.lexists(l): |
||||
|
os.symlink("vimrc", l) |
||||
|
|
||||
|
if not os.path.exists(os.path.join(d, ".profile")): |
||||
|
f = open(os.path.join(d, ".profile"), "w") |
||||
|
f.write('export PATH="$HOME/.cargo/bin:$PATH"\n') |
||||
|
f.close() |
||||
|
|
||||
|
def docker_run(cmd, interactive=False, ok_fail=False): |
||||
|
prep() |
||||
|
d = root() |
||||
|
params = "-v %s:/testplugin -v %s/test:/home/vimtest" % (d, d) |
||||
|
params += " -e HOME=/home/vimtest" |
||||
|
if not interactive: |
||||
|
params += " -a stderr" |
||||
|
params += " -e VADER_OUTPUT_FILE=/dev/stderr" |
||||
|
params += " -u %s" % (os.getuid(), ) |
||||
|
params += " -w /testplugin" |
||||
|
if interactive: |
||||
|
interactive_str = "-it" |
||||
|
else: |
||||
|
interactive_str = "" |
||||
|
return system("docker run %s --rm %s %s %s" % (interactive_str, params, IMAGE, cmd), |
||||
|
ok_fail=ok_fail) |
||||
|
|
||||
|
def image_exists(): |
||||
|
r = system("docker images -q %s" % (IMAGE, ), capture=True) |
||||
|
return len(r.strip().splitlines()) >= 1 |
||||
|
|
||||
|
def tests_on_docker(): |
||||
|
res = docker_run("bash -lc 'python /home/vimtest/run-tests inside-docker'", ok_fail=True) |
||||
|
if res == 0: |
||||
|
print "Tests OK" |
||||
|
else: |
||||
|
print "Tests Failed" |
||||
|
sys.exit(1) |
||||
|
|
||||
|
def inside_docker(): |
||||
|
res = system("/vim-build/bin/vim80 --not-a-term '+Vader! test/*.vader'", ok_fail=True) |
||||
|
if res != 0: |
||||
|
sys.exit(1) |
||||
|
|
||||
|
def run_with_vimrc(vimrc): |
||||
|
res = system("vim -u %s --not-a-term '+Vader! test/*.vader'" % (vimrc, ), ok_fail=True) |
||||
|
if res != 0: |
||||
|
sys.exit(1) |
||||
|
|
||||
|
def main(): |
||||
|
if sys.argv[1:] == ["inside-docker"]: |
||||
|
inside_docker() |
||||
|
return |
||||
|
|
||||
|
if sys.argv[1:2] == ["run-with-vimrc"]: |
||||
|
run_with_vimrc(sys.argv[2]) |
||||
|
return |
||||
|
|
||||
|
if not image_exists(): |
||||
|
print "Need to take image from remote" |
||||
|
system("docker pull %s" % (IMAGE, )) |
||||
|
|
||||
|
if "-i" in sys.argv[1:]: |
||||
|
docker_run("bash -l", interactive=True) |
||||
|
return |
||||
|
|
||||
|
tests_on_docker() |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
main() |
||||
@ -0,0 +1,30 @@ |
|||||
|
" vint: -ProhibitSetNoCompatible |
||||
|
" |
||||
|
|
||||
|
set nocompatible |
||||
|
filetype off |
||||
|
|
||||
|
" This script is currently designed to be run from within Docker, the |
||||
|
" following paths are intrinsic to the container: |
||||
|
source /rtp.vim |
||||
|
|
||||
|
" Paths need prepending (instead of what is originally done |
||||
|
" in vim-testbed) in order to supersede the rust.vim that is |
||||
|
" supplied with Vim. |
||||
|
exec 'set runtimepath=/vader,/testplugin,' . &runtimepath |
||||
|
cd /testplugin |
||||
|
|
||||
|
filetype plugin indent on |
||||
|
syntax on |
||||
|
|
||||
|
set nocompatible |
||||
|
set tabstop=8 |
||||
|
set softtabstop=4 |
||||
|
set shiftwidth=4 |
||||
|
set expandtab |
||||
|
set backspace=2 |
||||
|
set nofoldenable |
||||
|
set foldmethod=syntax |
||||
|
set foldlevelstart=10 |
||||
|
set foldnestmax=10 |
||||
|
set ttimeoutlen=0 |
||||
@ -0,0 +1,4 @@ |
|||||
|
*~ |
||||
|
*.swp |
||||
|
tags |
||||
|
.DS_Store |
||||
@ -0,0 +1,105 @@ |
|||||
|
# CONTRIBUTING |
||||
|
- - - |
||||
|
1\. [Bug reports / GitHub issues](#bugreps) |
||||
|
2\. [Submitting a patch](#patches) |
||||
|
3\. [General style notes](#generalstyle) |
||||
|
4\. [Syntax checker notes](#checkerstyle) |
||||
|
- - - |
||||
|
|
||||
|
<a name="bugreps"></a> |
||||
|
|
||||
|
## 1. Bug reports / GitHub issues |
||||
|
|
||||
|
Please note that the preferred channel for posting bug reports is the |
||||
|
[issue tracker at GitHub][bug_tracker]. 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 (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`. |
||||
|
|
||||
|
<a name="patches"></a> |
||||
|
|
||||
|
## 2. Submitting a patch |
||||
|
|
||||
|
Before you consider adding features to syntastic, _please_ spend a few minutes |
||||
|
(re-)reading the latest version of the [manual][manual]. Syntastic is changing |
||||
|
rapidly at times, and it's possible that some features you want to add exist |
||||
|
already. |
||||
|
|
||||
|
To submit a patch: |
||||
|
|
||||
|
* fork the [repo][github] on GitHub; |
||||
|
* make a [topic branch][branches] and start hacking; |
||||
|
* submit a pull request based off your topic branch. |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
Also, make sure to update the manual whenever applicable. Nobody can use |
||||
|
features that aren't documented. |
||||
|
|
||||
|
<a name="generalstyle"></a> |
||||
|
|
||||
|
## 3. General style notes |
||||
|
|
||||
|
Follow 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][variables] to |
||||
|
aid readability. |
||||
|
|
||||
|
<a name="checkerstyle"></a> |
||||
|
|
||||
|
## 4. Syntax checker notes |
||||
|
|
||||
|
Make sure to read the [guide][guide] 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%.%#' |
||||
|
``` |
||||
|
|
||||
|
[bug_tracker]: https://github.com/vim-syntastic/syntastic/issues |
||||
|
[manual]: https://github.com/vim-syntastic/syntastic/blob/master/doc/syntastic.txt |
||||
|
[github]: https://github.com/vim-syntastic/syntastic |
||||
|
[branches]: https://github.com/dchelimsky/rspec/wiki/Topic-Branches#using-topic-branches-when-contributing-patches |
||||
|
[variables]: http://www.refactoring.com/catalog/extractVariable.html |
||||
|
[guide]: https://github.com/vim-syntastic/syntastic/wiki/Syntax-Checker-Guide |
||||
@ -0,0 +1,13 @@ |
|||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
|
Version 2, December 2004 |
||||
|
|
||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
|
||||
|
Everyone is permitted to copy and distribute verbatim or modified |
||||
|
copies of this license document, and changing it is allowed as long |
||||
|
as the name is changed. |
||||
|
|
||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
|
||||
|
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
@ -0,0 +1,543 @@ |
|||||
|
, |
||||
|
/ \,,_ .'| |
||||
|
,{{| /}}}}/_.' _____________________________________________ |
||||
|
}}}}` '{{' '. / \ |
||||
|
{{{{{ _ ;, \ / Ladies and Gentlemen, \ |
||||
|
,}}}}}} /o`\ ` ;) | | |
||||
|
{{{{{{ / ( | this is ... | |
||||
|
}}}}}} | \ | | |
||||
|
{{{{{{{{ \ \ | | |
||||
|
}}}}}}}}} '.__ _ | | _____ __ __ _ | |
||||
|
{{{{{{{{ /`._ (_\ / | / ___/__ ______ / /_____ ______/ /_(_)____ | |
||||
|
}}}}}}' | //___/ --=: \__ \/ / / / __ \/ __/ __ `/ ___/ __/ / ___/ | |
||||
|
jgs `{{{{` | '--' | ___/ / /_/ / / / / /_/ /_/ (__ ) /_/ / /__ | |
||||
|
}}}` | /____/\__, /_/ /_/\__/\__,_/____/\__/_/\___/ | |
||||
|
| /____/ | |
||||
|
| / |
||||
|
\_____________________________________________/ |
||||
|
|
||||
|
|
||||
|
- - - |
||||
|
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. [Syntastic supports several checkers for my filetype, how do I tell it which one(s) to use?](#faqcheckers) |
||||
|
4.3. [How can I run checkers for "foreign" filetypes against the current file?](#faqforeign) |
||||
|
4.4. [I have enabled multiple checkers for the current filetype. How can I display all errors from all checkers together?](#faqaggregate) |
||||
|
4.5. [How can I pass additional arguments to a checker?](#faqargs) |
||||
|
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 jump between the different errors without using the location list at the bottom of the window?](#faqlnext) |
||||
|
4.8. [The error window is closed automatically when I `:quit` the current buffer but not when I `:bdelete` it?](#faqbdelete) |
||||
|
4.9. [My favourite checker needs to load a configuration file from the project's root rather than the current directory...](#faqconfig) |
||||
|
4.10. [What is the difference between syntax checkers and style checkers?](#faqstyle) |
||||
|
4.11. [How can I check scripts written for different versions of Python?](#faqpython) |
||||
|
4.12. [How can I check scripts written for different versions of Ruby?](#faqruby) |
||||
|
4.13. [The `perl` checker has stopped working...](#faqperl) |
||||
|
4.14. [What happened to the `rustc` checker?](#faqrust) |
||||
|
4.15. [What happened to the `tsc` checker?](#faqtsc) |
||||
|
4.16. [What happened to the `xcrun` checker?](#faqxcrun) |
||||
|
5. [Resources](#otherresources) |
||||
|
|
||||
|
- - - |
||||
|
|
||||
|
<a name="introduction"></a> |
||||
|
|
||||
|
## 1\. Introduction |
||||
|
|
||||
|
Syntastic is a syntax checking plugin for [Vim][vim] created by |
||||
|
[Martin Grenfell][scrooloose]. It 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, syntastic has checking plugins for ACPI |
||||
|
Source Language, ActionScript, Ada, Ansible configurations, API Blueprint, |
||||
|
AppleScript, AsciiDoc, Assembly languages, BEMHTML, Bro, Bourne shell, C, C++, |
||||
|
C#, Cabal, Chef, CMake, CoffeeScript, Coco, Coq, CSS, Cucumber, CUDA, D, Dart, |
||||
|
DocBook, Dockerfile, Dust, Elixir, Erlang, eRuby, Fortran, Gentoo metadata, |
||||
|
GLSL, Go, Haml, Haskell, Haxe, Handlebars, HSS, HTML, Java, JavaScript, JSON, |
||||
|
JSX, Julia, LESS, Lex, Limbo, LISP, LLVM intermediate language, Lua, Markdown, |
||||
|
MATLAB, Mercury, NASM, Nix, Objective-C, Objective-C++, OCaml, Perl, Perl |
||||
|
6, Perl POD, PHP, gettext Portable Object, OS X and iOS property lists, Pug |
||||
|
(formerly Jade), Puppet, Python, QML, R, Racket, RDF TriG, RDF Turtle, Relax |
||||
|
NG, reStructuredText, RPM spec, Ruby, SASS/SCSS, Scala, Slim, SML, Solidity, |
||||
|
Sphinx, SQL, Stylus, Tcl, TeX, Texinfo, Twig, TypeScript, Vala, Verilog, VHDL, |
||||
|
Vim help, VimL, Vue.js, xHtml, XML, XSLT, XQuery, YACC, YAML, YANG data models, |
||||
|
YARA rules, z80, Zope page templates, and Zsh. See the [manual][checkers] for |
||||
|
details about the corresponding supported checkers (`:help syntastic-checkers` |
||||
|
in Vim). |
||||
|
|
||||
|
A number of third-party Vim plugins also provide checkers for syntastic, for |
||||
|
example: [merlin][merlin], [omnisharp-vim][omnisharp], [rust.vim][rust], |
||||
|
[syntastic-extras][myint], [syntastic-more][roktas], [tsuquyomi][tsuquyomi], |
||||
|
[vim-crystal][crystal], [vim-eastwood][eastwood], and [vim-swift][swift]. |
||||
|
|
||||
|
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 |
||||
|
enabled. |
||||
|
|
||||
|
![Screenshot 1][screenshot] |
||||
|
|
||||
|
1. Errors are loaded into the location list for the corresponding window. |
||||
|
2. When the cursor is on a line containing an error, the error message is echoed in the command window. |
||||
|
3. Signs are placed beside lines with errors - note that warnings are displayed in a different color. |
||||
|
4. There is a configurable statusline flag you can include in your statusline config. |
||||
|
5. Hover the mouse over a line containing an error and the error message is displayed as a balloon. |
||||
|
6. (not shown) Highlighting errors with syntax highlighting. Erroneous parts of lines can be highlighted. |
||||
|
|
||||
|
<a name="installation"></a> |
||||
|
|
||||
|
## 2\. Installation |
||||
|
|
||||
|
<a name="requirements"></a> |
||||
|
|
||||
|
### 2.1\. Requirements |
||||
|
|
||||
|
Syntastic itself has rather relaxed requirements: it doesn't have any external |
||||
|
dependencies, and it needs a version of [Vim][vim] compiled with a few common |
||||
|
features: `autocmd`, `eval`, `file_in_path`, `modify_fname`, `quickfix`, |
||||
|
`reltime`, `statusline`, 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. |
||||
|
|
||||
|
Syntastic should work with any modern plugin managers for Vim, such as |
||||
|
[NeoBundle][neobundle], [Pathogen][pathogen], [Vim-Addon-Manager][vam], |
||||
|
[Vim-Plug][plug], or [Vundle][vundle]. Instructions for installing syntastic |
||||
|
with [Pathogen][pathogen] are included below for completeness. |
||||
|
|
||||
|
Starting with Vim version 7.4.1486 you can also load syntastic using the |
||||
|
standard mechanism of packages, without the help of third-party plugin managers |
||||
|
(see `:help packages` in Vim for details). Beware however that, while support |
||||
|
for packages has been added in Vim 7.4.1384, the functionality needed by |
||||
|
syntastic is present only in versions 7.4.1486 and later. |
||||
|
|
||||
|
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 |
||||
|
[manual][checkers] (`:help syntastic-checkers` in Vim) for a list of supported |
||||
|
checkers. |
||||
|
|
||||
|
<a name="installpathogen"></a> |
||||
|
|
||||
|
### 2.2\. Installing syntastic with Pathogen |
||||
|
|
||||
|
If you already have [Pathogen][pathogen] working then skip [Step 1](#step1) and go to |
||||
|
[Step 2](#step2). |
||||
|
|
||||
|
<a name="step1"></a> |
||||
|
|
||||
|
#### 2.2.1\. Step 1: Install pathogen.vim |
||||
|
|
||||
|
First I'll show you how to install Tim Pope's [Pathogen][pathogen] 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() |
||||
|
``` |
||||
|
|
||||
|
<a name="step2"></a> |
||||
|
|
||||
|
#### 2.2.2\. Step 2: Install syntastic as a Pathogen bundle |
||||
|
|
||||
|
You now have pathogen installed and can put syntastic into `~/.vim/bundle` like |
||||
|
this: |
||||
|
```sh |
||||
|
cd ~/.vim/bundle && \ |
||||
|
git clone --depth=1 https://github.com/vim-syntastic/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][pathogen] 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 `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. |
||||
|
|
||||
|
<a name="settings"></a> |
||||
|
|
||||
|
## 3\. Recommended settings |
||||
|
|
||||
|
Syntastic has numerous 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 |
||||
|
``` |
||||
|
|
||||
|
<a name="faq"></a> |
||||
|
|
||||
|
## 4\. FAQ |
||||
|
|
||||
|
<a name="faqinfo"></a> |
||||
|
|
||||
|
__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 |
||||
|
are installed. For example: by default, python requires either `flake8` or |
||||
|
`pylint` to be installed and in your `$PATH`. Read the [manual][checkers] |
||||
|
(`:help syntastic-checkers` in Vim) to find out what executables are |
||||
|
supported. 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`. |
||||
|
|
||||
|
A second probable reason is that none of the available checkers are |
||||
|
enabled. Syntastic comes preconfigured with a default list of enabled checkers |
||||
|
per filetype, but this list is kept short in order to prevent slowing down Vim |
||||
|
or trying to run conflicting checks. The command `:SyntasticInfo` will show you |
||||
|
which checkers are enabled. You can tell syntastic which checkers (among the |
||||
|
available ones) you want to run by setting `g:syntastic_<filetype>_checkers` in |
||||
|
your `vimrc` (see [below](#faqcheckers)). |
||||
|
|
||||
|
A third possible reason is that the `$PATH` seen by syntastic might not be same |
||||
|
as the `$PATH` in your login shell. Syntastic runs checkers using the shell |
||||
|
pointed to by Vim's `shell` (or by `g:syntastic_shell`, if set), and that's the |
||||
|
shell you need to configure to set the proper `$PATH` and environment variables |
||||
|
for your checkers. You can see syntastic's idea of `$PATH` by running |
||||
|
```vim |
||||
|
:echo syntastic#util#system('echo "$PATH"') |
||||
|
``` |
||||
|
on UNIX and Mac OS-X systems, or |
||||
|
```vim |
||||
|
:echo syntastic#util#system('echo %PATH%') |
||||
|
``` |
||||
|
on Windows. |
||||
|
|
||||
|
Finally, 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 post an [issue][bug_tracker] - or better yet, create a pull request. |
||||
|
|
||||
|
<a name="faqcheckers"></a> |
||||
|
|
||||
|
__4.2. Q. Syntastic supports several checkers for my filetype, how do I tell it |
||||
|
which one(s) to use?__ |
||||
|
|
||||
|
A. Add a line like this to your `vimrc`: |
||||
|
```vim |
||||
|
let g:syntastic_<filetype>_checkers = ['<checker-name>'] |
||||
|
``` |
||||
|
|
||||
|
To see the list of supported checkers for your filetype read the |
||||
|
[manual][checkers] (`:help syntastic-checkers` in Vim). |
||||
|
|
||||
|
For example, 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'] |
||||
|
``` |
||||
|
|
||||
|
Checkers can be chained together like this: |
||||
|
```vim |
||||
|
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`. |
||||
|
|
||||
|
You can also run checkers explicitly by calling `:SyntasticCheck <checker>`. |
||||
|
For example 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_<filetype>_checkers`. |
||||
|
|
||||
|
<a name="faqforeign"></a> |
||||
|
|
||||
|
__4.3. Q. How can I run checkers for "foreign" filetypes against the current |
||||
|
file?__ |
||||
|
|
||||
|
A. You need to qualify the name of the "foreign" checker with the name |
||||
|
of its filetype. For example to check `tex` files with the checker |
||||
|
`language_check` (which normally acts only on files of type `text`), you can |
||||
|
add `text/language_check` to the list fo checkers for `tex`: |
||||
|
```vim |
||||
|
let g:syntastic_tex_checkers = ['lacheck', 'text/language_check'] |
||||
|
``` |
||||
|
|
||||
|
This also works with `:SyntasticCheck`, e.g. the following command runs |
||||
|
`text/language_check` against the current file regardless of the current |
||||
|
filetype: |
||||
|
```vim |
||||
|
:SyntasticCheck text/language_check |
||||
|
``` |
||||
|
|
||||
|
Of course, the checkers specified this way need to be known to syntastic, and |
||||
|
they need to be shown as available when you run `:SyntasticInfo`. You can't |
||||
|
just make up a combination of a filetype and a program name and expect it to |
||||
|
work as a checker. |
||||
|
|
||||
|
<a name="faqaggregate"></a> |
||||
|
|
||||
|
__4.4. Q. I have enabled multiple checkers for the current filetype. How can I |
||||
|
display all errors from all 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. |
||||
|
|
||||
|
<a name="faqargs"></a> |
||||
|
|
||||
|
__4.5. Q. How can I pass additional arguments to a checker?__ |
||||
|
|
||||
|
A. In most cases a command line is constructed using an internal function |
||||
|
named `makeprgBuild()`, which provides a number of options that allow you to |
||||
|
customise every part of the command that gets run. You can set these options |
||||
|
using global variables. |
||||
|
|
||||
|
The general form of the global `args` variable is |
||||
|
`syntastic_<filetype>_<checker>_args`. Thus 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" |
||||
|
``` |
||||
|
|
||||
|
See `:help syntastic-checker-options` for more information. |
||||
|
|
||||
|
A number of checkers don't use the `makeprgBuild()` function mentioned above, |
||||
|
or have additional options that can be configured. For these checkers the exact |
||||
|
list of options should be included in the [manual][checkers] |
||||
|
(`:help syntastic-checkers` in Vim). |
||||
|
|
||||
|
<a name="faqloclist"></a> |
||||
|
|
||||
|
__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`: |
||||
|
```vim |
||||
|
let g:syntastic_always_populate_loc_list = 1 |
||||
|
``` |
||||
|
|
||||
|
<a name="faqlnext"></a> |
||||
|
|
||||
|
__4.7. 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 :lprevious`. |
||||
|
|
||||
|
If you use these commands a lot then you may want to add shortcut mappings to |
||||
|
your `vimrc`, or install something like [unimpaired][unimpaired], which provides such |
||||
|
mappings (among other things). |
||||
|
|
||||
|
<a name="faqbdelete"></a> |
||||
|
|
||||
|
__4.8. 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 |
||||
|
work around it: |
||||
|
```vim |
||||
|
nnoremap <silent> <C-d> :lclose<CR>:bdelete<CR> |
||||
|
cabbrev <silent> bd <C-r>=(getcmdtype()==#':' && getcmdpos()==1 ? 'lclose\|bdelete' : 'bd')<CR> |
||||
|
``` |
||||
|
|
||||
|
<a name="faqconfig"></a> |
||||
|
|
||||
|
__4.9. My favourite checker needs to load a configuration file from the |
||||
|
project's root rather than the current directory...__ |
||||
|
|
||||
|
A. You can set up an `autocmd` to search for the configuration file in the |
||||
|
current directory and upwards, and add it to the checker's options when found. |
||||
|
For example for `jscs`: |
||||
|
|
||||
|
```vim |
||||
|
function! FindConfig(prefix, what, where) |
||||
|
let cfg = findfile(a:what, escape(a:where, ' ') . ';') |
||||
|
return cfg !=# '' ? ' ' . a:prefix . ' ' . shellescape(cfg) : '' |
||||
|
endfunction |
||||
|
|
||||
|
autocmd FileType javascript let b:syntastic_javascript_jscs_args = |
||||
|
\ get(g:, 'syntastic_javascript_jscs_args', '') . |
||||
|
\ FindConfig('-c', '.jscsrc', expand('<afile>:p:h', 1)) |
||||
|
``` |
||||
|
|
||||
|
<a name="faqstyle"></a> |
||||
|
|
||||
|
__4.10. 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. |
||||
|
|
||||
|
Generally 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 more information. |
||||
|
|
||||
|
<a name="faqpython"></a> |
||||
|
|
||||
|
__4.11. Q. How can I check scripts written for different versions of Python?__ |
||||
|
|
||||
|
A. Install a Python version manager such as [virtualenv][virtualenv] |
||||
|
or [pyenv][pyenv], activate the environment for the relevant version |
||||
|
of Python, and install in it the checkers you want to use. Set |
||||
|
`g:syntastic_python_checkers` accordingly in your `vimrc`, and run [Vim][vim] |
||||
|
from the virtual environment. |
||||
|
|
||||
|
If you're starting Vim from a desktop manager rather than from a terminal you |
||||
|
might need to write wrapper scripts around your checkers, to activate the |
||||
|
virtual environment before running the actual checks. Then you'll need to |
||||
|
point the relevant `g:syntastic_python_<checker>_exec` variables to the wrapper |
||||
|
scripts. |
||||
|
|
||||
|
<a name="faqruby"></a> |
||||
|
|
||||
|
__4.12. Q. How can I check scripts written for different versions of Ruby?__ |
||||
|
|
||||
|
A. Install a Ruby version manager such as [rvm][rvm] or [rbenv][rbenv], |
||||
|
activate the relevant version of Ruby, and install in it the checkers you want |
||||
|
to use. Set `g:syntastic_ruby_checkers` accordingly in your `vimrc`, and run |
||||
|
[Vim][vim] under the relevant Ruby version. |
||||
|
|
||||
|
If you're starting Vim from a desktop manager rather than from a terminal |
||||
|
and depending on the version manager you use you might need to write wrapper |
||||
|
scripts around your checkers, to activate the relevant version of Ruby |
||||
|
before running the actual checks. Then you'll need to point the relevant |
||||
|
`g:syntastic_ruby_<checker>_exec` variables to the wrapper scripts. |
||||
|
|
||||
|
<a name="faqperl"></a> |
||||
|
|
||||
|
__4.13. Q. The `perl` checker has stopped working...__ |
||||
|
|
||||
|
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][perlrun]). 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 |
||||
|
``` |
||||
|
|
||||
|
<a name="faqrust"></a> |
||||
|
|
||||
|
__4.14. Q. What happened to the `rustc` checker?__ |
||||
|
|
||||
|
A. It is now part of the [rust.vim][rust] plugin. If you install this plugin the |
||||
|
checker should be picked up automatically by syntastic. |
||||
|
|
||||
|
<a name="faqtsc"></a> |
||||
|
|
||||
|
__4.15. Q. What happened to the `tsc` checker?__ |
||||
|
|
||||
|
A. It didn't meet people's expectations and it has been removed. The plugin |
||||
|
[tsuquyomi][tsuquyomi] comes packaged with a checker for TypeScript. If you |
||||
|
install this plugin the checker should be picked up automatically by syntastic. |
||||
|
|
||||
|
<a name="faqxcrun"></a> |
||||
|
|
||||
|
__4.16. Q. What happened to the `xcrun` checker?__ |
||||
|
|
||||
|
A. The `xcrun` checker used to have a security problem and it has been removed. |
||||
|
A better checker for __Swift__ is part of the [vim-swift][swift] plugin. If you |
||||
|
install this plugin the checker should be picked up automatically by syntastic. |
||||
|
|
||||
|
<a name="otherresources"></a> |
||||
|
|
||||
|
## 5\. Resources |
||||
|
|
||||
|
The preferred place for posting suggestions, reporting bugs, and general |
||||
|
discussions related to syntastic is the [issue tracker at GitHub][bug_tracker]. |
||||
|
A guide for writing syntax checkers can be found in the [wiki][guide]. |
||||
|
There are also a dedicated [google group][google_group], and a |
||||
|
[syntastic tag at StackOverflow][stack_overflow]. |
||||
|
|
||||
|
Syntastic aims to provide a common interface to syntax checkers for as many |
||||
|
languages as possible. For particular languages, there are, of course, other |
||||
|
plugins that provide more functionality than syntastic. You might want to take |
||||
|
a look at [ghcmod-vim][ghcmod], [jedi-vim][jedi], [python-mode][python_mode], [vim-go][vimgo], or |
||||
|
[YouCompleteMe][ycm]. |
||||
|
|
||||
|
[scrooloose]: https://github.com/scrooloose |
||||
|
[screenshot]: https://github.com/vim-syntastic/syntastic/raw/master/_assets/screenshot_1.png |
||||
|
|
||||
|
[bug_tracker]: https://github.com/vim-syntastic/syntastic/issues |
||||
|
[checkers]: https://github.com/vim-syntastic/syntastic/blob/master/doc/syntastic-checkers.txt |
||||
|
[crystal]: https://github.com/rhysd/vim-crystal |
||||
|
[eastwood]: https://github.com/venantius/vim-eastwood |
||||
|
[ghcmod]: https://github.com/eagletmt/ghcmod-vim |
||||
|
[google_group]: https://groups.google.com/group/vim-syntastic |
||||
|
[guide]: https://github.com/vim-syntastic/syntastic/wiki/Syntax-Checker-Guide |
||||
|
[jedi]: https://github.com/davidhalter/jedi-vim |
||||
|
[merlin]: https://github.com/the-lambda-church/merlin |
||||
|
[myint]: https://github.com/myint/syntastic-extras |
||||
|
[neobundle]: https://github.com/Shougo/neobundle.vim |
||||
|
[omnisharp]: https://github.com/OmniSharp/omnisharp-vim |
||||
|
[pathogen]: https://github.com/tpope/vim-pathogen |
||||
|
[perlrun]: http://perldoc.perl.org/perlrun.html#*-c* |
||||
|
[plug]: https://github.com/junegunn/vim-plug/ |
||||
|
[pyenv]: https://github.com/yyuu/pyenv |
||||
|
[python_mode]: https://github.com/klen/python-mode |
||||
|
[rbenv]: https://github.com/rbenv/rbenv |
||||
|
[roktas]: https://github.com/roktas/syntastic-more |
||||
|
[rust]: https://github.com/rust-lang/rust.vim |
||||
|
[rvm]: https://rvm.io/ |
||||
|
[stack_overflow]: http://stackoverflow.com/questions/tagged/syntastic |
||||
|
[swift]: https://github.com/kballard/vim-swift |
||||
|
[tsuquyomi]: https://github.com/Quramy/tsuquyomi/ |
||||
|
[unimpaired]: https://github.com/tpope/vim-unimpaired |
||||
|
[vam]: https://github.com/MarcWeber/vim-addon-manager |
||||
|
[vim]: http://www.vim.org/ |
||||
|
[vimgo]: https://github.com/fatih/vim-go |
||||
|
[virtualenv]: https://virtualenv.pypa.io/en/stable/ |
||||
|
[vundle]: https://github.com/gmarik/Vundle.vim |
||||
|
[ycm]: https://github.com/ycm-core/YouCompleteMe |
||||
|
|
||||
|
<!-- |
||||
|
vim:tw=79:sw=4: |
||||
|
--> |
||||
|
After Width: | Height: | Size: 90 KiB |
@ -0,0 +1,341 @@ |
|||||
|
if exists('g:loaded_syntastic_c_autoload') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_autoload = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
" Public functions {{{1 |
||||
|
|
||||
|
" convenience function to determine the 'null device' parameter |
||||
|
" based on the current operating system |
||||
|
function! syntastic#c#NullOutput() abort " {{{2 |
||||
|
let known_os = has('unix') || has('mac') || syntastic#util#isRunningWindows() |
||||
|
return known_os ? '-o ' . syntastic#util#DevNull() : '' |
||||
|
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) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: looking for', a:file) |
||||
|
|
||||
|
" search upwards from the current file's directory |
||||
|
let config = syntastic#util#findFileInParent(a:file, expand('%:p:h', 1)) |
||||
|
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 |
||||
|
|
||||
|
" convert filename into absolute path |
||||
|
let filepath = fnamemodify(config, ':p:h') |
||||
|
|
||||
|
" try to read config file |
||||
|
try |
||||
|
let lines = readfile(config) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E48[45]/ |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: error reading file') |
||||
|
return '' |
||||
|
endtry |
||||
|
|
||||
|
" filter out empty lines and comments |
||||
|
call filter(lines, 'v:val !~# ''\v^(\s*#|$)''') |
||||
|
|
||||
|
" remove leading and trailing spaces |
||||
|
call map(lines, 'substitute(v:val, ''\m^\s\+'', "", "")') |
||||
|
call map(lines, 'substitute(v:val, ''\m\s\+$'', "", "")') |
||||
|
|
||||
|
let parameters = [] |
||||
|
for line in lines |
||||
|
let matches = matchstr(line, '\m\C^\s*-I\s*\zs.\+') |
||||
|
if matches !=# '' |
||||
|
" this one looks like an absolute path |
||||
|
if match(matches, '\m^\%(/\|\a:\)') != -1 |
||||
|
call add(parameters, '-I' . matches) |
||||
|
else |
||||
|
call add(parameters, '-I' . filepath . syntastic#util#Slash() . matches) |
||||
|
endif |
||||
|
else |
||||
|
call add(parameters, line) |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return join(map(parameters, 'syntastic#util#shescape(v:val)')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" GetLocList() for C-like compilers |
||||
|
function! syntastic#c#GetLocList(filetype, subchecker, options) abort " {{{2 |
||||
|
try |
||||
|
let flags = s:_get_cflags(a:filetype, a:subchecker, a:options) |
||||
|
catch /\m\C^Syntastic: skip checks$/ |
||||
|
return [] |
||||
|
endtry |
||||
|
|
||||
|
let makeprg = syntastic#util#shexpand(g:syntastic_{a:filetype}_compiler) . |
||||
|
\ ' ' . flags . ' ' . syntastic#util#shexpand('%') |
||||
|
|
||||
|
let errorformat = s:_get_checker_var('g', a:filetype, a:subchecker, 'errorformat', a:options['errorformat']) |
||||
|
|
||||
|
let postprocess = s:_get_checker_var('g', a:filetype, a:subchecker, 'remove_include_errors', 0) ? |
||||
|
\ ['filterForeignErrors'] : [] |
||||
|
|
||||
|
" process makeprg |
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'postprocess': postprocess }) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
" initialize c/cpp syntax checker handlers |
||||
|
function! s:_init() abort " {{{2 |
||||
|
let s:handlers = [] |
||||
|
let s:cflags = {} |
||||
|
|
||||
|
call s:_registerHandler('\m\<cairo', 's:_checkPackage', ['cairo', 'cairo']) |
||||
|
call s:_registerHandler('\m\<freetype', 's:_checkPackage', ['freetype', 'freetype2', 'freetype']) |
||||
|
call s:_registerHandler('\m\<glade', 's:_checkPackage', ['glade', 'libglade-2.0', 'libglade']) |
||||
|
call s:_registerHandler('\m\<glib', 's:_checkPackage', ['glib', 'glib-2.0', 'glib']) |
||||
|
call s:_registerHandler('\m\<gtk', 's:_checkPackage', ['gtk', 'gtk+-2.0', 'gtk+', 'glib-2.0', 'glib']) |
||||
|
call s:_registerHandler('\m\<libsoup', 's:_checkPackage', ['libsoup', 'libsoup-2.4', 'libsoup-2.2']) |
||||
|
call s:_registerHandler('\m\<libxml', 's:_checkPackage', ['libxml', 'libxml-2.0', 'libxml']) |
||||
|
call s:_registerHandler('\m\<pango', 's:_checkPackage', ['pango', 'pango']) |
||||
|
call s:_registerHandler('\m\<SDL', 's:_checkPackage', ['sdl', 'sdl']) |
||||
|
call s:_registerHandler('\m\<opengl', 's:_checkPackage', ['opengl', 'gl']) |
||||
|
call s:_registerHandler('\m\<webkit', 's:_checkPackage', ['webkit', 'webkit-1.0']) |
||||
|
|
||||
|
call s:_registerHandler('\m\<php\.h\>', 's:_checkPhp', []) |
||||
|
call s:_registerHandler('\m\<Python\.h\>', 's:_checkPython', []) |
||||
|
call s:_registerHandler('\m\<ruby', 's:_checkRuby', []) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" register a handler dictionary object |
||||
|
function! s:_registerHandler(regex, function, args) abort " {{{2 |
||||
|
let handler = {} |
||||
|
let handler['regex'] = a:regex |
||||
|
let handler['func'] = function(a:function) |
||||
|
let handler['args'] = a:args |
||||
|
call add(s:handlers, handler) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" try to find library with 'pkg-config' |
||||
|
" search possible libraries from first to last given |
||||
|
" argument until one is found |
||||
|
function! s:_checkPackage(name, ...) abort " {{{2 |
||||
|
if executable('pkg-config') |
||||
|
if !has_key(s:cflags, a:name) |
||||
|
for pkg in a:000 |
||||
|
let pkg_flags = syntastic#util#system('pkg-config --cflags ' . pkg) |
||||
|
" since we cannot necessarily trust the pkg-config exit code |
||||
|
" we have to check for an error output as well |
||||
|
if v:shell_error == 0 && pkg_flags !~? 'not found' |
||||
|
let pkg_flags = ' ' . substitute(pkg_flags, "\n", '', '') |
||||
|
let s:cflags[a:name] = pkg_flags |
||||
|
return pkg_flags |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
return s:cflags[a:name] |
||||
|
endif |
||||
|
endif |
||||
|
return '' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" try to find PHP includes with 'php-config' |
||||
|
function! s:_checkPhp() abort " {{{2 |
||||
|
if executable('php-config') |
||||
|
if !has_key(s:cflags, 'php') |
||||
|
let s:cflags['php'] = syntastic#util#system('php-config --includes') |
||||
|
let s:cflags['php'] = ' ' . substitute(s:cflags['php'], "\n", '', '') |
||||
|
endif |
||||
|
return s:cflags['php'] |
||||
|
endif |
||||
|
return '' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" try to find the python headers with distutils |
||||
|
function! s:_checkPython() abort " {{{2 |
||||
|
if executable('python') |
||||
|
if !has_key(s:cflags, 'python') |
||||
|
let s:cflags['python'] = syntastic#util#system('python -c ''from distutils import ' . |
||||
|
\ 'sysconfig; import sys; sys.stdout.write(sysconfig.get_python_inc())''') |
||||
|
let s:cflags['python'] = substitute(s:cflags['python'], "\n", '', '') |
||||
|
let s:cflags['python'] = ' -I' . s:cflags['python'] |
||||
|
endif |
||||
|
return s:cflags['python'] |
||||
|
endif |
||||
|
return '' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" try to find the ruby headers with 'rbconfig' |
||||
|
function! s:_checkRuby() abort " {{{2 |
||||
|
if executable('ruby') |
||||
|
if !has_key(s:cflags, 'ruby') |
||||
|
let s:cflags['ruby'] = syntastic#util#system('ruby -r rbconfig -e ' . |
||||
|
\ '''puts RbConfig::CONFIG["rubyhdrdir"] || RbConfig::CONFIG["archdir"]''') |
||||
|
let s:cflags['ruby'] = substitute(s:cflags['ruby'], "\n", '', '') |
||||
|
let s:cflags['ruby'] = ' -I' . s:cflags['ruby'] |
||||
|
endif |
||||
|
return s:cflags['ruby'] |
||||
|
endif |
||||
|
return '' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
" resolve checker-related user variables |
||||
|
function! s:_get_checker_var(scope, filetype, subchecker, name, default) abort " {{{2 |
||||
|
let prefix = a:scope . ':' . 'syntastic_' |
||||
|
if exists(prefix . a:filetype . '_' . a:subchecker . '_' . a:name) |
||||
|
return {a:scope}:syntastic_{a:filetype}_{a:subchecker}_{a:name} |
||||
|
elseif exists(prefix . a:filetype . '_' . a:name) |
||||
|
return {a:scope}:syntastic_{a:filetype}_{a:name} |
||||
|
else |
||||
|
return a:default |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" resolve user CFLAGS |
||||
|
function! s:_get_cflags(ft, ck, opts) abort " {{{2 |
||||
|
" determine whether to parse header files as well |
||||
|
if has_key(a:opts, 'header_names') && expand('%', 1) =~? a:opts['header_names'] |
||||
|
if s:_get_checker_var('g', a:ft, a:ck, 'check_header', 0) |
||||
|
let flags = get(a:opts, 'header_flags', '') . ' -c ' . syntastic#c#NullOutput() |
||||
|
else |
||||
|
" checking headers when check_header is unset: bail out |
||||
|
throw 'Syntastic: skip checks' |
||||
|
endif |
||||
|
else |
||||
|
let flags = get(a:opts, 'main_flags', '') |
||||
|
endif |
||||
|
|
||||
|
let flags .= ' ' . s:_get_checker_var('g', a:ft, a:ck, 'compiler_options', '') . ' ' . s:_get_include_dirs(a:ft) |
||||
|
|
||||
|
" check if the user manually set some cflags |
||||
|
let b_cflags = s:_get_checker_var('b', a:ft, a:ck, 'cflags', '') |
||||
|
if b_cflags !=# '' |
||||
|
let flags .= ' ' . b_cflags |
||||
|
endif |
||||
|
|
||||
|
" add optional config file parameters |
||||
|
let config_file = s:_get_checker_var('b', a:ft, a:ck, 'config_file', s:_get_checker_var('g', a:ft, a:ck, 'config_file', '')) |
||||
|
let flags .= ' ' . syntastic#c#ReadConfig(config_file) |
||||
|
|
||||
|
if b_cflags ==# '' && (a:ft ==# 'c' || a:ft ==# 'cpp') && !s:_get_checker_var('g', a:ft, a:ck, 'no_include_search', 0) |
||||
|
" refresh the include file search if desired |
||||
|
if s:_get_checker_var('g', a:ft, a:ck, 'auto_refresh_includes', 0) |
||||
|
let flags .= ' ' . s:_search_headers() |
||||
|
else |
||||
|
" search for header includes if not cached already |
||||
|
if !exists('b:syntastic_' . a:ft . '_includes') |
||||
|
let b:syntastic_{a:ft}_includes = s:_search_headers() |
||||
|
endif |
||||
|
let flags .= ' ' . b:syntastic_{a:ft}_includes |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
return flags |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" get the gcc include directory argument depending on the default |
||||
|
" includes and the optional user-defined 'g:syntastic_c_include_dirs' |
||||
|
function! s:_get_include_dirs(filetype) abort " {{{2 |
||||
|
let include_dirs = [] |
||||
|
|
||||
|
if a:filetype =~# '\v^%(c|cpp|objc|objcpp)$' && |
||||
|
\ (!exists('g:syntastic_'.a:filetype.'_no_default_include_dirs') || |
||||
|
\ !g:syntastic_{a:filetype}_no_default_include_dirs) |
||||
|
let include_dirs = copy(s:default_includes) |
||||
|
endif |
||||
|
|
||||
|
if exists('g:syntastic_'.a:filetype.'_include_dirs') |
||||
|
call extend(include_dirs, g:syntastic_{a:filetype}_include_dirs) |
||||
|
endif |
||||
|
|
||||
|
return join(map(syntastic#util#unique(include_dirs), 'syntastic#util#shescape("-I" . v:val)')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" search the first 100 lines for include statements that are |
||||
|
" given in the handlers dictionary |
||||
|
function! s:_search_headers() abort " {{{2 |
||||
|
let includes = '' |
||||
|
let files = [] |
||||
|
let found = [] |
||||
|
let lines = filter(getline(1, 100), 'v:val =~# ''\m^\s*#\s*include''') |
||||
|
|
||||
|
" search current buffer |
||||
|
for line in lines |
||||
|
let file = matchstr(line, '\m"\zs\S\+\ze"') |
||||
|
if file !=# '' |
||||
|
call add(files, file) |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
for handler in s:handlers |
||||
|
if line =~# handler['regex'] |
||||
|
let includes .= call(handler['func'], handler['args']) |
||||
|
call add(found, handler['regex']) |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
|
||||
|
" search included headers |
||||
|
for hfile in files |
||||
|
if hfile !=# '' |
||||
|
let filename = expand('%:p:h', 1) . syntastic#util#Slash() . hfile |
||||
|
|
||||
|
try |
||||
|
let lines = readfile(filename, '', 100) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E484/ |
||||
|
continue |
||||
|
endtry |
||||
|
|
||||
|
call filter(lines, 'v:val =~# ''\m^\s*#\s*include''') |
||||
|
|
||||
|
for handler in s:handlers |
||||
|
if index(found, handler['regex']) != -1 |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
for line in lines |
||||
|
if line =~# handler['regex'] |
||||
|
let includes .= call(handler['func'], handler['args']) |
||||
|
call add(found, handler['regex']) |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return includes |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" default include directories |
||||
|
let s:default_includes = [ |
||||
|
\ '.', |
||||
|
\ '..', |
||||
|
\ 'include', |
||||
|
\ 'includes', |
||||
|
\ '..' . syntastic#util#Slash() . 'include', |
||||
|
\ '..' . syntastic#util#Slash() . 'includes' ] |
||||
|
|
||||
|
call s:_init() |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,222 @@ |
|||||
|
if exists('g:loaded_syntastic_log_autoload') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_log_autoload = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
let s:one_time_notices_issued = [] |
||||
|
|
||||
|
" Public functions {{{1 |
||||
|
|
||||
|
function! syntastic#log#info(msg) abort " {{{2 |
||||
|
echomsg 'syntastic: info: ' . a:msg |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#warn(msg) abort " {{{2 |
||||
|
echohl WarningMsg |
||||
|
echomsg 'syntastic: warning: ' . a:msg |
||||
|
echohl None |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#error(msg) abort " {{{2 |
||||
|
execute 'normal! \<Esc>' |
||||
|
echohl ErrorMsg |
||||
|
echomsg 'syntastic: error: ' . a:msg |
||||
|
echohl None |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#oneTimeWarn(msg) abort " {{{2 |
||||
|
if index(s:one_time_notices_issued, a:msg) >= 0 |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call add(s:one_time_notices_issued, a:msg) |
||||
|
call syntastic#log#warn(a:msg) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" @vimlint(EVL102, 1, l:OLD_VAR) |
||||
|
function! syntastic#log#deprecationWarn(old, new, ...) abort " {{{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 |
||||
|
|
||||
|
call syntastic#log#oneTimeWarn(msg) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL102, 0, l:OLD_VAR) |
||||
|
|
||||
|
function! syntastic#log#debug(level, msg, ...) abort " {{{2 |
||||
|
if !s:_isDebugEnabled(a:level) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let leader = s:_log_timestamp() |
||||
|
call s:_logRedirect(1) |
||||
|
|
||||
|
if a:0 |
||||
|
" filter out dictionary functions |
||||
|
echomsg leader . a:msg . ' ' . |
||||
|
\ strtrans(string(type(a:1) == type({}) || type(a:1) == type([]) ? |
||||
|
\ filter(copy(a:1), 'type(v:val) != type(function("tr"))') : a:1)) |
||||
|
else |
||||
|
echomsg leader . a:msg |
||||
|
endif |
||||
|
|
||||
|
call s:_logRedirect(0) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#debugShowOptions(level, names) abort " {{{2 |
||||
|
if !s:_isDebugEnabled(a:level) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let leader = s:_log_timestamp() |
||||
|
call s:_logRedirect(1) |
||||
|
|
||||
|
let vlist = copy(type(a:names) == type('') ? [a:names] : a:names) |
||||
|
let add_shell = index(vlist, 'shell') >= 0 && &shell !=# syntastic#util#var('shell') |
||||
|
if !empty(vlist) |
||||
|
call map(vlist, "'&' . v:val . ' = ' . strtrans(string(eval('&' . v:val))) . (s:_is_modified(v:val) ? ' (!)' : '')") |
||||
|
if add_shell |
||||
|
call add(vlist, 'u:shell = ' . strtrans(string(syntastic#util#var('shell'))) . ' (!)') |
||||
|
endif |
||||
|
echomsg leader . join(vlist, ', ') |
||||
|
endif |
||||
|
call s:_logRedirect(0) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#debugShowVariables(level, names) abort " {{{2 |
||||
|
if !s:_isDebugEnabled(a:level) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let leader = s:_log_timestamp() |
||||
|
call s:_logRedirect(1) |
||||
|
|
||||
|
let vlist = type(a:names) == type('') ? [a:names] : a:names |
||||
|
for name in vlist |
||||
|
let msg = s:_format_variable(name) |
||||
|
if msg !=# '' |
||||
|
echomsg leader . msg |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
call s:_logRedirect(0) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#debugDump(level) abort " {{{2 |
||||
|
if !s:_isDebugEnabled(a:level) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call syntastic#log#debugShowVariables( a:level, sort(keys(g:_SYNTASTIC_DEFAULTS)) ) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#log#ndebug(level, title, messages) abort " {{{2 |
||||
|
if s:_isDebugEnabled(a:level) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call syntastic#log#error(a:title) |
||||
|
if type(a:messages) == type([]) |
||||
|
for msg in a:messages |
||||
|
echomsg msg |
||||
|
endfor |
||||
|
else |
||||
|
echomsg a:messages |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
function! s:_isDebugEnabled_smart(level) abort " {{{2 |
||||
|
return and(g:syntastic_debug, a:level) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_isDebugEnabled_dumb(level) abort " {{{2 |
||||
|
" poor man's bit test for bit N, assuming a:level == 2**N |
||||
|
return (g:syntastic_debug / a:level) % 2 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
let s:_isDebugEnabled = function(exists('*and') ? 's:_isDebugEnabled_smart' : 's:_isDebugEnabled_dumb') |
||||
|
lockvar s:_isDebugEnabled |
||||
|
|
||||
|
function! s:_logRedirect(on) abort " {{{2 |
||||
|
if exists('g:syntastic_debug_file') |
||||
|
if a:on |
||||
|
try |
||||
|
execute 'redir >> ' . fnameescape(expand(g:syntastic_debug_file, 1)) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:/ |
||||
|
silent! redir END |
||||
|
unlet g:syntastic_debug_file |
||||
|
endtry |
||||
|
else |
||||
|
silent! redir END |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
function! s:_log_timestamp_smart() abort " {{{2 |
||||
|
return printf('syntastic: %f: ', reltimefloat(reltime(g:_SYNTASTIC_START))) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_log_timestamp_dumb() abort " {{{2 |
||||
|
return 'syntastic: ' . split(reltimestr(reltime(g:_SYNTASTIC_START)))[0] . ': ' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
let s:_log_timestamp = function(has('float') && exists('*reltimefloat') ? 's:_log_timestamp_smart' : 's:_log_timestamp_dumb') |
||||
|
lockvar s:_log_timestamp |
||||
|
|
||||
|
function! s:_format_variable(name) abort " {{{2 |
||||
|
let vals = [] |
||||
|
if exists('g:syntastic_' . a:name) |
||||
|
call add(vals, 'g:syntastic_' . a:name . ' = ' . strtrans(string(g:syntastic_{a:name}))) |
||||
|
endif |
||||
|
if exists('b:syntastic_' . a:name) |
||||
|
call add(vals, 'b:syntastic_' . a:name . ' = ' . strtrans(string(b:syntastic_{a:name}))) |
||||
|
endif |
||||
|
|
||||
|
return join(vals, ', ') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_is_modified(name) abort " {{{2 |
||||
|
if !exists('s:option_defaults') |
||||
|
let s:option_defaults = {} |
||||
|
endif |
||||
|
if !has_key(s:option_defaults, a:name) |
||||
|
let opt_save = eval('&' . a:name) |
||||
|
execute 'set ' . a:name . '&' |
||||
|
let s:option_defaults[a:name] = eval('&' . a:name) |
||||
|
execute 'let &' . a:name . ' = ' . string(opt_save) |
||||
|
endif |
||||
|
|
||||
|
return s:option_defaults[a:name] !=# eval('&' . a:name) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,84 @@ |
|||||
|
if exists('g:loaded_syntastic_postprocess_autoload') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_postprocess_autoload = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
" Public functions {{{1 |
||||
|
|
||||
|
" merge consecutive blanks |
||||
|
function! syntastic#postprocess#compressWhitespace(errors) abort " {{{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 " }}}2 |
||||
|
|
||||
|
" remove spurious CR under Cygwin |
||||
|
function! syntastic#postprocess#cygwinRemoveCR(errors) abort " {{{2 |
||||
|
if has('win32unix') |
||||
|
for e in a:errors |
||||
|
let e['text'] = substitute(e['text'], '\r', '', 'g') |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
return a:errors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" decode XML entities |
||||
|
function! syntastic#postprocess#decodeXMLEntities(errors) abort " {{{2 |
||||
|
for e in a:errors |
||||
|
let e['text'] = syntastic#util#decodeXMLEntities(e['text']) |
||||
|
endfor |
||||
|
|
||||
|
return a:errors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" filter out errors referencing other files |
||||
|
function! syntastic#postprocess#filterForeignErrors(errors) abort " {{{2 |
||||
|
return filter(copy(a:errors), 'get(v:val, "bufnr") == ' . bufnr('')) |
||||
|
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) abort " {{{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 |
||||
|
|
||||
|
" convert error messages from UTF-8 to the current encoding |
||||
|
function! syntastic#postprocess#iconv(errors) abort " {{{2 |
||||
|
if has('iconv') && &encoding !=# '' && &encoding !=# 'utf-8' |
||||
|
for e in a:errors |
||||
|
let e['text'] = iconv(e['text'], "utf-8", &encoding) |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
return a:errors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,809 @@ |
|||||
|
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#bandit(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
let json = s:_decode_JSON(join(a:errors, '')) |
||||
|
|
||||
|
if type(json) == type({}) && has_key(json, 'results') && type(json['results']) == type([]) |
||||
|
for issue in json['results'] |
||||
|
if type(issue) == type({}) |
||||
|
try |
||||
|
call add(out, |
||||
|
\ issue['filename'] . ':' . |
||||
|
\ issue['line_number'] . ':' . |
||||
|
\ { 'LOW': 'I', 'MEDIUM': 'W', 'HIGH': 'E' }[issue['issue_severity']] . ':' . |
||||
|
\ issue['test_id'][1:] . ':' . |
||||
|
\ issue['issue_text'] . |
||||
|
\ ' [' . issue['test_name'] . '] (confidence: ' . issue['issue_confidence'] . ')') |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker python/bandit: unrecognized error item ' . string(issue)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker python/bandit: unrecognized error item ' . string(issue)) |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker python/bandit: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#cabal(errors) abort " {{{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) abort " {{{2 |
||||
|
let out = [] |
||||
|
let fname = expand('%', 1) |
||||
|
for err in a:errors |
||||
|
if match(err, '\m<error\>') > -1 |
||||
|
let line = str2nr(matchstr(err, '\m\<line="\zs\d\+\ze"')) |
||||
|
if line == 0 |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
let col = str2nr(matchstr(err, '\m\<column="\zs\d\+\ze"')) |
||||
|
|
||||
|
let type = matchstr(err, '\m\<severity="\zs.\ze') |
||||
|
if type !~? '^[EW]' |
||||
|
let type = 'E' |
||||
|
endif |
||||
|
|
||||
|
let message = syntastic#util#decodeXMLEntities(matchstr(err, '\m\<message="\zs[^"]\+\ze"')) |
||||
|
|
||||
|
call add(out, join([fname, type, line, col, message], ':')) |
||||
|
elseif match(err, '\m<file name="') > -1 |
||||
|
let fname = syntastic#util#decodeXMLEntities(matchstr(err, '\v\<file name\="\zs[^"]+\ze"')) |
||||
|
endif |
||||
|
endfor |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#cppcheck(errors) abort " {{{2 |
||||
|
return map(copy(a:errors), 'substitute(v:val, ''\v^\[[^]]+\]\zs( -\> \[[^]]+\])+\ze:'', "", "")') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#dockerfile_lint(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
let json = s:_decode_JSON(join(a:errors, '')) |
||||
|
|
||||
|
if type(json) == type({}) |
||||
|
try |
||||
|
let data = json['error']['data'] + json['warn']['data'] + json['info']['data'] |
||||
|
for e in data |
||||
|
let type = toupper(e['level'][0]) |
||||
|
if type ==# 'I' |
||||
|
let type = 'W' |
||||
|
let style = 1 |
||||
|
else |
||||
|
let style = 0 |
||||
|
endif |
||||
|
|
||||
|
let line = get(e, 'line', 1) |
||||
|
let message = e['message'] |
||||
|
if has_key(e, 'description') && e['description'] !=# 'None' |
||||
|
let message = message . '. ' . e['description'] |
||||
|
endif |
||||
|
|
||||
|
let msg = |
||||
|
\ type . ':' . |
||||
|
\ style . ':' . |
||||
|
\ line . ':' . |
||||
|
\ message |
||||
|
call add(out, msg) |
||||
|
endfor |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker dockerfile/dockerfile_lint: unrecognized error format (crashed checker?)') |
||||
|
let out = [] |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker dockerfile/dockerfile_lint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#dscanner(errors) abort " {{{2 |
||||
|
let idx = 0 |
||||
|
while idx < len(a:errors) && a:errors[idx][0] !=# '{' |
||||
|
let idx += 1 |
||||
|
endwhile |
||||
|
let errs = s:_decode_JSON(join(a:errors[idx :], '')) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(errs) == type({}) && has_key(errs, 'issues') && type(errs['issues']) == type([]) |
||||
|
for issue in errs['issues'] |
||||
|
try |
||||
|
call add(out, |
||||
|
\ issue['fileName'] . ':' . |
||||
|
\ issue['line'] . ':' . |
||||
|
\ issue['column'] . ':' . |
||||
|
\ issue['message'] . ' [' . issue['key'] . ']') |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker d/dscanner: unrecognized error item ' . string(issue)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker d/dscanner: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#flow(errors) abort " {{{2 |
||||
|
let idx = 0 |
||||
|
while idx < len(a:errors) && a:errors[idx][0] !=# '{' |
||||
|
let idx += 1 |
||||
|
endwhile |
||||
|
let errs = s:_decode_JSON(join(a:errors[idx :], '')) |
||||
|
|
||||
|
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'] && str2nr(m['end']) > 0 ? 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: unrecognized error format (crashed checker?)') |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/flow: unrecognized error format (crashed checker?)') |
||||
|
let out = [] |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/flow: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#iconv(errors) abort " {{{2 |
||||
|
return |
||||
|
\ has('iconv') && &encoding !=# '' && &encoding !=# 'utf-8' ? |
||||
|
\ map(a:errors, 'iconv(v:val, "utf-8", &encoding)') : |
||||
|
\ a:errors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#jscs(errors) abort " {{{2 |
||||
|
let errs = join(a:errors, '') |
||||
|
if errs ==# '' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
let json = s:_decode_JSON(errs) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(json) == type({}) |
||||
|
for fname in keys(json) |
||||
|
if type(json[fname]) == type([]) |
||||
|
for e in json[fname] |
||||
|
try |
||||
|
let e['message'] = substitute(e['message'], "\n", ' ', 'g') |
||||
|
cal add(out, fname . ':' . e['line'] . ':' . e['column'] . ':' . e['message']) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker javascript/jscs: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
endtry |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/jscs: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/jscs: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#killEmpty(errors) abort " {{{2 |
||||
|
return filter(copy(a:errors), 'v:val !=# ""') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#lynt(errors) abort " {{{2 |
||||
|
let errs = join(a:errors, '') |
||||
|
if errs ==# '' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
let json = s:_decode_JSON(errs) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(json) == type([]) |
||||
|
for err in json |
||||
|
if type(err) == type({}) && type(get(err, 'filePath')) == type('') && type(get(err, 'errors')) == type([]) |
||||
|
let fname = get(err, 'filePath') |
||||
|
|
||||
|
for e in get(err, 'errors') |
||||
|
if type(e) == type({}) |
||||
|
try |
||||
|
let line = e['line'] |
||||
|
let col = e['column'] |
||||
|
let ecol = line == get(e, 'endLine') ? get(e, 'endColumn') : 0 |
||||
|
let msg = e['message'] . ' [' . e['ruleName'] . ']' |
||||
|
|
||||
|
cal add(out, join([fname, line, col, ecol, msg], ':')) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker javascript/lynt: unrecognized error item ' . string(e)) |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/lynt unrecognized error item ' . string(e)) |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/lynt unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#perl(errors) abort " {{{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 |
||||
|
|
||||
|
function! syntastic#preprocess#perl6(errors) abort " {{{2 |
||||
|
if a:errors[0] ==# 'Syntax OK' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
let errs = s:_decode_JSON(join(a:errors, '')) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(errs) == type({}) |
||||
|
try |
||||
|
for val in values(errs) |
||||
|
let line = get(val, 'line', 0) |
||||
|
let pos = get(val, 'pos', 0) |
||||
|
if pos && has('byte_offset') |
||||
|
let line_pos = byte2line(pos + 1) |
||||
|
let column = line_pos > 0 ? pos - line2byte(line_pos) + 2 : 0 |
||||
|
else |
||||
|
let column = 0 |
||||
|
endif |
||||
|
|
||||
|
call add(out, join([ |
||||
|
\ get(val, 'filename', ''), |
||||
|
\ line, |
||||
|
\ column, |
||||
|
\ get(val, 'message', '') ], ':')) |
||||
|
endfor |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker perl6/perl6: unrecognized error item ' . string(val)) |
||||
|
let out = [] |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker perl6/perl6: unrecognized error format') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#prospector(errors) abort " {{{2 |
||||
|
let errs = join(a:errors, '') |
||||
|
if errs ==# '' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
let json = s:_decode_JSON(errs) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(json) == type({}) && has_key(json, 'messages') |
||||
|
if type(json['messages']) == type([]) |
||||
|
for e in json['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: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker python/prospector: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker python/prospector: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
else |
||||
|
call syntastic#log#warn('checker python/prospector: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#rparse(errors) abort " {{{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#remark_lint(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
let fname = expand('%', 1) |
||||
|
|
||||
|
for err in a:errors |
||||
|
if err =~# '\m^\f\+$' |
||||
|
let fname = err |
||||
|
|
||||
|
elseif err =~# '\v^\s+\d+:\d+\s+%(warning|error)\s.*remark-lint$' |
||||
|
let parts = matchlist(err, '\v^\s+(\d+):(\d+)\s+([ew])\S+\s+(.{-})\s+(\S+)\s+remark-lint$') |
||||
|
if len(parts) >6 |
||||
|
let line = str2nr(parts[1]) |
||||
|
let col = str2nr(parts[2]) |
||||
|
let type = parts[3] |
||||
|
let message = parts[4] . ' [' . parts[5] . ']' |
||||
|
call add(out, join([fname, type, line, col, message], ':')) |
||||
|
else |
||||
|
call syntastic#log#warn('checker markdown/remark_lint: unrecognized error item ' . string(err)) |
||||
|
endif |
||||
|
|
||||
|
elseif err =~# '\v^\s+\d+:\d+-\d+:\d+\s+%(warning|error)\s.*remark-lint$' |
||||
|
let parts = matchlist(err, '\v^\s+(\d+):(\d+)-(\d+):(\d+)\s+([ew])\S+\s+(.{-})\s+(\S+)\s+remark-lint$') |
||||
|
if len(parts) >8 |
||||
|
let line1 = str2nr(parts[1]) |
||||
|
let col1 = str2nr(parts[2]) |
||||
|
let line2 = str2nr(parts[3]) |
||||
|
let col2 = str2nr(parts[4]) - 1 |
||||
|
let type = parts[5] |
||||
|
let message = parts[6] . ' [' . parts[7] . ']' |
||||
|
if line1 == line2 |
||||
|
call add(out, join([fname, type, line1, col1, col2, message], ':')) |
||||
|
else |
||||
|
call add(out, join([fname, type, line1, col1, message], ':')) |
||||
|
endif |
||||
|
else |
||||
|
call syntastic#log#warn('checker markdown/remark_lint: unrecognized error item ' . string(err)) |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#scss_lint(errors) abort " {{{2 |
||||
|
let errs = join(a:errors, '') |
||||
|
if errs ==# '' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
let json = s:_decode_JSON(errs) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(json) == type({}) |
||||
|
for fname in keys(json) |
||||
|
if type(json[fname]) == type([]) |
||||
|
for e in json[fname] |
||||
|
try |
||||
|
cal add(out, fname . ':' . |
||||
|
\ e['severity'][0] . ':' . |
||||
|
\ e['line'] . ':' . |
||||
|
\ e['column'] . ':' . |
||||
|
\ e['length'] . ':' . |
||||
|
\ ( has_key(e, 'linter') ? e['linter'] . ': ' : '' ) . |
||||
|
\ e['reason']) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker scss/scss_lint: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
endtry |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker scss/scss_lint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker scss/scss_lint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#stylelint(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
|
||||
|
" CssSyntaxError: /path/to/file.css:2:11: Missed semicolon |
||||
|
let parts = matchlist(a:errors[0], '\v^CssSyntaxError: (.{-1,}):(\d+):(\d+): (.+)') |
||||
|
if len(parts) > 4 |
||||
|
call add(out, 'E:' . join(parts[1:4], ':')) |
||||
|
else |
||||
|
let errs = s:_decode_JSON(join(a:errors, '')) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(errs) == type([]) && len(errs) == 1 && type(errs[0]) == type({}) && |
||||
|
\ has_key(errs[0], 'source') && has_key(errs[0], 'warnings') && type(errs[0]['warnings']) == type([]) |
||||
|
|
||||
|
for e in errs[0]['warnings'] |
||||
|
try |
||||
|
let severity = type(e['severity']) == type(0) ? ['W', 'E'][e['severity']-1] : e['severity'][0] |
||||
|
let msg = |
||||
|
\ severity . ':' . |
||||
|
\ errs[0]['source'] . ':' . |
||||
|
\ e['line'] . ':' . |
||||
|
\ e['column'] . ':' . |
||||
|
\ e['text'] |
||||
|
call add(out, msg) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker css/stylelint: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker css/stylelint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
endif |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#tern_lint(errors) abort " {{{2 |
||||
|
let errs = join(a:errors, '') |
||||
|
let json = s:_decode_JSON(errs) |
||||
|
|
||||
|
echomsg string(json) |
||||
|
let out = [] |
||||
|
if type(json) == type({}) && has_key(json, 'messages') && type(json['messages']) == type([]) |
||||
|
for e in json['messages'] |
||||
|
try |
||||
|
let line_from = byte2line(e['from'] + 1) |
||||
|
if line_from > 0 |
||||
|
let line = line_from |
||||
|
let column = e['from'] - line2byte(line_from) + 2 |
||||
|
let line_to = byte2line(e['from'] + 1) |
||||
|
let hl = line_to == line ? e['to'] - line2byte(line_to) + 1 : 0 |
||||
|
else |
||||
|
let line = 0 |
||||
|
let column = 0 |
||||
|
let hl = 0 |
||||
|
endif |
||||
|
|
||||
|
if column < 0 |
||||
|
let column = 0 |
||||
|
endif |
||||
|
if hl < 0 |
||||
|
let hl = 0 |
||||
|
endif |
||||
|
|
||||
|
call add(out, |
||||
|
\ e['file'] . ':' . |
||||
|
\ e['severity'][0] . ':' . |
||||
|
\ line . ':' . |
||||
|
\ column . ':' . |
||||
|
\ hl . ':' . |
||||
|
\ e['message']) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker javascript/tern_lint: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
endtry |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker javascript/tern_lint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
echomsg string(out) |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#tslint(errors) abort " {{{2 |
||||
|
return map(copy(a:errors), 'substitute(v:val, ''\v^((ERROR|WARNING): )?\zs(\([^)]+\))\s(.+)$'', ''\4 \3'', "")') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#validator(errors) abort " {{{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 |
||||
|
|
||||
|
function! syntastic#preprocess#vint(errors) abort " {{{2 |
||||
|
let errs = s:_decode_JSON(join(a:errors, '')) |
||||
|
|
||||
|
let out = [] |
||||
|
if type(errs) == type([]) |
||||
|
for e in errs |
||||
|
if type(e) == type({}) |
||||
|
try |
||||
|
let msg = |
||||
|
\ e['file_path'] . ':' . |
||||
|
\ e['line_number'] . ':' . |
||||
|
\ e['column_number'] . ':' . |
||||
|
\ e['severity'][0] . ': ' . |
||||
|
\ e['description'] . ' (' . |
||||
|
\ e['policy_name'] . ')' |
||||
|
|
||||
|
call add(out, msg) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E716/ |
||||
|
call syntastic#log#warn('checker vim/vint: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endtry |
||||
|
else |
||||
|
call syntastic#log#warn('checker vim/vint: unrecognized error item ' . string(e)) |
||||
|
let out = [] |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call syntastic#log#warn('checker vim/vint: unrecognized error format (crashed checker?)') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Workarounds {{{1 |
||||
|
|
||||
|
" In errorformat, \ or % following %f make it depend on isfname. The default |
||||
|
" setting of isfname is crafted to work with completion, rather than general |
||||
|
" filename matching. The result for syntastic is that filenames containing |
||||
|
" spaces (or a few other special characters) can't be matched. |
||||
|
" |
||||
|
" Fixing isfname to address this problem would depend on the set of legal |
||||
|
" characters for filenames on the filesystem the project's files lives on. |
||||
|
" Inferring the kind of filesystem a file lives on, in advance to parsing the |
||||
|
" file's name, is an interesting problem (think f.i. a file loaded from a VFAT |
||||
|
" partition, mounted on Linux). A problem syntastic is not prepared to solve. |
||||
|
" |
||||
|
" As a result, the functions below exist for the only reason to avoid using |
||||
|
" things like %f\, in errorformat. |
||||
|
" |
||||
|
" References: |
||||
|
" https://groups.google.com/forum/#!topic/vim_dev/pTKmZmouhio |
||||
|
" https://vimhelp.appspot.com/quickfix.txt.html#error-file-format |
||||
|
|
||||
|
function! syntastic#preprocess#basex(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
let idx = 0 |
||||
|
while idx < len(a:errors) |
||||
|
let parts = matchlist(a:errors[idx], '\v^\[\S+\] Stopped at (.+), (\d+)/(\d+):') |
||||
|
if len(parts) > 3 |
||||
|
let err = parts[1] . ':' . parts[2] . ':' . parts[3] . ':' |
||||
|
let parts = matchlist(a:errors[idx+1], '\v^\[(.)\D+(\d+)\] (.+)') |
||||
|
if len(parts) > 3 |
||||
|
let err .= (parts[1] ==? 'W' || parts[1] ==? 'E' ? parts[1] : 'E') . ':' . parts[2] . ':' . parts[3] |
||||
|
call add(out, err) |
||||
|
let idx +=1 |
||||
|
endif |
||||
|
elseif a:errors[idx] =~# '\m^\[' |
||||
|
" unparseable errors |
||||
|
call add(out, a:errors[idx]) |
||||
|
endif |
||||
|
let idx +=1 |
||||
|
endwhile |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#bro(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
for e in a:errors |
||||
|
let parts = matchlist(e, '\v^%(fatal )?(error|warning) in (.{-1,}), line (\d+): (.+)') |
||||
|
if len(parts) > 4 |
||||
|
let parts[1] = parts[1][0] |
||||
|
call add(out, join(parts[1:4], ':')) |
||||
|
endif |
||||
|
endfor |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#coffeelint(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
for e in a:errors |
||||
|
let parts = matchlist(e, '\v^(.{-1,}),(\d+)%(,\d*)?,(error|warn),(.+)') |
||||
|
if len(parts) > 4 |
||||
|
let parts[3] = parts[3][0] |
||||
|
call add(out, join(parts[1:4], ':')) |
||||
|
endif |
||||
|
endfor |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#mypy(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
for e in a:errors |
||||
|
" column numbers |
||||
|
let parts = matchlist(e, '\v^(.{-1,}):(\d+):(\d+): ([ew])%(rror|arning): (.+)') |
||||
|
if len(parts) > 5 |
||||
|
let parts[3] += 1 |
||||
|
call add(out, join(parts[1:5], ':')) |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
" no column numbers |
||||
|
let parts = matchlist(e, '\v^(.{-1,}):(\d+): ([ew])%(rror|arning): (.+)') |
||||
|
if len(parts) > 4 |
||||
|
call add(out, join(parts[1:4], ':')) |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
" obsolete format |
||||
|
let parts = matchlist(e, '\v^(.{-1,}), line (\d+): (.+)') |
||||
|
if len(parts) > 3 |
||||
|
let parts[4] = parts[3] |
||||
|
let parts[3] = 'e' |
||||
|
call add(out, join(parts[1:4], ':')) |
||||
|
endif |
||||
|
endfor |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#preprocess#nix(errors) abort " {{{2 |
||||
|
let out = [] |
||||
|
for e in a:errors |
||||
|
let parts = matchlist(e, '\v^(.{-1,}), at (.{-1,}):(\d+):(\d+)$') |
||||
|
if len(parts) > 4 |
||||
|
call add(out, join(parts[2:4], ':') . ':' . parts[1]) |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
let parts = matchlist(e, '\v^(.{-1,}) at (.{-1,}), line (\d+):') |
||||
|
if len(parts) > 3 |
||||
|
call add(out, parts[2] . ':' . parts[3] . ':' . parts[1]) |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
let parts = matchlist(e, '\v^error: (.{-1,}), in (.{-1,})$') |
||||
|
if len(parts) > 2 |
||||
|
call add(out, parts[2] . ':' . parts[1]) |
||||
|
endif |
||||
|
endfor |
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
" @vimlint(EVL102, 1, l:true) |
||||
|
" @vimlint(EVL102, 1, l:false) |
||||
|
" @vimlint(EVL102, 1, l:null) |
||||
|
function! s:_decode_JSON(json) abort " {{{2 |
||||
|
if a:json ==# '' |
||||
|
return [] |
||||
|
endif |
||||
|
|
||||
|
" The following is inspired by https://github.com/MarcWeber/vim-addon-manager and |
||||
|
" http://stackoverflow.com/questions/17751186/iterating-over-a-string-in-vimscript-or-parse-a-json-file/19105763#19105763 |
||||
|
" A hat tip to Marc Weber for this trick |
||||
|
if substitute(a:json, '\v\"%(\\.|[^"\\])*\"|true|false|null|[+-]?\d+%(\.\d+%([Ee][+-]?\d+)?)?', '', 'g') !~# "[^,:{}[\\] \t]" |
||||
|
" JSON artifacts |
||||
|
let true = 1 |
||||
|
let false = 0 |
||||
|
let null = '' |
||||
|
|
||||
|
try |
||||
|
let object = eval(a:json) |
||||
|
catch |
||||
|
" malformed JSON |
||||
|
let object = '' |
||||
|
endtry |
||||
|
else |
||||
|
let object = '' |
||||
|
endif |
||||
|
|
||||
|
return object |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL102, 0, l:true) |
||||
|
" @vimlint(EVL102, 0, l:false) |
||||
|
" @vimlint(EVL102, 0, l:null) |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,640 @@ |
|||||
|
if exists('g:loaded_syntastic_util_autoload') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_util_autoload = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
" Public functions {{{1 |
||||
|
|
||||
|
function! syntastic#util#isRunningWindows() abort " {{{2 |
||||
|
return has('win16') || has('win32') || has('win64') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#DevNull() abort " {{{2 |
||||
|
if syntastic#util#isRunningWindows() |
||||
|
return 'NUL' |
||||
|
endif |
||||
|
return '/dev/null' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Get directory separator |
||||
|
function! syntastic#util#Slash() abort " {{{2 |
||||
|
return (!exists('+shellslash') || &shellslash) ? '/' : '\' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#CygwinPath(path) abort " {{{2 |
||||
|
return substitute(syntastic#util#system('cygpath -m ' . syntastic#util#shescape(a:path)), "\n", '', 'g') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#system(command) abort " {{{2 |
||||
|
let old_shell = &shell |
||||
|
let old_lc_messages = $LC_MESSAGES |
||||
|
let old_lc_all = $LC_ALL |
||||
|
|
||||
|
let &shell = syntastic#util#var('shell') |
||||
|
let $LC_MESSAGES = 'C' |
||||
|
let $LC_ALL = '' |
||||
|
|
||||
|
let crashed = 0 |
||||
|
let cmd_start = reltime() |
||||
|
try |
||||
|
let out = system(a:command) |
||||
|
catch |
||||
|
if v:exception =~# '\m^Vim\%((\a\+)\)\=:\%(E145\|E484\|E684\)' |
||||
|
" XXX re-throwing unmodified v:exception triggers E608 |
||||
|
throw substitute(v:exception, '.*:\(E145\|E484\|E684\).*', '\1', '') |
||||
|
endif |
||||
|
|
||||
|
let crashed = 1 |
||||
|
call syntastic#log#error('exception running system(' . string(a:command) . '): ' . v:exception) |
||||
|
if syntastic#util#isRunningWindows() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMP = ' . string($TMP) . ', $TEMP = ' . string($TEMP)) |
||||
|
else |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TERM = ' . string($TERM)) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMPDIR = ' . string($TMPDIR)) |
||||
|
endif |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, '$PATH = ' . string($PATH)) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getcwd() = ' . string(getcwd())) |
||||
|
call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, g:_SYNTASTIC_SHELL_OPTIONS) |
||||
|
let out = '' |
||||
|
endtry |
||||
|
let cmd_time = split(reltimestr(reltime(cmd_start)))[0] |
||||
|
|
||||
|
let $LC_ALL = old_lc_all |
||||
|
let $LC_MESSAGES = old_lc_messages |
||||
|
|
||||
|
let &shell = old_shell |
||||
|
|
||||
|
if !crashed && exists('g:_SYNTASTIC_DEBUG_TRACE') |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'system: command run in ' . cmd_time . 's') |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Create a temporary directory |
||||
|
function! syntastic#util#tmpdir() abort " {{{2 |
||||
|
let tempdir = '' |
||||
|
|
||||
|
if (has('unix') || has('mac')) && executable('mktemp') && !has('win32unix') |
||||
|
" TODO: option "-t" to mktemp(1) is not portable |
||||
|
let tmp = $TMPDIR !=# '' ? $TMPDIR : $TMP !=# '' ? $TMP : '/tmp' |
||||
|
let out = split(syntastic#util#system('mktemp -q -d ' . tmp . '/vim-syntastic-' . s:_fuzz() . '-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-' . s:_fuzz() |
||||
|
elseif has('win32unix') |
||||
|
let tempdir = syntastic#util#CygwinPath('/tmp/vim-syntastic-' . s:_fuzz()) |
||||
|
elseif $TMPDIR !=# '' |
||||
|
let tempdir = $TMPDIR . '/vim-syntastic-' . s:_fuzz() |
||||
|
else |
||||
|
let tempdir = '/tmp/vim-syntastic-' . s:_fuzz() |
||||
|
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) abort " {{{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' |
||||
|
call s:_delete(a:what, 'rf') |
||||
|
else |
||||
|
silent! call delete(a:what) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#getbufvar(buf, name, ...) abort " {{{2 |
||||
|
return a:0 ? s:_getbufvar(a:buf, a:name, a:1) : getbufvar(a:buf, a:name) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Search the first 5 lines of the file for a magic number and return a map |
||||
|
" containing the args and the executable |
||||
|
" |
||||
|
" e.g. |
||||
|
" |
||||
|
" #!/usr/bin/perl -f -bar |
||||
|
" |
||||
|
" returns |
||||
|
" |
||||
|
" {'exe': '/usr/bin/perl', 'args': ['-f', '-bar']} |
||||
|
function! syntastic#util#parseShebang(buf) abort " {{{2 |
||||
|
for lnum in range(1, 5) |
||||
|
let line = get(getbufline(a:buf, lnum), 0, '') |
||||
|
if line =~# '^#!' |
||||
|
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 " }}}2 |
||||
|
|
||||
|
" Get the value of a Vim variable. Allow buffer variables to override global ones. |
||||
|
function! syntastic#util#bufRawVar(buf, name, ...) abort " {{{2 |
||||
|
return s:_getbufvar(a:buf, a:name, get(g:, a:name, a:0 ? a:1 : '')) |
||||
|
endfunction "}}}2 |
||||
|
|
||||
|
" Get the value of a syntastic variable. Allow buffer variables to override global ones. |
||||
|
function! syntastic#util#bufVar(buf, name, ...) abort " {{{2 |
||||
|
return call('syntastic#util#bufRawVar', [a:buf, 'syntastic_' . a:name] + a:000) |
||||
|
endfunction "}}}2 |
||||
|
|
||||
|
" Get the value of a Vim variable. Allow local variables to override global ones. |
||||
|
function! syntastic#util#rawVar(name, ...) abort " {{{2 |
||||
|
return get(b:, a:name, get(g:, a:name, a:0 ? a:1 : '')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Get the value of a syntastic variable. Allow local variables to override global ones. |
||||
|
function! syntastic#util#var(name, ...) abort " {{{2 |
||||
|
return call('syntastic#util#rawVar', ['syntastic_' . a:name] + a:000) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Parse a version string. Return an array of version components. |
||||
|
function! syntastic#util#parseVersion(version, ...) abort " {{{2 |
||||
|
return map(split(matchstr( a:version, a:0 ? a:1 : '\v^\D*\zs\d+(\.\d+)+\ze' ), '\m\.'), 'str2nr(v:val)') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Verify that the 'installed' version is at least the 'required' version. |
||||
|
" |
||||
|
" 'installed' and 'required' must be arrays. If they have different lengths, |
||||
|
" 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) abort " {{{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) abort " {{{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 |
||||
|
" still here, thus everything matched |
||||
|
return 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#screenWidth(str, tabstop) abort " {{{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) abort " {{{2 |
||||
|
let old_ruler = &ruler |
||||
|
let old_showcmd = &showcmd |
||||
|
|
||||
|
"This is here because it is possible for some error messages to |
||||
|
"begin with \n which will cause a "press enter" prompt. |
||||
|
let msg = substitute(a:msg, "\n", '', 'g') |
||||
|
|
||||
|
"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(" ", &tabstop - s:_width(v:val) % &tabstop)'), '') . chunks[-1] |
||||
|
let msg = strpart(msg, 0, &columns - 1) |
||||
|
|
||||
|
set noruler noshowcmd |
||||
|
call syntastic#util#redraw(0) |
||||
|
|
||||
|
echo msg |
||||
|
|
||||
|
let &ruler = old_ruler |
||||
|
let &showcmd = old_showcmd |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Check whether a buffer is loaded, listed, and not hidden |
||||
|
function! syntastic#util#bufIsActive(buffer) abort " {{{2 |
||||
|
" convert to number, or hell breaks loose |
||||
|
let buf = str2nr(a:buffer) |
||||
|
|
||||
|
if !bufloaded(buf) || !buflisted(buf) |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
" get rid of hidden buffers |
||||
|
for tab in range(1, tabpagenr('$')) |
||||
|
if index(tabpagebuflist(tab), buf) >= 0 |
||||
|
return 1 |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Start in directory a:where and walk up the parent folders until it finds a |
||||
|
" file named a:what; return path to that file |
||||
|
function! syntastic#util#findFileInParent(what, where) abort " {{{2 |
||||
|
let old_suffixesadd = &suffixesadd |
||||
|
let &suffixesadd = '' |
||||
|
let file = findfile(a:what, escape(a:where, ' ,') . ';') |
||||
|
let &suffixesadd = old_suffixesadd |
||||
|
return file |
||||
|
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#findGlobInParent(what, where) abort " {{{2 |
||||
|
let here = fnamemodify(a:where, ':p') |
||||
|
|
||||
|
let root = syntastic#util#Slash() |
||||
|
if syntastic#util#isRunningWindows() && here[1] ==# ':' |
||||
|
" The drive letter is an ever-green source of fun. That's because |
||||
|
" we don't care about running syntastic on Amiga these days. ;) |
||||
|
let root = fnamemodify(root, ':p') |
||||
|
let root = here[0] . root[1:] |
||||
|
endif |
||||
|
|
||||
|
let old = '' |
||||
|
while here !=# '' |
||||
|
try |
||||
|
" Vim 7.4.279 and later |
||||
|
let p = globpath(here, a:what, 1, 1) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E118/ |
||||
|
let p = split(globpath(here, a:what, 1), "\n") |
||||
|
endtry |
||||
|
|
||||
|
if !empty(p) |
||||
|
return fnamemodify(p[0], ':p') |
||||
|
elseif here ==? root || here ==? old |
||||
|
break |
||||
|
endif |
||||
|
|
||||
|
let old = here |
||||
|
|
||||
|
" we use ':h:h' rather than ':h' since ':p' adds a trailing '/' |
||||
|
" if 'here' is a directory |
||||
|
let here = fnamemodify(here, ':p:h:h') |
||||
|
endwhile |
||||
|
|
||||
|
return '' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Returns the buffer number of a filename |
||||
|
" @vimlint(EVL104, 1, l:old_shellslash) |
||||
|
function! syntastic#util#fname2buf(fname) abort " {{{2 |
||||
|
if exists('+shellslash') |
||||
|
" bufnr() can't cope with backslashes |
||||
|
let old_shellslash = &shellslash |
||||
|
let &shellslash = 1 |
||||
|
endif |
||||
|
|
||||
|
" this is a best-effort attempt to escape file patterns (cf. :h file-pattern) |
||||
|
" XXX it fails for filenames containing something like \{2,3} |
||||
|
let buf = -1 |
||||
|
for md in [':~:.', ':~', ':p'] |
||||
|
try |
||||
|
" Older versions of Vim can throw E94 here |
||||
|
let buf = bufnr('^' . escape(fnamemodify(a:fname, md), '\*?,{}[') . '$') |
||||
|
catch |
||||
|
" catch everything |
||||
|
endtry |
||||
|
if buf != -1 |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
if buf == -1 |
||||
|
" XXX definitely wrong, but hope is the last thing to die :) |
||||
|
let buf = bufnr(fnamemodify(a:fname, ':p')) |
||||
|
endif |
||||
|
|
||||
|
if exists('+shellslash') |
||||
|
let &shellslash = old_shellslash |
||||
|
endif |
||||
|
|
||||
|
return buf |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL104, 0, l:old_shellslash) |
||||
|
|
||||
|
" Returns unique elements in a list |
||||
|
function! syntastic#util#unique(list) abort " {{{2 |
||||
|
let seen = {} |
||||
|
let uniques = [] |
||||
|
for e in a:list |
||||
|
let k = string(e) |
||||
|
if !has_key(seen, k) |
||||
|
let seen[k] = 1 |
||||
|
call add(uniques, e) |
||||
|
endif |
||||
|
endfor |
||||
|
return uniques |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" A less noisy shellescape() |
||||
|
function! syntastic#util#shescape(string) abort " {{{2 |
||||
|
return a:string =~# '\m^[A-Za-z0-9_/.-]\+$' ? a:string : shellescape(a:string) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" A less noisy shellescape(expand()) |
||||
|
function! syntastic#util#shexpand(string, ...) abort " {{{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) abort " {{{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) abort " {{{2 |
||||
|
let str = a:string |
||||
|
let str = substitute(str, '\m<', '<', 'g') |
||||
|
let str = substitute(str, '\m>', '>', 'g') |
||||
|
let str = substitute(str, '\m"', '"', 'g') |
||||
|
let str = substitute(str, '\m'', "'", 'g') |
||||
|
let str = substitute(str, '\m&', '\&', 'g') |
||||
|
return str |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#redraw(full) abort " {{{2 |
||||
|
if a:full |
||||
|
redraw! |
||||
|
else |
||||
|
redraw |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#dictFilter(errors, filter) abort " {{{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 " }}}2 |
||||
|
|
||||
|
" Return a [seconds, fractions] list of strings, representing the |
||||
|
" (hopefully high resolution) time since program start |
||||
|
function! syntastic#util#stamp() abort " {{{2 |
||||
|
return split( split(reltimestr(reltime(g:_SYNTASTIC_START)))[0], '\.' ) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#setLastTick(buf) abort " {{{2 |
||||
|
call setbufvar(a:buf, 'syntastic_lasttick', getbufvar(a:buf, 'changedtick')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Add unique IDs to windows |
||||
|
function! syntastic#util#setWids() abort " {{{2 |
||||
|
for tab in range(1, tabpagenr('$')) |
||||
|
for win in range(1, tabpagewinnr(tab, '$')) |
||||
|
if gettabwinvar(tab, win, 'syntastic_wid') ==# '' |
||||
|
call settabwinvar(tab, win, 'syntastic_wid', s:_wid_base . s:_wid_pool) |
||||
|
let s:_wid_pool += 1 |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#str2float(val) abort " {{{2 |
||||
|
return s:_str2float(a:val) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! syntastic#util#float2str(val) abort " {{{2 |
||||
|
return s:_float2str(a:val) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Crude printf()-like width formatter. Handles wide characters. |
||||
|
function! syntastic#util#wformat(format, str) abort " {{{2 |
||||
|
if a:format ==# '' |
||||
|
return a:str |
||||
|
endif |
||||
|
|
||||
|
echomsg string(a:format) . ', ' . string(a:str) |
||||
|
let specs = matchlist(a:format, '\v^(-?)(0?)(%([1-9]\d*))?%(\.(\d+))?$') |
||||
|
if len(specs) < 5 |
||||
|
return a:str |
||||
|
endif |
||||
|
|
||||
|
let flushleft = specs[1] ==# '-' |
||||
|
let lpad = specs[2] ==# '0' ? '0' : ' ' |
||||
|
let minlen = str2nr(specs[3]) |
||||
|
let maxlen = str2nr(specs[4]) |
||||
|
let out = substitute(a:str, "\t", ' ', 'g') |
||||
|
|
||||
|
if maxlen && s:_width(out) > maxlen |
||||
|
let chars = filter(split(out, '\zs\ze', 1), 'v:val !=# ""') |
||||
|
let out = '' |
||||
|
|
||||
|
if flushleft |
||||
|
for c in chars |
||||
|
if s:_width(out . c) < maxlen |
||||
|
let out .= c |
||||
|
else |
||||
|
let out .= &encoding ==# 'utf-8' && &termencoding ==# 'utf-8' ? "\u2026" : '>' |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
call reverse(chars) |
||||
|
for c in chars |
||||
|
if s:_width(c . out) < maxlen |
||||
|
let out = c . out |
||||
|
else |
||||
|
let out = (&encoding ==# 'utf-8' && &termencoding ==# 'utf-8' ? "\u2026" : '<') . out |
||||
|
break |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
if minlen && s:_width(out) < minlen |
||||
|
if flushleft |
||||
|
let out .= repeat(' ', minlen - s:_width(out)) |
||||
|
else |
||||
|
let out = repeat(lpad, minlen - s:_width(out)) . out |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
return out |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
function! s:_translateFilter(filters) abort " {{{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)')) |
||||
|
else |
||||
|
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 " }}}2 |
||||
|
|
||||
|
function! s:_translateElement(key, term) abort " {{{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 " }}}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 |
||||
|
|
||||
|
" @vimlint(EVL103, 1, a:flags) |
||||
|
function! s:_delete_dumb(what, flags) abort " {{{2 |
||||
|
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 syntastic#util#system(s:rmrf . ' ' . syntastic#util#shescape(a:what)) |
||||
|
else |
||||
|
call s:_rmrf(a:what) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:flags) |
||||
|
|
||||
|
" delete(dir, 'rf') was added in Vim 7.4.1107, but it didn't become usable until 7.4.1128 |
||||
|
let s:_delete = function(v:version > 704 || (v:version == 704 && has('patch1128')) ? 'delete' : 's:_delete_dumb') |
||||
|
lockvar s:_delete |
||||
|
|
||||
|
function! s:_rmrf(what) abort " {{{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 |
||||
|
|
||||
|
try |
||||
|
" Vim 7.4.279 and later |
||||
|
let entries = globpath(a:what, '*', 1, 1) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E118/ |
||||
|
let entries = split(globpath(a:what, '*', 1), "\n") |
||||
|
endtry |
||||
|
for f in entries |
||||
|
call s:_rmrf(f) |
||||
|
endfor |
||||
|
silent! call syntastic#util#system(s:rmdir . ' ' . syntastic#util#shescape(a:what)) |
||||
|
else |
||||
|
silent! call delete(a:what) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
let s:_str2float = function(exists('*str2float') ? 'str2float' : 'str2nr') |
||||
|
lockvar s:_str2float |
||||
|
|
||||
|
function! s:_float2str_smart(val) abort " {{{2 |
||||
|
return printf('%.1f', a:val) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_float2str_dumb(val) abort " {{{2 |
||||
|
return a:val |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
let s:_float2str = function(has('float') ? 's:_float2str_smart' : 's:_float2str_dumb') |
||||
|
lockvar s:_float2str |
||||
|
|
||||
|
function! s:_getbufvar_dumb(buf, name, ...) abort " {{{2 |
||||
|
let ret = getbufvar(a:buf, a:name) |
||||
|
if a:0 && type(ret) == type('') && ret ==# '' |
||||
|
unlet! ret |
||||
|
let ret = a:1 |
||||
|
endif |
||||
|
return ret |
||||
|
endfunction "}}}2 |
||||
|
|
||||
|
let s:_getbufvar = function(v:version > 703 || (v:version == 703 && has('patch831')) ? 'getbufvar' : 's:_getbufvar_dumb') |
||||
|
lockvar s:_getbufvar |
||||
|
|
||||
|
function! s:_fuzz_dumb() abort " {{{2 |
||||
|
return 'tmp' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
let s:_fuzz = function(exists('*getpid') ? 'getpid' : 's:_fuzz_dumb') |
||||
|
lockvar s:_fuzz |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
let s:_wid_base = 'syntastic_' . s:_fuzz() . '_' . reltimestr(g:_SYNTASTIC_START) . '_' |
||||
|
let s:_wid_pool = 0 |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,798 @@ |
|||||
|
"============================================================================ |
||||
|
"File: syntastic.vim |
||||
|
"Description: Vim plugin for on the fly syntax checking. |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_plugin') || &compatible |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_plugin = 1 |
||||
|
|
||||
|
if has('reltime') |
||||
|
let g:_SYNTASTIC_START = reltime() |
||||
|
lockvar! g:_SYNTASTIC_START |
||||
|
endif |
||||
|
|
||||
|
let g:_SYNTASTIC_VERSION = '3.10.0-5' |
||||
|
lockvar g:_SYNTASTIC_VERSION |
||||
|
|
||||
|
" Sanity checks {{{1 |
||||
|
|
||||
|
if v:version < 700 || (v:version == 700 && !has('patch175')) |
||||
|
call syntastic#log#error('need Vim version 7.0.175 or later') |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
for s:feature in [ |
||||
|
\ 'autocmd', |
||||
|
\ 'eval', |
||||
|
\ 'file_in_path', |
||||
|
\ 'modify_fname', |
||||
|
\ 'quickfix', |
||||
|
\ 'reltime', |
||||
|
\ 'statusline', |
||||
|
\ 'user_commands', |
||||
|
\ ] |
||||
|
if !has(s:feature) |
||||
|
call syntastic#log#error('need Vim compiled with feature ' . s:feature) |
||||
|
finish |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
let s:_running_windows = syntastic#util#isRunningWindows() |
||||
|
lockvar s:_running_windows |
||||
|
|
||||
|
if !exists('g:syntastic_shell') |
||||
|
let g:syntastic_shell = &shell |
||||
|
endif |
||||
|
|
||||
|
if s:_running_windows |
||||
|
let g:_SYNTASTIC_UNAME = 'Windows' |
||||
|
elseif executable('uname') |
||||
|
try |
||||
|
let g:_SYNTASTIC_UNAME = split(syntastic#util#system('uname'), "\n")[0] |
||||
|
catch /\m^E145$/ |
||||
|
call syntastic#log#error("can't run in rvim") |
||||
|
finish |
||||
|
catch /\m^E484$/ |
||||
|
call syntastic#log#error("can't run external programs (misconfigured shell options?)") |
||||
|
finish |
||||
|
catch /\m^E684$/ |
||||
|
let g:_SYNTASTIC_UNAME = 'Unknown' |
||||
|
endtry |
||||
|
else |
||||
|
let g:_SYNTASTIC_UNAME = 'Unknown' |
||||
|
endif |
||||
|
lockvar g:_SYNTASTIC_UNAME |
||||
|
|
||||
|
" XXX Ugly hack to make g:_SYNTASTIC_UNAME available to :SyntasticInfo without |
||||
|
" polluting session namespaces |
||||
|
let g:syntastic_version = |
||||
|
\ g:_SYNTASTIC_VERSION . |
||||
|
\ ' (Vim ' . v:version . (has('nvim') ? ', Neovim' : '') . ', ' . |
||||
|
\ g:_SYNTASTIC_UNAME . |
||||
|
\ (has('gui') ? ', GUI' : '') . ')' |
||||
|
lockvar g:syntastic_version |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Defaults {{{1 |
||||
|
|
||||
|
let g:_SYNTASTIC_DEFAULTS = { |
||||
|
\ 'aggregate_errors': 0, |
||||
|
\ 'always_populate_loc_list': 0, |
||||
|
\ 'auto_jump': 0, |
||||
|
\ 'auto_loc_list': 2, |
||||
|
\ 'check_on_open': 0, |
||||
|
\ 'check_on_wq': 1, |
||||
|
\ 'cursor_columns': 1, |
||||
|
\ 'debug': 0, |
||||
|
\ 'echo_current_error': 1, |
||||
|
\ 'enable_balloons': 1, |
||||
|
\ 'enable_highlighting': 1, |
||||
|
\ 'enable_signs': 1, |
||||
|
\ 'error_symbol': '>>', |
||||
|
\ 'exit_checks': !(s:_running_windows && syntastic#util#var('shell', &shell) =~? '\m\<cmd\.exe$'), |
||||
|
\ 'filetype_map': {}, |
||||
|
\ 'full_redraws': !(has('gui_running') || has('gui_macvim')), |
||||
|
\ 'id_checkers': 1, |
||||
|
\ 'ignore_extensions': '\c\v^([gx]?z|lzma|bz2)$', |
||||
|
\ 'ignore_files': [], |
||||
|
\ 'loc_list_height': 10, |
||||
|
\ 'nested_autocommands': 0, |
||||
|
\ 'quiet_messages': {}, |
||||
|
\ 'reuse_loc_lists': 1, |
||||
|
\ 'shell': &shell, |
||||
|
\ 'sort_aggregated_errors': 1, |
||||
|
\ 'stl_format': '[Syntax: line:%F (%t)]', |
||||
|
\ 'style_error_symbol': 'S>', |
||||
|
\ 'style_warning_symbol': 'S>', |
||||
|
\ 'warning_symbol': '>>' |
||||
|
\ } |
||||
|
lockvar! g:_SYNTASTIC_DEFAULTS |
||||
|
|
||||
|
for s:key in keys(g:_SYNTASTIC_DEFAULTS) |
||||
|
if !exists('g:syntastic_' . s:key) |
||||
|
let g:syntastic_{s:key} = copy(g:_SYNTASTIC_DEFAULTS[s:key]) |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
if exists('g:syntastic_quiet_warnings') |
||||
|
call syntastic#log#oneTimeWarn("variable g:syntastic_quiet_warnings is deprecated, please use let g:syntastic_quiet_messages = {'level': 'warnings'} instead") |
||||
|
if g:syntastic_quiet_warnings |
||||
|
let s:quiet_warnings = get(g:syntastic_quiet_messages, 'type', []) |
||||
|
if type(s:quiet_warnings) != type([]) |
||||
|
let s:quiet_warnings = [s:quiet_warnings] |
||||
|
endif |
||||
|
call add(s:quiet_warnings, 'warnings') |
||||
|
let g:syntastic_quiet_messages['type'] = s:quiet_warnings |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Debug {{{1 |
||||
|
|
||||
|
let g:_SYNTASTIC_SHELL_OPTIONS = [ |
||||
|
\ 'shell', |
||||
|
\ 'shellcmdflag', |
||||
|
\ 'shellpipe', |
||||
|
\ 'shellquote', |
||||
|
\ 'shellredir', |
||||
|
\ 'shelltemp', |
||||
|
\ 'shellxquote' |
||||
|
\ ] |
||||
|
for s:feature in [ |
||||
|
\ 'autochdir', |
||||
|
\ 'shellslash', |
||||
|
\ 'shellxescape', |
||||
|
\ ] |
||||
|
|
||||
|
if exists('+' . s:feature) |
||||
|
call add(g:_SYNTASTIC_SHELL_OPTIONS, s:feature) |
||||
|
endif |
||||
|
endfor |
||||
|
lockvar! g:_SYNTASTIC_SHELL_OPTIONS |
||||
|
|
||||
|
" debug constants |
||||
|
let g:_SYNTASTIC_DEBUG_TRACE = 1 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_TRACE |
||||
|
let g:_SYNTASTIC_DEBUG_LOCLIST = 2 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_LOCLIST |
||||
|
let g:_SYNTASTIC_DEBUG_NOTIFICATIONS = 4 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_NOTIFICATIONS |
||||
|
let g:_SYNTASTIC_DEBUG_AUTOCOMMANDS = 8 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_AUTOCOMMANDS |
||||
|
let g:_SYNTASTIC_DEBUG_VARIABLES = 16 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_VARIABLES |
||||
|
let g:_SYNTASTIC_DEBUG_CHECKERS = 32 |
||||
|
lockvar g:_SYNTASTIC_DEBUG_CHECKERS |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
runtime! plugin/syntastic/*.vim |
||||
|
|
||||
|
let s:registry = g:SyntasticRegistry.Instance() |
||||
|
let s:notifiers = g:SyntasticNotifiers.Instance() |
||||
|
let s:modemap = g:SyntasticModeMap.Instance() |
||||
|
|
||||
|
let s:_check_stack = [] |
||||
|
let s:_quit_pre = [] |
||||
|
|
||||
|
" Commands {{{1 |
||||
|
|
||||
|
" @vimlint(EVL103, 1, a:cursorPos) |
||||
|
" @vimlint(EVL103, 1, a:cmdLine) |
||||
|
" @vimlint(EVL103, 1, a:argLead) |
||||
|
function! s:CompleteCheckerName(argLead, cmdLine, cursorPos) abort " {{{2 |
||||
|
let names = [] |
||||
|
|
||||
|
let sep_idx = stridx(a:argLead, '/') |
||||
|
if sep_idx >= 1 |
||||
|
let ft = a:argLead[: sep_idx-1] |
||||
|
call extend(names, map( s:registry.getNamesOfAvailableCheckers(ft), 'ft . "/" . v:val' )) |
||||
|
else |
||||
|
for ft in s:registry.resolveFiletypes(&filetype) |
||||
|
call extend(names, s:registry.getNamesOfAvailableCheckers(ft)) |
||||
|
endfor |
||||
|
call extend(names, map( copy(s:registry.getKnownFiletypes()), 'v:val . "/"' )) |
||||
|
endif |
||||
|
|
||||
|
return join(names, "\n") |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:cursorPos) |
||||
|
" @vimlint(EVL103, 0, a:cmdLine) |
||||
|
" @vimlint(EVL103, 0, a:argLead) |
||||
|
|
||||
|
|
||||
|
" @vimlint(EVL103, 1, a:cursorPos) |
||||
|
" @vimlint(EVL103, 1, a:cmdLine) |
||||
|
" @vimlint(EVL103, 1, a:argLead) |
||||
|
function! s:CompleteFiletypes(argLead, cmdLine, cursorPos) abort " {{{2 |
||||
|
return join(s:registry.getKnownFiletypes(), "\n") |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:cursorPos) |
||||
|
" @vimlint(EVL103, 0, a:cmdLine) |
||||
|
" @vimlint(EVL103, 0, a:argLead) |
||||
|
|
||||
|
command! -bar -nargs=* -complete=custom,s:CompleteCheckerName SyntasticCheck call SyntasticCheck(<f-args>) |
||||
|
command! -bar -nargs=? -complete=custom,s:CompleteFiletypes SyntasticInfo call SyntasticInfo(<f-args>) |
||||
|
command! -bar Errors call SyntasticErrors() |
||||
|
command! -bar SyntasticReset call SyntasticReset() |
||||
|
command! -bar SyntasticToggleMode call SyntasticToggleMode() |
||||
|
command! -bar SyntasticSetLoclist call SyntasticSetLoclist() |
||||
|
|
||||
|
command! SyntasticJavacEditClasspath runtime! syntax_checkers/java/*.vim | SyntasticJavacEditClasspath |
||||
|
command! SyntasticJavacEditConfig runtime! syntax_checkers/java/*.vim | SyntasticJavacEditConfig |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Public API {{{1 |
||||
|
|
||||
|
function! SyntasticCheck(...) abort " {{{2 |
||||
|
call s:UpdateErrors(bufnr(''), 0, a:000) |
||||
|
call syntastic#util#redraw(g:syntastic_full_redraws) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! SyntasticInfo(...) abort " {{{2 |
||||
|
call s:modemap.modeInfo(a:000) |
||||
|
call s:registry.echoInfoFor(a:000) |
||||
|
call s:_explain_skip(a:000) |
||||
|
call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, g:_SYNTASTIC_SHELL_OPTIONS) |
||||
|
call syntastic#log#debugDump(g:_SYNTASTIC_DEBUG_VARIABLES) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! SyntasticErrors() abort " {{{2 |
||||
|
call g:SyntasticLoclist.current().show() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! SyntasticReset() abort " {{{2 |
||||
|
call s:ClearCache(bufnr('')) |
||||
|
call s:notifiers.refresh(g:SyntasticLoclist.New([])) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! SyntasticToggleMode() abort " {{{2 |
||||
|
call s:modemap.toggleMode() |
||||
|
call s:ClearCache(bufnr('')) |
||||
|
call s:notifiers.refresh(g:SyntasticLoclist.New([])) |
||||
|
call s:modemap.echoMode() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! SyntasticSetLoclist() abort " {{{2 |
||||
|
call g:SyntasticLoclist.current().setloclist(0) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Autocommands {{{1 |
||||
|
|
||||
|
augroup syntastic |
||||
|
autocmd! |
||||
|
autocmd VimEnter * call s:VimEnterHook() |
||||
|
autocmd BufEnter * call s:BufEnterHook(expand('<afile>', 1)) |
||||
|
autocmd BufWinEnter * call s:BufWinEnterHook(expand('<afile>', 1)) |
||||
|
augroup END |
||||
|
|
||||
|
if g:syntastic_nested_autocommands |
||||
|
augroup syntastic |
||||
|
autocmd BufReadPost * nested call s:BufReadPostHook(expand('<afile>', 1)) |
||||
|
autocmd BufWritePost * nested call s:BufWritePostHook(expand('<afile>', 1)) |
||||
|
augroup END |
||||
|
else |
||||
|
augroup syntastic |
||||
|
autocmd BufReadPost * call s:BufReadPostHook(expand('<afile>', 1)) |
||||
|
autocmd BufWritePost * call s:BufWritePostHook(expand('<afile>', 1)) |
||||
|
augroup END |
||||
|
endif |
||||
|
|
||||
|
if exists('##QuitPre') |
||||
|
" QuitPre was added in Vim 7.3.544 |
||||
|
augroup syntastic |
||||
|
autocmd QuitPre * call s:QuitPreHook(expand('<afile>', 1)) |
||||
|
augroup END |
||||
|
endif |
||||
|
|
||||
|
function! s:BufReadPostHook(fname) abort " {{{2 |
||||
|
let buf = syntastic#util#fname2buf(a:fname) |
||||
|
if g:syntastic_check_on_open && buf > 0 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, |
||||
|
\ 'autocmd: BufReadPost, buffer ' . buf . ' = ' . string(a:fname)) |
||||
|
if index(s:_check_stack, buf) == -1 |
||||
|
call add(s:_check_stack, buf) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:BufWritePostHook(fname) abort " {{{2 |
||||
|
let buf = syntastic#util#fname2buf(a:fname) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, |
||||
|
\ 'autocmd: BufWritePost, buffer ' . buf . ' = ' . string(a:fname)) |
||||
|
call s:UpdateErrors(buf, 1, []) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:BufEnterHook(fname) abort " {{{2 |
||||
|
let buf = syntastic#util#fname2buf(a:fname) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, |
||||
|
\ 'autocmd: BufEnter, buffer ' . buf . ' = ' . string(a:fname) . ', &buftype = ' . string(&buftype)) |
||||
|
if buf > 0 && getbufvar(buf, '&buftype') ==# '' |
||||
|
let idx = index(reverse(copy(s:_check_stack)), buf) |
||||
|
if idx >= 0 |
||||
|
if !has('vim_starting') |
||||
|
call remove(s:_check_stack, -idx - 1) |
||||
|
call s:UpdateErrors(buf, 1, []) |
||||
|
endif |
||||
|
elseif &buftype ==# '' |
||||
|
call s:notifiers.refresh(g:SyntasticLoclist.current()) |
||||
|
endif |
||||
|
elseif &buftype ==# 'quickfix' |
||||
|
" TODO: this is needed because in recent versions of Vim lclose |
||||
|
" can no longer be called from BufWinLeave |
||||
|
" TODO: at this point there is no b:syntastic_loclist |
||||
|
let loclist = filter(copy(getloclist(0)), 'v:val["valid"]') |
||||
|
let owner = str2nr(getbufvar(buf, 'syntastic_owner_buffer')) |
||||
|
let buffers = syntastic#util#unique(map(loclist, 'v:val["bufnr"]') + (owner ? [owner] : [])) |
||||
|
if !empty(get(w:, 'syntastic_loclist_set', [])) && !empty(loclist) && empty(filter( buffers, 'syntastic#util#bufIsActive(v:val)' )) |
||||
|
call SyntasticLoclistHide() |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:BufWinEnterHook(fname) abort " {{{2 |
||||
|
let buf = syntastic#util#fname2buf(a:fname) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, |
||||
|
\ 'autocmd: BufWinEnter, buffer ' . buf . ' = ' . string(a:fname) . ', &buftype = ' . string(&buftype)) |
||||
|
if buf > 0 && getbufvar(buf, '&buftype') ==# '' |
||||
|
let idx = index(reverse(copy(s:_check_stack)), buf) |
||||
|
if idx >= 0 && !has('vim_starting') |
||||
|
call remove(s:_check_stack, -idx - 1) |
||||
|
call s:UpdateErrors(buf, 1, []) |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:VimEnterHook() abort " {{{2 |
||||
|
let buf = bufnr('') |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, |
||||
|
\ 'autocmd: VimEnter, buffer ' . buf . ' = ' . string(bufname(buf)) . ', &buftype = ' . string(&buftype)) |
||||
|
let idx = index(reverse(copy(s:_check_stack)), buf) |
||||
|
if idx >= 0 && getbufvar(buf, '&buftype') ==# '' |
||||
|
call remove(s:_check_stack, -idx - 1) |
||||
|
call s:UpdateErrors(buf, 1, []) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:QuitPreHook(fname) abort " {{{2 |
||||
|
let buf = syntastic#util#fname2buf(a:fname) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, 'autocmd: QuitPre, buffer ' . buf . ' = ' . string(a:fname)) |
||||
|
|
||||
|
if !syntastic#util#var('check_on_wq') |
||||
|
call syntastic#util#setWids() |
||||
|
call add(s:_quit_pre, buf . '_' . getbufvar(buf, 'changetick') . '_' . w:syntastic_wid) |
||||
|
endif |
||||
|
|
||||
|
if !empty(get(w:, 'syntastic_loclist_set', [])) |
||||
|
call SyntasticLoclistHide() |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Main {{{1 |
||||
|
|
||||
|
"refresh and redraw all the error info for this buf when saving or reading |
||||
|
function! s:UpdateErrors(buf, auto_invoked, checker_names) abort " {{{2 |
||||
|
call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'version') |
||||
|
call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, g:_SYNTASTIC_SHELL_OPTIONS) |
||||
|
call syntastic#log#debugDump(g:_SYNTASTIC_DEBUG_VARIABLES) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'UpdateErrors' . (a:auto_invoked ? ' (auto)' : '') . |
||||
|
\ ': ' . (len(a:checker_names) ? join(a:checker_names) : 'default checkers')) |
||||
|
|
||||
|
call s:modemap.synch() |
||||
|
|
||||
|
if s:_skip_file(a:buf) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let run_checks = !a:auto_invoked || s:modemap.doAutoChecking(a:buf) |
||||
|
if run_checks |
||||
|
call s:CacheErrors(a:buf, a:checker_names) |
||||
|
call syntastic#util#setLastTick(a:buf) |
||||
|
elseif a:auto_invoked |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
let loclist = g:SyntasticLoclist.current(a:buf) |
||||
|
|
||||
|
if exists('*SyntasticCheckHook') |
||||
|
call SyntasticCheckHook(loclist.getRaw()) |
||||
|
endif |
||||
|
|
||||
|
" populate loclist and jump {{{3 |
||||
|
let do_jump = syntastic#util#var('auto_jump') + 0 |
||||
|
if do_jump == 2 |
||||
|
let do_jump = loclist.getFirstError(1) |
||||
|
elseif do_jump == 3 |
||||
|
let do_jump = loclist.getFirstError() |
||||
|
elseif 0 > do_jump || do_jump > 3 |
||||
|
let do_jump = 0 |
||||
|
endif |
||||
|
|
||||
|
if syntastic#util#var('always_populate_loc_list') || do_jump |
||||
|
call loclist.setloclist(1) |
||||
|
if run_checks && do_jump && !loclist.isEmpty() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: jump') |
||||
|
execute 'silent! lrewind ' . do_jump |
||||
|
|
||||
|
" XXX: Vim doesn't call autocmd commands in a predictible |
||||
|
" order, which can lead to missing filetype when jumping |
||||
|
" to a new file; the following is a workaround for the |
||||
|
" resulting brain damage |
||||
|
if &filetype ==# '' |
||||
|
silent! filetype detect |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
call s:notifiers.refresh(loclist) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
"clear the loc list for the buffer |
||||
|
function! s:ClearCache(buf) abort " {{{2 |
||||
|
let loclist = g:SyntasticLoclist.current(a:buf) |
||||
|
call s:notifiers.reset(loclist) |
||||
|
call loclist.destroy() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
"detect and cache all syntax errors in this buffer |
||||
|
function! s:CacheErrors(buf, checker_names) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: ' . |
||||
|
\ (len(a:checker_names) ? join(a:checker_names) : 'default checkers')) |
||||
|
call s:ClearCache(a:buf) |
||||
|
let newLoclist = g:SyntasticLoclist.New([]) |
||||
|
call newLoclist.setOwner(a:buf) |
||||
|
|
||||
|
if !s:_skip_file(a:buf) |
||||
|
" debug logging {{{3 |
||||
|
call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'aggregate_errors') |
||||
|
if syntastic#util#isRunningWindows() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMP = ' . string($TMP) . ', $TEMP = ' . string($TEMP)) |
||||
|
else |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TERM = ' . string($TERM)) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMPDIR = ' . string($TMPDIR)) |
||||
|
endif |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$PATH = ' . string($PATH)) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getcwd() = ' . string(getcwd())) |
||||
|
" }}}3 |
||||
|
|
||||
|
let clist = s:registry.getCheckers(getbufvar(a:buf, '&filetype'), a:checker_names) |
||||
|
|
||||
|
let aggregate_errors = |
||||
|
\ syntastic#util#var('aggregate_errors') || len(syntastic#util#unique(map(copy(clist), 'v:val.getFiletype()'))) > 1 |
||||
|
let decorate_errors = aggregate_errors && syntastic#util#var('id_checkers') |
||||
|
let sort_aggregated_errors = aggregate_errors && syntastic#util#var('sort_aggregated_errors') |
||||
|
|
||||
|
let names = [] |
||||
|
let unavailable_checkers = 0 |
||||
|
for checker in clist |
||||
|
let cname = checker.getCName() |
||||
|
if !checker.isAvailable() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: Checker ' . cname . ' is not available') |
||||
|
let unavailable_checkers += 1 |
||||
|
continue |
||||
|
endif |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: Invoking checker: ' . cname) |
||||
|
|
||||
|
let loclist = checker.getLocList() |
||||
|
|
||||
|
if !loclist.isEmpty() |
||||
|
if decorate_errors |
||||
|
call loclist.decorate(cname) |
||||
|
endif |
||||
|
call add(names, cname) |
||||
|
if checker.wantSort() && !sort_aggregated_errors |
||||
|
call loclist.sort() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'sorted:', loclist) |
||||
|
endif |
||||
|
|
||||
|
call newLoclist.extend(loclist) |
||||
|
|
||||
|
if !aggregate_errors |
||||
|
break |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
" set names {{{3 |
||||
|
if !empty(names) |
||||
|
if len(syntastic#util#unique(map( copy(names), 'substitute(v:val, "\\m/.*", "", "")' ))) == 1 |
||||
|
let type = substitute(names[0], '\m/.*', '', '') |
||||
|
let name = join(map( names, 'substitute(v:val, "\\m.\\{-}/", "", "")' ), ', ') |
||||
|
call newLoclist.setName( name . ' ('. type . ')' ) |
||||
|
else |
||||
|
" checkers from mixed types |
||||
|
call newLoclist.setName(join(names, ', ')) |
||||
|
endif |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
" issue warning about no active checkers {{{3 |
||||
|
if len(clist) == unavailable_checkers |
||||
|
if !empty(a:checker_names) |
||||
|
if len(a:checker_names) == 1 |
||||
|
call syntastic#log#warn('checker ' . a:checker_names[0] . ' is not available') |
||||
|
else |
||||
|
call syntastic#log#warn('checkers ' . join(a:checker_names, ', ') . ' are not available') |
||||
|
endif |
||||
|
else |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: no checkers available for ' . &filetype) |
||||
|
endif |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'aggregated:', newLoclist) |
||||
|
if sort_aggregated_errors |
||||
|
call newLoclist.sort() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'sorted:', newLoclist) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
call newLoclist.deploy() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
"Emulates the :lmake command. Sets up the make environment according to the |
||||
|
"options given, runs make, resets the environment, returns the location list |
||||
|
" |
||||
|
"a:options can contain the following keys: |
||||
|
" 'makeprg' |
||||
|
" 'errorformat' |
||||
|
" |
||||
|
"The corresponding options are set for the duration of the function call. They |
||||
|
"are set with :let, so dont escape spaces. |
||||
|
" |
||||
|
"a:options may also contain: |
||||
|
" 'defaults' - a dict containing default values for the returned errors |
||||
|
" 'subtype' - all errors will be assigned the given subtype |
||||
|
" 'preprocess' - a function to be applied to the error file before parsing errors |
||||
|
" 'postprocess' - a list of functions to be applied to the error list |
||||
|
" 'cwd' - change directory to the given path before running the checker |
||||
|
" 'env' - environment variables to set before running the checker |
||||
|
" 'returns' - a list of valid exit codes for the checker |
||||
|
" @vimlint(EVL102, 1, l:env_save) |
||||
|
function! SyntasticMake(options) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'SyntasticMake: called with options:', a:options) |
||||
|
|
||||
|
" save options and locale env variables {{{3 |
||||
|
let old_local_errorformat = &l:errorformat |
||||
|
let old_errorformat = &errorformat |
||||
|
let old_cwd = getcwd() |
||||
|
" }}}3 |
||||
|
|
||||
|
if has_key(a:options, 'errorformat') |
||||
|
let &errorformat = a:options['errorformat'] |
||||
|
set errorformat< |
||||
|
endif |
||||
|
|
||||
|
if has_key(a:options, 'cwd') |
||||
|
execute 'lcd ' . fnameescape(a:options['cwd']) |
||||
|
endif |
||||
|
|
||||
|
" set environment variables {{{3 |
||||
|
let env_save = {} |
||||
|
if has_key(a:options, 'env') && len(a:options['env']) |
||||
|
for key in keys(a:options['env']) |
||||
|
if key =~? '\m^[a-z_][a-z0-9_]*$' |
||||
|
execute 'let env_save[' . string(key) . '] = $' . key |
||||
|
execute 'let $' . key . ' = ' . string(a:options['env'][key]) |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
let err_lines = split(syntastic#util#system(a:options['makeprg']), "\n", 1) |
||||
|
|
||||
|
" restore environment variables {{{3 |
||||
|
if len(env_save) |
||||
|
for key in keys(env_save) |
||||
|
execute 'let $' . key . ' = ' . string(env_save[key]) |
||||
|
endfor |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'checker output:', err_lines) |
||||
|
|
||||
|
" Does it still make sense to go on? |
||||
|
let bailout = |
||||
|
\ syntastic#util#var('exit_checks') && |
||||
|
\ has_key(a:options, 'returns') && |
||||
|
\ index(a:options['returns'], v:shell_error) == -1 |
||||
|
|
||||
|
if !bailout |
||||
|
if has_key(a:options, 'Preprocess') |
||||
|
let err_lines = call(a:options['Preprocess'], [err_lines]) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'preprocess (external):', err_lines) |
||||
|
elseif has_key(a:options, 'preprocess') |
||||
|
let err_lines = call('syntastic#preprocess#' . a:options['preprocess'], [err_lines]) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'preprocess:', err_lines) |
||||
|
endif |
||||
|
noautocmd lgetexpr err_lines |
||||
|
|
||||
|
let errors = deepcopy(getloclist(0)) |
||||
|
|
||||
|
if has_key(a:options, 'cwd') |
||||
|
execute 'lcd ' . fnameescape(old_cwd) |
||||
|
endif |
||||
|
|
||||
|
try |
||||
|
silent lolder |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E380/ |
||||
|
" E380: At bottom of quickfix stack |
||||
|
call setloclist(0, [], 'r') |
||||
|
try |
||||
|
" Vim 7.4.2200 or later |
||||
|
call setloclist(0, [], 'r', { 'title': '' }) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E\%(118\|731\)/ |
||||
|
" do nothing |
||||
|
endtry |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E776/ |
||||
|
" E776: No location list |
||||
|
" do nothing |
||||
|
endtry |
||||
|
else |
||||
|
let errors = [] |
||||
|
endif |
||||
|
|
||||
|
" restore options {{{3 |
||||
|
let &errorformat = old_errorformat |
||||
|
let &l:errorformat = old_local_errorformat |
||||
|
" }}}3 |
||||
|
|
||||
|
if !s:_running_windows && (s:_os_name() =~? 'FreeBSD' || s:_os_name() =~? 'OpenBSD') |
||||
|
call syntastic#util#redraw(g:syntastic_full_redraws) |
||||
|
endif |
||||
|
|
||||
|
if bailout |
||||
|
call syntastic#log#ndebug(g:_SYNTASTIC_DEBUG_LOCLIST, 'checker output:', err_lines) |
||||
|
throw 'Syntastic: checker error' |
||||
|
endif |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'raw loclist:', errors) |
||||
|
|
||||
|
if has_key(a:options, 'defaults') |
||||
|
call s:_add_to_errors(errors, a:options['defaults']) |
||||
|
endif |
||||
|
|
||||
|
" Add subtype info if present. |
||||
|
if has_key(a:options, 'subtype') |
||||
|
call s:_add_to_errors(errors, { 'subtype': a:options['subtype'] }) |
||||
|
endif |
||||
|
|
||||
|
if has_key(a:options, 'Postprocess') && !empty(a:options['Postprocess']) |
||||
|
for rule in a:options['Postprocess'] |
||||
|
let errors = call(rule, [errors]) |
||||
|
endfor |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'postprocess (external):', errors) |
||||
|
elseif has_key(a:options, 'postprocess') && !empty(a:options['postprocess']) |
||||
|
for rule in a:options['postprocess'] |
||||
|
let errors = call('syntastic#postprocess#' . rule, [errors]) |
||||
|
endfor |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'postprocess:', errors) |
||||
|
endif |
||||
|
|
||||
|
return errors |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL102, 0, l:env_save) |
||||
|
|
||||
|
"return a string representing the state of buffer according to |
||||
|
"g:syntastic_stl_format |
||||
|
" |
||||
|
"return '' if no errors are cached for the buffer |
||||
|
function! SyntasticStatuslineFlag() abort " {{{2 |
||||
|
return g:SyntasticLoclist.current().getStatuslineFlag() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
function! s:_ignore_file(filename) abort " {{{2 |
||||
|
let fname = fnamemodify(a:filename, ':p') |
||||
|
for pattern in g:syntastic_ignore_files |
||||
|
if fname =~# pattern |
||||
|
return 1 |
||||
|
endif |
||||
|
endfor |
||||
|
return 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_is_quitting(buf) abort " {{{2 |
||||
|
let quitting = 0 |
||||
|
if exists('w:syntastic_wid') |
||||
|
let key = a:buf . '_' . getbufvar(a:buf, 'changetick') . '_' . w:syntastic_wid |
||||
|
let idx = index(s:_quit_pre, key) |
||||
|
if idx >= 0 |
||||
|
call remove(s:_quit_pre, idx) |
||||
|
let quitting = 1 |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
return quitting |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Skip running in special buffers |
||||
|
function! s:_skip_file(buf) abort " {{{2 |
||||
|
let fname = bufname(a:buf) |
||||
|
let skip = s:_is_quitting(a:buf) || getbufvar(a:buf, 'syntastic_skip_checks') || |
||||
|
\ (getbufvar(a:buf, '&buftype') !=# '') || !filereadable(fname) || getwinvar(0, '&diff') || |
||||
|
\ getwinvar(0, '&previewwindow') || s:_ignore_file(fname) || |
||||
|
\ fnamemodify(fname, ':e') =~? g:syntastic_ignore_extensions |
||||
|
if skip |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, '_skip_file: skipping checks') |
||||
|
endif |
||||
|
return skip |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Explain why checks will be skipped for the current file |
||||
|
function! s:_explain_skip(filetypes) abort " {{{2 |
||||
|
let buf = bufnr('') |
||||
|
if empty(a:filetypes) && s:_skip_file(buf) |
||||
|
let why = [] |
||||
|
let fname = bufname(buf) |
||||
|
let bt = getbufvar(buf, '&buftype') |
||||
|
|
||||
|
if s:_is_quitting(buf) |
||||
|
call add(why, 'quitting buffer') |
||||
|
endif |
||||
|
if getbufvar(buf, 'syntastic_skip_checks') |
||||
|
call add(why, 'b:syntastic_skip_checks set') |
||||
|
endif |
||||
|
if bt !=# '' |
||||
|
call add(why, 'buftype = ' . string(&buftype)) |
||||
|
endif |
||||
|
if !filereadable(fname) |
||||
|
call add(why, 'file not readable / not local') |
||||
|
endif |
||||
|
if getwinvar(0, '&diff') |
||||
|
call add(why, 'diff mode') |
||||
|
endif |
||||
|
if getwinvar(0, '&previewwindow') |
||||
|
call add(why, 'preview window') |
||||
|
endif |
||||
|
if s:_ignore_file(fname) |
||||
|
call add(why, 'filename matching g:syntastic_ignore_files') |
||||
|
endif |
||||
|
if fnamemodify(fname, ':e') =~? g:syntastic_ignore_extensions |
||||
|
call add(why, 'extension matching g:syntastic_ignore_extensions') |
||||
|
endif |
||||
|
|
||||
|
echomsg 'The current file will not be checked (' . join(why, ', ') . ')' |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Take a list of errors and add default values to them from a:options |
||||
|
function! s:_add_to_errors(errors, options) abort " {{{2 |
||||
|
for err in a:errors |
||||
|
for key in keys(a:options) |
||||
|
if !has_key(err, key) || empty(err[key]) |
||||
|
let err[key] = a:options[key] |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
|
||||
|
return a:errors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_os_name() abort " {{{2 |
||||
|
return g:_SYNTASTIC_UNAME |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,55 @@ |
|||||
|
if exists('g:loaded_syntastic_notifier_autoloclist') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifier_autoloclist = 1 |
||||
|
|
||||
|
let g:SyntasticAutoloclistNotifier = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
" |
||||
|
function! g:SyntasticAutoloclistNotifier.New() abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticAutoloclistNotifier.refresh(loclist) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'autoloclist: refresh') |
||||
|
call g:SyntasticAutoloclistNotifier.AutoToggle(a:loclist) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticAutoloclistNotifier.AutoToggle(loclist) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'autoloclist: toggle') |
||||
|
let auto_loc_list = syntastic#util#var('auto_loc_list') |
||||
|
if !a:loclist.isEmpty() |
||||
|
if auto_loc_list == 1 || auto_loc_list == 3 |
||||
|
call a:loclist.show() |
||||
|
endif |
||||
|
else |
||||
|
if (auto_loc_list == 1 || auto_loc_list == 2) && !empty(get(w:, 'syntastic_loclist_set', [])) |
||||
|
try |
||||
|
" Vim 7.4.2200 or later |
||||
|
let title = get(getloclist(0, { 'title': 1 }), 'title', ':SyntasticCheck ') |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E\%(118\|731\)/ |
||||
|
let title = ':SyntasticCheck ' |
||||
|
endtry |
||||
|
|
||||
|
if strpart(title, 0, 16) ==# ':SyntasticCheck ' |
||||
|
" TODO: this will close the loc list window if one was opened |
||||
|
" by something other than syntastic |
||||
|
call SyntasticLoclistHide() |
||||
|
|
||||
|
try |
||||
|
" Vim 7.4.2200 or later |
||||
|
call setloclist(0, [], 'r', { 'title': '' }) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E\%(118\|731\)/ |
||||
|
" do nothing |
||||
|
endtry |
||||
|
let w:syntastic_loclist_set = [] |
||||
|
endif |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,58 @@ |
|||||
|
if exists('g:loaded_syntastic_notifier_balloons') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifier_balloons = 1 |
||||
|
|
||||
|
if !has('balloon_eval') |
||||
|
let g:syntastic_enable_balloons = 0 |
||||
|
endif |
||||
|
|
||||
|
let g:SyntasticBalloonsNotifier = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticBalloonsNotifier.New() abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticBalloonsNotifier.enabled() abort " {{{2 |
||||
|
return has('balloon_eval') && syntastic#util#var('enable_balloons') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Update the error balloons |
||||
|
function! g:SyntasticBalloonsNotifier.refresh(loclist) abort " {{{2 |
||||
|
unlet! b:syntastic_private_balloons |
||||
|
if self.enabled() && !a:loclist.isEmpty() |
||||
|
let b:syntastic_private_balloons = a:loclist.balloons() |
||||
|
if !empty(b:syntastic_private_balloons) |
||||
|
set ballooneval balloonexpr=SyntasticBalloonsExprNotifier() |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Reset the error balloons |
||||
|
" @vimlint(EVL103, 1, a:loclist) |
||||
|
function! g:SyntasticBalloonsNotifier.reset(loclist) abort " {{{2 |
||||
|
if has('balloon_eval') && !empty(get(b:, 'syntastic_private_balloons', {})) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'balloons: reset') |
||||
|
set noballooneval |
||||
|
endif |
||||
|
unlet! b:syntastic_private_balloons |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:loclist) |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
function! SyntasticBalloonsExprNotifier() abort " {{{2 |
||||
|
if !exists('b:syntastic_private_balloons') |
||||
|
return '' |
||||
|
endif |
||||
|
return get(b:syntastic_private_balloons, v:beval_lnum, '') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,282 @@ |
|||||
|
if exists('g:loaded_syntastic_checker') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_checker = 1 |
||||
|
|
||||
|
let g:SyntasticChecker = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticChecker.New(args, ...) abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
|
||||
|
let newObj._filetype = a:args['filetype'] |
||||
|
let newObj._name = a:args['name'] |
||||
|
|
||||
|
if a:0 |
||||
|
" redirected checker |
||||
|
let newObj._exec_default = get(a:args, 'exec', a:1['_exec_default']) |
||||
|
|
||||
|
let filetype = a:1['_filetype'] |
||||
|
let name = a:1['_name'] |
||||
|
let prefix = 'SyntaxCheckers_' . filetype . '_' . name . '_' |
||||
|
|
||||
|
if exists('g:syntastic_' . filetype . '_' . name . '_sort') && !exists('g:syntastic_' . newObj._filetype . '_' . newObj._name . '_sort') |
||||
|
let g:syntastic_{newObj._filetype}_{newObj._name}_sort = g:syntastic_{filetype}_{name}_sort |
||||
|
endif |
||||
|
|
||||
|
if has_key(a:args, 'enable') |
||||
|
let newObj._enable = a:args['enable'] |
||||
|
elseif has_key(a:1, '_enable') |
||||
|
let newObj._enable = a:1['_enable'] |
||||
|
endif |
||||
|
else |
||||
|
let newObj._exec_default = get(a:args, 'exec', newObj._name) |
||||
|
if newObj._exec_default ==# '' |
||||
|
let newObj._exec_default = '<dummy>' |
||||
|
endif |
||||
|
let prefix = 'SyntaxCheckers_' . newObj._filetype . '_' . newObj._name . '_' |
||||
|
|
||||
|
if has_key(a:args, 'enable') |
||||
|
let newObj._enable = a:args['enable'] |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
let newObj._locListFunc = function(prefix . 'GetLocList') |
||||
|
|
||||
|
if exists('*' . prefix . 'IsAvailable') |
||||
|
let newObj._isAvailableFunc = function(prefix . 'IsAvailable') |
||||
|
else |
||||
|
let newObj._isAvailableFunc = function('s:_isAvailableDefault') |
||||
|
endif |
||||
|
|
||||
|
if exists('*' . prefix . 'GetHighlightRegex') |
||||
|
let newObj._highlightRegexFunc = function(prefix . 'GetHighlightRegex') |
||||
|
endif |
||||
|
|
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getFiletype() abort " {{{2 |
||||
|
return self._filetype |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getName() abort " {{{2 |
||||
|
return self._name |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getCName() abort " {{{2 |
||||
|
return self._filetype . '/' . self._name |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Synchronise _exec with user's setting. Force re-validation if needed. |
||||
|
" |
||||
|
" XXX: This function must be called at least once before calling either |
||||
|
" getExec() or getExecEscaped(). Normally isAvailable() does that for you |
||||
|
" automatically, but you should keep still this in mind if you change the |
||||
|
" current checker workflow. |
||||
|
function! g:SyntasticChecker.syncExec(...) abort " {{{2 |
||||
|
if a:0 |
||||
|
let self._exec = a:1 |
||||
|
else |
||||
|
let suffix = self._name . '_exec' |
||||
|
let self._exec = expand( |
||||
|
\ syntastic#util#var(self._filetype . '_' . suffix, |
||||
|
\ syntastic#util#var(suffix, self._exec_default)), 1 ) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getExec() abort " {{{2 |
||||
|
return self._exec |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getExecEscaped() abort " {{{2 |
||||
|
return syntastic#util#shescape(self._exec) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getLocListRaw() abort " {{{2 |
||||
|
let checker_start = reltime() |
||||
|
let name = self.getCName() |
||||
|
|
||||
|
if has_key(self, '_enable') |
||||
|
let status = syntastic#util#var(self._enable, -1) |
||||
|
if type(status) != type(0) |
||||
|
call syntastic#log#error('checker ' . name . ': invalid value ' . strtrans(string(status)) . |
||||
|
\ ' for g:syntastic_' . self._enable . '; try 0 or 1 instead') |
||||
|
return [] |
||||
|
endif |
||||
|
if status < 0 |
||||
|
call syntastic#log#error('checker ' . name . ': checks disabled for security reasons; ' . |
||||
|
\ 'set g:syntastic_' . self._enable . ' to 1 to override') |
||||
|
endif |
||||
|
if status <= 0 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' enabled but not forced') |
||||
|
return [] |
||||
|
else |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' forced') |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
try |
||||
|
let list = self._locListFunc() |
||||
|
if self._exec !=# '' |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' returned ' . v:shell_error) |
||||
|
endif |
||||
|
catch /\m\C^Syntastic: checker error$/ |
||||
|
let list = [] |
||||
|
if self._exec !=# '' |
||||
|
call syntastic#log#error('checker ' . name . ' returned abnormal status ' . v:shell_error) |
||||
|
else |
||||
|
call syntastic#log#error('checker ' . name . ' aborted') |
||||
|
endif |
||||
|
endtry |
||||
|
call self._populateHighlightRegexes(list) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, name . ' raw:', list) |
||||
|
call self._quietMessages(list) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, |
||||
|
\ 'getLocList: checker ' . name . ' run in ' . split(reltimestr(reltime(checker_start)))[0] . 's') |
||||
|
return list |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getLocList() abort " {{{2 |
||||
|
return g:SyntasticLoclist.New(self.getLocListRaw()) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.getVersion(...) abort " {{{2 |
||||
|
if !exists('self._version') |
||||
|
let command = a:0 ? a:1 : self.getExecEscaped() . ' --version' |
||||
|
let version_output = syntastic#util#system(command) |
||||
|
call self.log('getVersion: ' . string(command) . ': ' . |
||||
|
\ string(split(version_output, "\n", 1)) . |
||||
|
\ (v:shell_error ? ' (exit code ' . v:shell_error . ')' : '') ) |
||||
|
let parsed_ver = syntastic#util#parseVersion(version_output) |
||||
|
if len(parsed_ver) |
||||
|
call self.setVersion(parsed_ver) |
||||
|
else |
||||
|
call syntastic#log#ndebug(g:_SYNTASTIC_DEBUG_LOCLIST, 'checker output:', split(version_output, "\n", 1)) |
||||
|
call syntastic#log#error("checker " . self.getCName() . ": can't parse version string (abnormal termination?)") |
||||
|
endif |
||||
|
endif |
||||
|
return get(self, '_version', []) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.setVersion(version) abort " {{{2 |
||||
|
if len(a:version) |
||||
|
let self._version = copy(a:version) |
||||
|
call self.log(self.getExec() . ' version =', a:version) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.log(msg, ...) abort " {{{2 |
||||
|
let leader = self.getCName() . ': ' |
||||
|
if a:0 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, leader . a:msg, a:1) |
||||
|
else |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, leader . a:msg) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.makeprgBuild(opts) abort " {{{2 |
||||
|
let basename = self._filetype . '_' . self._name . '_' |
||||
|
|
||||
|
let parts = [] |
||||
|
call extend(parts, self._getOpt(a:opts, basename, 'exe', self.getExecEscaped())) |
||||
|
call extend(parts, self._getOpt(a:opts, basename, 'args', '')) |
||||
|
call extend(parts, self._getOpt(a:opts, basename, 'fname', syntastic#util#shexpand('%'))) |
||||
|
call extend(parts, self._getOpt(a:opts, basename, 'post_args', '')) |
||||
|
call extend(parts, self._getOpt(a:opts, basename, 'tail', '')) |
||||
|
|
||||
|
return join(parts) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.isAvailable() abort " {{{2 |
||||
|
call self.syncExec() |
||||
|
|
||||
|
if !has_key(self, '_available') |
||||
|
let self._available = {} |
||||
|
endif |
||||
|
if !has_key(self._available, self._exec) |
||||
|
let self._available[self._exec] = self._isAvailableFunc() |
||||
|
endif |
||||
|
|
||||
|
return self._available[self._exec] |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.isDisabled() abort " {{{2 |
||||
|
return has_key(self, '_enable') && syntastic#util#var(self._enable, -1) <= 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker.wantSort() abort " {{{2 |
||||
|
return syntastic#util#var(self._filetype . '_' . self._name . '_sort', 0) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" This method is no longer used by syntastic. It's here only to maintain |
||||
|
" backwards compatibility with external checkers which might depend on it. |
||||
|
function! g:SyntasticChecker.setWantSort(val) abort " {{{2 |
||||
|
if !exists('g:syntastic_' . self._filetype . '_' . self._name . '_sort') |
||||
|
let g:syntastic_{self._filetype}_{self._name}_sort = a:val |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticChecker._quietMessages(errors) abort " {{{2 |
||||
|
" wildcard quiet_messages |
||||
|
let quiet_filters = copy(syntastic#util#var('quiet_messages', {})) |
||||
|
if type(quiet_filters) != type({}) |
||||
|
call syntastic#log#warn('ignoring invalid syntastic_quiet_messages') |
||||
|
unlet quiet_filters |
||||
|
let quiet_filters = {} |
||||
|
endif |
||||
|
|
||||
|
" per checker quiet_messages |
||||
|
let name = self._filetype . '_' . self._name |
||||
|
try |
||||
|
call extend( quiet_filters, copy(syntastic#util#var(name . '_quiet_messages', {})), 'force' ) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E712/ |
||||
|
call syntastic#log#warn('ignoring invalid syntastic_' . name . '_quiet_messages') |
||||
|
endtry |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'quiet_messages filter:', quiet_filters) |
||||
|
|
||||
|
if !empty(quiet_filters) |
||||
|
call syntastic#util#dictFilter(a:errors, quiet_filters) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'filtered by quiet_messages:', a:errors) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker._populateHighlightRegexes(errors) abort " {{{2 |
||||
|
if has_key(self, '_highlightRegexFunc') |
||||
|
for e in a:errors |
||||
|
if e['valid'] |
||||
|
let term = self._highlightRegexFunc(e) |
||||
|
if term !=# '' |
||||
|
let e['hl'] = term |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticChecker._getOpt(opts, basename, name, default) abort " {{{2 |
||||
|
let ret = [] |
||||
|
call extend( ret, syntastic#util#argsescape(get(a:opts, a:name . '_before', '')) ) |
||||
|
call extend( ret, syntastic#util#argsescape(syntastic#util#var( a:basename . a:name, get(a:opts, a:name, a:default) )) ) |
||||
|
call extend( ret, syntastic#util#argsescape(get(a:opts, a:name . '_after', '')) ) |
||||
|
|
||||
|
return ret |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
function! s:_isAvailableDefault() dict " {{{2 |
||||
|
return executable(self.getExec()) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,138 @@ |
|||||
|
if exists('g:loaded_syntastic_notifier_cursor') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifier_cursor = 1 |
||||
|
|
||||
|
let g:SyntasticCursorNotifier = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticCursorNotifier.New() abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticCursorNotifier.enabled() abort " {{{2 |
||||
|
return syntastic#util#var('echo_current_error') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticCursorNotifier.refresh(loclist) abort " {{{2 |
||||
|
if self.enabled() && !a:loclist.isEmpty() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'cursor: refresh') |
||||
|
let b:syntastic_private_messages = copy(a:loclist.messages(bufnr(''))) |
||||
|
let b:syntastic_private_line = -1 |
||||
|
let b:syntastic_cursor_columns = a:loclist.getCursorColumns() |
||||
|
autocmd! syntastic CursorMoved |
||||
|
autocmd syntastic CursorMoved * call SyntasticRefreshCursor() |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" @vimlint(EVL103, 1, a:loclist) |
||||
|
function! g:SyntasticCursorNotifier.reset(loclist) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'cursor: reset') |
||||
|
autocmd! syntastic CursorMoved |
||||
|
unlet! b:syntastic_private_messages |
||||
|
let b:syntastic_private_line = -1 |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:loclist) |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private functions {{{1 |
||||
|
|
||||
|
function! SyntasticRefreshCursor() abort " {{{2 |
||||
|
if !exists('b:syntastic_private_messages') || empty(b:syntastic_private_messages) |
||||
|
" file not checked |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
if !exists('b:syntastic_private_line') |
||||
|
let b:syntastic_private_line = -1 |
||||
|
endif |
||||
|
let l = line('.') |
||||
|
let current_messages = get(b:syntastic_private_messages, l, {}) |
||||
|
|
||||
|
if !exists('b:syntastic_cursor_columns') |
||||
|
let b:syntastic_cursor_columns = g:syntastic_cursor_columns |
||||
|
endif |
||||
|
|
||||
|
if b:syntastic_cursor_columns |
||||
|
let c = virtcol('.') |
||||
|
if !exists('b:syntastic_private_idx') |
||||
|
let b:syntastic_private_idx = -1 |
||||
|
endif |
||||
|
|
||||
|
if s:_is_same_index(l, b:syntastic_private_line, c, b:syntastic_private_idx, current_messages) |
||||
|
return |
||||
|
else |
||||
|
let b:syntastic_private_line = l |
||||
|
endif |
||||
|
|
||||
|
if !empty(current_messages) |
||||
|
let b:syntastic_private_idx = s:_find_index(c, current_messages) |
||||
|
call syntastic#util#wideMsg(current_messages[b:syntastic_private_idx].text) |
||||
|
else |
||||
|
let b:syntastic_private_idx = -1 |
||||
|
echo |
||||
|
endif |
||||
|
else |
||||
|
if l == b:syntastic_private_line |
||||
|
return |
||||
|
endif |
||||
|
let b:syntastic_private_line = l |
||||
|
|
||||
|
if !empty(current_messages) |
||||
|
call syntastic#util#wideMsg(current_messages[0].text) |
||||
|
else |
||||
|
echo |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
function! s:_is_same_index(line, old_line, column, idx, messages) abort " {{{2 |
||||
|
if a:old_line >= 0 && a:line == a:old_line && a:idx >= 0 |
||||
|
if len(a:messages) <= 1 |
||||
|
return 1 |
||||
|
endif |
||||
|
|
||||
|
if a:messages[a:idx].scol <= a:column || a:idx == 0 |
||||
|
if a:idx == len(a:messages) - 1 || a:column < a:messages[a:idx + 1].scol |
||||
|
return 1 |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_find_index(column, messages) abort " {{{2 |
||||
|
let max = len(a:messages) - 1 |
||||
|
if max == 0 |
||||
|
return 0 |
||||
|
endif |
||||
|
let min = 0 |
||||
|
|
||||
|
" modified binary search: assign index 0 to columns to the left of the first error |
||||
|
while min < max - 1 |
||||
|
let mid = (min + max) / 2 |
||||
|
if a:column < a:messages[mid].scol |
||||
|
let max = mid |
||||
|
else |
||||
|
let min = mid |
||||
|
endif |
||||
|
endwhile |
||||
|
|
||||
|
return a:column < a:messages[max].scol ? min : max |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,104 @@ |
|||||
|
if exists('g:loaded_syntastic_notifier_highlighting') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifier_highlighting = 1 |
||||
|
|
||||
|
" Highlighting requires getmatches introduced in 7.1.040 |
||||
|
let s:has_highlighting = v:version > 701 || (v:version == 701 && has('patch040')) |
||||
|
lockvar s:has_highlighting |
||||
|
|
||||
|
let g:SyntasticHighlightingNotifier = {} |
||||
|
|
||||
|
let s:setup_done = 0 |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticHighlightingNotifier.New() abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
|
||||
|
if !s:setup_done |
||||
|
call self._setup() |
||||
|
let s:setup_done = 1 |
||||
|
lockvar s:setup_done |
||||
|
endif |
||||
|
|
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticHighlightingNotifier.enabled() abort " {{{2 |
||||
|
return s:has_highlighting && syntastic#util#var('enable_highlighting') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Sets error highlights in the current window |
||||
|
function! g:SyntasticHighlightingNotifier.refresh(loclist) abort " {{{2 |
||||
|
if self.enabled() |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'highlighting: refresh') |
||||
|
call self._reset() |
||||
|
let buf = bufnr('') |
||||
|
let issues = filter(a:loclist.copyRaw(), 'v:val["bufnr"] == buf') |
||||
|
for item in issues |
||||
|
let group = 'Syntastic' . get(item, 'subtype', '') . ( item['type'] ==? 'E' ? 'Error' : 'Warning' ) |
||||
|
|
||||
|
" The function `Syntastic_{filetype}_{checker}_GetHighlightRegex` is |
||||
|
" used to override default highlighting. |
||||
|
if has_key(item, 'hl') |
||||
|
call matchadd(group, '\%' . item['lnum'] . 'l' . item['hl']) |
||||
|
elseif get(item, 'col', 0) |
||||
|
if get(item, 'vcol', 0) |
||||
|
let lastcol = virtcol([item['lnum'], '$']) |
||||
|
let coltype = 'v' |
||||
|
else |
||||
|
let lastcol = col([item['lnum'], '$']) |
||||
|
let coltype = 'c' |
||||
|
endif |
||||
|
let lcol = min([lastcol, item['col']]) |
||||
|
|
||||
|
call matchadd(group, '\%' . item['lnum'] . 'l\%' . lcol . coltype) |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Remove all error highlights from the window |
||||
|
" @vimlint(EVL103, 1, a:loclist) |
||||
|
function! g:SyntasticHighlightingNotifier.reset(loclist) abort " {{{2 |
||||
|
if s:has_highlighting |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'highlighting: reset') |
||||
|
call self._reset() |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
" @vimlint(EVL103, 0, a:loclist) |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
" One time setup: define our own highlighting |
||||
|
function! g:SyntasticHighlightingNotifier._setup() abort " {{{2 |
||||
|
if s:has_highlighting |
||||
|
if !hlexists('SyntasticError') |
||||
|
highlight link SyntasticError SpellBad |
||||
|
endif |
||||
|
if !hlexists('SyntasticWarning') |
||||
|
highlight link SyntasticWarning SpellCap |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleError') |
||||
|
highlight link SyntasticStyleError SyntasticError |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleWarning') |
||||
|
highlight link SyntasticStyleWarning SyntasticWarning |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticHighlightingNotifier._reset() abort " {{{2 |
||||
|
for match in getmatches() |
||||
|
if stridx(match['group'], 'Syntastic') == 0 |
||||
|
call matchdelete(match['id']) |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,445 @@ |
|||||
|
if exists('g:loaded_syntastic_loclist') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_loclist = 1 |
||||
|
|
||||
|
let g:SyntasticLoclist = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticLoclist.New(rawLoclist) abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
|
||||
|
let llist = filter(copy(a:rawLoclist), 'v:val["valid"]') |
||||
|
|
||||
|
for e in llist |
||||
|
if get(e, 'type', '') ==# '' |
||||
|
let e['type'] = 'E' |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
let newObj._rawLoclist = llist |
||||
|
let newObj._name = '' |
||||
|
let newObj._owner = bufnr('') |
||||
|
let newObj._sorted = 0 |
||||
|
let newObj._columns = g:syntastic_cursor_columns |
||||
|
|
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.current(...) abort " {{{2 |
||||
|
let buf = a:0 ? a:1 : bufnr('') |
||||
|
let loclist = syntastic#util#getbufvar(buf, 'syntastic_loclist', {}) |
||||
|
if type(loclist) != type({}) || empty(loclist) |
||||
|
unlet! loclist |
||||
|
let loclist = g:SyntasticLoclist.New([]) |
||||
|
endif |
||||
|
return loclist |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.extend(other) abort " {{{2 |
||||
|
call extend(self._rawLoclist, a:other.copyRaw()) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.sort() abort " {{{2 |
||||
|
if !self._sorted |
||||
|
for e in self._rawLoclist |
||||
|
call s:_set_screen_column(e) |
||||
|
endfor |
||||
|
|
||||
|
call sort(self._rawLoclist, self._columns ? 's:_compare_error_items_by_columns' : 's:_compare_error_items_by_lines') |
||||
|
|
||||
|
let self._sorted = 1 |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.isEmpty() abort " {{{2 |
||||
|
return empty(self._rawLoclist) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.isNewerThan(stamp) abort " {{{2 |
||||
|
if !exists('self._stamp') |
||||
|
let self._stamp = [] |
||||
|
return 0 |
||||
|
endif |
||||
|
return syntastic#util#compareLexi(self._stamp, a:stamp) > 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.copyRaw() abort " {{{2 |
||||
|
return copy(self._rawLoclist) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getRaw() abort " {{{2 |
||||
|
return self._rawLoclist |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getBuffers() abort " {{{2 |
||||
|
return syntastic#util#unique(map(copy(self._rawLoclist), 'str2nr(v:val["bufnr"])') + [self._owner]) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getCursorColumns() abort " {{{2 |
||||
|
return self._columns |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getStatuslineFlag() abort " {{{2 |
||||
|
if !exists('self._stl_format') |
||||
|
let self._stl_format = '' |
||||
|
endif |
||||
|
if !exists('self._stl_flag') |
||||
|
let self._stl_flag = '' |
||||
|
endif |
||||
|
|
||||
|
if g:syntastic_stl_format !=# self._stl_format |
||||
|
let self._stl_format = g:syntastic_stl_format |
||||
|
|
||||
|
if !empty(self._rawLoclist) |
||||
|
let errors = self.errors() |
||||
|
let warnings = self.warnings() |
||||
|
|
||||
|
let num_errors = len(errors) |
||||
|
let num_warnings = len(warnings) |
||||
|
let num_issues = len(self._rawLoclist) |
||||
|
|
||||
|
let output = self._stl_format |
||||
|
|
||||
|
"hide stuff wrapped in %E(...) unless there are errors |
||||
|
let output = substitute(output, '\m\C%E{\([^}]*\)}', num_errors ? '\1' : '' , 'g') |
||||
|
|
||||
|
"hide stuff wrapped in %W(...) unless there are warnings |
||||
|
let output = substitute(output, '\m\C%W{\([^}]*\)}', num_warnings ? '\1' : '' , 'g') |
||||
|
|
||||
|
"hide stuff wrapped in %B(...) unless there are both errors and warnings |
||||
|
let output = substitute(output, '\m\C%B{\([^}]*\)}', (num_warnings && num_errors) ? '\1' : '' , 'g') |
||||
|
|
||||
|
let flags = { |
||||
|
\ '%': '%', |
||||
|
\ 't': num_issues, |
||||
|
\ 'e': num_errors, |
||||
|
\ 'w': num_warnings, |
||||
|
\ 'N': (num_issues ? fnamemodify( bufname(self._rawLoclist[0]['bufnr']), ':t') : ''), |
||||
|
\ 'P': (num_issues ? fnamemodify( bufname(self._rawLoclist[0]['bufnr']), ':p:~:.') : ''), |
||||
|
\ 'F': (num_issues ? self._rawLoclist[0]['lnum'] : ''), |
||||
|
\ 'ne': (num_errors ? fnamemodify( bufname(errors[0]['bufnr']), ':t') : ''), |
||||
|
\ 'pe': (num_errors ? fnamemodify( bufname(errors[0]['bufnr']), ':p:~:.') : ''), |
||||
|
\ 'fe': (num_errors ? errors[0]['lnum'] : ''), |
||||
|
\ 'nw': (num_warnings ? fnamemodify( bufname(warnings[0]['bufnr']), ':t') : ''), |
||||
|
\ 'pw': (num_warnings ? fnamemodify( bufname(warnings[0]['bufnr']), ':p:~:.') : ''), |
||||
|
\ 'fw': (num_warnings ? warnings[0]['lnum'] : '') } |
||||
|
let output = substitute(output, '\v\C\%(-?\d*%(\.\d+)?)([npf][ew]|[NPFtew%])', '\=syntastic#util#wformat(submatch(1), flags[submatch(2)])', 'g') |
||||
|
|
||||
|
let self._stl_flag = output |
||||
|
else |
||||
|
let self._stl_flag = '' |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
return self._stl_flag |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getFirstError(...) abort " {{{2 |
||||
|
let max_issues = len(self._rawLoclist) |
||||
|
if a:0 && a:1 < max_issues |
||||
|
let max_issues = a:1 |
||||
|
endif |
||||
|
|
||||
|
for idx in range(max_issues) |
||||
|
if get(self._rawLoclist[idx], 'type', '') ==? 'E' |
||||
|
return idx + 1 |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getName() abort " {{{2 |
||||
|
return len(self._name) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.setName(name) abort " {{{2 |
||||
|
let self._name = a:name |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.getOwner() abort " {{{2 |
||||
|
return self._owner |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.setOwner(buffer) abort " {{{2 |
||||
|
let self._owner = type(a:buffer) == type(0) ? a:buffer : str2nr(a:buffer) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.deploy() abort " {{{2 |
||||
|
let self._stamp = syntastic#util#stamp() |
||||
|
for buf in self.getBuffers() |
||||
|
call setbufvar(buf, 'syntastic_loclist', self) |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.destroy() abort " {{{2 |
||||
|
for buf in self.getBuffers() |
||||
|
call setbufvar(buf, 'syntastic_loclist', {}) |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.decorate(tag) abort " {{{2 |
||||
|
for e in self._rawLoclist |
||||
|
let e['text'] .= ' [' . a:tag . ']' |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.balloons() abort " {{{2 |
||||
|
if !exists('self._cachedBalloons') |
||||
|
let sep = has('balloon_multiline') ? "\n" : ' | ' |
||||
|
|
||||
|
let self._cachedBalloons = {} |
||||
|
for e in self._rawLoclist |
||||
|
let buf = e['bufnr'] |
||||
|
|
||||
|
if !has_key(self._cachedBalloons, buf) |
||||
|
let self._cachedBalloons[buf] = {} |
||||
|
endif |
||||
|
|
||||
|
if has_key(self._cachedBalloons[buf], e['lnum']) |
||||
|
let self._cachedBalloons[buf][e['lnum']] .= sep . e['text'] |
||||
|
else |
||||
|
let self._cachedBalloons[buf][e['lnum']] = e['text'] |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
return get(self._cachedBalloons, bufnr(''), {}) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.errors() abort " {{{2 |
||||
|
if !exists('self._cachedErrors') |
||||
|
let self._cachedErrors = self.filter({'type': 'E'}) |
||||
|
endif |
||||
|
return self._cachedErrors |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.warnings() abort " {{{2 |
||||
|
if !exists('self._cachedWarnings') |
||||
|
let self._cachedWarnings = self.filter({'type': 'W'}) |
||||
|
endif |
||||
|
return self._cachedWarnings |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Legacy function. Syntastic no longer calls it, but we keep it |
||||
|
" around because other plugins (f.i. powerline) depend on it. |
||||
|
function! g:SyntasticLoclist.hasErrorsOrWarningsToDisplay() abort " {{{2 |
||||
|
return !self.isEmpty() |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" cache used by EchoCurrentError() |
||||
|
function! g:SyntasticLoclist.messages(buf) abort " {{{2 |
||||
|
if !exists('self._cachedMessages') |
||||
|
let self._cachedMessages = {} |
||||
|
|
||||
|
let errors = self.errors() + self.warnings() |
||||
|
for e in errors |
||||
|
let b = e['bufnr'] |
||||
|
let l = e['lnum'] |
||||
|
|
||||
|
if !has_key(self._cachedMessages, b) |
||||
|
let self._cachedMessages[b] = {} |
||||
|
endif |
||||
|
|
||||
|
if !has_key(self._cachedMessages[b], l) |
||||
|
let self._cachedMessages[b][l] = [e] |
||||
|
elseif self._columns |
||||
|
call add(self._cachedMessages[b][l], e) |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
if self._columns |
||||
|
if !self._sorted |
||||
|
for b in keys(self._cachedMessages) |
||||
|
for l in keys(self._cachedMessages[b]) |
||||
|
if len(self._cachedMessages[b][l]) > 1 |
||||
|
for e in self._cachedMessages[b][l] |
||||
|
call s:_set_screen_column(e) |
||||
|
endfor |
||||
|
call sort(self._cachedMessages[b][l], 's:_compare_error_items_by_columns') |
||||
|
endif |
||||
|
endfor |
||||
|
endfor |
||||
|
endif |
||||
|
|
||||
|
for b in keys(self._cachedMessages) |
||||
|
for l in keys(self._cachedMessages[b]) |
||||
|
call s:_remove_shadowed_items(self._cachedMessages[b][l]) |
||||
|
endfor |
||||
|
endfor |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
return get(self._cachedMessages, a:buf, {}) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
"Filter the list and return new native loclist |
||||
|
"e.g. |
||||
|
" .filter({'bufnr': 10, 'type': 'e'}) |
||||
|
" |
||||
|
"would return all errors for buffer 10. |
||||
|
" |
||||
|
"Note that all string comparisons are done with ==? |
||||
|
function! g:SyntasticLoclist.filter(filters) abort " {{{2 |
||||
|
let conditions = values(map(copy(a:filters), 's:_translate(v:key, v:val)')) |
||||
|
let filter = len(conditions) == 1 ? |
||||
|
\ conditions[0] : join(map(conditions, '"(" . v:val . ")"'), ' && ') |
||||
|
return filter(copy(self._rawLoclist), filter) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticLoclist.setloclist(new) abort " {{{2 |
||||
|
if !exists('w:syntastic_loclist_set') |
||||
|
let w:syntastic_loclist_set = [] |
||||
|
endif |
||||
|
if a:new || empty(w:syntastic_loclist_set) || w:syntastic_loclist_set != [self._owner, getbufvar(self._owner, 'changedtick')] |
||||
|
let replace = !a:new && g:syntastic_reuse_loc_lists && !empty(w:syntastic_loclist_set) |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: setloclist ' . (replace ? '(replace)' : '(new)')) |
||||
|
call setloclist(0, self.getRaw(), replace ? 'r' : ' ') |
||||
|
try |
||||
|
" Vim 7.4.2200 or later |
||||
|
call setloclist(0, [], 'r', { 'title': ':SyntasticCheck ' . self._name }) |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E\%(118\|731\)/ |
||||
|
" do nothing |
||||
|
endtry |
||||
|
call syntastic#util#setLastTick(self._owner) |
||||
|
let w:syntastic_loclist_set = [self._owner, getbufvar(self._owner, 'syntastic_lasttick')] |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
"display the cached errors for this buf in the location list |
||||
|
function! g:SyntasticLoclist.show() abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: show') |
||||
|
call self.setloclist(0) |
||||
|
|
||||
|
if !&previewwindow && !self.isEmpty() |
||||
|
let num = winnr() |
||||
|
execute 'lopen ' . syntastic#util#var('loc_list_height') |
||||
|
if num != winnr() |
||||
|
execute num . 'wincmd w' |
||||
|
endif |
||||
|
|
||||
|
" try to find the loclist window and set w:quickfix_title |
||||
|
let errors = getloclist(0) |
||||
|
for buf in tabpagebuflist() |
||||
|
if buflisted(buf) && bufloaded(buf) && getbufvar(buf, '&buftype') ==# 'quickfix' |
||||
|
let win = bufwinnr(buf) |
||||
|
let title = getwinvar(win, 'quickfix_title') |
||||
|
|
||||
|
" TODO: try to make sure we actually own this window; sadly, |
||||
|
" errors == getloclist(0) is the only somewhat safe way to |
||||
|
" achieve that |
||||
|
if strpart(title, 0, 16) ==# ':SyntasticCheck ' || |
||||
|
\ ( (title ==# '' || title ==# ':setloclist()') && errors == getloclist(0) ) |
||||
|
call setwinvar(win, 'quickfix_title', ':SyntasticCheck ' . self._name) |
||||
|
call setbufvar(buf, 'syntastic_owner_buffer', self._owner) |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Public functions {{{1 |
||||
|
|
||||
|
function! SyntasticLoclistHide() abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: hide') |
||||
|
silent! lclose |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
function! s:_translate(key, val) abort " {{{2 |
||||
|
return 'get(v:val, ' . string(a:key) . ', "") ==? ' . string(a:val) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_set_screen_column(item) abort " {{{2 |
||||
|
if !has_key(a:item, 'scol') |
||||
|
let col = get(a:item, 'col', 0) |
||||
|
if col != 0 && get(a:item, 'vcol', 0) == 0 |
||||
|
let buf = str2nr(a:item['bufnr']) |
||||
|
try |
||||
|
let line = getbufline(buf, a:item['lnum'])[0] |
||||
|
catch /\m^Vim\%((\a\+)\)\=:E684/ |
||||
|
let line = '' |
||||
|
endtry |
||||
|
let a:item['scol'] = syntastic#util#screenWidth(strpart(line, 0, col), getbufvar(buf, '&tabstop')) |
||||
|
else |
||||
|
let a:item['scol'] = col |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_remove_shadowed_items(errors) abort " {{{2 |
||||
|
" keep only the first message at a given column |
||||
|
let i = 0 |
||||
|
while i < len(a:errors) - 1 |
||||
|
let j = i + 1 |
||||
|
let dupes = 0 |
||||
|
while j < len(a:errors) && a:errors[j].scol == a:errors[i].scol |
||||
|
let dupes = 1 |
||||
|
let j += 1 |
||||
|
endwhile |
||||
|
if dupes |
||||
|
call remove(a:errors, i + 1, j - 1) |
||||
|
endif |
||||
|
let i += 1 |
||||
|
endwhile |
||||
|
|
||||
|
" merge messages with the same text |
||||
|
let i = 0 |
||||
|
while i < len(a:errors) - 1 |
||||
|
let j = i + 1 |
||||
|
let dupes = 0 |
||||
|
while j < len(a:errors) && a:errors[j].text == a:errors[i].text |
||||
|
let dupes = 1 |
||||
|
let j += 1 |
||||
|
endwhile |
||||
|
if dupes |
||||
|
call remove(a:errors, i + 1, j - 1) |
||||
|
endif |
||||
|
let i += 1 |
||||
|
endwhile |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_compare_error_items_by_columns(a, b) abort " {{{2 |
||||
|
if a:a['bufnr'] != a:b['bufnr'] |
||||
|
" group by file |
||||
|
return a:a['bufnr'] - a:b['bufnr'] |
||||
|
elseif a:a['lnum'] != a:b['lnum'] |
||||
|
" sort by line |
||||
|
return a:a['lnum'] - a:b['lnum'] |
||||
|
elseif a:a['scol'] != a:b['scol'] |
||||
|
" sort by screen column |
||||
|
return a:a['scol'] - a:b['scol'] |
||||
|
elseif a:a['type'] !=? a:b['type'] |
||||
|
" errors take precedence over warnings |
||||
|
return a:a['type'] ==? 'E' ? -1 : 1 |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_compare_error_items_by_lines(a, b) abort " {{{2 |
||||
|
if a:a['bufnr'] != a:b['bufnr'] |
||||
|
" group by file |
||||
|
return a:a['bufnr'] - a:b['bufnr'] |
||||
|
elseif a:a['lnum'] != a:b['lnum'] |
||||
|
" sort by line |
||||
|
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 |
||||
|
" sort by screen column |
||||
|
return a:a['scol'] - a:b['scol'] |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,118 @@ |
|||||
|
if exists('g:loaded_syntastic_modemap') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_modemap = 1 |
||||
|
|
||||
|
let g:SyntasticModeMap = {} |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticModeMap.Instance() abort " {{{2 |
||||
|
if !exists('s:SyntasticModeMapInstance') |
||||
|
let s:SyntasticModeMapInstance = copy(self) |
||||
|
call s:SyntasticModeMapInstance.synch() |
||||
|
endif |
||||
|
|
||||
|
return s:SyntasticModeMapInstance |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.synch() abort " {{{2 |
||||
|
if exists('g:syntastic_mode_map') |
||||
|
let self._mode = get(g:syntastic_mode_map, 'mode', 'active') |
||||
|
let self._activeFiletypes = copy(get(g:syntastic_mode_map, 'active_filetypes', [])) |
||||
|
let self._passiveFiletypes = copy(get(g:syntastic_mode_map, 'passive_filetypes', [])) |
||||
|
else |
||||
|
let self._mode = 'active' |
||||
|
let self._activeFiletypes = [] |
||||
|
let self._passiveFiletypes = [] |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.allowsAutoChecking(filetype) abort " {{{2 |
||||
|
let registry = g:SyntasticRegistry.Instance() |
||||
|
let fts = registry.resolveFiletypes(a:filetype) |
||||
|
|
||||
|
if self.isPassive() |
||||
|
return self._isOneFiletypeActive(fts) |
||||
|
else |
||||
|
return self._noFiletypesArePassive(fts) |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.doAutoChecking(buf) abort " {{{2 |
||||
|
let local_mode = getbufvar(a:buf, 'syntastic_mode') |
||||
|
if local_mode ==# 'active' || local_mode ==# 'passive' |
||||
|
return local_mode ==# 'active' |
||||
|
endif |
||||
|
|
||||
|
return self.allowsAutoChecking(getbufvar(a:buf, '&filetype')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.isPassive() abort " {{{2 |
||||
|
return self._mode ==# 'passive' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.toggleMode() abort " {{{2 |
||||
|
call self.synch() |
||||
|
|
||||
|
if self._mode ==# 'active' |
||||
|
let self._mode = 'passive' |
||||
|
else |
||||
|
let self._mode = 'active' |
||||
|
endif |
||||
|
|
||||
|
"XXX Changing a global variable. Tsk, tsk... |
||||
|
if !exists('g:syntastic_mode_map') |
||||
|
let g:syntastic_mode_map = {} |
||||
|
endif |
||||
|
let g:syntastic_mode_map['mode'] = self._mode |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.echoMode() abort " {{{2 |
||||
|
echo 'Syntastic: ' . self._mode . ' mode enabled' |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap.modeInfo(filetypes) abort " {{{2 |
||||
|
echomsg 'Syntastic version: ' . g:syntastic_version |
||||
|
let type = len(a:filetypes) ? a:filetypes[0] : &filetype |
||||
|
echomsg 'Info for filetype: ' . type |
||||
|
|
||||
|
call self.synch() |
||||
|
echomsg 'Global mode: ' . self._mode |
||||
|
if self._mode ==# 'active' |
||||
|
if len(self._passiveFiletypes) |
||||
|
let plural = len(self._passiveFiletypes) != 1 ? 's' : '' |
||||
|
echomsg 'Passive filetype' . plural . ': ' . join(sort(copy(self._passiveFiletypes))) |
||||
|
endif |
||||
|
else |
||||
|
if len(self._activeFiletypes) |
||||
|
let plural = len(self._activeFiletypes) != 1 ? 's' : '' |
||||
|
echomsg 'Active filetype' . plural . ': ' . join(sort(copy(self._activeFiletypes))) |
||||
|
endif |
||||
|
endif |
||||
|
echomsg 'Filetype ' . type . ' is ' . (self.allowsAutoChecking(type) ? 'active' : 'passive') |
||||
|
|
||||
|
if !len(a:filetypes) |
||||
|
if exists('b:syntastic_mode') && (b:syntastic_mode ==# 'active' || b:syntastic_mode ==# 'passive') |
||||
|
echomsg 'Local mode: ' . b:syntastic_mode |
||||
|
endif |
||||
|
|
||||
|
echomsg 'The current file will ' . (self.doAutoChecking(bufnr('')) ? '' : 'not ') . 'be checked automatically' |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticModeMap._isOneFiletypeActive(filetypes) abort " {{{2 |
||||
|
return !empty(filter(copy(a:filetypes), 'index(self._activeFiletypes, v:val) != -1')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticModeMap._noFiletypesArePassive(filetypes) abort " {{{2 |
||||
|
return empty(filter(copy(a:filetypes), 'index(self._passiveFiletypes, v:val) != -1')) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,86 @@ |
|||||
|
if exists('g:loaded_syntastic_notifiers') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifiers = 1 |
||||
|
|
||||
|
let g:SyntasticNotifiers = {} |
||||
|
|
||||
|
let s:_NOTIFIER_TYPES = ['signs', 'balloons', 'highlighting', 'cursor', 'autoloclist'] |
||||
|
lockvar! s:_NOTIFIER_TYPES |
||||
|
|
||||
|
let s:_PERSISTENT_NOTIFIERS = ['signs', 'balloons'] |
||||
|
lockvar! s:_PERSISTENT_NOTIFIERS |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticNotifiers.Instance() abort " {{{2 |
||||
|
if !exists('s:SyntasticNotifiersInstance') |
||||
|
let s:SyntasticNotifiersInstance = copy(self) |
||||
|
call s:SyntasticNotifiersInstance._initNotifiers() |
||||
|
endif |
||||
|
|
||||
|
return s:SyntasticNotifiersInstance |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticNotifiers.refresh(loclist) abort " {{{2 |
||||
|
if !syntastic#util#bufIsActive(bufnr('')) || (!a:loclist.isEmpty() && !a:loclist.isNewerThan([])) |
||||
|
" loclist not fully constructed yet |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'notifiers: refresh') |
||||
|
for type in self._enabled_types |
||||
|
let class = substitute(type, '\m.*', 'Syntastic\u&Notifier', '') |
||||
|
if !has_key(g:{class}, 'enabled') || self._notifier[type].enabled() |
||||
|
if index(s:_PERSISTENT_NOTIFIERS, type) > -1 |
||||
|
" refresh only if loclist has changed since last call |
||||
|
if !exists('b:syntastic_private_' . type . '_stamp') |
||||
|
let b:syntastic_private_{type}_stamp = [] |
||||
|
endif |
||||
|
if a:loclist.isNewerThan(b:syntastic_private_{type}_stamp) || a:loclist.isEmpty() |
||||
|
call self._notifier[type].refresh(a:loclist) |
||||
|
let b:syntastic_private_{type}_stamp = syntastic#util#stamp() |
||||
|
endif |
||||
|
else |
||||
|
call self._notifier[type].refresh(a:loclist) |
||||
|
endif |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticNotifiers.reset(loclist) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'notifiers: reset') |
||||
|
for type in self._enabled_types |
||||
|
let class = substitute(type, '\m.*', 'Syntastic\u&Notifier', '') |
||||
|
|
||||
|
" reset notifiers regardless if they are enabled or not, since |
||||
|
" the user might have disabled them since the last refresh(); |
||||
|
" notifiers MUST be prepared to deal with reset() when disabled |
||||
|
if has_key(g:{class}, 'reset') |
||||
|
call self._notifier[type].reset(a:loclist) |
||||
|
endif |
||||
|
|
||||
|
" also reset stamps |
||||
|
if index(s:_PERSISTENT_NOTIFIERS, type) > -1 |
||||
|
let b:syntastic_private_{type}_stamp = [] |
||||
|
endif |
||||
|
endfor |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticNotifiers._initNotifiers() abort " {{{2 |
||||
|
let self._notifier = {} |
||||
|
for type in s:_NOTIFIER_TYPES |
||||
|
let class = substitute(type, '\m.*', 'Syntastic\u&Notifier', '') |
||||
|
let self._notifier[type] = g:{class}.New() |
||||
|
endfor |
||||
|
|
||||
|
let self._enabled_types = copy(s:_NOTIFIER_TYPES) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,445 @@ |
|||||
|
if exists('g:loaded_syntastic_registry') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_registry = 1 |
||||
|
|
||||
|
" Initialisation {{{1 |
||||
|
|
||||
|
let s:_DEFAULT_CHECKERS = { |
||||
|
\ 'actionscript': ['mxmlc'], |
||||
|
\ 'ada': ['gcc'], |
||||
|
\ 'ansible': ['ansible_lint'], |
||||
|
\ 'apiblueprint': ['drafter'], |
||||
|
\ 'applescript': ['osacompile'], |
||||
|
\ 'asciidoc': ['asciidoc'], |
||||
|
\ 'asl': ['iasl'], |
||||
|
\ 'asm': ['gcc'], |
||||
|
\ 'bro': ['bro'], |
||||
|
\ 'bemhtml': ['bemhtmllint'], |
||||
|
\ 'c': ['gcc'], |
||||
|
\ 'cabal': ['cabal'], |
||||
|
\ 'chef': ['foodcritic'], |
||||
|
\ 'cmake': ['cmakelint'], |
||||
|
\ 'co': ['coco'], |
||||
|
\ 'cobol': ['cobc'], |
||||
|
\ 'coffee': ['coffee', 'coffeelint'], |
||||
|
\ 'coq': ['coqtop'], |
||||
|
\ 'cpp': ['gcc'], |
||||
|
\ 'cs': ['mcs'], |
||||
|
\ 'css': ['csslint'], |
||||
|
\ 'cucumber': ['cucumber'], |
||||
|
\ 'cuda': ['nvcc'], |
||||
|
\ 'd': ['dmd'], |
||||
|
\ 'dart': ['dartanalyzer'], |
||||
|
\ 'docbk': ['xmllint'], |
||||
|
\ 'dockerfile': ['dockerfile_lint'], |
||||
|
\ 'dustjs': ['swiffer'], |
||||
|
\ 'elixir': [], |
||||
|
\ 'erlang': ['escript'], |
||||
|
\ 'eruby': ['ruby'], |
||||
|
\ 'fortran': ['gfortran'], |
||||
|
\ 'glsl': ['cgc'], |
||||
|
\ 'go': [], |
||||
|
\ 'haml': ['haml'], |
||||
|
\ 'handlebars': ['handlebars'], |
||||
|
\ 'haskell': ['hdevtools', 'hlint'], |
||||
|
\ 'haxe': ['haxe'], |
||||
|
\ 'help': [], |
||||
|
\ 'hss': ['hss'], |
||||
|
\ 'html': ['tidy'], |
||||
|
\ 'jade': ['jade_lint'], |
||||
|
\ 'java': ['javac'], |
||||
|
\ 'javascript': ['jshint', 'jslint'], |
||||
|
\ 'json': ['jsonlint', 'jsonval'], |
||||
|
\ 'julia': [], |
||||
|
\ 'less': ['lessc'], |
||||
|
\ 'lex': ['flex'], |
||||
|
\ 'limbo': ['limbo'], |
||||
|
\ 'lisp': ['clisp'], |
||||
|
\ 'llvm': ['llvm'], |
||||
|
\ 'lua': ['luac'], |
||||
|
\ 'markdown': ['mdl'], |
||||
|
\ 'matlab': ['mlint'], |
||||
|
\ 'mercury': ['mmc'], |
||||
|
\ 'nasm': ['nasm'], |
||||
|
\ 'nix': ['nix'], |
||||
|
\ 'nroff': ['mandoc'], |
||||
|
\ 'objc': ['gcc'], |
||||
|
\ 'objcpp': ['gcc'], |
||||
|
\ 'ocaml': ['camlp4o'], |
||||
|
\ 'perl': ['perlcritic'], |
||||
|
\ 'perl6': [], |
||||
|
\ 'php': ['php', 'phpcs', 'phpmd'], |
||||
|
\ 'po': ['msgfmt'], |
||||
|
\ 'pod': ['podchecker'], |
||||
|
\ 'puppet': ['puppet', 'puppetlint'], |
||||
|
\ 'pug': ['pug_lint'], |
||||
|
\ 'python': ['python', 'flake8', 'pylint'], |
||||
|
\ 'qml': ['qmllint'], |
||||
|
\ 'r': [], |
||||
|
\ 'rmd': [], |
||||
|
\ 'racket': ['racket'], |
||||
|
\ 'rnc': ['rnv'], |
||||
|
\ 'rst': ['rst2pseudoxml'], |
||||
|
\ 'ruby': ['mri'], |
||||
|
\ 'sass': ['sass'], |
||||
|
\ 'scala': ['fsc', 'scalac'], |
||||
|
\ 'scss': ['sass', 'scss_lint'], |
||||
|
\ 'sh': ['sh', 'shellcheck'], |
||||
|
\ 'slim': ['slimrb'], |
||||
|
\ 'sml': ['smlnj'], |
||||
|
\ 'spec': ['rpmlint'], |
||||
|
\ 'solidity': ['solc'], |
||||
|
\ 'sql': ['sqlint'], |
||||
|
\ 'stylus': ['stylint'], |
||||
|
\ 'svg': [], |
||||
|
\ 'tcl': ['nagelfar'], |
||||
|
\ 'tex': ['lacheck', 'chktex'], |
||||
|
\ 'texinfo': ['makeinfo'], |
||||
|
\ 'text': [], |
||||
|
\ 'trig': ['rapper'], |
||||
|
\ 'turtle': ['rapper'], |
||||
|
\ 'twig': ['twiglint'], |
||||
|
\ 'typescript': [], |
||||
|
\ 'vala': ['valac'], |
||||
|
\ 'verilog': ['verilator'], |
||||
|
\ 'vhdl': ['ghdl'], |
||||
|
\ 'vim': ['vimlint'], |
||||
|
\ 'vue': ['pug_lint_vue', 'eslint'], |
||||
|
\ 'xhtml': ['tidy'], |
||||
|
\ 'xml': ['xmllint'], |
||||
|
\ 'xslt': ['xmllint'], |
||||
|
\ 'xquery': ['basex'], |
||||
|
\ 'yacc': ['bison'], |
||||
|
\ 'yaml': ['jsyaml'], |
||||
|
\ 'yang': ['pyang'], |
||||
|
\ 'yara': ['yarac'], |
||||
|
\ 'z80': ['z80syntaxchecker'], |
||||
|
\ 'zpt': ['zptlint'], |
||||
|
\ 'zsh': ['zsh'], |
||||
|
\ } |
||||
|
lockvar! s:_DEFAULT_CHECKERS |
||||
|
|
||||
|
let s:_DEFAULT_FILETYPE_MAP = { |
||||
|
\ 'gentoo-metadata': 'xml', |
||||
|
\ 'groff': 'nroff', |
||||
|
\ 'lhaskell': 'haskell', |
||||
|
\ 'litcoffee': 'coffee', |
||||
|
\ 'mail': 'text', |
||||
|
\ 'mkd': 'markdown', |
||||
|
\ 'pe-puppet': 'puppet', |
||||
|
\ 'sgml': 'docbk', |
||||
|
\ 'sgmllnx': 'docbk', |
||||
|
\ } |
||||
|
lockvar! s:_DEFAULT_FILETYPE_MAP |
||||
|
|
||||
|
let s:_ECLIM_TYPES = [ |
||||
|
\ 'c', |
||||
|
\ 'cpp', |
||||
|
\ 'html', |
||||
|
\ 'java', |
||||
|
\ 'php', |
||||
|
\ 'python', |
||||
|
\ 'ruby', |
||||
|
\ ] |
||||
|
lockvar! s:_ECLIM_TYPES |
||||
|
|
||||
|
let s:_YCM_TYPES = [ |
||||
|
\ 'c', |
||||
|
\ 'cpp', |
||||
|
\ 'objc', |
||||
|
\ 'objcpp', |
||||
|
\ ] |
||||
|
lockvar! s:_YCM_TYPES |
||||
|
|
||||
|
let g:SyntasticRegistry = {} |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
" Note: Handling of filetype aliases: all public methods take aliases as |
||||
|
" parameters, all private methods take normalized filetypes. Public methods |
||||
|
" are thus supposed to normalize filetypes before calling private methods. |
||||
|
|
||||
|
function! g:SyntasticRegistry.Instance() abort " {{{2 |
||||
|
if !exists('s:SyntasticRegistryInstance') |
||||
|
let s:SyntasticRegistryInstance = copy(self) |
||||
|
let s:SyntasticRegistryInstance._checkerMap = {} |
||||
|
endif |
||||
|
|
||||
|
return s:SyntasticRegistryInstance |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry.CreateAndRegisterChecker(args) abort " {{{2 |
||||
|
let registry = g:SyntasticRegistry.Instance() |
||||
|
|
||||
|
if has_key(a:args, 'redirect') |
||||
|
let [ft, name] = split(a:args['redirect'], '/') |
||||
|
call registry._loadCheckersFor(ft, 1) |
||||
|
|
||||
|
let clone = get(registry._checkerMap[ft], name, {}) |
||||
|
if empty(clone) |
||||
|
throw 'Syntastic: Checker ' . a:args['redirect'] . ' redirects to unregistered checker ' . ft . '/' . name |
||||
|
endif |
||||
|
|
||||
|
let checker = g:SyntasticChecker.New(a:args, clone) |
||||
|
else |
||||
|
let checker = g:SyntasticChecker.New(a:args) |
||||
|
endif |
||||
|
call registry._registerChecker(checker) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Given a list of checker names hints_list, return a map name --> checker. |
||||
|
" If hints_list is empty, user settings are are used instead. Checkers are |
||||
|
" not checked for availability (that is, the corresponding IsAvailable() are |
||||
|
" not run). |
||||
|
function! g:SyntasticRegistry.getCheckers(ftalias, hints_list) abort " {{{2 |
||||
|
let ftlist = self.resolveFiletypes(a:ftalias) |
||||
|
|
||||
|
let names = |
||||
|
\ !empty(a:hints_list) ? a:hints_list : |
||||
|
\ exists('b:syntastic_checkers') ? b:syntastic_checkers : [] |
||||
|
|
||||
|
let cnames = [] |
||||
|
if !empty(names) |
||||
|
for name in names |
||||
|
if name !~# '/' |
||||
|
for ft in ftlist |
||||
|
call add(cnames, ft . '/' . name) |
||||
|
endfor |
||||
|
else |
||||
|
call add(cnames, name) |
||||
|
endif |
||||
|
endfor |
||||
|
else |
||||
|
for ft in ftlist |
||||
|
call self._sanityCheck(ft) |
||||
|
let defs = |
||||
|
\ exists('g:syntastic_' . ft . '_checkers') ? g:syntastic_{ft}_checkers : |
||||
|
\ get(s:_DEFAULT_CHECKERS, ft, []) |
||||
|
call extend(cnames, map(copy(defs), 'stridx(v:val, "/") < 0 ? ft . "/" . v:val : v:val' )) |
||||
|
endfor |
||||
|
endif |
||||
|
let cnames = syntastic#util#unique(cnames) |
||||
|
|
||||
|
for ft in syntastic#util#unique(map( copy(cnames), 'v:val[: stridx(v:val, "/")-1]' )) |
||||
|
call self._loadCheckersFor(ft, 0) |
||||
|
endfor |
||||
|
|
||||
|
return self._filterCheckersByName(cnames) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Same as getCheckers(), but keep only the available checkers. This runs the |
||||
|
" corresponding IsAvailable() functions for all checkers. |
||||
|
function! g:SyntasticRegistry.getCheckersAvailable(ftalias, hints_list) abort " {{{2 |
||||
|
return filter(self.getCheckers(a:ftalias, a:hints_list), 'v:val.isAvailable()') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Same as getCheckers(), but keep only the checkers that are available and |
||||
|
" disabled. This runs the corresponding IsAvailable() functions for all checkers. |
||||
|
function! g:SyntasticRegistry.getCheckersDisabled(ftalias, hints_list) abort " {{{2 |
||||
|
return filter(self.getCheckers(a:ftalias, a:hints_list), 'v:val.isDisabled() && v:val.isAvailable()') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry.getKnownFiletypes() abort " {{{2 |
||||
|
let types = keys(s:_DEFAULT_CHECKERS) |
||||
|
|
||||
|
call extend(types, keys(s:_DEFAULT_FILETYPE_MAP)) |
||||
|
|
||||
|
if exists('g:syntastic_filetype_map') |
||||
|
call extend(types, keys(g:syntastic_filetype_map)) |
||||
|
endif |
||||
|
|
||||
|
if exists('g:syntastic_extra_filetypes') && type(g:syntastic_extra_filetypes) == type([]) |
||||
|
call extend(types, g:syntastic_extra_filetypes) |
||||
|
endif |
||||
|
|
||||
|
return syntastic#util#unique(types) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry.getNamesOfAvailableCheckers(ftalias) abort " {{{2 |
||||
|
let ft = s:_normalise_filetype(a:ftalias) |
||||
|
call self._loadCheckersFor(ft, 0) |
||||
|
return keys(filter( copy(self._checkerMap[ft]), 'v:val.isAvailable()' )) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry.resolveFiletypes(ftalias) abort " {{{2 |
||||
|
return map(split( get(g:syntastic_filetype_map, a:ftalias, a:ftalias), '\m\.' ), 's:_normalise_filetype(v:val)') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry.echoInfoFor(ftalias_list) abort " {{{2 |
||||
|
let ft_list = syntastic#util#unique(self.resolveFiletypes(empty(a:ftalias_list) ? &filetype : a:ftalias_list[0])) |
||||
|
if len(ft_list) != 1 |
||||
|
let available = [] |
||||
|
let active = [] |
||||
|
let disabled = [] |
||||
|
|
||||
|
for ft in ft_list |
||||
|
call extend(available, map( self.getNamesOfAvailableCheckers(ft), 'ft . "/" . v:val' )) |
||||
|
call extend(active, map( self.getCheckersAvailable(ft, []), 'ft . "/" . v:val.getName()' )) |
||||
|
call extend(disabled, map( self.getCheckersDisabled(ft, []), 'ft . "/" . v:val.getName()' )) |
||||
|
endfor |
||||
|
else |
||||
|
let ft = ft_list[0] |
||||
|
let available = self.getNamesOfAvailableCheckers(ft) |
||||
|
let active = map(self.getCheckersAvailable(ft, []), 'ft ==# v:val.getFiletype() ? v:val.getName() : v:val.getCName()') |
||||
|
let disabled = map(self.getCheckersDisabled(ft, []), 'ft ==# v:val.getFiletype() ? v:val.getName() : v:val.getCName()') |
||||
|
endif |
||||
|
|
||||
|
let cnt = len(available) |
||||
|
let plural = cnt != 1 ? 's' : '' |
||||
|
let cklist = cnt ? join(sort(available)) : '-' |
||||
|
echomsg 'Available checker' . plural . ': ' . cklist |
||||
|
|
||||
|
let cnt = len(active) |
||||
|
let plural = cnt != 1 ? 's' : '' |
||||
|
let cklist = cnt ? join(active) : '-' |
||||
|
echomsg 'Currently enabled checker' . plural . ': ' . cklist |
||||
|
|
||||
|
let cnt = len(disabled) |
||||
|
let plural = cnt != 1 ? 's' : '' |
||||
|
if len(disabled) |
||||
|
let cklist = join(sort(disabled, 's:_compare_checker_names')) |
||||
|
echomsg 'Checker' . plural . ' disabled for security reasons: ' . cklist |
||||
|
endif |
||||
|
|
||||
|
" Eclim feels entitled to mess with syntastic's variables {{{3 |
||||
|
if exists(':EclimValidate') && get(g:, 'EclimFileTypeValidate', 1) |
||||
|
let disabled = filter(copy(ft_list), 's:_disabled_by_eclim(v:val)') |
||||
|
let cnt = len(disabled) |
||||
|
if cnt |
||||
|
let plural = cnt != 1 ? 's' : '' |
||||
|
let cklist = join(disabled, ', ') |
||||
|
echomsg 'Checkers for filetype' . plural . ' ' . cklist . ' possibly disabled by Eclim' |
||||
|
endif |
||||
|
endif |
||||
|
" }}}3 |
||||
|
|
||||
|
" So does YouCompleteMe {{{3 |
||||
|
if exists('g:loaded_youcompleteme') && get(g:, 'ycm_show_diagnostics_ui', get(g:, 'ycm_register_as_syntastic_checker', 1)) |
||||
|
let disabled = filter(copy(ft_list), 's:_disabled_by_ycm(v:val)') |
||||
|
let cnt = len(disabled) |
||||
|
if cnt |
||||
|
let plural = cnt != 1 ? 's' : '' |
||||
|
let cklist = join(disabled, ', ') |
||||
|
echomsg 'Checkers for filetype' . plural . ' ' . cklist . ' possibly disabled by YouCompleteMe' |
||||
|
endif |
||||
|
endif |
||||
|
" }}}3 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticRegistry._registerChecker(checker) abort " {{{2 |
||||
|
let ft = a:checker.getFiletype() |
||||
|
if !has_key(self._checkerMap, ft) |
||||
|
let self._checkerMap[ft] = {} |
||||
|
endif |
||||
|
|
||||
|
let name = a:checker.getName() |
||||
|
if has_key(self._checkerMap[ft], name) |
||||
|
throw 'Syntastic: Duplicate syntax checker name: ' . ft . '/' . name |
||||
|
endif |
||||
|
|
||||
|
let self._checkerMap[ft][name] = a:checker |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry._findChecker(cname) abort " {{{2 |
||||
|
let sep_idx = stridx(a:cname, '/') |
||||
|
if sep_idx > 0 |
||||
|
let ft = a:cname[: sep_idx-1] |
||||
|
let name = a:cname[sep_idx+1 :] |
||||
|
else |
||||
|
let ft = &filetype |
||||
|
let name = a:cname |
||||
|
endif |
||||
|
return get(self._checkerMap[ft], name, {}) |
||||
|
endfunction "}}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry._filterCheckersByName(cnames) abort " {{{2 |
||||
|
return filter( map(copy(a:cnames), 'self._findChecker(v:val)'), '!empty(v:val)' ) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticRegistry._loadCheckersFor(filetype, force) abort " {{{2 |
||||
|
if !a:force && has_key(self._checkerMap, a:filetype) |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
execute 'runtime! syntax_checkers/' . a:filetype . '/*.vim' |
||||
|
|
||||
|
if !has_key(self._checkerMap, a:filetype) |
||||
|
let self._checkerMap[a:filetype] = {} |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Check for obsolete variable g:syntastic_<filetype>_checker |
||||
|
function! g:SyntasticRegistry._sanityCheck(filetype) abort " {{{2 |
||||
|
if exists('g:syntastic_' . a:filetype . '_checkers') && |
||||
|
\ type(g:syntastic_{a:filetype}_checkers) != type([]) |
||||
|
|
||||
|
unlet! g:syntastic_{a:filetype}_checkers |
||||
|
call syntastic#log#error('variable g:syntastic_' . a:filetype . '_checkers has to be a list of strings') |
||||
|
endif |
||||
|
|
||||
|
if exists('g:syntastic_' . a:filetype . '_checker') && |
||||
|
\ !exists('g:syntastic_' . a:filetype . '_checkers') && |
||||
|
\ type(g:syntastic_{a:filetype}_checker) == type('') |
||||
|
|
||||
|
let g:syntastic_{a:filetype}_checkers = [g:syntastic_{a:filetype}_checker] |
||||
|
call syntastic#log#oneTimeWarn('variable g:syntastic_' . a:filetype . '_checker is deprecated') |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
"resolve filetype aliases, and replace - with _ otherwise we cant name |
||||
|
"syntax checker functions legally for filetypes like "gentoo-metadata" |
||||
|
function! s:_normalise_filetype(ftalias) abort " {{{2 |
||||
|
let ft = get(s:_DEFAULT_FILETYPE_MAP, a:ftalias, a:ftalias) |
||||
|
let ft = get(g:syntastic_filetype_map, ft, ft) |
||||
|
let ft = substitute(ft, '\m-', '_', 'g') |
||||
|
return ft |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_disabled_by_eclim(filetype) abort " {{{2 |
||||
|
if index(s:_ECLIM_TYPES, a:filetype) >= 0 |
||||
|
let lang = toupper(a:filetype[0]) . a:filetype[1:] |
||||
|
let ft = a:filetype !=# 'cpp' ? lang : 'C' |
||||
|
return get(g:, 'Eclim' . lang . 'Validate', 1) && !get(g:, 'Eclim' . ft . 'SyntasticEnabled', 0) |
||||
|
endif |
||||
|
|
||||
|
return 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_disabled_by_ycm(filetype) abort " {{{2 |
||||
|
return index(s:_YCM_TYPES, a:filetype) >= 0 |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! s:_compare_checker_names(a, b) abort " {{{2 |
||||
|
if a:a ==# a:b |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
if stridx(a:a, '/') < 0 |
||||
|
if stridx(a:b, '/') < 0 |
||||
|
return a:a < a:b ? -1 : 1 |
||||
|
else |
||||
|
return -1 |
||||
|
endif |
||||
|
else |
||||
|
if stridx(a:b, '/') < 0 |
||||
|
return 1 |
||||
|
else |
||||
|
return a:a < a:b ? -1 : 1 |
||||
|
endif |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,138 @@ |
|||||
|
if exists('g:loaded_syntastic_notifier_signs') || !exists('g:loaded_syntastic_plugin') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_notifier_signs = 1 |
||||
|
|
||||
|
" Initialisation {{{1 |
||||
|
|
||||
|
" start counting sign ids at 5000, start here to hopefully avoid conflicting |
||||
|
" with any other code that places signs (not sure if this precaution is |
||||
|
" actually needed) |
||||
|
let s:first_sign_id = 5000 |
||||
|
let s:next_sign_id = s:first_sign_id |
||||
|
|
||||
|
let g:SyntasticSignsNotifier = {} |
||||
|
|
||||
|
let s:setup_done = 0 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Public methods {{{1 |
||||
|
|
||||
|
function! g:SyntasticSignsNotifier.New() abort " {{{2 |
||||
|
let newObj = copy(self) |
||||
|
return newObj |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticSignsNotifier.enabled() abort " {{{2 |
||||
|
return has('signs') && syntastic#util#var('enable_signs') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
function! g:SyntasticSignsNotifier.refresh(loclist) abort " {{{2 |
||||
|
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'signs: refresh') |
||||
|
|
||||
|
let old_signs = copy(self._bufSignIds()) |
||||
|
if self.enabled() |
||||
|
if !s:setup_done |
||||
|
call self._setup() |
||||
|
let s:setup_done = 1 |
||||
|
lockvar s:setup_done |
||||
|
endif |
||||
|
|
||||
|
call self._signErrors(a:loclist) |
||||
|
endif |
||||
|
call self._removeSigns(old_signs) |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" Private methods {{{1 |
||||
|
|
||||
|
" One time setup: define our own sign types and highlighting |
||||
|
function! g:SyntasticSignsNotifier._setup() abort " {{{2 |
||||
|
if has('signs') |
||||
|
if !hlexists('SyntasticErrorSign') |
||||
|
highlight link SyntasticErrorSign error |
||||
|
endif |
||||
|
if !hlexists('SyntasticWarningSign') |
||||
|
highlight link SyntasticWarningSign todo |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleErrorSign') |
||||
|
highlight link SyntasticStyleErrorSign SyntasticErrorSign |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleWarningSign') |
||||
|
highlight link SyntasticStyleWarningSign SyntasticWarningSign |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleErrorLine') |
||||
|
highlight link SyntasticStyleErrorLine SyntasticErrorLine |
||||
|
endif |
||||
|
if !hlexists('SyntasticStyleWarningLine') |
||||
|
highlight link SyntasticStyleWarningLine SyntasticWarningLine |
||||
|
endif |
||||
|
|
||||
|
" define the signs used to display syntax and style errors/warns |
||||
|
execute 'sign define SyntasticError text=' . g:syntastic_error_symbol . |
||||
|
\ ' texthl=SyntasticErrorSign linehl=SyntasticErrorLine' |
||||
|
execute 'sign define SyntasticWarning text=' . g:syntastic_warning_symbol . |
||||
|
\ ' texthl=SyntasticWarningSign linehl=SyntasticWarningLine' |
||||
|
execute 'sign define SyntasticStyleError text=' . g:syntastic_style_error_symbol . |
||||
|
\ ' texthl=SyntasticStyleErrorSign linehl=SyntasticStyleErrorLine' |
||||
|
execute 'sign define SyntasticStyleWarning text=' . g:syntastic_style_warning_symbol . |
||||
|
\ ' texthl=SyntasticStyleWarningSign linehl=SyntasticStyleWarningLine' |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Place signs by all syntax errors in the buffer |
||||
|
function! g:SyntasticSignsNotifier._signErrors(loclist) abort " {{{2 |
||||
|
let loclist = a:loclist |
||||
|
if !loclist.isEmpty() |
||||
|
|
||||
|
let buf = bufnr('') |
||||
|
if !bufloaded(buf) |
||||
|
" signs can be placed only in loaded buffers |
||||
|
return |
||||
|
endif |
||||
|
|
||||
|
" errors come first, so that they are not masked by warnings |
||||
|
let issues = copy(loclist.errors()) |
||||
|
call extend(issues, loclist.warnings()) |
||||
|
call filter(issues, 'v:val["bufnr"] == buf') |
||||
|
let seen = {} |
||||
|
|
||||
|
for i in issues |
||||
|
if i['lnum'] > 0 && !has_key(seen, i['lnum']) |
||||
|
let seen[i['lnum']] = 1 |
||||
|
|
||||
|
let sign_severity = i['type'] ==? 'W' ? 'Warning' : 'Error' |
||||
|
let sign_subtype = get(i, 'subtype', '') |
||||
|
let sign_type = 'Syntastic' . sign_subtype . sign_severity |
||||
|
|
||||
|
execute 'sign place ' . s:next_sign_id . ' line=' . i['lnum'] . ' name=' . sign_type . ' buffer=' . i['bufnr'] |
||||
|
call add(self._bufSignIds(), s:next_sign_id) |
||||
|
let s:next_sign_id += 1 |
||||
|
endif |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Remove the signs with the given ids from this buffer |
||||
|
function! g:SyntasticSignsNotifier._removeSigns(ids) abort " {{{2 |
||||
|
if has('signs') |
||||
|
for s in reverse(copy(a:ids)) |
||||
|
execute 'sign unplace ' . s |
||||
|
call remove(self._bufSignIds(), index(self._bufSignIds(), s)) |
||||
|
endfor |
||||
|
endif |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" Get all the ids of the SyntaxError signs in the buffer |
||||
|
function! g:SyntasticSignsNotifier._bufSignIds() abort " {{{2 |
||||
|
if !exists('b:syntastic_private_sign_ids') |
||||
|
let b:syntastic_private_sign_ids = [] |
||||
|
endif |
||||
|
return b:syntastic_private_sign_ids |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,67 @@ |
|||||
|
"============================================================================ |
||||
|
"File: mxmlc.vim |
||||
|
"Description: ActionScript syntax checker - using mxmlc |
||||
|
"Maintainer: Andy Earnshaw <andyearnshaw@gmail.com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_actionscript_mxmlc_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_actionscript_mxmlc_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_actionscript_mxmlc_GetHighlightRegex(item) |
||||
|
let term = '' |
||||
|
|
||||
|
if match(a:item['text'], '\mvariable ''') > -1 |
||||
|
let term = matchstr(a:item['text'], '\m''\zs[^'']\+\ze''') |
||||
|
|
||||
|
elseif match(a:item['text'], 'expected a definition keyword') > -1 |
||||
|
let term = matchstr(a:item['text'], '\mnot \zs[^.]\+\ze\.') |
||||
|
|
||||
|
elseif match(a:item['text'], '\mundefined \%(property\|method\)') > -1 |
||||
|
let term = matchstr(a:item['text'], '\mundefined \%(property\|method\) \zs[^. ]\+\ze') |
||||
|
|
||||
|
elseif match(a:item['text'], 'could not be found') > -1 |
||||
|
let term = matchstr(a:item['text'], '\m \zs\S\+\ze could not be found') |
||||
|
|
||||
|
elseif match(a:item['text'], 'Type was not found') > -1 |
||||
|
let term = matchstr(a:item['text'], '\m: \zs[^.]\+\zs\.') |
||||
|
|
||||
|
endif |
||||
|
|
||||
|
return term !=# '' ? '\V\<' . escape(term, '\') . '\>' : '' |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_actionscript_mxmlc_GetLocList() dict |
||||
|
call syntastic#log#deprecationWarn('actionscript_mxmlc_conf', 'actionscript_mxmlc_args', |
||||
|
\ "'-load-config+=' . syntastic#util#shexpand(OLD_VAR)") |
||||
|
|
||||
|
let makeprg = self.makeprgBuild({ 'args_after': '-output=' . syntastic#util#DevNull() }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%f(%l): col: %c %trror: %m,' . |
||||
|
\ '%f(%l): col: %c %tarning: %m,' . |
||||
|
\ '%f: %trror: %m,' . |
||||
|
\ '%-G%.%#' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'actionscript', |
||||
|
\ 'name': 'mxmlc'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,47 @@ |
|||||
|
"============================================================================ |
||||
|
"File: ada.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Alfredo Di Napoli <alfredo.dinapoli@gmail.com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_ada_gcc_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_ada_gcc_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_ada_compiler_options') |
||||
|
let g:syntastic_ada_compiler_options = '' |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_ada_gcc_IsAvailable() dict |
||||
|
if !exists('g:syntastic_ada_compiler') |
||||
|
let g:syntastic_ada_compiler = self.getExec() |
||||
|
endif |
||||
|
return executable(expand(g:syntastic_ada_compiler, 1)) |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_ada_gcc_GetLocList() dict |
||||
|
return syntastic#c#GetLocList('ada', 'gcc', { |
||||
|
\ 'errorformat': |
||||
|
\ '%-G%f:%s:,' . |
||||
|
\ '%f:%l:%c: %m,' . |
||||
|
\ '%f:%l: %m', |
||||
|
\ 'main_flags': '-c -x ada -gnats -gnatef', |
||||
|
\ 'header_flags': '-S -x ada -gnats -gnatef', |
||||
|
\ 'header_names': '\.ads$' }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'ada', |
||||
|
\ 'name': 'gcc' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,55 @@ |
|||||
|
"============================================================================ |
||||
|
"File: ansible_lint.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Erik Zaadi <erik.zaadi at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_ansible_ansible_lint_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_ansible_ansible_lint_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_ansible_ansible_lint_IsAvailable() dict |
||||
|
if !executable(self.getExec()) |
||||
|
return 0 |
||||
|
endif |
||||
|
return syntastic#util#versionIsAtLeast(self.getVersion(), [2, 0, 4]) |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_ansible_ansible_lint_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'args_after': '-p' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%f:%l: [E%n] %m,' . |
||||
|
\ '%f:%l: [EANSIBLE%n] %m,' . |
||||
|
\ '%f:%l: [ANSIBLE%n] %m' |
||||
|
|
||||
|
let env = syntastic#util#isRunningWindows() ? {} : { 'TERM': 'dumb' } |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'env': env, |
||||
|
\ 'defaults': {'type': 'E'}, |
||||
|
\ 'subtype': 'Style', |
||||
|
\ 'returns': [0, 2] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'ansible', |
||||
|
\ 'name': 'ansible_lint', |
||||
|
\ 'exec': 'ansible-lint'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,66 @@ |
|||||
|
"============================================================================ |
||||
|
"File: drafter.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_apiblueprint_drafter_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_apiblueprint_drafter_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_apiblueprint_drafter_sort') |
||||
|
let g:syntastic_apiblueprint_drafter_sort = 1 |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_apiblueprint_drafter_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'post_args': '-u -l' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%trror: (%n) %m,' . |
||||
|
\ '%tarning: (%n) %m,' . |
||||
|
\ '%-G%.%#' |
||||
|
|
||||
|
let loclist = SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'defaults': {'bufnr': bufnr('')}, |
||||
|
\ 'returns': [0, 2, 3, 4] }) |
||||
|
|
||||
|
for e in loclist |
||||
|
let matches = matchlist(e['text'], '\v^(.+); line (\d+), column (\d+) - line (\d+), column (\d+)$') |
||||
|
if len(matches) > 5 |
||||
|
let e['lnum'] = str2nr(matches[2]) |
||||
|
let e['col'] = str2nr(matches[3]) |
||||
|
let e['vcol'] = 0 |
||||
|
|
||||
|
if matches[2] == matches[4] |
||||
|
let e['hl'] = '\%>' . (e['col'] - 1) . 'c\%<' . matches[5] . 'c' |
||||
|
endif |
||||
|
|
||||
|
let e['text'] = matches[1] |
||||
|
else |
||||
|
let e['valid'] = 0 |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return loclist |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'apiblueprint', |
||||
|
\ 'name': 'drafter'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,49 @@ |
|||||
|
"============================================================================== |
||||
|
" FileName: applescript.vim |
||||
|
" Desc: Syntax checking plugin for syntastic |
||||
|
" Author: Zhao Cai |
||||
|
" Email: caizhaoff@gmail.com |
||||
|
" Version: 0.2.1 |
||||
|
" Date Created: Thu 09 Sep 2011 10:30:09 AM EST |
||||
|
" Last Modified: Fri 09 Dec 2011 01:10:24 PM EST |
||||
|
" |
||||
|
" History: 0.1.0 - working, but it will run the script everytime to check |
||||
|
" syntax. Should use osacompile but strangely it does not give |
||||
|
" errors. |
||||
|
" |
||||
|
" 0.2.0 - switch to osacompile, it gives less errors compared |
||||
|
" with osascript. |
||||
|
" |
||||
|
" 0.2.1 - remove g:syntastic_applescript_tempfile. use |
||||
|
" tempname() instead. |
||||
|
" |
||||
|
" License: This program is free software. It comes without any |
||||
|
" warranty, to the extent permitted by applicable law. You can |
||||
|
" redistribute it and/or modify it under the terms of the Do What The |
||||
|
" Fuck You Want To Public License, Version 2, as published by Sam |
||||
|
" Hocevar. See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_applescript_osacompile_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_applescript_osacompile_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_applescript_osacompile_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'args_after': '-o ' . tempname() . '.scpt' }) |
||||
|
let errorformat = '%f:%l:%m' |
||||
|
return SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'applescript', |
||||
|
\ 'name': 'osacompile' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,47 @@ |
|||||
|
"============================================================================ |
||||
|
"File: asciidoc.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_asciidoc_asciidoc_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_asciidoc_asciidoc_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_asciidoc_asciidoc_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'args_after': syntastic#c#NullOutput() }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%E%\w%\+: %tRROR: %f: line %l: %m,' . |
||||
|
\ '%E%\w%\+: %tRROR: %f: %m,' . |
||||
|
\ '%E%\w%\+: FAILED: %f: line %l: %m,' . |
||||
|
\ '%E%\w%\+: FAILED: %f: %m,' . |
||||
|
\ '%W%\w%\+: %tARNING: %f: line %l: %m,' . |
||||
|
\ '%W%\w%\+: %tARNING: %f: %m,' . |
||||
|
\ '%W%\w%\+: DEPRECATED: %f: line %l: %m,' . |
||||
|
\ '%W%\w%\+: DEPRECATED: %f: %m' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'returns': [0, 1] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'asciidoc', |
||||
|
\ 'name': 'asciidoc'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,23 @@ |
|||||
|
"============================================================================ |
||||
|
"File: proselint.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_asciidoc_proselint_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_asciidoc_proselint_checker = 1 |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'asciidoc', |
||||
|
\ 'name': 'proselint', |
||||
|
\ 'redirect': 'text/proselint'}) |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,59 @@ |
|||||
|
"============================================================================ |
||||
|
"File: iasl.vim |
||||
|
"Description: Syntax checking plugin for syntastic using iasl |
||||
|
"Maintainer: Peter Wu <peter@lekensteyn.nl> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_asl_iasl_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_asl_iasl_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_asl_iasl_GetLocList() dict |
||||
|
let tmpdir = syntastic#util#tmpdir() . syntastic#util#Slash() |
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'args': '-vi', |
||||
|
\ 'args_after': ['-p', tmpdir] }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%f(%l) : %trror %n - %m,' . |
||||
|
\ '%f(%l) : %tarning %n - %m,' . |
||||
|
\ '%f(%l) : %temark %n - %m,' . |
||||
|
\ '%f(%l) : %tptimize %n - %m,' . |
||||
|
\ '%f(%l) : %m' |
||||
|
|
||||
|
let loclist = SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'returns': [0, 255] }) |
||||
|
|
||||
|
for e in loclist |
||||
|
if e['type'] =~? 'r' |
||||
|
let e['type'] = 'W' |
||||
|
elseif e['type'] =~? 'o' |
||||
|
let e['type'] = 'W' |
||||
|
let e['subtype'] = 'Style' |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
call syntastic#util#rmrf(tmpdir) |
||||
|
|
||||
|
return loclist |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'asl', |
||||
|
\ 'name': 'iasl'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,62 @@ |
|||||
|
"============================================================================ |
||||
|
"File: gcc.vim |
||||
|
"Description: Syntax checking for at&t and intel assembly files with gcc |
||||
|
"Maintainer: Josh Rahm <joshuarahm@gmail.com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_asm_gcc_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_asm_gcc_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_asm_compiler_options') |
||||
|
let g:syntastic_asm_compiler_options = '' |
||||
|
endif |
||||
|
|
||||
|
if !exists('g:syntastic_asm_generic') |
||||
|
let g:syntastic_asm_generic = 0 |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_asm_gcc_IsAvailable() dict " {{{1 |
||||
|
if !exists('g:syntastic_asm_compiler') |
||||
|
let g:syntastic_asm_compiler = self.getExec() |
||||
|
endif |
||||
|
return executable(expand(g:syntastic_asm_compiler, 1)) |
||||
|
endfunction " }}}1 |
||||
|
|
||||
|
function! SyntaxCheckers_asm_gcc_GetLocList() dict " {{{1 |
||||
|
let buf = bufnr('') |
||||
|
return syntastic#c#GetLocList('asm', 'gcc', { |
||||
|
\ 'errorformat': |
||||
|
\ '%-G%f:%s:,' . |
||||
|
\ '%f:%l:%c: %trror: %m,' . |
||||
|
\ '%f:%l:%c: %tarning: %m,' . |
||||
|
\ '%f:%l: %m', |
||||
|
\ 'main_flags': '-x assembler -fsyntax-only' . (g:syntastic_asm_generic ? '' : ' -masm=' . s:GetDialect(buf)) }) |
||||
|
endfunction " }}}1 |
||||
|
|
||||
|
" Utilities {{{1 |
||||
|
|
||||
|
function! s:GetDialect(buf) " {{{2 |
||||
|
return syntastic#util#bufVar(a:buf, 'asm_dialect', fnamemodify(bufname(a:buf), ':e') ==? 'asm' ? 'intel' : 'att') |
||||
|
endfunction " }}}2 |
||||
|
|
||||
|
" }}}1 |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'asm', |
||||
|
\ 'name': 'gcc' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,35 @@ |
|||||
|
"============================================================================ |
||||
|
"File: bemhtmllint.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Sergej Tatarincev <s.tatarincev at yandex.ua> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_bemhtml_bemhtmllint_checker') |
||||
|
finish |
||||
|
endif |
||||
|
|
||||
|
let g:loaded_syntastic_bemhtml_bemhtmllint_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function SyntaxCheckers_bemhtml_bemhtmllint_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({}) |
||||
|
let errorformat = '%f:%l:%c: %m' |
||||
|
return SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'bemhtml', |
||||
|
\ 'name': 'bemhtmllint', |
||||
|
\ 'exec': 'bemhtml-lint' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,58 @@ |
|||||
|
"============================================================================ |
||||
|
"File: bro.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Justin Azoff <justin.azoff@gmail.com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_bro_bro_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_bro_bro_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_bro_bro_GetHighlightRegex(item) |
||||
|
let term = matchstr(a:item['text'], '\m at or near "\zs[^"]\+\ze"') |
||||
|
return term !=# '' ? '\V\<' . escape(term, '\') . '\>' : '' |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_bro_bro_IsAvailable() dict |
||||
|
if !executable(self.getExec()) |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
if syntastic#util#system(self.getExecEscaped() . ' --help') !~# '--parse-only' |
||||
|
call self.log('unknown option "--parse-only"') |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
return 1 |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_bro_bro_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'args_before': '--parse-only' }) |
||||
|
|
||||
|
"example: error in ./foo.bro, line 3: unknown identifier banana, at or near "banana" |
||||
|
let errorformat = '%t:%f:%l:%m' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'preprocess': 'bro' }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'bro', |
||||
|
\ 'name': 'bro'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,57 @@ |
|||||
|
"============================================================================ |
||||
|
"File: avrgcc.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Karel <karelishere at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_avrgcc_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_avrgcc_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
let s:opt_x = { 'c': 'c', 'cpp': 'c++' } |
||||
|
|
||||
|
function! SyntaxCheckers_c_avrgcc_GetLocList() dict |
||||
|
let buf = bufnr('') |
||||
|
|
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'args_before': syntastic#c#ReadConfig(syntastic#util#bufVar(buf, 'avrgcc_config_file')), |
||||
|
\ 'args_after': '-x ' . get(s:opt_x, self.getFiletype(), '') . ' -fsyntax-only' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%-G%f:%s:,' . |
||||
|
\ '%-G%f:%l: %#error: %#(Each undeclared identifier is reported only%.%#,' . |
||||
|
\ '%-G%f:%l: %#error: %#for each function it appears%.%#,' . |
||||
|
\ '%-GIn file included%.%#,' . |
||||
|
\ '%-G %#from %f:%l\,,' . |
||||
|
\ '%f:%l:%c: %trror: %m,' . |
||||
|
\ '%f:%l:%c: %tarning: %m,' . |
||||
|
\ '%f:%l:%c: %m,' . |
||||
|
\ '%f:%l: %trror: %m,' . |
||||
|
\ '%f:%l: %tarning: %m,'. |
||||
|
\ '%f:%l: %m' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'postprocess': ['compressWhitespace'] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'avrgcc', |
||||
|
\ 'exec': 'avr-gcc'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,61 @@ |
|||||
|
"============================================================================ |
||||
|
"File: checkpatch.vim |
||||
|
"Description: Syntax checking plugin for syntastic using checkpatch.pl |
||||
|
"Maintainer: Daniel Walker <dwalker at fifo99 dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_checkpatch_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_checkpatch_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_checkpatch_IsAvailable() dict |
||||
|
call syntastic#log#deprecationWarn('c_checker_checkpatch_location', 'c_checkpatch_exec') |
||||
|
|
||||
|
if !exists('g:syntastic_c_checkpatch_exec') && !executable(self.getExec()) |
||||
|
if executable('checkpatch') |
||||
|
let g:syntastic_c_checkpatch_exec = 'checkpatch' |
||||
|
elseif executable('./scripts/checkpatch.pl') |
||||
|
let g:syntastic_c_checkpatch_exec = fnamemodify('./scripts/checkpatch.pl', ':p') |
||||
|
elseif executable('./scripts/checkpatch') |
||||
|
let g:syntastic_c_checkpatch_exec = fnamemodify('./scripts/checkpatch', ':p') |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
call self.log('exec =', self.getExec()) |
||||
|
|
||||
|
return executable(self.getExec()) |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_c_checkpatch_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ 'args_after': '--no-summary --no-tree --terse --file' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%W%f:%l: CHECK: %m,' . |
||||
|
\ '%f:%l: %tARNING: %m,' . |
||||
|
\ '%f:%l: %tRROR: %m' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'returns': [0, 1], |
||||
|
\ 'subtype': 'Style' }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'checkpatch', |
||||
|
\ 'exec': 'checkpatch.pl'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,62 @@ |
|||||
|
"============================================================================ |
||||
|
"File: clang_check.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Benjamin Bannier <bbannier at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_clang_check_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_clang_check_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_c_clang_check_sort') |
||||
|
let g:syntastic_c_clang_check_sort = 1 |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_clang_check_GetLocList() dict |
||||
|
let buf = bufnr('') |
||||
|
|
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'post_args': |
||||
|
\ '-- ' . |
||||
|
\ syntastic#c#ReadConfig(syntastic#util#bufVar(buf, 'clang_check_config_file')) . ' ' . |
||||
|
\ '-fshow-column ' . |
||||
|
\ '-fshow-source-location ' . |
||||
|
\ '-fno-caret-diagnostics ' . |
||||
|
\ '-fno-color-diagnostics ' . |
||||
|
\ '-fdiagnostics-format=clang' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%E%f:%l:%c: fatal error: %m,' . |
||||
|
\ '%E%f:%l:%c: error: %m,' . |
||||
|
\ '%W%f:%l:%c: warning: %m,' . |
||||
|
\ '%-G%\m%\%%(LLVM ERROR:%\|No compilation database found%\)%\@!%.%#,' . |
||||
|
\ '%E%m' |
||||
|
|
||||
|
let env = syntastic#util#isRunningWindows() ? {} : { 'TERM': 'dumb' } |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'env': env, |
||||
|
\ 'defaults': {'bufnr': bufnr('')}, |
||||
|
\ 'returns': [0, 1] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'clang_check', |
||||
|
\ 'exec': 'clang-check'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,62 @@ |
|||||
|
"============================================================================ |
||||
|
"File: clang_tidy.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: Benjamin Bannier <bbannier at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_clang_tidy_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_clang_tidy_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_c_clang_tidy_sort') |
||||
|
let g:syntastic_c_clang_tidy_sort = 1 |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_clang_tidy_GetLocList() dict |
||||
|
let buf = bufnr('') |
||||
|
|
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'post_args': |
||||
|
\ '-- ' . |
||||
|
\ syntastic#c#ReadConfig(syntastic#util#bufVar(buf, 'clang_tidy_config_file')) . ' ' . |
||||
|
\ '-fshow-column ' . |
||||
|
\ '-fshow-source-location ' . |
||||
|
\ '-fno-caret-diagnostics ' . |
||||
|
\ '-fno-color-diagnostics ' . |
||||
|
\ '-fdiagnostics-format=clang' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '%E%f:%l:%c: fatal error: %m,' . |
||||
|
\ '%E%f:%l:%c: error: %m,' . |
||||
|
\ '%W%f:%l:%c: warning: %m,' . |
||||
|
\ '%-G%\m%\%%(LLVM ERROR:%\|No compilation database found%\)%\@!%.%#,' . |
||||
|
\ '%E%m' |
||||
|
|
||||
|
let env = syntastic#util#isRunningWindows() ? {} : { 'TERM': 'dumb' } |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'env': env, |
||||
|
\ 'defaults': {'bufnr': bufnr('')}, |
||||
|
\ 'returns': [0, 1] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'clang_tidy', |
||||
|
\ 'exec': 'clang-tidy'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,60 @@ |
|||||
|
"============================================================================ |
||||
|
"File: cppcheck.vim |
||||
|
"Description: Syntax checking plugin for syntastic using cppcheck.pl |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_cppcheck_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_cppcheck_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_cppcheck_GetLocList() dict |
||||
|
let buf = bufnr('') |
||||
|
|
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'args': syntastic#c#ReadConfig(syntastic#util#bufVar(buf, 'cppcheck_config_file')), |
||||
|
\ 'args_after': '-q --enable=style' }) |
||||
|
|
||||
|
let errorformat = |
||||
|
\ '[%f:%l]: (%trror) %m,' . |
||||
|
\ '[%f:%l]: (%tarning) %m,' . |
||||
|
\ '[%f:%l]: (%ttyle) %m,' . |
||||
|
\ '[%f:%l]: (%terformance) %m,' . |
||||
|
\ '[%f:%l]: (%tortability) %m,' . |
||||
|
\ '[%f:%l]: (%tnformation) %m,' . |
||||
|
\ '[%f:%l]: (%tnconclusive) %m,' . |
||||
|
\ '%-G%.%#' |
||||
|
|
||||
|
let loclist = SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'preprocess': 'cppcheck', |
||||
|
\ 'returns': [0] }) |
||||
|
|
||||
|
for e in loclist |
||||
|
if e['type'] =~? '\m^[SPI]' |
||||
|
let e['type'] = 'w' |
||||
|
let e['subtype'] = 'Style' |
||||
|
endif |
||||
|
endfor |
||||
|
|
||||
|
return loclist |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'cppcheck'}) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,40 @@ |
|||||
|
"============================================================================ |
||||
|
"File: cppclean.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_cppclean_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_cppclean_checker = 1 |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_cppclean_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({}) |
||||
|
|
||||
|
let errorformat = '%f:%l: %m' |
||||
|
|
||||
|
return SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'subtype': 'Style', |
||||
|
\ 'returns': [0, 1] }) |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'cppclean' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
@ -0,0 +1,61 @@ |
|||||
|
"============================================================================ |
||||
|
"File: flawfinder.vim |
||||
|
"Description: Syntax checking plugin for syntastic |
||||
|
"Maintainer: LCD 47 <lcd047 at gmail dot com> |
||||
|
"License: This program is free software. It comes without any warranty, |
||||
|
" to the extent permitted by applicable law. You can redistribute |
||||
|
" it and/or modify it under the terms of the Do What The Fuck You |
||||
|
" Want To Public License, Version 2, as published by Sam Hocevar. |
||||
|
" See http://sam.zoy.org/wtfpl/COPYING for more details. |
||||
|
" |
||||
|
"============================================================================ |
||||
|
|
||||
|
if exists('g:loaded_syntastic_c_flawfinder_checker') |
||||
|
finish |
||||
|
endif |
||||
|
let g:loaded_syntastic_c_flawfinder_checker = 1 |
||||
|
|
||||
|
if !exists('g:syntastic_c_flawfinder_sort') |
||||
|
let g:syntastic_c_flawfinder_sort = 1 |
||||
|
endif |
||||
|
|
||||
|
if !exists('g:syntastic_c_flawfinder_thres') |
||||
|
let g:syntastic_c_flawfinder_thres = 3 |
||||
|
endif |
||||
|
|
||||
|
let s:save_cpo = &cpo |
||||
|
set cpo&vim |
||||
|
|
||||
|
function! SyntaxCheckers_c_flawfinder_GetHighlightRegex(item) |
||||
|
let term = matchstr(a:item['text'], '\m^(\S\+)\s\+\zs\S\+\ze:') |
||||
|
return term !=# '' ? '\V\<' . escape(term, '\') . '\>' : '' |
||||
|
endfunction |
||||
|
|
||||
|
function! SyntaxCheckers_c_flawfinder_GetLocList() dict |
||||
|
let makeprg = self.makeprgBuild({ |
||||
|
\ 'args_after': '--columns --dataonly --singleline --quiet' }) |
||||
|
|
||||
|
let errorformat = '%f:%l:%c: [%n] %m' |
||||
|
|
||||
|
let loclist = SyntasticMake({ |
||||
|
\ 'makeprg': makeprg, |
||||
|
\ 'errorformat': errorformat, |
||||
|
\ 'subtype': 'Style', |
||||
|
\ 'returns': [0] }) |
||||
|
|
||||
|
for e in loclist |
||||
|
let e['type'] = e['nr'] < g:syntastic_{self.getFiletype()}_flawfinder_thres ? 'W' : 'E' |
||||
|
let e['nr'] = 0 |
||||
|
endfor |
||||
|
|
||||
|
return loclist |
||||
|
endfunction |
||||
|
|
||||
|
call g:SyntasticRegistry.CreateAndRegisterChecker({ |
||||
|
\ 'filetype': 'c', |
||||
|
\ 'name': 'flawfinder' }) |
||||
|
|
||||
|
let &cpo = s:save_cpo |
||||
|
unlet s:save_cpo |
||||
|
|
||||
|
" vim: set sw=4 sts=4 et fdm=marker: |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue