dense-analysis / dense-analysis/ale

Fixers + nvim + split windows causes jumps

Open
#4,735 3 comments 1 reaction 0 assignees View on GitHub
bug
Dominant language
Vim Script
Stars
14k
Forks
1.5k
Avg merge
17h 49m
Merged PRs (30d)
1

Description

## Information

**VIM version**

```
NVIM v0.9.5
Build type: Release
```
Also reproduced on

```
NVIM v0.9.1
Build type: Release
```

Operating System:

macOS Sonoma versions 14.2 + 14.3.1

## What went wrong

In neovim, if I have a split buffer and run `:ALEFix` (either directly or on save with `g:ale_fix_on_save=1`) then the cursor will jump to the top of the non-focused buffer. This can be very annoying since frequently when working on larger files I make use of split buffers so I can reference one part of the file while working on another part of that same file.

The same issue is not present when using vim.

~I believe this was caused by https://github.com/dense-analysis/ale/pull/3974, since everything worked as expected when I removed these changes locally (I just updated `autoload/ale/util.vim` to call `setbufline(a:buffer, 1, l:new_lines)` for both vim and nvim).~
**EDIT:** I think I misspoke here. I am still seeing the same issue in certain cases even after removing the changes I mentioned above. Specifically I was seeing this issue on both of my main machines, and while removing the above changes appears to have resolved the problems on one of them I am still seeing problems on the other.

## Reproducing the bug

1. Open a file with a filetype you have a fixer registered for
2. Navigate to a specific line
3. Split the buffer (either horizontally or vertically)
4. In the new buffer, make some changes
5. Save and run `:ALEFix`
6. Observe that the cursor stays in the correct place in the new buffer, but in the original buffer it jumps to the top

Below is a screen recording of this unexpected behaviour in neovim for a python file where I have `black` as a fixer, but I have had the same issue with other filetypes+fixers (specifically was having issues with `ocaml` + `ocamlformat` as well):

![nvim-ale-fix](https://github.com/dense-analysis/ale/assets/33360408/eaeb96dd-7979-4c96-8f5f-969756c0041f)

### :ALEInfo

Expand
Current Filetype: python
Available Linters: ['bandit', 'cspell', 'flake8', 'flakehell', 'jedils', 'mypy', 'prospector', 'pycln', 'pycodestyle', 'pydocstyle', 'pyflakes', 'pylama', 'pylint', 'pylsp', 'pyre', 'pyright', 'refurb', 'ruff', 'unimport', 'vulture']
Linter Aliases:
'jedils' -> ['jedi_language_server']
Enabled Linters: ['flake8', 'mypy', 'pylint', 'pyright', 'ruff']
Ignored Linters: ['pyright']
Suggested Fixers:
'add_blank_lines_for_python_control_statements' - Add blank lines before control statements.
'autoflake' - Fix flake issues with autoflake.
'autoimport' - Fix import issues with autoimport.
'autopep8' - Fix PEP8 issues with autopep8.
'black' - Fix PEP8 issues with black.
'isort' - Sort Python imports with isort.
'pycln' - remove unused python import statements
'pyflyby' - Tidy Python imports with pyflyby.
'remove_trailing_lines' - Remove all blank lines at the end of a file.
'reorder-python-imports' - Sort Python imports with reorder-python-imports.
'ruff' - A python linter/fixer for Python written in Rust
'ruff_format' - Fix python files with the ruff formatter.
'trim_whitespace' - Remove all trailing whitespace characters at the end of every line.
'yapf' - Fix Python files with yapf.

Linter Variables:
let g:ale_python_auto_pipenv = 0
let g:ale_python_auto_poetry = 0
let g:ale_python_auto_virtualenv = 0
let g:ale_python_black_auto_pipenv = 0
let g:ale_python_black_auto_poetry = 0
let g:ale_python_black_change_directory = 1
let g:ale_python_black_executable = 'black'
let g:ale_python_black_options = ''
let g:ale_python_black_use_global = 0
let g:ale_python_flake8_auto_pipenv = 0
let g:ale_python_flake8_auto_poetry = 0
let g:ale_python_flake8_change_directory = 'project'
let g:ale_python_flake8_executable = 'flake8'
let g:ale_python_flake8_options = '--max-line-length=90'
let g:ale_python_flake8_use_global = 0
let g:ale_python_isort_auto_pipenv = 0
let g:ale_python_isort_auto_poetry = 0
let g:ale_python_isort_executable = 'isort'
let g:ale_python_isort_options = ''
let g:ale_python_isort_use_global = 0
let g:ale_python_mypy_auto_pipenv = 0
let g:ale_python_mypy_auto_poetry = 0
let g:ale_python_mypy_executable = 'mypy'
let g:ale_python_mypy_ignore_invalid_syntax = 0
let g:ale_python_mypy_options = '--ignore-missing-imports'
let g:ale_python_mypy_show_notes = 1
let g:ale_python_mypy_use_global = 0
let g:ale_python_pylint_auto_pipenv = 0
let g:ale_python_pylint_auto_poetry = 0
let g:ale_python_pylint_change_directory = 1
let g:ale_python_pylint_executable = 'python3'
let g:ale_python_pylint_options = ''
let g:ale_python_pylint_use_global = 0
let g:ale_python_pylint_use_msg_id = 0
let g:ale_python_pyright_auto_pipenv = 0
let g:ale_python_pyright_auto_poetry = 0
let g:ale_python_pyright_config = {}
let g:ale_python_pyright_executable = 'pyright-langserver'
let g:ale_python_pyright_use_global = 0
let g:ale_python_ruff_auto_pipenv = 0
let g:ale_python_ruff_auto_poetry = 0
let g:ale_python_ruff_change_directory = 1
let g:ale_python_ruff_executable = 'ruff'
let g:ale_python_ruff_options = ''
let g:ale_python_ruff_use_global = 0

Global Variables:
let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = v:null
let g:ale_command_wrapper = ''
let g:ale_completion_delay = v:null
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = v:null
let g:ale_disable_lsp = 1
let g:ale_echo_cursor = 1
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 = 0
let g:ale_fixers = {'cpp': ['clang-format'], 'lisp': ['scmindent'], 'typescript': ['prettier'], 'dune': ['scmindent'], 'go': [], 'haskell': ['hindent'], 'ocaml': ['ocamlformat'], 'python': ['isort', 'black'], 'racket': ['scmindent'], 'c': ['clang-format'], 'proto': ['clang-format'], 'typescriptreact': ['prettier'], 'rust': ['rustfmt'], 'javascript': ['eslint', 'prettier'], 'swift': ['swiftformat'], 'arduino': ['clang-format']}
let g:ale_history_enabled = 1
let g:ale_info_default_mode = 'preview'
let g:ale_history_log_output = 1
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_filetype_changed = 1
let g:ale_lint_on_insert_leave = 0
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'never'
let g:ale_linter_aliases = {}
let g:ale_linters = {'swift': ['swiftlint', 'sourcekitlsp'], 'go': ['golangci-lint', 'staticcheck'], 'haskell': ['stack_build', 'stack_ghc'], 'rust': ['cargo'], 'javascript': ['eslint'], 'ocaml': ['merlin']}
let g:ale_linters_explicit = 0
let g:ale_linters_ignore = {}
let g:ale_list_vertical = 0
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 = v:null
let g:ale_maximum_file_size = v:null
let g:ale_open_list = 0
let g:ale_pattern_options = v:null
let g:ale_pattern_options_enabled = v:null
let g:ale_root = {}
let g:ale_set_balloons = 0
let g:ale_set_highlights = 0
let g:ale_set_loclist = 1
let g:ale_set_quickfix = 0
let g:ale_set_signs = 1
let g:ale_sign_column_always = v:null
let g:ale_sign_error = '>>'
let g:ale_sign_info = '--'
let g:ale_sign_offset = v:null
let g:ale_sign_style_error = v:null
let g:ale_sign_style_warning = v:null
let g:ale_sign_warning = v:null
let g:ale_sign_highlight_linenrs = v:null
let g:ale_type_map = {}
let g:ale_use_neovim_diagnostics_api = 1
let g:ale_use_global_executables = v:null
let g:ale_virtualtext_cursor = 'disabled'
let g:ale_warn_about_trailing_blank_lines = 1
let g:ale_warn_about_trailing_whitespace = 1

Command History:

(finished - exit code 0) ['/bin/zsh', '-c', '''python3'' --version']

<<>>
Python 3.12.1
<<>>

(executable check - failure) flake8
(executable check - failure) mypy
(executable check - success) python3
(finished - exit code 2) ['/bin/zsh', '-c', 'cd ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R'' && ''python3'' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n --from-stdin ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R/main.py'' < ''/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/nvim.shawnogrady/BPNAka/1/main.py''']

<<>>

(executable check - failure) ruff
(finished - exit code 127) ['/bin/zsh', '-c', '''isort'' --version']

<<>>
zsh:1: command not found: isort
<<>>

(finished - exit code 127) ['/bin/zsh', '-c', 'cd ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R'' && ''isort'' - < ''/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/nvim.shawnogrady/BPNAka/2/main.py''']
(finished - exit code 0) ['/bin/zsh', '-c', 'cd ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R'' && ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R/venv/bin/black'' - < ''/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/nvim.shawnogrady/BPNAka/3/main.py''']
(executable check - failure) flake8
(executable check - failure) mypy
(finished - exit code 2) ['/bin/zsh', '-c', 'cd ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R'' && ''python3'' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n --from-stdin ''/private/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/tmp.sM8ApdKB2R/main.py'' < ''/var/folders/b_/vg2rgw4x02x3m2rlpyp837p40000gn/T/nvim.shawnogrady/BPNAka/4/main.py''']

<<>>

(executable check - failure) ruff

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the split-window behavior with Neovim and :ALEFix, using the six-step scenario in the issue. Inspect autoload/ale/util.vim, the file mentioned in the report, and compare the behavior with Vim. Done means fixing the cursor jump in the non-focused split while preserving the correct cursor position in the focused buffer.

Written by the indexing model from the issue text.

Assessment

Tech stack
vim
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.