summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--ale_linters/cs/csc.vim95
-rw-r--r--ale_linters/cs/mcsc.vim34
-rw-r--r--ale_linters/ruby/sorbet.vim23
-rw-r--r--autoload/ale/completion.vim7
-rw-r--r--autoload/ale/fix/registry.vim10
-rw-r--r--autoload/ale/fixers/clangtidy.vim52
-rw-r--r--autoload/ale/fixers/sorbet.vim19
-rw-r--r--autoload/ale/list.vim15
-rw-r--r--doc/ale-c.txt9
-rw-r--r--doc/ale-cpp.txt9
-rw-r--r--doc/ale-cs.txt90
-rw-r--r--doc/ale-java.txt2
-rw-r--r--doc/ale-ruby.txt20
-rw-r--r--doc/ale-supported-languages-and-tools.txt2
-rw-r--r--doc/ale.txt2
-rw-r--r--rplugin/python3/deoplete/sources/ale.py14
-rw-r--r--supported-tools.md2
-rw-r--r--test/command_callback/test_cs_csc_command_callbacks.vader47
-rw-r--r--test/command_callback/test_sorbet_command_callback.vader27
-rw-r--r--test/completion/test_public_completion_api.vader4
-rw-r--r--test/fixers/test_clangtidy_fixer_callback.vader51
-rw-r--r--test/fixers/test_sorbet_fixer_callback.vader42
-rw-r--r--test/handler/test_csc_handler.vader98
-rw-r--r--test/handler/test_mcsc_handler.vader19
-rw-r--r--test/python/test_deoplete_source.py15
26 files changed, 681 insertions, 28 deletions
diff --git a/README.md b/README.md
index 91f0c3ea..fc7ac874 100644
--- a/README.md
+++ b/README.md
@@ -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/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 eea3d102..8e32c911 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|
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_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):