aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAndrew Wray2025-06-25 20:50:15 +0100
committerAndrew Wray2025-06-25 20:50:15 +0100
commit0b0f8d91bce18dbd452b6763f4b7c9f893c964d9 (patch)
tree123293a5af6800ac49fda0696eb41802316f33df
parent9e49019a2683bff012d53f28546ff968075ea3b9 (diff)
downloadale-codex/update-ale-to-prefer-ale_root-setting.tar.gz

Prefer ale_root setting for project roots

codex/update-ale-to-prefer-ale_root-setting
-rw-r--r--ale_linters/python/pylsp.vim2
-rw-r--r--ale_linters/python/pyright.vim2
-rw-r--r--autoload/ale/assert.vim2
-rw-r--r--autoload/ale/linter.vim29
-rw-r--r--autoload/ale/lsp_linter.vim40
-rw-r--r--autoload/ale/python.vim6
-rw-r--r--doc/ale-python.txt3
-rw-r--r--doc/ale.txt17
-rw-r--r--test/test_linter_defintion_processing.vader4
-rw-r--r--test/test_python_root_option.vader27
10 files changed, 80 insertions, 52 deletions
diff --git a/ale_linters/python/pylsp.vim b/ale_linters/python/pylsp.vim
index 75ec38842..d6867154e 100644
--- a/ale_linters/python/pylsp.vim
+++ b/ale_linters/python/pylsp.vim
@@ -36,7 +36,7 @@ function! ale_linters#python#pylsp#GetCwd(buffer) abort
\ 'name': 'pylsp',
\ 'project_root': function('ale#python#FindProjectRoot'),
\}
- let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter)
+ let l:root = ale#linter#GetRoot(a:buffer, l:fake_linter)
return !empty(l:root) ? l:root : v:null
endfunction
diff --git a/ale_linters/python/pyright.vim b/ale_linters/python/pyright.vim
index 95443a139..88aafb587 100644
--- a/ale_linters/python/pyright.vim
+++ b/ale_linters/python/pyright.vim
@@ -13,7 +13,7 @@ function! ale_linters#python#pyright#GetCwd(buffer) abort
\ 'name': 'pyright',
\ 'project_root': function('ale#python#FindProjectRoot'),
\}
- let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter)
+ let l:root = ale#linter#GetRoot(a:buffer, l:fake_linter)
return !empty(l:root) ? l:root : v:null
endfunction
diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim
index c5157dbae..f3ad34a02 100644
--- a/autoload/ale/assert.vim
+++ b/autoload/ale/assert.vim
@@ -216,7 +216,7 @@ endfunction
function! ale#assert#LSPProject(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
- let l:root = ale#lsp_linter#FindProjectRoot(l:buffer, l:linter)
+ let l:root = ale#linter#GetRoot(l:buffer, l:linter)
AssertEqual a:expected_root, l:root
endfunction
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index 65c5dd0dd..497b8c0ea 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -447,3 +447,32 @@ function! ale#linter#GetAddress(buffer, linter) abort
return type(l:Address) is v:t_func ? l:Address(a:buffer) : l:Address
endfunction
+
+" Get the project root for a linter.
+" If |b:ale_root| or |g:ale_root| is set to either a String or a Dict mapping
+" linter names to roots or callbacks, return that value immediately. When no
+" value is available, fall back to the linter-specific configuration.
+function! ale#linter#GetRoot(buffer, linter) abort
+ let l:buffer_ale_root = getbufvar(a:buffer, 'ale_root', {})
+
+ if type(l:buffer_ale_root) is v:t_string
+ return l:buffer_ale_root
+ endif
+
+ if has_key(l:buffer_ale_root, a:linter.name)
+ let l:Root = l:buffer_ale_root[a:linter.name]
+ return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root
+ endif
+
+ if has_key(g:ale_root, a:linter.name)
+ let l:Root = g:ale_root[a:linter.name]
+ return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root
+ endif
+
+ if has_key(a:linter, 'project_root')
+ let l:Root = a:linter.project_root
+ return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root
+ endif
+
+ return ''
+endfunction
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 3b3c403c6..0322287c3 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -296,44 +296,6 @@ function! ale#lsp_linter#GetConfig(buffer, linter) abort
return {}
endfunction
-function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
- let l:buffer_ale_root = getbufvar(a:buffer, 'ale_root', {})
-
- if type(l:buffer_ale_root) is v:t_string
- return l:buffer_ale_root
- endif
-
- " Try to get a buffer-local setting for the root
- if has_key(l:buffer_ale_root, a:linter.name)
- let l:Root = l:buffer_ale_root[a:linter.name]
-
- if type(l:Root) is v:t_func
- return l:Root(a:buffer)
- else
- return l:Root
- endif
- endif
-
- " Try to get a global setting for the root
- if has_key(g:ale_root, a:linter.name)
- let l:Root = g:ale_root[a:linter.name]
-
- if type(l:Root) is v:t_func
- return l:Root(a:buffer)
- else
- return l:Root
- endif
- endif
-
- " Fall back to the linter-specific configuration
- if has_key(a:linter, 'project_root')
- let l:Root = a:linter.project_root
-
- return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root
- endif
-
- return ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
-endfunction
" This function is accessible so tests can call it.
function! ale#lsp_linter#OnInit(linter, details, Callback) abort
@@ -504,7 +466,7 @@ endfunction
function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let l:command = ''
let l:address = ''
- let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter)
+ let l:root = ale#linter#GetRoot(a:buffer, a:linter)
if empty(l:root) && a:linter.lsp isnot# 'tsserver'
" If there's no project root, then we can't check files with LSP,
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index 81ab6eb78..92cf2d2a4 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -61,6 +61,12 @@ endfunction
" through paths, including the current directory, until no __init__.py files
" is found.
function! ale#python#FindProjectRoot(buffer) abort
+ let l:root = ale#linter#GetRoot(a:buffer, {'name': 'python'})
+
+ if !empty(l:root)
+ return l:root
+ endif
+
let l:ini_root = ale#python#FindProjectRootIni(a:buffer)
if !empty(l:ini_root)
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index 3a4cedf76..82e765818 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -55,6 +55,9 @@ For some linters, ALE will search for a Python project root by looking at the
files in directories on or above where a file being checked is. ALE applies
the following methods, in order:
+If |g:ale_root| or |b:ale_root| provides a value, that value is used as the
+project root instead and the searching described below is skipped.
+
1. Find the first directory containing a common Python configuration file.
2. If no configuration file can be found, use the first directory which does
not contain a readable file named `__init__.py`.
diff --git a/doc/ale.txt b/doc/ale.txt
index e508f769c..44b3b9302 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -2297,17 +2297,18 @@ g:ale_root
Type: |Dictionary| or |String|
Default: `{}`
- This option is used to determine the project root for a linter. If the value
- is a |Dictionary|, it maps a linter to either a |String| containing the
- project root or a |Funcref| to call to look up the root. The |Funcref| is
- provided the buffer number as its argument.
+ This option is used to determine the project root for a linter. When set to a
+ |String| it will be used for all linters. When set to a |Dictionary|, the
+ keys are linter names and the values are either |Strings| containing project
+ roots or |Funcref|s which are passed the buffer number.
- The buffer-specific variable may additionally be a string containing the
+ The buffer-specific variable may additionally be a |String| containing the
project root itself.
- If neither variable yields a result, a linter-specific function is invoked to
- detect a project root. If this, too, yields no result, and the linter is an
- LSP linter, it will not run.
+ If a value can be found from either variable, ALE uses it directly and skips
+ searching for a project root. If no value is found, a linter-specific
+ function is invoked to detect a project root. If this, too, yields no result
+ and the linter is an LSP linter, it will not run.
*ale-options.save_hidden*
*g:ale_save_hidden*
diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader
index 4c096a5e0..df9cbf675 100644
--- a/test/test_linter_defintion_processing.vader
+++ b/test/test_linter_defintion_processing.vader
@@ -407,7 +407,7 @@ Execute(PreProcess should allow the `project_root` to be set as a String):
\ 'project_root': '/foo/bar',
\})
- AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter)
+ AssertEqual '/foo/bar', ale#linter#GetRoot(0, g:linter)
Execute(PreProcess should `project_root` be set as a Function):
let g:linter = ale#linter#PreProcess('testft', {
@@ -418,7 +418,7 @@ Execute(PreProcess should `project_root` be set as a Function):
\ 'project_root': {-> '/foo/bar'},
\})
- AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter)
+ AssertEqual '/foo/bar', ale#linter#GetRoot(0, g:linter)
Execute(PreProcess should complain when `project_root` is invalid):
AssertThrows call ale#linter#PreProcess('testft', {
diff --git a/test/test_python_root_option.vader b/test/test_python_root_option.vader
new file mode 100644
index 000000000..f8ab88fc2
--- /dev/null
+++ b/test/test_python_root_option.vader
@@ -0,0 +1,27 @@
+Before:
+ Save g:ale_root
+ Save b:ale_root
+ call ale#test#SetDirectory('/testplugin/test')
+
+After:
+ Restore
+ call ale#test#RestoreDirectory()
+
+Execute(The global setting is used as the project root):
+ let g:ale_root = '/foo/python'
+ call ale#test#SetFilename('test-files/python/no_virtualenv/subdir/foo/bar.py')
+ AssertEqual '/foo/python', ale#python#FindProjectRoot(bufnr(''))
+
+Execute(The buffer setting overrides the global setting):
+ let g:ale_root = '/foo/python'
+ let b:ale_root = '/bar/python'
+ call ale#test#SetFilename('test-files/python/no_virtualenv/subdir/foo/bar.py')
+ AssertEqual '/bar/python', ale#python#FindProjectRoot(bufnr(''))
+
+Execute(Fallback to searching when no setting is used):
+ unlet! g:ale_root
+ unlet! b:ale_root
+ call ale#test#SetFilename('test-files/python/no_virtualenv/subdir/foo/bar.py')
+ AssertEqual \
+ \ ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir'),
+ \ ale#python#FindProjectRoot(bufnr(''))