mirror of https://github.com/amix/vimrc.git
parent
e83f5ea2e7
commit
a06964dd3b
@ -0,0 +1,5 @@ |
||||
" Author: Horacio Sanson (hsanson [รคt] gmail.com) |
||||
" Description: languagetool for asciidoc files, copied from markdown. |
||||
|
||||
|
||||
call ale#handlers#languagetool#DefineLinter('asciidoc') |
@ -0,0 +1,53 @@ |
||||
" Author: w0rp <devw0rp@gmail.com> |
||||
" Description: A C compiler linter for C files with gcc/clang, etc. |
||||
|
||||
call ale#Set('c_cc_executable', '<auto>') |
||||
call ale#Set('c_cc_options', '-std=c11 -Wall') |
||||
|
||||
function! ale_linters#c#cc#GetExecutable(buffer) abort |
||||
let l:executable = ale#Var(a:buffer, 'c_cc_executable') |
||||
|
||||
" Default to either clang or gcc. |
||||
if l:executable is# '<auto>' |
||||
if ale#engine#IsExecutable(a:buffer, 'clang') |
||||
let l:executable = 'clang' |
||||
else |
||||
let l:executable = 'gcc' |
||||
endif |
||||
endif |
||||
|
||||
return l:executable |
||||
endfunction |
||||
|
||||
function! ale_linters#c#cc#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
let l:ale_flags = ale#Var(a:buffer, 'c_cc_options') |
||||
|
||||
if l:cflags =~# '-std=' |
||||
let l:ale_flags = substitute( |
||||
\ l:ale_flags, |
||||
\ '-std=\(c\|gnu\)[0-9]\{2\}', |
||||
\ '', |
||||
\ 'g') |
||||
endif |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
" |
||||
" `-o /dev/null` or `-o null` is needed to catch all errors, |
||||
" -fsyntax-only doesn't catch everything. |
||||
return '%e -S -x c' |
||||
\ . ' -o ' . g:ale#util#nul_file |
||||
\ . ' -iquote %s:h' |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(l:ale_flags) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('c', { |
||||
\ 'name': 'cc', |
||||
\ 'aliases': ['gcc', 'clang'], |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': function('ale_linters#c#cc#GetExecutable'), |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#cc#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -1,24 +0,0 @@ |
||||
" Author: Masahiro H https://github.com/mshr-h |
||||
" Description: clang linter for c files |
||||
|
||||
call ale#Set('c_clang_executable', 'clang') |
||||
call ale#Set('c_clang_options', '-std=c11 -Wall') |
||||
|
||||
function! ale_linters#c#clang#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
return '%e -S -x c -fsyntax-only' |
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('c', { |
||||
\ 'name': 'clang', |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': {b -> ale#Var(b, 'c_clang_executable')}, |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clang#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -1,28 +0,0 @@ |
||||
" Author: w0rp <devw0rp@gmail.com> |
||||
" Description: gcc linter for c files |
||||
|
||||
call ale#Set('c_gcc_executable', 'gcc') |
||||
call ale#Set('c_gcc_options', '-std=c11 -Wall') |
||||
|
||||
function! ale_linters#c#gcc#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
" |
||||
" `-o /dev/null` or `-o null` is needed to catch all errors, |
||||
" -fsyntax-only doesn't catch everything. |
||||
return '%e -S -x c' |
||||
\ . ' -o ' . g:ale#util#nul_file |
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('c', { |
||||
\ 'name': 'gcc', |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': {b -> ale#Var(b, 'c_gcc_executable')}, |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#gcc#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -0,0 +1,53 @@ |
||||
" Author: w0rp <devw0rp@gmail.com> |
||||
" Description: A C++ compiler linter for C++ files with gcc/clang, etc. |
||||
|
||||
call ale#Set('cpp_cc_executable', '<auto>') |
||||
call ale#Set('cpp_cc_options', '-std=c++14 -Wall') |
||||
|
||||
function! ale_linters#cpp#cc#GetExecutable(buffer) abort |
||||
let l:executable = ale#Var(a:buffer, 'cpp_cc_executable') |
||||
|
||||
" Default to either clang++ or gcc. |
||||
if l:executable is# '<auto>' |
||||
if ale#engine#IsExecutable(a:buffer, 'clang++') |
||||
let l:executable = 'clang++' |
||||
else |
||||
let l:executable = 'gcc' |
||||
endif |
||||
endif |
||||
|
||||
return l:executable |
||||
endfunction |
||||
|
||||
function! ale_linters#cpp#cc#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
let l:ale_flags = ale#Var(a:buffer, 'cpp_cc_options') |
||||
|
||||
if l:cflags =~# '-std=' |
||||
let l:ale_flags = substitute( |
||||
\ l:ale_flags, |
||||
\ '-std=\(c\|gnu\)++[0-9]\{2\}', |
||||
\ '', |
||||
\ 'g') |
||||
endif |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
" |
||||
" `-o /dev/null` or `-o null` is needed to catch all errors, |
||||
" -fsyntax-only doesn't catch everything. |
||||
return '%e -S -x c++' |
||||
\ . ' -o ' . g:ale#util#nul_file |
||||
\ . ' -iquote %s:h' |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(l:ale_flags) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('cpp', { |
||||
\ 'name': 'cc', |
||||
\ 'aliases': ['gcc', 'clang', 'g++', 'clang++'], |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': function('ale_linters#cpp#cc#GetExecutable'), |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#cc#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -1,24 +0,0 @@ |
||||
" Author: Tomota Nakamura <https://github.com/tomotanakamura> |
||||
" Description: clang linter for cpp files |
||||
|
||||
call ale#Set('cpp_clang_executable', 'clang++') |
||||
call ale#Set('cpp_clang_options', '-std=c++14 -Wall') |
||||
|
||||
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
return '%e -S -x c++ -fsyntax-only' |
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('cpp', { |
||||
\ 'name': 'clang', |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')}, |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clang#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -1,29 +0,0 @@ |
||||
" Author: geam <mdelage@student.42.fr> |
||||
" Description: gcc linter for cpp files |
||||
" |
||||
call ale#Set('cpp_gcc_executable', 'gcc') |
||||
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall') |
||||
|
||||
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort |
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output) |
||||
|
||||
" -iquote with the directory the file is in makes #include work for |
||||
" headers in the same directory. |
||||
" |
||||
" `-o /dev/null` or `-o null` is needed to catch all errors, |
||||
" -fsyntax-only doesn't catch everything. |
||||
return '%e -S -x c++' |
||||
\ . ' -o ' . g:ale#util#nul_file |
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) |
||||
\ . ale#Pad(l:cflags) |
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('cpp', { |
||||
\ 'name': 'gcc', |
||||
\ 'aliases': ['g++'], |
||||
\ 'output_stream': 'stderr', |
||||
\ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')}, |
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#gcc#GetCommand'))}, |
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', |
||||
\}) |
@ -0,0 +1,39 @@ |
||||
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com> |
||||
" Description: Elvis linter for Erlang files |
||||
|
||||
call ale#Set('erlang_elvis_executable', 'elvis') |
||||
|
||||
function! ale_linters#erlang#elvis#Handle(buffer, lines) abort |
||||
let l:pattern = '\v:(\d+):[^:]+:(.+)' |
||||
let l:loclist = [] |
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern) |
||||
call add(l:loclist, { |
||||
\ 'lnum': str2nr(l:match[1]), |
||||
\ 'text': s:AbbreviateMessage(l:match[2]), |
||||
\ 'type': 'W', |
||||
\}) |
||||
endfor |
||||
|
||||
return l:loclist |
||||
endfunction |
||||
|
||||
function! s:AbbreviateMessage(text) abort |
||||
let l:pattern = '\v\c^(line \d+ is too long):.*$' |
||||
|
||||
return substitute(a:text, l:pattern, '\1.', '') |
||||
endfunction |
||||
|
||||
function! s:GetCommand(buffer) abort |
||||
let l:file = ale#Escape(expand('#' . a:buffer . ':.')) |
||||
|
||||
return '%e rock --output-format=parsable ' . l:file |
||||
endfunction |
||||
|
||||
call ale#linter#Define('erlang', { |
||||
\ 'name': 'elvis', |
||||
\ 'callback': 'ale_linters#erlang#elvis#Handle', |
||||
\ 'executable': {b -> ale#Var(b, 'erlang_elvis_executable')}, |
||||
\ 'command': function('s:GetCommand'), |
||||
\ 'lint_file': 1, |
||||
\}) |
@ -1,11 +1,22 @@ |
||||
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com> |
||||
" Description: Adds support for markdownlint |
||||
|
||||
call ale#Set('markdown_markdownlint_options', '') |
||||
|
||||
function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort |
||||
let l:executable = 'markdownlint' |
||||
|
||||
let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options') |
||||
|
||||
return ale#Escape(l:executable) |
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s' |
||||
endfunction |
||||
|
||||
call ale#linter#Define('markdown', { |
||||
\ 'name': 'markdownlint', |
||||
\ 'executable': 'markdownlint', |
||||
\ 'lint_file': 1, |
||||
\ 'output_stream': 'both', |
||||
\ 'command': 'markdownlint %s', |
||||
\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'), |
||||
\ 'callback': 'ale#handlers#markdownlint#Handle' |
||||
\}) |
||||
|
@ -0,0 +1,32 @@ |
||||
" Author: Eric Stern <eric@ericstern.com>, |
||||
" Arnold Chand <creativenull@outlook.com> |
||||
" Description: Intelephense language server integration for ALE |
||||
|
||||
call ale#Set('php_intelephense_executable', 'intelephense') |
||||
call ale#Set('php_intelephense_use_global', 1) |
||||
call ale#Set('php_intelephense_config', {}) |
||||
|
||||
function! ale_linters#php#intelephense#GetProjectRoot(buffer) abort |
||||
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') |
||||
|
||||
if (!empty(l:composer_path)) |
||||
return fnamemodify(l:composer_path, ':h') |
||||
endif |
||||
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') |
||||
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : '' |
||||
endfunction |
||||
|
||||
function! ale_linters#php#intelephense#GetInitializationOptions() abort |
||||
return ale#Get('php_intelephense_config') |
||||
endfunction |
||||
|
||||
call ale#linter#Define('php', { |
||||
\ 'name': 'intelephense', |
||||
\ 'lsp': 'stdio', |
||||
\ 'initialization_options': function('ale_linters#php#intelephense#GetInitializationOptions'), |
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_intelephense', [])}, |
||||
\ 'command': '%e --stdio', |
||||
\ 'project_root': function('ale_linters#php#intelephense#GetProjectRoot'), |
||||
\}) |
@ -0,0 +1,80 @@ |
||||
" Author: Jose Soto <jose@tighten.co> |
||||
" |
||||
" Description: Tighten Opinionated PHP Linting |
||||
" Website: https://github.com/tightenco/tlint |
||||
|
||||
call ale#Set('php_tlint_executable', 'tlint') |
||||
call ale#Set('php_tlint_use_global', get(g:, 'ale_use_global_executables', 0)) |
||||
call ale#Set('php_tlint_options', '') |
||||
|
||||
function! ale_linters#php#tlint#GetProjectRoot(buffer) abort |
||||
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') |
||||
|
||||
if !empty(l:composer_path) |
||||
return fnamemodify(l:composer_path, ':h') |
||||
endif |
||||
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') |
||||
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : '' |
||||
endfunction |
||||
|
||||
function! ale_linters#php#tlint#GetExecutable(buffer) abort |
||||
return ale#node#FindExecutable(a:buffer, 'php_tlint', [ |
||||
\ 'vendor/bin/tlint', |
||||
\ 'tlint', |
||||
\]) |
||||
endfunction |
||||
|
||||
function! ale_linters#php#tlint#GetCommand(buffer) abort |
||||
let l:executable = ale_linters#php#tlint#GetExecutable(a:buffer) |
||||
let l:options = ale#Var(a:buffer, 'php_tlint_options') |
||||
|
||||
return ale#node#Executable(a:buffer, l:executable) |
||||
\ . (!empty(l:options) ? ' ' . l:options : '') |
||||
\ . ' lint %s' |
||||
endfunction |
||||
|
||||
function! ale_linters#php#tlint#Handle(buffer, lines) abort |
||||
" Matches against lines like the following: |
||||
" |
||||
" ! There should be 1 space around `.` concatenations, and additional lines should always start with a `.` |
||||
" 22 : ` $something = 'a'.'name';` |
||||
" |
||||
let l:loop_count = 0 |
||||
let l:messages_pattern = '^\! \(.*\)' |
||||
let l:output = [] |
||||
let l:pattern = '^\(\d\+\) \:' |
||||
let l:temp_messages = [] |
||||
|
||||
for l:message in ale#util#GetMatches(a:lines, l:messages_pattern) |
||||
call add(l:temp_messages, l:message) |
||||
endfor |
||||
|
||||
let l:loop_count = 0 |
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern) |
||||
let l:num = l:match[1] |
||||
let l:text = l:temp_messages[l:loop_count] |
||||
|
||||
call add(l:output, { |
||||
\ 'lnum': l:num, |
||||
\ 'col': 0, |
||||
\ 'text': l:text, |
||||
\ 'type': 'W', |
||||
\ 'sub_type': 'style', |
||||
\}) |
||||
|
||||
let l:loop_count += 1 |
||||
endfor |
||||
|
||||
return l:output |
||||
endfunction |
||||
|
||||
call ale#linter#Define('php', { |
||||
\ 'name': 'tlint', |
||||
\ 'executable': function('ale_linters#php#tlint#GetExecutable'), |
||||
\ 'command': function('ale_linters#php#tlint#GetCommand'), |
||||
\ 'callback': 'ale_linters#php#tlint#Handle', |
||||
\ 'project_root': function('ale_linters#php#tlint#GetProjectRoot'), |
||||
\}) |
@ -0,0 +1,34 @@ |
||||
" Author: Dalius Dobravolskas <dalius.dobravolskas@gmail.com> |
||||
" Description: https://github.com/pappasam/jedi-language-server |
||||
|
||||
call ale#Set('python_jedils_executable', 'jedi-language-server') |
||||
call ale#Set('python_jedils_use_global', get(g:, 'ale_use_global_executables', 0)) |
||||
call ale#Set('python_jedils_auto_pipenv', 0) |
||||
|
||||
function! ale_linters#python#jedils#GetExecutable(buffer) abort |
||||
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_jedils_auto_pipenv')) |
||||
\ && ale#python#PipenvPresent(a:buffer) |
||||
return 'pipenv' |
||||
endif |
||||
|
||||
return ale#python#FindExecutable(a:buffer, 'python_jedils', ['jedi-language-server']) |
||||
endfunction |
||||
|
||||
function! ale_linters#python#jedils#GetCommand(buffer) abort |
||||
let l:executable = ale_linters#python#jedils#GetExecutable(a:buffer) |
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$' |
||||
\ ? ' run jedi-language-server' |
||||
\ : '' |
||||
|
||||
return ale#Escape(l:executable) . l:exec_args |
||||
endfunction |
||||
|
||||
call ale#linter#Define('python', { |
||||
\ 'name': 'jedils', |
||||
\ 'lsp': 'stdio', |
||||
\ 'executable': function('ale_linters#python#jedils#GetExecutable'), |
||||
\ 'command': function('ale_linters#python#jedils#GetCommand'), |
||||
\ 'project_root': function('ale#python#FindProjectRoot'), |
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter', |
||||
\}) |
@ -0,0 +1,43 @@ |
||||
call ale#Set('python_pyright_executable', 'pyright-langserver') |
||||
call ale#Set('python_pyright_config', {}) |
||||
|
||||
function! ale_linters#python#pyright#GetConfig(buffer) abort |
||||
let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config')) |
||||
|
||||
if !has_key(l:config, 'python') |
||||
let l:config.python = {} |
||||
endif |
||||
|
||||
if type(l:config.python) is v:t_dict |
||||
" Automatically detect the virtualenv path and use it. |
||||
if !has_key(l:config.python, 'venvPath') |
||||
let l:venv = ale#python#FindVirtualenv(a:buffer) |
||||
|
||||
if !empty(l:venv) |
||||
let l:config.python.venvPath = l:venv |
||||
endif |
||||
endif |
||||
|
||||
" Automatically use the version of Python in virtualenv. |
||||
if type(get(l:config.python, 'venvPath')) is v:t_string |
||||
\&& !empty(l:config.python.venvPath) |
||||
\&& !has_key(l:config.python, 'pythonPath') |
||||
let l:config.python.pythonPath = ale#path#Simplify( |
||||
\ l:config.python.venvPath |
||||
\ . (has('win32') ? '/Scripts/python' : '/bin/python') |
||||
\) |
||||
endif |
||||
endif |
||||
|
||||
return l:config |
||||
endfunction |
||||
|
||||
call ale#linter#Define('python', { |
||||
\ 'name': 'pyright', |
||||
\ 'lsp': 'stdio', |
||||
\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')}, |
||||
\ 'command': '%e --stdio', |
||||
\ 'project_root': function('ale#python#FindProjectRoot'), |
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter', |
||||
\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'), |
||||
\}) |
@ -0,0 +1,26 @@ |
||||
" Author: Eric Zhao <21zhaoe@protonmail.com> |
||||
" Description: Implementation of the Language Server Protocol for R. |
||||
|
||||
call ale#Set('r_languageserver_cmd', 'languageserver::run()') |
||||
call ale#Set('r_languageserver_config', {}) |
||||
|
||||
function! ale_linters#r#languageserver#GetCommand(buffer) abort |
||||
let l:cmd_string = ale#Var(a:buffer, 'r_languageserver_cmd') |
||||
|
||||
return 'Rscript --vanilla -e ' . ale#Escape(l:cmd_string) |
||||
endfunction |
||||
|
||||
function! ale_linters#r#languageserver#GetProjectRoot(buffer) abort |
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, '.Rprofile') |
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : fnamemodify(a:buffer, ':h') |
||||
endfunction |
||||
|
||||
call ale#linter#Define('r', { |
||||
\ 'name': 'languageserver', |
||||
\ 'lsp': 'stdio', |
||||
\ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')}, |
||||
\ 'executable': 'Rscript', |
||||
\ 'command': function('ale_linters#r#languageserver#GetCommand'), |
||||
\ 'project_root': function('ale_linters#r#languageserver#GetProjectRoot') |
||||
\}) |