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/java/javalsp.vim14
-rwxr-xr-xale_linters/powershell/powershell.vim22
-rw-r--r--ale_linters/ruby/sorbet.vim23
-rw-r--r--autoload/ale/completion.vim2
-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.txt29
-rw-r--r--doc/ale-ruby.txt20
-rw-r--r--doc/ale-supported-languages-and-tools.txt2
-rw-r--r--doc/ale.txt6
-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_javalsp_command_callback.vader49
-rw-r--r--test/command_callback/test_sorbet_command_callback.vader27
-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
-rwxr-xr-xtest/handler/test_powershell_handler.vader47
27 files changed, 804 insertions, 30 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/java/javalsp.vim b/ale_linters/java/javalsp.vim
index f56675d6..baf584c8 100644
--- a/ale_linters/java/javalsp.vim
+++ b/ale_linters/java/javalsp.vim
@@ -2,11 +2,24 @@
" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
call ale#Set('java_javalsp_executable', '')
+call ale#Set('java_javalsp_config', {})
function! ale_linters#java#javalsp#Executable(buffer) abort
return ale#Var(a:buffer, 'java_javalsp_executable')
endfunction
+function! ale_linters#java#javalsp#Config(buffer) abort
+ let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } }
+ let l:config = ale#Var(a:buffer, 'java_javalsp_config')
+
+ " Ensure the config dictionary contains both classPath and
+ " externalDependencies keys to avoid a NPE crash on Java Language Server.
+ call extend(l:config, l:defaults, 'keep')
+ call extend(l:config['java'], l:defaults['java'], 'keep')
+
+ return l:config
+endfunction
+
function! ale_linters#java#javalsp#Command(buffer) abort
let l:executable = ale_linters#java#javalsp#Executable(a:buffer)
@@ -38,4 +51,5 @@ call ale#linter#Define('java', {
\ 'command': function('ale_linters#java#javalsp#Command'),
\ 'language': 'java',
\ 'project_root': function('ale#java#FindProjectRoot'),
+\ 'lsp_config': function('ale_linters#java#javalsp#Config')
\})
diff --git a/ale_linters/powershell/powershell.vim b/ale_linters/powershell/powershell.vim
index 51ded71d..a63191fd 100755
--- a/ale_linters/powershell/powershell.vim
+++ b/ale_linters/powershell/powershell.vim
@@ -49,11 +49,19 @@ function! ale_linters#powershell#powershell#Handle(buffer, lines) abort
let l:matchcount = 1
endif
- let l:item = {
- \ 'lnum': str2nr(l:match[1]),
- \ 'col': str2nr(l:match[2]),
- \ 'type': 'E',
- \}
+ " If the match is 0, it was a failed match
+ " probably due to an unexpected token which
+ " contained a newline. Reset matchcount. to
+ " continue to the next match
+ if !empty(l:match[1])
+ let l:item = {
+ \ 'lnum': str2nr(l:match[1]),
+ \ 'col': str2nr(l:match[2]),
+ \ 'type': 'E',
+ \}
+ else
+ let l:matchcount = 0
+ endif
elseif l:matchcount == 2
" Second match[0] grabs the full line in order
" to handles the text
@@ -84,8 +92,8 @@ endfunction
call ale#linter#Define('powershell', {
\ 'name': 'powershell',
-\ 'executable_callback': 'ale_linters#powershell#powershell#GetExecutable',
-\ 'command_callback': 'ale_linters#powershell#powershell#GetCommand',
+\ 'executable': function('ale_linters#powershell#powershell#GetExecutable'),
+\ 'command': function('ale_linters#powershell#powershell#GetCommand'),
\ 'output_stream': 'stdout',
\ 'callback': 'ale_linters#powershell#powershell#Handle',
\})
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 f0d6425d..c0e8abd9 100644
--- a/autoload/ale/completion.vim
+++ b/autoload/ale/completion.vim
@@ -52,6 +52,7 @@ let s:should_complete_map = {
\ 'lisp': s:lisp_regex,
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$',
\ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$',
+\ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$',
\}
" Regular expressions for finding the start column to replace with completion.
@@ -65,6 +66,7 @@ let s:trigger_character_map = {
\ '<default>': ['.'],
\ 'typescript': ['.', '''', '"'],
\ 'rust': ['.', '::'],
+\ 'cpp': ['.', '::', '->'],
\}
function! s:GetFiletypeValue(map, filetype) abort
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 58acc272..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:
@@ -131,6 +131,33 @@ executable. For example:
let g:ale_java_javalsp_executable=/java-language-server/dist/mac/bin/launcher
<
+g:ale_java_javalsp_config *g:ale_java_javalsp_config*
+ *b:ale_java_javalsp_config*
+ Type: |Dictionary|
+ Default: `{}`
+
+The javalsp linter automatically detects external depenencies for Maven and
+Gradle projects. In case the javalsp fails to detect some of them, you can
+specify them setting a dictionary to |g:ale_java_javalsp_config| variable.
+>
+ let g:ale_java_javalsp_executable =
+ \ {
+ \ 'java': {
+ \ 'externalDependencies': [
+ \ 'junit:junit:jar:4.12:test', " Maven format
+ \ 'junit:junit:4.1' " Gradle format
+ \ ],
+ \ 'classPath': [
+ \ 'lib/some-dependency.jar',
+ \ '/android-sdk/platforms/android-28.jar'
+ \ ]
+ \ }
+ \ }
+
+The Java language server will look for the dependencies you specify in
+`externalDependencies` array in your Maven and Gradle caches ~/.m2 and
+~/.gradle.
+
===============================================================================
eclipselsp *ale-java-eclipselsp*
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 599ac2c3..8e32c911 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -981,7 +981,7 @@ g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave*
*b:ale_lint_on_insert_leave*
Type: |Number|
- Default: `0`
+ Default: `1`
When set to `1` in your vimrc file, this option will cause ALE to run
linters when you leave insert mode.
@@ -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|
@@ -3220,7 +3222,7 @@ ale#lsp_linter#SendRequest(buffer, linter_name, message, [Handler])
containing three elements:
`is_notification` - an |Integer| that has value 1 if the
request is a notification, 0 otherwise;
- `methdod` - a |String|, identifying an LSP method supported
+ `method` - a |String|, identifying an LSP method supported
by `linter`;
`parameters` - a |dictionary| of LSP parameters that are
applicable to `method`.
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_javalsp_command_callback.vader b/test/command_callback/test_javalsp_command_callback.vader
index ca7388c0..122f409b 100644
--- a/test/command_callback/test_javalsp_command_callback.vader
+++ b/test/command_callback/test_javalsp_command_callback.vader
@@ -29,3 +29,52 @@ Execute(The javalsp callback should return backward compatible value):
\]
AssertLinter '/bin/java', join(cmd, ' ')
+Execute(The javalsp should have default config):
+ AssertEqual
+ \ {
+ \ 'java': {
+ \ 'classPath': [],
+ \ 'externalDependencies': []
+ \ }
+ \ },
+ \ ale_linters#java#javalsp#Config(bufnr(''))
+
+Execute(The javalsp should have default config if user sets empty hash):
+ let b:ale_java_javalsp_config = {}
+
+ AssertEqual
+ \ {
+ \ 'java': {
+ \ 'classPath': [],
+ \ 'externalDependencies': []
+ \ }
+ \ },
+ \ ale_linters#java#javalsp#Config(bufnr(''))
+
+Execute(The javalsp should have add missing config):
+ let b:ale_java_javalsp_config = { 'java': { 'classPath': ['aaa.jar'] } }
+
+ AssertEqual
+ \ {
+ \ 'java': {
+ \ 'classPath': ['aaa.jar'],
+ \ 'externalDependencies': []
+ \ }
+ \ },
+ \ ale_linters#java#javalsp#Config(bufnr(''))
+
+ let b:ale_java_javalsp_config =
+ \ {
+ \ 'java': {
+ \ 'externalDependencies': ['unit-test:2.0.0']
+ \ }
+ \ }
+
+ AssertEqual
+ \ {
+ \ 'java': {
+ \ 'classPath': [],
+ \ 'externalDependencies': ['unit-test:2.0.0']
+ \ }
+ \ },
+ \ ale_linters#java#javalsp#Config(bufnr(''))
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/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/handler/test_powershell_handler.vader b/test/handler/test_powershell_handler.vader
index 635bcd20..77c3dc65 100755
--- a/test/handler/test_powershell_handler.vader
+++ b/test/handler/test_powershell_handler.vader
@@ -60,3 +60,50 @@ Execute(The powershell handler should process multiple syntax errors from parsin
\ '+ CategoryInfo : NotSpecified: (:) [], ParseException',
\ '+ FullyQualifiedErrorId : ParseException'
\ ])
+Execute(The powershell handler should process unexecpected token that contains a newline character):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 2,
+ \ 'col': 8,
+ \ 'type': 'E',
+ \ 'text': 'The string is missing the terminator: ".',
+ \ 'code': 'ParseException'
+ \ },
+ \ {
+ \ 'lnum': 2,
+ \ 'col': 8,
+ \ 'type': 'E',
+ \ 'text': 'Unexpected token ''"',
+ \ 'code': 'ParseException'
+ \ },
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'type': 'E',
+ \ 'text': 'Missing closing ''}'' in statement block or type definition.',
+ \ 'code': 'ParseException'
+ \ }
+ \ ],
+ \ ale_linters#powershell#powershell#Handle(bufnr(''), [
+ \ 'At line:2 char:8',
+ \ '+ "" "',
+ \ '+ ~',
+ \ 'The string is missing the terminator: ".',
+ \ 'At line:2 char:8',
+ \ '+ "" "',
+ \ '+ ~',
+ \ 'Unexpected token ''"',
+ \ '',
+ \ ' }'' in expression or statement.',
+ \ '',
+ \ 'At line:1 char:1',
+ \ '+ {',
+ \ '+ ~',
+ \ 'Missing closing ''}'' in statement block or type definition.',
+ \ 'At C:\Users\jpharris\AppData\Local\Temp\VIAA777.tmp\script.ps1:1 char:150',
+ \ '+ ... ontents); [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Con ...',
+ \ '+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~',
+ \ ' + CategoryInfo : NotSpecified: (:) [], ParseException',
+ \ ' + FullyQualifiedErrorId : ParseException'
+ \ ])