Skip to content

Vim hangs when searching for linters (ALE should allow the user to provide stop directories for file searches) #5089

@smaeul

Description

@smaeul

Information

VIM version

VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jan 01 1980 00:00:00)
Included patches: 1-1918

Operating System: Nix on RHEL

What went wrong

On my system, /home is an NFS automounter, and enumerating its contents takes an extremely long time:

$ time ls /home/$USER/node_modules/.bin/vim-language-server
ls: cannot access '/home/$USER/node_modules/.bin/vim-language-server': No such file or directory

real    0m0.009s
user    0m0.001s
sys     0m0.001s

$ time ls /home/node_modules/.bin/vim-language-server
ls: cannot access '/home/node_modules/.bin/vim-language-server': No such file or directory

real    0m25.432s
user    0m0.001s
sys     0m0.001s

Because ALE does an upward search for linters from the buffer file path without using any stop directories, it tries to look for linters in /home, which causes (on my system) a 25.4-second hang every time I try to load or save a file, if ALE cannot find the linter for that file type.

The solution would be to allow the user to specify stop directories (in my case, $HOME) that would be used for all upward finddir and findfile calls.

Reproducing the bug

  1. Install ALE.
  2. Do not install vim-language-server.
  3. Run strace -etrace=file -ostrace.log -tt vim ~/.vimrc.
  4. Run grep -A1 -F /home/node_modules/.bin/vim-language-server strace.log.
16:23:12.662908 newfstatat(AT_FDCWD, "/home/node_modules/.bin/vim-language-server", 0x7ffffffd0ee0, 0) = -1 ENOENT (No such file or directory)
16:23:38.077781 newfstatat(AT_FDCWD, "/", {st_mode=S_IFDIR|0700, st_size=4096, ...}, 0) = 0

On most systems this stat() syscall would be fast, but as you can see, on my system it takes 25.4 seconds. This bug would be fixed if ALE can be configured to stop looking for linters at $HOME, so this slow stat() syscall can be avoided.

:ALEInfo

Expand
 Current Filetype: vim
Available Linters: ['ale_custom_linting_rules', 'vimls', 'vint']
  Enabled Linters: ['ale_custom_linting_rules', 'vimls', 'vint']
  Ignored Linters: []
 Suggested Fixers:
  'remove_trailing_lines' - Remove all blank lines at the end of a file.
  'trim_whitespace' - Remove all trailing whitespace characters at the end of every line.
 
 Linter Variables:
" Press Space to read :help for a setting
let g:ale_vim_vimls_config = {}
let g:ale_vim_vimls_executable = 'vim-language-server'
let g:ale_vim_vimls_use_global = 0
let g:ale_vim_vint_executable = 'vint'
let g:ale_vim_vint_show_style_issues = 1
 
 Global Variables:
" Press Space to read :help for a setting
let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = v:false
let g:ale_command_wrapper = v:null
let g:ale_completion_delay = v:null
let g:ale_completion_enabled = v:false
let g:ale_completion_max_suggestions = v:null
let g:ale_disable_lsp = 'auto'
let g:ale_echo_cursor = v:true
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = '%code: %%s'
let g:ale_echo_msg_info_str = 'Info'
let g:ale_echo_msg_warning_str = 'Warning'
let g:ale_enabled = 1
let g:ale_fix_on_save = v:false
let g:ale_fixers = {}
let g:ale_history_enabled = v:true
let g:ale_info_default_mode = 'preview'
let g:ale_history_log_output = v:true
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = v:true
let g:ale_lint_on_filetype_changed = v:true
let g:ale_lint_on_insert_leave = v:true
let g:ale_lint_on_save = v:true
let g:ale_lint_on_text_changed = 'normal'
let g:ale_linter_aliases = {}
let g:ale_linters = {}
let g:ale_linters_explicit = v:false
let g:ale_linters_ignore = {}
let g:ale_list_vertical = v:false
let g:ale_list_window_size = 10
let g:ale_loclist_msg_format = '%code: %%s'
let g:ale_max_buffer_history_size = 20
let g:ale_max_signs = -1
let g:ale_maximum_file_size = v:null
let g:ale_open_list = v:false
let g:ale_pattern_options = v:null
let g:ale_pattern_options_enabled = v:null
let g:ale_root = {}
let g:ale_set_balloons = v:false
let g:ale_set_highlights = v:true
let g:ale_set_loclist = v:true
let g:ale_set_quickfix = v:false
let g:ale_set_signs = v:true
let g:ale_sign_column_always = v:false
let g:ale_sign_error = 'E'
let g:ale_sign_info = 'I'
let g:ale_sign_offset = 1000000
let g:ale_sign_style_error = 'E'
let g:ale_sign_style_warning = 'W'
let g:ale_sign_warning = 'W'
let g:ale_sign_highlight_linenrs = v:false
let g:ale_type_map = {}
let g:ale_use_neovim_diagnostics_api = v:false
let g:ale_use_global_executables = v:null
let g:ale_virtualtext_cursor = 'all'
let g:ale_warn_about_trailing_blank_lines = v:true
let g:ale_warn_about_trailing_whitespace = v:true
 
  Command History:

(executable check - failure) vim-language-server
(executable check - failure) vint

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions