dense-analysis / ale

Check syntax in Vim/Neovim asynchronously and fix files, with Language Server Protocol (LSP) support
BSD 2-Clause "Simplified" License
13.53k stars 1.43k forks source link

Right-click menu glitches in console vim #3527

Open liskin opened 3 years ago

liskin commented 3 years ago

Information

VIM version

VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Nov 19 2020 07:49:24)
Included patches: 1-1913

Operating System: Debian testing

What went wrong

The right-click popup menu in console (not gui) vim glitches because of two bugs/limitations in upstream vim:

https://user-images.githubusercontent.com/300342/103799763-d1596c80-504b-11eb-81f2-307e44fd6f51.mp4

The first issue is that the second entry is not Refactor... but (None) when opened for the first time and some old memory contents for the second time. The illegal memory access was fixed in https://github.com/vim/vim/commit/38455a921395a56690790c8c1d28c1c43ca04c8a, but the menu still isn't supposed to be updated asynchronously. Bram says:

You are not supposed to change the menu while it's being displayed. In the GUI this may work, because it uses the library functions of the GUI library. In the console we display the menu and it won't be updated dynamically. The only thing the patch does is avoid crashing when the menu is changed anyway.

ale doesn't change the number of entries in the PopUp menu itself, so with https://github.com/vim/vim/commit/38455a921395a56690790c8c1d28c1c43ca04c8a it should more or less work, but it'd still be better to do this synchronously, I think, just to be safe and to fix this in older versions of vim.

The second issue is better illustrated when running in vim with https://github.com/vim/vim/issues/7537 fixed:

https://user-images.githubusercontent.com/300342/103801429-036bce00-504e-11eb-9ec1-3d562c0c724f.mp4

Now the Refactor... entry is visible but it doesn't act as a submenu, so no refactors can be done in console vim. There is no reply in https://github.com/vim/vim/issues/7539 yet, but I did found a workaround:

anoremenu <silent> PopUp.Refactor\.\.\. :popup PopUp.Refactor<CR>
anoremenu <silent> PopUp.Refactor.A :echo "a"<CR>
anoremenu <silent> PopUp.Refactor.B :echo "b"<CR>
menu disable PopUp.Refactor

Both menus are visible in gvim, so this workaround must be only used in console vim.

Reproducing the bug

  1. Enable right-click popups:

    set nocompatible
    set mouse=a
    set mousemodel=popup_setpos
  2. Run vim with ale where some LSP is available & enabled.

  3. Right click somewhere.

  4. Popup appears, but the second entry is either corrupt (without https://github.com/vim/vim/issues/7537 fix) or not functional (with the fix but with https://github.com/vim/vim/issues/7539 still present).

:ALEInfo


 Current Filetype: python
Available Linters: ['bandit', 'flake8', 'jedils', 'mypy', 'prospector', 'pycodestyle', 'pydocstyle', 'pyflakes', 'pylama', 'pylint', 'pyls', 'pyre', 'pyright', 'vulture']
  Enabled Linters: ['flake8', 'pyls']
  Ignored Linters: []
 Suggested Fixers: 
  'add_blank_lines_for_python_control_statements' - Add blank lines before control statements.
  'autoimport' - Fix import issues with autoimport.
  'autopep8' - Fix PEP8 issues with autopep8.
  'black' - Fix PEP8 issues with black.
  'isort' - Sort Python imports with isort.
  'remove_trailing_lines' - Remove all blank lines at the end of a file.
  'reorder-python-imports' - Sort Python imports with reorder-python-imports.
  '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_flake8_auto_pipenv = 0
let g:ale_python_flake8_change_directory = 'project'
let g:ale_python_flake8_executable = 'flake8'
let g:ale_python_flake8_options = ''
let g:ale_python_flake8_use_global = 0
let g:ale_python_pyls_auto_pipenv = 0
let g:ale_python_pyls_config = {'pyls': {'configurationSources': ['flake8']}}
let g:ale_python_pyls_executable = 'pyls'
let g:ale_python_pyls_use_global = 0
 Global Variables:

let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = 0
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 = 0
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 = 1
let g:ale_fixers = {'elixir': ['mix_format']}
let g:ale_history_enabled = 1
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 = 0
let g:ale_linter_aliases = {'gitcommit': ['mail']}
let g:ale_linters = {'elixir': [], 'markdown': ['proselint'], 'rst': ['proselint'], 'sh': ['shellcheck'], 'mail': ['proselint'], 'gitcommit': ['proselint'], 'python': ['flake8', 'pyls'], 'text': ['proselint']}
let g:ale_linters_explicit = 1
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_lsp_root = {}
let g:ale_max_buffer_history_size = 20
let g:ale_max_signs = -1
let g:ale_maximum_file_size = 524288
let g:ale_open_list = 0
let g:ale_pattern_options = v:null
let g:ale_pattern_options_enabled = v:null
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 = 0
let g:ale_sign_error = '>>'
let g:ale_sign_info = '--'
let g:ale_sign_offset = 1000000
let g:ale_sign_style_error = '>>'
let g:ale_sign_style_warning = '--'
let g:ale_sign_warning = '--'
let g:ale_sign_highlight_linenrs = 0
let g:ale_statusline_format = v:null
let g:ale_type_map = {}
let g:ale_use_global_executables = v:null
let g:ale_virtualtext_cursor = 0
let g:ale_warn_about_trailing_blank_lines = 1
let g:ale_warn_about_trailing_whitespace = 1
  Command History:

(executable check - success) pyls
(executable check - success) flake8
(finished - exit code 0) ['/bin/bash', '-c', '''flake8'' --version']

<<<OUTPUT STARTS>>>
3.8.4 (mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.9.1 on Linux
<<<OUTPUT ENDS>>>

(finished - exit code 0) ['/bin/bash', '-c', 'cd ''/home/tomi/bin'' && ''flake8'' --format=default --stdin-display-name ''/home/tomi/bin/battery-watch'' - < ''/tmp/vpdXP0C/1/battery-watch''']

<<<NO OUTPUT RETURNED>>>

(started) ['/bin/bash', '-c', '''pyls''']
w0rp commented 3 years ago

I added a sentence to the documentation now saying to only turn the popup menu support on for GUI versions of Vim. The default setting is based on has('gui_running'), so it should only run in GUI Vim by default.

liskin commented 3 years ago

Oh. :-/

If I ever figure out how to do the menu setup synchronously and add the nested menu workaround, will you be interested in a PR or shall I carry this in my local fork?

w0rp commented 3 years ago

If you can put together something reasonable that works, feel free to create a pull request. Putting menu items in the menu synchronously might not work because the available code actions are sent asynchronously from the language servers, but "Rename" could work because we can assume we can just rename any word.

liskin commented 3 years ago

Well it just occurred to me that the nested menu workaround might actually solve both issues: by the time the user selects the submenu, it'll likely already have been populated from the async LSP reply. I'll try that once I get back to hacking on vim stuff. Thanks for your reply, I probably wouldn't get the idea otherwise. :-)

w0rp commented 3 years ago

I'll leave the issue open and you can tag it with your pull request.