diff options
28 files changed, 743 insertions, 48 deletions
@@ -1,4 +1,4 @@ -# Asynchronous Lint Engine [![Travis CI Build Status](https://travis-ci.com/w0rp/ale.svg?branch=master)](https://travis-ci.com/w0rp/ale) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/r0ef1xu8xjmik58d/branch/master?svg=true)](https://ci.appveyor.com/project/w0rp/ale) [![Join the chat at https://gitter.im/vim-ale/Lobby](https://badges.gitter.im/vim-ale/Lobby.svg)](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# Asynchronous Lint Engine [![Travis CI Build Status](https://travis-ci.com/dense-analysis/ale.svg?branch=master)](https://travis-ci.com/dense-analysis/ale) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/r0ef1xu8xjmik58d/branch/master?svg=true)](https://ci.appveyor.com/project/dense-analysis/ale) [![Join the chat at https://gitter.im/vim-ale/Lobby](https://badges.gitter.im/vim-ale/Lobby.svg)](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![ALE Logo by Mark Grealish - https://www.bhalash.com/](https://user-images.githubusercontent.com/3518142/59195920-2c339500-8b85-11e9-9c22-f6b7f69637b8.jpg) @@ -258,14 +258,14 @@ any other tools. Simply clone the plugin into your `pack` directory. ```bash mkdir -p ~/.vim/pack/git-plugins/start -git clone --depth 1 https://github.com/w0rp/ale.git ~/.vim/pack/git-plugins/start/ale +git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.vim/pack/git-plugins/start/ale ``` #### NeoVim on Unix ```bash mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start -git clone --depth 1 https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale +git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale ``` #### Vim 8 on Windows @@ -273,7 +273,7 @@ git clone --depth 1 https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pac ```bash # Run these commands in the "Git for Windows" Bash terminal mkdir -p ~/vimfiles/pack/git-plugins/start -git clone --depth 1 https://github.com/w0rp/ale.git ~/vimfiles/pack/git-plugins/start/ale +git clone --depth 1 https://github.com/dense-analysis/ale.git ~/vimfiles/pack/git-plugins/start/ale ``` #### Generating Vim help files @@ -304,7 +304,7 @@ You can run the following commands in your terminal to do so: ```bash cd ~/.vim/bundle -git clone https://github.com/w0rp/ale.git +git clone https://github.com/dense-analysis/ale.git ``` <a name="installation-with-vundle"></a> @@ -315,7 +315,7 @@ You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.v by using the path on GitHub for this repository. ```vim -Plugin 'w0rp/ale' +Plugin 'dense-analysis/ale' ``` See the Vundle documentation for more information. @@ -329,7 +329,7 @@ by adding the GitHub path for this repository to your `~/.vimrc` and running `:PlugInstall`. ```vim -Plug 'w0rp/ale' +Plug 'dense-analysis/ale' ``` <a name="contributing"></a> @@ -337,14 +337,14 @@ Plug 'w0rp/ale' ## 4. Contributing If you would like to see support for more languages and tools, please -[create an issue](https://github.com/w0rp/ale/issues) -or [create a pull request](https://github.com/w0rp/ale/pulls). +[create an issue](https://github.com/dense-analysis/ale/issues) +or [create a pull request](https://github.com/dense-analysis/ale/pulls). If your tool can read from stdin or you have code to suggest which is good, support can be happily added for it. If you are interested in the general direction of the project, check out the -[wiki home page](https://github.com/w0rp/ale/wiki). The wiki includes a -Roadmap for the future, and more. +[wiki home page](https://github.com/dense-analysis/ale/wiki). The wiki includes +a Roadmap for the future, and more. If you'd liked to discuss the project more directly, check out the `#vim-ale` channel on Freenode. Web chat is available [here](https://webchat.freenode.net/?channels=vim-ale). @@ -596,6 +596,7 @@ options off. ```vim " Write this in your vimrc file let g:ale_lint_on_text_changed = 'never' +let g:ale_lint_on_insert_leave = 0 " You can disable this option too " if you don't want linters to run on opening a file let g:ale_lint_on_enter = 0 diff --git a/ale_linters/cs/csc.vim b/ale_linters/cs/csc.vim new file mode 100644 index 00000000..308abc77 --- /dev/null +++ b/ale_linters/cs/csc.vim @@ -0,0 +1,95 @@ +call ale#Set('cs_csc_options', '') +call ale#Set('cs_csc_source', '') +call ale#Set('cs_csc_assembly_path', []) +call ale#Set('cs_csc_assemblies', []) + +function! s:GetWorkingDirectory(buffer) abort + let l:working_directory = ale#Var(a:buffer, 'cs_csc_source') + + if !empty(l:working_directory) + return l:working_directory + endif + + return expand('#' . a:buffer . ':p:h') +endfunction + +function! ale_linters#cs#csc#GetCommand(buffer) abort + " Pass assembly paths via the -lib: parameter. + let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path') + + let l:lib_option = !empty(l:path_list) + \ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',') + \ : '' + + " Pass paths to DLL files via the -r: parameter. + let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies') + + let l:r_option = !empty(l:assembly_list) + \ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',') + \ : '' + + " register temporary module target file with ale + " register temporary module target file with ALE. + let l:out = ale#command#CreateFile(a:buffer) + + " The code is compiled as a module and the output is redirected to a + " temporary file. + return ale#path#CdString(s:GetWorkingDirectory(a:buffer)) + \ . 'csc /unsafe' + \ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options')) + \ . ale#Pad(l:lib_option) + \ . ale#Pad(l:r_option) + \ . ' /out:' . l:out + \ . ' /t:module' + \ . ' /recurse:' . ale#Escape('*.cs') +endfunction + +function! ale_linters#cs#csc#Handle(buffer, lines) abort + " Look for lines like the following. + " + " Tests.cs(12,29): error CSXXXX: ; expected + " + " NOTE: pattern also captures file name as linter compiles all + " files within the source tree rooted at the specified source + " path and not just the file loaded in the buffer + let l:patterns = [ + \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', + \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', + \] + let l:output = [] + + let l:dir = s:GetWorkingDirectory(a:buffer) + + for l:match in ale#util#GetMatches(a:lines, l:patterns) + if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' + call add(l:output, { + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'type': l:match[4] is# 'error' ? 'E' : 'W', + \ 'code': l:match[5], + \ 'text': l:match[6] , + \}) + elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' + call add(l:output, { + \ 'filename':'<csc>', + \ 'lnum': -1, + \ 'col': -1, + \ 'type': l:match[1] is# 'error' ? 'E' : 'W', + \ 'code': l:match[2], + \ 'text': l:match[3], + \}) + endif + endfor + + return l:output +endfunction + +call ale#linter#Define('cs',{ +\ 'name': 'csc', +\ 'output_stream': 'stdout', +\ 'executable': 'csc', +\ 'command': function('ale_linters#cs#csc#GetCommand'), +\ 'callback': 'ale_linters#cs#csc#Handle', +\ 'lint_file': 1 +\}) diff --git a/ale_linters/cs/mcsc.vim b/ale_linters/cs/mcsc.vim index dd067eba..0e4e5667 100644 --- a/ale_linters/cs/mcsc.vim +++ b/ale_linters/cs/mcsc.vim @@ -52,20 +52,34 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort " NOTE: pattern also captures file name as linter compiles all " files within the source tree rooted at the specified source " path and not just the file loaded in the buffer - let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' + let l:patterns = [ + \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', + \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', + \] let l:output = [] let l:dir = s:GetWorkingDirectory(a:buffer) - for l:match in ale#util#GetMatches(a:lines, l:pattern) - call add(l:output, { - \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), - \ 'lnum': l:match[2] + 0, - \ 'col': l:match[3] + 0, - \ 'type': l:match[4] is# 'error' ? 'E' : 'W', - \ 'code': l:match[5], - \ 'text': l:match[6], - \}) + for l:match in ale#util#GetMatches(a:lines, l:patterns) + if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' + call add(l:output, { + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'type': l:match[4] is# 'error' ? 'E' : 'W', + \ 'code': l:match[5], + \ 'text': l:match[6] , + \}) + elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' + call add(l:output, { + \ 'filename':'<mcs>', + \ 'lnum': -1, + \ 'col': -1, + \ 'type': l:match[1] is# 'error' ? 'E' : 'W', + \ 'code': l:match[2], + \ 'text': l:match[3], + \}) + endif endfor return l:output diff --git a/ale_linters/ruby/sorbet.vim b/ale_linters/ruby/sorbet.vim new file mode 100644 index 00000000..ee765a6e --- /dev/null +++ b/ale_linters/ruby/sorbet.vim @@ -0,0 +1,23 @@ +call ale#Set('ruby_sorbet_executable', 'srb') +call ale#Set('ruby_sorbet_options', '') + +function! ale_linters#ruby#sorbet#GetCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') + let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') + + return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb') + \ . ' tc' + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . ' --lsp --disable-watchman' +endfunction + +call ale#linter#Define('ruby', { +\ 'name': 'sorbet', +\ 'aliases': ['srb'], +\ 'lsp': 'stdio', +\ 'language': 'ruby', +\ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')}, +\ 'command': function('ale_linters#ruby#sorbet#GetCommand'), +\ 'project_root': function('ale#ruby#FindProjectRoot') +\}) + diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim index f98dee9b..99178585 100644 --- a/ale_linters/rust/cargo.vim +++ b/ale_linters/rust/cargo.vim @@ -25,14 +25,11 @@ endfunction function! ale_linters#rust#cargo#GetCommand(buffer, version) abort let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') \ && ale#semver#GTE(a:version, [0, 17, 0]) - let l:use_all_targets = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_all_targets') + let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets') \ && ale#semver#GTE(a:version, [0, 22, 0]) - let l:use_examples = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_examples') + let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples') \ && ale#semver#GTE(a:version, [0, 22, 0]) - let l:use_tests = l:use_check - \ && ale#Var(a:buffer, 'rust_cargo_check_tests') + let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests') \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') @@ -69,7 +66,15 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort if ale#Var(a:buffer, 'rust_cargo_use_clippy') let l:subcommand = 'clippy' - let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options') + let l:clippy_options = ale#Var(a:buffer, 'rust_cargo_clippy_options') + + if l:clippy_options =~# '^-- ' + let l:clippy_options = join(split(l:clippy_options, '-- ')) + endif + + if l:clippy_options isnot# '' + let l:clippy_options = ' -- ' . l:clippy_options + endif endif return l:nearest_cargo_prefix . 'cargo ' diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index 43d84ea6..c0e8abd9 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -60,7 +60,8 @@ let s:omni_start_map = { \ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$', \} -" A map of exact characters for triggering LSP completions. +" A map of exact characters for triggering LSP completions. Do not forget to +" update self.input_patterns in ale.py in updating entries in this map. let s:trigger_character_map = { \ '<default>': ['.'], \ 'typescript': ['.', '''', '"'], @@ -217,6 +218,10 @@ function! ale#completion#GetCompletionPosition() abort return l:column - len(l:match) - 1 endfunction +function! ale#completion#GetCompletionPositionForDeoplete(input) abort + return match(a:input, '\k*$') +endfunction + function! ale#completion#GetCompletionResult() abort if exists('b:ale_completion_result') return b:ale_completion_result diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim index 1a8d02ef..c5ef1544 100644 --- a/autoload/ale/fix/registry.vim +++ b/autoload/ale/fix/registry.vim @@ -115,6 +115,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['scala'], \ 'description': 'Fix Scala files using scalafmt', \ }, +\ 'sorbet': { +\ 'function': 'ale#fixers#sorbet#Fix', +\ 'suggested_filetypes': ['ruby'], +\ 'description': 'Fix ruby files with srb tc --autocorrect.', +\ }, \ 'standard': { \ 'function': 'ale#fixers#standard#Fix', \ 'suggested_filetypes': ['javascript'], @@ -145,6 +150,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['php'], \ 'description': 'Fix PHP files with php-cs-fixer.', \ }, +\ 'clangtidy': { +\ 'function': 'ale#fixers#clangtidy#Fix', +\ 'suggested_filetypes': ['c', 'cpp', 'objc'], +\ 'description': 'Fix C/C++ and ObjectiveC files with clang-tidy.', +\ }, \ 'clang-format': { \ 'function': 'ale#fixers#clangformat#Fix', \ 'suggested_filetypes': ['c', 'cpp', 'cuda'], diff --git a/autoload/ale/fixers/clangtidy.vim b/autoload/ale/fixers/clangtidy.vim new file mode 100644 index 00000000..b37360a7 --- /dev/null +++ b/autoload/ale/fixers/clangtidy.vim @@ -0,0 +1,52 @@ +scriptencoding utf-8 +" Author: ObserverOfTime <chronobserver@disroot.org> +" Description: Fixing C/C++ files with clang-tidy. + +function! s:set_variables() abort + let l:use_global = get(g:, 'ale_use_global_executables', 0) + + for l:ft in ['c', 'cpp'] + call ale#Set(l:ft . '_clangtidy_executable', 'clang-tidy') + call ale#Set(l:ft . '_clangtidy_use_global', l:use_global) + call ale#Set(l:ft . '_clangtidy_checks', []) + call ale#Set(l:ft . '_clangtidy_options', '') + call ale#Set(l:ft . '_clangtidy_extra_options', '') + call ale#Set(l:ft . '_clangtidy_fix_errors', 1) + endfor + + call ale#Set('c_build_dir', '') +endfunction + +call s:set_variables() + +function! ale#fixers#clangtidy#Var(buffer, name) abort + let l:ft = getbufvar(str2nr(a:buffer), '&filetype') + let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c' + + return ale#Var(a:buffer, l:ft . '_clangtidy_' . a:name) +endfunction + +function! ale#fixers#clangtidy#GetCommand(buffer) abort + let l:checks = join(ale#fixers#clangtidy#Var(a:buffer, 'checks'), ',') + let l:extra_options = ale#fixers#clangtidy#Var(a:buffer, 'extra_options') + let l:build_dir = ale#c#GetBuildDirectory(a:buffer) + let l:options = empty(l:build_dir) + \ ? ale#fixers#clangtidy#Var(a:buffer, 'options') : '' + let l:fix_errors = ale#fixers#clangtidy#Var(a:buffer, 'fix_errors') + + return ' -fix' . (l:fix_errors ? ' -fix-errors' : '') + \ . (empty(l:checks) ? '' : ' -checks=' . ale#Escape(l:checks)) + \ . (empty(l:extra_options) ? '' : ' ' . l:extra_options) + \ . (empty(l:build_dir) ? '' : ' -p ' . ale#Escape(l:build_dir)) + \ . ' %t' . (empty(l:options) ? '' : ' -- ' . l:options) +endfunction + +function! ale#fixers#clangtidy#Fix(buffer) abort + let l:executable = ale#fixers#clangtidy#Var(a:buffer, 'executable') + let l:command = ale#fixers#clangtidy#GetCommand(a:buffer) + + return { + \ 'command': ale#Escape(l:executable) . l:command, + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/autoload/ale/fixers/sorbet.vim b/autoload/ale/fixers/sorbet.vim new file mode 100644 index 00000000..182f7300 --- /dev/null +++ b/autoload/ale/fixers/sorbet.vim @@ -0,0 +1,19 @@ +call ale#Set('ruby_sorbet_executable', 'srb') +call ale#Set('ruby_sorbet_options', '') + +function! ale#fixers#sorbet#GetCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') + let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') + + return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb') + \ . ' tc' + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . ' --autocorrect --file %t' +endfunction + +function! ale#fixers#sorbet#Fix(buffer) abort + return { + \ 'command': ale#fixers#sorbet#GetCommand(a:buffer), + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/autoload/ale/list.vim b/autoload/ale/list.vim index 80a30216..e9f3f4ec 100644 --- a/autoload/ale/list.vim +++ b/autoload/ale/list.vim @@ -110,8 +110,6 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort if s:ShouldOpen(a:buffer) && !empty(a:loclist) let l:winnr = winnr() let l:mode = mode() - let l:reset_visual_selection = l:mode is? 'v' || l:mode is# "\<c-v>" - let l:reset_character_selection = l:mode is? 's' || l:mode is# "\<c-s>" " open windows vertically instead of default horizontally let l:open_type = '' @@ -133,12 +131,13 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort wincmd p endif - if l:reset_visual_selection || l:reset_character_selection - " If we were in a selection mode before, select the last selection. - normal! gv - - if l:reset_character_selection - " Switch back to Select mode, if we were in that. + " Return to original mode when applicable + if mode() != l:mode + if l:mode is? 'v' || l:mode is# "\<c-v>" + " Reset our last visual selection + normal! gv + elseif l:mode is? 's' || l:mode is# "\<c-s>" + " Reset our last character selection normal! "\<c-g>" endif endif diff --git a/doc/ale-c.txt b/doc/ale-c.txt index ec7304f4..c9eb79db 100644 --- a/doc/ale-c.txt +++ b/doc/ale-c.txt @@ -177,6 +177,15 @@ g:ale_c_clangtidy_extra_options *g:ale_c_clangtidy_extra_options* This variable can be changed to modify flags given to clang-tidy. +g:ale_c_clangtidy_fix_errors *g:ale_c_clangtidy_fix_errors* + *b:ale_c_clangtidy_fix_errors* + Type: |Number| + Default: `1` + + This variable can be changed to disable the `-fix-errors` option for the + |clangtidy| fixer. + + =============================================================================== cppcheck *ale-c-cppcheck* diff --git a/doc/ale-cpp.txt b/doc/ale-cpp.txt index 50855c10..ead3be28 100644 --- a/doc/ale-cpp.txt +++ b/doc/ale-cpp.txt @@ -146,6 +146,15 @@ g:ale_cpp_clangtidy_extra_options *g:ale_cpp_clangtidy_extra_options* This variable can be changed to modify flags given to clang-tidy. +g:ale_cpp_clangtidy_fix_errors *g:ale_cpp_clangtidy_fix_errors* + *b:ale_cpp_clangtidy_fix_errors* + Type: |Number| + Default: `1` + + This variable can be changed to disable the `-fix-errors` option for the + |clangtidy| fixer. + + =============================================================================== clazy *ale-cpp-clazy* diff --git a/doc/ale-cs.txt b/doc/ale-cs.txt index 01e6348f..abcc43eb 100644 --- a/doc/ale-cs.txt +++ b/doc/ale-cs.txt @@ -7,10 +7,96 @@ with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim =============================================================================== +csc *ale-cs-csc* + + The |ale-cs-csc| linter checks for semantic errors when files are opened or + saved. + + See |ale-lint-file-linters| for more information on linters which do not + check for problems while you type. + + The csc linter uses the mono csc compiler providing full c# 7 and newer + support to generate a temporary module target file (/t:module). The module + includes including all '*.cs' files contained in the directory tree rooted + at the path defined by the |g:ale_cs_csc_source| or |b:ale_cs_csc_source| + variabl and all sub directories. + + It will in future replace the |ale-cs-mcs| and |ale-cs-mcsc| linters as both + utilizer the mcsc compiler which according to mono porject ist further + developed and as of writint these lines only receives maintenance updates. + The down is that the csc compiler does not support the -sytax option any more + and therefore |ale-cs-csc| linter doese not offer any as you type syntax + checking like the |ale-cs-mcsc| linter doesn't. + + The paths to search for additional assembly files can be specified using the + |g:ale_cs_csc_assembly_path| or |b:ale_cs_csc_assembly_path| variables. + + NOTE: ALE will not find any errors in files apart from syntax errors if any + one of the source files contains a syntax error. Syntax errors must be fixed + first before other errors will be shown. + + +g:ale_cs_csc_options *g:ale_cs_csc_options* + *b:ale_cs_csc_options* + Type: |String| + Default: `''` + + This option can be set to pass additional arguments to the `csc` compiler. + + For example, to add the dotnet package which is not added per default: > + + let g:ale_cs_mcs_options = ' /warn:4 /langversion:7.2' +< + NOTE: the `/unsafe` option is always passed to `csc`. + + +g:ale_cs_csc_source *g:ale_cs_csc_source* + *b:ale_cs_csc_source* + Type: |String| + Default: `''` + + This variable defines the root path of the directory tree searched for the + '*.cs' files to be linted. If this option is empty, the source file's + directory will be used. + + NOTE: Currently it is not possible to specify sub directories and + directory sub trees which shall not be searched for *.cs files. + + +g:ale_cs_csc_assembly_path *g:ale_cs_csc_assembly_path* + *b:ale_cs_csc_assembly_path* + Type: |List| + Default: `[]` + + This variable defines a list of path strings to be searched for external + assembly files. The list is passed to the csc compiler using the `/lib:` + flag. + + +g:ale_cs_csc_assemblies *g:ale_cs_csc_assemblies* + *b:ale_cs_csc_assemblies* + Type: |List| + Default: `[]` + + This variable defines a list of external assembly (*.dll) files required + by the mono mcs compiler to generate a valid module target. The list is + passed the csc compiler using the `/r:` flag. + + For example: > + + " Compile C# programs with the Unity engine DLL file on Mac. + let g:ale_cs_mcsc_assemblies = [ + \ '/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll', + \ 'path-to-unityproject/obj/Debug', + \] +< + +=============================================================================== mcs *ale-cs-mcs* - The `mcs` linter looks only for syntax errors while you type. See |ale-cs-mcsc| - for the separately configured linter for checking for semantic errors. + The `mcs` linter looks only for syntax errors while you type. See + |ale-cs-mcsc| for the separately configured linter for checking for semantic + errors. g:ale_cs_mcs_options *g:ale_cs_mcs_options* diff --git a/doc/ale-java.txt b/doc/ale-java.txt index 9b5e0c99..32f0e6eb 100644 --- a/doc/ale-java.txt +++ b/doc/ale-java.txt @@ -123,7 +123,7 @@ executable in this directory. g:ale_java_javalsp_executable *g:ale_java_javalsp_executable* *b:ale_java_javalsp_executable* Type: |String| - Default: `'launcher'` + Default: `''` This variable must be set to the absolute path of the language server launcher executable. For example: diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt index bf971e7c..e373ab8e 100644 --- a/doc/ale-ruby.txt +++ b/doc/ale-ruby.txt @@ -130,6 +130,26 @@ g:ale_ruby_solargraph_executable *g:ale_ruby_solargraph_executable* =============================================================================== +sorbet *ale-ruby-sorbet* + +g:ale_ruby_sorbet_executable *g:ale_ruby_sorbet_executable* + *b:ale_ruby_sorbet_executable* + Type: String + Default: `'srb'` + + Override the invoked sorbet binary. Set this to `'bundle'` to invoke + `'bundle` `exec` srb'. + + +g:ale_ruby_sorbet_options *g:ale_ruby_sorbet_options* + *b:ale_ruby_sorbet_options* + Type: |String| + Default: `''` + + This variable can be change to modify flags given to sorbet. + + +=============================================================================== standardrb *ale-ruby-standardrb* g:ale_ruby_standardrb_executable *g:ale_ruby_standardrb_executable* diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index 87e1ecde..d39aaf7e 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -53,6 +53,7 @@ Notes: * `gcc` * `uncrustify` * C# + * `csc`!! * `mcs` * `mcsc`!! * `uncrustify` @@ -391,6 +392,7 @@ Notes: * `ruby` * `rufo` * `solargraph` + * `sorbet` * `standardrb` * Rust * `cargo`!! diff --git a/doc/ale.txt b/doc/ale.txt index d18b98f0..5820bb20 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -1975,6 +1975,7 @@ documented in additional help files. uncrustify............................|ale-cpp-uncrustify| ccls..................................|ale-cpp-ccls| c#......................................|ale-cs-options| + csc...................................|ale-cs-csc| mcs...................................|ale-cs-mcs| mcsc..................................|ale-cs-mcsc| uncrustify............................|ale-cs-uncrustify| @@ -2219,6 +2220,7 @@ documented in additional help files. ruby..................................|ale-ruby-ruby| rufo..................................|ale-ruby-rufo| solargraph............................|ale-ruby-solargraph| + sorbet................................|ale-ruby-sorbet| standardrb............................|ale-ruby-standardrb| rust....................................|ale-rust-options| cargo.................................|ale-rust-cargo| @@ -3369,7 +3371,7 @@ snazzy looking ale glass logo. Cheers, Mark! 11. Contact *ale-contact* If you like this plugin, and wish to get in touch, check out the GitHub -page for issues and more at https://github.com/w0rp/ale +page for issues and more at https://github.com/dense-analysis/ale If you wish to contact the author of this plugin directly, please feel free to send an email to devw0rp@gmail.com. diff --git a/rplugin/python3/deoplete/sources/ale.py b/rplugin/python3/deoplete/sources/ale.py index 7f1c1d60..3955ed2d 100644 --- a/rplugin/python3/deoplete/sources/ale.py +++ b/rplugin/python3/deoplete/sources/ale.py @@ -24,10 +24,20 @@ class Source(Base): self.rank = 1000 self.is_bytepos = True self.min_pattern_length = 1 + # Do not forget to update s:trigger_character_map in completion.vim in + # updating entries in this map. + self.input_patterns = { + '_': r'\.\w*$', + 'rust': r'(\.|::)\w*$', + 'typescript': r'(\.|\'|")\w*$', + 'cpp': r'(\.|::|->)\w*$', + } # Returns an integer for the start position, as with omnifunc. - def get_completion_position(self): - return self.vim.call('ale#completion#GetCompletionPosition') + def get_complete_position(self, context): + return self.vim.call( + 'ale#completion#GetCompletionPositionForDeoplete', context['input'] + ) def gather_candidates(self, context): # Stop early if ALE can't provide completion data for this buffer. diff --git a/supported-tools.md b/supported-tools.md index f96f49a3..6cb9f418 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -62,6 +62,7 @@ formatting. * [gcc](https://gcc.gnu.org/) * [uncrustify](https://github.com/uncrustify/uncrustify) * C# + * [csc](http://www.mono-project.com/docs/about-mono/languages/csharp/) :floppy_disk: see:`help ale-cs-csc` for details and configuration * [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) see:`help ale-cs-mcs` for details * [mcsc](http://www.mono-project.com/docs/about-mono/languages/csharp/) :floppy_disk: see:`help ale-cs-mcsc` for details and configuration * [uncrustify](https://github.com/uncrustify/uncrustify) @@ -400,6 +401,7 @@ formatting. * [ruby](https://www.ruby-lang.org) * [rufo](https://github.com/ruby-formatter/rufo) * [solargraph](https://solargraph.org) + * [sorbet](https://github.com/sorbet/sorbet) * [standardrb](https://github.com/testdouble/standard) * Rust * [cargo](https://github.com/rust-lang/cargo) :floppy_disk: (see `:help ale-integration-rust` for configuration instructions) diff --git a/test/command_callback/test_cargo_command_callbacks.vader b/test/command_callback/test_cargo_command_callbacks.vader index 438c97db..e56551ae 100644 --- a/test/command_callback/test_cargo_command_callbacks.vader +++ b/test/command_callback/test_cargo_command_callbacks.vader @@ -139,23 +139,60 @@ Execute(When a crate belongs to a workspace we chdir into the crate, unless we d Execute(When ale_rust_cargo_use_clippy is set, cargo-clippy is used as linter): let b:ale_rust_cargo_use_clippy = 1 + AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', - \ 'cargo clippy --frozen --message-format=json -q ', + \ 'cargo clippy --frozen --message-format=json -q', \] Execute(When ale_rust_cargo_clippy_options is set, cargo-clippy appends it to commandline): let b:ale_rust_cargo_use_clippy = 1 let b:ale_rust_cargo_clippy_options = '-- -D warnings' + AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --frozen --message-format=json -q -- -D warnings', \] +Execute(Clippy options work without prepending --): + let b:ale_rust_cargo_use_clippy = 1 + let b:ale_rust_cargo_clippy_options = '-D warnings' + + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo clippy --frozen --message-format=json -q -- -D warnings', + \] + +Execute(Build supports all cargo flags): + let g:ale_rust_cargo_use_check = 0 + let g:ale_rust_cargo_check_all_targets = 1 + let g:ale_rust_cargo_check_tests = 1 + let g:ale_rust_cargo_check_examples = 1 + let b:ale_rust_cargo_default_feature_behavior = 'all' + + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo build --all-targets --examples --tests --frozen --message-format=json -q --all-features', + \] + +Execute(Clippy supports all cargo flags): + let b:ale_rust_cargo_use_clippy = 1 + let g:ale_rust_cargo_check_all_targets = 1 + let g:ale_rust_cargo_check_tests = 1 + let g:ale_rust_cargo_check_examples = 1 + let b:ale_rust_cargo_default_feature_behavior = 'all' + let b:ale_rust_cargo_clippy_options = '-D warnings' + + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo clippy --all-targets --examples --tests --frozen --message-format=json -q --all-features -- -D warnings', + \] + Execute(cargo-check does not refer ale_rust_cargo_clippy_options): let b:ale_rust_cargo_use_clippy = 0 let b:ale_rust_cargo_use_check = 1 let b:ale_rust_cargo_clippy_options = '-- -D warnings' + AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check --frozen --message-format=json -q', diff --git a/test/command_callback/test_cs_csc_command_callbacks.vader b/test/command_callback/test_cs_csc_command_callbacks.vader new file mode 100644 index 00000000..c21ce209 --- /dev/null +++ b/test/command_callback/test_cs_csc_command_callbacks.vader @@ -0,0 +1,47 @@ +Before: + call ale#assert#SetUpLinterTest('cs', 'csc') + +After: + call ale#assert#TearDownLinterTest() + +Execute(The csc linter should return the correct default command): + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + +Execute(The options should be be used in the command): + let g:ale_cs_csc_options = '' + + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + +Execute(The souce path should be be used in the command): + let g:ale_cs_csc_source = '../foo/bar' + + AssertLinter 'csc', ale#path#CdString('../foo/bar') + \ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + +Execute(The list of search pathes for assemblies should be be used in the command if not empty): + let g:ale_cs_csc_assembly_path = ['/usr/lib/mono', '../foo/bar'] + + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe' + \ . ' /lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar') + \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + + let g:ale_cs_csc_assembly_path = [] + + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + +Execute(The list of assemblies should be be used in the command if not empty): + let g:ale_cs_csc_assemblies = ['foo.dll', 'bar.dll'] + + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe' + \ . ' /r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll') + \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') + + let g:ale_cs_csc_assemblies = [] + + AssertLinter 'csc', ale#path#CdString(g:dir) + \ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') diff --git a/test/command_callback/test_sorbet_command_callback.vader b/test/command_callback/test_sorbet_command_callback.vader new file mode 100644 index 00000000..b46e90a4 --- /dev/null +++ b/test/command_callback/test_sorbet_command_callback.vader @@ -0,0 +1,27 @@ + +Before: + call ale#assert#SetUpLinterTest('ruby', 'sorbet') + call ale#test#SetFilename('dummy.rb') + + let g:ale_ruby_sorbet_executable = 'srb' + let g:ale_ruby_sorbet_options = '' + +After: + call ale#assert#TearDownLinterTest() + +Execute(Executable should default to srb): + AssertLinter 'srb', ale#Escape('srb') + \ . ' tc --lsp --disable-watchman' + +Execute(Should be able to set a custom executable): + let g:ale_ruby_sorbet_executable = 'bin/srb' + + AssertLinter 'bin/srb' , ale#Escape('bin/srb') + \ . ' tc --lsp --disable-watchman' + +Execute(Setting bundle appends 'exec srb tc'): + let g:ale_ruby_sorbet_executable = 'path to/bundle' + + AssertLinter 'path to/bundle', ale#Escape('path to/bundle') + \ . ' exec srb' + \ . ' tc --lsp --disable-watchman' diff --git a/test/completion/test_public_completion_api.vader b/test/completion/test_public_completion_api.vader index befbb436..c3cd42b8 100644 --- a/test/completion/test_public_completion_api.vader +++ b/test/completion/test_public_completion_api.vader @@ -32,6 +32,10 @@ Execute(ale#completion#GetCompletionPosition() should return the position in the " This is the first character of 'bar' AssertEqual 4, ale#completion#GetCompletionPosition() +Execute(ale#completion#GetCompletionPositionForDeoplete() should return the position on the given input string): + " This is the first character of 'bar' + AssertEqual 4, ale#completion#GetCompletionPositionForDeoplete('foo bar') + Execute(ale#completion#CanProvideCompletions should return 0 when no completion sources are available): AssertEqual 0, ale#completion#CanProvideCompletions() diff --git a/test/fixers/test_clangtidy_fixer_callback.vader b/test/fixers/test_clangtidy_fixer_callback.vader new file mode 100644 index 00000000..68416b36 --- /dev/null +++ b/test/fixers/test_clangtidy_fixer_callback.vader @@ -0,0 +1,51 @@ +Before: + Save g:ale_c_clangtidy_executable + + " Use an invalid global executable, so we don't match it. + let g:ale_c_clangtidy_executable = 'xxxinvalid' + let g:ale_c_build_dir = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd ../command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The clangtidy callback should return the correct default values): + call ale#test#SetFilename('c_paths/dummy.c') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_c_clangtidy_executable) + \ . ' -fix -fix-errors %t' + \ }, + \ ale#fixers#clangtidy#Fix(bufnr('')) + +Execute(The clangtidy callback should include any additional options): + call ale#test#SetFilename('c_paths/dummy.c') + let g:ale_c_clangtidy_extra_options = '--some-option' + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_c_clangtidy_executable) + \ . ' -fix -fix-errors --some-option %t', + \ }, + \ ale#fixers#clangtidy#Fix(bufnr('')) + +Execute(The clangtidy callback should support cpp files): + call ale#test#SetFilename('c_paths/dummy.cpp') + let g:ale_cpp_clangtidy_executable = 'invalidpp' + set filetype=cpp " The test fails without this + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_cpp_clangtidy_executable) + \ . ' -fix -fix-errors %t', + \ }, + \ ale#fixers#clangtidy#Fix(bufnr('')) diff --git a/test/fixers/test_sorbet_fixer_callback.vader b/test/fixers/test_sorbet_fixer_callback.vader new file mode 100644 index 00000000..71870e4c --- /dev/null +++ b/test/fixers/test_sorbet_fixer_callback.vader @@ -0,0 +1,42 @@ + +Before: + Save g:ale_ruby_sorbet_executable + Save g:ale_ruby_sorbet_options + + " Use an invalid global executable, so we don't match it. + let g:ale_ruby_sorbet_executable = 'xxxinvalid' + let g:ale_ruby_sorbet_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The sorbet callback should return the correct default values): + call ale#test#SetFilename('ruby_paths/dummy.rb') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_ruby_sorbet_executable) + \ . ' tc --autocorrect --file %t', + \ }, + \ ale#fixers#sorbet#Fix(bufnr('')) + +Execute(The sorbet callback should include custom sorbet options): + let g:ale_ruby_sorbet_options = '--enable-experimental-lsp-hover' + call ale#test#SetFilename('ruby_paths/with_config/dummy.rb') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_ruby_sorbet_executable) + \ . ' tc --enable-experimental-lsp-hover' + \ . ' --autocorrect --file %t', + \ }, + \ ale#fixers#sorbet#Fix(bufnr('')) diff --git a/test/handler/test_csc_handler.vader b/test/handler/test_csc_handler.vader new file mode 100644 index 00000000..3db5b6fd --- /dev/null +++ b/test/handler/test_csc_handler.vader @@ -0,0 +1,98 @@ +Before: + Save g:ale_cs_csc_source + + unlet! g:ale_cs_csc_source + + call ale#test#SetDirectory('/testplugin/test/handler') + call ale#test#SetFilename('Test.cs') + + runtime ale_linters/cs/csc.vim + +After: + unlet! g:ale_cs_csc_source + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The csc handler should work with the default of the buffer's directory): + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'col' : 29, + \ 'text': '; expected', + \ 'code': 'CS1001', + \ 'type': 'E', + \ 'filename': ale#path#Simplify(g:dir . '/Test.cs'), + \ }, + \ ], + \ ale_linters#cs#csc#Handle(bufnr(''), [ + \ 'Test.cs(12,29): error CS1001: ; expected', + \ 'Compilation failed: 2 error(s), 1 warnings', + \ ]) + +Execute(The csc handler should handle cannot find symbol errors): + let g:ale_cs_csc_source = '/home/foo/project/bar' + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'col' : 29, + \ 'text': '; expected', + \ 'code': 'CS1001', + \ 'type': 'E', + \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), + \ }, + \ { + \ 'lnum': 101, + \ 'col': 0, + \ 'text': 'Unexpected processor directive (no #if for this #endif)', + \ 'code': 'CS1028', + \ 'type': 'E', + \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), + \ }, + \ { + \ 'lnum': 10, + \ 'col': 12, + \ 'text': 'some warning', + \ 'code': 'CS0123', + \ 'type': 'W', + \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), + \ }, + \ ], + \ ale_linters#cs#csc#Handle(bufnr(''), [ + \ 'Test.cs(12,29): error CS1001: ; expected', + \ 'Test.cs(101,0): error CS1028: Unexpected processor directive (no #if for this #endif)', + \ 'Test.cs(10,12): warning CS0123: some warning', + \ 'Compilation failed: 2 error(s), 1 warnings', + \ ]) + +Execute(The csc handler should handle non file specific compiler errors without reporting overal status report as error): + let g:ale_cs_csc_source = '/home/foo/project/bar' + + AssertEqual + \ [ + \ { + \ 'lnum': -1, + \ 'col' : -1, + \ 'text': 'No source files specified.', + \ 'code': 'CS2008', + \ 'type': 'W', + \ 'filename': '<csc>', + \ }, + \ { + \ 'lnum': -1, + \ 'col': -1, + \ 'text': 'Outputs without source must have the /out option specified', + \ 'code': 'CS1562', + \ 'type': 'E', + \ 'filename': '<csc>', + \ }, + \ ], + \ ale_linters#cs#csc#Handle(bufnr(''), [ + \ 'Microsoft (R) Visual C# Compiler version 2.8.2.62916 (2ad4aabc)', + \ 'Copyright (C) Microsoft Corporation. All rights reserved.', + \ 'warning CS2008: No source files specified.', + \ 'error CS1562: Outputs without source must have the /out option specified', + \ ]) diff --git a/test/handler/test_mcsc_handler.vader b/test/handler/test_mcsc_handler.vader index 8ae47357..c04f7d27 100644 --- a/test/handler/test_mcsc_handler.vader +++ b/test/handler/test_mcsc_handler.vader @@ -67,3 +67,22 @@ Execute(The mcs handler should handle cannot find symbol errors): \ 'Test.cs(10,12): warning CS0123: some warning', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) + +Execute(The mcsc handler should handle non file specific compiler errors without reporting overal status report as error): + let g:ale_cs_mcsc_source = '/home/foo/project/bar' + + AssertEqual + \ [ + \ { + \ 'lnum': -1, + \ 'col' : -1, + \ 'text': 'No files to compile were specified', + \ 'code': 'CS2008', + \ 'type': 'E', + \ 'filename': '<mcs>', + \ }, + \ ], + \ ale_linters#cs#mcsc#Handle(bufnr(''), [ + \ 'error CS2008: No files to compile were specified', + \ 'Compilation failed: 1 error(s), 0 warnings', + \ ]) diff --git a/test/python/test_deoplete_source.py b/test/python/test_deoplete_source.py index 1462f77d..9e56a10d 100644 --- a/test/python/test_deoplete_source.py +++ b/test/python/test_deoplete_source.py @@ -41,6 +41,12 @@ class DeopleteSourceTest(unittest.TestCase): ) self.assertEqual(attributes, { + 'input_patterns': { + '_': r'\.\w*$', + 'rust': r'(\.|::)\w*$', + 'typescript': r'(\.|\'|")\w*$', + 'cpp': r'(\.|::|->)\w*$', + }, 'is_bytepos': True, 'mark': '[L]', 'min_pattern_length': 1, @@ -48,12 +54,13 @@ class DeopleteSourceTest(unittest.TestCase): 'rank': 1000, }) - def test_completion_position(self): - self.call_results['ale#completion#GetCompletionPosition'] = 2 + def test_complete_position(self): + self.call_results['ale#completion#GetCompletionPositionForDeoplete'] = 2 + context = {'input': 'foo'} - self.assertEqual(self.source.get_completion_position(), 2) + self.assertEqual(self.source.get_complete_position(context), 2) self.assertEqual(self.call_list, [ - ('ale#completion#GetCompletionPosition', ()), + ('ale#completion#GetCompletionPositionForDeoplete', ('foo',)), ]) def test_request_completion_results(self): |