aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/scripts/install_deps.sh4
-rw-r--r--.github/scripts/reviewers_add.js10
-rw-r--r--.github/workflows/release.yml4
-rw-r--r--.github/workflows/test.yml4
-rw-r--r--.gitignore1
-rw-r--r--BUILD.md1
-rw-r--r--CMakeLists.txt9
-rw-r--r--MAINTAIN.md2
-rw-r--r--cmake.config/config.h.in3
-rw-r--r--cmake.deps/cmake/GettextCMakeLists.txt23
-rw-r--r--cmake.deps/deps.txt20
-rw-r--r--cmake/FindLpeg.cmake11
-rw-r--r--cmake/Util.cmake22
-rw-r--r--runtime/CMakeLists.txt2
-rw-r--r--runtime/autoload/README.txt2
-rw-r--r--runtime/autoload/netrw.vim1606
-rw-r--r--runtime/autoload/netrwFileHandlers.vim363
-rw-r--r--runtime/autoload/paste.vim2
-rw-r--r--runtime/autoload/tar.vim105
-rw-r--r--runtime/autoload/typst.vim30
-rw-r--r--runtime/autoload/zip.vim4
-rw-r--r--runtime/colors/README.txt3
-rw-r--r--runtime/compiler/cppcheck.vim18
-rw-r--r--runtime/compiler/maven.vim40
-rw-r--r--runtime/compiler/mypy.vim19
-rw-r--r--runtime/compiler/pylint.vim25
-rw-r--r--runtime/compiler/ruff.vim19
-rw-r--r--runtime/doc/api.txt43
-rw-r--r--runtime/doc/autocmd.txt8
-rw-r--r--runtime/doc/builtin.txt44
-rw-r--r--runtime/doc/change.txt2
-rw-r--r--runtime/doc/deprecated.txt21
-rw-r--r--runtime/doc/dev_style.txt5
-rw-r--r--runtime/doc/diagnostic.txt8
-rw-r--r--runtime/doc/editing.txt11
-rw-r--r--runtime/doc/faq.txt2
-rw-r--r--runtime/doc/filetype.txt34
-rw-r--r--runtime/doc/gui.txt1
-rw-r--r--runtime/doc/indent.txt32
-rw-r--r--runtime/doc/insert.txt14
-rw-r--r--runtime/doc/intro.txt2
-rw-r--r--runtime/doc/lsp.txt563
-rw-r--r--runtime/doc/lua-guide.txt4
-rw-r--r--runtime/doc/lua.txt209
-rw-r--r--runtime/doc/map.txt4
-rw-r--r--runtime/doc/news-0.10.txt2
-rw-r--r--runtime/doc/news.txt70
-rw-r--r--runtime/doc/nvim.txt2
-rw-r--r--runtime/doc/options.txt341
-rw-r--r--runtime/doc/pattern.txt36
-rw-r--r--runtime/doc/pi_netrw.txt156
-rw-r--r--runtime/doc/pi_paren.txt19
-rw-r--r--runtime/doc/quickfix.txt28
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/doc/repeat.txt33
-rw-r--r--runtime/doc/support.txt4
-rw-r--r--runtime/doc/syntax.txt74
-rw-r--r--runtime/doc/terminal.txt15
-rw-r--r--runtime/doc/treesitter.txt45
-rw-r--r--runtime/doc/ui.txt17
-rw-r--r--runtime/doc/undo.txt2
-rw-r--r--runtime/doc/usr_10.txt5
-rw-r--r--runtime/doc/usr_41.txt2
-rw-r--r--runtime/doc/various.txt5
-rw-r--r--runtime/doc/vim_diff.txt26
-rw-r--r--runtime/doc/vvars.txt3
-rw-r--r--runtime/doc/windows.txt3
-rw-r--r--runtime/ftplugin/ada.vim2
-rw-r--r--runtime/ftplugin/checkhealth.vim6
-rw-r--r--runtime/ftplugin/cook.vim13
-rw-r--r--runtime/ftplugin/dune.vim3
-rw-r--r--runtime/ftplugin/erlang.vim2
-rw-r--r--runtime/ftplugin/gleam.vim16
-rw-r--r--runtime/ftplugin/idris2.vim34
-rw-r--r--runtime/ftplugin/ipkg.vim19
-rw-r--r--runtime/ftplugin/leo.vim13
-rw-r--r--runtime/ftplugin/llvm.vim12
-rw-r--r--runtime/ftplugin/man.vim6
-rw-r--r--runtime/ftplugin/mlir.vim10
-rw-r--r--runtime/ftplugin/mss.vim16
-rw-r--r--runtime/ftplugin/org.vim37
-rw-r--r--runtime/ftplugin/plaintex.vim2
-rw-r--r--runtime/ftplugin/racket.vim9
-rw-r--r--runtime/ftplugin/spec.vim10
-rw-r--r--runtime/ftplugin/sway.vim15
-rw-r--r--runtime/ftplugin/tex.vim2
-rw-r--r--runtime/ftplugin/typst.vim8
-rw-r--r--runtime/indent/idris2.vim183
-rw-r--r--runtime/indent/racket.vim12
-rw-r--r--runtime/indent/sh.vim6
-rw-r--r--runtime/indent/testdir/bash.in22
-rw-r--r--runtime/indent/testdir/bash.ok22
-rw-r--r--runtime/lua/man.lua3
-rw-r--r--runtime/lua/vim/_buf.lua23
-rw-r--r--runtime/lua/vim/_defaults.lua160
-rw-r--r--runtime/lua/vim/_editor.lua285
-rw-r--r--runtime/lua/vim/_meta.lua2
-rw-r--r--runtime/lua/vim/_meta/api.lua39
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua1
-rw-r--r--runtime/lua/vim/_meta/builtin.lua31
-rw-r--r--runtime/lua/vim/_meta/builtin_types.lua91
-rw-r--r--runtime/lua/vim/_meta/options.lua348
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua43
-rw-r--r--runtime/lua/vim/_meta/vvars.lua3
-rw-r--r--runtime/lua/vim/_options.lua4
-rw-r--r--runtime/lua/vim/_system.lua17
-rw-r--r--runtime/lua/vim/_watch.lua16
-rw-r--r--runtime/lua/vim/diagnostic.lua289
-rw-r--r--runtime/lua/vim/filetype.lua117
-rw-r--r--runtime/lua/vim/filetype/detect.lua13
-rw-r--r--runtime/lua/vim/fs.lua34
-rw-r--r--runtime/lua/vim/func/_memoize.lua6
-rw-r--r--runtime/lua/vim/glob.lua2
-rw-r--r--runtime/lua/vim/hl.lua (renamed from runtime/lua/vim/highlight.lua)26
-rw-r--r--runtime/lua/vim/keymap.lua18
-rw-r--r--runtime/lua/vim/loader.lua443
-rw-r--r--runtime/lua/vim/lsp.lua95
-rw-r--r--runtime/lua/vim/lsp/_dynamic.lua110
-rw-r--r--runtime/lua/vim/lsp/_meta.lua3
-rw-r--r--runtime/lua/vim/lsp/_tagfunc.lua49
-rw-r--r--runtime/lua/vim/lsp/_watchfiles.lua10
-rw-r--r--runtime/lua/vim/lsp/buf.lua702
-rw-r--r--runtime/lua/vim/lsp/client.lua255
-rw-r--r--runtime/lua/vim/lsp/codelens.lua4
-rw-r--r--runtime/lua/vim/lsp/completion.lua70
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua109
-rw-r--r--runtime/lua/vim/lsp/handlers.lua308
-rw-r--r--runtime/lua/vim/lsp/health.lua23
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua33
-rw-r--r--runtime/lua/vim/lsp/log.lua9
-rw-r--r--runtime/lua/vim/lsp/protocol.lua112
-rw-r--r--runtime/lua/vim/lsp/rpc.lua103
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua110
-rw-r--r--runtime/lua/vim/lsp/sync.lua59
-rw-r--r--runtime/lua/vim/lsp/util.lua1101
-rw-r--r--runtime/lua/vim/provider/health.lua2
-rw-r--r--runtime/lua/vim/secure.lua20
-rw-r--r--runtime/lua/vim/shared.lua354
-rw-r--r--runtime/lua/vim/termcap.lua8
-rw-r--r--runtime/lua/vim/treesitter.lua19
-rw-r--r--runtime/lua/vim/treesitter/_meta/tsnode.lua18
-rw-r--r--runtime/lua/vim/treesitter/_query_linter.lua8
-rw-r--r--runtime/lua/vim/treesitter/dev.lua19
-rw-r--r--runtime/lua/vim/treesitter/health.lua18
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua14
-rw-r--r--runtime/lua/vim/treesitter/language.lua21
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua2
-rw-r--r--runtime/lua/vim/treesitter/query.lua2
-rw-r--r--runtime/lua/vim/ui.lua33
-rw-r--r--runtime/macmap.vim75
-rw-r--r--runtime/macros/editexisting.vim119
-rw-r--r--runtime/macros/justify.vim3
-rw-r--r--runtime/macros/matchit.vim2
-rw-r--r--runtime/macros/shellmenu.vim3
-rw-r--r--runtime/macros/swapmous.vim3
-rw-r--r--runtime/menu.vim2
-rw-r--r--runtime/optwin.vim2
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim12
-rw-r--r--runtime/plugin/matchparen.vim17
-rw-r--r--runtime/plugin/netrwPlugin.vim9
-rw-r--r--runtime/scripts/emoji_list.lua (renamed from runtime/tools/emoji_list.lua)0
-rw-r--r--runtime/scripts/less.bat (renamed from runtime/macros/less.bat)4
-rwxr-xr-xruntime/scripts/less.sh (renamed from runtime/macros/less.sh)4
-rw-r--r--runtime/scripts/less.vim (renamed from runtime/macros/less.vim)0
-rw-r--r--runtime/scripts/mswin.vim (renamed from runtime/mswin.vim)0
-rw-r--r--runtime/syntax/8th.vim501
-rw-r--r--runtime/syntax/awk.vim4
-rw-r--r--runtime/syntax/cfg.vim11
-rw-r--r--runtime/syntax/help.vim23
-rw-r--r--runtime/syntax/help_it.vim17
-rw-r--r--runtime/syntax/idris2.vim86
-rw-r--r--runtime/syntax/ipkg.vim66
-rw-r--r--runtime/syntax/java.vim9
-rw-r--r--runtime/syntax/jinja.vim3
-rw-r--r--runtime/syntax/lf.vim236
-rw-r--r--runtime/syntax/lidris2.vim25
-rw-r--r--runtime/syntax/modula2/opt/r10.vim2
-rw-r--r--runtime/syntax/mss.vim23
-rw-r--r--runtime/syntax/nasm.vim1009
-rw-r--r--runtime/syntax/neomuttlog.vim69
-rw-r--r--runtime/syntax/neomuttrc.vim701
-rw-r--r--runtime/syntax/org.vim71
-rw-r--r--runtime/syntax/racket.vim4
-rw-r--r--runtime/syntax/shared/debversions.vim8
-rw-r--r--runtime/syntax/skill.vim5
-rw-r--r--runtime/syntax/structurizr.vim37
-rw-r--r--runtime/syntax/swayconfig.vim4
-rw-r--r--runtime/syntax/tex.vim6
-rw-r--r--runtime/syntax/typst.vim6
-rw-r--r--runtime/syntax/vim.vim181
-rw-r--r--runtime/tools/check_colors.vim252
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor8
-rwxr-xr-xscripts/bump_deps.lua6
-rwxr-xr-xscripts/gen_eval_files.lua14
-rw-r--r--scripts/gen_help_html.lua75
-rw-r--r--scripts/gen_lsp.lua43
-rwxr-xr-xscripts/gen_vimdoc.lua9
-rwxr-xr-xscripts/vim-patch.sh4
-rw-r--r--src/nvim/CMakeLists.txt20
-rw-r--r--src/nvim/api/deprecated.c40
-rw-r--r--src/nvim/api/extmark.c24
-rw-r--r--src/nvim/api/keysets_defs.h1
-rw-r--r--src/nvim/api/options.c55
-rw-r--r--src/nvim/api/private/helpers.c27
-rw-r--r--src/nvim/api/private/helpers.h6
-rw-r--r--src/nvim/api/ui_events.in.h4
-rw-r--r--src/nvim/api/vim.c64
-rw-r--r--src/nvim/api/win_config.c13
-rw-r--r--src/nvim/auevents.lua6
-rw-r--r--src/nvim/autocmd.c16
-rw-r--r--src/nvim/buffer.c12
-rw-r--r--src/nvim/buffer_defs.h12
-rw-r--r--src/nvim/bufwrite.c14
-rw-r--r--src/nvim/change.c4
-rw-r--r--src/nvim/charset.c196
-rw-r--r--src/nvim/cmdexpand.c69
-rw-r--r--src/nvim/cmdexpand_defs.h2
-rw-r--r--src/nvim/cmdhist.c49
-rw-r--r--src/nvim/cmdhist.h1
-rw-r--r--src/nvim/decoration_defs.h2
-rw-r--r--src/nvim/diff.c6
-rw-r--r--src/nvim/digraph.c8
-rw-r--r--src/nvim/drawline.c50
-rw-r--r--src/nvim/drawscreen.c57
-rw-r--r--src/nvim/errors.h8
-rw-r--r--src/nvim/eval.c81
-rw-r--r--src/nvim/eval.lua124
-rw-r--r--src/nvim/eval/funcs.c14
-rw-r--r--src/nvim/eval/vars.c21
-rw-r--r--src/nvim/ex_cmds.c18
-rw-r--r--src/nvim/ex_cmds2.c2
-rw-r--r--src/nvim/ex_docmd.c232
-rw-r--r--src/nvim/ex_getln.c204
-rw-r--r--src/nvim/ex_getln_defs.h6
-rw-r--r--src/nvim/file_search.c10
-rw-r--r--src/nvim/fileio.c28
-rw-r--r--src/nvim/fold.c2
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua2
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua4
-rw-r--r--src/nvim/generators/gen_options.lua347
-rw-r--r--src/nvim/generators/gen_options_enum.lua129
-rw-r--r--src/nvim/getchar.c82
-rw-r--r--src/nvim/getchar_defs.h2
-rw-r--r--src/nvim/globals.h8
-rw-r--r--src/nvim/grid_defs.h8
-rw-r--r--src/nvim/highlight.c12
-rw-r--r--src/nvim/highlight.h2
-rw-r--r--src/nvim/highlight_defs.h3
-rw-r--r--src/nvim/highlight_group.c35
-rw-r--r--src/nvim/indent.c22
-rw-r--r--src/nvim/input.c2
-rw-r--r--src/nvim/insexpand.c46
-rw-r--r--src/nvim/linematch.c4
-rw-r--r--src/nvim/lua/executor.c103
-rw-r--r--src/nvim/lua/stdlib.c14
-rw-r--r--src/nvim/lua/treesitter.c49
-rw-r--r--src/nvim/main.c12
-rw-r--r--src/nvim/mapping.c30
-rw-r--r--src/nvim/mapping.h7
-rw-r--r--src/nvim/mark.c13
-rw-r--r--src/nvim/mbyte.c13
-rw-r--r--src/nvim/memline.c51
-rw-r--r--src/nvim/menu.c4
-rw-r--r--src/nvim/message.c282
-rw-r--r--src/nvim/message.h2
-rw-r--r--src/nvim/message_defs.h6
-rw-r--r--src/nvim/mouse.c2
-rw-r--r--src/nvim/normal.c68
-rw-r--r--src/nvim/normal_defs.h5
-rw-r--r--src/nvim/ops.c290
-rw-r--r--src/nvim/ops.h2
-rw-r--r--src/nvim/option.c2078
-rw-r--r--src/nvim/option.h64
-rw-r--r--src/nvim/option_defs.h77
-rw-r--r--src/nvim/option_vars.h74
-rw-r--r--src/nvim/options.lua531
-rw-r--r--src/nvim/optionstr.c101
-rw-r--r--src/nvim/os/input.c62
-rw-r--r--src/nvim/os/shell.c8
-rw-r--r--src/nvim/path.c9
-rw-r--r--src/nvim/popupmenu.c48
-rw-r--r--src/nvim/popupmenu.h2
-rw-r--r--src/nvim/profile.c5
-rw-r--r--src/nvim/quickfix.c179
-rw-r--r--src/nvim/runtime.c2
-rw-r--r--src/nvim/search.c34
-rw-r--r--src/nvim/shada.c13
-rw-r--r--src/nvim/sign.c6
-rw-r--r--src/nvim/spell.c28
-rw-r--r--src/nvim/statusline.c14
-rw-r--r--src/nvim/strings.c4
-rw-r--r--src/nvim/syntax.c90
-rw-r--r--src/nvim/tag.c26
-rw-r--r--src/nvim/terminal.c11
-rw-r--r--src/nvim/textformat.c2
-rw-r--r--src/nvim/tui/tui.c36
-rw-r--r--src/nvim/types_defs.h4
-rw-r--r--src/nvim/ui.c60
-rw-r--r--src/nvim/ui.h4
-rw-r--r--src/nvim/ui_compositor.c2
-rw-r--r--src/nvim/undo.c16
-rw-r--r--src/nvim/usercmd.c16
-rw-r--r--src/nvim/vim_defs.h1
-rw-r--r--src/nvim/vvars.lua261
-rw-r--r--src/nvim/window.c62
-rw-r--r--src/nvim/winfloat.c7
-rw-r--r--src/nvim/yankmap.c2
-rw-r--r--src/uncrustify.cfg13
-rw-r--r--src/vterm/vterm.c509
-rw-r--r--src/vterm/vterm.h37
-rw-r--r--test/cmakeconfig/paths.lua.in1
-rw-r--r--test/functional/api/buffer_spec.lua5
-rw-r--r--test/functional/api/extmark_spec.lua12
-rw-r--r--test/functional/api/menu_spec.lua1
-rw-r--r--test/functional/api/ui_spec.lua8
-rw-r--r--test/functional/api/vim_spec.lua44
-rw-r--r--test/functional/api/window_spec.lua6
-rw-r--r--test/functional/autocmd/autocmd_oldtest_spec.lua1
-rw-r--r--test/functional/autocmd/autocmd_spec.lua3
-rw-r--r--test/functional/autocmd/cmdline_spec.lua1
-rw-r--r--test/functional/autocmd/show_spec.lua1
-rw-r--r--test/functional/autocmd/termxx_spec.lua7
-rw-r--r--test/functional/autocmd/win_scrolled_resized_spec.lua4
-rw-r--r--test/functional/core/fileio_spec.lua2
-rw-r--r--test/functional/core/job_spec.lua4
-rw-r--r--test/functional/core/log_spec.lua1
-rw-r--r--test/functional/core/main_spec.lua1
-rw-r--r--test/functional/core/startup_spec.lua35
-rw-r--r--test/functional/editor/completion_spec.lua1
-rw-r--r--test/functional/editor/ctrl_c_spec.lua1
-rw-r--r--test/functional/editor/defaults_spec.lua157
-rw-r--r--test/functional/editor/jump_spec.lua6
-rw-r--r--test/functional/editor/mark_spec.lua4
-rw-r--r--test/functional/editor/mode_cmdline_spec.lua21
-rw-r--r--test/functional/editor/mode_insert_spec.lua24
-rw-r--r--test/functional/editor/mode_normal_spec.lua20
-rw-r--r--test/functional/editor/put_spec.lua1
-rw-r--r--test/functional/editor/tabpage_spec.lua1
-rw-r--r--test/functional/ex_cmds/append_spec.lua1
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua1
-rw-r--r--test/functional/ex_cmds/debug_spec.lua1
-rw-r--r--test/functional/ex_cmds/digraphs_spec.lua1
-rw-r--r--test/functional/ex_cmds/drop_spec.lua1
-rw-r--r--test/functional/ex_cmds/highlight_spec.lua5
-rw-r--r--test/functional/ex_cmds/map_spec.lua1
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua6
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua1
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua2
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua4
-rw-r--r--test/functional/example_spec.lua4
-rw-r--r--test/functional/legacy/012_directory_spec.lua6
-rw-r--r--test/functional/legacy/063_match_and_matchadd_spec.lua1
-rw-r--r--test/functional/legacy/074_global_var_in_viminfo_spec.lua2
-rw-r--r--test/functional/legacy/078_swapfile_recover_spec.lua2
-rw-r--r--test/functional/legacy/107_adjust_window_and_contents_spec.lua1
-rw-r--r--test/functional/legacy/arglist_spec.lua1
-rw-r--r--test/functional/legacy/breakindent_spec.lua2
-rw-r--r--test/functional/legacy/cmdline_spec.lua30
-rw-r--r--test/functional/legacy/conceal_spec.lua156
-rw-r--r--test/functional/legacy/cpoptions_spec.lua1
-rw-r--r--test/functional/legacy/debugger_spec.lua1
-rw-r--r--test/functional/legacy/digraph_spec.lua1
-rw-r--r--test/functional/legacy/display_spec.lua5
-rw-r--r--test/functional/legacy/edit_spec.lua2
-rw-r--r--test/functional/legacy/ex_mode_spec.lua2
-rw-r--r--test/functional/legacy/excmd_spec.lua1
-rw-r--r--test/functional/legacy/fold_spec.lua1
-rw-r--r--test/functional/legacy/global_spec.lua1
-rw-r--r--test/functional/legacy/highlight_spec.lua2
-rw-r--r--test/functional/legacy/listchars_spec.lua1
-rw-r--r--test/functional/legacy/listlbr_spec.lua1
-rw-r--r--test/functional/legacy/listlbr_utf8_spec.lua1
-rw-r--r--test/functional/legacy/mapping_spec.lua1
-rw-r--r--test/functional/legacy/match_spec.lua4
-rw-r--r--test/functional/legacy/matchparen_spec.lua78
-rw-r--r--test/functional/legacy/messages_spec.lua9
-rw-r--r--test/functional/legacy/move_spec.lua1
-rw-r--r--test/functional/legacy/normal_spec.lua30
-rw-r--r--test/functional/legacy/number_spec.lua4
-rw-r--r--test/functional/legacy/options_spec.lua7
-rw-r--r--test/functional/legacy/prompt_buffer_spec.lua5
-rw-r--r--test/functional/legacy/put_spec.lua2
-rw-r--r--test/functional/legacy/scroll_opt_spec.lua1
-rw-r--r--test/functional/legacy/search_spec.lua3
-rw-r--r--test/functional/legacy/search_stat_spec.lua1
-rw-r--r--test/functional/legacy/signs_spec.lua1
-rw-r--r--test/functional/legacy/source_spec.lua1
-rw-r--r--test/functional/legacy/statusline_spec.lua1
-rw-r--r--test/functional/legacy/substitute_spec.lua1
-rw-r--r--test/functional/legacy/tabline_spec.lua1
-rw-r--r--test/functional/legacy/vimscript_spec.lua2
-rw-r--r--test/functional/legacy/visual_spec.lua1
-rw-r--r--test/functional/legacy/window_cmd_spec.lua2
-rw-r--r--test/functional/lua/buffer_updates_spec.lua1
-rw-r--r--test/functional/lua/commands_spec.lua2
-rw-r--r--test/functional/lua/diagnostic_spec.lua34
-rw-r--r--test/functional/lua/filetype_spec.lua12
-rw-r--r--test/functional/lua/hl_spec.lua (renamed from test/functional/lua/highlight_spec.lua)29
-rw-r--r--test/functional/lua/loop_spec.lua5
-rw-r--r--test/functional/lua/luaeval_spec.lua1
-rw-r--r--test/functional/lua/overrides_spec.lua2
-rw-r--r--test/functional/lua/runtime_spec.lua4
-rw-r--r--test/functional/lua/secure_spec.lua1
-rw-r--r--test/functional/lua/system_spec.lua12
-rw-r--r--test/functional/lua/thread_spec.lua2
-rw-r--r--test/functional/lua/ui_event_spec.lua189
-rw-r--r--test/functional/lua/ui_spec.lua2
-rw-r--r--test/functional/lua/vim_spec.lua376
-rw-r--r--test/functional/lua/with_spec.lua2
-rw-r--r--test/functional/options/belloff_spec.lua78
-rw-r--r--test/functional/options/chars_spec.lua2
-rw-r--r--test/functional/options/cursorbind_spec.lua1
-rw-r--r--test/functional/options/defaults_spec.lua2
-rw-r--r--test/functional/options/shortmess_spec.lua1
-rw-r--r--test/functional/plugin/health_spec.lua10
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua397
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua111
-rw-r--r--test/functional/plugin/lsp/inlay_hint_spec.lua2
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua1
-rw-r--r--test/functional/plugin/lsp/utils_spec.lua4
-rw-r--r--test/functional/plugin/lsp_spec.lua149
-rw-r--r--test/functional/plugin/man_spec.lua1
-rw-r--r--test/functional/plugin/matchparen_spec.lua1
-rw-r--r--test/functional/plugin/shada_spec.lua1
-rw-r--r--test/functional/plugin/tohtml_spec.lua3
-rw-r--r--test/functional/plugin/tutor_spec.lua1
-rw-r--r--test/functional/plugin/vim_syntax_spec.lua1
-rw-r--r--test/functional/provider/clipboard_spec.lua4
-rw-r--r--test/functional/terminal/buffer_spec.lua39
-rw-r--r--test/functional/terminal/channel_spec.lua4
-rw-r--r--test/functional/terminal/cursor_spec.lua3
-rw-r--r--test/functional/terminal/edit_spec.lua10
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua6
-rw-r--r--test/functional/terminal/highlight_spec.lua12
-rw-r--r--test/functional/terminal/scrollback_spec.lua4
-rw-r--r--test/functional/terminal/tui_spec.lua179
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua4
-rw-r--r--test/functional/testnvim.lua48
-rw-r--r--test/functional/testterm.lua4
-rw-r--r--test/functional/treesitter/fold_spec.lua4
-rw-r--r--test/functional/treesitter/highlight_spec.lua6
-rw-r--r--test/functional/treesitter/language_spec.lua28
-rw-r--r--test/functional/treesitter/node_spec.lua24
-rw-r--r--test/functional/treesitter/parser_spec.lua4
-rw-r--r--test/functional/treesitter/query_spec.lua34
-rw-r--r--test/functional/ui/bufhl_spec.lua1
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua1
-rw-r--r--test/functional/ui/cmdline_spec.lua115
-rw-r--r--test/functional/ui/cursor_spec.lua1
-rw-r--r--test/functional/ui/decorations_spec.lua9
-rw-r--r--test/functional/ui/diff_spec.lua114
-rw-r--r--test/functional/ui/embed_spec.lua77
-rw-r--r--test/functional/ui/float_spec.lua40
-rw-r--r--test/functional/ui/fold_spec.lua19
-rw-r--r--test/functional/ui/highlight_spec.lua80
-rw-r--r--test/functional/ui/hlstate_spec.lua47
-rw-r--r--test/functional/ui/inccommand_spec.lua13
-rw-r--r--test/functional/ui/inccommand_user_spec.lua35
-rw-r--r--test/functional/ui/input_spec.lua3
-rw-r--r--test/functional/ui/linematch_spec.lua4
-rw-r--r--test/functional/ui/messages_spec.lua216
-rw-r--r--test/functional/ui/mode_spec.lua3
-rw-r--r--test/functional/ui/mouse_spec.lua975
-rw-r--r--test/functional/ui/multibyte_spec.lua24
-rw-r--r--test/functional/ui/multigrid_spec.lua3
-rw-r--r--test/functional/ui/options_spec.lua10
-rw-r--r--test/functional/ui/output_spec.lua3
-rw-r--r--test/functional/ui/popupmenu_spec.lua449
-rw-r--r--test/functional/ui/quickfix_spec.lua1
-rw-r--r--test/functional/ui/screen.lua93
-rw-r--r--test/functional/ui/screen_basic_spec.lua10
-rw-r--r--test/functional/ui/scrollbind_spec.lua1
-rw-r--r--test/functional/ui/searchhl_spec.lua1
-rw-r--r--test/functional/ui/sign_spec.lua358
-rw-r--r--test/functional/ui/spell_spec.lua80
-rw-r--r--test/functional/ui/statuscolumn_spec.lua472
-rw-r--r--test/functional/ui/statusline_spec.lua137
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua1
-rw-r--r--test/functional/ui/tabline_spec.lua63
-rw-r--r--test/functional/ui/title_spec.lua1
-rw-r--r--test/functional/ui/wildmode_spec.lua5
-rw-r--r--test/functional/ui/winbar_spec.lua25
-rw-r--r--test/functional/vimscript/api_functions_spec.lua18
-rw-r--r--test/functional/vimscript/eval_spec.lua92
-rw-r--r--test/functional/vimscript/execute_spec.lua4
-rw-r--r--test/functional/vimscript/has_spec.lua9
-rw-r--r--test/functional/vimscript/input_spec.lua1
-rw-r--r--test/functional/vimscript/match_functions_spec.lua1
-rw-r--r--test/functional/vimscript/system_spec.lua8
-rw-r--r--test/functional/vimscript/timer_spec.lua9
-rw-r--r--test/old/testdir/Makefile15
-rw-r--r--test/old/testdir/gen_opt_test.vim507
-rw-r--r--test/old/testdir/runtest.vim26
-rw-r--r--test/old/testdir/script_util.vim2
-rw-r--r--test/old/testdir/shared.vim14
-rw-r--r--test/old/testdir/test_autocmd.vim11
-rw-r--r--test/old/testdir/test_cmdline.vim113
-rw-r--r--test/old/testdir/test_compiler.vim7
-rw-r--r--test/old/testdir/test_curswant.vim52
-rw-r--r--test/old/testdir/test_diffmode.vim27
-rw-r--r--test/old/testdir/test_edit.vim2
-rw-r--r--test/old/testdir/test_expr.vim10
-rw-r--r--test/old/testdir/test_filetype.vim67
-rw-r--r--test/old/testdir/test_findfile.vim525
-rw-r--r--test/old/testdir/test_functions.vim22
-rw-r--r--test/old/testdir/test_getvar.vim11
-rw-r--r--test/old/testdir/test_ins_complete.vim93
-rw-r--r--test/old/testdir/test_map_functions.vim19
-rw-r--r--test/old/testdir/test_mapping.vim77
-rw-r--r--test/old/testdir/test_modeline.vim1
-rw-r--r--test/old/testdir/test_normal.vim10
-rw-r--r--test/old/testdir/test_options.vim575
-rw-r--r--test/old/testdir/test_options_all.vim13
-rw-r--r--test/old/testdir/test_popup.vim30
-rw-r--r--test/old/testdir/test_quickfix.vim104
-rw-r--r--test/old/testdir/test_spellfile.vim2
-rw-r--r--test/old/testdir/test_swap.vim2
-rw-r--r--test/old/testdir/test_tagfunc.vim4
-rw-r--r--test/old/testdir/test_undo.vim3
-rw-r--r--test/old/testdir/test_window_cmd.vim2
-rw-r--r--test/old/testdir/test_windows_home.vim2
-rw-r--r--test/testutil.lua68
-rw-r--r--test/unit/testutil.lua7
-rw-r--r--test/unit/vterm_spec.lua3591
524 files changed, 21457 insertions, 12809 deletions
diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh
index b7d723e690..2aec8ea553 100755
--- a/.github/scripts/install_deps.sh
+++ b/.github/scripts/install_deps.sh
@@ -16,9 +16,9 @@ if [[ $os == Linux ]]; then
if [[ $CC == clang ]]; then
DEFAULT_CLANG_VERSION=$(echo | clang -dM -E - | grep __clang_major | awk '{print $3}')
- CLANG_VERSION=20
+ CLANG_VERSION=19
if ((DEFAULT_CLANG_VERSION >= CLANG_VERSION)); then
- echo "Default clang version is $DEFAULT_CLANG_VERSION, which equal or larger than wanted version $CLANG_VERSION. Aborting!"
+ echo "Default clang version is $DEFAULT_CLANG_VERSION, which is equal or larger than wanted version $CLANG_VERSION. Aborting!"
exit 1
fi
diff --git a/.github/scripts/reviewers_add.js b/.github/scripts/reviewers_add.js
index 50195497af..08b4e85b74 100644
--- a/.github/scripts/reviewers_add.js
+++ b/.github/scripts/reviewers_add.js
@@ -39,10 +39,6 @@ module.exports = async ({ github, context }) => {
reviewers.add("lewis6991");
}
- if (labels.includes("documentation")) {
- reviewers.add("clason");
- }
-
if (labels.includes("editorconfig")) {
reviewers.add("gpanders");
}
@@ -53,7 +49,6 @@ module.exports = async ({ github, context }) => {
if (labels.includes("filetype")) {
reviewers.add("clason");
- reviewers.add("gpanders");
}
if (labels.includes("inccommand")) {
@@ -90,10 +85,6 @@ module.exports = async ({ github, context }) => {
reviewers.add("famiu");
}
- if (labels.includes("test")) {
- reviewers.add("justinmk");
- }
-
if (labels.includes("treesitter")) {
reviewers.add("bfredl");
reviewers.add("clason");
@@ -110,7 +101,6 @@ module.exports = async ({ github, context }) => {
}
if (labels.includes("vim-patch")) {
- reviewers.add("seandewar");
reviewers.add("zeertzjq");
}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6abdd588ba..de90a077ff 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -81,9 +81,9 @@ jobs:
strategy:
fail-fast: false
matrix:
- runner: [ macos-12, macos-14 ]
+ runner: [ macos-13, macos-14 ]
include:
- - runner: macos-12
+ - runner: macos-13
arch: x86_64
- runner: macos-14
arch: arm64
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 522692b30a..0885efddd5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -107,8 +107,8 @@ jobs:
{ runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, cc: gcc },
- { runner: macos-12, os: macos, flavor: 12, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
- { runner: macos-15, os: macos, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
+ { runner: macos-13, os: macos, flavor: intel, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
+ { runner: macos-15, os: macos, flavor: arm, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON },
]
test: [unittest, functionaltest, oldtest]
diff --git a/.gitignore b/.gitignore
index f1661e1f00..98ec98ea72 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ compile_commands.json
/test/old/testdir/messages
/test/old/testdir/starttime
/test/old/testdir/viminfo
+/test/old/testdir/opt_test.vim
/test/old/testdir/test.ok
/test/old/testdir/*.failed
/test/old/testdir/X*
diff --git a/BUILD.md b/BUILD.md
index 4df69f5843..e5b1dcc707 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -12,6 +12,7 @@
- To build on Windows, see the [Building on Windows](#building-on-windows) section. _MSVC (Visual Studio) is recommended._
4. `sudo make install`
- Default install location is `/usr/local`
+ - On Debian/Ubuntu, instead of `sudo make install`, you can try `cd build && cpack -G DEB && sudo dpkg -i nvim-linux64.deb` to build DEB-package and install it. This helps ensure clean removal of installed files. Note: This is an unsupported, "best-effort" feature of the Nvim build.
**Notes**:
- From the repository's root directory, running `make` will download and build all the needed dependencies and put the `nvim` executable in `build/bin`.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0100146274..9723de9176 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,6 +46,7 @@ set(DEPS_IGNORE_SHA FALSE)
#-------------------------------------------------------------------------------
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
+set(VTERM_TEST_FILE ${PROJECT_BINARY_DIR}/test/vterm_test_output)
file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt)
@@ -111,10 +112,8 @@ if(APPLE)
endif()
if(WIN32 OR APPLE)
- # Ignore case when comparing filenames on Windows and Mac.
+ # Handle case-insensitive filenames for Windows and Mac.
set(CASE_INSENSITIVE_FILENAME TRUE)
- # Enable fixing case-insensitive filenames for Windows and Mac.
- set(USE_FNAME_CASE TRUE)
endif()
if (MINGW)
@@ -133,8 +132,8 @@ message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
set_default_buildtype(Debug)
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT isMultiConfig)
- # Unlike build dependencies in cmake.deps, we assume we want dev dependencies
- # such as Uncrustify to always be built with Release.
+ # Unlike build dependencies in cmake.deps, we want dev dependencies such as
+ # Uncrustify to always be built with Release.
list(APPEND DEPS_CMAKE_ARGS -D CMAKE_BUILD_TYPE=Release)
endif()
diff --git a/MAINTAIN.md b/MAINTAIN.md
index 5d046926c2..cd3dacb964 100644
--- a/MAINTAIN.md
+++ b/MAINTAIN.md
@@ -79,6 +79,8 @@ When a (non-experimental) feature is slated to be removed it should:
`v0.10.0-dev-1957+gd676746c33` then use `0.12`.
- For Vimscript features, use `v:lua.vim.deprecate()`. Use the same version
as described for Lua features.
+ - `vim.deprecate(…, 'x.y.z')` where major version `x` is greater than the
+ current Nvim major version, is always treated as _soft_ deprecation.
2. Be _hard_ deprecated in a following a release in which it was soft deprecated.
- Use of the deprecated feature will still work but should issue a warning.
- Features implemented in C will need bespoke implementations to communicate
diff --git a/cmake.config/config.h.in b/cmake.config/config.h.in
index af4e13fc11..833218abf9 100644
--- a/cmake.config/config.h.in
+++ b/cmake.config/config.h.in
@@ -34,7 +34,6 @@
#cmakedefine HAVE_WORKING_LIBINTL
#cmakedefine UNIX
#cmakedefine CASE_INSENSITIVE_FILENAME
-#cmakedefine USE_FNAME_CASE
#cmakedefine HAVE_SYS_UIO_H
#ifdef HAVE_SYS_UIO_H
#cmakedefine HAVE_READV
@@ -53,3 +52,5 @@
#cmakedefine HAVE_BUILTIN_ADD_OVERFLOW
#cmakedefine HAVE_WIMPLICIT_FALLTHROUGH_FLAG
#cmakedefine HAVE_BITSCANFORWARD64
+
+#define VTERM_TEST_FILE "@VTERM_TEST_FILE@"
diff --git a/cmake.deps/cmake/GettextCMakeLists.txt b/cmake.deps/cmake/GettextCMakeLists.txt
index 722420e830..b86f3c6a52 100644
--- a/cmake.deps/cmake/GettextCMakeLists.txt
+++ b/cmake.deps/cmake/GettextCMakeLists.txt
@@ -15,15 +15,20 @@ string(REPLACE "#undef HAVE_LONG_LONG_INT" "#define HAVE_LONG_LONG_INT 1" CONFIG
string(REPLACE "#undef HAVE_ICONV_H" "#define HAVE_ICONV_H 1" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef HAVE_ICONV" "#define HAVE_ICONV 1" CONFIG_CONTENT ${CONFIG_CONTENT})
string(REPLACE "#undef ICONV_CONST" "#define ICONV_CONST const" CONFIG_CONTENT ${CONFIG_CONTENT})
-string(REPLACE "#undef uintmax_t" "
- #if _WIN64
- # define intmax_t long long
- # define uintmax_t unsigned long long
- #elif _WIN32
- # define intmax_t long
- # define uintmax_t unsigned long
- #endif"
- CONFIG_CONTENT ${CONFIG_CONTENT})
+if(MSVC)
+ string(REPLACE "#undef HAVE_STDINT_H_WITH_UINTMAX" "#define HAVE_STDINT_H_WITH_UINTMAX 1" CONFIG_CONTENT ${CONFIG_CONTENT})
+ string(REPLACE "#undef HAVE_STDINT_H" "#define HAVE_STDINT_H 1" CONFIG_CONTENT ${CONFIG_CONTENT})
+else()
+ string(REPLACE "#undef uintmax_t" "
+ #if _WIN64
+ # define intmax_t long long
+ # define uintmax_t unsigned long long
+ #elif _WIN32
+ # define intmax_t long
+ # define uintmax_t unsigned long
+ #endif"
+ CONFIG_CONTENT ${CONFIG_CONTENT})
+ endif()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gettext-runtime/config.h ${CONFIG_CONTENT})
set(HAVE_NEWLOCALE 0)
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index 7acb7523b0..1623d0ff57 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -1,8 +1,8 @@
-LIBUV_URL https://github.com/libuv/libuv/archive/v1.49.0.tar.gz
-LIBUV_SHA256 a10656a0865e2cff7a1b523fa47d0f5a9c65be963157301f814d1cc5dbd4dc1d
+LIBUV_URL https://github.com/libuv/libuv/archive/v1.49.2.tar.gz
+LIBUV_SHA256 388ffcf3370d4cf7c4b3a3205504eea06c4be5f9e80d2ab32d19f8235accc1cf
-LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/97813fb924edf822455f91a5fbbdfdb349e5984f.tar.gz
-LUAJIT_SHA256 cbf1647acbd340c62b9c342dae43290762efa1b26d8bf8457f143fabf8ed86c7
+LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/fe71d0fb54ceadfb5b5f3b6baf29e486d97f6059.tar.gz
+LUAJIT_SHA256 92325f209b21aaf0a67b099bc73cf9bbac5789a9749bdc3898d4a990abb4f36e
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
@@ -50,13 +50,13 @@ TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/a
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.3.2.tar.gz
TREESITTER_MARKDOWN_SHA256 5dac48a6d971eb545aab665d59a18180d21963afc781bbf40f9077c06cb82ae5
-TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.24.1.tar.gz
-TREESITTER_SHA256 7adb5bb3b3c2c4f4fdc980a9a13df8fbf3526a82b5c37dd9cf2ed29de56a4683
+TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/e3c82633389256ccc2c5ab2e509046cbf20453d3.tar.gz
+TREESITTER_SHA256 61a21f5d83cfe256472bfa941123a6941fb45073784ee7ec0bc32fdd52f7a4e4
-WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v25.0.1.tar.gz
-WASMTIME_SHA256 0e816ee247eda6c35fca20dfaeac50c2cbb0df60d305b722fa2be9eced5b95da
+WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v25.0.2.tar.gz
+WASMTIME_SHA256 6d1c17c756b83f29f629963228e5fa208ba9d6578421ba2cd07132b6a120accb
-UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz
-UNCRUSTIFY_SHA256 e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f
+UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.80.1.tar.gz
+UNCRUSTIFY_SHA256 0e2616ec2f78e12816388c513f7060072ff7942b42f1175eb28b24cb75aaec48
LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz
LUA_DEV_DEPS_SHA256 27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2
diff --git a/cmake/FindLpeg.cmake b/cmake/FindLpeg.cmake
index 3d0ff5929d..7657bdac9e 100644
--- a/cmake/FindLpeg.cmake
+++ b/cmake/FindLpeg.cmake
@@ -1,4 +1,13 @@
-find_library2(LPEG_LIBRARY NAMES lpeg_a lpeg liblpeg_a lpeg${CMAKE_SHARED_LIBRARY_SUFFIX} PATH_SUFFIXES lua/5.1)
+find_library2(LPEG_LIBRARY NAMES lpeg_a lpeg liblpeg_a lpeg.so lpeg${CMAKE_SHARED_LIBRARY_SUFFIX} PATH_SUFFIXES lua/5.1)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND LPEG_LIBRARY MATCHES ".so$")
+ execute_process(
+ COMMAND otool -hv "${LPEG_LIBRARY}"
+ OUTPUT_VARIABLE LPEG_HEADER
+ )
+ if(LPEG_HEADER MATCHES ".* BUNDLE .*")
+ message(FATAL_ERROR "lpeg library found at ${LPEG_LIBRARY} but built as a bundle rather than a dylib, please rebuild with `-dynamiclib` rather than `-bundle`")
+ endif()
+endif()
find_package_handle_standard_args(Lpeg DEFAULT_MSG LPEG_LIBRARY)
mark_as_advanced(LPEG_LIBRARY)
diff --git a/cmake/Util.cmake b/cmake/Util.cmake
index f09de78668..8ca39e5f94 100644
--- a/cmake/Util.cmake
+++ b/cmake/Util.cmake
@@ -61,6 +61,7 @@ function(add_glob_target)
if(NOT ARG_COMMAND)
add_custom_target(${ARG_TARGET})
add_custom_command(TARGET ${ARG_TARGET}
+ POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET} SKIP: ${ARG_COMMAND} not found")
return()
endif()
@@ -175,8 +176,7 @@ function(add_target)
add_custom_target(${target} DEPENDS ${touch_file})
endfunction()
-# Set default build type to BUILD_TYPE. Also limit the list of allowable build
-# types to the ones defined in variable allowableBuildTypes.
+# Set default build type to BUILD_TYPE.
#
# The correct way to specify build type (for example Release) for
# single-configuration generators (Make and Ninja) is to run
@@ -193,28 +193,24 @@ endfunction()
# Passing CMAKE_BUILD_TYPE for multi-config generators will not only not be
# used, but also generate a warning for the user.
function(set_default_buildtype BUILD_TYPE)
- set(allowableBuildTypes Debug Release MinSizeRel RelWithDebInfo)
- if(NOT BUILD_TYPE IN_LIST allowableBuildTypes)
- message(FATAL_ERROR "Invalid build type: ${BUILD_TYPE}")
- endif()
+ set(defaultBuildTypes Debug Release MinSizeRel RelWithDebInfo)
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
- # Multi-config generators use the first element in CMAKE_CONFIGURATION_TYPES as the default build type
- list(INSERT allowableBuildTypes 0 ${BUILD_TYPE})
- list(REMOVE_DUPLICATES allowableBuildTypes)
- set(CMAKE_CONFIGURATION_TYPES ${allowableBuildTypes} PARENT_SCOPE)
+ # Multi-config generators use the first element in
+ # CMAKE_CONFIGURATION_TYPES as the default build type
+ list(INSERT defaultBuildTypes 0 ${BUILD_TYPE})
+ list(REMOVE_DUPLICATES defaultBuildTypes)
+ set(CMAKE_CONFIGURATION_TYPES ${defaultBuildTypes} PARENT_SCOPE)
if(CMAKE_BUILD_TYPE)
message(WARNING "CMAKE_BUILD_TYPE specified which is ignored on \
multi-configuration generators. Defaulting to ${BUILD_TYPE} build type.")
endif()
else()
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowableBuildTypes}")
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${defaultBuildTypes}")
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "CMAKE_BUILD_TYPE not specified, default is '${BUILD_TYPE}'")
set(CMAKE_BUILD_TYPE ${BUILD_TYPE} CACHE STRING "Choose the type of build" FORCE)
- elseif(NOT CMAKE_BUILD_TYPE IN_LIST allowableBuildTypes)
- message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}")
else()
message(STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif()
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index c171fab9e9..9f108b4df4 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -118,4 +118,4 @@ foreach(D ${RUNTIME_DIRS})
endforeach()
# only foo.sh script in runtime/
-install_helper(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/macros/less.sh DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/macros/)
+install_helper(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/less.sh DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/scripts/)
diff --git a/runtime/autoload/README.txt b/runtime/autoload/README.txt
index 3b18d3dde5..bca86a2a4c 100644
--- a/runtime/autoload/README.txt
+++ b/runtime/autoload/README.txt
@@ -7,7 +7,7 @@ gzip.vim for editing compressed files
netrw*.vim browsing (remote) directories and editing remote files
tar.vim browsing tar files
zip.vim browsing zip files
-paste.vim common code for mswin.vim, menu.vim and macmap.vim
+paste.vim common code for mswin.vim and menu.vim
spellfile.vim downloading of a missing spell file
Omni completion files:
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index a96364fb4b..1df545278f 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -4,8 +4,8 @@
" Date: May 03, 2023
" Version: 173a
" Last Change: {{{1
-" 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a)
-" 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a)
+" 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a)
+" 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a)
" 2024 Feb 19 by Vim Project: (announce adoption)
" 2024 Feb 29 by Vim Project: handle symlinks in tree mode correctly
" 2024 Apr 03 by Vim Project: detect filetypes for remote edited files
@@ -26,6 +26,16 @@
" 2024 Sep 15 by Vim Project: more strict confirmation dialog (#15680)
" 2024 Sep 19 by Vim Project: mf-selection highlight uses wrong pattern (#15700)
" 2024 Sep 21 by Vim Project: remove extraneous closing bracket (#15718)
+" 2024 Oct 21 by Vim Project: remove netrwFileHandlers (#15895)
+" 2024 Oct 27 by Vim Project: clean up gx mapping (#15721)
+" 2024 Oct 30 by Vim Project: fix filetype detection for remote files (#15961)
+" 2024 Oct 30 by Vim Project: fix x mapping on cygwin (#13687)
+" 2024 Oct 31 by Vim Project: add netrw#Launch() and netrw#Open() (#15962)
+" 2024 Oct 31 by Vim Project: fix E874 when browsing remote dir (#15964)
+" 2024 Nov 07 by Vim Project: use keeppatterns to prevent polluting the search history
+" 2024 Nov 07 by Vim Project: fix a few issues with netrw tree listing (#15996)
+" 2024 Nov 10 by Vim Project: directory symlink not resolved in tree view (#16020)
+" 2024 Nov 14 by Vim Project: small fixes to netrw#BrowseX (#16056)
" }}}
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
@@ -532,7 +542,6 @@ if !exists("g:netrw_sort_sequence")
endif
call s:NetrwInit("g:netrw_special_syntax" , 0)
call s:NetrwInit("g:netrw_ssh_browse_reject", '^total\s\+\d\+$')
-call s:NetrwInit("g:netrw_suppress_gx_mesg", 1)
call s:NetrwInit("g:netrw_use_noswf" , 1)
call s:NetrwInit("g:netrw_sizestyle" ,"b")
" Default values - t-w ---------- {{{3
@@ -672,11 +681,8 @@ endif
" == 4: Vexplore style == 5: Vexplore!
" == 6: Texplore
fun! netrw#Explore(indx,dosplit,style,...)
-" call Dfunc("netrw#Explore(indx=".a:indx." dosplit=".a:dosplit." style=".a:style.",a:1<".a:1.">) &modified=".&modified." modifiable=".&modifiable." a:0=".a:0." win#".winnr()." buf#".bufnr("%")." ft=".&ft)
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
if !exists("b:netrw_curdir")
let b:netrw_curdir= getcwd()
-" call Decho("set b:netrw_curdir<".b:netrw_curdir."> (used getcwd)",'~'.expand("<slnum>"))
endif
" record current file for Rexplore's benefit
@@ -690,17 +696,11 @@ fun! netrw#Explore(indx,dosplit,style,...)
if !exists("g:netrw_cygwin") && has("win32")
let curdir= substitute(curdir,'\','/','g')
endif
-" call Decho("curdir<".curdir."> curfiledir<".curfiledir.">",'~'.expand("<slnum>"))
" using completion, directories with spaces in their names (thanks, Bill Gates, for a truly dumb idea)
" will end up with backslashes here. Solution: strip off backslashes that precede white space and
" try Explore again.
if a:0 > 0
-" call Decho('considering retry: a:1<'.a:1.'>: '.
- \ ((a:1 =~ "\\\s")? 'has backslash whitespace' : 'does not have backslash whitespace').', '.
- \ ((filereadable(s:NetrwFile(a:1)))? 'is readable' : 'is not readable').', '.
- \ ((isdirectory(s:NetrwFile(a:1))))? 'is a directory' : 'is not a directory',
- \ '~'.expand("<slnum>"))
if a:1 =~ "\\\s" && !filereadable(s:NetrwFile(a:1)) && !isdirectory(s:NetrwFile(a:1))
let a1 = substitute(a:1, '\\\(\s\)', '\1', 'g')
if a1 != a:1
@@ -711,6 +711,11 @@ fun! netrw#Explore(indx,dosplit,style,...)
endif
" save registers
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+" call Decho("(netrw#Explore) save @* and @+",'~'.expand("<slnum>"))
+ sil! let keepregstar = @*
+ sil! let keepregplus = @+
+ endif
sil! let keepregslash= @/
" if dosplit
@@ -763,64 +768,45 @@ fun! netrw#Explore(indx,dosplit,style,...)
NetrwKeepj norm! 0
if a:0 > 0
-" call Decho("case [a:0=".a:0."] > 0: a:1<".a:1.">",'~'.expand("<slnum>"))
if a:1 =~ '^\~' && (has("unix") || (exists("g:netrw_cygwin") && g:netrw_cygwin))
-" call Decho("..case a:1<".a:1.">: starts with ~ and unix or cygwin",'~'.expand("<slnum>"))
let dirname= simplify(substitute(a:1,'\~',expand("$HOME"),''))
-" call Decho("..using dirname<".dirname."> (case: ~ && unix||cygwin)",'~'.expand("<slnum>"))
elseif a:1 == '.'
-" call Decho("..case a:1<".a:1.">: matches .",'~'.expand("<slnum>"))
let dirname= simplify(exists("b:netrw_curdir")? b:netrw_curdir : getcwd())
if dirname !~ '/$'
let dirname= dirname."/"
endif
-" call Decho("..using dirname<".dirname."> (case: ".(exists("b:netrw_curdir")? "b:netrw_curdir" : "getcwd()").")",'~'.expand("<slnum>"))
elseif a:1 =~ '\$'
-" call Decho("..case a:1<".a:1.">: matches ending $",'~'.expand("<slnum>"))
let dirname= simplify(expand(a:1))
-" call Decho("..using user-specified dirname<".dirname."> with $env-var",'~'.expand("<slnum>"))
elseif a:1 !~ '^\*\{1,2}/' && a:1 !~ '^\a\{3,}://'
-" call Decho("..case a:1<".a:1.">: other, not pattern or filepattern",'~'.expand("<slnum>"))
let dirname= simplify(a:1)
-" call Decho("..using user-specified dirname<".dirname.">",'~'.expand("<slnum>"))
else
-" call Decho("..case a:1: pattern or filepattern",'~'.expand("<slnum>"))
let dirname= a:1
endif
else
" clear explore
-" call Decho("case a:0=".a:0.": clearing Explore list",'~'.expand("<slnum>"))
call s:NetrwClearExplore()
-" call Dret("netrw#Explore : cleared list")
return
endif
-" call Decho("dirname<".dirname.">",'~'.expand("<slnum>"))
if dirname =~ '\.\./\=$'
let dirname= simplify(fnamemodify(dirname,':p:h'))
elseif dirname =~ '\.\.' || dirname == '.'
let dirname= simplify(fnamemodify(dirname,':p'))
endif
-" call Decho("dirname<".dirname."> (after simplify)",'~'.expand("<slnum>"))
if dirname =~ '^\*//'
" starpat=1: Explore *//pattern (current directory only search for files containing pattern)
-" call Decho("case starpat=1: Explore *//pattern",'~'.expand("<slnum>"))
let pattern= substitute(dirname,'^\*//\(.*\)$','\1','')
let starpat= 1
-" call Decho("..Explore *//pat: (starpat=".starpat.") dirname<".dirname."> -> pattern<".pattern.">",'~'.expand("<slnum>"))
if &hls | let keepregslash= s:ExplorePatHls(pattern) | endif
elseif dirname =~ '^\*\*//'
" starpat=2: Explore **//pattern (recursive descent search for files containing pattern)
-" call Decho("case starpat=2: Explore **//pattern",'~'.expand("<slnum>"))
let pattern= substitute(dirname,'^\*\*//','','')
let starpat= 2
-" call Decho("..Explore **//pat: (starpat=".starpat.") dirname<".dirname."> -> pattern<".pattern.">",'~'.expand("<slnum>"))
elseif dirname =~ '/\*\*/'
" handle .../**/.../filepat
-" call Decho("case starpat=4: Explore .../**/.../filepat",'~'.expand("<slnum>"))
let prefixdir= substitute(dirname,'^\(.\{-}\)\*\*.*$','\1','')
if prefixdir =~ '^/' || (prefixdir =~ '^\a:/' && has("win32"))
let b:netrw_curdir = prefixdir
@@ -829,30 +815,23 @@ fun! netrw#Explore(indx,dosplit,style,...)
endif
let dirname= substitute(dirname,'^.\{-}\(\*\*/.*\)$','\1','')
let starpat= 4
-" call Decho("..pwd<".getcwd()."> dirname<".dirname.">",'~'.expand("<slnum>"))
-" call Decho("..case Explore ../**/../filepat (starpat=".starpat.")",'~'.expand("<slnum>"))
elseif dirname =~ '^\*/'
" case starpat=3: Explore */filepat (search in current directory for filenames matching filepat)
let starpat= 3
-" call Decho("case starpat=3: Explore */filepat (starpat=".starpat.")",'~'.expand("<slnum>"))
elseif dirname=~ '^\*\*/'
" starpat=4: Explore **/filepat (recursive descent search for filenames matching filepat)
let starpat= 4
-" call Decho("case starpat=4: Explore **/filepat (starpat=".starpat.")",'~'.expand("<slnum>"))
else
let starpat= 0
-" call Decho("case starpat=0: default",'~'.expand("<slnum>"))
endif
if starpat == 0 && a:indx >= 0
" [Explore Hexplore Vexplore Sexplore] [dirname]
-" call Decho("case starpat==0 && a:indx=".a:indx.": dirname<".dirname.">, handles Explore Hexplore Vexplore Sexplore",'~'.expand("<slnum>"))
if dirname == ""
let dirname= curfiledir
-" call Decho("..empty dirname, using current file's directory<".dirname.">",'~'.expand("<slnum>"))
endif
if dirname =~# '^scp://' || dirname =~ '^ftp://'
call netrw#Nread(2,dirname)
@@ -868,10 +847,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
elseif dirname !~ '^/'
let dirname= b:netrw_curdir."/".dirname
endif
-" call Decho("..calling LocalBrowseCheck(dirname<".dirname.">)",'~'.expand("<slnum>"))
call netrw#LocalBrowseCheck(dirname)
-" call Decho(" modified=".&modified." modifiable=".&modifiable." readonly=".&readonly,'~'.expand("<slnum>"))
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
endif
if exists("w:netrw_bannercnt")
" done to handle P08-Ingelrest. :Explore will _Always_ go to the line just after the banner.
@@ -879,15 +855,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
exe w:netrw_bannercnt
endif
-" call Decho("curdir<".curdir.">",'~'.expand("<slnum>"))
- " ---------------------------------------------------------------------
- " Jan 24, 2013: not sure why the following was present. See P08-Ingelrest
-" if has("win32") || has("win95") || has("win64") || has("win16")
-" NetrwKeepj call search('\<'.substitute(curdir,'^.*[/\\]','','e').'\>','cW')
-" else
-" NetrwKeepj call search('\<'.substitute(curdir,'^.*/','','e').'\>','cW')
-" endif
- " ---------------------------------------------------------------------
" starpat=1: Explore *//pattern (current directory only search for files containing pattern)
" starpat=2: Explore **//pattern (recursive descent search for files containing pattern)
@@ -895,86 +862,75 @@ fun! netrw#Explore(indx,dosplit,style,...)
" starpat=4: Explore **/filepat (recursive descent search for filenames matching filepat)
elseif a:indx <= 0
" Nexplore, Pexplore, Explore: handle starpat
-" call Decho("case a:indx<=0: Nexplore, Pexplore, <s-down>, <s-up> starpat=".starpat." a:indx=".a:indx,'~'.expand("<slnum>"))
if !mapcheck("<s-up>","n") && !mapcheck("<s-down>","n") && exists("b:netrw_curdir")
-" call Decho("..set up <s-up> and <s-down> maps",'~'.expand("<slnum>"))
let s:didstarstar= 1
nnoremap <buffer> <silent> <s-up> :Pexplore<cr>
nnoremap <buffer> <silent> <s-down> :Nexplore<cr>
endif
if has("path_extra")
-" call Decho("..starpat=".starpat.": has +path_extra",'~'.expand("<slnum>"))
if !exists("w:netrw_explore_indx")
let w:netrw_explore_indx= 0
endif
let indx = a:indx
-" call Decho("..starpat=".starpat.": set indx= [a:indx=".indx."]",'~'.expand("<slnum>"))
if indx == -1
" Nexplore
-" call Decho("..case Nexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
if !exists("w:netrw_explore_list") " sanity check
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Nexplore or <s-down> improperly; see help for netrw-starstar",40)
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore")
return
endif
let indx= w:netrw_explore_indx
if indx < 0 | let indx= 0 | endif
if indx >= w:netrw_explore_listlen | let indx= w:netrw_explore_listlen - 1 | endif
let curfile= w:netrw_explore_list[indx]
-" call Decho("....indx=".indx." curfile<".curfile.">",'~'.expand("<slnum>"))
while indx < w:netrw_explore_listlen && curfile == w:netrw_explore_list[indx]
let indx= indx + 1
-" call Decho("....indx=".indx." (Nexplore while loop)",'~'.expand("<slnum>"))
endwhile
if indx >= w:netrw_explore_listlen | let indx= w:netrw_explore_listlen - 1 | endif
-" call Decho("....Nexplore: indx= [w:netrw_explore_indx=".w:netrw_explore_indx."]=".indx,'~'.expand("<slnum>"))
elseif indx == -2
" Pexplore
-" call Decho("case Pexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
if !exists("w:netrw_explore_list") " sanity check
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Pexplore or <s-up> improperly; see help for netrw-starstar",41)
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore")
return
endif
let indx= w:netrw_explore_indx
if indx < 0 | let indx= 0 | endif
if indx >= w:netrw_explore_listlen | let indx= w:netrw_explore_listlen - 1 | endif
let curfile= w:netrw_explore_list[indx]
-" call Decho("....indx=".indx." curfile<".curfile.">",'~'.expand("<slnum>"))
while indx >= 0 && curfile == w:netrw_explore_list[indx]
let indx= indx - 1
-" call Decho("....indx=".indx." (Pexplore while loop)",'~'.expand("<slnum>"))
endwhile
if indx < 0 | let indx= 0 | endif
-" call Decho("....Pexplore: indx= [w:netrw_explore_indx=".w:netrw_explore_indx."]=".indx,'~'.expand("<slnum>"))
else
" Explore -- initialize
" build list of files to Explore with Nexplore/Pexplore
-" call Decho("..starpat=".starpat.": case Explore: initialize (indx=".indx.")",'~'.expand("<slnum>"))
NetrwKeepj keepalt call s:NetrwClearExplore()
let w:netrw_explore_indx= 0
if !exists("b:netrw_curdir")
let b:netrw_curdir= getcwd()
endif
-" call Decho("....starpat=".starpat.": b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
" switch on starpat to build the w:netrw_explore_list of files
if starpat == 1
" starpat=1: Explore *//pattern (current directory only search for files containing pattern)
-" call Decho("..case starpat=".starpat.": build *//pattern list (curdir-only srch for files containing pattern) &hls=".&hls,'~'.expand("<slnum>"))
-" call Decho("....pattern<".pattern.">",'~'.expand("<slnum>"))
try
exe "NetrwKeepj noautocmd vimgrep /".pattern."/gj ".fnameescape(b:netrw_curdir)."/*"
catch /^Vim\%((\a\+)\)\=:E480/
keepalt call netrw#ErrorMsg(s:WARNING,"no match with pattern<".pattern.">",76)
-" call Dret("netrw#Explore : unable to find pattern<".pattern.">")
return
endtry
let w:netrw_explore_list = s:NetrwExploreListUniq(map(getqflist(),'bufname(v:val.bufnr)'))
@@ -982,15 +938,16 @@ fun! netrw#Explore(indx,dosplit,style,...)
elseif starpat == 2
" starpat=2: Explore **//pattern (recursive descent search for files containing pattern)
-" call Decho("..case starpat=".starpat.": build **//pattern list (recursive descent files containing pattern)",'~'.expand("<slnum>"))
-" call Decho("....pattern<".pattern.">",'~'.expand("<slnum>"))
try
exe "sil NetrwKeepj noautocmd keepalt vimgrep /".pattern."/gj "."**/*"
catch /^Vim\%((\a\+)\)\=:E480/
keepalt call netrw#ErrorMsg(s:WARNING,'no files matched pattern<'.pattern.'>',45)
if &hls | let keepregslash= s:ExplorePatHls(pattern) | endif
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore : no files matched pattern")
return
endtry
let s:netrw_curdir = b:netrw_curdir
@@ -1000,51 +957,43 @@ fun! netrw#Explore(indx,dosplit,style,...)
elseif starpat == 3
" starpat=3: Explore */filepat (search in current directory for filenames matching filepat)
-" call Decho("..case starpat=".starpat.": build */filepat list (curdir-only srch filenames matching filepat) &hls=".&hls,'~'.expand("<slnum>"))
let filepat= substitute(dirname,'^\*/','','')
let filepat= substitute(filepat,'^[%#<]','\\&','')
-" call Decho("....b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
-" call Decho("....filepat<".filepat.">",'~'.expand("<slnum>"))
let w:netrw_explore_list= s:NetrwExploreListUniq(split(expand(b:netrw_curdir."/".filepat),'\n'))
if &hls | let keepregslash= s:ExplorePatHls(filepat) | endif
elseif starpat == 4
" starpat=4: Explore **/filepat (recursive descent search for filenames matching filepat)
-" call Decho("..case starpat=".starpat.": build **/filepat list (recursive descent srch filenames matching filepat) &hls=".&hls,'~'.expand("<slnum>"))
let w:netrw_explore_list= s:NetrwExploreListUniq(split(expand(b:netrw_curdir."/".dirname),'\n'))
if &hls | let keepregslash= s:ExplorePatHls(dirname) | endif
endif " switch on starpat to build w:netrw_explore_list
let w:netrw_explore_listlen = len(w:netrw_explore_list)
-" call Decho("....w:netrw_explore_list<".string(w:netrw_explore_list).">",'~'.expand("<slnum>"))
-" call Decho("....w:netrw_explore_listlen=".w:netrw_explore_listlen,'~'.expand("<slnum>"))
if w:netrw_explore_listlen == 0 || (w:netrw_explore_listlen == 1 && w:netrw_explore_list[0] =~ '\*\*\/')
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"no files matched",42)
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore : no files matched")
return
endif
endif " if indx ... endif
" NetrwStatusLine support - for exploring support
let w:netrw_explore_indx= indx
-" call Decho("....w:netrw_explore_list<".join(w:netrw_explore_list,',')."> len=".w:netrw_explore_listlen,'~'.expand("<slnum>"))
" wrap the indx around, but issue a note
if indx >= w:netrw_explore_listlen || indx < 0
-" call Decho("....wrap indx (indx=".indx." listlen=".w:netrw_explore_listlen.")",'~'.expand("<slnum>"))
let indx = (indx < 0)? ( w:netrw_explore_listlen - 1 ) : 0
let w:netrw_explore_indx= indx
keepalt NetrwKeepj call netrw#ErrorMsg(s:NOTE,"no more files match Explore pattern",43)
endif
exe "let dirfile= w:netrw_explore_list[".indx."]"
-" call Decho("....dirfile=w:netrw_explore_list[indx=".indx."]= <".dirfile.">",'~'.expand("<slnum>"))
let newdir= substitute(dirfile,'/[^/]*$','','e')
-" call Decho("....newdir<".newdir.">",'~'.expand("<slnum>"))
-" call Decho("....calling LocalBrowseCheck(newdir<".newdir.">)",'~'.expand("<slnum>"))
call netrw#LocalBrowseCheck(newdir)
if !exists("w:netrw_liststyle")
let w:netrw_liststyle= g:netrw_liststyle
@@ -1058,20 +1007,20 @@ fun! netrw#Explore(indx,dosplit,style,...)
let w:netrw_explore_bufnr = bufnr("%")
let w:netrw_explore_line = line(".")
keepalt NetrwKeepj call s:SetupNetrwStatusLine('%f %h%m%r%=%9*%{NetrwStatusLine()}')
-" call Decho("....explore: mtchcnt=".w:netrw_explore_mtchcnt." bufnr=".w:netrw_explore_bufnr." line#".w:netrw_explore_line,'~'.expand("<slnum>"))
else
-" call Decho("..your vim does not have +path_extra",'~'.expand("<slnum>"))
if !exists("g:netrw_quiet")
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"your vim needs the +path_extra feature for Exploring with **!",44)
endif
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore : missing +path_extra")
return
endif
else
-" call Decho("..default case: Explore newdir<".dirname.">",'~'.expand("<slnum>"))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && dirname =~ '/'
sil! unlet w:netrw_treedict
sil! unlet w:netrw_treetop
@@ -1080,18 +1029,14 @@ fun! netrw#Explore(indx,dosplit,style,...)
if !exists("b:netrw_curdir")
NetrwKeepj call netrw#LocalBrowseCheck(getcwd())
else
- NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,newdir))
+ NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,newdir,0))
endif
endif
" visual display of **/ **// */ Exploration files
-" call Decho("w:netrw_explore_indx=".(exists("w:netrw_explore_indx")? w:netrw_explore_indx : "doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "n/a").">",'~'.expand("<slnum>"))
if exists("w:netrw_explore_indx") && exists("b:netrw_curdir")
-" call Decho("s:explore_prvdir<".(exists("s:explore_prvdir")? s:explore_prvdir : "-doesn't exist-"),'~'.expand("<slnum>"))
if !exists("s:explore_prvdir") || s:explore_prvdir != b:netrw_curdir
" only update match list when current directory isn't the same as before
-" call Decho("only update match list when current directory not the same as before",'~'.expand("<slnum>"))
let s:explore_prvdir = b:netrw_curdir
let s:explore_match = ""
let dirlen = strlen(b:netrw_curdir)
@@ -1100,7 +1045,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
endif
let prvfname= ""
for fname in w:netrw_explore_list
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
if fname =~ '^'.b:netrw_curdir
if s:explore_match == ""
let s:explore_match= '\<'.escape(strpart(fname,dirlen),g:netrw_markfileesc).'\>'
@@ -1116,7 +1060,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
endif
let prvfname= fname
endfor
-" call Decho("explore_match<".s:explore_match.">",'~'.expand("<slnum>"))
if has("syntax") && exists("g:syntax_on") && g:syntax_on
exe "2match netrwMarkFile /".s:explore_match."/"
endif
@@ -1126,15 +1069,17 @@ fun! netrw#Explore(indx,dosplit,style,...)
2match none
if exists("s:explore_match") | unlet s:explore_match | endif
if exists("s:explore_prvdir") | unlet s:explore_prvdir | endif
-" call Decho("cleared explore match list",'~'.expand("<slnum>"))
endif
" since Explore may be used to initialize netrw's browser,
" there's no danger of a late FocusGained event on initialization.
" Consequently, set s:netrw_events to 2.
let s:netrw_events= 2
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
sil! let @/ = keepregslash
-" call Dret("netrw#Explore : @/<".@/.">")
endfun
" ---------------------------------------------------------------------
@@ -1152,47 +1097,35 @@ fun! netrw#Lexplore(count,rightside,...)
" if a netrw window is already on the left-side of the tab
" and a directory has been specified, explore with that
" directory.
-" call Decho("case has input argument(s) (a:1<".a:1.">)")
let a1 = expand(a:1)
-" call Decho("a:1<".a:1."> curwin#".curwin,'~'.expand("<slnum>"))
exe "1wincmd w"
if &ft == "netrw"
-" call Decho("exe Explore ".fnameescape(a:1),'~'.expand("<slnum>"))
exe "Explore ".fnameescape(a1)
exe curwin."wincmd w"
let s:lexplore_win= curwin
let w:lexplore_buf= bufnr("%")
if exists("t:netrw_lexposn")
-" call Decho("forgetting t:netrw_lexposn",'~'.expand("<slnum>"))
unlet t:netrw_lexposn
endif
-" call Dret("netrw#Lexplore")
return
endif
exe curwin."wincmd w"
else
let a1= ""
-" call Decho("no input arguments")
endif
if exists("t:netrw_lexbufnr")
" check if t:netrw_lexbufnr refers to a netrw window
let lexwinnr = bufwinnr(t:netrw_lexbufnr)
-" call Decho("lexwinnr= bufwinnr(t:netrw_lexbufnr#".t:netrw_lexbufnr.")=".lexwinnr)
else
let lexwinnr= 0
-" call Decho("t:netrw_lexbufnr doesn't exist")
endif
-" call Decho("lexwinnr=".lexwinnr,'~'.expand("<slnum>"))
if lexwinnr > 0
" close down netrw explorer window
-" call Decho("t:netrw_lexbufnr#".t:netrw_lexbufnr.": close down netrw window",'~'.expand("<slnum>"))
exe lexwinnr."wincmd w"
let g:netrw_winsize = -winwidth(0)
let t:netrw_lexposn = winsaveview()
-" call Decho("saving posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>"))
-" call Decho("saving t:netrw_lexposn",'~'.expand("<slnum>"))
close
if lexwinnr < curwin
let curwin= curwin - 1
@@ -1201,11 +1134,9 @@ fun! netrw#Lexplore(count,rightside,...)
exe curwin."wincmd w"
endif
unlet t:netrw_lexbufnr
-" call Decho("unlet t:netrw_lexbufnr")
else
" open netrw explorer window
-" call Decho("t:netrw_lexbufnr<n/a>: open netrw explorer window",'~'.expand("<slnum>"))
exe "1wincmd w"
let keep_altv = g:netrw_altv
let g:netrw_altv = 0
@@ -1214,18 +1145,13 @@ fun! netrw#Lexplore(count,rightside,...)
let g:netrw_winsize = a:count
endif
let curfile= expand("%")
-" call Decho("curfile<".curfile.">",'~'.expand("<slnum>"))
exe (a:rightside? "botright" : "topleft")." vertical ".((g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize) . " new"
-" call Decho("new buf#".bufnr("%")." win#".winnr())
if a:0 > 0 && a1 != ""
-" call Decho("case 1: Explore ".a1,'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,a1)
exe "Explore ".fnameescape(a1)
elseif curfile =~ '^\a\{3,}://'
-" call Decho("case 2: Explore ".substitute(curfile,'[^/\\]*$','',''),'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,substitute(curfile,'[^/\\]*$','',''))
else
-" call Decho("case 3: Explore .",'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,".")
endif
if a:count != 0
@@ -1238,11 +1164,7 @@ fun! netrw#Lexplore(count,rightside,...)
" Since the intended use of :Lexplore is to have an always-present explorer window, the extra
" effort to prevent mis-use of :Lex is warranted.
set bh=wipe
-" call Decho("let t:netrw_lexbufnr=".t:netrw_lexbufnr)
-" call Decho("t:netrw_lexposn".(exists("t:netrw_lexposn")? string(t:netrw_lexposn) : " n/a"))
if exists("t:netrw_lexposn")
-" call Decho("restoring to t:netrw_lexposn",'~'.expand("<slnum>"))
-" call Decho("restoring posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>"))
call winrestview(t:netrw_lexposn)
unlet t:netrw_lexposn
endif
@@ -1255,10 +1177,8 @@ fun! netrw#Lexplore(count,rightside,...)
else
let g:netrw_chgwin= 2
endif
-" call Decho("let g:netrw_chgwin=".g:netrw_chgwin)
endif
-" call Dret("netrw#Lexplore")
endfun
" ---------------------------------------------------------------------
@@ -1670,8 +1590,13 @@ fun! s:NetrwOptionsSave(vt)
let {a:vt}netrw_dirkeep = getcwd()
" call Decho("saving to ".a:vt."netrw_dirkeep<".{a:vt}netrw_dirkeep.">",'~'.expand("<slnum>"))
endif
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ sil! let {a:vt}netrw_starkeep = @*
+ sil! let {a:vt}netrw_pluskeep = @+
+ endif
sil! let {a:vt}netrw_slashkeep= @/
+" call Decho("(s:NetrwOptionsSave) lines=".&lines)
" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
" call Dret("s:NetrwOptionsSave : tab#".tabpagenr()." win#".winnr())
endfun
@@ -1742,29 +1667,20 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwOptionsRestore: restore options (based on prior s:NetrwOptionsSave) {{{2
fun! s:NetrwOptionsRestore(vt)
-" call Dfunc("s:NetrwOptionsRestore(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> winnr($)=".winnr("$"))
-" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
if !exists("{a:vt}netrw_optionsave")
-" call Decho("case ".a:vt."netrw_optionsave : doesn't exist",'~'.expand("<slnum>"))
-
- " filereadable() returns zero for remote files (e.g. scp://localhost//etc/fstab)
- if filereadable(expand("%")) || expand("%") =~# '^\w\+://\f\+/'
-" call Decho("..doing filetype detect anyway")
+ " filereadable() returns zero for remote files (e.g. scp://user@localhost//etc/fstab)
+ " Note: @ may not be in 'isfname', so '^\w\+://\f\+/' may not match
+ if filereadable(expand("%")) || expand("%") =~# '^\w\+://\f\+'
filetype detect
-" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
else
setl ft=netrw
endif
-" call Decho("..ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("s:NetrwOptionsRestore : ".a:vt."netrw_optionsave doesn't exist")
return
endif
unlet {a:vt}netrw_optionsave
if exists("+acd")
if exists("{a:vt}netrw_acdkeep")
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
let curdir = getcwd()
let &l:acd = {a:vt}netrw_acdkeep
unlet {a:vt}netrw_acdkeep
@@ -1773,53 +1689,43 @@ fun! s:NetrwOptionsRestore(vt)
endif
endif
endif
-" call Decho("(s:NetrwOptionsRestore) #1 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_aikeep","&l:ai")
call s:NetrwRestoreSetting(a:vt."netrw_awkeep","&l:aw")
call s:NetrwRestoreSetting(a:vt."netrw_blkeep","&l:bl")
call s:NetrwRestoreSetting(a:vt."netrw_btkeep","&l:bt")
call s:NetrwRestoreSetting(a:vt."netrw_bombkeep","&l:bomb")
-" call Decho("(s:NetrwOptionsRestore) #2 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cedit","&cedit")
call s:NetrwRestoreSetting(a:vt."netrw_cikeep","&l:ci")
call s:NetrwRestoreSetting(a:vt."netrw_cinkeep","&l:cin")
call s:NetrwRestoreSetting(a:vt."netrw_cinokeep","&l:cino")
call s:NetrwRestoreSetting(a:vt."netrw_comkeep","&l:com")
-" call Decho("(s:NetrwOptionsRestore) #3 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cpokeep","&l:cpo")
call s:NetrwRestoreSetting(a:vt."netrw_diffkeep","&l:diff")
call s:NetrwRestoreSetting(a:vt."netrw_fenkeep","&l:fen")
if exists("g:netrw_ffkeep") && g:netrw_ffkeep
call s:NetrwRestoreSetting(a:vt."netrw_ffkeep")","&l:ff")
endif
-" call Decho("(s:NetrwOptionsRestore) #4 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_fokeep" ,"&l:fo")
call s:NetrwRestoreSetting(a:vt."netrw_gdkeep" ,"&l:gd")
call s:NetrwRestoreSetting(a:vt."netrw_gokeep" ,"&go")
call s:NetrwRestoreSetting(a:vt."netrw_hidkeep" ,"&l:hidden")
-" call Decho("(s:NetrwOptionsRestore) #5 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_imkeep" ,"&l:im")
call s:NetrwRestoreSetting(a:vt."netrw_iskkeep" ,"&l:isk")
-" call Decho("(s:NetrwOptionsRestore) #6 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_lines" ,"&lines")
-" call Decho("(s:NetrwOptionsRestore) #7 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_lskeep" ,"&l:ls")
call s:NetrwRestoreSetting(a:vt."netrw_makeep" ,"&l:ma")
call s:NetrwRestoreSetting(a:vt."netrw_magickeep","&l:magic")
call s:NetrwRestoreSetting(a:vt."netrw_modkeep" ,"&l:mod")
call s:NetrwRestoreSetting(a:vt."netrw_nukeep" ,"&l:nu")
-" call Decho("(s:NetrwOptionsRestore) #8 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_rnukeep" ,"&l:rnu")
call s:NetrwRestoreSetting(a:vt."netrw_repkeep" ,"&l:report")
call s:NetrwRestoreSetting(a:vt."netrw_rokeep" ,"&l:ro")
call s:NetrwRestoreSetting(a:vt."netrw_selkeep" ,"&l:sel")
-" call Decho("(s:NetrwOptionsRestore) #9 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_spellkeep","&l:spell")
call s:NetrwRestoreSetting(a:vt."netrw_twkeep" ,"&l:tw")
call s:NetrwRestoreSetting(a:vt."netrw_wigkeep" ,"&l:wig")
call s:NetrwRestoreSetting(a:vt."netrw_wrapkeep" ,"&l:wrap")
call s:NetrwRestoreSetting(a:vt."netrw_writekeep","&l:write")
-" call Decho("(s:NetrwOptionsRestore) #10 lines=".&lines)
call s:NetrwRestoreSetting("s:yykeep","@@")
" former problem: start with liststyle=0; press <i> : result, following line resets l:ts.
" Fixed; in s:PerformListing, when w:netrw_liststyle is s:LONGLIST, will use a printf to pad filename with spaces
@@ -1850,24 +1756,18 @@ fun! s:NetrwOptionsRestore(vt)
unlet {a:vt}netrw_dirkeep
endif
endif
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+ call s:NetrwRestoreSetting(a:vt."netrw_starkeep","@*")
+ call s:NetrwRestoreSetting(a:vt."netrw_pluskeep","@+")
+ endif
call s:NetrwRestoreSetting(a:vt."netrw_slashkeep","@/")
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
-" call Decho("fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Decho("diff=".&l:diff." win#".winnr()." w:netrw_diffkeep=".(exists("w:netrw_diffkeep")? w:netrw_diffkeep : "doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("ts=".&l:ts,'~'.expand("<slnum>"))
" Moved the filetype detect here from NetrwGetFile() because remote files
" were having their filetype detect-generated settings overwritten by
" NetrwOptionRestore.
if &ft != "netrw"
-" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
filetype detect
-" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
endif
-" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
-" call Dret("s:NetrwOptionsRestore : tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> modified=".&modified." modifiable=".&modifiable." readonly=".&readonly)
endfun
" ---------------------------------------------------------------------
@@ -2818,36 +2718,27 @@ endfun
" netrw#SetTreetop: resets the tree top to the current directory/specified directory {{{2
" (implements the :Ntree command)
fun! netrw#SetTreetop(iscmd,...)
-" call Dfunc("netrw#SetTreetop(iscmd=".a:iscmd." ".((a:0 > 0)? a:1 : "").") a:0=".a:0)
-" call Decho("w:netrw_treetop<".w:netrw_treetop.">")
" iscmd==0: netrw#SetTreetop called using gn mapping
" iscmd==1: netrw#SetTreetop called using :Ntree from the command line
-" call Decho("(iscmd=".a:iscmd.": called using :Ntree from command line",'~'.expand("<slnum>"))
" clear out the current tree
if exists("w:netrw_treetop")
-" call Decho("clearing out current tree",'~'.expand("<slnum>"))
let inittreetop= w:netrw_treetop
unlet w:netrw_treetop
endif
if exists("w:netrw_treedict")
-" call Decho("freeing w:netrw_treedict",'~'.expand("<slnum>"))
unlet w:netrw_treedict
endif
-" call Decho("inittreetop<".(exists("inittreetop")? inittreetop : "n/a").">")
if (a:iscmd == 0 || a:1 == "") && exists("inittreetop")
let treedir = s:NetrwTreePath(inittreetop)
-" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
else
if isdirectory(s:NetrwFile(a:1))
-" call Decho("a:1<".a:1."> is a directory",'~'.expand("<slnum>"))
let treedir = a:1
let s:netrw_treetop = treedir
elseif exists("b:netrw_curdir") && (isdirectory(s:NetrwFile(b:netrw_curdir."/".a:1)) || a:1 =~ '^\a\{3,}://')
let treedir = b:netrw_curdir."/".a:1
let s:netrw_treetop = treedir
-" call Decho("a:1<".a:1."> is NOT a directory, using treedir<".treedir.">",'~'.expand("<slnum>"))
else
" normally the cursor is left in the message window.
" However, here this results in the directory being listed in the message window, which is not wanted.
@@ -2858,20 +2749,17 @@ fun! netrw#SetTreetop(iscmd,...)
let s:netrw_treetop = getcwd()
endif
endif
-" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
" determine if treedir is remote or local
let islocal= expand("%") !~ '^\a\{3,}://'
-" call Decho("islocal=".islocal,'~'.expand("<slnum>"))
" browse the resulting directory
if islocal
- call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(islocal,treedir))
+ call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(islocal,treedir,0))
else
- call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,treedir))
+ call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,treedir,0))
endif
-" call Dret("netrw#SetTreetop")
endfun
" ===========================================
@@ -3729,16 +3617,11 @@ endfun
" Often called via: Explore/e dirname/etc -> netrw#LocalBrowseCheck() -> s:NetrwBrowse()
fun! s:NetrwBrowse(islocal,dirname)
if !exists("w:netrw_liststyle")|let w:netrw_liststyle= g:netrw_liststyle|endif
-" call Dfunc("s:NetrwBrowse(islocal=".a:islocal." dirname<".a:dirname.">) liststyle=".w:netrw_liststyle." ".g:loaded_netrw." buf#".bufnr("%")."<".bufname("%")."> win#".winnr())
-" call Decho("fyi: modified=".&modified." modifiable=".&modifiable." readonly=".&readonly,'~'.expand("<slnum>"))
-" call Decho("fyi: tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
-" call Dredir("ls!","s:NetrwBrowse")
" save alternate-file's filename if w:netrw_rexlocal doesn't exist
" This is useful when one edits a local file, then :e ., then :Rex
if a:islocal && !exists("w:netrw_rexfile") && bufname("#") != ""
let w:netrw_rexfile= bufname("#")
-" call Decho("setting w:netrw_rexfile<".w:netrw_rexfile."> win#".winnr(),'~'.expand("<slnum>"))
endif
" s:NetrwBrowse : initialize history {{{3
@@ -3749,32 +3632,26 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : simplify the dirname (especially for ".."s in dirnames) {{{3
if a:dirname !~ '^\a\{3,}://'
let dirname= simplify(a:dirname)
-" call Decho("simplified dirname<".dirname.">")
else
let dirname= a:dirname
endif
" repoint t:netrw_lexbufnr if appropriate
if exists("t:netrw_lexbufnr") && bufnr("%") == t:netrw_lexbufnr
-" call Decho("set repointlexbufnr to true!")
let repointlexbufnr= 1
endif
" s:NetrwBrowse : sanity checks: {{{3
if exists("s:netrw_skipbrowse")
unlet s:netrw_skipbrowse
-" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." filename<".expand("%")."> win#".winnr()." ft<".&ft.">",'~'.expand("<slnum>"))
-" call Dret("s:NetrwBrowse : s:netrw_skipbrowse existed")
return
endif
if !exists("*shellescape")
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"netrw can't run -- your vim is missing shellescape()",69)
-" call Dret("s:NetrwBrowse : missing shellescape()")
return
endif
if !exists("*fnameescape")
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"netrw can't run -- your vim is missing fnameescape()",70)
-" call Dret("s:NetrwBrowse : missing fnameescape()")
return
endif
@@ -3784,53 +3661,39 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : re-instate any marked files {{{3
if has("syntax") && exists("g:syntax_on") && g:syntax_on
if exists("s:netrwmarkfilelist_{bufnr('%')}")
-" call Decho("clearing marked files",'~'.expand("<slnum>"))
exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
endif
endif
if a:islocal && exists("w:netrw_acdkeep") && w:netrw_acdkeep
" s:NetrwBrowse : set up "safe" options for local directory/file {{{3
-" call Decho("handle w:netrw_acdkeep:",'~'.expand("<slnum>"))
-" call Decho("NetrwKeepj lcd ".fnameescape(dirname)." (due to w:netrw_acdkeep=".w:netrw_acdkeep." - acd=".&acd.")",'~'.expand("<slnum>"))
if s:NetrwLcd(dirname)
-" call Dret("s:NetrwBrowse : lcd failure")
return
endif
- " call s:NetrwOptionsSafe() " tst952 failed with this enabled.
-" call Decho("getcwd<".getcwd().">",'~'.expand("<slnum>"))
elseif !a:islocal && dirname !~ '[\/]$' && dirname !~ '^"'
" s:NetrwBrowse : remote regular file handler {{{3
-" call Decho("handle remote regular file: dirname<".dirname.">",'~'.expand("<slnum>"))
if bufname(dirname) != ""
-" call Decho("edit buf#".bufname(dirname)." in win#".winnr(),'~'.expand("<slnum>"))
exe "NetrwKeepj b ".bufname(dirname)
else
" attempt transfer of remote regular file
-" call Decho("attempt transfer as regular file<".dirname.">",'~'.expand("<slnum>"))
" remove any filetype indicator from end of dirname, except for the
" "this is a directory" indicator (/).
" There shouldn't be one of those here, anyway.
let path= substitute(dirname,'[*=@|]\r\=$','','e')
-" call Decho("new path<".path.">",'~'.expand("<slnum>"))
call s:RemotePathAnalysis(dirname)
" s:NetrwBrowse : remote-read the requested file into current buffer {{{3
call s:NetrwEnew(dirname)
call s:NetrwOptionsSafe(a:islocal)
setl ma noro
-" call Decho("setl ma noro",'~'.expand("<slnum>"))
let b:netrw_curdir = dirname
let url = s:method."://".((s:user == "")? "" : s:user."@").s:machine.(s:port ? ":".s:port : "")."/".s:path
call s:NetrwBufRename(url)
exe "sil! NetrwKeepj keepalt doau BufReadPre ".fnameescape(s:fname)
sil call netrw#NetRead(2,url)
" netrw.vim and tar.vim have already handled decompression of the tarball; avoiding gzip.vim error
-" call Decho("url<".url.">",'~'.expand("<slnum>"))
-" call Decho("s:path<".s:path.">",'~'.expand("<slnum>"))
-" call Decho("s:fname<".s:fname.">",'~'.expand("<slnum>"))
if s:path =~ '.bz2'
exe "sil NetrwKeepj keepalt doau BufReadPost ".fnameescape(substitute(s:fname,'\.bz2$','',''))
elseif s:path =~ '.gz'
@@ -3845,11 +3708,7 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : save certain window-oriented variables into buffer-oriented variables {{{3
call s:SetBufWinVars()
call s:NetrwOptionsRestore("w:")
-" call Decho("setl ma nomod",'~'.expand("<slnum>"))
setl ma nomod noro
-" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-
-" call Dret("s:NetrwBrowse : file<".s:fname.">")
return
endif
@@ -3865,33 +3724,31 @@ fun! s:NetrwBrowse(islocal,dirname)
NetrwKeepj call s:NetrwMenu(1)
" get/set-up buffer {{{3
-" call Decho("saving position across a buffer refresh",'~'.expand("<slnum>"))
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+
+ " NetrwGetBuffer might change buffers but s:rexposn_X was set for the
+ " previous buffer
+ let prevbufnr = bufnr('%')
let reusing= s:NetrwGetBuffer(a:islocal,dirname)
+ if exists("s:rexposn_".prevbufnr)
+ let s:rexposn_{bufnr('%')} = s:rexposn_{prevbufnr}
+ endif
" maintain markfile highlighting
if has("syntax") && exists("g:syntax_on") && g:syntax_on
if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != ""
-" " call Decho("bufnr(%)=".bufnr('%'),'~'.expand("<slnum>"))
-" " call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/",'~'.expand("<slnum>"))
exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
else
-" " call Decho("2match none",'~'.expand("<slnum>"))
2match none
endif
endif
if reusing && line("$") > 1
call s:NetrwOptionsRestore("w:")
-" call Decho("setl noma nomod nowrap",'~'.expand("<slnum>"))
setl noma nomod nowrap
-" call Decho("(set noma nomod nowrap) ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("s:NetrwBrowse : re-using not-cleared buffer")
return
endif
" set b:netrw_curdir to the new directory name {{{3
-" call Decho("set b:netrw_curdir to the new directory name<".dirname."> (buf#".bufnr("%").")",'~'.expand("<slnum>"))
let b:netrw_curdir= dirname
if b:netrw_curdir =~ '[/\\]$'
let b:netrw_curdir= substitute(b:netrw_curdir,'[/\\]$','','e')
@@ -3912,24 +3769,18 @@ fun! s:NetrwBrowse(islocal,dirname)
if !a:islocal && b:netrw_curdir !~ '/$'
let b:netrw_curdir= b:netrw_curdir.'/'
endif
-" call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
" ------------
" (local only) {{{3
" ------------
if a:islocal
-" call Decho("local only:",'~'.expand("<slnum>"))
-
" Set up ShellCmdPost handling. Append current buffer to browselist
call s:LocalFastBrowser()
" handle g:netrw_keepdir: set vim's current directory to netrw's notion of the current directory {{{3
if !g:netrw_keepdir
-" call Decho("handle g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
-" call Decho("l:acd".(exists("&l:acd")? "=".&l:acd : " doesn't exist"),'~'.expand("<slnum>"))
if !exists("&l:acd") || !&l:acd
if s:NetrwLcd(b:netrw_curdir)
-" call Dret("s:NetrwBrowse : lcd failure")
return
endif
endif
@@ -3939,23 +3790,18 @@ fun! s:NetrwBrowse(islocal,dirname)
" remote handling: {{{3
" --------------------------------
else
-" call Decho("remote only:",'~'.expand("<slnum>"))
" analyze dirname and g:netrw_list_cmd {{{3
-" call Decho("b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "doesn't exist")."> dirname<".dirname.">",'~'.expand("<slnum>"))
if dirname =~# "^NetrwTreeListing\>"
let dirname= b:netrw_curdir
-" call Decho("(dirname was <NetrwTreeListing>) dirname<".dirname.">",'~'.expand("<slnum>"))
elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("b:netrw_curdir")
let dirname= substitute(b:netrw_curdir,'\\','/','g')
if dirname !~ '/$'
let dirname= dirname.'/'
endif
let b:netrw_curdir = dirname
-" call Decho("(liststyle is TREELIST) dirname<".dirname.">",'~'.expand("<slnum>"))
else
let dirname = substitute(dirname,'\\','/','g')
-" call Decho("(normal) dirname<".dirname.">",'~'.expand("<slnum>"))
endif
let dirpat = '^\(\w\{-}\)://\(\w\+@\)\=\([^/]\+\)/\(.*\)$'
@@ -3964,14 +3810,10 @@ fun! s:NetrwBrowse(islocal,dirname)
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"netrw doesn't understand your dirname<".dirname.">",20)
endif
NetrwKeepj call s:NetrwOptionsRestore("w:")
-" call Decho("setl noma nomod nowrap",'~'.expand("<slnum>"))
setl noma nomod nowrap
-" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("s:NetrwBrowse : badly formatted dirname<".dirname.">")
return
endif
let b:netrw_curdir= dirname
-" call Decho("b:netrw_curdir<".b:netrw_curdir."> (remote)",'~'.expand("<slnum>"))
endif " (additional remote handling)
" -------------------------------
@@ -3983,12 +3825,10 @@ fun! s:NetrwBrowse(islocal,dirname)
" restore option(s)
call s:NetrwOptionsRestore("w:")
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
" If there is a rexposn: restore position with rexposn
" Otherwise : set rexposn
if exists("s:rexposn_".bufnr("%"))
-" call Decho("restoring posn to s:rexposn_".bufnr('%')."<".string(s:rexposn_{bufnr('%')}).">",'~'.expand("<slnum>"))
NetrwKeepj call winrestview(s:rexposn_{bufnr('%')})
if exists("w:netrw_bannercnt") && line(".") < w:netrw_bannercnt
NetrwKeepj exe w:netrw_bannercnt
@@ -3998,28 +3838,22 @@ fun! s:NetrwBrowse(islocal,dirname)
endif
if v:version >= 700 && has("balloon_eval") && &beval == 0 && &l:bexpr == "" && !exists("g:netrw_nobeval")
let &l:bexpr= "netrw#BalloonHelp()"
-" call Decho("set up balloon help: l:bexpr=".&l:bexpr,'~'.expand("<slnum>"))
setl beval
endif
" repoint t:netrw_lexbufnr if appropriate
if exists("repointlexbufnr")
let t:netrw_lexbufnr= bufnr("%")
-" call Decho("repoint t:netrw_lexbufnr to #".t:netrw_lexbufnr)
endif
" restore position
if reusing
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
call winrestview(svpos)
endif
" The s:LocalBrowseRefresh() function is called by an autocmd
" installed by s:LocalFastBrowser() when g:netrw_fastbrowse <= 1 (ie. slow or medium speed).
" However, s:NetrwBrowse() causes the FocusGained event to fire the first time.
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("s:NetrwBrowse : did PerformListing ft<".&ft.">")
return
endfun
@@ -4512,41 +4346,30 @@ endfun
" islocal=0: remote browsing
" =1: local browsing
fun! s:NetrwListStyle(islocal)
-" call Dfunc("NetrwListStyle(islocal=".a:islocal.") w:netrw_liststyle=".w:netrw_liststyle)
-
let ykeep = @@
let fname = s:NetrwGetWord()
if !exists("w:netrw_liststyle")|let w:netrw_liststyle= g:netrw_liststyle|endif
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let w:netrw_liststyle = (w:netrw_liststyle + 1) % s:MAXLIST
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
-" call Decho("chgd w:netrw_liststyle to ".w:netrw_liststyle,'~'.expand("<slnum>"))
-" call Decho("b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "doesn't exist").">",'~'.expand("<slnum>"))
" repoint t:netrw_lexbufnr if appropriate
if exists("t:netrw_lexbufnr") && bufnr("%") == t:netrw_lexbufnr
-" call Decho("set repointlexbufnr to true!")
let repointlexbufnr= 1
endif
if w:netrw_liststyle == s:THINLIST
" use one column listing
-" call Decho("use one column list",'~'.expand("<slnum>"))
let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge')
elseif w:netrw_liststyle == s:LONGLIST
" use long list
-" call Decho("use long list",'~'.expand("<slnum>"))
let g:netrw_list_cmd = g:netrw_list_cmd." -l"
elseif w:netrw_liststyle == s:WIDELIST
" give wide list
-" call Decho("use wide list",'~'.expand("<slnum>"))
let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge')
elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
-" call Decho("use tree list",'~'.expand("<slnum>"))
let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge')
else
@@ -4556,25 +4379,19 @@ fun! s:NetrwListStyle(islocal)
let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge')
endif
setl ma noro
-" call Decho("setl ma noro",'~'.expand("<slnum>"))
" clear buffer - this will cause NetrwBrowse/LocalBrowseCheck to do a refresh
-" call Decho("clear buffer<".expand("%")."> with :%d",'~'.expand("<slnum>"))
sil! NetrwKeepj %d _
" following prevents tree listing buffer from being marked "modified"
-" call Decho("setl nomod",'~'.expand("<slnum>"))
setl nomod
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
" refresh the listing
-" call Decho("refresh the listing",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call s:NetrwCursor(0)
" repoint t:netrw_lexbufnr if appropriate
if exists("repointlexbufnr")
let t:netrw_lexbufnr= bufnr("%")
-" call Decho("repoint t:netrw_lexbufnr to #".t:netrw_lexbufnr)
endif
" restore position; keep cursor on the filename
@@ -4582,22 +4399,18 @@ fun! s:NetrwListStyle(islocal)
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-" call Dret("NetrwListStyle".(exists("w:netrw_liststyle")? ' : w:netrw_liststyle='.w:netrw_liststyle : ""))
endfun
" ---------------------------------------------------------------------
" s:NetrwBannerCtrl: toggles the display of the banner {{{2
fun! s:NetrwBannerCtrl(islocal)
-" call Dfunc("s:NetrwBannerCtrl(islocal=".a:islocal.") g:netrw_banner=".g:netrw_banner)
-
let ykeep= @@
" toggle the banner (enable/suppress)
let g:netrw_banner= !g:netrw_banner
" refresh the listing
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
" keep cursor on the filename
if g:netrw_banner && exists("w:netrw_bannercnt") && line(".") >= w:netrw_bannercnt
@@ -4625,24 +4438,20 @@ endfun
"
" With bang: deletes files/directories from Netrw's bookmark system
fun! s:NetrwBookmark(del,...)
-" call Dfunc("s:NetrwBookmark(del=".a:del.",...) a:0=".a:0)
if a:0 == 0
if &ft == "netrw"
let curbufnr = bufnr("%")
if exists("s:netrwmarkfilelist_{curbufnr}")
" for every filename in the marked list
-" call Decho("bookmark every filename in marked list",'~'.expand("<slnum>"))
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let islocal= expand("%") !~ '^\a\{3,}://'
for fname in s:netrwmarkfilelist_{curbufnr}
if a:del|call s:DeleteBookmark(fname)|else|call s:MakeBookmark(fname)|endif
endfor
let curdir = exists("b:netrw_curdir")? b:netrw_curdir : getcwd()
call s:NetrwUnmarkList(curbufnr,curdir)
- NetrwKeepj call s:NetrwRefresh(islocal,s:NetrwBrowseChgDir(islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(islocal,s:NetrwBrowseChgDir(islocal,'./',0))
NetrwKeepj call winrestview(svpos)
else
let fname= s:NetrwGetWord()
@@ -4651,7 +4460,6 @@ fun! s:NetrwBookmark(del,...)
else
" bookmark currently open file
-" call Decho("bookmark currently open file",'~'.expand("<slnum>"))
let fname= expand("%")
if a:del|call s:DeleteBookmark(fname)|else|call s:MakeBookmark(fname)|endif
endif
@@ -4662,7 +4470,6 @@ fun! s:NetrwBookmark(del,...)
" by deciding if the current file begins with an url
" Globbing cannot be done remotely.
let islocal= expand("%") !~ '^\a\{3,}://'
-" call Decho("bookmark specified file".((a:0>1)? "s" : ""),'~'.expand("<slnum>"))
let i = 1
while i <= a:0
if islocal
@@ -4674,9 +4481,7 @@ fun! s:NetrwBookmark(del,...)
else
let mbfiles= [a:{i}]
endif
-" call Decho("mbfiles".string(mbfiles),'~'.expand("<slnum>"))
for mbfile in mbfiles
-" call Decho("mbfile<".mbfile.">",'~'.expand("<slnum>"))
if a:del|call s:DeleteBookmark(mbfile)|else|call s:MakeBookmark(mbfile)|endif
endfor
let i= i + 1
@@ -4685,8 +4490,6 @@ fun! s:NetrwBookmark(del,...)
" update the menu
call s:NetrwBookmarkMenu()
-
-" call Dret("s:NetrwBookmark")
endfun
" ---------------------------------------------------------------------
@@ -4758,58 +4561,61 @@ endfun
" directory and a new directory name. Also, if the
" "new directory name" is actually a file,
" NetrwBrowseChgDir() edits the file.
-fun! s:NetrwBrowseChgDir(islocal,newdir,...)
-" call Dfunc("s:NetrwBrowseChgDir(islocal=".a:islocal."> newdir<".a:newdir.">) a:0=".a:0." win#".winnr()." curpos<".string(getpos("."))."> b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "").">")
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
-
+" cursor=0: newdir is relative to b:netrw_curdir
+" =1: newdir is relative to the path to the word under the cursor in
+" tree view
+fun! s:NetrwBrowseChgDir(islocal,newdir,cursor,...)
let ykeep= @@
if !exists("b:netrw_curdir")
" Don't try to change-directory: this can happen, for example, when netrw#ErrorMsg has been called
" and the current window is the NetrwMessage window.
let @@= ykeep
-" call Decho("b:netrw_curdir doesn't exist!",'~'.expand("<slnum>"))
-" call Decho("getcwd<".getcwd().">",'~'.expand("<slnum>"))
-" call Dredir("ls!","s:NetrwBrowseChgDir")
-" call Dret("s:NetrwBrowseChgDir")
return
endif
-" call Decho("b:netrw_curdir<".b:netrw_curdir.">")
" NetrwBrowseChgDir; save options and initialize {{{3
-" call Decho("saving options",'~'.expand("<slnum>"))
call s:SavePosn(s:netrw_posn)
NetrwKeepj call s:NetrwOptionsSave("s:")
NetrwKeepj call s:NetrwOptionsSafe(a:islocal)
- if has("win32")
- let dirname = substitute(b:netrw_curdir,'\\','/','ge')
+
+ let newdir = a:newdir
+ if a:cursor && exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treetop")
+ " dirname is the path to the word under the cursor
+ let dirname = s:NetrwTreePath(w:netrw_treetop)
+ " newdir resolves to a directory and points to a directory in dirname
+ " /tmp/test/folder_symlink/ -> /tmp/test/original_folder/
+ if a:islocal && fnamemodify(dirname, ':t') == newdir && isdirectory(resolve(dirname)) && resolve(dirname) == resolve(newdir)
+ let dirname = fnamemodify(resolve(dirname), ':p:h:h')
+ let newdir = fnamemodify(resolve(newdir), ':t')
+ endif
+ " Remove trailing "/"
+ let dirname = substitute(dirname, "/$", "", "")
+
+ " If the word under the cursor is a directory (except for ../), NetrwTreePath
+ " returns the full path, including the word under the cursor, remove it
+ if newdir =~ "/$" && newdir != "../"
+ let dirname = fnamemodify(dirname, ":h")
+ endif
else
let dirname = b:netrw_curdir
endif
- let newdir = a:newdir
+ if has("win32")
+ let dirname = substitute(dirname,'\\','/','ge')
+ endif
let dolockout = 0
let dorestore = 1
-" call Decho("win#".winnr(),'~'.expand("<slnum>"))
-" call Decho("dirname<".dirname.">",'~'.expand("<slnum>"))
-" call Decho("newdir<".newdir.">",'~'.expand("<slnum>"))
" ignore <cr>s when done in the banner
-" call Decho('(s:NetrwBrowseChgDir) ignore [return]s when done in banner (g:netrw_banner='.g:netrw_banner.")",'~'.expand("<slnum>"))
if g:netrw_banner
-" call Decho("win#".winnr()." w:netrw_bannercnt=".(exists("w:netrw_bannercnt")? w:netrw_bannercnt : 'n/a')." line(.)#".line('.')." line($)#".line("#"),'~'.expand("<slnum>"))
if exists("w:netrw_bannercnt") && line(".") < w:netrw_bannercnt && line("$") >= w:netrw_bannercnt
if getline(".") =~# 'Quick Help'
-" call Decho("#1: quickhelp=".g:netrw_quickhelp." ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
let g:netrw_quickhelp= (g:netrw_quickhelp + 1)%len(s:QuickHelp)
-" call Decho("#2: quickhelp=".g:netrw_quickhelp." ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
setl ma noro nowrap
NetrwKeepj call setline(line('.'),'" Quick Help: <F1>:help '.s:QuickHelp[g:netrw_quickhelp])
setl noma nomod nowrap
NetrwKeepj call s:NetrwOptionsRestore("s:")
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
endif
-" else " Decho
-" call Decho("g:netrw_banner=".g:netrw_banner." (no banner)",'~'.expand("<slnum>"))
endif
" set up o/s-dependent directory recognition pattern
@@ -4818,69 +4624,45 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
else
let dirpat= '[\/]$'
endif
-" call Decho("set up o/s-dependent directory recognition pattern: dirname<".dirname."> dirpat<".dirpat.">",'~'.expand("<slnum>"))
if dirname !~ dirpat
" apparently vim is "recognizing" that it is in a directory and
" is removing the trailing "/". Bad idea, so let's put it back.
let dirname= dirname.'/'
-" call Decho("adjusting dirname<".dirname.'> (put trailing "/" back)','~'.expand("<slnum>"))
endif
-" call Decho("[newdir<".newdir."> ".((newdir =~ dirpat)? "=~" : "!~")." dirpat<".dirpat.">] && [islocal=".a:islocal."] && [newdir is ".(isdirectory(s:NetrwFile(newdir))? "" : "not ")."a directory]",'~'.expand("<slnum>"))
if newdir !~ dirpat && !(a:islocal && isdirectory(s:NetrwFile(s:ComposePath(dirname,newdir))))
" ------------------------------
" NetrwBrowseChgDir: edit a file {{{3
" ------------------------------
-" call Decho('edit-a-file: case "handling a file": win#'.winnr().' newdir<'.newdir.'> !~ dirpat<'.dirpat.">",'~'.expand("<slnum>"))
" save position for benefit of Rexplore
let s:rexposn_{bufnr("%")}= winsaveview()
-" call Decho("edit-a-file: saving posn to s:rexposn_".bufnr("%")."<".string(s:rexposn_{bufnr("%")}).">",'~'.expand("<slnum>"))
-" call Decho("edit-a-file: win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> ft=".&ft,'~'.expand("<slnum>"))
-" call Decho("edit-a-file: w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a')." w:netrw_treedict:".(exists("w:netrw_treedict")? "exists" : 'n/a')." newdir<".newdir.">",'~'.expand("<slnum>"))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict") && newdir !~ '^\(/\|\a:\)'
-" call Decho("edit-a-file: handle tree listing: w:netrw_treedict<".(exists("w:netrw_treedict")? string(w:netrw_treedict) : 'n/a').">",'~'.expand("<slnum>"))
-" call Decho("edit-a-file: newdir<".newdir.">",'~'.expand("<slnum>"))
-" let newdir = s:NetrwTreePath(s:netrw_treetop)
-" call Decho("edit-a-file: COMBAK why doesn't this recognize file1's directory???")
- let dirname= s:NetrwTreeDir(a:islocal)
- "COMBAK : not working for a symlink -- but what about a regular file? a directory?
-" call Decho("COMBAK : not working for a symlink -- but what about a regular file? a directory?")
- " Feb 17, 2019: following if-else-endif restored -- wasn't editing a file in tree mode
if dirname =~ '/$'
let dirname= dirname.newdir
else
let dirname= dirname."/".newdir
endif
-" call Decho("edit-a-file: dirname<".dirname.">",'~'.expand("<slnum>"))
-" call Decho("edit-a-file: tree listing",'~'.expand("<slnum>"))
elseif newdir =~ '^\(/\|\a:\)'
-" call Decho("edit-a-file: handle an url or path starting with /: <".newdir.">",'~'.expand("<slnum>"))
let dirname= newdir
else
let dirname= s:ComposePath(dirname,newdir)
endif
-" call Decho("edit-a-file: handling a file: dirname<".dirname."> (a:0=".a:0.")",'~'.expand("<slnum>"))
" this lets netrw#BrowseX avoid the edit
if a:0 < 1
-" call Decho("edit-a-file: (a:0=".a:0."<1) set up windows for editing<".fnameescape(dirname)."> didsplit=".(exists("s:didsplit")? s:didsplit : "doesn't exist"),'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwOptionsRestore("s:")
let curdir= b:netrw_curdir
if !exists("s:didsplit")
-" " call Decho("edit-a-file: s:didsplit does not exist; g:netrw_browse_split=".string(g:netrw_browse_split)." win#".winnr()." g:netrw_chgwin=".g:netrw_chgwin",'~'.expand("<slnum>"))
if type(g:netrw_browse_split) == 3
" open file in server
" Note that g:netrw_browse_split is a List: [servername,tabnr,winnr]
-" call Decho("edit-a-file: open file in server",'~'.expand("<slnum>"))
call s:NetrwServerEdit(a:islocal,dirname)
-" call Dret("s:NetrwBrowseChgDir")
return
elseif g:netrw_browse_split == 1
" horizontally splitting the window first
-" call Decho("edit-a-file: horizontally splitting window prior to edit",'~'.expand("<slnum>"))
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
exe "keepalt ".(g:netrw_alto? "bel " : "abo ").winsz."wincmd s"
if !&ea
@@ -4890,7 +4672,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
elseif g:netrw_browse_split == 2
" vertically splitting the window first
-" call Decho("edit-a-file: vertically splitting window prior to edit",'~'.expand("<slnum>"))
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
exe "keepalt ".(g:netrw_alto? "top " : "bot ")."vert ".winsz."wincmd s"
if !&ea
@@ -4900,7 +4681,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
elseif g:netrw_browse_split == 3
" open file in new tab
-" call Decho("edit-a-file: opening new tab prior to edit",'~'.expand("<slnum>"))
keepalt tabnew
if !exists("b:netrw_curdir")
let b:netrw_curdir= getcwd()
@@ -4909,21 +4689,17 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
elseif g:netrw_browse_split == 4
" act like "P" (ie. open previous window)
-" call Decho("edit-a-file: use previous window for edit",'~'.expand("<slnum>"))
if s:NetrwPrevWinOpen(2) == 3
let @@= ykeep
-" call Dret("s:NetrwBrowseChgDir")
return
endif
call s:SetRexDir(a:islocal,curdir)
else
" handling a file, didn't split, so remove menu
-" call Decho("edit-a-file: handling a file+didn't split, so remove menu",'~'.expand("<slnum>"))
call s:NetrwMenu(0)
" optional change to window
if g:netrw_chgwin >= 1
-" call Decho("edit-a-file: changing window to #".g:netrw_chgwin.": (due to g:netrw_chgwin)",'~'.expand("<slnum>"))
if winnr("$")+1 == g:netrw_chgwin
" if g:netrw_chgwin is set to one more than the last window, then
" vertically split the last window to make that window available.
@@ -4947,21 +4723,17 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
let dolockout= 1
endif
if a:islocal
-" call Decho("edit-a-file: edit local file: exe e! ".fnameescape(dirname),'~'.expand("<slnum>"))
" some like c-^ to return to the last edited file
" others like c-^ to return to the netrw buffer
" Apr 30, 2020: used to have e! here. That can cause loss of a modified file,
" so emit error E37 instead.
call s:NetrwEditFile("e","",dirname)
-" call Decho("edit-a-file: after e ".dirname.": hidden=".&hidden." bufhidden<".&bufhidden."> mod=".&mod,'~'.expand("<slnum>"))
- " COMBAK -- cuc cul related
call s:NetrwCursor(1)
if &hidden || &bufhidden == "hide"
" file came from vim's hidden storage. Don't "restore" options with it.
let dorestore= 0
endif
else
-" call Decho("edit-a-file: remote file: NetrwBrowse will edit it",'~'.expand("<slnum>"))
endif
" handle g:Netrw_funcref -- call external-to-netrw functions
@@ -4969,12 +4741,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" or as a list of function references. It will ignore anything that's not
" a function reference. See :help Funcref for information about function references.
if exists("g:Netrw_funcref")
-" call Decho("edit-a-file: handle optional Funcrefs",'~'.expand("<slnum>"))
if type(g:Netrw_funcref) == 2
-" call Decho("edit-a-file: handling a g:Netrw_funcref",'~'.expand("<slnum>"))
NetrwKeepj call g:Netrw_funcref()
elseif type(g:Netrw_funcref) == 3
-" call Decho("edit-a-file: handling a list of g:Netrw_funcrefs",'~'.expand("<slnum>"))
for Fncref in g:Netrw_funcref
if type(Fncref) == 2
NetrwKeepj call Fncref()
@@ -4988,7 +4757,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" ----------------------------------------------------
" NetrwBrowseChgDir: just go to the new directory spec {{{3
" ----------------------------------------------------
-" call Decho('goto-newdir: case "just go to new directory spec": newdir<'.newdir.'>','~'.expand("<slnum>"))
let dirname = newdir
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
NetrwKeepj call s:NetrwOptionsRestore("s:")
@@ -4998,7 +4766,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" ---------------------------------------------
" NetrwBrowseChgDir: refresh the directory list {{{3
" ---------------------------------------------
-" call Decho('(s:NetrwBrowseChgDir)refresh-dirlist: case "refresh directory listing": newdir == "./"','~'.expand("<slnum>"))
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
norm! m`
@@ -5006,26 +4773,21 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" --------------------------------------
" NetrwBrowseChgDir: go up one directory {{{3
" --------------------------------------
-" call Decho('(s:NetrwBrowseChgDir)go-up: case "go up one directory": newdir == "../"','~'.expand("<slnum>"))
if w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
" force a refresh
-" call Decho("go-up: clear buffer<".expand("%")."> with :%d",'~'.expand("<slnum>"))
-" call Decho("go-up: setl noro ma",'~'.expand("<slnum>"))
setl noro ma
NetrwKeepj %d _
endif
if has("amiga")
" amiga
-" call Decho('go-up: case "go up one directory": newdir == "../" and amiga','~'.expand("<slnum>"))
if a:islocal
let dirname= substitute(dirname,'^\(.*[/:]\)\([^/]\+$\)','\1','')
let dirname= substitute(dirname,'/$','','')
else
let dirname= substitute(dirname,'^\(.*[/:]\)\([^/]\+/$\)','\1','')
endif
-" call Decho("go-up: amiga: dirname<".dirname."> (go up one dir)",'~'.expand("<slnum>"))
elseif !g:netrw_cygwin && has("win32")
" windows
@@ -5040,11 +4802,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
if dirname =~ '^\a:$'
let dirname= dirname.'/'
endif
-" call Decho("go-up: windows: dirname<".dirname."> (go up one dir)",'~'.expand("<slnum>"))
else
" unix or cygwin
-" call Decho('(s:NetrwBrowseChgDir)go-up: case "go up one directory": newdir == "../" and unix or cygwin','~'.expand("<slnum>"))
if a:islocal
let dirname= substitute(dirname,'^\(.*\)/\([^/]\+\)/$','\1','')
if dirname == ""
@@ -5053,7 +4813,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
else
let dirname= substitute(dirname,'^\(\a\{3,}://.\{-}/\{1,2}\)\(.\{-}\)\([^/]\+\)/$','\1\2','')
endif
-" call Decho("go-up: unix: dirname<".dirname."> (go up one dir)",'~'.expand("<slnum>"))
endif
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
norm! m`
@@ -5062,69 +4821,48 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" --------------------------------------
" NetrwBrowseChgDir: Handle Tree Listing {{{3
" --------------------------------------
-" call Decho('(s:NetrwBrowseChgDir)tree-list: case liststyle is TREELIST and w:netrw_treedict exists','~'.expand("<slnum>"))
" force a refresh (for TREELIST, NetrwTreeDir() will force the refresh)
-" call Decho("tree-list: setl noro ma",'~'.expand("<slnum>"))
setl noro ma
if !(exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("b:netrw_curdir"))
-" call Decho("tree-list: clear buffer<".expand("%")."> with :%d (force refresh)",'~'.expand("<slnum>"))
NetrwKeepj %d _
endif
let treedir = s:NetrwTreeDir(a:islocal)
-" call Decho("tree-list: treedir<".treedir.">",'~'.expand("<slnum>"))
let s:treecurpos = winsaveview()
let haskey = 0
-" call Decho("tree-list: w:netrw_treedict<".string(w:netrw_treedict).">",'~'.expand("<slnum>"))
" search treedict for tree dir as-is
-" call Decho("tree-list: search treedict for tree dir as-is",'~'.expand("<slnum>"))
if has_key(w:netrw_treedict,treedir)
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : found it!','~'.expand("<slnum>"))
let haskey= 1
else
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
endif
" search treedict for treedir with a [/@] appended
-" call Decho("tree-list: search treedict for treedir with a [/@] appended",'~'.expand("<slnum>"))
if !haskey && treedir !~ '[/@]$'
if has_key(w:netrw_treedict,treedir."/")
let treedir= treedir."/"
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
let haskey = 1
else
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'/> : not found','~'.expand("<slnum>"))
endif
endif
" search treedict for treedir with any trailing / elided
-" call Decho("tree-list: search treedict for treedir with any trailing / elided",'~'.expand("<slnum>"))
if !haskey && treedir =~ '/$'
let treedir= substitute(treedir,'/$','','')
if has_key(w:netrw_treedict,treedir)
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
let haskey = 1
else
-" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
endif
endif
-" call Decho("haskey=".haskey,'~'.expand("<slnum>"))
if haskey
" close tree listing for selected subdirectory
-" call Decho("tree-list: closing selected subdirectory<".dirname.">",'~'.expand("<slnum>"))
call remove(w:netrw_treedict,treedir)
-" call Decho("tree-list: removed entry<".treedir."> from treedict",'~'.expand("<slnum>"))
-" call Decho("tree-list: yielding treedict<".string(w:netrw_treedict).">",'~'.expand("<slnum>"))
let dirname= w:netrw_treetop
else
" go down one directory
let dirname= substitute(treedir,'/*$','/','')
-" call Decho("tree-list: go down one dir: treedir<".treedir.">",'~'.expand("<slnum>"))
-" call Decho("tree-list: ... : dirname<".dirname.">",'~'.expand("<slnum>"))
endif
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
-" call Decho("setting s:treeforceredraw to true",'~'.expand("<slnum>"))
let s:treeforceredraw = 1
else
@@ -5132,7 +4870,6 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" NetrwBrowseChgDir: Go down one directory {{{3
" ----------------------------------------
let dirname = s:ComposePath(dirname,newdir)
-" call Decho("go down one dir: dirname<".dirname."> newdir<".newdir.">",'~'.expand("<slnum>"))
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
norm! m`
endif
@@ -5143,29 +4880,18 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
if dorestore
" dorestore is zero'd when a local file was hidden or bufhidden;
" in such a case, we want to keep whatever settings it may have.
-" call Decho("doing option restore (dorestore=".dorestore.")",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwOptionsRestore("s:")
-" else " Decho
-" call Decho("skipping option restore (dorestore==0): hidden=".&hidden." bufhidden=".&bufhidden." mod=".&mod,'~'.expand("<slnum>"))
endif
if dolockout && dorestore
-" call Decho("restore: filewritable(dirname<".dirname.">)=".filewritable(dirname),'~'.expand("<slnum>"))
if filewritable(dirname)
-" call Decho("restore: doing modification lockout settings: ma nomod noro",'~'.expand("<slnum>"))
-" call Decho("restore: setl ma nomod noro",'~'.expand("<slnum>"))
setl ma noro nomod
-" call Decho("restore: ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
else
-" call Decho("restore: doing modification lockout settings: ma nomod ro",'~'.expand("<slnum>"))
-" call Decho("restore: setl ma nomod noro",'~'.expand("<slnum>"))
setl ma ro nomod
-" call Decho("restore: ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
endif
call s:RestorePosn(s:netrw_posn)
let @@= ykeep
-" call Dret("s:NetrwBrowseChgDir <".dirname."> : curpos<".string(getpos(".")).">")
return dirname
endfun
@@ -5174,19 +4900,16 @@ endfun
" for thin, long, and wide: cursor placed just after banner
" for tree, keeps cursor on current filename
fun! s:NetrwBrowseUpDir(islocal)
-" call Dfunc("s:NetrwBrowseUpDir(islocal=".a:islocal.")")
if exists("w:netrw_bannercnt") && line(".") < w:netrw_bannercnt-1
" this test needed because occasionally this function seems to be incorrectly called
" when multiple leftmouse clicks are taken when atop the one line help in the banner.
" I'm allowing the very bottom line to permit a "-" exit so that one may escape empty
" directories.
-" call Dret("s:NetrwBrowseUpDir : cursor not in file area")
return
endif
norm! 0
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
-" call Decho("case: treestyle",'~'.expand("<slnum>"))
let curline= getline(".")
let swwline= winline() - 1
if exists("w:netrw_treetop")
@@ -5200,22 +4923,18 @@ fun! s:NetrwBrowseUpDir(islocal)
let curfile = getline(".")
let curpath = s:NetrwTreePath(w:netrw_treetop)
if a:islocal
- call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,'../'))
+ call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,'../',0))
else
- call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../'))
+ call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../',0))
endif
-" call Decho("looking for curfile<^".s:treedepthstring.curfile.">",'~'.expand("<slnum>"))
-" call Decho("having curpath<".curpath.">",'~'.expand("<slnum>"))
if w:netrw_treetop == '/'
keepj call search('^\M'.curfile,"w")
elseif curfile == '../'
keepj call search('^\M'.curfile,"wb")
else
-" call Decho("search(^\\M".s:treedepthstring.curfile.") backwards"))
while 1
keepj call search('^\M'.s:treedepthstring.curfile,"wb")
let treepath= s:NetrwTreePath(w:netrw_treetop)
-" call Decho("..current treepath<".treepath.">",'~'.expand("<slnum>"))
if treepath == curpath
break
endif
@@ -5223,7 +4942,6 @@ fun! s:NetrwBrowseUpDir(islocal)
endif
else
-" call Decho("case: not treestyle",'~'.expand("<slnum>"))
call s:SavePosn(s:netrw_posn)
if exists("b:netrw_curdir")
let curdir= b:netrw_curdir
@@ -5231,44 +4949,140 @@ fun! s:NetrwBrowseUpDir(islocal)
let curdir= expand(getcwd())
endif
if a:islocal
- call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,'../'))
+ call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,'../',0))
else
- call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../'))
+ call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../',0))
endif
call s:RestorePosn(s:netrw_posn)
let curdir= substitute(curdir,'^.*[\/]','','')
let curdir= '\<'. escape(curdir, '~'). '/'
call search(curdir,'wc')
endif
-" call Dret("s:NetrwBrowseUpDir")
endfun
+func s:redir()
+ " set up redirection (avoids browser messages)
+ " by default if not set, g:netrw_suppress_gx_mesg is true
+ if get(g:, 'netrw_suppress_gx_mesg', 1)
+ if &srr =~# "%s"
+ return printf(&srr, has("win32") ? "nul" : "/dev/null")
+ else
+ return &srr .. (has("win32") ? "nul" : "/dev/null")
+ endif
+ endif
+ return ''
+endfunc
+
+if has('unix')
+ if has('win32unix')
+ " Cygwin provides cygstart
+ if executable('cygstart')
+ fun! netrw#Launch(args)
+ exe 'silent ! cygstart --hide' a:args s:redir() | redraw!
+ endfun
+ elseif !empty($MSYSTEM) && executable('start')
+ " MSYS2/Git Bash comes by default without cygstart; see
+ " https://www.msys2.org/wiki/How-does-MSYS2-differ-from-Cygwin
+ " Instead it provides /usr/bin/start script running `cmd.exe //c start`
+ " Adding "" //b` sets void title, hides cmd window and blocks path conversion
+ " of /b to \b\ " by MSYS2; see https://www.msys2.org/docs/filesystem-paths/
+ fun! netrw#Launch(args)
+ exe 'silent !start "" //b' a:args s:redir() | redraw!
+ endfun
+ else
+ " imitate /usr/bin/start script for other environments and hope for the best
+ fun! netrw#Launch(args)
+ exe 'silent !cmd //c start "" //b' a:args s:redir() | redraw!
+ endfun
+ endif
+ elseif exists('$WSL_DISTRO_NAME') " use cmd.exe to start GUI apps in WSL
+ fun! netrw#Launch(args)
+ let args = a:args
+ exe 'silent !' ..
+ \ ((args =~? '\v<\f+\.(exe|com|bat|cmd)>') ?
+ \ 'cmd.exe /c start /b ' .. args :
+ \ 'nohup ' .. args .. ' ' .. s:redir() .. ' &')
+ \ | redraw!
+ endfun
+ else
+ fun! netrw#Launch(args)
+ exe ':silent ! nohup' a:args s:redir() '&' | redraw!
+ endfun
+ endif
+elseif has('win32')
+ fun! netrw#Launch(args)
+ exe 'silent !' .. (&shell =~? '\<cmd\.exe\>' ? '' : 'cmd.exe /c')
+ \ 'start "" /b' a:args s:redir() | redraw!
+ endfun
+else
+ fun! netrw#Launch(dummy)
+ echom 'No common launcher found'
+ endfun
+endif
+
+" Git Bash
+if has('win32unix')
+ " (cyg)start suffices
+ let s:os_viewer = ''
+" Windows / WSL
+elseif executable('explorer.exe')
+ let s:os_viewer = 'explorer.exe'
+" Linux / BSD
+elseif executable('xdg-open')
+ let s:os_viewer = 'xdg-open'
+" MacOS
+elseif executable('open')
+ let s:os_viewer = 'open'
+endif
+
+fun! s:viewer()
+ if exists('g:netrw_browsex_viewer') && executable(g:netrw_browsex_viewer)
+ " extract any viewing options. Assumes that they're set apart by spaces.
+ " call Decho("extract any viewing options from g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
+ if g:netrw_browsex_viewer =~ '\s'
+ let viewer = substitute(g:netrw_browsex_viewer,'\s.*$','','')
+ let viewopt = substitute(g:netrw_browsex_viewer,'^\S\+\s*','','')." "
+ let oviewer = ''
+ let cnt = 1
+ while !executable(viewer) && viewer != oviewer
+ let viewer = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\1','')
+ let viewopt = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\3','')." "
+ let cnt = cnt + 1
+ let oviewer = viewer
+ " call Decho("!exe: viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
+ endwhile
+ else
+ let viewer = g:netrw_browsex_viewer
+ let viewopt = ""
+ endif
+ " call Decho("viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
+ return viewer .. ' ' .. viewopt
+ else
+ if !exists('s:os_viewer')
+ call netrw#ErrorMsg(s:ERROR,"No program to open this path found. See :help Open for more information.",106)
+ else
+ return s:os_viewer
+ endif
+ endif
+endfun
+
+fun! netrw#Open(file) abort
+ call netrw#Launch(s:viewer() .. ' ' .. shellescape(a:file, 1))
+endf
+
+if !exists('g:netrw_regex_url')
+ let g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
+endif
+
" ---------------------------------------------------------------------
" netrw#BrowseX: (implements "x" and "gx") executes a special "viewer" script or program for the {{{2
" given filename; typically this means given their extension.
" 0=local, 1=remote
fun! netrw#BrowseX(fname,remote)
- let use_ctrlo= 1
-" call Dfunc("netrw#BrowseX(fname<".a:fname."> remote=".a:remote.") implements x and gx maps")
-
- if a:remote == 0 && isdirectory(a:fname)
- " if its really just a local directory, then do a "gf" instead
-" call Decho("remote≡0 and a:fname<".a:fname."> ".(isdirectory(a:fname)? "is a directory" : "is not a directory"),'~'.expand("<slnum>"))
-" call Decho("..appears to be a local directory; using e ".a:fname." instead",'~'.expand("<slnum>"))
- exe "e ".a:fname
-" call Dret("netrw#BrowseX")
- return
- elseif a:remote == 1 && a:fname !~ '^https\=:' && a:fname =~ '/$'
+ if a:remote == 1 && a:fname !~ '^https\=:' && a:fname =~ '/$'
" remote directory, not a webpage access, looks like an attempt to do a directory listing
-" call Decho("remote≡1 and a:fname<".a:fname.">",'~'.expand("<slnum>"))
-" call Decho("..and fname ".((a:fname =~ '^https\=:')? 'matches' : 'does not match').'^https\=:','~'.expand("<slnum>"))
-" call Decho("..and fname ".((a:fname =~ '/$')? 'matches' : 'does not match').' /$','~'.expand("<slnum>"))
-" call Decho("..appears to be a remote directory listing request; using gf instead",'~'.expand("<slnum>"))
norm! gf
-" call Dret("netrw#BrowseX")
- return
endif
-" call Decho("not a local file nor a webpage request",'~'.expand("<slnum>"))
if exists("g:netrw_browsex_viewer") && exists("g:netrw_browsex_support_remote") && !g:netrw_browsex_support_remote
let remote = a:remote
@@ -5278,7 +5092,6 @@ fun! netrw#BrowseX(fname,remote)
let ykeep = @@
let screenposn = winsaveview()
-" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
" need to save and restore aw setting as gx can invoke this function from non-netrw buffers
let awkeep = &aw
@@ -5289,22 +5102,18 @@ fun! netrw#BrowseX(fname,remote)
if exists("g:Netrw_corehandler")
if type(g:Netrw_corehandler) == 2
" g:Netrw_corehandler is a function reference (see :help Funcref)
-" call Decho("g:Netrw_corehandler is a funcref",'~'.expand("<slnum>"))
call g:Netrw_corehandler(s:NetrwFile(a:fname))
elseif type(g:Netrw_corehandler) == 3
" g:Netrw_corehandler is a List of function references (see :help Funcref)
-" call Decho("g:Netrw_corehandler is a List",'~'.expand("<slnum>"))
for Fncref in g:Netrw_corehandler
if type(Fncref) == 2
call Fncref(a:fname)
endif
endfor
endif
-" call Decho("restoring posn: screenposn<".string(screenposn).">,'~'.expand("<slnum>"))"
call winrestview(screenposn)
let @@= ykeep
let &aw= awkeep
-" call Dret("netrw#BrowseX : coredump handler invoked")
return
endif
endif
@@ -5318,171 +5127,35 @@ fun! netrw#BrowseX(fname,remote)
if exten =~ "[\\/]"
let exten= ""
endif
-" call Decho("exten<".exten.">",'~'.expand("<slnum>"))
if remote == 1
" create a local copy
-" call Decho("remote: remote=".remote.": create a local copy of <".a:fname.">",'~'.expand("<slnum>"))
setl bh=delete
call netrw#NetRead(3,a:fname)
" attempt to rename tempfile
let basename= substitute(a:fname,'^\(.*\)/\(.*\)\.\([^.]*\)$','\2','')
let newname = substitute(s:netrw_tmpfile,'^\(.*\)/\(.*\)\.\([^.]*\)$','\1/'.basename.'.\3','')
-" call Decho("basename<".basename.">",'~'.expand("<slnum>"))
-" call Decho("newname <".newname.">",'~'.expand("<slnum>"))
if s:netrw_tmpfile != newname && newname != ""
if rename(s:netrw_tmpfile,newname) == 0
" renaming succeeded
-" call Decho("renaming succeeded (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
let fname= newname
else
" renaming failed
-" call Decho("renaming failed (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
let fname= s:netrw_tmpfile
endif
else
let fname= s:netrw_tmpfile
endif
else
-" call Decho("local: remote=".remote.": handling local copy of <".a:fname.">",'~'.expand("<slnum>"))
let fname= a:fname
" special ~ handler for local
if fname =~ '^\~' && expand("$HOME") != ""
-" call Decho('invoking special ~ handler','~'.expand("<slnum>"))
let fname= s:NetrwFile(substitute(fname,'^\~',expand("$HOME"),''))
endif
endif
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
-" call Decho("exten<".exten."> "."netrwFileHandlers#NFH_".exten."():exists=".exists("*netrwFileHandlers#NFH_".exten),'~'.expand("<slnum>"))
-
- " set up redirection (avoids browser messages)
- " by default, g:netrw_suppress_gx_mesg is true
- if g:netrw_suppress_gx_mesg
- if &srr =~ "%s"
- if has("win32")
- let redir= substitute(&srr,"%s","nul","")
- else
- let redir= substitute(&srr,"%s","/dev/null","")
- endif
- elseif has("win32")
- let redir= &srr . "nul"
- else
- let redir= &srr . "/dev/null"
- endif
- else
- let redir= ""
- endif
-" call Decho("set up redirection: redir{".redir."} srr{".&srr."}",'~'.expand("<slnum>"))
-
- " extract any viewing options. Assumes that they're set apart by spaces.
- if exists("g:netrw_browsex_viewer")
-" call Decho("extract any viewing options from g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
- if g:netrw_browsex_viewer =~ '\s'
- let viewer = substitute(g:netrw_browsex_viewer,'\s.*$','','')
- let viewopt = substitute(g:netrw_browsex_viewer,'^\S\+\s*','','')." "
- let oviewer = ''
- let cnt = 1
- while !executable(viewer) && viewer != oviewer
- let viewer = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\1','')
- let viewopt = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\3','')." "
- let cnt = cnt + 1
- let oviewer = viewer
-" call Decho("!exe: viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
- endwhile
- else
- let viewer = g:netrw_browsex_viewer
- let viewopt = ""
- endif
-" call Decho("viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
- endif
-
- " execute the file handler
-" call Decho("execute the file handler (if any)",'~'.expand("<slnum>"))
- if exists("g:netrw_browsex_viewer") && g:netrw_browsex_viewer == '-'
-" call Decho("(netrw#BrowseX) g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
- let ret= netrwFileHandlers#Invoke(exten,fname)
-
- elseif exists("g:netrw_browsex_viewer") && executable(viewer)
-" call Decho("(netrw#BrowseX) g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !".viewer." ".viewopt.s:ShellEscape(fname,1).redir)
- let ret= v:shell_error
-
- elseif has("win32")
-" call Decho("(netrw#BrowseX) win".(has("win32")? "32" : "64"),'~'.expand("<slnum>"))
- if executable("start")
- call s:NetrwExe('sil! !start rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(fname,1))
- elseif executable("rundll32")
- call s:NetrwExe('sil! !rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(fname,1))
- else
- call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
- endif
- let ret= v:shell_error
-
- elseif has("win32unix")
- let winfname= 'c:\cygwin'.substitute(fname,'/','\\','g')
-" call Decho("(netrw#BrowseX) cygwin: winfname<".s:ShellEscape(winfname,1).">",'~'.expand("<slnum>"))
- if executable("start")
-" call Decho("(netrw#BrowseX) win32unix+start",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !start rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(winfname,1))
- elseif executable("rundll32")
-" call Decho("(netrw#BrowseX) win32unix+rundll32",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(winfname,1))
- elseif executable("cygstart")
-" call Decho("(netrw#BrowseX) win32unix+cygstart",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !cygstart '.s:ShellEscape(fname,1))
- else
- call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
- endif
- let ret= v:shell_error
-
- elseif has("unix") && $DESKTOP_SESSION == "mate" && executable("atril")
-" call Decho("(netrw#BrowseX) unix and atril",'~'.expand("<slnum>"))
- if a:fname =~ '^https\=://'
- " atril does not appear to understand how to handle html -- so use gvim to edit the document
- let use_ctrlo= 0
-" call Decho("fname<".fname.">")
-" call Decho("a:fname<".a:fname.">")
- call s:NetrwExe("sil! !gvim ".fname.' -c "keepj keepalt file '.fnameescape(a:fname).'"')
-
- else
- call s:NetrwExe("sil !atril ".s:ShellEscape(fname,1).redir)
- endif
- let ret= v:shell_error
-
- elseif has("unix") && executable("kfmclient") && s:CheckIfKde()
-" call Decho("(netrw#BrowseX) unix and kfmclient",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !kfmclient exec ".s:ShellEscape(fname,1)." ".redir)
- let ret= v:shell_error
-
- elseif has("unix") && executable("exo-open") && executable("xdg-open") && executable("setsid")
-" call Decho("(netrw#BrowseX) unix, exo-open, xdg-open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !setsid xdg-open ".s:ShellEscape(fname,1).redir.'&')
- let ret= v:shell_error
-
- elseif has("unix") && executable("xdg-open")
-" call Decho("(netrw#BrowseX) unix and xdg-open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !xdg-open ".s:ShellEscape(fname,1).redir.'&')
- let ret= v:shell_error
-
- elseif has("macunix") && executable("open")
-" call Decho("(netrw#BrowseX) macunix and open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !open ".s:ShellEscape(fname,1)." ".redir)
- let ret= v:shell_error
-
- else
- " netrwFileHandlers#Invoke() always returns 0
-" call Decho("(netrw#BrowseX) use netrwFileHandlers",'~'.expand("<slnum>"))
- let ret= netrwFileHandlers#Invoke(exten,fname)
- endif
-
- " if unsuccessful, attempt netrwFileHandlers#Invoke()
- if ret
-" call Decho("(netrw#BrowseX) ret=".ret," indicates unsuccessful thus far",'~'.expand("<slnum>"))
- let ret= netrwFileHandlers#Invoke(exten,fname)
- endif
- " restoring redraw! after external file handlers
- redraw!
+ " although shellescape(..., 1) is used in netrw#Open(), it's insufficient
+ call netrw#Open(escape(fname, '#%'))
" cleanup: remove temporary file,
" delete current buffer if success with handler,
@@ -5490,7 +5163,6 @@ fun! netrw#BrowseX(fname,remote)
" Feb 12, 2008: had to de-activate removal of
" temporary file because it wasn't getting seen.
" if remote == 1 && fname != a:fname
-"" call Decho("deleting temporary file<".fname.">",'~'.expand("<slnum>"))
" call s:NetrwDelete(fname)
" endif
@@ -5499,16 +5171,11 @@ fun! netrw#BrowseX(fname,remote)
if g:netrw_use_noswf
setl noswf
endif
- if use_ctrlo
- exe "sil! NetrwKeepj norm! \<c-o>"
- endif
+ exe "sil! NetrwKeepj norm! \<c-o>"
endif
-" call Decho("restoring posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
call winrestview(screenposn)
let @@ = ykeep
let &aw= awkeep
-
-" call Dret("netrw#BrowseX")
endfun
" ---------------------------------------------------------------------
@@ -5520,12 +5187,37 @@ fun! netrw#GX()
if &ft == "netrw"
let fname= s:NetrwGetWord()
else
- let fname= expand((exists("g:netrw_gx")? g:netrw_gx : '<cfile>'))
+ let fname= exists("g:netrw_gx")? expand(g:netrw_gx) : s:GetURL()
endif
" call Dret("netrw#GX <".fname.">")
return fname
endfun
+fun! s:GetURL() abort
+ let URL = ''
+ if exists('*Netrw_get_URL_' .. &filetype)
+ let URL = call('Netrw_get_URL_' .. &filetype, [])
+ endif
+ if !empty(URL) | return URL | endif
+ " URLs end in letter, digit or forward slash
+ let URL = matchstr(expand("<cWORD>"), '\<' .. g:netrw_regex_url .. '\ze[^A-Za-z0-9/]*$')
+ if !empty(URL) | return URL | endif
+
+ " Is it a file in the current work dir ...
+ let file = expand("<cfile>")
+ if filereadable(file) | return file | endif
+ " ... or in that of the current buffer?
+ let path = fnamemodify(expand('%'), ':p')
+ if isdirectory(path)
+ let dir = path
+ elseif filereadable(path)
+ let dir = fnamemodify(path, ':h')
+ endif
+ if exists('dir') && filereadable(dir..'/'..file) | return dir..'/'..file | endif
+
+ return ''
+endf
+
" ---------------------------------------------------------------------
" netrw#BrowseXVis: used by gx in visual mode to select a file for browsing {{{2
fun! netrw#BrowseXVis()
@@ -5600,23 +5292,20 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwChgPerm: (implements "gp") change file permission {{{2
fun! s:NetrwChgPerm(islocal,curdir)
-" call Dfunc("s:NetrwChgPerm(islocal=".a:islocal." curdir<".a:curdir.">)")
let ykeep = @@
call inputsave()
let newperm= input("Enter new permission: ")
call inputrestore()
let chgperm= substitute(g:netrw_chgperm,'\<FILENAME\>',s:ShellEscape(expand("<cfile>")),'')
let chgperm= substitute(chgperm,'\<PERM\>',s:ShellEscape(newperm),'')
-" call Decho("chgperm<".chgperm.">",'~'.expand("<slnum>"))
call system(chgperm)
if v:shell_error != 0
NetrwKeepj call netrw#ErrorMsg(1,"changing permission on file<".expand("<cfile>")."> seems to have failed",75)
endif
if a:islocal
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
endif
let @@= ykeep
-" call Dret("s:NetrwChgPerm")
endfun
" ---------------------------------------------------------------------
@@ -5697,8 +5386,6 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwExploreListUniq: {{{2
fun! s:NetrwExploreListUniq(explist)
-" call Dfunc("s:NetrwExploreListUniq(explist<".string(a:explist).">)")
-
" this assumes that the list is already sorted
let newexplist= []
for member in a:explist
@@ -5707,15 +5394,12 @@ fun! s:NetrwExploreListUniq(explist)
let newexplist = newexplist + [ member ]
endif
endfor
-
-" call Dret("s:NetrwExploreListUniq newexplist<".string(newexplist).">")
return newexplist
endfun
" ---------------------------------------------------------------------
" s:NetrwForceChgDir: (gd support) Force treatment as a directory {{{2
fun! s:NetrwForceChgDir(islocal,newdir)
-" call Dfunc("s:NetrwForceChgDir(islocal=".a:islocal." newdir<".a:newdir.">)")
let ykeep= @@
if a:newdir !~ '/$'
" ok, looks like force is needed to get directory-style treatment
@@ -5726,15 +5410,13 @@ fun! s:NetrwForceChgDir(islocal,newdir)
else
let newdir= a:newdir.'/'
endif
-" call Decho("adjusting newdir<".newdir."> due to gd",'~'.expand("<slnum>"))
else
" should already be getting treatment as a directory
let newdir= a:newdir
endif
- let newdir= s:NetrwBrowseChgDir(a:islocal,newdir)
+ let newdir= s:NetrwBrowseChgDir(a:islocal,newdir,0)
call s:NetrwBrowse(a:islocal,newdir)
let @@= ykeep
-" call Dret("s:NetrwForceChgDir")
endfun
" ---------------------------------------------------------------------
@@ -5760,7 +5442,7 @@ fun! s:NetrwGlob(direntry,expr,pare)
endif
let w:netrw_liststyle= keep_liststyle
else
- let path= s:ComposePath(fnameescape(a:direntry),a:expr)
+ let path= s:ComposePath(fnameescape(a:direntry), a:expr)
if has("win32")
" escape [ so it is not detected as wildcard character, see :h wildcard
let path= substitute(path, '[', '[[]', 'g')
@@ -5774,25 +5456,22 @@ fun! s:NetrwGlob(direntry,expr,pare)
let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")')
endif
endif
-" call Dret("s:NetrwGlob ".string(filelist))
return filelist
endfun
" ---------------------------------------------------------------------
" s:NetrwForceFile: (gf support) Force treatment as a file {{{2
fun! s:NetrwForceFile(islocal,newfile)
-" call Dfunc("s:NetrwForceFile(islocal=".a:islocal." newdir<".a:newfile.">)")
if a:newfile =~ '[/@*=|\\]$'
let newfile= substitute(a:newfile,'.$','','')
else
let newfile= a:newfile
endif
if a:islocal
- call s:NetrwBrowseChgDir(a:islocal,newfile)
+ call s:NetrwBrowseChgDir(a:islocal,newfile,0)
else
- call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,newfile))
+ call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,newfile,0))
endif
-" call Dret("s:NetrwForceFile")
endfun
" ---------------------------------------------------------------------
@@ -5803,24 +5482,18 @@ endfun
" 1: show not-hidden files
" 2: show hidden files only
fun! s:NetrwHide(islocal)
-" call Dfunc("NetrwHide(islocal=".a:islocal.") g:netrw_hide=".g:netrw_hide)
let ykeep= @@
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist_{bufnr('%')}")
-" call Decho("((g:netrw_hide == 1)? "unhide" : "hide")." files in markfilelist<".string(s:netrwmarkfilelist_{bufnr("%")}).">",'~'.expand("<slnum>"))
-" call Decho("g:netrw_list_hide<".g:netrw_list_hide.">",'~'.expand("<slnum>"))
" hide the files in the markfile list
for fname in s:netrwmarkfilelist_{bufnr("%")}
-" call Decho("match(g:netrw_list_hide<".g:netrw_list_hide.'> fname<\<'.fname.'\>>)='.match(g:netrw_list_hide,'\<'.fname.'\>')." l:isk=".&l:isk,'~'.expand("<slnum>"))
if match(g:netrw_list_hide,'\<'.fname.'\>') != -1
" remove fname from hiding list
let g:netrw_list_hide= substitute(g:netrw_list_hide,'..\<'.escape(fname,g:netrw_fname_escape).'\>..','','')
let g:netrw_list_hide= substitute(g:netrw_list_hide,',,',',','g')
let g:netrw_list_hide= substitute(g:netrw_list_hide,'^,\|,$','','')
-" call Decho("unhide: g:netrw_list_hide<".g:netrw_list_hide.">",'~'.expand("<slnum>"))
else
" append fname to hiding list
if exists("g:netrw_list_hide") && g:netrw_list_hide != ""
@@ -5828,7 +5501,6 @@ fun! s:NetrwHide(islocal)
else
let g:netrw_list_hide= '\<'.escape(fname,g:netrw_fname_escape).'\>'
endif
-" call Decho("hide: g:netrw_list_hide<".g:netrw_list_hide.">",'~'.expand("<slnum>"))
endif
endfor
NetrwKeepj call s:NetrwUnmarkList(bufnr("%"),b:netrw_curdir)
@@ -5842,64 +5514,49 @@ fun! s:NetrwHide(islocal)
if g:netrw_hide && g:netrw_list_hide == ""
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"your hiding list is empty!",49)
let @@= ykeep
-" call Dret("NetrwHide")
return
endif
endif
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-" call Dret("NetrwHide")
endfun
" ---------------------------------------------------------------------
" s:NetrwHideEdit: allows user to edit the file/directory hiding list {{{2
fun! s:NetrwHideEdit(islocal)
-" call Dfunc("NetrwHideEdit(islocal=".a:islocal.")")
-
let ykeep= @@
" save current cursor position
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
" get new hiding list from user
call inputsave()
let newhide= input("Edit Hiding List: ",g:netrw_list_hide)
call inputrestore()
let g:netrw_list_hide= newhide
-" call Decho("new g:netrw_list_hide<".g:netrw_list_hide.">",'~'.expand("<slnum>"))
" refresh the listing
- sil NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,"./"))
+ sil NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,"./",0))
" restore cursor position
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
call winrestview(svpos)
let @@= ykeep
-
-" call Dret("NetrwHideEdit")
endfun
" ---------------------------------------------------------------------
" s:NetrwHidden: invoked by "gh" {{{2
fun! s:NetrwHidden(islocal)
-" call Dfunc("s:NetrwHidden()")
let ykeep= @@
" save current position
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
if g:netrw_list_hide =~ '\(^\|,\)\\(^\\|\\s\\s\\)\\zs\\.\\S\\+'
" remove .file pattern from hiding list
-" call Decho("remove .file pattern from hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= substitute(g:netrw_list_hide,'\(^\|,\)\\(^\\|\\s\\s\\)\\zs\\.\\S\\+','','')
elseif s:Strlen(g:netrw_list_hide) >= 1
-" call Decho("add .file pattern from hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= g:netrw_list_hide . ',\(^\|\s\s\)\zs\.\S\+'
else
-" call Decho("set .file pattern as hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= '\(^\|\s\s\)\zs\.\S\+'
endif
if g:netrw_list_hide =~ '^,'
@@ -5907,11 +5564,9 @@ fun! s:NetrwHidden(islocal)
endif
" refresh screen and return to saved position
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-" call Dret("s:NetrwHidden")
endfun
" ---------------------------------------------------------------------
@@ -5946,7 +5601,6 @@ fun! s:NetrwLeftmouse(islocal)
if &ft != "netrw"
return
endif
-" call Dfunc("s:NetrwLeftmouse(islocal=".a:islocal.")")
let ykeep= @@
" check if the status bar was clicked on instead of a file/directory name
@@ -5958,36 +5612,30 @@ fun! s:NetrwLeftmouse(islocal)
let mouse_lnum = v:mouse_lnum
let wlastline = line('w$')
let lastline = line('$')
-" call Decho("v:mouse_lnum=".mouse_lnum." line(w$)=".wlastline." line($)=".lastline." v:mouse_win=".v:mouse_win." winnr#".winnr(),'~'.expand("<slnum>"))
-" call Decho("v:mouse_col =".v:mouse_col." col=".col(".")." wincol =".wincol()." winwidth =".winwidth(0),'~'.expand("<slnum>"))
if mouse_lnum >= wlastline + 1 || v:mouse_win != winnr()
" appears to be a status bar leftmouse click
let @@= ykeep
-" call Dret("s:NetrwLeftmouse : detected a status bar leftmouse click")
return
endif
" Dec 04, 2013: following test prevents leftmouse selection/deselection of directories and files in treelist mode
" Windows are separated by vertical separator bars - but the mouse seems to be doing what it should when dragging that bar
" without this test when its disabled.
" May 26, 2014: edit file, :Lex, resize window -- causes refresh. Reinstated a modified test. See if problems develop.
-" call Decho("v:mouse_col=".v:mouse_col." col#".col('.')." virtcol#".virtcol('.')." col($)#".col("$")." virtcol($)#".virtcol("$"),'~'.expand("<slnum>"))
if v:mouse_col > virtcol('.')
let @@= ykeep
-" call Dret("s:NetrwLeftmouse : detected a vertical separator bar leftmouse click")
return
endif
if a:islocal
if exists("b:netrw_curdir")
- NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord()))
+ NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord(),1))
endif
else
if exists("b:netrw_curdir")
- NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord()))
+ NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord(),1))
endif
endif
let @@= ykeep
-" call Dret("s:NetrwLeftmouse")
endfun
" ---------------------------------------------------------------------
@@ -5996,9 +5644,7 @@ fun! s:NetrwCLeftmouse(islocal)
if &ft != "netrw"
return
endif
-" call Dfunc("s:NetrwCLeftmouse(islocal=".a:islocal.")")
call s:NetrwMarkFileTgt(a:islocal)
-" call Dret("s:NetrwCLeftmouse")
endfun
" ---------------------------------------------------------------------
@@ -6011,39 +5657,30 @@ fun! s:NetrwServerEdit(islocal,fname)
" call Dfunc("s:NetrwServerEdit(islocal=".a:islocal.",fname<".a:fname.">)")
let islocal = a:islocal%2 " =0: remote =1: local
let ctrlr = a:islocal >= 2 " =0: <c-r> not used =1: <c-r> used
-" call Decho("islocal=".islocal." ctrlr=".ctrlr,'~'.expand("<slnum>"))
if (islocal && isdirectory(s:NetrwFile(a:fname))) || (!islocal && a:fname =~ '/$')
" handle directories in the local window -- not in the remote vim server
" user must have closed the NETRWSERVER window. Treat as normal editing from netrw.
-" call Decho("handling directory in client window",'~'.expand("<slnum>"))
let g:netrw_browse_split= 0
if exists("s:netrw_browse_split") && exists("s:netrw_browse_split_".winnr())
let g:netrw_browse_split= s:netrw_browse_split_{winnr()}
unlet s:netrw_browse_split_{winnr()}
endif
- call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,a:fname))
-" call Dret("s:NetrwServerEdit")
+ call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,a:fname,0))
return
endif
-" call Decho("handling file in server window",'~'.expand("<slnum>"))
if has("clientserver") && executable("gvim")
-" call Decho("has clientserver and gvim",'~'.expand("<slnum>"))
if exists("g:netrw_browse_split") && type(g:netrw_browse_split) == 3
-" call Decho("g:netrw_browse_split=".string(g:netrw_browse_split),'~'.expand("<slnum>"))
let srvrname = g:netrw_browse_split[0]
let tabnum = g:netrw_browse_split[1]
let winnum = g:netrw_browse_split[2]
if serverlist() !~ '\<'.srvrname.'\>'
-" call Decho("server not available; ctrlr=".ctrlr,'~'.expand("<slnum>"))
-
if !ctrlr
" user must have closed the server window and the user did not use <c-r>, but
" used something like <cr>.
-" call Decho("user must have closed server AND did not use ctrl-r",'~'.expand("<slnum>"))
if exists("g:netrw_browse_split")
unlet g:netrw_browse_split
endif
@@ -6051,50 +5688,40 @@ fun! s:NetrwServerEdit(islocal,fname)
if exists("s:netrw_browse_split_".winnr())
let g:netrw_browse_split= s:netrw_browse_split_{winnr()}
endif
- call s:NetrwBrowseChgDir(islocal,a:fname)
-" call Dret("s:NetrwServerEdit")
+ call s:NetrwBrowseChgDir(islocal,a:fname,0)
return
elseif has("win32") && executable("start")
" start up remote netrw server under windows
-" call Decho("starting up gvim server<".srvrname."> for windows",'~'.expand("<slnum>"))
call system("start gvim --servername ".srvrname)
else
" start up remote netrw server under linux
-" call Decho("starting up gvim server<".srvrname.">",'~'.expand("<slnum>"))
call system("gvim --servername ".srvrname)
endif
endif
-" call Decho("srvrname<".srvrname."> tabnum=".tabnum." winnum=".winnum." server-editing<".a:fname.">",'~'.expand("<slnum>"))
call remote_send(srvrname,":tabn ".tabnum."\<cr>")
call remote_send(srvrname,":".winnum."wincmd w\<cr>")
call remote_send(srvrname,":e ".fnameescape(s:NetrwFile(a:fname))."\<cr>")
-
else
if serverlist() !~ '\<'.g:netrw_servername.'\>'
if !ctrlr
-" call Decho("server<".g:netrw_servername."> not available and ctrl-r not used",'~'.expand("<slnum>"))
if exists("g:netrw_browse_split")
unlet g:netrw_browse_split
endif
let g:netrw_browse_split= 0
- call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,a:fname))
-" call Dret("s:NetrwServerEdit")
+ call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,a:fname,0))
return
else
-" call Decho("server<".g:netrw_servername."> not available but ctrl-r used",'~'.expand("<slnum>"))
if has("win32") && executable("start")
" start up remote netrw server under windows
-" call Decho("starting up gvim server<".g:netrw_servername."> for windows",'~'.expand("<slnum>"))
call system("start gvim --servername ".g:netrw_servername)
else
" start up remote netrw server under linux
-" call Decho("starting up gvim server<".g:netrw_servername.">",'~'.expand("<slnum>"))
call system("gvim --servername ".g:netrw_servername)
endif
endif
@@ -6102,7 +5729,6 @@ fun! s:NetrwServerEdit(islocal,fname)
while 1
try
-" call Decho("remote-send: e ".a:fname,'~'.expand("<slnum>"))
call remote_send(g:netrw_servername,":e ".fnameescape(s:NetrwFile(a:fname))."\<cr>")
break
catch /^Vim\%((\a\+)\)\=:E241/
@@ -6123,7 +5749,6 @@ fun! s:NetrwServerEdit(islocal,fname)
call netrw#ErrorMsg(s:ERROR,"you need a gui-capable vim and client-server to use <ctrl-r>",98)
endif
-" call Dret("s:NetrwServerEdit")
endfun
" ---------------------------------------------------------------------
@@ -6247,7 +5872,6 @@ endfun
" s:NetrwMakeDir: this function makes a directory (both local and remote) {{{2
" implements the "d" mapping.
fun! s:NetrwMakeDir(usrhost)
-" call Dfunc("s:NetrwMakeDir(usrhost<".a:usrhost.">)")
let ykeep= @@
" get name of new directory from user. A bare <CR> will skip.
@@ -6256,27 +5880,22 @@ fun! s:NetrwMakeDir(usrhost)
call inputsave()
let newdirname= input("Please give directory name: ")
call inputrestore()
-" call Decho("newdirname<".newdirname.">",'~'.expand("<slnum>"))
if newdirname == ""
let @@= ykeep
-" call Dret("s:NetrwMakeDir : user aborted with bare <cr>")
return
endif
if a:usrhost == ""
-" call Decho("local mkdir",'~'.expand("<slnum>"))
" Local mkdir:
" sanity checks
let fullnewdir= b:netrw_curdir.'/'.newdirname
-" call Decho("fullnewdir<".fullnewdir.">",'~'.expand("<slnum>"))
if isdirectory(s:NetrwFile(fullnewdir))
if !exists("g:netrw_quiet")
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"<".newdirname."> is already a directory!",24)
endif
let @@= ykeep
-" call Dret("s:NetrwMakeDir : directory<".newdirname."> exists previously")
return
endif
if s:FileReadable(fullnewdir)
@@ -6284,7 +5903,6 @@ fun! s:NetrwMakeDir(usrhost)
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"<".newdirname."> is already a file!",25)
endif
let @@= ykeep
-" call Dret("s:NetrwMakeDir : file<".newdirname."> exists previously")
return
endif
@@ -6299,21 +5917,16 @@ fun! s:NetrwMakeDir(usrhost)
else
let netrw_origdir= s:NetrwGetcwd(1)
if s:NetrwLcd(b:netrw_curdir)
-" call Dret("s:NetrwMakeDir : lcd failure")
return
endif
-" call Decho("netrw_origdir<".netrw_origdir.">: lcd b:netrw_curdir<".fnameescape(b:netrw_curdir).">",'~'.expand("<slnum>"))
call s:NetrwExe("sil! !".g:netrw_localmkdir.g:netrw_localmkdiropt.' '.s:ShellEscape(newdirname,1))
if v:shell_error != 0
let @@= ykeep
call netrw#ErrorMsg(s:ERROR,"consider setting g:netrw_localmkdir<".g:netrw_localmkdir."> to something that works",80)
-" call Dret("s:NetrwMakeDir : failed: sil! !".g:netrw_localmkdir.' '.s:ShellEscape(newdirname,1))
return
endif
if !g:netrw_keepdir
-" call Decho("restoring netrw_origdir since g:netrw_keepdir=".g:netrw_keepdir,'~'.expand("<slnum>"))
if s:NetrwLcd(netrw_origdir)
-" call Dret("s:NetrwBrowse : lcd failure")
return
endif
endif
@@ -6321,126 +5934,95 @@ fun! s:NetrwMakeDir(usrhost)
if v:shell_error == 0
" refresh listing
-" call Decho("refresh listing",'~'.expand("<slnum>"))
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
- call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
call winrestview(svpos)
elseif !exists("g:netrw_quiet")
call netrw#ErrorMsg(s:ERROR,"unable to make directory<".newdirname.">",26)
endif
-" redraw!
elseif !exists("b:netrw_method") || b:netrw_method == 4
" Remote mkdir: using ssh
-" call Decho("remote mkdir",'~'.expand("<slnum>"))
let mkdircmd = s:MakeSshCmd(g:netrw_mkdir_cmd)
let newdirname= substitute(b:netrw_curdir,'^\%(.\{-}/\)\{3}\(.*\)$','\1','').newdirname
call s:NetrwExe("sil! !".mkdircmd." ".s:ShellEscape(newdirname,1))
if v:shell_error == 0
" refresh listing
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./',0))
NetrwKeepj call winrestview(svpos)
elseif !exists("g:netrw_quiet")
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"unable to make directory<".newdirname.">",27)
endif
-" redraw!
elseif b:netrw_method == 2
" Remote mkdir: using ftp+.netrc
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
-" call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
if exists("b:netrw_fname")
-" call Decho("b:netrw_fname<".b:netrw_fname.">",'~'.expand("<slnum>"))
let remotepath= b:netrw_fname
else
let remotepath= ""
endif
call s:NetrwRemoteFtpCmd(remotepath,g:netrw_remote_mkdir.' "'.newdirname.'"')
- NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./',0))
NetrwKeepj call winrestview(svpos)
elseif b:netrw_method == 3
" Remote mkdir: using ftp + machine, id, passwd, and fname (ie. no .netrc)
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
-" call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
if exists("b:netrw_fname")
-" call Decho("b:netrw_fname<".b:netrw_fname.">",'~'.expand("<slnum>"))
let remotepath= b:netrw_fname
else
let remotepath= ""
endif
call s:NetrwRemoteFtpCmd(remotepath,g:netrw_remote_mkdir.' "'.newdirname.'"')
- NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./',0))
NetrwKeepj call winrestview(svpos)
endif
let @@= ykeep
-" call Dret("s:NetrwMakeDir")
endfun
" ---------------------------------------------------------------------
" s:TreeSqueezeDir: allows a shift-cr (gvim only) to squeeze the current tree-listing directory {{{2
fun! s:TreeSqueezeDir(islocal)
-" call Dfunc("s:TreeSqueezeDir(islocal=".a:islocal.")")
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
" its a tree-listing style
let curdepth = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e')
let stopline = (exists("w:netrw_bannercnt")? (w:netrw_bannercnt + 1) : 1)
let depth = strchars(substitute(curdepth,' ','','g'))
let srch = -1
-" call Decho("curdepth<".curdepth.'>','~'.expand("<slnum>"))
-" call Decho("depth =".depth,'~'.expand("<slnum>"))
-" call Decho("stopline#".stopline,'~'.expand("<slnum>"))
-" call Decho("curline#".line(".")."<".getline('.').'>','~'.expand("<slnum>"))
if depth >= 2
NetrwKeepj norm! 0
let curdepthm1= substitute(curdepth,'^'.s:treedepthstring,'','')
let srch = search('^'.curdepthm1.'\%('.s:treedepthstring.'\)\@!','bW',stopline)
-" call Decho("curdepthm1<".curdepthm1.'>','~'.expand("<slnum>"))
-" call Decho("case depth>=2: srch<".srch.'>','~'.expand("<slnum>"))
elseif depth == 1
NetrwKeepj norm! 0
let treedepthchr= substitute(s:treedepthstring,' ','','')
let srch = search('^[^'.treedepthchr.']','bW',stopline)
-" call Decho("case depth==1: srch<".srch.'>','~'.expand("<slnum>"))
endif
if srch > 0
-" call Decho("squeezing at line#".line(".").": ".getline('.'),'~'.expand("<slnum>"))
- call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,s:NetrwGetWord()))
+ call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,s:NetrwGetWord(),1))
exe srch
endif
endif
-" call Dret("s:TreeSqueezeDir")
endfun
" ---------------------------------------------------------------------
" s:NetrwMaps: {{{2
fun! s:NetrwMaps(islocal)
-" call Dfunc("s:NetrwMaps(islocal=".a:islocal.") b:netrw_curdir<".b:netrw_curdir.">")
" mouse <Plug> maps: {{{3
if g:netrw_mousemaps && g:netrw_retmap
" call Decho("set up Rexplore 2-leftmouse",'~'.expand("<slnum>"))
if !hasmapto("<Plug>NetrwReturn")
if maparg("<2-leftmouse>","n") == "" || maparg("<2-leftmouse>","n") =~ '^-$'
-" call Decho("making map for 2-leftmouse",'~'.expand("<slnum>"))
nmap <unique> <silent> <2-leftmouse> <Plug>NetrwReturn
elseif maparg("<c-leftmouse>","n") == ""
-" call Decho("making map for c-leftmouse",'~'.expand("<slnum>"))
nmap <unique> <silent> <c-leftmouse> <Plug>NetrwReturn
endif
endif
nno <silent> <Plug>NetrwReturn :Rexplore<cr>
-" call Decho("made <Plug>NetrwReturn map",'~'.expand("<slnum>"))
endif
" generate default <Plug> maps {{{3
@@ -6456,56 +6038,8 @@ fun! s:NetrwMaps(islocal)
if !hasmapto('<Plug>NetrwServerEdit') |nmap <buffer> <silent> <nowait> <c-r> <Plug>NetrwServerEdit|endif
if !hasmapto('<Plug>NetrwMakeDir') |nmap <buffer> <silent> <nowait> d <Plug>NetrwMakeDir|endif
if !hasmapto('<Plug>NetrwBookHistHandler_gb')|nmap <buffer> <silent> <nowait> gb <Plug>NetrwBookHistHandler_gb|endif
-" ---------------------------------------------------------------------
-" if !hasmapto('<Plug>NetrwForceChgDir') |nmap <buffer> <silent> <nowait> gd <Plug>NetrwForceChgDir|endif
-" if !hasmapto('<Plug>NetrwForceFile') |nmap <buffer> <silent> <nowait> gf <Plug>NetrwForceFile|endif
-" if !hasmapto('<Plug>NetrwHidden') |nmap <buffer> <silent> <nowait> gh <Plug>NetrwHidden|endif
-" if !hasmapto('<Plug>NetrwSetTreetop') |nmap <buffer> <silent> <nowait> gn <Plug>NetrwSetTreetop|endif
-" if !hasmapto('<Plug>NetrwChgPerm') |nmap <buffer> <silent> <nowait> gp <Plug>NetrwChgPerm|endif
-" if !hasmapto('<Plug>NetrwBannerCtrl') |nmap <buffer> <silent> <nowait> I <Plug>NetrwBannerCtrl|endif
-" if !hasmapto('<Plug>NetrwListStyle') |nmap <buffer> <silent> <nowait> i <Plug>NetrwListStyle|endif
-" if !hasmapto('<Plug>NetrwMarkMoveMF2Arglist')|nmap <buffer> <silent> <nowait> ma <Plug>NetrwMarkMoveMF2Arglist|endif
-" if !hasmapto('<Plug>NetrwMarkMoveArglist2MF')|nmap <buffer> <silent> <nowait> mA <Plug>NetrwMarkMoveArglist2MF|endif
-" if !hasmapto('<Plug>NetrwBookHistHandler_mA')|nmap <buffer> <silent> <nowait> mb <Plug>NetrwBookHistHandler_mA|endif
-" if !hasmapto('<Plug>NetrwBookHistHandler_mB')|nmap <buffer> <silent> <nowait> mB <Plug>NetrwBookHistHandler_mB|endif
-" if !hasmapto('<Plug>NetrwMarkFileCopy') |nmap <buffer> <silent> <nowait> mc <Plug>NetrwMarkFileCopy|endif
-" if !hasmapto('<Plug>NetrwMarkFileDiff') |nmap <buffer> <silent> <nowait> md <Plug>NetrwMarkFileDiff|endif
-" if !hasmapto('<Plug>NetrwMarkFileEdit') |nmap <buffer> <silent> <nowait> me <Plug>NetrwMarkFileEdit|endif
-" if !hasmapto('<Plug>NetrwMarkFile') |nmap <buffer> <silent> <nowait> mf <Plug>NetrwMarkFile|endif
-" if !hasmapto('<Plug>NetrwUnmarkList') |nmap <buffer> <silent> <nowait> mF <Plug>NetrwUnmarkList|endif
-" if !hasmapto('<Plug>NetrwMarkFileGrep') |nmap <buffer> <silent> <nowait> mg <Plug>NetrwMarkFileGrep|endif
-" if !hasmapto('<Plug>NetrwMarkHideSfx') |nmap <buffer> <silent> <nowait> mh <Plug>NetrwMarkHideSfx|endif
-" if !hasmapto('<Plug>NetrwMarkFileMove') |nmap <buffer> <silent> <nowait> mm <Plug>NetrwMarkFileMove|endif
-" if !hasmapto('<Plug>NetrwMarkFileRegexp') |nmap <buffer> <silent> <nowait> mr <Plug>NetrwMarkFileRegexp|endif
-" if !hasmapto('<Plug>NetrwMarkFileSource') |nmap <buffer> <silent> <nowait> ms <Plug>NetrwMarkFileSource|endif
-" if !hasmapto('<Plug>NetrwMarkFileTag') |nmap <buffer> <silent> <nowait> mT <Plug>NetrwMarkFileTag|endif
-" if !hasmapto('<Plug>NetrwMarkFileTgt') |nmap <buffer> <silent> <nowait> mt <Plug>NetrwMarkFileTgt|endif
-" if !hasmapto('<Plug>NetrwUnMarkFile') |nmap <buffer> <silent> <nowait> mu <Plug>NetrwUnMarkFile|endif
-" if !hasmapto('<Plug>NetrwMarkFileVimCmd') |nmap <buffer> <silent> <nowait> mv <Plug>NetrwMarkFileVimCmd|endif
-" if !hasmapto('<Plug>NetrwMarkFileExe_mx') |nmap <buffer> <silent> <nowait> mx <Plug>NetrwMarkFileExe_mx|endif
-" if !hasmapto('<Plug>NetrwMarkFileExe_mX') |nmap <buffer> <silent> <nowait> mX <Plug>NetrwMarkFileExe_mX|endif
-" if !hasmapto('<Plug>NetrwMarkFileCompress') |nmap <buffer> <silent> <nowait> mz <Plug>NetrwMarkFileCompress|endif
-" if !hasmapto('<Plug>NetrwObtain') |nmap <buffer> <silent> <nowait> O <Plug>NetrwObtain|endif
-" if !hasmapto('<Plug>NetrwSplit_o') |nmap <buffer> <silent> <nowait> o <Plug>NetrwSplit_o|endif
-" if !hasmapto('<Plug>NetrwPreview') |nmap <buffer> <silent> <nowait> p <Plug>NetrwPreview|endif
-" if !hasmapto('<Plug>NetrwPrevWinOpen') |nmap <buffer> <silent> <nowait> P <Plug>NetrwPrevWinOpen|endif
-" if !hasmapto('<Plug>NetrwBookHistHandler_qb')|nmap <buffer> <silent> <nowait> qb <Plug>NetrwBookHistHandler_qb|endif
-" if !hasmapto('<Plug>NetrwFileInfo') |nmap <buffer> <silent> <nowait> qf <Plug>NetrwFileInfo|endif
-" if !hasmapto('<Plug>NetrwMarkFileQFEL_qF') |nmap <buffer> <silent> <nowait> qF <Plug>NetrwMarkFileQFEL_qF|endif
-" if !hasmapto('<Plug>NetrwMarkFileQFEL_qL') |nmap <buffer> <silent> <nowait> qL <Plug>NetrwMarkFileQFEL_qL|endif
-" if !hasmapto('<Plug>NetrwSortStyle') |nmap <buffer> <silent> <nowait> s <Plug>NetrwSortStyle|endif
-" if !hasmapto('<Plug>NetSortSequence') |nmap <buffer> <silent> <nowait> S <Plug>NetSortSequence|endif
-" if !hasmapto('<Plug>NetrwSetTgt_Tb') |nmap <buffer> <silent> <nowait> Tb <Plug>NetrwSetTgt_Tb|endif
-" if !hasmapto('<Plug>NetrwSetTgt_Th') |nmap <buffer> <silent> <nowait> Th <Plug>NetrwSetTgt_Th|endif
-" if !hasmapto('<Plug>NetrwSplit_t') |nmap <buffer> <silent> <nowait> t <Plug>NetrwSplit_t|endif
-" if !hasmapto('<Plug>NetrwBookHistHandler_u') |nmap <buffer> <silent> <nowait> u <Plug>NetrwBookHistHandler_u|endif
-" if !hasmapto('<Plug>NetrwBookHistHandler_U') |nmap <buffer> <silent> <nowait> U <Plug>NetrwBookHistHandler_U|endif
-" if !hasmapto('<Plug>NetrwSplit_v') |nmap <buffer> <silent> <nowait> v <Plug>NetrwSplit_v|endif
-" if !hasmapto('<Plug>NetrwBrowseX') |nmap <buffer> <silent> <nowait> x <Plug>NetrwBrowseX|endif
-" if !hasmapto('<Plug>NetrwLocalExecute') |nmap <buffer> <silent> <nowait> X <Plug>NetrwLocalExecute|endif
if a:islocal
-" call Decho("make local maps",'~'.expand("<slnum>"))
" local normal-mode maps {{{3
nnoremap <buffer> <silent> <Plug>NetrwHide_a :<c-u>call <SID>NetrwHide(1)<cr>
nnoremap <buffer> <silent> <Plug>NetrwBrowseUpDir :<c-u>call <SID>NetrwBrowseUpDir(1)<cr>
@@ -6514,7 +6048,7 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <Plug>NetrwBadd_cB :<c-u>call <SID>NetrwBadd(1,1)<cr>
nnoremap <buffer> <silent> <Plug>NetrwLcd :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <Plug>NetrwSetChgwin :<c-u>call <SID>NetrwSetChgwin()<cr>
- nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr>
nnoremap <buffer> <silent> <Plug>NetrwServerEdit :<c-u>call <SID>NetrwServerEdit(3,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <Plug>NetrwMakeDir :<c-u>call <SID>NetrwMakeDir("")<cr>
nnoremap <buffer> <silent> <Plug>NetrwBookHistHandler_gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
@@ -6538,6 +6072,7 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mg :<c-u>call <SID>NetrwMarkFileGrep(1)<cr>
nnoremap <buffer> <silent> <nowait> mh :<c-u>call <SID>NetrwMarkHideSfx(1)<cr>
nnoremap <buffer> <silent> <nowait> mm :<c-u>call <SID>NetrwMarkFileMove(1)<cr>
+ "nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(1)<cr>
nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(1)<cr>
nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(1)<cr>
nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(1)<cr>
@@ -6549,7 +6084,7 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mz :<c-u>call <SID>NetrwMarkFileCompress(1)<cr>
nnoremap <buffer> <silent> <nowait> O :<c-u>call <SID>NetrwObtain(1)<cr>
nnoremap <buffer> <silent> <nowait> o :call <SID>NetrwSplit(3)<cr>
- nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr>
+ nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1,1))<cr>
nnoremap <buffer> <silent> <nowait> P :<c-u>call <SID>NetrwPrevWinOpen(1)<cr>
nnoremap <buffer> <silent> <nowait> qb :<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> qf :<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr>
@@ -6563,10 +6098,10 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> u :<c-u>call <SID>NetrwBookHistHandler(4,expand("%"))<cr>
nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,expand("%"))<cr>
nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(5)<cr>
- nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr>
+ nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1,0),0)"<cr>
nnoremap <buffer> <silent> <nowait> X :<c-u>call <SID>NetrwLocalExecute(expand("<cword>"))"<cr>
- nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr>
+ nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./',0))<cr>
if !hasmapto('<Plug>NetrwHideEdit')
nmap <buffer> <unique> <c-h> <Plug>NetrwHideEdit
endif
@@ -6574,7 +6109,7 @@ fun! s:NetrwMaps(islocal)
if !hasmapto('<Plug>NetrwRefresh')
nmap <buffer> <unique> <c-l> <Plug>NetrwRefresh
endif
- nnoremap <buffer> <silent> <Plug>NetrwRefresh <c-l>:call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(exists("w:netrw_liststyle") && exists("w:netrw_treetop") && w:netrw_liststyle == 3)? w:netrw_treetop : './'))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwRefresh <c-l>:call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(exists("w:netrw_liststyle") && exists("w:netrw_treetop") && w:netrw_liststyle == 3)? w:netrw_treetop : './',0))<cr>
if s:didstarstar || !mapcheck("<s-down>","n")
nnoremap <buffer> <silent> <s-down> :Nexplore<cr>
endif
@@ -6618,7 +6153,6 @@ fun! s:NetrwMaps(islocal)
else
" remote normal-mode maps {{{3
-" call Decho("make remote maps",'~'.expand("<slnum>"))
call s:RemotePathAnalysis(b:netrw_curdir)
nnoremap <buffer> <silent> <Plug>NetrwHide_a :<c-u>call <SID>NetrwHide(0)<cr>
nnoremap <buffer> <silent> <Plug>NetrwBrowseUpDir :<c-u>call <SID>NetrwBrowseUpDir(0)<cr>
@@ -6627,8 +6161,8 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <Plug>NetrwBadd_cB :<c-u>call <SID>NetrwBadd(0,1)<cr>
nnoremap <buffer> <silent> <Plug>NetrwLcd :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <Plug>NetrwSetChgwin :<c-u>call <SID>NetrwSetChgwin()<cr>
- nnoremap <buffer> <silent> <Plug>NetrwRefresh :<c-u>call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
- nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwRefresh :<c-u>call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./',0))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord(),1))<cr>
nnoremap <buffer> <silent> <Plug>NetrwServerEdit :<c-u>call <SID>NetrwServerEdit(2,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <Plug>NetrwBookHistHandler_gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
" ---------------------------------------------------------------------
@@ -6650,6 +6184,7 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mg :<c-u>call <SID>NetrwMarkFileGrep(0)<cr>
nnoremap <buffer> <silent> <nowait> mh :<c-u>call <SID>NetrwMarkHideSfx(0)<cr>
nnoremap <buffer> <silent> <nowait> mm :<c-u>call <SID>NetrwMarkFileMove(0)<cr>
+ "nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(0)<cr>
nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(0)<cr>
nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(0)<cr>
nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(0)<cr>
@@ -6661,13 +6196,13 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mz :<c-u>call <SID>NetrwMarkFileCompress(0)<cr>
nnoremap <buffer> <silent> <nowait> O :<c-u>call <SID>NetrwObtain(0)<cr>
nnoremap <buffer> <silent> <nowait> o :call <SID>NetrwSplit(0)<cr>
- nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr>
+ nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1,1))<cr>
nnoremap <buffer> <silent> <nowait> P :<c-u>call <SID>NetrwPrevWinOpen(0)<cr>
nnoremap <buffer> <silent> <nowait> qb :<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> qf :<c-u>call <SID>NetrwFileInfo(0,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(0,getqflist())<cr>
nnoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(0,getloclist(v:count))<cr>
- nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
+ nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./',0))<cr>
nnoremap <buffer> <silent> <nowait> s :call <SID>NetrwSortStyle(0)<cr>
nnoremap <buffer> <silent> <nowait> S :<c-u>call <SID>NetSortSequence(0)<cr>
nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt(0,'b',v:count1)<cr>
@@ -6676,7 +6211,8 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> u :<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(2)<cr>
- nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr>
+ nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord(),1),1)<cr>
+ nmap <buffer> <nowait> gx x
if !hasmapto('<Plug>NetrwHideEdit')
nmap <buffer> <c-h> <Plug>NetrwHideEdit
endif
@@ -6692,7 +6228,7 @@ fun! s:NetrwMaps(islocal)
let mapsafepath = escape(s:path, s:netrw_map_escape)
let mapsafeusermach = escape(((s:user == "")? "" : s:user."@").s:machine, s:netrw_map_escape)
- nnoremap <buffer> <silent> <Plug>NetrwRefresh :call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwRefresh :call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./',0))<cr>
if g:netrw_mousemaps == 1
nmap <buffer> <leftmouse> <Plug>NetrwLeftmouse
nno <buffer> <silent> <Plug>NetrwLeftmouse :exec "norm! \<lt>leftmouse>"<bar>call <SID>NetrwLeftmouse(0)<cr>
@@ -6724,8 +6260,6 @@ fun! s:NetrwMaps(islocal)
" support user-specified maps
call netrw#UserMaps(0)
endif " }}}3
-
-" call Dret("s:NetrwMaps")
endfun
" ---------------------------------------------------------------------
@@ -6779,7 +6313,6 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwMarkTarget: implements :MT (mark target) {{{2
fun! s:NetrwMarkTarget(...)
-" call Dfunc("s:NetrwMarkTarget() a:0=".a:0)
if a:0 == 0 || (a:0 == 1 && a:1 == "")
let curdir = s:NetrwGetCurdir(1)
let tgt = b:netrw_curdir
@@ -6787,16 +6320,12 @@ fun! s:NetrwMarkTarget(...)
let curdir = s:NetrwGetCurdir((a:1 =~ '^\a\{3,}://')? 0 : 1)
let tgt = a:1
endif
-" call Decho("tgt<".tgt.">",'~'.expand("<slnum>"))
let s:netrwmftgt = tgt
let s:netrwmftgt_islocal = tgt !~ '^\a\{3,}://'
let curislocal = b:netrw_curdir !~ '^\a\{3,}://'
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
- call s:NetrwRefresh(curislocal,s:NetrwBrowseChgDir(curislocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ call s:NetrwRefresh(curislocal,s:NetrwBrowseChgDir(curislocal,'./',0))
call winrestview(svpos)
-" call Dret("s:NetrwMarkTarget")
endfun
" ---------------------------------------------------------------------
@@ -6939,10 +6468,7 @@ endfun
" mA: move the argument list to marked file list (tomflist=1)
" Uses the global marked file list
fun! s:NetrwMarkFileArgList(islocal,tomflist)
-" call Dfunc("s:NetrwMarkFileArgList(islocal=".a:islocal.",tomflist=".a:tomflist.")")
-
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
@@ -6950,7 +6476,6 @@ fun! s:NetrwMarkFileArgList(islocal,tomflist)
" mA: move argument list to marked file list
while argc()
let fname= argv(0)
-" call Decho("exe argdel ".fname,'~'.expand("<slnum>"))
exe "argdel ".fnameescape(fname)
call s:NetrwMarkFile(a:islocal,fname)
endwhile
@@ -6961,19 +6486,16 @@ fun! s:NetrwMarkFileArgList(islocal,tomflist)
" for every filename in the marked list
for fname in s:netrwmarkfilelist
-" call Decho("exe argadd ".fname,'~'.expand("<slnum>"))
exe "argadd ".fnameescape(fname)
endfor " for every file in the marked list
" unmark list and refresh
call s:NetrwUnmarkList(curbufnr,curdir)
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
endif
endif
-" call Dret("s:NetrwMarkFileArgList")
endfun
" ---------------------------------------------------------------------
@@ -6985,30 +6507,24 @@ endfun
" g:netrw_compress = "gzip"
" g:netrw_decompress = { ".gz" : "gunzip" , ".bz2" : "bunzip2" , ".zip" : "unzip" , ".tar" : "tar -xf", ".xz" : "unxz"}
fun! s:NetrwMarkFileCompress(islocal)
-" call Dfunc("s:NetrwMarkFileCompress(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
" sanity check
if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
-" call Dret("s:NetrwMarkFileCompress")
return
endif
-" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist_{curbufnr}") && exists("g:netrw_compress") && exists("g:netrw_decompress")
" for every filename in the marked list
for fname in s:netrwmarkfilelist_{curbufnr}
let sfx= substitute(fname,'^.\{-}\(\.\a\+\)$','\1','')
-" call Decho("extracted sfx<".sfx.">",'~'.expand("<slnum>"))
if exists("g:netrw_decompress['".sfx."']")
" fname has a suffix indicating that its compressed; apply associated decompression routine
let exe= g:netrw_decompress[sfx]
-" call Decho("fname<".fname."> is compressed so decompress with <".exe.">",'~'.expand("<slnum>"))
let exe= netrw#WinPath(exe)
if a:islocal
if g:netrw_keepdir
@@ -7041,11 +6557,9 @@ fun! s:NetrwMarkFileCompress(islocal)
endfor " for every file in the marked list
call s:NetrwUnmarkList(curbufnr,curdir)
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
endif
-" call Dret("s:NetrwMarkFileCompress")
endfun
" ---------------------------------------------------------------------
@@ -7385,9 +6899,7 @@ endfun
" mx enbloc=0: Uses the local marked-file list, applies command to each file individually
" mX enbloc=1: Uses the global marked-file list, applies command to entire list
fun! s:NetrwMarkFileExe(islocal,enbloc)
-" call Dfunc("s:NetrwMarkFileExe(islocal=".a:islocal.",enbloc=".a:enbloc.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
@@ -7396,19 +6908,15 @@ fun! s:NetrwMarkFileExe(islocal,enbloc)
" sanity check
if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
-" call Dret("s:NetrwMarkFileExe")
return
endif
-" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist_{curbufnr}")
" get the command
call inputsave()
let cmd= input("Enter command: ","","file")
call inputrestore()
-" call Decho("cmd<".cmd.">",'~'.expand("<slnum>"))
if cmd == ""
-" call Dret("s:NetrwMarkFileExe : early exit, empty command")
return
endif
@@ -7428,10 +6936,8 @@ fun! s:NetrwMarkFileExe(islocal,enbloc)
let xcmd= cmd.' '.fname
endif
if a:islocal
-" call Decho("local: xcmd<".xcmd.">",'~'.expand("<slnum>"))
let ret= system(xcmd)
else
-" call Decho("remote: xcmd<".xcmd.">",'~'.expand("<slnum>"))
let ret= s:RemoteSystem(xcmd)
endif
if v:shell_error < 0
@@ -7452,8 +6958,7 @@ fun! s:NetrwMarkFileExe(islocal,enbloc)
call s:NetrwUnmarkList(curbufnr,curdir)
" refresh the listing
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
else
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59)
@@ -7464,9 +6969,7 @@ fun! s:NetrwMarkFileExe(islocal,enbloc)
call inputsave()
let cmd= input("Enter command: ","","file")
call inputrestore()
-" call Decho("cmd<".cmd.">",'~'.expand("<slnum>"))
if cmd == ""
-" call Dret("s:NetrwMarkFileExe : early exit, empty command")
return
endif
if cmd =~ '%'
@@ -7485,13 +6988,10 @@ fun! s:NetrwMarkFileExe(islocal,enbloc)
call s:NetrwUnmarkAll()
" refresh the listing
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
endif
-
-" call Dret("s:NetrwMarkFileExe")
endfun
" ---------------------------------------------------------------------
@@ -7499,16 +6999,13 @@ endfun
" as the marked file(s) (toggles suffix presence)
" Uses the local marked file list.
fun! s:NetrwMarkHideSfx(islocal)
-" call Dfunc("s:NetrwMarkHideSfx(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curbufnr = bufnr("%")
" s:netrwmarkfilelist_{curbufnr}: the List of marked files
if exists("s:netrwmarkfilelist_{curbufnr}")
for fname in s:netrwmarkfilelist_{curbufnr}
-" call Decho("s:NetrwMarkFileCopy: fname<".fname.">",'~'.expand("<slnum>"))
" construct suffix pattern
if fname =~ '\.'
let sfxpat= "^.*".substitute(fname,'^.*\(\.[^. ]\+\)$','\1','')
@@ -7528,7 +7025,6 @@ fun! s:NetrwMarkHideSfx(islocal)
let itemnum= itemnum + 1
endfor
endif
-" call Decho("fname<".fname."> inhidelist=".inhidelist." sfxpat<".sfxpat.">",'~'.expand("<slnum>"))
if inhidelist
" remove sfxpat from list
call remove(hidelist,itemnum)
@@ -7543,57 +7039,45 @@ fun! s:NetrwMarkHideSfx(islocal)
endfor
" refresh the listing
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
else
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59)
endif
-
-" call Dret("s:NetrwMarkHideSfx")
endfun
" ---------------------------------------------------------------------
" s:NetrwMarkFileVimCmd: (invoked by mv) execute arbitrary vim command on marked files, one at a time {{{2
" Uses the local marked-file list.
fun! s:NetrwMarkFileVimCmd(islocal)
-" call Dfunc("s:NetrwMarkFileVimCmd(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
" sanity check
if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
-" call Dret("s:NetrwMarkFileVimCmd")
return
endif
-" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist_{curbufnr}")
" get the command
call inputsave()
let cmd= input("Enter vim command: ","","file")
call inputrestore()
-" call Decho("cmd<".cmd.">",'~'.expand("<slnum>"))
if cmd == ""
-" " call Dret("s:NetrwMarkFileVimCmd : early exit, empty command")
return
endif
" apply command to marked files. Substitute: filename -> %
" If no %, then append a space and the filename to the command
for fname in s:netrwmarkfilelist_{curbufnr}
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
if a:islocal
1split
exe "sil! NetrwKeepj keepalt e ".fnameescape(fname)
-" call Decho("local<".fname.">: exe ".cmd,'~'.expand("<slnum>"))
exe cmd
exe "sil! keepalt wq!"
else
-" call Decho("remote<".fname.">: exe ".cmd." : NOT SUPPORTED YET",'~'.expand("<slnum>"))
echo "sorry, \"mv\" not supported yet for remote files"
endif
endfor
@@ -7602,14 +7086,11 @@ fun! s:NetrwMarkFileVimCmd(islocal)
call s:NetrwUnmarkList(curbufnr,curdir)
" refresh the listing
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
else
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59)
endif
-
-" call Dret("s:NetrwMarkFileVimCmd")
endfun
" ---------------------------------------------------------------------
@@ -7617,16 +7098,13 @@ endfun
" as the marked file(s) (toggles suffix presence)
" Uses the local marked file list.
fun! s:NetrwMarkHideSfx(islocal)
-" call Dfunc("s:NetrwMarkHideSfx(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curbufnr = bufnr("%")
" s:netrwmarkfilelist_{curbufnr}: the List of marked files
if exists("s:netrwmarkfilelist_{curbufnr}")
for fname in s:netrwmarkfilelist_{curbufnr}
-" call Decho("s:NetrwMarkFileCopy: fname<".fname.">",'~'.expand("<slnum>"))
" construct suffix pattern
if fname =~ '\.'
let sfxpat= "^.*".substitute(fname,'^.*\(\.[^. ]\+\)$','\1','')
@@ -7646,7 +7124,6 @@ fun! s:NetrwMarkHideSfx(islocal)
let itemnum= itemnum + 1
endfor
endif
-" call Decho("fname<".fname."> inhidelist=".inhidelist." sfxpat<".sfxpat.">",'~'.expand("<slnum>"))
if inhidelist
" remove sfxpat from list
call remove(hidelist,itemnum)
@@ -7661,14 +7138,11 @@ fun! s:NetrwMarkHideSfx(islocal)
endfor
" refresh the listing
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
else
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59)
endif
-
-" call Dret("s:NetrwMarkHideSfx")
endfun
" ---------------------------------------------------------------------
@@ -7872,6 +7346,46 @@ fun! s:NetrwMarkFileMove(islocal)
endfun
" ---------------------------------------------------------------------
+" s:NetrwMarkFilePrint: (invoked by mp) This function prints marked files {{{2
+" using the hardcopy command. Local marked-file list only.
+fun! s:NetrwMarkFilePrint(islocal)
+" call Dfunc("s:NetrwMarkFilePrint(islocal=".a:islocal.")")
+ let curbufnr= bufnr("%")
+
+ " sanity check
+ if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
+ NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
+" call Dret("s:NetrwMarkFilePrint")
+ return
+ endif
+" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
+ let curdir= s:NetrwGetCurdir(a:islocal)
+
+ if exists("s:netrwmarkfilelist_{curbufnr}")
+ let netrwmarkfilelist = s:netrwmarkfilelist_{curbufnr}
+ call s:NetrwUnmarkList(curbufnr,curdir)
+ for fname in netrwmarkfilelist
+ if a:islocal
+ if g:netrw_keepdir
+ let fname= s:ComposePath(curdir,fname)
+ endif
+ else
+ let fname= curdir.fname
+ endif
+ 1split
+ " the autocmds will handle both local and remote files
+" call Decho("exe sil e ".escape(fname,' '),'~'.expand("<slnum>"))
+ exe "sil NetrwKeepj e ".fnameescape(fname)
+" call Decho("hardcopy",'~'.expand("<slnum>"))
+ hardcopy
+ q
+ endfor
+ 2match none
+ endif
+" call Dret("s:NetrwMarkFilePrint")
+endfun
+
+" ---------------------------------------------------------------------
" s:NetrwMarkFileRegexp: (invoked by mr) This function is used to mark {{{2
" files when given a regexp (for which a prompt is
" issued) (matches to name of files).
@@ -7996,28 +7510,22 @@ endfun
" s:NetrwMarkFileTag: (invoked by mT) This function applies g:netrw_ctags to marked files {{{2
" Uses the global markfilelist
fun! s:NetrwMarkFileTag(islocal)
-" call Dfunc("s:NetrwMarkFileTag(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
" sanity check
if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
-" call Dret("s:NetrwMarkFileTag")
return
endif
-" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist")
-" call Decho("s:netrwmarkfilelist".string(s:netrwmarkfilelist).">",'~'.expand("<slnum>"))
let netrwmarkfilelist= join(map(deepcopy(s:netrwmarkfilelist), "s:ShellEscape(v:val,".!a:islocal.")"))
call s:NetrwUnmarkAll()
if a:islocal
-" call Decho("call system(".g:netrw_ctags." ".netrwmarkfilelist.")",'~'.expand("<slnum>"))
call system(g:netrw_ctags." ".netrwmarkfilelist)
if v:shell_error
call netrw#ErrorMsg(s:ERROR,"g:netrw_ctags<".g:netrw_ctags."> is not executable!",51)
@@ -8030,18 +7538,14 @@ fun! s:NetrwMarkFileTag(islocal)
1split
NetrwKeepj e tags
let path= substitute(curdir,'^\(.*\)/[^/]*$','\1/','')
-" call Decho("curdir<".curdir."> path<".path.">",'~'.expand("<slnum>"))
exe 'NetrwKeepj %s/\t\(\S\+\)\t/\t'.escape(path,"/\n\r\\").'\1\t/e'
call histdel("/",-1)
wq!
endif
2match none
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
call winrestview(svpos)
endif
-
-" call Dret("s:NetrwMarkFileTag")
endfun
" ---------------------------------------------------------------------
@@ -8051,9 +7555,7 @@ endfun
" s:netrwmftgt_islocal : 0=target directory is remote
" 1=target directory is local
fun! s:NetrwMarkFileTgt(islocal)
-" call Dfunc("s:NetrwMarkFileTgt(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curdir = s:NetrwGetCurdir(a:islocal)
let hadtgt = exists("s:netrwmftgt")
if !exists("w:netrw_bannercnt")
@@ -8062,46 +7564,36 @@ fun! s:NetrwMarkFileTgt(islocal)
" set up target
if line(".") < w:netrw_bannercnt
-" call Decho("set up target: line(.) < w:netrw_bannercnt=".w:netrw_bannercnt,'~'.expand("<slnum>"))
" if cursor in banner region, use b:netrw_curdir for the target unless its already the target
if exists("s:netrwmftgt") && exists("s:netrwmftgt_islocal") && s:netrwmftgt == b:netrw_curdir
-" call Decho("cursor in banner region, and target already is <".b:netrw_curdir.">: removing target",'~'.expand("<slnum>"))
unlet s:netrwmftgt s:netrwmftgt_islocal
if g:netrw_fastbrowse <= 1
call s:LocalBrowseRefresh()
endif
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
call winrestview(svpos)
-" call Dret("s:NetrwMarkFileTgt : removed target")
return
else
let s:netrwmftgt= b:netrw_curdir
-" call Decho("inbanner: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>"))
endif
else
" get word under cursor.
" * If directory, use it for the target.
" * If file, use b:netrw_curdir for the target
-" call Decho("get word under cursor",'~'.expand("<slnum>"))
let curword= s:NetrwGetWord()
let tgtdir = s:ComposePath(curdir,curword)
if a:islocal && isdirectory(s:NetrwFile(tgtdir))
let s:netrwmftgt = tgtdir
-" call Decho("local isdir: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>"))
elseif !a:islocal && tgtdir =~ '/$'
let s:netrwmftgt = tgtdir
-" call Decho("remote isdir: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>"))
else
let s:netrwmftgt = curdir
-" call Decho("isfile: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>"))
endif
endif
if a:islocal
" simplify the target (eg. /abc/def/../ghi -> /abc/ghi)
let s:netrwmftgt= simplify(s:netrwmftgt)
-" call Decho("simplify: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>"))
endif
if g:netrw_cygwin
let s:netrwmftgt= substitute(system("cygpath ".s:ShellEscape(s:netrwmftgt)),'\n$','','')
@@ -8112,24 +7604,18 @@ fun! s:NetrwMarkFileTgt(islocal)
" need to do refresh so that the banner will be updated
" s:LocalBrowseRefresh handles all local-browsing buffers when not fast browsing
if g:netrw_fastbrowse <= 1
-" call Decho("g:netrw_fastbrowse=".g:netrw_fastbrowse.", so refreshing all local netrw buffers",'~'.expand("<slnum>"))
call s:LocalBrowseRefresh()
endif
-" call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+" call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,w:netrw_treetop))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,w:netrw_treetop,0))
else
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
endif
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
call winrestview(svpos)
if !hadtgt
sil! NetrwKeepj norm! j
endif
-
-" call Decho("getmatches=".string(getmatches()),'~'.expand("<slnum>"))
-" call Decho("s:netrwmarkfilelist=".(exists("s:netrwmarkfilelist")? string(s:netrwmarkfilelist) : 'n/a'),'~'.expand("<slnum>"))
-" call Dret("s:NetrwMarkFileTgt : netrwmftgt<".(exists("s:netrwmftgt")? s:netrwmftgt : "").">")
endfun
" ---------------------------------------------------------------------
@@ -8248,7 +7734,7 @@ fun! netrw#Shrink()
elseif winwidth(bufwinnr(t:netrw_lexbufnr)) >= 0
exe "vert resize ".t:netrw_winwidth
" call Decho("vert resize ".t:netrw_winwidth,'~'.expand("<slnum>"))
- else
+ else
call netrw#Lexplore(0,0)
endif
@@ -8263,23 +7749,17 @@ endfun
" ---------------------------------------------------------------------
" s:NetSortSequence: allows user to edit the sorting sequence {{{2
fun! s:NetSortSequence(islocal)
-" call Dfunc("NetSortSequence(islocal=".a:islocal.")")
-
let ykeep= @@
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
call inputsave()
let newsortseq= input("Edit Sorting Sequence: ",g:netrw_sort_sequence)
call inputrestore()
" refresh the listing
let g:netrw_sort_sequence= newsortseq
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-
-" call Dret("NetSortSequence")
endfun
" ---------------------------------------------------------------------
@@ -8350,9 +7830,7 @@ endfun
" Marked files suitable for use with 2match are in:
" s:netrwmarkfilemtch_# -- used with 2match to display marked files
fun! s:NetrwUnMarkFile(islocal)
-" call Dfunc("s:NetrwUnMarkFile(islocal=".a:islocal.")")
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let curbufnr = bufnr("%")
" unmark marked file list
@@ -8372,10 +7850,8 @@ fun! s:NetrwUnMarkFile(islocal)
endwhile
2match none
-" call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-"call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+" call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
call winrestview(svpos)
-" call Dret("s:NetrwUnMarkFile")
endfun
" ---------------------------------------------------------------------
@@ -8510,69 +7986,47 @@ endfun
" choice = 2 : didn't save modified file, opened window
" choice = 3 : cancel open
fun! s:NetrwPrevWinOpen(islocal)
-" call Dfunc("s:NetrwPrevWinOpen(islocal=".a:islocal.") win#".winnr())
-
let ykeep= @@
" grab a copy of the b:netrw_curdir to pass it along to newly split windows
let curdir = b:netrw_curdir
-" call Decho("COMBAK#1: mod=".&mod." win#".winnr())
" get last window number and the word currently under the cursor
let origwin = winnr()
let lastwinnr = winnr("$")
-" call Decho("origwin#".origwin." lastwinnr#".lastwinnr)
-" call Decho("COMBAK#2: mod=".&mod." win#".winnr())
let curword = s:NetrwGetWord()
let choice = 0
let s:prevwinopen= 1 " lets s:NetrwTreeDir() know that NetrwPrevWinOpen called it (s:NetrwTreeDir() will unlet s:prevwinopen)
-" call Decho("COMBAK#3: mod=".&mod." win#".winnr())
let s:treedir = s:NetrwTreeDir(a:islocal)
-" call Decho("COMBAK#4: mod=".&mod." win#".winnr())
let curdir = s:treedir
-" call Decho("COMBAK#5: mod=".&mod." win#".winnr())
-" call Decho("winnr($)#".lastwinnr." curword<".curword.">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#6: mod=".&mod." win#".winnr())
let didsplit = 0
if lastwinnr == 1
" if only one window, open a new one first
-" call Decho("only one window, so open a new one (g:netrw_alto=".g:netrw_alto.")",'~'.expand("<slnum>"))
" g:netrw_preview=0: preview window shown in a horizontally split window
" g:netrw_preview=1: preview window shown in a vertically split window
if g:netrw_preview
" vertically split preview window
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
-" call Decho("exe ".(g:netrw_alto? "top " : "bot ")."vert ".winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "top " : "bot ")."vert ".winsz."wincmd s"
else
" horizontally split preview window
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
-" call Decho("exe ".(g:netrw_alto? "bel " : "abo ").winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "bel " : "abo ").winsz."wincmd s"
endif
let didsplit = 1
-" call Decho("did split",'~'.expand("<slnum>"))
else
-" call Decho("COMBAK#7: mod=".&mod." win#".winnr())
NetrwKeepj call s:SaveBufVars()
-" call Decho("COMBAK#8: mod=".&mod." win#".winnr())
let eikeep= &ei
-" call Decho("COMBAK#9: mod=".&mod." win#".winnr())
setl ei=all
-" call Decho("COMBAK#10: mod=".&mod." win#".winnr())
wincmd p
-" call Decho("COMBAK#11: mod=".&mod)
-" call Decho("wincmd p (now in win#".winnr().") curdir<".curdir.">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#12: mod=".&mod)
-
+
if exists("s:lexplore_win") && s:lexplore_win == winnr()
" whoops -- user trying to open file in the Lexplore window.
" Use Lexplore's opening-file window instead.
-" call Decho("whoops -- user trying to open file in Lexplore Window. Use win#".g:netrw_chgwin." instead")
" exe g:netrw_chgwin."wincmd w"
wincmd p
- call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord()))
+ call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord(),1))
endif
" prevwinnr: the window number of the "prev" window
@@ -8583,28 +8037,20 @@ fun! s:NetrwPrevWinOpen(islocal)
let prevbufname = bufname("%")
let prevmod = &mod
let bnrcnt = 0
-" call Decho("COMBAK#13: mod=".&mod." win#".winnr())
NetrwKeepj call s:RestoreBufVars()
-" call Decho("after wincmd p: win#".winnr()." win($)#".winnr("$")." origwin#".origwin." &mod=".&mod." bufname(%)<".bufname("%")."> prevbufnr=".prevbufnr,'~'.expand("<slnum>"))
-" call Decho("COMBAK#14: mod=".&mod." win#".winnr())
" if the previous window's buffer has been changed (ie. its modified flag is set),
" and it doesn't appear in any other extant window, then ask the
" user if s/he wants to abandon modifications therein.
if prevmod
-" call Decho("detected that prev window's buffer has been modified: prevbufnr=".prevbufnr." winnr()#".winnr(),'~'.expand("<slnum>"))
windo if winbufnr(0) == prevbufnr | let bnrcnt=bnrcnt+1 | endif
-" call Decho("prevbufnr=".prevbufnr." bnrcnt=".bnrcnt." buftype=".&bt." winnr()=".winnr()." prevwinnr#".prevwinnr,'~'.expand("<slnum>"))
exe prevwinnr."wincmd w"
-" call Decho("COMBAK#15: mod=".&mod." win#".winnr())
if bnrcnt == 1 && &hidden == 0
" only one copy of the modified buffer in a window, and
" hidden not set, so overwriting will lose the modified file. Ask first...
let choice = confirm("Save modified buffer<".prevbufname."> first?","&Yes\n&No\n&Cancel")
-" call Decho("prevbufname<".prevbufname."> choice=".choice." current-winnr#".winnr(),'~'.expand("<slnum>"))
let &ei= eikeep
-" call Decho("COMBAK#16: mod=".&mod." win#".winnr())
if choice == 1
" Yes -- write file & then browse
@@ -8615,41 +8061,35 @@ fun! s:NetrwPrevWinOpen(islocal)
exe origwin."wincmd w"
let &ei = eikeep
let @@ = ykeep
-" call Dret("s:NetrwPrevWinOpen ".choice." : unable to write <".prevbufname.">")
return choice
endif
elseif choice == 2
" No -- don't worry about changed file, just browse anyway
-" call Decho("don't worry about chgd file, just browse anyway (winnr($)#".winnr("$").")",'~'.expand("<slnum>"))
echomsg "**note** changes to ".prevbufname." abandoned"
else
" Cancel -- don't do this
-" call Decho("cancel, don't browse, switch to win#".origwin,'~'.expand("<slnum>"))
exe origwin."wincmd w"
let &ei= eikeep
let @@ = ykeep
-" call Dret("s:NetrwPrevWinOpen ".choice." : cancelled")
return choice
endif
endif
endif
let &ei= eikeep
endif
-" call Decho("COMBAK#17: mod=".&mod." win#".winnr())
" restore b:netrw_curdir (window split/enew may have lost it)
let b:netrw_curdir= curdir
if a:islocal < 2
if a:islocal
- call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(a:islocal,curword))
+ call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(a:islocal,curword,0))
else
- call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,curword))
+ call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,curword,0))
endif
endif
let @@= ykeep
-" call Dret("s:NetrwPrevWinOpen ".choice)
return choice
endfun
@@ -8956,32 +8396,25 @@ endfun
" Called by NetrwMarkFileCopy()
" Interfaces to s:NetrwRefresh() and s:LocalBrowseRefresh()
fun! s:NetrwRefreshDir(islocal,dirname)
-" call Dfunc("s:NetrwRefreshDir(islocal=".a:islocal." dirname<".a:dirname.">) g:netrw_fastbrowse=".g:netrw_fastbrowse)
if g:netrw_fastbrowse == 0
" slowest mode (keep buffers refreshed, local or remote)
-" call Decho("slowest mode: keep buffers refreshed, local or remote",'~'.expand("<slnum>"))
let tgtwin= bufwinnr(a:dirname)
-" call Decho("tgtwin= bufwinnr(".a:dirname.")=".tgtwin,'~'.expand("<slnum>"))
if tgtwin > 0
" tgtwin is being displayed, so refresh it
let curwin= winnr()
-" call Decho("refresh tgtwin#".tgtwin." (curwin#".curwin.")",'~'.expand("<slnum>"))
exe tgtwin."wincmd w"
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
exe curwin."wincmd w"
elseif bufnr(a:dirname) > 0
let bn= bufnr(a:dirname)
-" call Decho("bd bufnr(".a:dirname.")=".bn,'~'.expand("<slnum>"))
exe "sil keepj bd ".bn
endif
elseif g:netrw_fastbrowse <= 1
-" call Decho("medium-speed mode: refresh local buffers only",'~'.expand("<slnum>"))
NetrwKeepj call s:LocalBrowseRefresh()
endif
-" call Dret("s:NetrwRefreshDir")
endfun
" ---------------------------------------------------------------------
@@ -9121,18 +8554,13 @@ endfun
" =====================================================================
" s:NetrwSortStyle: change sorting style (name - time - size - exten) and refresh display {{{2
fun! s:NetrwSortStyle(islocal)
-" call Dfunc("s:NetrwSortStyle(islocal=".a:islocal.") netrw_sort_by<".g:netrw_sort_by.">")
NetrwKeepj call s:NetrwSaveWordPosn()
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let g:netrw_sort_by= (g:netrw_sort_by =~# '^n')? 'time' : (g:netrw_sort_by =~# '^t')? 'size' : (g:netrw_sort_by =~# '^siz')? 'exten' : 'name'
NetrwKeepj norm! 0
- NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
NetrwKeepj call winrestview(svpos)
-
-" call Dret("s:NetrwSortStyle : netrw_sort_by<".g:netrw_sort_by.">")
endfun
" ---------------------------------------------------------------------
@@ -9144,7 +8572,6 @@ endfun
" =4 : local and t
" =5 : local and v
fun! s:NetrwSplit(mode)
-" call Dfunc("s:NetrwSplit(mode=".a:mode.") alto=".g:netrw_alto." altv=".g:netrw_altv)
let ykeep= @@
call s:SaveWinVars()
@@ -9153,17 +8580,15 @@ fun! s:NetrwSplit(mode)
" remote and o
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
if winsz == 0|let winsz= ""|endif
-" call Decho("exe ".(g:netrw_alto? "bel " : "abo ").winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "bel " : "abo ").winsz."wincmd s"
let s:didsplit= 1
NetrwKeepj call s:RestoreWinVars()
- NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord()))
+ NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord(),1))
unlet s:didsplit
elseif a:mode == 1
" remote and t
- let newdir = s:NetrwBrowseChgDir(0,s:NetrwGetWord())
-" call Decho("tabnew",'~'.expand("<slnum>"))
+ let newdir = s:NetrwBrowseChgDir(0,s:NetrwGetWord(),1)
tabnew
let s:didsplit= 1
NetrwKeepj call s:RestoreWinVars()
@@ -9174,22 +8599,20 @@ fun! s:NetrwSplit(mode)
" remote and v
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
if winsz == 0|let winsz= ""|endif
-" call Decho("exe ".(g:netrw_altv? "rightb " : "lefta ").winsz."wincmd v",'~'.expand("<slnum>"))
exe (g:netrw_altv? "rightb " : "lefta ").winsz."wincmd v"
let s:didsplit= 1
NetrwKeepj call s:RestoreWinVars()
- NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord()))
+ NetrwKeepj call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord(),1))
unlet s:didsplit
elseif a:mode == 3
" local and o
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
if winsz == 0|let winsz= ""|endif
-" call Decho("exe ".(g:netrw_alto? "bel " : "abo ").winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "bel " : "abo ").winsz."wincmd s"
let s:didsplit= 1
NetrwKeepj call s:RestoreWinVars()
- NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord()))
+ NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord(),1))
unlet s:didsplit
elseif a:mode == 4
@@ -9206,12 +8629,11 @@ fun! s:NetrwSplit(mode)
exe "NetrwKeepj norm! ".netrw_line."G0".netrw_col."\<bar>"
let &ei = eikeep
let netrw_curdir = s:NetrwTreeDir(0)
-" call Decho("tabnew",'~'.expand("<slnum>"))
tabnew
let b:netrw_curdir = netrw_curdir
let s:didsplit = 1
NetrwKeepj call s:RestoreWinVars()
- NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,cursorword))
+ NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,cursorword,0))
if &ft == "netrw"
setl ei=all
exe "NetrwKeepj norm! ".netrw_hline."G0z\<CR>"
@@ -9224,11 +8646,10 @@ fun! s:NetrwSplit(mode)
" local and v
let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
if winsz == 0|let winsz= ""|endif
-" call Decho("exe ".(g:netrw_altv? "rightb " : "lefta ").winsz."wincmd v",'~'.expand("<slnum>"))
exe (g:netrw_altv? "rightb " : "lefta ").winsz."wincmd v"
let s:didsplit= 1
NetrwKeepj call s:RestoreWinVars()
- NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord()))
+ NetrwKeepj call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,s:NetrwGetWord(),1))
unlet s:didsplit
else
@@ -9236,7 +8657,6 @@ fun! s:NetrwSplit(mode)
endif
let @@= ykeep
-" call Dret("s:NetrwSplit")
endfun
" ---------------------------------------------------------------------
@@ -9306,91 +8726,49 @@ endfun
" s:NetrwTreeDir: determine tree directory given current cursor position {{{2
" (full path directory with trailing slash returned)
fun! s:NetrwTreeDir(islocal)
-" call Dfunc("s:NetrwTreeDir(islocal=".a:islocal.") getline(".line(".").")"."<".getline('.')."> b:netrw_curdir<".b:netrw_curdir."> tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> ft=".&ft)
-" call Decho("Determine tree directory given current cursor position")
-" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("w:netrw_treetop =".(exists("w:netrw_treetop")? w:netrw_treetop : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("current line<".getline(".").">")
if exists("s:treedir") && exists("s:prevwinopen")
" s:NetrwPrevWinOpen opens a "previous" window -- and thus needs to and does call s:NetrwTreeDir early
-" call Decho('s:NetrwPrevWinOpen opens a "previous" window -- and thus needs to and does call s:NetrwTreeDir early')
let treedir= s:treedir
unlet s:treedir
unlet s:prevwinopen
-" call Dret("s:NetrwTreeDir ".treedir.": early return since s:treedir existed previously")
return treedir
endif
if exists("s:prevwinopen")
unlet s:prevwinopen
endif
-" call Decho("COMBAK#18 : mod=".&mod." win#".winnr())
if !exists("b:netrw_curdir") || b:netrw_curdir == ""
let b:netrw_curdir= getcwd()
endif
let treedir = b:netrw_curdir
-" call Decho("set initial treedir<".treedir.">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#19 : mod=".&mod." win#".winnr())
-
let s:treecurpos= winsaveview()
-" call Decho("saving posn to s:treecurpos<".string(s:treecurpos).">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#20 : mod=".&mod." win#".winnr())
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
-" call Decho("w:netrw_liststyle is TREELIST:",'~'.expand("<slnum>"))
-" call Decho("line#".line(".")." getline(.)<".getline('.')."> treecurpos<".string(s:treecurpos).">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#21 : mod=".&mod." win#".winnr())
" extract tree directory if on a line specifying a subdirectory (ie. ends with "/")
let curline= substitute(getline('.'),"\t -->.*$",'','')
if curline =~ '/$'
-" call Decho("extract tree subdirectory from current line",'~'.expand("<slnum>"))
let treedir= substitute(getline('.'),'^\%('.s:treedepthstring.'\)*\([^'.s:treedepthstring.'].\{-}\)$','\1','e')
-" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
elseif curline =~ '@$'
-" call Decho("handle symbolic link from current line",'~'.expand("<slnum>"))
- let potentialdir= resolve(substitute(substitute(getline('.'),'@.*$','','e'),'^|*\s*','','e'))
-" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
+ let potentialdir= resolve(s:NetrwTreePath(w:netrw_treetop))
else
-" call Decho("do not extract tree subdirectory from current line and set treedir to empty",'~'.expand("<slnum>"))
let treedir= ""
endif
-" call Decho("COMBAK#22 : mod=".&mod." win#".winnr())
" detect user attempting to close treeroot
-" call Decho("check if user is attempting to close treeroot",'~'.expand("<slnum>"))
-" call Decho(".win#".winnr()." buf#".bufnr("%")."<".bufname("%").">",'~'.expand("<slnum>"))
-" call Decho(".getline(".line(".").")<".getline('.').'> '.((getline('.') =~# '^'.s:treedepthstring)? '=~#' : '!~').' ^'.s:treedepthstring,'~'.expand("<slnum>"))
if curline !~ '^'.s:treedepthstring && getline('.') != '..'
-" call Decho(".user may have attempted to close treeroot",'~'.expand("<slnum>"))
" now force a refresh
-" call Decho(".force refresh: clear buffer<".expand("%")."> with :%d",'~'.expand("<slnum>"))
sil! NetrwKeepj %d _
-" call Dret("s:NetrwTreeDir <".treedir."> : (side effect) s:treecurpos<".(exists("s:treecurpos")? string(s:treecurpos) : 'n/a').">")
return b:netrw_curdir
-" else " Decho
-" call Decho(".user not attempting to close treeroot",'~'.expand("<slnum>"))
endif
-" call Decho("COMBAK#23 : mod=".&mod." win#".winnr())
-
-" call Decho("islocal=".a:islocal." curline<".curline.">",'~'.expand("<slnum>"))
-" call Decho("potentialdir<".potentialdir."> isdir=".isdirectory(potentialdir),'~'.expand("<slnum>"))
-" call Decho("COMBAK#24 : mod=".&mod." win#".winnr())
" COMBAK: a symbolic link may point anywhere -- so it will be used to start a new treetop
" if a:islocal && curline =~ '@$' && isdirectory(s:NetrwFile(potentialdir))
" let newdir = w:netrw_treetop.'/'.potentialdir
-" " call Decho("apply NetrwTreePath to newdir<".newdir.">",'~'.expand("<slnum>"))
-" let treedir = s:NetrwTreePath(newdir)
-" let w:netrw_treetop = newdir
-" " call Decho("newdir <".newdir.">",'~'.expand("<slnum>"))
-" else
-" call Decho("apply NetrwTreePath to treetop<".w:netrw_treetop.">",'~'.expand("<slnum>"))
if a:islocal && curline =~ '@$'
if isdirectory(s:NetrwFile(potentialdir))
- let treedir = w:netrw_treetop.'/'.potentialdir.'/'
+ let treedir = potentialdir
let w:netrw_treetop = treedir
endif
else
@@ -9398,29 +8776,21 @@ fun! s:NetrwTreeDir(islocal)
let treedir = s:NetrwTreePath(w:netrw_treetop)
endif
endif
-" call Decho("COMBAK#25 : mod=".&mod." win#".winnr())
" sanity maintenance: keep those //s away...
let treedir= substitute(treedir,'//$','/','')
-" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
-" call Decho("COMBAK#26 : mod=".&mod." win#".winnr())
-
-" call Dret("s:NetrwTreeDir <".treedir."> : (side effect) s:treecurpos<".(exists("s:treecurpos")? string(s:treecurpos) : 'n/a').">")
return treedir
endfun
" ---------------------------------------------------------------------
" s:NetrwTreeDisplay: recursive tree display {{{2
fun! s:NetrwTreeDisplay(dir,depth)
-" call Dfunc("NetrwTreeDisplay(dir<".a:dir."> depth<".a:depth.">)")
-
- " insure that there are no folds
+ " ensure that there are no folds
setl nofen
" install ../ and shortdir
if a:depth == ""
call setline(line("$")+1,'../')
-" call Decho("setline#".line("$")." ../ (depth is zero)",'~'.expand("<slnum>"))
endif
if a:dir =~ '^\a\{3,}://'
if a:dir == w:netrw_treetop
@@ -9433,19 +8803,16 @@ fun! s:NetrwTreeDisplay(dir,depth)
let shortdir= substitute(a:dir,'^.*/','','e')
call setline(line("$")+1,a:depth.shortdir.'/')
endif
-" call Decho("setline#".line("$")." shortdir<".a:depth.shortdir.">",'~'.expand("<slnum>"))
" append a / to dir if its missing one
let dir= a:dir
" display subtrees (if any)
let depth= s:treedepthstring.a:depth
-" call Decho("display subtrees with depth<".depth."> and current leaves",'~'.expand("<slnum>"))
" implement g:netrw_hide for tree listings (uses g:netrw_list_hide)
if g:netrw_hide == 1
" hide given patterns
let listhide= split(g:netrw_list_hide,',')
-" call Decho("listhide=".string(listhide))
for pat in listhide
call filter(w:netrw_treedict[dir],'v:val !~ "'.escape(pat,'\\').'"')
endfor
@@ -9453,7 +8820,6 @@ fun! s:NetrwTreeDisplay(dir,depth)
elseif g:netrw_hide == 2
" show given patterns (only)
let listhide= split(g:netrw_list_hide,',')
-" call Decho("listhide=".string(listhide))
let entries=[]
for entry in w:netrw_treedict[dir]
for pat in listhide
@@ -9468,77 +8834,57 @@ fun! s:NetrwTreeDisplay(dir,depth)
if depth != ""
" always remove "." and ".." entries when there's depth
call filter(w:netrw_treedict[dir],'v:val !~ "\\.\\.$"')
+ call filter(w:netrw_treedict[dir],'v:val !~ "\\.\\./$"')
call filter(w:netrw_treedict[dir],'v:val !~ "\\.$"')
+ call filter(w:netrw_treedict[dir],'v:val !~ "\\./$"')
endif
-" call Decho("for every entry in w:netrw_treedict[".dir."]=".string(w:netrw_treedict[dir]),'~'.expand("<slnum>"))
for entry in w:netrw_treedict[dir]
if dir =~ '/$'
let direntry= substitute(dir.entry,'[@/]$','','e')
else
let direntry= substitute(dir.'/'.entry,'[@/]$','','e')
endif
-" call Decho("dir<".dir."> entry<".entry."> direntry<".direntry.">",'~'.expand("<slnum>"))
if entry =~ '/$' && has_key(w:netrw_treedict,direntry)
-" call Decho("<".direntry."> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwTreeDisplay(direntry,depth)
elseif entry =~ '/$' && has_key(w:netrw_treedict,direntry.'/')
-" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwTreeDisplay(direntry.'/',depth)
elseif entry =~ '@$' && has_key(w:netrw_treedict,direntry.'@')
-" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwTreeDisplay(direntry.'/',depth)
+ NetrwKeepj call s:NetrwTreeDisplay(direntry.'@',depth)
else
-" call Decho("<".entry."> is not a key in treedict (no subtree)",'~'.expand("<slnum>"))
sil! NetrwKeepj call setline(line("$")+1,depth.entry)
endif
endfor
-" call Decho("displaying: ".string(getline(w:netrw_bannercnt,'$')))
-
-" call Dret("NetrwTreeDisplay")
endfun
" ---------------------------------------------------------------------
" s:NetrwRefreshTreeDict: updates the contents information for a tree (w:netrw_treedict) {{{2
fun! s:NetrwRefreshTreeDict(dir)
-" call Dfunc("s:NetrwRefreshTreeDict(dir<".a:dir.">)")
if !exists("w:netrw_treedict")
-" call Dret("s:NetrwRefreshTreeDict : w:netrw_treedict doesn't exist")
return
endif
for entry in w:netrw_treedict[a:dir]
let direntry= substitute(a:dir.'/'.entry,'[@/]$','','e')
-" call Decho("a:dir<".a:dir."> entry<".entry."> direntry<".direntry.">",'~'.expand("<slnum>"))
if entry =~ '/$' && has_key(w:netrw_treedict,direntry)
-" call Decho("<".direntry."> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwRefreshTreeDict(direntry)
- let liststar = s:NetrwGlob(direntry,'*',1)
- let listdotstar = s:NetrwGlob(direntry,'.*',1)
- let w:netrw_treedict[direntry] = liststar + listdotstar
-" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>"))
+ let filelist = s:NetrwLocalListingList(direntry,0)
+ let w:netrw_treedict[direntry] = sort(filelist)
elseif entry =~ '/$' && has_key(w:netrw_treedict,direntry.'/')
-" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwRefreshTreeDict(direntry.'/')
- let liststar = s:NetrwGlob(direntry.'/','*',1)
- let listdotstar= s:NetrwGlob(direntry.'/','.*',1)
- let w:netrw_treedict[direntry]= liststar + listdotstar
-" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>"))
+ let filelist = s:NetrwLocalListingList(direntry.'/',0)
+ let w:netrw_treedict[direntry] = sort(filelist)
elseif entry =~ '@$' && has_key(w:netrw_treedict,direntry.'@')
-" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwRefreshTreeDict(direntry.'/')
let liststar = s:NetrwGlob(direntry.'/','*',1)
let listdotstar= s:NetrwGlob(direntry.'/','.*',1)
-" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>"))
else
-" call Decho('not updating w:netrw_treedict['.string(direntry).'] with entry<'.string(entry).'> (no subtree)','~'.expand("<slnum>"))
endif
endfor
-" call Dret("s:NetrwRefreshTreeDict")
endfun
" ---------------------------------------------------------------------
@@ -9546,22 +8892,16 @@ endfun
" Called by s:PerformListing()
fun! s:NetrwTreeListing(dirname)
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
-" call Dfunc("s:NetrwTreeListing() bufname<".expand("%").">")
-" call Decho("curdir<".a:dirname.">",'~'.expand("<slnum>"))
-" call Decho("win#".winnr().": w:netrw_treetop ".(exists("w:netrw_treetop")? "exists" : "doesn't exist")." w:netrw_treedict ".(exists("w:netrw_treedict")? "exists" : "doesn't exit"),'~'.expand("<slnum>"))
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
" update the treetop
if !exists("w:netrw_treetop")
-" call Decho("update the treetop (w:netrw_treetop doesn't exist yet)",'~'.expand("<slnum>"))
let w:netrw_treetop= a:dirname
let s:netrw_treetop= w:netrw_treetop
-" call Decho("w:netrw_treetop<".w:netrw_treetop."> (reusing)",'~'.expand("<slnum>"))
- elseif (w:netrw_treetop =~ ('^'.a:dirname) && s:Strlen(a:dirname) < s:Strlen(w:netrw_treetop)) || a:dirname !~ ('^'.w:netrw_treetop)
-" call Decho("update the treetop (override w:netrw_treetop with a:dirname<".a:dirname.">)",'~'.expand("<slnum>"))
+ " use \V in case the directory contains specials chars like '$' or '~'
+ elseif (w:netrw_treetop =~ ('^'.'\V'.a:dirname) && s:Strlen(a:dirname) < s:Strlen(w:netrw_treetop))
+ \ || a:dirname !~ ('^'.'\V'.w:netrw_treetop)
let w:netrw_treetop= a:dirname
let s:netrw_treetop= w:netrw_treetop
-" call Decho("w:netrw_treetop<".w:netrw_treetop."> (went up)",'~'.expand("<slnum>"))
endif
if exists("w:netrw_treetop")
let s:netrw_treetop= w:netrw_treetop
@@ -9572,16 +8912,12 @@ fun! s:NetrwTreeListing(dirname)
if !exists("w:netrw_treedict")
" insure that we have a treedict, albeit empty
-" call Decho("initializing w:netrw_treedict to empty",'~'.expand("<slnum>"))
let w:netrw_treedict= {}
endif
" update the dictionary for the current directory
-" call Decho("updating: w:netrw_treedict[".a:dirname.'] -> [directory listing]','~'.expand("<slnum>"))
-" call Decho("w:netrw_bannercnt=".w:netrw_bannercnt." line($)=".line("$"),'~'.expand("<slnum>"))
- exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$g@^\.\.\=/$@d _'
+ exe "sil! NetrwKeepj keepp ".w:netrw_bannercnt.',$g@^\.\.\=/$@d _'
let w:netrw_treedict[a:dirname]= getline(w:netrw_bannercnt,line("$"))
-" call Decho("w:treedict[".a:dirname."]= ".string(w:netrw_treedict[a:dirname]),'~'.expand("<slnum>"))
exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d _"
" if past banner, record word
@@ -9590,23 +8926,17 @@ fun! s:NetrwTreeListing(dirname)
else
let fname= ""
endif
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
" display from treetop on down
-" call Decho("(s:NetrwTreeListing) w:netrw_treetop<".w:netrw_treetop.">")
NetrwKeepj call s:NetrwTreeDisplay(w:netrw_treetop,"")
-" call Decho("s:NetrwTreeDisplay) setl noma nomod ro",'~'.expand("<slnum>"))
" remove any blank line remaining as line#1 (happens in treelisting mode with banner suppressed)
while getline(1) =~ '^\s*$' && byte2line(1) > 0
-" call Decho("deleting blank line",'~'.expand("<slnum>"))
1d
endwhile
exe "setl ".g:netrw_bufsettings
-" call Dret("s:NetrwTreeListing : bufname<".expand("%").">")
return
endif
endfun
@@ -9721,6 +9051,11 @@ fun! s:NetrwWideListing()
let newcolstart = w:netrw_bannercnt + fpc
let newcolend = newcolstart + fpc - 1
" call Decho("bannercnt=".w:netrw_bannercnt." fpl=".w:netrw_fpl." fpc=".fpc." newcol[".newcolstart.",".newcolend."]",'~'.expand("<slnum>"))
+ if !has('nvim') && has("clipboard") && g:netrw_clipboard
+" call Decho("(s:NetrwWideListing) save @* and @+",'~'.expand("<slnum>"))
+ sil! let keepregstar = @*
+ sil! let keepregplus = @+
+ endif
while line("$") >= newcolstart
if newcolend > line("$") | let newcolend= line("$") | endif
let newcolqty= newcolend - newcolstart
@@ -9734,6 +9069,11 @@ fun! s:NetrwWideListing()
exe "sil! NetrwKeepj ".newcolstart.','.newcolend.'d _'
exe 'sil! NetrwKeepj '.w:netrw_bannercnt
endwhile
+ if !has('nvim') && has("clipboard")
+" call Decho("(s:NetrwWideListing) restore @* and @+",'~'.expand("<slnum>"))
+ if @* != keepregstar | sil! let @* = keepregstar | endif
+ if @+ != keepregplus | sil! let @+ = keepregplus | endif
+ endif
exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$s/\s\+$//e'
NetrwKeepj call histdel("/",-1)
exe 'nno <buffer> <silent> w :call search(''^.\\|\s\s\zs\S'',''W'')'."\<cr>"
@@ -10003,7 +9343,7 @@ fun! s:PerformListing(islocal)
" resolve symbolic links if local and (thin or tree)
if a:islocal && (w:netrw_liststyle == s:THINLIST || (exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST))
" call Decho("--resolve symbolic links if local and thin|tree",'~'.expand("<slnum>"))
- sil! g/@$/call s:ShowLink()
+ sil! keepp g/@$/call s:ShowLink()
endif
if exists("w:netrw_bannercnt") && (line("$") >= w:netrw_bannercnt || !g:netrw_banner)
@@ -10452,15 +9792,11 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwRemoteRm: remove/delete a remote file or directory {{{2
fun! s:NetrwRemoteRm(usrhost,path) range
-" call Dfunc("s:NetrwRemoteRm(usrhost<".a:usrhost."> path<".a:path.">) virtcol=".virtcol("."))
-" call Decho("firstline=".a:firstline." lastline=".a:lastline,'~'.expand("<slnum>"))
let svpos= winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let all= 0
if exists("s:netrwmarkfilelist_{bufnr('%')}")
" remove all marked files
-" call Decho("remove all marked files with bufnr#".bufnr("%"),'~'.expand("<slnum>"))
for fname in s:netrwmarkfilelist_{bufnr("%")}
let ok= s:NetrwRemoteRmFile(a:path,fname,all)
if ok =~# 'q\%[uit]'
@@ -10473,7 +9809,6 @@ fun! s:NetrwRemoteRm(usrhost,path) range
else
" remove files specified by range
-" call Decho("remove files specified by range",'~'.expand("<slnum>"))
" preparation for removing multiple files/directories
let keepsol = &l:sol
@@ -10495,12 +9830,8 @@ fun! s:NetrwRemoteRm(usrhost,path) range
endif
" refresh the (remote) directory listing
-" call Decho("refresh remote directory listing",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./',0))
NetrwKeepj call winrestview(svpos)
-
-" call Dret("s:NetrwRemoteRm")
endfun
" ---------------------------------------------------------------------
@@ -10626,7 +9957,6 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwRemoteRename: rename a remote file or directory {{{2
fun! s:NetrwRemoteRename(usrhost,path) range
-" call Dfunc("NetrwRemoteRename(usrhost<".a:usrhost."> path<".a:path.">)")
" preparation for removing multiple files/directories
let svpos = winsaveview()
@@ -10637,10 +9967,8 @@ fun! s:NetrwRemoteRename(usrhost,path) range
" rename files given by the markfilelist
if exists("s:netrwmarkfilelist_{bufnr('%')}")
for oldname in s:netrwmarkfilelist_{bufnr("%")}
-" call Decho("oldname<".oldname.">",'~'.expand("<slnum>"))
if exists("subfrom")
let newname= substitute(oldname,subfrom,subto,'')
-" call Decho("subfrom<".subfrom."> subto<".subto."> newname<".newname.">",'~'.expand("<slnum>"))
else
call inputsave()
let newname= input("Moving ".oldname." to : ",oldname)
@@ -10649,7 +9977,6 @@ fun! s:NetrwRemoteRename(usrhost,path) range
let subfrom = substitute(newname,'^s/\([^/]*\)/.*/$','\1','')
let subto = substitute(newname,'^s/[^/]*/\(.*\)/$','\1','')
let newname = substitute(oldname,subfrom,subto,'')
-" call Decho("subfrom<".subfrom."> subto<".subto."> newname<".newname.">",'~'.expand("<slnum>"))
endif
endif
@@ -10658,7 +9985,6 @@ fun! s:NetrwRemoteRename(usrhost,path) range
else
let oldname= s:ShellEscape(a:path.oldname)
let newname= s:ShellEscape(a:path.newname)
-" call Decho("system(netrw#WinPath(".rename_cmd.") ".oldname.' '.newname.")",'~'.expand("<slnum>"))
let ret = system(netrw#WinPath(rename_cmd).' '.oldname.' '.newname)
endif
@@ -10674,7 +10000,6 @@ fun! s:NetrwRemoteRename(usrhost,path) range
exe "NetrwKeepj ".ctr
let oldname= s:NetrwGetWord()
-" call Decho("oldname<".oldname.">",'~'.expand("<slnum>"))
call inputsave()
let newname= input("Moving ".oldname." to : ",oldname)
@@ -10685,7 +10010,6 @@ fun! s:NetrwRemoteRename(usrhost,path) range
else
let oldname= s:ShellEscape(a:path.oldname)
let newname= s:ShellEscape(a:path.newname)
-" call Decho("system(netrw#WinPath(".rename_cmd.") ".oldname.' '.newname.")",'~'.expand("<slnum>"))
let ret = system(netrw#WinPath(rename_cmd).' '.oldname.' '.newname)
endif
@@ -10695,11 +10019,8 @@ fun! s:NetrwRemoteRename(usrhost,path) range
endif
" refresh the directory
- NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./',0))
NetrwKeepj call winrestview(svpos)
-
-" call Dret("NetrwRemoteRename")
endfun
" ==========================================
@@ -10826,17 +10147,11 @@ endfun
" buffers to be refreshed after a user has executed some shell command,
" on the chance that s/he removed/created a file/directory with it.
fun! s:LocalBrowseRefresh()
-" call Dfunc("s:LocalBrowseRefresh() tabpagenr($)=".tabpagenr("$"))
-" call Decho("s:netrw_browselist =".(exists("s:netrw_browselist")? string(s:netrw_browselist) : '<n/a>'),'~'.expand("<slnum>"))
-" call Decho("w:netrw_bannercnt =".(exists("w:netrw_bannercnt")? string(w:netrw_bannercnt) : '<n/a>'),'~'.expand("<slnum>"))
-
" determine which buffers currently reside in a tab
if !exists("s:netrw_browselist")
-" call Dret("s:LocalBrowseRefresh : browselist is empty")
return
endif
if !exists("w:netrw_bannercnt")
-" call Dret("s:LocalBrowseRefresh : don't refresh when focus not on netrw window")
return
endif
if !empty(getcmdwintype())
@@ -10846,7 +10161,6 @@ fun! s:LocalBrowseRefresh()
if exists("s:netrw_events") && s:netrw_events == 1
" s:LocalFastBrowser gets called (indirectly) from a
let s:netrw_events= 2
-" call Dret("s:LocalBrowseRefresh : avoid initial double refresh")
return
endif
let itab = 1
@@ -10857,47 +10171,36 @@ fun! s:LocalBrowseRefresh()
let itab = itab + 1
sil! tabn
endwhile
-" call Decho("buftablist".string(buftablist),'~'.expand("<slnum>"))
-" call Decho("s:netrw_browselist<".(exists("s:netrw_browselist")? string(s:netrw_browselist) : "").">",'~'.expand("<slnum>"))
" GO through all buffers on netrw_browselist (ie. just local-netrw buffers):
" | refresh any netrw window
" | wipe out any non-displaying netrw buffer
let curwinid = win_getid(winnr())
let ibl = 0
for ibuf in s:netrw_browselist
-" call Decho("bufwinnr(".ibuf.") index(buftablist,".ibuf.")=".index(buftablist,ibuf),'~'.expand("<slnum>"))
if bufwinnr(ibuf) == -1 && index(buftablist,ibuf) == -1
" wipe out any non-displaying netrw buffer
" (ibuf not shown in a current window AND
" ibuf not in any tab)
-" call Decho("wiping buf#".ibuf,"<".bufname(ibuf).">",'~'.expand("<slnum>"))
exe "sil! keepj bd ".fnameescape(ibuf)
call remove(s:netrw_browselist,ibl)
-" call Decho("browselist=".string(s:netrw_browselist),'~'.expand("<slnum>"))
continue
elseif index(tabpagebuflist(),ibuf) != -1
" refresh any netrw buffer
-" call Decho("refresh buf#".ibuf.'-> win#'.bufwinnr(ibuf),'~'.expand("<slnum>"))
exe bufwinnr(ibuf)."wincmd w"
if getline(".") =~# 'Quick Help'
" decrement g:netrw_quickhelp to prevent refresh from changing g:netrw_quickhelp
" (counteracts s:NetrwBrowseChgDir()'s incrementing)
let g:netrw_quickhelp= g:netrw_quickhelp - 1
endif
-" call Decho("#3: quickhelp=".g:netrw_quickhelp,'~'.expand("<slnum>"))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
NetrwKeepj call s:NetrwRefreshTreeDict(w:netrw_treetop)
endif
- NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./'))
+ NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
endif
let ibl= ibl + 1
-" call Decho("bottom of s:netrw_browselist for loop: ibl=".ibl,'~'.expand("<slnum>"))
endfor
-" call Decho("restore window: win_gotoid(".curwinid.")")
call win_gotoid(curwinid)
let @@= ykeep
-
-" call Dret("s:LocalBrowseRefresh")
endfun
" ---------------------------------------------------------------------
@@ -10919,22 +10222,15 @@ endfun
" If :Explore used: it sets s:netrw_events to 2, so no FocusGained events are ignored.
" =2: autocmds installed (doesn't ignore any FocusGained events)
fun! s:LocalFastBrowser()
-" call Dfunc("s:LocalFastBrowser() g:netrw_fastbrowse=".g:netrw_fastbrowse)
-" call Decho("s:netrw_events ".(exists("s:netrw_events")? "exists" : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("autocmd: ShellCmdPost ".(exists("#ShellCmdPost")? "already installed" : "not installed"),'~'.expand("<slnum>"))
-" call Decho("autocmd: FocusGained ".(exists("#FocusGained")? "already installed" : "not installed"),'~'.expand("<slnum>"))
" initialize browselist, a list of buffer numbers that the local browser has used
if !exists("s:netrw_browselist")
-" call Decho("initialize s:netrw_browselist",'~'.expand("<slnum>"))
let s:netrw_browselist= []
endif
" append current buffer to fastbrowse list
if empty(s:netrw_browselist) || bufnr("%") > s:netrw_browselist[-1]
-" call Decho("appendng current buffer to browselist",'~'.expand("<slnum>"))
call add(s:netrw_browselist,bufnr("%"))
-" call Decho("browselist=".string(s:netrw_browselist),'~'.expand("<slnum>"))
endif
" enable autocmd events to handle refreshing/removing local browser buffers
@@ -10948,10 +10244,8 @@ fun! s:LocalFastBrowser()
augroup AuNetrwEvent
au!
if has("win32")
-" call Decho("installing autocmd: ShellCmdPost",'~'.expand("<slnum>"))
au ShellCmdPost * call s:LocalBrowseRefresh()
else
-" call Decho("installing autocmds: ShellCmdPost FocusGained",'~'.expand("<slnum>"))
au ShellCmdPost,FocusGained * call s:LocalBrowseRefresh()
endif
augroup END
@@ -10959,86 +10253,55 @@ fun! s:LocalFastBrowser()
" user must have changed fastbrowse to its fast setting, so remove
" the associated autocmd events
elseif g:netrw_fastbrowse > 1 && exists("#ShellCmdPost") && exists("s:netrw_events")
-" call Decho("remove AuNetrwEvent autcmd group",'~'.expand("<slnum>"))
unlet s:netrw_events
augroup AuNetrwEvent
au!
augroup END
augroup! AuNetrwEvent
endif
-
-" call Dret("s:LocalFastBrowser : browselist<".string(s:netrw_browselist).">")
endfun
-" ---------------------------------------------------------------------
-" s:LocalListing: does the job of "ls" for local directories {{{2
-fun! s:LocalListing()
-" call Dfunc("s:LocalListing()")
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Decho("modified=".&modified." modifiable=".&modifiable." readonly=".&readonly,'~'.expand("<slnum>"))
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
-
-" if exists("b:netrw_curdir") |call Decho('b:netrw_curdir<'.b:netrw_curdir.">") |else|call Decho("b:netrw_curdir doesn't exist",'~'.expand("<slnum>")) |endif
-" if exists("g:netrw_sort_by")|call Decho('g:netrw_sort_by<'.g:netrw_sort_by.">")|else|call Decho("g:netrw_sort_by doesn't exist",'~'.expand("<slnum>"))|endif
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
-
+fun! s:NetrwLocalListingList(dirname,setmaxfilenamelen)
" get the list of files contained in the current directory
- let dirname = b:netrw_curdir
- let dirnamelen = strlen(b:netrw_curdir)
+ let dirname = a:dirname
+ let dirnamelen = strlen(dirname)
let filelist = s:NetrwGlob(dirname,"*",0)
let filelist = filelist + s:NetrwGlob(dirname,".*",0)
-" call Decho("filelist=".string(filelist),'~'.expand("<slnum>"))
if g:netrw_cygwin == 0 && has("win32")
-" call Decho("filelist=".string(filelist),'~'.expand("<slnum>"))
- elseif index(filelist,'..') == -1 && b:netrw_curdir !~ '/'
+ elseif index(filelist,'..') == -1 && dirname !~ '/'
" include ../ in the glob() entry if its missing
-" call Decho("forcibly including on \"..\"",'~'.expand("<slnum>"))
- let filelist= filelist+[s:ComposePath(b:netrw_curdir,"../")]
-" call Decho("filelist=".string(filelist),'~'.expand("<slnum>"))
+ let filelist= filelist+[s:ComposePath(dirname,"../")]
endif
-" call Decho("before while: dirname <".dirname.">",'~'.expand("<slnum>"))
-" call Decho("before while: dirnamelen<".dirnamelen.">",'~'.expand("<slnum>"))
-" call Decho("before while: filelist =".string(filelist),'~'.expand("<slnum>"))
-
- if get(g:, 'netrw_dynamic_maxfilenamelen', 0)
+ if a:setmaxfilenamelen && get(g:, 'netrw_dynamic_maxfilenamelen', 0)
let filelistcopy = map(deepcopy(filelist),'fnamemodify(v:val, ":t")')
let g:netrw_maxfilenamelen = max(map(filelistcopy,'len(v:val)')) + 1
-" call Decho("dynamic_maxfilenamelen: filenames =".string(filelistcopy),'~'.expand("<slnum>"))
-" call Decho("dynamic_maxfilenamelen: g:netrw_maxfilenamelen=".g:netrw_maxfilenamelen,'~'.expand("<slnum>"))
endif
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
+ let resultfilelist = []
for filename in filelist
-" call Decho(" ",'~'.expand("<slnum>"))
-" call Decho("for filename in filelist: filename<".filename.">",'~'.expand("<slnum>"))
if getftype(filename) == "link"
" indicate a symbolic link
-" call Decho("indicate <".filename."> is a symbolic link with trailing @",'~'.expand("<slnum>"))
let pfile= filename."@"
elseif getftype(filename) == "socket"
" indicate a socket
-" call Decho("indicate <".filename."> is a socket with trailing =",'~'.expand("<slnum>"))
let pfile= filename."="
elseif getftype(filename) == "fifo"
" indicate a fifo
-" call Decho("indicate <".filename."> is a fifo with trailing |",'~'.expand("<slnum>"))
let pfile= filename."|"
elseif isdirectory(s:NetrwFile(filename))
" indicate a directory
-" call Decho("indicate <".filename."> is a directory with trailing /",'~'.expand("<slnum>"))
let pfile= filename."/"
elseif exists("b:netrw_curdir") && b:netrw_curdir !~ '^.*://' && !isdirectory(s:NetrwFile(filename))
if has("win32")
if filename =~ '\.[eE][xX][eE]$' || filename =~ '\.[cC][oO][mM]$' || filename =~ '\.[bB][aA][tT]$'
" indicate an executable
-" call Decho("indicate <".filename."> is executable with trailing *",'~'.expand("<slnum>"))
let pfile= filename."*"
else
" normal file
@@ -11046,7 +10309,6 @@ fun! s:LocalListing()
endif
elseif executable(filename)
" indicate an executable
-" call Decho("indicate <".filename."> is executable with trailing *",'~'.expand("<slnum>"))
let pfile= filename."*"
else
" normal file
@@ -11057,16 +10319,12 @@ fun! s:LocalListing()
" normal file
let pfile= filename
endif
-" call Decho("pfile<".pfile."> (after *@/ appending)",'~'.expand("<slnum>"))
if pfile =~ '//$'
let pfile= substitute(pfile,'//$','/','e')
-" call Decho("change // to /: pfile<".pfile.">",'~'.expand("<slnum>"))
endif
let pfile= strpart(pfile,dirnamelen)
let pfile= substitute(pfile,'^[/\\]','','e')
-" call Decho("filename<".filename.">",'~'.expand("<slnum>"))
-" call Decho("pfile <".pfile.">",'~'.expand("<slnum>"))
if w:netrw_liststyle == s:LONGLIST
let longfile = printf("%-".g:netrw_maxfilenamelen."S",pfile)
@@ -11079,47 +10337,46 @@ fun! s:LocalListing()
endif
let fsz = printf("%".szlen."S",sz)
let pfile= longfile." ".fsz." ".strftime(g:netrw_timefmt,getftime(filename))
-" call Decho("longlist support: sz=".sz." fsz=".fsz,'~'.expand("<slnum>"))
endif
if g:netrw_sort_by =~# "^t"
" sort by time (handles time up to 1 quintillion seconds, US)
" Decorate listing by prepending a timestamp/ . Sorting will then be done based on time.
-" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (time)")
-" call Decho("getftime(".filename.")=".getftime(filename),'~'.expand("<slnum>"))
let t = getftime(filename)
let ft = printf("%018d",t)
-" call Decho("exe NetrwKeepj put ='".ft.'/'.pfile."'",'~'.expand("<slnum>"))
let ftpfile= ft.'/'.pfile
- sil! NetrwKeepj put=ftpfile
+ let resultfilelist += [ftpfile]
elseif g:netrw_sort_by =~ "^s"
" sort by size (handles file sizes up to 1 quintillion bytes, US)
-" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (size)")
-" call Decho("getfsize(".filename.")=".getfsize(filename),'~'.expand("<slnum>"))
let sz = getfsize(filename)
let fsz = printf("%018d",sz)
-" call Decho("exe NetrwKeepj put ='".fsz.'/'.filename."'",'~'.expand("<slnum>"))
let fszpfile= fsz.'/'.pfile
- sil! NetrwKeepj put =fszpfile
+ let resultfilelist += [fszpfile]
else
" sort by name
-" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (name)")
-" call Decho("exe NetrwKeepj put ='".pfile."'",'~'.expand("<slnum>"))
- sil! NetrwKeepj put=pfile
+ let resultfilelist += [pfile]
endif
-" call DechoBuf(bufnr("%"),"bufnr(%)")
+ endfor
+
+ return resultfilelist
+endfun
+
+" ---------------------------------------------------------------------
+" s:LocalListing: does the job of "ls" for local directories {{{2
+fun! s:LocalListing()
+
+ let filelist = s:NetrwLocalListingList(b:netrw_curdir, 1)
+ for filename in filelist
+ sil! NetrwKeepj put =filename
endfor
" cleanup any windows mess at end-of-line
sil! NetrwKeepj g/^$/d
sil! NetrwKeepj %s/\r$//e
call histdel("/",-1)
-" call Decho("exe setl ts=".(g:netrw_maxfilenamelen+1),'~'.expand("<slnum>"))
exe "setl ts=".(g:netrw_maxfilenamelen+1)
-
-" call Dret("s:LocalListing")
endfun
" ---------------------------------------------------------------------
@@ -11153,7 +10410,6 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwLocalRename: rename a local file or directory {{{2
fun! s:NetrwLocalRename(path) range
-" call Dfunc("NetrwLocalRename(path<".a:path.">)")
if !exists("w:netrw_bannercnt")
let w:netrw_bannercnt= b:netrw_bannercnt
@@ -11164,15 +10420,12 @@ fun! s:NetrwLocalRename(path) range
let ctr = a:firstline
let svpos = winsaveview()
let all = 0
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
" rename files given by the markfilelist
if exists("s:netrwmarkfilelist_{bufnr('%')}")
for oldname in s:netrwmarkfilelist_{bufnr("%")}
-" call Decho("oldname<".oldname.">",'~'.expand("<slnum>"))
if exists("subfrom")
let newname= substitute(oldname,subfrom,subto,'')
-" call Decho("subfrom<".subfrom."> subto<".subto."> newname<".newname.">",'~'.expand("<slnum>"))
else
call inputsave()
let newname= input("Moving ".oldname." to : ",oldname,"file")
@@ -11187,7 +10440,6 @@ fun! s:NetrwLocalRename(path) range
if newname =~ '^s/'
let subfrom = substitute(newname,'^s/\([^/]*\)/.*/$','\1','')
let subto = substitute(newname,'^s/[^/]*/\(.*\)/$','\1','')
-" call Decho("subfrom<".subfrom."> subto<".subto."> newname<".newname.">",'~'.expand("<slnum>"))
let newname = substitute(oldname,subfrom,subto,'')
endif
endif
@@ -11199,12 +10451,9 @@ fun! s:NetrwLocalRename(path) range
let all= 1
elseif response != "y" && response != "yes"
" refresh the directory
-" call Decho("refresh the directory listing",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-" call Dret("NetrwLocalRename")
return
endif
endif
@@ -11231,35 +10480,25 @@ fun! s:NetrwLocalRename(path) range
NetrwKeepj norm! 0
let oldname= s:ComposePath(a:path,curword)
-" call Decho("oldname<".oldname.">",'~'.expand("<slnum>"))
call inputsave()
let newname= input("Moving ".oldname." to : ",substitute(oldname,'/*$','','e'))
call inputrestore()
call rename(oldname,newname)
-" call Decho("renaming <".oldname."> to <".newname.">",'~'.expand("<slnum>"))
-
let ctr= ctr + 1
endwhile
endif
" refresh the directory
-" call Decho("refresh the directory listing",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
NetrwKeepj call winrestview(svpos)
let @@= ykeep
-
-" call Dret("NetrwLocalRename")
endfun
" ---------------------------------------------------------------------
" s:NetrwLocalRm: {{{2
fun! s:NetrwLocalRm(path) range
-" call Dfunc("s:NetrwLocalRm(path<".a:path.">)")
-" call Decho("firstline=".a:firstline." lastline=".a:lastline,'~'.expand("<slnum>"))
-
if !exists("w:netrw_bannercnt")
let w:netrw_bannercnt= b:netrw_bannercnt
endif
@@ -11269,11 +10508,9 @@ fun! s:NetrwLocalRm(path) range
let ret = 0
let all = 0
let svpos = winsaveview()
-" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
if exists("s:netrwmarkfilelist_{bufnr('%')}")
" remove all marked files
-" call Decho("remove all marked files",'~'.expand("<slnum>"))
for fname in s:netrwmarkfilelist_{bufnr("%")}
let ok= s:NetrwLocalRmFile(a:path,fname,all)
if ok =~# 'q\%[uit]' || ok == "no"
@@ -11286,7 +10523,6 @@ fun! s:NetrwLocalRm(path) range
else
" remove (multiple) files and directories
-" call Decho("remove files in range [".a:firstline.",".a:lastline."]",'~'.expand("<slnum>"))
let keepsol= &l:sol
setl nosol
@@ -11316,15 +10552,11 @@ fun! s:NetrwLocalRm(path) range
endif
" refresh the directory
-" call Decho("bufname<".bufname("%").">",'~'.expand("<slnum>"))
if bufname("%") != "NetrwMessage"
- NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./'))
-" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
NetrwKeepj call winrestview(svpos)
endif
let @@= ykeep
-
-" call Dret("s:NetrwLocalRm")
endfun
" ---------------------------------------------------------------------
@@ -11970,7 +11202,7 @@ fun! s:NetrwEnew(...)
" call Dfunc("s:NetrwEnew() a:0=".a:0." win#".winnr()." winnr($)=".winnr("$")." bufnr($)=".bufnr("$")." expand(%)<".expand("%").">")
" call Decho("curdir<".((a:0>0)? a:1 : "")."> buf#".bufnr("%")."<".bufname("%").">",'~'.expand("<slnum>"))
- " Clean out the last buffer:
+ " Clean out the last buffer:
" Check if the last buffer has # > 1, is unlisted, is unnamed, and does not appear in a window
" If so, delete it.
call s:NetrwBufRemover(bufnr("$"))
@@ -12050,13 +11282,16 @@ endfun
" s:NetrwExe: executes a string using "!" {{{2
fun! s:NetrwExe(cmd)
" call Dfunc("s:NetrwExe(a:cmd<".a:cmd.">)")
- if has("win32") && &shell !~? 'cmd\|pwsh\|powershell' && !g:netrw_cygwin
+ if has("win32")
" call Decho("using win32:",expand("<slnum>"))
let savedShell=[&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash]
set shell& shellcmdflag& shellxquote& shellxescape&
set shellquote& shellpipe& shellredir& shellslash&
- exe a:cmd
- let [&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] = savedShell
+ try
+ exe a:cmd
+ finally
+ let [&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] = savedShell
+ endtry
else
" call Decho("exe ".a:cmd,'~'.expand("<slnum>"))
exe a:cmd
@@ -12159,7 +11394,7 @@ fun! s:NetrwHumanReadable(sz)
" call Dfunc("s:NetrwHumanReadable(sz=".a:sz.") type=".type(a:sz)." style=".g:netrw_sizestyle )
if g:netrw_sizestyle == 'h'
- if a:sz >= 1000000000
+ if a:sz >= 1000000000
let sz = printf("%.1f",a:sz/1000000000.0)."g"
elseif a:sz >= 10000000
let sz = printf("%d",a:sz/1000000)."m"
@@ -12490,29 +11725,24 @@ endfun
" ---------------------------------------------------------------------
" s:ShowLink: used to modify thin and tree listings to show links {{{2
fun! s:ShowLink()
-" " call Dfunc("s:ShowLink()")
-" " call Decho("b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "doesn't exist").">",'~'.expand("<slnum>"))
-" " call Decho(printf("line#%4d: %s",line("."),getline(".")),'~'.expand("<slnum>"))
if exists("b:netrw_curdir")
norm! $?\a
- let fname = b:netrw_curdir.'/'.s:NetrwGetWord()
+ if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treetop")
+ let basedir = s:NetrwTreePath(w:netrw_treetop)
+ else
+ let basedir = b:netrw_curdir.'/'
+ endif
+ let fname = basedir.s:NetrwGetWord()
let resname = resolve(fname)
-" " call Decho("fname <".fname.">",'~'.expand("<slnum>"))
-" " call Decho("resname <".resname.">",'~'.expand("<slnum>"))
-" " call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>"))
- if resname =~ '^\M'.b:netrw_curdir.'/'
- let dirlen = strlen(b:netrw_curdir)
- let resname = strpart(resname,dirlen+1)
-" " call Decho("resname<".resname."> (b:netrw_curdir elided)",'~'.expand("<slnum>"))
+ if resname =~ '^\M'.basedir
+ let dirlen = strlen(basedir)
+ let resname = strpart(resname,dirlen)
endif
let modline = getline(".")."\t --> ".resname
-" " call Decho("fname <".fname.">",'~'.expand("<slnum>"))
-" " call Decho("modline<".modline.">",'~'.expand("<slnum>"))
setl noro ma
call setline(".",modline)
setl ro noma nomod
endif
-" " call Dret("s:ShowLink".((exists("fname")? ' : '.fname : 'n/a')))
endfun
" ---------------------------------------------------------------------
@@ -12587,7 +11817,7 @@ endfun
fun! s:ShellEscape(s, ...)
if has('win32') && $SHELL == '' && &shellslash
return printf('"%s"', substitute(a:s, '"', '""', 'g'))
- endif
+ endif
let f = a:0 > 0 ? a:1 : 0
return shellescape(a:s, f)
endfun
@@ -12673,8 +11903,6 @@ endfun
" * interprets result
" See netrw#UserMaps()
fun! s:UserMaps(islocal,funcname)
-" call Dfunc("s:UserMaps(islocal=".a:islocal.",funcname<".a:funcname.">)")
-
if !exists("b:netrw_curdir")
let b:netrw_curdir= getcwd()
endif
@@ -12683,30 +11911,22 @@ fun! s:UserMaps(islocal,funcname)
if type(result) == 1
" if result from user's funcref is a string...
-" call Decho("result string from user funcref<".result.">",'~'.expand("<slnum>"))
if result == "refresh"
-" call Decho("refreshing display",'~'.expand("<slnum>"))
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
elseif result != ""
-" call Decho("executing result<".result.">",'~'.expand("<slnum>"))
exe result
endif
elseif type(result) == 3
" if result from user's funcref is a List...
-" call Decho("result List from user funcref<".string(result).">",'~'.expand("<slnum>"))
for action in result
if action == "refresh"
-" call Decho("refreshing display",'~'.expand("<slnum>"))
- call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
+ call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./',0))
elseif action != ""
-" call Decho("executing action<".action.">",'~'.expand("<slnum>"))
exe action
endif
endfor
endif
-
-" call Dret("s:UserMaps")
endfun
" ==========================
diff --git a/runtime/autoload/netrwFileHandlers.vim b/runtime/autoload/netrwFileHandlers.vim
index 2b6f8f7a0f..e69de29bb2 100644
--- a/runtime/autoload/netrwFileHandlers.vim
+++ b/runtime/autoload/netrwFileHandlers.vim
@@ -1,363 +0,0 @@
-" netrwFileHandlers: contains various extension-based file handlers for
-" netrw's browsers' x command ("eXecute launcher")
-" Maintainer: This runtime file is looking for a new maintainer.
-" Original Author: Charles E. Campbell
-" Date: Sep 18, 2020
-" Version: 11
-" Copyright: Copyright (C) 1999-2012 Charles E. Campbell {{{1
-" Permission is hereby granted to use and distribute this code,
-" with or without modifications, provided that this copyright
-" notice is copied with it. Like anything else that's free,
-" netrwFileHandlers.vim is provided *as is* and comes with no
-" warranty of any kind, either expressed or implied. In no
-" event will the copyright holder be liable for any damages
-" resulting from the use of this software.
-"
-" Rom 6:23 (WEB) For the wages of sin is death, but the free gift of God {{{1
-" is eternal life in Christ Jesus our Lord.
-
-" ---------------------------------------------------------------------
-" Load Once: {{{1
-if exists("g:loaded_netrwFileHandlers") || &cp
- finish
-endif
-let g:loaded_netrwFileHandlers= "v11"
-if v:version < 702
- echohl WarningMsg
- echo "***warning*** this version of netrwFileHandlers needs vim 7.2"
- echohl Normal
- finish
-endif
-let s:keepcpo= &cpo
-set cpo&vim
-
-" ---------------------------------------------------------------------
-" netrwFileHandlers#Invoke: {{{1
-fun! netrwFileHandlers#Invoke(exten,fname)
-" call Dfunc("netrwFileHandlers#Invoke(exten<".a:exten."> fname<".a:fname.">)")
- let exten= a:exten
- " list of supported special characters. Consider rcs,v --- that can be
- " supported with a NFH_rcsCOMMAv() handler
- if exten =~ '[@:,$!=\-+%?;~]'
- let specials= {
-\ '@' : 'AT',
-\ ':' : 'COLON',
-\ ',' : 'COMMA',
-\ '$' : 'DOLLAR',
-\ '!' : 'EXCLAMATION',
-\ '=' : 'EQUAL',
-\ '-' : 'MINUS',
-\ '+' : 'PLUS',
-\ '%' : 'PERCENT',
-\ '?' : 'QUESTION',
-\ ';' : 'SEMICOLON',
-\ '~' : 'TILDE'}
- let exten= substitute(a:exten,'[@:,$!=\-+%?;~]','\=specials[submatch(0)]','ge')
-" call Decho('fname<'.fname.'> done with dictionary')
- endif
-
- if a:exten != "" && exists("*NFH_".exten)
- " support user NFH_*() functions
-" call Decho("let ret= netrwFileHandlers#NFH_".a:exten.'("'.fname.'")')
- exe "let ret= NFH_".exten.'("'.a:fname.'")'
- elseif a:exten != "" && exists("*s:NFH_".exten)
- " use builtin-NFH_*() functions
-" call Decho("let ret= netrwFileHandlers#NFH_".a:exten.'("'.fname.'")')
- exe "let ret= s:NFH_".a:exten.'("'.a:fname.'")'
- endif
-
-" call Dret("netrwFileHandlers#Invoke 0 : ret=".ret)
- return 0
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_html: handles html when the user hits "x" when the {{{1
-" cursor is atop a *.html file
-fun! s:NFH_html(pagefile)
-" call Dfunc("s:NFH_html(".a:pagefile.")")
-
- let page= substitute(a:pagefile,'^','file://','')
-
- if executable("mozilla")
-" call Decho("executing !mozilla ".page)
- exe "!mozilla ".shellescape(page,1)
- elseif executable("netscape")
-" call Decho("executing !netscape ".page)
- exe "!netscape ".shellescape(page,1)
- else
-" call Dret("s:NFH_html 0")
- return 0
- endif
-
-" call Dret("s:NFH_html 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_htm: handles html when the user hits "x" when the {{{1
-" cursor is atop a *.htm file
-fun! s:NFH_htm(pagefile)
-" call Dfunc("s:NFH_htm(".a:pagefile.")")
-
- let page= substitute(a:pagefile,'^','file://','')
-
- if executable("mozilla")
-" call Decho("executing !mozilla ".page)
- exe "!mozilla ".shellescape(page,1)
- elseif executable("netscape")
-" call Decho("executing !netscape ".page)
- exe "!netscape ".shellescape(page,1)
- else
-" call Dret("s:NFH_htm 0")
- return 0
- endif
-
-" call Dret("s:NFH_htm 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_jpg: {{{1
-fun! s:NFH_jpg(jpgfile)
-" call Dfunc("s:NFH_jpg(jpgfile<".a:jpgfile.">)")
-
- if executable("gimp")
- exe "silent! !gimp -s ".shellescape(a:jpgfile,1)
- elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE")
-" call Decho("silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".escape(a:jpgfile," []|'"))
- exe "!".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:jpgfile,1)
- else
-" call Dret("s:NFH_jpg 0")
- return 0
- endif
-
-" call Dret("s:NFH_jpg 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_gif: {{{1
-fun! s:NFH_gif(giffile)
-" call Dfunc("s:NFH_gif(giffile<".a:giffile.">)")
-
- if executable("gimp")
- exe "silent! !gimp -s ".shellescape(a:giffile,1)
- elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE")
- exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:giffile,1)
- else
-" call Dret("s:NFH_gif 0")
- return 0
- endif
-
-" call Dret("s:NFH_gif 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_png: {{{1
-fun! s:NFH_png(pngfile)
-" call Dfunc("s:NFH_png(pngfile<".a:pngfile.">)")
-
- if executable("gimp")
- exe "silent! !gimp -s ".shellescape(a:pngfile,1)
- elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE")
- exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:pngfile,1)
- else
-" call Dret("s:NFH_png 0")
- return 0
- endif
-
-" call Dret("s:NFH_png 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_pnm: {{{1
-fun! s:NFH_pnm(pnmfile)
-" call Dfunc("s:NFH_pnm(pnmfile<".a:pnmfile.">)")
-
- if executable("gimp")
- exe "silent! !gimp -s ".shellescape(a:pnmfile,1)
- elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE")
- exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:pnmfile,1)
- else
-" call Dret("s:NFH_pnm 0")
- return 0
- endif
-
-" call Dret("s:NFH_pnm 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_bmp: visualize bmp files {{{1
-fun! s:NFH_bmp(bmpfile)
-" call Dfunc("s:NFH_bmp(bmpfile<".a:bmpfile.">)")
-
- if executable("gimp")
- exe "silent! !gimp -s ".a:bmpfile
- elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE")
- exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:bmpfile,1)
- else
-" call Dret("s:NFH_bmp 0")
- return 0
- endif
-
-" call Dret("s:NFH_bmp 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_pdf: visualize pdf files {{{1
-fun! s:NFH_pdf(pdf)
-" call Dfunc("s:NFH_pdf(pdf<".a:pdf.">)")
- if executable("gs")
- exe 'silent! !gs '.shellescape(a:pdf,1)
- elseif executable("pdftotext")
- exe 'silent! pdftotext -nopgbrk '.shellescape(a:pdf,1)
- else
-" call Dret("s:NFH_pdf 0")
- return 0
- endif
-
-" call Dret("s:NFH_pdf 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_doc: visualize doc files {{{1
-fun! s:NFH_doc(doc)
-" call Dfunc("s:NFH_doc(doc<".a:doc.">)")
-
- if executable("oowriter")
- exe 'silent! !oowriter '.shellescape(a:doc,1)
- redraw!
- else
-" call Dret("s:NFH_doc 0")
- return 0
- endif
-
-" call Dret("s:NFH_doc 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_sxw: visualize sxw files {{{1
-fun! s:NFH_sxw(sxw)
-" call Dfunc("s:NFH_sxw(sxw<".a:sxw.">)")
-
- if executable("oowriter")
- exe 'silent! !oowriter '.shellescape(a:sxw,1)
- redraw!
- else
-" call Dret("s:NFH_sxw 0")
- return 0
- endif
-
-" call Dret("s:NFH_sxw 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_xls: visualize xls files {{{1
-fun! s:NFH_xls(xls)
-" call Dfunc("s:NFH_xls(xls<".a:xls.">)")
-
- if executable("oocalc")
- exe 'silent! !oocalc '.shellescape(a:xls,1)
- redraw!
- else
-" call Dret("s:NFH_xls 0")
- return 0
- endif
-
-" call Dret("s:NFH_xls 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_ps: handles PostScript files {{{1
-fun! s:NFH_ps(ps)
-" call Dfunc("s:NFH_ps(ps<".a:ps.">)")
- if executable("gs")
-" call Decho("exe silent! !gs ".a:ps)
- exe "silent! !gs ".shellescape(a:ps,1)
- redraw!
- elseif executable("ghostscript")
-" call Decho("exe silent! !ghostscript ".a:ps)
- exe "silent! !ghostscript ".shellescape(a:ps,1)
- redraw!
- elseif executable("gswin32")
-" call Decho("exe silent! !gswin32 ".shellescape(a:ps,1))
- exe "silent! !gswin32 ".shellescape(a:ps,1)
- redraw!
- else
-" call Dret("s:NFH_ps 0")
- return 0
- endif
-
-" call Dret("s:NFH_ps 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_eps: handles encapsulated PostScript files {{{1
-fun! s:NFH_eps(eps)
-" call Dfunc("s:NFH_eps()")
- if executable("gs")
- exe "silent! !gs ".shellescape(a:eps,1)
- redraw!
- elseif executable("ghostscript")
- exe "silent! !ghostscript ".shellescape(a:eps,1)
- redraw!
- elseif executable("ghostscript")
- exe "silent! !ghostscript ".shellescape(a:eps,1)
- redraw!
- elseif executable("gswin32")
- exe "silent! !gswin32 ".shellescape(a:eps,1)
- redraw!
- else
-" call Dret("s:NFH_eps 0")
- return 0
- endif
-" call Dret("s:NFH_eps 0")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_fig: handles xfig files {{{1
-fun! s:NFH_fig(fig)
-" call Dfunc("s:NFH_fig()")
- if executable("xfig")
- exe "silent! !xfig ".a:fig
- redraw!
- else
-" call Dret("s:NFH_fig 0")
- return 0
- endif
-
-" call Dret("s:NFH_fig 1")
- return 1
-endfun
-
-" ---------------------------------------------------------------------
-" s:NFH_obj: handles tgif's obj files {{{1
-fun! s:NFH_obj(obj)
-" call Dfunc("s:NFH_obj()")
- if has("unix") && executable("tgif")
- exe "silent! !tgif ".a:obj
- redraw!
- else
-" call Dret("s:NFH_obj 0")
- return 0
- endif
-
-" call Dret("s:NFH_obj 1")
- return 1
-endfun
-
-let &cpo= s:keepcpo
-unlet s:keepcpo
-" ---------------------------------------------------------------------
-" Modelines: {{{1
-" vim: fdm=marker
diff --git a/runtime/autoload/paste.vim b/runtime/autoload/paste.vim
index 1ba336c2b3..84d4d77401 100644
--- a/runtime/autoload/paste.vim
+++ b/runtime/autoload/paste.vim
@@ -4,7 +4,7 @@
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" Define the string to use for items that are present both in Edit, Popup and
-" Toolbar menu. Also used in mswin.vim and macmap.vim.
+" Toolbar menu. Also used in mswin.vim.
let paste#paste_cmd = {'n': ":call paste#Paste()<CR>"}
let paste#paste_cmd['v'] = '"-c<Esc>' . paste#paste_cmd['n']
diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim
index f2a74db5ed..12409f8145 100644
--- a/runtime/autoload/tar.vim
+++ b/runtime/autoload/tar.vim
@@ -1,6 +1,6 @@
" tar.vim: Handles browsing tarfiles
" AUTOLOAD PORTION
-" Date: Nov 14, 2023
+" Date: Nov 11, 2024
" Version: 32b (with modifications from the Vim Project)
" Maintainer: This runtime file is looking for a new maintainer.
" Former Maintainer: Charles E Campbell
@@ -23,7 +23,7 @@
if &cp || exists("g:loaded_tar")
finish
endif
-let g:loaded_tar= "v32a"
+let g:loaded_tar= "v32b"
if v:version < 702
echohl WarningMsg
echo "***warning*** this version of tar needs vim 7.2"
@@ -41,7 +41,7 @@ if !exists("g:tar_browseoptions")
let g:tar_browseoptions= "Ptf"
endif
if !exists("g:tar_readoptions")
- let g:tar_readoptions= "OPxf"
+ let g:tar_readoptions= "pPxf"
endif
if !exists("g:tar_cmd")
let g:tar_cmd= "tar"
@@ -80,7 +80,7 @@ if !exists("g:tar_copycmd")
let g:tar_copycmd= g:netrw_localcopycmd
endif
if !exists("g:tar_extractcmd")
- let g:tar_extractcmd= "tar -xf"
+ let g:tar_extractcmd= "tar -pxf"
endif
" set up shell quoting character
@@ -294,6 +294,41 @@ fun! tar#Read(fname,mode)
set report=10
let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
let fname = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
+
+" changing the directory to the temporary earlier to allow tar to extract the file with permissions intact
+ if !exists("*mkdir")
+ redraw!
+ echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
+ let &report= repkeep
+ return
+ endif
+
+ let curdir= getcwd()
+ let tmpdir= tempname()
+ let b:curdir= tmpdir
+ let b:tmpdir= curdir
+ if tmpdir =~ '\.'
+ let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
+ endif
+ call mkdir(tmpdir,"p")
+
+ " attempt to change to the indicated directory
+ try
+ exe "cd ".fnameescape(tmpdir)
+ catch /^Vim\%((\a\+)\)\=:E344/
+ redraw!
+ echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
+ let &report= repkeep
+ return
+ endtry
+
+ " place temporary files under .../_ZIPVIM_/
+ if isdirectory("_ZIPVIM_")
+ call s:Rmdir("_ZIPVIM_")
+ endif
+ call mkdir("_ZIPVIM_")
+ cd _ZIPVIM_
+
if has("win32unix") && executable("cygpath")
" assuming cygwin
let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
@@ -332,9 +367,10 @@ fun! tar#Read(fname,mode)
if tarfile =~# '\.bz2$'
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
elseif tarfile =~# '\.\(gz\)$'
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-
+ exe "read ".fname
elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)'
if has("unix") && executable("file")
let filekind= system("file ".shellescape(tarfile,1))
@@ -343,20 +379,27 @@ fun! tar#Read(fname,mode)
endif
if filekind =~ "bzip2"
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
elseif filekind =~ "XZ"
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
elseif filekind =~ "Zstandard"
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
else
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
endif
elseif tarfile =~# '\.lrp$'
exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
elseif tarfile =~# '\.lzma$'
exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
elseif tarfile =~# '\.\(xz\|txz\)$'
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
else
if tarfile =~ '^\s*-'
" A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
@@ -364,6 +407,16 @@ fun! tar#Read(fname,mode)
endif
" call Decho("8: exe silent r! ".g:tar_cmd." -".g:tar_readoptions.tar_secure.shellescape(tarfile,1)." ".shellescape(fname,1).decmp)
exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp
+ exe "read ".fname
+ endif
+
+ redraw!
+
+if v:shell_error != 0
+ cd ..
+ call s:Rmdir("_ZIPVIM_")
+ exe "cd ".fnameescape(curdir)
+ echohl Error | echo "***error*** (tar#Read) sorry, unable to open or extract ".tarfile." with ".fname | echohl None
endif
if doro
@@ -388,6 +441,10 @@ fun! tar#Write(fname)
" call Dfunc("tar#Write(fname<".a:fname.">) b:tarfile<".b:tarfile."> tblfile_".winnr()."<".s:tblfile_{winnr()}.">")
let repkeep= &report
set report=10
+
+ " temporary buffer variable workaround because too fucking tired. but it works now
+ let curdir= b:curdir
+ let tmpdir= b:tmpdir
if !exists("g:tar_secure") && a:fname =~ '^\s*-\|\s\+-'
redraw!
@@ -404,44 +461,6 @@ fun! tar#Write(fname)
" call Dret("tar#Write")
return
endif
- if !exists("*mkdir")
- redraw!
-" call Decho("***error*** (tar#Write) sorry, mkdir() doesn't work on your system")
- echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
- let &report= repkeep
-" call Dret("tar#Write")
- return
- endif
-
- let curdir= getcwd()
- let tmpdir= tempname()
-" call Decho("orig tempname<".tmpdir.">")
- if tmpdir =~ '\.'
- let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
- endif
-" call Decho("tmpdir<".tmpdir.">")
- call mkdir(tmpdir,"p")
-
- " attempt to change to the indicated directory
- try
- exe "cd ".fnameescape(tmpdir)
- catch /^Vim\%((\a\+)\)\=:E344/
- redraw!
-" call Decho("***error*** (tar#Write) cannot cd to temporary directory")
- echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
- let &report= repkeep
-" call Dret("tar#Write")
- return
- endtry
-" call Decho("current directory now: ".getcwd())
-
- " place temporary files under .../_ZIPVIM_/
- if isdirectory("_ZIPVIM_")
- call s:Rmdir("_ZIPVIM_")
- endif
- call mkdir("_ZIPVIM_")
- cd _ZIPVIM_
-" call Decho("current directory now: ".getcwd())
let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
diff --git a/runtime/autoload/typst.vim b/runtime/autoload/typst.vim
index 55edd23928..6d097dd922 100644
--- a/runtime/autoload/typst.vim
+++ b/runtime/autoload/typst.vim
@@ -1,6 +1,6 @@
" Language: Typst
" Maintainer: Gregory Anders
-" Last Change: 2024-07-14
+" Last Change: 2024 Nov 02
" Based on: https://github.com/kaarmu/typst.vim
function! typst#indentexpr() abort
@@ -18,6 +18,9 @@ function! typst#indentexpr() abort
" Use last indent for block comments
if l:synname == 'typstCommentBlock'
return l:ind
+ " do not change the indents of bullet lists
+ elseif l:synname == 'typstMarkupBulletList'
+ return indent(a:lnum)
endif
if l:pline =~ '\v[{[(]\s*$'
@@ -31,6 +34,31 @@ function! typst#indentexpr() abort
return l:ind
endfunction
+function typst#foldexpr()
+ let line = getline(v:lnum)
+
+ " Whenever the user wants to fold nested headers under the parent
+ let nested = get(g:, "typst_foldnested", 1)
+
+ " Regular headers
+ let depth = match(line, '\(^=\+\)\@<=\( .*$\)\@=')
+
+ " Do not fold nested regular headers
+ if depth > 1 && !nested
+ let depth = 1
+ endif
+
+ if depth > 0
+ " check syntax, it should be typstMarkupHeading
+ let syncode = synstack(v:lnum, 1)
+ if len(syncode) > 0 && synIDattr(syncode[0], 'name') ==# 'typstMarkupHeading'
+ return ">" . depth
+ endif
+ endif
+
+ return "="
+endfunction
+
" Gets the previous non-blank line that is not a comment.
function! s:get_prev_nonblank(lnum) abort
let l:lnum = prevnonblank(a:lnum)
diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim
index 172de98d36..a8ea6a3fab 100644
--- a/runtime/autoload/zip.vim
+++ b/runtime/autoload/zip.vim
@@ -408,7 +408,9 @@ fun! s:SetSaneOpts()
let dict.shellslash = &shellslash
let &report = 10
- let &shellslash = 0
+ if exists('+shellslash')
+ let &shellslash = 0
+ endif
return dict
endfun
diff --git a/runtime/colors/README.txt b/runtime/colors/README.txt
index bc6b8f0965..7a13312ed2 100644
--- a/runtime/colors/README.txt
+++ b/runtime/colors/README.txt
@@ -84,9 +84,6 @@ The default color settings can be found in the source file
If you think you have a color scheme that is good enough to be used by others,
please check the following items:
-- Source the $VIMRUNTIME/colors/tools/check_colors.vim script to check for
- common mistakes.
-
- Does it work in a color terminal as well as in the GUI? Is it consistent?
- Is "g:colors_name" set to a meaningful value? In case of doubt you can do
diff --git a/runtime/compiler/cppcheck.vim b/runtime/compiler/cppcheck.vim
index ed7c46e90f..4df12d1714 100644
--- a/runtime/compiler/cppcheck.vim
+++ b/runtime/compiler/cppcheck.vim
@@ -1,15 +1,15 @@
" vim compiler file
" Compiler: cppcheck (C++ static checker)
" Maintainer: Vincent B. (twinside@free.fr)
-" Last Change: 2024 Oct 4 by @Konfekt
+" Last Change: 2024 Nov 08 by @Konfekt
-if exists("cppcheck")
- finish
-endif
+if exists("current_compiler") | finish | endif
let current_compiler = "cppcheck"
let s:cpo_save = &cpo
-set cpo-=C
+set cpo&vim
+
+let s:slash = has('win32')? '\' : '/'
if !exists('g:c_cppcheck_params')
let g:c_cppcheck_params = '--verbose --force --inline-suppr'
@@ -20,12 +20,12 @@ endif
let &l:makeprg = 'cppcheck --quiet'
\ ..' --template="{file}:{line}:{column}: {severity}: [{id}] {message} {callstack}"'
- \ ..' '..get(b:, 'c_cppcheck_params',
- \ g:c_cppcheck_params..' '..(&filetype ==# 'cpp' ? ' --language=c++' : ''))
+ \ ..' '..get(b:, 'c_cppcheck_params', get(g:, 'c_cppcheck_params', (&filetype ==# 'cpp' ? ' --language=c++' : '')))
\ ..' '..get(b:, 'c_cppcheck_includes', get(g:, 'c_cppcheck_includes',
\ (filereadable('compile_commands.json') ? '--project=compile_commands.json' :
- \ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I'))))
-silent CompilerSet makeprg
+ \ (!empty(glob('*'..s:slash..'compile_commands.json', 1, 1)) ? '--project='..glob('*'..s:slash..'compile_commands.json', 1, 1)[0] :
+ \ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I')))))
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
CompilerSet errorformat=
\%f:%l:%c:\ %tarning:\ %m,
diff --git a/runtime/compiler/maven.vim b/runtime/compiler/maven.vim
new file mode 100644
index 0000000000..ef8d8a6fb2
--- /dev/null
+++ b/runtime/compiler/maven.vim
@@ -0,0 +1,40 @@
+" Vim compiler file
+" Compiler: Maven
+" Maintainer: D. Ben Knoble <ben.knoble+vim@gmail.com>
+" Maintainer: Konfekt
+" Original Source: https://github.com/JalaiAmitahl/maven-compiler.vim/blob/master/compiler/mvn.vim
+" (Copyright Dan Taylor, distributed under the same terms as LICENSE)
+" Original Source: https://github.com/mikelue/vim-maven-plugin/blob/master/compiler/maven.vim
+" (distributed under same terms as LICENSE per
+" https://github.com/mikelue/vim-maven-plugin/issues/13)
+" Last Change: 2024 Nov 12
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "maven"
+
+CompilerSet makeprg=mvn\ --batch-mode
+
+" Error message for POM
+CompilerSet errorformat=[FATAL]\ Non-parseable\ POM\ %f:\ %m%\\s%\\+@%.%#line\ %l\\,\ column\ %c%.%#,
+CompilerSet errorformat+=[%tRROR]\ Malformed\ POM\ %f:\ %m%\\s%\\+@%.%#line\ %l\\,\ column\ %c%.%#
+
+" Java related build messages
+CompilerSet errorformat+=[%tARNING]\ %f:[%l\\,%c]\ %m
+CompilerSet errorformat+=[%tRROR]\ %f:[%l\\,%c]\ %m
+CompilerSet errorformat+=%A[%t%[A-Z]%#]\ %f:[%l\\,%c]\ %m,%Z
+CompilerSet errorformat+=%A%f:[%l\\,%c]\ %m,%Z
+
+" jUnit related build messages
+CompilerSet errorformat+=%+E\ \ %#test%m,%Z
+CompilerSet errorformat+=%+E[ERROR]\ Please\ refer\ to\ %f\ for\ the\ individual\ test\ results.
+" Message from JUnit 5(5.3.X), TestNG(6.14.X), JMockit(1.43), and AssertJ(3.11.X)
+CompilerSet errorformat+=%+E%>[ERROR]\ %.%\\+Time\ elapsed:%.%\\+<<<\ FAILURE!,
+CompilerSet errorformat+=%+E%>[ERROR]\ %.%\\+Time\ elapsed:%.%\\+<<<\ ERROR!,
+CompilerSet errorformat+=%+Z%\\s%#at\ %f(%\\f%\\+:%l),
+CompilerSet errorformat+=%+C%.%#
+
+" Misc message removal
+CompilerSet errorformat+=%-G[INFO]\ %.%#,
+CompilerSet errorformat+=%-G[debug]\ %.%#
diff --git a/runtime/compiler/mypy.vim b/runtime/compiler/mypy.vim
new file mode 100644
index 0000000000..891488626a
--- /dev/null
+++ b/runtime/compiler/mypy.vim
@@ -0,0 +1,19 @@
+" Vim compiler file
+" Compiler: Mypy (Python static checker)
+" Maintainer: @Konfekt
+" Last Change: 2024 Nov 07
+
+if exists("current_compiler") | finish | endif
+let current_compiler = "mypy"
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=mypy
+let &l:makeprg = 'mypy --show-column-numbers '
+ \ ..get(b:, 'mypy_makeprg_params', get(g:, 'mypy_makeprg_params', '--strict --ignore-missing-imports'))
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+CompilerSet errorformat=%f:%l:%c:\ %t%*[^:]:\ %m
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/compiler/pylint.vim b/runtime/compiler/pylint.vim
index 14e9696dbb..4c9c23e125 100644
--- a/runtime/compiler/pylint.vim
+++ b/runtime/compiler/pylint.vim
@@ -1,13 +1,20 @@
" Vim compiler file
-" Compiler: Pylint for Python
-" Maintainer: Daniel Moch <daniel@danielmoch.com>
-" Last Change: 2016 May 20
-" 2024 Apr 03 by The Vim Project (removed :CompilerSet definition)
-
-if exists("current_compiler")
- finish
-endif
+" Compiler: Pylint for Python
+" Maintainer: Daniel Moch <daniel@danielmoch.com>
+" Last Change: 2024 Nov 07 by The Vim Project (added params variable)
+
+if exists("current_compiler") | finish | endif
let current_compiler = "pylint"
-CompilerSet makeprg=pylint\ --output-format=text\ --msg-template=\"{path}:{line}:{column}:{C}:\ [{symbol}]\ {msg}\"\ --reports=no
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=ruff
+let &l:makeprg = 'pylint ' .
+ \ '--output-format=text --msg-template="{path}:{line}:{column}:{C}: [{symbol}] {msg}" --reports=no ' .
+ \ get(b:, "pylint_makeprg_params", get(g:, "pylint_makeprg_params", '--jobs=0'))
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
CompilerSet errorformat=%A%f:%l:%c:%t:\ %m,%A%f:%l:\ %m,%A%f:(%l):\ %m,%-Z%p^%.%#,%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/compiler/ruff.vim b/runtime/compiler/ruff.vim
new file mode 100644
index 0000000000..11a69740d8
--- /dev/null
+++ b/runtime/compiler/ruff.vim
@@ -0,0 +1,19 @@
+" Vim compiler file
+" Compiler: Ruff (Python linter)
+" Maintainer: @pbnj-dragon
+" Last Change: 2024 Nov 07
+
+if exists("current_compiler") | finish | endif
+let current_compiler = "ruff"
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=ruff
+let &l:makeprg= 'ruff check --output-format=concise '
+ \ ..get(b:, 'ruff_makeprg_params', get(g:, 'ruff_makeprg_params', '--preview'))
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+CompilerSet errorformat=%f:%l:%c:\ %m,%f:%l:\ %m,%f:%l:%c\ -\ %m,%f:
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index dee0324a5b..c5dabeb551 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -658,12 +658,12 @@ nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
Parameters: ~
• {chunks} A list of `[text, hl_group]` arrays, each representing a
- text chunk with specified highlight. `hl_group` element can
- be omitted for no highlight.
+ text chunk with specified highlight group name or ID.
+ `hl_group` element can be omitted for no highlight.
• {history} if true, add to |message-history|.
• {opts} Optional parameters.
- • verbose: Message was printed as a result of 'verbose'
- option if Nvim was invoked with -V3log_file, the message
+ • verbose: Message is printed as a result of 'verbose'
+ option. If Nvim was invoked with -V3log_file, the message
will be redirected to the log_file and suppressed from
direct output.
@@ -2672,8 +2672,10 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• id : id of the extmark to edit.
• end_row : ending line of the mark, 0-based inclusive.
• end_col : ending col of the mark, 0-based exclusive.
- • hl_group : name of the highlight group used to highlight
- this mark.
+ • hl_group : highlight group used for the text range. This
+ and below highlight groups can be supplied either as a
+ string or as an integer, the latter of which can be
+ obtained using |nvim_get_hl_id_by_name()|.
• hl_eol : when true, for a multiline highlight covering the
EOL of a line, continue the highlight for the rest of the
screen line (just like for diff and cursorline highlight).
@@ -2682,9 +2684,7 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
with specified highlight. `highlight` element can either
be a single highlight group, or an array of multiple
highlight groups that will be stacked (highest priority
- last). A highlight group can be supplied either as a
- string or as an integer, the latter which can be obtained
- using |nvim_get_hl_id_by_name()|.
+ last).
• virt_text_pos : position of virtual text. Possible values:
• "eol": right after eol character (default).
• "overlay": display over the specified column, without
@@ -2750,15 +2750,14 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
buffer or end of the line respectively. Defaults to true.
• sign_text: string of length 1-2 used to display in the
sign column.
- • sign_hl_group: name of the highlight group used to
- highlight the sign column text.
- • number_hl_group: name of the highlight group used to
- highlight the number column.
- • line_hl_group: name of the highlight group used to
- highlight the whole line.
- • cursorline_hl_group: name of the highlight group used to
- highlight the sign column text when the cursor is on the
- same line as the mark and 'cursorline' is enabled.
+ • sign_hl_group: highlight group used for the sign column
+ text.
+ • number_hl_group: highlight group used for the number
+ column.
+ • line_hl_group: highlight group used for the whole line.
+ • cursorline_hl_group: highlight group used for the sign
+ column text when the cursor is on the same line as the
+ mark and 'cursorline' is enabled.
• conceal: string which should be either empty or a single
character. Enable concealing similar to |:syn-conceal|.
When a character is supplied it is used as |:syn-cchar|.
@@ -3195,7 +3194,13 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
be fractional.
• focusable: Enable focus by user actions (wincmds, mouse
events). Defaults to true. Non-focusable windows can be
- entered by |nvim_set_current_win()|.
+ entered by |nvim_set_current_win()|, or, when the `mouse`
+ field is set to true, by mouse events. See |focusable|.
+ • mouse: Specify how this window interacts with mouse
+ events. Defaults to `focusable` value.
+ • If false, mouse events pass through this window.
+ • If true, mouse events interact with this window
+ normally.
• external: GUI should display the window as an external
top-level window. Currently accepts no other positioning
configuration together with this.
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 8e5e2628de..998ef5e9f3 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -353,15 +353,11 @@ BufWritePost After writing the whole buffer to a file
ChanInfo State of channel changed, for instance the
client of a RPC channel described itself.
Sets these |v:event| keys:
- info
- See |nvim_get_chan_info()| for the format of
- the info Dictionary.
+ info as from |nvim_get_chan_info()|
*ChanOpen*
ChanOpen Just after a channel was opened.
Sets these |v:event| keys:
- info
- See |nvim_get_chan_info()| for the format of
- the info Dictionary.
+ info as from |nvim_get_chan_info()|
*CmdUndefined*
CmdUndefined When a user command is used but it isn't
defined. Useful for defining a command only
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 4c726f86d2..ada3b7103c 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -269,16 +269,16 @@ assert_equal({expected}, {actual} [, {msg}]) *assert_equal()*
Return: ~
(`0|1`)
-assert_equalfile({fname-one}, {fname-two}) *assert_equalfile()*
- When the files {fname-one} and {fname-two} do not contain
+assert_equalfile({fname_one}, {fname_two}) *assert_equalfile()*
+ When the files {fname_one} and {fname_two} do not contain
exactly the same text an error message is added to |v:errors|.
Also see |assert-return|.
- When {fname-one} or {fname-two} does not exist the error will
+ When {fname_one} or {fname_two} does not exist the error will
mention that.
Parameters: ~
- • {fname-one} (`string`)
- • {fname-two} (`string`)
+ • {fname_one} (`string`)
+ • {fname_two} (`string`)
Return: ~
(`0|1`)
@@ -936,7 +936,7 @@ charclass({string}) *charclass()*
The character class is one of:
0 blank
1 punctuation
- 2 word character
+ 2 word character (depends on 'iskeyword')
3 emoji
other specific Unicode class
The class is used in patterns and word motions.
@@ -959,7 +959,7 @@ charcol({expr} [, {winid}]) *charcol()*
<
Parameters: ~
- • {expr} (`string|integer[]`)
+ • {expr} (`string|any[]`)
• {winid} (`integer?`)
Return: ~
@@ -1100,7 +1100,7 @@ col({expr} [, {winid}]) *col()*
<
Parameters: ~
- • {expr} (`string|integer[]`)
+ • {expr} (`string|any[]`)
• {winid} (`integer?`)
Return: ~
@@ -3224,13 +3224,24 @@ getcharstr([{expr}]) *getcharstr()*
Return: ~
(`string`)
+getcmdcomplpat() *getcmdcomplpat()*
+ Return completion pattern of the current command-line.
+ Only works when the command line is being edited, thus
+ requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
+ Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
+ |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|.
+ Returns an empty string when completion is not defined.
+
+ Return: ~
+ (`string`)
+
getcmdcompltype() *getcmdcompltype()*
Return the type of the current command-line completion.
Only works when the command line is being edited, thus
requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
See |:command-completion| for the return string.
Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
- |getcmdprompt()| and |setcmdline()|.
+ |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|.
Returns an empty string when completion is not defined.
Return: ~
@@ -3351,6 +3362,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
runtime |:runtime| completion
scriptnames sourced script names |:scriptnames|
shellcmd Shell command
+ shellcmdline Shell command line with filename arguments
sign |:sign| suboptions
syntax syntax file names |'syntax'|
syntime |:syntime| suboptions
@@ -5746,7 +5758,7 @@ luaeval({expr} [, {expr}]) *luaeval()*
map({expr1}, {expr2}) *map()*
{expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
- When {expr1} is a |List|| or |Dictionary|, replace each
+ When {expr1} is a |List| or |Dictionary|, replace each
item in {expr1} with the result of evaluating {expr2}.
For a |Blob| each byte is replaced.
For a |String|, each character, including composing
@@ -8690,7 +8702,7 @@ setcellwidths({list}) *setcellwidths()*
To clear the overrides pass an empty {list}: >vim
call setcellwidths([])
-< You can use the script $VIMRUNTIME/tools/emoji_list.lua to see
+< You can use the script $VIMRUNTIME/scripts/emoji_list.lua to see
the effect for known emoji characters. Move the cursor
through the text to check if the cell widths of your terminal
match with what Vim knows about each emoji. If it doesn't
@@ -9027,6 +9039,8 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()*
clear the list: >vim
call setqflist([], 'r')
<
+ 'u' Like 'r', but tries to preserve the current selection
+ in the quickfix list.
'f' All the quickfix lists in the quickfix stack are
freed.
@@ -9083,9 +9097,9 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()*
`:cc 1` to jump to the first position.
Parameters: ~
- • {list} (`any[]`)
+ • {list} (`vim.quickfix.entry[]`)
• {action} (`string?`)
- • {what} (`table?`)
+ • {what} (`vim.fn.setqflist.what?`)
Return: ~
(`any`)
@@ -11597,7 +11611,7 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()*
<
Parameters: ~
- • {expr} (`string|integer[]`)
+ • {expr} (`string|any[]`)
• {list} (`boolean?`)
• {winid} (`integer?`)
@@ -11691,7 +11705,7 @@ wildmenumode() *wildmenumode()*
For example to make <c-j> work like <down> in wildmode, use: >vim
cnoremap <expr> <C-j> wildmenumode() ? "\<Down>\<Tab>" : "\<c-j>"
<
- (Note, this needs the 'wildcharm' option set appropriately).
+ (Note: this needs the 'wildcharm' option set appropriately).
Return: ~
(`any`)
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 928b834600..768a449581 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -561,6 +561,8 @@ with ".". Vim does not recognize a comment (starting with '"') after the
program {filter} (for {Visual} see |Visual-mode|).
:{range}![!]{filter} [!][arg] *:range!*
+ For executing external commands see |:!|
+
Filter {range} lines through the external program
{filter}. Vim replaces the optional bangs with the
latest given command and appends the optional [arg].
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 72d2faca02..5e809ad26c 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -21,6 +21,8 @@ API
LUA
- vim.region() Use |getregionpos()| instead.
+- *vim.highlight* Renamed to |vim.hl|.
+- vim.validate(opts: table) Use form 1. See |vim.validate()|.
DIAGNOSTICS
- *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count=1, float=true}` instead.
@@ -36,6 +38,25 @@ DIAGNOSTICS
- The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to
"pos"
+TREESITTER
+• *TSNode:child_containing_descendant()* Use
+ |TSNode:child_with_descendant()| instead; it is identical except that it can
+ return the descendant itself.
+
+LSP
+• *vim.lsp.util.jump_to_location* Use |vim.lsp.util.show_document()| with
+ `{focus=true}` instead.
+• *vim.lsp.buf.execute_command* Use |Client:exec_cmd()| instead.
+• *vim.lsp.buf.completion* Use |vim.lsp.completion.trigger()| instead.
+• vim.lsp.buf_request_all The `error` key has been renamed to `err` inside
+ the result parameter of the handler.
+• *vim.lsp.with()* Pass configuration to equivalent
+ functions in `vim.lsp.buf.*'.
+• |vim.lsp.handlers|
+ No longer support client to server response handlers. Only server to
+ client requests/notification handlers are supported.
+• *vim.lsp.handlers.signature_help()* Use |vim.lsp.buf.signature_help()| instead.
+
------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10*
diff --git a/runtime/doc/dev_style.txt b/runtime/doc/dev_style.txt
index 32f7279704..97d5ebdb52 100644
--- a/runtime/doc/dev_style.txt
+++ b/runtime/doc/dev_style.txt
@@ -64,9 +64,8 @@ Symbols:
- `extern` variables (including the `EXTERN` macro)
Non-symbols:
- - macros, i.e. `#define`.
- - static inline functions, but only if its function declaration has a
- `REAL_FATTR_ALWAYS_INLINE` attribute.
+ - macros, i.e. `#define`
+ - static inline functions with the `FUNC_ATTR_ALWAYS_INLINE` attribute
- typedefs
- structs
- enums
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 342947595e..9ccc3102b6 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -445,10 +445,10 @@ Lua module: vim.diagnostic *diagnostic-api*
updated on |InsertLeave|)
• {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`)
Sort diagnostics by severity. This affects the
- order in which signs and virtual text are
- displayed. When true, higher severities are
- displayed before lower severities (e.g. ERROR is
- displayed before WARN). Options:
+ order in which signs, virtual text, and
+ highlights are displayed. When true, higher
+ severities are displayed before lower severities
+ (e.g. ERROR is displayed before WARN). Options:
• {reverse}? (boolean) Reverse sort order
• {jump}? (`vim.diagnostic.Opts.Jump`) Default values for
|vim.diagnostic.jump()|. See
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 0008713025..4224709a39 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1032,6 +1032,15 @@ explanation of when the copy is made and when the file is renamed.
If the creation of a backup file fails, the write is not done. If you want
to write anyway add a '!' to the command.
+ *file-watcher*
+When you notice issues with programs, that act upon when a buffer is written
+(like inotify, entr or fswatch) or when external applications execute Vim to
+edit the file (like git) and those programs do not seem to notice that the
+original file has been changed, you may want to consider switching the
+'backupcopy' option value to "yes". This makes sure, Vim writes to the same
+file, that those watcher programs expect, without creating a new file (which
+prevents them from detecting that the file has changed). See also |crontab|
+
*write-permissions*
When writing a new file the permissions are read-write. For unix the mask is
0o666 with additionally umask applied. When writing a file that was read Vim
@@ -1287,7 +1296,7 @@ separated by ';'.
For example, to have only Vim files in the dialog, you could use the following
command: >
- let g:browsefilter = "Vim Scripts\t*.vim\nVim Startup Files\t*vimrc\n"
+ let g:browsefilter = "Vim scripts\t*.vim\nVim Startup Files\t*vimrc\n"
You can override the filter setting on a per-buffer basis by setting the
b:browsefilter variable. You would most likely set b:browsefilter in a
diff --git a/runtime/doc/faq.txt b/runtime/doc/faq.txt
index 7d2774c191..a9a7b1768e 100644
--- a/runtime/doc/faq.txt
+++ b/runtime/doc/faq.txt
@@ -189,7 +189,7 @@ Other hints:
- The python `neovim` module was renamed to `pynvim` (long ago).
- If you're using pyenv or virtualenv for the `pynvim` module
- https://pypi.python.org/pypi/pynvim/, you must set `g:python3_host_prog` to
+ https://pypi.org/project/pynvim/, you must set `g:python3_host_prog` to
the virtualenv's interpreter path.
- Read |provider-python|.
- Be sure you have the latest version of the `pynvim` Python module: >bash
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index a577b0c5fb..19c018bc11 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -40,7 +40,7 @@ Detail: The ":filetype on" command will load these files:
$VIMRUNTIME/scripts.vim is used to detect it from the contents of the
file.
When the GUI is running or will start soon, the |menu.vim| script is
- also sourced. See |'go-M'| about avoiding that.
+ also sourced.
To add your own file types, see |new-filetype| below. To search for help on a
filetype prepend "ft-" and optionally append "-syntax", "-indent" or
@@ -630,6 +630,19 @@ HARE *ft-hare*
Since the text for this plugin is rather long it has been put in a separate
file: |ft_hare.txt|.
+IDRIS2 *ft-idris2-plugin*
+
+By default the following options are set: >
+
+ setlocal shiftwidth=2 tabstop=2 expandtab
+ setlocal comments=s1:{-,mb:-,ex:-},:\|\|\|,:--
+ setlocal commentstring=--\ %s
+ setlocal wildignore+=*.ibc
+
+To use tabs instead of spaces for indentation, set the following variable
+in your vimrc: >
+
+ let g:idris2#allow_tabchar = 1
JAVA *ft-java-plugin*
@@ -774,6 +787,12 @@ To enable folding use this: >
let g:markdown_recommended_style = 0
+ORG *ft-org-plugin*
+
+To enable folding use this: >
+ let g:org_folding = 1
+<
+
PDF *ft-pdf-plugin*
Two maps, <C-]> and <C-T>, are provided to simulate a tag stack for navigating
@@ -1039,6 +1058,19 @@ TYPST *ft-typst-plugin*
*g:typst_conceal*
When |TRUE| the Typst filetype plugin will set the 'conceallevel' option to 2.
+ *g:typst_folding*
+When |TRUE| the Typst filetype plugin will fold headings. (default: |FALSE|)
+
+To enable: >
+ let g:typst_folding = 1
+<
+ *g:typst_foldnested*
+When |TRUE| the Typst filetype plugin will fold nested heading under their
+parents. (default: |TRUE|)
+
+To disable: >
+ let g:typst_foldnested = 0
+<
VIM *ft-vim-plugin*
The Vim filetype plugin defines mappings to move to the start and end of
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 9ab5bf4e1e..21f1ba8241 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -164,7 +164,6 @@ menus and menu items. They are most useful for things that you can't remember
what the key sequence was.
For creating menus in a different language, see |:menutrans|.
-If you don't want to use menus at all, see |'go-M'|.
*menu.vim*
The default menus are read from the file "$VIMRUNTIME/menu.vim". See
diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt
index f97ae24068..49d770124a 100644
--- a/runtime/doc/indent.txt
+++ b/runtime/doc/indent.txt
@@ -809,6 +809,38 @@ Detail:
: GetCSSIndent() else
<!-- --> : -1
+IDRIS2 *ft-idris2-indent*
+
+Idris 2 indentation can be configured with several variables that control the
+indentation level for different language constructs:
+
+The "g:idris2_indent_if" variable controls the indentation of `then` and `else`
+blocks after `if` statements. Defaults to 3.
+
+The "g:idris2_indent_case" variable controls the indentation of patterns in
+`case` expressions. Defaults to 5.
+
+The "g:idris2_indent_let" variable controls the indentation after `let`
+bindings. Defaults to 4.
+
+The "g:idris2_indent_rewrite" variable controls the indentation after `rewrite`
+expressions. Defaults to 8.
+
+The "g:idris2_indent_where" variable controls the indentation of `where`
+blocks. Defaults to 6.
+
+The "g:idris2_indent_do" variable controls the indentation in `do` blocks.
+Defaults to 3.
+
+Example configuration: >
+
+ let g:idris2_indent_if = 2
+ let g:idris2_indent_case = 4
+ let g:idris2_indent_let = 4
+ let g:idris2_indent_rewrite = 8
+ let g:idris2_indent_where = 6
+ let g:idris2_indent_do = 3
+<
MATLAB *ft-matlab-indent* *matlab-indent* *matlab-indenting*
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index d7cbb7c78e..48fd442b7e 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -1177,12 +1177,12 @@ items:
user_data custom data which is associated with the item and
available in |v:completed_item|; it can be any type;
defaults to an empty string
- hl_group an additional highlight group whose attributes are
+ abbr_hlgroup an additional highlight group whose attributes are
combined with |hl-PmenuSel| and |hl-Pmenu| or
|hl-PmenuMatchSel| and |hl-PmenuMatch| highlight
attributes in the popup menu to apply cterm and gui
properties (with higher priority) like strikethrough
- to the completion items
+ to the completion items abbreviation
kind_hlgroup an additional highlight group specifically for setting
the highlight attributes of the completion kind. When
this field is present, it will override the
@@ -1907,6 +1907,16 @@ These commands are used to start inserting text. You can end insert mode with
<Esc>. See |mode-ins-repl| for the other special characters in Insert mode.
The effect of [count] takes place after Insert mode is exited.
+The following commands insert text, but stay in normal mode:
+
+ *]<Space>*
+]<Space> Insert an empty line below the cursor without leaving
+ Normal mode, repeat [count] times.
+
+ *[<Space>*
+[<Space> Insert an empty line above the cursor without leaving
+ Normal mode, repeat [count] times.
+
When 'autoindent' is on, the indent for a new line is obtained from the
previous line. When 'smartindent' or 'cindent' is on, the indent for a line
is automatically adjusted for C programs.
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index 41846f8eed..d099c29bdb 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -536,7 +536,7 @@ CTRL-O in Insert mode you get a beep but you are still in Insert mode, type
Select *5 ^O ^G *6 -- -- --
Insert <Esc> -- -- <Insert> -- --
Replace <Esc> -- -- <Insert> -- --
- Command-line `*3` -- -- :start -- --
+ Command-line *3 -- -- :start -- --
Ex :vi -- -- -- -- --
-- not possible
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 419f583c36..64bef849fc 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -71,11 +71,13 @@ options are not restored when the LSP client is stopped or detached.
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
a custom keymap for `K` exists.
- *grr* *gra* *grn* *i_CTRL-S*
+ *grr* *gra* *grn* *gri* *i_CTRL-S*
Some keymaps are created unconditionally when Nvim starts:
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
+- "gri" is mapped in Normal mode to |vim.lsp.buf.implementation()|
+- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
If not wanted, these keymaps can be removed at any time using
@@ -193,41 +195,41 @@ Requests and notifications defined by the LSP specification are referred to as
They are also listed below. Note that handlers depend on server support: they
won't run if your server doesn't support them.
-- callHierarchy/incomingCalls
-- callHierarchy/outgoingCalls
-- textDocument/codeAction
-- textDocument/completion
-- textDocument/declaration*
-- textDocument/definition
-- textDocument/diagnostic
-- textDocument/documentHighlight
-- textDocument/documentSymbol
-- textDocument/formatting
-- textDocument/hover
-- textDocument/implementation*
-- textDocument/inlayHint
-- textDocument/prepareTypeHierarchy
-- textDocument/publishDiagnostics
-- textDocument/rangeFormatting
-- textDocument/rangesFormatting
-- textDocument/references
-- textDocument/rename
-- textDocument/semanticTokens/full
-- textDocument/semanticTokens/full/delta
-- textDocument/signatureHelp
-- textDocument/typeDefinition*
-- typeHierarchy/subtypes
-- typeHierarchy/supertypes
-- window/logMessage
-- window/showMessage
-- window/showDocument
-- window/showMessageRequest
-- workspace/applyEdit
-- workspace/configuration
-- workspace/executeCommand
-- workspace/inlayHint/refresh
-- workspace/symbol
-- workspace/workspaceFolders
+- `'callHierarchy/incomingCalls'`
+- `'callHierarchy/outgoingCalls'`
+- `'textDocument/codeAction'`
+- `'textDocument/completion'`
+- `'textDocument/declaration'`
+- `'textDocument/definition'`
+- `'textDocument/diagnostic'`
+- `'textDocument/documentHighlight'`
+- `'textDocument/documentSymbol'`
+- `'textDocument/formatting'`
+- `'textDocument/hover'`
+- `'textDocument/implementation'`
+- `'textDocument/inlayHint'`
+- `'textDocument/prepareTypeHierarchy'`
+- `'textDocument/publishDiagnostics'`
+- `'textDocument/rangeFormatting'`
+- `'textDocument/rangesFormatting'`
+- `'textDocument/references'`
+- `'textDocument/rename'`
+- `'textDocument/semanticTokens/full'`
+- `'textDocument/semanticTokens/full/delta'`
+- `'textDocument/signatureHelp'`
+- `'textDocument/typeDefinition*'`
+- `'typeHierarchy/subtypes'`
+- `'typeHierarchy/supertypes'`
+- `'window/logMessage'`
+- `'window/showMessage'`
+- `'window/showDocument'`
+- `'window/showMessageRequest'`
+- `'workspace/applyEdit'`
+- `'workspace/configuration'`
+- `'workspace/executeCommand'`
+- `'workspace/inlayHint/refresh'`
+- `'workspace/symbol'`
+- `'workspace/workspaceFolders'`
*lsp-handler*
LSP handlers are functions that handle |lsp-response|s to requests made by Nvim
@@ -236,7 +238,7 @@ there is no response, so they can't be handled. |lsp-notification|)
Each response handler has this signature: >
- function(err, result, ctx, config)
+ function(err, result, ctx)
<
Parameters: ~
• {err} (`table|nil`) Error info dict, or `nil` if the request
@@ -253,121 +255,53 @@ Each response handler has this signature: >
request. Handlers can compare this to the
current document version to check if the
response is "stale". See also |b:changedtick|.
- • {config} (`table`) Handler-defined configuration table, which allows
- users to customize handler behavior.
- For an example, see:
- |vim.lsp.diagnostic.on_publish_diagnostics()|
- To configure a particular |lsp-handler|, see:
- |lsp-handler-configuration|
Returns: ~
Two values `result, err` where `err` is shaped like an RPC error: >
{ code, message, data? }
< You can use |vim.lsp.rpc.rpc_response_error()| to create this object.
- *lsp-handler-configuration*
-
-To configure the behavior of a builtin |lsp-handler|, the convenient method
-|vim.lsp.with()| is provided for users.
-
- To configure the behavior of |vim.lsp.diagnostic.on_publish_diagnostics()|,
- consider the following example, where a new |lsp-handler| is created using
- |vim.lsp.with()| that no longer generates signs for the diagnostics: >lua
-
- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {
- -- Disable signs
- signs = false,
- }
- )
-<
- To enable signs, use |vim.lsp.with()| again to create and assign a new
- |lsp-handler| to |vim.lsp.handlers| for the associated method: >lua
-
- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {
- -- Enable signs
- signs = true,
- }
- )
-<
- To configure a handler on a per-server basis, you can use the {handlers} key
- for |vim.lsp.start_client()| >lua
-
- vim.lsp.start_client {
- ..., -- Other configuration omitted.
- handlers = {
- ["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {
- -- Disable virtual_text
- virtual_text = false,
- }
- ),
- },
- }
-<
- or if using "nvim-lspconfig", you can use the {handlers} key of `setup()`:
- >lua
-
- require('lspconfig').rust_analyzer.setup {
- handlers = {
- ["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {
- -- Disable virtual_text
- virtual_text = false
- }
- ),
- }
- }
-<
- Some handlers do not have an explicitly named handler function (such as
- |vim.lsp.diagnostic.on_publish_diagnostics()|). To override these, first
- create a reference to the existing handler: >lua
-
- local on_references = vim.lsp.handlers["textDocument/references"]
- vim.lsp.handlers["textDocument/references"] = vim.lsp.with(
- on_references, {
- -- Use location list instead of quickfix list
- loclist = true,
- }
- )
-<
*lsp-handler-resolution*
-Handlers can be set by:
+Handlers can be set by (in increasing priority):
- Setting a field in vim.lsp.handlers. *vim.lsp.handlers*
- vim.lsp.handlers is a global table that contains the default mapping of
- |lsp-method| names to |lsp-handlers|. To override the handler for the
- `"textDocument/definition"` method: >lua
+ `vim.lsp.handlers` is a global table that contains the default mapping of
+ |lsp-method| names to lsp-handlers.
- vim.lsp.handlers["textDocument/definition"] = my_custom_default_definition
+ Example: >lua
+
+ vim.lsp.handlers['textDocument/publishDiagnostics'] = my_custom_diagnostics_handler
<
+ Note: this only applies for requests/notifications made by the
+ server to the client.
+
- The {handlers} parameter of |vim.lsp.start()|. This sets the default
- |lsp-handler| for the server being started. Example: >lua
+ |lsp-handler| for a specific server.
+
+ Example: >lua
vim.lsp.start {
..., -- Other configuration omitted.
handlers = {
- ["textDocument/definition"] = my_custom_server_definition
+ ['textDocument/publishDiagnostics'] = my_custom_server_definition
},
}
+<
+ Note: this only applies for requests/notifications made by the
+ server to the client.
- The {handler} parameter of |vim.lsp.buf_request_all()|. This sets
- the |lsp-handler| ONLY for the given request(s). Example: >lua
+ the |lsp-handler| ONLY for the given request(s).
+
+ Example: >lua
vim.lsp.buf_request_all(
0,
- "textDocument/definition",
+ 'textDocument/publishDiagnostics',
my_request_params,
my_handler
)
<
-In summary, the |lsp-handler| will be chosen based on the current |lsp-method|
-in the following order:
-
-1. Handler passed to |vim.lsp.buf_request_all()|, if any.
-2. Handler defined in |vim.lsp.start()|, if any.
-3. Handler defined in |vim.lsp.handlers|, if any.
*vim.lsp.log_levels*
Log levels are defined in |vim.log.levels|
@@ -404,13 +338,16 @@ Highlight groups that are meant to be used by |vim.lsp.buf.document_highlight()|
You can see more about the differences in types here:
https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight
- *hl-LspReferenceText*
+ *hl-LspReferenceText*
LspReferenceText used for highlighting "text" references
- *hl-LspReferenceRead*
+ *hl-LspReferenceRead*
LspReferenceRead used for highlighting "read" references
- *hl-LspReferenceWrite*
+ *hl-LspReferenceWrite*
LspReferenceWrite used for highlighting "write" references
- *hl-LspInlayHint*
+ *hl-LspReferenceTarget*
+LspReferenceTarget used for highlighting reference targets (e.g. in a
+ hover range)
+ *hl-LspInlayHint*
LspInlayHint used for highlighting inlay hints
@@ -463,7 +400,7 @@ Use |:Inspect| to view the highlights for a specific token. Use |:hi| or
hi @lsp.mod.deprecated gui=strikethrough " deprecated is crossed out
hi @lsp.typemod.function.async guifg=Blue " async functions are blue
<
-The value |vim.highlight.priorities|`.semantic_tokens` is the priority of the
+The value |vim.hl.priorities|`.semantic_tokens` is the priority of the
`@lsp.type.*` highlights. The `@lsp.mod.*` and `@lsp.typemod.*` highlights
have priorities one and two higher, respectively.
@@ -541,10 +478,10 @@ LspDetach *LspDetach*
-- Remove the autocommand to format the buffer on save, if it exists
if client.supports_method('textDocument/formatting') then
- vim.api.nvim_clear_autocmds({
- event = 'BufWritePre',
- buffer = args.buf,
- })
+ vim.api.nvim_clear_autocmds({
+ event = 'BufWritePre',
+ buffer = args.buf,
+ })
end
end,
})
@@ -701,7 +638,10 @@ buf_request_all({bufnr}, {method}, {params}, {handler})
Parameters: ~
• {bufnr} (`integer`) Buffer handle, or 0 for current.
• {method} (`string`) LSP method name
- • {params} (`table?`) Parameters to send to the server
+ • {params} (`table|(fun(client: vim.lsp.Client, bufnr: integer): table?)?`)
+ Parameters to send to the server. Can also be passed as a
+ function that returns the params table for cases where
+ parameters are specific to the client.
• {handler} (`function`) Handler called after all requests are
completed. Server results are passed as a
`client_id:result` map.
@@ -866,9 +806,9 @@ start({config}, {opts}) *vim.lsp.start()*
|vim.lsp.start_client()|.
• `root_dir` path to the project root. By default this is used to decide
if an existing client should be re-used. The example above uses
- |vim.fs.root()| and |vim.fs.dirname()| to detect the root by traversing
- the file system upwards starting from the current directory until either
- a `pyproject.toml` or `setup.py` file is found.
+ |vim.fs.root()| to detect the root by traversing the file system upwards
+ starting from the current directory until either a `pyproject.toml` or
+ `setup.py` file is found.
• `workspace_folders` list of `{ uri:string, name: string }` tables
specifying the project root folders used by the language server. If
`nil` the property is derived from `root_dir` for convenience.
@@ -950,14 +890,6 @@ tagfunc({pattern}, {flags}) *vim.lsp.tagfunc()*
Return: ~
(`table[]`) tags A list of matching tags
-with({handler}, {override_config}) *vim.lsp.with()*
- Function to manage overriding defaults for LSP handlers.
-
- Parameters: ~
- • {handler} (`lsp.Handler`) See |lsp-handler|
- • {override_config} (`table`) Table containing the keys to override
- behavior of the {handler}
-
==============================================================================
Lua module: vim.lsp.client *lsp-client*
@@ -1083,6 +1015,11 @@ Lua module: vim.lsp.client *lsp-client*
• {is_stopped} (`fun(): boolean`) Checks whether a client is
stopped. Returns: true if the client is fully
stopped.
+ • {exec_cmd} (`fun(self: vim.lsp.Client, command: lsp.Command, context: {bufnr?: integer}?, handler: lsp.Handler?)`)
+ Execute a lsp command, either via client
+ command function (if available) or via
+ workspace/executeCommand (if supported by the
+ server)
*vim.lsp.Client.Progress*
Extends: |vim.Ringbuf|
@@ -1153,7 +1090,8 @@ Lua module: vim.lsp.client *lsp-client*
• {name}? (`string`, default: client-id) Name in log
messages.
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
- Language ID as string. Defaults to the filetype.
+ Language ID as string. Defaults to the buffer
+ filetype.
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) The encoding that
the LSP server expects. Client does not verify
this is correct.
@@ -1212,6 +1150,15 @@ Lua module: vim.lsp.client *lsp-client*
on initialization.
+Client:exec_cmd({command}, {context}, {handler}) *Client:exec_cmd()*
+ Execute a lsp command, either via client command function (if available)
+ or via workspace/executeCommand (if supported by the server)
+
+ Parameters: ~
+ • {command} (`lsp.Command`)
+ • {context} (`{bufnr?: integer}?`)
+ • {handler} (`lsp.Handler?`) only called if a server command
+
==============================================================================
Lua module: vim.lsp.buf *lsp-buf*
@@ -1253,6 +1200,20 @@ Lua module: vim.lsp.buf *lsp-buf*
• {title}? (`string`) Title for the list.
• {context}? (`table`) `ctx` from |lsp-handler|
+*vim.lsp.buf.hover.Opts*
+ Extends: |vim.lsp.util.open_floating_preview.Opts|
+
+
+ Fields: ~
+ • {silent}? (`boolean`)
+
+*vim.lsp.buf.signature_help.Opts*
+ Extends: |vim.lsp.util.open_floating_preview.Opts|
+
+
+ Fields: ~
+ • {silent}? (`boolean`)
+
*vim.lsp.buf.add_workspace_folder()*
add_workspace_folder({workspace_folder})
@@ -1294,19 +1255,6 @@ code_action({opts}) *vim.lsp.buf.code_action()*
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
• vim.lsp.protocol.CodeActionTriggerKind
-completion({context}) *vim.lsp.buf.completion()*
- Retrieves the completion items at the current cursor position. Can only be
- called in Insert mode.
-
- Parameters: ~
- • {context} (`table`) (context support not yet implemented) Additional
- information about the context in which a completion was
- triggered (how it was triggered, and by which trigger
- character, if applicable)
-
- See also: ~
- • vim.lsp.protocol.CompletionTriggerKind
-
declaration({opts}) *vim.lsp.buf.declaration()*
Jumps to the declaration of the symbol under the cursor.
@@ -1343,15 +1291,6 @@ document_symbol({opts}) *vim.lsp.buf.document_symbol()*
Parameters: ~
• {opts} (`vim.lsp.ListOpts?`) See |vim.lsp.ListOpts|.
-execute_command({command_params}) *vim.lsp.buf.execute_command()*
- Executes an LSP server command.
-
- Parameters: ~
- • {command_params} (`lsp.ExecuteCommandParams`)
-
- See also: ~
- • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
-
format({opts}) *vim.lsp.buf.format()*
Formats a buffer using the attached (and optionally filtered) language
server clients.
@@ -1392,7 +1331,7 @@ format({opts}) *vim.lsp.buf.format()*
contain `start` and `end` keys as described above, in which
case `textDocument/rangesFormatting` support is required.
-hover() *vim.lsp.buf.hover()*
+hover({config}) *vim.lsp.buf.hover()*
Displays hover information about the symbol under the cursor in a floating
window. The window will be dismissed on cursor move. Calling the function
twice will jump into the floating window (thus by default, "KK" will open
@@ -1400,6 +1339,17 @@ hover() *vim.lsp.buf.hover()*
mappings are available as usual, except that "q" dismisses the window. You
can scroll the contents the same as you would any other buffer.
+ Note: to disable hover highlights, add the following to your config: >lua
+ vim.api.nvim_create_autocmd('ColorScheme', {
+ callback = function()
+ vim.api.nvim_set_hl(0, 'LspReferenceTarget', {})
+ end,
+ })
+<
+
+ Parameters: ~
+ • {config} (`vim.lsp.buf.hover.Opts?`) See |vim.lsp.buf.hover.Opts|.
+
implementation({opts}) *vim.lsp.buf.implementation()*
Lists all the implementations for the symbol under the cursor in the
quickfix window.
@@ -1454,10 +1404,14 @@ rename({new_name}, {opts}) *vim.lsp.buf.rename()*
ones where client.name matches this field.
• {bufnr}? (`integer`) (default: current buffer)
-signature_help() *vim.lsp.buf.signature_help()*
+signature_help({config}) *vim.lsp.buf.signature_help()*
Displays signature information about the symbol under the cursor in a
floating window.
+ Parameters: ~
+ • {config} (`vim.lsp.buf.signature_help.Opts?`) See
+ |vim.lsp.buf.signature_help.Opts|.
+
type_definition({opts}) *vim.lsp.buf.type_definition()*
Jumps to the definition of the type of the symbol under the cursor.
@@ -1507,66 +1461,24 @@ get_namespace({client_id}, {is_pull})
client. Defaults to push
*vim.lsp.diagnostic.on_diagnostic()*
-on_diagnostic({_}, {result}, {ctx}, {config})
+on_diagnostic({_}, {result}, {ctx})
|lsp-handler| for the method "textDocument/diagnostic"
- See |vim.diagnostic.config()| for configuration options. Handler-specific
- configuration can be set using |vim.lsp.with()|: >lua
- vim.lsp.handlers["textDocument/diagnostic"] = vim.lsp.with(
- vim.lsp.diagnostic.on_diagnostic, {
- -- Enable underline, use default values
- underline = true,
- -- Enable virtual text, override spacing to 4
- virtual_text = {
- spacing = 4,
- },
- -- Use a function to dynamically turn signs off
- -- and on, using buffer local variables
- signs = function(namespace, bufnr)
- return vim.b[bufnr].show_signs == true
- end,
- -- Disable a feature
- update_in_insert = false,
- }
- )
-<
+ See |vim.diagnostic.config()| for configuration options.
Parameters: ~
• {result} (`lsp.DocumentDiagnosticReport`)
• {ctx} (`lsp.HandlerContext`)
- • {config} (`vim.diagnostic.Opts`) Configuration table (see
- |vim.diagnostic.config()|).
*vim.lsp.diagnostic.on_publish_diagnostics()*
-on_publish_diagnostics({_}, {result}, {ctx}, {config})
+on_publish_diagnostics({_}, {result}, {ctx})
|lsp-handler| for the method "textDocument/publishDiagnostics"
- See |vim.diagnostic.config()| for configuration options. Handler-specific
- configuration can be set using |vim.lsp.with()|: >lua
- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {
- -- Enable underline, use default values
- underline = true,
- -- Enable virtual text, override spacing to 4
- virtual_text = {
- spacing = 4,
- },
- -- Use a function to dynamically turn signs off
- -- and on, using buffer local variables
- signs = function(namespace, bufnr)
- return vim.b[bufnr].show_signs == true
- end,
- -- Disable a feature
- update_in_insert = false,
- }
- )
-<
+ See |vim.diagnostic.config()| for configuration options.
Parameters: ~
• {result} (`lsp.PublishDiagnosticsParams`)
• {ctx} (`lsp.HandlerContext`)
- • {config} (`vim.diagnostic.Opts?`) Configuration table (see
- |vim.diagnostic.config()|).
==============================================================================
@@ -1638,8 +1550,9 @@ Lua module: vim.lsp.completion *lsp-completion*
*vim.lsp.completion.BufferOpts*
Fields: ~
- • {autotrigger}? (`boolean`) Whether to trigger completion
- automatically. Default: false
+ • {autotrigger}? (`boolean`) Default: false When true, completion
+ triggers automatically based on the server's
+ `triggerCharacters`.
• {convert}? (`fun(item: lsp.CompletionItem): table`) Transforms an
LSP CompletionItem to |complete-items|.
@@ -1778,8 +1691,8 @@ highlight_token({token}, {bufnr}, {client_id}, {hl_group}, {opts})
• {hl_group} (`string`) Highlight group name
• {opts} (`table?`) Optional parameters:
• {priority}? (`integer`, default:
- `vim.highlight.priorities.semantic_tokens + 3`)
- Priority for the applied extmark.
+ `vim.hl.priorities.semantic_tokens + 3`) Priority for
+ the applied extmark.
start({bufnr}, {client_id}, {opts}) *vim.lsp.semantic_tokens.start()*
Start the semantic token highlighting engine for the given buffer with the
@@ -1816,54 +1729,44 @@ stop({bufnr}, {client_id}) *vim.lsp.semantic_tokens.stop()*
==============================================================================
-Lua module: vim.lsp.handlers *lsp-handlers*
-
-hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()*
- |lsp-handler| for the method "textDocument/hover" >lua
- vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(
- vim.lsp.handlers.hover, {
- -- Use a sharp border with `FloatBorder` highlights
- border = "single",
- -- add the title in hover float window
- title = "hover"
- }
- )
-<
-
- Parameters: ~
- • {result} (`lsp.Hover`)
- • {ctx} (`lsp.HandlerContext`)
- • {config} (`table`) Configuration table.
- • border: (default=nil)
- • Add borders to the floating window
- • See |vim.lsp.util.open_floating_preview()| for more
- options.
-
- *vim.lsp.handlers.signature_help()*
-signature_help({_}, {result}, {ctx}, {config})
- |lsp-handler| for the method "textDocument/signatureHelp".
-
- The active parameter is highlighted with |hl-LspSignatureActiveParameter|. >lua
- vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(
- vim.lsp.handlers.signature_help, {
- -- Use a sharp border with `FloatBorder` highlights
- border = "single"
- }
- )
-<
+Lua module: vim.lsp.util *lsp-util*
- Parameters: ~
- • {result} (`lsp.SignatureHelp`) Response from the language server
- • {ctx} (`lsp.HandlerContext`) Client context
- • {config} (`table`) Configuration table.
- • border: (default=nil)
- • Add borders to the floating window
- • See |vim.lsp.util.open_floating_preview()| for more
- options
+*vim.lsp.util.open_floating_preview.Opts*
+ Fields: ~
+ • {height}? (`integer`) Height of floating window
+ • {width}? (`integer`) Width of floating window
+ • {wrap}? (`boolean`, default: `true`) Wrap long lines
+ • {wrap_at}? (`integer`) Character to wrap at for computing height
+ when wrap is enabled
+ • {max_width}? (`integer`) Maximal width of floating window
+ • {max_height}? (`integer`) Maximal height of floating window
+ • {focus_id}? (`string`) If a popup with this id is opened, then
+ focus it
+ • {close_events}? (`table`) List of events that closes the floating
+ window
+ • {focusable}? (`boolean`, default: `true`) Make float focusable.
+ • {focus}? (`boolean`, default: `true`) If `true`, and if
+ {focusable} is also `true`, focus an existing
+ floating window with the same {focus_id}
+ • {offset_x}? (`integer`) offset to add to `col`
+ • {offset_y}? (`integer`) offset to add to `row`
+ • {border}? (`string|(string|[string,string])[]`) override
+ `border`
+ • {zindex}? (`integer`) override `zindex`, defaults to 50
+ • {title}? (`string`)
+ • {title_pos}? (`'left'|'center'|'right'`)
+ • {relative}? (`'mouse'|'cursor'`) (default: `'cursor'`)
+ • {anchor_bias}? (`'auto'|'above'|'below'`, default: `'auto'`) -
+ "auto": place window based on which side of the
+ cursor has more lines
+ • "above": place the window above the cursor unless
+ there are not enough lines to display the full
+ window height.
+ • "below": place the window below the cursor unless
+ there are not enough lines to display the full
+ window height.
-==============================================================================
-Lua module: vim.lsp.util *lsp-util*
*vim.lsp.util.apply_text_document_edit()*
apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
@@ -1874,7 +1777,7 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
• {text_document_edit} (`lsp.TextDocumentEdit`)
• {index} (`integer?`) Optional index of the edit, if from
a list of edits (or nil, if not from a list)
- • {offset_encoding} (`string?`)
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
@@ -1886,7 +1789,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
Parameters: ~
• {text_edits} (`lsp.TextEdit[]`)
• {bufnr} (`integer`) Buffer id
- • {offset_encoding} (`string`) utf-8|utf-16|utf-32
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
@@ -1897,7 +1800,7 @@ apply_workspace_edit({workspace_edit}, {offset_encoding})
Parameters: ~
• {workspace_edit} (`lsp.WorkspaceEdit`)
- • {offset_encoding} (`string`) utf-8|utf-16|utf-32 (required)
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) (required)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
@@ -1915,7 +1818,7 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding})
Parameters: ~
• {bufnr} (`integer`) Buffer id
• {references} (`lsp.DocumentHighlight[]`) objects to highlight
- • {offset_encoding} (`string`) One of "utf-8", "utf-16", "utf-32".
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
@@ -1928,7 +1831,7 @@ character_offset({buf}, {row}, {col}, {offset_encoding})
• {buf} (`integer`) buffer number (0 for current)
• {row} (`integer`) 0-indexed line
• {col} (`integer`) 0-indexed byte offset in line
- • {offset_encoding} (`string`) utf-8|utf-16|utf-32 defaults to
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
`offset_encoding` of first client of `buf`
Return: ~
@@ -1966,12 +1869,13 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
`textDocument/SignatureHelp`
• {ft} (`string?`) filetype that will be use as the `lang`
for the label markdown code block
- • {triggers} (`table?`) list of trigger characters from the lsp
- server. used to better determine parameter offsets
+ • {triggers} (`string[]?`) list of trigger characters from the
+ lsp server. used to better determine parameter
+ offsets
Return (multiple): ~
- (`string[]?`) table list of lines of converted markdown.
- (`number[]?`) table of active hl
+ (`string[]?`) lines of converted markdown.
+ (`Range4?`) highlight range for the active parameter
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
@@ -1988,19 +1892,6 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
See also: ~
• 'shiftwidth'
- *vim.lsp.util.jump_to_location()*
-jump_to_location({location}, {offset_encoding}, {reuse_win})
- Jumps to a location.
-
- Parameters: ~
- • {location} (`lsp.Location|lsp.LocationLink`)
- • {offset_encoding} (`string?`) utf-8|utf-16|utf-32
- • {reuse_win} (`boolean?`) Jump to existing window if buffer is
- already open.
-
- Return: ~
- (`boolean`) `true` if the jump succeeded
-
*vim.lsp.util.locations_to_items()*
locations_to_items({locations}, {offset_encoding})
Returns the items with the byte position calculated correctly and in
@@ -2014,19 +1905,11 @@ locations_to_items({locations}, {offset_encoding})
Parameters: ~
• {locations} (`lsp.Location[]|lsp.LocationLink[]`)
- • {offset_encoding} (`string`) offset_encoding for locations
- utf-8|utf-16|utf-32 default to first client of
- buffer
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) default to first
+ client of buffer
Return: ~
- (`table[]`) A list of objects with the following fields:
- • {filename} (`string`)
- • {lnum} (`integer`) 1-indexed line number
- • {end_lnum} (`integer`) 1-indexed end line number
- • {col} (`integer`) 1-indexed column
- • {end_col} (`integer`) 1-indexed end column
- • {text} (`string`)
- • {user_data} (`lsp.Location|lsp.LocationLink`)
+ (`vim.quickfix.entry[]`) See |setqflist()| for the format
*vim.lsp.util.make_floating_popup_options()*
make_floating_popup_options({width}, {height}, {opts})
@@ -2036,23 +1919,11 @@ make_floating_popup_options({width}, {height}, {opts})
Parameters: ~
• {width} (`integer`) window width (in character cells)
• {height} (`integer`) window height (in character cells)
- • {opts} (`table`) optional
- • offset_x (integer) offset to add to `col`
- • offset_y (integer) offset to add to `row`
- • border (string or table) override `border`
- • focusable (string or table) override `focusable`
- • zindex (string or table) override `zindex`, defaults to 50
- • relative ("mouse"|"cursor") defaults to "cursor"
- • anchor_bias ("auto"|"above"|"below") defaults to "auto"
- • "auto": place window based on which side of the cursor
- has more lines
- • "above": place the window above the cursor unless there
- are not enough lines to display the full window height.
- • "below": place the window below the cursor unless there
- are not enough lines to display the full window height.
+ • {opts} (`vim.lsp.util.open_floating_preview.Opts?`) See
+ |vim.lsp.util.open_floating_preview.Opts|.
Return: ~
- (`table`) Options
+ (`vim.api.keyset.win_config`)
*vim.lsp.util.make_formatting_params()*
make_formatting_params({options})
@@ -2075,13 +1946,15 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
similar to |vim.lsp.util.make_range_params()|.
Parameters: ~
- • {start_pos} (`integer[]?`) {row,col} mark-indexed position.
- Defaults to the start of the last visual selection.
- • {end_pos} (`integer[]?`) {row,col} mark-indexed position.
- Defaults to the end of the last visual selection.
+ • {start_pos} (`[integer,integer]?`) {row,col} mark-indexed
+ position. Defaults to the start of the last visual
+ selection.
+ • {end_pos} (`[integer,integer]?`) {row,col} mark-indexed
+ position. Defaults to the end of the last visual
+ selection.
• {bufnr} (`integer?`) buffer handle or 0 for current,
defaults to current
- • {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"?`) defaults to
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
`offset_encoding` of first client of `bufnr`
Return: ~
@@ -2096,7 +1969,7 @@ make_position_params({window}, {offset_encoding})
Parameters: ~
• {window} (`integer?`) window handle or 0 for current,
defaults to current
- • {offset_encoding} (`string?`) utf-8|utf-16|utf-32|nil defaults to
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
`offset_encoding` of first client of buffer of
`window`
@@ -2155,27 +2028,11 @@ open_floating_preview({contents}, {syntax}, {opts})
Parameters: ~
• {contents} (`table`) of lines to show in window
• {syntax} (`string`) of syntax to set for opened buffer
- • {opts} (`table?`) with optional fields (additional keys are
- filtered with |vim.lsp.util.make_floating_popup_options()|
- before they are passed on to |nvim_open_win()|)
- • {height}? (`integer`) Height of floating window
- • {width}? (`integer`) Width of floating window
- • {wrap}? (`boolean`, default: `true`) Wrap long lines
- • {wrap_at}? (`integer`) Character to wrap at for
- computing height when wrap is enabled
- • {max_width}? (`integer`) Maximal width of floating
- window
- • {max_height}? (`integer`) Maximal height of floating
- window
- • {focus_id}? (`string`) If a popup with this id is
- opened, then focus it
- • {close_events}? (`table`) List of events that closes the
- floating window
- • {focusable}? (`boolean`, default: `true`) Make float
- focusable.
- • {focus}? (`boolean`, default: `true`) If `true`, and if
- {focusable} is also `true`, focus an existing floating
- window with the same {focus_id}
+ • {opts} (`vim.lsp.util.open_floating_preview.Opts?`) with optional
+ fields (additional keys are filtered with
+ |vim.lsp.util.make_floating_popup_options()| before they
+ are passed on to |nvim_open_win()|). See
+ |vim.lsp.util.open_floating_preview.Opts|.
Return (multiple): ~
(`integer`) bufnr of newly created float window
@@ -2191,7 +2048,8 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()*
Parameters: ~
• {location} (`lsp.Location|lsp.LocationLink`)
- • {opts} (`table`)
+ • {opts} (`vim.lsp.util.open_floating_preview.Opts?`) See
+ |vim.lsp.util.open_floating_preview.Opts|.
Return (multiple): ~
(`integer?`) buffer id of float window
@@ -2221,12 +2079,12 @@ show_document({location}, {offset_encoding}, {opts})
Parameters: ~
• {location} (`lsp.Location|lsp.LocationLink`)
- • {offset_encoding} (`string?`) utf-8|utf-16|utf-32
- • {opts} (`table?`) options
- • reuse_win (boolean) Jump to existing window if
- buffer is already open.
- • focus (boolean) Whether to focus/jump to location
- if possible. Defaults to true.
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`)
+ • {opts} (`table?`) A table with the following fields:
+ • {reuse_win}? (`boolean`) Jump to existing window
+ if buffer is already open.
+ • {focus}? (`boolean`) Whether to focus/jump to
+ location if possible. (defaults: true)
Return: ~
(`boolean`) `true` if succeeded
@@ -2246,7 +2104,7 @@ stylize_markdown({bufnr}, {contents}, {opts})
Parameters: ~
• {bufnr} (`integer`)
• {contents} (`string[]`) of lines to show in window
- • {opts} (`table`) with optional fields
+ • {opts} (`table?`) with optional fields
• height of floating window
• width of floating window
• wrap_at character to wrap at for computing height
@@ -2261,9 +2119,12 @@ symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
Converts symbols to quickfix list items.
Parameters: ~
- • {symbols} (`table`) DocumentSymbol[] or SymbolInformation[]
+ • {symbols} (`lsp.DocumentSymbol[]|lsp.SymbolInformation[]`)
• {bufnr} (`integer?`)
+ Return: ~
+ (`vim.quickfix.entry[]`) See |setqflist()| for the format
+
==============================================================================
Lua module: vim.lsp.log *lsp-log*
@@ -2300,7 +2161,7 @@ should_log({level}) *vim.lsp.log.should_log()*
• {level} (`integer`) log level
Return: ~
- (`bool`) true if would log, false if not
+ (`boolean`) true if would log, false if not
==============================================================================
diff --git a/runtime/doc/lua-guide.txt b/runtime/doc/lua-guide.txt
index 5f06d51f42..b40d5a0791 100644
--- a/runtime/doc/lua-guide.txt
+++ b/runtime/doc/lua-guide.txt
@@ -552,7 +552,7 @@ This means that if your callback itself takes an (even optional) argument, you
must wrap it in `function() end` to avoid an error:
>lua
vim.api.nvim_create_autocmd('TextYankPost', {
- callback = function() vim.highlight.on_yank() end
+ callback = function() vim.hl.on_yank() end
})
<
(Since unused arguments can be omitted in Lua function definitions, this is
@@ -576,7 +576,7 @@ Instead of using a pattern, you can create a buffer-local autocommand (see
Similarly to mappings, you can (and should) add a description using `desc`:
>lua
vim.api.nvim_create_autocmd('TextYankPost', {
- callback = function() vim.highlight.on_yank() end,
+ callback = function() vim.hl.on_yank() end,
desc = "Briefly highlight yanked text"
})
<
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 396f24a1aa..243c907180 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -636,13 +636,13 @@ A subset of the `vim.*` API is available in threads. This includes:
==============================================================================
-VIM.HIGHLIGHT *vim.highlight*
+VIM.HL *vim.hl*
-vim.highlight.on_yank({opts}) *vim.highlight.on_yank()*
+vim.hl.on_yank({opts}) *vim.hl.on_yank()*
Highlight the yanked text during a |TextYankPost| event.
Add the following to your `init.vim`: >vim
- autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup='Visual', timeout=300}
+ autocmd TextYankPost * silent! lua vim.hl.on_yank {higroup='Visual', timeout=300}
<
Parameters: ~
@@ -655,9 +655,9 @@ vim.highlight.on_yank({opts}) *vim.highlight.on_yank()*
true)
• event event structure (default vim.v.event)
• priority integer priority (default
- |vim.highlight.priorities|`.user`)
+ |vim.hl.priorities|`.user`)
-vim.highlight.priorities *vim.highlight.priorities*
+vim.hl.priorities *vim.hl.priorities*
Table with default priorities used for highlighting:
• `syntax`: `50`, used for standard syntax highlighting
• `treesitter`: `100`, used for treesitter-based highlighting
@@ -666,8 +666,8 @@ vim.highlight.priorities *vim.highlight.priorities*
• `user`: `200`, used for user-triggered highlights such as LSP document
symbols or `on_yank` autocommands
- *vim.highlight.range()*
-vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts})
+ *vim.hl.range()*
+vim.hl.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts})
Apply highlight group to range of text.
Parameters: ~
@@ -684,8 +684,7 @@ vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts})
• {inclusive}? (`boolean`, default: `false`) Indicates
whether the range is end-inclusive
• {priority}? (`integer`, default:
- `vim.highlight.priorities.user`) Indicates priority of
- highlight
+ `vim.hl.priorities.user`) Highlight priority
==============================================================================
@@ -1001,22 +1000,6 @@ vim.schedule({fn}) *vim.schedule()*
Parameters: ~
• {fn} (`fun()`)
-vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()*
- Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
- supplied, it defaults to false (use UTF-32). Returns the byte index.
-
- Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|. An {index}
- in the middle of a UTF-16 sequence is rounded upwards to the end of that
- sequence.
-
- Parameters: ~
- • {str} (`string`)
- • {index} (`integer`)
- • {use_utf16} (`boolean?`)
-
- Return: ~
- (`integer`)
-
vim.str_utf_end({str}, {index}) *vim.str_utf_end()*
Gets the distance (in bytes) from the last byte of the codepoint
(character) that {index} points to.
@@ -1074,23 +1057,6 @@ vim.str_utf_start({str}, {index}) *vim.str_utf_start()*
Return: ~
(`integer`)
-vim.str_utfindex({str}, {index}) *vim.str_utfindex()*
- Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
- supplied, the length of the string is used. All indices are zero-based.
-
- Embedded NUL bytes are treated as terminating the string. Invalid UTF-8
- bytes, and embedded surrogates are counted as one code point each. An
- {index} in the middle of a UTF-8 sequence is rounded upwards to the end of
- that sequence.
-
- Parameters: ~
- • {str} (`string`)
- • {index} (`integer?`)
-
- Return (multiple): ~
- (`integer`) UTF-32 index
- (`integer`) UTF-16 index
-
vim.stricmp({a}, {b}) *vim.stricmp()*
Compares strings case-insensitively.
@@ -1117,6 +1083,12 @@ vim.ui_attach({ns}, {options}, {callback}) *vim.ui_attach()*
|ui-popupmenu| and the sections below for event format for respective
events.
+ Callbacks for `msg_show` events are executed in |api-fast| context unless
+ Nvim will wait for input, in which case messages should be shown
+ immediately.
+
+ Excessive errors inside the callback will result in forced detachment.
+
WARNING: This api is considered experimental. Usability will vary for
different screen elements. In particular `ext_messages` behavior is
subject to further changes and usability improvements. This is expected to
@@ -1464,12 +1436,9 @@ Option:remove({value}) *vim.opt:remove()*
• {value} (`string`) Value to remove
vim.bo[{bufnr}] *vim.bo*
- Get or set buffer-scoped |options| for the buffer with number {bufnr}. If
- {bufnr} is omitted then the current buffer is used. Invalid {bufnr} or key
- is an error.
-
- Note: this is equivalent to `:setlocal` for |global-local| options and
- `:set` otherwise.
+ Get or set buffer-scoped |options| for the buffer with number {bufnr}.
+ Like `:setlocal`. If {bufnr} is omitted then the current buffer is used.
+ Invalid {bufnr} or key is an error.
Example: >lua
local bufnr = vim.api.nvim_get_current_buf()
@@ -1672,7 +1641,7 @@ vim.notify_once({msg}, {level}, {opts}) *vim.notify_once()*
Return: ~
(`boolean`) true if message was displayed, else false
-vim.on_key({fn}, {ns_id}) *vim.on_key()*
+vim.on_key({fn}, {ns_id}, {opts}) *vim.on_key()*
Adds Lua function {fn} with namespace id {ns_id} as a listener to every,
yes every, input key.
@@ -1681,22 +1650,32 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
Note: ~
• {fn} will be removed on error.
+ • {fn} won't be invoked recursively, i.e. if {fn} itself consumes input,
+ it won't be invoked for those keys.
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
Parameters: ~
- • {fn} (`fun(key: string, typed: string)?`) Function invoked on
- every key press. |i_CTRL-V| {key} is the key after mappings
- have been applied, and {typed} is the key(s) before mappings
- are applied, which may be empty if {key} is produced by
- non-typed keys. When {fn} is nil and {ns_id} is specified,
- the callback associated with namespace {ns_id} is removed.
+ • {fn} (`fun(key: string, typed: string): string??`) Function
+ invoked for every input key, after mappings have been applied
+ but before further processing. Arguments {key} and {typed}
+ are raw keycodes, where {key} is the key after mappings are
+ applied, and {typed} is the key(s) before mappings are
+ applied. {typed} may be empty if {key} is produced by
+ non-typed key(s) or by the same typed key(s) that produced a
+ previous {key}. If {fn} returns an empty string, {key} is
+ discarded/ignored. When {fn} is `nil`, the callback
+ associated with namespace {ns_id} is removed.
• {ns_id} (`integer?`) Namespace ID. If nil or 0, generates and returns
a new |nvim_create_namespace()| id.
+ • {opts} (`table?`) Optional parameters
Return: ~
(`integer`) Namespace id associated with {fn}. Or count of all
callbacks if on_key() is called without arguments.
+ See also: ~
+ • |keytrans()|
+
vim.paste({lines}, {phase}) *vim.paste()*
Paste handler, invoked by |nvim_paste()|.
@@ -1772,6 +1751,44 @@ vim.schedule_wrap({fn}) *vim.schedule_wrap()*
• |vim.schedule()|
• |vim.in_fast_event()|
+ *vim.str_byteindex()*
+vim.str_byteindex({s}, {encoding}, {index}, {strict_indexing})
+ Convert UTF-32, UTF-16 or UTF-8 {index} to byte index. If
+ {strict_indexing} is false then then an out of range index will return
+ byte length instead of throwing an error.
+
+ Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|. An {index}
+ in the middle of a UTF-16 sequence is rounded upwards to the end of that
+ sequence.
+
+ Parameters: ~
+ • {s} (`string`)
+ • {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
+ • {index} (`integer`)
+ • {strict_indexing} (`boolean?`) default: true
+
+ Return: ~
+ (`integer`)
+
+ *vim.str_utfindex()*
+vim.str_utfindex({s}, {encoding}, {index}, {strict_indexing})
+ Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If {index} is not
+ supplied, the length of the string is used. All indices are zero-based.
+
+ If {strict_indexing} is false then an out of range index will return
+ string length instead of throwing an error. Invalid UTF-8 bytes, and
+ embedded surrogates are counted as one code point each. An {index} in the
+ middle of a UTF-8 sequence is rounded upwards to the end of that sequence.
+
+ Parameters: ~
+ • {s} (`string`)
+ • {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
+ • {index} (`integer?`)
+ • {strict_indexing} (`boolean?`) default: true
+
+ Return: ~
+ (`integer`)
+
vim.system({cmd}, {opts}, {on_exit}) *vim.system()*
Runs a system command or throws an error if {cmd} cannot be run.
@@ -2394,31 +2411,29 @@ vim.trim({s}) *vim.trim()*
• |lua-patterns|
• https://www.lua.org/pil/20.2.html
-vim.validate({opt}) *vim.validate()*
+ *vim.validate()*
+vim.validate({name}, {value}, {validator}, {optional}, {message})
Validate function arguments.
This function has two valid forms:
- 1. vim.validate(name: str, value: any, type: string, optional?: bool)
- 2. vim.validate(spec: table)
-
- Form 1 validates that argument {name} with value {value} has the type
- {type}. {type} must be a value returned by |lua-type()|. If {optional} is
- true, then {value} may be null. This form is significantly faster and
- should be preferred for simple cases.
-
- Example: >lua
- function vim.startswith(s, prefix)
+ 1. `vim.validate(name, value, validator[, optional][, message])`
+ Validates that argument {name} with value {value} satisfies
+ {validator}. If {optional} is given and is `true`, then {value} may be
+ `nil`. If {message} is given, then it is used as the expected type in
+ the error message.
+ Example: >lua
+ function vim.startswith(s, prefix)
vim.validate('s', s, 'string')
vim.validate('prefix', prefix, 'string')
...
end
<
-
- Form 2 validates a parameter specification (types and values). Specs are
- evaluated in alphanumeric order, until the first failure.
-
- Usage example: >lua
- function user.new(name, age, hobbies)
+ 2. `vim.validate(spec)` (deprecated) where `spec` is of type
+ `table<string,[value:any, validator: vim.validate.Validator, optional_or_msg? : boolean|string]>)`
+ Validates a argument specification. Specs are evaluated in alphanumeric
+ order, until the first failure.
+ Example: >lua
+ function user.new(name, age, hobbies)
vim.validate{
name={name, 'string'},
age={age, 'number'},
@@ -2429,40 +2444,44 @@ vim.validate({opt}) *vim.validate()*
<
Examples with explicit argument values (can be run directly): >lua
- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
+ vim.validate('arg1', {'foo'}, 'table')
+ --> NOP (success)
+ vim.validate('arg2', 'foo', 'string')
--> NOP (success)
- vim.validate{arg1={1, 'table'}}
+ vim.validate('arg1', 1, 'table')
--> error('arg1: expected table, got number')
- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
+ vim.validate('arg1', 3, function(a) return (a % 2) == 0 end, 'even number')
--> error('arg1: expected even number, got 3')
<
If multiple types are valid they can be given as a list. >lua
- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
+ vim.validate('arg1', {'foo'}, {'table', 'string'})
+ vim.validate('arg2', 'foo', {'table', 'string'})
-- NOP (success)
- vim.validate{arg1={1, {'string', 'table'}}}
+ vim.validate('arg1', 1, {'string', 'table'})
-- error('arg1: expected string|table, got number')
<
+ Note: ~
+ • `validator` set to a value returned by |lua-type()| provides the best
+ performance.
+
Parameters: ~
- • {opt} (`table`) Names of parameters to validate. Each key is a
- parameter name; each value is a tuple in one of these forms:
- 1. (arg_value, type_name, optional)
- • arg_value: argument value
- • type_name: string|table type name, one of: ("table", "t",
- "string", "s", "number", "n", "boolean", "b", "function",
- "f", "nil", "thread", "userdata") or list of them.
- • optional: (optional) boolean, if true, `nil` is valid
- 2. (arg_value, fn, msg)
- • arg_value: argument value
- • fn: any function accepting one argument, returns true if
- and only if the argument is valid. Can optionally return
- an additional informative error message as the second
- returned value.
- • msg: (optional) error string if validation fails
+ • {name} (`string`) Argument name
+ • {value} (`string`) Argument value
+ • {validator} (`vim.validate.Validator`)
+ • (`string|string[]`): Any value that can be returned
+ from |lua-type()| in addition to `'callable'`:
+ `'boolean'`, `'callable'`, `'function'`, `'nil'`,
+ `'number'`, `'string'`, `'table'`, `'thread'`,
+ `'userdata'`.
+ • (`fun(val:any): boolean, string?`) A function that
+ returns a boolean and an optional string message.
+ • {optional} (`boolean?`) Argument is optional (may be omitted)
+ • {message} (`string?`) message when validation fails
==============================================================================
@@ -2508,8 +2527,8 @@ vim.loader.find({modname}, {opts}) *vim.loader.find()*
(`table[]`) A list of objects with the following fields:
• {modpath} (`string`) Path of the module
• {modname} (`string`) Name of the module
- • {stat}? (`uv.uv_fs_t`) The fs_stat of the module path. Won't be
- returned for `modname="*"`
+ • {stat}? (`uv.fs_stat.result`) The fs_stat of the module path. Won't
+ be returned for `modname="*"`
vim.loader.reset({path}) *vim.loader.reset()*
WARNING: This feature is experimental/unstable.
@@ -2671,7 +2690,7 @@ vim.ui.select({items}, {opts}, {on_choice}) *vim.ui.select()*
item shape. Plugins reimplementing `vim.ui.select` may
wish to use this to infer the structure or semantics of
`items`, or the context in which select() was called.
- • {on_choice} (`fun(item: any?, idx: integer?)`) Called once the user
+ • {on_choice} (`fun(item: T?, idx: integer?)`) Called once the user
made a choice. `idx` is the 1-based index of `item`
within `items`. `nil` if the user aborted the dialog.
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 7fd1f3bfbb..11048aee30 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -66,6 +66,8 @@ modes.
where the map command applies. Disallow mapping of
{rhs}, to avoid nested and recursive mappings. Often
used to redefine a command.
+ Note: Keys in {rhs} also won't trigger abbreviation,
+ with the exception of |i_CTRL-]| and |c_CTRL-]|.
Note: When <Plug> appears in the {rhs} this part is
always applied even if remapping is disallowed.
@@ -1411,6 +1413,8 @@ completion can be enabled:
-complete=runtime file and directory names in |'runtimepath'|
-complete=scriptnames sourced script names
-complete=shellcmd Shell command
+ -complete=shellcmdline First is a shell command and subsequent ones
+ are filenames. The same behavior as |:!cmd|
-complete=sign |:sign| suboptions
-complete=syntax syntax file names |'syntax'|
-complete=syntime |:syntime| suboptions
diff --git a/runtime/doc/news-0.10.txt b/runtime/doc/news-0.10.txt
index a5ded1ca22..35af570ec3 100644
--- a/runtime/doc/news-0.10.txt
+++ b/runtime/doc/news-0.10.txt
@@ -246,7 +246,7 @@ The following new features were added.
indicator to see if a server supports a feature. Instead use
`client.supports_method(<method>)`. It considers both the dynamic
capabilities and static `server_capabilities`.
- • `anchor_bias` option to |lsp-handlers| aids in positioning of floating
+ • `anchor_bias` option to lsp-handlers aids in positioning of floating
windows.
• |vim.lsp.util.locations_to_items()| sets the `user_data` of each item to
the original LSP `Location` or `LocationLink`.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index ed5bd973be..d19df84023 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -40,6 +40,8 @@ API
This is not expected to break clients because there are no known clients
that actually use the `return_type` field or the parameter type names
reported by |--api-info| or |nvim_get_api_info()|.
+• |nvim_open_win()| supports a `mouse` field that allows configuring mouse
+ interaction with the window separately from `focusable` field.
• Renamed `nvim__id_dictionary` (unsupported/experimental API) to
`nvim__id_dict`.
@@ -53,6 +55,8 @@ DIAGNOSTICS
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|vim.diagnostic.jump()|.
+• The "underline" diagnostics handler sorts diagnostics by severity when using
+ the "severity_sort" option.
EDITOR
@@ -63,10 +67,13 @@ EDITOR
• Moving in the buffer list using |:bnext| and similar commands behaves as
documented and skips help buffers if run from a non-help buffer, otherwise
it moves to another help buffer.
+• Bells from a |terminal| buffer are now silent by default, unless 'belloff'
+ option doesn't contain "term" or "all".
EVENTS
-• TODO
+• |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in
+ |api-fast| context.
LSP
@@ -75,6 +82,19 @@ LSP
customizing the transformation of an LSP CompletionItem to |complete-items|.
• |vim.lsp.diagnostic.from()| can be used to convert a list of
|vim.Diagnostic| objects into their LSP diagnostic representation.
+• |vim.lsp.buf.references()|, |vim.lsp.buf.declaration()|, |vim.lsp.buf.definition()|,
+ |vim.lsp.buf.type_definition()|, |vim.lsp.buf.implementation()| and
+ |vim.lsp.buf.hover()| now support merging the results of multiple clients
+ but no longer trigger the global handlers from `vim.lsp.handlers`
+• |vim.lsp.buf.typehierarchy()| now passes the correct params for each
+ client request.
+• |vim.lsp.handlers.signature_help()| is no longer used.
+• |vim.lsp.diagnostic.on_publish_diagnostics()| and
+ |vim.lsp.diagnostic.on_diagnostic()| no longer accept a config parameter and
+ can no longer be configured with |vim.lsp.with()|.
+ Instead use: >lua
+ vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
+<
LUA
@@ -90,6 +110,12 @@ OPTIONS
changes according to related options. It takes care of alignment, 'number',
'relativenumber' and 'signcolumn' set to "number". The now redundant `%r` item
is no longer treated specially for 'statuscolumn'.
+• `:set {option}<` removes the local value for all |global-local| options instead
+ of just string |global-local| options.
+• `:setlocal {option}<` copies the global value to the local value for number
+ and boolean |global-local| options instead of removing the local value.
+• Setting |hidden-options| now gives an error. In particular, setting
+ 'noshellslash' is now only allowed on Windows.
PLUGINS
@@ -108,6 +134,9 @@ TREESITTER
if no languages are explicitly registered.
• |vim.treesitter.language.add()| returns `true` if a parser was loaded
successfully and `nil,errmsg` otherwise instead of throwing an error.
+• New |TSNode:child_with_descendant()|, which is nearly identical to
+ |TSNode:child_containing_descendant()| except that it can return the
+ descendant itself.
TUI
@@ -136,8 +165,10 @@ DEFAULTS
• Mappings:
• |grn| in Normal mode maps to |vim.lsp.buf.rename()|
• |grr| in Normal mode maps to |vim.lsp.buf.references()|
+ • |gri| in Normal mode maps to |vim.lsp.buf.implementation()|
+ • |gO| in Normal mode maps to |vim.lsp.buf.document_symbol()|
• |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|
- • CTRL-S in Insert mode maps to |vim.lsp.buf.signature_help()|
+ • CTRL-S in Insert and Select mode maps to |vim.lsp.buf.signature_help()|
• Mouse |popup-menu| includes an "Open in web browser" item when you right-click
on a URL.
• Mouse |popup-menu| includes a "Go to definition" item when LSP is active
@@ -148,6 +179,7 @@ DEFAULTS
• |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T| navigate through the |tag-matchlist|
• |[a|, |]a|, |[A|, |]A| navigate through the |argument-list|
• |[b|, |]b|, |[B|, |]B| navigate through the |buffer-list|
+ • |[<Space>|, |]<Space>| add an empty line above and below the cursor
• Snippet:
• `<Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = 1 })`
@@ -169,6 +201,7 @@ EVENTS
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
for completion being done.
+• |vim.on_key()| callbacks can consume the key by returning an empty string.
LSP
@@ -178,14 +211,26 @@ LSP
• |vim.lsp.buf.format()| now supports passing a list of ranges
via the `range` parameter (this requires support for the
`textDocument/rangesFormatting` request).
+• |vim.lsp.buf.code_action()| actions show client name when there are multiple
+ clients.
+• |vim.lsp.buf.signature_help()| can now cycle through different signatures
+ using `<C-s>` and also support multiple clients.
+• The client now supports `'utf-8'` and `'utf-32'` position encodings.
+• |vim.lsp.buf.hover()| now highlights hover ranges using the
+ |hl-LspReferenceTarget| highlight group.
LUA
• |vim.fs.rm()| can delete files and directories.
+• |vim.validate()| now has a new signature which uses less tables,
+ is more peformant and easier to read.
+• |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures
+ supporting two new parameters, `encoding` and `strict_indexing`.
OPTIONS
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
+• 'msghistory' controls maximum number of messages to remember.
• 'tabclose' controls which tab page to focus when closing a tab page.
PERFORMANCE
@@ -234,6 +279,16 @@ UI
which controls the tool used to open the given path or URL. If you want to
globally set this, you can override vim.ui.open using the same approach
described at |vim.paste()|.
+- `vim.ui.open()` now supports
+ [lemonade](https://github.com/lemonade-command/lemonade) as an option for
+ opening urls/files. This is handy if you are in an ssh connection and use
+ `lemonade`.
+• The |ins-completion-menu| now supports cascading highlight styles.
+ |hl-PmenuSel| and |hl-PmenuMatch| both inherit from |hl-Pmenu|, and
+ |hl-PmenuMatchSel| inherits highlights from both |hl-PmenuSel| and
+ |hl-PmenuMatch|.
+
+• |ui-messages| content chunks now also contain the highlight group ID.
==============================================================================
CHANGED FEATURES *news-changed*
@@ -254,6 +309,17 @@ These existing features changed their behavior.
more emoji characters than before, including those encoded with multiple
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
+• Text in the 'statusline', 'tabline', and 'winbar' now inherits highlights
+ from the respective |hl-StatusLine|, |hl-TabLine|, and |hl-WinBar| highlight
+ groups.
+
+• |vim.on_key()| callbacks won't be invoked recursively when a callback itself
+ consumes input.
+
+• "q" in man pages now uses |CTRL-W_q| instead of |CTRL-W_c| to close the
+ current window, and it no longer throws |E444| when there is only one window
+ on the screen. Global variable `vim.g.pager` is removed.
+
==============================================================================
REMOVED FEATURES *news-removed*
diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt
index f8eba3f7f8..86e344c654 100644
--- a/runtime/doc/nvim.txt
+++ b/runtime/doc/nvim.txt
@@ -4,7 +4,7 @@
NVIM REFERENCE MANUAL
-Nvim *neovim* *nvim* *nvim-intro*
+Nvim *nvim* *neovim* *nvim-intro*
Nvim is based on Vim by Bram Moolenaar.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6dd062124b..97d5082e9e 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -306,19 +306,13 @@ created, thus they behave slightly differently:
:se[t] {option}< Set the effective value of {option} to its global
value.
- For string |global-local| options, the local value is
- removed, so that the global value will be used.
+ For |global-local| options, the local value is removed,
+ so that the global value will be used.
For all other options, the global value is copied to
the local value.
:setl[ocal] {option}< Set the effective value of {option} to its global
- value.
- For number and boolean |global-local| options, the
- local value is removed, so that the global value will
- be used.
- For all other options, including string |global-local|
- options, the global value is copied to the local
- value.
+ value by copying the global value to the local value.
Note that the behaviour for |global-local| options is slightly different
between string and number-based options.
@@ -376,10 +370,11 @@ Note: In the future more global options can be made |global-local|. Using
":setlocal" on a global option might work differently then.
*option-value-function*
-Some options ('completefunc', 'omnifunc', 'operatorfunc', 'quickfixtextfunc',
-'tagfunc' and 'thesaurusfunc') are set to a function name or a function
-reference or a lambda function. When using a lambda it will be converted to
-the name, e.g. "<lambda>123". Examples:
+Some options ('completefunc', 'findfunc', 'omnifunc', 'operatorfunc',
+'quickfixtextfunc', 'tagfunc' and 'thesaurusfunc') are set to a function name
+or a function reference or a lambda function. When using a lambda it will be
+converted to the name, e.g. "<lambda>123".
+Examples:
>
set opfunc=MyOpFunc
set opfunc=function('MyOpFunc')
@@ -647,11 +642,12 @@ Hidden options *hidden-options*
Not all options are supported in all versions. This depends on the supported
features and sometimes on the system. A remark about this is in curly braces
-below. When an option is not supported it may still be set without getting an
-error, this is called a hidden option. You can't get the value of a hidden
-option though, it is not stored.
+below. When an option is not supported, it is called a hidden option. Trying
+to get the value of a hidden option will not give an error, it will return the
+default value for that option instead. You can't change the value of a hidden
+option.
-To test if option "foo" can be used with ":set" use something like this: >
+To test if "foo" is a valid option name, use something like this: >
if exists('&foo')
This also returns true for a hidden option. To test if option "foo" is really
supported use something like this: >
@@ -897,12 +893,13 @@ A jump table for the options with a short description can be found at |Q_op|.
useful for example in source trees where all the files are symbolic or
hard links and any changes should stay in the local source tree, not
be propagated back to the original source.
- *crontab*
+ *crontab*
One situation where "no" and "auto" will cause problems: A program
that opens a file, invokes Vim to edit that file, and then tests if
the open file was changed (through the file descriptor) will check the
backup file instead of the newly created file. "crontab -e" is an
- example.
+ example, as are several |file-watcher| daemons like inotify. In that
+ case you probably want to switch this option.
When a copy is made, the original file is truncated and then filled
with the new text. This means that protection bits, owner and
@@ -1014,6 +1011,7 @@ A jump table for the options with a short description can be found at |Q_op|.
separated list of items. For each item that is present, the bell
will be silenced. This is most useful to specify specific events in
insert mode to be silenced.
+ You can also make it flash by using 'visualbell'.
item meaning when present ~
all All events.
@@ -1037,6 +1035,7 @@ A jump table for the options with a short description can be found at |Q_op|.
register Unknown register after <C-R> in |Insert-mode|.
shell Bell from shell output |:!|.
spell Error happened on spell suggest.
+ term Bell from |:terminal| output.
wildmode More matches in |cmdline-completion| available
(depends on the 'wildmode' setting).
@@ -1138,16 +1137,6 @@ A jump table for the options with a short description can be found at |Q_op|.
added for the 'showbreak' setting.
(default: off)
- *'browsedir'* *'bsdir'*
-'browsedir' 'bsdir' string (default "last")
- global
- Which directory to use for the file browser:
- last Use same directory as with last file browser, where a
- file was opened or saved.
- buffer Use the directory of the related buffer.
- current Use the current directory.
- {path} Use the specified directory
-
*'bufhidden'* *'bh'*
'bufhidden' 'bh' string (default "")
local to buffer |local-noglobal|
@@ -1414,7 +1403,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'cmdheight'* *'ch'*
'cmdheight' 'ch' number (default 1)
- global or local to tab page |global-local|
+ global or local to tab page
Number of screen lines to use for the command-line. Helps avoiding
|hit-enter| prompts.
The value of this option is stored with the tab page, so that each tab
@@ -1585,7 +1574,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'completeslash'* *'csl'*
'completeslash' 'csl' string (default "")
local to buffer
- only for MS-Windows
+ only modifiable in MS-Windows
When this option is set it overrules 'shellslash' for completion:
- When this option is set to "slash", a forward slash is used for path
completion in insert mode. This is useful when editing HTML tag, or
@@ -2611,6 +2600,55 @@ A jump table for the options with a short description can be found at |Q_op|.
eob EndOfBuffer |hl-EndOfBuffer|
lastline NonText |hl-NonText|
+ *'findfunc'* *'ffu'* *E1514*
+'findfunc' 'ffu' string (default "")
+ global or local to buffer |global-local|
+ Function that is called to obtain the filename(s) for the |:find|
+ command. When this option is empty, the internal |file-searching|
+ mechanism is used.
+
+ The value can be the name of a function, a |lambda| or a |Funcref|.
+ See |option-value-function| for more information.
+
+ The function is called with two arguments. The first argument is a
+ |String| and is the |:find| command argument. The second argument is
+ a |Boolean| and is set to |v:true| when the function is called to get
+ a List of command-line completion matches for the |:find| command.
+ The function should return a List of strings.
+
+ The function is called only once per |:find| command invocation.
+ The function can process all the directories specified in 'path'.
+
+ If a match is found, the function should return a |List| containing
+ one or more file names. If a match is not found, the function
+ should return an empty List.
+
+ If any errors are encountered during the function invocation, an
+ empty List is used as the return value.
+
+ It is not allowed to change text or jump to another window while
+ executing the 'findfunc' |textlock|.
+
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+
+ Examples:
+ >vim
+ " Use glob()
+ func FindFuncGlob(cmdarg, cmdcomplete)
+ let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
+ return glob(pat, v:false, v:true)
+ endfunc
+ set findfunc=FindFuncGlob
+
+ " Use the 'git ls-files' output
+ func FindGitFiles(cmdarg, cmdcomplete)
+ let fnames = systemlist('git ls-files')
+ return fnames->filter('v:val =~? a:cmdarg')
+ endfunc
+ set findfunc=FindGitFiles
+<
+
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on)
local to buffer
@@ -3097,136 +3135,6 @@ A jump table for the options with a short description can be found at |Q_op|.
When 'guifont' has a valid font and 'guifontwide' is empty Vim will
attempt to set 'guifontwide' to a matching double-width font.
- *'guioptions'* *'go'*
-'guioptions' 'go' string (default "egmrLT" (MS-Windows))
- global
- This option only has an effect in the GUI version of Vim. It is a
- sequence of letters which describes what components and options of the
- GUI should be used.
- To avoid problems with flags that are added in the future, use the
- "+=" and "-=" feature of ":set" |add-option-flags|.
-
- Valid letters are as follows:
- *guioptions_a* *'go-a'*
- 'a' Autoselect: If present, then whenever VISUAL mode is started,
- or the Visual area extended, Vim tries to become the owner of
- the windowing system's global selection. This means that the
- Visually highlighted text is available for pasting into other
- applications as well as into Vim itself. When the Visual mode
- ends, possibly due to an operation on the text, or when an
- application wants to paste the selection, the highlighted text
- is automatically yanked into the "* selection register.
- Thus the selection is still available for pasting into other
- applications after the VISUAL mode has ended.
- If not present, then Vim won't become the owner of the
- windowing system's global selection unless explicitly told to
- by a yank or delete operation for the "* register.
- The same applies to the modeless selection.
- *'go-P'*
- 'P' Like autoselect but using the "+ register instead of the "*
- register.
- *'go-A'*
- 'A' Autoselect for the modeless selection. Like 'a', but only
- applies to the modeless selection.
-
- 'guioptions' autoselect Visual autoselect modeless ~
- "" - -
- "a" yes yes
- "A" - yes
- "aA" yes yes
-
- *'go-c'*
- 'c' Use console dialogs instead of popup dialogs for simple
- choices.
- *'go-d'*
- 'd' Use dark theme variant if available.
- *'go-e'*
- 'e' Add tab pages when indicated with 'showtabline'.
- 'guitablabel' can be used to change the text in the labels.
- When 'e' is missing a non-GUI tab pages line may be used.
- The GUI tabs are only supported on some systems, currently
- Mac OS/X and MS-Windows.
- *'go-i'*
- 'i' Use a Vim icon.
- *'go-m'*
- 'm' Menu bar is present.
- *'go-M'*
- 'M' The system menu "$VIMRUNTIME/menu.vim" is not sourced. Note
- that this flag must be added in the vimrc file, before
- switching on syntax or filetype recognition (when the |gvimrc|
- file is sourced the system menu has already been loaded; the
- `:syntax on` and `:filetype on` commands load the menu too).
- *'go-g'*
- 'g' Grey menu items: Make menu items that are not active grey. If
- 'g' is not included inactive menu items are not shown at all.
- *'go-T'*
- 'T' Include Toolbar. Currently only in Win32 GUI.
- *'go-r'*
- 'r' Right-hand scrollbar is always present.
- *'go-R'*
- 'R' Right-hand scrollbar is present when there is a vertically
- split window.
- *'go-l'*
- 'l' Left-hand scrollbar is always present.
- *'go-L'*
- 'L' Left-hand scrollbar is present when there is a vertically
- split window.
- *'go-b'*
- 'b' Bottom (horizontal) scrollbar is present. Its size depends on
- the longest visible line, or on the cursor line if the 'h'
- flag is included. |gui-horiz-scroll|
- *'go-h'*
- 'h' Limit horizontal scrollbar size to the length of the cursor
- line. Reduces computations. |gui-horiz-scroll|
-
- And yes, you may even have scrollbars on the left AND the right if
- you really want to :-). See |gui-scrollbars| for more information.
-
- *'go-v'*
- 'v' Use a vertical button layout for dialogs. When not included,
- a horizontal layout is preferred, but when it doesn't fit a
- vertical layout is used anyway. Not supported in GTK 3.
- *'go-p'*
- 'p' Use Pointer callbacks for X11 GUI. This is required for some
- window managers. If the cursor is not blinking or hollow at
- the right moment, try adding this flag. This must be done
- before starting the GUI. Set it in your |gvimrc|. Adding or
- removing it after the GUI has started has no effect.
- *'go-k'*
- 'k' Keep the GUI window size when adding/removing a scrollbar, or
- toolbar, tabline, etc. Instead, the behavior is similar to
- when the window is maximized and will adjust 'lines' and
- 'columns' to fit to the window. Without the 'k' flag Vim will
- try to keep 'lines' and 'columns' the same when adding and
- removing GUI components.
-
- *'guitablabel'* *'gtl'*
-'guitablabel' 'gtl' string (default "")
- global
- When non-empty describes the text to use in a label of the GUI tab
- pages line. When empty and when the result is empty Vim will use a
- default label. See |setting-guitablabel| for more info.
-
- The format of this option is like that of 'statusline'.
- 'guitabtooltip' is used for the tooltip, see below.
- The expression will be evaluated in the |sandbox| when set from a
- modeline, see |sandbox-option|.
- This option cannot be set in a modeline when 'modelineexpr' is off.
-
- Only used when the GUI tab pages line is displayed. 'e' must be
- present in 'guioptions'. For the non-GUI tab pages line 'tabline' is
- used.
-
- *'guitabtooltip'* *'gtt'*
-'guitabtooltip' 'gtt' string (default "")
- global
- When non-empty describes the text to use in a tooltip for the GUI tab
- pages line. When empty Vim will use a default tooltip.
- This option is otherwise just like 'guitablabel' above.
- You can include a line break. Simplest method is to use |:let|: >vim
- let &guitabtooltip = "line one\nline two"
-<
-
*'helpfile'* *'hf'*
'helpfile' 'hf' string (default (MS-Windows) "$VIMRUNTIME\doc\help.txt"
(others) "$VIMRUNTIME/doc/help.txt")
@@ -3289,7 +3197,8 @@ A jump table for the options with a short description can be found at |Q_op|.
global
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
- each of these histories (see |cmdline-editing|).
+ each of these histories (see |cmdline-editing| and 'msghistory' for
+ the number of messages to remember).
The maximum value is 10000.
*'hlsearch'* *'hls'* *'nohlsearch'* *'nohls'*
@@ -3344,23 +3253,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|.
- *'imcmdline'* *'imc'* *'noimcmdline'* *'noimc'*
-'imcmdline' 'imc' boolean (default off)
- global
- When set the Input Method is always on when starting to edit a command
- line, unless entering a search pattern (see 'imsearch' for that).
- Setting this option is useful when your input method allows entering
- English characters directly, e.g., when it's used to type accented
- characters with dead keys.
-
- *'imdisable'* *'imd'* *'noimdisable'* *'noimd'*
-'imdisable' 'imd' boolean (default off, on for some systems (SGI))
- global
- When set the Input Method is never used. This is useful to disable
- the IM when it doesn't work properly.
- Currently this option is on by default for SGI/IRIX machines. This
- may change in later releases.
-
*'iminsert'* *'imi'*
'iminsert' 'imi' number (default 0)
local to buffer
@@ -4392,75 +4284,18 @@ A jump table for the options with a short description can be found at |Q_op|.
< Will make Nvim scroll 5 lines at a time when scrolling vertically, and
scroll 2 columns at a time when scrolling horizontally.
- *'mouseshape'* *'mouses'* *E547*
-'mouseshape' 'mouses' string (default "i:beam,r:beam,s:updown,sd:cross,
- m:no,ml:up-arrow,v:rightup-arrow")
- global
- This option tells Vim what the mouse pointer should look like in
- different modes. The option is a comma-separated list of parts, much
- like used for 'guicursor'. Each part consist of a mode/location-list
- and an argument-list:
- mode-list:shape,mode-list:shape,..
- The mode-list is a dash separated list of these modes/locations:
- In a normal window: ~
- n Normal mode
- v Visual mode
- ve Visual mode with 'selection' "exclusive" (same as 'v',
- if not specified)
- o Operator-pending mode
- i Insert mode
- r Replace mode
-
- Others: ~
- c appending to the command-line
- ci inserting in the command-line
- cr replacing in the command-line
- m at the 'Hit ENTER' or 'More' prompts
- ml idem, but cursor in the last line
- e any mode, pointer below last window
- s any mode, pointer on a status line
- sd any mode, while dragging a status line
- vs any mode, pointer on a vertical separator line
- vd any mode, while dragging a vertical separator line
- a everywhere
-
- The shape is one of the following:
- avail name looks like ~
- w x arrow Normal mouse pointer
- w x blank no pointer at all (use with care!)
- w x beam I-beam
- w x updown up-down sizing arrows
- w x leftright left-right sizing arrows
- w x busy The system's usual busy pointer
- w x no The system's usual "no input" pointer
- x udsizing indicates up-down resizing
- x lrsizing indicates left-right resizing
- x crosshair like a big thin +
- x hand1 black hand
- x hand2 white hand
- x pencil what you write with
- x question big ?
- x rightup-arrow arrow pointing right-up
- w x up-arrow arrow pointing up
- x <number> any X11 pointer number (see X11/cursorfont.h)
-
- The "avail" column contains a 'w' if the shape is available for Win32,
- x for X11.
- Any modes not specified or shapes not available use the normal mouse
- pointer.
-
- Example: >vim
- set mouseshape=s:udsizing,m:no
-< will make the mouse turn to a sizing arrow over the status lines and
- indicate no input when the hit-enter prompt is displayed (since
- clicking the mouse has no effect in this state.)
-
*'mousetime'* *'mouset'*
'mousetime' 'mouset' number (default 500)
global
Defines the maximum time in msec between two mouse clicks for the
second click to be recognized as a multi click.
+ *'msghistory'* *'mhi'*
+'msghistory' 'mhi' number (default 500)
+ global
+ Determines how many entries are remembered in the |:messages| history.
+ The maximum value is 10000.
+
*'nrformats'* *'nf'*
'nrformats' 'nf' string (default "bin,hex")
local to buffer
@@ -4558,16 +4393,6 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
- *'opendevice'* *'odev'* *'noopendevice'* *'noodev'*
-'opendevice' 'odev' boolean (default off)
- global
- only for Windows
- Enable reading and writing from devices. This may get Vim stuck on a
- device that can be opened but doesn't actually do the I/O. Therefore
- it is off by default.
- Note that on Windows editing "aux.h", "lpt1.txt" and the like also
- result in editing a device.
-
*'operatorfunc'* *'opfunc'*
'operatorfunc' 'opfunc' string (default "")
global
@@ -5363,7 +5188,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*shell-powershell*
To use PowerShell: >vim
let &shell = executable('pwsh') ? 'pwsh' : 'powershell'
- let &shellcmdflag = '-NoLogo -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
+ let &shellcmdflag = '-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';$PSStyle.OutputRendering=''plaintext'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode'
let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode'
set shellquote= shellxquote=
@@ -5460,9 +5285,9 @@ A jump table for the options with a short description can be found at |Q_op|.
security reasons.
*'shellslash'* *'ssl'* *'noshellslash'* *'nossl'*
-'shellslash' 'ssl' boolean (default off)
+'shellslash' 'ssl' boolean (default on, Windows: off)
global
- only for MS-Windows
+ only modifiable in MS-Windows
When set, a forward slash is used when expanding file names. This is
useful when a Unix-like shell is used instead of cmd.exe. Backward
slashes can still be typed, but they are changed to forward slashes by
@@ -6275,7 +6100,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Examples:
Emulate standard status line with 'ruler' set >vim
- set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+ set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P
< Similar, but add ASCII value of char under the cursor (like "ga") >vim
set statusline=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
< Display byte count and byte value, modified flag in red. >vim
@@ -6762,7 +6587,9 @@ A jump table for the options with a short description can be found at |Q_op|.
window. This happens only when the 'title' option is on.
When this option contains printf-style '%' items, they will be
- expanded according to the rules used for 'statusline'.
+ expanded according to the rules used for 'statusline'. If it contains
+ an invalid '%' format, the value is used as-is and no error or warning
+ will be given when the value is set.
This option cannot be set in a modeline when 'modelineexpr' is off.
Example: >vim
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 8ec02276cc..7f0938be05 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -154,7 +154,7 @@ or auto suspended with nohlsearch plugin. See |nohlsearch-install|.
When 'shortmess' does not include the "S" flag, Vim will automatically show an
-index, on which the cursor is. This can look like this: >
+index, on which the cursor is. This can look like this: >
[1/5] Cursor is on first of 5 matches.
[1/>99] Cursor is on first of more than 99 matches.
@@ -743,7 +743,7 @@ overview.
\([a-z]\+\)\zs,\1 ",abc" in "abc,abc"
\@123<=
- Like "\@<=" but only look back 123 bytes. This avoids trying lots
+ Like "\@<=" but only look back 123 bytes. This avoids trying lots
of matches that are known to fail and make executing the pattern very
slow. Example, check if there is a "<" just before "span":
/<\@1<=span
@@ -769,7 +769,7 @@ overview.
\(\/\/.*\)\@<!in "in" which is not after "//"
\@123<!
- Like "\@<!" but only look back 123 bytes. This avoids trying lots of
+ Like "\@<!" but only look back 123 bytes. This avoids trying lots of
matches that are known to fail and make executing the pattern very
slow.
@@ -892,7 +892,7 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
inside the Visual area put it at the start and just before the end of
the pattern, e.g.: >
/\%Vfoo.*ba\%Vr
-< This also works if only "foo bar" was Visually selected. This: >
+< This also works if only "foo bar" was Visually selected. This: >
/\%Vfoo.*bar\%V
< would match "foo bar" if the Visual selection continues after the "r".
Only works for the current buffer.
@@ -999,7 +999,7 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
< To match all characters after the current virtual column (where the
cursor is): >
/\%>.v.*
-< Column 17 is not included, because this is a |/zero-width| match. To
+< Column 17 is not included, because this is a |/zero-width| match. To
include the column use: >
/^.*\%17v.
< This command does the same thing, but also matches when there is no
@@ -1123,11 +1123,11 @@ x A single character, with no special meaning, matches itself
in the collection: "[^xyz]" matches anything but 'x', 'y' and 'z'.
- If two characters in the sequence are separated by '-', this is
shorthand for the full list of ASCII characters between them. E.g.,
- "[0-9]" matches any decimal digit. If the starting character exceeds
- the ending character, e.g. [c-a], E944 occurs. Non-ASCII characters
+ "[0-9]" matches any decimal digit. If the starting character exceeds
+ the ending character, e.g. [c-a], E944 occurs. Non-ASCII characters
can be used, but the character values must not be more than 256 apart
- in the old regexp engine. For example, searching by [\u3000-\u4000]
- after setting re=1 emits a E945 error. Prepending \%#=2 will fix it.
+ in the old regexp engine. For example, searching by [\u3000-\u4000]
+ after setting re=1 emits a E945 error. Prepending \%#=2 will fix it.
- A character class expression is evaluated to the set of characters
belonging to that character class. The following character classes
are supported:
@@ -1193,7 +1193,7 @@ x A single character, with no special meaning, matches itself
any character that's not in "^]-\bdertnoUux". "[\xyz]" matches '\',
'x', 'y' and 'z'. It's better to use "\\" though, future expansions
may use other characters after '\'.
- - Omitting the trailing ] is not considered an error. "[]" works like
+ - Omitting the trailing ] is not considered an error. "[]" works like
"[]]", it matches the ']' character.
- The following translations are accepted when the 'l' flag is not
included in 'cpoptions':
@@ -1425,14 +1425,14 @@ Finally, these constructs are unique to Perl:
display you may get unexpected results. That is because Vim
looks for a match in the line where redrawing starts.
- Also see |matcharg()| and |getmatches()|. The former returns
+ Also see |matcharg()| and |getmatches()|. The former returns
the highlight group and pattern of a previous |:match|
command. The latter returns a list with highlight groups and
patterns defined by both |matchadd()| and |:match|.
Highlighting matches using |:match| are limited to three
matches (aside from |:match|, |:2match| and |:3match| are
- available). |matchadd()| does not have this limitation and in
+ available). |matchadd()| does not have this limitation and in
addition makes it possible to prioritize matches.
Another example, which highlights all characters in virtual
@@ -1461,7 +1461,7 @@ Finally, these constructs are unique to Perl:
with the lowest number has priority if several match at the
same position. It uses the match id 3.
The ":3match" command is used by (older Vims) |matchparen|
- plugin. You are suggested to use ":match" for manual matching
+ plugin. You are suggested to use ":match" for manual matching
and ":2match" for another plugin or even better make use of
the more flexible |matchadd()| (and similar) functions instead.
@@ -1470,10 +1470,10 @@ Finally, these constructs are unique to Perl:
Fuzzy matching refers to matching strings using a non-exact search string.
Fuzzy matching will match a string, if all the characters in the search string
-are present anywhere in the string in the same order. Case is ignored. In a
+are present anywhere in the string in the same order. Case is ignored. In a
matched string, other characters can be present between two consecutive
-characters in the search string. If the search string has multiple words, then
-each word is matched separately. So the words in the search string can be
+characters in the search string. If the search string has multiple words, then
+each word is matched separately. So the words in the search string can be
present in any order in a string.
Fuzzy matching assigns a score for each matched string based on the following
@@ -1492,8 +1492,8 @@ will match the strings "GetPattern", "PatternGet", "getPattern", "patGetter",
"getSomePattern", "MatchpatternGet" etc.
The functions |matchfuzzy()| and |matchfuzzypos()| can be used to fuzzy search
-a string in a List of strings. The matchfuzzy() function returns a List of
-matching strings. The matchfuzzypos() functions returns the List of matches,
+a string in a List of strings. The matchfuzzy() function returns a List of
+matching strings. The matchfuzzypos() functions returns the List of matches,
the matching positions and the fuzzy match scores.
The "f" flag of `:vimgrep` enables fuzzy matching.
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index 0652fb27e7..09d1369d46 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -54,9 +54,10 @@ Copyright: Copyright (C) 2017 Charles E Campbell *netrw-copyright*
Browsing With A Horizontally Split Window...........|netrw-o|
Browsing With A New Tab.............................|netrw-t|
Browsing With A Vertically Split Window.............|netrw-v|
- Change File Permission..............................|netrw-gp|
- Change Listing Style.(thin wide long tree)..........|netrw-i|
+ Change Listing Style (thin wide long tree)..........|netrw-i|
Changing To A Bookmarked Directory..................|netrw-gb|
+ Quick hide/unhide of dot-files......................|netrw-gh|
+ Changing local-only File Permission.................|netrw-gp|
Changing To A Predecessor Directory.................|netrw-u|
Changing To A Successor Directory...................|netrw-U|
Customizing Browsing With A Special Handler.........|netrw-x|
@@ -1465,98 +1466,106 @@ With either form of the command, netrw will first ask for confirmation
that the removal is in fact what you want to do. If netrw doesn't have
permission to remove a file, it will issue an error message.
- *netrw-gx*
CUSTOMIZING BROWSING WITH A SPECIAL HANDLER *netrw-x* *netrw-handler* {{{2
- (also see |netrw_filehandler|)
Certain files, such as html, gif, jpeg, (word/office) doc, etc, files, are
best seen with a special handler (ie. a tool provided with your computer's
-operating system). Netrw allows one to invoke such special handlers by: >
+operating system). Netrw allows one to invoke such special handlers by:
- * when Exploring, hit the "x" key
- * when editing, hit gx with the cursor atop the special filename
-< (latter not available if the |g:netrw_nogx| variable exists)
+ * hitting gx with the cursor atop the file path or alternatively x
+ in a netrw buffer; the former can be disabled by defining the
+ |g:netrw_nogx| variable
+ * when in command line, typing :Open <path>, see |:Open| below.
-Netrw determines which special handler by the following method:
-
- * if |g:netrw_browsex_viewer| exists, then it will be used to attempt to
- view files. Examples of useful settings (place into your <.vimrc>): >
-
- :let g:netrw_browsex_viewer= "kfmclient exec"
-< or >
- :let g:netrw_browsex_viewer= "xdg-open"
-<
- If g:netrw_browsex_viewer == '-', then netrwFileHandlers#Invoke() will be
- used instead (see |netrw_filehandler|).
-
- If the viewer you wish to use does not support handling of a remote URL
- directory, set |g:netrw_browsex_support_remote| to 0.
- * for Windows 32 or 64, the URL and FileProtocolHandler dlls are used.
- * for Gnome (with gnome-open): gnome-open is used.
- * for KDE (with kfmclient) : kfmclient is used
- * for Mac OS X : open is used.
- * otherwise the netrwFileHandler plugin is used.
-
-The file's suffix is used by these various approaches to determine an
-appropriate application to use to "handle" these files. Such things as
-OpenOffice (*.sfx), visualization (*.jpg, *.gif, etc), and PostScript (*.ps,
-*.eps) can be handled.
-
-The gx mapping extends to all buffers; apply "gx" while atop a word and netrw
-will apply a special handler to it (like "x" works when in a netrw buffer).
One may also use visual mode (see |visual-start|) to select the text that the
-special handler will use. Normally gx uses expand("<cfile>") to pick up the
-text under the cursor; one may change what |expand()| uses via the
+special handler will use. Normally gx checks for a close-by URL or file name
+to pick up the text under the cursor; one may change what |expand()| uses via the
|g:netrw_gx| variable (options include "<cword>", "<cWORD>"). Note that
expand("<cfile>") depends on the |'isfname'| setting. Alternatively, one may
select the text to be used by gx by making a visual selection (see
|visual-block|) and then pressing gx.
+The selection function can be adapted for each filetype by adding a function
+`Netrw_get_URL_<filetype>`, where <filetype> is given by the 'filetype'.
+The function should return the URL or file name to be used by gx, and will
+fall back to the default behavior if it returns an empty string.
+For example, special handlers for links Markdown and HTML are
+
+" make gx work on concealed links regardless of exact cursor position: >
+
+ function Netrw_get_URL_markdown()
+ " markdown URL such as [link text](http://ya.ru 'yandex search')
+ try
+ let save_view = winsaveview()
+ if searchpair('\[.\{-}\](', '', ')\zs', 'cbW', '', line('.')) > 0
+ return matchstr(getline('.')[col('.')-1:],
+ \ '\[.\{-}\](\zs' .. g:netrw_regex_url .. '\ze\(\s\+.\{-}\)\?)')
+ endif
+ return ''
+ finally
+ call winrestview(save_view)
+ endtry
+ endfunction
+
+ function Netrw_get_URL_html()
+ " HTML URL such as <a href='http://www.python.org'>Python is here</a>
+ " <a href="http://www.python.org"/>
+ try
+ let save_view = winsaveview()
+ if searchpair('<a\s\+href=', '', '\%(</a>\|/>\)\zs', 'cbW', '', line('.')) > 0
+ return matchstr(getline('.')[col('.') - 1 : ],
+ \ 'href=["'.."'"..']\?\zs\S\{-}\ze["'.."'"..']\?/\?>')
+ endif
+ return ''
+ finally
+ call winrestview(save_view)
+ endtry
+ endfunction
+<
+Other than a file path, the text under the cursor may be a URL. Netrw uses
+by default the following regular expression to determine if the text under the
+cursor is a URL:
+>
+ :let g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
+<
Associated setting variables:
|g:netrw_gx| control how gx picks up the text under the cursor
|g:netrw_nogx| prevent gx map while editing
|g:netrw_suppress_gx_mesg| controls gx's suppression of browser messages
- *netrw_filehandler*
+OPENING FILES AND LAUNCHING APPS *netrw-gx* *:Open* *:Launch* {{{2
-When |g:netrw_browsex_viewer| exists and is "-", then netrw will attempt to
-handle the special file with a vim function. The "x" map applies a function
-to a file, based on its extension. Of course, the handler function must exist
-for it to be called!
->
- Ex. mypgm.html x -> NFH_html("scp://user@host/some/path/mypgm.html")
+Netrw determines which special handler by the following method:
-< Users may write their own netrw File Handler functions to
- support more suffixes with special handling. See
- <autoload/netrwFileHandlers.vim> for examples on how to make
- file handler functions. As an example: >
+ * if |g:netrw_browsex_viewer| exists, then it will be used to attempt to
+ view files.
+ If the viewer you wish to use does not support handling of a remote URL
+ directory, set |g:netrw_browsex_support_remote| to 0.
+ * otherwise:
- " NFH_suffix(filename)
- fun! NFH_suffix(filename)
- ..do something special with filename..
- endfun
-<
-These functions need to be defined in some file in your .vim/plugin
-(vimfiles\plugin) directory. Vim's function names may not have punctuation
-characters (except for the underscore) in them. To support suffices that
-contain such characters, netrw will first convert the suffix using the
-following table: >
-
- @ -> AT ! -> EXCLAMATION % -> PERCENT
- : -> COLON = -> EQUAL ? -> QUESTION
- , -> COMMA - -> MINUS ; -> SEMICOLON
- $ -> DOLLAR + -> PLUS ~ -> TILDE
-<
-So, for example: >
+ * for Windows : explorer.exe is used
+ * for Mac OS X : open is used.
+ * for Linux : xdg-open is used.
+
+To open a path (or URL) <path> by the appropriate handler, type >
- file.rcs,v -> NFH_rcsCOMMAv()
+ :Open <path>
<
-If more such translations are necessary, please send me email: >
- NcampObell@SdrPchip.AorgM-NOSPAM
-with a request. (remove the embedded NOSPAM first)
+No escaping, neither for the shell nor for Vim's command-line, is needed.
+
+To launch a specific application <app> <args>, often <args> being <path> >
+
+ :Launch <app> <args>.
+
+Since <args> can be arbitrarily complex, in particular contain many file
+paths, the escaping is left to the user.
-Associated setting variable: |g:netrw_browsex_viewer|
+If you disabled the netrw plugin by setting g:loaded_netrwPlugin (see
+|netrw-noload|), then you can use >
+ :call netrw#Launch('<app> <args>')
+ :call netrw#Open('<path>')
+<
*netrw-curdir*
DELETING BOOKMARKS *netrw-mB* {{{2
@@ -2569,12 +2578,7 @@ your browsing preferences. (see also: |netrw-settings|)
*g:netrw_browsex_viewer* specify user's preference for a viewer: >
"kfmclient exec"
"gnome-open"
-< If >
- "-"
-< is used, then netrwFileHandler() will look for
- a script/function to handle the given
- extension. (see |netrw_filehandler|).
-
+<
*g:netrw_browsex_support_remote*
specify if the specified viewer supports a
remote URL. (see |netrw-handler|).
diff --git a/runtime/doc/pi_paren.txt b/runtime/doc/pi_paren.txt
index 77083362da..caa88e8d56 100644
--- a/runtime/doc/pi_paren.txt
+++ b/runtime/doc/pi_paren.txt
@@ -10,6 +10,7 @@ The functionality mentioned here is a |standard-plugin|.
This plugin is only available if 'compatible' is not set.
You can avoid loading this plugin by setting the "loaded_matchparen" variable: >
+
:let loaded_matchparen = 1
The plugin installs CursorMoved, CursorMovedI and WinEnter autocommands to
@@ -29,6 +30,16 @@ the ":highlight" command. Example: >
:hi MatchParen ctermbg=blue guibg=lightblue
+By default the plugin will highlight both the paren under the cursor and the
+matching one using the |hl-MatchParen| highlighting group. This may result in
+the cursor briefly disappearing from the screen as the MatchParen colors take
+over the cursor highlight. To prevent this from happening and have the plugin
+only highlight the matching paren and not the one under the cursor
+(effectively leaving the cursor style unchanged), you can set the
+"matchparen_disable_cursor_hl" variable: >
+
+ :let matchparen_disable_cursor_hl = 1
+
The characters to be matched come from the 'matchpairs' option. You can
change the value to highlight different matches. Note that not everything is
possible. For example, you can't highlight single or double quotes, because
@@ -46,10 +57,10 @@ are:
closed folds.
- 'synmaxcol' times 2 bytes before or after the cursor to avoid a delay
in a long line with syntax highlighting.
-- A timeout of 300 msec (60 msec in Insert mode). This can be changed with the
- g:matchparen_timeout and g:matchparen_insert_timeout variables and their
- buffer-local equivalents b:matchparen_timeout and
- b:matchparen_insert_timeout.
+- A timeout of 300 msec (60 msec in Insert mode). This can be changed with
+ the "g:matchparen_timeout" and "g:matchparen_insert_timeout" variables and
+ their buffer-local equivalents "b:matchparen_timeout" and
+ "b:matchparen_insert_timeout".
If you would like the |%| command to work better, the |matchit| plugin can be
used. This plugin also helps to skip matches in comments. This is unrelated
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 63109bdaf3..b3399b2766 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -349,7 +349,7 @@ processing a quickfix or location list command, it will be aborted.
Example: >
:g/mypattern/caddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")
<
- *:lad* *:addd* *:laddexpr*
+ *:lad* *:ladd* *:laddexpr*
:lad[dexpr] {expr} Same as ":caddexpr", except the location list for the
current window is used instead of the quickfix list.
@@ -1366,6 +1366,32 @@ being checked. To disable this set g:perl_compiler_force_warnings to a zero
value. For example: >
let g:perl_compiler_force_warnings = 0
+MYPY TYPE CHECKER *compiler-mypy*
+
+Commonly used compiler options can be added to 'makeprg' by setting the
+b/g:mypy_makeprg_params variable. For example: >
+
+ let b:mypy_makeprg_params = "--warn-unused-ignores"
+
+The global default is "--strict --ignore-missing-imports".
+
+RUFF LINTER *compiler-ruff*
+
+Commonly used compiler options can be added to 'makeprg' by setting the
+b/g:ruff_makeprg_params variable. For example: >
+
+ let b:ruff_makeprg_params = "--max-line-length "..&textwidth
+
+The global default is "--preview".
+
+PYLINT LINTER *compiler-pylint*
+
+Commonly used compiler options can be added to 'makeprg' by setting the
+b/g:pylint_makeprg_params variable. For example: >
+
+ let b:pylint_makeprg_params = "--max-line-length "..&textwidth
+
+The global default is "--jobs=0" to use (almost) all cores.
PYUNIT COMPILER *compiler-pyunit*
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index d77750b485..f43ddb57fb 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -705,6 +705,7 @@ Short explanation of each option: *option-list*
'fileignorecase' 'fic' ignore case when using file names
'filetype' 'ft' type of file, used for autocommands
'fillchars' 'fcs' characters to use for displaying special items
+'findfunc' 'ffu' function to be called for the |:find| command
'fixendofline' 'fixeol' make sure last line in file has <EOL>
'foldclose' 'fcl' close a fold when the cursor leaves it
'foldcolumn' 'fdc' width of the column used to indicate folds
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 521d690d93..abeefb980e 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -967,21 +967,24 @@ For example, to profile the one_script.vim script file: >
:prof[ile] start {fname} *:prof* *:profile* *E750*
- Start profiling, write the output in {fname} upon exit.
+ Start profiling, write the output in {fname} upon exit or when
+ a `:profile stop` or `:profile dump` command is invoked.
"~/" and environment variables in {fname} will be expanded.
If {fname} already exists it will be silently overwritten.
The variable |v:profiling| is set to one.
:prof[ile] stop
- Write the logfile and stop profiling.
+ Write the collected profiling information to the logfile and
+ stop profiling. You can use the `:profile start` command to
+ clear the profiling statistics and start profiling again.
:prof[ile] pause
- Don't profile until the following ":profile continue". Can be
- used when doing something that should not be counted (e.g., an
- external command). Does not nest.
+ Stop profiling until the next `:profile continue` command.
+ Can be used when doing something that should not be counted
+ (e.g., an external command). Does not nest.
:prof[ile] continue
- Continue profiling after ":profile pause".
+ Continue profiling after `:profile pause`.
:prof[ile] func {pattern}
Profile function that matches the pattern {pattern}.
@@ -999,16 +1002,24 @@ For example, to profile the one_script.vim script file: >
won't work.
:prof[ile] dump
- Don't wait until exiting Vim and write the current state of
- profiling to the log immediately.
+ Write the current state of profiling to the logfile
+ immediately. After running this command, Vim continues to
+ collect the profiling statistics.
:profd[el] ... *:profd* *:profdel*
Stop profiling for the arguments specified. See |:breakdel|
- for the arguments.
-
+ for the arguments. Examples: >
+ profdel func MyFunc
+ profdel file MyScript.vim
+ profdel here
You must always start with a ":profile start fname" command. The resulting
-file is written when Vim exits. Here is an example of the output, with line
+file is written when Vim exits. For example, to profile one specific
+function: >
+ profile start /tmp/vimprofile
+ profile func MyFunc
+
+Here is an example of the output, with line
numbers prepended for the explanation:
1 FUNCTION Test2() ~
diff --git a/runtime/doc/support.txt b/runtime/doc/support.txt
index 0ddf037fba..a2776fca0d 100644
--- a/runtime/doc/support.txt
+++ b/runtime/doc/support.txt
@@ -13,10 +13,10 @@ Supported platforms *supported-platforms*
`System` `Tier` `Versions` `Tested versions`
Linux 1 >= 2.6.32, glibc >= 2.12 Ubuntu 24.04
-macOS (Intel) 1 >= 11 macOS 12
+macOS (Intel) 1 >= 11 macOS 13
macOS (M1) 1 >= 11 macOS 15
Windows 64-bit 1 >= Windows 10 Version 1809 Windows Server 2022
-FreeBSD 1 >= 10 FreeBSD 13
+FreeBSD 1 >= 10 FreeBSD 14
OpenBSD 2 >= 7
MinGW 2 MinGW-w64
Windows 64-bit 3 < Windows 10 Version 1809
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 219be92c58..75a855bbdd 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -45,7 +45,7 @@ directory where the Vim stuff is located. For example, if your syntax files
are in the "/usr/vim/vim82/syntax" directory, set $VIMRUNTIME to
"/usr/vim/vim82". You must do this in the shell, before starting Vim.
This command also sources the |menu.vim| script when the GUI is running or
-will start soon. See |'go-M'| about avoiding that.
+will start soon.
*:hi-normal* *:highlight-normal*
If you are running in the GUI, you can get white text on a black background
@@ -1209,20 +1209,20 @@ on" command in your .vimrc file.
When you edit an existing Fortran file, the syntax script will assume free
source form if the fortran_free_source variable has been set, and assumes
fixed source form if the fortran_fixed_source variable has been set. Suppose
-neither of these variables have been set. In that case, the syntax script attempts to
-determine which source form has been used by examining the file extension
-using conventions common to the ifort, gfortran, Cray, NAG, and PathScale
-compilers (.f, .for, .f77 for fixed-source, .f90, .f95, .f03, .f08 for
-free-source). No default is used for the .fpp and .ftn file extensions because
-different compilers treat them differently. If none of this works, then the
-script examines the first five columns of the first 500 lines of your file. If
-no signs of free source form are detected, then the file is assumed to be in
-fixed source form. The algorithm should work in the vast majority of cases.
-In some cases, such as a file that begins with 500 or more full-line comments,
-the script may incorrectly decide that the code is in fixed form. If that
-happens, just add a non-comment statement beginning anywhere in the first five
-columns of the first twenty-five lines, save (:w), and then reload (:e!) the
-file.
+neither of these variables have been set. In that case, the syntax script
+attempts to determine which source form has been used by examining the file
+extension using conventions common to the ifort, gfortran, Cray, NAG, and
+PathScale compilers (.f, .for, .f77 for fixed-source, .f90, .f95, .f03, .f08
+for free-source). No default is used for the .fpp and .ftn file extensions
+because different compilers treat them differently. If none of this works,
+then the script examines the first five columns of the first 500 lines of your
+file. If no signs of free source form are detected, then the file is assumed
+to be in fixed source form. The algorithm should work in the vast majority of
+cases. In some cases, such as a file that begins with 500 or more full-line
+comments, the script may incorrectly decide that the code is in fixed form.
+If that happens, just add a non-comment statement beginning anywhere in the
+first five columns of the first twenty-five lines, save (:w), and then reload
+(:e!) the file.
Vendor extensions ~
Fixed-form Fortran requires a maximum line length of 72 characters but the
@@ -1750,6 +1750,20 @@ define the vim variable 'lace_case_insensitive' in your startup file: >
:let lace_case_insensitive=1
+LF (LFRC) *lf.vim* *ft-lf-syntax* *g:lf_shell_syntax*
+ *b:lf_shell_syntax*
+
+For the lf file manager configuration files (lfrc) the shell commands syntax
+highlighting can be changed globally and per buffer by setting a different
+'include' command search pattern using these variables: >
+ let g:lf_shell_syntax = "syntax/dosbatch.vim"
+ let b:lf_shell_syntax = "syntax/zsh.vim"
+
+These variables are unset by default.
+
+The default 'include' command search pattern is 'syntax/sh.vim'.
+
+
LEX *lex.vim* *ft-lex-syntax*
Lex uses brute-force synchronizing as the "^%%$" section delimiter
@@ -2051,6 +2065,13 @@ set "msql_minlines" to the value you desire. Example: >
:let msql_minlines = 200
+NEOMUTT *neomutt.vim* *ft-neomuttrc-syntax*
+ *ft-neomuttlog-syntax*
+
+To disable the default NeoMutt log colors: >
+
+ :let g:neolog_disable_default_colors = 1
+
N1QL *n1ql.vim* *ft-n1ql-syntax*
N1QL is a SQL-like declarative language for manipulating JSON documents in
@@ -2175,7 +2196,7 @@ To specify elements that should not be concealed, set the following variable: >
:let g:pandoc#syntax#conceal#blacklist = []
-This is a list of the rules wich can be used here:
+This is a list of the rules which can be used here:
- titleblock
- image
@@ -2216,9 +2237,9 @@ specified. Default = 1 >
:let g:pandoc#syntax#codeblocks#embeds#use = 1
-For specify what languages and using what syntax files to highlight embeds. This is a
-list of language names. When the language pandoc and vim use don't match, you
-can use the "PANDOC=VIM" syntax. For example: >
+For specify what languages and using what syntax files to highlight embeds.
+This is a list of language names. When the language pandoc and vim use don't
+match, you can use the "PANDOC=VIM" syntax. For example: >
:let g:pandoc#syntax#codeblocks#embeds#langs = ["ruby", "bash=sh"]
@@ -3426,7 +3447,7 @@ set "tf_minlines" to the value you desire. Example: >
:let tf_minlines = your choice
<
TYPESCRIPT *typescript.vim* *ft-typescript-syntax*
- *typescriptreact.vim* *ft-typescriptreact-syntax*
+ *typescriptreact.vim* *ft-typescriptreact-syntax*
There is one option to control the TypeScript syntax highlighting.
@@ -3472,7 +3493,7 @@ This option is disabled by default.
Some folding is now supported with when 'foldmethod' is set to "syntax": >
g:vimsyn_folding == 0 or doesn't exist: no syntax-based folding
- g:vimsyn_folding =~ 'a' : augroups
+ g:vimsyn_folding =~ 'a' : fold augroups
g:vimsyn_folding =~ 'f' : fold functions
g:vimsyn_folding =~ 'h' : fold heredocs
g:vimsyn_folding =~ 'l' : fold Lua script
@@ -5202,7 +5223,7 @@ NormalNC Normal text in non-current windows.
*hl-Pmenu*
Pmenu Popup menu: Normal item.
*hl-PmenuSel*
-PmenuSel Popup menu: Selected item.
+PmenuSel Popup menu: Selected item. Combined with |hl-Pmenu|.
*hl-PmenuKind*
PmenuKind Popup menu: Normal item "kind".
*hl-PmenuKindSel*
@@ -5216,9 +5237,11 @@ PmenuSbar Popup menu: Scrollbar.
*hl-PmenuThumb*
PmenuThumb Popup menu: Thumb of the scrollbar.
*hl-PmenuMatch*
-PmenuMatch Popup menu: Matched text in normal item.
+PmenuMatch Popup menu: Matched text in normal item. Combined with
+ |hl-Pmenu|.
*hl-PmenuMatchSel*
-PmenuMatchSel Popup menu: Matched text in selected item.
+PmenuMatchSel Popup menu: Matched text in selected item. Combined with
+ |hl-PmenuMatch| and |hl-PmenuSel|.
*hl-Question*
Question |hit-enter| prompt and yes/no questions.
*hl-QuickFixLine*
@@ -5450,7 +5473,8 @@ This will set the "w:current_syntax" variable to "foo". The value of
restoring "b:current_syntax", since the syntax files do set
"b:current_syntax". The value set by the syntax file is assigned to
"w:current_syntax".
-Note: This resets the 'spell', 'spellcapcheck' and 'spellfile' options.
+Note: This resets the 'spell', 'spellcapcheck', 'spellfile' and 'spelloptions'
+options.
Once a window has its own syntax, syntax commands executed from other windows
on the same buffer (including :syntax clear) have no effect. Conversely,
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index 9c47e6de7d..ed9659d6e7 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -509,6 +509,7 @@ If the current window has enough horizontal space, it will be vertically split
and the Var window will be shown side by side with the source code window (and
the height options won't be used).
+
Communication ~
*termdebug-communication*
There is another, hidden, buffer, which is used for Vim to communicate with
@@ -601,15 +602,19 @@ If there is no g:termdebug_config you can use: >vim
Change default signs ~
*termdebug_signs*
Termdebug uses the hex number of the breakpoint ID in the signcolumn to
-represent breakpoints. if it is greater than "0xFF", then it will be displayed
+represent breakpoints. If it is greater than "0xFF", then it will be displayed
as "F+", due to we really only have two screen cells for the sign.
+You may also use decimal breakpoint signs instead, in which case IDs greater
+than 99 will be displayed as "9+".
-If you want to customize the breakpoint signs: >vim
+If you want to customize the breakpoint signs to show `>>` in the signcolumn: >vim
let g:termdebug_config['sign'] = '>>'
-If there is no g:terminal_config yet you can use: >vim
+If you would like to use decimal (base 10) breakpoint signs: >vim
+ let g:termdebug_config['sign_decimal'] = 1
+If the variable g:termdebug_config does not yet exist, you can use: >vim
let g:termdebug_config = {'sign': '>>'}
-
-After this, breakpoints will be displayed as `>>` in the signcolumn.
+Likewise, to enable decimal signs: >vim
+ let g:termdebug_config = {'sign_decimal': 1}
Vim window width ~
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 35192cc43d..5fc6429f7a 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -622,9 +622,23 @@ TSNode:child({index}) *TSNode:child()*
Return: ~
(`TSNode?`)
- *TSNode:child_containing_descendant()*
-TSNode:child_containing_descendant({descendant})
- Get the node's child that contains {descendant}.
+TSNode:child_count() *TSNode:child_count()*
+ Get the node's number of children.
+
+ Return: ~
+ (`integer`)
+
+ *TSNode:child_with_descendant()*
+TSNode:child_with_descendant({descendant})
+ Get the node's child that contains {descendant} (includes {descendant}).
+
+ For example, with the following node hierarchy: >
+ a -> b -> c
+
+ a:child_with_descendant(c) == b
+ a:child_with_descendant(b) == b
+ a:child_with_descendant(a) == nil
+<
Parameters: ~
• {descendant} (`TSNode`)
@@ -632,12 +646,6 @@ TSNode:child_containing_descendant({descendant})
Return: ~
(`TSNode?`)
-TSNode:child_count() *TSNode:child_count()*
- Get the node's number of children.
-
- Return: ~
- (`integer`)
-
*TSNode:descendant_for_range()*
TSNode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
Get the smallest node within this node that spans the given range of (row,
@@ -778,9 +786,8 @@ TSNode:next_sibling() *TSNode:next_sibling()*
(`TSNode?`)
TSNode:parent() *TSNode:parent()*
- Get the node's immediate parent. Prefer
- |TSNode:child_containing_descendant()| for iterating over the node's
- ancestors.
+ Get the node's immediate parent. Prefer |TSNode:child_with_descendant()|
+ for iterating over the node's ancestors.
Return: ~
(`TSNode?`)
@@ -1143,8 +1150,13 @@ get_lang({filetype}) *vim.treesitter.language.get_lang()*
inspect({lang}) *vim.treesitter.language.inspect()*
Inspects the provided language.
- Inspecting provides some useful information on the language like node
- names, ...
+ Inspecting provides some useful information on the language like node and
+ field names, ABI version, and whether the language came from a WASM
+ module.
+
+ Node names are returned in a table mapping each node name to a `boolean`
+ indicating whether or not the node is named (i.e., not anonymous).
+ Anonymous nodes are surrounded with double quotes (`"`).
Parameters: ~
• {lang} (`string`) Language
@@ -1199,7 +1211,7 @@ add_predicate({name}, {handler}, {opts})
Parameters: ~
• {name} (`string`) Name of the predicate, without leading #
- • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata)`)
+ • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata): boolean?`)
• see |vim.treesitter.query.add_directive()| for argument
meanings
• {opts} (`table?`) A table with the following fields:
@@ -1593,8 +1605,7 @@ LanguageTree:register_cbs({cbs}, {recursive})
• {cbs} (`table<TSCallbackNameOn,function>`) An
|nvim_buf_attach()|-like table argument with the
following handlers:
- • `on_bytes` : see |nvim_buf_attach()|, but this will be
- called after the parsers callback.
+ • `on_bytes` : see |nvim_buf_attach()|.
• `on_changedtree` : a callback that will be called every
time the tree has syntactical changes. It will be
passed two arguments: a table of the ranges (as node
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index d37cdfb9df..4e8253c47a 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -610,11 +610,12 @@ tabs.
size). If the window was previously hidden, it should now be shown
again.
-["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, focusable, zindex] ~
+["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, mouse_enabled, zindex] ~
Display or reconfigure floating window `win`. The window should be
displayed above another grid `anchor_grid` at the specified position
- `anchor_row` and `anchor_col`. For the meaning of `anchor` and more
- details of positioning, see |nvim_open_win()|.
+ `anchor_row` and `anchor_col`. For the meaning of `anchor` and more details
+ of positioning, see |nvim_open_win()|. `mouse_enabled` is true if the
+ window can receive mouse events.
["win_external_pos", grid, win] ~
Display or reconfigure external window `win`. The window should be
@@ -795,6 +796,7 @@ must handle.
"echomsg" |:echomsg| message
"echoerr" |:echoerr| message
"lua_error" Error in |:lua| code
+ "lua_print" |print()| from |:lua| code
"rpc_error" Error response from |rpcrequest()|
"return_prompt" |press-enter| prompt after a multiple messages
"quickfix" Quickfix navigation message
@@ -804,10 +806,11 @@ must handle.
kinds as the empty kind.
content
- Array of `[attr_id, text_chunk]` tuples, building up the message
- text of chunks of different highlights. No extra spacing should be
- added between chunks, the `text_chunk` by itself contains any
- necessary whitespace. Messages can contain line breaks "\n".
+ Array of `[attr_id, text_chunk, hl_id]` tuples, building up the
+ message text of chunks of different highlights. No extra spacing
+ should be added between chunks, the `text_chunk` by itself
+ contains any necessary whitespace. Messages can contain line
+ breaks "\n".
replace_last
Decides how multiple messages should be displayed:
diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt
index b3a49dbb7e..7d8277d90e 100644
--- a/runtime/doc/undo.txt
+++ b/runtime/doc/undo.txt
@@ -184,7 +184,7 @@ g- Go to older text state. With a count repeat that many
g+ Go to newer text state. With a count repeat that many
times.
*:lat* *:later*
-:lat[er] {count} Go to newer text state {count} times.
+:lat[er] {count} Go to newer text state {count} times.
:lat[er] {N}s Go to newer text state about {N} seconds later.
:lat[er] {N}m Go to newer text state about {N} minutes later.
:lat[er] {N}h Go to newer text state about {N} hours later.
diff --git a/runtime/doc/usr_10.txt b/runtime/doc/usr_10.txt
index 3e45fda882..2f55aadef0 100644
--- a/runtime/doc/usr_10.txt
+++ b/runtime/doc/usr_10.txt
@@ -736,6 +736,11 @@ The "!!" command filters the current line through a filter. In Unix the "date"
command prints the current time and date. "!!date<Enter>" replaces the current
line with the output of "date". This is useful to add a timestamp to a file.
+Note: There is a difference between "!cmd" (e.g. using it without any file
+range) and "{range}!cmd". While the former will simply execute the external
+command and Vim will show the output, the latter will filter {range}lines
+through the filter and replace that range by the result of the filter command.
+See |:!| and |:range!| for details.
WHEN IT DOESN'T WORK
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 8c7ed875cf..3202a70b76 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -906,6 +906,8 @@ Buffers, windows and the argument list:
swapname() get the swap file path of a buffer
Command line: *command-line-functions*
+ getcmdcomplpat() get completion pattern of the current command
+ line
getcmdcompltype() get the type of the current command line
completion
getcmdline() get the current command line input
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 33da539c66..1ded5154a7 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -267,6 +267,7 @@ gx Opens the current filepath or URL (decided by
<
*:!cmd* *:!*
:!{cmd} Execute {cmd} with 'shell'. See also |:terminal|.
+ For the filter command, see |:range!|.
The command runs in a non-interactive shell connected
to a pipe (not a terminal). Use |:terminal| to run an
@@ -548,9 +549,9 @@ gO Show a filetype-specific, navigable "outline" of the
If you use the less or more program to view a file, you don't get syntax
highlighting. Thus you would like to use Vim instead. You can do this by
-using the shell script "$VIMRUNTIME/macros/less.sh".
+using the shell script "$VIMRUNTIME/scripts/less.sh".
-This shell script uses the Vim script "$VIMRUNTIME/macros/less.vim". It sets
+This shell script uses the Vim script "$VIMRUNTIME/scripts/less.vim". It sets
up mappings to simulate the commands that less supports. Otherwise, you can
still use the Vim commands.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index e069678b30..8fa94a2601 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -150,6 +150,8 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
- |grn|
- |grr|
- |gra|
+ - |gri|
+ - |gO|
- <C-S> |i_CTRL-S|
- ]d |]d-default|
- [d |[d-default|
@@ -161,6 +163,7 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
- |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T|
- |[a|, |]a|, |[A|, |]A|
- |[b|, |]b|, |[B|, |]B|
+- |[<Space>|, |]<Space>|
- Nvim LSP client defaults |lsp-defaults|
- K |K-lsp-default|
@@ -248,7 +251,7 @@ backwards-compatibility cost. Some examples:
Some features are built in that otherwise required external plugins:
-- Highlighting the yanked region, see |vim.highlight|.
+- Highlighting the yanked region, see |vim.hl|.
ARCHITECTURE
@@ -338,10 +341,8 @@ Normal commands:
Options:
-Local values for global-local number/boolean options are unset when the option
-is set without a scope (e.g. by using |:set|), similarly to how global-local
-string options work.
-
+- `:set {option}<` removes local value for all |global-local| options.
+- `:setlocal {option}<` copies global value to local value for all options.
- 'autoread' works in the terminal (if it supports "focus" events)
- 'cpoptions' flags: |cpo-_|
- 'diffopt' "linematch" feature
@@ -561,6 +562,9 @@ Highlight groups:
the regexp `[a-zA-Z0-9_.@-]*` (see |group-name|).
- |hl-StatusLineTerm| |hl-StatusLineTermNC| are implemented as 'winhighlight'
window-local highlights which are set by the default |TermOpen| handler.
+- The |ins-completion-menu| has cascading highlight styles. |hl-PmenuSel| and
+ |hl-PmenuMatch| both inherit from |hl-Pmenu|, and |hl-PmenuMatchSel|
+ inherits highlights from both |hl-PmenuSel| and |hl-PmenuMatch|.
Macro (|recording|) behavior:
- Replay of a macro recorded during :lmap produces the same actions as when it
@@ -619,7 +623,12 @@ These legacy Vim features are not yet implemented:
- *:gui*
- *:gvim*
+- *'browsedir'* *'bsdir'*
- *'completepopup'*
+- *'guioptions'* *'go'*
+- *'guitablabel'* *'gtl'*
+- *'guitabtooltip'* *'gtt'*
+- *'mouseshape'* *'mouses'*
- *'previewpopup'*
==============================================================================
@@ -726,6 +735,8 @@ Options:
CMD-v (macOS), middle-click, …).
- *'imactivatefunc'* *'imaf'*
- *'imactivatekey'* *'imak'*
+- *'imcmdline'* *'imc'* *'noimcmdline'* *'noimc'*
+- *'imdisable'* *'imd'* *'noimdisable'* *'noimd'*
- *'imstatusfunc'* *'imsf'*
- *'insertmode'* *'im'* Use the following script to emulate 'insertmode': >vim
autocmd BufWinEnter * startinsert
@@ -763,6 +774,7 @@ Options:
6 composing chars only.
- *'maxmem'* Nvim delegates memory-management to the OS.
- *'maxmemtot'* Nvim delegates memory-management to the OS.
+- *'opendevice'* *'odev'* *'noopendevice'* *'noodev'*
- printoptions
- *'printdevice'*
- *'printencoding'*
@@ -797,6 +809,10 @@ Plugins:
- logiPat
- rrhelper
- *vimball*
+- macmap.vim
+- tools/check_colors.vim
+- macros/{justify,matchit,shellmenu,swapmous}.vim: use `packadd! justify` etc.
+ directly
Providers:
diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt
index 15d836a83d..0c349c4e57 100644
--- a/runtime/doc/vvars.txt
+++ b/runtime/doc/vvars.txt
@@ -152,13 +152,14 @@ v:event
an aborting condition (e.g. |c_Esc| or
|c_CTRL-C| for |CmdlineLeave|).
chan |channel-id|
+ info Dict of arbitrary event data.
cmdlevel Level of cmdline.
cmdtype Type of cmdline, |cmdline-char|.
cwd Current working directory.
inclusive Motion is |inclusive|, else exclusive.
scope Event-specific scope name.
operator Current |operator|. Also set for Ex
- commands (unlike |v:operator|). For
+ commands (unlike |v:operator|). For
example if |TextYankPost| is triggered
by the |:yank| Ex command then
`v:event.operator` is "y".
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 5729dd0874..24aa7b1b11 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -69,7 +69,8 @@ If a window is focusable, it is part of the "navigation stack", that is,
editor commands such as :windo, |CTRL-W|, etc., will consider the window as
one that can be made the "current window". A non-focusable window will be
skipped by such commands (though it can be explicitly focused by
-|nvim_set_current_win()|).
+|nvim_set_current_win()|). Non-focusable windows are not listed by |:tabs|, and
+are not counted by the default 'tabline'.
Windows (especially floating windows) can have many other |api-win_config|
properties such as "hide" and "fixed" which also affect behavior.
diff --git a/runtime/ftplugin/ada.vim b/runtime/ftplugin/ada.vim
index 688d912126..50e1388c80 100644
--- a/runtime/ftplugin/ada.vim
+++ b/runtime/ftplugin/ada.vim
@@ -103,7 +103,7 @@ endif
if !exists ("b:match_words") &&
\ exists ("loaded_matchit")
"
- " The following lines enable the macros/matchit.vim plugin for
+ " The following lines enable the matchit.vim plugin for
" Ada-specific extended matching with the % key.
"
let s:notend = '\%(\<end\s\+\)\@<!'
diff --git a/runtime/ftplugin/checkhealth.vim b/runtime/ftplugin/checkhealth.vim
index 62a1970b4a..00f24a2912 100644
--- a/runtime/ftplugin/checkhealth.vim
+++ b/runtime/ftplugin/checkhealth.vim
@@ -8,11 +8,11 @@ endif
runtime! ftplugin/help.vim
-setlocal wrap breakindent linebreak
+setlocal wrap breakindent linebreak nolist
let &l:iskeyword='!-~,^*,^|,^",192-255'
if exists("b:undo_ftplugin")
- let b:undo_ftplugin .= "|setl wrap< bri< lbr< kp< isk<"
+ let b:undo_ftplugin .= "|setl wrap< bri< lbr< kp< isk< list<"
else
- let b:undo_ftplugin = "setl wrap< bri< lbr< kp< isk<"
+ let b:undo_ftplugin = "setl wrap< bri< lbr< kp< isk< list<"
endif
diff --git a/runtime/ftplugin/cook.vim b/runtime/ftplugin/cook.vim
new file mode 100644
index 0000000000..3697803e74
--- /dev/null
+++ b/runtime/ftplugin/cook.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin
+" Language: Cooklang
+" Maintainer: Riley Bruins <ribru17@gmail.com>
+" Last Change: 2024 Nov 03
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setl comments=:-- commentstring=--\ %s
+
+let b:undo_ftplugin = 'setl com< cms<'
diff --git a/runtime/ftplugin/dune.vim b/runtime/ftplugin/dune.vim
index 6e20a8fabb..7608d53527 100644
--- a/runtime/ftplugin/dune.vim
+++ b/runtime/ftplugin/dune.vim
@@ -6,13 +6,14 @@
" 2023 Aug 28 - Added undo_ftplugin (Vim Project)
" 2018 Nov 03 - Added commentstring (Markus Mottl)
" 2017 Sep 06 - Initial version (Etienne Millon)
+" 2024 Nov 09 - use setl instead of :set
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin=1
-set lisp
+setl lisp
" Comment string
setl commentstring=;\ %s
diff --git a/runtime/ftplugin/erlang.vim b/runtime/ftplugin/erlang.vim
index 5a3ab717d9..e82263d300 100644
--- a/runtime/ftplugin/erlang.vim
+++ b/runtime/ftplugin/erlang.vim
@@ -97,7 +97,7 @@ if !exists('*ErlangFoldText')
endfunction
endif
-" The following lines enable the macros/matchit.vim plugin for extended
+" The following lines enable the matchit.vim plugin for extended
" matching with the % key.
let b:match_ignorecase = 0
let b:match_words =
diff --git a/runtime/ftplugin/gleam.vim b/runtime/ftplugin/gleam.vim
new file mode 100644
index 0000000000..9ed607c4b3
--- /dev/null
+++ b/runtime/ftplugin/gleam.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: Gleam
+" Maintainer: Trilowy (https://github.com/trilowy)
+" Last Change: 2024 Oct 13
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal comments=://,:///,:////
+setlocal commentstring=//\ %s
+
+let b:undo_ftplugin = "setlocal comments< commentstring<"
+
+" vim: sw=2 sts=2 et
diff --git a/runtime/ftplugin/idris2.vim b/runtime/ftplugin/idris2.vim
new file mode 100644
index 0000000000..54e5acef90
--- /dev/null
+++ b/runtime/ftplugin/idris2.vim
@@ -0,0 +1,34 @@
+" Vim ftplugin file
+" Language: Idris 2
+" Last Change: 2024 Nov 05
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+"
+" Based on ftplugin/idris2.vim from https://github.com/edwinb/idris2-vim
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+setlocal shiftwidth=2
+setlocal tabstop=2
+
+" Set g:idris2#allow_tabchar = 1 to use tabs instead of spaces
+if exists('g:idris2#allow_tabchar') && g:idris2#allow_tabchar != 0
+ setlocal noexpandtab
+else
+ setlocal expandtab
+endif
+
+setlocal comments=s1:{-,mb:-,ex:-},:\|\|\|,:--
+setlocal commentstring=--\ %s
+
+" makes ? a part of a word, e.g. for named holes `vzipWith f [] [] = ?vzipWith_rhs_3`, uncomment if want to reenable
+" setlocal iskeyword+=?
+
+setlocal wildignore+=*.ibc
+
+let b:undo_ftplugin = "setlocal shiftwidth< tabstop< expandtab< comments< commentstring< iskeyword< wildignore<"
+
+let b:did_ftplugin = 1
diff --git a/runtime/ftplugin/ipkg.vim b/runtime/ftplugin/ipkg.vim
new file mode 100644
index 0000000000..70ae26ec17
--- /dev/null
+++ b/runtime/ftplugin/ipkg.vim
@@ -0,0 +1,19 @@
+" Vim ftplugin file
+" Language: Ipkg
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" Last Change: 2024 Nov 05
+" Author: ShinKage
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+setlocal comments=:--
+setlocal commentstring=--\ %s
+setlocal wildignore+=*.ibc
+
+let b:undo_ftplugin = "setlocal shiftwidth< tabstop< expandtab< comments< commentstring< iskeyword< wildignore<"
+
+let b:did_ftplugin = 1
diff --git a/runtime/ftplugin/leo.vim b/runtime/ftplugin/leo.vim
new file mode 100644
index 0000000000..a009c02df4
--- /dev/null
+++ b/runtime/ftplugin/leo.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin
+" Language: Leo
+" Maintainer: Riley Bruins <ribru17@gmail.com>
+" Last Change: 2024 Nov 03
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setl comments=:// commentstring=//\ %s
+
+let b:undo_ftplugin = 'setl com< cms<'
diff --git a/runtime/ftplugin/llvm.vim b/runtime/ftplugin/llvm.vim
new file mode 100644
index 0000000000..148b12f102
--- /dev/null
+++ b/runtime/ftplugin/llvm.vim
@@ -0,0 +1,12 @@
+" Vim filetype plugin file
+" Language: LLVM IR
+" Last Change: 2024 Oct 22
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:did_ftplugin") | finish | endif
+let b:did_ftplugin = 1
+
+setl comments=:;
+setl commentstring=;\ %s
+
+let b:undo_ftplugin = "setl commentstring< comments<"
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim
index 37667477f3..5ea36c32ce 100644
--- a/runtime/ftplugin/man.vim
+++ b/runtime/ftplugin/man.vim
@@ -26,11 +26,7 @@ if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
nnoremap <silent> <buffer> k gk
nnoremap <silent> <buffer> gO :lua require'man'.show_toc()<CR>
nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR>
- if get(g:, 'pager')
- nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>q
- else
- nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c
- endif
+ nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>q
endif
if get(g:, 'ft_man_folding_enable', 0)
diff --git a/runtime/ftplugin/mlir.vim b/runtime/ftplugin/mlir.vim
new file mode 100644
index 0000000000..c6a9dc341f
--- /dev/null
+++ b/runtime/ftplugin/mlir.vim
@@ -0,0 +1,10 @@
+" Vim filetype plugin file
+" Language: MLIR
+
+if exists("b:did_ftplugin") | finish | endif
+let b:did_ftplugin = 1
+
+setl comments=:///,://
+setl commentstring=//\ %s
+
+let b:undo_ftplugin = "setl commentstring< comments<"
diff --git a/runtime/ftplugin/mss.vim b/runtime/ftplugin/mss.vim
new file mode 100644
index 0000000000..de2f8791ec
--- /dev/null
+++ b/runtime/ftplugin/mss.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: Vivado mss file
+" Last Change: 2024 Oct 22
+" Document: https://docs.amd.com/r/2020.2-English/ug1400-vitis-embedded/Microprocessor-Software-Specification-MSS
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal comments=b:#,fb:-
+setlocal commentstring=#\ %s
+
+let b:match_words = '\<BEGIN\>:\<END\>'
+let b:undo_ftplugin = "setl com< cms< | unlet b:match_words"
diff --git a/runtime/ftplugin/org.vim b/runtime/ftplugin/org.vim
new file mode 100644
index 0000000000..45a5e19d49
--- /dev/null
+++ b/runtime/ftplugin/org.vim
@@ -0,0 +1,37 @@
+" Vim filetype plugin file
+" Language: Org
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Nov 14
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+if exists('b:undo_ftplugin')
+ let b:undo_ftplugin .= "|setl cms< com< fo< flp<"
+else
+ let b:undo_ftplugin = "setl cms< com< fo< flp<"
+endif
+
+setl commentstring=#\ %s
+setl comments=fb:*,fb:-,fb:+,b:#,b:\:
+
+setl formatoptions+=nql
+setl formatlistpat=^\\s*\\(\\(\\d\\|\\a\\)\\+[.)]\\|[+-]\\)\\s\\+
+
+function OrgFoldExpr()
+ let l:depth = match(getline(v:lnum), '\(^\*\+\)\@<=\( .*$\)\@=')
+ if l:depth > 0 && synIDattr(synID(v:lnum, 1, 1), 'name') =~# '\m^orgHeadline'
+ return ">" . l:depth
+ endif
+ return "="
+endfunction
+
+if has("folding") && get(g:, 'org_folding', 0)
+ setl foldexpr=OrgFoldExpr()
+ setl foldmethod=expr
+ let b:undo_ftplugin .= "|setl foldexpr< foldmethod<"
+endif
+
+" vim: ts=8 sts=2 sw=2 et
diff --git a/runtime/ftplugin/plaintex.vim b/runtime/ftplugin/plaintex.vim
index 9e0e402680..17c1f5672f 100644
--- a/runtime/ftplugin/plaintex.vim
+++ b/runtime/ftplugin/plaintex.vim
@@ -22,7 +22,7 @@ let b:undo_ftplugin .= "| unlet! b:match_ignorecase b:match_skip b:match_words"
let &l:define .= '\|\\new\(count\|dimen\|skip\|muskip\|box\|toks\|read\|write'
\ . '\|fam\|insert\)'
-" The following lines enable the macros/matchit.vim plugin for
+" The following lines enable the matchit.vim plugin for
" extended matching with the % key.
" There is no default meaning for \(...\) etc., but many users define one.
if exists("loaded_matchit")
diff --git a/runtime/ftplugin/racket.vim b/runtime/ftplugin/racket.vim
index 7bfd87ddc3..52768d67f5 100644
--- a/runtime/ftplugin/racket.vim
+++ b/runtime/ftplugin/racket.vim
@@ -3,7 +3,7 @@
" Maintainer: D. Ben Knoble <ben.knoble+github@gmail.com>
" Previous Maintainer: Will Langstroth <will@langstroth.com>
" URL: https://github.com/benknoble/vim-racket
-" Last Change: 2024 May 28
+" Last Change: 2024 Jun 01
if exists("b:did_ftplugin")
finish
@@ -16,19 +16,20 @@ set cpo&vim
" quick hack to allow adding values
setlocal iskeyword=@,!,#-',*-:,<-Z,a-z,~,_,94
+setlocal shiftwidth=2 softtabstop=2
+
" Enable auto begin new comment line when continuing from an old comment line
setlocal comments=:;;;;,:;;;,:;;,:;
setlocal formatoptions+=r
-"setlocal commentstring=;;\ %s
-setlocal commentstring=#\|\ %s\ \|#
+setlocal commentstring=;;\ %s
setlocal formatprg=raco\ fmt
" Undo our settings when the filetype changes away from Racket
" (this should be amended if settings/mappings are added above!)
let b:undo_ftplugin =
- \ "setlocal iskeyword< lispwords< lisp< comments< formatoptions< formatprg<"
+ \ "setlocal iskeyword< shiftwidth< softtabstop< comments< formatoptions< formatprg<"
\. " | setlocal commentstring<"
if !exists("no_plugin_maps") && !exists("no_racket_maps")
diff --git a/runtime/ftplugin/spec.vim b/runtime/ftplugin/spec.vim
index fa125be52c..4aaef26a2e 100644
--- a/runtime/ftplugin/spec.vim
+++ b/runtime/ftplugin/spec.vim
@@ -5,6 +5,7 @@
" Last Change: 2015 Jun 01
" Update by Zdenek Dohnal, 2022 May 17
" 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537
+" 2024 Oct 07 by Vim Project: add comment support, #15817
if exists("b:did_ftplugin")
finish
@@ -14,6 +15,11 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
+setlocal comments=b:#
+setlocal commentstring=#\ %s
+
+let b:undo_ftplugin = "setlocal comments< commentstring<"
+
if !exists("no_plugin_maps") && !exists("no_spec_maps")
if !hasmapto("<Plug>SpecChangelog")
map <buffer> <LocalLeader>c <Plug>SpecChangelog
@@ -204,7 +210,7 @@ if !exists("*s:ParseRpmVars")
endfunction
endif
-" The following lines, along with the macros/matchit.vim plugin,
+" The following lines, along with the matchit.vim plugin,
" make it easy to navigate the different sections of a spec file
" with the % key (thanks to Max Ischenko).
@@ -216,4 +222,4 @@ let b:match_words =
let &cpo = s:cpo_save
unlet s:cpo_save
-let b:undo_ftplugin = "unlet! b:match_ignorecase b:match_words"
+let b:undo_ftplugin ..= " | unlet! b:match_ignorecase b:match_words"
diff --git a/runtime/ftplugin/sway.vim b/runtime/ftplugin/sway.vim
new file mode 100644
index 0000000000..35970b257c
--- /dev/null
+++ b/runtime/ftplugin/sway.vim
@@ -0,0 +1,15 @@
+" Vim filetype plugin
+" Language: Sway
+" Maintainer: Riley Bruins <ribru17@gmail.com>
+" Last Change: 2024 Nov 01
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setl commentstring=//\ %s
+" From Rust comments
+setl comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,://
+
+let b:undo_ftplugin = 'setl com< cms<'
diff --git a/runtime/ftplugin/tex.vim b/runtime/ftplugin/tex.vim
index 0d68b51d46..7b58f67863 100644
--- a/runtime/ftplugin/tex.vim
+++ b/runtime/ftplugin/tex.vim
@@ -32,7 +32,7 @@ let &l:include .= '\|\\include{'
" TeX file has \include{fname} (LaTeX only), strip everything except "fname".
let &l:includeexpr = "substitute(v:fname, '^.\\{-}{\\|}.*', '', 'g')"
-" The following lines enable the macros/matchit.vim plugin for
+" The following lines enable the matchit.vim plugin for
" extended matching with the % key.
" ftplugin/plaintex.vim already defines b:match_skip and b:match_ignorecase
" and matches \(, \), \[, \], \{, and \} .
diff --git a/runtime/ftplugin/typst.vim b/runtime/ftplugin/typst.vim
index 895fc688d9..3841e427f3 100644
--- a/runtime/ftplugin/typst.vim
+++ b/runtime/ftplugin/typst.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: Typst
" Maintainer: Gregory Anders
-" Last Change: 2024 Oct 04
+" Last Change: 2024 Oct 21
" Based on: https://github.com/kaarmu/typst.vim
if exists('b:did_ftplugin')
@@ -21,6 +21,12 @@ if get(g:, 'typst_conceal', 0)
let b:undo_ftplugin .= ' cole<'
endif
+if has("folding") && get(g:, 'typst_folding', 0)
+ setlocal foldexpr=typst#foldexpr()
+ setlocal foldmethod=expr
+ let b:undo_ftplugin .= "|setl foldexpr< foldmethod<"
+endif
+
if !exists('current_compiler')
compiler typst
let b:undo_ftplugin ..= "| compiler make"
diff --git a/runtime/indent/idris2.vim b/runtime/indent/idris2.vim
new file mode 100644
index 0000000000..d3c306e0a1
--- /dev/null
+++ b/runtime/indent/idris2.vim
@@ -0,0 +1,183 @@
+" Vim indent file
+" Language: Idris 2
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" Author: raichoo <raichoo@googlemail.com>
+" Last Change: 2024 Nov 05
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+"
+" indentation for idris (idris-lang.org)
+"
+" Based on haskell indentation by motemen <motemen@gmail.com>
+"
+" Indentation configuration variables:
+"
+" g:idris2_indent_if (default: 3)
+" Controls indentation after 'if' statements
+" Example:
+" if condition
+" >>>then expr
+" >>>else expr
+"
+" g:idris2_indent_case (default: 5)
+" Controls indentation of case expressions
+" Example:
+" case x of
+" >>>>>Left y => ...
+" >>>>>Right z => ...
+"
+" g:idris2_indent_let (default: 4)
+" Controls indentation after 'let' bindings
+" Example:
+" let x = expr in
+" >>>>body
+"
+" g:idris2_indent_rewrite (default: 8)
+" Controls indentation after 'rewrite' expressions
+" Example:
+" rewrite proof in
+" >>>>>>>>expr
+"
+" g:idris2_indent_where (default: 6)
+" Controls indentation of 'where' blocks
+" Example:
+" function args
+" >>>>>>where helper = expr
+"
+" g:idris2_indent_do (default: 3)
+" Controls indentation in 'do' blocks
+" Example:
+" do x <- action
+" >>>y <- action
+"
+" Example configuration in .vimrc:
+" let g:idris2_indent_if = 2
+
+if exists('b:did_indent')
+ finish
+endif
+
+setlocal indentexpr=GetIdrisIndent()
+setlocal indentkeys=!^F,o,O,}
+
+let b:did_indent = 1
+let b:undo_indent = "setlocal indentexpr< indentkeys<"
+
+" we want to use line continuations (\) BEGINNING
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Define defaults for indent configuration
+let s:indent_defaults = {
+ \ 'idris2_indent_if': 3,
+ \ 'idris2_indent_case': 5,
+ \ 'idris2_indent_let': 4,
+ \ 'idris2_indent_rewrite': 8,
+ \ 'idris2_indent_where': 6,
+ \ 'idris2_indent_do': 3
+ \ }
+
+" we want to use line continuations (\) END
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" Set up indent settings with user overrides
+for [key, default] in items(s:indent_defaults)
+ let varname = 'g:' . key
+ if !exists(varname)
+ execute 'let' varname '=' default
+ endif
+endfor
+
+if exists("*GetIdrisIndent")
+ finish
+endif
+
+function! GetIdrisIndent()
+ let prevline = getline(v:lnum - 1)
+
+ if prevline =~ '\s\+(\s*.\+\s\+:\s\+.\+\s*)\s\+->\s*$'
+ return match(prevline, '(')
+ elseif prevline =~ '\s\+{\s*.\+\s\+:\s\+.\+\s*}\s\+->\s*$'
+ return match(prevline, '{')
+ endif
+
+ if prevline =~ '[!#$%&*+./<>?@\\^|~-]\s*$'
+ let s = match(prevline, '[:=]')
+ if s > 0
+ return s + 2
+ else
+ return match(prevline, '\S')
+ endif
+ endif
+
+ if prevline =~ '[{([][^})\]]\+$'
+ return match(prevline, '[{([]')
+ endif
+
+ if prevline =~ '\<let\>\s\+.\+\<in\>\s*$'
+ return match(prevline, '\<let\>') + g:idris2_indent_let
+ endif
+
+ if prevline =~ '\<rewrite\>\s\+.\+\<in\>\s*$'
+ return match(prevline, '\<rewrite\>') + g:idris2_indent_rewrite
+ endif
+
+ if prevline !~ '\<else\>'
+ let s = match(prevline, '\<if\>.*\&.*\zs\<then\>')
+ if s > 0
+ return s
+ endif
+
+ let s = match(prevline, '\<if\>')
+ if s > 0
+ return s + g:idris2_indent_if
+ endif
+ endif
+
+ if prevline =~ '\(\<where\>\|\<do\>\|=\|[{([]\)\s*$'
+ return match(prevline, '\S') + &shiftwidth
+ endif
+
+ if prevline =~ '\<where\>\s\+\S\+.*$'
+ return match(prevline, '\<where\>') + g:idris2_indent_where
+ endif
+
+ if prevline =~ '\<do\>\s\+\S\+.*$'
+ return match(prevline, '\<do\>') + g:idris2_indent_do
+ endif
+
+ if prevline =~ '^\s*\<\(co\)\?data\>\s\+[^=]\+\s\+=\s\+\S\+.*$'
+ return match(prevline, '=')
+ endif
+
+ if prevline =~ '\<with\>\s\+([^)]*)\s*$'
+ return match(prevline, '\S') + &shiftwidth
+ endif
+
+ if prevline =~ '\<case\>\s\+.\+\<of\>\s*$'
+ return match(prevline, '\<case\>') + g:idris2_indent_case
+ endif
+
+ if prevline =~ '^\s*\(\<namespace\>\|\<\(co\)\?data\>\)\s\+\S\+\s*$'
+ return match(prevline, '\(\<namespace\>\|\<\(co\)\?data\>\)') + &shiftwidth
+ endif
+
+ if prevline =~ '^\s*\(\<using\>\|\<parameters\>\)\s*([^(]*)\s*$'
+ return match(prevline, '\(\<using\>\|\<parameters\>\)') + &shiftwidth
+ endif
+
+ if prevline =~ '^\s*\<mutual\>\s*$'
+ return match(prevline, '\<mutual\>') + &shiftwidth
+ endif
+
+ let line = getline(v:lnum)
+
+ if (line =~ '^\s*}\s*' && prevline !~ '^\s*;')
+ return match(prevline, '\S') - &shiftwidth
+ endif
+
+ return match(prevline, '\S')
+endfunction
+
+" vim:et:sw=2:sts=2
diff --git a/runtime/indent/racket.vim b/runtime/indent/racket.vim
index d301cd64f9..2bab3f3bed 100644
--- a/runtime/indent/racket.vim
+++ b/runtime/indent/racket.vim
@@ -3,7 +3,7 @@
" Maintainer: D. Ben Knoble <ben.knoble+github@gmail.com>
" Previous Maintainer: Will Langstroth <will@langstroth.com>
" URL: https://github.com/benknoble/vim-racket
-" Last Change: 2024 Jan 31
+" Last Change: 2024 Nov 12
if exists("b:did_indent")
finish
@@ -21,6 +21,7 @@ setlocal lispwords+=λ
setlocal lispwords+=with-handlers
setlocal lispwords+=define-values,opt-lambda,case-lambda,syntax-rules,with-syntax,syntax-case,syntax-parse
setlocal lispwords+=define-for-syntax,define-syntax-parser,define-syntax-parse-rule,define-syntax-class,define-splicing-syntax-class
+setlocal lispwords+=syntax/loc,quasisyntax/loc
setlocal lispwords+=define-syntax-parameter,syntax-parameterize
setlocal lispwords+=define-signature,unit,unit/sig,compund-unit/sig,define-values/invoke-unit/sig
setlocal lispwords+=define-opt/c,define-syntax-rule
@@ -30,6 +31,11 @@ setlocal lispwords+=with-input-from-file,with-output-to-file
setlocal lispwords+=begin,begin0
setlocal lispwords+=place
setlocal lispwords+=cond
+" Racket style indents if like a function application:
+" (if test
+" then
+" else)
+setlocal lispwords-=if
" Racket OOP
" TODO missing a lot of define-like forms here (e.g., define/augment, etc.)
@@ -50,6 +56,7 @@ setlocal lispwords+=for/set,for*/set
setlocal lispwords+=for/first,for*/first
setlocal lispwords+=for/last,for*/last
setlocal lispwords+=for/stream,for*/stream
+setlocal lispwords+=for/lists,for*/lists
setlocal lispwords+=match,match*,match/values,define/match,match-lambda,match-lambda*,match-lambda**
setlocal lispwords+=match-let,match-let*,match-let-values,match-let*-values
@@ -66,4 +73,7 @@ setlocal lispwords+=if-view,case-view,cond-view,list-view,dyn-view
setlocal lispwords+=case/dep
setlocal lispwords+=define/obs
+" rackunit
+setlocal lispwords+=define-simple-check,define-binary-check,define-check,with-check-info
+
let b:undo_indent = "setlocal lisp< ai< si< lw<" .. (has('vim9script') ? ' indentexpr< lispoptions<' : '')
diff --git a/runtime/indent/sh.vim b/runtime/indent/sh.vim
index aa47c6d1bd..184e829873 100644
--- a/runtime/indent/sh.vim
+++ b/runtime/indent/sh.vim
@@ -7,6 +7,8 @@
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-sh-indent
" Changelog:
+" 20241411 - Detect dash character in function keyword for
+" bash mode (issue #16049)
" 20190726 - Correctly skip if keywords in syntax comments
" (issue #17)
" 20190603 - Do not indent in zsh filetypes with an `if` in comments
@@ -195,7 +197,9 @@ endfunction
function! s:is_function_definition(line)
return a:line =~ '^\s*\<\k\+\>\s*()\s*{' ||
\ a:line =~ '^\s*{' ||
- \ a:line =~ '^\s*function\s*\k\+\s*\%(()\)\?\s*{'
+ \ a:line =~ '^\s*function\s*\k\+\s*\%(()\)\?\s*{' ||
+ \ ((&ft is# 'zsh' || s:is_bash()) &&
+ \ a:line =~ '^\s*function\s*\S\+\s*\%(()\)\?\s*{' )
endfunction
function! s:is_array(line)
diff --git a/runtime/indent/testdir/bash.in b/runtime/indent/testdir/bash.in
new file mode 100644
index 0000000000..7ffcfc7a9d
--- /dev/null
+++ b/runtime/indent/testdir/bash.in
@@ -0,0 +1,22 @@
+#!/bin/bash
+# vim: set ft=bash sw=2 noet:
+
+# START_INDENT
+a = 10
+b = 20
+
+function add() {
+c = $((a + b))
+}
+
+function print {
+# do nothing
+}
+
+if [[ $c -ge 15 ]];
+then
+print("ok")
+else
+print("not ok")
+fi
+# END_INDENT
diff --git a/runtime/indent/testdir/bash.ok b/runtime/indent/testdir/bash.ok
new file mode 100644
index 0000000000..93d5b33c38
--- /dev/null
+++ b/runtime/indent/testdir/bash.ok
@@ -0,0 +1,22 @@
+#!/bin/bash
+# vim: set ft=bash sw=2 noet:
+
+# START_INDENT
+a = 10
+b = 20
+
+function add() {
+ c = $((a + b))
+}
+
+function print {
+ # do nothing
+}
+
+if [[ $c -ge 15 ]];
+then
+ print("ok")
+else
+ print("not ok")
+fi
+# END_INDENT
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index fce8f89be8..114c94f9e5 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -305,7 +305,7 @@ local function matchstr(text, pat_or_re)
return
end
- return text:sub(vim.str_utfindex(text, s) + 1, vim.str_utfindex(text, e))
+ return text:sub(vim.str_utfindex(text, 'utf-32', s) + 1, vim.str_utfindex(text, 'utf-32', e))
end
-- attempt to extract the name and sect out of 'name(sect)'
@@ -675,7 +675,6 @@ function M.init_pager()
vim.cmd.file({ 'man://' .. fn.fnameescape(ref):lower(), mods = { silent = true } })
end
- vim.g.pager = true
set_options()
end
diff --git a/runtime/lua/vim/_buf.lua b/runtime/lua/vim/_buf.lua
new file mode 100644
index 0000000000..0631c96f77
--- /dev/null
+++ b/runtime/lua/vim/_buf.lua
@@ -0,0 +1,23 @@
+local M = {}
+
+--- Adds one or more blank lines above or below the cursor.
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+--- @param above? boolean Place blank line(s) above the cursor
+local function add_blank(above)
+ local offset = above and 1 or 0
+ local repeated = vim.fn['repeat']({ '' }, vim.v.count1)
+ local linenr = vim.api.nvim_win_get_cursor(0)[1]
+ vim.api.nvim_buf_set_lines(0, linenr - offset, linenr - offset, true, repeated)
+end
+
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+function M.space_above()
+ add_blank(true)
+end
+
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+function M.space_below()
+ add_blank()
+end
+
+return M
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 6cad1dbca9..06f6ed6829 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -157,7 +157,7 @@ do
--- client is attached. If no client is attached, or if a server does not support a capability, an
--- error message is displayed rather than exhibiting different behavior.
---
- --- See |grr|, |grn|, |gra|, |i_CTRL-S|.
+ --- See |grr|, |grn|, |gra|, |gri|, |gO|, |i_CTRL-S|.
do
vim.keymap.set('n', 'grn', function()
vim.lsp.buf.rename()
@@ -171,7 +171,15 @@ do
vim.lsp.buf.references()
end, { desc = 'vim.lsp.buf.references()' })
- vim.keymap.set('i', '<C-S>', function()
+ vim.keymap.set('n', 'gri', function()
+ vim.lsp.buf.implementation()
+ end, { desc = 'vim.lsp.buf.implementation()' })
+
+ vim.keymap.set('n', 'gO', function()
+ vim.lsp.buf.document_symbol()
+ end, { desc = 'vim.lsp.buf.document_symbol()' })
+
+ vim.keymap.set({ 'i', 's' }, '<C-S>', function()
vim.lsp.buf.signature_help()
end, { desc = 'vim.lsp.buf.signature_help()' })
end
@@ -211,173 +219,163 @@ do
--- vim-unimpaired style mappings. See: https://github.com/tpope/vim-unimpaired
do
+ --- Execute a command and print errors without a stacktrace.
+ --- @param opts table Arguments to |nvim_cmd()|
+ local function cmd(opts)
+ local _, err = pcall(vim.api.nvim_cmd, opts, {})
+ if err then
+ vim.api.nvim_err_writeln(err:sub(#'Vim:' + 1))
+ end
+ end
+
-- Quickfix mappings
vim.keymap.set('n', '[q', function()
- vim.cmd.cprevious({ count = vim.v.count1 })
- end, {
- desc = ':cprevious',
- })
+ cmd({ cmd = 'cprevious', count = vim.v.count1 })
+ end, { desc = ':cprevious' })
vim.keymap.set('n', ']q', function()
- vim.cmd.cnext({ count = vim.v.count1 })
- end, {
- desc = ':cnext',
- })
+ cmd({ cmd = 'cnext', count = vim.v.count1 })
+ end, { desc = ':cnext' })
vim.keymap.set('n', '[Q', function()
- vim.cmd.crewind({ count = vim.v.count ~= 0 and vim.v.count or nil })
- end, {
- desc = ':crewind',
- })
+ cmd({ cmd = 'crewind', count = vim.v.count ~= 0 and vim.v.count or nil })
+ end, { desc = ':crewind' })
vim.keymap.set('n', ']Q', function()
- vim.cmd.clast({ count = vim.v.count ~= 0 and vim.v.count or nil })
- end, {
- desc = ':clast',
- })
+ cmd({ cmd = 'clast', count = vim.v.count ~= 0 and vim.v.count or nil })
+ end, { desc = ':clast' })
vim.keymap.set('n', '[<C-Q>', function()
- vim.cmd.cpfile({ count = vim.v.count1 })
- end, {
- desc = ':cpfile',
- })
+ cmd({ cmd = 'cpfile', count = vim.v.count1 })
+ end, { desc = ':cpfile' })
vim.keymap.set('n', ']<C-Q>', function()
- vim.cmd.cnfile({ count = vim.v.count1 })
- end, {
- desc = ':cnfile',
- })
+ cmd({ cmd = 'cnfile', count = vim.v.count1 })
+ end, { desc = ':cnfile' })
-- Location list mappings
vim.keymap.set('n', '[l', function()
- vim.cmd.lprevious({ count = vim.v.count1 })
- end, {
- desc = ':lprevious',
- })
+ cmd({ cmd = 'lprevious', count = vim.v.count1 })
+ end, { desc = ':lprevious' })
vim.keymap.set('n', ']l', function()
- vim.cmd.lnext({ count = vim.v.count1 })
- end, {
- desc = ':lnext',
- })
+ cmd({ cmd = 'lnext', count = vim.v.count1 })
+ end, { desc = ':lnext' })
vim.keymap.set('n', '[L', function()
- vim.cmd.lrewind({ count = vim.v.count ~= 0 and vim.v.count or nil })
- end, {
- desc = ':lrewind',
- })
+ cmd({ cmd = 'lrewind', count = vim.v.count ~= 0 and vim.v.count or nil })
+ end, { desc = ':lrewind' })
vim.keymap.set('n', ']L', function()
- vim.cmd.llast({ count = vim.v.count ~= 0 and vim.v.count or nil })
- end, {
- desc = ':llast',
- })
+ cmd({ cmd = 'llast', count = vim.v.count ~= 0 and vim.v.count or nil })
+ end, { desc = ':llast' })
vim.keymap.set('n', '[<C-L>', function()
- vim.cmd.lpfile({ count = vim.v.count1 })
- end, {
- desc = ':lpfile',
- })
+ cmd({ cmd = 'lpfile', count = vim.v.count1 })
+ end, { desc = ':lpfile' })
vim.keymap.set('n', ']<C-L>', function()
- vim.cmd.lnfile({ count = vim.v.count1 })
- end, {
- desc = ':lnfile',
- })
+ cmd({ cmd = 'lnfile', count = vim.v.count1 })
+ end, { desc = ':lnfile' })
-- Argument list
vim.keymap.set('n', '[a', function()
- vim.cmd.previous({ count = vim.v.count1 })
- end, {
- desc = ':previous',
- })
+ cmd({ cmd = 'previous', count = vim.v.count1 })
+ end, { desc = ':previous' })
vim.keymap.set('n', ']a', function()
-- count doesn't work with :next, must use range. See #30641.
- vim.cmd.next({ range = { vim.v.count1 } })
- end, {
- desc = ':next',
- })
+ cmd({ cmd = 'next', range = { vim.v.count1 } })
+ end, { desc = ':next' })
vim.keymap.set('n', '[A', function()
if vim.v.count ~= 0 then
- vim.cmd.argument({ count = vim.v.count })
+ cmd({ cmd = 'argument', count = vim.v.count })
else
- vim.cmd.rewind()
+ cmd({ cmd = 'rewind' })
end
- end, {
- desc = ':rewind',
- })
+ end, { desc = ':rewind' })
vim.keymap.set('n', ']A', function()
if vim.v.count ~= 0 then
- vim.cmd.argument({ count = vim.v.count })
+ cmd({ cmd = 'argument', count = vim.v.count })
else
- vim.cmd.last()
+ cmd({ cmd = 'last' })
end
- end, {
- desc = ':last',
- })
+ end, { desc = ':last' })
-- Tags
vim.keymap.set('n', '[t', function()
-- count doesn't work with :tprevious, must use range. See #30641.
- vim.cmd.tprevious({ range = { vim.v.count1 } })
+ cmd({ cmd = 'tprevious', range = { vim.v.count1 } })
end, { desc = ':tprevious' })
vim.keymap.set('n', ']t', function()
-- count doesn't work with :tnext, must use range. See #30641.
- vim.cmd.tnext({ range = { vim.v.count1 } })
+ cmd({ cmd = 'tnext', range = { vim.v.count1 } })
end, { desc = ':tnext' })
vim.keymap.set('n', '[T', function()
-- count doesn't work with :trewind, must use range. See #30641.
- vim.cmd.trewind({ range = vim.v.count ~= 0 and { vim.v.count } or nil })
+ cmd({ cmd = 'trewind', range = vim.v.count ~= 0 and { vim.v.count } or nil })
end, { desc = ':trewind' })
vim.keymap.set('n', ']T', function()
-- :tlast does not accept a count, so use :trewind if count given
if vim.v.count ~= 0 then
- vim.cmd.trewind({ range = { vim.v.count } })
+ cmd({ cmd = 'trewind', range = { vim.v.count } })
else
- vim.cmd.tlast()
+ cmd({ cmd = 'tlast' })
end
end, { desc = ':tlast' })
vim.keymap.set('n', '[<C-T>', function()
-- count doesn't work with :ptprevious, must use range. See #30641.
- vim.cmd.ptprevious({ range = { vim.v.count1 } })
+ cmd({ cmd = 'ptprevious', range = { vim.v.count1 } })
end, { desc = ' :ptprevious' })
vim.keymap.set('n', ']<C-T>', function()
-- count doesn't work with :ptnext, must use range. See #30641.
- vim.cmd.ptnext({ range = { vim.v.count1 } })
+ cmd({ cmd = 'ptnext', range = { vim.v.count1 } })
end, { desc = ':ptnext' })
-- Buffers
vim.keymap.set('n', '[b', function()
- vim.cmd.bprevious({ count = vim.v.count1 })
+ cmd({ cmd = 'bprevious', count = vim.v.count1 })
end, { desc = ':bprevious' })
vim.keymap.set('n', ']b', function()
- vim.cmd.bnext({ count = vim.v.count1 })
+ cmd({ cmd = 'bnext', count = vim.v.count1 })
end, { desc = ':bnext' })
vim.keymap.set('n', '[B', function()
if vim.v.count ~= 0 then
- vim.cmd.buffer({ count = vim.v.count })
+ cmd({ cmd = 'buffer', count = vim.v.count })
else
- vim.cmd.brewind()
+ cmd({ cmd = 'brewind' })
end
end, { desc = ':brewind' })
vim.keymap.set('n', ']B', function()
if vim.v.count ~= 0 then
- vim.cmd.buffer({ count = vim.v.count })
+ cmd({ cmd = 'buffer', count = vim.v.count })
else
- vim.cmd.blast()
+ cmd({ cmd = 'blast' })
end
end, { desc = ':blast' })
+
+ -- Add empty lines
+ vim.keymap.set('n', '[<Space>', function()
+ -- TODO: update once it is possible to assign a Lua function to options #25672
+ vim.go.operatorfunc = "v:lua.require'vim._buf'.space_above"
+ return 'g@l'
+ end, { expr = true, desc = 'Add empty line above cursor' })
+
+ vim.keymap.set('n', ']<Space>', function()
+ -- TODO: update once it is possible to assign a Lua function to options #25672
+ vim.go.operatorfunc = "v:lua.require'vim._buf'.space_below"
+ return 'g@l'
+ end, { expr = true, desc = 'Add empty line below cursor' })
end
end
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 2e829578a7..44f17b3f85 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -32,7 +32,7 @@ for k, v in pairs({
func = true,
F = true,
lsp = true,
- highlight = true,
+ hl = true,
diagnostic = true,
keymap = true,
ui = true,
@@ -68,6 +68,12 @@ vim.log = {
},
}
+local utfs = {
+ ['utf-8'] = true,
+ ['utf-16'] = true,
+ ['utf-32'] = true,
+}
+
-- TODO(lewis6991): document that the signature is system({cmd}, [{opts},] {on_exit})
--- Runs a system command or throws an error if {cmd} cannot be run.
---
@@ -467,15 +473,11 @@ vim.cmd = setmetatable({}, {
-- These are the vim.env/v/g/o/bo/wo variable magic accessors.
do
- local validate = vim.validate
-
--- @param scope string
--- @param handle? false|integer
--- @return vim.var_accessor
local function make_dict_accessor(scope, handle)
- validate({
- scope = { scope, 's' },
- })
+ vim.validate('scope', scope, 'string')
local mt = {}
function mt:__newindex(k, v)
return vim._setvar(scope, handle or 0, k, v)
@@ -543,7 +545,7 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
-- TODO: handle double-width characters
if regtype:byte() == 22 then
local bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1]
- pos1[2] = vim.str_utfindex(bufline, pos1[2])
+ pos1[2] = vim.str_utfindex(bufline, 'utf-32', pos1[2])
end
local region = {}
@@ -555,14 +557,14 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
c2 = c1 + tonumber(regtype:sub(2))
-- and adjust for non-ASCII characters
local bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
- local utflen = vim.str_utfindex(bufline, #bufline)
+ local utflen = vim.str_utfindex(bufline, 'utf-32', #bufline)
if c1 <= utflen then
- c1 = assert(tonumber(vim.str_byteindex(bufline, c1)))
+ c1 = assert(tonumber(vim.str_byteindex(bufline, 'utf-32', c1)))
else
c1 = #bufline + 1
end
if c2 <= utflen then
- c2 = assert(tonumber(vim.str_byteindex(bufline, c2)))
+ c2 = assert(tonumber(vim.str_byteindex(bufline, 'utf-32', c2)))
else
c2 = #bufline + 1
end
@@ -591,7 +593,7 @@ end
---@param timeout integer Number of milliseconds to wait before calling `fn`
---@return table timer luv timer object
function vim.defer_fn(fn, timeout)
- vim.validate({ fn = { fn, 'c', true } })
+ vim.validate('fn', fn, 'callable', true)
local timer = assert(vim.uv.new_timer())
timer:start(
timeout,
@@ -649,7 +651,7 @@ do
end
end
-local on_key_cbs = {} --- @type table<integer,function>
+local on_key_cbs = {} --- @type table<integer,[function, table]>
--- Adds Lua function {fn} with namespace id {ns_id} as a listener to every,
--- yes every, input key.
@@ -658,64 +660,225 @@ local on_key_cbs = {} --- @type table<integer,function>
--- and cannot be toggled dynamically.
---
---@note {fn} will be removed on error.
+---@note {fn} won't be invoked recursively, i.e. if {fn} itself consumes input,
+--- it won't be invoked for those keys.
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
---
----@param fn fun(key: string, typed: string)?
---- Function invoked on every key press. |i_CTRL-V|
---- {key} is the key after mappings have been applied, and
---- {typed} is the key(s) before mappings are applied, which
---- may be empty if {key} is produced by non-typed keys.
---- When {fn} is nil and {ns_id} is specified, the callback
---- associated with namespace {ns_id} is removed.
+---@param fn nil|fun(key: string, typed: string): string? Function invoked for every input key,
+--- after mappings have been applied but before further processing. Arguments
+--- {key} and {typed} are raw keycodes, where {key} is the key after mappings
+--- are applied, and {typed} is the key(s) before mappings are applied.
+--- {typed} may be empty if {key} is produced by non-typed key(s) or by the
+--- same typed key(s) that produced a previous {key}.
+--- If {fn} returns an empty string, {key} is discarded/ignored.
+--- When {fn} is `nil`, the callback associated with namespace {ns_id} is removed.
---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a
---- new |nvim_create_namespace()| id.
+--- new |nvim_create_namespace()| id.
+---@param opts table? Optional parameters
+---
+---@see |keytrans()|
---
---@return integer Namespace id associated with {fn}. Or count of all callbacks
---if on_key() is called without arguments.
-function vim.on_key(fn, ns_id)
+function vim.on_key(fn, ns_id, opts)
if fn == nil and ns_id == nil then
return vim.tbl_count(on_key_cbs)
end
- vim.validate({
- fn = { fn, 'c', true },
- ns_id = { ns_id, 'n', true },
- })
+ vim.validate('fn', fn, 'callable', true)
+ vim.validate('ns_id', ns_id, 'number', true)
+ vim.validate('opts', opts, 'table', true)
+ opts = opts or {}
if ns_id == nil or ns_id == 0 then
ns_id = vim.api.nvim_create_namespace('')
end
- on_key_cbs[ns_id] = fn
+ on_key_cbs[ns_id] = fn and { fn, opts }
return ns_id
end
--- Executes the on_key callbacks.
---@private
function vim._on_key(buf, typed_buf)
- local failed_ns_ids = {}
- local failed_messages = {}
+ local failed = {} ---@type [integer, string][]
+ local discard = false
for k, v in pairs(on_key_cbs) do
- local ok, err_msg = pcall(v, buf, typed_buf)
+ local fn = v[1]
+ local ok, rv = xpcall(function()
+ return fn(buf, typed_buf)
+ end, debug.traceback)
+ if ok and rv ~= nil then
+ if type(rv) == 'string' and #rv == 0 then
+ discard = true
+ -- break -- Without break deliver to all callbacks even when it eventually discards.
+ -- "break" does not make sense unless callbacks are sorted by ???.
+ else
+ ok = false
+ rv = 'return string must be empty'
+ end
+ end
if not ok then
vim.on_key(nil, k)
- table.insert(failed_ns_ids, k)
- table.insert(failed_messages, err_msg)
+ table.insert(failed, { k, rv })
+ end
+ end
+
+ if #failed > 0 then
+ local errmsg = ''
+ for _, v in ipairs(failed) do
+ errmsg = errmsg .. string.format('\nWith ns_id %d: %s', v[1], v[2])
+ end
+ error(errmsg)
+ end
+ return discard
+end
+
+--- Convert UTF-32, UTF-16 or UTF-8 {index} to byte index.
+--- If {strict_indexing} is false
+--- then then an out of range index will return byte length
+--- instead of throwing an error.
+---
+--- Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|.
+--- An {index} in the middle of a UTF-16 sequence is rounded upwards to
+--- the end of that sequence.
+---@param s string
+---@param encoding "utf-8"|"utf-16"|"utf-32"
+---@param index integer
+---@param strict_indexing? boolean # default: true
+---@return integer
+function vim.str_byteindex(s, encoding, index, strict_indexing)
+ if type(encoding) == 'number' then
+ -- Legacy support for old API
+ -- Parameters: ~
+ -- • {str} (`string`)
+ -- • {index} (`integer`)
+ -- • {use_utf16} (`boolean?`)
+ vim.deprecate(
+ 'vim.str_byteindex',
+ 'vim.str_byteindex(s, encoding, index, strict_indexing)',
+ '1.0'
+ )
+ local old_index = encoding
+ local use_utf16 = index or false
+ return vim._str_byteindex(s, old_index, use_utf16) or error('index out of range')
+ end
+
+ -- Avoid vim.validate for performance.
+ if type(s) ~= 'string' or type(index) ~= 'number' then
+ vim.validate('s', s, 'string')
+ vim.validate('index', index, 'number')
+ end
+
+ local len = #s
+
+ if index == 0 or len == 0 then
+ return 0
+ end
+
+ if not utfs[encoding] then
+ vim.validate('encoding', encoding, function(v)
+ return utfs[v], 'invalid encoding'
+ end)
+ end
+
+ if strict_indexing ~= nil and type(strict_indexing) ~= 'boolean' then
+ vim.validate('strict_indexing', strict_indexing, 'boolean', true)
+ end
+ if strict_indexing == nil then
+ strict_indexing = true
+ end
+
+ if encoding == 'utf-8' then
+ if index > len then
+ return strict_indexing and error('index out of range') or len
end
+ return index
end
+ return vim._str_byteindex(s, index, encoding == 'utf-16')
+ or strict_indexing and error('index out of range')
+ or len
+end
- if failed_ns_ids[1] then
- error(
- string.format(
- "Error executing 'on_key' with ns_ids '%s'\n Messages: %s",
- table.concat(failed_ns_ids, ', '),
- table.concat(failed_messages, '\n')
- )
+--- Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If {index} is not
+--- supplied, the length of the string is used. All indices are zero-based.
+---
+--- If {strict_indexing} is false then an out of range index will return string
+--- length instead of throwing an error.
+--- Invalid UTF-8 bytes, and embedded surrogates are counted as one code point
+--- each. An {index} in the middle of a UTF-8 sequence is rounded upwards to the end of
+--- that sequence.
+---@param s string
+---@param encoding "utf-8"|"utf-16"|"utf-32"
+---@param index? integer
+---@param strict_indexing? boolean # default: true
+---@return integer
+function vim.str_utfindex(s, encoding, index, strict_indexing)
+ if encoding == nil or type(encoding) == 'number' then
+ -- Legacy support for old API
+ -- Parameters: ~
+ -- • {str} (`string`)
+ -- • {index} (`integer?`)
+ vim.deprecate(
+ 'vim.str_utfindex',
+ 'vim.str_utfindex(s, encoding, index, strict_indexing)',
+ '1.0'
)
+ local old_index = encoding
+ local col32, col16 = vim._str_utfindex(s, old_index) --[[@as integer,integer]]
+ if not col32 or not col16 then
+ error('index out of range')
+ end
+ -- Return (multiple): ~
+ -- (`integer`) UTF-32 index
+ -- (`integer`) UTF-16 index
+ return col32, col16
+ end
+
+ if type(s) ~= 'string' or (index ~= nil and type(index) ~= 'number') then
+ vim.validate('s', s, 'string')
+ vim.validate('index', index, 'number', true)
+ end
+
+ if not index then
+ index = math.huge
+ strict_indexing = false
+ end
+
+ if index == 0 then
+ return 0
+ end
+
+ if not utfs[encoding] then
+ vim.validate('encoding', encoding, function(v)
+ return utfs[v], 'invalid encoding'
+ end)
end
+
+ if strict_indexing ~= nil and type(strict_indexing) ~= 'boolean' then
+ vim.validate('strict_indexing', strict_indexing, 'boolean', true)
+ end
+ if strict_indexing == nil then
+ strict_indexing = true
+ end
+
+ if encoding == 'utf-8' then
+ local len = #s
+ return index <= len and index or (strict_indexing and error('index out of range') or len)
+ end
+ local col32, col16 = vim._str_utfindex(s, index) --[[@as integer?,integer?]]
+ local col = encoding == 'utf-16' and col16 or col32
+ if col then
+ return col
+ end
+ if strict_indexing then
+ error('index out of range')
+ end
+ local max32, max16 = vim._str_utfindex(s)--[[@as integer integer]]
+ return encoding == 'utf-16' and max16 or max32
end
---- Generates a list of possible completions for the string.
+--- Generates a list of possible completions for the str
--- String has the pattern.
---
--- 1. Can we get it to just return things in the global namespace with that name prefix
@@ -988,21 +1151,16 @@ end
--- @param ... any
--- @return any # given arguments.
function vim.print(...)
- if vim.in_fast_event() then
- print(...)
- return ...
- end
-
+ local msg = {}
for i = 1, select('#', ...) do
local o = select(i, ...)
if type(o) == 'string' then
- vim.api.nvim_out_write(o)
+ table.insert(msg, o)
else
- vim.api.nvim_out_write(vim.inspect(o, { newline = '\n', indent = ' ' }))
+ table.insert(msg, vim.inspect(o, { newline = '\n', indent = ' ' }))
end
- vim.api.nvim_out_write('\n')
end
-
+ print(table.concat(msg, '\n'))
return ...
end
@@ -1146,16 +1304,22 @@ function vim.deprecate(name, alternative, version, plugin, backtrace)
if plugin == 'Nvim' then
require('vim.deprecated.health').add(name, version, traceback(), alternative)
- -- Only issue warning if feature is hard-deprecated as specified by MAINTAIN.md.
- -- Example: if removal_version is 0.12 (soft-deprecated since 0.10-dev), show warnings starting at
- -- 0.11, including 0.11-dev
+ -- Show a warning only if feature is hard-deprecated (see MAINTAIN.md).
+ -- Example: if removal `version` is 0.12 (soft-deprecated since 0.10-dev), show warnings
+ -- starting at 0.11, including 0.11-dev.
local major, minor = version:match('(%d+)%.(%d+)')
major, minor = tonumber(major), tonumber(minor)
+ local nvim_major = 0 --- Current Nvim major version.
+
+ -- We can't "subtract" from a major version, so:
+ -- * Always treat `major > nvim_major` as soft-deprecation.
+ -- * Compare `minor - 1` if `major == nvim_major`.
+ if major > nvim_major then
+ return -- Always soft-deprecation (see MAINTAIN.md).
+ end
local hard_deprecated_since = string.format('nvim-%d.%d', major, minor - 1)
- -- Assume there will be no next minor version before bumping up the major version
- local is_hard_deprecated = minor == 0 or vim.fn.has(hard_deprecated_since) == 1
- if not is_hard_deprecated then
+ if major == nvim_major and vim.fn.has(hard_deprecated_since) == 0 then
return
end
@@ -1166,12 +1330,10 @@ function vim.deprecate(name, alternative, version, plugin, backtrace)
local displayed = vim._truncated_echo_once(msg)
return displayed and msg or nil
else
- vim.validate {
- name = { name, 'string' },
- alternative = { alternative, 'string', true },
- version = { version, 'string', true },
- plugin = { plugin, 'string', true },
- }
+ vim.validate('name', name, 'string')
+ vim.validate('alternative', alternative, 'string', true)
+ vim.validate('version', version, 'string', true)
+ vim.validate('plugin', plugin, 'string', true)
local msg = ('%s is deprecated'):format(name)
msg = alternative and ('%s, use %s instead.'):format(msg, alternative) or (msg .. '.')
@@ -1190,4 +1352,7 @@ require('vim._options')
---@deprecated
vim.loop = vim.uv
+-- Deprecated. Remove at Nvim 2.0
+vim.highlight = vim._defer_deprecated_module('vim.highlight', 'vim.hl')
+
return vim
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index c9f207cb20..f8672d1f1f 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -15,7 +15,7 @@ vim.fs = require('vim.fs')
vim.func = require('vim.func')
vim.glob = require('vim.glob')
vim.health = require('vim.health')
-vim.highlight = require('vim.highlight')
+vim.hl = require('vim.hl')
vim.iter = require('vim.iter')
vim.keymap = require('vim.keymap')
vim.loader = require('vim.loader')
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index c66b295d3a..3c9b9d4f44 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -592,8 +592,9 @@ function vim.api.nvim_buf_line_count(buffer) end
--- - id : id of the extmark to edit.
--- - end_row : ending line of the mark, 0-based inclusive.
--- - end_col : ending col of the mark, 0-based exclusive.
---- - hl_group : name of the highlight group used to highlight
---- this mark.
+--- - hl_group : highlight group used for the text range. This and below
+--- highlight groups can be supplied either as a string or as an integer,
+--- the latter of which can be obtained using `nvim_get_hl_id_by_name()`.
--- - hl_eol : when true, for a multiline highlight covering the
--- EOL of a line, continue the highlight for the rest
--- of the screen line (just like for diff and
@@ -603,9 +604,7 @@ function vim.api.nvim_buf_line_count(buffer) end
--- text chunk with specified highlight. `highlight` element
--- can either be a single highlight group, or an array of
--- multiple highlight groups that will be stacked
---- (highest priority last). A highlight group can be supplied
---- either as a string or as an integer, the latter which
---- can be obtained using `nvim_get_hl_id_by_name()`.
+--- (highest priority last).
--- - virt_text_pos : position of virtual text. Possible values:
--- - "eol": right after eol character (default).
--- - "overlay": display over the specified column, without
@@ -676,15 +675,12 @@ function vim.api.nvim_buf_line_count(buffer) end
--- buffer or end of the line respectively. Defaults to true.
--- - sign_text: string of length 1-2 used to display in the
--- sign column.
---- - sign_hl_group: name of the highlight group used to
---- highlight the sign column text.
---- - number_hl_group: name of the highlight group used to
---- highlight the number column.
---- - line_hl_group: name of the highlight group used to
---- highlight the whole line.
---- - cursorline_hl_group: name of the highlight group used to
---- highlight the sign column text when the cursor is on
---- the same line as the mark and 'cursorline' is enabled.
+--- - sign_hl_group: highlight group used for the sign column text.
+--- - number_hl_group: highlight group used for the number column.
+--- - line_hl_group: highlight group used for the whole line.
+--- - cursorline_hl_group: highlight group used for the sign
+--- column text when the cursor is on the same line as the
+--- mark and 'cursorline' is enabled.
--- - conceal: string which should be either empty or a single
--- character. Enable concealing similar to `:syn-conceal`.
--- When a character is supplied it is used as `:syn-cchar`.
@@ -1106,12 +1102,12 @@ function vim.api.nvim_del_var(name) end
--- Echo a message.
---
--- @param chunks any[] A list of `[text, hl_group]` arrays, each representing a
---- text chunk with specified highlight. `hl_group` element
---- can be omitted for no highlight.
+--- text chunk with specified highlight group name or ID.
+--- `hl_group` element can be omitted for no highlight.
--- @param history boolean if true, add to `message-history`.
--- @param opts vim.api.keyset.echo_opts Optional parameters.
---- - verbose: Message was printed as a result of 'verbose' option
---- if Nvim was invoked with -V3log_file, the message will be
+--- - verbose: Message is printed as a result of 'verbose' option.
+--- If Nvim was invoked with -V3log_file, the message will be
--- redirected to the log_file and suppressed from direct output.
function vim.api.nvim_echo(chunks, history, opts) end
@@ -1767,7 +1763,12 @@ function vim.api.nvim_open_term(buffer, opts) end
--- fractional.
--- - focusable: Enable focus by user actions (wincmds, mouse events).
--- Defaults to true. Non-focusable windows can be entered by
---- `nvim_set_current_win()`.
+--- `nvim_set_current_win()`, or, when the `mouse` field is set to true,
+--- by mouse events. See `focusable`.
+--- - mouse: Specify how this window interacts with mouse events.
+--- Defaults to `focusable` value.
+--- - If false, mouse events pass through this window.
+--- - If true, mouse events interact with this window normally.
--- - external: GUI should display the window as an external
--- top-level window. Currently accepts no other positioning
--- configuration together with this.
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index 2fe5c32faf..bf184dee2d 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -295,6 +295,7 @@ error('Cannot require a meta file')
--- @field bufpos? any[]
--- @field external? boolean
--- @field focusable? boolean
+--- @field mouse? boolean
--- @field vertical? boolean
--- @field zindex? integer
--- @field border? any
diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua
index 13bd1c1294..b8779b66fe 100644
--- a/runtime/lua/vim/_meta/builtin.lua
+++ b/runtime/lua/vim/_meta/builtin.lua
@@ -112,18 +112,6 @@ function vim.rpcrequest(channel, method, ...) end
--- equal, {a} is greater than {b} or {a} is lesser than {b}, respectively.
function vim.stricmp(a, b) end
---- Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
---- supplied, it defaults to false (use UTF-32). Returns the byte index.
----
---- Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|.
---- An {index} in the middle of a UTF-16 sequence is rounded upwards to
---- the end of that sequence.
---- @param str string
---- @param index integer
---- @param use_utf16? boolean
---- @return integer
-function vim.str_byteindex(str, index, use_utf16) end
-
--- Gets a list of the starting byte positions of each UTF-8 codepoint in the given string.
---
--- Embedded NUL bytes are treated as terminating the string.
@@ -173,19 +161,6 @@ function vim.str_utf_start(str, index) end
--- @return integer
function vim.str_utf_end(str, index) end
---- Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
---- supplied, the length of the string is used. All indices are zero-based.
----
---- Embedded NUL bytes are treated as terminating the string. Invalid UTF-8
---- bytes, and embedded surrogates are counted as one code point each. An
---- {index} in the middle of a UTF-8 sequence is rounded upwards to the end of
---- that sequence.
---- @param str string
---- @param index? integer
---- @return integer # UTF-32 index
---- @return integer # UTF-16 index
-function vim.str_utfindex(str, index) end
-
--- The result is a String, which is the text {str} converted from
--- encoding {from} to encoding {to}. When the conversion fails `nil` is
--- returned. When some characters could not be converted they
@@ -258,6 +233,12 @@ function vim.wait(time, callback, interval, fast_only) end
--- {callback} receives event name plus additional parameters. See |ui-popupmenu|
--- and the sections below for event format for respective events.
---
+--- Callbacks for `msg_show` events are executed in |api-fast| context unless
+--- Nvim will wait for input, in which case messages should be shown
+--- immediately.
+---
+--- Excessive errors inside the callback will result in forced detachment.
+---
--- WARNING: This api is considered experimental. Usability will vary for
--- different screen elements. In particular `ext_messages` behavior is subject
--- to further changes and usability improvements. This is expected to be
diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua
index aca6649957..eae76d80d7 100644
--- a/runtime/lua/vim/_meta/builtin_types.lua
+++ b/runtime/lua/vim/_meta/builtin_types.lua
@@ -66,6 +66,97 @@
--- @field winnr integer
--- @field winrow integer
+--- @class vim.quickfix.entry
+--- buffer number; must be the number of a valid buffer
+--- @field bufnr? integer
+---
+--- name of a file; only used when "bufnr" is not
+--- present or it is invalid.
+--- @field filename? string
+---
+--- name of a module; if given it will be used in
+--- quickfix error window instead of the filename.
+--- @field module? string
+---
+--- line number in the file
+--- @field lnum? integer
+---
+--- end of lines, if the item spans multiple lines
+--- @field end_lnum? integer
+---
+--- search pattern used to locate the error
+--- @field pattern? string
+---
+--- column number
+--- @field col? integer
+---
+--- when non-zero: "col" is visual column
+--- when zero: "col" is byte index
+--- @field vcol? integer
+---
+--- end column, if the item spans multiple columns
+--- @field end_col? integer
+---
+--- error number
+--- @field nr? integer
+---
+--- description of the error
+--- @field text? string
+---
+--- single-character error type, 'E', 'W', etc.
+--- @field type? string
+---
+--- recognized error message
+--- @field valid? boolean
+---
+--- custom data associated with the item, can be
+--- any type.
+--- @field user_data? any
+
+--- @class vim.fn.setqflist.what
+---
+--- quickfix list context. See |quickfix-context|
+--- @field context? table
+---
+--- errorformat to use when parsing text from
+--- "lines". If this is not present, then the
+--- 'errorformat' option value is used.
+--- See |quickfix-parse|
+--- @field efm? string
+---
+--- quickfix list identifier |quickfix-ID|
+--- @field id? integer
+--- index of the current entry in the quickfix
+--- list specified by "id" or "nr". If set to '$',
+--- then the last entry in the list is set as the
+--- current entry. See |quickfix-index|
+--- @field idx? integer
+---
+--- list of quickfix entries. Same as the {list}
+--- argument.
+--- @field items? vim.quickfix.entry[]
+---
+--- use 'errorformat' to parse a list of lines and
+--- add the resulting entries to the quickfix list
+--- {nr} or {id}. Only a |List| value is supported.
+--- See |quickfix-parse|
+--- @field lines? string[]
+---
+--- list number in the quickfix stack; zero
+--- means the current quickfix list and "$" means
+--- the last quickfix list.
+--- @field nr? integer
+---
+--- function to get the text to display in the
+--- quickfix window. The value can be the name of
+--- a function or a funcref or a lambda. Refer
+--- to |quickfix-window-function| for an explanation
+--- of how to write the function and an example.
+--- @field quickfixtextfunc? function
+---
+--- quickfix list title text. See |quickfix-title|
+--- @field title? string
+
--- @class vim.fn.sign_define.dict
--- @field text string
--- @field icon? string
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index ce3ff4f861..cb783720ac 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -289,12 +289,13 @@ vim.go.bk = vim.go.backup
--- useful for example in source trees where all the files are symbolic or
--- hard links and any changes should stay in the local source tree, not
--- be propagated back to the original source.
---- *crontab*
+--- *crontab*
--- One situation where "no" and "auto" will cause problems: A program
--- that opens a file, invokes Vim to edit that file, and then tests if
--- the open file was changed (through the file descriptor) will check the
--- backup file instead of the newly created file. "crontab -e" is an
---- example.
+--- example, as are several `file-watcher` daemons like inotify. In that
+--- case you probably want to switch this option.
---
--- When a copy is made, the original file is truncated and then filled
--- with the new text. This means that protection bits, owner and
@@ -429,6 +430,7 @@ vim.go.bsk = vim.go.backupskip
--- separated list of items. For each item that is present, the bell
--- will be silenced. This is most useful to specify specific events in
--- insert mode to be silenced.
+--- You can also make it flash by using 'visualbell'.
---
--- item meaning when present ~
--- all All events.
@@ -452,6 +454,7 @@ vim.go.bsk = vim.go.backupskip
--- register Unknown register after <C-R> in `Insert-mode`.
--- shell Bell from shell output `:!`.
--- spell Error happened on spell suggest.
+--- term Bell from `:terminal` output.
--- wildmode More matches in `cmdline-completion` available
--- (depends on the 'wildmode' setting).
---
@@ -572,19 +575,6 @@ vim.o.briopt = vim.o.breakindentopt
vim.wo.breakindentopt = vim.o.breakindentopt
vim.wo.briopt = vim.wo.breakindentopt
---- Which directory to use for the file browser:
---- last Use same directory as with last file browser, where a
---- file was opened or saved.
---- buffer Use the directory of the related buffer.
---- current Use the current directory.
---- {path} Use the specified directory
----
---- @type string
-vim.o.browsedir = ""
-vim.o.bsdir = vim.o.browsedir
-vim.go.browsedir = vim.o.browsedir
-vim.go.bsdir = vim.go.browsedir
-
--- This option specifies what happens when a buffer is no longer
--- displayed in a window:
--- <empty> follow the global 'hidden' option
@@ -1116,7 +1106,7 @@ vim.bo.cot = vim.bo.completeopt
vim.go.completeopt = vim.o.completeopt
vim.go.cot = vim.go.completeopt
---- only for MS-Windows
+--- only modifiable in MS-Windows
--- When this option is set it overrules 'shellslash' for completion:
--- - When this option is set to "slash", a forward slash is used for path
--- completion in insert mode. This is useful when editing HTML tag, or
@@ -2304,6 +2294,62 @@ vim.wo.fcs = vim.wo.fillchars
vim.go.fillchars = vim.o.fillchars
vim.go.fcs = vim.go.fillchars
+--- Function that is called to obtain the filename(s) for the `:find`
+--- command. When this option is empty, the internal `file-searching`
+--- mechanism is used.
+---
+--- The value can be the name of a function, a `lambda` or a `Funcref`.
+--- See `option-value-function` for more information.
+---
+--- The function is called with two arguments. The first argument is a
+--- `String` and is the `:find` command argument. The second argument is
+--- a `Boolean` and is set to `v:true` when the function is called to get
+--- a List of command-line completion matches for the `:find` command.
+--- The function should return a List of strings.
+---
+--- The function is called only once per `:find` command invocation.
+--- The function can process all the directories specified in 'path'.
+---
+--- If a match is found, the function should return a `List` containing
+--- one or more file names. If a match is not found, the function
+--- should return an empty List.
+---
+--- If any errors are encountered during the function invocation, an
+--- empty List is used as the return value.
+---
+--- It is not allowed to change text or jump to another window while
+--- executing the 'findfunc' `textlock`.
+---
+--- This option cannot be set from a `modeline` or in the `sandbox`, for
+--- security reasons.
+---
+--- Examples:
+---
+--- ```vim
+--- " Use glob()
+--- func FindFuncGlob(cmdarg, cmdcomplete)
+--- let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
+--- return glob(pat, v:false, v:true)
+--- endfunc
+--- set findfunc=FindFuncGlob
+---
+--- " Use the 'git ls-files' output
+--- func FindGitFiles(cmdarg, cmdcomplete)
+--- let fnames = systemlist('git ls-files')
+--- return fnames->filter('v:val =~? a:cmdarg')
+--- endfunc
+--- set findfunc=FindGitFiles
+--- ```
+---
+---
+--- @type string
+vim.o.findfunc = ""
+vim.o.ffu = vim.o.findfunc
+vim.bo.findfunc = vim.o.findfunc
+vim.bo.ffu = vim.bo.findfunc
+vim.go.findfunc = vim.o.findfunc
+vim.go.ffu = vim.go.findfunc
+
--- When writing a file and this option is on, <EOL> at the end of file
--- will be restored if missing. Turn this option off if you want to
--- preserve the situation from the original file.
@@ -2897,148 +2943,6 @@ vim.o.gfw = vim.o.guifontwide
vim.go.guifontwide = vim.o.guifontwide
vim.go.gfw = vim.go.guifontwide
---- This option only has an effect in the GUI version of Vim. It is a
---- sequence of letters which describes what components and options of the
---- GUI should be used.
---- To avoid problems with flags that are added in the future, use the
---- "+=" and "-=" feature of ":set" `add-option-flags`.
----
---- Valid letters are as follows:
---- *guioptions_a* *'go-a'*
---- 'a' Autoselect: If present, then whenever VISUAL mode is started,
---- or the Visual area extended, Vim tries to become the owner of
---- the windowing system's global selection. This means that the
---- Visually highlighted text is available for pasting into other
---- applications as well as into Vim itself. When the Visual mode
---- ends, possibly due to an operation on the text, or when an
---- application wants to paste the selection, the highlighted text
---- is automatically yanked into the "* selection register.
---- Thus the selection is still available for pasting into other
---- applications after the VISUAL mode has ended.
---- If not present, then Vim won't become the owner of the
---- windowing system's global selection unless explicitly told to
---- by a yank or delete operation for the "* register.
---- The same applies to the modeless selection.
---- *'go-P'*
---- 'P' Like autoselect but using the "+ register instead of the "*
---- register.
---- *'go-A'*
---- 'A' Autoselect for the modeless selection. Like 'a', but only
---- applies to the modeless selection.
----
---- 'guioptions' autoselect Visual autoselect modeless ~
---- "" - -
---- "a" yes yes
---- "A" - yes
---- "aA" yes yes
----
---- *'go-c'*
---- 'c' Use console dialogs instead of popup dialogs for simple
---- choices.
---- *'go-d'*
---- 'd' Use dark theme variant if available.
---- *'go-e'*
---- 'e' Add tab pages when indicated with 'showtabline'.
---- 'guitablabel' can be used to change the text in the labels.
---- When 'e' is missing a non-GUI tab pages line may be used.
---- The GUI tabs are only supported on some systems, currently
---- Mac OS/X and MS-Windows.
---- *'go-i'*
---- 'i' Use a Vim icon.
---- *'go-m'*
---- 'm' Menu bar is present.
---- *'go-M'*
---- 'M' The system menu "$VIMRUNTIME/menu.vim" is not sourced. Note
---- that this flag must be added in the vimrc file, before
---- switching on syntax or filetype recognition (when the `gvimrc`
---- file is sourced the system menu has already been loaded; the
---- `:syntax on` and `:filetype on` commands load the menu too).
---- *'go-g'*
---- 'g' Grey menu items: Make menu items that are not active grey. If
---- 'g' is not included inactive menu items are not shown at all.
---- *'go-T'*
---- 'T' Include Toolbar. Currently only in Win32 GUI.
---- *'go-r'*
---- 'r' Right-hand scrollbar is always present.
---- *'go-R'*
---- 'R' Right-hand scrollbar is present when there is a vertically
---- split window.
---- *'go-l'*
---- 'l' Left-hand scrollbar is always present.
---- *'go-L'*
---- 'L' Left-hand scrollbar is present when there is a vertically
---- split window.
---- *'go-b'*
---- 'b' Bottom (horizontal) scrollbar is present. Its size depends on
---- the longest visible line, or on the cursor line if the 'h'
---- flag is included. `gui-horiz-scroll`
---- *'go-h'*
---- 'h' Limit horizontal scrollbar size to the length of the cursor
---- line. Reduces computations. `gui-horiz-scroll`
----
---- And yes, you may even have scrollbars on the left AND the right if
---- you really want to :-). See `gui-scrollbars` for more information.
----
---- *'go-v'*
---- 'v' Use a vertical button layout for dialogs. When not included,
---- a horizontal layout is preferred, but when it doesn't fit a
---- vertical layout is used anyway. Not supported in GTK 3.
---- *'go-p'*
---- 'p' Use Pointer callbacks for X11 GUI. This is required for some
---- window managers. If the cursor is not blinking or hollow at
---- the right moment, try adding this flag. This must be done
---- before starting the GUI. Set it in your `gvimrc`. Adding or
---- removing it after the GUI has started has no effect.
---- *'go-k'*
---- 'k' Keep the GUI window size when adding/removing a scrollbar, or
---- toolbar, tabline, etc. Instead, the behavior is similar to
---- when the window is maximized and will adjust 'lines' and
---- 'columns' to fit to the window. Without the 'k' flag Vim will
---- try to keep 'lines' and 'columns' the same when adding and
---- removing GUI components.
----
---- @type string
-vim.o.guioptions = ""
-vim.o.go = vim.o.guioptions
-vim.go.guioptions = vim.o.guioptions
-vim.go.go = vim.go.guioptions
-
---- When non-empty describes the text to use in a label of the GUI tab
---- pages line. When empty and when the result is empty Vim will use a
---- default label. See `setting-guitablabel` for more info.
----
---- The format of this option is like that of 'statusline'.
---- 'guitabtooltip' is used for the tooltip, see below.
---- The expression will be evaluated in the `sandbox` when set from a
---- modeline, see `sandbox-option`.
---- This option cannot be set in a modeline when 'modelineexpr' is off.
----
---- Only used when the GUI tab pages line is displayed. 'e' must be
---- present in 'guioptions'. For the non-GUI tab pages line 'tabline' is
---- used.
----
---- @type string
-vim.o.guitablabel = ""
-vim.o.gtl = vim.o.guitablabel
-vim.go.guitablabel = vim.o.guitablabel
-vim.go.gtl = vim.go.guitablabel
-
---- When non-empty describes the text to use in a tooltip for the GUI tab
---- pages line. When empty Vim will use a default tooltip.
---- This option is otherwise just like 'guitablabel' above.
---- You can include a line break. Simplest method is to use `:let`:
----
---- ```vim
---- let &guitabtooltip = "line one\nline two"
---- ```
----
----
---- @type string
-vim.o.guitabtooltip = ""
-vim.o.gtt = vim.o.guitabtooltip
-vim.go.guitabtooltip = vim.o.guitabtooltip
-vim.go.gtt = vim.go.guitabtooltip
-
--- Name of the main help file. All distributed help files should be
--- placed together in one directory. Additionally, all "doc" directories
--- in 'runtimepath' will be used.
@@ -3112,7 +3016,8 @@ vim.go.hid = vim.go.hidden
--- A history of ":" commands, and a history of previous search patterns
--- is remembered. This option decides how many entries may be stored in
---- each of these histories (see `cmdline-editing`).
+--- each of these histories (see `cmdline-editing` and 'msghistory' for
+--- the number of messages to remember).
--- The maximum value is 10000.
---
--- @type integer
@@ -3181,29 +3086,6 @@ vim.o.ic = vim.o.ignorecase
vim.go.ignorecase = vim.o.ignorecase
vim.go.ic = vim.go.ignorecase
---- When set the Input Method is always on when starting to edit a command
---- line, unless entering a search pattern (see 'imsearch' for that).
---- Setting this option is useful when your input method allows entering
---- English characters directly, e.g., when it's used to type accented
---- characters with dead keys.
----
---- @type boolean
-vim.o.imcmdline = false
-vim.o.imc = vim.o.imcmdline
-vim.go.imcmdline = vim.o.imcmdline
-vim.go.imc = vim.go.imcmdline
-
---- When set the Input Method is never used. This is useful to disable
---- the IM when it doesn't work properly.
---- Currently this option is on by default for SGI/IRIX machines. This
---- may change in later releases.
----
---- @type boolean
-vim.o.imdisable = false
-vim.o.imd = vim.o.imdisable
-vim.go.imdisable = vim.o.imdisable
-vim.go.imd = vim.go.imdisable
-
--- Specifies whether :lmap or an Input Method (IM) is to be used in
--- Insert mode. Valid values:
--- 0 :lmap is off and IM is off
@@ -4488,74 +4370,6 @@ vim.go.mousemev = vim.go.mousemoveevent
vim.o.mousescroll = "ver:3,hor:6"
vim.go.mousescroll = vim.o.mousescroll
---- This option tells Vim what the mouse pointer should look like in
---- different modes. The option is a comma-separated list of parts, much
---- like used for 'guicursor'. Each part consist of a mode/location-list
---- and an argument-list:
---- mode-list:shape,mode-list:shape,..
---- The mode-list is a dash separated list of these modes/locations:
---- In a normal window: ~
---- n Normal mode
---- v Visual mode
---- ve Visual mode with 'selection' "exclusive" (same as 'v',
---- if not specified)
---- o Operator-pending mode
---- i Insert mode
---- r Replace mode
----
---- Others: ~
---- c appending to the command-line
---- ci inserting in the command-line
---- cr replacing in the command-line
---- m at the 'Hit ENTER' or 'More' prompts
---- ml idem, but cursor in the last line
---- e any mode, pointer below last window
---- s any mode, pointer on a status line
---- sd any mode, while dragging a status line
---- vs any mode, pointer on a vertical separator line
---- vd any mode, while dragging a vertical separator line
---- a everywhere
----
---- The shape is one of the following:
---- avail name looks like ~
---- w x arrow Normal mouse pointer
---- w x blank no pointer at all (use with care!)
---- w x beam I-beam
---- w x updown up-down sizing arrows
---- w x leftright left-right sizing arrows
---- w x busy The system's usual busy pointer
---- w x no The system's usual "no input" pointer
---- x udsizing indicates up-down resizing
---- x lrsizing indicates left-right resizing
---- x crosshair like a big thin +
---- x hand1 black hand
---- x hand2 white hand
---- x pencil what you write with
---- x question big ?
---- x rightup-arrow arrow pointing right-up
---- w x up-arrow arrow pointing up
---- x <number> any X11 pointer number (see X11/cursorfont.h)
----
---- The "avail" column contains a 'w' if the shape is available for Win32,
---- x for X11.
---- Any modes not specified or shapes not available use the normal mouse
---- pointer.
----
---- Example:
----
---- ```vim
---- set mouseshape=s:udsizing,m:no
---- ```
---- will make the mouse turn to a sizing arrow over the status lines and
---- indicate no input when the hit-enter prompt is displayed (since
---- clicking the mouse has no effect in this state.)
----
---- @type string
-vim.o.mouseshape = ""
-vim.o.mouses = vim.o.mouseshape
-vim.go.mouseshape = vim.o.mouseshape
-vim.go.mouses = vim.go.mouseshape
-
--- Defines the maximum time in msec between two mouse clicks for the
--- second click to be recognized as a multi click.
---
@@ -4565,6 +4379,15 @@ vim.o.mouset = vim.o.mousetime
vim.go.mousetime = vim.o.mousetime
vim.go.mouset = vim.go.mousetime
+--- Determines how many entries are remembered in the `:messages` history.
+--- The maximum value is 10000.
+---
+--- @type integer
+vim.o.msghistory = 500
+vim.o.mhi = vim.o.msghistory
+vim.go.msghistory = vim.o.msghistory
+vim.go.mhi = vim.go.msghistory
+
--- This defines what bases Vim will consider for numbers when using the
--- CTRL-A and CTRL-X commands for adding to and subtracting from a number
--- respectively; see `CTRL-A` for more info on these commands.
@@ -4675,19 +4498,6 @@ vim.o.ofu = vim.o.omnifunc
vim.bo.omnifunc = vim.o.omnifunc
vim.bo.ofu = vim.bo.omnifunc
---- only for Windows
---- Enable reading and writing from devices. This may get Vim stuck on a
---- device that can be opened but doesn't actually do the I/O. Therefore
---- it is off by default.
---- Note that on Windows editing "aux.h", "lpt1.txt" and the like also
---- result in editing a device.
----
---- @type boolean
-vim.o.opendevice = false
-vim.o.odev = vim.o.opendevice
-vim.go.opendevice = vim.o.opendevice
-vim.go.odev = vim.go.opendevice
-
--- This option specifies a function to be called by the `g@` operator.
--- See `:map-operator` for more info and an example. The value can be
--- the name of a function, a `lambda` or a `Funcref`. See
@@ -5634,7 +5444,7 @@ vim.go.sdf = vim.go.shadafile
---
--- ```vim
--- let &shell = executable('pwsh') ? 'pwsh' : 'powershell'
---- let &shellcmdflag = '-NoLogo -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
+--- let &shellcmdflag = '-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';$PSStyle.OutputRendering=''plaintext'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
--- let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode'
--- let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode'
--- set shellquote= shellxquote=
@@ -5747,7 +5557,7 @@ vim.o.srr = vim.o.shellredir
vim.go.shellredir = vim.o.shellredir
vim.go.srr = vim.go.shellredir
---- only for MS-Windows
+--- only modifiable in MS-Windows
--- When set, a forward slash is used when expanding file names. This is
--- useful when a Unix-like shell is used instead of cmd.exe. Backward
--- slashes can still be typed, but they are changed to forward slashes by
@@ -5764,7 +5574,7 @@ vim.go.srr = vim.go.shellredir
--- Also see 'completeslash'.
---
--- @type boolean
-vim.o.shellslash = false
+vim.o.shellslash = true
vim.o.ssl = vim.o.shellslash
vim.go.shellslash = vim.o.shellslash
vim.go.ssl = vim.go.shellslash
@@ -6695,7 +6505,7 @@ vim.wo.stc = vim.wo.statuscolumn
--- Emulate standard status line with 'ruler' set
---
--- ```vim
---- set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+--- set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P
--- ```
--- Similar, but add ASCII value of char under the cursor (like "ga")
---
@@ -7309,7 +7119,9 @@ vim.go.titleold = vim.o.titleold
--- window. This happens only when the 'title' option is on.
---
--- When this option contains printf-style '%' items, they will be
---- expanded according to the rules used for 'statusline'.
+--- expanded according to the rules used for 'statusline'. If it contains
+--- an invalid '%' format, the value is used as-is and no error or warning
+--- will be given when the value is set.
--- This option cannot be set in a modeline when 'modelineexpr' is off.
---
--- Example:
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 3f6deba092..5eb15e1eee 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -221,16 +221,16 @@ function vim.fn.assert_beeps(cmd) end
--- @return 0|1
function vim.fn.assert_equal(expected, actual, msg) end
---- When the files {fname-one} and {fname-two} do not contain
+--- When the files {fname_one} and {fname_two} do not contain
--- exactly the same text an error message is added to |v:errors|.
--- Also see |assert-return|.
---- When {fname-one} or {fname-two} does not exist the error will
+--- When {fname_one} or {fname_two} does not exist the error will
--- mention that.
---
---- @param fname-one string
---- @param fname-two string
+--- @param fname_one string
+--- @param fname_two string
--- @return 0|1
-function vim.fn.assert_equalfile(fname-one, fname-two) end
+function vim.fn.assert_equalfile(fname_one, fname_two) end
--- When v:exception does not contain the string {error} an error
--- message is added to |v:errors|. Also see |assert-return|.
@@ -809,7 +809,7 @@ function vim.fn.char2nr(string, utf8) end
--- The character class is one of:
--- 0 blank
--- 1 punctuation
---- 2 word character
+--- 2 word character (depends on 'iskeyword')
--- 3 emoji
--- other specific Unicode class
--- The class is used in patterns and word motions.
@@ -828,7 +828,7 @@ function vim.fn.charclass(string) end
--- echo col('.') " returns 7
--- <
---
---- @param expr string|integer[]
+--- @param expr string|any[]
--- @param winid? integer
--- @return integer
function vim.fn.charcol(expr, winid) end
@@ -956,7 +956,7 @@ function vim.fn.clearmatches(win) end
--- imap <F2> <Cmd>echo col(".").."\n"<CR>
--- <
---
---- @param expr string|integer[]
+--- @param expr string|any[]
--- @param winid? integer
--- @return integer
function vim.fn.col(expr, winid) end
@@ -2879,12 +2879,22 @@ function vim.fn.getcharsearch() end
--- @return string
function vim.fn.getcharstr(expr) end
+--- Return completion pattern of the current command-line.
+--- Only works when the command line is being edited, thus
+--- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
+--- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
+--- |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|.
+--- Returns an empty string when completion is not defined.
+---
+--- @return string
+function vim.fn.getcmdcomplpat() end
+
--- Return the type of the current command-line completion.
--- Only works when the command line is being edited, thus
--- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
--- See |:command-completion| for the return string.
--- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
---- |getcmdprompt()| and |setcmdline()|.
+--- |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|.
--- Returns an empty string when completion is not defined.
---
--- @return string
@@ -2998,6 +3008,7 @@ function vim.fn.getcmdwintype() end
--- runtime |:runtime| completion
--- scriptnames sourced script names |:scriptnames|
--- shellcmd Shell command
+--- shellcmdline Shell command line with filename arguments
--- sign |:sign| suboptions
--- syntax syntax file names |'syntax'|
--- syntime |:syntime| suboptions
@@ -5181,7 +5192,7 @@ function vim.fn.log(expr) end
function vim.fn.log10(expr) end
--- {expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
---- When {expr1} is a |List|| or |Dictionary|, replace each
+--- When {expr1} is a |List| or |Dictionary|, replace each
--- item in {expr1} with the result of evaluating {expr2}.
--- For a |Blob| each byte is replaced.
--- For a |String|, each character, including composing
@@ -7912,7 +7923,7 @@ function vim.fn.setbufvar(buf, varname, val) end
--- To clear the overrides pass an empty {list}: >vim
--- call setcellwidths([])
---
---- <You can use the script $VIMRUNTIME/tools/emoji_list.lua to see
+--- <You can use the script $VIMRUNTIME/scripts/emoji_list.lua to see
--- the effect for known emoji characters. Move the cursor
--- through the text to check if the cell widths of your terminal
--- match with what Vim knows about each emoji. If it doesn't
@@ -8218,6 +8229,8 @@ function vim.fn.setpos(expr, list) end
--- clear the list: >vim
--- call setqflist([], 'r')
--- <
+--- 'u' Like 'r', but tries to preserve the current selection
+--- in the quickfix list.
--- 'f' All the quickfix lists in the quickfix stack are
--- freed.
---
@@ -8273,9 +8286,9 @@ function vim.fn.setpos(expr, list) end
--- independent of the 'errorformat' setting. Use a command like
--- `:cc 1` to jump to the first position.
---
---- @param list any[]
+--- @param list vim.quickfix.entry[]
--- @param action? string
---- @param what? table
+--- @param what? vim.fn.setqflist.what
--- @return any
function vim.fn.setqflist(list, action, what) end
@@ -10533,7 +10546,7 @@ function vim.fn.values(dict) end
--- echo max(map(range(1, line('$')), "virtcol([v:val, '$'])"))
--- <
---
---- @param expr string|integer[]
+--- @param expr string|any[]
--- @param list? boolean
--- @param winid? integer
--- @return any
@@ -10616,7 +10629,7 @@ function vim.fn.wait(timeout, condition, interval) end
--- For example to make <c-j> work like <down> in wildmode, use: >vim
--- cnoremap <expr> <C-j> wildmenumode() ? "\<Down>\<Tab>" : "\<c-j>"
--- <
---- (Note, this needs the 'wildcharm' option set appropriately).
+--- (Note: this needs the 'wildcharm' option set appropriately).
---
--- @return any
function vim.fn.wildmenumode() end
diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua
index e00402ab3f..8784fdbac9 100644
--- a/runtime/lua/vim/_meta/vvars.lua
+++ b/runtime/lua/vim/_meta/vvars.lua
@@ -160,13 +160,14 @@ vim.v.errors = ...
--- an aborting condition (e.g. `c_Esc` or
--- `c_CTRL-C` for `CmdlineLeave`).
--- chan `channel-id`
+--- info Dict of arbitrary event data.
--- cmdlevel Level of cmdline.
--- cmdtype Type of cmdline, `cmdline-char`.
--- cwd Current working directory.
--- inclusive Motion is `inclusive`, else exclusive.
--- scope Event-specific scope name.
--- operator Current `operator`. Also set for Ex
---- commands (unlike `v:operator`). For
+--- commands (unlike `v:operator`). For
--- example if `TextYankPost` is triggered
--- by the `:yank` Ex command then
--- `v:event.operator` is "y".
diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua
index a61fa61256..77d7054626 100644
--- a/runtime/lua/vim/_options.lua
+++ b/runtime/lua/vim/_options.lua
@@ -274,11 +274,9 @@ vim.go = setmetatable({}, {
})
--- Get or set buffer-scoped |options| for the buffer with number {bufnr}.
---- If {bufnr} is omitted then the current buffer is used.
+--- Like `:setlocal`. If {bufnr} is omitted then the current buffer is used.
--- Invalid {bufnr} or key is an error.
---
---- Note: this is equivalent to `:setlocal` for |global-local| options and `:set` otherwise.
----
--- Example:
---
--- ```lua
diff --git a/runtime/lua/vim/_system.lua b/runtime/lua/vim/_system.lua
index d603971495..ce5dbffeaa 100644
--- a/runtime/lua/vim/_system.lua
+++ b/runtime/lua/vim/_system.lua
@@ -230,6 +230,8 @@ local function default_handler(stream, text, bucket)
end
end
+local is_win = vim.fn.has('win32') == 1
+
local M = {}
--- @param cmd string
@@ -238,6 +240,13 @@ local M = {}
--- @param on_error fun()
--- @return uv.uv_process_t, integer
local function spawn(cmd, opts, on_exit, on_error)
+ if is_win then
+ local cmd1 = vim.fn.exepath(cmd)
+ if cmd1 ~= '' then
+ cmd = cmd1
+ end
+ end
+
local handle, pid_or_err = uv.spawn(cmd, opts, on_exit)
if not handle then
on_error()
@@ -309,11 +318,9 @@ end
--- @param on_exit? fun(out: vim.SystemCompleted)
--- @return vim.SystemObj
function M.run(cmd, opts, on_exit)
- vim.validate({
- cmd = { cmd, 'table' },
- opts = { opts, 'table', true },
- on_exit = { on_exit, 'function', true },
- })
+ vim.validate('cmd', cmd, 'table')
+ vim.validate('opts', opts, 'table', true)
+ vim.validate('on_exit', on_exit, 'function', true)
opts = opts or {}
diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua
index 11f6742941..13894c6147 100644
--- a/runtime/lua/vim/_watch.lua
+++ b/runtime/lua/vim/_watch.lua
@@ -59,11 +59,9 @@ end
--- @param callback vim._watch.Callback Callback for new events
--- @return fun() cancel Stops the watcher
function M.watch(path, opts, callback)
- vim.validate({
- path = { path, 'string', false },
- opts = { opts, 'table', true },
- callback = { callback, 'function', false },
- })
+ vim.validate('path', path, 'string')
+ vim.validate('opts', opts, 'table', true)
+ vim.validate('callback', callback, 'function')
opts = opts or {}
@@ -127,11 +125,9 @@ end
--- @param callback vim._watch.Callback Callback for new events
--- @return fun() cancel Stops the watcher
function M.watchdirs(path, opts, callback)
- vim.validate({
- path = { path, 'string', false },
- opts = { opts, 'table', true },
- callback = { callback, 'function', false },
- })
+ vim.validate('path', path, 'string')
+ vim.validate('opts', opts, 'table', true)
+ vim.validate('callback', callback, 'function')
opts = opts or {}
local debounce = opts.debounce or 500
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index ef00a1fa51..4fb8c6a686 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -71,9 +71,9 @@ local M = {}
--- (default: `false`)
--- @field update_in_insert? boolean
---
---- Sort diagnostics by severity. This affects the order in which signs and
---- virtual text are displayed. When true, higher severities are displayed
---- before lower severities (e.g. ERROR is displayed before WARN).
+--- Sort diagnostics by severity. This affects the order in which signs,
+--- virtual text, and highlights are displayed. When true, higher severities are
+--- displayed before lower severities (e.g. ERROR is displayed before WARN).
--- Options:
--- - {reverse}? (boolean) Reverse sort order
--- (default: `false`)
@@ -282,6 +282,11 @@ M.severity = {
[2] = 'WARN',
[3] = 'INFO',
[4] = 'HINT',
+ --- Mappings from qflist/loclist error types to severities
+ E = 1,
+ W = 2,
+ I = 3,
+ N = 4,
}
--- @alias vim.diagnostic.SeverityInt 1|2|3|4
@@ -289,12 +294,6 @@ M.severity = {
--- See |diagnostic-severity| and |vim.diagnostic.get()|
--- @alias vim.diagnostic.SeverityFilter vim.diagnostic.Severity|vim.diagnostic.Severity[]|{min:vim.diagnostic.Severity,max:vim.diagnostic.Severity}
--- Mappings from qflist/loclist error types to severities
-M.severity.E = M.severity.ERROR
-M.severity.W = M.severity.WARN
-M.severity.I = M.severity.INFO
-M.severity.N = M.severity.HINT
-
--- @type vim.diagnostic.Opts
local global_diagnostic_options = {
signs = true,
@@ -320,7 +319,7 @@ local global_diagnostic_options = {
--- @type table<string,vim.diagnostic.Handler>
M.handlers = setmetatable({}, {
__newindex = function(t, name, handler)
- vim.validate({ handler = { handler, 't' } })
+ vim.validate('handler', handler, 'table')
rawset(t, name, handler)
if global_diagnostic_options[name] == nil then
global_diagnostic_options[name] = true
@@ -477,10 +476,8 @@ end
--- @param diagnostics vim.Diagnostic[]
--- @return vim.Diagnostic[]
local function reformat_diagnostics(format, diagnostics)
- vim.validate({
- format = { format, 'f' },
- diagnostics = { diagnostics, 't' },
- })
+ vim.validate('format', format, 'function')
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
local formatted = vim.deepcopy(diagnostics, true)
for _, diagnostic in ipairs(formatted) do
@@ -659,6 +656,28 @@ local function save_extmarks(namespace, bufnr)
api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true })
end
+--- Create a function that converts a diagnostic severity to an extmark priority.
+--- @param priority integer Base priority
+--- @param opts vim.diagnostic.OptsResolved
+--- @return fun(severity: vim.diagnostic.Severity): integer
+local function severity_to_extmark_priority(priority, opts)
+ if opts.severity_sort then
+ if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then
+ return function(severity)
+ return priority + (severity - vim.diagnostic.severity.ERROR)
+ end
+ end
+
+ return function(severity)
+ return priority + (vim.diagnostic.severity.HINT - severity)
+ end
+ end
+
+ return function()
+ return priority
+ end
+end
+
--- @type table<string,true>
local registered_autocmds = {}
@@ -871,14 +890,14 @@ local function next_diagnostic(search_forward, opts)
if opts.win_id then
vim.deprecate('opts.win_id', 'opts.winid', '0.13')
opts.winid = opts.win_id
- opts.win_id = nil
+ opts.win_id = nil --- @diagnostic disable-line
end
-- Support deprecated cursor_position alias
if opts.cursor_position then
vim.deprecate('opts.cursor_position', 'opts.pos', '0.13')
opts.pos = opts.cursor_position
- opts.cursor_position = nil
+ opts.cursor_position = nil --- @diagnostic disable-line
end
local winid = opts.winid or api.nvim_get_current_win()
@@ -959,7 +978,7 @@ local function goto_diagnostic(diagnostic, opts)
if opts.win_id then
vim.deprecate('opts.win_id', 'opts.winid', '0.13')
opts.winid = opts.win_id
- opts.win_id = nil
+ opts.win_id = nil --- @diagnostic disable-line
end
local winid = opts.winid or api.nvim_get_current_win()
@@ -972,8 +991,9 @@ local function goto_diagnostic(diagnostic, opts)
vim.cmd('normal! zv')
end)
- if opts.float then
- local float_opts = type(opts.float) == 'table' and opts.float or {}
+ local float_opts = opts.float
+ if float_opts then
+ float_opts = type(float_opts) == 'table' and float_opts or {}
vim.schedule(function()
M.open_float(vim.tbl_extend('keep', float_opts, {
bufnr = api.nvim_win_get_buf(winid),
@@ -1012,10 +1032,8 @@ end
--- When omitted, update the global diagnostic options.
---@return vim.diagnostic.Opts? : Current diagnostic config if {opts} is omitted.
function M.config(opts, namespace)
- vim.validate({
- opts = { opts, 't', true },
- namespace = { namespace, 'n', true },
- })
+ vim.validate('opts', opts, 'table', true)
+ vim.validate('namespace', namespace, 'number', true)
local t --- @type vim.diagnostic.Opts
if namespace then
@@ -1058,16 +1076,10 @@ end
---@param diagnostics vim.Diagnostic[]
---@param opts? vim.diagnostic.Opts Display options to pass to |vim.diagnostic.show()|
function M.set(namespace, bufnr, diagnostics, opts)
- vim.validate({
- namespace = { namespace, 'n' },
- bufnr = { bufnr, 'n' },
- diagnostics = {
- diagnostics,
- vim.islist,
- 'a list of diagnostics',
- },
- opts = { opts, 't', true },
- })
+ vim.validate('namespace', namespace, 'number')
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
+ vim.validate('opts', opts, 'table', true)
bufnr = get_bufnr(bufnr)
@@ -1092,7 +1104,7 @@ end
---@param namespace integer Diagnostic namespace
---@return vim.diagnostic.NS : Namespace metadata
function M.get_namespace(namespace)
- vim.validate({ namespace = { namespace, 'n' } })
+ vim.validate('namespace', namespace, 'number')
if not all_namespaces[namespace] then
local name --- @type string?
for k, v in pairs(api.nvim_get_namespaces()) do
@@ -1131,10 +1143,8 @@ end
---@return vim.Diagnostic[] : Fields `bufnr`, `end_lnum`, `end_col`, and `severity`
--- are guaranteed to be present.
function M.get(bufnr, opts)
- vim.validate({
- bufnr = { bufnr, 'n', true },
- opts = { opts, 't', true },
- })
+ vim.validate('bufnr', bufnr, 'number', true)
+ vim.validate('opts', opts, 'table', true)
return vim.deepcopy(get_diagnostics(bufnr, opts, false), true)
end
@@ -1147,10 +1157,8 @@ end
---@return table : Table with actually present severity values as keys
--- (see |diagnostic-severity|) and integer counts as values.
function M.count(bufnr, opts)
- vim.validate({
- bufnr = { bufnr, 'n', true },
- opts = { opts, 't', true },
- })
+ vim.validate('bufnr', bufnr, 'number', true)
+ vim.validate('opts', opts, 'table', true)
local diagnostics = get_diagnostics(bufnr, opts, false)
local count = {} --- @type table<integer,integer>
@@ -1309,7 +1317,7 @@ function M.jump(opts)
if opts.cursor_position then
vim.deprecate('opts.cursor_position', 'opts.pos', '0.13')
opts.pos = opts.cursor_position
- opts.cursor_position = nil
+ opts.cursor_position = nil --- @diagnostic disable-line
end
local diag = nil
@@ -1348,16 +1356,10 @@ end
M.handlers.signs = {
show = function(namespace, bufnr, diagnostics, opts)
- vim.validate({
- namespace = { namespace, 'n' },
- bufnr = { bufnr, 'n' },
- diagnostics = {
- diagnostics,
- vim.islist,
- 'a list of diagnostics',
- },
- opts = { opts, 't', true },
- })
+ vim.validate('namespace', namespace, 'number')
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
+ vim.validate('opts', opts, 'table', true)
bufnr = get_bufnr(bufnr)
opts = opts or {}
@@ -1372,22 +1374,7 @@ M.handlers.signs = {
-- 10 is the default sign priority when none is explicitly specified
local priority = opts.signs and opts.signs.priority or 10
- local get_priority --- @type function
- if opts.severity_sort then
- if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then
- get_priority = function(severity)
- return priority + (severity - vim.diagnostic.severity.ERROR)
- end
- else
- get_priority = function(severity)
- return priority + (vim.diagnostic.severity.HINT - severity)
- end
- end
- else
- get_priority = function()
- return priority
- end
- end
+ local get_priority = severity_to_extmark_priority(priority, opts)
local ns = M.get_namespace(namespace)
if not ns.user_data.sign_ns then
@@ -1475,16 +1462,10 @@ M.handlers.signs = {
M.handlers.underline = {
show = function(namespace, bufnr, diagnostics, opts)
- vim.validate({
- namespace = { namespace, 'n' },
- bufnr = { bufnr, 'n' },
- diagnostics = {
- diagnostics,
- vim.islist,
- 'a list of diagnostics',
- },
- opts = { opts, 't', true },
- })
+ vim.validate('namespace', namespace, 'number')
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
+ vim.validate('opts', opts, 'table', true)
bufnr = get_bufnr(bufnr)
opts = opts or {}
@@ -1504,15 +1485,12 @@ M.handlers.underline = {
end
local underline_ns = ns.user_data.underline_ns
+ local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts)
+
for _, diagnostic in ipairs(diagnostics) do
- --- @type string?
+ -- Default to error if we don't have a highlight associated
local higroup = underline_highlight_map[assert(diagnostic.severity)]
-
- if higroup == nil then
- -- Default to error if we don't have a highlight associated
- -- TODO(lewis6991): this is always nil since underline_highlight_map only has integer keys
- higroup = underline_highlight_map.Error
- end
+ or underline_highlight_map[vim.diagnostic.severity.ERROR]
if diagnostic._tags then
-- TODO(lewis6991): we should be able to stack these.
@@ -1524,13 +1502,13 @@ M.handlers.underline = {
end
end
- vim.highlight.range(
+ vim.hl.range(
bufnr,
underline_ns,
higroup,
{ diagnostic.lnum, diagnostic.col },
{ diagnostic.end_lnum, diagnostic.end_col },
- { priority = vim.highlight.priorities.diagnostics }
+ { priority = get_priority(diagnostic.severity) }
)
end
save_extmarks(underline_ns, bufnr)
@@ -1548,16 +1526,10 @@ M.handlers.underline = {
M.handlers.virtual_text = {
show = function(namespace, bufnr, diagnostics, opts)
- vim.validate({
- namespace = { namespace, 'n' },
- bufnr = { bufnr, 'n' },
- diagnostics = {
- diagnostics,
- vim.islist,
- 'a list of diagnostics',
- },
- opts = { opts, 't', true },
- })
+ vim.validate('namespace', namespace, 'number')
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
+ vim.validate('opts', opts, 'table', true)
bufnr = get_bufnr(bufnr)
opts = opts or {}
@@ -1681,10 +1653,8 @@ end
---@param bufnr integer? Buffer number, or 0 for current buffer. When
--- omitted, hide diagnostics in all buffers.
function M.hide(namespace, bufnr)
- vim.validate({
- namespace = { namespace, 'n', true },
- bufnr = { bufnr, 'n', true },
- })
+ vim.validate('namespace', namespace, 'number', true)
+ vim.validate('bufnr', bufnr, 'number', true)
local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
for _, iter_bufnr in ipairs(buffers) do
@@ -1741,18 +1711,10 @@ end
--- or {bufnr} is nil.
---@param opts? vim.diagnostic.Opts Display options.
function M.show(namespace, bufnr, diagnostics, opts)
- vim.validate({
- namespace = { namespace, 'n', true },
- bufnr = { bufnr, 'n', true },
- diagnostics = {
- diagnostics,
- function(v)
- return v == nil or vim.islist(v)
- end,
- 'a list of diagnostics',
- },
- opts = { opts, 't', true },
- })
+ vim.validate('namespace', namespace, 'number', true)
+ vim.validate('bufnr', bufnr, 'number', true)
+ vim.validate('diagnostics', diagnostics, vim.islist, true, 'a list of diagnostics')
+ vim.validate('opts', opts, 'table', true)
if not bufnr or not namespace then
assert(not diagnostics, 'Cannot show diagnostics without a buffer and namespace')
@@ -1825,9 +1787,7 @@ function M.open_float(opts, ...)
bufnr = opts
opts = ... --- @type vim.diagnostic.Opts.Float
else
- vim.validate({
- opts = { opts, 't', true },
- })
+ vim.validate('opts', opts, 'table', true)
end
opts = opts or {}
@@ -1905,13 +1865,7 @@ function M.open_float(opts, ...)
local highlights = {} --- @type table[]
local header = if_nil(opts.header, 'Diagnostics:')
if header then
- vim.validate({
- header = {
- header,
- { 'string', 'table' },
- "'string' or 'table'",
- },
- })
+ vim.validate('header', header, { 'string', 'table' }, "'string' or 'table'")
if type(header) == 'table' then
-- Don't insert any lines for an empty string
if string.len(if_nil(header[1], '')) > 0 then
@@ -1939,13 +1893,12 @@ function M.open_float(opts, ...)
local prefix, prefix_hl_group --- @type string?, string?
if prefix_opt then
- vim.validate({
- prefix = {
- prefix_opt,
- { 'string', 'table', 'function' },
- "'string' or 'table' or 'function'",
- },
- })
+ vim.validate(
+ 'prefix',
+ prefix_opt,
+ { 'string', 'table', 'function' },
+ "'string' or 'table' or 'function'"
+ )
if type(prefix_opt) == 'string' then
prefix, prefix_hl_group = prefix_opt, 'NormalFloat'
elseif type(prefix_opt) == 'table' then
@@ -1959,13 +1912,12 @@ function M.open_float(opts, ...)
local suffix, suffix_hl_group --- @type string?, string?
if suffix_opt then
- vim.validate({
- suffix = {
- suffix_opt,
- { 'string', 'table', 'function' },
- "'string' or 'table' or 'function'",
- },
- })
+ vim.validate(
+ 'suffix',
+ suffix_opt,
+ { 'string', 'table', 'function' },
+ "'string' or 'table' or 'function'"
+ )
if type(suffix_opt) == 'string' then
suffix, suffix_hl_group = suffix_opt, 'NormalFloat'
elseif type(suffix_opt) == 'table' then
@@ -2038,10 +1990,8 @@ end
---@param bufnr integer? Remove diagnostics for the given buffer. When omitted,
--- diagnostics are removed for all buffers.
function M.reset(namespace, bufnr)
- vim.validate({
- namespace = { namespace, 'n', true },
- bufnr = { bufnr, 'n', true },
- })
+ vim.validate('namespace', namespace, 'number', true)
+ vim.validate('bufnr', bufnr, 'number', true)
local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
for _, iter_bufnr in ipairs(buffers) do
@@ -2144,10 +2094,8 @@ function M.enable(enable, filter)
'0.12'
)
- vim.validate({
- enable = { enable, 'n', true }, -- Legacy `bufnr` arg.
- filter = { filter, 'n', true }, -- Legacy `namespace` arg.
- })
+ vim.validate('enable', enable, 'number', true) -- Legacy `bufnr` arg.
+ vim.validate('filter', filter, 'number', true) -- Legacy `namespace` arg.
local ns_id = type(filter) == 'number' and filter or nil
filter = {}
@@ -2156,17 +2104,16 @@ function M.enable(enable, filter)
enable = true
else
filter = filter or {}
- vim.validate({
- enable = { enable, 'b', true },
- filter = { filter, 't', true },
- })
+ vim.validate('enable', enable, 'boolean', true)
+ vim.validate('filter', filter, 'table', true)
end
enable = enable == nil and true or enable
local bufnr = filter.bufnr
+ local ns_id = filter.ns_id
- if bufnr == nil then
- if filter.ns_id == nil then
+ if not bufnr then
+ if not ns_id then
diagnostic_disabled = (
enable
-- Enable everything by setting diagnostic_disabled to an empty table.
@@ -2180,12 +2127,12 @@ function M.enable(enable, filter)
})
)
else
- local ns = M.get_namespace(filter.ns_id)
+ local ns = M.get_namespace(ns_id)
ns.disabled = not enable
end
else
bufnr = get_bufnr(bufnr)
- if filter.ns_id == nil then
+ if not ns_id then
diagnostic_disabled[bufnr] = (not enable) and true or nil
else
if type(diagnostic_disabled[bufnr]) ~= 'table' then
@@ -2195,14 +2142,14 @@ function M.enable(enable, filter)
diagnostic_disabled[bufnr] = {}
end
end
- diagnostic_disabled[bufnr][filter.ns_id] = (not enable) and true or nil
+ diagnostic_disabled[bufnr][ns_id] = (not enable) and true or nil
end
end
if enable then
- M.show(filter.ns_id, bufnr)
+ M.show(ns_id, bufnr)
else
- M.hide(filter.ns_id, bufnr)
+ M.hide(ns_id, bufnr)
end
end
@@ -2234,13 +2181,11 @@ end
--- ERROR.
---@return vim.Diagnostic?: |vim.Diagnostic| structure or `nil` if {pat} fails to match {str}.
function M.match(str, pat, groups, severity_map, defaults)
- vim.validate({
- str = { str, 's' },
- pat = { pat, 's' },
- groups = { groups, 't' },
- severity_map = { severity_map, 't', true },
- defaults = { defaults, 't', true },
- })
+ vim.validate('str', str, 'string')
+ vim.validate('pat', pat, 'string')
+ vim.validate('groups', groups, 'table')
+ vim.validate('severity_map', severity_map, 'table', true)
+ vim.validate('defaults', defaults, 'table', true)
--- @type table<string,vim.diagnostic.Severity>
severity_map = severity_map or M.severity
@@ -2283,13 +2228,7 @@ local errlist_type_map = {
---@param diagnostics vim.Diagnostic[]
---@return table[] : Quickfix list items |setqflist-what|
function M.toqflist(diagnostics)
- vim.validate({
- diagnostics = {
- diagnostics,
- vim.islist,
- 'a list of diagnostics',
- },
- })
+ vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
local list = {} --- @type table[]
for _, v in ipairs(diagnostics) do
@@ -2323,13 +2262,7 @@ end
---@param list table[] List of quickfix items from |getqflist()| or |getloclist()|.
---@return vim.Diagnostic[]
function M.fromqflist(list)
- vim.validate({
- list = {
- list,
- vim.islist,
- 'a list of quickfix items',
- },
- })
+ vim.validate('list', list, 'table')
local diagnostics = {} --- @type vim.Diagnostic[]
for _, item in ipairs(list) do
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index d3910e26eb..e1e73d63fe 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -4,15 +4,22 @@ local fn = vim.fn
local M = {}
--- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)?
---- @alias vim.filetype.mapopts { parent: string, priority: number }
+--- @alias vim.filetype.mapopts { priority: number }
--- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, vim.filetype.mapopts]
--- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl
--- @alias vim.filetype.mapping table<string,vim.filetype.mapping.value>
+--- @class vim.filetype.mapping.sorted
+--- @nodoc
+--- @field [1] string parent pattern
+--- @field [2] string pattern
+--- @field [3] string|vim.filetype.mapfn
+--- @field [4] integer priority
+
--- @param ft string|vim.filetype.mapfn
---- @param opts? vim.filetype.mapopts
+--- @param priority? integer
--- @return vim.filetype.maptbl
-local function starsetf(ft, opts)
+local function starsetf(ft, priority)
return {
function(path, bufnr)
-- Note: when `ft` is a function its return value may be nil.
@@ -27,11 +34,8 @@ local function starsetf(ft, opts)
end
end,
{
- -- Allow setting "parent" to be reused in closures, but don't have default as it will be
- -- assigned later from grouping
- parent = opts and opts.parent,
-- Starset matches should have lowest priority by default
- priority = (opts and opts.priority) or -math.huge,
+ priority = priority or -math.huge,
},
}
end
@@ -402,6 +406,7 @@ local extension = {
dtso = 'dts',
its = 'dts',
keymap = 'dts',
+ overlay = 'dts',
dylan = 'dylan',
intr = 'dylanintr',
lid = 'dylanlid',
@@ -587,6 +592,7 @@ local extension = {
ibi = 'ibasic',
icn = 'icon',
idl = detect.idl,
+ idr = 'idris2',
inc = detect.inc,
inf = 'inform',
INF = 'inform',
@@ -594,6 +600,7 @@ local extension = {
inko = 'inko',
inp = detect.inp,
ms = detect_seq(detect.nroff, 'xmath'),
+ ipkg = 'ipkg',
iss = 'iss',
mst = 'ist',
ist = 'ist',
@@ -667,13 +674,14 @@ local extension = {
journal = 'ledger',
ldg = 'ledger',
ledger = 'ledger',
+ leo = 'leo',
less = 'less',
lex = 'lex',
lxx = 'lex',
['l++'] = 'lex',
l = 'lex',
lhs = 'lhaskell',
- ll = 'lifelines',
+ lidr = 'lidris2',
ly = 'lilypond',
ily = 'lilypond',
liquid = 'liquid',
@@ -688,6 +696,7 @@ local extension = {
lt = 'lite',
lite = 'lite',
livemd = 'livebook',
+ ll = detect.ll,
log = detect.log,
Log = detect.log,
LOG = detect.log,
@@ -752,6 +761,7 @@ local extension = {
mib = 'mib',
mix = 'mix',
mixal = 'mix',
+ mlir = 'mlir',
mm = detect.mm,
nb = 'mma',
wl = 'mma',
@@ -782,6 +792,7 @@ local extension = {
mof = 'msidl',
odl = 'msidl',
msql = 'msql',
+ mss = 'mss',
mu = 'mupad',
mush = 'mush',
mustache = 'mustache',
@@ -1067,6 +1078,9 @@ local extension = {
envrc = detect.sh,
ksh = detect.ksh,
sh = detect.sh,
+ lo = 'sh',
+ la = 'sh',
+ lai = 'sh',
mdd = 'sh',
sieve = 'sieve',
siv = 'sieve',
@@ -1146,6 +1160,7 @@ local extension = {
sface = 'surface',
svelte = 'svelte',
svg = 'svg',
+ sw = 'sway',
swift = 'swift',
swiftinterface = 'swift',
swig = 'swig',
@@ -1303,6 +1318,7 @@ local extension = {
xpfm = 'xml',
spfm = 'xml',
bxml = 'xml',
+ mmi = 'xml',
xcu = 'xml',
xlb = 'xml',
xlc = 'xml',
@@ -1610,6 +1626,7 @@ local filename = {
['ldaprc'] = 'ldapconf',
['.ldaprc'] = 'ldapconf',
['ldap.conf'] = 'ldapconf',
+ ['lfrc'] = 'lf',
['lftp.conf'] = 'lftp',
['.lftprc'] = 'lftp',
['/.libao'] = 'libao',
@@ -1862,11 +1879,10 @@ local filename = {
}
-- Re-use closures as much as possible
-local detect_apache_diretc = starsetf('apache', { parent = '/etc/' })
-local detect_apache_dotconf = starsetf('apache', { parent = '%.conf' })
-local detect_muttrc = starsetf('muttrc', { parent = 'utt' })
-local detect_neomuttrc = starsetf('neomuttrc', { parent = 'utt' })
-local detect_xkb = starsetf('xkb', { parent = '/usr/' })
+local detect_apache = starsetf('apache')
+local detect_muttrc = starsetf('muttrc')
+local detect_neomuttrc = starsetf('neomuttrc')
+local detect_xkb = starsetf('xkb')
---@type table<string,vim.filetype.mapping>
local pattern = {
@@ -1883,14 +1899,14 @@ local pattern = {
['/etc/asound%.conf$'] = 'alsaconf',
['/etc/apache2/sites%-.*/.*%.com$'] = 'apache',
['/etc/httpd/.*%.conf$'] = 'apache',
- ['/etc/apache2/.*%.conf'] = detect_apache_diretc,
- ['/etc/apache2/conf%..*/'] = detect_apache_diretc,
- ['/etc/apache2/mods%-.*/'] = detect_apache_diretc,
- ['/etc/apache2/sites%-.*/'] = detect_apache_diretc,
- ['/etc/httpd/conf%..*/'] = detect_apache_diretc,
- ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache_diretc,
- ['/etc/httpd/mods%-.*/'] = detect_apache_diretc,
- ['/etc/httpd/sites%-.*/'] = detect_apache_diretc,
+ ['/etc/apache2/.*%.conf'] = detect_apache,
+ ['/etc/apache2/conf%..*/'] = detect_apache,
+ ['/etc/apache2/mods%-.*/'] = detect_apache,
+ ['/etc/apache2/sites%-.*/'] = detect_apache,
+ ['/etc/httpd/conf%..*/'] = detect_apache,
+ ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache,
+ ['/etc/httpd/mods%-.*/'] = detect_apache,
+ ['/etc/httpd/sites%-.*/'] = detect_apache,
['/etc/proftpd/.*%.conf'] = starsetf('apachestyle'),
['/etc/proftpd/conf%..*/'] = starsetf('apachestyle'),
['/etc/cdrdao%.conf$'] = 'cdrdaoconf',
@@ -2106,6 +2122,7 @@ local pattern = {
['/build/conf/.*%.conf$'] = 'bitbake',
['/meta%-.*/conf/.*%.conf$'] = 'bitbake',
['/meta/conf/.*%.conf$'] = 'bitbake',
+ ['/project%-spec/configs/.*%.conf$'] = 'bitbake',
['/%.cabal/config$'] = 'cabalconfig',
['/cabal/config$'] = 'cabalconfig',
['/%.aws/config$'] = 'confini',
@@ -2132,6 +2149,7 @@ local pattern = {
['/sway/config$'] = 'swayconfig',
['/%.cargo/config$'] = 'toml',
['/%.bundle/config$'] = 'yaml',
+ ['/%.kube/config$'] = 'yaml',
},
['/%.'] = {
['/%.aws/credentials$'] = 'confini',
@@ -2180,11 +2198,13 @@ local pattern = {
},
['%.conf'] = {
['^proftpd%.conf'] = starsetf('apachestyle'),
- ['^access%.conf'] = detect_apache_dotconf,
- ['^apache%.conf'] = detect_apache_dotconf,
- ['^apache2%.conf'] = detect_apache_dotconf,
- ['^httpd%.conf'] = detect_apache_dotconf,
- ['^srm%.conf'] = detect_apache_dotconf,
+ ['^access%.conf'] = detect_apache,
+ ['^apache%.conf'] = detect_apache,
+ ['^apache2%.conf'] = detect_apache,
+ ['^httpd%.conf'] = detect_apache,
+ ['^httpd%-.*%.conf'] = detect_apache,
+ ['^proxy%-html%.conf'] = detect_apache,
+ ['^srm%.conf'] = detect_apache,
['asterisk/.*%.conf'] = starsetf('asterisk'),
['asterisk.*/.*voicemail%.conf'] = starsetf('asteriskvm'),
['^dictd.*%.conf$'] = 'dictdconf',
@@ -2260,6 +2280,7 @@ local pattern = {
['^%.?neomuttrc'] = detect_neomuttrc,
['/%.neomutt/neomuttrc'] = detect_neomuttrc,
['^Neomuttrc'] = detect_neomuttrc,
+ ['%.neomuttdebug'] = 'neomuttlog',
},
['^%.'] = {
['^%.cshrc'] = detect.csh,
@@ -2293,6 +2314,8 @@ local pattern = {
['^crontab%.'] = starsetf('crontab'),
['^cvs%d+$'] = 'cvs',
['^php%.ini%-'] = 'dosini',
+ ['^php%-fpm%.conf'] = 'dosini',
+ ['^www%.conf'] = 'dosini',
['^drac%.'] = starsetf('dracula'),
['/dtrace/.*%.d$'] = 'dtrace',
['esmtprc$'] = 'esmtprc',
@@ -2354,7 +2377,7 @@ local pattern = {
['/app%-defaults/'] = starsetf('xdefaults'),
['^Xresources'] = starsetf('xdefaults'),
-- Increase priority to run before the pattern below
- ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }),
+ ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, -math.huge + 1),
['^XF86Config'] = starsetf(detect.xfree86_v3),
['Xmodmap$'] = 'xmodmap',
['xmodmap'] = starsetf('xmodmap'),
@@ -2380,8 +2403,10 @@ local pattern = {
--- @type table<string,vim.filetype.pattern_cache>
local pattern_lookup = {}
+--- @param a vim.filetype.mapping.sorted
+--- @param b vim.filetype.mapping.sorted
local function compare_by_priority(a, b)
- return a[next(a)][2].priority > b[next(b)][2].priority
+ return a[4] > b[4]
end
--- @param pat string
@@ -2391,30 +2416,30 @@ local function parse_pattern(pat)
end
--- @param t table<string,vim.filetype.mapping>
---- @return vim.filetype.mapping[]
---- @return vim.filetype.mapping[]
+--- @return vim.filetype.mapping.sorted[]
+--- @return vim.filetype.mapping.sorted[]
local function sort_by_priority(t)
-- Separate patterns with non-negative and negative priority because they
-- will be processed separately
- local pos = {} --- @type vim.filetype.mapping[]
- local neg = {} --- @type vim.filetype.mapping[]
+ local pos = {} --- @type vim.filetype.mapping.sorted[]
+ local neg = {} --- @type vim.filetype.mapping.sorted[]
for parent, ft_map in pairs(t) do
pattern_lookup[parent] = pattern_lookup[parent] or parse_pattern(parent)
for pat, maptbl in pairs(ft_map) do
- local ft = type(maptbl) == 'table' and maptbl[1] or maptbl
+ local ft_or_fun = type(maptbl) == 'table' and maptbl[1] or maptbl
assert(
- type(ft) == 'string' or type(ft) == 'function',
+ type(ft_or_fun) == 'string' or type(ft_or_fun) == 'function',
'Expected string or function for filetype'
)
-- Parse pattern for common data and cache it once
pattern_lookup[pat] = pattern_lookup[pat] or parse_pattern(pat)
- local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {}
- opts.parent = opts.parent or parent
- opts.priority = opts.priority or 0
+ --- @type vim.filetype.mapopts?
+ local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or nil
+ local priority = opts and opts.priority or 0
- table.insert(opts.priority >= 0 and pos or neg, { [pat] = { ft, opts } })
+ table.insert(priority >= 0 and pos or neg, { parent, pat, ft_or_fun, priority })
end
end
@@ -2625,7 +2650,8 @@ local function match_pattern(name, path, tail, pat, try_all_candidates)
if some_env_missing then
return nil
end
- pat, has_slash = expanded, expanded:find('/') ~= nil
+ pat = expanded
+ has_slash = has_slash or expanded:find('/') ~= nil
end
-- Try all possible candidates to make parent patterns not depend on slash presence
@@ -2647,14 +2673,13 @@ end
--- @param name string
--- @param path string
--- @param tail string
---- @param pattern_sorted vim.filetype.mapping[]
+--- @param pattern_sorted vim.filetype.mapping.sorted[]
--- @param parent_matches table<string,boolean>
--- @param bufnr integer?
local function match_pattern_sorted(name, path, tail, pattern_sorted, parent_matches, bufnr)
- for i = 1, #pattern_sorted do
- local pat, ft_data = next(pattern_sorted[i])
+ for _, p in ipairs(pattern_sorted) do
+ local parent, pat, ft_or_fn = p[1], p[2], p[3]
- local parent = ft_data[2].parent
local parent_is_matched = parent_matches[parent]
if parent_is_matched == nil then
parent_matches[parent] = match_pattern(name, path, tail, parent, true) ~= nil
@@ -2664,7 +2689,7 @@ local function match_pattern_sorted(name, path, tail, pattern_sorted, parent_mat
if parent_is_matched then
local matches = match_pattern(name, path, tail, pat, false)
if matches then
- local ft, on_detect = dispatch(ft_data[1], path, bufnr, matches)
+ local ft, on_detect = dispatch(ft_or_fn, path, bufnr, matches)
if ft then
return ft, on_detect
end
@@ -2729,9 +2754,7 @@ end
--- filetype specific buffer variables). The function accepts a buffer number as
--- its only argument.
function M.match(args)
- vim.validate({
- arg = { args, 't' },
- })
+ vim.validate('arg', args, 'table')
if not (args.buf or args.filename or args.contents) then
error('At least one of "buf", "filename", or "contents" must be given')
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 1cc81b177f..98b001bd51 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -869,6 +869,16 @@ function M.log(path, _)
end
--- @type vim.filetype.mapfn
+function M.ll(_, bufnr)
+ local first_line = getline(bufnr, 1)
+ if matchregex(first_line, [[;\|\<source_filename\>\|\<target\>]]) then
+ return 'llvm'
+ else
+ return 'lifelines'
+ end
+end
+
+--- @type vim.filetype.mapfn
function M.lpc(_, bufnr)
if vim.g.lpc_syntax_for_c then
for _, line in ipairs(getlines(bufnr, 1, 12)) do
@@ -1908,7 +1918,7 @@ local function match_from_hashbang(contents, path, dispatch_extension)
end
for k, v in pairs(patterns_hashbang) do
- local ft = type(v) == 'table' and v[1] or v
+ local ft = type(v) == 'table' and v[1] or v --[[@as string]]
local opts = type(v) == 'table' and v[2] or {}
if opts.vim_regex and matchregex(name, k) or name:find(k) then
return ft
@@ -2080,6 +2090,7 @@ local function match_from_text(contents, path)
return ft
end
else
+ --- @cast k string
local opts = type(v) == 'table' and v[2] or {}
if opts.start_lnum and opts.end_lnum then
assert(
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index ccddf826f7..d91eeaf02f 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -53,7 +53,7 @@ function M.dirname(file)
if file == nil then
return nil
end
- vim.validate({ file = { file, 's' } })
+ vim.validate('file', file, 'string')
if iswin then
file = file:gsub(os_sep, '/') --[[@as string]]
if file:match('^%w:/?$') then
@@ -83,7 +83,7 @@ function M.basename(file)
if file == nil then
return nil
end
- vim.validate({ file = { file, 's' } })
+ vim.validate('file', file, 'string')
if iswin then
file = file:gsub(os_sep, '/') --[[@as string]]
if file:match('^%w:/?$') then
@@ -123,11 +123,9 @@ end
function M.dir(path, opts)
opts = opts or {}
- vim.validate({
- path = { path, { 'string' } },
- depth = { opts.depth, { 'number' }, true },
- skip = { opts.skip, { 'function' }, true },
- })
+ vim.validate('path', path, 'string')
+ vim.validate('depth', opts.depth, 'number', true)
+ vim.validate('skip', opts.skip, 'function', true)
path = M.normalize(path)
if not opts.depth or opts.depth == 1 then
@@ -231,14 +229,12 @@ end
---@return (string[]) # Normalized paths |vim.fs.normalize()| of all matching items
function M.find(names, opts)
opts = opts or {}
- vim.validate({
- names = { names, { 's', 't', 'f' } },
- path = { opts.path, 's', true },
- upward = { opts.upward, 'b', true },
- stop = { opts.stop, 's', true },
- type = { opts.type, 's', true },
- limit = { opts.limit, 'n', true },
- })
+ vim.validate('names', names, { 'string', 'table', 'function' })
+ vim.validate('path', opts.path, 'string', true)
+ vim.validate('upward', opts.upward, 'boolean', true)
+ vim.validate('stop', opts.stop, 'string', true)
+ vim.validate('type', opts.type, 'string', true)
+ vim.validate('limit', opts.limit, 'number', true)
if type(names) == 'string' then
names = { names }
@@ -547,11 +543,9 @@ function M.normalize(path, opts)
opts = opts or {}
if not opts._fast then
- vim.validate({
- path = { path, { 'string' } },
- expand_env = { opts.expand_env, { 'boolean' }, true },
- win = { opts.win, { 'boolean' }, true },
- })
+ vim.validate('path', path, 'string')
+ vim.validate('expand_env', opts.expand_env, 'boolean', true)
+ vim.validate('win', opts.win, 'boolean', true)
end
local win = opts.win == nil and iswin or not not opts.win
diff --git a/runtime/lua/vim/func/_memoize.lua b/runtime/lua/vim/func/_memoize.lua
index 65210351bf..6e557905a7 100644
--- a/runtime/lua/vim/func/_memoize.lua
+++ b/runtime/lua/vim/func/_memoize.lua
@@ -39,10 +39,8 @@ end
--- @param strong? boolean
--- @return F
return function(hash, fn, strong)
- vim.validate({
- hash = { hash, { 'number', 'string', 'function' } },
- fn = { fn, 'function' },
- })
+ vim.validate('hash', hash, { 'number', 'string', 'function' })
+ vim.validate('fn', fn, 'function')
---@type table<any,table<any,any>>
local cache = {}
diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua
index 22073b15c8..4f86d5e1ca 100644
--- a/runtime/lua/vim/glob.lua
+++ b/runtime/lua/vim/glob.lua
@@ -48,7 +48,7 @@ function M.to_lpeg(pattern)
end
-- luacheck: push ignore s
- local function cut(s, idx, match)
+ local function cut(_s, idx, match)
return idx, match
end
-- luacheck: pop
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/hl.lua
index a8d88db372..099efa3c61 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/hl.lua
@@ -17,7 +17,7 @@ M.priorities = {
user = 200,
}
---- @class vim.highlight.range.Opts
+--- @class vim.hl.range.Opts
--- @inlinedoc
---
--- Type of range. See [getregtype()]
@@ -28,8 +28,8 @@ M.priorities = {
--- (default: `false`)
--- @field inclusive? boolean
---
---- Indicates priority of highlight
---- (default: `vim.highlight.priorities.user`)
+--- Highlight priority
+--- (default: `vim.hl.priorities.user`)
--- @field priority? integer
--- Apply highlight group to range of text.
@@ -39,7 +39,7 @@ M.priorities = {
---@param higroup string Highlight group to use for highlighting
---@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()|
---@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()|
----@param opts? vim.highlight.range.Opts
+---@param opts? vim.hl.range.Opts
function M.range(bufnr, ns, higroup, start, finish, opts)
opts = opts or {}
local regtype = opts.regtype or 'v'
@@ -124,7 +124,7 @@ local yank_cancel --- @type fun()?
--- Add the following to your `init.vim`:
---
--- ```vim
---- autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup='Visual', timeout=300}
+--- autocmd TextYankPost * silent! lua vim.hl.on_yank {higroup='Visual', timeout=300}
--- ```
---
--- @param opts table|nil Optional parameters
@@ -133,21 +133,9 @@ local yank_cancel --- @type fun()?
--- - on_macro highlight when executing macro (default false)
--- - on_visual highlight when yanking visual selection (default true)
--- - event event structure (default vim.v.event)
---- - priority integer priority (default |vim.highlight.priorities|`.user`)
+--- - priority integer priority (default |vim.hl.priorities|`.user`)
function M.on_yank(opts)
- vim.validate({
- opts = {
- opts,
- function(t)
- if t == nil then
- return true
- else
- return type(t) == 'table'
- end
- end,
- 'a table or nil to configure options (see `:h highlight.on_yank`)',
- },
- })
+ vim.validate('opts', opts, 'table', true)
opts = opts or {}
local event = opts.event or vim.v.event
local on_macro = opts.on_macro or false
diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua
index 50ca0d2d0e..4c19435ef8 100644
--- a/runtime/lua/vim/keymap.lua
+++ b/runtime/lua/vim/keymap.lua
@@ -42,12 +42,10 @@ local keymap = {}
---@see |mapcheck()|
---@see |mapset()|
function keymap.set(mode, lhs, rhs, opts)
- vim.validate({
- mode = { mode, { 's', 't' } },
- lhs = { lhs, 's' },
- rhs = { rhs, { 's', 'f' } },
- opts = { opts, 't', true },
- })
+ vim.validate('mode', mode, { 'string', 'table' })
+ vim.validate('lhs', lhs, 'string')
+ vim.validate('rhs', rhs, { 'string', 'function' })
+ vim.validate('opts', opts, 'table', true)
opts = vim.deepcopy(opts or {}, true)
@@ -107,11 +105,9 @@ end
---@param opts? vim.keymap.del.Opts
---@see |vim.keymap.set()|
function keymap.del(modes, lhs, opts)
- vim.validate({
- mode = { modes, { 's', 't' } },
- lhs = { lhs, 's' },
- opts = { opts, 't', true },
- })
+ vim.validate('mode', modes, { 'string', 'table' })
+ vim.validate('lhs', lhs, 'string')
+ vim.validate('opts', opts, 'table', true)
opts = opts or {}
modes = type(modes) == 'string' and { modes } or modes
diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua
index e86d33bf53..0cce0ab21d 100644
--- a/runtime/lua/vim/loader.lua
+++ b/runtime/lua/vim/loader.lua
@@ -4,11 +4,14 @@ local uri_encode = vim.uri_encode --- @type function
--- @type (fun(modename: string): fun()|string)[]
local loaders = package.loaders
+local _loadfile = loadfile
+
+local VERSION = 4
local M = {}
----@alias CacheHash {mtime: {nsec: integer, sec: integer}, size: integer, type?: string}
----@alias CacheEntry {hash:CacheHash, chunk:string}
+--- @alias vim.loader.CacheHash {mtime: {nsec: integer, sec: integer}, size: integer, type?: string}
+--- @alias vim.loader.CacheEntry {hash:vim.loader.CacheHash, chunk:string}
--- @class vim.loader.find.Opts
--- @inlinedoc
@@ -40,107 +43,97 @@ local M = {}
--- @field modname string
---
--- The fs_stat of the module path. Won't be returned for `modname="*"`
---- @field stat? uv.uv_fs_t
+--- @field stat? uv.fs_stat.result
----@alias LoaderStats table<string, {total:number, time:number, [string]:number?}?>
+--- @alias vim.loader.Stats table<string, {total:number, time:number, [string]:number?}?>
----@nodoc
+--- @private
M.path = vim.fn.stdpath('cache') .. '/luac'
----@nodoc
+--- @private
M.enabled = false
----@class (private) Loader
----@field private _rtp string[]
----@field private _rtp_pure string[]
----@field private _rtp_key string
----@field private _hashes? table<string, CacheHash>
-local Loader = {
- VERSION = 4,
- ---@type table<string, table<string,vim.loader.ModuleInfo>>
- _indexed = {},
- ---@type table<string, string[]>
- _topmods = {},
- _loadfile = loadfile,
- ---@type LoaderStats
- _stats = {
- find = { total = 0, time = 0, not_found = 0 },
- },
-}
+--- @type vim.loader.Stats
+local stats = { find = { total = 0, time = 0, not_found = 0 } }
+
+--- @type table<string, uv.fs_stat.result>?
+local fs_stat_cache
+
+--- @type table<string, table<string,vim.loader.ModuleInfo>>
+local indexed = {}
--- @param path string
---- @return CacheHash
---- @private
-function Loader.get_hash(path)
- if not Loader._hashes then
- return uv.fs_stat(path) --[[@as CacheHash]]
+--- @return uv.fs_stat.result?
+local function fs_stat_cached(path)
+ if not fs_stat_cache then
+ return uv.fs_stat(path)
end
- if not Loader._hashes[path] then
+ if not fs_stat_cache[path] then
-- Note we must never save a stat for a non-existent path.
-- For non-existent paths fs_stat() will return nil.
- Loader._hashes[path] = uv.fs_stat(path)
+ fs_stat_cache[path] = uv.fs_stat(path)
end
- return Loader._hashes[path]
+ return fs_stat_cache[path]
end
local function normalize(path)
return fs.normalize(path, { expand_env = false, _fast = true })
end
+local rtp_cached = {} --- @type string[]
+local rtp_cache_key --- @type string?
+
--- Gets the rtp excluding after directories.
--- The result is cached, and will be updated if the runtime path changes.
--- When called from a fast event, the cached value will be returned.
--- @return string[] rtp, boolean updated
----@private
-function Loader.get_rtp()
+local function get_rtp()
if vim.in_fast_event() then
- return (Loader._rtp or {}), false
+ return (rtp_cached or {}), false
end
local updated = false
local key = vim.go.rtp
- if key ~= Loader._rtp_key then
- Loader._rtp = {}
+ if key ~= rtp_cache_key then
+ rtp_cached = {}
for _, path in ipairs(vim.api.nvim_get_runtime_file('', true)) do
path = normalize(path)
-- skip after directories
if
path:sub(-6, -1) ~= '/after'
- and not (Loader._indexed[path] and vim.tbl_isempty(Loader._indexed[path]))
+ and not (indexed[path] and vim.tbl_isempty(indexed[path]))
then
- Loader._rtp[#Loader._rtp + 1] = path
+ rtp_cached[#rtp_cached + 1] = path
end
end
updated = true
- Loader._rtp_key = key
+ rtp_cache_key = key
end
- return Loader._rtp, updated
+ return rtp_cached, updated
end
--- Returns the cache file name
----@param name string can be a module name, or a file name
----@return string file_name
----@private
-function Loader.cache_file(name)
+--- @param name string can be a module name, or a file name
+--- @return string file_name
+local function cache_filename(name)
local ret = ('%s/%s'):format(M.path, uri_encode(name, 'rfc2396'))
return ret:sub(-4) == '.lua' and (ret .. 'c') or (ret .. '.luac')
end
--- Saves the cache entry for a given module or file
----@param name string module name or filename
----@param entry CacheEntry
----@private
-function Loader.write(name, entry)
- local cname = Loader.cache_file(name)
+--- @param cname string cache filename
+--- @param hash vim.loader.CacheHash
+--- @param chunk function
+local function write_cachefile(cname, hash, chunk)
local f = assert(uv.fs_open(cname, 'w', 438))
local header = {
- Loader.VERSION,
- entry.hash.size,
- entry.hash.mtime.sec,
- entry.hash.mtime.nsec,
+ VERSION,
+ hash.size,
+ hash.mtime.sec,
+ hash.mtime.nsec,
}
uv.fs_write(f, table.concat(header, ',') .. '\0')
- uv.fs_write(f, entry.chunk)
+ uv.fs_write(f, string.dump(chunk))
uv.fs_close(f)
end
@@ -150,151 +143,159 @@ end
local function readfile(path, mode)
local f = uv.fs_open(path, 'r', mode)
if f then
- local hash = assert(uv.fs_fstat(f))
- local data = uv.fs_read(f, hash.size, 0) --[[@as string?]]
+ local size = assert(uv.fs_fstat(f)).size
+ local data = uv.fs_read(f, size, 0)
uv.fs_close(f)
return data
end
end
--- Loads the cache entry for a given module or file
----@param name string module name or filename
----@return CacheEntry?
----@private
-function Loader.read(name)
- local cname = Loader.cache_file(name)
+--- @param cname string cache filename
+--- @return vim.loader.CacheHash? hash
+--- @return string? chunk
+local function read_cachefile(cname)
local data = readfile(cname, 438)
- if data then
- local zero = data:find('\0', 1, true)
- if not zero then
- return
- end
+ if not data then
+ return
+ end
- ---@type integer[]|{[0]:integer}
- local header = vim.split(data:sub(1, zero - 1), ',')
- if tonumber(header[1]) ~= Loader.VERSION then
- return
- end
- return {
- hash = {
- size = tonumber(header[2]),
- mtime = { sec = tonumber(header[3]), nsec = tonumber(header[4]) },
- },
- chunk = data:sub(zero + 1),
- }
+ local zero = data:find('\0', 1, true)
+ if not zero then
+ return
+ end
+
+ --- @type integer[]|{[0]:integer}
+ local header = vim.split(data:sub(1, zero - 1), ',')
+ if tonumber(header[1]) ~= VERSION then
+ return
end
+
+ local hash = {
+ size = tonumber(header[2]),
+ mtime = { sec = tonumber(header[3]), nsec = tonumber(header[4]) },
+ }
+
+ local chunk = data:sub(zero + 1)
+
+ return hash, chunk
end
--- The `package.loaders` loader for Lua files using the cache.
----@param modname string module name
----@return string|function
----@private
-function Loader.loader(modname)
- Loader._hashes = {}
+--- @param modname string module name
+--- @return string|function
+local function loader_cached(modname)
+ fs_stat_cache = {}
local ret = M.find(modname)[1]
if ret then
-- Make sure to call the global loadfile so we respect any augmentations done elsewhere.
-- E.g. profiling
local chunk, err = loadfile(ret.modpath)
- Loader._hashes = nil
+ fs_stat_cache = nil
return chunk or error(err)
end
- Loader._hashes = nil
+ fs_stat_cache = nil
return ("\n\tcache_loader: module '%s' not found"):format(modname)
end
+local is_win = vim.fn.has('win32') == 1
+
--- The `package.loaders` loader for libs
----@param modname string module name
----@return string|function
----@private
-function Loader.loader_lib(modname)
- local is_win = vim.fn.has('win32') == 1
- local ret = M.find(modname, { patterns = is_win and { '.dll' } or { '.so' } })[1]
- if ret then
- -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
- -- a) strip prefix up to and including the first dash, if any
- -- b) replace all dots by underscores
- -- c) prepend "luaopen_"
- -- So "foo-bar.baz" should result in "luaopen_bar_baz"
- local dash = modname:find('-', 1, true)
- local funcname = dash and modname:sub(dash + 1) or modname
- local chunk, err = package.loadlib(ret.modpath, 'luaopen_' .. funcname:gsub('%.', '_'))
- return chunk or error(err)
+--- @param modname string module name
+--- @return string|function
+local function loader_lib_cached(modname)
+ local ret = M.find(modname, { patterns = { is_win and '.dll' or '.so' } })[1]
+ if not ret then
+ return ("\n\tcache_loader_lib: module '%s' not found"):format(modname)
end
- return ("\n\tcache_loader_lib: module '%s' not found"):format(modname)
-end
---- `loadfile` using the cache
---- Note this has the mode and env arguments which is supported by LuaJIT and is 5.1 compatible.
----@param filename? string
----@param _mode? "b"|"t"|"bt"
----@param env? table
----@return function?, string? error_message
----@private
-function Loader.loadfile(filename, _mode, env)
- -- ignore mode, since we byte-compile the Lua source files
- return Loader.load(normalize(filename), { env = env })
+ -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
+ -- a) strip prefix up to and including the first dash, if any
+ -- b) replace all dots by underscores
+ -- c) prepend "luaopen_"
+ -- So "foo-bar.baz" should result in "luaopen_bar_baz"
+ local dash = modname:find('-', 1, true)
+ local funcname = dash and modname:sub(dash + 1) or modname
+ local chunk, err = package.loadlib(ret.modpath, 'luaopen_' .. funcname:gsub('%.', '_'))
+ return chunk or error(err)
end
--- Checks whether two cache hashes are the same based on:
--- * file size
--- * mtime in seconds
--- * mtime in nanoseconds
----@param h1 CacheHash
----@param h2 CacheHash
----@private
-function Loader.eq(h1, h2)
- return h1
- and h2
- and h1.size == h2.size
- and h1.mtime.sec == h2.mtime.sec
- and h1.mtime.nsec == h2.mtime.nsec
+--- @param a? vim.loader.CacheHash
+--- @param b? vim.loader.CacheHash
+local function hash_eq(a, b)
+ return a
+ and b
+ and a.size == b.size
+ and a.mtime.sec == b.mtime.sec
+ and a.mtime.nsec == b.mtime.nsec
end
---- Loads the given module path using the cache
----@param modpath string
----@param opts? {mode?: "b"|"t"|"bt", env?:table} (table|nil) Options for loading the module:
---- - mode: (string) the mode to load the module with. "b"|"t"|"bt" (defaults to `nil`)
---- - env: (table) the environment to load the module in. (defaults to `nil`)
----@see |luaL_loadfile()|
----@return function?, string? error_message
----@private
-function Loader.load(modpath, opts)
- opts = opts or {}
- local hash = Loader.get_hash(modpath)
- ---@type function?, string?
- local chunk, err
-
- if not hash then
- -- trigger correct error
- return Loader._loadfile(modpath, opts.mode, opts.env)
- end
-
- local entry = Loader.read(modpath)
- if entry and Loader.eq(entry.hash, hash) then
- -- found in cache and up to date
- chunk, err = load(entry.chunk --[[@as string]], '@' .. modpath, opts.mode, opts.env)
- if not (err and err:find('cannot load incompatible bytecode', 1, true)) then
- return chunk, err
+--- `loadfile` using the cache
+--- Note this has the mode and env arguments which is supported by LuaJIT and is 5.1 compatible.
+--- @param filename? string
+--- @param mode? "b"|"t"|"bt"
+--- @param env? table
+--- @return function?, string? error_message
+local function loadfile_cached(filename, mode, env)
+ local modpath = normalize(filename)
+ local stat = fs_stat_cached(modpath)
+ local cname = cache_filename(modpath)
+ if stat then
+ local e_hash, e_chunk = read_cachefile(cname)
+ if hash_eq(e_hash, stat) and e_chunk then
+ -- found in cache and up to date
+ local chunk, err = load(e_chunk, '@' .. modpath, mode, env)
+ if not (err and err:find('cannot load incompatible bytecode', 1, true)) then
+ return chunk, err
+ end
end
end
- entry = { hash = hash, modpath = modpath }
- chunk, err = Loader._loadfile(modpath, opts.mode, opts.env)
- if chunk then
- entry.chunk = string.dump(chunk)
- Loader.write(modpath, entry)
+ local chunk, err = _loadfile(modpath, mode, env)
+ if chunk and stat then
+ write_cachefile(cname, stat, chunk)
end
return chunk, err
end
+--- Return the top-level \`/lua/*` modules for this path
+--- @param path string path to check for top-level Lua modules
+local function lsmod(path)
+ if not indexed[path] then
+ indexed[path] = {}
+ for name, t in fs.dir(path .. '/lua') do
+ local modpath = path .. '/lua/' .. name
+ -- HACK: type is not always returned due to a bug in luv
+ t = t or fs_stat_cached(modpath).type
+ --- @type string
+ local topname
+ local ext = name:sub(-4)
+ if ext == '.lua' or ext == '.dll' then
+ topname = name:sub(1, -5)
+ elseif name:sub(-3) == '.so' then
+ topname = name:sub(1, -4)
+ elseif t == 'link' or t == 'directory' then
+ topname = name
+ end
+ if topname then
+ indexed[path][topname] = { modpath = modpath, modname = topname }
+ end
+ end
+ end
+ return indexed[path]
+end
+
--- Finds Lua modules for the given module name.
---
--- @since 0
---
----@param modname string Module name, or `"*"` to find the top-level modules instead
----@param opts? vim.loader.find.Opts Options for finding a module:
----@return vim.loader.ModuleInfo[]
+--- @param modname string Module name, or `"*"` to find the top-level modules instead
+--- @param opts? vim.loader.find.Opts Options for finding a module:
+--- @return vim.loader.ModuleInfo[]
function M.find(modname, opts)
opts = opts or {}
@@ -320,7 +321,7 @@ function M.find(modname, opts)
patterns[p] = '/lua/' .. basename .. pattern
end
- ---@type vim.loader.ModuleInfo[]
+ --- @type vim.loader.ModuleInfo[]
local results = {}
-- Only continue if we haven't found anything yet or we want to find all
@@ -330,23 +331,23 @@ function M.find(modname, opts)
-- Checks if the given paths contain the top-level module.
-- If so, it tries to find the module path for the given module name.
- ---@param paths string[]
+ --- @param paths string[]
local function _find(paths)
for _, path in ipairs(paths) do
if topmod == '*' then
- for _, r in pairs(Loader.lsmod(path)) do
+ for _, r in pairs(lsmod(path)) do
results[#results + 1] = r
if not continue() then
return
end
end
- elseif Loader.lsmod(path)[topmod] then
+ elseif lsmod(path)[topmod] then
for _, pattern in ipairs(patterns) do
local modpath = path .. pattern
- Loader._stats.find.stat = (Loader._stats.find.stat or 0) + 1
- local hash = Loader.get_hash(modpath)
- if hash then
- results[#results + 1] = { modpath = modpath, stat = hash, modname = modname }
+ stats.find.stat = (stats.find.stat or 0) + 1
+ local stat = fs_stat_cached(modpath)
+ if stat then
+ results[#results + 1] = { modpath = modpath, stat = stat, modname = modname }
if not continue() then
return
end
@@ -358,9 +359,9 @@ function M.find(modname, opts)
-- always check the rtp first
if opts.rtp ~= false then
- _find(Loader._rtp or {})
+ _find(rtp_cached or {})
if continue() then
- local rtp, updated = Loader.get_rtp()
+ local rtp, updated = get_rtp()
if updated then
_find(rtp)
end
@@ -374,7 +375,7 @@ function M.find(modname, opts)
if #results == 0 then
-- module not found
- Loader._stats.find.not_found = Loader._stats.find.not_found + 1
+ stats.find.not_found = stats.find.not_found + 1
end
return results
@@ -384,17 +385,17 @@ end
---
--- @since 0
---
----@param path string? path to reset
+--- @param path string? path to reset
function M.reset(path)
if path then
- Loader._indexed[normalize(path)] = nil
+ indexed[normalize(path)] = nil
else
- Loader._indexed = {}
+ indexed = {}
end
-- Path could be a directory so just clear all the hashes.
- if Loader._hashes then
- Loader._hashes = {}
+ if fs_stat_cache then
+ fs_stat_cache = {}
end
end
@@ -411,11 +412,11 @@ function M.enable()
end
M.enabled = true
vim.fn.mkdir(vim.fn.fnamemodify(M.path, ':p'), 'p')
- _G.loadfile = Loader.loadfile
+ _G.loadfile = loadfile_cached
-- add Lua loader
- table.insert(loaders, 2, Loader.loader)
+ table.insert(loaders, 2, loader_cached)
-- add libs loader
- table.insert(loaders, 3, Loader.loader_lib)
+ table.insert(loaders, 3, loader_lib_cached)
-- remove Nvim loader
for l, loader in ipairs(loaders) do
if loader == vim._load_package then
@@ -435,111 +436,75 @@ function M.disable()
return
end
M.enabled = false
- _G.loadfile = Loader._loadfile
+ _G.loadfile = _loadfile
for l, loader in ipairs(loaders) do
- if loader == Loader.loader or loader == Loader.loader_lib then
+ if loader == loader_cached or loader == loader_lib_cached then
table.remove(loaders, l)
end
end
table.insert(loaders, 2, vim._load_package)
end
---- Return the top-level \`/lua/*` modules for this path
----@param path string path to check for top-level Lua modules
----@private
-function Loader.lsmod(path)
- if not Loader._indexed[path] then
- Loader._indexed[path] = {}
- for name, t in fs.dir(path .. '/lua') do
- local modpath = path .. '/lua/' .. name
- -- HACK: type is not always returned due to a bug in luv
- t = t or Loader.get_hash(modpath).type
- ---@type string
- local topname
- local ext = name:sub(-4)
- if ext == '.lua' or ext == '.dll' then
- topname = name:sub(1, -5)
- elseif name:sub(-3) == '.so' then
- topname = name:sub(1, -4)
- elseif t == 'link' or t == 'directory' then
- topname = name
- end
- if topname then
- Loader._indexed[path][topname] = { modpath = modpath, modname = topname }
- Loader._topmods[topname] = Loader._topmods[topname] or {}
- if not vim.list_contains(Loader._topmods[topname], path) then
- table.insert(Loader._topmods[topname], path)
- end
- end
- end
- end
- return Loader._indexed[path]
-end
-
--- Tracks the time spent in a function
--- @generic F: function
--- @param f F
--- @return F
---- @private
-function Loader.track(stat, f)
+local function track(stat, f)
return function(...)
local start = vim.uv.hrtime()
local r = { f(...) }
- Loader._stats[stat] = Loader._stats[stat] or { total = 0, time = 0 }
- Loader._stats[stat].total = Loader._stats[stat].total + 1
- Loader._stats[stat].time = Loader._stats[stat].time + uv.hrtime() - start
+ stats[stat] = stats[stat] or { total = 0, time = 0 }
+ stats[stat].total = stats[stat].total + 1
+ stats[stat].time = stats[stat].time + uv.hrtime() - start
return unpack(r, 1, table.maxn(r))
end
end
----@class (private) vim.loader._profile.Opts
----@field loaders? boolean Add profiling to the loaders
+--- @class (private) vim.loader._profile.Opts
+--- @field loaders? boolean Add profiling to the loaders
--- Debug function that wraps all loaders and tracks stats
----@private
----@param opts vim.loader._profile.Opts?
+--- Must be called before vim.loader.enable()
+--- @private
+--- @param opts vim.loader._profile.Opts?
function M._profile(opts)
- Loader.get_rtp = Loader.track('get_rtp', Loader.get_rtp)
- Loader.read = Loader.track('read', Loader.read)
- Loader.loader = Loader.track('loader', Loader.loader)
- Loader.loader_lib = Loader.track('loader_lib', Loader.loader_lib)
- Loader.loadfile = Loader.track('loadfile', Loader.loadfile)
- Loader.load = Loader.track('load', Loader.load)
- M.find = Loader.track('find', M.find)
- Loader.lsmod = Loader.track('lsmod', Loader.lsmod)
+ get_rtp = track('get_rtp', get_rtp)
+ read_cachefile = track('read', read_cachefile)
+ loader_cached = track('loader', loader_cached)
+ loader_lib_cached = track('loader_lib', loader_lib_cached)
+ loadfile_cached = track('loadfile', loadfile_cached)
+ M.find = track('find', M.find)
+ lsmod = track('lsmod', lsmod)
if opts and opts.loaders then
for l, loader in pairs(loaders) do
local loc = debug.getinfo(loader, 'Sn').source:sub(2)
- loaders[l] = Loader.track('loader ' .. l .. ': ' .. loc, loader)
+ loaders[l] = track('loader ' .. l .. ': ' .. loc, loader)
end
end
end
--- Prints all cache stats
----@param opts? {print?:boolean}
----@return LoaderStats
----@private
+--- @param opts? {print?:boolean}
+--- @return vim.loader.Stats
+--- @private
function M._inspect(opts)
if opts and opts.print then
local function ms(nsec)
return math.floor(nsec / 1e6 * 1000 + 0.5) / 1000 .. 'ms'
end
- local chunks = {} ---@type string[][]
- ---@type string[]
- local stats = vim.tbl_keys(Loader._stats)
- table.sort(stats)
- for _, stat in ipairs(stats) do
+ local chunks = {} --- @type string[][]
+ for _, stat in vim.spairs(stats) do
vim.list_extend(chunks, {
{ '\n' .. stat .. '\n', 'Title' },
{ '* total: ' },
- { tostring(Loader._stats[stat].total) .. '\n', 'Number' },
+ { tostring(stat.total) .. '\n', 'Number' },
{ '* time: ' },
- { ms(Loader._stats[stat].time) .. '\n', 'Bold' },
+ { ms(stat.time) .. '\n', 'Bold' },
{ '* avg time: ' },
- { ms(Loader._stats[stat].time / Loader._stats[stat].total) .. '\n', 'Bold' },
+ { ms(stat.time / stat.total) .. '\n', 'Bold' },
})
- for k, v in pairs(Loader._stats[stat]) do
+ for k, v in pairs(stat) do
if not vim.list_contains({ 'time', 'total' }, k) then
chunks[#chunks + 1] = { '* ' .. k .. ':' .. string.rep(' ', 9 - #k) }
chunks[#chunks + 1] = { tostring(v) .. '\n', 'Number' }
@@ -548,7 +513,7 @@ function M._inspect(opts)
end
vim.api.nvim_echo(chunks, true, {})
end
- return Loader._stats
+ return stats
end
return M
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 60677554ce..0de3b4ee4d 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -3,7 +3,6 @@ local validate = vim.validate
local lsp = vim._defer_require('vim.lsp', {
_changetracking = ..., --- @module 'vim.lsp._changetracking'
- _dynamic = ..., --- @module 'vim.lsp._dynamic'
_snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar'
_tagfunc = ..., --- @module 'vim.lsp._tagfunc'
_watchfiles = ..., --- @module 'vim.lsp._watchfiles'
@@ -31,6 +30,13 @@ local changetracking = lsp._changetracking
---@nodoc
lsp.rpc_response_error = lsp.rpc.rpc_response_error
+lsp._resolve_to_request = {
+ [ms.codeAction_resolve] = ms.textDocument_codeAction,
+ [ms.codeLens_resolve] = ms.textDocument_codeLens,
+ [ms.documentLink_resolve] = ms.textDocument_documentLink,
+ [ms.inlayHint_resolve] = ms.textDocument_inlayHint,
+}
+
-- maps request name to the required server_capability in the client.
lsp._request_name_to_capability = {
[ms.callHierarchy_incomingCalls] = { 'callHierarchyProvider' },
@@ -86,7 +92,7 @@ lsp._request_name_to_capability = {
---@param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer
---@return integer bufnr
local function resolve_bufnr(bufnr)
- validate({ bufnr = { bufnr, 'n', true } })
+ validate('bufnr', bufnr, 'number', true)
if bufnr == nil or bufnr == 0 then
return api.nvim_get_current_buf()
end
@@ -189,9 +195,10 @@ local function reuse_client_default(client, config)
end
if config.root_dir then
+ local root = vim.uri_from_fname(config.root_dir)
for _, dir in ipairs(client.workspace_folders or {}) do
-- note: do not need to check client.root_dir since that should be client.workspace_folders[1]
- if config.root_dir == dir.name then
+ if root == dir.uri then
return true
end
end
@@ -235,9 +242,9 @@ end
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
--- - `cmd` command string[] or function, described at |vim.lsp.start_client()|.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
---- should be re-used. The example above uses |vim.fs.root()| and |vim.fs.dirname()| to detect
---- the root by traversing the file system upwards starting from the current directory until
---- either a `pyproject.toml` or `setup.py` file is found.
+--- should be re-used. The example above uses |vim.fs.root()| to detect the root by traversing
+--- the file system upwards starting from the current directory until either a `pyproject.toml`
+--- or `setup.py` file is found.
--- - `workspace_folders` list of `{ uri:string, name: string }` tables specifying the project root
--- folders used by the language server. If `nil` the property is derived from `root_dir` for
--- convenience.
@@ -630,10 +637,8 @@ end
---@param client_id (integer) Client id
---@return boolean success `true` if client was attached successfully; `false` otherwise
function lsp.buf_attach_client(bufnr, client_id)
- validate({
- bufnr = { bufnr, 'n', true },
- client_id = { client_id, 'n' },
- })
+ validate('bufnr', bufnr, 'number', true)
+ validate('client_id', client_id, 'number')
bufnr = resolve_bufnr(bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
@@ -669,10 +674,8 @@ end
---@param bufnr integer Buffer handle, or 0 for current
---@param client_id integer Client id
function lsp.buf_detach_client(bufnr, client_id)
- validate({
- bufnr = { bufnr, 'n', true },
- client_id = { client_id, 'n' },
- })
+ validate('bufnr', bufnr, 'number', true)
+ validate('client_id', client_id, 'number')
bufnr = resolve_bufnr(bufnr)
local client = all_clients[client_id]
@@ -773,7 +776,7 @@ end
---@param filter? vim.lsp.get_clients.Filter
---@return vim.lsp.Client[]: List of |vim.lsp.Client| objects
function lsp.get_clients(filter)
- validate({ filter = { filter, 't', true } })
+ validate('filter', filter, 'table', true)
filter = filter or {}
@@ -858,7 +861,7 @@ api.nvim_create_autocmd('VimLeavePre', {
---
---@param bufnr (integer) Buffer handle, or 0 for current.
---@param method (string) LSP method name
----@param params table|nil Parameters to send to the server
+---@param params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?) Parameters to send to the server
---@param handler? lsp.Handler See |lsp-handler|
--- If nil, follows resolution strategy defined in |lsp-handler-configuration|
---@param on_unsupported? fun()
@@ -870,12 +873,10 @@ api.nvim_create_autocmd('VimLeavePre', {
---cancel all the requests. You could instead
---iterate all clients and call their `cancel_request()` methods.
function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
- validate({
- bufnr = { bufnr, 'n', true },
- method = { method, 's' },
- handler = { handler, 'f', true },
- on_unsupported = { on_unsupported, 'f', true },
- })
+ validate('bufnr', bufnr, 'number', true)
+ validate('method', method, 'string')
+ validate('handler', handler, 'function', true)
+ validate('on_unsupported', on_unsupported, 'function', true)
bufnr = resolve_bufnr(bufnr)
local method_supported = false
@@ -885,7 +886,8 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
if client.supports_method(method, { bufnr = bufnr }) then
method_supported = true
- local request_success, request_id = client.request(method, params, handler, bufnr)
+ local cparams = type(params) == 'function' and params(client, bufnr) or params --[[@as table?]]
+ local request_success, request_id = client.request(method, cparams, handler, bufnr)
-- This could only fail if the client shut down in the time since we looked
-- it up and we did the request, which should be rare.
if request_success then
@@ -920,35 +922,31 @@ end
---
---@param bufnr (integer) Buffer handle, or 0 for current.
---@param method (string) LSP method name
----@param params (table|nil) Parameters to send to the server
----@param handler fun(results: table<integer, {error: lsp.ResponseError?, result: any}>) (function)
+---@param params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?) Parameters to send to the server.
+--- Can also be passed as a function that returns the params table for cases where
+--- parameters are specific to the client.
+---@param handler lsp.MultiHandler (function)
--- Handler called after all requests are completed. Server results are passed as
--- a `client_id:result` map.
---@return function cancel Function that cancels all requests.
function lsp.buf_request_all(bufnr, method, params, handler)
- local results = {} --- @type table<integer,{error: lsp.ResponseError?, result: any}>
- local result_count = 0
- local expected_result_count = 0
-
- local set_expected_result_count = once(function()
- for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
- if client.supports_method(method, { bufnr = bufnr }) then
- expected_result_count = expected_result_count + 1
- end
+ local results = {} --- @type table<integer,{err: lsp.ResponseError?, result: any}>
+ local remaining --- @type integer?
+
+ local _, cancel = lsp.buf_request(bufnr, method, params, function(err, result, ctx, config)
+ if not remaining then
+ -- Calculate as late as possible in case a client is removed during the request
+ remaining = #lsp.get_clients({ bufnr = bufnr, method = method })
end
- end)
- local function _sync_handler(err, result, ctx)
- results[ctx.client_id] = { error = err, result = result }
- result_count = result_count + 1
- set_expected_result_count()
+ -- The error key is deprecated and will be removed in 0.13
+ results[ctx.client_id] = { err = err, error = err, result = result }
+ remaining = remaining - 1
- if result_count >= expected_result_count then
- handler(results)
+ if remaining == 0 then
+ handler(results, ctx, config)
end
- end
-
- local _, cancel = lsp.buf_request(bufnr, method, params, _sync_handler)
+ end)
return cancel
end
@@ -992,10 +990,8 @@ end
---
---@return boolean success true if any client returns true; false otherwise
function lsp.buf_notify(bufnr, method, params)
- validate({
- bufnr = { bufnr, 'n', true },
- method = { method, 's' },
- })
+ validate('bufnr', bufnr, 'number', true)
+ validate('method', method, 'string')
local resp = false
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
if client.rpc.notify(method, params) then
@@ -1056,7 +1052,7 @@ function lsp.formatexpr(opts)
if client.supports_method(ms.textDocument_rangeFormatting) then
local params = util.make_formatting_params()
local end_line = vim.fn.getline(end_lnum) --[[@as string]]
- local end_col = util._str_utfindex_enc(end_line, nil, client.offset_encoding)
+ local end_col = vim.str_utfindex(end_line, client.offset_encoding)
--- @cast params +lsp.DocumentRangeFormattingParams
params.range = {
start = {
@@ -1175,6 +1171,7 @@ function lsp.for_each_buffer_client(bufnr, fn)
end
end
+--- @deprecated
--- Function to manage overriding defaults for LSP handlers.
---@param handler (lsp.Handler) See |lsp-handler|
---@param override_config (table) Table containing the keys to override behavior of the {handler}
diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua
deleted file mode 100644
index 27113c0e74..0000000000
--- a/runtime/lua/vim/lsp/_dynamic.lua
+++ /dev/null
@@ -1,110 +0,0 @@
-local glob = vim.glob
-
---- @class lsp.DynamicCapabilities
---- @field capabilities table<string, lsp.Registration[]>
---- @field client_id number
-local M = {}
-
---- @param client_id number
---- @return lsp.DynamicCapabilities
-function M.new(client_id)
- return setmetatable({
- capabilities = {},
- client_id = client_id,
- }, { __index = M })
-end
-
-function M:supports_registration(method)
- local client = vim.lsp.get_client_by_id(self.client_id)
- if not client then
- return false
- end
- local capability = vim.tbl_get(client.capabilities, unpack(vim.split(method, '/')))
- return type(capability) == 'table' and capability.dynamicRegistration
-end
-
---- @param registrations lsp.Registration[]
-function M:register(registrations)
- -- remove duplicates
- self:unregister(registrations)
- for _, reg in ipairs(registrations) do
- local method = reg.method
- if not self.capabilities[method] then
- self.capabilities[method] = {}
- end
- table.insert(self.capabilities[method], reg)
- end
-end
-
---- @param unregisterations lsp.Unregistration[]
-function M:unregister(unregisterations)
- for _, unreg in ipairs(unregisterations) do
- local method = unreg.method
- if not self.capabilities[method] then
- return
- end
- local id = unreg.id
- for i, reg in ipairs(self.capabilities[method]) do
- if reg.id == id then
- table.remove(self.capabilities[method], i)
- break
- end
- end
- end
-end
-
---- @param method string
---- @param opts? {bufnr: integer?}
---- @return lsp.Registration? (table|nil) the registration if found
-function M:get(method, opts)
- opts = opts or {}
- opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
- for _, reg in ipairs(self.capabilities[method] or {}) do
- if not reg.registerOptions then
- return reg
- end
- local documentSelector = reg.registerOptions.documentSelector
- if not documentSelector then
- return reg
- end
- if self:match(opts.bufnr, documentSelector) then
- return reg
- end
- end
-end
-
---- @param method string
---- @param opts? {bufnr: integer?}
-function M:supports(method, opts)
- return self:get(method, opts) ~= nil
-end
-
---- @param bufnr number
---- @param documentSelector lsp.DocumentSelector
---- @private
-function M:match(bufnr, documentSelector)
- local client = vim.lsp.get_client_by_id(self.client_id)
- if not client then
- return false
- end
- local language = client.get_language_id(bufnr, vim.bo[bufnr].filetype)
- local uri = vim.uri_from_bufnr(bufnr)
- local fname = vim.uri_to_fname(uri)
- for _, filter in ipairs(documentSelector) do
- local matches = true
- if filter.language and language ~= filter.language then
- matches = false
- end
- if matches and filter.scheme and not vim.startswith(uri, filter.scheme .. ':') then
- matches = false
- end
- if matches and filter.pattern and not glob.to_lpeg(filter.pattern):match(fname) then
- matches = false
- end
- if matches then
- return true
- end
- end
-end
-
-return M
diff --git a/runtime/lua/vim/lsp/_meta.lua b/runtime/lua/vim/lsp/_meta.lua
index be3222828d..bf693ccc57 100644
--- a/runtime/lua/vim/lsp/_meta.lua
+++ b/runtime/lua/vim/lsp/_meta.lua
@@ -1,7 +1,8 @@
---@meta
error('Cannot require a meta file')
----@alias lsp.Handler fun(err: lsp.ResponseError?, result: any, context: lsp.HandlerContext, config?: table): ...any
+---@alias lsp.Handler fun(err: lsp.ResponseError?, result: any, context: lsp.HandlerContext): ...any
+---@alias lsp.MultiHandler fun(results: table<integer,{err: lsp.ResponseError?, result: any}>, context: lsp.HandlerContext): ...any
---@class lsp.HandlerContext
---@field method string
diff --git a/runtime/lua/vim/lsp/_tagfunc.lua b/runtime/lua/vim/lsp/_tagfunc.lua
index 4ad50e4a58..f75d43f373 100644
--- a/runtime/lua/vim/lsp/_tagfunc.lua
+++ b/runtime/lua/vim/lsp/_tagfunc.lua
@@ -1,4 +1,5 @@
local lsp = vim.lsp
+local api = vim.api
local util = lsp.util
local ms = lsp.protocol.Methods
@@ -21,32 +22,48 @@ end
---@param pattern string
---@return table[]
local function query_definition(pattern)
- local params = util.make_position_params()
- local results_by_client, err = lsp.buf_request_sync(0, ms.textDocument_definition, params, 1000)
- if err then
+ local bufnr = api.nvim_get_current_buf()
+ local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_definition })
+ if not next(clients) then
return {}
end
+ local win = api.nvim_get_current_win()
local results = {}
+
+ --- @param range lsp.Range
+ --- @param uri string
+ --- @param offset_encoding string
local add = function(range, uri, offset_encoding)
table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding))
end
- for client_id, lsp_results in pairs(assert(results_by_client)) do
- local client = lsp.get_client_by_id(client_id)
- local offset_encoding = client and client.offset_encoding or 'utf-16'
- local result = lsp_results.result or {}
- if result.range then -- Location
- add(result.range, result.uri)
- else
- result = result --[[@as (lsp.Location[]|lsp.LocationLink[])]]
- for _, item in pairs(result) do
- if item.range then -- Location
- add(item.range, item.uri, offset_encoding)
- else -- LocationLink
- add(item.targetSelectionRange, item.targetUri, offset_encoding)
+
+ local remaining = #clients
+ for _, client in ipairs(clients) do
+ ---@param result nil|lsp.Location|lsp.Location[]|lsp.LocationLink[]
+ local function on_response(_, result)
+ if result then
+ local encoding = client.offset_encoding
+ -- single Location
+ if result.range then
+ add(result.range, result.uri, encoding)
+ else
+ for _, location in ipairs(result) do
+ if location.range then -- Location
+ add(location.range, location.uri, encoding)
+ else -- LocationLink
+ add(location.targetSelectionRange, location.targetUri, encoding)
+ end
+ end
end
end
+ remaining = remaining - 1
end
+ local params = util.make_position_params(win, client.offset_encoding)
+ client.request(ms.textDocument_definition, params, on_response, bufnr)
end
+ vim.wait(1000, function()
+ return remaining == 0
+ end)
return results
end
diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua
index 98e9818bcd..c4cdb5aea8 100644
--- a/runtime/lua/vim/lsp/_watchfiles.lua
+++ b/runtime/lua/vim/lsp/_watchfiles.lua
@@ -44,9 +44,8 @@ M._poll_exclude_pattern = glob.to_lpeg('**/.git/{objects,subtree-cache}/**')
--- Registers the workspace/didChangeWatchedFiles capability dynamically.
---
---@param reg lsp.Registration LSP Registration object.
----@param ctx lsp.HandlerContext Context from the |lsp-handler|.
-function M.register(reg, ctx)
- local client_id = ctx.client_id
+---@param client_id integer Client ID.
+function M.register(reg, client_id)
local client = assert(vim.lsp.get_client_by_id(client_id), 'Client must be running')
-- Ill-behaved servers may not honor the client capability and try to register
-- anyway, so ignore requests when the user has opted out of the feature.
@@ -155,9 +154,8 @@ end
--- Unregisters the workspace/didChangeWatchedFiles capability dynamically.
---
---@param unreg lsp.Unregistration LSP Unregistration object.
----@param ctx lsp.HandlerContext Context from the |lsp-handler|.
-function M.unregister(unreg, ctx)
- local client_id = ctx.client_id
+---@param client_id integer Client ID.
+function M.unregister(unreg, client_id)
local client_cancels = cancels[client_id]
local reg_cancels = client_cancels[unreg.id]
while #reg_cancels > 0 do
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 301c1f0cb6..6383855a30 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -1,4 +1,5 @@
local api = vim.api
+local lsp = vim.lsp
local validate = vim.validate
local util = require('vim.lsp.util')
local npcall = vim.F.npcall
@@ -6,28 +7,24 @@ local ms = require('vim.lsp.protocol').Methods
local M = {}
---- Sends an async request to all active clients attached to the current
---- buffer.
----
----@param method (string) LSP method name
----@param params (table|nil) Parameters to send to the server
----@param handler lsp.Handler? See |lsp-handler|. Follows |lsp-handler-resolution|
----
----@return table<integer, integer> client_request_ids Map of client-id:request-id pairs
----for all successful requests.
----@return function _cancel_all_requests Function which can be used to
----cancel all the requests. You could instead
----iterate all clients and call their `cancel_request()` methods.
----
----@see |vim.lsp.buf_request()|
-local function request(method, params, handler)
- validate({
- method = { method, 's' },
- handler = { handler, 'f', true },
- })
- return vim.lsp.buf_request(0, method, params, handler)
+--- @param params? table
+--- @return fun(client: vim.lsp.Client): lsp.TextDocumentPositionParams
+local function client_positional_params(params)
+ local win = api.nvim_get_current_win()
+ return function(client)
+ local ret = util.make_position_params(win, client.offset_encoding)
+ if params then
+ ret = vim.tbl_extend('force', ret, params)
+ end
+ return ret
+ end
end
+local hover_ns = api.nvim_create_namespace('vim_lsp_hover_range')
+
+--- @class vim.lsp.buf.hover.Opts : vim.lsp.util.open_floating_preview.Opts
+--- @field silent? boolean
+
--- Displays hover information about the symbol under the cursor in a floating
--- window. The window will be dismissed on cursor move.
--- Calling the function twice will jump into the floating window
@@ -35,21 +32,210 @@ end
--- In the floating window, all commands and mappings are available as usual,
--- except that "q" dismisses the window.
--- You can scroll the contents the same as you would any other buffer.
-function M.hover()
- local params = util.make_position_params()
- request(ms.textDocument_hover, params)
+---
+--- Note: to disable hover highlights, add the following to your config:
+---
+--- ```lua
+--- vim.api.nvim_create_autocmd('ColorScheme', {
+--- callback = function()
+--- vim.api.nvim_set_hl(0, 'LspReferenceTarget', {})
+--- end,
+--- })
+--- ```
+--- @param config? vim.lsp.buf.hover.Opts
+function M.hover(config)
+ config = config or {}
+ config.focus_id = ms.textDocument_hover
+
+ lsp.buf_request_all(0, ms.textDocument_hover, client_positional_params(), function(results, ctx)
+ local bufnr = assert(ctx.bufnr)
+ if api.nvim_get_current_buf() ~= bufnr then
+ -- Ignore result since buffer changed. This happens for slow language servers.
+ return
+ end
+
+ -- Filter errors from results
+ local results1 = {} --- @type table<integer,lsp.Hover>
+
+ for client_id, resp in pairs(results) do
+ local err, result = resp.err, resp.result
+ if err then
+ lsp.log.error(err.code, err.message)
+ elseif result then
+ results1[client_id] = result
+ end
+ end
+
+ if vim.tbl_isempty(results1) then
+ if config.silent ~= true then
+ vim.notify('No information available')
+ end
+ return
+ end
+
+ local contents = {} --- @type string[]
+
+ local nresults = #vim.tbl_keys(results1)
+
+ local format = 'markdown'
+
+ for client_id, result in pairs(results1) do
+ local client = assert(lsp.get_client_by_id(client_id))
+ if nresults > 1 then
+ -- Show client name if there are multiple clients
+ contents[#contents + 1] = string.format('# %s', client.name)
+ end
+ if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then
+ if #results1 == 1 then
+ format = 'plaintext'
+ contents = vim.split(result.contents.value or '', '\n', { trimempty = true })
+ else
+ -- Surround plaintext with ``` to get correct formatting
+ contents[#contents + 1] = '```'
+ vim.list_extend(
+ contents,
+ vim.split(result.contents.value or '', '\n', { trimempty = true })
+ )
+ contents[#contents + 1] = '```'
+ end
+ else
+ vim.list_extend(contents, util.convert_input_to_markdown_lines(result.contents))
+ end
+ local range = result.range
+ if range then
+ local start = range.start
+ local end_ = range['end']
+ local start_idx = util._get_line_byte_from_position(bufnr, start, client.offset_encoding)
+ local end_idx = util._get_line_byte_from_position(bufnr, end_, client.offset_encoding)
+
+ vim.hl.range(
+ bufnr,
+ hover_ns,
+ 'LspReferenceTarget',
+ { start.line, start_idx },
+ { end_.line, end_idx },
+ { priority = vim.hl.priorities.user }
+ )
+ end
+ contents[#contents + 1] = '---'
+ end
+
+ -- Remove last linebreak ('---')
+ contents[#contents] = nil
+
+ if vim.tbl_isempty(contents) then
+ if config.silent ~= true then
+ vim.notify('No information available')
+ end
+ return
+ end
+
+ local _, winid = lsp.util.open_floating_preview(contents, format, config)
+
+ api.nvim_create_autocmd('WinClosed', {
+ pattern = tostring(winid),
+ once = true,
+ callback = function()
+ api.nvim_buf_clear_namespace(bufnr, hover_ns, 0, -1)
+ return true
+ end,
+ })
+ end)
end
local function request_with_opts(name, params, opts)
local req_handler --- @type function?
if opts then
req_handler = function(err, result, ctx, config)
- local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
- local handler = client.handlers[name] or vim.lsp.handlers[name]
+ local client = assert(lsp.get_client_by_id(ctx.client_id))
+ local handler = client.handlers[name] or lsp.handlers[name]
handler(err, result, ctx, vim.tbl_extend('force', config or {}, opts))
end
end
- request(name, params, req_handler)
+ lsp.buf_request(0, name, params, req_handler)
+end
+
+---@param method string
+---@param opts? vim.lsp.LocationOpts
+local function get_locations(method, opts)
+ opts = opts or {}
+ local bufnr = api.nvim_get_current_buf()
+ local clients = lsp.get_clients({ method = method, bufnr = bufnr })
+ if not next(clients) then
+ vim.notify(lsp._unsupported_method(method), vim.log.levels.WARN)
+ return
+ end
+ local win = api.nvim_get_current_win()
+ local from = vim.fn.getpos('.')
+ from[1] = bufnr
+ local tagname = vim.fn.expand('<cword>')
+ local remaining = #clients
+
+ ---@type vim.quickfix.entry[]
+ local all_items = {}
+
+ ---@param result nil|lsp.Location|lsp.Location[]
+ ---@param client vim.lsp.Client
+ local function on_response(_, result, client)
+ local locations = {}
+ if result then
+ locations = vim.islist(result) and result or { result }
+ end
+ local items = util.locations_to_items(locations, client.offset_encoding)
+ vim.list_extend(all_items, items)
+ remaining = remaining - 1
+ if remaining == 0 then
+ if vim.tbl_isempty(all_items) then
+ vim.notify('No locations found', vim.log.levels.INFO)
+ return
+ end
+
+ local title = 'LSP locations'
+ if opts.on_list then
+ assert(vim.is_callable(opts.on_list), 'on_list is not a function')
+ opts.on_list({
+ title = title,
+ items = all_items,
+ context = { bufnr = bufnr, method = method },
+ })
+ return
+ end
+
+ if #all_items == 1 then
+ local item = all_items[1]
+ local b = item.bufnr or vim.fn.bufadd(item.filename)
+
+ -- Save position in jumplist
+ vim.cmd("normal! m'")
+ -- Push a new item into tagstack
+ local tagstack = { { tagname = tagname, from = from } }
+ vim.fn.settagstack(vim.fn.win_getid(win), { items = tagstack }, 't')
+
+ vim.bo[b].buflisted = true
+ local w = opts.reuse_win and vim.fn.win_findbuf(b)[1] or win
+ api.nvim_win_set_buf(w, b)
+ api.nvim_win_set_cursor(w, { item.lnum, item.col - 1 })
+ vim._with({ win = w }, function()
+ -- Open folds under the cursor
+ vim.cmd('normal! zv')
+ end)
+ return
+ end
+ if opts.loclist then
+ vim.fn.setloclist(0, {}, ' ', { title = title, items = all_items })
+ vim.cmd.lopen()
+ else
+ vim.fn.setqflist({}, ' ', { title = title, items = all_items })
+ vim.cmd('botright copen')
+ end
+ end
+ end
+ for _, client in ipairs(clients) do
+ local params = util.make_position_params(win, client.offset_encoding)
+ client.request(method, params, function(_, result)
+ on_response(_, result, client)
+ end)
+ end
end
--- @class vim.lsp.ListOpts
@@ -89,39 +275,145 @@ end
--- @note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead.
--- @param opts? vim.lsp.LocationOpts
function M.declaration(opts)
- local params = util.make_position_params()
- request_with_opts(ms.textDocument_declaration, params, opts)
+ get_locations(ms.textDocument_declaration, opts)
end
--- Jumps to the definition of the symbol under the cursor.
--- @param opts? vim.lsp.LocationOpts
function M.definition(opts)
- local params = util.make_position_params()
- request_with_opts(ms.textDocument_definition, params, opts)
+ get_locations(ms.textDocument_definition, opts)
end
--- Jumps to the definition of the type of the symbol under the cursor.
--- @param opts? vim.lsp.LocationOpts
function M.type_definition(opts)
- local params = util.make_position_params()
- request_with_opts(ms.textDocument_typeDefinition, params, opts)
+ get_locations(ms.textDocument_typeDefinition, opts)
end
--- Lists all the implementations for the symbol under the cursor in the
--- quickfix window.
--- @param opts? vim.lsp.LocationOpts
function M.implementation(opts)
- local params = util.make_position_params()
- request_with_opts(ms.textDocument_implementation, params, opts)
+ get_locations(ms.textDocument_implementation, opts)
end
+--- @param results table<integer,{err: lsp.ResponseError?, result: lsp.SignatureHelp?}>
+local function process_signature_help_results(results)
+ local signatures = {} --- @type [vim.lsp.Client,lsp.SignatureInformation][]
+
+ -- Pre-process results
+ for client_id, r in pairs(results) do
+ local err = r.err
+ local client = assert(lsp.get_client_by_id(client_id))
+ if err then
+ vim.notify(
+ client.name .. ': ' .. tostring(err.code) .. ': ' .. err.message,
+ vim.log.levels.ERROR
+ )
+ api.nvim_command('redraw')
+ else
+ local result = r.result --- @type lsp.SignatureHelp
+ if result and result.signatures and result.signatures[1] then
+ for _, sig in ipairs(result.signatures) do
+ signatures[#signatures + 1] = { client, sig }
+ end
+ end
+ end
+ end
+
+ return signatures
+end
+
+local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help')
+
+--- @class vim.lsp.buf.signature_help.Opts : vim.lsp.util.open_floating_preview.Opts
+--- @field silent? boolean
+
+-- TODO(lewis6991): support multiple clients
--- Displays signature information about the symbol under the cursor in a
--- floating window.
-function M.signature_help()
- local params = util.make_position_params()
- request(ms.textDocument_signatureHelp, params)
+--- @param config? vim.lsp.buf.signature_help.Opts
+function M.signature_help(config)
+ local method = ms.textDocument_signatureHelp
+
+ config = config and vim.deepcopy(config) or {}
+ config.focus_id = method
+
+ lsp.buf_request_all(0, method, client_positional_params(), function(results, ctx)
+ if api.nvim_get_current_buf() ~= ctx.bufnr then
+ -- Ignore result since buffer changed. This happens for slow language servers.
+ return
+ end
+
+ local signatures = process_signature_help_results(results)
+
+ if not next(signatures) then
+ if config.silent ~= true then
+ print('No signature help available')
+ end
+ return
+ end
+
+ local ft = vim.bo[ctx.bufnr].filetype
+ local total = #signatures
+ local idx = 0
+
+ --- @param update_win? integer
+ local function show_signature(update_win)
+ idx = (idx % total) + 1
+ local client, result = signatures[idx][1], signatures[idx][2]
+ --- @type string[]?
+ local triggers =
+ vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
+ local lines, hl =
+ util.convert_signature_help_to_markdown_lines({ signatures = { result } }, ft, triggers)
+ if not lines then
+ return
+ end
+
+ local sfx = total > 1 and string.format(' (%d/%d) (<C-s> to cycle)', idx, total) or ''
+ local title = string.format('Signature Help: %s%s', client.name, sfx)
+ if config.border then
+ config.title = title
+ else
+ table.insert(lines, 1, '# ' .. title)
+ if hl then
+ hl[1] = hl[1] + 1
+ hl[3] = hl[3] + 1
+ end
+ end
+
+ config._update_win = update_win
+
+ local buf, win = util.open_floating_preview(lines, 'markdown', config)
+
+ if hl then
+ vim.api.nvim_buf_clear_namespace(buf, sig_help_ns, 0, -1)
+ vim.hl.range(
+ buf,
+ sig_help_ns,
+ 'LspSignatureActiveParameter',
+ { hl[1], hl[2] },
+ { hl[3], hl[4] }
+ )
+ end
+ return buf, win
+ end
+
+ local fbuf, fwin = show_signature()
+
+ if total > 1 then
+ vim.keymap.set('n', '<C-s>', function()
+ show_signature(fwin)
+ end, {
+ buffer = fbuf,
+ desc = 'Cycle next signature',
+ })
+ end
+ end)
end
+--- @deprecated
--- Retrieves the completion items at the current cursor position. Can only be
--- called in Insert mode.
---
@@ -131,9 +423,14 @@ end
---
---@see vim.lsp.protocol.CompletionTriggerKind
function M.completion(context)
- local params = util.make_position_params()
- params.context = context
- return request(ms.textDocument_completion, params)
+ vim.depends('vim.lsp.buf.completion', 'vim.lsp.commpletion.trigger', '0.12')
+ return lsp.buf_request(
+ 0,
+ ms.textDocument_completion,
+ client_positional_params({
+ context = context,
+ })
+ )
end
---@param bufnr integer
@@ -240,7 +537,7 @@ function M.format(opts)
method = ms.textDocument_formatting
end
- local clients = vim.lsp.get_clients({
+ local clients = lsp.get_clients({
id = opts.id,
bufnr = bufnr,
name = opts.name,
@@ -277,7 +574,7 @@ function M.format(opts)
end
local params = set_range(client, util.make_formatting_params(opts.formatting_options))
client.request(method, params, function(...)
- local handler = client.handlers[method] or vim.lsp.handlers[method]
+ local handler = client.handlers[method] or lsp.handlers[method]
handler(...)
do_format(next(clients, idx))
end, bufnr)
@@ -319,7 +616,7 @@ end
function M.rename(new_name, opts)
opts = opts or {}
local bufnr = opts.bufnr or api.nvim_get_current_buf()
- local clients = vim.lsp.get_clients({
+ local clients = lsp.get_clients({
bufnr = bufnr,
name = opts.name,
-- Clients must at least support rename, prepareRename is optional
@@ -338,6 +635,8 @@ function M.rename(new_name, opts)
-- Compute early to account for cursor movements after going async
local cword = vim.fn.expand('<cword>')
+ --- @param range lsp.Range
+ --- @param offset_encoding string
local function get_text_at_range(range, offset_encoding)
return api.nvim_buf_get_text(
bufnr,
@@ -359,7 +658,7 @@ function M.rename(new_name, opts)
local params = util.make_position_params(win, client.offset_encoding)
params.newName = name
local handler = client.handlers[ms.textDocument_rename]
- or vim.lsp.handlers[ms.textDocument_rename]
+ or lsp.handlers[ms.textDocument_rename]
client.request(ms.textDocument_rename, params, function(...)
handler(...)
try_use_client(next(clients, idx))
@@ -437,12 +736,60 @@ end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
---@param opts? vim.lsp.ListOpts
function M.references(context, opts)
- validate({ context = { context, 't', true } })
- local params = util.make_position_params()
- params.context = context or {
- includeDeclaration = true,
- }
- request_with_opts(ms.textDocument_references, params, opts)
+ validate('context', context, 'table', true)
+ local bufnr = api.nvim_get_current_buf()
+ local clients = lsp.get_clients({ method = ms.textDocument_references, bufnr = bufnr })
+ if not next(clients) then
+ return
+ end
+ local win = api.nvim_get_current_win()
+ opts = opts or {}
+
+ local all_items = {}
+ local title = 'References'
+
+ local function on_done()
+ if not next(all_items) then
+ vim.notify('No references found')
+ else
+ local list = {
+ title = title,
+ items = all_items,
+ context = {
+ method = ms.textDocument_references,
+ bufnr = bufnr,
+ },
+ }
+ if opts.loclist then
+ vim.fn.setloclist(0, {}, ' ', list)
+ vim.cmd.lopen()
+ elseif opts.on_list then
+ assert(vim.is_callable(opts.on_list), 'on_list is not a function')
+ opts.on_list(list)
+ else
+ vim.fn.setqflist({}, ' ', list)
+ vim.cmd('botright copen')
+ end
+ end
+ end
+
+ local remaining = #clients
+ for _, client in ipairs(clients) do
+ local params = util.make_position_params(win, client.offset_encoding)
+
+ ---@diagnostic disable-next-line: inject-field
+ params.context = context or {
+ includeDeclaration = true,
+ }
+ client.request(ms.textDocument_references, params, function(_, result)
+ local items = util.locations_to_items(result or {}, client.offset_encoding)
+ vim.list_extend(all_items, items)
+ remaining = remaining - 1
+ if remaining == 0 then
+ on_done()
+ end
+ end)
+ end
end
--- Lists all symbols in the current buffer in the quickfix window.
@@ -452,65 +799,116 @@ function M.document_symbol(opts)
request_with_opts(ms.textDocument_documentSymbol, params, opts)
end
---- @param call_hierarchy_items lsp.CallHierarchyItem[]
---- @return lsp.CallHierarchyItem?
-local function pick_call_hierarchy_item(call_hierarchy_items)
- if #call_hierarchy_items == 1 then
- return call_hierarchy_items[1]
- end
- local items = {}
- for i, item in pairs(call_hierarchy_items) do
- local entry = item.detail or item.name
- table.insert(items, string.format('%d. %s', i, entry))
- end
- local choice = vim.fn.inputlist(items)
- if choice < 1 or choice > #items then
+--- @param client_id integer
+--- @param method string
+--- @param params table
+--- @param handler? lsp.Handler
+--- @param bufnr? integer
+local function request_with_id(client_id, method, params, handler, bufnr)
+ local client = lsp.get_client_by_id(client_id)
+ if not client then
+ vim.notify(
+ string.format('Client with id=%d disappeared during hierarchy request', client_id),
+ vim.log.levels.WARN
+ )
return
end
- return call_hierarchy_items[choice]
+ client.request(method, params, handler, bufnr)
+end
+
+--- @param item lsp.TypeHierarchyItem|lsp.CallHierarchyItem
+local function format_hierarchy_item(item)
+ if not item.detail or #item.detail == 0 then
+ return item.name
+ end
+ return string.format('%s %s', item.name, item.detail)
end
+local hierarchy_methods = {
+ [ms.typeHierarchy_subtypes] = 'type',
+ [ms.typeHierarchy_supertypes] = 'type',
+ [ms.callHierarchy_incomingCalls] = 'call',
+ [ms.callHierarchy_outgoingCalls] = 'call',
+}
+
--- @param method string
-local function call_hierarchy(method)
- local params = util.make_position_params()
- --- @param result lsp.CallHierarchyItem[]?
- request(ms.textDocument_prepareCallHierarchy, params, function(err, result, ctx)
- if err then
- vim.notify(err.message, vim.log.levels.WARN)
- return
- end
- if not result or vim.tbl_isempty(result) then
+local function hierarchy(method)
+ local kind = hierarchy_methods[method]
+ if not kind then
+ error('unsupported method ' .. method)
+ end
+
+ local prepare_method = kind == 'type' and ms.textDocument_prepareTypeHierarchy
+ or ms.textDocument_prepareCallHierarchy
+
+ local bufnr = api.nvim_get_current_buf()
+ local clients = lsp.get_clients({ bufnr = bufnr, method = prepare_method })
+ if not next(clients) then
+ vim.notify(lsp._unsupported_method(method), vim.log.levels.WARN)
+ return
+ end
+
+ local win = api.nvim_get_current_win()
+
+ --- @param results [integer, lsp.TypeHierarchyItem|lsp.CallHierarchyItem][]
+ local function on_response(results)
+ if #results == 0 then
vim.notify('No item resolved', vim.log.levels.WARN)
- return
- end
- local call_hierarchy_item = pick_call_hierarchy_item(result)
- if not call_hierarchy_item then
- return
- end
- local client = vim.lsp.get_client_by_id(ctx.client_id)
- if client then
- client.request(method, { item = call_hierarchy_item }, nil, ctx.bufnr)
+ elseif #results == 1 then
+ local client_id, item = results[1][1], results[1][2]
+ request_with_id(client_id, method, { item = item }, nil, bufnr)
else
- vim.notify(
- string.format('Client with id=%d disappeared during call hierarchy request', ctx.client_id),
- vim.log.levels.WARN
- )
+ vim.ui.select(results, {
+ prompt = string.format('Select a %s hierarchy item:', kind),
+ kind = kind .. 'hierarchy',
+ format_item = function(x)
+ return format_hierarchy_item(x[2])
+ end,
+ }, function(x)
+ if x then
+ local client_id, item = x[1], x[2]
+ request_with_id(client_id, method, { item = item }, nil, bufnr)
+ end
+ end)
end
- end)
+ end
+
+ local results = {} --- @type [integer, lsp.TypeHierarchyItem|lsp.CallHierarchyItem][]
+
+ local remaining = #clients
+
+ for _, client in ipairs(clients) do
+ local params = util.make_position_params(win, client.offset_encoding)
+ --- @param result lsp.CallHierarchyItem[]|lsp.TypeHierarchyItem[]?
+ client.request(prepare_method, params, function(err, result, ctx)
+ if err then
+ vim.notify(err.message, vim.log.levels.WARN)
+ elseif result then
+ for _, item in ipairs(result) do
+ results[#results + 1] = { ctx.client_id, item }
+ end
+ end
+
+ remaining = remaining - 1
+ if remaining == 0 then
+ on_response(results)
+ end
+ end, bufnr)
+ end
end
--- Lists all the call sites of the symbol under the cursor in the
--- |quickfix| window. If the symbol can resolve to multiple
--- items, the user can pick one in the |inputlist()|.
function M.incoming_calls()
- call_hierarchy(ms.callHierarchy_incomingCalls)
+ hierarchy(ms.callHierarchy_incomingCalls)
end
--- Lists all the items that are called by the symbol under the
--- cursor in the |quickfix| window. If the symbol can resolve to
--- multiple items, the user can pick one in the |inputlist()|.
function M.outgoing_calls()
- call_hierarchy(ms.callHierarchy_outgoingCalls)
+ hierarchy(ms.callHierarchy_outgoingCalls)
end
--- Lists all the subtypes or supertypes of the symbol under the
@@ -519,79 +917,14 @@ end
---@param kind "subtypes"|"supertypes"
function M.typehierarchy(kind)
local method = kind == 'subtypes' and ms.typeHierarchy_subtypes or ms.typeHierarchy_supertypes
-
- --- Merge results from multiple clients into a single table. Client-ID is preserved.
- ---
- --- @param results table<integer, {error: lsp.ResponseError?, result: lsp.TypeHierarchyItem[]?}>
- --- @return [integer, lsp.TypeHierarchyItem][]
- local function merge_results(results)
- local merged_results = {}
- for client_id, client_result in pairs(results) do
- if client_result.error then
- vim.notify(client_result.error.message, vim.log.levels.WARN)
- elseif client_result.result then
- for _, item in pairs(client_result.result) do
- table.insert(merged_results, { client_id, item })
- end
- end
- end
- return merged_results
- end
-
- local bufnr = api.nvim_get_current_buf()
- local params = util.make_position_params()
- --- @param results table<integer, {error: lsp.ResponseError?, result: lsp.TypeHierarchyItem[]?}>
- vim.lsp.buf_request_all(bufnr, ms.textDocument_prepareTypeHierarchy, params, function(results)
- local merged_results = merge_results(results)
- if #merged_results == 0 then
- vim.notify('No items resolved', vim.log.levels.INFO)
- return
- end
-
- if #merged_results == 1 then
- local item = merged_results[1]
- local client = vim.lsp.get_client_by_id(item[1])
- if client then
- client.request(method, { item = item[2] }, nil, bufnr)
- else
- vim.notify(
- string.format('Client with id=%d disappeared during call hierarchy request', item[1]),
- vim.log.levels.WARN
- )
- end
- else
- local select_opts = {
- prompt = 'Select a type hierarchy item:',
- kind = 'typehierarchy',
- format_item = function(item)
- if not item[2].detail or #item[2].detail == 0 then
- return item[2].name
- end
- return string.format('%s %s', item[2].name, item[2].detail)
- end,
- }
-
- vim.ui.select(merged_results, select_opts, function(item)
- local client = vim.lsp.get_client_by_id(item[1])
- if client then
- --- @type lsp.TypeHierarchyItem
- client.request(method, { item = item[2] }, nil, bufnr)
- else
- vim.notify(
- string.format('Client with id=%d disappeared during call hierarchy request', item[1]),
- vim.log.levels.WARN
- )
- end
- end)
- end
- end)
+ hierarchy(method)
end
--- List workspace folders.
---
function M.list_workspace_folders()
local workspace_folders = {}
- for _, client in pairs(vim.lsp.get_clients({ bufnr = 0 })) do
+ for _, client in pairs(lsp.get_clients({ bufnr = 0 })) do
for _, folder in pairs(client.workspace_folders or {}) do
table.insert(workspace_folders, folder.name)
end
@@ -614,7 +947,7 @@ function M.add_workspace_folder(workspace_folder)
return
end
local bufnr = api.nvim_get_current_buf()
- for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do
+ for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
client:_add_workspace_folder(workspace_folder)
end
end
@@ -631,7 +964,7 @@ function M.remove_workspace_folder(workspace_folder)
return
end
local bufnr = api.nvim_get_current_buf()
- for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do
+ for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
client:_remove_workspace_folder(workspace_folder)
end
print(workspace_folder, 'is not currently part of the workspace')
@@ -670,8 +1003,7 @@ end
--- |hl-LspReferenceRead|
--- |hl-LspReferenceWrite|
function M.document_highlight()
- local params = util.make_position_params()
- request(ms.textDocument_documentHighlight, params)
+ lsp.buf_request(0, ms.textDocument_documentHighlight, client_positional_params())
end
--- Removes document highlights from current buffer.
@@ -773,7 +1105,8 @@ local function on_code_action_results(results, opts)
local a_cmd = action.command
if a_cmd then
local command = type(a_cmd) == 'table' and a_cmd or action
- client:_exec_cmd(command, ctx)
+ --- @cast command lsp.Command
+ client:exec_cmd(command, ctx)
end
end
@@ -794,16 +1127,11 @@ local function on_code_action_results(results, opts)
-- command: string
-- arguments?: any[]
--
- local client = assert(vim.lsp.get_client_by_id(choice.ctx.client_id))
+ local client = assert(lsp.get_client_by_id(choice.ctx.client_id))
local action = choice.action
local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number')
- local reg = client.dynamic_capabilities:get(ms.textDocument_codeAction, { bufnr = bufnr })
-
- local supports_resolve = vim.tbl_get(reg or {}, 'registerOptions', 'resolveProvider')
- or client.supports_method(ms.codeAction_resolve)
-
- if not action.edit and client and supports_resolve then
+ if not action.edit and client.supports_method(ms.codeAction_resolve) then
client.request(ms.codeAction_resolve, action, function(err, resolved_action)
if err then
if action.command then
@@ -827,11 +1155,19 @@ local function on_code_action_results(results, opts)
return
end
- ---@param item {action: lsp.Command|lsp.CodeAction}
+ ---@param item {action: lsp.Command|lsp.CodeAction, ctx: lsp.HandlerContext}
local function format_item(item)
- local title = item.action.title:gsub('\r\n', '\\r\\n')
- return title:gsub('\n', '\\n')
+ local clients = lsp.get_clients({ bufnr = item.ctx.bufnr })
+ local title = item.action.title:gsub('\r\n', '\\r\\n'):gsub('\n', '\\n')
+
+ if #clients == 1 then
+ return title
+ end
+
+ local source = lsp.get_client_by_id(item.ctx.client_id).name
+ return ('%s [%s]'):format(title, source)
end
+
local select_opts = {
prompt = 'Code actions:',
kind = 'codeaction',
@@ -847,7 +1183,7 @@ end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
---@see vim.lsp.protocol.CodeActionTriggerKind
function M.code_action(opts)
- validate({ options = { opts, 't', true } })
+ validate('options', opts, 'table', true)
opts = opts or {}
-- Detect old API call code_action(context) which should now be
-- code_action({ context = context} )
@@ -857,16 +1193,16 @@ function M.code_action(opts)
end
local context = opts.context and vim.deepcopy(opts.context) or {}
if not context.triggerKind then
- context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked
+ context.triggerKind = lsp.protocol.CodeActionTriggerKind.Invoked
end
local mode = api.nvim_get_mode().mode
local bufnr = api.nvim_get_current_buf()
local win = api.nvim_get_current_win()
- local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_codeAction })
+ local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_codeAction })
local remaining = #clients
if remaining == 0 then
- if next(vim.lsp.get_clients({ bufnr = bufnr })) then
- vim.notify(vim.lsp._unsupported_method(ms.textDocument_codeAction), vim.log.levels.WARN)
+ if next(lsp.get_clients({ bufnr = bufnr })) then
+ vim.notify(lsp._unsupported_method(ms.textDocument_codeAction), vim.log.levels.WARN)
end
return
end
@@ -903,8 +1239,8 @@ function M.code_action(opts)
if context.diagnostics then
params.context = context
else
- local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false)
- local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true)
+ local ns_push = lsp.diagnostic.get_namespace(client.id, false)
+ local ns_pull = lsp.diagnostic.get_namespace(client.id, true)
local diagnostics = {}
local lnum = api.nvim_win_get_cursor(0)[1] - 1
vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum }))
@@ -921,20 +1257,20 @@ function M.code_action(opts)
end
end
+--- @deprecated
--- Executes an LSP server command.
--- @param command_params lsp.ExecuteCommandParams
--- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
function M.execute_command(command_params)
- validate({
- command = { command_params.command, 's' },
- arguments = { command_params.arguments, 't', true },
- })
+ validate('command', command_params.command, 'string')
+ validate('arguments', command_params.arguments, 'table', true)
+ vim.deprecate('execute_command', 'client:exec_cmd', '0.12')
command_params = {
command = command_params.command,
arguments = command_params.arguments,
workDoneToken = command_params.workDoneToken,
}
- request(ms.workspace_executeCommand, command_params)
+ lsp.buf_request(0, ms.workspace_executeCommand, command_params)
end
return M
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index e3c82f4169..11ecb87507 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -91,7 +91,7 @@ local validate = vim.validate
--- (default: client-id)
--- @field name? string
---
---- Language ID as string. Defaults to the filetype.
+--- Language ID as string. Defaults to the buffer filetype.
--- @field get_language_id? fun(bufnr: integer, filetype: string): string
---
--- The encoding that the LSP server expects. Client does not verify this is correct.
@@ -216,6 +216,7 @@ local validate = vim.validate
---
--- The capabilities provided by the client (editor or tool)
--- @field capabilities lsp.ClientCapabilities
+--- @field private registrations table<string,lsp.Registration[]>
--- @field dynamic_capabilities lsp.DynamicCapabilities
---
--- Sends a request to the server.
@@ -291,7 +292,7 @@ local client_index = 0
--- @param filename (string) path to check
--- @return boolean # true if {filename} exists and is a directory, false otherwise
local function is_dir(filename)
- validate({ filename = { filename, 's' } })
+ validate('filename', filename, 'string')
local stat = uv.fs_stat(filename)
return stat and stat.type == 'directory' or false
end
@@ -312,9 +313,7 @@ local valid_encodings = {
--- @param encoding string? Encoding to normalize
--- @return string # normalized encoding name
local function validate_encoding(encoding)
- validate({
- encoding = { encoding, 's', true },
- })
+ validate('encoding', encoding, 'string', true)
if not encoding then
return valid_encodings.UTF16
end
@@ -350,27 +349,23 @@ end
--- Validates a client configuration as given to |vim.lsp.start_client()|.
--- @param config vim.lsp.ClientConfig
local function validate_config(config)
- validate({
- config = { config, 't' },
- })
- validate({
- handlers = { config.handlers, 't', true },
- capabilities = { config.capabilities, 't', true },
- cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), 'directory' },
- cmd_env = { config.cmd_env, 't', true },
- detached = { config.detached, 'b', true },
- name = { config.name, 's', true },
- on_error = { config.on_error, 'f', true },
- on_exit = { config.on_exit, { 'f', 't' }, true },
- on_init = { config.on_init, { 'f', 't' }, true },
- on_attach = { config.on_attach, { 'f', 't' }, true },
- settings = { config.settings, 't', true },
- commands = { config.commands, 't', true },
- before_init = { config.before_init, { 'f', 't' }, true },
- offset_encoding = { config.offset_encoding, 's', true },
- flags = { config.flags, 't', true },
- get_language_id = { config.get_language_id, 'f', true },
- })
+ validate('config', config, 'table')
+ validate('handlers', config.handlers, 'table', true)
+ validate('capabilities', config.capabilities, 'table', true)
+ validate('cmd_cwd', config.cmd_cwd, optional_validator(is_dir), 'directory')
+ validate('cmd_env', config.cmd_env, 'table', true)
+ validate('detached', config.detached, 'boolean', true)
+ validate('name', config.name, 'string', true)
+ validate('on_error', config.on_error, 'function', true)
+ validate('on_exit', config.on_exit, { 'function', 'table' }, true)
+ validate('on_init', config.on_init, { 'function', 'table' }, true)
+ validate('on_attach', config.on_attach, { 'function', 'table' }, true)
+ validate('settings', config.settings, 'table', true)
+ validate('commands', config.commands, 'table', true)
+ validate('before_init', config.before_init, { 'function', 'table' }, true)
+ validate('offset_encoding', config.offset_encoding, 'string', true)
+ validate('flags', config.flags, 'table', true)
+ validate('get_language_id', config.get_language_id, 'function', true)
assert(
(
@@ -409,18 +404,16 @@ local function get_name(id, config)
return tostring(id)
end
---- @param workspace_folders lsp.WorkspaceFolder[]?
---- @param root_dir string?
+--- @param workspace_folders string|lsp.WorkspaceFolder[]?
--- @return lsp.WorkspaceFolder[]?
-local function get_workspace_folders(workspace_folders, root_dir)
- if workspace_folders then
+local function get_workspace_folders(workspace_folders)
+ if type(workspace_folders) == 'table' then
return workspace_folders
- end
- if root_dir then
+ elseif type(workspace_folders) == 'string' then
return {
{
- uri = vim.uri_from_fname(root_dir),
- name = root_dir,
+ uri = vim.uri_from_fname(workspace_folders),
+ name = workspace_folders,
},
}
end
@@ -457,13 +450,13 @@ function Client.create(config)
requests = {},
attached_buffers = {},
server_capabilities = {},
- dynamic_capabilities = lsp._dynamic.new(id),
+ registrations = {},
commands = config.commands or {},
settings = config.settings or {},
flags = config.flags or {},
get_language_id = config.get_language_id or default_get_language_id,
capabilities = config.capabilities or lsp.protocol.make_client_capabilities(),
- workspace_folders = get_workspace_folders(config.workspace_folders, config.root_dir),
+ workspace_folders = get_workspace_folders(config.workspace_folders or config.root_dir),
root_dir = config.root_dir,
_before_init_cb = config.before_init,
_on_init_cbs = ensure_list(config.on_init),
@@ -484,6 +477,28 @@ function Client.create(config)
messages = { name = name, messages = {}, progress = {}, status = {} },
}
+ --- @class lsp.DynamicCapabilities
+ --- @nodoc
+ self.dynamic_capabilities = {
+ capabilities = self.registrations,
+ client_id = id,
+ register = function(_, registrations)
+ return self:_register_dynamic(registrations)
+ end,
+ unregister = function(_, unregistrations)
+ return self:_unregister_dynamic(unregistrations)
+ end,
+ get = function(_, method, opts)
+ return self:_get_registration(method, opts and opts.bufnr)
+ end,
+ supports_registration = function(_, method)
+ return self:_supports_registration(method)
+ end,
+ supports = function(_, method, opts)
+ return self:_get_registration(method, opts and opts.bufnr) ~= nil
+ end,
+ }
+
self.request = method_wrapper(self, Client._request)
self.request_sync = method_wrapper(self, Client._request_sync)
self.notify = method_wrapper(self, Client._notify)
@@ -640,7 +655,7 @@ end
--- @param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer
--- @return integer bufnr
local function resolve_bufnr(bufnr)
- validate({ bufnr = { bufnr, 'n', true } })
+ validate('bufnr', bufnr, 'number', true)
if bufnr == nil or bufnr == 0 then
return api.nvim_get_current_buf()
end
@@ -806,7 +821,7 @@ end
--- @return boolean status true if notification was successful. false otherwise
--- @see |vim.lsp.client.notify()|
function Client:_cancel_request(id)
- validate({ id = { id, 'n' } })
+ validate('id', id, 'number')
local request = self.requests[id]
if request and request.type == 'pending' then
request.type = 'cancel'
@@ -852,6 +867,105 @@ function Client:_stop(force)
end)
end
+--- Get options for a method that is registered dynamically.
+--- @param method string
+function Client:_supports_registration(method)
+ local capability = vim.tbl_get(self.capabilities, unpack(vim.split(method, '/')))
+ return type(capability) == 'table' and capability.dynamicRegistration
+end
+
+--- @private
+--- @param registrations lsp.Registration[]
+function Client:_register_dynamic(registrations)
+ -- remove duplicates
+ self:_unregister_dynamic(registrations)
+ for _, reg in ipairs(registrations) do
+ local method = reg.method
+ if not self.registrations[method] then
+ self.registrations[method] = {}
+ end
+ table.insert(self.registrations[method], reg)
+ end
+end
+
+--- @param registrations lsp.Registration[]
+function Client:_register(registrations)
+ self:_register_dynamic(registrations)
+
+ local unsupported = {} --- @type string[]
+
+ for _, reg in ipairs(registrations) do
+ local method = reg.method
+ if method == ms.workspace_didChangeWatchedFiles then
+ vim.lsp._watchfiles.register(reg, self.id)
+ elseif not self:_supports_registration(method) then
+ unsupported[#unsupported + 1] = method
+ end
+ end
+
+ if #unsupported > 0 then
+ local warning_tpl = 'The language server %s triggers a registerCapability '
+ .. 'handler for %s despite dynamicRegistration set to false. '
+ .. 'Report upstream, this warning is harmless'
+ log.warn(string.format(warning_tpl, self.name, table.concat(unsupported, ', ')))
+ end
+end
+
+--- @private
+--- @param unregistrations lsp.Unregistration[]
+function Client:_unregister_dynamic(unregistrations)
+ for _, unreg in ipairs(unregistrations) do
+ local sreg = self.registrations[unreg.method]
+ -- Unegister dynamic capability
+ for i, reg in ipairs(sreg or {}) do
+ if reg.id == unreg.id then
+ table.remove(sreg, i)
+ break
+ end
+ end
+ end
+end
+
+--- @param unregistrations lsp.Unregistration[]
+function Client:_unregister(unregistrations)
+ self:_unregister_dynamic(unregistrations)
+ for _, unreg in ipairs(unregistrations) do
+ if unreg.method == ms.workspace_didChangeWatchedFiles then
+ vim.lsp._watchfiles.unregister(unreg, self.id)
+ end
+ end
+end
+
+--- @private
+function Client:_get_language_id(bufnr)
+ return self.get_language_id(bufnr, vim.bo[bufnr].filetype)
+end
+
+--- @param method string
+--- @param bufnr? integer
+--- @return lsp.Registration?
+function Client:_get_registration(method, bufnr)
+ bufnr = bufnr or vim.api.nvim_get_current_buf()
+ for _, reg in ipairs(self.registrations[method] or {}) do
+ if not reg.registerOptions or not reg.registerOptions.documentSelector then
+ return reg
+ end
+ local documentSelector = reg.registerOptions.documentSelector
+ local language = self:_get_language_id(bufnr)
+ local uri = vim.uri_from_bufnr(bufnr)
+ local fname = vim.uri_to_fname(uri)
+ for _, filter in ipairs(documentSelector) do
+ if
+ not (filter.language and language ~= filter.language)
+ and not (filter.scheme and not vim.startswith(uri, filter.scheme .. ':'))
+ and not (filter.pattern and not vim.glob.to_lpeg(filter.pattern):match(fname))
+ then
+ return reg
+ end
+ end
+ end
+end
+
--- @private
--- Checks whether a client is stopped.
---
@@ -865,10 +979,9 @@ end
--- or via workspace/executeCommand (if supported by the server)
---
--- @param command lsp.Command
---- @param context? {bufnr: integer}
+--- @param context? {bufnr?: integer}
--- @param handler? lsp.Handler only called if a server command
---- @param on_unsupported? function handler invoked when the command is not supported by the client.
-function Client:_exec_cmd(command, context, handler, on_unsupported)
+function Client:exec_cmd(command, context, handler)
context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]]
context.bufnr = context.bufnr or api.nvim_get_current_buf()
context.client_id = self.id
@@ -881,25 +994,23 @@ function Client:_exec_cmd(command, context, handler, on_unsupported)
local command_provider = self.server_capabilities.executeCommandProvider
local commands = type(command_provider) == 'table' and command_provider.commands or {}
+
if not vim.list_contains(commands, cmdname) then
- if on_unsupported then
- on_unsupported()
- else
- vim.notify_once(
- string.format(
- 'Language server `%s` does not support command `%s`. This command may require a client extension.',
- self.name,
- cmdname
- ),
- vim.log.levels.WARN
- )
- end
+ vim.notify_once(
+ string.format(
+ 'Language server `%s` does not support command `%s`. This command may require a client extension.',
+ self.name,
+ cmdname
+ ),
+ vim.log.levels.WARN
+ )
return
end
-- Not using command directly to exclude extra properties,
-- see https://github.com/python-lsp/python-lsp-server/issues/146
+ --- @type lsp.ExecuteCommandParams
local params = {
- command = command.command,
+ command = cmdname,
arguments = command.arguments,
}
self.request(ms.workspace_executeCommand, params, handler, context.bufnr)
@@ -917,12 +1028,11 @@ function Client:_text_document_did_open_handler(bufnr)
return
end
- local filetype = vim.bo[bufnr].filetype
self.notify(ms.textDocument_didOpen, {
textDocument = {
version = lsp.util.buf_versions[bufnr],
uri = vim.uri_from_bufnr(bufnr),
- languageId = self.get_language_id(bufnr, filetype),
+ languageId = self:_get_language_id(bufnr),
text = lsp._buf_get_full_text(bufnr),
},
})
@@ -987,12 +1097,37 @@ function Client:_supports_method(method, opts)
if vim.tbl_get(self.server_capabilities, unpack(required_capability)) then
return true
end
- if self.dynamic_capabilities:supports_registration(method) then
- return self.dynamic_capabilities:supports(method, opts)
+
+ local rmethod = lsp._resolve_to_request[method]
+ if rmethod then
+ if self:_supports_registration(rmethod) then
+ local reg = self:_get_registration(rmethod, opts and opts.bufnr)
+ return vim.tbl_get(reg or {}, 'registerOptions', 'resolveProvider') or false
+ end
+ else
+ if self:_supports_registration(method) then
+ return self:_get_registration(method, opts and opts.bufnr) ~= nil
+ end
end
return false
end
+--- Get options for a method that is registered dynamically.
+--- @param method string
+--- @param bufnr? integer
+--- @return lsp.LSPAny?
+function Client:_get_registration_options(method, bufnr)
+ if not self:_supports_registration(method) then
+ return
+ end
+
+ local reg = self:_get_registration(method, bufnr)
+
+ if reg then
+ return reg.registerOptions
+ end
+end
+
--- @private
--- Handles a notification sent by an LSP server by invoking the
--- corresponding handler.
@@ -1070,7 +1205,7 @@ function Client:_add_workspace_folder(dir)
end
end
- local wf = assert(get_workspace_folders(nil, dir))
+ local wf = assert(get_workspace_folders(dir))
self:_notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = wf, removed = {} },
@@ -1085,7 +1220,7 @@ end
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
- local wf = assert(get_workspace_folders(nil, dir))
+ local wf = assert(get_workspace_folders(dir))
self:_notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = {}, removed = wf },
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index c1b6bfb28c..fdbdda695a 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -48,7 +48,7 @@ local function execute_lens(lens, bufnr, client_id)
local client = vim.lsp.get_client_by_id(client_id)
assert(client, 'Client is required to execute lens, client_id=' .. client_id)
- client:_exec_cmd(lens.command, { bufnr = bufnr }, function(...)
+ client:exec_cmd(lens.command, { bufnr = bufnr }, function(...)
vim.lsp.handlers[ms.workspace_executeCommand](...)
M.refresh()
end)
@@ -261,7 +261,7 @@ end
---@param err lsp.ResponseError?
---@param result lsp.CodeLens[]
---@param ctx lsp.HandlerContext
-function M.on_codelens(err, result, ctx, _)
+function M.on_codelens(err, result, ctx)
if err then
active_refreshes[assert(ctx.bufnr)] = nil
log.error('codelens', err)
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index 71ea2df100..92bc110a97 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -113,12 +113,11 @@ local function parse_snippet(input)
end
--- @param item lsp.CompletionItem
---- @param suffix? string
-local function apply_snippet(item, suffix)
+local function apply_snippet(item)
if item.textEdit then
- vim.snippet.expand(item.textEdit.newText .. suffix)
+ vim.snippet.expand(item.textEdit.newText)
elseif item.insertText then
- vim.snippet.expand(item.insertText .. suffix)
+ vim.snippet.expand(item.insertText)
end
end
@@ -221,6 +220,20 @@ local function get_doc(item)
return ''
end
+---@param value string
+---@param prefix string
+---@return boolean
+local function match_item_by_value(value, prefix)
+ if vim.o.completeopt:find('fuzzy') ~= nil then
+ return next(vim.fn.matchfuzzy({ value }, prefix)) ~= nil
+ end
+
+ if vim.o.ignorecase and (not vim.o.smartcase or not prefix:find('%u')) then
+ return vim.startswith(value:lower(), prefix:lower())
+ end
+ return vim.startswith(value, prefix)
+end
+
--- Turns the result of a `textDocument/completion` request into vim-compatible
--- |complete-items|.
---
@@ -245,8 +258,16 @@ function M._lsp_to_complete_items(result, prefix, client_id)
else
---@param item lsp.CompletionItem
matches = function(item)
- local text = item.filterText or item.label
- return next(vim.fn.matchfuzzy({ text }, prefix)) ~= nil
+ if item.filterText then
+ return match_item_by_value(item.filterText, prefix)
+ end
+
+ if item.textEdit then
+ -- server took care of filtering
+ return true
+ end
+
+ return match_item_by_value(item.label, prefix)
end
end
@@ -272,7 +293,7 @@ function M._lsp_to_complete_items(result, prefix, client_id)
icase = 1,
dup = 1,
empty = 1,
- hl_group = hl_group,
+ abbr_hlgroup = hl_group,
user_data = {
nvim = {
lsp = {
@@ -316,7 +337,7 @@ local function adjust_start_col(lnum, line, items, encoding)
end
end
if min_start_char then
- return lsp.util._str_byteindex_enc(line, min_start_char, encoding)
+ return vim.str_byteindex(line, encoding, min_start_char, false)
else
return nil
end
@@ -539,35 +560,24 @@ local function on_complete_done()
-- Remove the already inserted word.
local start_char = cursor_col - #completed_item.word
- local line = api.nvim_buf_get_lines(bufnr, cursor_row, cursor_row + 1, true)[1]
- api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, #line, { '' })
- return line:sub(cursor_col + 1)
+ api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, cursor_col, { '' })
end
- --- @param suffix? string
- local function apply_snippet_and_command(suffix)
+ local function apply_snippet_and_command()
if expand_snippet then
- apply_snippet(completion_item, suffix)
+ apply_snippet(completion_item)
end
local command = completion_item.command
if command then
- client:_exec_cmd(command, { bufnr = bufnr }, nil, function()
- vim.lsp.log.warn(
- string.format(
- 'Language server `%s` does not support command `%s`. This command may require a client extension.',
- client.name,
- command.command
- )
- )
- end)
+ client:exec_cmd(command, { bufnr = bufnr })
end
end
if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then
- local suffix = clear_word()
+ clear_word()
lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding)
- apply_snippet_and_command(suffix)
+ apply_snippet_and_command()
elseif resolve_provider and type(completion_item) == 'table' then
local changedtick = vim.b[bufnr].changedtick
@@ -577,7 +587,7 @@ local function on_complete_done()
return
end
- local suffix = clear_word()
+ clear_word()
if err then
vim.notify_once(err.message, vim.log.levels.WARN)
elseif result and result.additionalTextEdits then
@@ -587,16 +597,16 @@ local function on_complete_done()
end
end
- apply_snippet_and_command(suffix)
+ apply_snippet_and_command()
end, bufnr)
else
- local suffix = clear_word()
- apply_snippet_and_command(suffix)
+ clear_word()
+ apply_snippet_and_command()
end
end
--- @class vim.lsp.completion.BufferOpts
---- @field autotrigger? boolean Whether to trigger completion automatically. Default: false
+--- @field autotrigger? boolean Default: false When true, completion triggers automatically based on the server's `triggerCharacters`.
--- @field convert? fun(item: lsp.CompletionItem): table Transforms an LSP CompletionItem to |complete-items|.
---@param client_id integer
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index c10312484b..8fd30c7668 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -9,14 +9,6 @@ local augroup = api.nvim_create_augroup('vim_lsp_diagnostic', {})
local DEFAULT_CLIENT_ID = -1
-local function get_client_id(client_id)
- if client_id == nil then
- client_id = DEFAULT_CLIENT_ID
- end
-
- return client_id
-end
-
---@param severity lsp.DiagnosticSeverity
local function severity_lsp_to_vim(severity)
if type(severity) == 'string' then
@@ -33,25 +25,6 @@ local function severity_vim_to_lsp(severity)
return severity
end
----@param lines string[]?
----@param lnum integer
----@param col integer
----@param offset_encoding string
----@return integer
-local function line_byte_from_position(lines, lnum, col, offset_encoding)
- if not lines or offset_encoding == 'utf-8' then
- return col
- end
-
- local line = lines[lnum + 1]
- local ok, result = pcall(vim.str_byteindex, line, col, offset_encoding == 'utf-16')
- if ok then
- return result --- @type integer
- end
-
- return col
-end
-
---@param bufnr integer
---@return string[]?
local function get_buf_lines(bufnr)
@@ -118,12 +91,13 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
)
message = diagnostic.message.value
end
+ local line = buf_lines and buf_lines[start.line + 1] or ''
--- @type vim.Diagnostic
return {
lnum = start.line,
- col = line_byte_from_position(buf_lines, start.line, start.character, offset_encoding),
+ col = vim.str_byteindex(line, offset_encoding, start.character, false),
end_lnum = _end.line,
- end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
+ end_col = vim.str_byteindex(line, offset_encoding, _end.character, false),
severity = severity_lsp_to_vim(diagnostic.severity),
message = message,
source = diagnostic.source,
@@ -195,7 +169,7 @@ local _client_pull_namespaces = {}
---@param client_id integer The id of the LSP client
---@param is_pull boolean? Whether the namespace is for a pull or push client. Defaults to push
function M.get_namespace(client_id, is_pull)
- vim.validate({ client_id = { client_id, 'n' } })
+ vim.validate('client_id', client_id, 'number')
local client = vim.lsp.get_client_by_id(client_id)
if is_pull then
@@ -236,8 +210,7 @@ end
--- @param client_id? integer
--- @param diagnostics vim.Diagnostic[]
--- @param is_pull boolean
---- @param config? vim.diagnostic.Opts
-local function handle_diagnostics(uri, client_id, diagnostics, is_pull, config)
+local function handle_diagnostics(uri, client_id, diagnostics, is_pull)
local fname = vim.uri_to_fname(uri)
if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then
@@ -249,91 +222,39 @@ local function handle_diagnostics(uri, client_id, diagnostics, is_pull, config)
return
end
- client_id = get_client_id(client_id)
- local namespace = M.get_namespace(client_id, is_pull)
-
- if config then
- --- @cast config table<string, table>
- for _, opt in pairs(config) do
- convert_severity(opt)
- end
- -- Persist configuration to ensure buffer reloads use the same
- -- configuration. To make lsp.with configuration work (See :help
- -- lsp-handler-configuration)
- vim.diagnostic.config(config, namespace)
+ if client_id == nil then
+ client_id = DEFAULT_CLIENT_ID
end
+ local namespace = M.get_namespace(client_id, is_pull)
+
vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id))
end
--- |lsp-handler| for the method "textDocument/publishDiagnostics"
---
---- See |vim.diagnostic.config()| for configuration options. Handler-specific
---- configuration can be set using |vim.lsp.with()|:
----
---- ```lua
---- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
---- vim.lsp.diagnostic.on_publish_diagnostics, {
---- -- Enable underline, use default values
---- underline = true,
---- -- Enable virtual text, override spacing to 4
---- virtual_text = {
---- spacing = 4,
---- },
---- -- Use a function to dynamically turn signs off
---- -- and on, using buffer local variables
---- signs = function(namespace, bufnr)
---- return vim.b[bufnr].show_signs == true
---- end,
---- -- Disable a feature
---- update_in_insert = false,
---- }
---- )
---- ```
+--- See |vim.diagnostic.config()| for configuration options.
---
---@param _ lsp.ResponseError?
---@param result lsp.PublishDiagnosticsParams
---@param ctx lsp.HandlerContext
----@param config? vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|).
-function M.on_publish_diagnostics(_, result, ctx, config)
- handle_diagnostics(result.uri, ctx.client_id, result.diagnostics, false, config)
+function M.on_publish_diagnostics(_, result, ctx)
+ handle_diagnostics(result.uri, ctx.client_id, result.diagnostics, false)
end
--- |lsp-handler| for the method "textDocument/diagnostic"
---
---- See |vim.diagnostic.config()| for configuration options. Handler-specific
---- configuration can be set using |vim.lsp.with()|:
----
---- ```lua
---- vim.lsp.handlers["textDocument/diagnostic"] = vim.lsp.with(
---- vim.lsp.diagnostic.on_diagnostic, {
---- -- Enable underline, use default values
---- underline = true,
---- -- Enable virtual text, override spacing to 4
---- virtual_text = {
---- spacing = 4,
---- },
---- -- Use a function to dynamically turn signs off
---- -- and on, using buffer local variables
---- signs = function(namespace, bufnr)
---- return vim.b[bufnr].show_signs == true
---- end,
---- -- Disable a feature
---- update_in_insert = false,
---- }
---- )
---- ```
+--- See |vim.diagnostic.config()| for configuration options.
---
---@param _ lsp.ResponseError?
---@param result lsp.DocumentDiagnosticReport
---@param ctx lsp.HandlerContext
----@param config vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|).
-function M.on_diagnostic(_, result, ctx, config)
+function M.on_diagnostic(_, result, ctx)
if result == nil or result.kind == 'unchanged' then
return
end
- handle_diagnostics(ctx.params.textDocument.uri, ctx.client_id, result.items, true, config)
+ handle_diagnostics(ctx.params.textDocument.uri, ctx.client_id, result.items, true)
end
--- Clear push diagnostics and diagnostic cache.
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 44548fec92..5c28d88b38 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -5,10 +5,21 @@ local util = require('vim.lsp.util')
local api = vim.api
local completion = require('vim.lsp.completion')
---- @type table<string,lsp.Handler>
+--- @type table<string, lsp.Handler>
local M = {}
--- FIXME: DOC: Expose in vimdocs
+--- @deprecated
+--- Client to server response handlers.
+--- @type table<vim.lsp.protocol.Method.ClientToServer, lsp.Handler>
+local RCS = {}
+
+--- Server to client request handlers.
+--- @type table<vim.lsp.protocol.Method.ServerToClient, lsp.Handler>
+local RSC = {}
+
+--- Server to client notification handlers.
+--- @type table<vim.lsp.protocol.Method.ServerToClient, lsp.Handler>
+local NSC = {}
--- Writes to error buffer.
---@param ... string Will be concatenated before being written
@@ -18,14 +29,15 @@ local function err_message(...)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
-M[ms.workspace_executeCommand] = function(_, _, _, _)
+RCS[ms.workspace_executeCommand] = function(_, _, _)
-- Error handling is done implicitly by wrapping all handlers; see end of this file
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
---@param params lsp.ProgressParams
---@param ctx lsp.HandlerContext
-M[ms.dollar_progress] = function(_, params, ctx)
+---@diagnostic disable-next-line:no-unknown
+RSC[ms.dollar_progress] = function(_, params, ctx)
local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
err_message('LSP[id=', tostring(ctx.client_id), '] client has shut down during progress update')
@@ -59,26 +71,26 @@ M[ms.dollar_progress] = function(_, params, ctx)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create
----@param result lsp.WorkDoneProgressCreateParams
+---@param params lsp.WorkDoneProgressCreateParams
---@param ctx lsp.HandlerContext
-M[ms.window_workDoneProgress_create] = function(_, result, ctx)
+RSC[ms.window_workDoneProgress_create] = function(_, params, ctx)
local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
err_message('LSP[id=', tostring(ctx.client_id), '] client has shut down during progress update')
return vim.NIL
end
- client.progress:push(result)
+ client.progress:push(params)
return vim.NIL
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest
----@param result lsp.ShowMessageRequestParams
-M[ms.window_showMessageRequest] = function(_, result)
- local actions = result.actions or {}
+---@param params lsp.ShowMessageRequestParams
+RSC[ms.window_showMessageRequest] = function(_, params)
+ local actions = params.actions or {}
local co, is_main = coroutine.running()
if co and not is_main then
local opts = {
- prompt = result.message .. ': ',
+ prompt = params.message .. ': ',
format_item = function(action)
return (action.title:gsub('\r\n', '\\r\\n')):gsub('\n', '\\n')
end,
@@ -92,7 +104,7 @@ M[ms.window_showMessageRequest] = function(_, result)
end)
return coroutine.yield()
else
- local option_strings = { result.message, '\nRequest Actions:' }
+ local option_strings = { params.message, '\nRequest Actions:' }
for i, action in ipairs(actions) do
local title = action.title:gsub('\r\n', '\\r\\n')
title = title:gsub('\n', '\\n')
@@ -108,65 +120,37 @@ M[ms.window_showMessageRequest] = function(_, result)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
---- @param result lsp.RegistrationParams
-M[ms.client_registerCapability] = function(_, result, ctx)
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
-
- client.dynamic_capabilities:register(result.registrations)
- for bufnr, _ in pairs(client.attached_buffers) do
+--- @param params lsp.RegistrationParams
+RSC[ms.client_registerCapability] = function(_, params, ctx)
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
+ client:_register(params.registrations)
+ for bufnr in pairs(client.attached_buffers) do
vim.lsp._set_defaults(client, bufnr)
end
-
- ---@type string[]
- local unsupported = {}
- for _, reg in ipairs(result.registrations) do
- if reg.method == ms.workspace_didChangeWatchedFiles then
- vim.lsp._watchfiles.register(reg, ctx)
- elseif not client.dynamic_capabilities:supports_registration(reg.method) then
- unsupported[#unsupported + 1] = reg.method
- end
- end
- if #unsupported > 0 then
- local warning_tpl = 'The language server %s triggers a registerCapability '
- .. 'handler for %s despite dynamicRegistration set to false. '
- .. 'Report upstream, this warning is harmless'
- local client_name = client and client.name or string.format('id=%d', client_id)
- local warning = string.format(warning_tpl, client_name, table.concat(unsupported, ', '))
- log.warn(warning)
- end
return vim.NIL
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_unregisterCapability
---- @param result lsp.UnregistrationParams
-M[ms.client_unregisterCapability] = function(_, result, ctx)
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
- client.dynamic_capabilities:unregister(result.unregisterations)
-
- for _, unreg in ipairs(result.unregisterations) do
- if unreg.method == ms.workspace_didChangeWatchedFiles then
- vim.lsp._watchfiles.unregister(unreg, ctx)
- end
- end
+--- @param params lsp.UnregistrationParams
+RSC[ms.client_unregisterCapability] = function(_, params, ctx)
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
+ client:_unregister(params.unregisterations)
return vim.NIL
end
+-- TODO(lewis6991): Do we need to notify other servers?
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
-M[ms.workspace_applyEdit] = function(_, workspace_edit, ctx)
+RSC[ms.workspace_applyEdit] = function(_, params, ctx)
assert(
- workspace_edit,
+ params,
'workspace/applyEdit must be called with `ApplyWorkspaceEditParams`. Server is violating the specification'
)
-- TODO(ashkan) Do something more with label?
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
- if workspace_edit.label then
- print('Workspace edit', workspace_edit.label)
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
+ if params.label then
+ print('Workspace edit', params.label)
end
- local status, result =
- pcall(util.apply_workspace_edit, workspace_edit.edit, client.offset_encoding)
+ local status, result = pcall(util.apply_workspace_edit, params.edit, client.offset_encoding)
return {
applied = status,
failureReason = result,
@@ -182,24 +166,23 @@ local function lookup_section(table, section)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
---- @param result lsp.ConfigurationParams
-M[ms.workspace_configuration] = function(_, result, ctx)
- local client_id = ctx.client_id
- local client = vim.lsp.get_client_by_id(client_id)
+--- @param params lsp.ConfigurationParams
+RSC[ms.workspace_configuration] = function(_, params, ctx)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
err_message(
'LSP[',
- client_id,
+ ctx.client_id,
'] client has shut down after sending a workspace/configuration request'
)
return
end
- if not result.items then
+ if not params.items then
return {}
end
local response = {}
- for _, item in ipairs(result.items) do
+ for _, item in ipairs(params.items) do
if item.section then
local value = lookup_section(client.settings, item.section)
-- For empty sections with no explicit '' key, return settings as is
@@ -216,57 +199,34 @@ M[ms.workspace_configuration] = function(_, result, ctx)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_workspaceFolders
-M[ms.workspace_workspaceFolders] = function(_, _, ctx)
- local client_id = ctx.client_id
- local client = vim.lsp.get_client_by_id(client_id)
+RSC[ms.workspace_workspaceFolders] = function(_, _, ctx)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
- err_message('LSP[id=', client_id, '] client has shut down after sending the message')
+ err_message('LSP[id=', ctx.client_id, '] client has shut down after sending the message')
return
end
return client.workspace_folders or vim.NIL
end
-M[ms.textDocument_publishDiagnostics] = function(...)
+NSC[ms.textDocument_publishDiagnostics] = function(...)
return vim.lsp.diagnostic.on_publish_diagnostics(...)
end
-M[ms.textDocument_diagnostic] = function(...)
+--- @private
+RCS[ms.textDocument_diagnostic] = function(...)
return vim.lsp.diagnostic.on_diagnostic(...)
end
-M[ms.textDocument_codeLens] = function(...)
+--- @private
+RCS[ms.textDocument_codeLens] = function(...)
return vim.lsp.codelens.on_codelens(...)
end
-M[ms.textDocument_inlayHint] = function(...)
+--- @private
+RCS[ms.textDocument_inlayHint] = function(...)
return vim.lsp.inlay_hint.on_inlayhint(...)
end
---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
-M[ms.textDocument_references] = function(_, result, ctx, config)
- if not result or vim.tbl_isempty(result) then
- vim.notify('No references found')
- return
- end
-
- local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
- config = config or {}
- local title = 'References'
- local items = util.locations_to_items(result, client.offset_encoding)
-
- local list = { title = title, items = items, context = ctx }
- if config.loclist then
- vim.fn.setloclist(0, {}, ' ', list)
- vim.cmd.lopen()
- elseif config.on_list then
- assert(vim.is_callable(config.on_list), 'on_list is not a function')
- config.on_list(list)
- else
- vim.fn.setqflist({}, ' ', list)
- vim.cmd('botright copen')
- end
-end
-
--- Return a function that converts LSP responses to list items and opens the list
---
--- The returned function has an optional {config} parameter that accepts |vim.lsp.ListOpts|
@@ -276,6 +236,7 @@ end
---@param title_fn fun(ctx: lsp.HandlerContext): string Function to call to generate list title
---@return lsp.Handler
local function response_to_list(map_result, entity, title_fn)
+ --- @diagnostic disable-next-line:redundant-parameter
return function(_, result, ctx, config)
if not result or vim.tbl_isempty(result) then
vim.notify('No ' .. entity .. ' found')
@@ -299,8 +260,9 @@ local function response_to_list(map_result, entity, title_fn)
end
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
-M[ms.textDocument_documentSymbol] = response_to_list(
+RCS[ms.textDocument_documentSymbol] = response_to_list(
util.symbols_to_items,
'document symbols',
function(ctx)
@@ -309,13 +271,15 @@ M[ms.textDocument_documentSymbol] = response_to_list(
end
)
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
-M[ms.workspace_symbol] = response_to_list(util.symbols_to_items, 'symbols', function(ctx)
+RCS[ms.workspace_symbol] = response_to_list(util.symbols_to_items, 'symbols', function(ctx)
return string.format("Symbols matching '%s'", ctx.params.query)
end)
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
-M[ms.textDocument_rename] = function(_, result, ctx, _)
+RCS[ms.textDocument_rename] = function(_, result, ctx)
if not result then
vim.notify("Language server couldn't provide rename result", vim.log.levels.INFO)
return
@@ -324,8 +288,9 @@ M[ms.textDocument_rename] = function(_, result, ctx, _)
util.apply_workspace_edit(result, client.offset_encoding)
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
-M[ms.textDocument_rangeFormatting] = function(_, result, ctx, _)
+RCS[ms.textDocument_rangeFormatting] = function(_, result, ctx)
if not result then
return
end
@@ -333,8 +298,9 @@ M[ms.textDocument_rangeFormatting] = function(_, result, ctx, _)
util.apply_text_edits(result, ctx.bufnr, client.offset_encoding)
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
-M[ms.textDocument_formatting] = function(_, result, ctx, _)
+RCS[ms.textDocument_formatting] = function(_, result, ctx)
if not result then
return
end
@@ -342,8 +308,9 @@ M[ms.textDocument_formatting] = function(_, result, ctx, _)
util.apply_text_edits(result, ctx.bufnr, client.offset_encoding)
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
-M[ms.textDocument_completion] = function(_, result, _, _)
+RCS[ms.textDocument_completion] = function(_, result, _)
if vim.tbl_isempty(result or {}) then
return
end
@@ -358,6 +325,7 @@ M[ms.textDocument_completion] = function(_, result, _, _)
vim.fn.complete(textMatch + 1, matches)
end
+--- @deprecated
--- |lsp-handler| for the method "textDocument/hover"
---
--- ```lua
@@ -378,6 +346,7 @@ end
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.lsp.util.open_floating_preview()| for more options.
+--- @diagnostic disable-next-line:redundant-parameter
function M.hover(_, result, ctx, config)
config = config or {}
config.focus_id = ctx.method
@@ -408,60 +377,14 @@ function M.hover(_, result, ctx, config)
return util.open_floating_preview(contents, format, config)
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
-M[ms.textDocument_hover] = M.hover
-
---- Jumps to a location. Used as a handler for multiple LSP methods.
----@param _ nil not used
----@param result (table) result of LSP method; a location or a list of locations.
----@param ctx (lsp.HandlerContext) table containing the context of the request, including the method
----@param config? vim.lsp.LocationOpts
----(`textDocument/definition` can return `Location` or `Location[]`
-local function location_handler(_, result, ctx, config)
- if result == nil or vim.tbl_isempty(result) then
- log.info(ctx.method, 'No location found')
- return nil
- end
- local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
-
- config = config or {}
-
- -- textDocument/definition can return Location or Location[]
- -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
- if not vim.islist(result) then
- result = { result }
- end
+--- @diagnostic disable-next-line: deprecated
+RCS[ms.textDocument_hover] = M.hover
- local title = 'LSP locations'
- local items = util.locations_to_items(result, client.offset_encoding)
-
- if config.on_list then
- assert(vim.is_callable(config.on_list), 'on_list is not a function')
- config.on_list({ title = title, items = items })
- return
- end
- if #result == 1 then
- util.jump_to_location(result[1], client.offset_encoding, config.reuse_win)
- return
- end
- if config.loclist then
- vim.fn.setloclist(0, {}, ' ', { title = title, items = items })
- vim.cmd.lopen()
- else
- vim.fn.setqflist({}, ' ', { title = title, items = items })
- vim.cmd('botright copen')
- end
-end
-
---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
-M[ms.textDocument_declaration] = location_handler
---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
-M[ms.textDocument_definition] = location_handler
---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
-M[ms.textDocument_typeDefinition] = location_handler
---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
-M[ms.textDocument_implementation] = location_handler
+local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help')
+--- @deprecated remove in 0.13
--- |lsp-handler| for the method "textDocument/signatureHelp".
---
--- The active parameter is highlighted with |hl-LspSignatureActiveParameter|.
@@ -476,12 +399,13 @@ M[ms.textDocument_implementation] = location_handler
--- ```
---
---@param _ lsp.ResponseError?
----@param result lsp.SignatureHelp Response from the language server
+---@param result lsp.SignatureHelp? Response from the language server
---@param ctx lsp.HandlerContext Client context
---@param config table Configuration table.
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.lsp.util.open_floating_preview()| for more options
+--- @diagnostic disable-next-line:redundant-parameter
function M.signature_help(_, result, ctx, config)
config = config or {}
config.focus_id = ctx.method
@@ -509,19 +433,27 @@ function M.signature_help(_, result, ctx, config)
return
end
local fbuf, fwin = util.open_floating_preview(lines, 'markdown', config)
+ -- Highlight the active parameter.
if hl then
- -- Highlight the second line if the signature is wrapped in a Markdown code block.
- local line = vim.startswith(lines[1], '```') and 1 or 0
- api.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', line, unpack(hl))
+ vim.hl.range(
+ fbuf,
+ sig_help_ns,
+ 'LspSignatureActiveParameter',
+ { hl[1], hl[2] },
+ { hl[3], hl[4] }
+ )
end
return fbuf, fwin
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
-M[ms.textDocument_signatureHelp] = M.signature_help
+--- @diagnostic disable-next-line:deprecated
+RCS[ms.textDocument_signatureHelp] = M.signature_help
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
-M[ms.textDocument_documentHighlight] = function(_, result, ctx, _)
+RCS[ms.textDocument_documentHighlight] = function(_, result, ctx)
if not result then
return
end
@@ -564,11 +496,13 @@ local function make_call_hierarchy_handler(direction)
end
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls
-M[ms.callHierarchy_incomingCalls] = make_call_hierarchy_handler('from')
+RCS[ms.callHierarchy_incomingCalls] = make_call_hierarchy_handler('from')
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls
-M[ms.callHierarchy_outgoingCalls] = make_call_hierarchy_handler('to')
+RCS[ms.callHierarchy_outgoingCalls] = make_call_hierarchy_handler('to')
--- Displays type hierarchy in the quickfix window.
local function make_type_hierarchy_handler()
@@ -603,17 +537,19 @@ local function make_type_hierarchy_handler()
end
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#typeHierarchy_incomingCalls
-M[ms.typeHierarchy_subtypes] = make_type_hierarchy_handler()
+RCS[ms.typeHierarchy_subtypes] = make_type_hierarchy_handler()
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#typeHierarchy_outgoingCalls
-M[ms.typeHierarchy_supertypes] = make_type_hierarchy_handler()
+RCS[ms.typeHierarchy_supertypes] = make_type_hierarchy_handler()
--- @see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage
---- @param result lsp.LogMessageParams
-M[ms.window_logMessage] = function(_, result, ctx, _)
- local message_type = result.type
- local message = result.message
+--- @param params lsp.LogMessageParams
+NSC['window/logMessage'] = function(_, params, ctx)
+ local message_type = params.type
+ local message = params.message
local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format('id=%d', client_id)
@@ -629,14 +565,14 @@ M[ms.window_logMessage] = function(_, result, ctx, _)
else
log.debug(message)
end
- return result
+ return params
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage
---- @param result lsp.ShowMessageParams
-M[ms.window_showMessage] = function(_, result, ctx, _)
- local message_type = result.type
- local message = result.message
+--- @param params lsp.ShowMessageParams
+NSC['window/showMessage'] = function(_, params, ctx)
+ local message_type = params.type
+ local message = params.message
local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format('id=%d', client_id)
@@ -650,15 +586,16 @@ M[ms.window_showMessage] = function(_, result, ctx, _)
local message_type_name = protocol.MessageType[message_type]
api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
end
- return result
+ return params
end
+--- @private
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showDocument
---- @param result lsp.ShowDocumentParams
-M[ms.window_showDocument] = function(_, result, ctx, _)
- local uri = result.uri
+--- @param params lsp.ShowDocumentParams
+RSC[ms.window_showDocument] = function(_, params, ctx)
+ local uri = params.uri
- if result.external then
+ if params.external then
-- TODO(lvimuser): ask the user for confirmation
local cmd, err = vim.ui.open(uri)
local ret = cmd and cmd:wait(2000) or nil
@@ -686,35 +623,39 @@ M[ms.window_showDocument] = function(_, result, ctx, _)
local location = {
uri = uri,
- range = result.selection,
+ range = params.selection,
}
local success = util.show_document(location, client.offset_encoding, {
reuse_win = true,
- focus = result.takeFocus,
+ focus = params.takeFocus,
})
return { success = success or false }
end
---@see https://microsoft.github.io/language-server-protocol/specification/#workspace_inlayHint_refresh
-M[ms.workspace_inlayHint_refresh] = function(err, result, ctx, config)
- return vim.lsp.inlay_hint.on_refresh(err, result, ctx, config)
+RSC[ms.workspace_inlayHint_refresh] = function(err, result, ctx)
+ return vim.lsp.inlay_hint.on_refresh(err, result, ctx)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#semanticTokens_refreshRequest
-M[ms.workspace_semanticTokens_refresh] = function(err, result, ctx, _config)
+RSC[ms.workspace_semanticTokens_refresh] = function(err, result, ctx)
return vim.lsp.semantic_tokens._refresh(err, result, ctx)
end
+--- @nodoc
+--- @type table<string, lsp.Handler>
+M = vim.tbl_extend('force', M, RSC, NSC, RCS)
+
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
+ --- @diagnostic disable-next-line:redundant-parameter
M[k] = function(err, result, ctx, config)
if log.trace() then
log.trace('default_handler', ctx.method, {
err = err,
result = result,
ctx = vim.inspect(ctx),
- config = config,
})
end
@@ -735,6 +676,7 @@ for k, fn in pairs(M) do
return
end
+ --- @diagnostic disable-next-line:redundant-parameter
return fn(err, result, ctx, config)
end
end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index 18066a84db..0d314108fe 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -39,12 +39,27 @@ local function check_active_clients()
elseif type(client.config.cmd) == 'function' then
cmd = tostring(client.config.cmd)
end
+ local dirs_info ---@type string
+ if client.workspace_folders and #client.workspace_folders > 1 then
+ dirs_info = string.format(
+ ' Workspace folders:\n %s',
+ vim
+ .iter(client.workspace_folders)
+ ---@param folder lsp.WorkspaceFolder
+ :map(function(folder)
+ return folder.name
+ end)
+ :join('\n ')
+ )
+ else
+ dirs_info = string.format(
+ ' Root directory: %s',
+ client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~')
+ ) or nil
+ end
report_info(table.concat({
string.format('%s (id: %d)', client.name, client.id),
- string.format(
- ' Root directory: %s',
- client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~') or nil
- ),
+ dirs_info,
string.format(' Command: %s', cmd),
string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })),
string.format(
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index 61059180fe..f1ae9a8e9e 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -37,7 +37,7 @@ local augroup = api.nvim_create_augroup('vim_lsp_inlayhint', {})
---@param result lsp.InlayHint[]?
---@param ctx lsp.HandlerContext
---@private
-function M.on_inlayhint(err, result, ctx, _)
+function M.on_inlayhint(err, result, ctx)
if err then
log.error('inlayhint', err)
return
@@ -65,37 +65,29 @@ function M.on_inlayhint(err, result, ctx, _)
if num_unprocessed == 0 then
client_hints[client_id] = {}
bufstate.version = ctx.version
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
return
end
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
- ---@param position lsp.Position
- ---@return integer
- local function pos_to_byte(position)
- local col = position.character
- if col > 0 then
- local line = lines[position.line + 1] or ''
- return util._str_byteindex_enc(line, col, client.offset_encoding)
- end
- return col
- end
for _, hint in ipairs(result) do
local lnum = hint.position.line
- hint.position.character = pos_to_byte(hint.position)
+ local line = lines and lines[lnum + 1] or ''
+ hint.position.character =
+ vim.str_byteindex(line, client.offset_encoding, hint.position.character, false)
table.insert(new_lnum_hints[lnum], hint)
end
client_hints[client_id] = new_lnum_hints
bufstate.version = ctx.version
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
end
--- |lsp-handler| for the method `workspace/inlayHint/refresh`
---@param ctx lsp.HandlerContext
---@private
-function M.on_refresh(err, _, ctx, _)
+function M.on_refresh(err, _, ctx)
if err then
return vim.NIL
end
@@ -145,7 +137,7 @@ end
--- @return vim.lsp.inlay_hint.get.ret[]
--- @since 12
function M.get(filter)
- vim.validate({ filter = { filter, 'table', true } })
+ vim.validate('filter', filter, 'table', true)
filter = filter or {}
local bufnr = filter.bufnr
@@ -223,7 +215,7 @@ local function clear(bufnr)
end
end
api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
end
--- Disable inlay hints for a buffer
@@ -375,11 +367,11 @@ api.nvim_set_decoration_provider(namespace, {
--- @return boolean
--- @since 12
function M.is_enabled(filter)
- vim.validate({ filter = { filter, 'table', true } })
+ vim.validate('filter', filter, 'table', true)
filter = filter or {}
local bufnr = filter.bufnr
- vim.validate({ bufnr = { bufnr, 'number', true } })
+ vim.validate('bufnr', bufnr, 'number', true)
if bufnr == nil then
return globalstate.enabled
elseif bufnr == 0 then
@@ -406,7 +398,8 @@ end
--- @param filter vim.lsp.inlay_hint.enable.Filter?
--- @since 12
function M.enable(enable, filter)
- vim.validate({ enable = { enable, 'boolean', true }, filter = { filter, 'table', true } })
+ vim.validate('enable', enable, 'boolean', true)
+ vim.validate('filter', filter, 'table', true)
enable = enable == nil or enable
filter = filter or {}
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 4f177b47fd..ec78dd3dc5 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -32,12 +32,12 @@ local function notify(msg, level)
end
end
-local logfilename = vim.fs.joinpath(vim.fn.stdpath('log'), 'lsp.log')
+local logfilename = vim.fs.joinpath(vim.fn.stdpath('log') --[[@as string]], 'lsp.log')
-- TODO: Ideally the directory should be created in open_logfile(), right
-- before opening the log file, but open_logfile() can be called from libuv
-- callbacks, where using fn.mkdir() is not allowed.
-vim.fn.mkdir(vim.fn.stdpath('log'), 'p')
+vim.fn.mkdir(vim.fn.stdpath('log') --[[@as string]], 'p')
--- Returns the log filename.
---@return string log filename
@@ -82,6 +82,7 @@ end
for level, levelnr in pairs(log_levels) do
-- Also export the log level on the root object.
+ ---@diagnostic disable-next-line: no-unknown
log[level] = levelnr
-- Add a reverse lookup.
@@ -93,7 +94,7 @@ end
--- @return fun(...:any): boolean?
local function create_logger(level, levelnr)
return function(...)
- if levelnr < current_log_level then
+ if not log.should_log(levelnr) then
return false
end
local argc = select('#', ...)
@@ -169,7 +170,7 @@ end
--- Checks whether the level is sufficient for logging.
---@param level integer log level
----@return bool : true if would log, false if not
+---@return boolean : true if would log, false if not
function log.should_log(level)
return level >= current_log_level
end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 1699fff0c1..7db48b0c06 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -12,6 +12,8 @@ end
local sysname = vim.uv.os_uname().sysname
+--- @class vim.lsp.protocol.constants
+--- @nodoc
local constants = {
--- @enum lsp.DiagnosticSeverity
DiagnosticSeverity = {
@@ -314,7 +316,9 @@ local constants = {
},
}
--- Protocol for the Microsoft Language Server Protocol (mslsp)
+--- Protocol for the Microsoft Language Server Protocol (mslsp)
+--- @class vim.lsp.protocol : vim.lsp.protocol.constants
+--- @nodoc
local protocol = {}
--- @diagnostic disable:no-unknown
@@ -334,7 +338,9 @@ function protocol.make_client_capabilities()
return {
general = {
positionEncodings = {
+ 'utf-8',
'utf-16',
+ 'utf-32',
},
},
textDocument = {
@@ -615,9 +621,109 @@ function protocol.resolve_capabilities(server_capabilities)
end
-- Generated by gen_lsp.lua, keep at end of file.
+--- @alias vim.lsp.protocol.Method.ClientToServer
+--- | 'callHierarchy/incomingCalls',
+--- | 'callHierarchy/outgoingCalls',
+--- | 'codeAction/resolve',
+--- | 'codeLens/resolve',
+--- | 'completionItem/resolve',
+--- | 'documentLink/resolve',
+--- | '$/setTrace',
+--- | 'exit',
+--- | 'initialize',
+--- | 'initialized',
+--- | 'inlayHint/resolve',
+--- | 'notebookDocument/didChange',
+--- | 'notebookDocument/didClose',
+--- | 'notebookDocument/didOpen',
+--- | 'notebookDocument/didSave',
+--- | 'shutdown',
+--- | 'textDocument/codeAction',
+--- | 'textDocument/codeLens',
+--- | 'textDocument/colorPresentation',
+--- | 'textDocument/completion',
+--- | 'textDocument/declaration',
+--- | 'textDocument/definition',
+--- | 'textDocument/diagnostic',
+--- | 'textDocument/didChange',
+--- | 'textDocument/didClose',
+--- | 'textDocument/didOpen',
+--- | 'textDocument/didSave',
+--- | 'textDocument/documentColor',
+--- | 'textDocument/documentHighlight',
+--- | 'textDocument/documentLink',
+--- | 'textDocument/documentSymbol',
+--- | 'textDocument/foldingRange',
+--- | 'textDocument/formatting',
+--- | 'textDocument/hover',
+--- | 'textDocument/implementation',
+--- | 'textDocument/inlayHint',
+--- | 'textDocument/inlineCompletion',
+--- | 'textDocument/inlineValue',
+--- | 'textDocument/linkedEditingRange',
+--- | 'textDocument/moniker',
+--- | 'textDocument/onTypeFormatting',
+--- | 'textDocument/prepareCallHierarchy',
+--- | 'textDocument/prepareRename',
+--- | 'textDocument/prepareTypeHierarchy',
+--- | 'textDocument/rangeFormatting',
+--- | 'textDocument/rangesFormatting',
+--- | 'textDocument/references',
+--- | 'textDocument/rename',
+--- | 'textDocument/selectionRange',
+--- | 'textDocument/semanticTokens/full',
+--- | 'textDocument/semanticTokens/full/delta',
+--- | 'textDocument/semanticTokens/range',
+--- | 'textDocument/signatureHelp',
+--- | 'textDocument/typeDefinition',
+--- | 'textDocument/willSave',
+--- | 'textDocument/willSaveWaitUntil',
+--- | 'typeHierarchy/subtypes',
+--- | 'typeHierarchy/supertypes',
+--- | 'window/workDoneProgress/cancel',
+--- | 'workspaceSymbol/resolve',
+--- | 'workspace/diagnostic',
+--- | 'workspace/didChangeConfiguration',
+--- | 'workspace/didChangeWatchedFiles',
+--- | 'workspace/didChangeWorkspaceFolders',
+--- | 'workspace/didCreateFiles',
+--- | 'workspace/didDeleteFiles',
+--- | 'workspace/didRenameFiles',
+--- | 'workspace/executeCommand',
+--- | 'workspace/symbol',
+--- | 'workspace/willCreateFiles',
+--- | 'workspace/willDeleteFiles',
+--- | 'workspace/willRenameFiles',
+
+--- @alias vim.lsp.protocol.Method.ServerToClient
+--- | 'client/registerCapability',
+--- | 'client/unregisterCapability',
+--- | '$/logTrace',
+--- | 'telemetry/event',
+--- | 'textDocument/publishDiagnostics',
+--- | 'window/logMessage',
+--- | 'window/showDocument',
+--- | 'window/showMessage',
+--- | 'window/showMessageRequest',
+--- | 'window/workDoneProgress/create',
+--- | 'workspace/applyEdit',
+--- | 'workspace/codeLens/refresh',
+--- | 'workspace/configuration',
+--- | 'workspace/diagnostic/refresh',
+--- | 'workspace/foldingRange/refresh',
+--- | 'workspace/inlayHint/refresh',
+--- | 'workspace/inlineValue/refresh',
+--- | 'workspace/semanticTokens/refresh',
+--- | 'workspace/workspaceFolders',
+
+--- @alias vim.lsp.protocol.Method
+--- | vim.lsp.protocol.Method.ClientToServer
+--- | vim.lsp.protocol.Method.ServerToClient
+
+-- Generated by gen_lsp.lua, keep at end of file.
---
----@enum vim.lsp.protocol.Methods
----@see https://microsoft.github.io/language-server-protocol/specification/#metaModel
+--- @enum vim.lsp.protocol.Methods
+--- @see https://microsoft.github.io/language-server-protocol/specification/#metaModel
--- LSP method names.
protocol.Methods = {
--- A request to resolve the incoming calls for a given `CallHierarchyItem`.
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index e79dbd2db3..6c8564845f 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -1,7 +1,7 @@
local uv = vim.uv
local log = require('vim.lsp.log')
local protocol = require('vim.lsp.protocol')
-local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
+local validate, schedule_wrap = vim.validate, vim.schedule_wrap
local is_win = vim.fn.has('win32') == 1
@@ -152,9 +152,7 @@ end
---@param err table The error object
---@return string error_message The formatted error message
function M.format_rpc_error(err)
- validate({
- err = { err, 't' },
- })
+ validate('err', err, 'table')
-- There is ErrorCodes in the LSP specification,
-- but in ResponseError.code it is not used and the actual type is number.
@@ -329,10 +327,8 @@ end
---@return boolean success `true` if request could be sent, `false` if not
---@return integer? message_id if request could be sent, `nil` if not
function Client:request(method, params, callback, notify_reply_callback)
- validate({
- callback = { callback, 'f' },
- notify_reply_callback = { notify_reply_callback, 'f', true },
- })
+ validate('callback', callback, 'function')
+ validate('notify_reply_callback', notify_reply_callback, 'function', true)
self.message_index = self.message_index + 1
local message_id = self.message_index
local result = self:encode_and_send({
@@ -413,49 +409,44 @@ function Client:handle_body(body)
local err --- @type lsp.ResponseError|nil
-- Schedule here so that the users functions don't trigger an error and
-- we can still use the result.
- schedule(function()
- coroutine.wrap(function()
- local status, result
- status, result, err = self:try_call(
- M.client_errors.SERVER_REQUEST_HANDLER_ERROR,
- self.dispatchers.server_request,
- decoded.method,
- decoded.params
- )
- log.debug(
- 'server_request: callback result',
- { status = status, result = result, err = err }
- )
- if status then
- if result == nil and err == nil then
- error(
- string.format(
- 'method %q: either a result or an error must be sent to the server in response',
- decoded.method
- )
- )
- end
- if err then
- ---@cast err lsp.ResponseError
- assert(
- type(err) == 'table',
- 'err must be a table. Use rpc_response_error to help format errors.'
- )
- ---@type string
- local code_name = assert(
- protocol.ErrorCodes[err.code],
- 'Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.'
+ vim.schedule(coroutine.wrap(function()
+ local status, result
+ status, result, err = self:try_call(
+ M.client_errors.SERVER_REQUEST_HANDLER_ERROR,
+ self.dispatchers.server_request,
+ decoded.method,
+ decoded.params
+ )
+ log.debug('server_request: callback result', { status = status, result = result, err = err })
+ if status then
+ if result == nil and err == nil then
+ error(
+ string.format(
+ 'method %q: either a result or an error must be sent to the server in response',
+ decoded.method
)
- err.message = err.message or code_name
- end
- else
- -- On an exception, result will contain the error message.
- err = M.rpc_response_error(protocol.ErrorCodes.InternalError, result)
- result = nil
+ )
+ end
+ if err then
+ ---@cast err lsp.ResponseError
+ assert(
+ type(err) == 'table',
+ 'err must be a table. Use rpc_response_error to help format errors.'
+ )
+ ---@type string
+ local code_name = assert(
+ protocol.ErrorCodes[err.code],
+ 'Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.'
+ )
+ err.message = err.message or code_name
end
- self:send_response(decoded.id, err, result)
- end)()
- end)
+ else
+ -- On an exception, result will contain the error message.
+ err = M.rpc_response_error(protocol.ErrorCodes.InternalError, result)
+ result = nil
+ end
+ self:send_response(decoded.id, err, result)
+ end))
-- This works because we are expecting vim.NIL here
elseif decoded.id and (decoded.result ~= vim.NIL or decoded.error ~= vim.NIL) then
-- We sent a number, so we expect a number.
@@ -465,9 +456,7 @@ function Client:handle_body(body)
local notify_reply_callbacks = self.notify_reply_callbacks
local notify_reply_callback = notify_reply_callbacks and notify_reply_callbacks[result_id]
if notify_reply_callback then
- validate({
- notify_reply_callback = { notify_reply_callback, 'f' },
- })
+ validate('notify_reply_callback', notify_reply_callback, 'function')
notify_reply_callback(result_id)
notify_reply_callbacks[result_id] = nil
end
@@ -498,9 +487,7 @@ function Client:handle_body(body)
local callback = message_callbacks and message_callbacks[result_id]
if callback then
message_callbacks[result_id] = nil
- validate({
- callback = { callback, 'f' },
- })
+ validate('callback', callback, 'function')
if decoded.error then
decoded.error = setmetatable(decoded.error, {
__tostring = M.format_rpc_error,
@@ -734,10 +721,8 @@ end
function M.start(cmd, dispatchers, extra_spawn_params)
log.info('Starting RPC client', { cmd = cmd, extra = extra_spawn_params })
- validate({
- cmd = { cmd, 't' },
- dispatchers = { dispatchers, 't', true },
- })
+ validate('cmd', cmd, 'table')
+ validate('dispatchers', dispatchers, 'table', true)
extra_spawn_params = extra_spawn_params or {}
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index 8182457dd0..215e5f41aa 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -99,11 +99,12 @@ local function tokens_to_ranges(data, bufnr, client, request)
local legend = client.server_capabilities.semanticTokensProvider.legend
local token_types = legend.tokenTypes
local token_modifiers = legend.tokenModifiers
+ local encoding = client.offset_encoding
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
local ranges = {} ---@type STTokenRange[]
local start = uv.hrtime()
- local ms_to_ns = 1000 * 1000
+ local ms_to_ns = 1e6
local yield_interval_ns = 5 * ms_to_ns
local co, is_main = coroutine.running()
@@ -135,20 +136,13 @@ local function tokens_to_ranges(data, bufnr, client, request)
-- data[i+3] +1 because Lua tables are 1-indexed
local token_type = token_types[data[i + 3] + 1]
- local modifiers = modifiers_from_number(data[i + 4], token_modifiers)
-
- local function _get_byte_pos(col)
- if col > 0 then
- local buf_line = lines[line + 1] or ''
- return util._str_byteindex_enc(buf_line, col, client.offset_encoding)
- end
- return col
- end
-
- local start_col = _get_byte_pos(start_char)
- local end_col = _get_byte_pos(start_char + data[i + 2])
if token_type then
+ local modifiers = modifiers_from_number(data[i + 4], token_modifiers)
+ local end_char = start_char + data[i + 2]
+ local buf_line = lines and lines[line + 1] or ''
+ local start_col = vim.str_byteindex(buf_line, encoding, start_char, false)
+ local end_col = vim.str_byteindex(buf_line, encoding, end_char, false)
ranges[#ranges + 1] = {
line = line,
start_col = start_col,
@@ -386,6 +380,37 @@ function STHighlighter:process_response(response, client, version)
api.nvim__redraw({ buf = self.bufnr, valid = true })
end
+--- @param bufnr integer
+--- @param ns integer
+--- @param token STTokenRange
+--- @param hl_group string
+--- @param priority integer
+local function set_mark(bufnr, ns, token, hl_group, priority)
+ vim.api.nvim_buf_set_extmark(bufnr, ns, token.line, token.start_col, {
+ hl_group = hl_group,
+ end_col = token.end_col,
+ priority = priority,
+ strict = false,
+ })
+end
+
+--- @param lnum integer
+--- @param foldend integer?
+--- @return boolean, integer?
+local function check_fold(lnum, foldend)
+ if foldend and lnum <= foldend then
+ return true, foldend
+ end
+
+ local folded = vim.fn.foldclosed(lnum)
+
+ if folded == -1 then
+ return false, nil
+ end
+
+ return folded ~= lnum, vim.fn.foldclosedend(lnum)
+end
+
--- on_win handler for the decoration provider (see |nvim_set_decoration_provider|)
---
--- If there is a current result for the buffer and the version matches the
@@ -439,13 +464,14 @@ function STHighlighter:on_win(topline, botline)
-- finishes, clangd sends a refresh request which lets the client
-- re-synchronize the tokens.
- local set_mark = function(token, hl_group, delta)
- vim.api.nvim_buf_set_extmark(self.bufnr, state.namespace, token.line, token.start_col, {
- hl_group = hl_group,
- end_col = token.end_col,
- priority = vim.highlight.priorities.semantic_tokens + delta,
- strict = false,
- })
+ local function set_mark0(token, hl_group, delta)
+ set_mark(
+ self.bufnr,
+ state.namespace,
+ token,
+ hl_group,
+ vim.hl.priorities.semantic_tokens + delta
+ )
end
local ft = vim.bo[self.bufnr].filetype
@@ -453,13 +479,19 @@ function STHighlighter:on_win(topline, botline)
local first = lower_bound(highlights, topline, 1, #highlights + 1)
local last = upper_bound(highlights, botline, first, #highlights + 1) - 1
+ --- @type boolean?, integer?
+ local is_folded, foldend
+
for i = first, last do
local token = highlights[i]
- if not token.marked then
- set_mark(token, string.format('@lsp.type.%s.%s', token.type, ft), 0)
- for modifier, _ in pairs(token.modifiers) do
- set_mark(token, string.format('@lsp.mod.%s.%s', modifier, ft), 1)
- set_mark(token, string.format('@lsp.typemod.%s.%s.%s', token.type, modifier, ft), 2)
+
+ is_folded, foldend = check_fold(token.line + 1, foldend)
+
+ if not is_folded and not token.marked then
+ set_mark0(token, string.format('@lsp.type.%s.%s', token.type, ft), 0)
+ for modifier in pairs(token.modifiers) do
+ set_mark0(token, string.format('@lsp.mod.%s.%s', modifier, ft), 1)
+ set_mark0(token, string.format('@lsp.typemod.%s.%s.%s', token.type, modifier, ft), 2)
end
token.marked = true
@@ -565,10 +597,8 @@ local M = {}
--- - debounce (integer, default: 200): Debounce token requests
--- to the server by the given number in milliseconds
function M.start(bufnr, client_id, opts)
- vim.validate({
- bufnr = { bufnr, 'n', false },
- client_id = { client_id, 'n', false },
- })
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('client_id', client_id, 'number')
if bufnr == 0 then
bufnr = api.nvim_get_current_buf()
@@ -622,10 +652,8 @@ end
---@param bufnr (integer) Buffer number, or `0` for current buffer
---@param client_id (integer) The ID of the |vim.lsp.Client|
function M.stop(bufnr, client_id)
- vim.validate({
- bufnr = { bufnr, 'n', false },
- client_id = { client_id, 'n', false },
- })
+ vim.validate('bufnr', bufnr, 'number')
+ vim.validate('client_id', client_id, 'number')
if bufnr == 0 then
bufnr = api.nvim_get_current_buf()
@@ -708,9 +736,7 @@ end
---@param bufnr (integer|nil) filter by buffer. All buffers if nil, current
--- buffer if 0
function M.force_refresh(bufnr)
- vim.validate({
- bufnr = { bufnr, 'n', true },
- })
+ vim.validate('bufnr', bufnr, 'number', true)
local buffers = bufnr == nil and vim.tbl_keys(STHighlighter.active)
or bufnr == 0 and { api.nvim_get_current_buf() }
@@ -729,7 +755,7 @@ end
--- @inlinedoc
---
--- Priority for the applied extmark.
---- (Default: `vim.highlight.priorities.semantic_tokens + 3`)
+--- (Default: `vim.hl.priorities.semantic_tokens + 3`)
--- @field priority? integer
--- Highlight a semantic token.
@@ -757,15 +783,9 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts)
return
end
- opts = opts or {}
- local priority = opts.priority or vim.highlight.priorities.semantic_tokens + 3
+ local priority = opts and opts.priority or vim.hl.priorities.semantic_tokens + 3
- vim.api.nvim_buf_set_extmark(bufnr, state.namespace, token.line, token.start_col, {
- hl_group = hl_group,
- end_col = token.end_col,
- priority = priority,
- strict = false,
- })
+ set_mark(bufnr, state.namespace, token, hl_group, priority)
end
--- |lsp-handler| for the method `workspace/semanticTokens/refresh`
diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua
index bdfe8d51b8..3df45ebff0 100644
--- a/runtime/lua/vim/lsp/sync.lua
+++ b/runtime/lua/vim/lsp/sync.lua
@@ -48,45 +48,6 @@ local str_utfindex = vim.str_utfindex
local str_utf_start = vim.str_utf_start
local str_utf_end = vim.str_utf_end
--- Given a line, byte idx, and offset_encoding convert to the
--- utf-8, utf-16, or utf-32 index.
----@param line string the line to index into
----@param byte integer the byte idx
----@param offset_encoding string utf-8|utf-16|utf-32|nil (default: utf-8)
----@return integer utf_idx for the given encoding
-local function byte_to_utf(line, byte, offset_encoding)
- -- convert to 0 based indexing for str_utfindex
- byte = byte - 1
-
- local utf_idx, _ --- @type integer, integer
- -- Convert the byte range to utf-{8,16,32} and convert 1-based (lua) indexing to 0-based
- if offset_encoding == 'utf-16' then
- _, utf_idx = str_utfindex(line, byte)
- elseif offset_encoding == 'utf-32' then
- utf_idx, _ = str_utfindex(line, byte)
- else
- utf_idx = byte
- end
-
- -- convert to 1 based indexing
- return utf_idx + 1
-end
-
----@param line string
----@param offset_encoding string
----@return integer
-local function compute_line_length(line, offset_encoding)
- local length, _ --- @type integer, integer
- if offset_encoding == 'utf-16' then
- _, length = str_utfindex(line)
- elseif offset_encoding == 'utf-32' then
- length, _ = str_utfindex(line)
- else
- length = #line
- end
- return length
-end
-
-- Given a line, byte idx, alignment, and offset_encoding convert to the aligned
-- utf-8 index and either the utf-16, or utf-32 index.
---@param line string the line to index into
@@ -101,7 +62,7 @@ local function align_end_position(line, byte, offset_encoding)
char = byte
-- Called in the case of extending an empty line "" -> "a"
elseif byte == #line + 1 then
- char = compute_line_length(line, offset_encoding) + 1
+ char = str_utfindex(line, offset_encoding) + 1
else
-- Modifying line, find the nearest utf codepoint
local offset = str_utf_start(line, byte)
@@ -111,9 +72,10 @@ local function align_end_position(line, byte, offset_encoding)
byte = byte + str_utf_end(line, byte) + 1
end
if byte <= #line then
- char = byte_to_utf(line, byte, offset_encoding)
+ --- Convert to 0 based for input, and from 0 based for output
+ char = str_utfindex(line, offset_encoding, byte - 1) + 1
else
- char = compute_line_length(line, offset_encoding) + 1
+ char = str_utfindex(line, offset_encoding) + 1
end
-- Extending line, find the nearest utf codepoint for the last valid character
end
@@ -153,7 +115,7 @@ local function compute_start_range(
if line then
line_idx = firstline - 1
byte_idx = #line + 1
- char_idx = compute_line_length(line, offset_encoding) + 1
+ char_idx = str_utfindex(line, offset_encoding) + 1
else
line_idx = firstline
byte_idx = 1
@@ -190,10 +152,11 @@ local function compute_start_range(
char_idx = 1
elseif start_byte_idx == #prev_line + 1 then
byte_idx = start_byte_idx
- char_idx = compute_line_length(prev_line, offset_encoding) + 1
+ char_idx = str_utfindex(prev_line, offset_encoding) + 1
else
byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx)
- char_idx = byte_to_utf(prev_line, byte_idx, offset_encoding)
+ --- Convert to 0 based for input, and from 0 based for output
+ char_idx = vim.str_utfindex(prev_line, offset_encoding, byte_idx - 1) + 1
end
-- Return the start difference (shared for new and prev lines)
@@ -230,7 +193,7 @@ local function compute_end_range(
return {
line_idx = lastline - 1,
byte_idx = #prev_line + 1,
- char_idx = compute_line_length(prev_line, offset_encoding) + 1,
+ char_idx = str_utfindex(prev_line, offset_encoding) + 1,
}, { line_idx = 1, byte_idx = 1, char_idx = 1 }
end
-- If firstline == new_lastline, the first change occurred on a line that was deleted.
@@ -376,7 +339,7 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi
local start_line = lines[start_range.line_idx]
local range_length --- @type integer
if start_line and #start_line > 0 then
- range_length = compute_line_length(start_line, offset_encoding)
+ range_length = str_utfindex(start_line, offset_encoding)
- start_range.char_idx
+ 1
+ line_ending_length
@@ -389,7 +352,7 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi
for idx = start_range.line_idx + 1, end_range.line_idx - 1 do
-- Length full line plus newline character
if #lines[idx] > 0 then
- range_length = range_length + compute_line_length(lines[idx], offset_encoding) + #line_ending
+ range_length = range_length + str_utfindex(lines[idx], offset_encoding) + #line_ending
else
range_length = range_length + line_ending_length
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 882ec22ca6..6eab0f3da4 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -2,12 +2,8 @@ local protocol = require('vim.lsp.protocol')
local validate = vim.validate
local api = vim.api
local list_extend = vim.list_extend
-local highlight = vim.highlight
local uv = vim.uv
-local npcall = vim.F.npcall
-local split = vim.split
-
local M = {}
local default_border = {
@@ -21,82 +17,73 @@ local default_border = {
{ ' ', 'NormalFloat' },
}
+--- @param border string|(string|[string,string])[]
+local function border_error(border)
+ error(
+ string.format(
+ 'invalid floating preview border: %s. :help vim.api.nvim_open_win()',
+ vim.inspect(border)
+ ),
+ 2
+ )
+end
+
+local border_size = {
+ none = { 0, 0 },
+ single = { 2, 2 },
+ double = { 2, 2 },
+ rounded = { 2, 2 },
+ solid = { 2, 2 },
+ shadow = { 1, 1 },
+}
+
--- Check the border given by opts or the default border for the additional
--- size it adds to a float.
----@param opts table optional options for the floating window
---- - border (string or table) the border
----@return table size of border in the form of { height = height, width = width }
+--- @param opts? {border:string|(string|[string,string])[]}
+--- @return integer height
+--- @return integer width
local function get_border_size(opts)
local border = opts and opts.border or default_border
- local height = 0
- local width = 0
if type(border) == 'string' then
- local border_size = {
- none = { 0, 0 },
- single = { 2, 2 },
- double = { 2, 2 },
- rounded = { 2, 2 },
- solid = { 2, 2 },
- shadow = { 1, 1 },
- }
- if border_size[border] == nil then
- error(
- string.format(
- 'invalid floating preview border: %s. :help vim.api.nvim_open_win()',
- vim.inspect(border)
- )
- )
+ if not border_size[border] then
+ border_error(border)
end
- height, width = unpack(border_size[border])
- else
- if 8 % #border ~= 0 then
- error(
- string.format(
- 'invalid floating preview border: %s. :help vim.api.nvim_open_win()',
- vim.inspect(border)
- )
- )
- end
- local function border_width(id)
- id = (id - 1) % #border + 1
- if type(border[id]) == 'table' then
- -- border specified as a table of <character, highlight group>
- return vim.fn.strdisplaywidth(border[id][1])
- elseif type(border[id]) == 'string' then
- -- border specified as a list of border characters
- return vim.fn.strdisplaywidth(border[id])
- end
- error(
- string.format(
- 'invalid floating preview border: %s. :help vim.api.nvim_open_win()',
- vim.inspect(border)
- )
- )
- end
- local function border_height(id)
- id = (id - 1) % #border + 1
- if type(border[id]) == 'table' then
- -- border specified as a table of <character, highlight group>
- return #border[id][1] > 0 and 1 or 0
- elseif type(border[id]) == 'string' then
- -- border specified as a list of border characters
- return #border[id] > 0 and 1 or 0
- end
- error(
- string.format(
- 'invalid floating preview border: %s. :help vim.api.nvim_open_win()',
- vim.inspect(border)
- )
- )
+ return unpack(border_size[border])
+ end
+
+ if 8 % #border ~= 0 then
+ border_error(border)
+ end
+
+ --- @param id integer
+ --- @return string
+ local function elem(id)
+ id = (id - 1) % #border + 1
+ local e = border[id]
+ if type(e) == 'table' then
+ -- border specified as a table of <character, highlight group>
+ return e[1]
+ elseif type(e) == 'string' then
+ -- border specified as a list of border characters
+ return e
end
- height = height + border_height(2) -- top
- height = height + border_height(6) -- bottom
- width = width + border_width(4) -- right
- width = width + border_width(8) -- left
+ --- @diagnostic disable-next-line:missing-return
+ border_error(border)
+ end
+
+ --- @param e string
+ local function border_height(e)
+ return #e > 0 and 1 or 0
end
- return { height = height, width = width }
+ local top, bottom = elem(2), elem(6)
+ local height = border_height(top) + border_height(bottom)
+
+ local right, left = elem(4), elem(8)
+ local width = vim.fn.strdisplaywidth(right) + vim.fn.strdisplaywidth(left)
+
+ return height, width
end
--- Splits string at newlines, optionally removing unwanted blank lines.
@@ -122,79 +109,13 @@ local function split_lines(s, no_blank)
end
local function create_window_without_focus()
- local prev = vim.api.nvim_get_current_win()
+ local prev = api.nvim_get_current_win()
vim.cmd.new()
- local new = vim.api.nvim_get_current_win()
- vim.api.nvim_set_current_win(prev)
+ local new = api.nvim_get_current_win()
+ api.nvim_set_current_win(prev)
return new
end
---- Convert byte index to `encoding` index.
---- Convenience wrapper around vim.str_utfindex
----@param line string line to be indexed
----@param index integer|nil byte index (utf-8), or `nil` for length
----@param encoding 'utf-8'|'utf-16'|'utf-32'|nil defaults to utf-16
----@return integer `encoding` index of `index` in `line`
-function M._str_utfindex_enc(line, index, encoding)
- local len32, len16 = vim.str_utfindex(line)
- if not encoding then
- encoding = 'utf-16'
- end
- if encoding == 'utf-8' then
- if index then
- return index
- else
- return #line
- end
- elseif encoding == 'utf-16' then
- if not index or index > len16 then
- return len16
- end
- local _, col16 = vim.str_utfindex(line, index)
- return col16
- elseif encoding == 'utf-32' then
- if not index or index > len32 then
- return len32
- end
- local col32, _ = vim.str_utfindex(line, index)
- return col32
- else
- error('Invalid encoding: ' .. vim.inspect(encoding))
- end
-end
-
---- Convert UTF index to `encoding` index.
---- Convenience wrapper around vim.str_byteindex
----Alternative to vim.str_byteindex that takes an encoding.
----@param line string line to be indexed
----@param index integer UTF index
----@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
----@return integer byte (utf-8) index of `encoding` index `index` in `line`
-function M._str_byteindex_enc(line, index, encoding)
- local len = #line
- if index > len then
- -- LSP spec: if character > line length, default to the line length.
- -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
- return len
- end
- if not encoding then
- encoding = 'utf-16'
- end
- if encoding == 'utf-8' then
- if index then
- return index
- else
- return len
- end
- elseif encoding == 'utf-16' then
- return vim.str_byteindex(line, index, true)
- elseif encoding == 'utf-32' then
- return vim.str_byteindex(line, index)
- else
- error('Invalid encoding: ' .. vim.inspect(encoding))
- end
-end
-
--- Replaces text in a range with new text.
---
--- CAUTION: Changes in-place!
@@ -243,6 +164,8 @@ function M.set_lines(lines, A, B, new_lines)
return lines
end
+--- @param fn fun(x:any):any[]
+--- @return function
local function sort_by_key(fn)
return function(a, b)
local ka, kb = fn(a), fn(b)
@@ -354,7 +277,7 @@ end
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
---@param position lsp.Position
----@param offset_encoding? string utf-8|utf-16|utf-32
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@return integer
local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- LSP's line and characters are 0-indexed
@@ -364,7 +287,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- character
if col > 0 then
local line = get_line(bufnr, position.line) or ''
- return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
+ return vim.str_byteindex(line, offset_encoding, col, false)
end
return col
end
@@ -372,14 +295,13 @@ end
--- Applies a list of text edits to a buffer.
---@param text_edits lsp.TextEdit[]
---@param bufnr integer Buffer id
----@param offset_encoding string utf-8|utf-16|utf-32
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
function M.apply_text_edits(text_edits, bufnr, offset_encoding)
- validate({
- text_edits = { text_edits, 't', false },
- bufnr = { bufnr, 'number', false },
- offset_encoding = { offset_encoding, 'string', false },
- })
+ validate('text_edits', text_edits, 'table', false)
+ validate('bufnr', bufnr, 'number', false)
+ validate('offset_encoding', offset_encoding, 'string', false)
+
if not next(text_edits) then
return
end
@@ -392,10 +314,8 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
vim.bo[bufnr].buflisted = true
-- Fix reversed range and indexing each text_edits
- local index = 0
- --- @param text_edit lsp.TextEdit
- text_edits = vim.tbl_map(function(text_edit)
- index = index + 1
+ for index, text_edit in ipairs(text_edits) do
+ --- @cast text_edit lsp.TextEdit|{_index: integer}
text_edit._index = index
if
@@ -407,8 +327,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
text_edit.range.start = text_edit.range['end']
text_edit.range['end'] = start
end
- return text_edit
- end, text_edits)
+ end
-- Sort text_edits
---@param a lsp.TextEdit | { _index: integer }
@@ -439,47 +358,45 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
text_edit.newText, _ = string.gsub(text_edit.newText, '\r\n?', '\n')
-- Convert from LSP style ranges to Neovim style ranges.
- local e = {
- start_row = text_edit.range.start.line,
- start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding),
- end_row = text_edit.range['end'].line,
- end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding),
- text = split(text_edit.newText, '\n', { plain = true }),
- }
+ local start_row = text_edit.range.start.line
+ local start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding)
+ local end_row = text_edit.range['end'].line
+ local end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding)
+ local text = vim.split(text_edit.newText, '\n', { plain = true })
local max = api.nvim_buf_line_count(bufnr)
-- If the whole edit is after the lines in the buffer we can simply add the new text to the end
-- of the buffer.
- if max <= e.start_row then
- api.nvim_buf_set_lines(bufnr, max, max, false, e.text)
+ if max <= start_row then
+ api.nvim_buf_set_lines(bufnr, max, max, false, text)
else
- local last_line_len = #(get_line(bufnr, math.min(e.end_row, max - 1)) or '')
+ local last_line_len = #(get_line(bufnr, math.min(end_row, max - 1)) or '')
-- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't
-- accept it so we should fix it here.
- if max <= e.end_row then
- e.end_row = max - 1
- e.end_col = last_line_len
+ if max <= end_row then
+ end_row = max - 1
+ end_col = last_line_len
has_eol_text_edit = true
else
- -- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the
+ -- If the replacement is over the end of a line (i.e. end_col is equal to the line length and the
-- replacement text ends with a newline We can likely assume that the replacement is assumed
-- to be meant to replace the newline with another newline and we need to make sure this
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
-- in the file some servers (clangd on windows) will include that character in the line
-- while nvim_buf_set_text doesn't count it as part of the line.
if
- e.end_col >= last_line_len
- and text_edit.range['end'].character > e.end_col
+ end_col >= last_line_len
+ and text_edit.range['end'].character > end_col
and #text_edit.newText > 0
and string.sub(text_edit.newText, -1) == '\n'
then
- table.remove(e.text, #e.text)
+ table.remove(text, #text)
end
end
- -- Make sure we don't go out of bounds for e.end_col
- e.end_col = math.min(last_line_len, e.end_col)
+ -- Make sure we don't go out of bounds for end_col
+ end_col = math.min(last_line_len, end_col)
- api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
+ api.nvim_buf_set_text(bufnr, start_row, start_col, end_row, end_col, text)
end
end
@@ -495,7 +412,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
-- make sure we don't go out of bounds
pos[1] = math.min(pos[1], max)
pos[2] = math.min(pos[2], #(get_line(bufnr, pos[1] - 1) or ''))
- vim.api.nvim_buf_set_mark(bufnr or 0, mark, pos[1], pos[2], {})
+ api.nvim_buf_set_mark(bufnr or 0, mark, pos[1], pos[2], {})
end
end
@@ -513,7 +430,7 @@ end
---
---@param text_document_edit lsp.TextDocumentEdit
---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list)
----@param offset_encoding? string
+---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
local text_document = text_document_edit.textDocument
@@ -523,19 +440,15 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
'apply_text_document_edit must be called with valid offset encoding',
vim.log.levels.WARN
)
- end
-
- -- For lists of text document edits,
- -- do not check the version after the first edit.
- local should_check_version = true
- if index and index > 1 then
- should_check_version = false
+ return
end
-- `VersionedTextDocumentIdentifier`s version may be null
-- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier
if
- should_check_version
+ -- For lists of text document edits,
+ -- do not check the version after the first edit.
+ not (index and index > 1)
and (
text_document.version
and text_document.version > 0
@@ -553,6 +466,9 @@ local function path_components(path)
return vim.split(path, '/', { plain = true })
end
+--- @param path string[]
+--- @param prefix string[]
+--- @return boolean
local function path_under_prefix(path, prefix)
for i, c in ipairs(prefix) do
if c ~= path[i] then
@@ -562,17 +478,24 @@ local function path_under_prefix(path, prefix)
return true
end
---- Get list of buffers whose filename matches the given path prefix (normalized full path)
+--- Get list of loaded writable buffers whose filename matches the given path
+--- prefix (normalized full path).
---@param prefix string
---@return integer[]
-local function get_bufs_with_prefix(prefix)
- prefix = path_components(prefix)
- local buffers = {}
- for _, v in ipairs(vim.api.nvim_list_bufs()) do
- local bname = vim.api.nvim_buf_get_name(v)
- local path = path_components(vim.fs.normalize(bname, { expand_env = false }))
- if path_under_prefix(path, prefix) then
- table.insert(buffers, v)
+local function get_writable_bufs(prefix)
+ local prefix_parts = path_components(prefix)
+ local buffers = {} --- @type integer[]
+ for _, buf in ipairs(api.nvim_list_bufs()) do
+ -- No need to care about unloaded or nofile buffers. Also :saveas won't work for them.
+ if
+ api.nvim_buf_is_loaded(buf)
+ and not vim.list_contains({ 'nofile', 'nowrite' }, vim.bo[buf].buftype)
+ then
+ local bname = api.nvim_buf_get_name(buf)
+ local path = path_components(vim.fs.normalize(bname, { expand_env = false }))
+ if path_under_prefix(path, prefix_parts) then
+ buffers[#buffers + 1] = buf
+ end
end
end
return buffers
@@ -616,19 +539,13 @@ function M.rename(old_fname, new_fname, opts)
local buf_rename = {} ---@type table<integer, {from: string, to: string}>
local old_fname_pat = '^' .. vim.pesc(old_fname_full)
- for b in
- vim.iter(get_bufs_with_prefix(old_fname_full)):filter(function(b)
- -- No need to care about unloaded or nofile buffers. Also :saveas won't work for them.
- return api.nvim_buf_is_loaded(b)
- and not vim.list_contains({ 'nofile', 'nowrite' }, vim.bo[b].buftype)
- end)
- do
+ for _, b in ipairs(get_writable_bufs(old_fname_full)) do
-- Renaming a buffer may conflict with another buffer that happens to have the same name. In
-- most cases, this would have been already detected by the file conflict check above, but the
-- conflicting buffer may not be associated with a file. For example, 'buftype' can be "nofile"
-- or "nowrite", or the buffer can be a normal buffer but has not been written to the file yet.
-- Renaming should fail in such cases to avoid losing the contents of the conflicting buffer.
- local old_bname = vim.api.nvim_buf_get_name(b)
+ local old_bname = api.nvim_buf_get_name(b)
local new_bname = old_bname:gsub(old_fname_pat, escape_gsub_repl(new_fname))
if vim.fn.bufexists(new_bname) == 1 then
local existing_buf = vim.fn.bufnr(new_bname)
@@ -702,7 +619,7 @@ end
--- Applies a `WorkspaceEdit`.
---
---@param workspace_edit lsp.WorkspaceEdit
----@param offset_encoding string utf-8|utf-16|utf-32 (required)
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' (required)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit, offset_encoding)
if offset_encoding == nil then
@@ -710,16 +627,18 @@ function M.apply_workspace_edit(workspace_edit, offset_encoding)
'apply_workspace_edit must be called with valid offset encoding',
vim.log.levels.WARN
)
+ return
end
if workspace_edit.documentChanges then
for idx, change in ipairs(workspace_edit.documentChanges) do
if change.kind == 'rename' then
- M.rename(vim.uri_to_fname(change.oldUri), vim.uri_to_fname(change.newUri), change.options)
+ local options = change.options --[[@as vim.lsp.util.rename.Opts]]
+ M.rename(vim.uri_to_fname(change.oldUri), vim.uri_to_fname(change.newUri), options)
elseif change.kind == 'create' then
create_file(change)
elseif change.kind == 'delete' then
delete_file(change)
- elseif change.kind then
+ elseif change.kind then --- @diagnostic disable-line:undefined-field
error(string.format('Unsupported change: %q', vim.inspect(change)))
else
M.apply_text_document_edit(change, idx, offset_encoding)
@@ -748,7 +667,7 @@ end
--- then the corresponding value is returned without further modifications.
---
---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent
----@param contents string[]|nil List of strings to extend with converted lines. Defaults to {}.
+---@param contents string[]? List of strings to extend with converted lines. Defaults to {}.
---@return string[] extended with lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
@@ -781,111 +700,117 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
+--- Returns the line/column-based position in `contents` at the given offset.
+---
+---@param offset integer
+---@param contents string[]
+---@return { [1]: integer, [2]: integer }?
+local function get_pos_from_offset(offset, contents)
+ local i = 0
+ for l, line in ipairs(contents) do
+ if offset >= i and offset < i + #line then
+ return { l - 1, offset - i + 1 }
+ else
+ i = i + #line + 1
+ end
+ end
+end
+
--- Converts `textDocument/signatureHelp` response to markdown lines.
---
---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp`
----@param ft string|nil filetype that will be use as the `lang` for the label markdown code block
----@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets
----@return string[]|nil table list of lines of converted markdown.
----@return number[]|nil table of active hl
+---@param ft string? filetype that will be use as the `lang` for the label markdown code block
+---@param triggers string[]? list of trigger characters from the lsp server. used to better determine parameter offsets
+---@return string[]? # lines of converted markdown.
+---@return Range4? # highlight range for the active parameter
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
- if not signature_help.signatures then
- return
- end
--The active signature. If omitted or the value lies outside the range of
--`signatures` the value defaults to zero or is ignored if `signatures.length == 0`.
--Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value.
- local contents = {}
- local active_hl
+ local contents = {} --- @type string[]
+ local active_offset ---@type [integer, integer]?
local active_signature = signature_help.activeSignature or 0
-- If the activeSignature is not inside the valid range, then clip it.
-- In 3.15 of the protocol, activeSignature was allowed to be negative
if active_signature >= #signature_help.signatures or active_signature < 0 then
active_signature = 0
end
- local signature = signature_help.signatures[active_signature + 1]
- if not signature then
- return
- end
+ local signature = vim.deepcopy(signature_help.signatures[active_signature + 1])
local label = signature.label
if ft then
-- wrap inside a code block for proper rendering
label = ('```%s\n%s\n```'):format(ft, label)
end
- list_extend(contents, split(label, '\n', { plain = true, trimempty = true }))
- if signature.documentation then
+ list_extend(contents, vim.split(label, '\n', { plain = true, trimempty = true }))
+ local doc = signature.documentation
+ if doc then
-- if LSP returns plain string, we treat it as plaintext. This avoids
-- special characters like underscore or similar from being interpreted
-- as markdown font modifiers
- if type(signature.documentation) == 'string' then
- signature.documentation = { kind = 'plaintext', value = signature.documentation }
+ if type(doc) == 'string' then
+ signature.documentation = { kind = 'plaintext', value = doc }
end
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
if signature.parameters and #signature.parameters > 0 then
- local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0)
- if active_parameter < 0 then
- active_parameter = 0
- end
+ -- First check if the signature has an activeParameter. If it doesn't check if the response
+ -- had that property instead. Else just default to 0.
+ local active_parameter =
+ math.max(signature.activeParameter or signature_help.activeParameter or 0, 0)
-- If the activeParameter is > #parameters, then set it to the last
-- NOTE: this is not fully according to the spec, but a client-side interpretation
- if active_parameter >= #signature.parameters then
- active_parameter = #signature.parameters - 1
- end
+ active_parameter = math.min(active_parameter, #signature.parameters - 1)
local parameter = signature.parameters[active_parameter + 1]
- if parameter then
- --[=[
- --Represents a parameter of a callable-signature. A parameter can
- --have a label and a doc-comment.
- interface ParameterInformation {
- --The label of this parameter information.
- --
- --Either a string or an inclusive start and exclusive end offsets within its containing
- --signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
- --string representation as `Position` and `Range` does.
- --
- --*Note*: a label of type string should be a substring of its containing signature label.
- --Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
- label: string | [number, number];
- --The human-readable doc-comment of this parameter. Will be shown
- --in the UI but can be omitted.
- documentation?: string | MarkupContent;
- }
- --]=]
- if parameter.label then
- if type(parameter.label) == 'table' then
- active_hl = parameter.label
- else
- local offset = 1
- -- try to set the initial offset to the first found trigger character
- for _, t in ipairs(triggers or {}) do
- local trigger_offset = signature.label:find(t, 1, true)
- if trigger_offset and (offset == 1 or trigger_offset < offset) then
- offset = trigger_offset
- end
- end
- for p, param in pairs(signature.parameters) do
- offset = signature.label:find(param.label, offset, true)
- if not offset then
- break
- end
- if p == active_parameter + 1 then
- active_hl = { offset - 1, offset + #parameter.label - 1 }
- break
- end
- offset = offset + #param.label + 1
- end
+ local parameter_label = parameter.label
+ if type(parameter_label) == 'table' then
+ active_offset = parameter_label
+ else
+ local offset = 1 ---@type integer?
+ -- try to set the initial offset to the first found trigger character
+ for _, t in ipairs(triggers or {}) do
+ local trigger_offset = signature.label:find(t, 1, true)
+ if trigger_offset and (offset == 1 or trigger_offset < offset) then
+ offset = trigger_offset
end
end
- if parameter.documentation then
- M.convert_input_to_markdown_lines(parameter.documentation, contents)
+ for p, param in pairs(signature.parameters) do
+ local plabel = param.label
+ assert(type(plabel) == 'string', 'Expected label to be a string')
+ offset = signature.label:find(plabel, offset, true)
+ if not offset then
+ break
+ end
+ if p == active_parameter + 1 then
+ active_offset = { offset - 1, offset + #parameter_label - 1 }
+ break
+ end
+ offset = offset + #param.label + 1
end
end
+ if parameter.documentation then
+ M.convert_input_to_markdown_lines(parameter.documentation, contents)
+ end
end
+
+ local active_hl = nil
+ if active_offset then
+ -- Account for the start of the markdown block.
+ if ft then
+ active_offset[1] = active_offset[1] + #contents[1]
+ active_offset[2] = active_offset[2] + #contents[1]
+ end
+
+ local a_start = get_pos_from_offset(active_offset[1], contents)
+ local a_end = get_pos_from_offset(active_offset[2], contents)
+ if a_start and a_end then
+ active_hl = { a_start[1], a_start[2], a_end[1], a_end[2] }
+ end
+ end
+
return contents, active_hl
end
@@ -894,32 +819,15 @@ end
---
---@param width integer window width (in character cells)
---@param height integer window height (in character cells)
----@param opts table optional
---- - offset_x (integer) offset to add to `col`
---- - offset_y (integer) offset to add to `row`
---- - border (string or table) override `border`
---- - focusable (string or table) override `focusable`
---- - zindex (string or table) override `zindex`, defaults to 50
---- - relative ("mouse"|"cursor") defaults to "cursor"
---- - anchor_bias ("auto"|"above"|"below") defaults to "auto"
---- - "auto": place window based on which side of the cursor has more lines
---- - "above": place the window above the cursor unless there are not enough lines
---- to display the full window height.
---- - "below": place the window below the cursor unless there are not enough lines
---- to display the full window height.
----@return table Options
+---@param opts? vim.lsp.util.open_floating_preview.Opts
+---@return vim.api.keyset.win_config
function M.make_floating_popup_options(width, height, opts)
- validate({
- opts = { opts, 't', true },
- })
+ validate('opts', opts, 'table', true)
opts = opts or {}
- validate({
- ['opts.offset_x'] = { opts.offset_x, 'n', true },
- ['opts.offset_y'] = { opts.offset_y, 'n', true },
- })
+ validate('opts.offset_x', opts.offset_x, 'number', true)
+ validate('opts.offset_y', opts.offset_y, 'number', true)
local anchor = ''
- local row, col
local lines_above = opts.relative == 'mouse' and vim.fn.getmousepos().line - 1
or vim.fn.winline() - 1
@@ -927,7 +835,7 @@ function M.make_floating_popup_options(width, height, opts)
local anchor_bias = opts.anchor_bias or 'auto'
- local anchor_below
+ local anchor_below --- @type boolean?
if anchor_bias == 'below' then
anchor_below = (lines_below > lines_above) or (height <= lines_below)
@@ -938,7 +846,8 @@ function M.make_floating_popup_options(width, height, opts)
anchor_below = lines_below > lines_above
end
- local border_height = get_border_size(opts).height
+ local border_height = get_border_size(opts)
+ local row, col --- @type integer?, integer?
if anchor_below then
anchor = anchor .. 'N'
height = math.max(math.min(lines_below - border_height, height), 0)
@@ -960,7 +869,7 @@ function M.make_floating_popup_options(width, height, opts)
end
local title = (opts.border and opts.title) and opts.title or nil
- local title_pos
+ local title_pos --- @type 'left'|'center'|'right'?
if title then
title_pos = opts.title_pos or 'center'
@@ -982,13 +891,21 @@ function M.make_floating_popup_options(width, height, opts)
}
end
+--- @class vim.lsp.util.show_document.Opts
+--- @inlinedoc
+---
+--- Jump to existing window if buffer is already open.
+--- @field reuse_win? boolean
+---
+--- Whether to focus/jump to location if possible.
+--- (defaults: true)
+--- @field focus? boolean
+
--- Shows document and optionally jumps to the location.
---
---@param location lsp.Location|lsp.LocationLink
----@param offset_encoding string|nil utf-8|utf-16|utf-32
----@param opts table|nil options
---- - reuse_win (boolean) Jump to existing window if buffer is already open.
---- - focus (boolean) Whether to focus/jump to location if possible. Defaults to true.
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'?
+---@param opts? vim.lsp.util.show_document.Opts
---@return boolean `true` if succeeded
function M.show_document(location, offset_encoding, opts)
-- location may be Location or LocationLink
@@ -998,6 +915,7 @@ function M.show_document(location, offset_encoding, opts)
end
if offset_encoding == nil then
vim.notify_once('show_document must be called with valid offset encoding', vim.log.levels.WARN)
+ return false
end
local bufnr = vim.uri_to_bufnr(uri)
@@ -1041,18 +959,13 @@ end
--- Jumps to a location.
---
+---@deprecated use `vim.lsp.util.show_document` with `{focus=true}` instead
---@param location lsp.Location|lsp.LocationLink
----@param offset_encoding string|nil utf-8|utf-16|utf-32
----@param reuse_win boolean|nil Jump to existing window if buffer is already open.
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'?
+---@param reuse_win boolean? Jump to existing window if buffer is already open.
---@return boolean `true` if the jump succeeded
function M.jump_to_location(location, offset_encoding, reuse_win)
- if offset_encoding == nil then
- vim.notify_once(
- 'jump_to_location must be called with valid offset encoding',
- vim.log.levels.WARN
- )
- end
-
+ vim.deprecate('vim.lsp.util.jump_to_location', nil, '0.12')
return M.show_document(location, offset_encoding, { reuse_win = reuse_win, focus = true })
end
@@ -1063,9 +976,9 @@ end
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location lsp.Location|lsp.LocationLink
----@param opts table
----@return integer|nil buffer id of float window
----@return integer|nil window id of float window
+---@param opts? vim.lsp.util.open_floating_preview.Opts
+---@return integer? buffer id of float window
+---@return integer? window id of float window
function M.preview_location(location, opts)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -1092,7 +1005,7 @@ end
local function find_window_by_var(name, value)
for _, win in ipairs(api.nvim_list_wins()) do
- if npcall(api.nvim_win_get_var, win, name) == value then
+ if vim.w[win][name] == value then
return win
end
end
@@ -1158,8 +1071,10 @@ local function collapse_blank_lines(contents)
end
local function get_markdown_fences()
- local fences = {}
- for _, fence in pairs(vim.g.markdown_fenced_languages or {}) do
+ local fences = {} --- @type table<string,string>
+ for _, fence in
+ pairs(vim.g.markdown_fenced_languages or {} --[[@as string[] ]])
+ do
local lang, syntax = fence:match('^(.*)=(.*)$')
if lang then
fences[lang] = syntax
@@ -1179,7 +1094,7 @@ end
---
---@param bufnr integer
---@param contents string[] of lines to show in window
----@param opts table with optional fields
+---@param opts? table with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap_at character to wrap at for computing height
@@ -1188,10 +1103,8 @@ end
--- - separator insert separator after code block
---@return table stripped content
function M.stylize_markdown(bufnr, contents, opts)
- validate({
- contents = { contents, 't' },
- opts = { opts, 't', true },
- })
+ validate('contents', contents, 'table')
+ validate('opts', opts, 'table', true)
opts = opts or {}
-- table of fence types to {ft, begin, end}
@@ -1203,8 +1116,11 @@ function M.stylize_markdown(bufnr, contents, opts)
text = { 'text', '<text>', '</text>' },
}
- local match_begin = function(line)
+ --- @param line string
+ --- @return {type:string,ft:string}?
+ local function match_begin(line)
for type, pattern in pairs(matchers) do
+ --- @type string?
local ret = line:match(string.format('^%%s*%s%%s*$', pattern[2]))
if ret then
return {
@@ -1215,7 +1131,10 @@ function M.stylize_markdown(bufnr, contents, opts)
end
end
- local match_end = function(line, match)
+ --- @param line string
+ --- @param match {type:string,ft:string}
+ --- @return string
+ local function match_end(line, match)
local pattern = matchers[match.type]
return line:match(string.format('^%%s*%s%%s*$', pattern[3]))
end
@@ -1224,76 +1143,80 @@ function M.stylize_markdown(bufnr, contents, opts)
contents = vim.split(table.concat(contents, '\n'), '\n', { trimempty = true })
local stripped = {}
- local highlights = {}
+ local highlights = {} --- @type {ft:string,start:integer,finish:integer}[]
-- keep track of lnums that contain markdown
- local markdown_lines = {}
- do
- local i = 1
- while i <= #contents do
- local line = contents[i]
- local match = match_begin(line)
- if match then
- local start = #stripped
- i = i + 1
- while i <= #contents do
- line = contents[i]
- if match_end(line, match) then
- i = i + 1
- break
- end
- table.insert(stripped, line)
+ local markdown_lines = {} --- @type table<integer,boolean>
+
+ local i = 1
+ while i <= #contents do
+ local line = contents[i]
+ local match = match_begin(line)
+ if match then
+ local start = #stripped
+ i = i + 1
+ while i <= #contents do
+ line = contents[i]
+ if match_end(line, match) then
i = i + 1
+ break
end
- table.insert(highlights, {
- ft = match.ft,
- start = start + 1,
- finish = #stripped,
- })
- -- add a separator, but not on the last line
- if opts.separator and i < #contents then
- table.insert(stripped, '---')
- markdown_lines[#stripped] = true
- end
- else
- -- strip any empty lines or separators prior to this separator in actual markdown
- if line:match('^---+$') then
- while
- markdown_lines[#stripped]
- and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$'))
- do
- markdown_lines[#stripped] = false
- table.remove(stripped, #stripped)
- end
- end
- -- add the line if its not an empty line following a separator
- if
- not (
- line:match('^%s*$')
- and markdown_lines[#stripped]
- and stripped[#stripped]:match('^---+$')
- )
- then
- table.insert(stripped, line)
- markdown_lines[#stripped] = true
- end
+ table.insert(stripped, line)
i = i + 1
end
+ table.insert(highlights, {
+ ft = match.ft,
+ start = start + 1,
+ finish = #stripped,
+ })
+ -- add a separator, but not on the last line
+ if opts.separator and i < #contents then
+ table.insert(stripped, '---')
+ markdown_lines[#stripped] = true
+ end
+ else
+ -- strip any empty lines or separators prior to this separator in actual markdown
+ if line:match('^---+$') then
+ while
+ markdown_lines[#stripped]
+ and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$'))
+ do
+ markdown_lines[#stripped] = false
+ table.remove(stripped, #stripped)
+ end
+ end
+ -- add the line if its not an empty line following a separator
+ if
+ not (
+ line:match('^%s*$')
+ and markdown_lines[#stripped]
+ and stripped[#stripped]:match('^---+$')
+ )
+ then
+ table.insert(stripped, line)
+ markdown_lines[#stripped] = true
+ end
+ i = i + 1
end
end
-- Handle some common html escape sequences
- stripped = vim.tbl_map(function(line)
- local escapes = {
- ['&gt;'] = '>',
- ['&lt;'] = '<',
- ['&quot;'] = '"',
- ['&apos;'] = "'",
- ['&ensp;'] = ' ',
- ['&emsp;'] = ' ',
- ['&amp;'] = '&',
- }
- return (string.gsub(line, '&[^ ;]+;', escapes))
- end, stripped)
+ --- @type string[]
+ stripped = vim.tbl_map(
+ --- @param line string
+ function(line)
+ local escapes = {
+ ['&gt;'] = '>',
+ ['&lt;'] = '<',
+ ['&quot;'] = '"',
+ ['&apos;'] = "'",
+ ['&ensp;'] = ' ',
+ ['&emsp;'] = ' ',
+ ['&amp;'] = '&',
+ }
+ return (line:gsub('&[^ ;]+;', escapes))
+ end,
+ stripped
+ )
-- Compute size of float needed to show (wrapped) lines
opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and api.nvim_win_get_width(0))
@@ -1312,7 +1235,7 @@ function M.stylize_markdown(bufnr, contents, opts)
local idx = 1
-- keep track of syntaxes we already included.
-- no need to include the same syntax more than once
- local langs = {}
+ local langs = {} --- @type table<string,boolean>
local fences = get_markdown_fences()
local function apply_syntax_to_region(ft, start, finish)
if ft == '' then
@@ -1335,6 +1258,7 @@ function M.stylize_markdown(bufnr, contents, opts)
if #api.nvim_get_runtime_file(('syntax/%s.vim'):format(ft), true) == 0 then
return
end
+ --- @diagnostic disable-next-line:param-type-mismatch
pcall(vim.cmd, string.format('syntax include %s syntax/%s.vim', lang, ft))
langs[lang] = true
end
@@ -1390,10 +1314,8 @@ end
---@return string[] table of lines containing normalized Markdown
---@see https://github.github.com/gfm
function M._normalize_markdown(contents, opts)
- validate({
- contents = { contents, 't' },
- opts = { opts, 't', true },
- })
+ validate('contents', contents, 'table')
+ validate('opts', opts, 'table', true)
opts = opts or {}
-- 1. Carriage returns are removed
@@ -1412,7 +1334,7 @@ end
--- Closes the preview window
---
---@param winnr integer window id of preview window
----@param bufnrs table|nil optional list of ignored buffers
+---@param bufnrs table? optional list of ignored buffers
local function close_preview_window(winnr, bufnrs)
vim.schedule(function()
-- exit if we are in one of ignored buffers
@@ -1460,20 +1382,13 @@ end
---@private
--- Computes size of float needed to show contents (with optional wrapping)
---
----@param contents table of lines to show in window
----@param opts? table with optional fields
---- - height of floating window
---- - width of floating window
---- - wrap_at character to wrap at for computing height
---- - max_width maximal width of floating window
---- - max_height maximal height of floating window
+---@param contents string[] of lines to show in window
+---@param opts? vim.lsp.util.open_floating_preview.Opts
---@return integer width size of float
---@return integer height size of float
function M._make_floating_popup_size(contents, opts)
- validate({
- contents = { contents, 't' },
- opts = { opts, 't', true },
- })
+ validate('contents', contents, 'table')
+ validate('opts', opts, 'table', true)
opts = opts or {}
local width = opts.width
@@ -1481,7 +1396,7 @@ function M._make_floating_popup_size(contents, opts)
local wrap_at = opts.wrap_at
local max_width = opts.max_width
local max_height = opts.max_height
- local line_widths = {}
+ local line_widths = {} --- @type table<integer,integer>
if not width then
width = 0
@@ -1492,17 +1407,15 @@ function M._make_floating_popup_size(contents, opts)
end
end
- local border_width = get_border_size(opts).width
+ local _, border_width = get_border_size(opts)
local screen_width = api.nvim_win_get_width(0)
width = math.min(width, screen_width)
-- make sure borders are always inside the screen
- if width + border_width > screen_width then
- width = width - (width + border_width - screen_width)
- end
+ width = math.min(width, screen_width - border_width)
- if wrap_at and wrap_at > width then
- wrap_at = width
+ if wrap_at then
+ wrap_at = math.min(wrap_at, width)
end
if max_width then
@@ -1534,7 +1447,6 @@ function M._make_floating_popup_size(contents, opts)
end
--- @class vim.lsp.util.open_floating_preview.Opts
---- @inlinedoc
---
--- Height of floating window
--- @field height? integer
@@ -1569,6 +1481,29 @@ end
--- window with the same {focus_id}
--- (default: `true`)
--- @field focus? boolean
+---
+--- offset to add to `col`
+--- @field offset_x? integer
+---
+--- offset to add to `row`
+--- @field offset_y? integer
+--- @field border? string|(string|[string,string])[] override `border`
+--- @field zindex? integer override `zindex`, defaults to 50
+--- @field title? string
+--- @field title_pos? 'left'|'center'|'right'
+---
+--- (default: `'cursor'`)
+--- @field relative? 'mouse'|'cursor'
+---
+--- - "auto": place window based on which side of the cursor has more lines
+--- - "above": place the window above the cursor unless there are not enough lines
+--- to display the full window height.
+--- - "below": place the window below the cursor unless there are not enough lines
+--- to display the full window height.
+--- (default: `'auto'`)
+--- @field anchor_bias? 'auto'|'above'|'below'
+---
+--- @field _update_win? integer
--- Shows contents in a floating window.
---
@@ -1580,11 +1515,9 @@ end
---@return integer bufnr of newly created float window
---@return integer winid of newly created float window preview window
function M.open_floating_preview(contents, syntax, opts)
- validate({
- contents = { contents, 't' },
- syntax = { syntax, 's', true },
- opts = { opts, 't', true },
- })
+ validate('contents', contents, 'table')
+ validate('syntax', syntax, 'string', true)
+ validate('opts', opts, 'table', true)
opts = opts or {}
opts.wrap = opts.wrap ~= false -- wrapping by default
opts.focus = opts.focus ~= false
@@ -1592,43 +1525,49 @@ function M.open_floating_preview(contents, syntax, opts)
local bufnr = api.nvim_get_current_buf()
- -- check if this popup is focusable and we need to focus
- if opts.focus_id and opts.focusable ~= false and opts.focus then
- -- Go back to previous window if we are in a focusable one
- local current_winnr = api.nvim_get_current_win()
- if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then
- api.nvim_command('wincmd p')
- return bufnr, current_winnr
- end
- do
- local win = find_window_by_var(opts.focus_id, bufnr)
- if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
- -- focus and return the existing buf, win
- api.nvim_set_current_win(win)
- api.nvim_command('stopinsert')
- return api.nvim_win_get_buf(win), win
+ local floating_winnr = opts._update_win
+
+ -- Create/get the buffer
+ local floating_bufnr --- @type integer
+ if floating_winnr then
+ floating_bufnr = api.nvim_win_get_buf(floating_winnr)
+ else
+ -- check if this popup is focusable and we need to focus
+ if opts.focus_id and opts.focusable ~= false and opts.focus then
+ -- Go back to previous window if we are in a focusable one
+ local current_winnr = api.nvim_get_current_win()
+ if vim.w[current_winnr][opts.focus_id] then
+ api.nvim_command('wincmd p')
+ return bufnr, current_winnr
+ end
+ do
+ local win = find_window_by_var(opts.focus_id, bufnr)
+ if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
+ -- focus and return the existing buf, win
+ api.nvim_set_current_win(win)
+ api.nvim_command('stopinsert')
+ return api.nvim_win_get_buf(win), win
+ end
end
end
- end
- -- check if another floating preview already exists for this buffer
- -- and close it if needed
- local existing_float = npcall(api.nvim_buf_get_var, bufnr, 'lsp_floating_preview')
- if existing_float and api.nvim_win_is_valid(existing_float) then
- api.nvim_win_close(existing_float, true)
+ -- check if another floating preview already exists for this buffer
+ -- and close it if needed
+ local existing_float = vim.b[bufnr].lsp_floating_preview
+ if existing_float and api.nvim_win_is_valid(existing_float) then
+ api.nvim_win_close(existing_float, true)
+ end
+ floating_bufnr = api.nvim_create_buf(false, true)
end
- -- Create the buffer
- local floating_bufnr = api.nvim_create_buf(false, true)
-
-- Set up the contents, using treesitter for markdown
local do_stylize = syntax == 'markdown' and vim.g.syntax_on ~= nil
+
if do_stylize then
local width = M._make_floating_popup_size(contents, opts)
contents = M._normalize_markdown(contents, { width = width })
vim.bo[floating_bufnr].filetype = 'markdown'
vim.treesitter.start(floating_bufnr)
- api.nvim_buf_set_lines(floating_bufnr, 0, -1, false, contents)
else
-- Clean up input: trim empty lines
contents = vim.split(table.concat(contents, '\n'), '\n', { trimempty = true })
@@ -1636,19 +1575,47 @@ function M.open_floating_preview(contents, syntax, opts)
if syntax then
vim.bo[floating_bufnr].syntax = syntax
end
- api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
end
- -- Compute size of float needed to show (wrapped) lines
- if opts.wrap then
- opts.wrap_at = opts.wrap_at or api.nvim_win_get_width(0)
+ vim.bo[floating_bufnr].modifiable = true
+ api.nvim_buf_set_lines(floating_bufnr, 0, -1, false, contents)
+
+ if floating_winnr then
+ api.nvim_win_set_config(floating_winnr, {
+ border = opts.border,
+ title = opts.title,
+ })
else
- opts.wrap_at = nil
- end
- local width, height = M._make_floating_popup_size(contents, opts)
+ -- Compute size of float needed to show (wrapped) lines
+ if opts.wrap then
+ opts.wrap_at = opts.wrap_at or api.nvim_win_get_width(0)
+ else
+ opts.wrap_at = nil
+ end
- local float_option = M.make_floating_popup_options(width, height, opts)
- local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
+ -- TODO(lewis6991): These function assume the current window to determine options,
+ -- therefore it won't work for opts._update_win and the current window if the floating
+ -- window
+ local width, height = M._make_floating_popup_size(contents, opts)
+ local float_option = M.make_floating_popup_options(width, height, opts)
+
+ floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
+
+ api.nvim_buf_set_keymap(
+ floating_bufnr,
+ 'n',
+ 'q',
+ '<cmd>bdelete<cr>',
+ { silent = true, noremap = true, nowait = true }
+ )
+ close_preview_autocmd(opts.close_events, floating_winnr, { floating_bufnr, bufnr })
+
+ -- save focus_id
+ if opts.focus_id then
+ api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
+ end
+ api.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
+ end
if do_stylize then
vim.wo[floating_winnr].conceallevel = 2
@@ -1656,25 +1623,11 @@ function M.open_floating_preview(contents, syntax, opts)
vim.wo[floating_winnr].foldenable = false -- Disable folding.
vim.wo[floating_winnr].wrap = opts.wrap -- Soft wrapping.
vim.wo[floating_winnr].breakindent = true -- Slightly better list presentation.
+ vim.wo[floating_winnr].smoothscroll = true -- Scroll by screen-line instead of buffer-line.
vim.bo[floating_bufnr].modifiable = false
vim.bo[floating_bufnr].bufhidden = 'wipe'
- api.nvim_buf_set_keymap(
- floating_bufnr,
- 'n',
- 'q',
- '<cmd>bdelete<cr>',
- { silent = true, noremap = true, nowait = true }
- )
- close_preview_autocmd(opts.close_events, floating_winnr, { floating_bufnr, bufnr })
-
- -- save focus_id
- if opts.focus_id then
- api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
- end
- api.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
-
return floating_bufnr, floating_winnr
end
@@ -1683,9 +1636,8 @@ do --[[ References ]]
--- Removes document highlights from a buffer.
---
- ---@param bufnr integer|nil Buffer id
+ ---@param bufnr integer? Buffer id
function M.buf_clear_references(bufnr)
- validate({ bufnr = { bufnr, { 'n' }, true } })
api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
end
@@ -1693,29 +1645,18 @@ do --[[ References ]]
---
---@param bufnr integer Buffer id
---@param references lsp.DocumentHighlight[] objects to highlight
- ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32".
+ ---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
function M.buf_highlight_references(bufnr, references, offset_encoding)
- validate({
- bufnr = { bufnr, 'n', true },
- offset_encoding = { offset_encoding, 'string', false },
- })
+ validate('bufnr', bufnr, 'number', true)
+ validate('offset_encoding', offset_encoding, 'string', false)
for _, reference in ipairs(references) do
- local start_line, start_char =
- reference['range']['start']['line'], reference['range']['start']['character']
- local end_line, end_char =
- reference['range']['end']['line'], reference['range']['end']['character']
+ local range = reference.range
+ local start_line = range.start.line
+ local end_line = range['end'].line
- local start_idx = get_line_byte_from_position(
- bufnr,
- { line = start_line, character = start_char },
- offset_encoding
- )
- local end_idx = get_line_byte_from_position(
- bufnr,
- { line = start_line, character = end_char },
- offset_encoding
- )
+ local start_idx = get_line_byte_from_position(bufnr, range.start, offset_encoding)
+ local end_idx = get_line_byte_from_position(bufnr, range['end'], offset_encoding)
local document_highlight_kind = {
[protocol.DocumentHighlightKind.Text] = 'LspReferenceText',
@@ -1723,13 +1664,13 @@ do --[[ References ]]
[protocol.DocumentHighlightKind.Write] = 'LspReferenceWrite',
}
local kind = reference['kind'] or protocol.DocumentHighlightKind.Text
- highlight.range(
+ vim.hl.range(
bufnr,
reference_ns,
document_highlight_kind[kind],
{ start_line, start_idx },
{ end_line, end_idx },
- { priority = vim.highlight.priorities.user }
+ { priority = vim.hl.priorities.user }
)
end
end
@@ -1739,16 +1680,6 @@ local position_sort = sort_by_key(function(v)
return { v.start.line, v.start.character }
end)
----@class vim.lsp.util.locations_to_items.ret
----@inlinedoc
----@field filename string
----@field lnum integer 1-indexed line number
----@field end_lnum integer 1-indexed end line number
----@field col integer 1-indexed column
----@field end_col integer 1-indexed end column
----@field text string
----@field user_data lsp.Location|lsp.LocationLink
-
--- Returns the items with the byte position calculated correctly and in sorted
--- order, for display in quickfix and location lists.
---
@@ -1759,9 +1690,9 @@ end)
--- |setloclist()|.
---
---@param locations lsp.Location[]|lsp.LocationLink[]
----@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32
---- default to first client of buffer
----@return vim.lsp.util.locations_to_items.ret[]
+---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'
+--- default to first client of buffer
+---@return vim.quickfix.entry[] # See |setqflist()| for the format
function M.locations_to_items(locations, offset_encoding)
if offset_encoding == nil then
vim.notify_once(
@@ -1771,28 +1702,19 @@ function M.locations_to_items(locations, offset_encoding)
offset_encoding = vim.lsp.get_clients({ bufnr = 0 })[1].offset_encoding
end
- local items = {}
+ local items = {} --- @type vim.quickfix.entry[]
+
---@type table<string, {start: lsp.Position, end: lsp.Position, location: lsp.Location|lsp.LocationLink}[]>
- local grouped = setmetatable({}, {
- __index = function(t, k)
- local v = {}
- rawset(t, k, v)
- return v
- end,
- })
+ local grouped = {}
for _, d in ipairs(locations) do
-- locations may be Location or LocationLink
local uri = d.uri or d.targetUri
local range = d.range or d.targetSelectionRange
+ grouped[uri] = grouped[uri] or {}
table.insert(grouped[uri], { start = range.start, ['end'] = range['end'], location = d })
end
- ---@type string[]
- local keys = vim.tbl_keys(grouped)
- table.sort(keys)
- -- TODO(ashkan) I wish we could do this lazily.
- for _, uri in ipairs(keys) do
- local rows = grouped[uri]
+ for uri, rows in vim.spairs(grouped) do
table.sort(rows, position_sort)
local filename = vim.uri_to_fname(uri)
@@ -1814,10 +1736,10 @@ function M.locations_to_items(locations, offset_encoding)
local end_row = end_pos.line
local line = lines[row] or ''
local end_line = lines[end_row] or ''
- local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
- local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
+ local col = vim.str_byteindex(line, offset_encoding, pos.character, false)
+ local end_col = vim.str_byteindex(end_line, offset_encoding, end_pos.character, false)
- table.insert(items, {
+ items[#items + 1] = {
filename = filename,
lnum = row + 1,
end_lnum = end_row + 1,
@@ -1825,58 +1747,51 @@ function M.locations_to_items(locations, offset_encoding)
end_col = end_col + 1,
text = line,
user_data = temp.location,
- })
+ }
end
end
return items
end
--- According to LSP spec, if the client set "symbolKind.valueSet",
--- the client must handle it properly even if it receives a value outside the specification.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
-function M._get_symbol_kind_name(symbol_kind)
- return protocol.SymbolKind[symbol_kind] or 'Unknown'
-end
-
--- Converts symbols to quickfix list items.
---
----@param symbols table DocumentSymbol[] or SymbolInformation[]
+---@param symbols lsp.DocumentSymbol[]|lsp.SymbolInformation[]
---@param bufnr? integer
+---@return vim.quickfix.entry[] # See |setqflist()| for the format
function M.symbols_to_items(symbols, bufnr)
- local function _symbols_to_items(_symbols, _items, _bufnr)
- for _, symbol in ipairs(_symbols) do
- if symbol.location then -- SymbolInformation type
- local range = symbol.location.range
- local kind = M._get_symbol_kind_name(symbol.kind)
- table.insert(_items, {
- filename = vim.uri_to_fname(symbol.location.uri),
- lnum = range.start.line + 1,
- col = range.start.character + 1,
- kind = kind,
- text = '[' .. kind .. '] ' .. symbol.name,
- })
- elseif symbol.selectionRange then -- DocumentSymbole type
- local kind = M._get_symbol_kind_name(symbol.kind)
- table.insert(_items, {
- -- bufnr = _bufnr,
- filename = api.nvim_buf_get_name(_bufnr),
- lnum = symbol.selectionRange.start.line + 1,
- col = symbol.selectionRange.start.character + 1,
- kind = kind,
- text = '[' .. kind .. '] ' .. symbol.name,
- })
- if symbol.children then
- for _, v in ipairs(_symbols_to_items(symbol.children, _items, _bufnr)) do
- for _, s in ipairs(v) do
- table.insert(_items, s)
- end
- end
- end
- end
+ bufnr = bufnr or 0
+ local items = {} --- @type vim.quickfix.entry[]
+ for _, symbol in ipairs(symbols) do
+ --- @type string?, lsp.Position?
+ local filename, pos
+
+ if symbol.location then
+ --- @cast symbol lsp.SymbolInformation
+ filename = vim.uri_to_fname(symbol.location.uri)
+ pos = symbol.location.range.start
+ elseif symbol.selectionRange then
+ --- @cast symbol lsp.DocumentSymbol
+ filename = api.nvim_buf_get_name(bufnr)
+ pos = symbol.selectionRange.start
+ end
+
+ if filename and pos then
+ local kind = protocol.SymbolKind[symbol.kind] or 'Unknown'
+ items[#items + 1] = {
+ filename = filename,
+ lnum = pos.line + 1,
+ col = pos.character + 1,
+ kind = kind,
+ text = '[' .. kind .. '] ' .. symbol.name,
+ }
+ end
+
+ if symbol.children then
+ list_extend(items, M.symbols_to_items(symbol.children, bufnr))
end
- return _items
end
- return _symbols_to_items(symbols, {}, bufnr or 0)
+
+ return items
end
--- Removes empty lines from the beginning and end.
@@ -1899,7 +1814,7 @@ function M.trim_empty_lines(lines)
break
end
end
- return list_extend({}, lines, start, finish)
+ return vim.list_slice(lines, start, finish)
end
--- Accepts markdown lines and tries to reduce them to a filetype if they
@@ -1932,8 +1847,8 @@ function M.try_trim_markdown_code_blocks(lines)
return 'markdown'
end
----@param window integer|nil: window handle or 0 for current, defaults to current
----@param offset_encoding? string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
+---@param window integer?: window handle or 0 for current, defaults to current
+---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
local function make_position_param(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
@@ -1945,15 +1860,15 @@ local function make_position_param(window, offset_encoding)
return { line = 0, character = 0 }
end
- col = M._str_utfindex_enc(line, col, offset_encoding)
+ col = vim.str_utfindex(line, offset_encoding, col, false)
return { line = row, character = col }
end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
---
----@param window integer|nil: window handle or 0 for current, defaults to current
----@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
+---@param window integer?: window handle or 0 for current, defaults to current
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
@@ -1970,11 +1885,9 @@ end
---@param bufnr integer buffer handle or 0 for current, defaults to current
---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
- validate({
- bufnr = { bufnr, 'n', true },
- })
+ validate('bufnr', bufnr, 'number', true)
- local offset_encoding
+ local offset_encoding --- @type 'utf-8'|'utf-16'|'utf-32'?
for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do
if client.offset_encoding == nil then
@@ -2005,8 +1918,8 @@ end
--- `textDocument/codeAction`, `textDocument/colorPresentation`,
--- `textDocument/rangeFormatting`.
---
----@param window integer|nil: window handle or 0 for current, defaults to current
----@param offset_encoding "utf-8"|"utf-16"|"utf-32"|nil defaults to `offset_encoding` of first client of buffer of `window`
+---@param window integer? window handle or 0 for current, defaults to current
+---@param offset_encoding "utf-8"|"utf-16"|"utf-32"? defaults to `offset_encoding` of first client of buffer of `window`
---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
function M.make_range_params(window, offset_encoding)
@@ -2022,33 +1935,33 @@ end
--- Using the given range in the current buffer, creates an object that
--- is similar to |vim.lsp.util.make_range_params()|.
---
----@param start_pos integer[]|nil {row,col} mark-indexed position.
+---@param start_pos [integer,integer]? {row,col} mark-indexed position.
--- Defaults to the start of the last visual selection.
----@param end_pos integer[]|nil {row,col} mark-indexed position.
+---@param end_pos [integer,integer]? {row,col} mark-indexed position.
--- Defaults to the end of the last visual selection.
----@param bufnr integer|nil buffer handle or 0 for current, defaults to current
----@param offset_encoding "utf-8"|"utf-16"|"utf-32"|nil defaults to `offset_encoding` of first client of `bufnr`
+---@param bufnr integer? buffer handle or 0 for current, defaults to current
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of `bufnr`
---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`start_position`, end = `end_position` } }
function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
- validate({
- start_pos = { start_pos, 't', true },
- end_pos = { end_pos, 't', true },
- offset_encoding = { offset_encoding, 's', true },
- })
+ validate('start_pos', start_pos, 'table', true)
+ validate('end_pos', end_pos, 'table', true)
+ validate('offset_encoding', offset_encoding, 'string', true)
bufnr = bufnr or api.nvim_get_current_buf()
offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
- local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<'))
- local B = list_extend({}, end_pos or api.nvim_buf_get_mark(bufnr, '>'))
+ --- @type [integer, integer]
+ local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) }
+ --- @type [integer, integer]
+ local B = { unpack(end_pos or api.nvim_buf_get_mark(bufnr, '>')) }
-- convert to 0-index
A[1] = A[1] - 1
B[1] = B[1] - 1
-- account for offset_encoding.
if A[2] > 0 then
- A = { A[1], M.character_offset(bufnr, A[1], A[2], offset_encoding) }
+ A[2] = M.character_offset(bufnr, A[1], A[2], offset_encoding)
end
if B[2] > 0 then
- B = { B[1], M.character_offset(bufnr, B[1], B[2], offset_encoding) }
+ B[2] = M.character_offset(bufnr, B[1], B[2], offset_encoding)
end
-- we need to offset the end character position otherwise we loose the last
-- character of the selection, as LSP end position is exclusive
@@ -2067,7 +1980,7 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
----@param bufnr integer|nil: Buffer handle, defaults to current
+---@param bufnr integer?: Buffer handle, defaults to current
---@return lsp.TextDocumentIdentifier
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params(bufnr)
@@ -2085,10 +1998,10 @@ end
--- Returns indentation size.
---
---@see 'shiftwidth'
----@param bufnr integer|nil: Buffer handle, defaults to current
+---@param bufnr integer?: Buffer handle, defaults to current
---@return integer indentation size
function M.get_effective_tabstop(bufnr)
- validate({ bufnr = { bufnr, 'n', true } })
+ validate('bufnr', bufnr, 'number', true)
local bo = bufnr and vim.bo[bufnr] or vim.bo
local sw = bo.shiftwidth
return (sw == 0 and bo.tabstop) or sw
@@ -2096,11 +2009,11 @@ end
--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
----@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries
+---@param options lsp.FormattingOptions? with valid `FormattingOptions` entries
---@return lsp.DocumentFormattingParams object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
- validate({ options = { options, 't', true } })
+ validate('options', options, 'table', true)
options = vim.tbl_extend('keep', options or {}, {
tabSize = M.get_effective_tabstop(),
insertSpaces = vim.bo.expandtab,
@@ -2116,7 +2029,8 @@ end
---@param buf integer buffer number (0 for current)
---@param row integer 0-indexed line
---@param col integer 0-indexed byte offset in line
----@param offset_encoding string utf-8|utf-16|utf-32 defaults to `offset_encoding` of first client of `buf`
+---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'
+--- defaults to `offset_encoding` of first client of `buf`
---@return integer `offset_encoding` index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col, offset_encoding)
local line = get_line(buf, row)
@@ -2127,7 +2041,7 @@ function M.character_offset(buf, row, col, offset_encoding)
)
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
end
- return M._str_utfindex_enc(line, col, offset_encoding)
+ return vim.str_utfindex(line, offset_encoding, col, false)
end
--- Helper function to return nested values in language server settings
@@ -2139,6 +2053,7 @@ end
function M.lookup_section(settings, section)
vim.deprecate('vim.lsp.util.lookup_section()', 'vim.tbl_get() with `vim.split`', '0.12')
for part in vim.gsplit(section, '.', { plain = true }) do
+ --- @diagnostic disable-next-line:no-unknown
settings = settings[part]
if settings == nil then
return vim.NIL
@@ -2153,7 +2068,7 @@ end
---@param bufnr integer
---@param start_line integer
---@param end_line integer
----@param offset_encoding lsp.PositionEncodingKind
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@return lsp.Range
local function make_line_range_params(bufnr, start_line, end_line, offset_encoding)
local last_line = api.nvim_buf_line_count(bufnr) - 1
@@ -2161,7 +2076,7 @@ local function make_line_range_params(bufnr, start_line, end_line, offset_encodi
---@type lsp.Position
local end_pos
- if end_line == last_line and not vim.api.nvim_get_option_value('endofline', { buf = bufnr }) then
+ if end_line == last_line and not vim.bo[bufnr].endofline then
end_pos = {
line = end_line,
character = M.character_offset(bufnr, end_line, #get_line(bufnr, end_line), offset_encoding),
@@ -2201,9 +2116,7 @@ function M._refresh(method, opts)
local textDocument = M.make_text_document_params(bufnr)
- local only_visible = opts.only_visible or false
-
- if only_visible then
+ if opts.only_visible then
for _, window in ipairs(api.nvim_list_wins()) do
if api.nvim_win_get_buf(window) == bufnr then
local first = vim.fn.line('w0', window)
diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua
index 47c2080e3c..5ecb00f49b 100644
--- a/runtime/lua/vim/provider/health.lua
+++ b/runtime/lua/vim/provider/health.lua
@@ -449,7 +449,7 @@ end
--- Get the latest Nvim Python client (pynvim) version from PyPI.
local function latest_pypi_version()
local pypi_version = 'unable to get pypi response'
- local pypi_response = download('https://pypi.python.org/pypi/pynvim/json')
+ local pypi_response = download('https://pypi.org/pypi/pynvim/json')
if pypi_response ~= '' then
local pcall_ok, output = pcall(vim.fn.json_decode, pypi_response)
if not pcall_ok then
diff --git a/runtime/lua/vim/secure.lua b/runtime/lua/vim/secure.lua
index 266725cce2..7b1d071270 100644
--- a/runtime/lua/vim/secure.lua
+++ b/runtime/lua/vim/secure.lua
@@ -26,7 +26,7 @@ end
---
---@param trust table<string, string> Trust table to write
local function write_trust(trust)
- vim.validate({ trust = { trust, 't' } })
+ vim.validate('trust', trust, 'table')
local f = assert(io.open(vim.fn.stdpath('state') .. '/trust', 'w'))
local t = {} ---@type string[]
@@ -49,7 +49,7 @@ end
---@return (string|nil) The contents of the given file if it exists and is
--- trusted, or nil otherwise.
function M.read(path)
- vim.validate({ path = { path, 's' } })
+ vim.validate('path', path, 'string')
local fullpath = vim.uv.fs_realpath(vim.fs.normalize(path))
if not fullpath then
return nil
@@ -132,17 +132,11 @@ end
---@return boolean success true if operation was successful
---@return string msg full path if operation was successful, else error message
function M.trust(opts)
- vim.validate({
- path = { opts.path, 's', true },
- bufnr = { opts.bufnr, 'n', true },
- action = {
- opts.action,
- function(m)
- return m == 'allow' or m == 'deny' or m == 'remove'
- end,
- [["allow" or "deny" or "remove"]],
- },
- })
+ vim.validate('path', opts.path, 'string', true)
+ vim.validate('bufnr', opts.bufnr, 'number', true)
+ vim.validate('action', opts.action, function(m)
+ return m == 'allow' or m == 'deny' or m == 'remove'
+ end, [["allow" or "deny" or "remove"]])
---@cast opts vim.trust.opts
local path = opts.path
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 4d06cdd77d..4f2373b182 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -109,7 +109,9 @@ function vim.gsplit(s, sep, opts)
if type(opts) == 'boolean' then
plain = opts -- For backwards compatibility.
else
- vim.validate({ s = { s, 's' }, sep = { sep, 's' }, opts = { opts, 't', true } })
+ vim.validate('s', s, 'string')
+ vim.validate('sep', sep, 'string')
+ vim.validate('opts', opts, 'table', true)
opts = opts or {}
plain, trimempty = opts.plain, opts.trimempty
end
@@ -249,7 +251,8 @@ end
---@param t table<any, T> Table
---@return table : Table of transformed values
function vim.tbl_map(func, t)
- vim.validate({ func = { func, 'c' }, t = { t, 't' } })
+ vim.validate('func', func, 'callable')
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
local rettab = {} --- @type table<any,any>
@@ -266,7 +269,8 @@ end
---@param t table<any, T> (table) Table
---@return T[] : Table of filtered values
function vim.tbl_filter(func, t)
- vim.validate({ func = { func, 'c' }, t = { t, 't' } })
+ vim.validate('func', func, 'callable')
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
local rettab = {} --- @type table<any,any>
@@ -303,12 +307,13 @@ end
---@param opts? vim.tbl_contains.Opts Keyword arguments |kwargs|:
---@return boolean `true` if `t` contains `value`
function vim.tbl_contains(t, value, opts)
- vim.validate({ t = { t, 't' }, opts = { opts, 't', true } })
+ vim.validate('t', t, 'table')
+ vim.validate('opts', opts, 'table', true)
--- @cast t table<any,any>
local pred --- @type fun(v: any): boolean?
if opts and opts.predicate then
- vim.validate({ value = { value, 'c' } })
+ vim.validate('value', value, 'callable')
pred = value
else
pred = function(v)
@@ -550,12 +555,10 @@ end
---@param finish integer? Final index on src. Defaults to `#src`
---@return T dst
function vim.list_extend(dst, src, start, finish)
- vim.validate({
- dst = { dst, 't' },
- src = { src, 't' },
- start = { start, 'n', true },
- finish = { finish, 'n', true },
- })
+ vim.validate('dst', dst, 'table')
+ vim.validate('src', src, 'table')
+ vim.validate('start', start, 'number', true)
+ vim.validate('finish', finish, 'number', true)
for i = start or 1, finish or #src do
table.insert(dst, src[i])
end
@@ -778,231 +781,227 @@ function vim.endswith(s, suffix)
end
do
- --- @alias vim.validate.Type
- --- | 't' | 'table'
- --- | 's' | 'string'
- --- | 'n' | 'number'
- --- | 'f' | 'function'
- --- | 'c' | 'callable'
- --- | 'nil'
- --- | 'thread'
- --- | 'userdata
-
- local type_names = {
- ['table'] = 'table',
- t = 'table',
- ['string'] = 'string',
- s = 'string',
- ['number'] = 'number',
- n = 'number',
- ['boolean'] = 'boolean',
+ --- @alias vim.validate.Validator
+ --- | type
+ --- | 'callable'
+ --- | (type|'callable')[]
+ --- | fun(v:any):boolean, string?
+
+ local type_aliases = {
b = 'boolean',
- ['function'] = 'function',
- f = 'function',
- ['callable'] = 'callable',
c = 'callable',
- ['nil'] = 'nil',
- ['thread'] = 'thread',
- ['userdata'] = 'userdata',
+ f = 'function',
+ n = 'number',
+ s = 'string',
+ t = 'table',
}
--- @nodoc
- --- @class vim.validate.Spec [any, string|string[], boolean]
+ --- @class vim.validate.Spec
--- @field [1] any Argument value
- --- @field [2] string|string[]|fun(v:any):boolean, string? Type name, or callable
- --- @field [3]? boolean
+ --- @field [2] vim.validate.Validator Argument validator
+ --- @field [3]? boolean|string Optional flag or error message
- local function _is_type(val, t)
+ local function is_type(val, t)
return type(val) == t or (t == 'callable' and vim.is_callable(val))
end
--- @param param_name string
- --- @param spec vim.validate.Spec
+ --- @param val any
+ --- @param validator vim.validate.Validator
+ --- @param message? string
+ --- @param allow_alias? boolean Allow short type names: 'n', 's', 't', 'b', 'f', 'c'
--- @return string?
- local function is_param_valid(param_name, spec)
- if type(spec) ~= 'table' then
- return string.format('opt[%s]: expected table, got %s', param_name, type(spec))
- end
+ local function is_valid(param_name, val, validator, message, allow_alias)
+ if type(validator) == 'string' then
+ local expected = allow_alias and type_aliases[validator] or validator
- local val = spec[1] -- Argument value
- local types = spec[2] -- Type name, or callable
- local optional = (true == spec[3])
-
- if type(types) == 'string' then
- types = { types }
- end
+ if not expected then
+ return string.format('invalid type name: %s', validator)
+ end
- if vim.is_callable(types) then
+ if not is_type(val, expected) then
+ return string.format('%s: expected %s, got %s', param_name, expected, type(val))
+ end
+ elseif vim.is_callable(validator) then
-- Check user-provided validation function
- local valid, optional_message = types(val)
+ local valid, opt_msg = validator(val)
if not valid then
- local error_message =
- string.format('%s: expected %s, got %s', param_name, (spec[3] or '?'), tostring(val))
- if optional_message ~= nil then
- error_message = string.format('%s. Info: %s', error_message, optional_message)
+ local err_msg =
+ string.format('%s: expected %s, got %s', param_name, message or '?', tostring(val))
+
+ if opt_msg then
+ err_msg = string.format('%s. Info: %s', err_msg, opt_msg)
end
- return error_message
+ return err_msg
end
- elseif type(types) == 'table' then
- local success = false
- for i, t in ipairs(types) do
- local t_name = type_names[t]
- if not t_name then
+ elseif type(validator) == 'table' then
+ for _, t in ipairs(validator) do
+ local expected = allow_alias and type_aliases[t] or t
+ if not expected then
return string.format('invalid type name: %s', t)
end
- types[i] = t_name
- if (optional and val == nil) or _is_type(val, t_name) then
- success = true
- break
+ if is_type(val, expected) then
+ return -- success
end
end
- if not success then
- return string.format(
- '%s: expected %s, got %s',
- param_name,
- table.concat(types, '|'),
- type(val)
- )
+
+ -- Normalize validator types for error message
+ if allow_alias then
+ for i, t in ipairs(validator) do
+ validator[i] = type_aliases[t] or t
+ end
end
+
+ return string.format(
+ '%s: expected %s, got %s',
+ param_name,
+ table.concat(validator, '|'),
+ type(val)
+ )
else
- return string.format('invalid type name: %s', tostring(types))
+ return string.format('invalid validator: %s', tostring(validator))
end
end
- --- @param opt table<vim.validate.Type,vim.validate.Spec>
- --- @return boolean, string?
- local function is_valid(opt)
- if type(opt) ~= 'table' then
- return false, string.format('opt: expected table, got %s', type(opt))
- end
-
+ --- @param opt table<type|'callable',vim.validate.Spec>
+ --- @return string?
+ local function validate_spec(opt)
local report --- @type table<string,string>?
for param_name, spec in pairs(opt) do
- local msg = is_param_valid(param_name, spec)
- if msg then
+ local err_msg --- @type string?
+ if type(spec) ~= 'table' then
+ err_msg = string.format('opt[%s]: expected table, got %s', param_name, type(spec))
+ else
+ local value, validator = spec[1], spec[2]
+ local msg = type(spec[3]) == 'string' and spec[3] or nil --[[@as string?]]
+ local optional = spec[3] == true
+ if not (optional and value == nil) then
+ err_msg = is_valid(param_name, value, validator, msg, true)
+ end
+ end
+
+ if err_msg then
report = report or {}
- report[param_name] = msg
+ report[param_name] = err_msg
end
end
if report then
for _, msg in vim.spairs(report) do -- luacheck: ignore
- return false, msg
+ return msg
end
end
-
- return true
end
--- Validate function arguments.
---
--- This function has two valid forms:
---
- --- 1. vim.validate(name: str, value: any, type: string, optional?: bool)
- --- 2. vim.validate(spec: table)
+ --- 1. `vim.validate(name, value, validator[, optional][, message])`
---
- --- Form 1 validates that argument {name} with value {value} has the type
- --- {type}. {type} must be a value returned by |lua-type()|. If {optional} is
- --- true, then {value} may be null. This form is significantly faster and
- --- should be preferred for simple cases.
+ --- Validates that argument {name} with value {value} satisfies
+ --- {validator}. If {optional} is given and is `true`, then {value} may be
+ --- `nil`. If {message} is given, then it is used as the expected type in the
+ --- error message.
---
- --- Example:
+ --- Example:
---
- --- ```lua
- --- function vim.startswith(s, prefix)
- --- vim.validate('s', s, 'string')
- --- vim.validate('prefix', prefix, 'string')
- --- ...
- --- end
- --- ```
+ --- ```lua
+ --- function vim.startswith(s, prefix)
+ --- vim.validate('s', s, 'string')
+ --- vim.validate('prefix', prefix, 'string')
+ --- ...
+ --- end
+ --- ```
---
- --- Form 2 validates a parameter specification (types and values). Specs are
- --- evaluated in alphanumeric order, until the first failure.
+ --- 2. `vim.validate(spec)` (deprecated)
+ --- where `spec` is of type
+ --- `table<string,[value:any, validator: vim.validate.Validator, optional_or_msg? : boolean|string]>)`
---
- --- Usage example:
+ --- Validates a argument specification.
+ --- Specs are evaluated in alphanumeric order, until the first failure.
---
- --- ```lua
- --- function user.new(name, age, hobbies)
- --- vim.validate{
- --- name={name, 'string'},
- --- age={age, 'number'},
- --- hobbies={hobbies, 'table'},
- --- }
- --- ...
- --- end
- --- ```
+ --- Example:
+ ---
+ --- ```lua
+ --- function user.new(name, age, hobbies)
+ --- vim.validate{
+ --- name={name, 'string'},
+ --- age={age, 'number'},
+ --- hobbies={hobbies, 'table'},
+ --- }
+ --- ...
+ --- end
+ --- ```
---
--- Examples with explicit argument values (can be run directly):
---
--- ```lua
- --- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
+ --- vim.validate('arg1', {'foo'}, 'table')
+ --- --> NOP (success)
+ --- vim.validate('arg2', 'foo', 'string')
--- --> NOP (success)
---
- --- vim.validate{arg1={1, 'table'}}
+ --- vim.validate('arg1', 1, 'table')
--- --> error('arg1: expected table, got number')
---
- --- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
+ --- vim.validate('arg1', 3, function(a) return (a % 2) == 0 end, 'even number')
--- --> error('arg1: expected even number, got 3')
--- ```
---
--- If multiple types are valid they can be given as a list.
---
--- ```lua
- --- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
+ --- vim.validate('arg1', {'foo'}, {'table', 'string'})
+ --- vim.validate('arg2', 'foo', {'table', 'string'})
--- -- NOP (success)
---
- --- vim.validate{arg1={1, {'string', 'table'}}}
+ --- vim.validate('arg1', 1, {'string', 'table'})
--- -- error('arg1: expected string|table, got number')
--- ```
---
- ---@param opt table<vim.validate.Type,vim.validate.Spec> (table) Names of parameters to validate. Each key is a parameter
- --- name; each value is a tuple in one of these forms:
- --- 1. (arg_value, type_name, optional)
- --- - arg_value: argument value
- --- - type_name: string|table type name, one of: ("table", "t", "string",
- --- "s", "number", "n", "boolean", "b", "function", "f", "nil",
- --- "thread", "userdata") or list of them.
- --- - optional: (optional) boolean, if true, `nil` is valid
- --- 2. (arg_value, fn, msg)
- --- - arg_value: argument value
- --- - fn: any function accepting one argument, returns true if and
- --- only if the argument is valid. Can optionally return an additional
- --- informative error message as the second returned value.
- --- - msg: (optional) error string if validation fails
- --- @overload fun(name: string, val: any, expected: string, optional?: boolean)
- function vim.validate(opt, ...)
- local ok = false
- local err_msg ---@type string?
- local narg = select('#', ...)
- if narg == 0 then
- ok, err_msg = is_valid(opt)
- elseif narg >= 2 then
- -- Overloaded signature for fast/simple cases
- local name = opt --[[@as string]]
- local v, expected, optional = ... ---@type string, string, boolean?
- local actual = type(v)
-
- ok = (actual == expected) or (v == nil and optional == true)
+ --- @note `validator` set to a value returned by |lua-type()| provides the
+ --- best performance.
+ ---
+ --- @param name string Argument name
+ --- @param value string Argument value
+ --- @param validator vim.validate.Validator
+ --- - (`string|string[]`): Any value that can be returned from |lua-type()| in addition to
+ --- `'callable'`: `'boolean'`, `'callable'`, `'function'`, `'nil'`, `'number'`, `'string'`, `'table'`,
+ --- `'thread'`, `'userdata'`.
+ --- - (`fun(val:any): boolean, string?`) A function that returns a boolean and an optional
+ --- string message.
+ --- @param optional? boolean Argument is optional (may be omitted)
+ --- @param message? string message when validation fails
+ --- @overload fun(name: string, val: any, validator: vim.validate.Validator, message: string)
+ --- @overload fun(spec: table<string,[any, vim.validate.Validator, boolean|string]>)
+ function vim.validate(name, value, validator, optional, message)
+ local err_msg --- @type string?
+ if validator then -- Form 1
+ -- Check validator as a string first to optimize the common case.
+ local ok = (type(value) == validator) or (value == nil and optional == true)
if not ok then
- err_msg = ('%s: expected %s, got %s%s'):format(
- name,
- expected,
- actual,
- v and (' (%s)'):format(v) or ''
- )
+ local msg = type(optional) == 'string' and optional or message --[[@as string?]]
+ -- Check more complicated validators
+ err_msg = is_valid(name, value, validator, msg, false)
end
+ elseif type(name) == 'table' then -- Form 2
+ vim.deprecate('vim.validate', 'vim.validate(name, value, validator, optional_or_msg)', '1.0')
+ err_msg = validate_spec(name)
else
error('invalid arguments')
end
- if not ok then
+ if err_msg then
error(err_msg, 2)
end
end
end
+
--- Returns true if object `f` can be called as a function.
---
---@param f any Any object
@@ -1143,7 +1142,7 @@ end
--- @param mod T
--- @return T
function vim._defer_require(root, mod)
- return setmetatable({}, {
+ return setmetatable({ _submodules = mod }, {
---@param t table<string, any>
---@param k string
__index = function(t, k)
@@ -1157,6 +1156,34 @@ function vim._defer_require(root, mod)
})
end
+--- @private
+--- Creates a module alias/shim that lazy-loads a target module.
+---
+--- Unlike `vim.defaulttable()` this also:
+--- - implements __call
+--- - calls vim.deprecate()
+---
+--- @param old_name string Name of the deprecated module, which will be shimmed.
+--- @param new_name string Name of the new module, which will be loaded by require().
+function vim._defer_deprecated_module(old_name, new_name)
+ return setmetatable({}, {
+ ---@param _ table<string, any>
+ ---@param k string
+ __index = function(_, k)
+ vim.deprecate(old_name, new_name, '2.0.0', nil, false)
+ --- @diagnostic disable-next-line:no-unknown
+ local target = require(new_name)
+ return target[k]
+ end,
+ __call = function(self)
+ vim.deprecate(old_name, new_name, '2.0.0', nil, false)
+ --- @diagnostic disable-next-line:no-unknown
+ local target = require(new_name)
+ return target(self)
+ end,
+ })
+end
+
--- @nodoc
--- @class vim.context.mods
--- @field bo? table<string, any>
@@ -1193,11 +1220,14 @@ local state_restore_order = { 'bo', 'wo', 'go', 'env' }
--- @param context vim.context.mods
--- @return vim.context.state
local get_context_state = function(context)
+ --- @type vim.context.state
local res = { bo = {}, env = {}, go = {}, wo = {} }
-- Use specific order from possibly most to least intrusive
for _, scope in ipairs(scope_order) do
- for name, _ in pairs(context[scope] or {}) do
+ for name, _ in
+ pairs(context[scope] or {} --[[@as table<string,any>]])
+ do
local sc = scope == 'o' and scope_map[vim.api.nvim_get_option_info2(name, {}).scope] or scope
-- Do not override already set state and fall back to `vim.NIL` for
@@ -1291,7 +1321,10 @@ function vim._with(context, f)
-- Apply some parts of the context in specific order
-- NOTE: triggers `OptionSet` event
for _, scope in ipairs(scope_order) do
- for name, context_value in pairs(context[scope] or {}) do
+ for name, context_value in
+ pairs(context[scope] or {} --[[@as table<string,any>]])
+ do
+ --- @diagnostic disable-next-line:no-unknown
vim[scope][name] = context_value
end
end
@@ -1302,7 +1335,10 @@ function vim._with(context, f)
-- Restore relevant cached values in specific order, global scope last
-- NOTE: triggers `OptionSet` event
for _, scope in ipairs(state_restore_order) do
- for name, cached_value in pairs(state[scope]) do
+ for name, cached_value in
+ pairs(state[scope] --[[@as table<string,any>]])
+ do
+ --- @diagnostic disable-next-line:no-unknown
vim[scope][name] = cached_value
end
end
diff --git a/runtime/lua/vim/termcap.lua b/runtime/lua/vim/termcap.lua
index 1da2e71839..4aa41bba9b 100644
--- a/runtime/lua/vim/termcap.lua
+++ b/runtime/lua/vim/termcap.lua
@@ -17,10 +17,8 @@ local M = {}
--- otherwise. {seq} is the control sequence for the capability if found, or nil for
--- boolean capabilities.
function M.query(caps, cb)
- vim.validate({
- caps = { caps, { 'string', 'table' } },
- cb = { cb, 'f' },
- })
+ vim.validate('caps', caps, { 'string', 'table' })
+ vim.validate('cb', cb, 'function')
if type(caps) ~= 'table' then
caps = { caps }
@@ -40,7 +38,7 @@ function M.query(caps, cb)
local k, rest = resp:match('^\027P1%+r(%x+)(.*)$')
if k and rest then
local cap = vim.text.hexdecode(k)
- if not pending[cap] then
+ if not cap or not pending[cap] then
-- Received a response for a capability we didn't request. This can happen if there are
-- multiple concurrent XTGETTCAP requests
return
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index ed7d31e1f7..dca89f413c 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -133,10 +133,8 @@ end
---
---@return vim.treesitter.LanguageTree object to use for parsing
function M.get_string_parser(str, lang, opts)
- vim.validate({
- str = { str, 'string' },
- lang = { lang, 'string' },
- })
+ vim.validate('str', str, 'string')
+ vim.validate('lang', lang, 'string')
return LanguageTree.new(str, lang, opts)
end
@@ -152,8 +150,7 @@ function M.is_ancestor(dest, source)
return false
end
- -- child_containing_descendant returns nil if dest is a direct parent
- return source:parent() == dest or dest:child_containing_descendant(source) ~= nil
+ return dest:child_with_descendant(source) ~= nil
end
--- Returns the node's range or an unpacked range table
@@ -168,7 +165,7 @@ function M.get_node_range(node_or_range)
if type(node_or_range) == 'table' then
return unpack(node_or_range)
else
- return node_or_range:range()
+ return node_or_range:range(false)
end
end
@@ -244,11 +241,9 @@ end
---
---@return boolean True if the {node} contains the {range}
function M.node_contains(node, range)
- vim.validate({
- -- allow a table so nodes can be mocked
- node = { node, { 'userdata', 'table' } },
- range = { range, M._range.validate, 'integer list with 4 or 6 elements' },
- })
+ -- allow a table so nodes can be mocked
+ vim.validate('node', node, { 'userdata', 'table' })
+ vim.validate('range', range, M._range.validate, 'integer list with 4 or 6 elements')
return M._range.contains({ node:range() }, range)
end
diff --git a/runtime/lua/vim/treesitter/_meta/tsnode.lua b/runtime/lua/vim/treesitter/_meta/tsnode.lua
index acc9f8d24e..d982b6a505 100644
--- a/runtime/lua/vim/treesitter/_meta/tsnode.lua
+++ b/runtime/lua/vim/treesitter/_meta/tsnode.lua
@@ -15,7 +15,7 @@ error('Cannot require a meta file')
local TSNode = {} -- luacheck: no unused
--- Get the node's immediate parent.
---- Prefer |TSNode:child_containing_descendant()|
+--- Prefer |TSNode:child_with_descendant()|
--- for iterating over the node's ancestors.
--- @return TSNode?
function TSNode:parent() end
@@ -71,8 +71,24 @@ function TSNode:named_child(index) end
--- Get the node's child that contains {descendant}.
--- @param descendant TSNode
--- @return TSNode?
+--- @deprecated
function TSNode:child_containing_descendant(descendant) end
+--- Get the node's child that contains {descendant} (includes {descendant}).
+---
+--- For example, with the following node hierarchy:
+---
+--- ```
+--- a -> b -> c
+---
+--- a:child_with_descendant(c) == b
+--- a:child_with_descendant(b) == b
+--- a:child_with_descendant(a) == nil
+--- ```
+--- @param descendant TSNode
+--- @return TSNode?
+function TSNode:child_with_descendant(descendant) end
+
--- Get the node's start position. Return three values: the row, column and
--- total byte count (all zero-based).
--- @return integer, integer, integer
diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua
index c5e4b86e1e..a825505378 100644
--- a/runtime/lua/vim/treesitter/_query_linter.lua
+++ b/runtime/lua/vim/treesitter/_query_linter.lua
@@ -240,8 +240,12 @@ function M.omnifunc(findstart, base)
table.insert(items, text)
end
end
- for _, s in pairs(parser_info.symbols) do
- local text = s[2] and s[1] or string.format('%q', s[1]):gsub('\n', 'n') ---@type string
+ for text, named in
+ pairs(parser_info.symbols --[[@as table<string, boolean>]])
+ do
+ if not named then
+ text = string.format('%q', text:sub(2, -2)):gsub('\n', 'n') ---@type string
+ end
if text:find(base, 1, true) then
table.insert(items, text)
end
diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua
index 90c3720b80..26817cdba5 100644
--- a/runtime/lua/vim/treesitter/dev.lua
+++ b/runtime/lua/vim/treesitter/dev.lua
@@ -330,9 +330,7 @@ end
---
--- @param opts vim.treesitter.dev.inspect_tree.Opts?
function M.inspect_tree(opts)
- vim.validate({
- opts = { opts, 't', true },
- })
+ vim.validate('opts', opts, 'table', true)
opts = opts or {}
@@ -529,15 +527,22 @@ function M.inspect_tree(opts)
end,
})
- api.nvim_create_autocmd('BufHidden', {
+ api.nvim_create_autocmd({ 'BufHidden', 'BufUnload', 'QuitPre' }, {
group = group,
buffer = buf,
- once = true,
callback = function()
+ -- don't close inpector window if source buffer
+ -- has more than one open window
+ if #vim.fn.win_findbuf(buf) > 1 then
+ return
+ end
+
-- close all tree windows
for _, window in pairs(vim.fn.win_findbuf(b)) do
close_win(window)
end
+
+ return true
end,
})
end
@@ -667,10 +672,10 @@ function M.edit_query(lang)
api.nvim_buf_clear_namespace(query_buf, edit_ns, 0, -1)
end,
})
- api.nvim_create_autocmd('BufHidden', {
+ api.nvim_create_autocmd({ 'BufHidden', 'BufUnload' }, {
group = group,
buffer = buf,
- desc = 'Close the editor window when the source buffer is hidden',
+ desc = 'Close the editor window when the source buffer is hidden or unloaded',
once = true,
callback = function()
close_win(query_win)
diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua
index 637f9ea543..53b64d1dec 100644
--- a/runtime/lua/vim/treesitter/health.lua
+++ b/runtime/lua/vim/treesitter/health.lua
@@ -4,10 +4,21 @@ local health = vim.health
--- Performs a healthcheck for treesitter integration
function M.check()
- local parsers = vim.api.nvim_get_runtime_file('parser/*', true)
+ health.start('Treesitter features')
+
+ health.info(
+ string.format(
+ 'Treesitter ABI support: min %d, max %d',
+ vim.treesitter.minimum_language_version,
+ ts.language_version
+ )
+ )
- health.info(string.format('Nvim runtime ABI version: %d', ts.language_version))
+ local can_wasm = vim._ts_add_language_from_wasm ~= nil
+ health.info(string.format('WASM parser support: %s', tostring(can_wasm)))
+ health.start('Treesitter parsers')
+ local parsers = vim.api.nvim_get_runtime_file('parser/*', true)
for _, parser in pairs(parsers) do
local parsername = vim.fn.fnamemodify(parser, ':t:r')
local is_loadable, err_or_nil = pcall(ts.language.add, parsername)
@@ -28,9 +39,6 @@ function M.check()
)
end
end
-
- local can_wasm = vim._ts_add_language_from_wasm ~= nil
- health.info(string.format('Can load WASM parsers: %s', tostring(can_wasm)))
end
return M
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index a94c408f4e..8ce8652f7d 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -93,9 +93,6 @@ function TSHighlighter.new(tree, opts)
opts = opts or {} ---@type { queries: table<string,string> }
self.tree = tree
tree:register_cbs({
- on_bytes = function(...)
- self:on_bytes(...)
- end,
on_detach = function()
self:on_detach()
end,
@@ -215,13 +212,6 @@ function TSHighlighter:for_each_highlight_state(fn)
end
---@package
----@param start_row integer
----@param new_end integer
-function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end)
- api.nvim__redraw({ buf = self.bufnr, range = { start_row, start_row + new_end + 1 } })
-end
-
----@package
function TSHighlighter:on_detach()
self:destroy()
end
@@ -230,7 +220,7 @@ end
---@param changes Range6[]
function TSHighlighter:on_changedtree(changes)
for _, ch in ipairs(changes) do
- api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] + 1 } })
+ api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] + 1 }, flush = false })
end
end
@@ -328,7 +318,7 @@ local function on_line_impl(self, buf, line, is_spell_nav)
-- The "priority" attribute can be set at the pattern level or on a particular capture
local priority = (
tonumber(metadata.priority or metadata[capture] and metadata[capture].priority)
- or vim.highlight.priorities.treesitter
+ or vim.hl.priorities.treesitter
) + spell_pri_offset
-- The "conceal" attribute can be set at the pattern level or on a particular capture
diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua
index 9f7807e036..446051dfd7 100644
--- a/runtime/lua/vim/treesitter/language.lua
+++ b/runtime/lua/vim/treesitter/language.lua
@@ -108,11 +108,9 @@ function M.add(lang, opts)
local path = opts.path
local symbol_name = opts.symbol_name
- vim.validate({
- lang = { lang, 'string' },
- path = { path, 'string', true },
- symbol_name = { symbol_name, 'string', true },
- })
+ vim.validate('lang', lang, 'string')
+ vim.validate('path', path, 'string', true)
+ vim.validate('symbol_name', symbol_name, 'string', true)
-- parser names are assumed to be lowercase (consistent behavior on case-insensitive file systems)
lang = lang:lower()
@@ -156,10 +154,8 @@ end
--- @param lang string Name of parser
--- @param filetype string|string[] Filetype(s) to associate with lang
function M.register(lang, filetype)
- vim.validate({
- lang = { lang, 'string' },
- filetype = { filetype, { 'string', 'table' } },
- })
+ vim.validate('lang', lang, 'string')
+ vim.validate('filetype', filetype, { 'string', 'table' })
for _, f in ipairs(ensure_list(filetype)) do
if f ~= '' then
@@ -170,7 +166,12 @@ end
--- Inspects the provided language.
---
---- Inspecting provides some useful information on the language like node names, ...
+--- Inspecting provides some useful information on the language like node and field names, ABI
+--- version, and whether the language came from a WASM module.
+---
+--- Node names are returned in a table mapping each node name to a `boolean` indicating whether or
+--- not the node is named (i.e., not anonymous). Anonymous nodes are surrounded with double quotes
+--- (`"`).
---
---@param lang string Language
---@return table
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index fd68c2b910..4b42164dc8 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -1037,7 +1037,7 @@ end
--- Registers callbacks for the [LanguageTree].
---@param cbs table<TSCallbackNameOn,function> An [nvim_buf_attach()]-like table argument with the following handlers:
---- - `on_bytes` : see [nvim_buf_attach()], but this will be called _after_ the parsers callback.
+--- - `on_bytes` : see [nvim_buf_attach()].
--- - `on_changedtree` : a callback that will be called every time the tree has syntactical changes.
--- It will be passed two arguments: a table of the ranges (as node ranges) that
--- changed and the changed tree.
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 4614967799..1677e8d364 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -626,7 +626,7 @@ local directive_handlers = {
--- Adds a new predicate to be used in queries
---
---@param name string Name of the predicate, without leading #
----@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata)
+---@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata): boolean?
--- - see |vim.treesitter.query.add_directive()| for argument meanings
---@param opts? vim.treesitter.query.add_predicate.Opts
function M.add_predicate(name, handler, opts)
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
index 532decf5e9..cd159f0172 100644
--- a/runtime/lua/vim/ui.lua
+++ b/runtime/lua/vim/ui.lua
@@ -20,7 +20,8 @@ local M = {}
--- end)
--- ```
---
----@param items any[] Arbitrary items
+---@generic T
+---@param items T[] Arbitrary items
---@param opts table Additional options
--- - prompt (string|nil)
--- Text of the prompt. Defaults to `Select one of:`
@@ -32,19 +33,19 @@ local M = {}
--- Plugins reimplementing `vim.ui.select` may wish to
--- use this to infer the structure or semantics of
--- `items`, or the context in which select() was called.
----@param on_choice fun(item: any|nil, idx: integer|nil)
+---@param on_choice fun(item: T|nil, idx: integer|nil)
--- Called once the user made a choice.
--- `idx` is the 1-based index of `item` within `items`.
--- `nil` if the user aborted the dialog.
function M.select(items, opts, on_choice)
- vim.validate({
- items = { items, 'table', false },
- on_choice = { on_choice, 'function', false },
- })
+ vim.validate('items', items, 'table')
+ vim.validate('on_choice', on_choice, 'function')
opts = opts or {}
local choices = { opts.prompt or 'Select one of:' }
local format_item = opts.format_item or tostring
- for i, item in ipairs(items) do
+ for i, item in
+ ipairs(items --[[@as any[] ]])
+ do
table.insert(choices, string.format('%d: %s', i, format_item(item)))
end
local choice = vim.fn.inputlist(choices)
@@ -86,10 +87,8 @@ end
--- an empty string if nothing was entered), or
--- `nil` if the user aborted the dialog.
function M.input(opts, on_confirm)
- vim.validate({
- opts = { opts, 'table', true },
- on_confirm = { on_confirm, 'function', false },
- })
+ vim.validate('opts', opts, 'table', true)
+ vim.validate('on_confirm', on_confirm, 'function')
opts = (opts and not vim.tbl_isempty(opts)) and opts or vim.empty_dict()
@@ -135,9 +134,7 @@ end
---
---@see |vim.system()|
function M.open(path, opt)
- vim.validate({
- path = { path, 'string' },
- })
+ vim.validate('path', path, 'string')
local is_uri = path:match('%w+:')
if not is_uri then
path = vim.fs.normalize(path)
@@ -165,8 +162,10 @@ function M.open(path, opt)
cmd = { 'wslview', path }
elseif vim.fn.executable('explorer.exe') == 1 then
cmd = { 'explorer.exe', path }
+ elseif vim.fn.executable('lemonade') == 1 then
+ cmd = { 'lemonade', 'open', path }
else
- return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
+ return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open, lemonade)'
end
return vim.system(cmd, job_opt), nil
@@ -207,7 +206,9 @@ function M._get_urls()
if vim.treesitter.node_contains(node, range) then
local url = metadata[id] and metadata[id].url
if url and match[url] then
- for _, n in ipairs(match[url]) do
+ for _, n in
+ ipairs(match[url] --[[@as TSNode[] ]])
+ do
urls[#urls + 1] =
vim.treesitter.get_node_text(n, bufnr, { metadata = metadata[url] })
end
diff --git a/runtime/macmap.vim b/runtime/macmap.vim
deleted file mode 100644
index dc76f15f96..0000000000
--- a/runtime/macmap.vim
+++ /dev/null
@@ -1,75 +0,0 @@
-" System gvimrc file for Mac OS X
-" Author: Benji Fisher <benji@member.AMS.org>
-" Last Change: Thu Mar 09 09:00 AM 2006 EST
-"
-" Define Mac-standard keyboard shortcuts.
-
-" We don't change 'cpoptions' here, because it would not be set properly when
-" a .vimrc file is found later. Thus don't use line continuation and use
-" <special> in mappings.
-
-nnoremap <special> <D-n> :confirm enew<CR>
-vmap <special> <D-n> <Esc><D-n>gv
-imap <special> <D-n> <C-O><D-n>
-cmap <special> <D-n> <C-C><D-n>
-omap <special> <D-n> <Esc><D-n>
-
-nnoremap <special> <D-o> :browse confirm e<CR>
-vmap <special> <D-o> <Esc><D-o>gv
-imap <special> <D-o> <C-O><D-o>
-cmap <special> <D-o> <C-C><D-o>
-omap <special> <D-o> <Esc><D-o>
-
-nnoremap <silent> <special> <D-w> :if winheight(2) < 0 <Bar> confirm enew <Bar> else <Bar> confirm close <Bar> endif<CR>
-vmap <special> <D-w> <Esc><D-w>gv
-imap <special> <D-w> <C-O><D-w>
-cmap <special> <D-w> <C-C><D-w>
-omap <special> <D-w> <Esc><D-w>
-
-nnoremap <silent> <special> <D-s> :if expand("%") == ""<Bar>browse confirm w<Bar> else<Bar>confirm w<Bar>endif<CR>
-vmap <special> <D-s> <Esc><D-s>gv
-imap <special> <D-s> <C-O><D-s>
-cmap <special> <D-s> <C-C><D-s>
-omap <special> <D-s> <Esc><D-s>
-
-nnoremap <special> <D-S-s> :browse confirm saveas<CR>
-vmap <special> <D-S-s> <Esc><D-s>gv
-imap <special> <D-S-s> <C-O><D-s>
-cmap <special> <D-S-s> <C-C><D-s>
-omap <special> <D-S-s> <Esc><D-s>
-
-" From the Edit menu of SimpleText:
-nnoremap <special> <D-z> u
-vmap <special> <D-z> <Esc><D-z>gv
-imap <special> <D-z> <C-O><D-z>
-cmap <special> <D-z> <C-C><D-z>
-omap <special> <D-z> <Esc><D-z>
-
-vnoremap <special> <D-x> "+x
-
-vnoremap <special> <D-c> "+y
-
-cnoremap <special> <D-c> <C-Y>
-
-nnoremap <special> <D-v> "+gP
-cnoremap <special> <D-v> <C-R>+
-execute 'vnoremap <script> <special> <D-v>' paste#paste_cmd['v']
-execute 'inoremap <script> <special> <D-v>' paste#paste_cmd['i']
-
-nnoremap <silent> <special> <D-a> :if &slm != ""<Bar>exe ":norm gggH<C-O>G"<Bar> else<Bar>exe ":norm ggVG"<Bar>endif<CR>
-vmap <special> <D-a> <Esc><D-a>
-imap <special> <D-a> <Esc><D-a>
-cmap <special> <D-a> <C-C><D-a>
-omap <special> <D-a> <Esc><D-a>
-
-nnoremap <special> <D-f> /
-vmap <special> <D-f> <Esc><D-f>
-imap <special> <D-f> <Esc><D-f>
-cmap <special> <D-f> <C-C><D-f>
-omap <special> <D-f> <Esc><D-f>
-
-nnoremap <special> <D-g> n
-vmap <special> <D-g> <Esc><D-g>
-imap <special> <D-g> <C-O><D-g>
-cmap <special> <D-g> <C-C><D-g>
-omap <special> <D-g> <Esc><D-g>
diff --git a/runtime/macros/editexisting.vim b/runtime/macros/editexisting.vim
deleted file mode 100644
index b21777d861..0000000000
--- a/runtime/macros/editexisting.vim
+++ /dev/null
@@ -1,119 +0,0 @@
-" Vim Plugin: Edit the file with an existing Vim if possible
-" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2023 Aug 13
-
-" This is a plugin, drop it in your (Unix) ~/.vim/plugin or (Win32)
-" $VIM/vimfiles/plugin directory. Or make a symbolic link, so that you
-" automatically use the latest version.
-
-" This plugin serves two purposes:
-" 1. On startup, if we were invoked with one file name argument and the file
-" is not modified then try to find another Vim instance that is editing
-" this file. If there is one then bring it to the foreground and exit.
-" 2. When a file is edited and a swap file exists for it, try finding that
-" other Vim and bring it to the foreground. Requires Vim 7, because it
-" uses the SwapExists autocommand event.
-if v:version < 700
- finish
-endif
-
-" Function that finds the Vim instance that is editing "filename" and brings
-" it to the foreground.
-func s:EditElsewhere(filename)
- let fname_esc = substitute(a:filename, "'", "''", "g")
-
- let servers = serverlist()
- while servers != ''
- " Get next server name in "servername"; remove it from "servers".
- let i = match(servers, "\n")
- if i == -1
- let servername = servers
- let servers = ''
- else
- let servername = strpart(servers, 0, i)
- let servers = strpart(servers, i + 1)
- endif
-
- " Skip ourselves.
- if servername ==? v:servername
- continue
- endif
-
- " Check if this server is editing our file.
- if remote_expr(servername, "bufloaded('" . fname_esc . "')")
- " Yes, bring it to the foreground.
- if has("win32")
- call remote_foreground(servername)
- endif
- call remote_expr(servername, "foreground()")
-
- if remote_expr(servername, "exists('*EditExisting')")
- " Make sure the file is visible in a window (not hidden).
- " If v:swapcommand exists and is set, send it to the server.
- if exists("v:swapcommand")
- let c = substitute(v:swapcommand, "'", "''", "g")
- call remote_expr(servername, "EditExisting('" . fname_esc . "', '" . c . "')")
- else
- call remote_expr(servername, "EditExisting('" . fname_esc . "', '')")
- endif
- endif
-
- if !(has('vim_starting') && has('gui_running') && has('gui_win32'))
- " Tell the user what is happening. Not when the GUI is starting
- " though, it would result in a message box.
- echomsg "File is being edited by " . servername
- sleep 2
- endif
- return 'q'
- endif
- endwhile
- return ''
-endfunc
-
-" When the plugin is loaded and there is one file name argument: Find another
-" Vim server that is editing this file right now.
-if argc() == 1 && !&modified
- if s:EditElsewhere(expand("%:p")) == 'q'
- quit
- endif
-endif
-
-" Setup for handling the situation that an existing swap file is found.
-try
- au! SwapExists * let v:swapchoice = s:EditElsewhere(expand("<afile>:p"))
-catch
- " Without SwapExists we don't do anything for ":edit" commands
-endtry
-
-" Function used on the server to make the file visible and possibly execute a
-" command.
-func! EditExisting(fname, command)
- " Get the window number of the file in the current tab page.
- let winnr = bufwinnr(a:fname)
- if winnr <= 0
- " Not found, look in other tab pages.
- let bufnr = bufnr(a:fname)
- for i in range(tabpagenr('$'))
- if index(tabpagebuflist(i + 1), bufnr) >= 0
- " Make this tab page the current one and find the window number.
- exe 'tabnext ' . (i + 1)
- let winnr = bufwinnr(a:fname)
- break
- endif
- endfor
- endif
-
- if winnr > 0
- exe winnr . "wincmd w"
- elseif exists('*fnameescape')
- exe "split " . fnameescape(a:fname)
- else
- exe "split " . escape(a:fname, " \t\n*?[{`$\\%#'\"|!<")
- endif
-
- if a:command != ''
- exe "normal! " . a:command
- endif
-
- redraw
-endfunc
diff --git a/runtime/macros/justify.vim b/runtime/macros/justify.vim
deleted file mode 100644
index 011a911401..0000000000
--- a/runtime/macros/justify.vim
+++ /dev/null
@@ -1,3 +0,0 @@
-" Load the justify package.
-" For those users who were loading the justify plugin from here.
-packadd justify
diff --git a/runtime/macros/matchit.vim b/runtime/macros/matchit.vim
deleted file mode 100644
index d4f8cb22e8..0000000000
--- a/runtime/macros/matchit.vim
+++ /dev/null
@@ -1,2 +0,0 @@
-" This file is a compatibility stub for any plugins which source it.
-" Nvim already loads the matchit plugin by default; see ':help pi_matchit.txt'.
diff --git a/runtime/macros/shellmenu.vim b/runtime/macros/shellmenu.vim
deleted file mode 100644
index 4eb72a556a..0000000000
--- a/runtime/macros/shellmenu.vim
+++ /dev/null
@@ -1,3 +0,0 @@
-" Load the shellmenu package.
-" For those users who were loading the shellmenu plugin from here.
-packadd shellmenu
diff --git a/runtime/macros/swapmous.vim b/runtime/macros/swapmous.vim
deleted file mode 100644
index 5884d83473..0000000000
--- a/runtime/macros/swapmous.vim
+++ /dev/null
@@ -1,3 +0,0 @@
-" Load the swapmouse package.
-" For those users who were loading the swapmous plugin from here.
-packadd swapmouse
diff --git a/runtime/menu.vim b/runtime/menu.vim
index 4576ca0ab7..662eea9403 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -1130,7 +1130,7 @@ else
endif
tmenu ToolBar.LoadSesn Choose a session to load
tmenu ToolBar.SaveSesn Save current session
- tmenu ToolBar.RunScript Choose a Vim Script to run
+ tmenu ToolBar.RunScript Choose a Vim script to run
tmenu ToolBar.Make Make current project (:make)
tmenu ToolBar.RunCtags Build tags in current directory tree (!ctags -R .)
tmenu ToolBar.TagJump Jump to tag under cursor
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index da70ff1afe..48a4bd2816 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -626,6 +626,8 @@ call <SID>AddOption("terse", gettext("add 's' flag in 'shortmess' (don't show se
call <SID>BinOptionG("terse", &terse)
call <SID>AddOption("shortmess", gettext("list of flags to make messages shorter"))
call <SID>OptionG("shm", &shm)
+call <SID>AddOption("msghistory", gettext("how many messages are remembered"))
+call append("$", " \tset mhi=" . &mhi)
call <SID>AddOption("showcmd", gettext("show (partial) command keys in location given by 'showcmdloc'"))
let &sc = s:old_sc
call <SID>BinOptionG("sc", &sc)
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 9412a821e8..fd8c4b8817 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -1688,10 +1688,14 @@ func s:CreateBreakpoint(id, subid, enabled)
let hiName = "debugBreakpoint"
endif
let label = ''
- if exists('g:termdebug_config')
- let label = get(g:termdebug_config, 'sign', '')
- endif
- if label == ''
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'sign')
+ let label = g:termdebug_config['sign']
+ elseif exists('g:termdebug_config') && has_key(g:termdebug_config, 'sign_decimal')
+ let label = printf('%02d', a:id)
+ if a:id > 99
+ let label = '9+'
+ endif
+ else
let label = printf('%02X', a:id)
if a:id > 255
let label = 'F+'
diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim
index 2899612dce..661a34b578 100644
--- a/runtime/plugin/matchparen.vim
+++ b/runtime/plugin/matchparen.vim
@@ -17,6 +17,9 @@ endif
if !exists("g:matchparen_insert_timeout")
let g:matchparen_insert_timeout = 60
endif
+if !exists("g:matchparen_disable_cursor_hl")
+ let g:matchparen_disable_cursor_hl = 0
+endif
let s:has_matchaddpos = exists('*matchaddpos')
@@ -189,10 +192,18 @@ func s:Highlight_Matching_Pair()
" If a match is found setup match highlighting.
if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom
if s:has_matchaddpos
- call add(w:matchparen_ids, matchaddpos('MatchParen', [[c_lnum, c_col - before], [m_lnum, m_col]], 10))
+ if !g:matchparen_disable_cursor_hl
+ call add(w:matchparen_ids, matchaddpos('MatchParen', [[c_lnum, c_col - before], [m_lnum, m_col]], 10))
+ else
+ call add(w:matchparen_ids, matchaddpos('MatchParen', [[m_lnum, m_col]], 10))
+ endif
else
- exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
- \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+ if !g:matchparen_disable_cursor_hl
+ exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
+ \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+ else
+ exe '3match MatchParen /\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+ endif
call add(w:matchparen_ids, 3)
endif
let w:paren_hl_on = 1
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index c70e6518ff..775b650e71 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -1,9 +1,12 @@
" netrwPlugin.vim: Handles file transfer and remote directory listing across a network
" PLUGIN SECTION
" Maintainer: This runtime file is looking for a new maintainer.
-" Date: Feb 09, 2021
+" Date: Sep 09, 2021
" Last Change:
" 2024 May 08 by Vim Project: cleanup legacy Win9X checks
+" 2024 Oct 27 by Vim Project: cleanup gx mapping
+" 2024 Oct 28 by Vim Project: further improvements
+" 2024 Oct 31 by Vim Project: use autoloaded functions
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 1999-2021 Charles E. Campbell {{{1
@@ -31,6 +34,10 @@ set cpo&vim
" ---------------------------------------------------------------------
" Public Interface: {{{1
+" Commands Launch/URL {{{2
+command -complete=shellcmd -nargs=1 Launch call netrw#Launch(trim(<q-args>))
+command -complete=file -nargs=1 Open call netrw#Open(trim(<q-args>))
+" " }}}
" Local Browsing Autocmds: {{{2
augroup FileExplorer
au!
diff --git a/runtime/tools/emoji_list.lua b/runtime/scripts/emoji_list.lua
index 63bbbe4371..63bbbe4371 100644
--- a/runtime/tools/emoji_list.lua
+++ b/runtime/scripts/emoji_list.lua
diff --git a/runtime/macros/less.bat b/runtime/scripts/less.bat
index 7395a70003..f80bf9209e 100644
--- a/runtime/macros/less.bat
+++ b/runtime/scripts/less.bat
@@ -4,7 +4,7 @@ rem Read stdin if no arguments were given.
rem Written by Ken Takata.
if "%1"=="" (
- nvim --cmd "let no_plugin_maps = 1" -c "runtime! macros/less.vim" -
+ nvim --cmd "let no_plugin_maps = 1" -c "runtime! scripts/less.vim" -
) else (
- nvim --cmd "let no_plugin_maps = 1" -c "runtime! macros/less.vim" %*
+ nvim --cmd "let no_plugin_maps = 1" -c "runtime! scripts/less.vim" %*
)
diff --git a/runtime/macros/less.sh b/runtime/scripts/less.sh
index 125162f10a..4ff32b0529 100755
--- a/runtime/macros/less.sh
+++ b/runtime/scripts/less.sh
@@ -8,9 +8,9 @@ if test -t 1; then
echo "Missing filename" 1>&2
exit
fi
- nvim --cmd 'let no_plugin_maps = 1' -c 'runtime! macros/less.vim' -
+ nvim --cmd 'let no_plugin_maps = 1' -c 'runtime! scripts/less.vim' -
else
- nvim --cmd 'let no_plugin_maps = 1' -c 'runtime! macros/less.vim' "$@"
+ nvim --cmd 'let no_plugin_maps = 1' -c 'runtime! scripts/less.vim' "$@"
fi
else
# Output is not a terminal, cat arguments or stdin
diff --git a/runtime/macros/less.vim b/runtime/scripts/less.vim
index 8df29d96e6..8df29d96e6 100644
--- a/runtime/macros/less.vim
+++ b/runtime/scripts/less.vim
diff --git a/runtime/mswin.vim b/runtime/scripts/mswin.vim
index 689bc792cf..689bc792cf 100644
--- a/runtime/mswin.vim
+++ b/runtime/scripts/mswin.vim
diff --git a/runtime/syntax/8th.vim b/runtime/syntax/8th.vim
index a88a5a294a..e53c185df1 100644
--- a/runtime/syntax/8th.vim
+++ b/runtime/syntax/8th.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: 8th
-" Version: 23.09.01
-" Last Change: 2023 Dec 19
+" Version: 24.08
+" Last Change: 2024 Nov 07
" Maintainer: Ron Aaron <ron@aaron-tech.com>
" URL: https://8th-dev.com/
" Filetypes: *.8th
@@ -36,16 +36,16 @@ com! -nargs=+ Builtin syn keyword eighthBuiltin <args>
Builtin gen-secret 2fa:gen-secret gen-url 2fa:gen-url validate-code 2fa:validate-code cb AWS:cb cli AWS:cli
-Builtin cmd AWS:cmd cp AWS:cp rc AWS:rc call DBUS:call init DBUS:init + DOM:+ - DOM:- attr! DOM:attr!
-Builtin attr@ DOM:attr@ attrs DOM:attrs children DOM:children css-parse DOM:css-parse each DOM:each
-Builtin find DOM:find new DOM:new type DOM:type ! G:! !if G:!if #! G:#! ## G:## #if G:#if ' G:' ( G:(
-Builtin (* G:(* (:) G:(:) (code) G:(code) (defer) G:(defer) (dump) G:(dump) (getc) G:(getc) (gets) G:(gets)
+Builtin cmd AWS:cmd cp AWS:cp rc AWS:rc LIBS DBUS:LIBS call DBUS:call init DBUS:init + DOM:+ - DOM:-
+Builtin attr! DOM:attr! attr@ DOM:attr@ attrs DOM:attrs children DOM:children css-parse DOM:css-parse
+Builtin each DOM:each find DOM:find new DOM:new type DOM:type ! G:! !if G:!if #! G:#! ## G:## #if G:#if
+Builtin ' G:' ( G:( (:) G:(:) (code) G:(code) (defer) G:(defer) (dump) G:(dump) (getc) G:(getc) (gets) G:(gets)
Builtin (interp) G:(interp) (log) G:(log) (needs) G:(needs) (parseln) G:(parseln) (putc) G:(putc) (puts) G:(puts)
-Builtin (stat) G:(stat) (with) G:(with) ) G:) +hook G:+hook +ref G:+ref ,# G:,# -- G:-- -----BEGIN G:-----BEGIN
+Builtin (stat) G:(stat) (with) G:(with) ) G:) +hook G:+hook +ref G:+ref ,# G:,# -----BEGIN G:-----BEGIN
Builtin -Inf G:-Inf -Inf? G:-Inf? -hook G:-hook -ref G:-ref -rot G:-rot . G:. .# G:.# .hook G:.hook
Builtin .needs G:.needs .r G:.r .s G:.s .s-truncate G:.s-truncate .stats G:.stats .ver G:.ver .with G:.with
Builtin 0; G:0; 2dip G:2dip 2drop G:2drop 2dup G:2dup 2nip G:2nip 2over G:2over 2swap G:2swap 2tuck G:2tuck
-Builtin 3drop G:3drop 3drop G:3drop 3dup G:3dup 3rev G:3rev 4drop G:4drop 8thdt? G:8thdt? 8thsku G:8thsku
+Builtin 3drop G:3drop 3drop G:3drop 3dup G:3dup 3rev G:3rev 4drop G:4drop 8thdt? G:8thdt? 8thsku? G:8thsku?
Builtin 8thver? G:8thver? 8thvernum? G:8thvernum? : G:: ; G:; ;; G:;; ;;; G:;;; ;with G:;with >clip G:>clip
Builtin >json G:>json >kind G:>kind >n G:>n >r G:>r >s G:>s ?: G:?: ?@ G:?@ @ G:@ BITMAP: G:BITMAP:
Builtin ENUM: G:ENUM: FLAG: G:FLAG: I G:I Inf G:Inf Inf? G:Inf? J G:J K G:K NaN G:NaN NaN? G:NaN? SED-CHECK G:SED-CHECK
@@ -59,16 +59,17 @@ Builtin counting-allocations G:counting-allocations cr G:cr critical: G:critica
Builtin curlang G:curlang curry G:curry curry: G:curry: decimal G:decimal default: G:default: defer: G:defer:
Builtin deferred: G:deferred: deg>rad G:deg>rad depth G:depth die G:die dip G:dip drop G:drop dstack G:dstack
Builtin dump G:dump dup G:dup dup>r G:dup>r dup? G:dup? e# G:e# enum: G:enum: error? G:error? eval G:eval
-Builtin eval! G:eval! eval0 G:eval0 expect G:expect extra! G:extra! extra@ G:extra@ false G:false fnv G:fnv
-Builtin fourth G:fourth free G:free func: G:func: getc G:getc getcwd G:getcwd getenv G:getenv gets G:gets
-Builtin handler G:handler header G:header help G:help hex G:hex i: G:i: i; G:i; isa? G:isa? items-used G:items-used
-Builtin jcall G:jcall jclass G:jclass jmethod G:jmethod json! G:json! json-8th> G:json-8th> json-nesting G:json-nesting
-Builtin json-pretty G:json-pretty json-throw G:json-throw json> G:json> json@ G:json@ k32 G:k32 keep G:keep
-Builtin l: G:l: last G:last lib G:lib libbin G:libbin libc G:libc literal G:literal locals: G:locals:
-Builtin lock G:lock lock-to G:lock-to locked? G:locked? log G:log log-syslog G:log-syslog log-task G:log-task
-Builtin log-time G:log-time log-time-local G:log-time-local long-days G:long-days long-months G:long-months
-Builtin longjmp G:longjmp lookup G:lookup loop G:loop loop- G:loop- map? G:map? mark G:mark mark? G:mark?
-Builtin mobile? G:mobile? n# G:n# name>os G:name>os name>sem G:name>sem ndrop G:ndrop needs G:needs
+Builtin eval! G:eval! eval0 G:eval0 exit G:exit expect G:expect extra! G:extra! extra@ G:extra@ false G:false
+Builtin fnv G:fnv fourth G:fourth free G:free func: G:func: getc G:getc getcwd G:getcwd getenv G:getenv
+Builtin gets G:gets goto G:goto handler G:handler header G:header help G:help help_db G:help_db here G:here
+Builtin hex G:hex i: G:i: i; G:i; isa? G:isa? items-used G:items-used jcall G:jcall jclass G:jclass
+Builtin jmethod G:jmethod json! G:json! json-8th> G:json-8th> json-nesting G:json-nesting json-pretty G:json-pretty
+Builtin json-throw G:json-throw json> G:json> json@ G:json@ k32 G:k32 keep G:keep l: G:l: last G:last
+Builtin lib G:lib libbin G:libbin libc G:libc libimg G:libimg literal G:literal locals: G:locals: lock G:lock
+Builtin lock-to G:lock-to locked? G:locked? log G:log log-syslog G:log-syslog log-task G:log-task log-time G:log-time
+Builtin log-time-local G:log-time-local long-days G:long-days long-months G:long-months longjmp G:longjmp
+Builtin lookup G:lookup loop G:loop loop- G:loop- map? G:map? mark G:mark mark? G:mark? mobile? G:mobile?
+Builtin n# G:n# name>os G:name>os name>sem G:name>sem ndrop G:ndrop needs G:needs needs-throws G:needs-throws
Builtin new G:new next-arg G:next-arg nip G:nip noop G:noop not G:not nothrow G:nothrow ns G:ns ns: G:ns:
Builtin ns>ls G:ns>ls ns>s G:ns>s ns? G:ns? null G:null null; G:null; null? G:null? nullvar G:nullvar
Builtin number? G:number? of: G:of: off G:off on G:on onexit G:onexit only G:only op! G:op! or G:or
@@ -76,128 +77,132 @@ Builtin os G:os os-names G:os-names os>long-name G:os>long-name os>name G:os>na
Builtin pack G:pack parse G:parse parse-csv G:parse-csv parse-date G:parse-date parsech G:parsech parseln G:parseln
Builtin parsews G:parsews pick G:pick poke G:poke pool-clear G:pool-clear pool-clear-all G:pool-clear-all
Builtin prior G:prior private G:private process-args G:process-args process-args-fancy G:process-args-fancy
-Builtin process-args-help G:process-args-help process-args-vars G:process-args-vars prompt G:prompt
-Builtin public G:public putc G:putc puts G:puts quote G:quote r! G:r! r> G:r> r@ G:r@ rad>deg G:rad>deg
-Builtin rand-jit G:rand-jit rand-jsf G:rand-jsf rand-native G:rand-native rand-normal G:rand-normal
-Builtin rand-pcg G:rand-pcg rand-pcg-seed G:rand-pcg-seed rand-range G:rand-range rand-select G:rand-select
-Builtin randbuf-pcg G:randbuf-pcg random G:random rdrop G:rdrop recurse G:recurse recurse-stack G:recurse-stack
-Builtin ref@ G:ref@ reg! G:reg! reg@ G:reg@ regbin@ G:regbin@ remaining-args G:remaining-args repeat G:repeat
-Builtin required? G:required? requires G:requires reset G:reset roll G:roll rop! G:rop! rot G:rot rpick G:rpick
-Builtin rreset G:rreset rroll G:rroll rstack G:rstack rswap G:rswap rusage G:rusage s>ns G:s>ns same? G:same?
-Builtin scriptdir G:scriptdir scriptfile G:scriptfile sem G:sem sem-post G:sem-post sem-rm G:sem-rm
-Builtin sem-wait G:sem-wait sem-wait? G:sem-wait? sem>name G:sem>name semi-throw G:semi-throw set-wipe G:set-wipe
-Builtin setenv G:setenv setjmp G:setjmp settings! G:settings! settings![] G:settings![] settings@ G:settings@
-Builtin settings@? G:settings@? settings@[] G:settings@[] sh G:sh sh$ G:sh$ short-days G:short-days
-Builtin short-months G:short-months sleep G:sleep sleep-msec G:sleep-msec sleep-until G:sleep-until
-Builtin slog G:slog space G:space stack-check G:stack-check stack-size G:stack-size step G:step sthrow G:sthrow
-Builtin string? G:string? struct: G:struct: swap G:swap tab-hook G:tab-hook tell-conflict G:tell-conflict
-Builtin tempdir G:tempdir tempfilename G:tempfilename third G:third throw G:throw thrownull G:thrownull
-Builtin times G:times tlog G:tlog tri G:tri true G:true tuck G:tuck type-check G:type-check typeassert G:typeassert
-Builtin uid G:uid uname G:uname unlock G:unlock unpack G:unpack until G:until until! G:until! while G:while
-Builtin while! G:while! with: G:with: word? G:word? words G:words words-like G:words-like words/ G:words/
-Builtin xchg G:xchg xor G:xor >auth HTTP:>auth (curry) I:(curry) notimpl I:notimpl sh I:sh trace-word I:trace-word
-Builtin call JSONRPC:call auth-string OAuth:auth-string gen-nonce OAuth:gen-nonce params OAuth:params
-Builtin call SOAP:call ! a:! + a:+ - a:- / a:/ 2each a:2each 2map a:2map 2map+ a:2map+ 2map= a:2map=
-Builtin <> a:<> = a:= @ a:@ @? a:@? _@ a:_@ all a:all any a:any bsearch a:bsearch centroid a:centroid
-Builtin clear a:clear close a:close cmp a:cmp diff a:diff dot a:dot each a:each each! a:each! each-par a:each-par
-Builtin each-slice a:each-slice exists? a:exists? filter a:filter filter-par a:filter-par generate a:generate
-Builtin group a:group indexof a:indexof insert a:insert intersect a:intersect join a:join len a:len
-Builtin map a:map map+ a:map+ map-par a:map-par map= a:map= maxlen a:maxlen mean a:mean mean&variance a:mean&variance
-Builtin merge a:merge new a:new op! a:op! open a:open pigeon a:pigeon pivot a:pivot pop a:pop push a:push
+Builtin process-args-help G:process-args-help prompt G:prompt public G:public putc G:putc puts G:puts
+Builtin quote G:quote r! G:r! r> G:r> r@ G:r@ rad>deg G:rad>deg rand-jit G:rand-jit rand-jsf G:rand-jsf
+Builtin rand-native G:rand-native rand-normal G:rand-normal rand-pcg G:rand-pcg rand-pcg-seed G:rand-pcg-seed
+Builtin rand-range G:rand-range rand-select G:rand-select randbuf-pcg G:randbuf-pcg random G:random
+Builtin rdrop G:rdrop recurse G:recurse recurse-stack G:recurse-stack ref@ G:ref@ reg! G:reg! reg@ G:reg@
+Builtin regbin@ G:regbin@ remaining-args G:remaining-args repeat G:repeat requires G:requires reset G:reset
+Builtin roll G:roll rop! G:rop! rot G:rot rpick G:rpick rreset G:rreset rroll G:rroll rstack G:rstack
+Builtin rswap G:rswap rusage G:rusage s>ns G:s>ns same? G:same? scriptdir G:scriptdir scriptfile G:scriptfile
+Builtin sem G:sem sem-post G:sem-post sem-rm G:sem-rm sem-wait G:sem-wait sem-wait? G:sem-wait? sem>name G:sem>name
+Builtin semi-throw G:semi-throw set-wipe G:set-wipe setenv G:setenv setjmp G:setjmp settings! G:settings!
+Builtin settings![] G:settings![] settings@ G:settings@ settings@? G:settings@? settings@[] G:settings@[]
+Builtin sh G:sh sh$ G:sh$ short-days G:short-days short-months G:short-months sleep G:sleep sleep-msec G:sleep-msec
+Builtin sleep-until G:sleep-until slog G:slog space G:space stack-check G:stack-check stack-size G:stack-size
+Builtin step G:step sthrow G:sthrow string? G:string? struct: G:struct: swap G:swap tab-hook G:tab-hook
+Builtin tell-conflict G:tell-conflict tempdir G:tempdir tempfilename G:tempfilename third G:third throw G:throw
+Builtin thrownull G:thrownull times G:times tlog G:tlog toggle G:toggle tri G:tri true G:true tuck G:tuck
+Builtin type-check G:type-check typeassert G:typeassert uid G:uid uname G:uname unlock G:unlock unpack G:unpack
+Builtin until G:until until! G:until! while G:while while! G:while! with: G:with: word? G:word? words G:words
+Builtin words-like G:words-like words/ G:words/ xchg G:xchg xor G:xor >auth HTTP:>auth (curry) I:(curry)
+Builtin appopts I:appopts notimpl I:notimpl sh I:sh trace-word I:trace-word call JSONRPC:call auth-string OAuth:auth-string
+Builtin gen-nonce OAuth:gen-nonce params OAuth:params call SOAP:call ! a:! + a:+ - a:- / a:/ 2each a:2each
+Builtin 2len a:2len 2map a:2map 2map+ a:2map+ 2map= a:2map= <> a:<> = a:= @ a:@ @? a:@? _@ a:_@ _len a:_len
+Builtin all a:all any a:any bsearch a:bsearch centroid a:centroid clear a:clear close a:close cmp a:cmp
+Builtin diff a:diff dot a:dot each a:each each! a:each! each-par a:each-par each-slice a:each-slice
+Builtin exists? a:exists? filter a:filter filter-par a:filter-par generate a:generate group a:group
+Builtin indexof a:indexof insert a:insert intersect a:intersect join a:join len a:len map a:map map+ a:map+
+Builtin map-par a:map-par map= a:map= maxlen a:maxlen mean a:mean mean&variance a:mean&variance merge a:merge
+Builtin new a:new op! a:op! open a:open pigeon a:pigeon pivot a:pivot pop a:pop push a:push push' a:push'
Builtin qsort a:qsort randeach a:randeach reduce a:reduce reduce+ a:reduce+ remove a:remove rev a:rev
Builtin rindexof a:rindexof shift a:shift shuffle a:shuffle slice a:slice slice+ a:slice+ slide a:slide
Builtin smear a:smear sort a:sort split a:split squash a:squash switch a:switch union a:union uniq a:uniq
Builtin unzip a:unzip x a:x x-each a:x-each xchg a:xchg y a:y zip a:zip 8thdir app:8thdir asset app:asset
Builtin atrun app:atrun atrun app:atrun atrun app:atrun basedir app:basedir basename app:basename config-file-name app:config-file-name
Builtin current app:current datadir app:datadir display-moved app:display-moved exename app:exename
-Builtin localechanged app:localechanged lowmem app:lowmem main app:main name app:name oncrash app:oncrash
-Builtin opts! app:opts! opts@ app:opts@ orientation app:orientation orientation! app:orientation! pid app:pid
-Builtin post-main app:post-main pre-main app:pre-main privdir app:privdir raise app:raise read-config app:read-config
-Builtin read-config-map app:read-config-map read-config-var app:read-config-var request-perm app:request-perm
-Builtin restart app:restart resumed app:resumed signal app:signal standalone app:standalone subdir app:subdir
-Builtin suspended app:suspended sysquit app:sysquit terminated app:terminated timeout app:timeout trap app:trap
-Builtin dawn astro:dawn do-dawn astro:do-dawn do-dusk astro:do-dusk do-rise astro:do-rise dusk astro:dusk
-Builtin latitude astro:latitude location! astro:location! longitude astro:longitude sunrise astro:sunrise
-Builtin genkeys auth:genkeys secret auth:secret session-id auth:session-id session-key auth:session-key
+Builtin localechanged app:localechanged lowmem app:lowmem main app:main name app:name onback app:onback
+Builtin oncrash app:oncrash opts! app:opts! opts@ app:opts@ orientation app:orientation orientation! app:orientation!
+Builtin pid app:pid post-main app:post-main pre-main app:pre-main privdir app:privdir raise app:raise
+Builtin read-config app:read-config read-config-map app:read-config-map read-config-var app:read-config-var
+Builtin request-perm app:request-perm restart app:restart resumed app:resumed signal app:signal standalone app:standalone
+Builtin standalone! app:standalone! subdir app:subdir suspended app:suspended sysquit app:sysquit terminated app:terminated
+Builtin ticks app:ticks timeout app:timeout trap app:trap dawn astro:dawn do-dawn astro:do-dawn do-dusk astro:do-dusk
+Builtin do-rise astro:do-rise dusk astro:dusk latitude astro:latitude location! astro:location! longitude astro:longitude
+Builtin sunrise astro:sunrise genkeys auth:genkeys secret auth:secret session-id auth:session-id session-key auth:session-key
Builtin validate auth:validate ! b:! + b:+ / b:/ 1+ b:1+ 1- b:1- <> b:<> = b:= >base16 b:>base16 >base32 b:>base32
-Builtin >base64 b:>base64 >base85 b:>base85 >hex b:>hex >mpack b:>mpack @ b:@ append b:append base16> b:base16>
-Builtin base32> b:base32> base64> b:base64> base85> b:base85> bit! b:bit! bit@ b:bit@ clear b:clear
-Builtin compress b:compress conv b:conv each b:each each! b:each! each-slice b:each-slice expand b:expand
-Builtin fill b:fill getb b:getb hex> b:hex> len b:len mem> b:mem> move b:move mpack-compat b:mpack-compat
+Builtin >base64 b:>base64 >base85 b:>base85 >hex b:>hex >mpack b:>mpack @ b:@ ICONVLIBS b:ICONVLIBS
+Builtin append b:append base16> b:base16> base32> b:base32> base64> b:base64> base85> b:base85> bit! b:bit!
+Builtin bit@ b:bit@ clear b:clear compress b:compress conv b:conv each b:each each! b:each! each-slice b:each-slice
+Builtin expand b:expand fill b:fill getb b:getb hex> b:hex> len b:len mem> b:mem> move b:move mpack-compat b:mpack-compat
Builtin mpack-date b:mpack-date mpack-ignore b:mpack-ignore mpack> b:mpack> n! b:n! n+ b:n+ n@ b:n@
Builtin new b:new op b:op op! b:op! pad b:pad rev b:rev search b:search shmem b:shmem slice b:slice
Builtin splice b:splice ungetb b:ungetb unpad b:unpad writable b:writable xor b:xor +block bc:+block
Builtin .blocks bc:.blocks add-block bc:add-block block-hash bc:block-hash block@ bc:block@ first-block bc:first-block
Builtin hash bc:hash last-block bc:last-block load bc:load new bc:new save bc:save set-sql bc:set-sql
Builtin validate bc:validate validate-block bc:validate-block add bloom:add filter bloom:filter in? bloom:in?
-Builtin parse bson:parse accept bt:accept ch! bt:ch! ch@ bt:ch@ connect bt:connect disconnect bt:disconnect
+Builtin parse bson:parse LIBS bt:LIBS accept bt:accept ch! bt:ch! ch@ bt:ch@ connect bt:connect disconnect bt:disconnect
Builtin init bt:init leconnect bt:leconnect lescan bt:lescan listen bt:listen on? bt:on? read bt:read
Builtin scan bt:scan service? bt:service? services? bt:services? write bt:write * c:* * c:* + c:+ + c:+
-Builtin = c:= = c:= >ri c:>ri >ri c:>ri abs c:abs abs c:abs arg c:arg arg c:arg conj c:conj conj c:conj
-Builtin im c:im n> c:n> new c:new new c:new re c:re (.hebrew) cal:(.hebrew) (.islamic) cal:(.islamic)
-Builtin .hebrew cal:.hebrew .islamic cal:.islamic >hebepoch cal:>hebepoch >jdn cal:>jdn Adar cal:Adar
-Builtin Adar2 cal:Adar2 Adar2 cal:Adar2 Av cal:Av Elul cal:Elul Heshvan cal:Heshvan Iyar cal:Iyar Kislev cal:Kislev
-Builtin Nissan cal:Nissan Shevat cal:Shevat Sivan cal:Sivan Tammuz cal:Tammuz Tevet cal:Tevet Tishrei cal:Tishrei
-Builtin days-in-hebrew-year cal:days-in-hebrew-year displaying-hebrew cal:displaying-hebrew fixed>hebrew cal:fixed>hebrew
-Builtin fixed>islamic cal:fixed>islamic gershayim cal:gershayim hanukkah cal:hanukkah hebrew-epoch cal:hebrew-epoch
-Builtin hebrew>fixed cal:hebrew>fixed hebrewtoday cal:hebrewtoday hmonth-name cal:hmonth-name islamic.epoch cal:islamic.epoch
-Builtin islamic>fixed cal:islamic>fixed islamictoday cal:islamictoday jdn> cal:jdn> last-day-of-hebrew-month cal:last-day-of-hebrew-month
+Builtin = c:= = c:= >polar c:>polar >polar c:>polar >ri c:>ri >ri c:>ri ^ c:^ ^ c:^ abs c:abs abs c:abs
+Builtin arg c:arg arg c:arg conj c:conj conj c:conj im c:im im c:im log c:log log c:log n> c:n> n> c:n>
+Builtin new c:new new c:new polar> c:polar> polar> c:polar> re c:re re c:re (.hebrew) cal:(.hebrew)
+Builtin (.islamic) cal:(.islamic) .hebrew cal:.hebrew .islamic cal:.islamic >hebepoch cal:>hebepoch
+Builtin >jdn cal:>jdn Adar cal:Adar Adar2 cal:Adar2 Av cal:Av Elul cal:Elul Heshvan cal:Heshvan Iyar cal:Iyar
+Builtin Kislev cal:Kislev Nissan cal:Nissan Shevat cal:Shevat Sivan cal:Sivan Tammuz cal:Tammuz Tevet cal:Tevet
+Builtin Tishrei cal:Tishrei days-in-hebrew-year cal:days-in-hebrew-year displaying-hebrew cal:displaying-hebrew
+Builtin fixed>hebrew cal:fixed>hebrew fixed>islamic cal:fixed>islamic gershayim cal:gershayim hanukkah cal:hanukkah
+Builtin hebrew-epoch cal:hebrew-epoch hebrew-leap-year? cal:hebrew-leap-year? hebrew>fixed cal:hebrew>fixed
+Builtin hebrewtoday cal:hebrewtoday hmonth-name cal:hmonth-name islamic.epoch cal:islamic.epoch islamic>fixed cal:islamic>fixed
+Builtin islamictoday cal:islamictoday jdn> cal:jdn> last-day-of-hebrew-month cal:last-day-of-hebrew-month
Builtin number>hebrew cal:number>hebrew omer cal:omer pesach cal:pesach purim cal:purim rosh-chodesh? cal:rosh-chodesh?
Builtin rosh-hashanah cal:rosh-hashanah shavuot cal:shavuot taanit-esther cal:taanit-esther tisha-beav cal:tisha-beav
-Builtin yom-haatsmaut cal:yom-haatsmaut yom-kippur cal:yom-kippur >redir con:>redir accept con:accept
-Builtin accept-nl con:accept-nl accept-pwd con:accept-pwd alert con:alert ansi? con:ansi? black con:black
-Builtin blue con:blue clreol con:clreol cls con:cls ctrld-empty con:ctrld-empty cyan con:cyan down con:down
-Builtin file>history con:file>history free con:free getxy con:getxy gotoxy con:gotoxy green con:green
-Builtin history-handler con:history-handler history>file con:history>file key con:key key? con:key?
-Builtin left con:left load-history con:load-history magenta con:magenta max-history con:max-history
-Builtin onBlack con:onBlack onBlue con:onBlue onCyan con:onCyan onGreen con:onGreen onMagenta con:onMagenta
-Builtin onRed con:onRed onWhite con:onWhite onYellow con:onYellow print con:print red con:red redir> con:redir>
-Builtin redir? con:redir? right con:right save-history con:save-history size? con:size? up con:up white con:white
-Builtin yellow con:yellow >aes128gcm cr:>aes128gcm >aes256gcm cr:>aes256gcm >cp cr:>cp >cpe cr:>cpe
-Builtin >decrypt cr:>decrypt >edbox cr:>edbox >encrypt cr:>encrypt >nbuf cr:>nbuf >rsabox cr:>rsabox
-Builtin >uuid cr:>uuid aad? cr:aad? aes128box-sig cr:aes128box-sig aes128gcm> cr:aes128gcm> aes256box-sig cr:aes256box-sig
-Builtin aes256gcm> cr:aes256gcm> aesgcm cr:aesgcm blakehash cr:blakehash chacha20box-sig cr:chacha20box-sig
-Builtin chachapoly cr:chachapoly cipher! cr:cipher! cipher@ cr:cipher@ ciphers cr:ciphers cp> cr:cp>
-Builtin cpe> cr:cpe> decrypt cr:decrypt decrypt+ cr:decrypt+ decrypt> cr:decrypt> ebox-sig cr:ebox-sig
-Builtin ecc-curves cr:ecc-curves ecc-genkey cr:ecc-genkey ecc-secret cr:ecc-secret ecc-sign cr:ecc-sign
-Builtin ecc-verify cr:ecc-verify ed25519 cr:ed25519 ed25519-secret cr:ed25519-secret ed25519-sign cr:ed25519-sign
-Builtin ed25519-verify cr:ed25519-verify edbox-sig cr:edbox-sig edbox> cr:edbox> encrypt cr:encrypt
-Builtin encrypt+ cr:encrypt+ encrypt> cr:encrypt> ensurekey cr:ensurekey genkey cr:genkey hash cr:hash
-Builtin hash! cr:hash! hash+ cr:hash+ hash>b cr:hash>b hash>s cr:hash>s hash@ cr:hash@ hashes cr:hashes
-Builtin hmac cr:hmac hotp cr:hotp iv? cr:iv? pem-read cr:pem-read pem-write cr:pem-write pwd-valid? cr:pwd-valid?
-Builtin pwd/ cr:pwd/ pwd>hash cr:pwd>hash rand cr:rand randbuf cr:randbuf randkey cr:randkey restore cr:restore
-Builtin root-certs cr:root-certs rsa_decrypt cr:rsa_decrypt rsa_encrypt cr:rsa_encrypt rsa_sign cr:rsa_sign
-Builtin rsa_verify cr:rsa_verify rsabox-sig cr:rsabox-sig rsabox> cr:rsabox> rsagenkey cr:rsagenkey
+Builtin yom-haatsmaut cal:yom-haatsmaut yom-kippur cal:yom-kippur >hsva clr:>hsva complement clr:complement
+Builtin dist clr:dist gradient clr:gradient hsva> clr:hsva> invert clr:invert nearest-name clr:nearest-name
+Builtin parse clr:parse >redir con:>redir accept con:accept accept-nl con:accept-nl accept-pwd con:accept-pwd
+Builtin alert con:alert ansi? con:ansi? black con:black blue con:blue clreol con:clreol cls con:cls
+Builtin ctrld-empty con:ctrld-empty cyan con:cyan down con:down file>history con:file>history free con:free
+Builtin getxy con:getxy gotoxy con:gotoxy green con:green history-handler con:history-handler history>file con:history>file
+Builtin init con:init key con:key key? con:key? left con:left load-history con:load-history magenta con:magenta
+Builtin max-history con:max-history onBlack con:onBlack onBlue con:onBlue onCyan con:onCyan onGreen con:onGreen
+Builtin onMagenta con:onMagenta onRed con:onRed onWhite con:onWhite onYellow con:onYellow print con:print
+Builtin red con:red redir> con:redir> redir? con:redir? right con:right save-history con:save-history
+Builtin size? con:size? up con:up white con:white yellow con:yellow >aes128gcm cr:>aes128gcm >aes256gcm cr:>aes256gcm
+Builtin >cp cr:>cp >cpe cr:>cpe >decrypt cr:>decrypt >edbox cr:>edbox >encrypt cr:>encrypt >nbuf cr:>nbuf
+Builtin >rsabox cr:>rsabox >uuid cr:>uuid aad? cr:aad? aes128box-sig cr:aes128box-sig aes128gcm> cr:aes128gcm>
+Builtin aes256box-sig cr:aes256box-sig aes256gcm> cr:aes256gcm> aesgcm cr:aesgcm blakehash cr:blakehash
+Builtin chacha20box-sig cr:chacha20box-sig chachapoly cr:chachapoly cipher! cr:cipher! cipher@ cr:cipher@
+Builtin ciphers cr:ciphers cp> cr:cp> cpe> cr:cpe> decrypt cr:decrypt decrypt+ cr:decrypt+ decrypt> cr:decrypt>
+Builtin ebox-sig cr:ebox-sig ecc-curves cr:ecc-curves ecc-genkey cr:ecc-genkey ecc-secret cr:ecc-secret
+Builtin ecc-sign cr:ecc-sign ecc-verify cr:ecc-verify ed25519 cr:ed25519 ed25519-secret cr:ed25519-secret
+Builtin ed25519-sign cr:ed25519-sign ed25519-verify cr:ed25519-verify edbox-sig cr:edbox-sig edbox> cr:edbox>
+Builtin encrypt cr:encrypt encrypt+ cr:encrypt+ encrypt> cr:encrypt> ensurekey cr:ensurekey genkey cr:genkey
+Builtin hash cr:hash hash! cr:hash! hash+ cr:hash+ hash>b cr:hash>b hash>s cr:hash>s hash@ cr:hash@
+Builtin hashes cr:hashes hmac cr:hmac hotp cr:hotp iv? cr:iv? pem-read cr:pem-read pem-write cr:pem-write
+Builtin pwd-valid? cr:pwd-valid? pwd/ cr:pwd/ pwd>hash cr:pwd>hash rand cr:rand randbuf cr:randbuf
+Builtin randkey cr:randkey restore cr:restore root-certs cr:root-certs rsa_decrypt cr:rsa_decrypt rsa_encrypt cr:rsa_encrypt
+Builtin rsa_sign cr:rsa_sign rsa_verify cr:rsa_verify rsabox-sig cr:rsabox-sig rsabox> cr:rsabox> rsagenkey cr:rsagenkey
Builtin save cr:save sbox-sig cr:sbox-sig sha1-hmac cr:sha1-hmac shard cr:shard tag? cr:tag? totp cr:totp
Builtin totp-epoch cr:totp-epoch totp-time-step cr:totp-time-step unshard cr:unshard uuid cr:uuid uuid> cr:uuid>
-Builtin validate-pgp-sig cr:validate-pgp-sig validate-pwd cr:validate-pwd + d:+ +day d:+day +hour d:+hour
-Builtin +min d:+min +msec d:+msec - d:- .time d:.time / d:/ = d:= >fixed d:>fixed >hmds d:>hmds >hmds: d:>hmds:
-Builtin >msec d:>msec >unix d:>unix >ymd d:>ymd ?= d:?= Fri d:Fri Mon d:Mon Sat d:Sat Sun d:Sun Thu d:Thu
-Builtin Tue d:Tue Wed d:Wed adjust-dst d:adjust-dst alarm d:alarm approx! d:approx! approx? d:approx?
-Builtin approximates! d:approximates! between d:between cmp d:cmp d. d:d. default-now d:default-now
+Builtin validate-pgp-sig cr:validate-pgp-sig validate-pwd cr:validate-pwd (.time) d:(.time) + d:+ +day d:+day
+Builtin +hour d:+hour +min d:+min +msec d:+msec - d:- .time d:.time / d:/ = d:= >fixed d:>fixed >hmds d:>hmds
+Builtin >hmds: d:>hmds: >msec d:>msec >unix d:>unix >ymd d:>ymd ?= d:?= Fri d:Fri Mon d:Mon Sat d:Sat
+Builtin Sun d:Sun Thu d:Thu Tue d:Tue Wed d:Wed adjust-dst d:adjust-dst alarm d:alarm approx! d:approx!
+Builtin approx? d:approx? approximates! d:approximates! between d:between cmp d:cmp d. d:d. default-now d:default-now
Builtin doy d:doy dst-ofs d:dst-ofs dst? d:dst? dstinfo d:dstinfo dstquery d:dstquery dstzones? d:dstzones?
Builtin elapsed-timer d:elapsed-timer elapsed-timer-hmds d:elapsed-timer-hmds elapsed-timer-msec d:elapsed-timer-msec
Builtin elapsed-timer-seconds d:elapsed-timer-seconds first-dow d:first-dow fixed> d:fixed> fixed>dow d:fixed>dow
Builtin format d:format join d:join last-dow d:last-dow last-month d:last-month last-week d:last-week
-Builtin last-year d:last-year msec d:msec msec> d:msec> new d:new next-dow d:next-dow next-month d:next-month
-Builtin next-week d:next-week next-year d:next-year parse d:parse parse-approx d:parse-approx parse-range d:parse-range
-Builtin prev-dow d:prev-dow rfc5322 d:rfc5322 start-timer d:start-timer ticks d:ticks ticks/sec d:ticks/sec
-Builtin timer d:timer timer-ctrl d:timer-ctrl tzadjust d:tzadjust unix> d:unix> unknown d:unknown unknown? d:unknown?
-Builtin updatetz d:updatetz year@ d:year@ ymd d:ymd ymd> d:ymd> add-func db:add-func aes! db:aes! again? db:again?
+Builtin last-year d:last-year leap? d:leap? mdays d:mdays msec d:msec msec> d:msec> new d:new next-dow d:next-dow
+Builtin next-month d:next-month next-week d:next-week next-year d:next-year parse d:parse parse-approx d:parse-approx
+Builtin parse-range d:parse-range prev-dow d:prev-dow rfc5322 d:rfc5322 start-timer d:start-timer ticks d:ticks
+Builtin ticks/sec d:ticks/sec timer d:timer timer-ctrl d:timer-ctrl tzadjust d:tzadjust unix> d:unix>
+Builtin unknown d:unknown unknown? d:unknown? updatetz d:updatetz year@ d:year@ ymd d:ymd ymd> d:ymd>
+Builtin MYSQLLIB db:MYSQLLIB ODBCLIB db:ODBCLIB add-func db:add-func aes! db:aes! again? db:again?
Builtin begin db:begin bind db:bind bind-exec db:bind-exec bind-exec{} db:bind-exec{} close db:close
Builtin col db:col col{} db:col{} commit db:commit db db:db dbpush db:dbpush disuse db:disuse each db:each
Builtin err-handler db:err-handler exec db:exec exec-cb db:exec-cb exec-name db:exec-name exec{} db:exec{}
Builtin get db:get get-sub db:get-sub key db:key kind? db:kind? last-rowid db:last-rowid mysql? db:mysql?
Builtin odbc? db:odbc? open db:open open? db:open? prep-name db:prep-name prepare db:prepare query db:query
Builtin query-all db:query-all rekey db:rekey rollback db:rollback set db:set set-sub db:set-sub sql@ db:sql@
-Builtin sql[] db:sql[] sql[np] db:sql[np] sql{np} db:sql{np} sql{} db:sql{} use db:use zip db:zip bp dbg:bp
-Builtin bt dbg:bt except-task@ dbg:except-task@ go dbg:go line-info dbg:line-info prompt dbg:prompt
-Builtin stop dbg:stop trace dbg:trace trace-enter dbg:trace-enter trace-leave dbg:trace-leave / f:/
-Builtin >posix f:>posix abspath f:abspath absrel f:absrel append f:append associate f:associate atime f:atime
-Builtin autodel f:autodel canwrite? f:canwrite? chmod f:chmod close f:close copy f:copy copydir f:copydir
-Builtin create f:create ctime f:ctime dir? f:dir? dname f:dname eachbuf f:eachbuf eachline f:eachline
-Builtin enssep f:enssep eof? f:eof? exec f:exec exists? f:exists? flush f:flush fname f:fname getb f:getb
-Builtin getc f:getc getline f:getline getmod f:getmod glob f:glob glob-links f:glob-links glob-nocase f:glob-nocase
+Builtin sql[] db:sql[] sql[np] db:sql[np] sql{np} db:sql{np} sql{} db:sql{} use db:use zip db:zip .state dbg:.state
+Builtin bp dbg:bp bt dbg:bt except-task@ dbg:except-task@ go dbg:go prompt dbg:prompt see dbg:see stop dbg:stop
+Builtin trace dbg:trace trace-enter dbg:trace-enter trace-leave dbg:trace-leave pso ds:pso / f:/ >posix f:>posix
+Builtin abspath f:abspath absrel f:absrel append f:append associate f:associate atime f:atime autodel f:autodel
+Builtin canwrite? f:canwrite? chmod f:chmod close f:close copy f:copy copydir f:copydir create f:create
+Builtin ctime f:ctime dir? f:dir? dname f:dname eachbuf f:eachbuf eachline f:eachline enssep f:enssep
+Builtin eof? f:eof? exec f:exec exists? f:exists? flush f:flush fname f:fname getb f:getb getc f:getc
+Builtin getline f:getline getmod f:getmod glob f:glob glob-links f:glob-links glob-nocase f:glob-nocase
Builtin gunz f:gunz homedir f:homedir homedir! f:homedir! include f:include ioctl f:ioctl join f:join
Builtin launch f:launch link f:link link> f:link> link? f:link? lock f:lock mkdir f:mkdir mmap f:mmap
Builtin mmap-range f:mmap-range mmap-range? f:mmap-range? mtime f:mtime mv f:mv name@ f:name@ open f:open
@@ -209,9 +214,9 @@ Builtin ungetc f:ungetc unzip f:unzip unzip-entry f:unzip-entry watch f:watch w
Builtin zip+ f:zip+ zip@ f:zip@ zipentry f:zipentry zipnew f:zipnew zipopen f:zipopen zipsave f:zipsave
Builtin atlas! font:atlas! atlas@ font:atlas@ default-size font:default-size default-size@ font:default-size@
Builtin info font:info ls font:ls measure font:measure new font:new oversample font:oversample pixels font:pixels
-Builtin pixels? font:pixels? system font:system system font:system distance geo:distance km/deg-lat geo:km/deg-lat
-Builtin km/deg-lon geo:km/deg-lon nearest geo:nearest +edge gr:+edge +edge+w gr:+edge+w +node gr:+node
-Builtin connect gr:connect edges gr:edges edges! gr:edges! m! gr:m! m@ gr:m@ neighbors gr:neighbors
+Builtin pixels? font:pixels? system font:system system font:system media? g:media? distance geo:distance
+Builtin km/deg-lat geo:km/deg-lat km/deg-lon geo:km/deg-lon nearest geo:nearest +edge gr:+edge +edge+w gr:+edge+w
+Builtin +node gr:+node connect gr:connect edges gr:edges edges! gr:edges! m! gr:m! m@ gr:m@ neighbors gr:neighbors
Builtin new gr:new node-edges gr:node-edges nodes gr:nodes traverse gr:traverse weight! gr:weight!
Builtin + h:+ clear h:clear cmp! h:cmp! len h:len max! h:max! new h:new peek h:peek pop h:pop push h:push
Builtin unique h:unique parse html:parse arm? hw:arm? camera hw:camera camera-img hw:camera-img camera-limits hw:camera-limits
@@ -219,163 +224,171 @@ Builtin camera? hw:camera? cpu? hw:cpu? device? hw:device? displays? hw:display
Builtin finger-match hw:finger-match finger-support hw:finger-support gpio hw:gpio gpio! hw:gpio! gpio-mmap hw:gpio-mmap
Builtin gpio@ hw:gpio@ i2c hw:i2c i2c! hw:i2c! i2c!reg hw:i2c!reg i2c@ hw:i2c@ i2c@reg hw:i2c@reg isround? hw:isround?
Builtin iswatch? hw:iswatch? mac? hw:mac? mem? hw:mem? model? hw:model? poll hw:poll sensor hw:sensor
-Builtin start hw:start stop hw:stop uid? hw:uid? fetch-full imap:fetch-full fetch-uid-mail imap:fetch-uid-mail
+Builtin start hw:start stop hw:stop touch? hw:touch? uid? hw:uid? fetch-full imap:fetch-full fetch-uid-mail imap:fetch-uid-mail
Builtin login imap:login logout imap:logout new imap:new search imap:search select-inbox imap:select-inbox
Builtin >file img:>file >fmt img:>fmt copy img:copy crop img:crop data img:data desat img:desat draw img:draw
Builtin draw-sub img:draw-sub fill img:fill fillrect img:fillrect filter img:filter flip img:flip from-svg img:from-svg
Builtin line img:line new img:new pikchr img:pikchr pix! img:pix! pix@ img:pix@ qr-gen img:qr-gen qr-parse img:qr-parse
Builtin rect img:rect rotate img:rotate scale img:scale scroll img:scroll size img:size countries iso:countries
-Builtin languages iso:languages utils/help library:utils/help find loc:find sort loc:sort ! m:! !? m:!?
-Builtin + m:+ +? m:+? - m:- <> m:<> = m:= >arr m:>arr @ m:@ @? m:@? _! m:_! _@ m:_@ alias m:alias arr> m:arr>
-Builtin bitmap m:bitmap clear m:clear data m:data each m:each exists? m:exists? filter m:filter ic m:ic
-Builtin iter m:iter iter-all m:iter-all keys m:keys len m:len map m:map merge m:merge new m:new op! m:op!
-Builtin open m:open slice m:slice vals m:vals xchg m:xchg zip m:zip ! mat:! * mat:* + mat:+ = mat:=
-Builtin @ mat:@ affine mat:affine col mat:col data mat:data det mat:det dim? mat:dim? get-n mat:get-n
-Builtin ident mat:ident inv mat:inv m. mat:m. minor mat:minor n* mat:n* new mat:new new-minor mat:new-minor
-Builtin rotate mat:rotate row mat:row same-size? mat:same-size? scale mat:scale shear mat:shear trans mat:trans
-Builtin translate mat:translate xform mat:xform 2console md:2console 2html md:2html 2nk md:2nk color meta:color
-Builtin console meta:console gui meta:gui meta meta:meta ! n:! * n:* */ n:*/ + n:+ +! n:+! - n:- / n:/
-Builtin /mod n:/mod 1+ n:1+ 1- n:1- < n:< = n:= > n:> >bool n:>bool BIGE n:BIGE BIGPI n:BIGPI E n:E
-Builtin PI n:PI ^ n:^ _mod n:_mod abs n:abs acos n:acos acos n:acos andor n:andor asin n:asin asin n:asin
-Builtin atan n:atan atan n:atan atan2 n:atan2 band n:band between n:between bfloat n:bfloat bic n:bic
+Builtin languages iso:languages utils/help library:utils/help bearing loc:bearing find loc:find sort loc:sort
+Builtin ! m:! !? m:!? + m:+ +? m:+? - m:- <> m:<> = m:= >arr m:>arr @ m:@ @? m:@? _! m:_! _@ m:_@ _@? m:_@?
+Builtin alias m:alias arr> m:arr> bitmap m:bitmap clear m:clear data m:data each m:each exists? m:exists?
+Builtin filter m:filter ic m:ic iter m:iter iter-all m:iter-all keys m:keys len m:len map m:map merge m:merge
+Builtin new m:new op! m:op! open m:open slice m:slice vals m:vals xchg m:xchg zip m:zip ! mat:! * mat:*
+Builtin + mat:+ = mat:= @ mat:@ affine mat:affine col mat:col data mat:data det mat:det dim? mat:dim?
+Builtin get-n mat:get-n ident mat:ident inv mat:inv m. mat:m. minor mat:minor n* mat:n* new mat:new
+Builtin new-minor mat:new-minor rotate mat:rotate row mat:row same-size? mat:same-size? scale mat:scale
+Builtin shear mat:shear trans mat:trans translate mat:translate xform mat:xform 2console md:2console
+Builtin 2html md:2html 2nk md:2nk color meta:color console meta:console gui meta:gui meta meta:meta
+Builtin ! n:! * n:* */ n:*/ + n:+ +! n:+! - n:- / n:/ /mod n:/mod 1+ n:1+ 1- n:1- < n:< = n:= > n:>
+Builtin >bool n:>bool BIGE n:BIGE BIGPI n:BIGPI E n:E PI n:PI ^ n:^ _mod n:_mod abs n:abs acos n:acos
+Builtin acosd n:acosd acosh n:acosh andor n:andor asin n:asin asind n:asind asinh n:asinh atan n:atan
+Builtin atan2 n:atan2 atand n:atand atanh n:atanh band n:band between n:between bfloat n:bfloat bic n:bic
Builtin bint n:bint binv n:binv bnot n:bnot bor n:bor bxor n:bxor cast n:cast ceil n:ceil clamp n:clamp
-Builtin cmp n:cmp comb n:comb cos n:cos cosd n:cosd emod n:emod exp n:exp expm1 n:expm1 expmod n:expmod
-Builtin float n:float floor n:floor fmod n:fmod frac n:frac gcd n:gcd int n:int invmod n:invmod kind? n:kind?
-Builtin lcm n:lcm lerp n:lerp ln n:ln ln1p n:ln1p lnerp n:lnerp max n:max median n:median min n:min
-Builtin mod n:mod neg n:neg odd? n:odd? perm n:perm prime? n:prime? quantize n:quantize quantize! n:quantize!
-Builtin r+ n:r+ range n:range rot32l n:rot32l rot32r n:rot32r round n:round round2 n:round2 rounding n:rounding
-Builtin running-variance n:running-variance running-variance-finalize n:running-variance-finalize sgn n:sgn
-Builtin shl n:shl shr n:shr sin n:sin sind n:sind sqr n:sqr sqrt n:sqrt tan n:tan tand n:tand trunc n:trunc
-Builtin ~= n:~= ! net:! !? net:!? - net:- >base64url net:>base64url >url net:>url @ net:@ @? net:@?
-Builtin CGI net:CGI DGRAM net:DGRAM INET4 net:INET4 INET6 net:INET6 PROTO_TCP net:PROTO_TCP PROTO_UDP net:PROTO_UDP
-Builtin REMOTE_IP net:REMOTE_IP STREAM net:STREAM accept net:accept active? net:active? addrinfo>o net:addrinfo>o
-Builtin again? net:again? alloc-and-read net:alloc-and-read alloc-buf net:alloc-buf base64url> net:base64url>
-Builtin bind net:bind cgi-get net:cgi-get cgi-http-header net:cgi-http-header cgi-init net:cgi-init
-Builtin cgi-init-stunnel net:cgi-init-stunnel cgi-out net:cgi-out close net:close closed? net:closed?
-Builtin connect net:connect curnet net:curnet debug? net:debug? delete net:delete get net:get getaddrinfo net:getaddrinfo
-Builtin getpeername net:getpeername head net:head ifaces? net:ifaces? ipv6? net:ipv6? listen net:listen
-Builtin map>url net:map>url mime-type net:mime-type net-socket net:net-socket opts net:opts port-is-ssl? net:port-is-ssl?
+Builtin cmp n:cmp comb n:comb cos n:cos cosd n:cosd cosh n:cosh emod n:emod erf n:erf erfc n:erfc exp n:exp
+Builtin expm1 n:expm1 expmod n:expmod float n:float floor n:floor fmod n:fmod frac n:frac gcd n:gcd
+Builtin int n:int invmod n:invmod kind? n:kind? lcm n:lcm lerp n:lerp ln n:ln ln1p n:ln1p lnerp n:lnerp
+Builtin logistic n:logistic max n:max median n:median min n:min mod n:mod neg n:neg odd? n:odd? perm n:perm
+Builtin prime? n:prime? quantize n:quantize quantize! n:quantize! r+ n:r+ range n:range rot32l n:rot32l
+Builtin rot32r n:rot32r round n:round round2 n:round2 rounding n:rounding running-variance n:running-variance
+Builtin running-variance-finalize n:running-variance-finalize sgn n:sgn shl n:shl shr n:shr sin n:sin
+Builtin sincos n:sincos sind n:sind sinh n:sinh sqr n:sqr sqrt n:sqrt tan n:tan tand n:tand tanh n:tanh
+Builtin trunc n:trunc ~= n:~= ! net:! !? net:!? - net:- >base64url net:>base64url >url net:>url @ net:@
+Builtin @? net:@? CGI net:CGI DGRAM net:DGRAM INET4 net:INET4 INET6 net:INET6 PROTO_TCP net:PROTO_TCP
+Builtin PROTO_UDP net:PROTO_UDP REMOTE_IP net:REMOTE_IP REMOTE_IP net:REMOTE_IP STREAM net:STREAM accept net:accept
+Builtin active? net:active? addrinfo>o net:addrinfo>o again? net:again? alloc-and-read net:alloc-and-read
+Builtin alloc-buf net:alloc-buf avail? net:avail? base64url> net:base64url> bind net:bind cgi-get net:cgi-get
+Builtin cgi-http-header net:cgi-http-header cgi-init net:cgi-init cgi-init-stunnel net:cgi-init-stunnel
+Builtin cgi-out net:cgi-out close net:close closed? net:closed? connect net:connect curnet net:curnet
+Builtin debug? net:debug? delete net:delete dns net:dns get net:get getaddrinfo net:getaddrinfo getpeername net:getpeername
+Builtin head net:head ifaces? net:ifaces? ipv6? net:ipv6? launch net:launch listen net:listen map>url net:map>url
+Builtin mime-type net:mime-type net-socket net:net-socket opts net:opts port-is-ssl? net:port-is-ssl?
Builtin post net:post proxy! net:proxy! put net:put read net:read read-all net:read-all read-buf net:read-buf
Builtin recvfrom net:recvfrom s>url net:s>url sendto net:sendto server net:server setsockopt net:setsockopt
Builtin socket net:socket tcp-connect net:tcp-connect tlserr net:tlserr tlshello net:tlshello udp-connect net:udp-connect
-Builtin url> net:url> user-agent net:user-agent vpncheck net:vpncheck wait net:wait webserver net:webserver
-Builtin write net:write (begin) nk:(begin) (chart-begin) nk:(chart-begin) (chart-begin-colored) nk:(chart-begin-colored)
-Builtin (chart-end) nk:(chart-end) (end) nk:(end) (group-begin) nk:(group-begin) (group-end) nk:(group-end)
-Builtin (property) nk:(property) >img nk:>img addfont nk:addfont anti-alias nk:anti-alias any-clicked? nk:any-clicked?
-Builtin bounds nk:bounds bounds! nk:bounds! button nk:button button-color nk:button-color button-label nk:button-label
-Builtin button-set-behavior nk:button-set-behavior button-symbol nk:button-symbol button-symbol-label nk:button-symbol-label
-Builtin center-rect nk:center-rect chart-add-slot nk:chart-add-slot chart-add-slot-colored nk:chart-add-slot-colored
-Builtin chart-push nk:chart-push chart-push-slot nk:chart-push-slot checkbox nk:checkbox circle nk:circle
-Builtin clicked? nk:clicked? close-this! nk:close-this! close-this? nk:close-this? close? nk:close?
-Builtin color-picker nk:color-picker combo nk:combo combo-begin-color nk:combo-begin-color combo-begin-label nk:combo-begin-label
-Builtin combo-cb nk:combo-cb combo-end nk:combo-end contextual-begin nk:contextual-begin contextual-close nk:contextual-close
+Builtin url> net:url> user-agent net:user-agent valid-email? net:valid-email? vpncheck net:vpncheck
+Builtin wait net:wait webserver net:webserver write net:write (begin) nk:(begin) (chart-begin) nk:(chart-begin)
+Builtin (chart-begin-colored) nk:(chart-begin-colored) (chart-end) nk:(chart-end) (end) nk:(end) (group-begin) nk:(group-begin)
+Builtin (group-end) nk:(group-end) (property) nk:(property) >img nk:>img GLLIBS nk:GLLIBS GLXLIBS nk:GLXLIBS
+Builtin addfont nk:addfont anti-alias nk:anti-alias any-clicked? nk:any-clicked? bounds nk:bounds bounds! nk:bounds!
+Builtin button nk:button button-color nk:button-color button-label nk:button-label button-set-behavior nk:button-set-behavior
+Builtin button-symbol nk:button-symbol button-symbol-label nk:button-symbol-label chart-add-slot nk:chart-add-slot
+Builtin chart-add-slot-colored nk:chart-add-slot-colored chart-push nk:chart-push chart-push-slot nk:chart-push-slot
+Builtin checkbox nk:checkbox circle nk:circle clicked? nk:clicked? close-this! nk:close-this! close-this? nk:close-this?
+Builtin close? nk:close? color-chooser nk:color-chooser color-picker nk:color-picker combo nk:combo
+Builtin combo-begin-color nk:combo-begin-color combo-begin-label nk:combo-begin-label combo-cb nk:combo-cb
+Builtin combo-end nk:combo-end contextual-begin nk:contextual-begin contextual-close nk:contextual-close
Builtin contextual-end nk:contextual-end contextual-item-image-text nk:contextual-item-image-text contextual-item-symbol-text nk:contextual-item-symbol-text
Builtin contextual-item-text nk:contextual-item-text cp! nk:cp! cp@ nk:cp@ curpos nk:curpos cursor-load nk:cursor-load
Builtin cursor-set nk:cursor-set cursor-show nk:cursor-show display-info nk:display-info display@ nk:display@
Builtin do nk:do down? nk:down? draw-image nk:draw-image draw-image-at nk:draw-image-at draw-image-centered nk:draw-image-centered
Builtin draw-sub-image nk:draw-sub-image draw-text nk:draw-text draw-text-centered nk:draw-text-centered
-Builtin draw-text-high nk:draw-text-high draw-text-wrap nk:draw-text-wrap drivers nk:drivers edit-focus nk:edit-focus
-Builtin edit-string nk:edit-string event nk:event event-boost nk:event-boost event-msec nk:event-msec
-Builtin event-wait nk:event-wait event? nk:event? fill-arc nk:fill-arc fill-circle nk:fill-circle fill-color nk:fill-color
-Builtin fill-poly nk:fill-poly fill-rect nk:fill-rect fill-rect-color nk:fill-rect-color fill-triangle nk:fill-triangle
-Builtin finger nk:finger flags! nk:flags! flags@ nk:flags@ flash nk:flash fullscreen nk:fullscreen
-Builtin gesture nk:gesture get nk:get get-row-height nk:get-row-height getfont nk:getfont getmap nk:getmap
-Builtin getmap! nk:getmap! gl? nk:gl? grid nk:grid grid-push nk:grid-push group-scroll-ofs nk:group-scroll-ofs
-Builtin group-scroll-ofs! nk:group-scroll-ofs! hovered? nk:hovered? hrule nk:hrule image nk:image init nk:init
-Builtin input-button nk:input-button input-key nk:input-key input-motion nk:input-motion input-scroll nk:input-scroll
-Builtin input-string nk:input-string key-down? nk:key-down? key-pressed? nk:key-pressed? key-released? nk:key-released?
-Builtin label nk:label label-colored nk:label-colored label-wrap nk:label-wrap label-wrap-colored nk:label-wrap-colored
-Builtin layout-bounds nk:layout-bounds layout-grid-begin nk:layout-grid-begin layout-grid-end nk:layout-grid-end
-Builtin layout-push-dynamic nk:layout-push-dynamic layout-push-static nk:layout-push-static layout-push-variable nk:layout-push-variable
-Builtin layout-ratio-from-pixel nk:layout-ratio-from-pixel layout-reset-row-height nk:layout-reset-row-height
-Builtin layout-row nk:layout-row layout-row-begin nk:layout-row-begin layout-row-dynamic nk:layout-row-dynamic
-Builtin layout-row-end nk:layout-row-end layout-row-height nk:layout-row-height layout-row-push nk:layout-row-push
-Builtin layout-row-static nk:layout-row-static layout-row-template-begin nk:layout-row-template-begin
+Builtin draw-text-high nk:draw-text-high draw-text-wrap nk:draw-text-wrap driver nk:driver drivers nk:drivers
+Builtin dropped nk:dropped dropping nk:dropping edit-focus nk:edit-focus edit-string nk:edit-string
+Builtin event nk:event event-boost nk:event-boost event-msec nk:event-msec event-wait nk:event-wait
+Builtin event? nk:event? fill-arc nk:fill-arc fill-circle nk:fill-circle fill-color nk:fill-color fill-poly nk:fill-poly
+Builtin fill-rect nk:fill-rect fill-rect-color nk:fill-rect-color fill-triangle nk:fill-triangle finger nk:finger
+Builtin flags! nk:flags! flags@ nk:flags@ flash nk:flash fullscreen nk:fullscreen gesture nk:gesture
+Builtin get nk:get get-row-height nk:get-row-height getfont nk:getfont getmap nk:getmap getmap! nk:getmap!
+Builtin gl? nk:gl? grid nk:grid grid-peek nk:grid-peek grid-push nk:grid-push group-scroll-ofs nk:group-scroll-ofs
+Builtin group-scroll-ofs! nk:group-scroll-ofs! hints nk:hints hovered? nk:hovered? hrule nk:hrule image nk:image
+Builtin init nk:init input-button nk:input-button input-key nk:input-key input-motion nk:input-motion
+Builtin input-scroll nk:input-scroll input-string nk:input-string key-down? nk:key-down? key-pressed? nk:key-pressed?
+Builtin key-released? nk:key-released? knob nk:knob label nk:label label-colored nk:label-colored label-wrap nk:label-wrap
+Builtin label-wrap-colored nk:label-wrap-colored layout-bounds nk:layout-bounds layout-grid-begin nk:layout-grid-begin
+Builtin layout-grid-end nk:layout-grid-end layout-push-dynamic nk:layout-push-dynamic layout-push-static nk:layout-push-static
+Builtin layout-push-variable nk:layout-push-variable layout-ratio-from-pixel nk:layout-ratio-from-pixel
+Builtin layout-reset-row-height nk:layout-reset-row-height layout-row nk:layout-row layout-row-begin nk:layout-row-begin
+Builtin layout-row-dynamic nk:layout-row-dynamic layout-row-end nk:layout-row-end layout-row-height nk:layout-row-height
+Builtin layout-row-push nk:layout-row-push layout-row-static nk:layout-row-static layout-row-template-begin nk:layout-row-template-begin
Builtin layout-row-template-end nk:layout-row-template-end layout-space-begin nk:layout-space-begin
Builtin layout-space-end nk:layout-space-end layout-space-push nk:layout-space-push layout-widget-bounds nk:layout-widget-bounds
Builtin line-rel nk:line-rel line-to nk:line-to list-begin nk:list-begin list-end nk:list-end list-new nk:list-new
-Builtin list-range nk:list-range m! nk:m! m@ nk:m@ make-style nk:make-style max-vertex-element nk:max-vertex-element
+Builtin list-ofs nk:list-ofs list-range nk:list-range m! nk:m! m@ nk:m@ make-style nk:make-style max-vertex-element nk:max-vertex-element
Builtin maximize nk:maximize measure nk:measure measure-font nk:measure-font menu-begin nk:menu-begin
Builtin menu-close nk:menu-close menu-end nk:menu-end menu-item-image nk:menu-item-image menu-item-label nk:menu-item-label
Builtin menu-item-symbol nk:menu-item-symbol menubar-begin nk:menubar-begin menubar-end nk:menubar-end
Builtin minimize nk:minimize mouse-pos nk:mouse-pos move-back nk:move-back move-rel nk:move-rel move-to nk:move-to
Builtin msg nk:msg msgdlg nk:msgdlg ontop nk:ontop option nk:option pen-color nk:pen-color pen-width nk:pen-width
-Builtin plot nk:plot plot-fn nk:plot-fn pop-font nk:pop-font popup-begin nk:popup-begin popup-close nk:popup-close
-Builtin popup-end nk:popup-end popup-scroll-ofs nk:popup-scroll-ofs popup-scroll-ofs! nk:popup-scroll-ofs!
-Builtin progress nk:progress prop-int nk:prop-int pt-in? nk:pt-in? pt-open nk:pt-open pt>local nk:pt>local
-Builtin pt>rect nk:pt>rect pt>screen nk:pt>screen pt>x nk:pt>x pts>rect nk:pts>rect push-font nk:push-font
-Builtin raise nk:raise rect! nk:rect! rect-center nk:rect-center rect-intersect nk:rect-intersect rect-ofs nk:rect-ofs
-Builtin rect-open nk:rect-open rect-pad nk:rect-pad rect-rel nk:rect-rel rect-shrink nk:rect-shrink
-Builtin rect-to nk:rect-to rect-union nk:rect-union rect/high nk:rect/high rect/wide nk:rect/wide rect= nk:rect=
-Builtin rect>local nk:rect>local rect>pos nk:rect>pos rect>pts nk:rect>pts rect>pts4 nk:rect>pts4 rect>screen nk:rect>screen
-Builtin rect>size nk:rect>size rect>x nk:rect>x rect@ nk:rect@ released? nk:released? render nk:render
-Builtin render-timed nk:render-timed restore nk:restore rotate nk:rotate rotate-rel nk:rotate-rel save nk:save
-Builtin scale nk:scale scancode? nk:scancode? screen-saver nk:screen-saver screen-size nk:screen-size
-Builtin screen-win-close nk:screen-win-close selectable nk:selectable set nk:set set-font nk:set-font
-Builtin set-num-vertices nk:set-num-vertices set-radius nk:set-radius setpos nk:setpos setwin nk:setwin
-Builtin show nk:show slider nk:slider slider-int nk:slider-int space nk:space spacing nk:spacing stroke-arc nk:stroke-arc
-Builtin stroke-circle nk:stroke-circle stroke-curve nk:stroke-curve stroke-line nk:stroke-line stroke-polygon nk:stroke-polygon
-Builtin stroke-polyline nk:stroke-polyline stroke-rect nk:stroke-rect stroke-tri nk:stroke-tri style-from-table nk:style-from-table
-Builtin swipe nk:swipe swipe-dir-threshold nk:swipe-dir-threshold swipe-threshold nk:swipe-threshold
-Builtin text nk:text text-align nk:text-align text-font nk:text-font text-pad nk:text-pad text? nk:text?
-Builtin timer-delay nk:timer-delay timer? nk:timer? tooltip nk:tooltip translate nk:translate tree-pop nk:tree-pop
-Builtin tree-state-push nk:tree-state-push use-style nk:use-style vsync nk:vsync widget nk:widget widget-bounds nk:widget-bounds
+Builtin pix! nk:pix! plot nk:plot plot-fn nk:plot-fn polygon nk:polygon pop-font nk:pop-font popup-begin nk:popup-begin
+Builtin popup-close nk:popup-close popup-end nk:popup-end popup-scroll-ofs nk:popup-scroll-ofs popup-scroll-ofs! nk:popup-scroll-ofs!
+Builtin progress nk:progress prop-int nk:prop-int pt-in? nk:pt-in? pt>local nk:pt>local pt>screen nk:pt>screen
+Builtin push-font nk:push-font raise nk:raise rect-rel nk:rect-rel rect-to nk:rect-to rect>local nk:rect>local
+Builtin rect>screen nk:rect>screen released? nk:released? render nk:render render-timed nk:render-timed
+Builtin rendering nk:rendering restore nk:restore rotate nk:rotate rotate-rel nk:rotate-rel rtl! nk:rtl!
+Builtin rtl? nk:rtl? save nk:save scale nk:scale scancode? nk:scancode? screen-saver nk:screen-saver
+Builtin screen-size nk:screen-size screen-win-close nk:screen-win-close selectable nk:selectable set nk:set
+Builtin set-font nk:set-font set-num-vertices nk:set-num-vertices set-radius nk:set-radius setpos nk:setpos
+Builtin setwin nk:setwin show nk:show slider nk:slider slider-int nk:slider-int space nk:space spacing nk:spacing
+Builtin stroke-arc nk:stroke-arc stroke-circle nk:stroke-circle stroke-curve nk:stroke-curve stroke-line nk:stroke-line
+Builtin stroke-polygon nk:stroke-polygon stroke-polyline nk:stroke-polyline stroke-rect nk:stroke-rect
+Builtin stroke-tri nk:stroke-tri style-from-table nk:style-from-table swipe nk:swipe swipe-dir-threshold nk:swipe-dir-threshold
+Builtin swipe-threshold nk:swipe-threshold text nk:text text-align nk:text-align text-font nk:text-font
+Builtin text-pad nk:text-pad text? nk:text? timer-delay nk:timer-delay timer? nk:timer? toast nk:toast
+Builtin tooltip nk:tooltip translate nk:translate tree-pop nk:tree-pop tree-state-push nk:tree-state-push
+Builtin triangle nk:triangle use-style nk:use-style vsync nk:vsync widget nk:widget widget-bounds nk:widget-bounds
Builtin widget-disable nk:widget-disable widget-fitting nk:widget-fitting widget-high nk:widget-high
Builtin widget-hovered? nk:widget-hovered? widget-mouse-click-down? nk:widget-mouse-click-down? widget-mouse-clicked? nk:widget-mouse-clicked?
-Builtin widget-pos nk:widget-pos widget-size nk:widget-size widget-size nk:widget-size widget-wide nk:widget-wide
-Builtin win nk:win win-bounds nk:win-bounds win-bounds! nk:win-bounds! win-close nk:win-close win-closed? nk:win-closed?
-Builtin win-collapse nk:win-collapse win-collapsed? nk:win-collapsed? win-content-bounds nk:win-content-bounds
+Builtin widget-pos nk:widget-pos widget-size nk:widget-size widget-size-allot nk:widget-size-allot
+Builtin widget-wide nk:widget-wide win nk:win win-bounds nk:win-bounds win-bounds! nk:win-bounds! win-close nk:win-close
+Builtin win-closed? nk:win-closed? win-collapse nk:win-collapse win-collapsed? nk:win-collapsed? win-content-bounds nk:win-content-bounds
Builtin win-focus nk:win-focus win-focused? nk:win-focused? win-hidden? nk:win-hidden? win-high nk:win-high
-Builtin win-hovered? nk:win-hovered? win-pos nk:win-pos win-scroll-ofs nk:win-scroll-ofs win-scroll-ofs! nk:win-scroll-ofs!
-Builtin win-show nk:win-show win-size nk:win-size win-wide nk:win-wide win? nk:win? x>pt nk:x>pt x>rect nk:x>rect
-Builtin MAX ns:MAX ! o:! + o:+ +? o:+? ??? o:??? @ o:@ class o:class exec o:exec isa o:isa method o:method
-Builtin mutate o:mutate new o:new super o:super chroot os:chroot devname os:devname docker? os:docker?
-Builtin env os:env lang os:lang locales os:locales notify os:notify power-state os:power-state region os:region
-Builtin waitpid os:waitpid bezier pdf:bezier bezierq pdf:bezierq circle pdf:circle color pdf:color
-Builtin ellipse pdf:ellipse font pdf:font img pdf:img line pdf:line new pdf:new page pdf:page page-size pdf:page-size
-Builtin rect pdf:rect save pdf:save size pdf:size text pdf:text text-rotate pdf:text-rotate text-size pdf:text-size
-Builtin text-width pdf:text-width text-wrap pdf:text-wrap text-wrap-rotate pdf:text-wrap-rotate cast ptr:cast
+Builtin win-hovered? nk:win-hovered? win-icon! nk:win-icon! win-pos nk:win-pos win-scroll-ofs nk:win-scroll-ofs
+Builtin win-scroll-ofs! nk:win-scroll-ofs! win-show nk:win-show win-size nk:win-size win-title! nk:win-title!
+Builtin win-wide nk:win-wide win? nk:win? MAX ns:MAX ! o:! + o:+ +? o:+? ??? o:??? @ o:@ class o:class
+Builtin exec o:exec isa o:isa method o:method mutate o:mutate new o:new super o:super POSIX os:POSIX
+Builtin chroot os:chroot devname os:devname docker? os:docker? env os:env lang os:lang locales os:locales
+Builtin notify os:notify power-state os:power-state region os:region waitpid os:waitpid bezier pdf:bezier
+Builtin bezierq pdf:bezierq circle pdf:circle color pdf:color ellipse pdf:ellipse font pdf:font img pdf:img
+Builtin line pdf:line new pdf:new page pdf:page page-size pdf:page-size rect pdf:rect save pdf:save
+Builtin size pdf:size text pdf:text text-rotate pdf:text-rotate text-size pdf:text-size text-width pdf:text-width
+Builtin text-wrap pdf:text-wrap text-wrap-rotate pdf:text-wrap-rotate cast ptr:cast deref ptr:deref
Builtin len ptr:len null? ptr:null? pack ptr:pack unpack ptr:unpack unpack_orig ptr:unpack_orig publish pubsub:publish
Builtin qsize pubsub:qsize subscribe pubsub:subscribe + q:+ clear q:clear len q:len new q:new notify q:notify
Builtin overwrite q:overwrite peek q:peek pick q:pick pop q:pop push q:push remove q:remove shift q:shift
Builtin size q:size slide q:slide throwing q:throwing wait q:wait ++match r:++match +/ r:+/ +match r:+match
-Builtin / r:/ @ r:@ len r:len match r:match new r:new rx r:rx str r:str * rat:* + rat:+ - rat:- / rat:/
-Builtin >n rat:>n >s rat:>s new rat:new proper rat:proper ! s:! * s:* + s:+ - s:- / s:/ /scripts s:/scripts
-Builtin <+ s:<+ <> s:<> = s:= =ic s:=ic >base64 s:>base64 >ucs2 s:>ucs2 @ s:@ append s:append base64> s:base64>
-Builtin clear s:clear cmp s:cmp cmpi s:cmpi compress s:compress count-match s:count-match days! s:days!
-Builtin dist s:dist each s:each each! s:each! eachline s:eachline escape s:escape expand s:expand fill s:fill
-Builtin fold s:fold globmatch s:globmatch hexupr s:hexupr insert s:insert intl s:intl intl! s:intl!
-Builtin lang s:lang lc s:lc lc? s:lc? len s:len lsub s:lsub ltrim s:ltrim map s:map months! s:months!
-Builtin n> s:n> new s:new norm s:norm reduce s:reduce repinsert s:repinsert replace s:replace replace! s:replace!
-Builtin rev s:rev rsearch s:rsearch rsub s:rsub rtrim s:rtrim scan-match s:scan-match script? s:script?
-Builtin search s:search size s:size slice s:slice soundex s:soundex strfmap s:strfmap strfmt s:strfmt
-Builtin term s:term text-wrap s:text-wrap tr s:tr translate s:translate trim s:trim tsub s:tsub uc s:uc
-Builtin uc? s:uc? ucs2> s:ucs2> utf8? s:utf8? zt s:zt close sio:close enum sio:enum open sio:open opts! sio:opts!
-Builtin opts@ sio:opts@ read sio:read write sio:write @ slv:@ auto slv:auto build slv:build constraint slv:constraint
-Builtin dump slv:dump edit slv:edit named-variable slv:named-variable new slv:new relation slv:relation
-Builtin reset slv:reset suggest slv:suggest term slv:term update slv:update v[] slv:v[] variable slv:variable
-Builtin v{} slv:v{} new smtp:new send smtp:send apply-filter snd:apply-filter devices? snd:devices?
-Builtin end-record snd:end-record filter snd:filter freq snd:freq gain snd:gain gain? snd:gain? init snd:init
-Builtin len snd:len loop snd:loop loop? snd:loop? mix snd:mix new snd:new pause snd:pause play snd:play
-Builtin played snd:played rate snd:rate ready? snd:ready? record snd:record resume snd:resume seek snd:seek
-Builtin stop snd:stop stopall snd:stopall volume snd:volume volume? snd:volume? + st:+ . st:. clear st:clear
-Builtin len st:len ndrop st:ndrop new st:new op! st:op! peek st:peek pick st:pick pop st:pop push st:push
-Builtin roll st:roll shift st:shift size st:size slide st:slide swap st:swap throwing st:throwing >buf struct:>buf
-Builtin arr> struct:arr> buf struct:buf buf> struct:buf> byte struct:byte double struct:double field! struct:field!
+Builtin / r:/ @ r:@ len r:len match r:match match[] r:match[] matchall[] r:matchall[] new r:new rx r:rx
+Builtin str r:str * rat:* + rat:+ - rat:- / rat:/ >n rat:>n >s rat:>s new rat:new proper rat:proper
+Builtin ! rect:! /high rect:/high /wide rect:/wide = rect:= >a rect:>a >pts rect:>pts >pts4 rect:>pts4
+Builtin @ rect:@ center rect:center center-pt rect:center-pt intersect rect:intersect new rect:new
+Builtin new-pt rect:new-pt ofs rect:ofs open rect:open pad rect:pad pos rect:pos pt-open rect:pt-open
+Builtin pt>a rect:pt>a pt>rect rect:pt>rect pts> rect:pts> restrict rect:restrict shrink rect:shrink
+Builtin size rect:size union rect:union ! s:! * s:* + s:+ - s:- / s:/ /scripts s:/scripts /ws s:/ws
+Builtin 2len s:2len <+ s:<+ <> s:<> = s:= =ic s:=ic >base64 s:>base64 >ucs2 s:>ucs2 @ s:@ _len s:_len
+Builtin append s:append base64> s:base64> clear s:clear cmp s:cmp cmpi s:cmpi compress s:compress count-match s:count-match
+Builtin days! s:days! dist s:dist each s:each each! s:each! eachline s:eachline escape s:escape expand s:expand
+Builtin fill s:fill fold s:fold gen-uid s:gen-uid globmatch s:globmatch hexupr s:hexupr insert s:insert
+Builtin intl s:intl intl! s:intl! lang s:lang lc s:lc lc? s:lc? len s:len lsub s:lsub ltrim s:ltrim
+Builtin map s:map months! s:months! n> s:n> new s:new norm s:norm reduce s:reduce repinsert s:repinsert
+Builtin replace s:replace replace! s:replace! rev s:rev rsearch s:rsearch rsub s:rsub rtl s:rtl rtrim s:rtrim
+Builtin scan-match s:scan-match script? s:script? search s:search size s:size slice s:slice soundex s:soundex
+Builtin strfmap s:strfmap strfmt s:strfmt term s:term text-wrap s:text-wrap tr s:tr translate s:translate
+Builtin trim s:trim tsub s:tsub uc s:uc uc? s:uc? ucs2> s:ucs2> utf8? s:utf8? zt s:zt close sio:close
+Builtin enum sio:enum open sio:open opts! sio:opts! opts@ sio:opts@ read sio:read write sio:write @ slv:@
+Builtin auto slv:auto build slv:build constraint slv:constraint dump slv:dump edit slv:edit named-variable slv:named-variable
+Builtin new slv:new relation slv:relation reset slv:reset suggest slv:suggest term slv:term update slv:update
+Builtin v[] slv:v[] variable slv:variable v{} slv:v{} new smtp:new send smtp:send apply-filter snd:apply-filter
+Builtin devices? snd:devices? end-record snd:end-record filter snd:filter freq snd:freq gain snd:gain
+Builtin gain? snd:gain? init snd:init len snd:len loop snd:loop loop? snd:loop? mix snd:mix new snd:new
+Builtin pause snd:pause play snd:play played snd:played rate snd:rate ready? snd:ready? record snd:record
+Builtin resume snd:resume seek snd:seek stop snd:stop stopall snd:stopall volume snd:volume volume? snd:volume?
+Builtin + st:+ . st:. clear st:clear dot-depth st:dot-depth len st:len list st:list ndrop st:ndrop
+Builtin new st:new op! st:op! peek st:peek pick st:pick pop st:pop push st:push roll st:roll shift st:shift
+Builtin size st:size slide st:slide swap st:swap throwing st:throwing >buf struct:>buf arr> struct:arr>
+Builtin buf struct:buf buf> struct:buf> byte struct:byte double struct:double field! struct:field!
Builtin field@ struct:field@ float struct:float ignore struct:ignore int struct:int long struct:long
-Builtin struct; struct:struct; word struct:word ! t:! @ t:@ by-name t:by-name cor t:cor cor-drop t:cor-drop
-Builtin curtask t:curtask def-queue t:def-queue def-stack t:def-stack done? t:done? dtor t:dtor err! t:err!
-Builtin err? t:err? errno? t:errno? extra t:extra getq t:getq handler t:handler handler@ t:handler@
-Builtin kill t:kill list t:list main t:main max-exceptions t:max-exceptions name! t:name! name@ t:name@
-Builtin notify t:notify parent t:parent pop t:pop priority t:priority push t:push push! t:push! q-notify t:q-notify
-Builtin q-wait t:q-wait qlen t:qlen result t:result set-affinity t:set-affinity setq t:setq start t:start
-Builtin task t:task task-n t:task-n task-stop t:task-stop ticks t:ticks wait t:wait yield t:yield yield! t:yield!
-Builtin add tree:add binary tree:binary bk tree:bk btree tree:btree cmp! tree:cmp! data tree:data del tree:del
-Builtin find tree:find iter tree:iter next tree:next nodes tree:nodes parent tree:parent parse tree:parse
-Builtin prev tree:prev root tree:root search tree:search trie tree:trie ! w:! (is) w:(is) @ w:@ alias: w:alias:
-Builtin cb w:cb deprecate w:deprecate dlcall w:dlcall dlopen w:dlopen dlsym w:dlsym exec w:exec exec? w:exec?
-Builtin ffifail w:ffifail find w:find forget w:forget is w:is name w:name undo w:undo close ws:close
-Builtin decode ws:decode encode ws:encode encode-nomask ws:encode-nomask gen-accept-header ws:gen-accept-header
+Builtin struct; struct:struct; word struct:word ! t:! @ t:@ by-name t:by-name curtask t:curtask def-queue t:def-queue
+Builtin def-stack t:def-stack done? t:done? dtor t:dtor err! t:err! err? t:err? errno? t:errno? extra t:extra
+Builtin getq t:getq handler t:handler handler@ t:handler@ kill t:kill list t:list main t:main max-exceptions t:max-exceptions
+Builtin name! t:name! name@ t:name@ notify t:notify parent t:parent pop t:pop priority t:priority push t:push
+Builtin push! t:push! q-notify t:q-notify q-wait t:q-wait qlen t:qlen result t:result set-affinity t:set-affinity
+Builtin setq t:setq task t:task task-n t:task-n task-stop t:task-stop ticks t:ticks wait t:wait add tree:add
+Builtin binary tree:binary bk tree:bk btree tree:btree cmp! tree:cmp! data tree:data del tree:del find tree:find
+Builtin iter tree:iter next tree:next nodes tree:nodes parent tree:parent parse tree:parse prev tree:prev
+Builtin root tree:root search tree:search trie tree:trie ! w:! (is) w:(is) @ w:@ alias: w:alias: cb w:cb
+Builtin deprecate w:deprecate dlcall w:dlcall dlopen w:dlopen dlsym w:dlsym exec w:exec exec? w:exec?
+Builtin ffifail w:ffifail find w:find forget w:forget is w:is name w:name undo w:undo xt w:xt xt> w:xt>
+Builtin close ws:close decode ws:decode encode ws:encode encode-nomask ws:encode-nomask gen-accept-header ws:gen-accept-header
Builtin gen-accept-key ws:gen-accept-key opcodes ws:opcodes open ws:open >s xml:>s >txt xml:>txt md-init xml:md-init
Builtin md-parse xml:md-parse parse xml:parse parse-html xml:parse-html parse-stream xml:parse-stream
Builtin getmsg[] zmq:getmsg[] sendmsg[] zmq:sendmsg[]
@@ -413,8 +426,9 @@ syn match eighthBuiltin /db:bind-exec\[]/
syn match eighthBuiltin /db:exec\[]/
syn match eighthBuiltin /db:col\[]/
-" TODO
-syn region eighthComment start="\zs\\" end="$" contains=eighthTodo
+syn region eighthComment start="\zs\\" end="$" contains=eighthTodo,@Spell
+syn region eighthComment start="\zs--\s" end="$" contains=eighthTodo,@Spell
+syn region eighthComment start="\zs(\*\_[:space:]" end="\_[:space:]\*)\ze" contains=eightTodo,@Spell
" The default methods for highlighting. Can be overriden later.
hi def link eighthTodo Todo
@@ -452,6 +466,7 @@ hi def link jsonArray Special
hi def link jsonNull Function
hi def link jsonBool Boolean
+delcommand Builtin
let b:current_syntax = "8th"
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/syntax/awk.vim b/runtime/syntax/awk.vim
index 3082c1cb5c..4e7c0d1e72 100644
--- a/runtime/syntax/awk.vim
+++ b/runtime/syntax/awk.vim
@@ -2,7 +2,7 @@
" Language: awk, nawk, gawk, mawk
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Antonio Colombo <azc100@gmail.com>
-" Last Change: 2020 Aug 18
+" Last Change: 2024 Oct 28
" AWK ref. is: Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger
" The AWK Programming Language, Addison-Wesley, 1988
@@ -92,7 +92,7 @@ syn match awkSpecialCharacter display contained "\\x[0-9A-Fa-f]\+"
syn match awkFieldVars "\$\d\+"
" catch errors caused by wrong parenthesis
-syn region awkParen transparent start="(" end=")" contains=ALLBUT,awkParenError,awkSpecialCharacter,awkArrayElement,awkArrayArray,awkTodo,awkRegExp,awkBrktRegExp,awkBrackets,awkCharClass,awkComment
+syn region awkParen transparent start="(" end=")" contains=ALLBUT,awkParenError,awkSpecialCharacter,awkArrayElement,awkArrayArray,awkTodo,awkRegExp,awkBrktRegExp,awkBrackets,awkCharClass
syn match awkParenError display ")"
"syn match awkInParen display contained "[{}]"
diff --git a/runtime/syntax/cfg.vim b/runtime/syntax/cfg.vim
index f347b1379f..4b5ebf5c25 100644
--- a/runtime/syntax/cfg.vim
+++ b/runtime/syntax/cfg.vim
@@ -2,6 +2,7 @@
" Language: Good old CFG files
" Maintainer: Igor N. Prischepoff (igor@tyumbit.ru, pri_igor@mail.ru)
" Last change: 2012 Aug 11
+" 2024 Nov 14 by Vim project: // only denotes a comment when starting a line (#16051)
" quit when a syntax file was already loaded
if exists ("b:current_syntax")
@@ -27,17 +28,17 @@ syn match CfgSection "{.*}"
syn match CfgString "\".*\"" contained
syn match CfgString "'.*'" contained
-" Comments (Everything before '#' or '//' or ';')
+" Comments (Everything before '#' or ';' or leading '//')
syn match CfgComment "#.*"
syn match CfgComment ";.*"
-syn match CfgComment "\/\/.*"
+syn match CfgComment "^\s*\/\/.*"
" Define the default highlighting.
" Only when an item doesn't have highlighting yet
hi def link CfgOnOff Label
-hi def link CfgComment Comment
-hi def link CfgSection Type
-hi def link CfgString String
+hi def link CfgComment Comment
+hi def link CfgSection Type
+hi def link CfgString String
hi def link CfgParams Keyword
hi def link CfgValues Constant
hi def link CfgDirectory Directory
diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim
index fd128bb0b5..c8ad8bfe4a 100644
--- a/runtime/syntax/help.vim
+++ b/runtime/syntax/help.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Vim help file
" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2024 Oct 05
+" Last Change: 2024 Oct 16
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" Quit when a (custom) syntax file was already loaded
@@ -43,7 +43,8 @@ syn match helpOption "'[a-z]\{2,\}'"
syn match helpOption "'t_..'"
syn match helpNormal "'ab'"
syn match helpCommand "`[^` \t]\+`"hs=s+1,he=e-1 contains=helpBacktick
-syn match helpCommand "\(^\|[^a-z"[]\)\zs`[^`]\+`\ze\([^a-z\t."']\|$\)"hs=s+1,he=e-1 contains=helpBacktick
+" doesn't allow a . directly after an ending backtick. See :helpgrep `[^`,]\+ [^`,]\+`\.
+syn match helpCommand "\(^\|[^a-z"[]\)\zs`[^`]\+`\ze\([^a-z\t."']\|[.?!]\?$\)"hs=s+1,he=e-1 contains=helpBacktick
syn match helpHeader "\s*\zs.\{-}\ze\s\=\~$" nextgroup=helpIgnore
syn match helpGraphic ".* \ze`$" nextgroup=helpIgnore
if has("conceal")
@@ -52,6 +53,7 @@ else
syn match helpIgnore "." contained
endif
syn keyword helpNote note Note NOTE note: Note: NOTE: Notes Notes:
+syn match helpNote "\c(note\(:\|\>\)"ms=s+1
syn keyword helpWarning WARNING WARNING: Warning:
syn keyword helpDeprecated DEPRECATED DEPRECATED: Deprecated:
syn match helpSpecial "\<N\>"
@@ -64,6 +66,10 @@ syn match helpSpecial "\[N]"
syn match helpSpecial "N N"he=s+1
syn match helpSpecial "Nth"me=e-2
syn match helpSpecial "N-1"me=e-2
+" highlighting N for :resize in windows.txt
+syn match helpSpecial "] -N\>"ms=s+3
+syn match helpSpecial "+N\>"ms=s+1
+syn match helpSpecial "\[+-]N\>"ms=s+4
" highlighting N of cinoptions-values in indent.txt
syn match helpSpecial "^\t-\?\zsNs\?\s"me=s+1
" highlighting N of cinoptions-values in indent.txt
@@ -92,6 +98,7 @@ syn match helpSpecial "\[group]"
syn match helpNormal "\[\(readonly\|fifo\|socket\|converted\|crypted\)]"
syn match helpSpecial "CTRL-."
+syn match helpSpecial "CTRL-<\a\+>"
syn match helpSpecial "CTRL-SHIFT-."
syn match helpSpecial "CTRL-Break"
syn match helpSpecial "CTRL-PageUp"
@@ -138,7 +145,7 @@ syn match helpUnderlined "\t[* ]Underlined\t\+[a-z].*"
syn match helpError "\t[* ]Error\t\+[a-z].*"
syn match helpTodo "\t[* ]Todo\t\+[a-z].*"
-syn match helpURL `\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^' <>"]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^' <>"]+)[a-zA-Z0-9/]`
+syn match helpURL `\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^'" \t<>{}]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^'" \t<>{}]+)[a-zA-Z0-9/]`
syn match helpDiffAdded "\t[* ]Added\t\+[a-z].*"
syn match helpDiffChanged "\t[* ]Changed\t\+[a-z].*"
@@ -150,16 +157,6 @@ if s:i > 0
exe "runtime syntax/help_" . strpart(expand("%"), s:i + 1, 2) . ".vim"
endif
-" Italian
-if v:lang =~ '\<IT\>' || v:lang =~ '_IT\>' || v:lang =~? "italian"
- syn keyword helpNote nota Nota NOTA nota: Nota: NOTA: notare Notare NOTARE notare: Notare: NOTARE:
- syn match helpSpecial "Nma"me=e-2
- syn match helpSpecial "Nme"me=e-2
- syn match helpSpecial "Nmi"me=e-2
- syn match helpSpecial "Nmo"me=e-2
- syn match helpSpecial "\[interv.]"
-endif
-
syn sync minlines=40
diff --git a/runtime/syntax/help_it.vim b/runtime/syntax/help_it.vim
new file mode 100644
index 0000000000..e76851d446
--- /dev/null
+++ b/runtime/syntax/help_it.vim
@@ -0,0 +1,17 @@
+" Vim syntax file
+" Language: Italian Vim program help files *.itx
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2024 Oct 16
+"
+" This script is sourced from syntax/help.vim.
+
+syn keyword helpNote nota Nota NOTA nota: Nota: NOTA: notare Notare NOTARE notare: Notare: NOTARE:
+syn match helpNote "\c(nota\(:\|\>\)"ms=s+1
+syn match helpSpecial "Nma"me=e-2
+syn match helpSpecial "Nme"me=e-2
+syn match helpSpecial "Nmi"me=e-2
+syn match helpSpecial "Nmo"me=e-2
+syn match helpSpecial "\[interv.]"
+syn region helpNotVi start="{non" start="{solo" start="{disponibile" end="}" contains=helpLeadBlank,helpHyperTextJump
+
+" vim: ts=8 sw=2
diff --git a/runtime/syntax/idris2.vim b/runtime/syntax/idris2.vim
new file mode 100644
index 0000000000..e3e3d0dcee
--- /dev/null
+++ b/runtime/syntax/idris2.vim
@@ -0,0 +1,86 @@
+" Vim syntax file
+" Language: Idris 2
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" Last Change: 2024 Nov 05
+" Original Author: raichoo (raichoo@googlemail.com)
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+"
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn match idris2TypeDecl "[a-zA-Z][a-zA-z0-9_']*\s\+:\s\+" contains=idris2Identifier,idris2Operators
+syn region idris2Parens matchgroup=idris2Delimiter start="(" end=")" contains=TOP,idris2TypeDecl
+syn region idris2Brackets matchgroup=idris2Delimiter start="\[" end="]" contains=TOP,idris2TypeDecl
+syn region idris2Block matchgroup=idris2Delimiter start="{" end="}" contains=TOP,idris2TypeDecl
+syn region idris2SnocBrackets matchgroup=idris2Delimiter start="\[<" end="]" contains=TOP
+syn region idris2ListBrackets matchgroup=idris2Delimiter start="\[>" end="]" contains=TOP
+syn keyword idris2Module module namespace
+syn keyword idris2Import import
+syn keyword idris2Structure data record interface implementation
+syn keyword idris2Where where
+syn keyword idris2Visibility public abstract private export
+syn keyword idris2Block parameters mutual using
+syn keyword idris2Totality total partial covering
+syn keyword idris2Annotation auto impossible default constructor
+syn keyword idris2Statement do case of rewrite with proof
+syn keyword idris2Let let in
+syn keyword idris2Forall forall
+syn keyword idris2DataOpt noHints uniqueSearch search external noNewtype containedin=idris2Brackets
+syn keyword idris2Conditional if then else
+syn match idris2Number "\<[0-9]\+\>\|\<0[xX][0-9a-fA-F]\+\>\|\<0[oO][0-7]\+\>"
+syn match idris2Float "\<[0-9]\+\.[0-9]\+\([eE][-+]\=[0-9]\+\)\=\>"
+syn match idris2Delimiter "[,;]"
+syn keyword idris2Infix prefix infix infixl infixr
+syn match idris2Operators "\([-!#$%&\*\+./<=>\?@\\^|~:]\|\<_\>\)"
+syn match idris2Type "\<[A-Z][a-zA-Z0-9_']*\>"
+syn keyword idris2Todo TODO FIXME XXX HACK contained
+syn match idris2LineComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=idris2Todo,@Spell
+syn match idris2DocComment "|||\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=idris2Todo,@Spell
+syn match idris2MetaVar "?[a-zA-Z_][A-Za-z0-9_']*"
+syn match idris2Pragma "%\(hide\|logging\|auto_lazy\|unbound_implicits\|prefix_record_projections\|ambiguity_depth\|nf_metavar_threshold\|search_timeout\|pair\|rewrite\|integerLit\|stringLit\|charLit\|doubleLit\|name\|start\|allow_overloads\|language\|default\|transform\|hint\|globalhint\|defaulthint\|inline\|noinline\|extern\|macro\|spec\|foreign\|nomangle\|builtin\|MkWorld\|World\|search\|runElab\|tcinline\|auto_implicit_depth\)"
+syn match idris2Char "'[^'\\]'\|'\\.'\|'\\u[0-9a-fA-F]\{4}'"
+syn match idris2Backtick "`[A-Za-z][A-Za-z0-9_']*`"
+syn region idris2String start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell
+syn region idris2BlockComment start="{-" end="-}" contains=idris2BlockComment,idris2Todo,@Spell
+syn match idris2Identifier "[a-zA-Z][a-zA-z0-9_']*" contained
+
+" Default Highlighting {{{1
+
+highlight def link idris2Deprecated Error
+highlight def link idris2Identifier Identifier
+highlight def link idris2Import Structure
+highlight def link idris2Module Structure
+highlight def link idris2Structure Structure
+highlight def link idris2Statement Statement
+highlight def link idris2Forall Structure
+highlight def link idris2DataOpt Statement
+highlight def link idris2DSL Statement
+highlight def link idris2Block Statement
+highlight def link idris2Annotation Statement
+highlight def link idris2Where Structure
+highlight def link idris2Let Structure
+highlight def link idris2Totality Statement
+highlight def link idris2Visibility Statement
+highlight def link idris2Conditional Conditional
+highlight def link idris2Pragma Statement
+highlight def link idris2Number Number
+highlight def link idris2Float Float
+highlight def link idris2Delimiter Delimiter
+highlight def link idris2Infix PreProc
+highlight def link idris2Operators Operator
+highlight def link idris2Type Include
+highlight def link idris2DocComment Comment
+highlight def link idris2LineComment Comment
+highlight def link idris2BlockComment Comment
+highlight def link idris2Todo Todo
+highlight def link idris2MetaVar Macro
+highlight def link idris2String String
+highlight def link idris2Char String
+highlight def link idris2Backtick Operator
+
+let b:current_syntax = "idris2"
+
+" vim: nowrap sw=2 sts=2 ts=8 noexpandtab ft=vim
diff --git a/runtime/syntax/ipkg.vim b/runtime/syntax/ipkg.vim
new file mode 100644
index 0000000000..218c243983
--- /dev/null
+++ b/runtime/syntax/ipkg.vim
@@ -0,0 +1,66 @@
+" Vim syntax file
+" Language: Ipkg
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" Last Change: 2020 May 19
+" Version: 0.1
+" Author: ShinKage
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+"
+" Syntax highlight for Idris 2 Package Descriptors (idris-lang.org)
+"
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" we want to use line continuations (\) BEGINNING
+let s:cpo_save = &cpo
+set cpo&vim
+
+syn keyword ipkgKey
+ \ package
+ \ authors
+ \ maintainers
+ \ license
+ \ brief
+ \ readme
+ \ homepage
+ \ sourceloc
+ \ bugtracker
+ \ options
+ \ opts
+ \ sourcedir
+ \ builddir
+ \ outputdir
+ \ prebuild
+ \ postbuild
+ \ preinstall
+ \ postinstall
+ \ preclean
+ \ postclean
+ \ version
+ \ langversion
+ \ modules
+ \ main
+ \ executable
+ \ depends
+
+" we want to use line continuations (\) END
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+syn region ipkgString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell
+syn match ipkgVersion "[0-9]*\([.][0-9]*\)*"
+syn match ipkgName "[a-zA-Z][a-zA-z0-9_']*\([.][a-zA-Z][a-zA-z0-9_']*\)*" contained
+syn match ipkgOperator "\(,\|&&\|<\|<=\|==\|>=\|>\)"
+syn match ipkgComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=@Spell
+
+highlight def link ipkgKey Statement
+highlight def link ipkgString String
+highlight def link ipkgVersion Number
+highlight def link ipkgName Identifier
+highlight def link ipkgOperator Operator
+highlight def link ipkgComment Comment
+
+let b:current_syntax = "ipkg"
diff --git a/runtime/syntax/java.vim b/runtime/syntax/java.vim
index 307fc26349..b3e17b55f6 100644
--- a/runtime/syntax/java.vim
+++ b/runtime/syntax/java.vim
@@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://github.com/zzzyxwvut/java-vim.git
-" Last Change: 2024 Oct 03
+" Last Change: 2024 Oct 10
" Please check ":help java.vim" for comments on some of the options
" available.
@@ -724,10 +724,15 @@ if exists("g:java_highlight_debug")
hi def link DebugType Type
endif
+" Complement javaBlock and javaInParen for highlighting.
+syn region javaBlockOther transparent matchgroup=javaBlockOtherStart start="{" end="}"
+
" Try not to fold top-level-type bodies under assumption that there is
" but one such body.
-exec 'syn region javaBlock transparent start="\%(^\|^\S[^:]\+\)\@' . s:ff.Peek('120', '') . '<!{" end="}" fold'
+exec 'syn region javaBlock transparent matchgroup=javaBlockStart start="\%(^\|^\S[^:]\+\)\@' . s:ff.Peek('120', '') . '<!{" end="}" fold'
+" See "D.2.1 Anonymous Classes" at
+" https://web.archive.org/web/20010821025330/java.sun.com/docs/books/jls/first_edition/html/1.1Update.html#12959.
if exists("g:java_mark_braces_in_parens_as_errors")
syn match javaInParen contained "[{}]"
hi def link javaInParen javaError
diff --git a/runtime/syntax/jinja.vim b/runtime/syntax/jinja.vim
index 6000855ff7..fa32c05f17 100644
--- a/runtime/syntax/jinja.vim
+++ b/runtime/syntax/jinja.vim
@@ -2,8 +2,9 @@
" Language: Jinja
" Maintainer: Gregory Anders
" Upstream: https://gitlab.com/HiPhish/jinja.vim
+" Last Change: 2024 Oct 16
-if exists('b:current_syntax')
+if exists('b:current_syntax') && b:current_syntax =~? 'jinja'
finish
endif
diff --git a/runtime/syntax/lf.vim b/runtime/syntax/lf.vim
new file mode 100644
index 0000000000..e4cf014865
--- /dev/null
+++ b/runtime/syntax/lf.vim
@@ -0,0 +1,236 @@
+" Vim syntax file
+" Language: lf file manager configuration file (lfrc)
+" Maintainer: Andis Sprinkis <andis@sprinkis.com>
+" Former Maintainer: Cameron Wright
+" Former URL: https://github.com/andis-sprinkis/lf-vim
+" Last Change: 13 October 2024
+"
+" The shell syntax highlighting is configurable. See $VIMRUNTIME/doc/syntax.txt
+" lf version: 32
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let b:current_syntax = "lf"
+
+"{{{ Comment Matching
+syn match lfComment '#.*$'
+"}}}
+
+"{{{ String Matching
+syn match lfString "'.*'"
+syn match lfString '".*"' contains=lfVar,lfSpecial
+"}}}
+
+"{{{ Match lf Variables
+syn match lfVar '\$f\|\$fx\|\$fs\|\$id'
+"}}}
+
+"{{{ Keywords
+syn keyword lfKeyword set setlocal cmd map cmap skipwhite
+"}}}
+
+"{{{ Options Keywords
+syn keyword lfOptions
+ \ quit
+ \ up
+ \ half-up
+ \ page-up
+ \ scroll-up
+ \ down
+ \ half-down
+ \ page-down
+ \ scroll-down
+ \ updir
+ \ open
+ \ jump-next
+ \ jump-prev
+ \ top
+ \ bottom
+ \ high
+ \ middle
+ \ low
+ \ toggle
+ \ invert
+ \ invert-below
+ \ unselect
+ \ glob-select
+ \ glob-unselect
+ \ calcdirsize
+ \ clearmaps
+ \ copy
+ \ cut
+ \ paste
+ \ clear
+ \ sync
+ \ draw
+ \ redraw
+ \ load
+ \ reload
+ \ echo
+ \ echomsg
+ \ echoerr
+ \ cd
+ \ select
+ \ delete
+ \ rename
+ \ source
+ \ push
+ \ read
+ \ shell
+ \ shell-pipe
+ \ shell-wait
+ \ shell-async
+ \ find
+ \ find-back
+ \ find-next
+ \ find-prev
+ \ search
+ \ search-back
+ \ search-next
+ \ search-prev
+ \ filter
+ \ setfilter
+ \ mark-save
+ \ mark-load
+ \ mark-remove
+ \ tag
+ \ tag-toggle
+ \ cmd-escape
+ \ cmd-complete
+ \ cmd-menu-complete
+ \ cmd-menu-complete-back
+ \ cmd-menu-accept
+ \ cmd-enter
+ \ cmd-interrupt
+ \ cmd-history-next
+ \ cmd-history-prev
+ \ cmd-left
+ \ cmd-right
+ \ cmd-home
+ \ cmd-end
+ \ cmd-delete
+ \ cmd-delete-back
+ \ cmd-delete-home
+ \ cmd-delete-end
+ \ cmd-delete-unix-word
+ \ cmd-yank
+ \ cmd-transpose
+ \ cmd-transpose-word
+ \ cmd-word
+ \ cmd-word-back
+ \ cmd-delete-word
+ \ cmd-delete-word-back
+ \ cmd-capitalize-word
+ \ cmd-uppercase-word
+ \ cmd-lowercase-word
+ \ anchorfind
+ \ autoquit
+ \ borderfmt
+ \ cleaner
+ \ copyfmt
+ \ cursoractivefmt
+ \ cursorparentfmt
+ \ cursorpreviewfmt
+ \ cutfmt
+ \ dircache
+ \ dircounts
+ \ dirfirst
+ \ dironly
+ \ dirpreviews
+ \ drawbox
+ \ dupfilefmt
+ \ errorfmt
+ \ filesep
+ \ findlen
+ \ globfilter
+ \ globsearch
+ \ hidden
+ \ hiddenfiles
+ \ hidecursorinactive
+ \ history
+ \ icons
+ \ ifs
+ \ ignorecase
+ \ ignoredia
+ \ incfilter
+ \ incsearch
+ \ info
+ \ infotimefmtnew
+ \ infotimefmtold
+ \ mouse
+ \ number
+ \ numberfmt
+ \ period
+ \ preserve
+ \ preview
+ \ previewer
+ \ promptfmt
+ \ ratios
+ \ relativenumber
+ \ reverse
+ \ roundbox
+ \ ruler
+ \ rulerfmt
+ \ scrolloff
+ \ selectfmt
+ \ selmode
+ \ shell
+ \ shellflag
+ \ shellopts
+ \ sixel
+ \ smartcase
+ \ smartdia
+ \ sortby
+ \ statfmt
+ \ tabstop
+ \ tagfmt
+ \ tempmarks
+ \ timefmt
+ \ truncatechar
+ \ truncatepct
+ \ waitmsg
+ \ wrapscan
+ \ wrapscroll
+ \ pre-cd
+ \ on-cd
+ \ on-select
+ \ on-redraw
+ \ on-quit
+"}}}
+
+"{{{ Special Matching
+syn match lfSpecial '<.*>\|\\.'
+"}}}
+
+"{{{ Shell Script Matching for cmd
+let s:shell_syntax = get(g:, 'lf_shell_syntax', "syntax/sh.vim")
+let s:shell_syntax = get(b:, 'lf_shell_syntax', s:shell_syntax)
+unlet b:current_syntax
+exe 'syn include @Shell '.s:shell_syntax
+let b:current_syntax = "lf"
+syn region lfIgnore start=".{{\n" end="^}}"
+ \ keepend contains=lfExternalShell,lfExternalPatch
+syn match lfShell '\$[a-zA-Z].*$
+ \\|:[a-zA-Z].*$
+ \\|%[a-zA-Z].*$
+ \\|![a-zA-Z].*$
+ \\|&[a-zA-Z].*$'
+ \ transparent contains=@Shell,lfExternalPatch
+syn match lfExternalShell "^.*$" transparent contained contains=@Shell
+syn match lfExternalPatch "^\s*cmd\ .*\ .{{$\|^}}$" contained
+"}}}
+
+"{{{ Link Highlighting
+hi def link lfComment Comment
+hi def link lfVar Type
+hi def link lfSpecial Special
+hi def link lfString String
+hi def link lfKeyword Statement
+hi def link lfOptions Constant
+hi def link lfConstant Constant
+hi def link lfExternalShell Normal
+hi def link lfExternalPatch Special
+hi def link lfIgnore Special
+"}}}
diff --git a/runtime/syntax/lidris2.vim b/runtime/syntax/lidris2.vim
new file mode 100644
index 0000000000..328ffdf685
--- /dev/null
+++ b/runtime/syntax/lidris2.vim
@@ -0,0 +1,25 @@
+" Vim syntax file
+" Language: Literate Idris 2
+" Maintainer: Idris Hackers (https://github.com/edwinb/idris2-vim), Serhii Khoma <srghma@gmail.com>
+" Last Change: 2020 May 19
+" Version: 0.1
+" License: Vim (see :h license)
+" Repository: https://github.com/ShinKage/idris2-nvim
+"
+" This is just a minimal adaption of the Literate Haskell syntax file.
+
+" quit when a syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+" Read Idris highlighting.
+syntax include @idris2Top syntax/idris2.vim
+
+" Recognize blocks of Bird tracks, highlight as Idris.
+syntax region lidris2BirdTrackBlock start="^>" end="\%(^[^>]\)\@=" contains=@idris2Top,lidris2BirdTrack
+syntax match lidris2BirdTrack "^>" contained
+
+hi def link lidris2BirdTrack Comment
+
+let b:current_syntax = "lidris2"
diff --git a/runtime/syntax/modula2/opt/r10.vim b/runtime/syntax/modula2/opt/r10.vim
index 775f498dfb..5172be54c6 100644
--- a/runtime/syntax/modula2/opt/r10.vim
+++ b/runtime/syntax/modula2/opt/r10.vim
@@ -157,7 +157,7 @@ syn match modula2Base16Num "0[ux][0-9A-F]\+\('[0-9A-F]\+\)*"
"| which greatly diminishes readability and thereby increases the opportunity
"| for error during maintenance. Ideally, regular expressions should be split
"| into small human readable pieces with interleaved comments that explain
-"| precisely what each piece is doing. Vimscript imposes poor design. :-(
+"| precisely what each piece is doing. Vim script imposes poor design. :-(
syn match modula2Base10Num
\ "\(\(0[bux]\@!\|[1-9]\)[0-9]*\('[0-9]\+\)*\)\(\.[0-9]\+\('[0-9]\+\)*\(e[+-]\?[0-9]\+\('[0-9]\+\)*\)\?\)\?"
diff --git a/runtime/syntax/mss.vim b/runtime/syntax/mss.vim
new file mode 100644
index 0000000000..de95d1d2ad
--- /dev/null
+++ b/runtime/syntax/mss.vim
@@ -0,0 +1,23 @@
+" Vim syntax file
+" Language: Vivado mss file
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2024 Oct 22
+" Document: https://docs.amd.com/r/2020.2-English/ug1400-vitis-embedded/Microprocessor-Software-Specification-MSS
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn case ignore
+syn match mssComment "#.*$" contains=@Spell
+syn keyword mssKeyword BEGIN END PARAMETER
+syn keyword mssType OS PROCESSOR DRIVER LIBRARY
+syn keyword mssConstant VERSION PROC_INSTANCE HW_INSTANCE OS_NAME OS_VER DRIVER_NAME DRIVER_VER LIBRARY_NAME LIBRARY_VER STDIN STDOUT XMDSTUB_PERIPHERAL ARCHIVER COMPILER COMPILER_FLAGS EXTRA_COMPILER_FLAGS
+
+hi def link mssComment Comment
+hi def link mssKeyword Keyword
+hi def link mssType Type
+hi def link mssConstant Constant
+
+let b:current_syntax = "mss"
diff --git a/runtime/syntax/nasm.vim b/runtime/syntax/nasm.vim
index e1dfc1db12..22d7c2729a 100644
--- a/runtime/syntax/nasm.vim
+++ b/runtime/syntax/nasm.vim
@@ -3,16 +3,16 @@
" Maintainer: Andrii Sokolov <andriy145@gmail.com>
" Original Author: Manuel M.H. Stol <Manuel.Stol@allieddata.nl>
" Former Maintainer: Manuel M.H. Stol <Manuel.Stol@allieddata.nl>
-" Contributors:
+" Contributors:
" Leonard König <leonard.r.koenig@gmail.com> (C string highlighting),
" Peter Stanhope <dev.rptr@gmail.com> (Add missing 64-bit mode registers)
-" Frédéric Hamel <rederic.hamel123@gmail.com> (F16c support, partial AVX
+" Frédéric Hamel <frederic.hamel123@gmail.com> (F16c support, partial AVX
" support, other)
-" Last Change: 2023 Sep 7
+" sarvel <sarvel@protonmail.com> (Complete set of supported instructions)
+" Last Change: 2024 Oct 8
" NASM Home: http://www.nasm.us/
-
" Setup Syntax:
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -22,7 +22,6 @@ endif
syn case ignore
-
" Vim search and movement commands on identifers
" Comments at start of a line inside which to skip search for indentifiers
setlocal comments=:;
@@ -89,16 +88,20 @@ syn match nasmString +\("[^"]\{-}"\|'[^']\{-}'\)+
" Highlight C escape- and format-sequences within ``-strings
syn match nasmCString +\(`[^`]\{-}`\)+ contains=nasmCStringEscape,nasmCStringFormat extend
syn case ignore
-syn match nasmBinNumber "\<[0-1]\+b\>"
-syn match nasmBinNumber "\<\~[0-1]\+b\>"lc=1
-syn match nasmOctNumber "\<\o\+q\>"
-syn match nasmOctNumber "\<\~\o\+q\>"lc=1
-syn match nasmDecNumber "\<\d\+\>"
-syn match nasmDecNumber "\<\~\d\+\>"lc=1
-syn match nasmHexNumber "\<\(\d\x*h\|0x\x\+\|\$\d\x*\)\>"
-syn match nasmHexNumber "\<\~\(\d\x*h\|0x\x\+\|\$\d\x*\)\>"lc=1
-syn match nasmFltNumber "\<\d\+\.\d*\(e[+-]\=\d\+\)\=\>"
-syn keyword nasmFltNumber Inf Infinity Indefinite NaN SNaN QNaN
+syn match nasmBinNumber "\<\([01][01_]*[by]\|0[by][01_]\+\)\>"
+syn match nasmBinNumber "\<\~\([01][01_]*[by]\|0[by][01_]\+\)\>"lc=1
+syn match nasmOctNumber "\<\(\o[0-7_]*[qo]\|0[qo][0-7_]\+\)\>"
+syn match nasmOctNumber "\<\~\(\o[0-7_]*[qo]\|0[qo][0-7_]\+\)\>"lc=1
+syn match nasmDecNumber "\<\(\d[0-9_]*\|\d[0-9_]*d\|0d[0-9_]\+\)\>"
+syn match nasmDecNumber "\<\~\(\d[0-9_]*\|\d[0-9_]*d\|0d[0-9_]\+\)\>"lc=1
+syn match nasmHexNumber "\<\(\d[0-9a-f_]*h\|0[xh][0-9a-f_]\+\|\$\d[0-9a-f_]*\)\>"
+syn match nasmHexNumber "\<\~\(\d[0-9a-f_]*h\|0[xh][0-9a-f_]\+\|\$\d[0-9a-f_]*\)\>"lc=1
+syn match nasmBinFloat "\<\(0[by][01_]*\.[01_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[by][01_]*p[+-]\=[0-9_]*\)\>"
+syn match nasmOctFloat "\<\(0[qo][0-7_]*\.[0-7_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[qo][0-7_]*p[+-]\=[0-9_]*\)\>"
+syn match nasmDecFloat "\<\(\d[0-9_]*\.[0-9_]*\(e[+-]\=[0-9_]*\)\=\)\|\(\d[0-9_]*e[+-]\=[0-9_]*\)\>"
+syn match nasmHexFloat "\<\(0[xh][0-9a-f_]\+\.[0-9a-f_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[xh][0-9a-f_]\+p[+-]\=[0-9_]*\)\>"
+syn keyword nasmSpecFloat Inf NaN SNaN QNaN __?Infinity?__ __?NaN?__ __?SNaN?__ __?QNaN?__
+syn match nasmBcdConst "\<\(\d[0-9_]*p\|0p[0-9_]\+\)\>"
syn match nasmNumberError "\<\~\s*\d\+\.\d*\(e[+-]\=\d\+\)\=\>"
@@ -108,8 +111,8 @@ syn keyword nasmTypeError DF EXTRN FWORD RESF TBYTE
syn keyword nasmType FAR NEAR SHORT
syn keyword nasmType BYTE WORD DWORD QWORD DQWORD HWORD DHWORD TWORD
syn keyword nasmType CDECL FASTCALL NONE PASCAL STDCALL
-syn keyword nasmStorage DB DW DD DQ DDQ DT
-syn keyword nasmStorage RESB RESW RESD RESQ RESDQ REST
+syn keyword nasmStorage DB DW DD DQ DT DO DY DZ
+syn keyword nasmStorage RESB RESW RESD RESQ REST RESO RESY RESZ
syn keyword nasmStorage EXTERN GLOBAL COMMON
" Structured storage types
syn match nasmTypeError "\<\(AT\|I\=\(END\)\=\(STRUCT\=\|UNION\)\|I\=END\)\>"
@@ -272,7 +275,6 @@ syn keyword nasmConstant __BITS__ __DATE__ __FILE__ __FORMAT__ __LINE__
syn keyword nasmConstant __NASM_MAJOR__ __NASM_MINOR__ __NASM_VERSION__
syn keyword nasmConstant __TIME__
" Instruction modifiers
-syn match nasmInstructnError "\<TO\>"
syn match nasmInstrModifier "\(^\|:\)\s*[C-GS]S\>"ms=e-1
syn keyword nasmInstrModifier A16 A32 O16 O32
syn match nasmInstrModifier "\<F\(ADD\|MUL\|\(DIV\|SUB\)R\=\)\s\+TO\>"lc=5,ms=e-1
@@ -290,7 +292,7 @@ syn keyword nasmStdDirective ENDPROC EPILOGUE LOCALS PROC PROLOGUE USES
syn keyword nasmStdDirective ENDIF ELSE ELIF ELSIF IF
"syn keyword nasmStdDirective BREAK CASE DEFAULT ENDSWITCH SWITCH
"syn keyword nasmStdDirective CASE OF ENDCASE
-syn keyword nasmStdDirective DO ENDFOR ENDWHILE FOR REPEAT UNTIL WHILE EXIT
+syn keyword nasmStdDirective ENDFOR ENDWHILE FOR REPEAT UNTIL WHILE EXIT
syn case ignore
" Format specific directives: (all formats)
" (excluded: extension directives to section, global, common and extern)
@@ -302,193 +304,726 @@ syn keyword nasmFmtDirective _GLOBAL_OFFSET_TABLE_ __GLOBAL_OFFSET_TABLE_
syn keyword nasmFmtDirective ..start ..got ..gotoff ..gotpc ..plt ..sym
syn case ignore
-
-
+" Instruction errors:
+" Instruction modifiers
+syn match nasmInstructnError "\<TO\>"
" Standard Instructions:
-syn match nasmInstructnError "\<\(F\=CMOV\|SET\)N\=\a\{0,2}\>"
+syn match nasmInstructnError "\<\(F\=CMOV\|SET\|J\)N\=\a\{0,2}\>"
+syn match nasmInstructnError "\<CMP\a\{0,2}XADD\>"
syn keyword nasmInstructnError CMPS MOVS LCS LODS STOS XLAT
-syn match nasmStdInstruction "\<MOV\>"
syn match nasmInstructnError "\<MOV\s[^,;[]*\<CS\>\s*[^:]"he=e-1
-syn match nasmStdInstruction "\<\(CMOV\|J\|SET\)\(N\=\([ABGL]E\=\|[CEOSZ]\)\|P[EO]\=\)\>"
-syn match nasmStdInstruction "\<POP\>"
-syn keyword nasmStdInstruction AAA AAD AAM AAS ADC ADD AND
-syn keyword nasmStdInstruction BOUND BSF BSR BSWAP BT[C] BTR BTS
-syn keyword nasmStdInstruction CALL CBW CDQ CDQE CLC CLD CMC CMP CMPSB CMPSD CMPSW CMPSQ
-syn keyword nasmStdInstruction CMPXCHG CMPXCHG8B CPUID CWD[E] CQO
-syn keyword nasmStdInstruction DAA DAS DEC DIV ENTER
-syn keyword nasmStdInstruction IDIV IMUL INC INT[O] IRET[D] IRETW IRETQ
-syn keyword nasmStdInstruction JCXZ JECXZ JMP
-syn keyword nasmStdInstruction LAHF LDS LEA LEAVE LES LFS LGS LODSB LODSD LODSQ
-syn keyword nasmStdInstruction LODSW LOOP[E] LOOPNE LOOPNZ LOOPZ LSS
-syn keyword nasmStdInstruction MOVSB MOVSD MOVSW MOVSX MOVSQ MOVZX MUL NEG NOP NOT
-syn keyword nasmStdInstruction OR POPA[D] POPAW POPF[D] POPFW POPFQ
-syn keyword nasmStdInstruction PUSH[AD] PUSHAW PUSHF[D] PUSHFW PUSHFQ
-syn keyword nasmStdInstruction PAUSE
-syn keyword nasmStdInstruction RCL RCR RETF RET[N] ROL ROR
-syn keyword nasmStdInstruction SAHF SAL SAR SBB SCASB SCASD SCASW
-syn keyword nasmStdInstruction SHL[D] SHR[D] STC STD STOSB STOSD STOSW STOSQ SUB
-syn keyword nasmStdInstruction TEST XADD XCHG XLATB XOR
-syn keyword nasmStdInstruction LFENCE MFENCE SFENCE
-
-
-" System Instructions: (usually privileged)
-" Verification of pointer parameters
-syn keyword nasmSysInstruction ARPL LAR LSL VERR VERW
-" Addressing descriptor tables
-syn keyword nasmSysInstruction LLDT SLDT LGDT SGDT
-" Multitasking
-syn keyword nasmSysInstruction LTR STR
-" Coprocessing and Multiprocessing (requires fpu and multiple cpu's resp.)
-syn keyword nasmSysInstruction CLTS LOCK WAIT
" Input and Output
syn keyword nasmInstructnError INS OUTS
-syn keyword nasmSysInstruction IN INSB INSW INSD OUT OUTSB OUTSB OUTSW OUTSD
-" Interrupt control
-syn keyword nasmSysInstruction CLI STI LIDT SIDT
-" System control
-syn match nasmSysInstruction "\<MOV\s[^;]\{-}\<CR\o\>"me=s+3
-syn keyword nasmSysInstruction HLT INVD LMSW
-syn keyword nasmSseInstruction PREFETCHT0 PREFETCHT1 PREFETCHT2 PREFETCHNTA
-syn keyword nasmSseInstruction RSM SFENCE SMSW SYSENTER SYSEXIT UD2 WBINVD
-" TLB (Translation Lookahead Buffer) testing
-syn match nasmSysInstruction "\<MOV\s[^;]\{-}\<TR\o\>"me=s+3
-syn keyword nasmSysInstruction INVLPG
-
-" Debugging Instructions: (privileged)
-syn match nasmDbgInstruction "\<MOV\s[^;]\{-}\<DR\o\>"me=s+3
-syn keyword nasmDbgInstruction INT1 INT3 RDMSR RDTSC RDPMC WRMSR
-
-
-" Floating Point Instructions: (requires FPU)
-syn match nasmFpuInstruction "\<FCMOVN\=\([AB]E\=\|[CEPUZ]\)\>"
-syn keyword nasmFpuInstruction F2XM1 FABS FADD[P] FBLD FBSTP
-syn keyword nasmFpuInstruction FCHS FCLEX FCOM[IP] FCOMP[P] FCOS
-syn keyword nasmFpuInstruction FDECSTP FDISI FDIV[P] FDIVR[P] FENI FFREE
-syn keyword nasmFpuInstruction FIADD FICOM[P] FIDIV[R] FILD
-syn keyword nasmFpuInstruction FIMUL FINCSTP FINIT FIST[P] FISUB[R]
-syn keyword nasmFpuInstruction FLD[1] FLDCW FLDENV FLDL2E FLDL2T FLDLG2
-syn keyword nasmFpuInstruction FLDLN2 FLDPI FLDZ FMUL[P]
-syn keyword nasmFpuInstruction FNCLEX FNDISI FNENI FNINIT FNOP FNSAVE
-syn keyword nasmFpuInstruction FNSTCW FNSTENV FNSTSW FNSTSW
-syn keyword nasmFpuInstruction FPATAN FPREM[1] FPTAN FRNDINT FRSTOR
-syn keyword nasmFpuInstruction FSAVE FSCALE FSETPM FSIN FSINCOS FSQRT
-syn keyword nasmFpuInstruction FSTCW FSTENV FST[P] FSTSW FSUB[P] FSUBR[P]
-syn keyword nasmFpuInstruction FTST FUCOM[IP] FUCOMP[P]
-syn keyword nasmFpuInstruction FXAM FXCH FXTRACT FYL2X FYL2XP1
-
-
-" Multi Media Xtension Packed Instructions: (requires MMX unit)
" Standard MMX instructions: (requires MMX1 unit)
syn match nasmInstructnError "\<P\(ADD\|SUB\)U\=S\=[DQ]\=\>"
syn match nasmInstructnError "\<PCMP\a\{0,2}[BDWQ]\=\>"
-syn keyword nasmMmxInstruction EMMS MOVD MOVQ
-syn keyword nasmMmxInstruction PACKSSDW PACKSSWB PACKUSWB PADDB PADDD PADDW
-syn keyword nasmMmxInstruction PADDSB PADDSW PADDUSB PADDUSW PAND[N]
-syn keyword nasmMmxInstruction PCMPEQB PCMPEQD PCMPEQW PCMPGTB PCMPGTD PCMPGTW
-syn keyword nasmMmxInstruction PMACHRIW PMADDWD PMULHW PMULLW POR
-syn keyword nasmMmxInstruction PSLLD PSLLQ PSLLW PSRAD PSRAW PSRLD PSRLQ PSRLW
-syn keyword nasmMmxInstruction PSUBB PSUBD PSUBW PSUBSB PSUBSW PSUBUSB PSUBUSW
-syn keyword nasmMmxInstruction PUNPCKHBW PUNPCKHDQ PUNPCKHWD
-syn keyword nasmMmxInstruction PUNPCKLBW PUNPCKLDQ PUNPCKLWD PXOR
-" Extended MMX instructions: (requires MMX2/SSE unit)
-syn keyword nasmMmxInstruction MASKMOVQ MOVNTQ
-syn keyword nasmMmxInstruction PAVGB PAVGW PEXTRW PINSRW PMAXSW PMAXUB
-syn keyword nasmMmxInstruction PMINSW PMINUB PMOVMSKB PMULHUW PSADBW PSHUFW
-
-
" Streaming SIMD Extension Packed Instructions: (requires SSE unit)
syn match nasmInstructnError "\<CMP\a\{1,5}[PS]S\>"
-syn match nasmSseInstruction "\<CMP\(N\=\(EQ\|L[ET]\)\|\(UN\)\=ORD\)\=[PS]S\>"
-syn keyword nasmSseInstruction ADDPS ADDSS ANDNPS ANDPS
-syn keyword nasmSseInstruction COMISS CVTPI2PS CVTPS2PI
-syn keyword nasmSseInstruction CVTSI2SS CVTSS2SI CVTTPS2PI CVTTSS2SI
-syn keyword nasmSseInstruction DIVPS DIVSS FXRSTOR FXSAVE LDMXCSR
-syn keyword nasmSseInstruction MAXPS MAXSS MINPS MINSS MOVAPS MOVHLPS MOVHPS
-syn keyword nasmSseInstruction MOVLHPS MOVLPS MOVMSKPS MOVNTPS MOVSS MOVUPS
-syn keyword nasmSseInstruction MULPS MULSS
-syn keyword nasmSseInstruction ORPS RCPPS RCPSS RSQRTPS RSQRTSS
-syn keyword nasmSseInstruction SHUFPS SQRTPS SQRTSS STMXCSR SUBPS SUBSS
-syn keyword nasmSseInstruction UCOMISS UNPCKHPS UNPCKLPS XORPS
-
-" F16c Instructions
-syn keyword nasmF16CInstruction VCVTPH2PS VCVTPS2PH
-
" AVX Instructions
-syn keyword nasmAVXInstruction VCVTDQ2PD VCVTDQ2PS VCVTPD2DQ VCVTPD2P VCVTPD2PS
-syn keyword nasmAVXInstruction VCVTPS2DQ VCVTPS2PD
-syn keyword nasmAVXInstruction VCVTSD2SI VCVTSD2SS VCVTSI2SD VCVTSI2SS VCVTSS2SD VCVTSS2SI
-syn keyword nasmAVXInstruction VMAXPS VMAXSS VMINPS VMINSS VMOVAPS VMOVHLPS VMOVHPS
-syn keyword nasmAVXInstruction VMAXPD VMAXSD VMINPD VMINSD VMOVAPD VMOVHLPD VMOVHPD
-syn keyword nasmAVXInstruction VMOVLHPS VMOVLPS VMOVMSKPS VMOVNTPS VMOVSS VMOVUPS
-syn keyword nasmAVXInstruction VMULPS VMULSS VPXOR
-
syn match nasmInstructnError "\<VP\a\{3}R\a\>"
-syn match nasmAVXInstruction "\<VP\(INS\|EXT\)R[BDQW]\>"
-
-syn keyword nasmAVXInstruction VORPS VPABSB VPABSD VPABSW
-syn keyword nasmAVXInstruction PACKSSDW VPACKSSWB VPACKUSDW VPACKUSWB VPADDD
-syn keyword nasmAVXInstruction PADDQ VPADDSB VPADDSW VPADDUSB VPADDUSW
-syn keyword nasmAVXInstruction PADDW VPALIGNR VPAND VPANDN VPAVGB
-syn keyword nasmAVXInstruction PAVGW VPBLENDD VPBLENDVB VPBLENDW VPBROADCASTB
-syn keyword nasmAVXInstruction PBROADCASTD VPBROADCASTQ VPBROADCASTW VPCLMULQDQ VPCMOV
-syn keyword nasmAVXInstruction PCMPEQB VPCMPEQD VPCMPEQQ VPCMPEQW VPCMPESTRI
-syn keyword nasmAVXInstruction PCMPESTRM VPCMPGTB VPCMPGTD VPCMPGTQ VPCMPGTW
-syn keyword nasmAVXInstruction PCMPISTRI VPCMPISTRM VPCOMB VPCOMD VPCOMQ
-syn keyword nasmAVXInstruction PCOMUB VPCOMUD VPCOMUQ VPCOMUW VPCOMW
-syn keyword nasmAVXInstruction PERM2FVPERM2IVPERMD VPERMIL2PD VPERMIL2PS VPERMILPD VPERMILPS
-syn keyword nasmAVXInstruction PERMPD VPERMPS VPERMQ VPEXTRB VPEXTRD
-syn keyword nasmAVXInstruction PEXTRQ VPEXTRW VPGATHERDD VPGATHERDQ VPGATHERQD
-syn keyword nasmAVXInstruction PGATHERQQ VPHADDBD VPHADDBQ VPHADDBW VPHADDD
-syn keyword nasmAVXInstruction PHADDDQ VPHADDSW VPHADDUBQ VPHADDUBW VPHADDUDQ
-syn keyword nasmAVXInstruction PHADDUWD VPHADDUWQ VPHADDW VPHADDWD VPHADDWQ
-syn keyword nasmAVXInstruction PHMINPOSUW VPHSUBBW VPHSUBD VPHSUBDQ VPHSUBSW
-syn keyword nasmAVXInstruction PHSUBW VPHSUBWD VPINSRB VPINSRD VPINSRQ
-syn keyword nasmAVXInstruction PINSRW VPMACSDD VPMACSDQH
-syn keyword nasmAVXInstruction VPMACSDQL VPMACSSDD VPMACSSDQL VPMACSSQH VPMACSSWD
-syn keyword nasmAVXInstruction VPMACSSWW VPMACSWD VPMACSWW VPMADCSSWD VPMADCSWD
-syn keyword nasmAVXInstruction VPMADDUBSW VPMADDWD VPMASKMOVD VPMASKMOVQ VPMAXSB
-syn keyword nasmAVXInstruction VPMAXSD VPMAXSW VPMAXUB VPMAXUD VPMAXUW
-syn keyword nasmAVXInstruction VPMINSB VPMINSD VPMINSW VPMINUB VPMINUD
-syn keyword nasmAVXInstruction VPMINUW VPMOVMSKB VPMOVSXBD VPMOVSXBQ VPMOVSXBW
-syn keyword nasmAVXInstruction VPMOVSXDQ VPMOVSXWD VPMOVSXWQ VPMOVZXBD VPMOVZXBQ
-syn keyword nasmAVXInstruction VPMOVZXBW VPMOVZXDQ VPMOVZXWD VPMOVZXWQ VPMULDQ
-syn keyword nasmAVXInstruction VPMULHRSW VPMULHUW VPMULHW VPMULLD VPMULLW
-syn keyword nasmAVXInstruction VPMULUDQ VPOR VPPERM VPROTB VPROTD
-syn keyword nasmAVXInstruction VPROTQ VPROTW VPSADBW VPSHAB VPSHAD
-syn keyword nasmAVXInstruction VPSHAQ VPSHAW VPSHLB VPSHLD VPSHLQ
-syn keyword nasmAVXInstruction VPSHLW VPSHUFB VPSHUFD VPSHUFHW VPSHUFLW
-syn keyword nasmAVXInstruction VPSIGNB VPSIGND VPSIGNW VPSLLD VPSLLDQ
-syn keyword nasmAVXInstruction VPSLLQ VPSLLVD VPSLLVQ VPSLLW VPSRAD
-syn keyword nasmAVXInstruction VPSRAVD VPSRAW VPSRLD VPSRLDQ VPSRLQ
-syn keyword nasmAVXInstruction VPSRLVD VPSRLVQ VPSRLW VPSUBB VPSUBD
-syn keyword nasmAVXInstruction VPSUBQ VPSUBSB VPSUBSW VPSUBUSB VPSUBUSW
-syn keyword nasmAVXInstruction VPSUBW VPTEST VPUNPCKHBW VPUNPCKHDQ VPUNPCKHQDQ
-syn keyword nasmAVXInstruction VPUNPCKHWD VPUNPCKLBW VPUNPCKLDQ VPUNPCKLQDQ VPUNPCKLWD
-syn keyword nasmAVXInstruction VPXOR VRCPPS
-
-
-" Three Dimensional Now Packed Instructions: (requires 3DNow! unit)
-syn keyword nasmNowInstruction FEMMS PAVGUSB PF2ID PFACC PFADD PFCMPEQ PFCMPGE
-syn keyword nasmNowInstruction PFCMPGT PFMAX PFMIN PFMUL PFRCP PFRCPIT1
-syn keyword nasmNowInstruction PFRCPIT2 PFRSQIT1 PFRSQRT PFSUB[R] PI2FD
-syn keyword nasmNowInstruction PMULHRWA PREFETCH[W]
-
-
-" Vendor Specific Instructions:
+
+
+" Instructions:
+" Standard
+syn keyword nasmInstructionStandard AAA AAD AAM AAS ADC
+syn keyword nasmInstructionStandard ADD AND ARPL
+syn keyword nasmInstructionStandard BOUND BSF BSR BSWAP BT
+syn keyword nasmInstructionStandard BTC BTR BTS CALL CBW
+syn keyword nasmInstructionStandard CDQ CDQE CLC CLD CLI
+syn keyword nasmInstructionStandard CLTS CMC CMP CMPSB CMPSD
+syn keyword nasmInstructionStandard CMPSQ CMPSW CMPXCHG CMPXCHG486 CMPXCHG8B
+syn keyword nasmInstructionStandard CMPXCHG16B CPUID CQO
+syn keyword nasmInstructionStandard CWD CWDE DAA DAS DEC
+syn keyword nasmInstructionStandard DIV EMMS ENTER EQU
+syn keyword nasmInstructionStandard F2XM1 FABS FADD FADDP FBLD
+syn keyword nasmInstructionStandard FBSTP FCHS FCLEX FCMOVB FCMOVBE
+syn keyword nasmInstructionStandard FCMOVE FCMOVNB FCMOVNBE FCMOVNE FCMOVNU
+syn keyword nasmInstructionStandard FCMOVU FCOM FCOMI FCOMIP FCOMP
+syn keyword nasmInstructionStandard FCOMPP FCOS FDECSTP FDISI FDIV
+syn keyword nasmInstructionStandard FDIVP FDIVR FDIVRP FEMMS FENI
+syn keyword nasmInstructionStandard FFREE FFREEP FIADD FICOM FICOMP
+syn keyword nasmInstructionStandard FIDIV FIDIVR FILD FIMUL FINCSTP
+syn keyword nasmInstructionStandard FINIT FIST FISTP FISTTP FISUB
+syn keyword nasmInstructionStandard FISUBR FLD FLD1 FLDCW FLDENV
+syn keyword nasmInstructionStandard FLDL2E FLDL2T FLDLG2 FLDLN2 FLDPI
+syn keyword nasmInstructionStandard FLDZ FMUL FMULP FNCLEX FNDISI
+syn keyword nasmInstructionStandard FNENI FNINIT FNOP FNSAVE FNSTCW
+syn keyword nasmInstructionStandard FNSTENV FNSTSW FPATAN FPREM FPREM1
+syn keyword nasmInstructionStandard FPTAN FRNDINT FRSTOR FSAVE FSCALE
+syn keyword nasmInstructionStandard FSETPM FSIN FSINCOS FSQRT FST
+syn keyword nasmInstructionStandard FSTCW FSTENV FSTP FSTSW FSUB
+syn keyword nasmInstructionStandard FSUBP FSUBR FSUBRP FTST FUCOM
+syn keyword nasmInstructionStandard FUCOMI FUCOMIP FUCOMP FUCOMPP FXAM
+syn keyword nasmInstructionStandard FXCH FXTRACT FYL2X FYL2XP1 HLT
+syn keyword nasmInstructionStandard IBTS ICEBP IDIV IMUL IN
+syn keyword nasmInstructionStandard INC INSB INSD INSW INT
+syn keyword nasmInstructionStandard INTO
+syn keyword nasmInstructionStandard INVD INVPCID INVLPG INVLPGA IRET
+syn keyword nasmInstructionStandard IRETD IRETQ IRETW JCXZ JECXZ
+syn keyword nasmInstructionStandard JRCXZ JMP JMPE LAHF LAR
+syn keyword nasmInstructionStandard LDS LEA LEAVE LES LFENCE
+syn keyword nasmInstructionStandard LFS LGDT LGS LIDT LLDT
+syn keyword nasmInstructionStandard LMSW LOADALL LOADALL286 LODSB LODSD
+syn keyword nasmInstructionStandard LODSQ LODSW LOOP LOOPE LOOPNE
+syn keyword nasmInstructionStandard LOOPNZ LOOPZ LSL LSS LTR
+syn keyword nasmInstructionStandard MFENCE MONITOR MONITORX MOV MOVD
+syn keyword nasmInstructionStandard MOVQ MOVSB MOVSD MOVSQ MOVSW
+syn keyword nasmInstructionStandard MOVSX MOVSXD MOVSX MOVZX MUL
+syn keyword nasmInstructionStandard MWAIT MWAITX NEG NOP NOT
+syn keyword nasmInstructionStandard OR OUT OUTSB OUTSD OUTSW
+syn keyword nasmInstructionStandard PACKSSDW PACKSSWB PACKUSWB PADDB PADDD
+syn keyword nasmInstructionStandard PADDSB PADDSW PADDUSB PADDUSW
+syn keyword nasmInstructionStandard PADDW PAND PANDN PAUSE
+syn keyword nasmInstructionStandard PAVGUSB PCMPEQB PCMPEQD PCMPEQW PCMPGTB
+syn keyword nasmInstructionStandard PCMPGTD PCMPGTW PF2ID PFACC
+syn keyword nasmInstructionStandard PFADD PFCMPEQ PFCMPGE PFCMPGT PFMAX
+syn keyword nasmInstructionStandard PFMIN PFMUL PFRCP PFRCPIT1 PFRCPIT2
+syn keyword nasmInstructionStandard PFRSQIT1 PFRSQRT PFSUB PFSUBR PI2FD
+syn keyword nasmInstructionStandard PMADDWD PMULHRWA
+syn keyword nasmInstructionStandard PMULHW PMULLW
+syn keyword nasmInstructionStandard POP POPA POPAD
+syn keyword nasmInstructionStandard POPAW POPF POPFD POPFQ POPFW
+syn keyword nasmInstructionStandard POR PREFETCH PREFETCHW PSLLD PSLLQ
+syn keyword nasmInstructionStandard PSLLW PSRAD PSRAW PSRLD PSRLQ
+syn keyword nasmInstructionStandard PSRLW PSUBB PSUBD PSUBSB
+syn keyword nasmInstructionStandard PSUBSW PSUBUSB PSUBUSW PSUBW PUNPCKHBW
+syn keyword nasmInstructionStandard PUNPCKHDQ PUNPCKHWD PUNPCKLBW PUNPCKLDQ PUNPCKLWD
+syn keyword nasmInstructionStandard PUSH PUSHA PUSHAD PUSHAW PUSHF
+syn keyword nasmInstructionStandard PUSHFD PUSHFQ PUSHFW PXOR RCL
+syn keyword nasmInstructionStandard RCR
+syn keyword nasmInstructionStandard RDTSCP RET RETF RETN RETW
+syn keyword nasmInstructionStandard RETFW RETNW RETD RETFD RETND
+syn keyword nasmInstructionStandard RETQ RETFQ RETNQ ROL ROR
+syn keyword nasmInstructionStandard RSM RSTS
+syn keyword nasmInstructionStandard SAHF SAL SALC SAR SBB
+syn keyword nasmInstructionStandard SCASB SCASD SCASQ SCASW SFENCE
+syn keyword nasmInstructionStandard SGDT SHL SHLD SHR SHRD
+syn keyword nasmInstructionStandard SIDT SLDT SKINIT SMI
+syn keyword nasmInstructionStandard SMSW STC STD STI
+syn keyword nasmInstructionStandard STOSB STOSD STOSQ STOSW STR
+syn keyword nasmInstructionStandard SUB SWAPGS
+syn keyword nasmInstructionStandard SYSCALL SYSENTER SYSEXIT SYSRET TEST
+syn keyword nasmInstructionStandard UD0 UD1 UD2B UD2 UD2A
+syn keyword nasmInstructionStandard UMOV VERR VERW FWAIT WBINVD
+syn keyword nasmInstructionStandard XADD XBTS XCHG
+syn keyword nasmInstructionStandard XLATB XLAT XOR CMOVA CMOVAE
+syn keyword nasmInstructionStandard CMOVB CMOVBE CMOVC CMOVE CMOVG
+syn keyword nasmInstructionStandard CMOVGE CMOVL CMOVLE CMOVNA CMOVNAE
+syn keyword nasmInstructionStandard CMOVNB CMOVNBE CMOVNC CMOVNE CMOVNG
+syn keyword nasmInstructionStandard CMOVNGE CMOVNL CMOVNLE CMOVNO CMOVNP
+syn keyword nasmInstructionStandard CMOVNS CMOVNZ CMOVO CMOVP CMOVPE
+syn keyword nasmInstructionStandard CMOVPO CMOVS CMOVZ JA JAE
+syn keyword nasmInstructionStandard JB JBE JC JCXZ JE
+syn keyword nasmInstructionStandard JECXZ JG JGE JL JLE
+syn keyword nasmInstructionStandard JNA JNAE JNB JNBE JNC
+syn keyword nasmInstructionStandard JNE JNG JNGE JNL JNLE
+syn keyword nasmInstructionStandard JNO JNP JNS JNZ JO
+syn keyword nasmInstructionStandard JP JPE JPO JRCXZ JS
+syn keyword nasmInstructionStandard JZ SETA SETAE SETB SETBE
+syn keyword nasmInstructionStandard SETC SETE SETG SETGE SETL
+syn keyword nasmInstructionStandard SETLE SETNA SETNAE SETNB SETNBE
+syn keyword nasmInstructionStandard SETNC SETNE SETNG SETNGE SETNL
+syn keyword nasmInstructionStandard SETNLE SETNO SETNP SETNS SETNZ
+syn keyword nasmInstructionStandard SETO SETP SETPE SETPO SETS
+syn keyword nasmInstructionStandard SETZ
+" SIMD
+syn keyword nasmInstructionSIMD ADDPS ADDSS ANDNPS ANDPS CMPEQPS
+syn keyword nasmInstructionSIMD CMPEQSS CMPLEPS CMPLESS CMPLTPS CMPLTSS
+syn keyword nasmInstructionSIMD CMPNEQPS CMPNEQSS CMPNLEPS CMPNLESS CMPNLTPS
+syn keyword nasmInstructionSIMD CMPNLTSS CMPORDPS CMPORDSS CMPUNORDPS CMPUNORDSS
+syn keyword nasmInstructionSIMD CMPPS CMPSS COMISS CVTPI2PS CVTPS2PI
+syn keyword nasmInstructionSIMD CVTSI2SS CVTSS2SI CVTTPS2PI CVTTSS2SI DIVPS
+syn keyword nasmInstructionSIMD DIVSS LDMXCSR MAXPS MAXSS MINPS
+syn keyword nasmInstructionSIMD MINSS MOVAPS MOVHPS MOVLHPS MOVLPS
+syn keyword nasmInstructionSIMD MOVHLPS MOVMSKPS MOVNTPS MOVSS MOVUPS
+syn keyword nasmInstructionSIMD MULPS MULSS ORPS RCPPS RCPSS
+syn keyword nasmInstructionSIMD RSQRTPS RSQRTSS SHUFPS SQRTPS SQRTSS
+syn keyword nasmInstructionSIMD STMXCSR SUBPS SUBSS UCOMISS UNPCKHPS
+syn keyword nasmInstructionSIMD UNPCKLPS XORPS
+" SSE
+syn keyword nasmInstructionSSE FXRSTOR FXRSTOR64 FXSAVE FXSAVE64
+" XSAVE
+syn keyword nasmInstructionXSAVE XGETBV XSETBV XSAVE XSAVE64 XSAVEC
+syn keyword nasmInstructionXSAVE XSAVEC64 XSAVEOPT XSAVEOPT64 XSAVES XSAVES64
+syn keyword nasmInstructionXSAVE XRSTOR XRSTOR64 XRSTORS XRSTORS64
+" MEM
+syn keyword nasmInstructionMEM PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 PREFETCHIT0
+syn keyword nasmInstructionMEM PREFETCHIT1 SFENCE
+" MMX
+syn keyword nasmInstructionMMX MASKMOVQ MOVNTQ PAVGB PAVGW PEXTRW
+syn keyword nasmInstructionMMX PINSRW PMAXSW PMAXUB PMINSW PMINUB
+syn keyword nasmInstructionMMX PMOVMSKB PMULHUW PSADBW PSHUFW
+" 3DNOW
+syn keyword nasmInstruction3DNOW PF2IW PFNACC PFPNACC PI2FW PSWAPD
+" SSE2
+syn keyword nasmInstructionSSE2 MASKMOVDQU CLFLUSH MOVNTDQ MOVNTI MOVNTPD
+syn keyword nasmInstructionSSE2 LFENCE MFENCE
+" WMMX
+syn keyword nasmInstructionWMMX MOVD MOVDQA MOVDQU MOVDQ2Q MOVQ
+syn keyword nasmInstructionWMMX MOVQ2DQ PACKSSWB PACKSSDW PACKUSWB PADDB
+syn keyword nasmInstructionWMMX PADDW PADDD PADDQ PADDSB PADDSW
+syn keyword nasmInstructionWMMX PADDUSB PADDUSW PAND PANDN PAVGB
+syn keyword nasmInstructionWMMX PAVGW PCMPEQB PCMPEQW PCMPEQD PCMPGTB
+syn keyword nasmInstructionWMMX PCMPGTW PCMPGTD PEXTRW PINSRW PMADDWD
+syn keyword nasmInstructionWMMX PMAXSW PMAXUB PMINSW PMINUB PMOVMSKB
+syn keyword nasmInstructionWMMX PMULHUW PMULHW PMULLW PMULUDQ POR
+syn keyword nasmInstructionWMMX PSADBW PSHUFD PSHUFHW PSHUFLW PSLLDQ
+syn keyword nasmInstructionWMMX PSLLW PSLLD PSLLQ PSRAW PSRAD
+syn keyword nasmInstructionWMMX PSRLDQ PSRLW PSRLD PSRLQ PSUBB
+syn keyword nasmInstructionWMMX PSUBW PSUBD PSUBQ PSUBSB PSUBSW
+syn keyword nasmInstructionWMMX PSUBUSB PSUBUSW PUNPCKHBW PUNPCKHWD PUNPCKHDQ
+syn keyword nasmInstructionWMMX PUNPCKHQDQ PUNPCKLBW PUNPCKLWD PUNPCKLDQ PUNPCKLQDQ
+syn keyword nasmInstructionWMMX PXOR
+" WSSD
+syn keyword nasmInstructionWSSD ADDPD ADDSD ANDNPD ANDPD CMPEQPD
+syn keyword nasmInstructionWSSD CMPEQSD CMPLEPD CMPLESD CMPLTPD CMPLTSD
+syn keyword nasmInstructionWSSD CMPNEQPD CMPNEQSD CMPNLEPD CMPNLESD CMPNLTPD
+syn keyword nasmInstructionWSSD CMPNLTSD CMPORDPD CMPORDSD CMPUNORDPD CMPUNORDSD
+syn keyword nasmInstructionWSSD CMPPD CMPSD COMISD CVTDQ2PD CVTDQ2PS
+syn keyword nasmInstructionWSSD CVTPD2DQ CVTPD2PI CVTPD2PS CVTPI2PD CVTPS2DQ
+syn keyword nasmInstructionWSSD CVTPS2PD CVTSD2SI CVTSD2SS CVTSI2SD CVTSS2SD
+syn keyword nasmInstructionWSSD CVTTPD2PI CVTTPD2DQ CVTTPS2DQ CVTTSD2SI DIVPD
+syn keyword nasmInstructionWSSD DIVSD MAXPD MAXSD MINPD MINSD
+syn keyword nasmInstructionWSSD MOVAPD MOVHPD MOVLPD MOVMSKPD MOVSD
+syn keyword nasmInstructionWSSD MOVUPD MULPD MULSD ORPD SHUFPD
+syn keyword nasmInstructionWSSD SQRTPD SQRTSD SUBPD SUBSD UCOMISD
+syn keyword nasmInstructionWSSD UNPCKHPD UNPCKLPD XORPD
+" PRESSCOT
+syn keyword nasmInstructionPRESSCOT ADDSUBPD ADDSUBPS HADDPD HADDPS HSUBPD
+syn keyword nasmInstructionPRESSCOT HSUBPS LDDQU MOVDDUP MOVSHDUP MOVSLDUP
+" VMXSVM
+syn keyword nasmInstructionVMXSVM CLGI STGI VMCALL VMCLEAR VMFUNC
+syn keyword nasmInstructionVMXSVM VMLAUNCH VMLOAD VMMCALL VMPTRLD VMPTRST
+syn keyword nasmInstructionVMXSVM VMREAD VMRESUME VMRUN VMSAVE VMWRITE
+syn keyword nasmInstructionVMXSVM VMXOFF VMXON
+" PTVMX
+syn keyword nasmInstructionPTVMX INVEPT INVVPID
+" SEVSNPAMD
+syn keyword nasmInstructionSEVSNPAMD PVALIDATE RMPADJUST VMGEXIT
+" TEJAS
+syn keyword nasmInstructionTEJAS PABSB PABSW PABSD PALIGNR PHADDW
+syn keyword nasmInstructionTEJAS PHADDD PHADDSW PHSUBW PHSUBD PHSUBSW
+syn keyword nasmInstructionTEJAS PMADDUBSW PMULHRSW PSHUFB PSIGNB PSIGNW
+syn keyword nasmInstructionTEJAS PSIGND
+" AMD_SSE4A
+syn keyword nasmInstructionAMD_SSE4A EXTRQ INSERTQ MOVNTSD MOVNTSS
+" BARCELONA
+syn keyword nasmInstructionBARCELONA LZCNT
+" PENRY
+syn keyword nasmInstructionPENRY BLENDPD BLENDPS BLENDVPD BLENDVPS DPPD
+syn keyword nasmInstructionPENRY DPPS EXTRACTPS INSERTPS MOVNTDQA MPSADBW
+syn keyword nasmInstructionPENRY PACKUSDW PBLENDVB PBLENDW PCMPEQQ PEXTRB
+syn keyword nasmInstructionPENRY PEXTRD PEXTRQ PEXTRW PHMINPOSUW PINSRB
+syn keyword nasmInstructionPENRY PINSRD PINSRQ PMAXSB PMAXSD PMAXUD
+syn keyword nasmInstructionPENRY PMAXUW PMINSB PMINSD PMINUD PMINUW
+syn keyword nasmInstructionPENRY PMOVSXBW PMOVSXBD PMOVSXBQ PMOVSXWD PMOVSXWQ
+syn keyword nasmInstructionPENRY PMOVSXDQ PMOVZXBW PMOVZXBD PMOVZXBQ PMOVZXWD
+syn keyword nasmInstructionPENRY PMOVZXWQ PMOVZXDQ PMULDQ PMULLD PTEST
+syn keyword nasmInstructionPENRY ROUNDPD ROUNDPS ROUNDSD ROUNDSS
+" NEHALEM
+syn keyword nasmInstructionNEHALEM CRC32 PCMPESTRI PCMPESTRM PCMPISTRI PCMPISTRM
+syn keyword nasmInstructionNEHALEM PCMPGTQ POPCNT
+" SMX
+syn keyword nasmInstructionSMX GETSEC
+" GEODE_3DNOW
+syn keyword nasmInstructionGEODE_3DNOW PFRCPV PFRSQRTV
+" INTEL_NEW
+syn keyword nasmInstructionINTEL_NEW MOVBE
+" AES
+syn keyword nasmInstructionAES AESENC AESENCLAST AESDEC AESDECLAST AESIMC
+syn keyword nasmInstructionAES AESKEYGENASSIST
+" AVX_AES
+syn keyword nasmInstructionAVX_AES VAESENC VAESENCLAST VAESDEC VAESDECLAST VAESIMC
+syn keyword nasmInstructionAVX_AES VAESKEYGENASSIST
+" INTEL_PUB
+syn keyword nasmInstructionINTEL_PUB VAESENC VAESENCLAST VAESDEC VAESDECLAST VAESENC
+syn keyword nasmInstructionINTEL_PUB VAESENCLAST VAESDEC VAESDECLAST VAESENC VAESENCLAST
+syn keyword nasmInstructionINTEL_PUB VAESDEC VAESDECLAST
+" AVX
+syn keyword nasmInstructionAVX VADDPD VADDPS VADDSD VADDSS VADDSUBPD
+syn keyword nasmInstructionAVX VADDSUBPS VANDPD VANDPS VANDNPD VANDNPS
+syn keyword nasmInstructionAVX VBLENDPD VBLENDPS VBLENDVPD VBLENDVPS VBROADCASTSS
+syn keyword nasmInstructionAVX VBROADCASTSD VBROADCASTF128 VCMPEQ_OSPD VCMPEQPD VCMPLT_OSPD
+syn keyword nasmInstructionAVX VCMPLTPD VCMPLE_OSPD VCMPLEPD VCMPUNORD_QPD VCMPUNORDPD
+syn keyword nasmInstructionAVX VCMPNEQ_UQPD VCMPNEQPD VCMPNLT_USPD VCMPNLTPD VCMPNLE_USPD
+syn keyword nasmInstructionAVX VCMPNLEPD VCMPORD_QPD VCMPORDPD VCMPEQ_UQPD VCMPNGE_USPD
+syn keyword nasmInstructionAVX VCMPNGEPD VCMPNGT_USPD VCMPNGTPD VCMPFALSE_OQPD VCMPFALSEPD
+syn keyword nasmInstructionAVX VCMPNEQ_OQPD VCMPGE_OSPD VCMPGEPD VCMPGT_OSPD VCMPGTPD
+syn keyword nasmInstructionAVX VCMPTRUE_UQPD VCMPTRUEPD VCMPEQ_OSPD VCMPLT_OQPD VCMPLE_OQPD
+syn keyword nasmInstructionAVX VCMPUNORD_SPD VCMPNEQ_USPD VCMPNLT_UQPD VCMPNLE_UQPD VCMPORD_SPD
+syn keyword nasmInstructionAVX VCMPEQ_USPD VCMPNGE_UQPD VCMPNGT_UQPD VCMPFALSE_OSPD VCMPNEQ_OSPD
+syn keyword nasmInstructionAVX VCMPGE_OQPD VCMPGT_OQPD VCMPTRUE_USPD VCMPPD VCMPEQ_OSPS
+syn keyword nasmInstructionAVX VCMPEQPS VCMPLT_OSPS VCMPLTPS VCMPLE_OSPS VCMPLEPS
+syn keyword nasmInstructionAVX VCMPUNORD_QPS VCMPUNORDPS VCMPNEQ_UQPS VCMPNEQPS VCMPNLT_USPS
+syn keyword nasmInstructionAVX VCMPNLTPS VCMPNLE_USPS VCMPNLEPS VCMPORD_QPS VCMPORDPS
+syn keyword nasmInstructionAVX VCMPEQ_UQPS VCMPNGE_USPS VCMPNGEPS VCMPNGT_USPS VCMPNGTPS
+syn keyword nasmInstructionAVX VCMPFALSE_OQPS VCMPFALSEPS VCMPNEQ_OQPS VCMPGE_OSPS VCMPGEPS
+syn keyword nasmInstructionAVX VCMPGT_OSPS VCMPGTPS VCMPTRUE_UQPS VCMPTRUEPS VCMPEQ_OSPS
+syn keyword nasmInstructionAVX VCMPLT_OQPS VCMPLE_OQPS VCMPUNORD_SPS VCMPNEQ_USPS VCMPNLT_UQPS
+syn keyword nasmInstructionAVX VCMPNLE_UQPS VCMPORD_SPS VCMPEQ_USPS VCMPNGE_UQPS VCMPNGT_UQPS
+syn keyword nasmInstructionAVX VCMPFALSE_OSPS VCMPNEQ_OSPS VCMPGE_OQPS VCMPGT_OQPS VCMPTRUE_USPS
+syn keyword nasmInstructionAVX VCMPPS VCMPEQ_OSSD VCMPEQSD VCMPLT_OSSD VCMPLTSD
+syn keyword nasmInstructionAVX VCMPLE_OSSD VCMPLESD VCMPUNORD_QSD VCMPUNORDSD VCMPNEQ_UQSD
+syn keyword nasmInstructionAVX VCMPNEQSD VCMPNLT_USSD VCMPNLTSD VCMPNLE_USSD VCMPNLESD
+syn keyword nasmInstructionAVX VCMPORD_QSD VCMPORDSD VCMPEQ_UQSD VCMPNGE_USSD VCMPNGESD
+syn keyword nasmInstructionAVX VCMPNGT_USSD VCMPNGTSD VCMPFALSE_OQSD VCMPFALSESD VCMPNEQ_OQSD
+syn keyword nasmInstructionAVX VCMPGE_OSSD VCMPGESD VCMPGT_OSSD VCMPGTSD VCMPTRUE_UQSD
+syn keyword nasmInstructionAVX VCMPTRUESD VCMPEQ_OSSD VCMPLT_OQSD VCMPLE_OQSD VCMPUNORD_SSD
+syn keyword nasmInstructionAVX VCMPNEQ_USSD VCMPNLT_UQSD VCMPNLE_UQSD VCMPORD_SSD VCMPEQ_USSD
+syn keyword nasmInstructionAVX VCMPNGE_UQSD VCMPNGT_UQSD VCMPFALSE_OSSD VCMPNEQ_OSSD VCMPGE_OQSD
+syn keyword nasmInstructionAVX VCMPGT_OQSD VCMPTRUE_USSD VCMPSD VCMPEQ_OSSS VCMPEQSS
+syn keyword nasmInstructionAVX VCMPLT_OSSS VCMPLTSS VCMPLE_OSSS VCMPLESS VCMPUNORD_QSS
+syn keyword nasmInstructionAVX VCMPUNORDSS VCMPNEQ_UQSS VCMPNEQSS VCMPNLT_USSS VCMPNLTSS
+syn keyword nasmInstructionAVX VCMPNLE_USSS VCMPNLESS VCMPORD_QSS VCMPORDSS VCMPEQ_UQSS
+syn keyword nasmInstructionAVX VCMPNGE_USSS VCMPNGESS VCMPNGT_USSS VCMPNGTSS VCMPFALSE_OQSS
+syn keyword nasmInstructionAVX VCMPFALSESS VCMPNEQ_OQSS VCMPGE_OSSS VCMPGESS VCMPGT_OSSS
+syn keyword nasmInstructionAVX VCMPGTSS VCMPTRUE_UQSS VCMPTRUESS VCMPEQ_OSSS VCMPLT_OQSS
+syn keyword nasmInstructionAVX VCMPLE_OQSS VCMPUNORD_SSS VCMPNEQ_USSS VCMPNLT_UQSS VCMPNLE_UQSS
+syn keyword nasmInstructionAVX VCMPORD_SSS VCMPEQ_USSS VCMPNGE_UQSS VCMPNGT_UQSS VCMPFALSE_OSSS
+syn keyword nasmInstructionAVX VCMPNEQ_OSSS VCMPGE_OQSS VCMPGT_OQSS VCMPTRUE_USSS VCMPSS
+syn keyword nasmInstructionAVX VCOMISD VCOMISS VCVTDQ2PD VCVTDQ2PS VCVTPD2DQ
+syn keyword nasmInstructionAVX VCVTPD2PS VCVTPS2DQ VCVTPS2PD VCVTSD2SI VCVTSD2SS
+syn keyword nasmInstructionAVX VCVTSI2SD VCVTSI2SS VCVTSS2SD VCVTSS2SI VCVTTPD2DQ
+syn keyword nasmInstructionAVX VCVTTPS2DQ VCVTTSD2SI VCVTTSS2SI VDIVPD VDIVPS
+syn keyword nasmInstructionAVX VDIVSD VDIVSS VDPPD VDPPS VEXTRACTF128
+syn keyword nasmInstructionAVX VEXTRACTPS VHADDPD VHADDPS VHSUBPD VHSUBPS
+syn keyword nasmInstructionAVX VINSERTF128 VINSERTPS VLDDQU VLDQQU VLDDQU
+syn keyword nasmInstructionAVX VLDMXCSR VMASKMOVDQU VMASKMOVPS VMASKMOVPD VMAXPD
+syn keyword nasmInstructionAVX VMAXPS VMAXSD VMAXSS VMINPD VMINPS
+syn keyword nasmInstructionAVX VMINSD VMINSS VMOVAPD VMOVAPS VMOVD
+syn keyword nasmInstructionAVX VMOVQ VMOVDDUP VMOVDQA VMOVQQA VMOVDQA
+syn keyword nasmInstructionAVX VMOVDQU VMOVQQU VMOVDQU VMOVHLPS VMOVHPD
+syn keyword nasmInstructionAVX VMOVHPS VMOVLHPS VMOVLPD VMOVLPS VMOVMSKPD
+syn keyword nasmInstructionAVX VMOVMSKPS VMOVNTDQ VMOVNTQQ VMOVNTDQ VMOVNTDQA
+syn keyword nasmInstructionAVX VMOVNTPD VMOVNTPS VMOVSD VMOVSHDUP VMOVSLDUP
+syn keyword nasmInstructionAVX VMOVSS VMOVUPD VMOVUPS VMPSADBW VMULPD
+syn keyword nasmInstructionAVX VMULPS VMULSD VMULSS VORPD VORPS
+syn keyword nasmInstructionAVX VPABSB VPABSW VPABSD VPACKSSWB VPACKSSDW
+syn keyword nasmInstructionAVX VPACKUSWB VPACKUSDW VPADDB VPADDW VPADDD
+syn keyword nasmInstructionAVX VPADDQ VPADDSB VPADDSW VPADDUSB VPADDUSW
+syn keyword nasmInstructionAVX VPALIGNR VPAND VPANDN VPAVGB VPAVGW
+syn keyword nasmInstructionAVX VPBLENDVB VPBLENDW VPCMPESTRI VPCMPESTRM VPCMPISTRI
+syn keyword nasmInstructionAVX VPCMPISTRM VPCMPEQB VPCMPEQW VPCMPEQD VPCMPEQQ
+syn keyword nasmInstructionAVX VPCMPGTB VPCMPGTW VPCMPGTD VPCMPGTQ VPERMILPD
+syn keyword nasmInstructionAVX VPERMILPS VPERM2F128 VPEXTRB VPEXTRW VPEXTRD
+syn keyword nasmInstructionAVX VPEXTRQ VPHADDW VPHADDD VPHADDSW VPHMINPOSUW
+syn keyword nasmInstructionAVX VPHSUBW VPHSUBD VPHSUBSW VPINSRB VPINSRW
+syn keyword nasmInstructionAVX VPINSRD VPINSRQ VPMADDWD VPMADDUBSW VPMAXSB
+syn keyword nasmInstructionAVX VPMAXSW VPMAXSD VPMAXUB VPMAXUW VPMAXUD
+syn keyword nasmInstructionAVX VPMINSB VPMINSW VPMINSD VPMINUB VPMINUW
+syn keyword nasmInstructionAVX VPMINUD VPMOVMSKB VPMOVSXBW VPMOVSXBD VPMOVSXBQ
+syn keyword nasmInstructionAVX VPMOVSXWD VPMOVSXWQ VPMOVSXDQ VPMOVZXBW VPMOVZXBD
+syn keyword nasmInstructionAVX VPMOVZXBQ VPMOVZXWD VPMOVZXWQ VPMOVZXDQ VPMULHUW
+syn keyword nasmInstructionAVX VPMULHRSW VPMULHW VPMULLW VPMULLD VPMULUDQ
+syn keyword nasmInstructionAVX VPMULDQ VPOR VPSADBW VPSHUFB VPSHUFD
+syn keyword nasmInstructionAVX VPSHUFHW VPSHUFLW VPSIGNB VPSIGNW VPSIGND
+syn keyword nasmInstructionAVX VPSLLDQ VPSRLDQ VPSLLW VPSLLD VPSLLQ
+syn keyword nasmInstructionAVX VPSRAW VPSRAD VPSRLW VPSRLD VPSRLQ
+syn keyword nasmInstructionAVX VPTEST VPSUBB VPSUBW VPSUBD VPSUBQ
+syn keyword nasmInstructionAVX VPSUBSB VPSUBSW VPSUBUSB VPSUBUSW VPUNPCKHBW
+syn keyword nasmInstructionAVX VPUNPCKHWD VPUNPCKHDQ VPUNPCKHQDQ VPUNPCKLBW VPUNPCKLWD
+syn keyword nasmInstructionAVX VPUNPCKLDQ VPUNPCKLQDQ VPXOR VRCPPS VRCPSS
+syn keyword nasmInstructionAVX VRSQRTPS VRSQRTSS VROUNDPD VROUNDPS VROUNDSD
+syn keyword nasmInstructionAVX VROUNDSS VSHUFPD VSHUFPS VSQRTPD VSQRTPS
+syn keyword nasmInstructionAVX VSQRTSD VSQRTSS VSTMXCSR VSUBPD VSUBPS
+syn keyword nasmInstructionAVX VSUBSD VSUBSS VTESTPS VTESTPD VUCOMISD
+syn keyword nasmInstructionAVX VUCOMISS VUNPCKHPD VUNPCKHPS VUNPCKLPD VUNPCKLPS
+syn keyword nasmInstructionAVX VXORPD VXORPS VZEROALL VZEROUPPER
+" INTEL_CMUL
+syn keyword nasmInstructionINTEL_CMUL PCLMULLQLQDQ PCLMULHQLQDQ PCLMULLQHQDQ PCLMULHQHQDQ PCLMULQDQ
+" INTEL_AVX_CMUL
+syn keyword nasmInstructionINTEL_AVX_CMUL VPCLMULLQLQDQ VPCLMULHQLQDQ VPCLMULLQHQDQ VPCLMULHQHQDQ VPCLMULQDQ
+syn keyword nasmInstructionINTEL_AVX_CMUL VPCLMULLQLQDQ VPCLMULHQLQDQ VPCLMULLQHQDQ VPCLMULHQHQDQ VPCLMULQDQ
+syn keyword nasmInstructionINTEL_AVX_CMUL VPCLMULLQLQDQ VPCLMULHQLQDQ VPCLMULLQHQDQ VPCLMULHQHQDQ VPCLMULQDQ
+syn keyword nasmInstructionINTEL_AVX_CMUL VPCLMULLQLQDQ VPCLMULHQLQDQ VPCLMULLQHQDQ VPCLMULHQHQDQ VPCLMULQDQ
+syn keyword nasmInstructionINTEL_AVX_CMUL VPCLMULLQLQDQ VPCLMULHQLQDQ VPCLMULLQHQDQ VPCLMULHQHQDQ VPCLMULQDQ
+" INTEL_FMA
+syn keyword nasmInstructionINTEL_FMA VFMADD132PS VFMADD132PD VFMADD312PS VFMADD312PD VFMADD213PS
+syn keyword nasmInstructionINTEL_FMA VFMADD213PD VFMADD123PS VFMADD123PD VFMADD231PS VFMADD231PD
+syn keyword nasmInstructionINTEL_FMA VFMADD321PS VFMADD321PD VFMADDSUB132PS VFMADDSUB132PD VFMADDSUB312PS
+syn keyword nasmInstructionINTEL_FMA VFMADDSUB312PD VFMADDSUB213PS VFMADDSUB213PD VFMADDSUB123PS VFMADDSUB123PD
+syn keyword nasmInstructionINTEL_FMA VFMADDSUB231PS VFMADDSUB231PD VFMADDSUB321PS VFMADDSUB321PD VFMSUB132PS
+syn keyword nasmInstructionINTEL_FMA VFMSUB132PD VFMSUB312PS VFMSUB312PD VFMSUB213PS VFMSUB213PD
+syn keyword nasmInstructionINTEL_FMA VFMSUB123PS VFMSUB123PD VFMSUB231PS VFMSUB231PD VFMSUB321PS
+syn keyword nasmInstructionINTEL_FMA VFMSUB321PD VFMSUBADD132PS VFMSUBADD132PD VFMSUBADD312PS VFMSUBADD312PD
+syn keyword nasmInstructionINTEL_FMA VFMSUBADD213PS VFMSUBADD213PD VFMSUBADD123PS VFMSUBADD123PD VFMSUBADD231PS
+syn keyword nasmInstructionINTEL_FMA VFMSUBADD231PD VFMSUBADD321PS VFMSUBADD321PD VFNMADD132PS VFNMADD132PD
+syn keyword nasmInstructionINTEL_FMA VFNMADD312PS VFNMADD312PD VFNMADD213PS VFNMADD213PD VFNMADD123PS
+syn keyword nasmInstructionINTEL_FMA VFNMADD123PD VFNMADD231PS VFNMADD231PD VFNMADD321PS VFNMADD321PD
+syn keyword nasmInstructionINTEL_FMA VFNMSUB132PS VFNMSUB132PD VFNMSUB312PS VFNMSUB312PD VFNMSUB213PS
+syn keyword nasmInstructionINTEL_FMA VFNMSUB213PD VFNMSUB123PS VFNMSUB123PD VFNMSUB231PS VFNMSUB231PD
+syn keyword nasmInstructionINTEL_FMA VFNMSUB321PS VFNMSUB321PD VFMADD132SS VFMADD132SD VFMADD312SS
+syn keyword nasmInstructionINTEL_FMA VFMADD312SD VFMADD213SS VFMADD213SD VFMADD123SS VFMADD123SD
+syn keyword nasmInstructionINTEL_FMA VFMADD231SS VFMADD231SD VFMADD321SS VFMADD321SD VFMSUB132SS
+syn keyword nasmInstructionINTEL_FMA VFMSUB132SD VFMSUB312SS VFMSUB312SD VFMSUB213SS VFMSUB213SD
+syn keyword nasmInstructionINTEL_FMA VFMSUB123SS VFMSUB123SD VFMSUB231SS VFMSUB231SD VFMSUB321SS
+syn keyword nasmInstructionINTEL_FMA VFMSUB321SD VFNMADD132SS VFNMADD132SD VFNMADD312SS VFNMADD312SD
+syn keyword nasmInstructionINTEL_FMA VFNMADD213SS VFNMADD213SD VFNMADD123SS VFNMADD123SD VFNMADD231SS
+syn keyword nasmInstructionINTEL_FMA VFNMADD231SD VFNMADD321SS VFNMADD321SD VFNMSUB132SS VFNMSUB132SD
+syn keyword nasmInstructionINTEL_FMA VFNMSUB312SS VFNMSUB312SD VFNMSUB213SS VFNMSUB213SD VFNMSUB123SS
+syn keyword nasmInstructionINTEL_FMA VFNMSUB123SD VFNMSUB231SS VFNMSUB231SD VFNMSUB321SS VFNMSUB321SD
+" INTEL_POST32
+syn keyword nasmInstructionINTEL_POST32 RDFSBASE RDGSBASE RDRAND WRFSBASE WRGSBASE
+syn keyword nasmInstructionINTEL_POST32 VCVTPH2PS VCVTPS2PH ADCX ADOX RDSEED
+" SUPERVISOR
+syn keyword nasmInstructionSUPERVISOR CLAC STAC
+" VIA_SECURITY
+syn keyword nasmInstructionVIA_SECURITY XSTORE XCRYPTECB XCRYPTCBC XCRYPTCTR XCRYPTCFB
+syn keyword nasmInstructionVIA_SECURITY XCRYPTOFB MONTMUL XSHA1 XSHA256
+" AMD_PROFILING
+syn keyword nasmInstructionAMD_PROFILING LLWPCB SLWPCB LWPVAL LWPINS
+" XOP_FMA4
+syn keyword nasmInstructionXOP_FMA4 VFMADDPD VFMADDPS VFMADDSD VFMADDSS VFMADDSUBPD
+syn keyword nasmInstructionXOP_FMA4 VFMADDSUBPS VFMSUBADDPD VFMSUBADDPS VFMSUBPD VFMSUBPS
+syn keyword nasmInstructionXOP_FMA4 VFMSUBSD VFMSUBSS VFNMADDPD VFNMADDPS VFNMADDSD
+syn keyword nasmInstructionXOP_FMA4 VFNMADDSS VFNMSUBPD VFNMSUBPS VFNMSUBSD VFNMSUBSS
+syn keyword nasmInstructionXOP_FMA4 VFRCZPD VFRCZPS VFRCZSD VFRCZSS VPCMOV
+syn keyword nasmInstructionXOP_FMA4 VPCOMB VPCOMD VPCOMQ VPCOMUB VPCOMUD
+syn keyword nasmInstructionXOP_FMA4 VPCOMUQ VPCOMUW VPCOMW VPHADDBD VPHADDBQ
+syn keyword nasmInstructionXOP_FMA4 VPHADDBW VPHADDDQ VPHADDUBD VPHADDUBQ VPHADDUBW
+syn keyword nasmInstructionXOP_FMA4 VPHADDUDQ VPHADDUWD VPHADDUWQ VPHADDWD VPHADDWQ
+syn keyword nasmInstructionXOP_FMA4 VPHSUBBW VPHSUBDQ VPHSUBWD VPMACSDD VPMACSDQH
+syn keyword nasmInstructionXOP_FMA4 VPMACSDQL VPMACSSDD VPMACSSDQH VPMACSSDQL VPMACSSWD
+syn keyword nasmInstructionXOP_FMA4 VPMACSSWW VPMACSWD VPMACSWW VPMADCSSWD VPMADCSWD
+syn keyword nasmInstructionXOP_FMA4 VPPERM VPROTB VPROTD VPROTQ VPROTW
+syn keyword nasmInstructionXOP_FMA4 VPSHAB VPSHAD VPSHAQ VPSHAW VPSHLB
+syn keyword nasmInstructionXOP_FMA4 VPSHLD VPSHLQ VPSHLW
+" AVX2
+syn keyword nasmInstructionAVX2 VMPSADBW VPABSB VPABSW VPABSD VPACKSSWB
+syn keyword nasmInstructionAVX2 VPACKSSDW VPACKUSDW VPACKUSWB VPADDB VPADDW
+syn keyword nasmInstructionAVX2 VPADDD VPADDQ VPADDSB VPADDSW VPADDUSB
+syn keyword nasmInstructionAVX2 VPADDUSW VPALIGNR VPAND VPANDN VPAVGB
+syn keyword nasmInstructionAVX2 VPAVGW VPBLENDVB VPBLENDW VPCMPEQB VPCMPEQW
+syn keyword nasmInstructionAVX2 VPCMPEQD VPCMPEQQ VPCMPGTB VPCMPGTW VPCMPGTD
+syn keyword nasmInstructionAVX2 VPCMPGTQ VPHADDW VPHADDD VPHADDSW VPHSUBW
+syn keyword nasmInstructionAVX2 VPHSUBD VPHSUBSW VPMADDUBSW VPMADDWD VPMAXSB
+syn keyword nasmInstructionAVX2 VPMAXSW VPMAXSD VPMAXUB VPMAXUW VPMAXUD
+syn keyword nasmInstructionAVX2 VPMINSB VPMINSW VPMINSD VPMINUB VPMINUW
+syn keyword nasmInstructionAVX2 VPMINUD VPMOVMSKB VPMOVSXBW VPMOVSXBD VPMOVSXBQ
+syn keyword nasmInstructionAVX2 VPMOVSXWD VPMOVSXWQ VPMOVSXDQ VPMOVZXBW VPMOVZXBD
+syn keyword nasmInstructionAVX2 VPMOVZXBQ VPMOVZXWD VPMOVZXWQ VPMOVZXDQ VPMULDQ
+syn keyword nasmInstructionAVX2 VPMULHRSW VPMULHUW VPMULHW VPMULLW VPMULLD
+syn keyword nasmInstructionAVX2 VPMULUDQ VPOR VPSADBW VPSHUFB VPSHUFD
+syn keyword nasmInstructionAVX2 VPSHUFHW VPSHUFLW VPSIGNB VPSIGNW VPSIGND
+syn keyword nasmInstructionAVX2 VPSLLDQ VPSLLW VPSLLD VPSLLQ VPSRAW
+syn keyword nasmInstructionAVX2 VPSRAD VPSRLDQ VPSRLW VPSRLD VPSRLQ
+syn keyword nasmInstructionAVX2 VPSUBB VPSUBW VPSUBD VPSUBQ VPSUBSB
+syn keyword nasmInstructionAVX2 VPSUBSW VPSUBUSB VPSUBUSW VPUNPCKHBW VPUNPCKHWD
+syn keyword nasmInstructionAVX2 VPUNPCKHDQ VPUNPCKHQDQ VPUNPCKLBW VPUNPCKLWD VPUNPCKLDQ
+syn keyword nasmInstructionAVX2 VPUNPCKLQDQ VPXOR VMOVNTDQA VBROADCASTSS VBROADCASTSD
+syn keyword nasmInstructionAVX2 VBROADCASTI128 VPBLENDD VPBROADCASTB VPBROADCASTW VPBROADCASTD
+syn keyword nasmInstructionAVX2 VPBROADCASTQ VPERMD VPERMPD VPERMPS VPERMQ
+syn keyword nasmInstructionAVX2 VPERM2I128 VEXTRACTI128 VINSERTI128 VPMASKMOVD VPMASKMOVQ
+syn keyword nasmInstructionAVX2 VPMASKMOVD VPMASKMOVQ VPSLLVD VPSLLVQ VPSLLVD
+syn keyword nasmInstructionAVX2 VPSLLVQ VPSRAVD VPSRLVD VPSRLVQ VPSRLVD
+syn keyword nasmInstructionAVX2 VPSRLVQ VGATHERDPD VGATHERQPD VGATHERDPD VGATHERQPD
+syn keyword nasmInstructionAVX2 VGATHERDPS VGATHERQPS VGATHERDPS VGATHERQPS VPGATHERDD
+syn keyword nasmInstructionAVX2 VPGATHERQD VPGATHERDD VPGATHERQD VPGATHERDQ VPGATHERQQ
+syn keyword nasmInstructionAVX2 VPGATHERDQ VPGATHERQQ
+" TRANSACTIONS
+syn keyword nasmInstructionTRANSACTIONS XABORT XBEGIN XEND XTEST
+" BMI_ABM
+syn keyword nasmInstructionBMI_ABM ANDN BEXTR BLCI BLCIC BLSI
+syn keyword nasmInstructionBMI_ABM BLSIC BLCFILL BLSFILL BLCMSK BLSMSK
+syn keyword nasmInstructionBMI_ABM BLSR BLCS BZHI MULX PDEP
+syn keyword nasmInstructionBMI_ABM PEXT RORX SARX SHLX SHRX
+syn keyword nasmInstructionBMI_ABM TZCNT TZMSK T1MSKC PREFETCHWT1
+" MPE
+syn keyword nasmInstructionMPE BNDMK BNDCL BNDCU BNDCN BNDMOV
+syn keyword nasmInstructionMPE BNDLDX BNDSTX
+" SHA
+syn keyword nasmInstructionSHA SHA1MSG1 SHA1MSG2 SHA1NEXTE SHA1RNDS4 SHA256MSG1
+syn keyword nasmInstructionSHA SHA256MSG2 SHA256RNDS2 VSHA512MSG1 VSHA512MSG2 VSHA512RNDS2
+" SM3
+syn keyword nasmInstructionSM3 VSM3MSG1 VSM3MSG2 VSM3RNDS2
+" SM4
+syn keyword nasmInstructionSM4 VSM4KEY4 VSM4RNDS4
+" AVX_NOEXCEPT
+syn keyword nasmInstructionAVX_NOEXCEPT VBCSTNEBF16PS VBCSTNESH2PS VCVTNEEBF162PS VCVTNEEPH2PS VCVTNEOBF162PS
+syn keyword nasmInstructionAVX_NOEXCEPT VCVTNEOPH2PS VCVTNEPS2BF16
+" AVX_VECTOR_NN
+syn keyword nasmInstructionAVX_VECTOR_NN VPDPBSSD VPDPBSSDS VPDPBSUD VPDPBSUDS VPDPBUUD
+syn keyword nasmInstructionAVX_VECTOR_NN VPDPBUUDS
+" AVX_IFMA
+syn keyword nasmInstructionAVX_IFMA VPMADD52HUQ VPMADD52LUQ
+" AVX512_MASK
+syn keyword nasmInstructionAVX512_MASK KADDB KADDD KADDQ KADDW KANDB
+syn keyword nasmInstructionAVX512_MASK KANDD KANDNB KANDND KANDNQ KANDNW
+syn keyword nasmInstructionAVX512_MASK KANDQ KANDW KMOVB KMOVD KMOVQ
+syn keyword nasmInstructionAVX512_MASK KMOVW KNOTB KNOTD KNOTQ KNOTW
+syn keyword nasmInstructionAVX512_MASK KORB KORD KORQ KORW KORTESTB
+syn keyword nasmInstructionAVX512_MASK KORTESTD KORTESTQ KORTESTW KSHIFTLB KSHIFTLD
+syn keyword nasmInstructionAVX512_MASK KSHIFTLQ KSHIFTLW KSHIFTRB KSHIFTRD KSHIFTRQ
+syn keyword nasmInstructionAVX512_MASK KSHIFTRW KTESTB KTESTD KTESTQ KTESTW
+syn keyword nasmInstructionAVX512_MASK KUNPCKBW KUNPCKDQ KUNPCKWD KXNORB KXNORD
+syn keyword nasmInstructionAVX512_MASK KXNORQ KXNORW KXORB KXORD KXORQ
+syn keyword nasmInstructionAVX512_MASK KXORW
+" AVX512_MASK_REG
+syn keyword nasmInstructionAVX512_MASK_REG KADD KAND KANDN KAND KMOV
+syn keyword nasmInstructionAVX512_MASK_REG KNOT KOR KORTEST KSHIFTL KSHIFTR
+syn keyword nasmInstructionAVX512_MASK_REG KTEST KUNPCK KXNOR KXOR
+" AVX512
+syn keyword nasmInstructionAVX512 VADDPD VADDPS VADDSD VADDSS VALIGND
+syn keyword nasmInstructionAVX512 VALIGNQ VANDNPD VANDNPS VANDPD VANDPS
+syn keyword nasmInstructionAVX512 VBLENDMPD VBLENDMPS VBROADCASTF32X2 VBROADCASTF32X4 VBROADCASTF32X8
+syn keyword nasmInstructionAVX512 VBROADCASTF64X2 VBROADCASTF64X4 VBROADCASTI32X2 VBROADCASTI32X4 VBROADCASTI32X8
+syn keyword nasmInstructionAVX512 VBROADCASTI64X2 VBROADCASTI64X4 VBROADCASTSD VBROADCASTSS VCMPEQPD
+syn keyword nasmInstructionAVX512 VCMPEQPS VCMPEQSD VCMPEQSS VCMPEQ_OQPD VCMPEQ_OQPS
+syn keyword nasmInstructionAVX512 VCMPEQ_OQSD VCMPEQ_OQSS VCMPLTPD VCMPLTPS VCMPLTSD
+syn keyword nasmInstructionAVX512 VCMPLTSS VCMPLT_OSPD VCMPLT_OSPS VCMPLT_OSSD VCMPLT_OSSS
+syn keyword nasmInstructionAVX512 VCMPLEPD VCMPLEPS VCMPLESD VCMPLESS VCMPLE_OSPD
+syn keyword nasmInstructionAVX512 VCMPLE_OSPS VCMPLE_OSSD VCMPLE_OSSS VCMPUNORDPD VCMPUNORDPS
+syn keyword nasmInstructionAVX512 VCMPUNORDSD VCMPUNORDSS VCMPUNORD_QPD VCMPUNORD_QPS VCMPUNORD_QSD
+syn keyword nasmInstructionAVX512 VCMPUNORD_QSS VCMPNEQPD VCMPNEQPS VCMPNEQSD VCMPNEQSS
+syn keyword nasmInstructionAVX512 VCMPNEQ_UQPD VCMPNEQ_UQPS VCMPNEQ_UQSD VCMPNEQ_UQSS VCMPNLTPD
+syn keyword nasmInstructionAVX512 VCMPNLTPS VCMPNLTSD VCMPNLTSS VCMPNLT_USPD VCMPNLT_USPS
+syn keyword nasmInstructionAVX512 VCMPNLT_USSD VCMPNLT_USSS VCMPNLEPD VCMPNLEPS VCMPNLESD
+syn keyword nasmInstructionAVX512 VCMPNLESS VCMPNLE_USPD VCMPNLE_USPS VCMPNLE_USSD VCMPNLE_USSS
+syn keyword nasmInstructionAVX512 VCMPORDPD VCMPORDPS VCMPORDSD VCMPORDSS VCMPORD_QPD
+syn keyword nasmInstructionAVX512 VCMPORD_QPS VCMPORD_QSD VCMPORD_QSS VCMPEQ_UQPD VCMPEQ_UQPS
+syn keyword nasmInstructionAVX512 VCMPEQ_UQSD VCMPEQ_UQSS VCMPNGEPD VCMPNGEPS VCMPNGESD
+syn keyword nasmInstructionAVX512 VCMPNGESS VCMPNGE_USPD VCMPNGE_USPS VCMPNGE_USSD VCMPNGE_USSS
+syn keyword nasmInstructionAVX512 VCMPNGTPD VCMPNGTPS VCMPNGTSD VCMPNGTSS VCMPNGT_USPD
+syn keyword nasmInstructionAVX512 VCMPNGT_USPS VCMPNGT_USSD VCMPNGT_USSS VCMPFALSEPD VCMPFALSEPS
+syn keyword nasmInstructionAVX512 VCMPFALSESD VCMPFALSESS VCMPFALSE_OQPD VCMPFALSE_OQPS VCMPFALSE_OQSD
+syn keyword nasmInstructionAVX512 VCMPFALSE_OQSS VCMPNEQ_OQPD VCMPNEQ_OQPS VCMPNEQ_OQSD VCMPNEQ_OQSS
+syn keyword nasmInstructionAVX512 VCMPGEPD VCMPGEPS VCMPGESD VCMPGESS VCMPGE_OSPD
+syn keyword nasmInstructionAVX512 VCMPGE_OSPS VCMPGE_OSSD VCMPGE_OSSS VCMPGTPD VCMPGTPS
+syn keyword nasmInstructionAVX512 VCMPGTSD VCMPGTSS VCMPGT_OSPD VCMPGT_OSPS VCMPGT_OSSD
+syn keyword nasmInstructionAVX512 VCMPGT_OSSS VCMPTRUEPD VCMPTRUEPS VCMPTRUESD VCMPTRUESS
+syn keyword nasmInstructionAVX512 VCMPTRUE_UQPD VCMPTRUE_UQPS VCMPTRUE_UQSD VCMPTRUE_UQSS VCMPEQ_OSPD
+syn keyword nasmInstructionAVX512 VCMPEQ_OSPS VCMPEQ_OSSD VCMPEQ_OSSS VCMPLT_OQPD VCMPLT_OQPS
+syn keyword nasmInstructionAVX512 VCMPLT_OQSD VCMPLT_OQSS VCMPLE_OQPD VCMPLE_OQPS VCMPLE_OQSD
+syn keyword nasmInstructionAVX512 VCMPLE_OQSS VCMPUNORD_SPD VCMPUNORD_SPS VCMPUNORD_SSD VCMPUNORD_SSS
+syn keyword nasmInstructionAVX512 VCMPNEQ_USPD VCMPNEQ_USPS VCMPNEQ_USSD VCMPNEQ_USSS VCMPNLT_UQPD
+syn keyword nasmInstructionAVX512 VCMPNLT_UQPS VCMPNLT_UQSD VCMPNLT_UQSS VCMPNLE_UQPD VCMPNLE_UQPS
+syn keyword nasmInstructionAVX512 VCMPNLE_UQSD VCMPNLE_UQSS VCMPORD_SPD VCMPORD_SPS VCMPORD_SSD
+syn keyword nasmInstructionAVX512 VCMPORD_SSS VCMPEQ_USPD VCMPEQ_USPS VCMPEQ_USSD VCMPEQ_USSS
+syn keyword nasmInstructionAVX512 VCMPNGE_UQPD VCMPNGE_UQPS VCMPNGE_UQSD VCMPNGE_UQSS VCMPNGT_UQPD
+syn keyword nasmInstructionAVX512 VCMPNGT_UQPS VCMPNGT_UQSD VCMPNGT_UQSS VCMPFALSE_OSPD VCMPFALSE_OSPS
+syn keyword nasmInstructionAVX512 VCMPFALSE_OSSD VCMPFALSE_OSSS VCMPNEQ_OSPD VCMPNEQ_OSPS VCMPNEQ_OSSD
+syn keyword nasmInstructionAVX512 VCMPNEQ_OSSS VCMPGE_OQPD VCMPGE_OQPS VCMPGE_OQSD VCMPGE_OQSS
+syn keyword nasmInstructionAVX512 VCMPGT_OQPD VCMPGT_OQPS VCMPGT_OQSD VCMPGT_OQSS VCMPTRUE_USPD
+syn keyword nasmInstructionAVX512 VCMPTRUE_USPS VCMPTRUE_USSD VCMPTRUE_USSS VCMPPD VCMPPS
+syn keyword nasmInstructionAVX512 VCMPSD VCMPSS VCOMISD VCOMISS VCOMPRESSPD
+syn keyword nasmInstructionAVX512 VCOMPRESSPS VCVTDQ2PD VCVTDQ2PS VCVTPD2DQ VCVTPD2PS
+syn keyword nasmInstructionAVX512 VCVTPD2QQ VCVTPD2UDQ VCVTPD2UQQ VCVTPH2PS VCVTPS2DQ
+syn keyword nasmInstructionAVX512 VCVTPS2PD VCVTPS2PH VCVTPS2QQ VCVTPS2UDQ VCVTPS2UQQ
+syn keyword nasmInstructionAVX512 VCVTQQ2PD VCVTQQ2PS VCVTSD2SI VCVTSD2SS VCVTSD2USI
+syn keyword nasmInstructionAVX512 VCVTSI2SD VCVTSI2SS VCVTSS2SD VCVTSS2SI VCVTSS2USI
+syn keyword nasmInstructionAVX512 VCVTTPD2DQ VCVTTPD2QQ VCVTTPD2UDQ VCVTTPD2UQQ VCVTTPS2DQ
+syn keyword nasmInstructionAVX512 VCVTTPS2QQ VCVTTPS2UDQ VCVTTPS2UQQ VCVTTSD2SI VCVTTSD2USI
+syn keyword nasmInstructionAVX512 VCVTTSS2SI VCVTTSS2USI VCVTUDQ2PD VCVTUDQ2PS VCVTUQQ2PD
+syn keyword nasmInstructionAVX512 VCVTUQQ2PS VCVTUSI2SD VCVTUSI2SS VDBPSADBW VDIVPD
+syn keyword nasmInstructionAVX512 VDIVPS VDIVSD VDIVSS VEXP2PD VEXP2PS
+syn keyword nasmInstructionAVX512 VEXPANDPD VEXPANDPS VEXTRACTF32X4 VEXTRACTF32X8 VEXTRACTF64X2
+syn keyword nasmInstructionAVX512 VEXTRACTF64X4 VEXTRACTI32X4 VEXTRACTI32X8 VEXTRACTI64X2 VEXTRACTI64X4
+syn keyword nasmInstructionAVX512 VEXTRACTPS VFIXUPIMMPD VFIXUPIMMPS VFIXUPIMMSD VFIXUPIMMSS
+syn keyword nasmInstructionAVX512 VFMADD132PD VFMADD132PS VFMADD132SD VFMADD132SS VFMADD213PD
+syn keyword nasmInstructionAVX512 VFMADD213PS VFMADD213SD VFMADD213SS VFMADD231PD VFMADD231PS
+syn keyword nasmInstructionAVX512 VFMADD231SD VFMADD231SS VFMADDSUB132PD VFMADDSUB132PS VFMADDSUB213PD
+syn keyword nasmInstructionAVX512 VFMADDSUB213PS VFMADDSUB231PD VFMADDSUB231PS VFMSUB132PD VFMSUB132PS
+syn keyword nasmInstructionAVX512 VFMSUB132SD VFMSUB132SS VFMSUB213PD VFMSUB213PS VFMSUB213SD
+syn keyword nasmInstructionAVX512 VFMSUB213SS VFMSUB231PD VFMSUB231PS VFMSUB231SD VFMSUB231SS
+syn keyword nasmInstructionAVX512 VFMSUBADD132PD VFMSUBADD132PS VFMSUBADD213PD VFMSUBADD213PS VFMSUBADD231PD
+syn keyword nasmInstructionAVX512 VFMSUBADD231PS VFNMADD132PD VFNMADD132PS VFNMADD132SD VFNMADD132SS
+syn keyword nasmInstructionAVX512 VFNMADD213PD VFNMADD213PS VFNMADD213SD VFNMADD213SS VFNMADD231PD
+syn keyword nasmInstructionAVX512 VFNMADD231PS VFNMADD231SD VFNMADD231SS VFNMSUB132PD VFNMSUB132PS
+syn keyword nasmInstructionAVX512 VFNMSUB132SD VFNMSUB132SS VFNMSUB213PD VFNMSUB213PS VFNMSUB213SD
+syn keyword nasmInstructionAVX512 VFNMSUB213SS VFNMSUB231PD VFNMSUB231PS VFNMSUB231SD VFNMSUB231SS
+syn keyword nasmInstructionAVX512 VFPCLASSPD VFPCLASSPS VFPCLASSSD VFPCLASSSS VGATHERDPD
+syn keyword nasmInstructionAVX512 VGATHERDPS VGATHERPF0DPD VGATHERPF0DPS VGATHERPF0QPD VGATHERPF0QPS
+syn keyword nasmInstructionAVX512 VGATHERPF1DPD VGATHERPF1DPS VGATHERPF1QPD VGATHERPF1QPS VGATHERQPD
+syn keyword nasmInstructionAVX512 VGATHERQPS VGETEXPPD VGETEXPPS VGETEXPSD VGETEXPSS
+syn keyword nasmInstructionAVX512 VGETMANTPD VGETMANTPS VGETMANTSD VGETMANTSS VINSERTF32X4
+syn keyword nasmInstructionAVX512 VINSERTF32X8 VINSERTF64X2 VINSERTF64X4 VINSERTI32X4 VINSERTI32X8
+syn keyword nasmInstructionAVX512 VINSERTI64X2 VINSERTI64X4 VINSERTPS VMAXPD VMAXPS
+syn keyword nasmInstructionAVX512 VMAXSD VMAXSS VMINPD VMINPS VMINSD
+syn keyword nasmInstructionAVX512 VMINSS VMOVAPD VMOVAPS VMOVD VMOVDDUP
+syn keyword nasmInstructionAVX512 VMOVDQA32 VMOVDQA64 VMOVDQU16 VMOVDQU32 VMOVDQU64
+syn keyword nasmInstructionAVX512 VMOVDQU8 VMOVHLPS VMOVHPD VMOVHPS VMOVLHPS
+syn keyword nasmInstructionAVX512 VMOVLPD VMOVLPS VMOVNTDQ VMOVNTDQA VMOVNTPD
+syn keyword nasmInstructionAVX512 VMOVNTPS VMOVQ VMOVSD VMOVSHDUP VMOVSLDUP
+syn keyword nasmInstructionAVX512 VMOVSS VMOVUPD VMOVUPS VMULPD VMULPS
+syn keyword nasmInstructionAVX512 VMULSD VMULSS VORPD VORPS VPABSB
+syn keyword nasmInstructionAVX512 VPABSD VPABSQ VPABSW VPACKSSDW VPACKSSWB
+syn keyword nasmInstructionAVX512 VPACKUSDW VPACKUSWB VPADDB VPADDD VPADDQ
+syn keyword nasmInstructionAVX512 VPADDSB VPADDSW VPADDUSB VPADDUSW VPADDW
+syn keyword nasmInstructionAVX512 VPALIGNR VPANDD VPANDND VPANDNQ VPANDQ
+syn keyword nasmInstructionAVX512 VPAVGB VPAVGW VPBLENDMB VPBLENDMD VPBLENDMQ
+syn keyword nasmInstructionAVX512 VPBLENDMW VPBROADCASTB VPBROADCASTD VPBROADCASTMB2Q VPBROADCASTMW2D
+syn keyword nasmInstructionAVX512 VPBROADCASTQ VPBROADCASTW VPCMPEQB VPCMPEQD VPCMPEQQ
+syn keyword nasmInstructionAVX512 VPCMPEQW VPCMPGTB VPCMPGTD VPCMPGTQ VPCMPGTW
+syn keyword nasmInstructionAVX512 VPCMPEQB VPCMPEQD VPCMPEQQ VPCMPEQUB VPCMPEQUD
+syn keyword nasmInstructionAVX512 VPCMPEQUQ VPCMPEQUW VPCMPEQW VPCMPGEB VPCMPGED
+syn keyword nasmInstructionAVX512 VPCMPGEQ VPCMPGEUB VPCMPGEUD VPCMPGEUQ VPCMPGEUW
+syn keyword nasmInstructionAVX512 VPCMPGEW VPCMPGTB VPCMPGTD VPCMPGTQ VPCMPGTUB
+syn keyword nasmInstructionAVX512 VPCMPGTUD VPCMPGTUQ VPCMPGTUW VPCMPGTW VPCMPLEB
+syn keyword nasmInstructionAVX512 VPCMPLED VPCMPLEQ VPCMPLEUB VPCMPLEUD VPCMPLEUQ
+syn keyword nasmInstructionAVX512 VPCMPLEUW VPCMPLEW VPCMPLTB VPCMPLTD VPCMPLTQ
+syn keyword nasmInstructionAVX512 VPCMPLTUB VPCMPLTUD VPCMPLTUQ VPCMPLTUW VPCMPLTW
+syn keyword nasmInstructionAVX512 VPCMPNEQB VPCMPNEQD VPCMPNEQQ VPCMPNEQUB VPCMPNEQUD
+syn keyword nasmInstructionAVX512 VPCMPNEQUQ VPCMPNEQUW VPCMPNEQW VPCMPNGTB VPCMPNGTD
+syn keyword nasmInstructionAVX512 VPCMPNGTQ VPCMPNGTUB VPCMPNGTUD VPCMPNGTUQ VPCMPNGTUW
+syn keyword nasmInstructionAVX512 VPCMPNGTW VPCMPNLEB VPCMPNLED VPCMPNLEQ VPCMPNLEUB
+syn keyword nasmInstructionAVX512 VPCMPNLEUD VPCMPNLEUQ VPCMPNLEUW VPCMPNLEW VPCMPNLTB
+syn keyword nasmInstructionAVX512 VPCMPNLTD VPCMPNLTQ VPCMPNLTUB VPCMPNLTUD VPCMPNLTUQ
+syn keyword nasmInstructionAVX512 VPCMPNLTUW VPCMPNLTW VPCMPB VPCMPD VPCMPQ
+syn keyword nasmInstructionAVX512 VPCMPUB VPCMPUD VPCMPUQ VPCMPUW VPCMPW
+syn keyword nasmInstructionAVX512 VPCOMPRESSD VPCOMPRESSQ VPCONFLICTD VPCONFLICTQ VPERMB
+syn keyword nasmInstructionAVX512 VPERMD VPERMI2B VPERMI2D VPERMI2PD VPERMI2PS
+syn keyword nasmInstructionAVX512 VPERMI2Q VPERMI2W VPERMILPD VPERMILPS VPERMPD
+syn keyword nasmInstructionAVX512 VPERMPS VPERMQ VPERMT2B VPERMT2D VPERMT2PD
+syn keyword nasmInstructionAVX512 VPERMT2PS VPERMT2Q VPERMT2W VPERMW VPEXPANDD
+syn keyword nasmInstructionAVX512 VPEXPANDQ VPEXTRB VPEXTRD VPEXTRQ VPEXTRW
+syn keyword nasmInstructionAVX512 VPGATHERDD VPGATHERDQ VPGATHERQD VPGATHERQQ VPINSRB
+syn keyword nasmInstructionAVX512 VPINSRD VPINSRQ VPINSRW VPLZCNTD VPLZCNTQ
+syn keyword nasmInstructionAVX512 VPMADD52HUQ VPMADD52LUQ VPMADDUBSW VPMADDWD VPMAXSB
+syn keyword nasmInstructionAVX512 VPMAXSD VPMAXSQ VPMAXSW VPMAXUB VPMAXUD
+syn keyword nasmInstructionAVX512 VPMAXUQ VPMAXUW VPMINSB VPMINSD VPMINSQ
+syn keyword nasmInstructionAVX512 VPMINSW VPMINUB VPMINUD VPMINUQ VPMINUW
+syn keyword nasmInstructionAVX512 VPMOVB2M VPMOVD2M VPMOVDB VPMOVDW VPMOVM2B
+syn keyword nasmInstructionAVX512 VPMOVM2D VPMOVM2Q VPMOVM2W VPMOVQ2M VPMOVQB
+syn keyword nasmInstructionAVX512 VPMOVQD VPMOVQW VPMOVSDB VPMOVSDW VPMOVSQB
+syn keyword nasmInstructionAVX512 VPMOVSQD VPMOVSQW VPMOVSWB VPMOVSXBD VPMOVSXBQ
+syn keyword nasmInstructionAVX512 VPMOVSXBW VPMOVSXDQ VPMOVSXWD VPMOVSXWQ VPMOVUSDB
+syn keyword nasmInstructionAVX512 VPMOVUSDW VPMOVUSQB VPMOVUSQD VPMOVUSQW VPMOVUSWB
+syn keyword nasmInstructionAVX512 VPMOVW2M VPMOVWB VPMOVZXBD VPMOVZXBQ VPMOVZXBW
+syn keyword nasmInstructionAVX512 VPMOVZXDQ VPMOVZXWD VPMOVZXWQ VPMULDQ VPMULHRSW
+syn keyword nasmInstructionAVX512 VPMULHUW VPMULHW VPMULLD VPMULLQ VPMULLW
+syn keyword nasmInstructionAVX512 VPMULTISHIFTQB VPMULUDQ VPORD VPORQ VPROLD
+syn keyword nasmInstructionAVX512 VPROLQ VPROLVD VPROLVQ VPRORD VPRORQ
+syn keyword nasmInstructionAVX512 VPRORVD VPRORVQ VPSADBW VPSCATTERDD VPSCATTERDQ
+syn keyword nasmInstructionAVX512 VPSCATTERQD VPSCATTERQQ VPSHUFB VPSHUFD VPSHUFHW
+syn keyword nasmInstructionAVX512 VPSHUFLW VPSLLD VPSLLDQ VPSLLQ VPSLLVD
+syn keyword nasmInstructionAVX512 VPSLLVQ VPSLLVW VPSLLW VPSRAD VPSRAQ
+syn keyword nasmInstructionAVX512 VPSRAVD VPSRAVQ VPSRAVW VPSRAW VPSRLD
+syn keyword nasmInstructionAVX512 VPSRLDQ VPSRLQ VPSRLVD VPSRLVQ VPSRLVW
+syn keyword nasmInstructionAVX512 VPSRLW VPSUBB VPSUBD VPSUBQ VPSUBSB
+syn keyword nasmInstructionAVX512 VPSUBSW VPSUBUSB VPSUBUSW VPSUBW VPTERNLOGD
+syn keyword nasmInstructionAVX512 VPTERNLOGQ VPTESTMB VPTESTMD VPTESTMQ VPTESTMW
+syn keyword nasmInstructionAVX512 VPTESTNMB VPTESTNMD VPTESTNMQ VPTESTNMW VPUNPCKHBW
+syn keyword nasmInstructionAVX512 VPUNPCKHDQ VPUNPCKHQDQ VPUNPCKHWD VPUNPCKLBW VPUNPCKLDQ
+syn keyword nasmInstructionAVX512 VPUNPCKLQDQ VPUNPCKLWD VPXORD VPXORQ VRANGEPD
+syn keyword nasmInstructionAVX512 VRANGEPS VRANGESD VRANGESS VRCP14PD VRCP14PS
+syn keyword nasmInstructionAVX512 VRCP14SD VRCP14SS VRCP28PD VRCP28PS VRCP28SD
+syn keyword nasmInstructionAVX512 VRCP28SS VREDUCEPD VREDUCEPS VREDUCESD VREDUCESS
+syn keyword nasmInstructionAVX512 VRNDSCALEPD VRNDSCALEPS VRNDSCALESD VRNDSCALESS VRSQRT14PD
+syn keyword nasmInstructionAVX512 VRSQRT14PS VRSQRT14SD VRSQRT14SS VRSQRT28PD VRSQRT28PS
+syn keyword nasmInstructionAVX512 VRSQRT28SD VRSQRT28SS VSCALEFPD VSCALEFPS VSCALEFSD
+syn keyword nasmInstructionAVX512 VSCALEFSS VSCATTERDPD VSCATTERDPS VSCATTERPF0DPD VSCATTERPF0DPS
+syn keyword nasmInstructionAVX512 VSCATTERPF0QPD VSCATTERPF0QPS VSCATTERPF1DPD VSCATTERPF1DPS VSCATTERPF1QPD
+syn keyword nasmInstructionAVX512 VSCATTERPF1QPS VSCATTERQPD VSCATTERQPS VSHUFF32X4 VSHUFF64X2
+syn keyword nasmInstructionAVX512 VSHUFI32X4 VSHUFI64X2 VSHUFPD VSHUFPS VSQRTPD
+syn keyword nasmInstructionAVX512 VSQRTPS VSQRTSD VSQRTSS VSUBPD VSUBPS
+syn keyword nasmInstructionAVX512 VSUBSD VSUBSS VUCOMISD VUCOMISS VUNPCKHPD
+syn keyword nasmInstructionAVX512 VUNPCKHPS VUNPCKLPD VUNPCKLPS VXORPD VXORPS
+" PROTECTION
+syn keyword nasmInstructionPROTECTION RDPKRU WRPKRU
+" RDPID
+syn keyword nasmInstructionRDPID RDPID
+" NMEM
+syn keyword nasmInstructionNMEM CLFLUSHOPT CLWB PCOMMIT
+syn keyword nasmInstructionNMEM CLZERO
+" INTEL_EXTENSIONS
+syn keyword nasmInstructionINTEL_EXTENSIONS CLDEMOTE MOVDIRI MOVDIR64B PCONFIG TPAUSE
+syn keyword nasmInstructionINTEL_EXTENSIONS UMONITOR UMWAIT WBNOINVD
+" GALOISFIELD
+syn keyword nasmInstructionGALOISFIELD GF2P8AFFINEINVQB VGF2P8AFFINEINVQB GF2P8AFFINEQB VGF2P8AFFINEQB GF2P8MULB
+syn keyword nasmInstructionGALOISFIELD VGF2P8MULB
+" AVX512_BMI
+syn keyword nasmInstructionAVX512_BMI VPCOMPRESSB VPCOMPRESSW VPEXPANDB VPEXPANDW VPSHLDW
+syn keyword nasmInstructionAVX512_BMI VPSHLDD VPSHLDQ VPSHLDVW VPSHLDVD VPSHLDVQ
+syn keyword nasmInstructionAVX512_BMI VPSHRDW VPSHRDD VPSHRDQ VPSHRDVW VPSHRDVD
+syn keyword nasmInstructionAVX512_BMI VPSHRDVQ
+" AVX512_VNNI
+syn keyword nasmInstructionAVX512_VNNI VPDPBUSD VPDPBUSDS VPDPWSSD VPDPWSSDS
+" AVX512_BITALG
+syn keyword nasmInstructionAVX512_BITALG VPOPCNTB VPOPCNTW VPOPCNTD VPOPCNTQ VPSHUFBITQMB
+" AVX512_FMA
+syn keyword nasmInstructionAVX512_FMA V4FMADDPS V4FNMADDPS V4FMADDSS V4FNMADDSS
+" AVX512_DP
+syn keyword nasmInstructionAVX512_DP V4DPWSSDS V4DPWSSD
+" SGX
+syn keyword nasmInstructionSGX ENCLS ENCLU ENCLV
+" CET
+syn keyword nasmInstructionCET CLRSSBSY ENDBR32 ENDBR64 INCSSPD INCSSPQ
+syn keyword nasmInstructionCET RDSSPD RDSSPQ RSTORSSP SAVEPREVSSP SETSSBSY
+syn keyword nasmInstructionCET WRUSSD WRUSSQ WRSSD WRSSQ
+" INTEL_EXTENSION
+syn keyword nasmInstructionINTEL_EXTENSION ENQCMD ENQCMDS PCONFIG SERIALIZE WBNOINVD
+syn keyword nasmInstructionINTEL_EXTENSION XRESLDTRK XSUSLDTRK
+" AVX512_BF16
+syn keyword nasmInstructionAVX512_BF16 VCVTNE2PS2BF16 VCVTNEPS2BF16 VDPBF16PS
+" AVX512_MASK_INTERSECT
+syn keyword nasmInstructionAVX512_MASK_INTERSECT VP2INTERSECTD
+" AMX
+syn keyword nasmInstructionAMX LDTILECFG STTILECFG TDPBF16PS TDPBSSD TDPBSUD
+syn keyword nasmInstructionAMX TDPBUSD TDPBUUD TILELOADD TILELOADDT1 TILERELEASE
+syn keyword nasmInstructionAMX TILESTORED TILEZERO
+" AVX512_FP16
+syn keyword nasmInstructionAVX512_FP16 VADDPH VADDSH VCMPPH VCMPSH VCOMISH
+syn keyword nasmInstructionAVX512_FP16 VCVTDQ2PH VCVTPD2PH VCVTPH2DQ VCVTPH2PD VCVTPH2PS
+syn keyword nasmInstructionAVX512_FP16 VCVTPH2PSX VCVTPH2QQ VCVTPH2UDQ VCVTPH2UQQ VCVTPH2UW
+syn keyword nasmInstructionAVX512_FP16 VCVTPH2W VCVTPS2PH VCVTQQ2PH VCVTSD2SH VCVTSH2SD
+syn keyword nasmInstructionAVX512_FP16 VCVTSH2SI VCVTSH2SS VCVTSH2USI VCVTSI2SH VCVTSS2SH
+syn keyword nasmInstructionAVX512_FP16 VCVTTPH2DQ VCVTTPH2QQ VCVTTPH2UDQ VCVTTPH2UQQ VCVTTPH2UW
+syn keyword nasmInstructionAVX512_FP16 VCVTTPH2W VCVTTSH2SI VCVTTSH2USI VCVTUDQ2PH VCVTUQQ2PH
+syn keyword nasmInstructionAVX512_FP16 VCVTUSI2SH VCVTUSI2SS VCVTUW2PH VCVTW2PH VDIVPH
+syn keyword nasmInstructionAVX512_FP16 VDIVSH VFCMADDCPH VFMADDCPH VFCMADDCSH VFMADDCSH
+syn keyword nasmInstructionAVX512_FP16 VFCMULCPCH VFMULCPCH VFCMULCSH VFMULCSH VFMADDSUB132PH
+syn keyword nasmInstructionAVX512_FP16 VFMADDSUB213PH VFMADDSUB231PH VFMSUBADD132PH VFMSUBADD213PH VFMSUBADD231PH
+syn keyword nasmInstructionAVX512_FP16 VPMADD132PH VPMADD213PH VPMADD231PH VFMADD132PH VFMADD213PH
+syn keyword nasmInstructionAVX512_FP16 VFMADD231PH VPMADD132SH VPMADD213SH VPMADD231SH VPNMADD132SH
+syn keyword nasmInstructionAVX512_FP16 VPNMADD213SH VPNMADD231SH VPMSUB132PH VPMSUB213PH VPMSUB231PH
+syn keyword nasmInstructionAVX512_FP16 VFMSUB132PH VFMSUB213PH VFMSUB231PH VPMSUB132SH VPMSUB213SH
+syn keyword nasmInstructionAVX512_FP16 VPMSUB231SH VPNMSUB132SH VPNMSUB213SH VPNMSUB231SH VFPCLASSPH
+syn keyword nasmInstructionAVX512_FP16 VFPCLASSSH VGETEXPPH VGETEXPSH VGETMANTPH VGETMANTSH
+syn keyword nasmInstructionAVX512_FP16 VGETMAXPH VGETMAXSH VGETMINPH VGETMINSH VMOVSH
+syn keyword nasmInstructionAVX512_FP16 VMOVW VMULPH VMULSH VRCPPH VRCPSH
+syn keyword nasmInstructionAVX512_FP16 VREDUCEPH VREDUCESH VENDSCALEPH VENDSCALESH VRSQRTPH
+syn keyword nasmInstructionAVX512_FP16 VRSQRTSH VSCALEFPH VSCALEFSH VSQRTPH VSQRTSH
+syn keyword nasmInstructionAVX512_FP16 VSUBPH VSUBSH VUCOMISH
+" RAO-INT
+syn keyword nasmInstructionRAO_INT AADD AAND AXOR
+" USERINT
+syn keyword nasmInstructionUSERINT CLUI SENDUIPI STUI TESTUI UIRET
+" CMPCCXADD
+syn keyword nasmInstructionCMPCCXADD CMPOXADD CMPNOXADD CMPBXADD CMPNBXADD CMPZXADD
+syn keyword nasmInstructionCMPCCXADD CMPNZXADD CMPBEXADD CMPNBEXADD CMPSXADD CMPNSXADD
+syn keyword nasmInstructionCMPCCXADD CMPPXADD CMPNPXADD CMPLXADD CMPNLXADD CMPLEXADD
+syn keyword nasmInstructionCMPCCXADD CMPNLEXADD
+" FRET
+syn keyword nasmInstructionFRET ERETS ERETU LKGS
+" WRMSRNS_MSRLIST
+syn keyword nasmInstructionWRMSRNS_MSRLIST WRMSRNS RDMSRLIST WRMSRLIST
+" HRESET
+syn keyword nasmInstructionHRESET HRESET
+" PTWRITE
+syn keyword nasmInstructionPTWRITE PTWRITE
+" HINTNOP
+syn keyword nasmInstructionHINTNOP HINT_NOP0 HINT_NOP1 HINT_NOP2 HINT_NOP3 HINT_NOP4
+syn keyword nasmInstructionHINTNOP HINT_NOP5 HINT_NOP6 HINT_NOP7 HINT_NOP8 HINT_NOP9
+syn keyword nasmInstructionHINTNOP HINT_NOP10 HINT_NOP11 HINT_NOP12 HINT_NOP13 HINT_NOP14
+syn keyword nasmInstructionHINTNOP HINT_NOP15 HINT_NOP16 HINT_NOP17 HINT_NOP18 HINT_NOP19
+syn keyword nasmInstructionHINTNOP HINT_NOP20 HINT_NOP21 HINT_NOP22 HINT_NOP23 HINT_NOP24
+syn keyword nasmInstructionHINTNOP HINT_NOP25 HINT_NOP26 HINT_NOP27 HINT_NOP28 HINT_NOP29
+syn keyword nasmInstructionHINTNOP HINT_NOP30 HINT_NOP31 HINT_NOP32 HINT_NOP33 HINT_NOP34
+syn keyword nasmInstructionHINTNOP HINT_NOP35 HINT_NOP36 HINT_NOP37 HINT_NOP38 HINT_NOP39
+syn keyword nasmInstructionHINTNOP HINT_NOP40 HINT_NOP41 HINT_NOP42 HINT_NOP43 HINT_NOP44
+syn keyword nasmInstructionHINTNOP HINT_NOP45 HINT_NOP46 HINT_NOP47 HINT_NOP48 HINT_NOP49
+syn keyword nasmInstructionHINTNOP HINT_NOP50 HINT_NOP51 HINT_NOP52 HINT_NOP53 HINT_NOP54
+syn keyword nasmInstructionHINTNOP HINT_NOP55 HINT_NOP56 HINT_NOP57 HINT_NOP58 HINT_NOP59
+syn keyword nasmInstructionHINTNOP HINT_NOP60 HINT_NOP61 HINT_NOP62 HINT_NOP63
" Cyrix instructions (requires Cyrix processor)
-syn keyword nasmCrxInstruction PADDSIW PAVEB PDISTIB PMAGW PMULHRW[C] PMULHRIW
+syn keyword nasmCrxInstruction PADDSIW PAVEB PDISTIB PMAGW PMULHRWC PMULHRIW
syn keyword nasmCrxInstruction PMVGEZB PMVLZB PMVNZB PMVZB PSUBSIW
syn keyword nasmCrxInstruction RDSHR RSDC RSLDT SMINT SMINTOLD SVDC SVLDT SVTS
-syn keyword nasmCrxInstruction WRSHR
-" AMD instructions (requires AMD processor)
-syn keyword nasmAmdInstruction SYSCALL SYSRET
-
-
-" Undocumented Instructions:
-syn match nasmUndInstruction "\<POP\s[^;]*\<CS\>"me=s+3
-syn keyword nasmUndInstruction CMPXCHG486 IBTS ICEBP INT01 INT03 LOADALL
-syn keyword nasmUndInstruction LOADALL286 LOADALL386 SALC SMI UD1 UMOV XBTS
+syn keyword nasmCrxInstruction WRSHR BB0_RESET BB1_RESET
+syn keyword nasmCrxInstruction CPU_WRITE CPU_READ DMINT RDM PMACHRIW
+" Debugging Instructions: (privileged)
+syn keyword nasmDbgInstruction INT1 INT3 RDMSR RDTSC RDPMC WRMSR INT01 INT03
" Synchronize Syntax:
@@ -529,7 +1064,12 @@ hi def link nasmBinNumber Number
hi def link nasmOctNumber Number
hi def link nasmDecNumber Number
hi def link nasmHexNumber Number
-hi def link nasmFltNumber Float
+hi def link nasmBinFloat Float
+hi def link nasmOctFloat Float
+hi def link nasmDecFloat Float
+hi def link nasmHexFloat Float
+hi def link nasmSpecFloat Float
+hi def link nasmBcdConst Float
hi def link nasmNumberError Error
" Identifier Group:
@@ -563,6 +1103,7 @@ hi def link nasmStdDirective Operator
hi def link nasmFmtDirective Keyword
" Register Group:
+hi def link nasmRegisterError Error
hi def link nasmCtrlRegister Special
hi def link nasmDebugRegister Debug
hi def link nasmTestRegister Special
@@ -570,19 +1111,81 @@ hi def link nasmRegisterError Error
hi def link nasmMemRefError Error
" Instruction Group:
-hi def link nasmStdInstruction Statement
-hi def link nasmSysInstruction Statement
-hi def link nasmDbgInstruction Debug
-hi def link nasmFpuInstruction Statement
-hi def link nasmMmxInstruction Statement
-hi def link nasmSseInstruction Statement
-hi def link nasmF16cInstruction Statement
-hi def link nasmAVXInstruction Statement
-hi def link nasmNowInstruction Statement
-hi def link nasmAmdInstruction Special
-hi def link nasmCrxInstruction Special
-hi def link nasmUndInstruction Todo
hi def link nasmInstructnError Error
+hi def link nasmCrxInstruction Special
+hi def link nasmDbgInstruction Debug
+hi def link nasmInstructionStandard Statement
+hi def link nasmInstructionSIMD Statement
+hi def link nasmInstructionSSE Statement
+hi def link nasmInstructionXSAVE Statement
+hi def link nasmInstructionMEM Statement
+hi def link nasmInstructionMMX Statement
+hi def link nasmInstruction3DNOW Statement
+hi def link nasmInstructionSSE2 Statement
+hi def link nasmInstructionWMMX Statement
+hi def link nasmInstructionWSSD Statement
+hi def link nasmInstructionPRESSCOT Statement
+hi def link nasmInstructionVMXSVM Statement
+hi def link nasmInstructionPTVMX Statement
+hi def link nasmInstructionSEVSNPAMD Statement
+hi def link nasmInstructionTEJAS Statement
+hi def link nasmInstructionAMD_SSE4A Statement
+hi def link nasmInstructionBARCELONA Statement
+hi def link nasmInstructionPENRY Statement
+hi def link nasmInstructionNEHALEM Statement
+hi def link nasmInstructionSMX Statement
+hi def link nasmInstructionGEODE_3DNOW Statement
+hi def link nasmInstructionINTEL_NEW Statement
+hi def link nasmInstructionAES Statement
+hi def link nasmInstructionAVX_AES Statement
+hi def link nasmInstructionINTEL_PUB Statement
+hi def link nasmInstructionAVX Statement
+hi def link nasmInstructionINTEL_CMUL Statement
+hi def link nasmInstructionINTEL_AVX_CMUL Statement
+hi def link nasmInstructionINTEL_FMA Statement
+hi def link nasmInstructionINTEL_POST32 Statement
+hi def link nasmInstructionSUPERVISOR Statement
+hi def link nasmInstructionVIA_SECURITY Statement
+hi def link nasmInstructionAMD_PROFILING Statement
+hi def link nasmInstructionXOP_FMA4 Statement
+hi def link nasmInstructionAVX2 Statement
+hi def link nasmInstructionTRANSACTIONS Statement
+hi def link nasmInstructionBMI_ABM Statement
+hi def link nasmInstructionMPE Statement
+hi def link nasmInstructionSHA Statement
+hi def link nasmInstructionSM3 Statement
+hi def link nasmInstructionSM4 Statement
+hi def link nasmInstructionAVX_NOEXCEPT Statement
+hi def link nasmInstructionAVX_VECTOR_NN Statement
+hi def link nasmInstructionAVX_IFMA Statement
+hi def link nasmInstructionAVX512_MASK Statement
+hi def link nasmInstructionAVX512_MASK_REG Statement
+hi def link nasmInstructionAVX512 Statement
+hi def link nasmInstructionPROTECTION Statement
+hi def link nasmInstructionRDPID Statement
+hi def link nasmInstructionNMEM Statement
+hi def link nasmInstructionINTEL_EXTENSIONS Statement
+hi def link nasmInstructionGALOISFIELD Statement
+hi def link nasmInstructionAVX512_BMI Statement
+hi def link nasmInstructionAVX512_VNNI Statement
+hi def link nasmInstructionAVX512_BITALG Statement
+hi def link nasmInstructionAVX512_FMA Statement
+hi def link nasmInstructionAVX512_DP Statement
+hi def link nasmInstructionSGX Statement
+hi def link nasmInstructionCET Statement
+hi def link nasmInstructionINTEL_EXTENSION Statement
+hi def link nasmInstructionAVX512_BF16 Statement
+hi def link nasmInstructionAVX512_MASK_INTERSECT Statement
+hi def link nasmInstructionAMX Statement
+hi def link nasmInstructionAVX512_FP16 Statement
+hi def link nasmInstructionRAO_INT Statement
+hi def link nasmInstructionUSERINT Statement
+hi def link nasmInstructionCMPCCXADD Statement
+hi def link nasmInstructionFRET Statement
+hi def link nasmInstructionWRMSRNS_MSRLIST Statement
+hi def link nasmInstructionHRESET Statement
+hi def link nasmInstructionHINTNOP Statement
+hi def link nasmInstructionPTWRITE Statement
let b:current_syntax = "nasm"
diff --git a/runtime/syntax/neomuttlog.vim b/runtime/syntax/neomuttlog.vim
new file mode 100644
index 0000000000..27f73493bd
--- /dev/null
+++ b/runtime/syntax/neomuttlog.vim
@@ -0,0 +1,69 @@
+" Vim syntax file
+" Language: NeoMutt log files
+" Maintainer: Richard Russon <rich@flatcap.org>
+" Last Change: 2024 Oct 12
+
+" quit when a syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+syntax match neolog_date "\v^\[\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] *" conceal
+syntax match neolog_version "\v<NeoMutt-\d{8}(-\d+-\x+)*(-dirty)*>"
+syntax match neolog_banner "\v^\[\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] .*" contains=neolog_date,neolog_version
+syntax match neolog_function "\v%26v\i+\(\)"
+
+syntax match neolog_perror_key "\v%22v\<P\> " conceal transparent
+syntax match neolog_error_key "\v%22v\<E\> " conceal transparent
+syntax match neolog_warning_key "\v%22v\<W\> " conceal transparent
+syntax match neolog_message_key "\v%22v\<M\> " conceal transparent
+syntax match neolog_debug1_key "\v%22v\<1\> " conceal transparent
+syntax match neolog_debug2_key "\v%22v\<2\> " conceal transparent
+syntax match neolog_debug3_key "\v%22v\<3\> " conceal transparent
+syntax match neolog_debug4_key "\v%22v\<4\> " conceal transparent
+syntax match neolog_debug5_key "\v%22v\<5\> " conceal transparent
+syntax match neolog_notify_key "\v%22v\<N\> " conceal transparent
+
+syntax match neolog_perror "\v%22v\<P\> .*" contains=neolog_perror_key,neolog_function
+syntax match neolog_error "\v%22v\<E\> .*" contains=neolog_error_key,neolog_function
+syntax match neolog_warning "\v%22v\<W\> .*" contains=neolog_warning_key,neolog_function
+syntax match neolog_message "\v%22v\<M\> .*" contains=neolog_message_key,neolog_function
+syntax match neolog_debug1 "\v%22v\<1\> .*" contains=neolog_debug1_key,neolog_function
+syntax match neolog_debug2 "\v%22v\<2\> .*" contains=neolog_debug2_key,neolog_function
+syntax match neolog_debug3 "\v%22v\<3\> .*" contains=neolog_debug3_key,neolog_function
+syntax match neolog_debug4 "\v%22v\<4\> .*" contains=neolog_debug4_key,neolog_function
+syntax match neolog_debug5 "\v%22v\<5\> .*" contains=neolog_debug5_key,neolog_function
+syntax match neolog_notify "\v%22v\<N\> .*" contains=neolog_notify_key,neolog_function
+
+if !exists('g:neolog_disable_default_colors')
+ highlight neolog_date ctermfg=cyan guifg=#40ffff
+ highlight neolog_banner ctermfg=magenta guifg=#ff00ff
+ highlight neolog_version cterm=reverse gui=reverse
+ highlight neolog_function guibg=#282828
+
+ highlight neolog_perror ctermfg=red guifg=#ff8080
+ highlight neolog_error ctermfg=red guifg=#ff8080
+ highlight neolog_warning ctermfg=yellow guifg=#ffff80
+ highlight neolog_message ctermfg=green guifg=#80ff80
+ highlight neolog_debug1 ctermfg=white guifg=#ffffff
+ highlight neolog_debug2 ctermfg=white guifg=#ffffff
+ highlight neolog_debug3 ctermfg=grey guifg=#c0c0c0
+ highlight neolog_debug4 ctermfg=grey guifg=#c0c0c0
+ highlight neolog_debug5 ctermfg=grey guifg=#c0c0c0
+ highlight neolog_notify ctermfg=grey guifg=#c0c0c0
+endif
+
+highlight link neolog_perror_key neolog_perror
+highlight link neolog_error_key neolog_error
+highlight link neolog_warning_key neolog_warning
+highlight link neolog_message_key neolog_message
+highlight link neolog_debug1_key neolog_debug1
+highlight link neolog_debug2_key neolog_debug2
+highlight link neolog_debug3_key neolog_debug3
+highlight link neolog_debug4_key neolog_debug4
+highlight link neolog_debug5_key neolog_debug5
+highlight link neolog_notify_key neolog_notify
+
+let b:current_syntax = "neomuttlog"
+
+" vim: ts=2 et tw=100 sw=2 sts=0 ft=vim
diff --git a/runtime/syntax/neomuttrc.vim b/runtime/syntax/neomuttrc.vim
index 421b11ffa3..815e160bbb 100644
--- a/runtime/syntax/neomuttrc.vim
+++ b/runtime/syntax/neomuttrc.vim
@@ -2,10 +2,10 @@
" Language: NeoMutt setup files
" Maintainer: Richard Russon <rich@flatcap.org>
" Previous Maintainer: Guillaume Brogi <gui-gui@netcourrier.com>
-" Last Change: 2022-04-08
+" Last Change: 2024 Oct 12
" Original version based on syntax/muttrc.vim
-" This file covers NeoMutt 2022-04-08
+" This file covers NeoMutt 2024-10-02
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -22,7 +22,7 @@ setlocal isk=@,48-57,_,-
syntax match muttrcComment "^# .*$" contains=@Spell
syntax match muttrcComment "^#[^ ].*$"
syntax match muttrcComment "^#$"
-syntax match muttrcComment "[^\\]#.*$"lc=1
+syntax match muttrcComment "[^\\]#.*$"lc=1 contains=@Spell
" Escape sequences (back-tick and pipe goes here too)
syntax match muttrcEscape +\\[#tnr"'Cc ]+
@@ -34,7 +34,7 @@ syntax region muttrcString contained keepend start=+"+ms=e skip=+\\"+ end=+"+ co
syntax region muttrcString contained keepend start=+'+ms=e skip=+\\'+ end=+'+ contains=muttrcEscape,muttrcCommand,muttrcAction
syntax match muttrcStringNL contained skipwhite skipnl "\s*\\$" nextgroup=muttrcString,muttrcStringNL
-syntax region muttrcShellString matchgroup=muttrcEscape keepend start=+`+ skip=+\\`+ end=+`+ contains=muttrcVarStr,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcCommand
+syntax region muttrcShellString matchgroup=muttrcEscape keepend start=+`+ skip=+\\`+ end=+`+ contains=muttrcVarString,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcCommand
syntax match muttrcRXChars contained /[^\\][][.*?+]\+/hs=s+1
syntax match muttrcRXChars contained /[][|()][.*?+]*/
@@ -67,21 +67,21 @@ syntax match muttrcRXDef contained "-rx\s\+" skipwhite nextgroup=muttrcRXPat
syntax match muttrcSpecial +\(['"]\)!\1+
-syntax match muttrcSetStrAssignment contained skipwhite /=\s*\%(\\\?\$\)\?[0-9A-Za-z_-]\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable
-syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*"+hs=s+1 end=+"+ skip=+\\"+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcString
-syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*'+hs=s+1 end=+'+ skip=+\\'+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcString
-syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable
-syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetBoolAssignment contained skipwhite /=\s*"\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetBoolAssignment contained skipwhite /=\s*'\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable
-syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\%(ask-\)\?\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetQuadAssignment contained skipwhite /=\s*"\%(ask-\)\?\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetQuadAssignment contained skipwhite /=\s*'\%(ask-\)\?\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetNumAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable
-syntax match muttrcSetNumAssignment contained skipwhite /=\s*\d\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetNumAssignment contained skipwhite /=\s*"\d\+"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax match muttrcSetNumAssignment contained skipwhite /=\s*'\d\+'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax match muttrcSetStrAssignment contained skipwhite /=\s*\%(\\\?\$\)\?[0-9A-Za-z_-]\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcVariable,muttrcEscapedVariable
+syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*"+hs=s+1 end=+"+ skip=+\\"+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcString
+syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*'+hs=s+1 end=+'+ skip=+\\'+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcString
+syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcVariable,muttrcEscapedVariable
+syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetBoolAssignment contained skipwhite /=\s*"\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetBoolAssignment contained skipwhite /=\s*'\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcVariable,muttrcEscapedVariable
+syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\%(ask-\)\?\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetQuadAssignment contained skipwhite /=\s*"\%(ask-\)\?\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetQuadAssignment contained skipwhite /=\s*'\%(ask-\)\?\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetNumAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString contains=muttrcVariable,muttrcEscapedVariable
+syntax match muttrcSetNumAssignment contained skipwhite /=\s*\d\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetNumAssignment contained skipwhite /=\s*"\d\+"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax match muttrcSetNumAssignment contained skipwhite /=\s*'\d\+'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" Now catch some email addresses and headers (purified version from mail.vim)
syntax match muttrcEmail "[a-zA-Z0-9._-]\+@[a-zA-Z0-9./-]\+"
@@ -101,38 +101,9 @@ syntax match muttrcStrftimeEscapes contained /%[AaBbCcDdeFGgHhIjklMmnpRrSsTtUuVv
syntax match muttrcStrftimeEscapes contained /%E[cCxXyY]/
syntax match muttrcStrftimeEscapes contained /%O[BdeHImMSuUVwWy]/
-syntax region muttrcAliasFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcAliasFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcAttachFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcAttachFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcComposeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcComposeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcFolderFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcFolderFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcMixFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcMixFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPatternFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPatternFormatEscapes,muttrcPatternFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPatternFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPatternFormatEscapes,muttrcPatternFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPGPFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcPGPFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcQueryFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcQueryFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcStatusFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcStatusFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-
-" Format escapes and conditionals
+" Defines syntax matches for muttrc[baseName]Escapes, muttrc[baseName]Conditionals
+" If padding==1, also match `%>` `%|` `%*` expandos
+" If conditional==1, some expandos support %X? format
syntax match muttrcFormatConditionals2 contained /[^?]*?/
function! s:escapesConditionals(baseName, sequence, padding, conditional)
exec 'syntax match muttrc' . a:baseName . 'Escapes contained /%\%(\%(-\?[0-9]\+\)\?\%(\.[0-9]\+\)\?\)\?[:_]\?\%(' . a:sequence . '\|%\)/'
@@ -146,65 +117,107 @@ function! s:escapesConditionals(baseName, sequence, padding, conditional)
endif
endfunction
-" CHECKED 2022-04-08
-" Ref: alias_format_str() in alias/dlg_alias.c
-call s:escapesConditionals('AliasFormat', '[acfnrt]', 1, 0)
-" Ref: attach_format_str() in attach/dlg_attach.c
+" CHECKED 2024 Oct 12
+" Ref: AliasFormatDef in alias/config.c
+call s:escapesConditionals('AliasFormat', '[acfnrtY]', 1, 0)
+" Ref: AttachFormatDef in mutt_config.c
call s:escapesConditionals('AttachFormat', '[CcDdeFfIMmnQsTtuX]', 1, 1)
-" Ref: compose_format_str() in compose/cbar.c
+" Ref: AutocryptFormatDef in autocrypt/config.c
+call s:escapesConditionals('AutocryptFormat', '[aknps]', 1, 0)
+" Ref: ComposeFormatDef in compose/config.c
call s:escapesConditionals('ComposeFormat', '[ahlv]', 1, 1)
-" Ref: folder_format_str() in browser/browser.c
-call s:escapesConditionals('FolderFormat', '[CDdFfgilmNnstu]', 1, 0)
-" Ref: group_index_format_str() in nntp/browse.c
-call s:escapesConditionals('GroupIndexFormat', '[CdfMNns]', 1, 1)
-" Ref: index_format_str() in hdrline.c
+" Ref: FolderFormatDef in browser/config.c
+call s:escapesConditionals('FolderFormat', '[aCDdFfgilmNnpstu[]', 1, 1)
+" Ref: GreetingFormatDef in send/config.c
+call s:escapesConditionals('GreetingFormat', '[nuv]', 0, 0)
+" Ref: GroupIndexFormatDef in browser/config.c
+call s:escapesConditionals('GroupIndexFormat', '[aCdfMNnps]', 1, 0)
+" Ref: HistoryFormatDef in history/config.c
+call s:escapesConditionals('HistoryFormat', '[Cs]', 1, 0)
+" Ref: IndexFormatDef in mutt_config.c
call s:escapesConditionals('IndexFormat', '[AaBbCDdEefgHIiJKLlMmNnOPqRrSsTtuvWXxYyZ(<[{]\|@\i\+@\|G[a-zA-Z]\+\|Fp\=\|z[cst]\|cr\=', 1, 1)
-" Ref: mix_format_str() in remailer.c
-call s:escapesConditionals('MixFormat', '[acns]', 1, 0)
-" Ref: pattern_format_str() in pattern/dlg_pattern.c
+" Ref: PatternFormatDef in pattern/config.c
call s:escapesConditionals('PatternFormat', '[den]', 1, 0)
-" Ref: pgp_command_format_str() in ncrypt/pgpinvoke.c
-call s:escapesConditionals('PGPCmdFormat', '[afprs]', 0, 1)
-" Ref: crypt_format_str() in ncrypt/dlg_gpgme.c
-" Ref: pgp_entry_format_str() in ncrypt/dlg_pgp.c
-" Note: crypt_format_str() supports 'p', but pgp_entry_fmt() does not
-call s:escapesConditionals('PGPFormat', '[AaCcFfKkLlnptu[]', 0, 0)
-" Ref: query_format_str() in alias/dlg_query.c
-call s:escapesConditionals('QueryFormat', '[acent]', 1, 1)
-" Ref: sidebar_format_str() in sidebar/window.c
-call s:escapesConditionals('SidebarFormat', '[!BDdFLNnorStZ]', 1, 1)
-" Ref: smime_command_format_str() in ncrypt/smime.c
-call s:escapesConditionals('SmimeFormat', '[aCcdfiks]', 0, 1)
-" Ref: status_format_str() in status.c
+" Ref: PgpCommandFormatDef in ncrypt/config.c
+call s:escapesConditionals('PgpCommandFormat', '[afprs]', 0, 1)
+" Ref: PgpEntryFormatDef in ncrypt/config.c
+call s:escapesConditionals('PgpEntryFormat', '[AaCcFfIiKkLlnptu[]', 1, 1)
+" Ref: QueryFormatDef in alias/config.c
+call s:escapesConditionals('QueryFormat', '[acentY]', 1, 1)
+" Ref: SidebarFormatDef in sidebar/config.c
+call s:escapesConditionals('SidebarFormat', '[!aBDdFLNnoprStZ]', 1, 1)
+" Ref: SmimeCommandFormatDef in ncrypt/config.c
+call s:escapesConditionals('SmimeCommandFormat', '[aCcdfiks]', 0, 1)
+" Ref: StatusFormatDef in mutt_config.c
call s:escapesConditionals('StatusFormat', '[bDdFfhLlMmnoPpRrSsTtuVv]', 1, 1)
-syntax region muttrcPGPTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes
+syntax region muttrcAliasFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcAliasFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcAttachFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcAttachFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcAutocryptFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAutocryptFormatEscapes,muttrcAutocryptFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcAutocryptFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAutocryptFormatEscapes,muttrcAutocryptFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcComposeFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcComposeFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcFolderFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcFolderFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcGreetingFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcGreetingFormatEscapes,muttrcGreetingFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcGreetingFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcGreetingFormatEscapes,muttrcGreetingFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcGroupIndexFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcGroupIndexFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcHistoryFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcHistoryFormatEscapes,muttrcHistoryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcHistoryFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcHistoryFormatEscapes,muttrcHistoryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcIndexFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcIndexFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPatternFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPatternFormatEscapes,muttrcPatternFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPatternFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPatternFormatEscapes,muttrcPatternFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPgpCommandFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPgpCommandFormatEscapes,muttrcPgpCommandFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPgpCommandFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPgpCommandFormatEscapes,muttrcPgpCommandFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPgpEntryFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPgpEntryFormatEscapes,muttrcPgpEntryFormatConditionals,muttrcFormatErrors,muttrcPgpTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcPgpEntryFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPgpEntryFormatEscapes,muttrcPgpEntryFormatConditionals,muttrcFormatErrors,muttrcPgpTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcQueryFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcQueryFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcSidebarFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcSidebarFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcSmimeCommandFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSmimeCommandFormatEscapes,muttrcSmimeCommandFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcSmimeCommandFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSmimeCommandFormatEscapes,muttrcSmimeCommandFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcStatusFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcStatusFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcStrftimeFormatString contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax region muttrcStrftimeFormatString contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+
+" Format escapes and conditionals
+syntax match muttrcFormatConditionals2 contained /[^?]*?/
+
+syntax region muttrcPgpTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes
syntax region muttrcTimeEscapes contained start=+%(+ end=+)+ contains=muttrcStrftimeEscapes
syntax region muttrcTimeEscapes contained start=+%<+ end=+>+ contains=muttrcStrftimeEscapes
syntax region muttrcTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes
syntax region muttrcTimeEscapes contained start=+%{+ end=+}+ contains=muttrcStrftimeEscapes
-syntax match muttrcVarEqualsAliasFmt contained skipwhite "=" nextgroup=muttrcAliasFormatStr
-syntax match muttrcVarEqualsAttachFmt contained skipwhite "=" nextgroup=muttrcAttachFormatStr
-syntax match muttrcVarEqualsComposeFmt contained skipwhite "=" nextgroup=muttrcComposeFormatStr
-syntax match muttrcVarEqualsFolderFmt contained skipwhite "=" nextgroup=muttrcFolderFormatStr
-syntax match muttrcVarEqualsGrpIdxFmt contained skipwhite "=" nextgroup=muttrcGroupIndexFormatStr
-syntax match muttrcVarEqualsIdxFmt contained skipwhite "=" nextgroup=muttrcIndexFormatStr
-syntax match muttrcVarEqualsMixFmt contained skipwhite "=" nextgroup=muttrcMixFormatStr
-syntax match muttrcVarEqualsPatternFmt contained skipwhite "=" nextgroup=muttrcPatternFormatStr
-syntax match muttrcVarEqualsPGPCmdFmt contained skipwhite "=" nextgroup=muttrcPGPCmdFormatStr
-syntax match muttrcVarEqualsPGPFmt contained skipwhite "=" nextgroup=muttrcPGPFormatStr
-syntax match muttrcVarEqualsQueryFmt contained skipwhite "=" nextgroup=muttrcQueryFormatStr
-syntax match muttrcVarEqualsSdbFmt contained skipwhite "=" nextgroup=muttrcSidebarFormatStr
-syntax match muttrcVarEqualsSmimeFmt contained skipwhite "=" nextgroup=muttrcSmimeFormatStr
-syntax match muttrcVarEqualsStatusFmt contained skipwhite "=" nextgroup=muttrcStatusFormatStr
-syntax match muttrcVarEqualsStrftimeFmt contained skipwhite "=" nextgroup=muttrcStrftimeFormatStr
-
-syntax match muttrcVPrefix contained /[?&]/ nextgroup=muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-
-" CHECKED 2022-04-08
+syntax match muttrcVarEqualsAliasFormat contained skipwhite "=" nextgroup=muttrcAliasFormatString
+syntax match muttrcVarEqualsAttachFormat contained skipwhite "=" nextgroup=muttrcAttachFormatString
+syntax match muttrcVarEqualsAutocryptFormat contained skipwhite "=" nextgroup=muttrcAutocryptFormatString
+syntax match muttrcVarEqualsComposeFormat contained skipwhite "=" nextgroup=muttrcComposeFormatString
+syntax match muttrcVarEqualsFolderFormat contained skipwhite "=" nextgroup=muttrcFolderFormatString
+syntax match muttrcVarEqualsGreetingFormat contained skipwhite "=" nextgroup=muttrcGreetingFormatString
+syntax match muttrcVarEqualsGroupIndexFormat contained skipwhite "=" nextgroup=muttrcGroupIndexFormatString
+syntax match muttrcVarEqualsHistoryFormat contained skipwhite "=" nextgroup=muttrcHistoryFormatString
+syntax match muttrcVarEqualsIndexFormat contained skipwhite "=" nextgroup=muttrcIndexFormatString
+syntax match muttrcVarEqualsPatternFormat contained skipwhite "=" nextgroup=muttrcPatternFormatString
+syntax match muttrcVarEqualsPgpCommandFormat contained skipwhite "=" nextgroup=muttrcPgpCommandFormatString
+syntax match muttrcVarEqualsPgpEntryFormat contained skipwhite "=" nextgroup=muttrcPgpEntryFormatString
+syntax match muttrcVarEqualsQueryFormat contained skipwhite "=" nextgroup=muttrcQueryFormatString
+syntax match muttrcVarEqualsSidebarFormat contained skipwhite "=" nextgroup=muttrcSidebarFormatString
+syntax match muttrcVarEqualsSmimeCommandFormat contained skipwhite "=" nextgroup=muttrcSmimeCommandFormatString
+syntax match muttrcVarEqualsStatusFormat contained skipwhite "=" nextgroup=muttrcStatusFormatString
+syntax match muttrcVarEqualsStrftimeFormat contained skipwhite "=" nextgroup=muttrcStrftimeFormatString
+
+syntax match muttrcVPrefix contained /[?&]/ nextgroup=muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+
+" CHECKED 2024 Oct 12
" List of the different screens in NeoMutt (see MenuNames in menu/type.c)
-syntax keyword muttrcMenu contained alias attach autocrypt browser compose editor generic index key_select_pgp key_select_smime mix pager pgp postpone query smime
+syntax keyword muttrcMenu contained alias attach autocrypt browser compose dialog editor generic index key_select_pgp key_select_smime pager pgp postpone query smime
syntax match muttrcMenuList "\S\+" contained contains=muttrcMenu
syntax match muttrcMenuCommas /,/ contained
@@ -239,10 +252,12 @@ syntax match muttrcEscapedVariable contained "\\\$[a-zA-Z_-]\+"
syntax match muttrcBadAction contained "[^<>]\+" contains=muttrcEmail
syntax match muttrcAction contained "<[^>]\{-}>" contains=muttrcBadAction,muttrcFunction,muttrcKeyName
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" First, hooks that take regular expressions:
-syntax match muttrcRXHookNot contained /!\s*/ skipwhite nextgroup=muttrcRXHookString,muttrcRXHookStringNL
-syntax match muttrcRXHooks /\<\%(account\|append\|close\|crypt\|folder\|mbox\|open\|pgp\)-hook\>/ skipwhite nextgroup=muttrcRXHookNot,muttrcRXHookString,muttrcRXHookStringNL
+syntax match muttrcRXHookNot contained /!\s*/ skipwhite nextgroup=muttrcRXHookString,muttrcRXHookStringNL
+syntax match muttrcRXHookNoRegex contained /-noregex/ skipwhite nextgroup=muttrcRXHookString,muttrcRXHookStringNL
+syntax match muttrcRXHooks /\<\%(account\|append\|close\|crypt\|open\|pgp\|shutdown\|startup\|timeout\)-hook\>/ skipwhite nextgroup=muttrcRXHookNot,muttrcRXHookString,muttrcRXHookStringNL
+syntax match muttrcRXHooks /\<\%(folder\|mbox\)-hook\>/ skipwhite nextgroup=muttrcRXHookNoRegex,muttrcRXHookNot,muttrcRXHookString,muttrcRXHookStringNL
" Now, hooks that take patterns
syntax match muttrcPatHookNot contained /!\s*/ skipwhite nextgroup=muttrcPattern
@@ -252,11 +267,11 @@ syntax match muttrcPatHooks /\<\%(message\|reply\|send\|send2\|save\|fcc\|fcc-sa
" Global hooks that take a command
syntax keyword muttrcHooks skipwhite shutdown-hook startup-hook timeout-hook nextgroup=muttrcCommand
-syntax match muttrcBindFunction contained /\S\+\>/ skipwhite contains=muttrcFunction
+syntax match muttrcBindFunction contained /\S\+\>/ skipwhite contains=muttrcFunction
syntax match muttrcBindFunctionNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcBindFunction,muttrcBindFunctionNL
-syntax match muttrcBindKey contained /\S\+/ skipwhite contains=muttrcKey nextgroup=muttrcBindFunction,muttrcBindFunctionNL
-syntax match muttrcBindKeyNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcBindKey,muttrcBindKeyNL
-syntax match muttrcBindMenuList contained /\S\+/ skipwhite contains=muttrcMenu,muttrcMenuCommas nextgroup=muttrcBindKey,muttrcBindKeyNL
+syntax match muttrcBindKey contained /\S\+/ skipwhite contains=muttrcKey nextgroup=muttrcBindFunction,muttrcBindFunctionNL
+syntax match muttrcBindKeyNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcBindKey,muttrcBindKeyNL
+syntax match muttrcBindMenuList contained /\S\+/ skipwhite contains=muttrcMenu,muttrcMenuCommas nextgroup=muttrcBindKey,muttrcBindKeyNL
syntax match muttrcBindMenuListNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcBindMenuList,muttrcBindMenuListNL
syntax region muttrcMacroDescr contained keepend skipwhite start=+\s*\S+ms=e skip=+\\ + end=+ \|$+me=s
@@ -300,7 +315,7 @@ syntax match muttrcAliasNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrc
syntax match muttrcUnAliasKey contained "\s*\w\+\s*" skipwhite nextgroup=muttrcUnAliasKey,muttrcUnAliasNL
syntax match muttrcUnAliasNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcUnAliasKey,muttrcUnAliasNL
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of letters in Flags in pattern/flags.c
" Parameter: none
syntax match muttrcSimplePat contained "!\?\^\?[~][ADEFGgklNOPpQRSTUuVv#$=]"
@@ -309,7 +324,7 @@ syntax match muttrcSimplePat contained "!\?\^\?[~][mnXz]\s*\%([<>-][0-9]\+[kM]\?
" Parameter: date
syntax match muttrcSimplePat contained "!\?\^\?[~][dr]\s*\%(\%(-\?[0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)*\)\|\%(\%([0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)*\)-\%([0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)\?\)\?\)\|\%([<>=][0-9]\+[ymwd]\)\|\%(`[^`]\+`\)\|\%(\$[a-zA-Z0-9_-]\+\)\)" contains=muttrcShellString,muttrcVariable
" Parameter: regex
-syntax match muttrcSimplePat contained "!\?\^\?[~][BbCcefHhIiLMstwxYy]\s*" nextgroup=muttrcSimplePatRXContainer
+syntax match muttrcSimplePat contained "!\?\^\?[~][BbCcefHhIiKLMstwxYy]\s*" nextgroup=muttrcSimplePatRXContainer
" Parameter: pattern
syntax match muttrcSimplePat contained "!\?\^\?[%][BbCcefHhiLstxy]\s*" nextgroup=muttrcSimplePatString
" Parameter: pattern
@@ -341,21 +356,25 @@ syntax match muttrcPattern contained skipwhite /[.]/
syntax region muttrcPatternInner contained keepend start=+"[~=%!(^]+ms=s+1 skip=+\\"+ end=+"+me=e-1 contains=muttrcSimplePat,muttrcUnHighlightSpace,muttrcSimplePatMetas
syntax region muttrcPatternInner contained keepend start=+'[~=%!(^]+ms=s+1 skip=+\\'+ end=+'+me=e-1 contains=muttrcSimplePat,muttrcUnHighlightSpace,muttrcSimplePatMetas
-" Colour definitions takes object, foreground and background arguments (regexps excluded).
+" Colour definitions takes object, foreground and background arguments (regexes excluded).
syntax match muttrcColorMatchCount contained "[0-9]\+"
syntax match muttrcColorMatchCountNL contained skipwhite skipnl "\s*\\$" nextgroup=muttrcColorMatchCount,muttrcColorMatchCountNL
syntax region muttrcColorRXPat contained start=+\s*'+ skip=+\\'+ end=+'\s*+ keepend skipwhite contains=muttrcRXString2 nextgroup=muttrcColorMatchCount,muttrcColorMatchCountNL
syntax region muttrcColorRXPat contained start=+\s*"+ skip=+\\"+ end=+"\s*+ keepend skipwhite contains=muttrcRXString2 nextgroup=muttrcColorMatchCount,muttrcColorMatchCountNL
syntax keyword muttrcColor contained black blue cyan default green magenta red white yellow
syntax keyword muttrcColor contained brightblack brightblue brightcyan brightdefault brightgreen brightmagenta brightred brightwhite brightyellow
+syntax keyword muttrcColor contained lightblack lightblue lightcyan lightdefault lightgreen lightmagenta lightred lightwhite lightyellow
+syntax keyword muttrcColor contained alertblack alertblue alertcyan alertdefault alertgreen alertmagenta alertred alertwhite alertyellow
syntax match muttrcColor contained "\<\%(bright\)\=color\d\{1,3}\>"
+syntax match muttrcColor contained "#[0-9a-fA-F]\{6}\>"
+
" Now for the structure of the color line
syntax match muttrcColorRXNL contained skipnl "\s*\\$" nextgroup=muttrcColorRXPat,muttrcColorRXNL
-syntax match muttrcColorBG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorRXPat,muttrcColorRXNL
+syntax match muttrcColorBG contained /\s*[#$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorRXPat,muttrcColorRXNL
syntax match muttrcColorBGNL contained skipnl "\s*\\$" nextgroup=muttrcColorBG,muttrcColorBGNL
-syntax match muttrcColorFG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorBG,muttrcColorBGNL
+syntax match muttrcColorFG contained /\s*[#$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorBG,muttrcColorBGNL
syntax match muttrcColorFGNL contained skipnl "\s*\\$" nextgroup=muttrcColorFG,muttrcColorFGNL
-syntax match muttrcColorContext contained /\s*[$]\?\w\+/ contains=muttrcColorField,muttrcVariable,muttrcUnHighlightSpace,muttrcColorCompose nextgroup=muttrcColorFG,muttrcColorFGNL
+syntax match muttrcColorContext contained /\s*[#$]\?\w\+/ contains=muttrcColorField,muttrcVariable,muttrcUnHighlightSpace,muttrcColorCompose nextgroup=muttrcColorFG,muttrcColorFGNL
syntax match muttrcColorNL contained skipnl "\s*\\$" nextgroup=muttrcColorContext,muttrcColorNL,muttrcColorCompose
syntax match muttrcColorKeyword contained /^\s*color\s\+/ nextgroup=muttrcColorContext,muttrcColorNL,muttrcColorCompose
" And now color's brother:
@@ -370,25 +389,26 @@ syntax match muttrcUnColorIndexNL contained skipwhite skipnl /\s*\\$/ nextgroup=
syntax match muttrcUnColorKeyword contained skipwhite /^\s*uncolor\s\+/ nextgroup=muttrcUnColorIndex,muttrcUnColorIndexNL
syntax region muttrcUnColorLine keepend start=+^\s*uncolor\s+ skip=+\\$+ end=+$+ contains=muttrcUnColorKeyword,muttrcComment,muttrcUnHighlightSpace
-syntax keyword muttrcMonoAttrib contained bold none normal reverse standout underline
+syntax keyword muttrcMonoAttrib contained bold italic none normal reverse standout underline
syntax keyword muttrcMono contained mono skipwhite nextgroup=muttrcColorField,muttrcColorCompose
syntax match muttrcMonoLine "^\s*mono\s\+\S\+" skipwhite nextgroup=muttrcMonoAttrib contains=muttrcMono
-" CHECKED 2022-04-08
-" List of fields in ColorFields in color/commmand.c
+" CHECKED 2024 Oct 12
+" List of fields in ColorFields in color/command.c
syntax keyword muttrcColorField skipwhite contained
\ attachment attach_headers body bold error hdrdefault header index index_author
\ index_collapsed index_date index_flags index_label index_number index_size index_subject
- \ index_tag index_tags indicator markers message normal options progress prompt quoted
- \ search sidebar_divider sidebar_flagged sidebar_highlight sidebar_indicator sidebar_new
- \ sidebar_ordinary sidebar_spoolfile sidebar_unread signature status tilde tree underline
- \ warning nextgroup=muttrcColor
+ \ index_tag index_tags indicator italic markers message normal options progress prompt
+ \ search sidebar_background sidebar_divider sidebar_flagged sidebar_highlight
+ \ sidebar_indicator sidebar_new sidebar_ordinary sidebar_spool_file sidebar_unread signature
+ \ status stripe_even stripe_odd tilde tree underline warning
+ \ nextgroup=muttrcColor
syntax match muttrcColorField contained "\<quoted\d\=\>"
syntax match muttrcColorCompose skipwhite contained /\s*compose\s*/ nextgroup=muttrcColorComposeField
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of fields in ComposeColorFields in color/command.c
syntax keyword muttrcColorComposeField skipwhite contained
\ header security_both security_encrypt security_none security_sign
@@ -409,37 +429,39 @@ function! s:boolQuadGen(type, vars, deprecated)
exec 'syntax keyword muttrcVar' . l:type . ' ' . join(l:invvars)
else
let l:type = a:type
- exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(a:vars) . ' nextgroup=muttrcSet' . l:orig_type . 'Assignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr'
- exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:novars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr'
- exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:invvars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr'
+ exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(a:vars) . ' nextgroup=muttrcSet' . l:orig_type . 'Assignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString'
+ exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:novars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString'
+ exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:invvars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString'
endif
endfunction
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of DT_BOOL in MuttVars in mutt_config.c
call s:boolQuadGen('Bool', [
\ 'abort_backspace', 'allow_8bit', 'allow_ansi', 'arrow_cursor', 'ascii_chars', 'ask_bcc',
- \ 'ask_cc', 'ask_follow_up', 'ask_x_comment_to', 'attach_save_without_prompting',
+ \ 'ask_cc', 'ask_followup_to', 'ask_x_comment_to', 'attach_save_without_prompting',
\ 'attach_split', 'autocrypt', 'autocrypt_reply', 'auto_edit', 'auto_subscribe', 'auto_tag',
\ 'beep', 'beep_new', 'bounce_delivered', 'braille_friendly',
- \ 'browser_abbreviate_mailboxes', 'change_folder_next', 'check_mbox_size', 'check_new',
- \ 'collapse_all', 'collapse_flagged', 'collapse_unread', 'compose_show_user_headers',
+ \ 'browser_abbreviate_mailboxes', 'browser_sort_dirs_first', 'change_folder_next',
+ \ 'check_mbox_size', 'check_new', 'collapse_all', 'collapse_flagged', 'collapse_unread',
+ \ 'color_directcolor', 'compose_confirm_detach_first', 'compose_show_user_headers',
\ 'confirm_append', 'confirm_create', 'copy_decode_weed', 'count_alternatives',
\ 'crypt_auto_encrypt', 'crypt_auto_pgp', 'crypt_auto_sign', 'crypt_auto_smime',
- \ 'crypt_confirm_hook', 'crypt_opportunistic_encrypt',
+ \ 'crypt_confirm_hook', 'crypt_encryption_info', 'crypt_opportunistic_encrypt',
\ 'crypt_opportunistic_encrypt_strong_keys', 'crypt_protected_headers_read',
- \ 'crypt_protected_headers_save', 'crypt_protected_headers_write', 'crypt_reply_encrypt',
- \ 'crypt_reply_sign', 'crypt_reply_sign_encrypted', 'crypt_timestamp', 'crypt_use_gpgme',
- \ 'crypt_use_pka', 'delete_untag', 'digest_collapse', 'duplicate_threads', 'edit_headers',
- \ 'encode_from', 'fast_reply', 'fcc_before_send', 'fcc_clear', 'flag_safe', 'followup_to',
- \ 'force_name', 'forward_decode', 'forward_decrypt', 'forward_quote', 'forward_references',
- \ 'hdrs', 'header', 'header_color_partial', 'help', 'hidden_host', 'hide_limited',
- \ 'hide_missing', 'hide_thread_subject', 'hide_top_limited', 'hide_top_missing',
- \ 'history_remove_dups', 'honor_disposition', 'idn_decode', 'idn_encode',
- \ 'ignore_list_reply_to', 'imap_check_subscribed', 'imap_condstore', 'imap_deflate',
- \ 'imap_idle', 'imap_list_subscribed', 'imap_passive', 'imap_peek', 'imap_qresync',
- \ 'imap_rfc5161', 'imap_server_noise', 'implicit_autoview', 'include_encrypted',
+ \ 'crypt_protected_headers_save', 'crypt_protected_headers_weed',
+ \ 'crypt_protected_headers_write', 'crypt_reply_encrypt', 'crypt_reply_sign',
+ \ 'crypt_reply_sign_encrypted', 'crypt_timestamp', 'crypt_use_gpgme', 'crypt_use_pka',
+ \ 'delete_untag', 'digest_collapse', 'duplicate_threads', 'edit_headers', 'encode_from',
+ \ 'fast_reply', 'fcc_before_send', 'fcc_clear', 'flag_safe', 'followup_to', 'force_name',
+ \ 'forward_decode', 'forward_decrypt', 'forward_quote', 'forward_references', 'hdrs',
+ \ 'header', 'header_color_partial', 'help', 'hidden_host', 'hide_limited', 'hide_missing',
+ \ 'hide_thread_subject', 'hide_top_limited', 'hide_top_missing', 'history_remove_dups',
+ \ 'honor_disposition', 'idn_decode', 'idn_encode', 'ignore_list_reply_to',
+ \ 'imap_check_subscribed', 'imap_condstore', 'imap_deflate', 'imap_idle',
+ \ 'imap_list_subscribed', 'imap_passive', 'imap_peek', 'imap_qresync', 'imap_rfc5161',
+ \ 'imap_send_id', 'imap_server_noise', 'implicit_auto_view', 'include_encrypted',
\ 'include_only_first', 'keep_flagged', 'local_date_header', 'mailcap_sanitize',
\ 'maildir_check_cur', 'maildir_header_cache_verify', 'maildir_trash', 'mail_check_recent',
\ 'mail_check_stats', 'markers', 'mark_old', 'menu_move_off', 'menu_scroll',
@@ -469,166 +491,175 @@ call s:boolQuadGen('Bool', [
\ 'virtual_spool_file', 'wait_key', 'weed', 'wrap_search', 'write_bcc', 'x_comment_to'
\ ], 0)
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" Deprecated Bools
" List of DT_SYNONYM or DT_DEPRECATED Bools in MuttVars in mutt_config.c
call s:boolQuadGen('Bool', [
- \ 'askbcc', 'askcc', 'autoedit', 'confirmappend', 'confirmcreate', 'crypt_autoencrypt',
- \ 'crypt_autopgp', 'crypt_autosign', 'crypt_autosmime', 'crypt_confirmhook',
- \ 'crypt_replyencrypt', 'crypt_replysign', 'crypt_replysignencrypted', 'edit_hdrs',
- \ 'envelope_from', 'forw_decode', 'forw_decrypt', 'forw_quote', 'header_cache_compress',
- \ 'ignore_linear_white_space', 'imap_servernoise', 'include_onlyfirst', 'metoo',
- \ 'mime_subject', 'pgp_autoencrypt', 'pgp_autoinline', 'pgp_autosign',
- \ 'pgp_auto_traditional', 'pgp_create_traditional', 'pgp_replyencrypt', 'pgp_replyinline',
- \ 'pgp_replysign', 'pgp_replysignencrypted', 'reverse_realname', 'ssl_usesystemcerts',
+ \ 'askbcc', 'askcc', 'ask_follow_up', 'autoedit', 'confirmappend', 'confirmcreate',
+ \ 'crypt_autoencrypt', 'crypt_autopgp', 'crypt_autosign', 'crypt_autosmime',
+ \ 'crypt_confirmhook', 'crypt_replyencrypt', 'crypt_replysign', 'crypt_replysignencrypted',
+ \ 'cursor_overlay', 'edit_hdrs', 'envelope_from', 'forw_decode', 'forw_decrypt',
+ \ 'forw_quote', 'header_cache_compress', 'ignore_linear_white_space', 'imap_servernoise',
+ \ 'implicit_autoview', 'include_onlyfirst', 'metoo', 'mime_subject', 'pgp_autoencrypt',
+ \ 'pgp_autoinline', 'pgp_autosign', 'pgp_auto_traditional', 'pgp_create_traditional',
+ \ 'pgp_replyencrypt', 'pgp_replyinline', 'pgp_replysign', 'pgp_replysignencrypted',
+ \ 'pgp_self_encrypt_as', 'reverse_realname', 'smime_self_encrypt_as', 'ssl_usesystemcerts',
\ 'use_8bitmime', 'virtual_spoolfile', 'xterm_set_titles'
\ ], 1)
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of DT_QUAD in MuttVars in mutt_config.c
call s:boolQuadGen('Quad', [
\ 'abort_noattach', 'abort_nosubject', 'abort_unmodified', 'bounce', 'catchup_newsgroup',
\ 'copy', 'crypt_verify_sig', 'delete', 'fcc_attach', 'followup_to_poster',
\ 'forward_attachments', 'forward_edit', 'honor_followup_to', 'include', 'mime_forward',
\ 'mime_forward_rest', 'move', 'pgp_mime_auto', 'pop_delete', 'pop_reconnect', 'postpone',
- \ 'post_moderated', 'print', 'quit', 'recall', 'reply_to', 'ssl_starttls',
+ \ 'post_moderated', 'print', 'quit', 'recall', 'reply_to', 'ssl_starttls'
\ ], 0)
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" Deprecated Quads
" List of DT_SYNONYM or DT_DEPRECATED Quads in MuttVars in mutt_config.c
call s:boolQuadGen('Quad', [
\ 'mime_fwd', 'pgp_encrypt_self', 'pgp_verify_sig', 'smime_encrypt_self'
\ ], 1)
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of DT_NUMBER or DT_LONG in MuttVars in mutt_config.c
syntax keyword muttrcVarNum skipwhite contained
- \ connect_timeout debug_level header_cache_compress_level history imap_fetch_chunk_size
- \ imap_keepalive imap_pipeline_depth imap_poll_timeout mail_check mail_check_stats_interval
- \ menu_context net_inc nm_db_limit nm_open_timeout nm_query_window_current_position
+ \ debug_level header_cache_compress_level history imap_fetch_chunk_size imap_keep_alive
+ \ imap_pipeline_depth imap_poll_timeout mail_check mail_check_stats_interval menu_context
+ \ net_inc nm_db_limit nm_open_timeout nm_query_window_current_position
\ nm_query_window_duration nntp_context nntp_poll pager_context pager_index_lines
\ pager_read_delay pager_skip_quoted_context pgp_timeout pop_check_interval read_inc
\ reflow_wrap save_history score_threshold_delete score_threshold_flag score_threshold_read
\ search_context sendmail_wait sidebar_component_depth sidebar_width sleep_time
- \ smime_timeout ssl_min_dh_prime_bits timeout time_inc toggle_quoted_show_levels wrap
- \ wrap_headers write_inc
- \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-" CHECKED 2022-04-08
+ \ smime_timeout socket_timeout ssl_min_dh_prime_bits timeout time_inc
+ \ toggle_quoted_show_levels wrap wrap_headers write_inc
+ \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+" CHECKED 2024 Oct 12
" Deprecated Numbers
-syntax keyword muttrcVarDeprecatedNum contained skipwhite
- \ header_cache_pagesize pop_checkinterval skip_quoted_offset
+syntax keyword muttrcVarDeprecatedNum
+ \ connect_timeout header_cache_pagesize imap_keepalive pop_checkinterval skip_quoted_offset
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of DT_STRING in MuttVars in mutt_config.c
" Special cases first, and all the rest at the end
" Formats themselves must be updated in their respective groups
" See s:escapesConditionals
-syntax match muttrcVarStr contained skipwhite 'my_[a-zA-Z0-9_]\+' nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-syntax keyword muttrcVarStr contained skipwhite alias_format nextgroup=muttrcVarEqualsAliasFmt
-syntax keyword muttrcVarStr contained skipwhite attach_format nextgroup=muttrcVarEqualsAttachFmt
-syntax keyword muttrcVarStr contained skipwhite compose_format nextgroup=muttrcVarEqualsComposeFmt
-syntax keyword muttrcVarStr contained skipwhite folder_format vfolder_format nextgroup=muttrcVarEqualsFolderFmt
-syntax keyword muttrcVarStr contained skipwhite attribution forward_format index_format message_format pager_format nextgroup=muttrcVarEqualsIdxFmt
-syntax keyword muttrcVarStr contained skipwhite mix_entry_format nextgroup=muttrcVarEqualsMixFmt
-syntax keyword muttrcVarStr contained skipwhite pattern_format nextgroup=muttrcVarEqualsPatternFmt
-syntax keyword muttrcVarStr contained skipwhite
+syntax match muttrcVarString contained skipwhite 'my_[a-zA-Z0-9_]\+' nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+syntax keyword muttrcVarString contained skipwhite alias_format nextgroup=muttrcVarEqualsAliasFormat
+syntax keyword muttrcVarString contained skipwhite attach_format nextgroup=muttrcVarEqualsAttachFormat
+syntax keyword muttrcVarString contained skipwhite autocrypt_acct_format nextgroup=muttrcVarEqualsAutocryptFormat
+syntax keyword muttrcVarString contained skipwhite compose_format nextgroup=muttrcVarEqualsComposeFormat
+syntax keyword muttrcVarString contained skipwhite folder_format mailbox_folder_format nextgroup=muttrcVarEqualsFolderFormat
+syntax keyword muttrcVarString contained skipwhite greeting nextgroup=muttrcVarEqualsGreetingFormat
+syntax keyword muttrcVarString contained skipwhite history_format nextgroup=muttrcVarEqualsHistoryFormat
+syntax keyword muttrcVarString contained skipwhite
+ \ attribution_intro attribution_trailer forward_attribution_intro forward_attribution_trailer
+ \ forward_format indent_string index_format message_format pager_format
+ \ nextgroup=muttrcVarEqualsIndexFormat
+syntax keyword muttrcVarString contained skipwhite pattern_format nextgroup=muttrcVarEqualsPatternFormat
+syntax keyword muttrcVarString contained skipwhite
\ pgp_clear_sign_command pgp_decode_command pgp_decrypt_command pgp_encrypt_only_command
\ pgp_encrypt_sign_command pgp_export_command pgp_get_keys_command pgp_import_command
\ pgp_list_pubring_command pgp_list_secring_command pgp_sign_command pgp_verify_command
\ pgp_verify_key_command
- \ nextgroup=muttrcVarEqualsPGPCmdFmt
-syntax keyword muttrcVarStr contained skipwhite pgp_entry_format nextgroup=muttrcVarEqualsPGPFmt
-syntax keyword muttrcVarStr contained skipwhite query_format nextgroup=muttrcVarEqualsQueryFmt
-syntax keyword muttrcVarStr contained skipwhite
+ \ nextgroup=muttrcVarEqualsPgpCommandFormat
+syntax keyword muttrcVarString contained skipwhite pgp_entry_format nextgroup=muttrcVarEqualsPgpEntryFormat
+syntax keyword muttrcVarString contained skipwhite query_format nextgroup=muttrcVarEqualsQueryFormat
+syntax keyword muttrcVarString contained skipwhite
\ smime_decrypt_command smime_encrypt_command smime_get_cert_command
\ smime_get_cert_email_command smime_get_signer_cert_command smime_import_cert_command
\ smime_pk7out_command smime_sign_command smime_verify_command smime_verify_opaque_command
- \ nextgroup=muttrcVarEqualsSmimeFmt
-syntax keyword muttrcVarStr contained skipwhite status_format ts_icon_format ts_status_format nextgroup=muttrcVarEqualsStatusFmt
-syntax keyword muttrcVarStr contained skipwhite date_format nextgroup=muttrcVarEqualsStrftimeFmt
-syntax keyword muttrcVarStr contained skipwhite group_index_format nextgroup=muttrcVarEqualsGrpIdxFmt
-syntax keyword muttrcVarStr contained skipwhite sidebar_format nextgroup=muttrcVarEqualsSdbFmt
-syntax keyword muttrcVarStr contained skipwhite
+ \ nextgroup=muttrcVarEqualsSmimeCommandFormat
+syntax keyword muttrcVarString contained skipwhite status_format ts_icon_format ts_status_format nextgroup=muttrcVarEqualsStatusFormat
+syntax keyword muttrcVarString contained skipwhite date_format nextgroup=muttrcVarEqualsStrftimeFormat
+syntax keyword muttrcVarString contained skipwhite group_index_format nextgroup=muttrcVarEqualsGroupIndexFormat
+syntax keyword muttrcVarString contained skipwhite sidebar_format nextgroup=muttrcVarEqualsSidebarFormat
+syntax keyword muttrcVarString contained skipwhite
\ abort_key arrow_string assumed_charset attach_charset attach_sep attribution_locale
- \ autocrypt_acct_format charset config_charset content_type crypt_protected_headers_subject
- \ default_hook dsn_notify dsn_return empty_subject forward_attribution_intro
- \ forward_attribution_trailer greeting header_cache_backend header_cache_compress_method
+ \ charset config_charset content_type crypt_protected_headers_subject default_hook
+ \ dsn_notify dsn_return empty_subject header_cache_backend header_cache_compress_method
\ hidden_tags hostname imap_authenticators imap_delim_chars imap_headers imap_login
- \ imap_pass imap_user indent_string mailcap_path mark_macro_prefix mh_seq_flagged
- \ mh_seq_replied mh_seq_unseen newsgroups_charset news_server nm_default_url nm_exclude_tags
- \ nm_flagged_tag nm_query_type nm_query_window_current_search nm_query_window_or_terms
- \ nm_query_window_timebase nm_record_tags nm_replied_tag nm_unread_tag nntp_authenticators
- \ nntp_pass nntp_user pgp_default_key pgp_sign_as pipe_sep pop_authenticators pop_host
- \ pop_pass pop_user postpone_encrypt_as post_indent_string preconnect preferred_languages
- \ real_name send_charset show_multipart_alternative sidebar_delim_chars sidebar_divider_char
- \ sidebar_indent_string simple_search smime_default_key smime_encrypt_with smime_sign_as
- \ smime_sign_digest_alg smtp_authenticators smtp_pass smtp_url smtp_user spam_separator
- \ ssl_ciphers
- \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+ \ imap_pass imap_user mailcap_path maildir_field_delimiter mark_macro_prefix mh_seq_flagged
+ \ mh_seq_replied mh_seq_unseen newsgroups_charset newsrc news_server nm_config_profile
+ \ nm_default_url nm_exclude_tags nm_flagged_tag nm_query_type nm_query_window_current_search
+ \ nm_query_window_or_terms nm_query_window_timebase nm_record_tags nm_replied_tag
+ \ nm_unread_tag nntp_authenticators nntp_pass nntp_user pgp_default_key pgp_sign_as pipe_sep
+ \ pop_authenticators pop_host pop_pass pop_user postpone_encrypt_as preconnect
+ \ preferred_languages real_name send_charset show_multipart_alternative sidebar_delim_chars
+ \ sidebar_divider_char sidebar_indent_string simple_search smime_default_key
+ \ smime_encrypt_with smime_sign_as smime_sign_digest_alg smtp_authenticators smtp_pass
+ \ smtp_url smtp_user spam_separator ssl_ciphers
+ \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" Deprecated strings
-syntax keyword muttrcVarDeprecatedStr
- \ abort_noattach_regexp attach_keyword escape forw_format hdr_format indent_str msg_format
- \ nm_default_uri pgp_clearsign_command pgp_getkeys_command pgp_self_encrypt_as
- \ post_indent_str print_cmd quote_regexp realname reply_regexp smime_self_encrypt_as
- \ spoolfile visual xterm_icon xterm_title
-
-" CHECKED 2022-04-08
+syntax keyword muttrcVarDeprecatedString
+ \ abort_noattach_regexp attach_keyword attribution escape forw_format hdr_format indent_str
+ \ message_cachedir mixmaster mix_entry_format msg_format nm_default_uri
+ \ pgp_clearsign_command pgp_getkeys_command pgp_self_encrypt_as post_indent_str
+ \ post_indent_string print_cmd quote_regexp realname reply_regexp smime_self_encrypt_as
+ \ spoolfile tmpdir vfolder_format visual xterm_icon xterm_title
+
+" CHECKED 2024 Oct 12
" List of DT_ADDRESS
-syntax keyword muttrcVarStr contained skipwhite envelope_from_address from nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarString contained skipwhite envelope_from_address from nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" List of DT_ENUM
-syntax keyword muttrcVarStr contained skipwhite mbox_type use_threads nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarString contained skipwhite mbox_type use_threads nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" List of DT_MBTABLE
-syntax keyword muttrcVarStr contained skipwhite crypt_chars flag_chars from_chars status_chars to_chars nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-
-" CHECKED 2022-04-08
-" List of DT_PATH or DT_MAILBOX
-syntax keyword muttrcVarStr contained skipwhite
- \ alias_file attach_save_dir autocrypt_dir certificate_file debug_file
- \ entropy_file folder header_cache history_file mbox message_cachedir newsrc
- \ news_cache_dir postponed record signature smime_ca_location
- \ smime_certificates smime_keys spool_file ssl_ca_certificates_file ssl_client_cert
- \ tmpdir trash
- \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarString contained skipwhite crypt_chars flag_chars from_chars status_chars to_chars nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+
+" CHECKED 2024 Oct 12
+" List of DT_PATH or D_STRING_MAILBOX
+syntax keyword muttrcVarString contained skipwhite
+ \ alias_file attach_save_dir autocrypt_dir certificate_file debug_file entropy_file folder
+ \ header_cache history_file mbox message_cache_dir news_cache_dir nm_config_file postponed
+ \ record signature smime_ca_location smime_certificates smime_keys spool_file
+ \ ssl_ca_certificates_file ssl_client_cert tmp_dir trash
+ \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" List of DT_COMMAND (excluding pgp_*_command and smime_*_command)
-syntax keyword muttrcVarStr contained skipwhite
- \ display_filter editor inews ispell mixmaster new_mail_command pager
- \ print_command query_command sendmail shell external_search_command
- \ imap_oauth_refresh_command pop_oauth_refresh_command
- \ mime_type_query_command smtp_oauth_refresh_command tunnel
- \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-
-" CHECKED 2022-04-08
+syntax keyword muttrcVarString contained skipwhite
+ \ account_command display_filter editor external_search_command imap_oauth_refresh_command
+ \ inews ispell mime_type_query_command new_mail_command pager pop_oauth_refresh_command
+ \ print_command query_command sendmail shell smtp_oauth_refresh_command tunnel
+ \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
+
+" CHECKED 2024 Oct 12
" List of DT_REGEX
-syntax keyword muttrcVarStr contained skipwhite
- \ abort_noattach_regex gecos_mask mask pgp_decryption_okay pgp_good_sign quote_regex
+syntax keyword muttrcVarString contained skipwhite
+ \ abort_noattach_regex gecos_mask mask pgp_decryption_okay pgp_good_sign quote_regex
\ reply_regex smileys
- \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+ \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
" List of DT_SORT
-syntax keyword muttrcVarStr contained skipwhite
+syntax keyword muttrcVarString contained skipwhite
\ pgp_sort_keys sidebar_sort_method sort sort_alias sort_aux sort_browser
- \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+ \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
-" CHECKED 2022-04-08
-" List of commands in mutt_commands in mutt_commands.c
+" CHECKED 2024 Oct 12
+" List of commands in mutt_commands in commands.c
" Remember to remove hooks, they have already been dealt with
syntax keyword muttrcCommand skipwhite alias nextgroup=muttrcAliasGroupDef,muttrcAliasKey,muttrcAliasNL
syntax keyword muttrcCommand skipwhite bind nextgroup=muttrcBindMenuList,muttrcBindMenuListNL
syntax keyword muttrcCommand skipwhite exec nextgroup=muttrcFunction
syntax keyword muttrcCommand skipwhite macro nextgroup=muttrcMacroMenuList,muttrcMacroMenuListNL
syntax keyword muttrcCommand skipwhite nospam nextgroup=muttrcNoSpamPattern
-syntax keyword muttrcCommand skipwhite set unset reset toggle nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcCommand skipwhite set unset reset toggle nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarString
syntax keyword muttrcCommand skipwhite spam nextgroup=muttrcSpamPattern
syntax keyword muttrcCommand skipwhite unalias nextgroup=muttrcUnAliasKey,muttrcUnAliasNL
syntax keyword muttrcCommand skipwhite unhook nextgroup=muttrcHooks
syntax keyword muttrcCommand skipwhite
\ alternative_order attachments auto_view cd echo finish hdr_order ifdef ifndef ignore lua
\ lua-source mailboxes mailto_allow mime_lookup my_hdr named-mailboxes push score setenv
- \ sidebar_whitelist source subjectrx subscribe-to tag-formats tag-transforms
+ \ sidebar_pin sidebar_unpin source subjectrx subscribe-to tag-formats tag-transforms
\ unalternative_order unattachments unauto_view unbind uncolor unhdr_order unignore unmacro
- \ unmailboxes unmailto_allow unmime_lookup unmono unmy_hdr unscore unsetenv
- \ unsidebar_whitelist unsubjectrx unsubscribe-from unvirtual-mailboxes virtual-mailboxes
+ \ unmailboxes unmailto_allow unmime_lookup unmono unmy_hdr unscore unsetenv unsubjectrx
+ \ unsubscribe-from unvirtual-mailboxes version virtual-mailboxes
+
+" CHECKED 2024 Oct 12
+" Deprecated commands
+syntax keyword muttrcDeprecatedCommand skipwhite
+ \ sidebar_whitelist unsidebar_whitelist
function! s:genFunctions(functions)
for f in a:functions
@@ -636,68 +667,67 @@ function! s:genFunctions(functions)
endfor
endfunction
-" CHECKED 2022-04-08
+" CHECKED 2024 Oct 12
" List of functions in functions.c
" Note: 'noop' is included but is elsewhere in the source
call s:genFunctions(['noop',
- \ 'accept', 'alias-dialog', 'append', 'attach-file', 'attach-key', 'attach-message',
- \ 'attach-news-message', 'autocrypt-acct-menu', 'autocrypt-menu', 'backspace',
- \ 'backward-char', 'backward-word', 'bol', 'bottom', 'bottom-page', 'bounce-message',
- \ 'break-thread', 'buffy-cycle', 'buffy-list', 'capitalize-word', 'catchup', 'chain-next',
- \ 'chain-prev', 'change-dir', 'change-folder', 'change-folder-readonly', 'change-newsgroup',
- \ 'change-newsgroup-readonly', 'change-vfolder', 'check-new', 'check-stats',
- \ 'check-traditional-pgp', 'clear-flag', 'collapse-all', 'collapse-parts',
- \ 'collapse-thread', 'complete', 'complete-query', 'compose-to-sender', 'copy-file',
- \ 'copy-message', 'create-account', 'create-alias', 'create-mailbox', 'current-bottom',
- \ 'current-middle', 'current-top', 'decode-copy', 'decode-save', 'decrypt-copy',
- \ 'decrypt-save', 'delete', 'delete-account', 'delete-char', 'delete-entry',
- \ 'delete-mailbox', 'delete-message', 'delete-pattern', 'delete-subthread', 'delete-thread',
- \ 'descend-directory', 'detach-file', 'display-address', 'display-filename',
- \ 'display-message', 'display-toggle-weed', 'downcase-word', 'edit', 'edit-bcc', 'edit-cc',
- \ 'edit-content-id', 'edit-description', 'edit-encoding', 'edit-fcc', 'edit-file',
- \ 'edit-followup-to', 'edit-from', 'edit-headers', 'edit-label', 'edit-language',
- \ 'edit-message', 'edit-mime', 'edit-newsgroups', 'edit-or-view-raw-message',
- \ 'edit-raw-message', 'edit-reply-to', 'edit-subject', 'edit-to', 'edit-type',
- \ 'edit-x-comment-to', 'end-cond', 'enter-command', 'enter-mask', 'entire-thread', 'eol',
- \ 'error-history', 'exit', 'extract-keys', 'fetch-mail', 'filter-entry', 'first-entry',
- \ 'flag-message', 'followup-message', 'forget-passphrase', 'forward-char',
- \ 'forward-message', 'forward-to-group', 'forward-word', 'get-attachment', 'get-children',
- \ 'get-message', 'get-parent', 'goto-folder', 'goto-parent', 'group-alternatives',
- \ 'group-chat-reply', 'group-multilingual', 'group-related', 'group-reply', 'half-down',
- \ 'half-up', 'help', 'history-down', 'history-search', 'history-up', 'imap-fetch-mail',
- \ 'imap-logout-all', 'insert', 'ispell', 'jump', 'kill-eol', 'kill-eow', 'kill-line',
- \ 'kill-word', 'last-entry', 'limit', 'limit-current-thread', 'link-threads', 'list-reply',
- \ 'list-subscribe', 'list-unsubscribe', 'mail', 'mail-key', 'mailbox-cycle', 'mailbox-list',
- \ 'mark-as-new', 'mark-message', 'middle-page', 'mix', 'modify-labels',
- \ 'modify-labels-then-hide', 'modify-tags', 'modify-tags-then-hide', 'move-down', 'move-up',
- \ 'new-mime', 'next-entry', 'next-line', 'next-new', 'next-new-then-unread', 'next-page',
- \ 'next-subthread', 'next-thread', 'next-undeleted', 'next-unread', 'next-unread-mailbox',
- \ 'parent-message', 'pgp-menu', 'pipe-entry', 'pipe-message', 'post-message',
- \ 'postpone-message', 'previous-entry', 'previous-line', 'previous-new',
- \ 'previous-new-then-unread', 'previous-page', 'previous-subthread', 'previous-thread',
- \ 'previous-undeleted', 'previous-unread', 'print-entry', 'print-message', 'purge-message',
- \ 'purge-thread', 'quasi-delete', 'query', 'query-append', 'quit', 'quote-char',
- \ 'read-subthread', 'read-thread', 'recall-message', 'reconstruct-thread', 'redraw-screen',
- \ 'refresh', 'reload-active', 'rename-attachment', 'rename-file', 'rename-mailbox', 'reply',
- \ 'resend-message', 'root-message', 'save-entry', 'save-message', 'search', 'search-next',
- \ 'search-opposite', 'search-reverse', 'search-toggle', 'select-entry', 'select-new',
- \ 'send-message', 'set-flag', 'shell-escape', 'show-limit', 'show-log-messages',
- \ 'show-version', 'sidebar-first', 'sidebar-last', 'sidebar-next', 'sidebar-next-new',
- \ 'sidebar-open', 'sidebar-page-down', 'sidebar-page-up', 'sidebar-prev',
- \ 'sidebar-prev-new', 'sidebar-toggle-virtual', 'sidebar-toggle-visible', 'skip-headers',
- \ 'skip-quoted', 'smime-menu', 'sort', 'sort-alias', 'sort-alias-reverse', 'sort-mailbox',
- \ 'sort-reverse', 'subscribe', 'subscribe-pattern', 'sync-mailbox', 'tag-entry',
- \ 'tag-message', 'tag-pattern', 'tag-prefix', 'tag-prefix-cond', 'tag-subthread',
- \ 'tag-thread', 'toggle-active', 'toggle-disposition', 'toggle-mailboxes', 'toggle-new',
- \ 'toggle-prefer-encrypt', 'toggle-quoted', 'toggle-read', 'toggle-recode',
- \ 'toggle-subscribed', 'toggle-unlink', 'toggle-write', 'top', 'top-page',
- \ 'transpose-chars', 'uncatchup', 'undelete-entry', 'undelete-message', 'undelete-pattern',
- \ 'undelete-subthread', 'undelete-thread', 'ungroup-attachment', 'unsubscribe',
- \ 'unsubscribe-pattern', 'untag-pattern', 'upcase-word', 'update-encoding', 'verify-key',
- \ 'vfolder-from-query', 'vfolder-from-query-readonly', 'vfolder-window-backward',
- \ 'vfolder-window-forward', 'vfolder-window-reset', 'view-attach', 'view-attachments',
- \ 'view-file', 'view-mailcap', 'view-name', 'view-pager', 'view-raw-message', 'view-text',
- \ 'what-key', 'write-fcc'
+ \ 'alias-dialog', 'attach-file', 'attach-key', 'attach-message', 'attach-news-message',
+ \ 'autocrypt-acct-menu', 'autocrypt-menu', 'backspace', 'backward-char', 'backward-word',
+ \ 'bol', 'bottom', 'bottom-page', 'bounce-message', 'break-thread', 'buffy-cycle',
+ \ 'buffy-list', 'capitalize-word', 'catchup', 'change-dir', 'change-folder',
+ \ 'change-folder-readonly', 'change-newsgroup', 'change-newsgroup-readonly',
+ \ 'change-vfolder', 'check-new', 'check-stats', 'check-traditional-pgp', 'clear-flag',
+ \ 'collapse-all', 'collapse-parts', 'collapse-thread', 'complete', 'complete-query',
+ \ 'compose-to-sender', 'copy-file', 'copy-message', 'create-account', 'create-alias',
+ \ 'create-mailbox', 'current-bottom', 'current-middle', 'current-top', 'decode-copy',
+ \ 'decode-save', 'decrypt-copy', 'decrypt-save', 'delete-account', 'delete-char',
+ \ 'delete-entry', 'delete-mailbox', 'delete-message', 'delete-pattern', 'delete-subthread',
+ \ 'delete-thread', 'descend-directory', 'detach-file', 'display-address',
+ \ 'display-filename', 'display-message', 'display-toggle-weed', 'downcase-word', 'edit',
+ \ 'edit-bcc', 'edit-cc', 'edit-content-id', 'edit-description', 'edit-encoding', 'edit-fcc',
+ \ 'edit-file', 'edit-followup-to', 'edit-from', 'edit-headers', 'edit-label',
+ \ 'edit-language', 'edit-message', 'edit-mime', 'edit-newsgroups',
+ \ 'edit-or-view-raw-message', 'edit-raw-message', 'edit-reply-to', 'edit-subject',
+ \ 'edit-to', 'edit-type', 'edit-x-comment-to', 'end-cond', 'enter-command', 'enter-mask',
+ \ 'entire-thread', 'eol', 'error-history', 'exit', 'extract-keys', 'fetch-mail',
+ \ 'filter-entry', 'first-entry', 'flag-message', 'followup-message', 'forget-passphrase',
+ \ 'forward-char', 'forward-message', 'forward-to-group', 'forward-word', 'get-attachment',
+ \ 'get-children', 'get-message', 'get-parent', 'goto-folder', 'goto-parent',
+ \ 'group-alternatives', 'group-chat-reply', 'group-multilingual', 'group-related',
+ \ 'group-reply', 'half-down', 'half-up', 'help', 'history-down', 'history-search',
+ \ 'history-up', 'imap-fetch-mail', 'imap-logout-all', 'ispell', 'jump', 'kill-eol',
+ \ 'kill-eow', 'kill-line', 'kill-whole-line', 'kill-word', 'last-entry', 'limit',
+ \ 'limit-current-thread', 'link-threads', 'list-reply', 'list-subscribe',
+ \ 'list-unsubscribe', 'mail', 'mail-key', 'mailbox-cycle', 'mailbox-list', 'mark-as-new',
+ \ 'mark-message', 'middle-page', 'modify-labels', 'modify-labels-then-hide', 'modify-tags',
+ \ 'modify-tags-then-hide', 'move-down', 'move-up', 'new-mime', 'next-entry', 'next-line',
+ \ 'next-new', 'next-new-then-unread', 'next-page', 'next-subthread', 'next-thread',
+ \ 'next-undeleted', 'next-unread', 'next-unread-mailbox', 'parent-message', 'pgp-menu',
+ \ 'pipe-entry', 'pipe-message', 'post-message', 'postpone-message', 'previous-entry',
+ \ 'previous-line', 'previous-new', 'previous-new-then-unread', 'previous-page',
+ \ 'previous-subthread', 'previous-thread', 'previous-undeleted', 'previous-unread',
+ \ 'print-entry', 'print-message', 'purge-message', 'purge-thread', 'quasi-delete', 'query',
+ \ 'query-append', 'quit', 'quote-char', 'read-subthread', 'read-thread', 'recall-message',
+ \ 'reconstruct-thread', 'redraw-screen', 'refresh', 'reload-active', 'rename-attachment',
+ \ 'rename-file', 'rename-mailbox', 'reply', 'resend-message', 'root-message', 'save-entry',
+ \ 'save-message', 'search', 'search-next', 'search-opposite', 'search-reverse',
+ \ 'search-toggle', 'select-entry', 'select-new', 'send-message', 'set-flag', 'shell-escape',
+ \ 'show-limit', 'show-log-messages', 'show-version', 'sidebar-first', 'sidebar-last',
+ \ 'sidebar-next', 'sidebar-next-new', 'sidebar-open', 'sidebar-page-down',
+ \ 'sidebar-page-up', 'sidebar-prev', 'sidebar-prev-new', 'sidebar-toggle-virtual',
+ \ 'sidebar-toggle-visible', 'skip-headers', 'skip-quoted', 'smime-menu', 'sort',
+ \ 'sort-alias', 'sort-alias-reverse', 'sort-mailbox', 'sort-reverse', 'subscribe',
+ \ 'subscribe-pattern', 'sync-mailbox', 'tag-entry', 'tag-message', 'tag-pattern',
+ \ 'tag-prefix', 'tag-prefix-cond', 'tag-subthread', 'tag-thread', 'toggle-active',
+ \ 'toggle-disposition', 'toggle-mailboxes', 'toggle-new', 'toggle-prefer-encrypt',
+ \ 'toggle-quoted', 'toggle-read', 'toggle-recode', 'toggle-subscribed', 'toggle-unlink',
+ \ 'toggle-write', 'top', 'top-page', 'transpose-chars', 'uncatchup', 'undelete-entry',
+ \ 'undelete-message', 'undelete-pattern', 'undelete-subthread', 'undelete-thread',
+ \ 'ungroup-attachment', 'unsubscribe', 'unsubscribe-pattern', 'untag-pattern',
+ \ 'upcase-word', 'update-encoding', 'verify-key', 'vfolder-from-query',
+ \ 'vfolder-from-query-readonly', 'vfolder-window-backward', 'vfolder-window-forward',
+ \ 'vfolder-window-reset', 'view-attach', 'view-attachments', 'view-file', 'view-mailcap',
+ \ 'view-name', 'view-pager', 'view-raw-message', 'view-text', 'what-key', 'write-fcc'
\ ])
" Define the default highlighting.
@@ -713,29 +743,23 @@ highlight def link muttrcBadAction Error
highlight def link muttrcBindFunction Error
highlight def link muttrcBindMenuList Error
highlight def link muttrcColorBG Error
-highlight def link muttrcColorBGH Error
-highlight def link muttrcColorBGI Error
highlight def link muttrcColorContext Error
highlight def link muttrcColorFG Error
-highlight def link muttrcColorFGH Error
-highlight def link muttrcColorFGI Error
highlight def link muttrcColorLine Error
+highlight def link muttrcDeprecatedCommand Error
highlight def link muttrcFormatErrors Error
highlight def link muttrcGroupLine Error
-highlight def link muttrcListsLine Error
highlight def link muttrcPattern Error
-highlight def link muttrcSubscribeLine Error
highlight def link muttrcUnColorLine Error
highlight def link muttrcVarDeprecatedBool Error
+highlight def link muttrcVarDeprecatedNum Error
highlight def link muttrcVarDeprecatedQuad Error
-highlight def link muttrcVarDeprecatedStr Error
+highlight def link muttrcVarDeprecatedString Error
highlight def link muttrcAliasEncEmail Identifier
highlight def link muttrcAliasKey Identifier
highlight def link muttrcColorCompose Identifier
highlight def link muttrcColorComposeField Identifier
-highlight def link muttrcColorContextH Identifier
-highlight def link muttrcColorContextI Identifier
highlight def link muttrcColorField Identifier
highlight def link muttrcMenu Identifier
highlight def link muttrcSimplePat Identifier
@@ -744,7 +768,7 @@ highlight def link muttrcUnColorIndex Identifier
highlight def link muttrcVarBool Identifier
highlight def link muttrcVarNum Identifier
highlight def link muttrcVarQuad Identifier
-highlight def link muttrcVarStr Identifier
+highlight def link muttrcVarString Identifier
highlight def link muttrcCommand Keyword
@@ -769,52 +793,61 @@ highlight def link muttrcUnColorKeyword muttrcCommand
highlight def link muttrcAliasFormatEscapes muttrcEscape
highlight def link muttrcAttachFormatEscapes muttrcEscape
+highlight def link muttrcAutocryptFormatEscapes muttrcEscape
highlight def link muttrcComposeFormatEscapes muttrcEscape
highlight def link muttrcFolderFormatEscapes muttrcEscape
+highlight def link muttrcGreetingFormatEscapes muttrcEscape
highlight def link muttrcGroupIndexFormatEscapes muttrcEscape
+highlight def link muttrcHistoryFormatEscapes muttrcEscape
highlight def link muttrcIndexFormatEscapes muttrcEscape
-highlight def link muttrcMixFormatEscapes muttrcEscape
highlight def link muttrcPatternFormatEscapes muttrcEscape
-highlight def link muttrcPGPCmdFormatEscapes muttrcEscape
-highlight def link muttrcPGPFormatEscapes muttrcEscape
-highlight def link muttrcPGPTimeEscapes muttrcEscape
+highlight def link muttrcPgpCommandFormatEscapes muttrcEscape
+highlight def link muttrcPgpEntryFormatEscapes muttrcEscape
+highlight def link muttrcPgpTimeEscapes muttrcEscape
highlight def link muttrcQueryFormatEscapes muttrcEscape
highlight def link muttrcShellString muttrcEscape
highlight def link muttrcSidebarFormatEscapes muttrcEscape
-highlight def link muttrcSmimeFormatEscapes muttrcEscape
+highlight def link muttrcSmimeCommandFormatEscapes muttrcEscape
highlight def link muttrcStatusFormatEscapes muttrcEscape
highlight def link muttrcTimeEscapes muttrcEscape
-highlight def link muttrcAliasFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcAttachFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcComposeFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcFolderFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcIndexFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcMixFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcPatternFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcPGPCmdFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcPGPFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcSmimeFormatConditionals muttrcFormatConditionals2
-highlight def link muttrcStatusFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcAliasFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcAttachFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcAutocryptFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcComposeFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcFolderFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcGreetingFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcGroupIndexFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcHistoryFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcIndexFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcPatternFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcPgpCommandFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcPgpEntryFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcQueryFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcSidebarFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcSmimeCommandFormatConditionals muttrcFormatConditionals2
+highlight def link muttrcStatusFormatConditionals muttrcFormatConditionals2
highlight def link muttrcAddrDef muttrcGroupFlag
highlight def link muttrcRXDef muttrcGroupFlag
-highlight def link muttrcAliasFormatStr muttrcString
-highlight def link muttrcAttachFormatStr muttrcString
-highlight def link muttrcComposeFormatStr muttrcString
-highlight def link muttrcFolderFormatStr muttrcString
-highlight def link muttrcGroupIndexFormatStr muttrcString
-highlight def link muttrcIndexFormatStr muttrcString
-highlight def link muttrcMixFormatStr muttrcString
-highlight def link muttrcPatternFormatStr muttrcString
-highlight def link muttrcPGPCmdFormatStr muttrcString
-highlight def link muttrcPGPFormatStr muttrcString
-highlight def link muttrcQueryFormatStr muttrcString
-highlight def link muttrcSidebarFormatStr muttrcString
-highlight def link muttrcSmimeFormatStr muttrcString
-highlight def link muttrcStatusFormatStr muttrcString
-highlight def link muttrcStrftimeFormatStr muttrcString
+highlight def link muttrcAliasFormatString muttrcString
+highlight def link muttrcAttachFormatString muttrcString
+highlight def link muttrcAutocryptFormatString muttrcString
+highlight def link muttrcComposeFormatString muttrcString
+highlight def link muttrcFolderFormatString muttrcString
+highlight def link muttrcGreetingFormatString muttrcString
+highlight def link muttrcGroupIndexFormatString muttrcString
+highlight def link muttrcHistoryFormatString muttrcString
+highlight def link muttrcIndexFormatString muttrcString
+highlight def link muttrcPatternFormatString muttrcString
+highlight def link muttrcPgpCommandFormatString muttrcString
+highlight def link muttrcPgpEntryFormatString muttrcString
+highlight def link muttrcQueryFormatString muttrcString
+highlight def link muttrcSidebarFormatString muttrcString
+highlight def link muttrcSmimeCommandFormatString muttrcString
+highlight def link muttrcStatusFormatString muttrcString
+highlight def link muttrcStrftimeFormatString muttrcString
highlight def link muttrcSetNumAssignment Number
@@ -843,7 +876,6 @@ highlight def link muttrcMacroBodyNL SpecialChar
highlight def link muttrcMacroDescrNL SpecialChar
highlight def link muttrcMacroKeyNL SpecialChar
highlight def link muttrcMacroMenuListNL SpecialChar
-highlight def link muttrcPatternNL SpecialChar
highlight def link muttrcRXChars SpecialChar
highlight def link muttrcStringNL SpecialChar
highlight def link muttrcUnAliasNL SpecialChar
@@ -860,7 +892,6 @@ highlight def link muttrcRXString2 String
highlight def link muttrcSetStrAssignment String
highlight def link muttrcString String
-highlight def link muttrcAliasParens Type
highlight def link muttrcAttachmentsFlag Type
highlight def link muttrcColor Type
highlight def link muttrcFormatConditionals2 Type
diff --git a/runtime/syntax/org.vim b/runtime/syntax/org.vim
new file mode 100644
index 0000000000..89c8de31b4
--- /dev/null
+++ b/runtime/syntax/org.vim
@@ -0,0 +1,71 @@
+" Vim syntax file
+" Language: Org
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Nov 14
+"
+" Reference Specification: Org mode manual
+" GNU Info: `$ info Org`
+" Web: <https://orgmode.org/manual/index.html>
+
+" Quit when a (custom) syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+let b:current_syntax = 'org'
+
+syn case ignore
+
+" Bold
+syn region orgBold matchgroup=orgBoldDelimiter start="\(^\|[- '"({\]]\)\@<=\*\ze[^ ]" end="^\@!\*\([^\k\*]\|$\)\@=" keepend
+hi def link orgBold markdownBold
+hi def link orgBoldDelimiter orgBold
+
+" Italic
+syn region orgItalic matchgroup=orgItalicDelimiter start="\(^\|[- '"({\]]\)\@<=\/\ze[^ ]" end="^\@!\/\([^\k\/]\|$\)\@=" keepend
+hi def link orgItalic markdownItalic
+hi def link orgItalicDelimiter orgItalic
+
+" Strikethrogh
+syn region orgStrikethrough matchgroup=orgStrikethroughDelimiter start="\(^\|[ '"({\]]\)\@<=+\ze[^ ]" end="^\@!+\([^\k+]\|$\)\@=" keepend
+hi def link orgStrikethrough markdownStrike
+hi def link orgStrikethroughDelimiter orgStrikethrough
+
+" Underline
+syn region orgUnderline matchgroup=orgUnderlineDelimiter start="\(^\|[- '"({\]]\)\@<=_\ze[^ ]" end="^\@!_\([^\k_]\|$\)\@=" keepend
+
+" Headlines
+syn match orgHeadline "^\*\+\s\+.*$" keepend
+hi def link orgHeadline Title
+
+" Line Comment
+syn match orgLineComment /^\s*#\s\+.*$/ keepend
+hi def link orgLineComment Comment
+
+" Block Comment
+syn region orgBlockComment matchgroup=orgBlockCommentDelimiter start="\c^\s*#+BEGIN_COMMENT" end="\c^\s*#+END_COMMENT" keepend
+hi def link orgBlockComment Comment
+hi def link orgBlockCommentDelimiter Comment
+
+" Lists
+syn match orgUnorderedListMarker "^\s*[-+]\s\+" keepend
+hi def link orgUnorderedListMarker markdownOrderedListMarker
+syn match orgOrderedListMarker "^\s*\(\d\|\a\)\+[.)]\s\+" keepend
+hi def link orgOrderedListMarker markdownOrderedListMarker
+"
+" Verbatim
+syn region orgVerbatimInline matchgroup=orgVerbatimInlineDelimiter start="\(^\|[- '"({\]]\)\@<==\ze[^ ]" end="^\@!=\([^\k=]\|$\)\@=" keepend
+hi def link orgVerbatimInline markdownCodeBlock
+hi def link orgVerbatimInlineDelimiter orgVerbatimInline
+syn region orgVerbatimBlock matchgroup=orgVerbatimBlockDelimiter start="\c^\s*#+BEGIN_.*" end="\c^\s*#+END_.*" keepend
+hi def link orgVerbatimBlock orgCode
+hi def link orgVerbatimBlockDelimiter orgVerbatimBlock
+
+" Code
+syn region orgCodeInline matchgroup=orgCodeInlineDelimiter start="\(^\|[- '"({\]]\)\@<=\~\ze[^ ]" end="^\@!\~\([^\k\~]\|$\)\@=" keepend
+highlight def link orgCodeInline markdownCodeBlock
+highlight def link orgCodeInlineDelimiter orgCodeInline
+syn region orgCodeBlock matchgroup=orgCodeBlockDelimiter start="\c^\s*#+BEGIN_SRC.*" end="\c^\s*#+END_SRC" keepend
+highlight def link orgCodeBlock markdownCodeBlock
+highlight def link orgCodeBlockDelimiter orgCodeBlock
+
+" vim: ts=8 sts=2 sw=2 et
diff --git a/runtime/syntax/racket.vim b/runtime/syntax/racket.vim
index fcd64a7c9b..7dcca6082c 100644
--- a/runtime/syntax/racket.vim
+++ b/runtime/syntax/racket.vim
@@ -4,7 +4,7 @@
" Previous Maintainer: Will Langstroth <will@langstroth.com>
" URL: https://github.com/benknoble/vim-racket
" Description: Contains all of the keywords in #lang racket
-" Last Change: 2023 Sep 22
+" Last Change: 2024 Apr 14
" Initializing:
if exists("b:current_syntax")
@@ -30,7 +30,7 @@ endif
" http://docs.racket-lang.org/reference/index.html
"
syntax keyword racketSyntax module module* module+ require provide quote
-syntax keyword racketSyntax #%datum #%expression #%top #%variable-reference #%app
+syntax keyword racketSyntax #%module-begin #%datum #%expression #%top #%variable-reference #%app
syntax keyword racketSyntax lambda case-lambda let let* letrec
syntax keyword racketSyntax let-values let*-values let-syntax letrec-syntax
syntax keyword racketSyntax let-syntaxes letrec-syntaxes letrec-syntaxes+values
diff --git a/runtime/syntax/shared/debversions.vim b/runtime/syntax/shared/debversions.vim
index 56f18b969a..404a0a49e3 100644
--- a/runtime/syntax/shared/debversions.vim
+++ b/runtime/syntax/shared/debversions.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Debian version information
" Maintainer: Debian Vim Maintainers
-" Last Change: 2024 May 25
+" Last Change: 2024 Nov 04
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/syntax/shared/debversions.vim
let s:cpo = &cpo
@@ -11,7 +11,7 @@ let g:debSharedSupportedVersions = [
\ 'oldstable', 'stable', 'testing', 'unstable', 'experimental', 'sid', 'rc-buggy',
\ 'bullseye', 'bookworm', 'trixie', 'forky',
\
- \ 'focal', 'jammy', 'mantic', 'noble', 'oracular',
+ \ 'focal', 'jammy', 'noble', 'oracular', 'plucky',
\ 'devel'
\ ]
let g:debSharedUnsupportedVersions = [
@@ -23,8 +23,8 @@ let g:debSharedUnsupportedVersions = [
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'trusty', 'utopic', 'vivid', 'wily', 'xenial', 'yakkety', 'zesty',
- \ 'artful', 'bionic', 'cosmic', 'disco', 'eoan', 'hirsute',
- \ 'impish', 'kinetic', 'lunar', 'groovy'
+ \ 'artful', 'bionic', 'cosmic', 'disco', 'eoan', 'groovy',
+ \ 'hirsute', 'impish', 'kinetic', 'lunar', 'mantic',
\ ]
let &cpo=s:cpo
diff --git a/runtime/syntax/skill.vim b/runtime/syntax/skill.vim
index 47afffc0a9..dd4c191b6f 100644
--- a/runtime/syntax/skill.vim
+++ b/runtime/syntax/skill.vim
@@ -1,13 +1,14 @@
" Vim syntax file
" Language: SKILL
" Maintainer: Toby Schaffer <jtschaff@eos.ncsu.edu>
-" Last Change: 2003 May 11
" Comments: SKILL is a Lisp-like programming language for use in EDA
" tools from Cadence Design Systems. It allows you to have
" a programming environment within the Cadence environment
" that gives you access to the complete tool set and design
" database. This file also defines syntax highlighting for
" certain Design Framework II interface functions.
+" Last Change: 2003 May 11
+" 2024 Oct 08 by Vim Project: allow double backslashes in skillString
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -509,7 +510,7 @@ syn match skilltechFunctions "(\(tech\|tc\)\u\a\+\>"hs=s+1
syn match skilltechFunctions "\<\(tech\|tc\)\u\a\+("he=e-1
" strings
-syn region skillString start=+"+ skip=+\\"+ end=+"+
+syn region skillString start=+"+ skip=+\\\@<!\\"+ end=+"+
syn keyword skillTodo contained TODO FIXME XXX
syn keyword skillNote contained NOTE IMPORTANT
diff --git a/runtime/syntax/structurizr.vim b/runtime/syntax/structurizr.vim
index 363ee70438..c10f1a4569 100644
--- a/runtime/syntax/structurizr.vim
+++ b/runtime/syntax/structurizr.vim
@@ -1,10 +1,9 @@
" Vim syntax file
" Language: Structurizr DSL
" Maintainer: Bastian Venthur <venthur@debian.org>
-" Last Change: 2022-05-22
+" Last Change: 2024-11-06
" Remark: For a language reference, see
-" https://github.com/structurizr/dsl
-
+" https://docs.structurizr.com/dsl/language
if exists("b:current_syntax")
finish
@@ -20,7 +19,11 @@ syn region scomment start="/\*" end="\*/"
" keywords
syn keyword skeyword animation
syn keyword skeyword autoLayout
+syn keyword skeyword background
+syn keyword skeyword border
syn keyword skeyword branding
+syn keyword skeyword color
+syn keyword skeyword colour
syn keyword skeyword component
syn keyword skeyword configuration
syn keyword skeyword container
@@ -37,48 +40,74 @@ syn keyword skeyword element
syn keyword skeyword enterprise
syn keyword skeyword exclude
syn keyword skeyword filtered
+syn keyword skeyword font
+syn keyword skeyword fontsize
syn keyword skeyword group
syn keyword skeyword healthcheck
+syn keyword skeyword height
+syn keyword skeyword icon
+syn keyword skeyword image
syn keyword skeyword include
syn keyword skeyword infrastructurenode
syn keyword skeyword instances
+syn keyword skeyword logo
+syn keyword skeyword metadata
syn keyword skeyword model
+syn keyword skeyword opacity
syn keyword skeyword person
syn keyword skeyword perspectives
syn keyword skeyword properties
syn keyword skeyword relationship
+syn keyword skeyword routing
+syn keyword skeyword scope
+syn keyword skeyword shape
syn keyword skeyword softwaresystem
syn keyword skeyword softwaresysteminstance
+syn keyword skeyword stroke
+syn keyword skeyword strokewidth
syn keyword skeyword styles
syn keyword skeyword systemcontext
syn keyword skeyword systemlandscape
+syn keyword skeyword tag
syn keyword skeyword tags
syn keyword skeyword technology
syn keyword skeyword terminology
syn keyword skeyword theme
syn keyword skeyword themes
+syn keyword skeyword thickness
+syn keyword skeyword this
syn keyword skeyword title
syn keyword skeyword url
syn keyword skeyword users
syn keyword skeyword views
+syn keyword skeyword visibility
+syn keyword skeyword width
syn keyword skeyword workspace
syn match skeyword "\!adrs\s\+"
-syn match skeyword "\!constant\s\+"
+syn match skeyword "\!components\s\+"
syn match skeyword "\!docs\s\+"
+syn match skeyword "\!element\s\+"
+syn match skeyword "\!elements\s\+"
+syn match skeyword "\!extend\s\+"
syn match skeyword "\!identifiers\s\+"
syn match skeyword "\!impliedrelationships\s\+"
syn match skeyword "\!include\s\+"
syn match skeyword "\!plugin\s\+"
syn match skeyword "\!ref\s\+"
+syn match skeyword "\!relationship\s\+"
+syn match skeyword "\!relationships\s\+"
syn match skeyword "\!script\s\+"
syn region sstring oneline start='"' end='"'
syn region sblock start='{' end='}' fold transparent
+syn match soperator "\->\s+"
+
hi def link sstring string
hi def link scomment comment
hi def link skeyword keyword
+hi def link soperator operator
let b:current_syntax = "structurizr"
diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim
index d09d476a5a..94b9a913fc 100644
--- a/runtime/syntax/swayconfig.vim
+++ b/runtime/syntax/swayconfig.vim
@@ -3,7 +3,7 @@
" Original Author: Josef Litos (JosefLitos/i3config.vim)
" Maintainer: James Eapen <james.eapen@vai.org>
" Version: 1.2.4
-" Last Change: 2024-05-24
+" Last Change: 2024 Oct 17
" References:
" http://i3wm.org/docs/userguide.html#configuring
@@ -29,7 +29,7 @@ syn keyword i3ConfigConditionProp app_id pid shell contained
syn keyword i3ConfigWorkspaceDir prev_on_output next_on_output contained
-syn match i3ConfigBindArgument /--\(locked\|to-code\|no-repeat\|input-device=[^ '"]*\|no-warn\) / contained contains=i3ConfigShOper,@i3ConfigStrVar nextgroup=i3ConfigBindArgument,i3ConfigBindCombo
+syn match i3ConfigBindArgument /--\(locked\|to-code\|no-repeat\|input-device=[^ '"]*\|no-warn\|inhibited\) / contained contains=i3ConfigShOper,@i3ConfigStrVar nextgroup=i3ConfigBindArgument,i3ConfigBindCombo
syn region i3ConfigBindArgument start=/--input-device=['"]/ end=/\s/ contained contains=@i3ConfigIdent,i3ConfigShOper,i3ConfigString nextgroup=i3ConfigBindArgument,i3ConfigBindCombo
syn region i3ConfigBindCombo matchgroup=i3ConfigParen start=/{$/ end=/^\s*}$/ contained contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigComment fold keepend extend
diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim
index d782bd4845..77a40e11d3 100644
--- a/runtime/syntax/tex.vim
+++ b/runtime/syntax/tex.vim
@@ -109,9 +109,9 @@ if s:tex_fold_enabled && &fdm == "manual"
setl fdm=syntax
endif
if s:tex_fold_enabled && has("folding")
- com! -nargs=* TexFold <args> fold
+ com! -nargs=* TexFold <args> fold
else
- com! -nargs=* TexFold <args>
+ com! -nargs=* TexFold <args>
endif
" (La)TeX keywords: uses the characters 0-9,a-z,A-Z,192-255 only... {{{1
@@ -424,7 +424,7 @@ if s:tex_fast =~# 'b'
syn region texEmphStyle matchgroup=texTypeStyle start="\\texts[cfl]\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
syn region texEmphStyle matchgroup=texTypeStyle start="\\textup\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
syn region texEmphStyle matchgroup=texTypeStyle start="\\texttt\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
- else
+ else
syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup
syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
diff --git a/runtime/syntax/typst.vim b/runtime/syntax/typst.vim
index 82fdadb3d5..dae1424780 100644
--- a/runtime/syntax/typst.vim
+++ b/runtime/syntax/typst.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Typst
" Maintainer: Gregory Anders <greg@gpanders.com>
-" Last Change: 2024-07-14
+" Last Change: 2024 Nov 02
" Based on: https://github.com/kaarmu/typst.vim
if exists('b:current_syntax')
@@ -18,8 +18,8 @@ syntax cluster typstCommon
" Common > Comment {{{2
syntax cluster typstComment
\ contains=typstCommentBlock,typstCommentLine
-syntax match typstCommentBlock
- \ #/\*\%(\_.\{-}\)\*/#
+syntax region typstCommentBlock
+ \ start="/\*" end="\*/" keepend
\ contains=typstCommentTodo,@Spell
syntax match typstCommentLine
\ #//.*#
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 9073c6e7bf..3ad04e2957 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -74,12 +74,22 @@ syn case match
com! -nargs=* Vim9 execute <q-args> s:vim9script ? "" : "contained"
com! -nargs=* VimL execute <q-args> s:vim9script ? "contained" : ""
-if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[afhHlmpPrt]'
+if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[acefhiHlmpPrt]'
if g:vimsyn_folding =~# 'a'
com! -nargs=* VimFolda <args> fold
else
com! -nargs=* VimFolda <args>
endif
+ if g:vimsyn_folding =~# 'c'
+ com! -nargs=* VimFoldc <args> fold
+ else
+ com! -nargs=* VimFoldc <args>
+ endif
+ if g:vimsyn_folding =~# 'e'
+ com! -nargs=* VimFolde <args> fold
+ else
+ com! -nargs=* VimFolde <args>
+ endif
if g:vimsyn_folding =~# 'f'
com! -nargs=* VimFoldf <args> fold
else
@@ -95,6 +105,11 @@ if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[afhHlmpPrt]'
else
com! -nargs=* VimFoldH <args>
endif
+ if g:vimsyn_folding =~# 'i'
+ com! -nargs=* VimFoldi <args> fold
+ else
+ com! -nargs=* VimFoldi <args>
+ endif
if g:vimsyn_folding =~# 'l'
com! -nargs=* VimFoldl <args> fold
else
@@ -127,7 +142,10 @@ if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[afhHlmpPrt]'
endif
else
com! -nargs=* VimFolda <args>
+ com! -nargs=* VimFoldc <args>
+ com! -nargs=* VimFolde <args>
com! -nargs=* VimFoldf <args>
+ com! -nargs=* VimFoldi <args>
com! -nargs=* VimFoldh <args>
com! -nargs=* VimFoldH <args>
com! -nargs=* VimFoldl <args>
@@ -177,8 +195,8 @@ syn match vimNumber '\%(^\|\A\)\zs#\x\{6}' skipwhite nextgroup=vimGlobal,vimSub
syn case match
" All vimCommands are contained by vimIsCommand. {{{2
-syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimCall,vimCatch,vimConst,vimDef,vimDelcommand,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimFuncFold,vimGlobal,vimHighlight,vimLet,vimLoadkeymap,vimMap,vimMark,vimMatch,vimNotFunc,vimNorm,vimSet,vimSleep,vimSyntax,vimThrow,vimUnlet,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate,@vim9CmdList
-syn cluster vim9CmdList contains=vim9Const,vim9Final,vim9For,vim9Var
+syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimCall,vimCatch,vimConst,vimDef,vimDefFold,vimDelcommand,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimFuncFold,vimGlobal,vimHighlight,vimLet,vimLoadkeymap,vimMap,vimMark,vimMatch,vimNotFunc,vimNormal,vimSet,vimSleep,vimSyntax,vimThrow,vimUnlet,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate,@vim9CmdList
+syn cluster vim9CmdList contains=vim9Class,vim9Const,vim9Enum,vim9Export,vim9Final,vim9For,vim9Interface,vim9Type,vim9Var
syn match vimCmdSep "[:|]\+" skipwhite nextgroup=@vimCmdList,vimSubst1
syn match vimIsCommand "\<\%(\h\w*\|[23]mat\%[ch]\)\>" contains=vimCommand
syn match vimBang contained "!"
@@ -189,6 +207,7 @@ syn match vimVar "\s\zs&t_\S[a-zA-Z0-9]\>"
syn match vimVar "\s\zs&t_k;"
syn match vimFBVar contained "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>"
syn keyword vimCommand contained in
+syn match vimBang contained "!"
syn cluster vimExprList contains=vimEnvvar,vimFunc,vimNumber,vimOper,vimOperParen,vimLetRegister,vimString,vimVar,@vim9ExprList
syn cluster vim9ExprList contains=vim9Boolean,vim9Null
@@ -220,6 +239,12 @@ syn keyword vimThrow th[row] skipwhite nextgroup=@vimExprList
syn keyword vimCatch cat[ch] skipwhite nextgroup=vimCatchPattern
syn region vimCatchPattern contained matchgroup=Delimiter start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSubstList oneline
+" Export {{{2
+" ======
+if s:vim9script
+ syn keyword vim9Export export skipwhite nextgroup=vim9Abstract,vim9ClassBody,vim9Const,vim9Def,vim9EnumBody,vim9Final,vim9InterfaceBody,vim9Type,vim9Var
+endif
+
" Filetypes {{{2
" =========
syn match vimFiletype "\<filet\%[ype]\(\s\+\I\i*\)*" skipwhite contains=vimFTCmd,vimFTOption,vimFTError
@@ -264,7 +289,7 @@ endif
syn cluster vimFuncList contains=vimFuncBang,vimFunctionError,vimFuncKey,vimFuncSID,Tag
syn cluster vimDefList contains=vimFuncBang,vimFunctionError,vimDefKey,vimFuncSID,Tag
-syn cluster vimFuncBodyCommon contains=@vimCmdList,vimCmplxRepeat,vimContinue,vimCtrlChar,vimDef,vimEnvvar,vimFBVar,vimFunc,vimFunction,vimLetHereDoc,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegister,vimSearch,vimSpecFile,vimString,vimSubst,vimFuncFold
+syn cluster vimFuncBodyCommon contains=@vimCmdList,vimCmplxRepeat,vimContinue,vimCtrlChar,vimDef,vimEnvvar,vimFBVar,vimFunc,vimFunction,vimLetHereDoc,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegister,vimSearch,vimSpecFile,vimString,vimSubst,vimFuncFold,vimDefFold
syn cluster vimFuncBodyList contains=@vimFuncBodyCommon,vimComment,vimLineComment,vimFuncVar,vimInsert,vimConst,vimLet
syn cluster vimDefBodyList contains=@vimFuncBodyCommon,vim9Comment,vim9LineComment,vim9Const,vim9Final,vim9Var,vim9Null,vim9Boolean,vim9For
@@ -273,7 +298,6 @@ syn match vimFunction "\<fu\%[nction]\>" skipwhite nextgroup=vimCmdSep,vimCommen
syn match vimDef "\<def\>" skipwhite nextgroup=vimCmdSep,vimComment,vimFuncPattern contains=vimDefKey
syn match vimFunction "\<fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+" contains=@vimFuncList skipwhite nextgroup=vimFuncParams
-syn match vimDef "\<def\s\+new\%(\i\|{.\{-1,}}\)\+" contains=@vimDefList nextgroup=vimDefParams
syn match vimDef "\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+" contains=@vimDefList nextgroup=vimDefParams
syn match vimFuncComment contained +".*+ skipwhite skipempty nextgroup=vimFuncBody,vimEndfunction
@@ -300,9 +324,8 @@ syn match vimEndfunction "\<endf\%[unction]\>" skipwhite nextgroup=vimCmdSep,vim
syn match vimEnddef "\<enddef\>" skipwhite nextgroup=vimCmdSep,vim9Comment,vimCommentError
if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f'
- syn region vimFuncFold start="\<fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+\s*(" end="\<endf\%[unction]\>" contains=vimFunction fold keepend extend transparent
- syn region vimFuncFold start="\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\)\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent
- syn region vimFuncFold start="\<def\s\+new\i\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent
+ syn region vimFuncFold start="\<fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+\s*(" end="\<endf\%[unction]\>" contains=vimFunction fold keepend extend transparent
+ syn region vimDefFold start="\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\)\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent
endif
syn match vimFuncVar contained "a:\%(\K\k*\|\d\+\)\>"
@@ -323,6 +346,100 @@ syn match vimUserType contained "\<\u\w*\>"
syn cluster vimType contains=vimType,vimCompoundType,vimUserType
+" Classes, Enums And Interfaces: {{{2
+" =============================
+
+if s:vim9script
+ " Methods {{{3
+ syn match vim9MethodDef contained "\<def\>" skipwhite nextgroup=vim9MethodDefName
+ syn match vim9MethodDefName contained "\<\h\w*\>" nextgroup=vim9MethodDefParams contains=@vim9MethodName
+ syn region vim9MethodDefParams contained
+ \ matchgroup=Delimiter start="(" end=")"
+ \ skipwhite skipnl nextgroup=vim9MethodDefBody,vimDefComment,vimEnddef,vim9MethodDefReturnType,vimCommentError
+ \ contains=vimDefParam,vim9Comment,vimFuncParamEquals
+ syn region vim9MethodDefReturnType contained
+ \ start=":\s" end="$" matchgroup=vim9Comment end="\ze[#"]"
+ \ skipwhite skipnl nextgroup=vim9MethodDefBody,vimDefComment,vimCommentError
+ \ contains=vimTypeSep
+ \ transparent
+ syn region vim9MethodDefBody contained
+ \ start="^.\=" matchgroup=vimCommand end="\<enddef\>"
+ \ skipwhite nextgroup=vimCmdSep,vim9Comment,vimCommentError
+ \ contains=@vim9MethodDefBodyList
+
+ syn cluster vim9MethodDefBodyList contains=@vimDefBodyList,vim9This,vim9Super
+
+ if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror")
+ syn match vim9MethodNameError contained "\<[a-z0-9]\i\>"
+ endif
+ syn match vim9MethodName contained "\<new\i*\>"
+ syn keyword vim9MethodName contained empty len string
+
+ syn cluster vim9MethodName contains=vim9MethodName,vim9MethodNameError
+
+ if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f'
+ syn region vim9MethodDefFold contained start="\%(^\s*\%(:\=static\s\+\)\=\)\@16<=:\=def\s\+\h\i*(" end="^\s*:\=enddef\>" contains=vim9MethodDef fold keepend extend transparent
+ syn region vim9MethodDefFold contained start="^\s*:\=def\s\+new\i*(" end="^\s*:\=enddef\>" contains=vim9MethodDef fold keepend extend transparent
+ endif
+
+ syn cluster vim9MethodDef contains=vim9MethodDef,vim9MethodDefFold
+
+ " Classes {{{3
+ syn cluster vim9ClassBodyList contains=vim9Abstract,vim9Class,vim9Comment,vim9LineComment,@vim9Continue,@vimExprList,vim9Extends,vim9Implements,@vim9MethodDef,vim9Public,vim9Static,vim9Const,vim9Final,vim9This,vim9Super,vim9Var
+
+ syn match vim9Class contained "\<class\>" skipwhite nextgroup=vim9ClassName
+ syn match vim9ClassName contained "\<\u\w*\>" skipwhite skipnl nextgroup=vim9Extends,vim9Implements
+ syn match vim9SuperClass contained "\<\u\w*\>" skipwhite skipnl nextgroup=vim9Implements
+ syn match vim9ImplementedInterface contained "\<\u\w*\>" skipwhite skipnl nextgroup=vim9InterfaceListComma,vim9Extends
+ syn match vim9InterfaceListComma contained "," skipwhite skipnl nextgroup=vim9ImplementedInterface
+ syn keyword vim9Abstract abstract skipwhite skipnl nextgroup=vim9ClassBody,vim9AbstractDef
+ syn keyword vim9Extends contained extends skipwhite skipnl nextgroup=vim9SuperClass
+ syn keyword vim9Implements contained implements skipwhite skipnl nextgroup=vim9ImplementedInterface
+ syn keyword vim9Public contained public
+ syn keyword vim9Static contained static
+ syn keyword vim9This contained this
+ syn keyword vim9Super contained super
+
+ VimFoldc syn region vim9ClassBody start="\<class\>" matchgroup=vimCommand end="\<endclass\>" contains=@vim9ClassBodyList transparent
+
+ " Enums {{{3
+ syn cluster vim9EnumBodyList contains=vim9Comment,vim9LineComment,@vim9Continue,vim9Enum,vim9Implements,@vim9MethodDef,vim9Const,vim9Final,vim9Var
+
+ syn match vim9Enum contained "\<enum\>" skipwhite nextgroup=vim9EnumName
+ syn match vim9EnumName contained "\<\u\w*\>" skipwhite skipnl nextgroup=vim9Implements
+
+ VimFolde syn region vim9EnumBody start="\<enum\>" matchgroup=vimCommand end="\<endenum\>" contains=@vim9EnumBodyList transparent
+
+ " Interfaces {{{3
+ " TODO: limit to decl only - no init values
+ syn cluster vim9InterfaceBodyList contains=vim9Comment,vim9LineComment,@vim9Continue,vim9Extends,vim9Interface,vim9AbstractDef,vim9Var
+
+ syn match vim9Interface contained "\<interface\>" skipwhite nextgroup=vim9InterfaceName
+ syn match vim9InterfaceName contained "\<\u\w*\>" skipwhite skipnl nextgroup=vim9Extends
+
+ syn keyword vim9AbstractDef contained def skipwhite nextgroup=vim9AbstractDefName
+ syn match vim9AbstractDefName contained "\<\h\w*\>" skipwhite nextgroup=vim9AbstractDefParams contains=@vim9MethodName
+ syn region vim9AbstractDefParams contained
+ \ matchgroup=Delimiter start="(" end=")"
+ \ skipwhite skipnl nextgroup=vimDefComment,vim9AbstractDefReturnType,vimCommentError
+ \ contains=vimDefParam,vim9Comment,vimFuncParamEquals
+ syn region vim9AbstractDefReturnType contained
+ \ start=":\s" end="$" matchgroup=vim9Comment end="\ze[#"]"
+ \ skipwhite skipnl nextgroup=vimDefComment,vimCommentError
+ \ contains=vimTypeSep
+ \ transparent
+
+ VimFoldi syn region vim9InterfaceBody start="\<interface\>" matchgroup=vimCommand end="\<endinterface\>" contains=@vim9InterfaceBodyList transparent
+
+ " type {{{3
+ syn match vim9Type "\<ty\%[pe]\>" skipwhite nextgroup=vim9TypeAlias,vim9TypeAliasError
+ syn match vim9TypeAlias contained "\<\u\w*\>" skipwhite nextgroup=vim9TypeEquals
+ syn match vim9TypeEquals contained "=" skipwhite nextgroup=@vimType
+ if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_notypealiaserror")
+ syn match vim9TypeAliasError contained "\<\U\w*"
+ endif
+endif
+
" Keymaps: {{{2
" =======
@@ -381,7 +498,7 @@ endif
syn case ignore
syn keyword vimUserCmdAttrKey contained a[ddr] ban[g] bar bu[ffer] com[plete] cou[nt] k[eepscript] n[args] ra[nge] re[gister]
" GEN_SYN_VIM: vimUserCmdAttrCmplt, START_STR='syn keyword vimUserCmdAttrCmplt contained', END_STR=''
-syn keyword vimUserCmdAttrCmplt contained arglist augroup behave breakpoint buffer color command compiler cscope diff_buffer dir dir_in_path environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages option packadd runtime scriptnames shellcmd sign syntax syntime tag tag_listfiles user var
+syn keyword vimUserCmdAttrCmplt contained arglist augroup behave breakpoint buffer color command compiler cscope diff_buffer dir dir_in_path environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages option packadd runtime scriptnames shellcmd shellcmdline sign syntax syntime tag tag_listfiles user var
syn keyword vimUserCmdAttrCmplt contained custom customlist nextgroup=vimUserCmdAttrCmpltFunc,vimUserCmdError
syn match vimUserCmdAttrCmpltFunc contained ",\%([sS]:\|<[sS][iI][dD]>\)\=\%(\h\w*\%([.#]\h\w*\)\+\|\h\w*\)"hs=s+1 nextgroup=vimUserCmdError
" GEN_SYN_VIM: vimUserCmdAttrAddr, START_STR='syn keyword vimUserCmdAttrAddr contained', END_STR=''
@@ -541,7 +658,7 @@ Vim9 syn keyword vim9Const const skipwhite nextgroup=vim9Variable,vim9VariableLi
Vim9 syn keyword vim9Final final skipwhite nextgroup=vim9Variable,vim9VariableList
Vim9 syn keyword vim9Var var skipwhite nextgroup=vim9Variable,vim9VariableList
-syn match vim9Variable contained "\<\h\w*\>" skipwhite nextgroup=vimTypeSep,vimLetHereDoc
+syn match vim9Variable contained "\<\h\w*\>" skipwhite nextgroup=vimTypeSep,vimLetHereDoc,vimOper
syn region vim9VariableList contained start="\[" end="]" contains=vim9Variable,@vimContinue
" For: {{{2
@@ -668,7 +785,7 @@ syn case match
" (following Gautam Iyer's suggestion)
" ==========================
syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" contains=vimFuncEcho,vimFuncName,vimUserFunc,vimExecute
-syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation
+syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation,vim9MethodName
syn keyword vimFuncEcho contained ec ech echo
syn match vimMap "\<map\%(\s\+(\)\@=" skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
@@ -696,10 +813,10 @@ syn keyword vimMatchNone contained none
syn case match
syn region vimMatchPattern contained matchgroup=Delimiter start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSubstList oneline
-" Norm: {{{2
-" ====
-syn match vimNorm "\<norm\%[al]!\=" skipwhite nextgroup=vimNormCmds
-syn match vimNormCmds contained ".*$"
+" Normal: {{{2
+" ======
+syn match vimNormal "\<norm\%[al]\>!\=" skipwhite nextgroup=vimNormalArg contains=vimBang
+syn region vimNormalArg contained start="\S" skip=+\n\s*\\\|\n\s*["#]\\ + end="$" contains=@vimContinue
" Sleep: {{{2
" =====
@@ -886,7 +1003,10 @@ syn match vimShebang "\%^#!.*" display
syn match vimContinue "^\s*\zs\\"
syn match vimContinueComment '^\s*\zs["#]\\ .*'
-syn cluster vimContinue contains=vimContinue,vimContinueComment
+syn match vim9ContinueComment "^\s*\zs#\\ .*"
+syn cluster vimContinue contains=vimContinue,vimContinueComment
+syn cluster vim9Continue contains=vimContinue,vim9ContinueComment
+
syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue
syn match vimCommentTitleLeader '"\s\+'ms=s+1 contained
syn match vim9CommentTitleLeader '#\s\+'ms=s+1 contained
@@ -1145,6 +1265,8 @@ if !exists("skip_vim_syntax_inits")
hi def link vimSynCaseError vimError
hi def link vimSynFoldMethodError vimError
hi def link vimBufnrWarn vimWarn
+
+ hi def link vim9TypeAliasError vimError
endif
hi def link vimAbb vimCommand
@@ -1255,8 +1377,9 @@ if !exists("skip_vim_syntax_inits")
hi def link vimMenuPriority Number
hi def link vimMenuStatus Special
hi def link vimMenutranslateComment vimComment
+ hi def link vim9MethodName vimFuncName
hi def link vimMtchComment vimComment
- hi def link vimNorm vimCommand
+ hi def link vimNormal vimCommand
hi def link vimNotation Special
hi def link vimNotFunc vimCommand
hi def link vimNotPatSep vimString
@@ -1348,19 +1471,36 @@ if !exists("skip_vim_syntax_inits")
hi def link vimVar Identifier
hi def link vimWarn WarningMsg
+ hi def link vim9Abstract vimCommand
hi def link vim9Boolean Boolean
+ hi def link vim9Class vimCommand
hi def link vim9Comment Comment
hi def link vim9CommentError vimError
hi def link vim9CommentTitle PreProc
hi def link vim9Const vimCommand
+ hi def link vim9ContinueComment vimContinueComment
+ hi def link vim9Enum vimCommand
+ hi def link vim9Export vimCommand
+ hi def link vim9Extends Keyword
hi def link vim9Final vimCommand
hi def link vim9For vimCommand
+ hi def link vim9Implements Keyword
+ hi def link vim9AbstractDef vimCommand
+ hi def link vim9Interface vimCommand
hi def link vim9LineComment vimComment
+ hi def link vim9MethodDef vimCommand
+ hi def link vim9MethodNameError vimFunctionError
hi def link vim9Null Constant
- hi def link vim9Var vimCommand
+ hi def link vim9Public vimCommand
+ hi def link vim9Static vimCommand
+ hi def link vim9Super Identifier
+ hi def link vim9This Identifier
+ hi def link vim9Type vimCommand
+ hi def link vim9TypeEquals vimOper
hi def link vim9Variable vimVar
- hi def link vim9Vim9Script vimCommand
+ hi def link vim9Var vimCommand
hi def link vim9Vim9ScriptArg Special
+ hi def link vim9Vim9Script vimCommand
hi def link nvimAutoEvent vimAutoEvent
hi def link nvimHLGroup vimHLGroup
@@ -1374,9 +1514,12 @@ let b:current_syntax = "vim"
delc Vim9
delc VimL
delc VimFolda
+delc VimFoldc
+delc VimFolde
delc VimFoldf
delc VimFoldh
delc VimFoldH
+delc VimFoldi
delc VimFoldl
delc VimFoldm
delc VimFoldp
diff --git a/runtime/tools/check_colors.vim b/runtime/tools/check_colors.vim
deleted file mode 100644
index 035914980d..0000000000
--- a/runtime/tools/check_colors.vim
+++ /dev/null
@@ -1,252 +0,0 @@
-" This script tests a color scheme for some errors and lists potential errors.
-" Load the scheme and source this script, like this:
-" :edit colors/desert.vim | :so tools/check_colors.vim
-
-let s:save_cpo= &cpo
-set cpo&vim
-
-func! Test_check_colors()
- let l:savedview = winsaveview()
- call cursor(1,1)
-
- " err is
- " {
- " colors_name: "message",
- " init: "message",
- " background: "message",
- " ....etc
- " highlight: {
- " 'Normal': "Missing ...",
- " 'Conceal': "Missing ..."
- " ....etc
- " }
- " }
- let err = {}
-
- " 1) Check g:colors_name is existing
- if search('\<\%(g:\)\?colors_name\>', 'cnW') == 0
- let err['colors_name'] = 'g:colors_name not set'
- else
- let err['colors_name'] = 'OK'
- endif
-
- " 2) Check for some well-defined highlighting groups
- let hi_groups = [
- \ 'ColorColumn',
- \ 'Comment',
- \ 'Conceal',
- \ 'Constant',
- \ 'Cursor',
- \ 'CursorColumn',
- \ 'CursorLine',
- \ 'CursorLineNr',
- \ 'DiffAdd',
- \ 'DiffChange',
- \ 'DiffDelete',
- \ 'DiffText',
- \ 'Directory',
- \ 'EndOfBuffer',
- \ 'Error',
- \ 'ErrorMsg',
- \ 'FoldColumn',
- \ 'Folded',
- \ 'Identifier',
- \ 'Ignore',
- \ 'IncSearch',
- \ 'LineNr',
- \ 'MatchParen',
- \ 'ModeMsg',
- \ 'MoreMsg',
- \ 'NonText',
- \ 'Normal',
- \ 'Pmenu',
- \ 'PmenuSbar',
- \ 'PmenuSel',
- \ 'PmenuThumb',
- \ 'PreProc',
- \ 'Question',
- \ 'QuickFixLine',
- \ 'Search',
- \ 'SignColumn',
- \ 'Special',
- \ 'SpecialKey',
- \ 'SpellBad',
- \ 'SpellCap',
- \ 'SpellLocal',
- \ 'SpellRare',
- \ 'Statement',
- \ 'StatusLine',
- \ 'StatusLineNC',
- \ 'StatusLineTerm',
- \ 'StatusLineTermNC',
- \ 'TabLine',
- \ 'TabLineFill',
- \ 'TabLineSel',
- \ 'Title',
- \ 'Todo',
- \ 'ToolbarButton',
- \ 'ToolbarLine',
- \ 'Type',
- \ 'Underlined',
- \ 'VertSplit',
- \ 'Visual',
- \ 'VisualNOS',
- \ 'WarningMsg',
- \ 'WildMenu',
- \ ]
- let groups = {}
- for group in hi_groups
- if search('\c@suppress\s\+\<' .. group .. '\>', 'cnW')
- " skip check, if the script contains a line like
- " @suppress Visual:
- continue
- endif
- if search('hi\%[ghlight]!\= \+link \+' .. group, 'cnW') " Linked group
- continue
- endif
- if !search('hi\%[ghlight] \+\<' .. group .. '\>', 'cnW')
- let groups[group] = 'No highlight definition for ' .. group
- continue
- endif
- if !search('hi\%[ghlight] \+\<' .. group .. '\>.*[bf]g=', 'cnW')
- let groups[group] = 'Missing foreground or background color for ' .. group
- continue
- endif
- if search('hi\%[ghlight] \+\<' .. group .. '\>.*guibg=', 'cnW') &&
- \ !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermbg=', 'cnW')
- \ && group != 'Cursor'
- let groups[group] = 'Missing bg terminal color for ' .. group
- continue
- endif
- if !search('hi\%[ghlight] \+\<' .. group .. '\>.*guifg=', 'cnW')
- \ && group !~ '^Diff'
- let groups[group] = 'Missing guifg definition for ' .. group
- continue
- endif
- if !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermfg=', 'cnW')
- \ && group !~ '^Diff'
- \ && group != 'Cursor'
- let groups[group] = 'Missing ctermfg definition for ' .. group
- continue
- endif
- " do not check for background colors, they could be intentionally left out
- call cursor(1,1)
- endfor
- let err['highlight'] = groups
-
- " 3) Check, that it does not set background highlighting
- " Doesn't ':hi Normal ctermfg=253 ctermfg=233' also set the background sometimes?
- let bg_set = '\(set\?\|setl\(ocal\)\?\) .*\(background\|bg\)=\(dark\|light\)'
- let bg_let = 'let \%([&]\%([lg]:\)\?\)\%(background\|bg\)\s*=\s*\([''"]\?\)\w\+\1'
- let bg_pat = '\%(' .. bg_set .. '\|' .. bg_let .. '\)'
- let line = search(bg_pat, 'cnW')
- if search(bg_pat, 'cnW')
- exe line
- if search('hi \U\w\+\s\+\S', 'cbnW')
- let err['background'] = 'Should not set background option after :hi statement'
- endif
- else
- let err['background'] = 'OK'
- endif
- call cursor(1,1)
-
- " 4) Check, that t_Co is checked
- let pat = '[&]t_Co\s*[<>=]=\?\s*\d\+'
- if !search(pat, 'ncW')
- let err['t_Co'] = 'Does not check terminal for capable colors'
- endif
-
- " 5) Initializes correctly, e.g. should have a section like
- " hi clear
- " if exists("syntax_on")
- " syntax reset
- " endif
- let pat = 'hi\%[ghlight]\s*clear\n\s*if\s*exists(\([''"]\)syntax_on\1)\n\s*syn\%[tax]\s*reset\n\s*endif'
- if !search(pat, 'cnW')
- let err['init'] = 'No initialization'
- endif
-
- " 6) Does not use :syn on
- if search('syn\%[tax]\s\+on', 'cnW')
- let err['background'] = 'Should not issue :syn on'
- endif
-
- " 7) Does not define filetype specific groups like vimCommand, htmlTag,
- let hi_groups = filter(getcompletion('', 'filetype'), { _,v -> v !~# '\%[no]syn\%(color\|load\|tax\)' })
- let ft_groups = []
- " let group = '\%('.join(hi_groups, '\|').'\)' " More efficient than a for loop, but less informative
- for group in hi_groups
- let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\w\+\>\ze \+.' " Skips `hi clear`
- if search(pat, 'cW')
- call add(ft_groups, matchstr(getline('.'), pat))
- endif
- call cursor(1,1)
- endfor
- if !empty(ft_groups)
- let err['filetype'] = get(err, 'filetype', 'Should not define: ') . join(uniq(sort(ft_groups)))
- endif
-
- " 8) Were debugPC and debugBreakpoint defined?
- for group in ['debugPC', 'debugBreakpoint']
- let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\>'
- if search(pat, 'cnW')
- let line = search(pat, 'cW')
- let err['filetype'] = get(err, 'filetype', 'Should not define: ') . matchstr(getline('.'), pat). ' '
- endif
- call cursor(1,1)
- endfor
-
- " 9) Normal should be defined first, not use reverse, fg or bg
- call cursor(1,1)
- let pat = 'hi\%[ghlight] \+\%(link\|clear\)\@!\w\+\>'
- call search(pat, 'cW') " Look for the first hi def, skipping `hi link` and `hi clear`
- if getline('.') !~# '\m\<Normal\>'
- let err['highlight']['Normal'] = 'Should be defined first'
- elseif getline('.') =~# '\m\%(=\%(fg\|bg\)\)'
- let err['highlight']['Normal'] = "Should not use 'fg' or 'bg'"
- elseif getline('.') =~# '\m=\%(inv\|rev\)erse'
- let err['highlight']['Normal'] = 'Should not use reverse mode'
- endif
-
- call winrestview(l:savedview)
- let g:err = err
-
- " print Result
- call Result(err)
-endfu
-
-
-fu! Result(err)
- let do_groups = 0
- echohl Title|echomsg "---------------"|echohl Normal
- for key in sort(keys(a:err))
- if key ==# 'highlight'
- let do_groups = !empty(a:err[key])
- continue
- else
- if a:err[key] !~ 'OK'
- echohl Title
- endif
- echomsg printf("%15s: %s", key, a:err[key])
- echohl Normal
- endif
- endfor
- echohl Title|echomsg "---------------"|echohl Normal
- if do_groups
- echohl Title | echomsg "Groups" | echohl Normal
- for v1 in sort(keys(a:err['highlight']))
- echomsg printf("%25s: %s", v1, a:err['highlight'][v1])
- endfor
- endif
-endfu
-
-try
- call Test_check_colors()
-catch
- echohl ErrorMsg
- echomsg v:exception
- echohl NONE
-finally
- let &cpo = s:save_cpo
- unlet s:save_cpo
-endtry
diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor
index e6b81d63b9..95d4f4eafd 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -302,7 +302,7 @@ it would be easier to simply type two d's to delete a line.
3. Now move to the fourth line.
- 4. Type `2dd`{normal} to delete two lines.
+ 4. Type `2dd`{normal} to delete two lines, then press `u`{normal} twice to undo all three lines.
1) Roses are red,
2) Mud is fun,
@@ -689,7 +689,7 @@ NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move the c
1. Place the cursor just above this line.
NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
- DOWN to see this lesson again.
+ DOWN to see this lesson again. Press `u`{normal} to undo after you are done.
2. Now retrieve your TEST file using the command
@@ -736,12 +736,12 @@ NOTE: You can also read the output of an external command. For example,
2. Type the lowercase letter `o`{normal} to [open](o) up a line BELOW the
cursor and place you in Insert mode.
- 3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
+ 3. Now type some text and press `<Esc>`{normal} to exit Insert mode. Remove your opened lines after you're done.
After typing `o`{normal} the cursor is placed on the open line in Insert mode.
4. To open up a line ABOVE the cursor, simply type a [capital O](O), rather
- than a lowercase `o`{normal}. Try this on the line below.
+ than a lowercase `o`{normal}. Try this on the line below. Remove your opened lines after you're done.
Open up a line above this by typing O while the cursor is on this line.
diff --git a/scripts/bump_deps.lua b/scripts/bump_deps.lua
index e332ef475f..ad71da5150 100755
--- a/scripts/bump_deps.lua
+++ b/scripts/bump_deps.lua
@@ -325,10 +325,8 @@ function M.commit(dependency_name, commit)
end
function M.version(dependency_name, version)
- vim.validate {
- dependency_name = { dependency_name, 's' },
- version = { version, 's' },
- }
+ vim.validate('dependency_name', dependency_name, 'string')
+ vim.validate('version', version, 'string')
local dependency = assert(get_dependency(dependency_name))
verify_cmakelists_committed()
local commit_sha = get_gh_commit_sha(dependency.repo, version)
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index b9ea4e73f0..a9431ae2e5 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -617,8 +617,8 @@ local function render_option_meta(_f, opt, write)
end
for _, s in pairs {
- { 'wo', 'window' },
- { 'bo', 'buffer' },
+ { 'wo', 'win' },
+ { 'bo', 'buf' },
{ 'go', 'global' },
} do
local id, scope = s[1], s[2]
@@ -661,8 +661,8 @@ end
local function scope_to_doc(s)
local m = {
global = 'global',
- buffer = 'local to buffer',
- window = 'local to window',
+ buf = 'local to buffer',
+ win = 'local to window',
tab = 'local to tab page',
}
@@ -670,7 +670,7 @@ local function scope_to_doc(s)
return m[s[1]]
end
assert(s[1] == 'global')
- return 'global or ' .. m[s[2]] .. ' |global-local|'
+ return 'global or ' .. m[s[2]] .. (s[2] ~= 'tab' and ' |global-local|' or '')
end
-- @param o vim.option_meta
@@ -717,7 +717,9 @@ local function get_option_meta()
local optinfo = vim.api.nvim_get_all_options_info()
local ret = {} --- @type table<string,vim.option_meta>
for _, o in ipairs(opts) do
- if o.desc then
+ local is_window_option = #o.scope == 1 and o.scope[1] == 'win'
+ local is_option_hidden = o.immutable and not o.varname and not is_window_option
+ if not is_option_hidden and o.desc then
if o.full_name == 'cmdheight' then
table.insert(o.scope, 'tab')
end
diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua
index f6e799508b..b8f80e94be 100644
--- a/scripts/gen_help_html.lua
+++ b/scripts/gen_help_html.lua
@@ -554,11 +554,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
return '' -- Spurious "===" or "---" in the help doc.
end
- -- Use the first *tag* node as the heading anchor, if any.
- local tagnode = first(heading_node, 'tag')
- -- Use the *tag* as the heading anchor id, if possible.
- local tagname = tagnode and url_encode(trim(node_text(tagnode:child(1), false)))
- or to_heading_tag(hname)
+ -- Generate an anchor id from the heading text.
+ local tagname = to_heading_tag(hname)
if node_name == 'h1' or #headings == 0 then
---@type nvim.gen_help_html.heading
local heading = { name = hname, subheadings = {}, tag = tagname }
@@ -678,7 +675,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
table.insert(stats.first_tags, tagname)
return ''
end
- local el = in_heading and 'span' or 'code'
+ local el = 'span'
local encoded_tagname = url_encode(tagname)
local s = ('%s<%s id="%s" class="%s"><a href="#%s">%s</a></%s>'):format(
ws(),
@@ -694,15 +691,6 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
end
if in_heading and prev ~= 'tag' then
- -- Don't set "id", let the heading use the tag as its "id" (used by search engines).
- s = ('%s<%s class="%s"><a href="#%s">%s</a></%s>'):format(
- ws(),
- el,
- cssclass,
- encoded_tagname,
- trimmed,
- el
- )
-- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2>
@@ -957,7 +945,7 @@ local function gen_one(fname, text, to_fname, old, commit, parser_path)
<div class="container golden-grid help-body">
<div class="col-wide">
- <a name="%s"></a><h1 id="%s">%s</h1>
+ <a name="%s" href="#%s"><h1 id="%s">%s</h1></a>
<p>
<i>
Nvim <code>:help</code> pages, <a href="https://github.com/neovim/neovim/blob/master/scripts/gen_help_html.lua">generated</a>
@@ -970,8 +958,9 @@ local function gen_one(fname, text, to_fname, old, commit, parser_path)
</div>
]]):format(
logo_svg,
- stats.first_tags[2] or '',
stats.first_tags[1] or '',
+ stats.first_tags[2] or '',
+ stats.first_tags[2] or '',
title,
vim.fs.basename(fname),
main
@@ -1300,25 +1289,15 @@ end
---
--- @return nvim.gen_help_html.gen_result result
function M.gen(help_dir, to_dir, include, commit, parser_path)
- vim.validate {
- help_dir = {
- help_dir,
- function(d)
- return vim.fn.isdirectory(vim.fs.normalize(d)) == 1
- end,
- 'valid directory',
- },
- to_dir = { to_dir, 's' },
- include = { include, 't', true },
- commit = { commit, 's', true },
- parser_path = {
- parser_path,
- function(f)
- return f == nil or vim.fn.filereadable(vim.fs.normalize(f)) == 1
- end,
- 'valid vimdoc.{so,dll} filepath',
- },
- }
+ vim.validate('help_dir', help_dir, function(d)
+ return vim.fn.isdirectory(vim.fs.normalize(d)) == 1
+ end, 'valid directory')
+ vim.validate('to_dir', to_dir, 'string')
+ vim.validate('include', include, 'table', true)
+ vim.validate('commit', commit, 'string', true)
+ vim.validate('parser_path', parser_path, function(f)
+ return vim.fn.filereadable(vim.fs.normalize(f)) == 1
+ end, true, 'valid vimdoc.{so,dll} filepath')
local err_count = 0
local redirects_count = 0
@@ -1421,23 +1400,13 @@ end
---
--- @return nvim.gen_help_html.validate_result result
function M.validate(help_dir, include, parser_path)
- vim.validate {
- help_dir = {
- help_dir,
- function(d)
- return vim.fn.isdirectory(vim.fs.normalize(d)) == 1
- end,
- 'valid directory',
- },
- include = { include, 't', true },
- parser_path = {
- parser_path,
- function(f)
- return f == nil or vim.fn.filereadable(vim.fs.normalize(f)) == 1
- end,
- 'valid vimdoc.{so,dll} filepath',
- },
- }
+ vim.validate('help_dir', help_dir, function(d)
+ return vim.fn.isdirectory(vim.fs.normalize(d)) == 1
+ end, 'valid directory')
+ vim.validate('include', include, 'table', true)
+ vim.validate('parser_path', parser_path, function(f)
+ return vim.fn.filereadable(vim.fs.normalize(f)) == 1
+ end, true, 'valid vimdoc.{so,dll} filepath')
local err_count = 0 ---@type integer
local files_to_errors = {} ---@type table<string, string[]>
ensure_runtimepath()
diff --git a/scripts/gen_lsp.lua b/scripts/gen_lsp.lua
index c8dcf8c018..8afbae239a 100644
--- a/scripts/gen_lsp.lua
+++ b/scripts/gen_lsp.lua
@@ -58,14 +58,6 @@ end
---@param protocol vim._gen_lsp.Protocol
local function gen_methods(protocol)
- local output = {
- '-- Generated by gen_lsp.lua, keep at end of file.',
- '---',
- '---@enum vim.lsp.protocol.Methods',
- '---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel',
- '--- LSP method names.',
- 'protocol.Methods = {',
- }
local indent = (' '):rep(2)
--- @class vim._gen_lsp.Request
@@ -98,6 +90,41 @@ local function gen_methods(protocol)
table.sort(all, function(a, b)
return to_luaname(a.method) < to_luaname(b.method)
end)
+
+ local output = {
+ '-- Generated by gen_lsp.lua, keep at end of file.',
+ '--- @alias vim.lsp.protocol.Method.ClientToServer',
+ }
+ for _, item in ipairs(all) do
+ if item.method and item.messageDirection == 'clientToServer' then
+ output[#output + 1] = ("--- | '%s',"):format(item.method)
+ end
+ end
+
+ vim.list_extend(output, {
+ '',
+ '--- @alias vim.lsp.protocol.Method.ServerToClient',
+ })
+ for _, item in ipairs(all) do
+ if item.method and item.messageDirection == 'serverToClient' then
+ output[#output + 1] = ("--- | '%s',"):format(item.method)
+ end
+ end
+
+ vim.list_extend(output, {
+ '',
+ '--- @alias vim.lsp.protocol.Method',
+ '--- | vim.lsp.protocol.Method.ClientToServer',
+ '--- | vim.lsp.protocol.Method.ServerToClient',
+ '',
+ '-- Generated by gen_lsp.lua, keep at end of file.',
+ '---',
+ '--- @enum vim.lsp.protocol.Methods',
+ '--- @see https://microsoft.github.io/language-server-protocol/specification/#metaModel',
+ '--- LSP method names.',
+ 'protocol.Methods = {',
+ })
+
for _, item in ipairs(all) do
if item.method then
if item.documentation then
diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua
index 8908097397..9cd5b598da 100755
--- a/scripts/gen_vimdoc.lua
+++ b/scripts/gen_vimdoc.lua
@@ -135,7 +135,7 @@ local config = {
lua = {
filename = 'lua.txt',
section_order = {
- 'highlight.lua',
+ 'hl.lua',
'diff.lua',
'mpack.lua',
'json.lua',
@@ -174,7 +174,7 @@ local config = {
'runtime/lua/vim/filetype.lua',
'runtime/lua/vim/keymap.lua',
'runtime/lua/vim/fs.lua',
- 'runtime/lua/vim/highlight.lua',
+ 'runtime/lua/vim/hl.lua',
'runtime/lua/vim/secure.lua',
'runtime/lua/vim/version.lua',
'runtime/lua/vim/_inspector.lua',
@@ -221,7 +221,7 @@ local config = {
end
if
contains(name, {
- 'highlight',
+ 'hl',
'mpack',
'json',
'base64',
@@ -289,6 +289,9 @@ local config = {
},
fn_xform = function(fun)
fun.name = fun.name:gsub('result%.', '')
+ if fun.module == 'vim.lsp.protocol' then
+ fun.classvar = nil
+ end
end,
section_fmt = function(name)
if name:lower() == 'lsp' then
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index bfa9f6d99c..b0ec225633 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -213,8 +213,8 @@ preprocess_patch() {
# Remove "Last change ..." changes in doc files.
2>/dev/null $nvim --cmd 'set dir=/tmp' +'%s/^@@.*\n.*For Vim version.*Last change.*\n.*For Vim version.*Last change.*//' +w +q "$file"
- # Remove gui, option, setup, screen dumps, testdir/Make_*.mak files
- local na_src_testdir='gen_opt_test\.vim\|gui_.*\|Make_amiga\.mak\|Make_dos\.mak\|Make_ming\.mak\|Make_vms\.mms\|dumps/.*\.dump\|setup_gui\.vim'
+ # Remove gui, setup, screen dumps, testdir/Make_*.mak files
+ local na_src_testdir='gui_.*\|Make_amiga\.mak\|Make_dos\.mak\|Make_ming\.mak\|Make_vms\.mms\|dumps/.*\.dump\|setup_gui\.vim'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/testdir/\<\%('"${na_src_testdir}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
# Remove testdir/test_*.vim files
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index c2a358327a..344b4bef00 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -31,7 +31,7 @@ target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY})
find_package(Iconv REQUIRED)
find_package(Libuv 1.28.0 REQUIRED)
find_package(Lpeg REQUIRED)
-find_package(Treesitter 0.23.0 REQUIRED)
+find_package(Treesitter 0.24.0 REQUIRED)
find_package(Unibilium 2.0 REQUIRED)
find_package(UTF8proc REQUIRED)
@@ -49,7 +49,7 @@ if(ENABLE_LIBINTL)
endif()
if(ENABLE_WASMTIME)
- find_package(Wasmtime 25.0.1 EXACT REQUIRED)
+ find_package(Wasmtime 25.0.2 EXACT REQUIRED)
target_link_libraries(main_lib INTERFACE wasmtime)
target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME)
endif()
@@ -308,7 +308,6 @@ set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua)
set(GENERATOR_PRELOAD ${GENERATOR_DIR}/preload.lua)
set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua)
-set(OPTIONS_ENUM_GENERATOR ${GENERATOR_DIR}/gen_options_enum.lua)
set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua)
# GENERATED_DIR and GENERATED_INCLUDES_DIR
@@ -687,16 +686,11 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${LUA_GEN_DEPS} ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
-add_custom_command(OUTPUT ${GENERATED_OPTIONS}
- COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS}
+add_custom_command(OUTPUT ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
+ COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
)
-add_custom_command(OUTPUT ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
- COMMAND ${LUA_GEN} ${OPTIONS_ENUM_GENERATOR} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
- DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_ENUM_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
-)
-
# NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive.
foreach(hfile ${NVIM_GENERATED_FOR_HEADERS})
list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx)
@@ -750,6 +744,7 @@ add_custom_target(nvim_runtime_deps)
if(WIN32)
# Copy DLLs and third-party tools to bin/ and install them along with nvim
add_custom_command(TARGET nvim_runtime_deps
+ POST_BUILD
COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${PROJECT_BINARY_DIR}/windows_runtime_deps/
${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
install(DIRECTORY ${PROJECT_BINARY_DIR}/windows_runtime_deps/
@@ -791,7 +786,10 @@ file(MAKE_DIRECTORY ${BINARY_LIB_DIR})
# install treesitter parser if bundled
if(EXISTS ${DEPS_PREFIX}/lib/nvim/parser)
- add_custom_command(TARGET nvim_runtime_deps COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser)
+ add_custom_command(
+ TARGET nvim_runtime_deps
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser)
endif()
install(DIRECTORY ${BINARY_LIB_DIR}
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 6376011106..b38a7d4173 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -533,7 +533,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(11)
{
- set_option_to(channel_id, NULL, kOptReqGlobal, name, value, err);
+ set_option_to(channel_id, NULL, kOptScopeGlobal, name, value, err);
}
/// Gets the global value of an option.
@@ -546,7 +546,7 @@ Object nvim_get_option(String name, Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(11)
{
- return get_option_from(NULL, kOptReqGlobal, name, err);
+ return get_option_from(NULL, kOptScopeGlobal, name, err);
}
/// Gets a buffer option value
@@ -566,7 +566,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return get_option_from(buf, kOptReqBuf, name, err);
+ return get_option_from(buf, kOptScopeBuf, name, err);
}
/// Sets a buffer option value. Passing `nil` as value deletes the option (only
@@ -588,7 +588,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object
return;
}
- set_option_to(channel_id, buf, kOptReqBuf, name, value, err);
+ set_option_to(channel_id, buf, kOptScopeBuf, name, value, err);
}
/// Gets a window option value
@@ -608,7 +608,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return get_option_from(win, kOptReqWin, name, err);
+ return get_option_from(win, kOptScopeWin, name, err);
}
/// Sets a window option value. Passing `nil` as value deletes the option (only
@@ -630,26 +630,32 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object
return;
}
- set_option_to(channel_id, win, kOptReqWin, name, value, err);
+ set_option_to(channel_id, win, kOptScopeWin, name, value, err);
}
/// Gets the value of a global or local (buffer, window) option.
///
/// @param[in] from Pointer to buffer or window for local option value.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param name The option name.
/// @param[out] err Details of an error that may have occurred.
///
/// @return the option value.
-static Object get_option_from(void *from, OptReqScope req_scope, String name, Error *err)
+static Object get_option_from(void *from, OptScope req_scope, String name, Error *err)
{
VALIDATE_S(name.size > 0, "option name", "<empty>", {
return (Object)OBJECT_INIT;
});
- OptVal value = get_option_value_strict(find_option(name.data), req_scope, from, err);
- if (ERROR_SET(err)) {
- return (Object)OBJECT_INIT;
+ OptIndex opt_idx = find_option(name.data);
+ OptVal value = NIL_OPTVAL;
+
+ if (option_has_scope(opt_idx, req_scope)) {
+ value = get_option_value_for(opt_idx, req_scope == kOptScopeGlobal ? OPT_GLOBAL : OPT_LOCAL,
+ req_scope, from, err);
+ if (ERROR_SET(err)) {
+ return (Object)OBJECT_INIT;
+ }
}
VALIDATE_S(value.type != kOptValTypeNil, "option name", name.data, {
@@ -662,11 +668,11 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er
/// Sets the value of a global or local (buffer, window) option.
///
/// @param[in] to Pointer to buffer or window for local option value.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param name The option name.
/// @param value New option value.
/// @param[out] err Details of an error that may have occurred.
-static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, String name,
+static void set_option_to(uint64_t channel_id, void *to, OptScope req_scope, String name,
Object value, Error *err)
{
VALIDATE_S(name.size > 0, "option name", "<empty>", {
@@ -689,12 +695,12 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope,
return;
});
- int attrs = get_option_attrs(opt_idx);
// For global-win-local options -> setlocal
// For win-local options -> setglobal and setlocal (opt_flags == 0)
- const int opt_flags = (req_scope == kOptReqWin && !(attrs & SOPT_GLOBAL))
- ? 0
- : (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL;
+ const int opt_flags
+ = (req_scope == kOptScopeWin && !option_has_scope(opt_idx, kOptScopeGlobal))
+ ? 0
+ : ((req_scope == kOptScopeGlobal) ? OPT_GLOBAL : OPT_LOCAL);
WITH_SCRIPT_CONTEXT(channel_id, {
set_option_value_for(name.data, opt_idx, optval, opt_flags, req_scope, to, err);
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 7786c30624..c94b8df9ea 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -381,8 +381,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// - id : id of the extmark to edit.
/// - end_row : ending line of the mark, 0-based inclusive.
/// - end_col : ending col of the mark, 0-based exclusive.
-/// - hl_group : name of the highlight group used to highlight
-/// this mark.
+/// - hl_group : highlight group used for the text range. This and below
+/// highlight groups can be supplied either as a string or as an integer,
+/// the latter of which can be obtained using |nvim_get_hl_id_by_name()|.
/// - hl_eol : when true, for a multiline highlight covering the
/// EOL of a line, continue the highlight for the rest
/// of the screen line (just like for diff and
@@ -392,9 +393,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// text chunk with specified highlight. `highlight` element
/// can either be a single highlight group, or an array of
/// multiple highlight groups that will be stacked
-/// (highest priority last). A highlight group can be supplied
-/// either as a string or as an integer, the latter which
-/// can be obtained using |nvim_get_hl_id_by_name()|.
+/// (highest priority last).
/// - virt_text_pos : position of virtual text. Possible values:
/// - "eol": right after eol character (default).
/// - "overlay": display over the specified column, without
@@ -465,15 +464,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// buffer or end of the line respectively. Defaults to true.
/// - sign_text: string of length 1-2 used to display in the
/// sign column.
-/// - sign_hl_group: name of the highlight group used to
-/// highlight the sign column text.
-/// - number_hl_group: name of the highlight group used to
-/// highlight the number column.
-/// - line_hl_group: name of the highlight group used to
-/// highlight the whole line.
-/// - cursorline_hl_group: name of the highlight group used to
-/// highlight the sign column text when the cursor is on
-/// the same line as the mark and 'cursorline' is enabled.
+/// - sign_hl_group: highlight group used for the sign column text.
+/// - number_hl_group: highlight group used for the number column.
+/// - line_hl_group: highlight group used for the whole line.
+/// - cursorline_hl_group: highlight group used for the sign
+/// column text when the cursor is on the same line as the
+/// mark and 'cursorline' is enabled.
/// - conceal: string which should be either empty or a single
/// character. Enable concealing similar to |:syn-conceal|.
/// When a character is supplied it is used as |:syn-cchar|.
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 552612dd13..96aabb851f 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -119,6 +119,7 @@ typedef struct {
Array bufpos;
Boolean external;
Boolean focusable;
+ Boolean mouse;
Boolean vertical;
Integer zindex;
Object border;
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 1a0edd551e..3289daeb6f 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -23,8 +23,8 @@
#endif
static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *opt_idxp,
- int *scope, OptReqScope *req_scope, void **from,
- char **filetype, Error *err)
+ int *scope, OptScope *req_scope, void **from, char **filetype,
+ Error *err)
{
#define HAS_KEY_X(d, v) HAS_KEY(d, option, v)
if (HAS_KEY_X(opts, scope)) {
@@ -39,14 +39,14 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
}
}
- *req_scope = kOptReqGlobal;
+ *req_scope = kOptScopeGlobal;
if (filetype != NULL && HAS_KEY_X(opts, filetype)) {
*filetype = opts->filetype.data;
}
if (HAS_KEY_X(opts, win)) {
- *req_scope = kOptReqWin;
+ *req_scope = kOptScopeWin;
*from = find_window_by_handle(opts->win, err);
if (ERROR_SET(err)) {
return FAIL;
@@ -59,7 +59,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
return FAIL;
});
*scope = OPT_LOCAL;
- *req_scope = kOptReqBuf;
+ *req_scope = kOptScopeBuf;
*from = find_buffer_by_handle(opts->buf, err);
if (ERROR_SET(err)) {
return FAIL;
@@ -78,18 +78,17 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
});
*opt_idxp = find_option(name);
- int flags = get_option_attrs(*opt_idxp);
- if (flags == 0) {
- // hidden or unknown option
+ if (*opt_idxp == kOptInvalid) {
+ // unknown option
api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name);
- } else if (*req_scope == kOptReqBuf || *req_scope == kOptReqWin) {
+ } else if (*req_scope == kOptScopeBuf || *req_scope == kOptScopeWin) {
// if 'buf' or 'win' is passed, make sure the option supports it
- int req_flags = *req_scope == kOptReqBuf ? SOPT_BUF : SOPT_WIN;
- if (!(flags & req_flags)) {
- char *tgt = *req_scope & kOptReqBuf ? "buf" : "win";
- char *global = flags & SOPT_GLOBAL ? "global " : "";
- char *req = flags & SOPT_BUF ? "buffer-local "
- : flags & SOPT_WIN ? "window-local " : "";
+ if (!option_has_scope(*opt_idxp, *req_scope)) {
+ char *tgt = *req_scope == kOptScopeBuf ? "buf" : "win";
+ char *global = option_has_scope(*opt_idxp, kOptScopeGlobal) ? "global " : "";
+ char *req = option_has_scope(*opt_idxp, kOptScopeBuf)
+ ? "buffer-local "
+ : (option_has_scope(*opt_idxp, kOptScopeWin) ? "window-local " : "");
api_set_error(err, kErrorTypeValidation, "'%s' cannot be passed for %s%soption '%s'",
tgt, global, req, name);
@@ -153,7 +152,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *from = NULL;
char *filetype = NULL;
@@ -166,6 +165,14 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
buf_T *ftbuf = do_ft_buf(filetype, &aco, err);
if (ERROR_SET(err)) {
+ if (ftbuf != NULL) {
+ // restore curwin/curbuf and a few other things
+ aucmd_restbuf(&aco);
+
+ assert(curbuf != ftbuf); // safety check
+ wipe_buffer(ftbuf, false);
+ }
+
return (Object)OBJECT_INIT;
}
@@ -175,7 +182,6 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
}
OptVal value = get_option_value_for(opt_idx, scope, req_scope, from, err);
- bool hidden = is_option_hidden(opt_idx);
if (ftbuf != NULL) {
// restore curwin/curbuf and a few other things
@@ -189,7 +195,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
goto err;
}
- VALIDATE_S(!hidden && value.type != kOptValTypeNil, "option", name.data, {
+ VALIDATE_S(value.type != kOptValTypeNil, "option", name.data, {
goto err;
});
@@ -219,7 +225,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *to = NULL;
if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &to, NULL, err)) {
return;
@@ -231,9 +237,8 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
// - option is global or local to window (global-local)
//
// Then force scope to local since we don't want to change the global option
- if (req_scope == kOptReqWin && scope == 0) {
- int flags = get_option_attrs(opt_idx);
- if (flags & SOPT_GLOBAL) {
+ if (req_scope == kOptScopeWin && scope == 0) {
+ if (option_has_scope(opt_idx, kOptScopeGlobal)) {
scope = OPT_LOCAL;
}
}
@@ -306,15 +311,15 @@ Dict nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *from = NULL;
if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL,
err)) {
return (Dict)ARRAY_DICT_INIT;
}
- buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf;
- win_T *win = (req_scope == kOptReqWin) ? (win_T *)from : curwin;
+ buf_T *buf = (req_scope == kOptScopeBuf) ? (buf_T *)from : curbuf;
+ win_T *win = (req_scope == kOptScopeWin) ? (win_T *)from : curwin;
return get_vimoption(name, scope, buf, win, arena, err);
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index e1fb4ed732..8ddaecc58e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -771,7 +771,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
int id = (int)obj.data.integer;
return (1 <= id && id <= highlight_num_groups()) ? id : 0;
} else {
- api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what);
+ api_set_error(err, kErrorTypeValidation, "Invalid hl_group: %s", what);
return 0;
}
}
@@ -809,31 +809,22 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
{
HlMessage hl_msg = KV_INITIAL_VALUE;
for (size_t i = 0; i < chunks.size; i++) {
- if (chunks.items[i].type != kObjectTypeArray) {
- api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
+ VALIDATE_T("chunk", kObjectTypeArray, chunks.items[i].type, {
goto free_exit;
- }
+ });
Array chunk = chunks.items[i].data.array;
- if (chunk.size == 0 || chunk.size > 2
- || chunk.items[0].type != kObjectTypeString
- || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
- api_set_error(err, kErrorTypeValidation,
- "Chunk is not an array with one or two strings");
+ VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString),
+ "%s", "Invalid chunk: expected Array with 1 or 2 Strings", {
goto free_exit;
- }
+ });
String str = copy_string(chunk.items[0].data.string, NULL);
- int attr = 0;
+ int hl_id = 0;
if (chunk.size == 2) {
- String hl = chunk.items[1].data.string;
- if (hl.size > 0) {
- // TODO(bfredl): use object_to_hl_id and allow integer
- int hl_id = syn_check_group(hl.data, hl.size);
- attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- }
+ hl_id = object_to_hl_id(chunk.items[1], "text highlight", err);
}
- kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr }));
+ kv_push(hl_msg, ((HlMessageChunk){ .text = str, .hl_id = hl_id }));
}
return hl_msg;
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 57932e067e..d06f5c9c65 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -111,6 +111,12 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder;
#define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s))
#define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s))
+#define API_CLEAR_STRING(s) \
+ do { \
+ XFREE_CLEAR(s.data); \
+ s.size = 0; \
+ } while (0)
+
// Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean
#define api_init_integer
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 2bd8792d71..0ed208fc1a 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -102,7 +102,7 @@ void win_pos(Integer grid, Window win, Integer startrow, Integer startcol, Integ
Integer height)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_float_pos(Integer grid, Window win, String anchor, Integer anchor_grid, Float anchor_row,
- Float anchor_col, Boolean focusable, Integer zindex)
+ Float anchor_col, Boolean mouse_enabled, Integer zindex)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_external_pos(Integer grid, Window win)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
@@ -159,7 +159,7 @@ void wildmenu_hide(void)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void msg_show(String kind, Array content, Boolean replace_last)
- FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(6) FUNC_API_FAST FUNC_API_REMOTE_ONLY;
void msg_clear(void)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void msg_showcmd(Array content)
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 8c88a19147..83f9aa573d 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -594,10 +594,12 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Er
kvi_init(cookie.rv);
int flags = DIP_DIRFILE | (all ? DIP_ALL : 0);
+ TryState tstate;
+
+ try_enter(&tstate);
+ do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
+ vim_ignored = try_leave(&tstate, err);
- TRY_WRAP(err, {
- do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
- });
return arena_take_arraybuilder(arena, &cookie.rv);
}
@@ -777,12 +779,12 @@ void nvim_set_vvar(String name, Object value, Error *err)
/// Echo a message.
///
/// @param chunks A list of `[text, hl_group]` arrays, each representing a
-/// text chunk with specified highlight. `hl_group` element
-/// can be omitted for no highlight.
+/// text chunk with specified highlight group name or ID.
+/// `hl_group` element can be omitted for no highlight.
/// @param history if true, add to |message-history|.
/// @param opts Optional parameters.
-/// - verbose: Message was printed as a result of 'verbose' option
-/// if Nvim was invoked with -V3log_file, the message will be
+/// - verbose: Message is printed as a result of 'verbose' option.
+/// If Nvim was invoked with -V3log_file, the message will be
/// redirected to the log_file and suppressed from direct output.
void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err)
FUNC_API_SINCE(7)
@@ -796,7 +798,7 @@ void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err)
verbose_enter();
}
- msg_multiattr(hl_msg, history ? "echomsg" : "echo", history);
+ msg_multihl(hl_msg, history ? "echomsg" : "echo", history);
if (opts->verbose) {
verbose_leave();
@@ -1002,10 +1004,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
- set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
- set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
+ set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
+ set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
@@ -1317,15 +1319,15 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow,
return; // Nothing to do.
}
- reg->y_array = arena_alloc(arena, lines.size * sizeof(uint8_t *), true);
+ reg->y_array = arena_alloc(arena, lines.size * sizeof(String), true);
reg->y_size = lines.size;
for (size_t i = 0; i < lines.size; i++) {
VALIDATE_T("line", kObjectTypeString, lines.items[i].type, {
return;
});
String line = lines.items[i].data.string;
- reg->y_array[i] = arena_memdupz(arena, line.data, line.size);
- memchrsub(reg->y_array[i], NUL, NL, line.size);
+ reg->y_array[i] = copy_string(line, arena);
+ memchrsub(reg->y_array[i].data, NUL, NL, line.size);
}
finish_yankreg_from_object(reg, false);
@@ -2161,11 +2163,11 @@ Dict nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena,
if (num_id) {
stc_hl_id = num_id;
} else if (statuscol.use_cul) {
- stc_hl_id = HLF_CLN + 1;
+ stc_hl_id = HLF_CLN;
} else if (wp->w_p_rnu) {
- stc_hl_id = (lnum < wp->w_cursor.lnum ? HLF_LNA : HLF_LNB) + 1;
+ stc_hl_id = (lnum < wp->w_cursor.lnum ? HLF_LNA : HLF_LNB);
} else {
- stc_hl_id = HLF_N + 1;
+ stc_hl_id = HLF_N;
}
set_vim_var_nr(VV_LNUM, lnum);
@@ -2396,14 +2398,22 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
redraw_buf_range_later(rbuf, first, last);
}
- bool flush = opts->flush;
+ // Redraw later types require update_screen() so call implicitly unless set to false.
+ if (HAS_KEY(opts, redraw, valid) || HAS_KEY(opts, redraw, range)) {
+ opts->flush = HAS_KEY(opts, redraw, flush) ? opts->flush : true;
+ }
+
+ // When explicitly set to false and only "redraw later" types are present,
+ // don't call ui_flush() either.
+ bool flush_ui = opts->flush;
if (opts->tabline) {
// Flush later in case tabline was just hidden or shown for the first time.
if (redraw_tabline && firstwin->w_lines_valid == 0) {
- flush = true;
+ opts->flush = true;
} else {
draw_tabline();
}
+ flush_ui = true;
}
bool save_lz = p_lz;
@@ -2414,31 +2424,35 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
if (win == NULL) {
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (buf == NULL || wp->w_buffer == buf) {
- redraw_status(wp, opts, &flush);
+ redraw_status(wp, opts, &opts->flush);
}
}
} else {
- redraw_status(win, opts, &flush);
+ redraw_status(win, opts, &opts->flush);
}
+ flush_ui = true;
}
win_T *cwin = win ? win : curwin;
// Allow moving cursor to recently opened window and make sure it is drawn #28868.
if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) {
- flush = true;
+ opts->flush = true;
}
// Redraw pending screen updates when explicitly requested or when determined
// that it is necessary to properly draw other requested components.
- if (flush && !cmdpreview) {
+ if (opts->flush && !cmdpreview) {
update_screen();
}
if (opts->cursor) {
setcursor_mayforce(cwin, true);
+ flush_ui = true;
}
- ui_flush();
+ if (flush_ui) {
+ ui_flush();
+ }
RedrawingDisabled = save_rd;
p_lz = save_lz;
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index f63fdc5381..6f5a9a90c0 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -129,7 +129,12 @@
/// fractional.
/// - focusable: Enable focus by user actions (wincmds, mouse events).
/// Defaults to true. Non-focusable windows can be entered by
-/// |nvim_set_current_win()|.
+/// |nvim_set_current_win()|, or, when the `mouse` field is set to true,
+/// by mouse events. See |focusable|.
+/// - mouse: Specify how this window interacts with mouse events.
+/// Defaults to `focusable` value.
+/// - If false, mouse events pass through this window.
+/// - If true, mouse events interact with this window normally.
/// - external: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
@@ -714,6 +719,7 @@ Dict(win_config) nvim_win_get_config(Window window, Arena *arena, Error *err)
PUT_KEY_X(rv, focusable, config->focusable);
PUT_KEY_X(rv, external, config->external);
PUT_KEY_X(rv, hide, config->hide);
+ PUT_KEY_X(rv, mouse, config->mouse);
if (wp->w_floating) {
PUT_KEY_X(rv, width, config->width);
@@ -1202,6 +1208,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (HAS_KEY_X(config, focusable)) {
fconfig->focusable = config->focusable;
+ fconfig->mouse = config->focusable;
+ }
+
+ if (HAS_KEY_X(config, mouse)) {
+ fconfig->mouse = config->mouse;
}
if (HAS_KEY_X(config, zindex)) {
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index d509837de7..3243822c94 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -73,10 +73,10 @@ return {
'InsertLeavePre', -- just before leaving Insert mode
'LspAttach', -- after an LSP client attaches to a buffer
'LspDetach', -- after an LSP client detaches from a buffer
- 'LspRequest', -- after an LSP request is started, canceled, or completed
'LspNotify', -- after an LSP notice has been sent to the server
- 'LspTokenUpdate', -- after a visible LSP token is updated
'LspProgress', -- after a LSP progress update
+ 'LspRequest', -- after an LSP request is started, canceled, or completed
+ 'LspTokenUpdate', -- after a visible LSP token is updated
'MenuPopup', -- just before popup menu is displayed
'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
@@ -162,8 +162,8 @@ return {
LspAttach = true,
LspDetach = true,
LspNotify = true,
- LspRequest = true,
LspProgress = true,
+ LspRequest = true,
LspTokenUpdate = true,
RecordingEnter = true,
RecordingLeave = true,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 5a4ade913d..c08ef7a4c1 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -220,14 +220,14 @@ static void au_show_for_event(int group, event_T event, const char *pat)
// show the group name, if it's not the default group
if (ac->pat->group != AUGROUP_DEFAULT) {
if (last_group_name == NULL) {
- msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E));
+ msg_puts_hl(get_deleted_augroup(), HLF_E, false);
} else {
- msg_puts_attr(last_group_name, HL_ATTR(HLF_T));
+ msg_puts_hl(last_group_name, HLF_T, false);
}
msg_puts(" ");
}
// show the event name
- msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T));
+ msg_puts_hl(event_nr2name(event), HLF_T, false);
}
// Show pattern only if it changed.
@@ -240,7 +240,7 @@ static void au_show_for_event(int group, event_T event, const char *pat)
}
msg_col = 4;
- msg_outtrans(ac->pat->pat, 0);
+ msg_outtrans(ac->pat->pat, 0, false);
}
if (got_int) {
@@ -260,17 +260,17 @@ static void au_show_for_event(int group, event_T event, const char *pat)
size_t msglen = 100;
char *msg = xmallocz(msglen);
if (ac->exec.type == CALLABLE_CB) {
- msg_puts_attr(exec_to_string, HL_ATTR(HLF_8));
+ msg_puts_hl(exec_to_string, HLF_8, false);
snprintf(msg, msglen, " [%s]", ac->desc);
} else {
snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc);
}
- msg_outtrans(msg, 0);
+ msg_outtrans(msg, 0, false);
XFREE_CLEAR(msg);
} else if (ac->exec.type == CALLABLE_CB) {
- msg_puts_attr(exec_to_string, HL_ATTR(HLF_8));
+ msg_puts_hl(exec_to_string, HLF_8, false);
} else {
- msg_outtrans(exec_to_string, 0);
+ msg_outtrans(exec_to_string, 0, false);
}
XFREE_CLEAR(exec_to_string);
if (p_verbose > 0) {
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 4a87cebfa7..abcce0dfe8 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -255,7 +255,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg)
emsg(_("E83: Cannot allocate buffer, using other one..."));
enter_buffer(curbuf);
if (old_tw != curbuf->b_p_tw) {
- check_colorcolumn(curwin);
+ check_colorcolumn(NULL, curwin);
}
return FAIL;
}
@@ -1029,7 +1029,7 @@ void handle_swap_exists(bufref_T *old_curbuf)
enter_buffer(buf);
if (old_tw != curbuf->b_p_tw) {
- check_colorcolumn(curwin);
+ check_colorcolumn(NULL, curwin);
}
}
// If "old_curbuf" is NULL we are in big trouble here...
@@ -1669,7 +1669,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist)
// enter some buffer. Using the last one is hopefully OK.
enter_buffer(valid ? buf : lastbuf);
if (old_tw != curbuf->b_p_tw) {
- check_colorcolumn(curwin);
+ check_colorcolumn(NULL, curwin);
}
}
@@ -2097,6 +2097,8 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
clear_string_option(&buf->b_p_tc);
clear_string_option(&buf->b_p_tfu);
callback_free(&buf->b_tfu_cb);
+ clear_string_option(&buf->b_p_ffu);
+ callback_free(&buf->b_ffu_cb);
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);
clear_string_option(&buf->b_p_qe);
@@ -2900,7 +2902,7 @@ void buflist_list(exarg_T *eap)
buf == curbuf ? (int64_t)curwin->w_cursor.lnum : (int64_t)buflist_findlnum(buf));
}
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
line_breakcheck();
}
@@ -2985,7 +2987,7 @@ int setfname(buf_T *buf, char *ffname_arg, char *sfname_arg, bool message)
close_buffer(NULL, obuf, DOBUF_WIPE, false, false);
}
sfname = xstrdup(sfname);
-#ifdef USE_FNAME_CASE
+#ifdef CASE_INSENSITIVE_FILENAME
path_fix_case(sfname); // set correct case for short file name
#endif
if (buf->b_sfname != buf->b_ffname) {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index a68e841f3e..8cd1ffc979 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -206,7 +206,7 @@ typedef struct {
OptInt wo_winbl;
#define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
- LastSet wo_script_ctx[WV_COUNT]; // SCTXs for window-local options
+ LastSet wo_script_ctx[kWinOptCount]; // SCTXs for window-local options
#define w_p_script_ctx w_onebuf_opt.wo_script_ctx
} winopt_T;
@@ -512,7 +512,7 @@ struct file_buffer {
// or contents of the file being edited.
bool b_p_initialized; // set when options initialized
- LastSet b_p_script_ctx[BV_COUNT]; // SCTXs for buffer-local options
+ LastSet b_p_script_ctx[kBufOptCount]; // SCTXs for buffer-local options
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
@@ -543,9 +543,11 @@ struct file_buffer {
Callback b_cfu_cb; ///< 'completefunc' callback
char *b_p_ofu; ///< 'omnifunc'
Callback b_ofu_cb; ///< 'omnifunc' callback
- char *b_p_tfu; ///< 'tagfunc'
+ char *b_p_tfu; ///< 'tagfunc' option value
Callback b_tfu_cb; ///< 'tagfunc' callback
char *b_p_urf; ///< 'userregfunc'
+ char *b_p_ffu; ///< 'findfunc' option value
+ Callback b_ffu_cb; ///< 'findfunc' callback
int b_p_eof; ///< 'endoffile'
int b_p_eol; ///< 'endofline'
int b_p_fixeol; ///< 'fixendofline'
@@ -939,6 +941,7 @@ typedef struct {
FloatRelative relative;
bool external;
bool focusable;
+ bool mouse;
WinSplit split;
int zindex;
WinStyle style;
@@ -965,6 +968,7 @@ typedef struct {
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
.focusable = true, \
+ .mouse = true, \
.split = 0, \
.zindex = kZIndexFloatDefault, \
.style = kWinStyleUnused, \
@@ -1248,7 +1252,7 @@ struct window_S {
// transform a pointer to a "onebuf" option into a "allbuf" option
#define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T))
- // A few options have local flags for P_INSECURE.
+ // A few options have local flags for kOptFlagInsecure.
uint32_t w_p_stl_flags; // flags for 'statusline'
uint32_t w_p_wbr_flags; // flags for 'winbar'
uint32_t w_p_fde_flags; // flags for 'foldexpr'
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c
index fa0a55e7b6..5f830b4219 100644
--- a/src/nvim/bufwrite.c
+++ b/src/nvim/bufwrite.c
@@ -350,7 +350,7 @@ static int check_mtime(buf_T *buf, FileInfo *file_info)
msg_scroll = true; // Don't overwrite messages here.
msg_silent = 0; // Must give this prompt.
// Don't use emsg() here, don't want to flush the buffers.
- msg(_("WARNING: The file has been changed since reading it!!!"), HL_ATTR(HLF_E));
+ msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E);
if (ask_yesno(_("Do you really want to write to it"), true) == 'n') {
return FAIL;
}
@@ -1150,9 +1150,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
if (!filtering) {
// show that we are busy
#ifndef UNIX
- filemess(buf, sfname, "", 0);
+ filemess(buf, sfname, "");
#else
- filemess(buf, fname, "", 0);
+ filemess(buf, fname, "");
#endif
}
msg_scroll = false; // always overwrite the file message now
@@ -1881,11 +1881,9 @@ nofail:
retval = FAIL;
if (end == 0) {
- const int attr = HL_ATTR(HLF_E); // Set highlight for error messages.
- msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"),
- attr | MSG_HIST);
- msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
- attr | MSG_HIST);
+ const int hl_id = HLF_E; // Set highlight for error messages.
+ msg_puts_hl(_("\nWARNING: Original file may be lost or damaged\n"), hl_id, true);
+ msg_puts_hl(_("don't quit the editor until the file is successfully written!"), hl_id, true);
// Update the timestamp to avoid an "overwrite changed file"
// prompt when writing again.
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 51a13b80e7..f3a8e0b208 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -89,9 +89,9 @@ void change_warning(buf_T *buf, int col)
if (msg_row == Rows - 1) {
msg_col = col;
}
- msg_source(HL_ATTR(HLF_W));
+ msg_source(HLF_W);
msg_ext_set_kind("wmsg");
- msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
+ msg_puts_hl(_(w_readonly), HLF_W, true);
set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
msg_clr_eos();
msg_end();
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 430f6b15fe..1afd590b0e 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -88,13 +88,11 @@ int init_chartab(void)
/// an error, OK otherwise.
int buf_init_chartab(buf_T *buf, bool global)
{
- int c;
-
if (global) {
// Set the default size for printable characters:
// From <Space> to '~' is 1 (printable), others are 2 (not printable).
// This also inits all 'isident' and 'isfname' flags to false.
- c = 0;
+ int c = 0;
while (c < ' ') {
g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
@@ -124,9 +122,7 @@ int buf_init_chartab(buf_T *buf, bool global)
SET_CHARTAB(buf, '-');
}
- // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
- // options Each option is a list of characters, character numbers or
- // ranges, separated by commas, e.g.: "200-210,x,#-178,-"
+ // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' options.
for (int i = global ? 0 : 3; i <= 3; i++) {
const char *p;
if (i == 0) {
@@ -142,110 +138,130 @@ int buf_init_chartab(buf_T *buf, bool global)
// fourth round: 'iskeyword'
p = buf->b_p_isk;
}
+ if (parse_isopt(p, buf, false) == FAIL) {
+ return FAIL;
+ }
+ }
- while (*p) {
- bool tilde = false;
- bool do_isalpha = false;
+ chartab_initialized = true;
+ return OK;
+}
- if ((*p == '^') && (p[1] != NUL)) {
- tilde = true;
- p++;
- }
+/// Checks the format for the option settings 'iskeyword', 'isident', 'isfname'
+/// or 'isprint'.
+/// Returns FAIL if has an error, OK otherwise.
+int check_isopt(char *var)
+{
+ return parse_isopt(var, NULL, true);
+}
+
+/// @param only_check if false: refill g_chartab[]
+static int parse_isopt(const char *var, buf_T *buf, bool only_check)
+{
+ const char *p = var;
+
+ // Parses the 'isident', 'iskeyword', 'isfname' and 'isprint' options.
+ // Each option is a list of characters, character numbers or ranges,
+ // separated by commas, e.g.: "200-210,x,#-178,-"
+ while (*p) {
+ bool tilde = false;
+ bool do_isalpha = false;
+
+ if (*p == '^' && p[1] != NUL) {
+ tilde = true;
+ p++;
+ }
+
+ int c;
+ if (ascii_isdigit(*p)) {
+ c = getdigits_int((char **)&p, true, 0);
+ } else {
+ c = mb_ptr2char_adv(&p);
+ }
+ int c2 = -1;
+
+ if (*p == '-' && p[1] != NUL) {
+ p++;
if (ascii_isdigit(*p)) {
- c = getdigits_int((char **)&p, true, 0);
+ c2 = getdigits_int((char **)&p, true, 0);
} else {
- c = mb_ptr2char_adv(&p);
+ c2 = mb_ptr2char_adv(&p);
}
- int c2 = -1;
+ }
- if ((*p == '-') && (p[1] != NUL)) {
- p++;
+ if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256
+ || !(*p == NUL || *p == ',')) {
+ return FAIL;
+ }
- if (ascii_isdigit(*p)) {
- c2 = getdigits_int((char **)&p, true, 0);
- } else {
- c2 = mb_ptr2char_adv(&p);
- }
- }
+ bool trail_comma = *p == ',';
+ p = skip_to_option_part(p);
+ if (trail_comma && *p == NUL) {
+ // Trailing comma is not allowed.
+ return FAIL;
+ }
- if ((c <= 0)
- || (c >= 256)
- || ((c2 < c) && (c2 != -1))
- || (c2 >= 256)
- || !((*p == NUL) || (*p == ','))) {
- return FAIL;
- }
+ if (only_check) {
+ continue;
+ }
- if (c2 == -1) { // not a range
- // A single '@' (not "@-@"):
- // Decide on letters being ID/printable/keyword chars with
- // standard function isalpha(). This takes care of locale for
- // single-byte characters).
- if (c == '@') {
- do_isalpha = true;
- c = 1;
- c2 = 255;
- } else {
- c2 = c;
- }
+ if (c2 == -1) { // not a range
+ // A single '@' (not "@-@"):
+ // Decide on letters being ID/printable/keyword chars with
+ // standard function isalpha(). This takes care of locale for
+ // single-byte characters).
+ if (c == '@') {
+ do_isalpha = true;
+ c = 1;
+ c2 = 255;
+ } else {
+ c2 = c;
}
+ }
- while (c <= c2) {
- // Use the MB_ functions here, because isalpha() doesn't
- // work properly when 'encoding' is "latin1" and the locale is
- // "C".
- if (!do_isalpha
- || mb_islower(c)
- || mb_isupper(c)) {
- if (i == 0) {
- // (re)set ID flag
- if (tilde) {
- g_chartab[c] &= (uint8_t) ~CT_ID_CHAR;
- } else {
- g_chartab[c] |= CT_ID_CHAR;
- }
- } else if (i == 1) {
- // (re)set printable
- if (c < ' ' || c > '~') {
- if (tilde) {
- g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK)
- + ((dy_flags & DY_UHEX) ? 4 : 2));
- g_chartab[c] &= (uint8_t) ~CT_PRINT_CHAR;
- } else {
- g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1);
- g_chartab[c] |= CT_PRINT_CHAR;
- }
- }
- } else if (i == 2) {
- // (re)set fname flag
- if (tilde) {
- g_chartab[c] &= (uint8_t) ~CT_FNAME_CHAR;
- } else {
- g_chartab[c] |= CT_FNAME_CHAR;
- }
- } else { // i == 3
- // (re)set keyword flag
+ while (c <= c2) {
+ // Use the MB_ functions here, because isalpha() doesn't
+ // work properly when 'encoding' is "latin1" and the locale is
+ // "C".
+ if (!do_isalpha
+ || mb_islower(c)
+ || mb_isupper(c)) {
+ if (var == p_isi) { // (re)set ID flag
+ if (tilde) {
+ g_chartab[c] &= (uint8_t) ~CT_ID_CHAR;
+ } else {
+ g_chartab[c] |= CT_ID_CHAR;
+ }
+ } else if (var == p_isp) { // (re)set printable
+ if (c < ' ' || c > '~') {
if (tilde) {
- RESET_CHARTAB(buf, c);
+ g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK)
+ + ((dy_flags & DY_UHEX) ? 4 : 2));
+ g_chartab[c] &= (uint8_t) ~CT_PRINT_CHAR;
} else {
- SET_CHARTAB(buf, c);
+ g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1);
+ g_chartab[c] |= CT_PRINT_CHAR;
}
}
+ } else if (var == p_isf) { // (re)set fname flag
+ if (tilde) {
+ g_chartab[c] &= (uint8_t) ~CT_FNAME_CHAR;
+ } else {
+ g_chartab[c] |= CT_FNAME_CHAR;
+ }
+ } else { // (var == p_isk || var == buf->b_p_isk) (re)set keyword flag
+ if (tilde) {
+ RESET_CHARTAB(buf, c);
+ } else {
+ SET_CHARTAB(buf, c);
+ }
}
- c++;
- }
-
- c = (uint8_t)(*p);
- p = skip_to_option_part(p);
-
- if ((c == ',') && (*p == NUL)) {
- // Trailing comma is not allowed.
- return FAIL;
}
+ c++;
}
}
- chartab_initialized = true;
+
return OK;
}
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 402a891099..700d554821 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
+ && xp->xp_context != EXPAND_FINDFUNC
&& xp->xp_context != EXPAND_HELP
&& xp->xp_context != EXPAND_KEYMAP
&& xp->xp_context != EXPAND_LUA
@@ -119,6 +120,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_PACKADD
&& xp->xp_context != EXPAND_RUNTIME
&& xp->xp_context != EXPAND_SHELLCMD
+ && xp->xp_context != EXPAND_SHELLCMDLINE
&& xp->xp_context != EXPAND_TAGS
&& xp->xp_context != EXPAND_TAGS_LISTFILES
&& xp->xp_context != EXPAND_USER_LIST
@@ -356,7 +358,8 @@ static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches,
.pum_info = NULL,
.pum_extra = NULL,
.pum_kind = NULL,
- .pum_user_hlattr = -1,
+ .pum_user_abbr_hlattr = -1,
+ .pum_user_kind_hlattr = -1,
};
}
@@ -976,20 +979,19 @@ void ExpandCleanup(expand_T *xp)
/// @param linenr line number of matches to display
/// @param maxlen maximum number of characters in each line
/// @param showtail display only the tail of the full path of a file name
-/// @param dir_attr highlight attribute to use for directory names
static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, int lines, int linenr,
- int maxlen, bool showtail, int dir_attr)
+ int maxlen, bool showtail)
{
char *p;
int lastlen = 999;
for (int j = linenr; j < numMatches; j += lines) {
if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
- msg_outtrans(matches[j], HL_ATTR(HLF_D));
+ msg_outtrans(matches[j], HLF_D, false);
p = matches[j] + strlen(matches[j]) + 1;
msg_advance(maxlen + 1);
msg_puts(p);
msg_advance(maxlen + 3);
- msg_outtrans_long(p + 2, HL_ATTR(HLF_D));
+ msg_outtrans_long(p + 2, HLF_D);
break;
}
for (int i = maxlen - lastlen; --i >= 0;) {
@@ -1026,7 +1028,7 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in
isdir = false;
p = SHOW_MATCH(j);
}
- lastlen = msg_outtrans(p, isdir ? dir_attr : 0);
+ lastlen = msg_outtrans(p, isdir ? HLF_D : 0, false);
}
if (msg_col > 0) { // when not wrapped around
msg_clr_eos();
@@ -1116,18 +1118,16 @@ int showmatches(expand_T *xp, bool wildmenu)
lines = (numMatches + columns - 1) / columns;
}
- int attr = HL_ATTR(HLF_D); // find out highlighting for directories
-
if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
- msg_puts_attr(_("tagname"), HL_ATTR(HLF_T));
+ msg_puts_hl(_("tagname"), HLF_T, false);
msg_clr_eos();
msg_advance(maxlen - 3);
- msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T));
+ msg_puts_hl(_(" kind file\n"), HLF_T, false);
}
// list the files line by line
for (int i = 0; i < lines; i++) {
- showmatches_oneline(xp, matches, numMatches, lines, i, maxlen, showtail, attr);
+ showmatches_oneline(xp, matches, numMatches, lines, i, maxlen, showtail);
if (got_int) {
got_int = false;
break;
@@ -1226,7 +1226,8 @@ char *addstar(char *fname, size_t len, int context)
// For help tags the translation is done in find_help_tags().
// For a tag pattern starting with "/" no translation is needed.
- if (context == EXPAND_HELP
+ if (context == EXPAND_FINDFUNC
+ || context == EXPAND_HELP
|| context == EXPAND_COLORS
|| context == EXPAND_COMPILER
|| context == EXPAND_OWNSYNTAX
@@ -1348,7 +1349,7 @@ char *addstar(char *fname, size_t len, int context)
/// it.
/// EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
/// EXPAND_FILES After command with EX_XFILE set, or after setting
-/// with P_EXPAND set. eg :e ^I, :w>>^I
+/// with kOptFlagExpand set. eg :e ^I, :w>>^I
/// EXPAND_DIRECTORIES In some cases this is used instead of the latter
/// when we know only directories are of interest.
/// E.g. :set dir=^I and :cd ^I
@@ -1527,7 +1528,9 @@ static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool use
xp->xp_context = EXPAND_FILES;
// For a shell command more chars need to be escaped.
- if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal) {
+ if (usefilter
+ || (eap != NULL && (eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal))
+ || *complp == EXPAND_SHELLCMDLINE) {
#ifndef BACKSLASH_IN_FILENAME
xp->xp_shell = true;
#endif
@@ -1823,7 +1826,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
case CMD_sfind:
case CMD_tabfind:
if (xp->xp_context == EXPAND_FILES) {
- xp->xp_context = EXPAND_FILES_IN_PATH;
+ xp->xp_context = *get_findfunc() != NUL ? EXPAND_FINDFUNC : EXPAND_FILES_IN_PATH;
}
break;
case CMD_cd:
@@ -2493,21 +2496,25 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int *
}
}
- if (xp->xp_context == EXPAND_FILES) {
- flags |= EW_FILE;
- } else if (xp->xp_context == EXPAND_FILES_IN_PATH) {
- flags |= (EW_FILE | EW_PATH);
- } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
- flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
+ int ret = FAIL;
+ if (xp->xp_context == EXPAND_FINDFUNC) {
+ ret = expand_findfunc(pat, matches, numMatches);
} else {
- flags = (flags | EW_DIR) & ~EW_FILE;
- }
- if (options & WILD_ICASE) {
- flags |= EW_ICASE;
+ if (xp->xp_context == EXPAND_FILES) {
+ flags |= EW_FILE;
+ } else if (xp->xp_context == EXPAND_FILES_IN_PATH) {
+ flags |= (EW_FILE | EW_PATH);
+ } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
+ flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
+ } else {
+ flags = (flags | EW_DIR) & ~EW_FILE;
+ }
+ if (options & WILD_ICASE) {
+ flags |= EW_ICASE;
+ }
+ // Expand wildcards, supporting %:h and the like.
+ ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
}
-
- // Expand wildcards, supporting %:h and the like.
- int ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
if (free_pat) {
xfree(pat);
}
@@ -2712,6 +2719,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_FINDFUNC
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options);
}
@@ -3601,6 +3609,11 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
set_context_in_runtime_cmd(&xpc, xpc.xp_pattern);
xpc.xp_pattern_len = strlen(xpc.xp_pattern);
}
+ if (xpc.xp_context == EXPAND_SHELLCMDLINE) {
+ int context = EXPAND_SHELLCMDLINE;
+ set_context_for_wildcard_arg(NULL, xpc.xp_pattern, false, &xpc, &context);
+ xpc.xp_pattern_len = strlen(xpc.xp_pattern);
+ }
theend:
if (xpc.xp_context == EXPAND_LUA) {
diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h
index 3369790151..dfda9fdaed 100644
--- a/src/nvim/cmdexpand_defs.h
+++ b/src/nvim/cmdexpand_defs.h
@@ -106,6 +106,8 @@ enum {
EXPAND_ARGOPT,
EXPAND_KEYMAP,
EXPAND_DIRS_IN_CDPATH,
+ EXPAND_SHELLCMDLINE,
+ EXPAND_FINDFUNC,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index 47a4ffba9e..5993eefd67 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -221,7 +221,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep)
// well.
char *p = history[type][i].hisstr;
if (strcmp(str, p) == 0
- && (type != HIST_SEARCH || sep == p[strlen(p) + 1])) {
+ && (type != HIST_SEARCH || sep == p[history[type][i].hisstrlen + 1])) {
if (!move_to_front) {
return true;
}
@@ -239,6 +239,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep)
AdditionalData *ad = history[type][i].additional_data;
char *const save_hisstr = history[type][i].hisstr;
+ const size_t save_hisstrlen = history[type][i].hisstrlen;
while (i != hisidx[type]) {
if (++i >= hislen) {
i = 0;
@@ -249,6 +250,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep)
xfree(ad);
history[type][i].hisnum = ++hisnum[type];
history[type][i].hisstr = save_hisstr;
+ history[type][i].hisstrlen = save_hisstrlen;
history[type][i].timestamp = os_time();
history[type][i].additional_data = NULL;
return true;
@@ -339,6 +341,7 @@ void add_to_history(int histype, const char *new_entry, size_t new_entrylen, boo
hisptr->timestamp = os_time();
hisptr->additional_data = NULL;
hisptr->hisstr[new_entrylen + 1] = (char)sep;
+ hisptr->hisstrlen = new_entrylen;
hisptr->hisnum = ++hisnum[histype];
if (histype == HIST_SEARCH && in_map) {
@@ -400,19 +403,6 @@ static int calc_hist_idx(int histype, int num)
return -1;
}
-/// Get a history entry by its index.
-///
-/// @param histype may be one of the HIST_ values.
-static char *get_history_entry(int histype, int idx)
-{
- idx = calc_hist_idx(histype, idx);
- if (idx >= 0) {
- return history[histype][idx].hisstr;
- } else {
- return "";
- }
-}
-
/// Clear all entries in a history
///
/// @param[in] histype One of the HIST_ values.
@@ -575,10 +565,15 @@ void f_histget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (argvars[1].v_type == VAR_UNKNOWN) {
idx = get_history_idx(type);
} else {
- idx = (int)tv_get_number_chk(&argvars[1], NULL);
+ idx = (int)tv_get_number_chk(&argvars[1], NULL); // -1 on type error
+ }
+ idx = calc_hist_idx(type, idx);
+ if (idx < 0) {
+ rettv->vval.v_string = xstrnsave("", 0);
+ } else {
+ rettv->vval.v_string = xstrnsave(history[type][idx].hisstr,
+ history[type][idx].hisstrlen);
}
- // -1 on type error
- rettv->vval.v_string = xstrdup(get_history_entry(type, idx));
}
rettv->v_type = VAR_STRING;
}
@@ -591,9 +586,10 @@ void f_histnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
? HIST_INVALID
: get_histtype(histname, strlen(histname), false);
if (i != HIST_INVALID) {
- i = get_history_idx(i);
+ rettv->vval.v_number = get_history_idx(i);
+ } else {
+ rettv->vval.v_number = HIST_INVALID;
}
- rettv->vval.v_number = i;
}
/// :history command - print a history
@@ -642,10 +638,8 @@ void ex_history(exarg_T *eap)
}
for (; !got_int && histype1 <= histype2; histype1++) {
- xstrlcpy(IObuff, "\n # ", IOSIZE);
assert(history_names[histype1] != NULL);
- xstrlcat(IObuff, history_names[histype1], IOSIZE);
- xstrlcat(IObuff, " history", IOSIZE);
+ vim_snprintf(IObuff, IOSIZE, "\n # %s history", history_names[histype1]);
msg_puts_title(IObuff);
int idx = hisidx[histype1];
histentry_T *hist = history[histype1];
@@ -666,15 +660,14 @@ void ex_history(exarg_T *eap)
&& hist[i].hisnum >= j && hist[i].hisnum <= k
&& !message_filtered(hist[i].hisstr)) {
msg_putchar('\n');
- snprintf(IObuff, IOSIZE, "%c%6d ", i == idx ? '>' : ' ',
- hist[i].hisnum);
+ int len = snprintf(IObuff, IOSIZE,
+ "%c%6d ", i == idx ? '>' : ' ', hist[i].hisnum);
if (vim_strsize(hist[i].hisstr) > Columns - 10) {
- trunc_string(hist[i].hisstr, IObuff + strlen(IObuff),
- Columns - 10, IOSIZE - (int)strlen(IObuff));
+ trunc_string(hist[i].hisstr, IObuff + len, Columns - 10, IOSIZE - len);
} else {
- xstrlcat(IObuff, hist[i].hisstr, IOSIZE);
+ xstrlcpy(IObuff + len, hist[i].hisstr, (size_t)(IOSIZE - len));
}
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
}
if (i == idx) {
break;
diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h
index 4df4b09e68..c933982593 100644
--- a/src/nvim/cmdhist.h
+++ b/src/nvim/cmdhist.h
@@ -23,6 +23,7 @@ enum { HIST_COUNT = HIST_DEBUG + 1, }; ///< Number of history tables
typedef struct {
int hisnum; ///< Entry identifier number.
char *hisstr; ///< Actual entry, separator char after the NUL.
+ size_t hisstrlen; ///< Length of hisstr (excluding the NUL).
Timestamp timestamp; ///< Time when entry was added.
AdditionalData *additional_data; ///< Additional entries from ShaDa file.
} histentry_T;
diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h
index 49dc4f9168..58ba93a7ba 100644
--- a/src/nvim/decoration_defs.h
+++ b/src/nvim/decoration_defs.h
@@ -55,7 +55,7 @@ typedef struct {
schar_T conceal_char;
} DecorHighlightInline;
-#define DECOR_HIGHLIGHT_INLINE_INIT { 0, DECOR_PRIORITY_BASE, 0, 0 }
+#define DECOR_HIGHLIGHT_INLINE_INIT { 0, DECOR_PRIORITY_BASE, 0, 0 }
typedef struct {
uint16_t flags;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index d22fb65827..f1dd08f0e6 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -801,7 +801,7 @@ static int diff_write(buf_T *buf, diffin_T *din)
// Always use 'fileformat' set to "unix".
char *save_ff = buf->b_p_ff;
- buf->b_p_ff = xstrdup(FF_UNIX);
+ buf->b_p_ff = xstrdup("unix");
const bool save_cmod_flags = cmdmod.cmod_flags;
// Writing the buffer is an implementation detail of performing the diff,
// so it shouldn't update the '[ and '] marks.
@@ -1390,8 +1390,8 @@ void diff_win_options(win_T *wp, bool addbuf)
}
wp->w_p_fdm_save = xstrdup(wp->w_p_fdm);
}
- set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, kOptReqWin,
- wp);
+ set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0,
+ kOptScopeWin, wp);
if (!wp->w_p_diff) {
wp->w_p_fen_save = wp->w_p_fen;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 7413d33fe4..ea0d1ba708 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1707,7 +1707,7 @@ static void digraph_header(const char *msg)
if (msg_col > 0) {
msg_putchar('\n');
}
- msg_outtrans(msg, HL_ATTR(HLF_CM));
+ msg_outtrans(msg, HLF_CM, false);
msg_putchar('\n');
}
@@ -1861,7 +1861,7 @@ static void printdigraph(const digr_T *dp, result_T *previous)
*p++ = (char)dp->char2;
*p++ = ' ';
*p = NUL;
- msg_outtrans(buf, 0);
+ msg_outtrans(buf, 0, false);
p = buf;
// add a space to draw a composing char on
@@ -1871,14 +1871,14 @@ static void printdigraph(const digr_T *dp, result_T *previous)
p += utf_char2bytes(dp->result, p);
*p = NUL;
- msg_outtrans(buf, HL_ATTR(HLF_8));
+ msg_outtrans(buf, HLF_8, false);
p = buf;
if (char2cells(dp->result) == 1) {
*p++ = ' ';
}
assert(p >= buf);
vim_snprintf(p, sizeof(buf) - (size_t)(p - buf), " %3d", dp->result);
- msg_outtrans(buf, 0);
+ msg_outtrans(buf, 0, false);
}
/// Get the two digraph characters from a typval.
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 3b88dd2e90..79f3298eb4 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -927,7 +927,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
bool noinvcur = false; // don't invert the cursor
bool lnum_in_visual_area = false;
- bool attr_pri = false; // char_attr has priority
+ int char_attr_pri = 0; // attributes with high priority
+ int char_attr_base = 0; // attributes with low priority
bool area_highlighting = false; // Visual or incsearch highlighting in this line
int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by highlighting
@@ -1741,16 +1742,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
// Decide which of the highlight attributes to use.
- attr_pri = true;
-
if (area_attr != 0) {
- wlv.char_attr = hl_combine_attr(wlv.line_attr, area_attr);
+ char_attr_pri = hl_combine_attr(wlv.line_attr, area_attr);
if (!highlight_match) {
// let search highlight show in Visual area if possible
- wlv.char_attr = hl_combine_attr(search_attr, wlv.char_attr);
+ char_attr_pri = hl_combine_attr(search_attr, char_attr_pri);
}
} else if (search_attr != 0) {
- wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr);
+ char_attr_pri = hl_combine_attr(wlv.line_attr, search_attr);
} else if (wlv.line_attr != 0
&& ((wlv.fromcol == -10 && wlv.tocol == MAXCOL)
|| wlv.vcol < wlv.fromcol
@@ -1758,15 +1757,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|| wlv.vcol >= wlv.tocol)) {
// Use wlv.line_attr when not in the Visual or 'incsearch' area
// (area_attr may be 0 when "noinvcur" is set).
- wlv.char_attr = wlv.line_attr;
+ char_attr_pri = wlv.line_attr;
} else {
- attr_pri = false;
- wlv.char_attr = decor_attr;
- }
-
- if (folded_attr != 0) {
- wlv.char_attr = hl_combine_attr(folded_attr, wlv.char_attr);
+ char_attr_pri = 0;
}
+ char_attr_base = hl_combine_attr(folded_attr, decor_attr);
+ wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
@@ -1997,25 +1993,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell);
}
- if (folded_attr) {
- decor_attr = hl_combine_attr(folded_attr, decor_attr);
- }
-
- if (decor_attr) {
- if (!attr_pri) {
- if (wlv.cul_attr) {
- wlv.char_attr = 0 != wlv.line_attr_lowprio
- ? hl_combine_attr(wlv.cul_attr, decor_attr)
- : hl_combine_attr(decor_attr, wlv.cul_attr);
- } else {
- wlv.char_attr = decor_attr;
- }
- } else {
- wlv.char_attr = hl_combine_attr(decor_attr, wlv.char_attr);
- }
- } else if (!attr_pri) {
- wlv.char_attr = 0;
- }
+ char_attr_base = hl_combine_attr(folded_attr, decor_attr);
+ wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
// Check spelling (unless at the end of the line).
// Only do this when there is no syntax highlighting, the
@@ -2083,11 +2062,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
}
if (spell_attr != 0) {
- if (!attr_pri) {
- wlv.char_attr = hl_combine_attr(wlv.char_attr, spell_attr);
- } else {
- wlv.char_attr = hl_combine_attr(spell_attr, wlv.char_attr);
- }
+ char_attr_base = hl_combine_attr(char_attr_base, spell_attr);
+ wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
if (wp->w_buffer->terminal) {
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index aa5c66465b..e90a0d945f 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -952,7 +952,7 @@ int showmode(void)
// Position on the last line in the window, column 0
msg_pos_mode();
- int attr = HL_ATTR(HLF_CM); // Highlight mode
+ int hl_id = HLF_CM; // Highlight mode
// When the screen is too narrow to show the entire mode message,
// avoid scrolling and truncate instead.
@@ -961,7 +961,7 @@ int showmode(void)
lines_left = 0;
if (do_mode) {
- msg_puts_attr("--", attr);
+ msg_puts_hl("--", hl_id, false);
// CTRL-X in Insert mode
if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU)) {
// These messages can get long, avoid a wrap in a narrow window.
@@ -981,52 +981,49 @@ int showmode(void)
}
if (length - vim_strsize(edit_submode) > 0) {
if (edit_submode_pre != NULL) {
- msg_puts_attr(edit_submode_pre, attr);
+ msg_puts_hl(edit_submode_pre, hl_id, false);
}
- msg_puts_attr(edit_submode, attr);
+ msg_puts_hl(edit_submode, hl_id, false);
}
if (edit_submode_extra != NULL) {
- msg_puts_attr(" ", attr); // Add a space in between.
- int sub_attr = edit_submode_highl < HLF_COUNT
- ? win_hl_attr(curwin, (int)edit_submode_highl)
- : attr;
- msg_puts_attr(edit_submode_extra, sub_attr);
+ msg_puts_hl(" ", hl_id, false); // Add a space in between.
+ int sub_id = edit_submode_highl < HLF_COUNT ? (int)edit_submode_highl : hl_id;
+ msg_puts_hl(edit_submode_extra, sub_id, false);
}
}
} else {
if (State & MODE_TERMINAL) {
- msg_puts_attr(_(" TERMINAL"), attr);
+ msg_puts_hl(_(" TERMINAL"), hl_id, false);
} else if (State & VREPLACE_FLAG) {
- msg_puts_attr(_(" VREPLACE"), attr);
+ msg_puts_hl(_(" VREPLACE"), hl_id, false);
} else if (State & REPLACE_FLAG) {
- msg_puts_attr(_(" REPLACE"), attr);
+ msg_puts_hl(_(" REPLACE"), hl_id, false);
} else if (State & MODE_INSERT) {
if (p_ri) {
- msg_puts_attr(_(" REVERSE"), attr);
+ msg_puts_hl(_(" REVERSE"), hl_id, false);
}
- msg_puts_attr(_(" INSERT"), attr);
+ msg_puts_hl(_(" INSERT"), hl_id, false);
} else if (restart_edit == 'I' || restart_edit == 'i'
|| restart_edit == 'a' || restart_edit == 'A') {
if (curbuf->terminal) {
- msg_puts_attr(_(" (terminal)"), attr);
+ msg_puts_hl(_(" (terminal)"), hl_id, false);
} else {
- msg_puts_attr(_(" (insert)"), attr);
+ msg_puts_hl(_(" (insert)"), hl_id, false);
}
} else if (restart_edit == 'R') {
- msg_puts_attr(_(" (replace)"), attr);
+ msg_puts_hl(_(" (replace)"), hl_id, false);
} else if (restart_edit == 'V') {
- msg_puts_attr(_(" (vreplace)"), attr);
+ msg_puts_hl(_(" (vreplace)"), hl_id, false);
}
if (State & MODE_LANGMAP) {
if (curwin->w_p_arab) {
- msg_puts_attr(_(" Arabic"), attr);
- } else if (get_keymap_str(curwin, " (%s)",
- NameBuff, MAXPATHL)) {
- msg_puts_attr(NameBuff, attr);
+ msg_puts_hl(_(" Arabic"), hl_id, false);
+ } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL)) {
+ msg_puts_hl(NameBuff, hl_id, false);
}
}
if ((State & MODE_INSERT) && p_paste) {
- msg_puts_attr(_(" (paste)"), attr);
+ msg_puts_hl(_(" (paste)"), hl_id, false);
}
if (VIsual_active) {
@@ -1050,9 +1047,9 @@ int showmode(void)
default:
p = N_(" SELECT BLOCK"); break;
}
- msg_puts_attr(_(p), attr);
+ msg_puts_hl(_(p), hl_id, false);
}
- msg_puts_attr(" --", attr);
+ msg_puts_hl(" --", hl_id, false);
}
need_clear = true;
@@ -1060,7 +1057,7 @@ int showmode(void)
if (reg_recording != 0
&& edit_submode == NULL // otherwise it gets too long
) {
- recording_mode(attr);
+ recording_mode(hl_id);
need_clear = true;
}
@@ -1136,7 +1133,7 @@ void clearmode(void)
msg_ext_ui_flush();
msg_pos_mode();
if (reg_recording != 0) {
- recording_mode(HL_ATTR(HLF_CM));
+ recording_mode(HLF_CM);
}
msg_clr_eos();
msg_ext_flush_showmode();
@@ -1145,16 +1142,16 @@ void clearmode(void)
msg_row = save_msg_row;
}
-static void recording_mode(int attr)
+static void recording_mode(int hl_id)
{
if (shortmess(SHM_RECORDING)) {
return;
}
- msg_puts_attr(_("recording"), attr);
+ msg_puts_hl(_("recording"), hl_id, false);
char s[4];
snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording);
- msg_puts_attr(s, attr);
+ msg_puts_hl(s, hl_id, false);
}
#define COL_RULER 17 // columns needed by standard ruler
diff --git a/src/nvim/errors.h b/src/nvim/errors.h
index 39095db952..df94945a3d 100644
--- a/src/nvim/errors.h
+++ b/src/nvim/errors.h
@@ -151,11 +151,16 @@ EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to ab
EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
-EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
+EXTERN const char e_fast_api_disabled[] INIT(= N_("E5560: %s must not be called in a fast event context"));
EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
+EXTERN const char e_cant_find_directory_str_in_cdpath[] INIT(= N_("E344: Can't find directory \"%s\" in cdpath"));
+EXTERN const char e_cant_find_file_str_in_path[] INIT(= N_("E345: Can't find file \"%s\" in path"));
+EXTERN const char e_no_more_directory_str_found_in_cdpath[] INIT(= N_("E346: No more directory \"%s\" found in cdpath"));
+EXTERN const char e_no_more_file_str_found_in_path[] INIT(= N_("E347: No more file \"%s\" found in path"));
+
EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
@@ -181,6 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")
EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
+EXTERN const char e_invalid_return_type_from_findfunc[] INIT( = N_("E1514: 'findfunc' did not return a List type"));
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 8682139b32..faacf3c65a 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -126,7 +126,7 @@ bool *eval_lavars_used = NULL;
#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars)
#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
-static int echo_attr = 0; // attributes used for ":echo"
+static int echo_hl_id = 0; // highlight id used for ":echo"
/// Info used by a ":for" loop.
typedef struct {
@@ -460,6 +460,8 @@ void eval_init(void)
set_vim_var_nr(VV_SEARCHFORWARD, 1);
set_vim_var_nr(VV_HLSEARCH, 1);
set_vim_var_nr(VV_COUNT1, 1);
+ set_vim_var_special(VV_EXITING, kSpecialVarNull);
+
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
@@ -475,7 +477,6 @@ void eval_init(void)
set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
- set_vim_var_special(VV_EXITING, kSpecialVarNull);
set_vim_var_nr(VV_MAXCOL, MAXCOL);
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
@@ -921,13 +922,12 @@ int eval_expr_typval(const typval_T *expr, bool want_func, typval_T *argv, int a
{
if (expr->v_type == VAR_PARTIAL) {
return eval_expr_partial(expr, argv, argc, rettv);
- } else if (expr->v_type == VAR_FUNC || want_func) {
+ }
+ if (expr->v_type == VAR_FUNC || want_func) {
return eval_expr_func(expr, argv, argc, rettv);
- } else {
- return eval_expr_string(expr, rettv);
}
- return OK;
+ return eval_expr_string(expr, rettv);
}
/// Like eval_to_bool() but using a typval_T instead of a string.
@@ -1047,7 +1047,7 @@ char *eval_to_string_eap(char *arg, const bool join_list, exarg_T *eap,
retval = typval2string(&tv, join_list);
tv_clear(&tv);
}
- clear_evalarg(&EVALARG_EVALUATE, NULL);
+ clear_evalarg(&evalarg, NULL);
return retval;
}
@@ -1367,7 +1367,7 @@ int eval_foldexpr(win_T *wp, int *cp)
const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
char *arg = skipwhite(wp->w_p_fde);
- current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx;
+ current_sctx = wp->w_p_script_ctx[kWinOptFoldexpr].script_ctx;
emsg_off++;
if (use_sandbox) {
@@ -1981,7 +1981,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, bool copy, const bool
// handle +=, -=, *=, /=, %= and .=
di = NULL;
- if (eval_variable(lp->ll_name, (int)strlen(lp->ll_name),
+ if (eval_variable(lp->ll_name, (int)lp->ll_name_len,
&tv, &di, true, false) == OK) {
if ((di == NULL
|| (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING)
@@ -2631,7 +2631,7 @@ static int may_call_simple_func(const char *arg, typval_T *rettv)
/// Handle zero level expression with optimization for a simple function call.
/// Same arguments and return value as eval0().
-static int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
+int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
{
int r = may_call_simple_func(arg, rettv);
@@ -4788,6 +4788,7 @@ bool garbage_collect(bool testing)
ABORTING(set_ref_in_callback)(&buf->b_ofu_cb, copyID, NULL, NULL);
ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL);
ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL);
+ ABORTING(set_ref_in_callback)(&buf->b_ffu_cb, copyID, NULL, NULL);
}
// 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks
@@ -4799,6 +4800,9 @@ bool garbage_collect(bool testing)
// 'tagfunc' callback
ABORTING(set_ref_in_tagfunc)(copyID);
+ // 'findfunc' callback
+ ABORTING(set_ref_in_findfunc)(copyID);
+
FOR_ALL_TAB_WINDOWS(tp, wp) {
// window-local variables
ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL);
@@ -6850,11 +6854,11 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex
char *temp_result = eval_to_string(expr_start + 1, false, false);
if (temp_result != NULL) {
- retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start)
- + (size_t)(in_end - expr_end) + 1);
- STRCPY(retval, in_start);
- strcat(retval, temp_result);
- strcat(retval, expr_end + 1);
+ size_t retvalsize = (size_t)(expr_start - in_start)
+ + strlen(temp_result)
+ + (size_t)(in_end - expr_end) + 1;
+ retval = xmalloc(retvalsize);
+ vim_snprintf(retval, retvalsize, "%s%s%s", in_start, temp_result, expr_end + 1);
}
xfree(temp_result);
@@ -7869,12 +7873,12 @@ void ex_echo(exarg_T *eap)
msg_start();
}
} else if (eap->cmdidx == CMD_echo) {
- msg_puts_attr(" ", echo_attr);
+ msg_puts_hl(" ", echo_hl_id, false);
}
char *tofree = encode_tv2echo(&rettv, NULL);
if (*tofree != NUL) {
msg_ext_set_kind("echo");
- msg_multiline(tofree, echo_attr, true, &need_clear);
+ msg_multiline(cstr_as_string(tofree), echo_hl_id, true, false, &need_clear);
}
xfree(tofree);
}
@@ -7900,13 +7904,13 @@ void ex_echo(exarg_T *eap)
/// ":echohl {name}".
void ex_echohl(exarg_T *eap)
{
- echo_attr = syn_name2attr(eap->arg);
+ echo_hl_id = syn_name2id(eap->arg);
}
-/// Returns the :echo attribute
-int get_echo_attr(void)
+/// Returns the :echo highlight id
+int get_echo_hl_id(void)
{
- return echo_attr;
+ return echo_hl_id;
}
/// ":execute expr1 ..." execute the result of an expression.
@@ -7957,7 +7961,7 @@ void ex_execute(exarg_T *eap)
if (ret != FAIL && ga.ga_data != NULL) {
if (eap->cmdidx == CMD_echomsg) {
msg_ext_set_kind("echomsg");
- msg(ga.ga_data, echo_attr);
+ msg(ga.ga_data, echo_hl_id);
} else if (eap->cmdidx == CMD_echoerr) {
// We don't want to abort following commands, restore did_emsg.
int save_did_emsg = did_emsg;
@@ -8343,9 +8347,10 @@ repeat:
char *const sub = xmemdupz(s, (size_t)(p - s));
char *const str = xmemdupz(*fnamep, *fnamelen);
*usedlen = (size_t)(p + 1 - src);
- s = do_string_sub(str, pat, sub, NULL, flags);
+ size_t slen;
+ s = do_string_sub(str, *fnamelen, pat, sub, NULL, flags, &slen);
*fnamep = s;
- *fnamelen = strlen(s);
+ *fnamelen = slen;
xfree(*bufp);
*bufp = s;
didit = true;
@@ -8384,12 +8389,14 @@ repeat:
/// When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
/// "flags" can be "g" to do a global substitute.
///
+/// @param ret_len length of returned buffer
+///
/// @return an allocated string, NULL for error.
-char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char *flags)
+char *do_string_sub(char *str, size_t len, char *pat, char *sub, typval_T *expr, const char *flags,
+ size_t *ret_len)
{
regmatch_T regmatch;
garray_T ga;
- char *zero_width = NULL;
// Make 'cpoptions' empty, so that the 'l' flag doesn't work here
char *save_cpo = p_cpo;
@@ -8397,14 +8404,15 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
ga_init(&ga, 1, 200);
- int do_all = (flags[0] == 'g');
-
regmatch.rm_ic = p_ic;
regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
- int sublen;
char *tail = str;
- char *end = str + strlen(str);
+ char *end = str + len;
+ bool do_all = (flags[0] == 'g');
+ int sublen;
+ char *zero_width = NULL;
+
while (vim_regexec_nl(&regmatch, str, (colnr_T)(tail - str))) {
// Skip empty match except for first match.
if (regmatch.startp[0] == regmatch.endp[0]) {
@@ -8451,12 +8459,17 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
if (ga.ga_data != NULL) {
STRCPY((char *)ga.ga_data + ga.ga_len, tail);
+ ga.ga_len += (int)(end - tail);
}
vim_regfree(regmatch.regprog);
}
- char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data);
+ if (ga.ga_data != NULL) {
+ str = ga.ga_data;
+ len = (size_t)ga.ga_len;
+ }
+ char *ret = xstrnsave(str, len);
ga_clear(&ga);
if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
@@ -8470,6 +8483,10 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
free_string_option(save_cpo);
}
+ if (ret_len != NULL) {
+ *ret_len = len;
+ }
+
return ret;
}
@@ -8609,7 +8626,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast)
}
if (throw_if_fast && !nlua_is_deferred_safe()) {
- semsg(e_luv_api_disabled, "Vimscript function");
+ semsg(e_fast_api_disabled, "Vimscript function");
return false;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 50aaf9e03b..a418b34909 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -326,17 +326,17 @@ M.funcs = {
args = { 2, 3 },
base = 1,
desc = [=[
- When the files {fname-one} and {fname-two} do not contain
+ When the files {fname_one} and {fname_two} do not contain
exactly the same text an error message is added to |v:errors|.
Also see |assert-return|.
- When {fname-one} or {fname-two} does not exist the error will
+ When {fname_one} or {fname_two} does not exist the error will
mention that.
]=],
name = 'assert_equalfile',
- params = { { 'fname-one', 'string' }, { 'fname-two', 'string' } },
+ params = { { 'fname_one', 'string' }, { 'fname_two', 'string' } },
returns = '0|1',
- signature = 'assert_equalfile({fname-one}, {fname-two})',
+ signature = 'assert_equalfile({fname_one}, {fname_two})',
},
assert_exception = {
args = { 1, 2 },
@@ -1111,7 +1111,7 @@ M.funcs = {
The character class is one of:
0 blank
1 punctuation
- 2 word character
+ 2 word character (depends on 'iskeyword')
3 emoji
other specific Unicode class
The class is used in patterns and word motions.
@@ -1137,7 +1137,7 @@ M.funcs = {
]=],
name = 'charcol',
- params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } },
+ params = { { 'expr', 'string|any[]' }, { 'winid', 'integer' } },
returns = 'integer',
signature = 'charcol({expr} [, {winid}])',
},
@@ -1296,7 +1296,7 @@ M.funcs = {
]=],
name = 'col',
- params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } },
+ params = { { 'expr', 'string|any[]' }, { 'winid', 'integer' } },
returns = 'integer',
signature = 'col({expr} [, {winid}])',
},
@@ -2165,6 +2165,7 @@ M.funcs = {
If {expr} starts with "./" the |current-directory| is used.
]=],
+ fast = true,
name = 'exepath',
params = { { 'expr', 'string' } },
signature = 'exepath({expr})',
@@ -3611,6 +3612,20 @@ M.funcs = {
returns = 'string',
signature = 'getcharstr([{expr}])',
},
+ getcmdcomplpat = {
+ desc = [=[
+ Return completion pattern of the current command-line.
+ Only works when the command line is being edited, thus
+ requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
+ Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
+ |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|.
+ Returns an empty string when completion is not defined.
+ ]=],
+ name = 'getcmdcomplpat',
+ params = {},
+ returns = 'string',
+ signature = 'getcmdcomplpat()',
+ },
getcmdcompltype = {
desc = [=[
Return the type of the current command-line completion.
@@ -3618,7 +3633,7 @@ M.funcs = {
requires use of |c_CTRL-\_e| or |c_CTRL-R_=|.
See |:command-completion| for the return string.
Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|,
- |getcmdprompt()| and |setcmdline()|.
+ |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|.
Returns an empty string when completion is not defined.
]=],
name = 'getcmdcompltype',
@@ -3761,6 +3776,7 @@ M.funcs = {
runtime |:runtime| completion
scriptnames sourced script names |:scriptnames|
shellcmd Shell command
+ shellcmdline Shell command line with filename arguments
sign |:sign| suboptions
syntax syntax file names |'syntax'|
syntime |:syntime| suboptions
@@ -6391,7 +6407,7 @@ M.funcs = {
base = 1,
desc = [=[
{expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
- When {expr1} is a |List|| or |Dictionary|, replace each
+ When {expr1} is a |List| or |Dictionary|, replace each
item in {expr1} with the result of evaluating {expr2}.
For a |Blob| each byte is replaced.
For a |String|, each character, including composing
@@ -9525,7 +9541,7 @@ M.funcs = {
To clear the overrides pass an empty {list}: >vim
call setcellwidths([])
- <You can use the script $VIMRUNTIME/tools/emoji_list.lua to see
+ <You can use the script $VIMRUNTIME/scripts/emoji_list.lua to see
the effect for known emoji characters. Move the cursor
through the text to check if the cell widths of your terminal
match with what Vim knows about each emoji. If it doesn't
@@ -9881,6 +9897,8 @@ M.funcs = {
clear the list: >vim
call setqflist([], 'r')
<
+ 'u' Like 'r', but tries to preserve the current selection
+ in the quickfix list.
'f' All the quickfix lists in the quickfix stack are
freed.
@@ -9938,7 +9956,11 @@ M.funcs = {
]=],
name = 'setqflist',
- params = { { 'list', 'any[]' }, { 'action', 'string' }, { 'what', 'table' } },
+ params = {
+ { 'list', 'vim.quickfix.entry[]' },
+ { 'action', 'string' },
+ { 'what', 'vim.fn.setqflist.what' },
+ },
signature = 'setqflist({list} [, {action} [, {what}]])',
},
setreg = {
@@ -10994,6 +11016,44 @@ M.funcs = {
params = { { 'expr', 'number' } },
signature = 'srand([{expr}])',
},
+ state = {
+ args = { 0, 1 },
+ base = 1,
+ desc = [=[
+ Return a string which contains characters indicating the
+ current state. Mostly useful in callbacks that want to do
+ work that may not always be safe. Roughly this works like:
+ - callback uses state() to check if work is safe to do.
+ Yes: then do it right away.
+ No: add to work queue and add a |SafeState| autocommand.
+ - When SafeState is triggered and executes your autocommand,
+ check with `state()` if the work can be done now, and if yes
+ remove it from the queue and execute.
+ Remove the autocommand if the queue is now empty.
+ Also see |mode()|.
+
+ When {what} is given only characters in this string will be
+ added. E.g, this checks if the screen has scrolled: >vim
+ if state('s') == ''
+ " screen has not scrolled
+ <
+ These characters indicate the state, generally indicating that
+ something is busy:
+ m halfway a mapping, :normal command, feedkeys() or
+ stuffed command
+ o operator pending, e.g. after |d|
+ a Insert mode autocomplete active
+ x executing an autocommand
+ S not triggering SafeState, e.g. after |f| or a count
+ c callback invoked, including timer (repeats for
+ recursiveness up to "ccc")
+ s screen has scrolled for messages
+ ]=],
+ fast = true,
+ name = 'state',
+ params = { { 'what', 'string' } },
+ signature = 'state([{what}])',
+ },
stdioopen = {
args = 1,
desc = [=[
@@ -11052,44 +11112,6 @@ M.funcs = {
returns = 'string|string[]',
signature = 'stdpath({what})',
},
- state = {
- args = { 0, 1 },
- base = 1,
- desc = [=[
- Return a string which contains characters indicating the
- current state. Mostly useful in callbacks that want to do
- work that may not always be safe. Roughly this works like:
- - callback uses state() to check if work is safe to do.
- Yes: then do it right away.
- No: add to work queue and add a |SafeState| autocommand.
- - When SafeState is triggered and executes your autocommand,
- check with `state()` if the work can be done now, and if yes
- remove it from the queue and execute.
- Remove the autocommand if the queue is now empty.
- Also see |mode()|.
-
- When {what} is given only characters in this string will be
- added. E.g, this checks if the screen has scrolled: >vim
- if state('s') == ''
- " screen has not scrolled
- <
- These characters indicate the state, generally indicating that
- something is busy:
- m halfway a mapping, :normal command, feedkeys() or
- stuffed command
- o operator pending, e.g. after |d|
- a Insert mode autocomplete active
- x executing an autocommand
- S not triggering SafeState, e.g. after |f| or a count
- c callback invoked, including timer (repeats for
- recursiveness up to "ccc")
- s screen has scrolled for messages
- ]=],
- fast = true,
- name = 'state',
- params = { { 'what', 'string' } },
- signature = 'state([{what}])',
- },
str2float = {
args = 1,
base = 1,
@@ -12662,7 +12684,7 @@ M.funcs = {
]=],
name = 'virtcol',
- params = { { 'expr', 'string|integer[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } },
+ params = { { 'expr', 'string|any[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } },
signature = 'virtcol({expr} [, {list} [, {winid}]])',
},
virtcol2col = {
@@ -12751,7 +12773,7 @@ M.funcs = {
For example to make <c-j> work like <down> in wildmode, use: >vim
cnoremap <expr> <C-j> wildmenumode() ? "\<Down>\<Tab>" : "\<c-j>"
<
- (Note, this needs the 'wildcharm' option set appropriately).
+ (Note: this needs the 'wildcharm' option set appropriately).
]=],
name = 'wildmenumode',
params = {},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 6d1cb4b2c3..9e9e36d3c5 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1342,7 +1342,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
hlID = HLF_CHD; // Changed line.
}
}
- rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (hlID + 1);
+ rettv->vval.v_number = hlID;
}
/// "empty({expr})" function
@@ -4352,9 +4352,17 @@ static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (wp != NULL && tp != NULL) {
switchwin_T switchwin;
if (switch_win_noblock(&switchwin, wp, tp, true) == OK) {
+ // in diff mode, prevent that the window scrolls
+ // and keep the topline
+ if (curwin->w_p_diff && switchwin.sw_curwin->w_p_diff) {
+ skip_update_topline = true;
+ }
check_cursor(curwin);
fp = var2fpos(&argvars[0], true, &fnum, false);
}
+ if (curwin->w_p_diff && switchwin.sw_curwin->w_p_diff) {
+ skip_update_topline = false;
+ }
restore_win_noblock(&switchwin, true);
}
} else {
@@ -7841,8 +7849,8 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|| flg == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = do_string_sub((char *)str, (char *)pat,
- (char *)sub, expr, (char *)flg);
+ rettv->vval.v_string = do_string_sub((char *)str, strlen(str), (char *)pat,
+ (char *)sub, expr, (char *)flg, NULL);
}
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 0e0088bfad..a8358aab51 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -34,6 +34,7 @@
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/macros_defs.h"
+#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/ops.h"
@@ -1412,7 +1413,7 @@ static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t
msg_start();
msg_puts(prefix);
if (name != NULL) { // "a:" vars don't have a name stored
- msg_puts_len(name, name_len, 0);
+ msg_puts_len(name, name_len, 0, false);
}
msg_putchar(' ');
msg_advance(22);
@@ -1434,7 +1435,7 @@ static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t
msg_putchar(' ');
}
- msg_outtrans(string, 0);
+ msg_outtrans(string, 0, false);
if (type == VAR_FUNC || type == VAR_PARTIAL) {
msg_puts("()");
@@ -1913,7 +1914,7 @@ static OptVal tv_to_optval(typval_T *tv, OptIndex opt_idx, const char *option, b
const bool option_has_num = !is_tty_opt && option_has_type(opt_idx, kOptValTypeNumber);
const bool option_has_str = is_tty_opt || option_has_type(opt_idx, kOptValTypeString);
- if (!is_tty_opt && (get_option(opt_idx)->flags & P_FUNC) && tv_is_func(*tv)) {
+ if (!is_tty_opt && (get_option(opt_idx)->flags & kOptFlagFunc) && tv_is_func(*tv)) {
// If the option can be set to a function reference or a lambda
// and the passed value is a function reference, then convert it to
// the name (string) of the function reference.
@@ -1970,14 +1971,12 @@ typval_T optval_as_tv(OptVal value, bool numbool)
case kOptValTypeNil:
break;
case kOptValTypeBoolean:
- if (value.data.boolean != kNone) {
- if (numbool) {
- rettv.v_type = VAR_NUMBER;
- rettv.vval.v_number = value.data.boolean == kTrue;
- } else {
- rettv.v_type = VAR_BOOL;
- rettv.vval.v_bool = value.data.boolean == kTrue;
- }
+ if (numbool) {
+ rettv.v_type = VAR_NUMBER;
+ rettv.vval.v_number = value.data.boolean;
+ } else if (value.data.boolean != kNone) {
+ rettv.v_type = VAR_BOOL;
+ rettv.vval.v_bool = value.data.boolean == kTrue;
}
break; // return v:null for None boolean value.
case kOptValTypeNumber:
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a98de05815..8cccf08e11 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -189,7 +189,7 @@ void do_ascii(exarg_T *eap)
transchar(c), buf1, buf2, cval, cval, cval);
}
- msg_multiline(IObuff, 0, true, &need_clear);
+ msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data); // needed for overlong ascii?
}
@@ -224,7 +224,7 @@ void do_ascii(exarg_T *eap)
c, c, c);
}
- msg_multiline(IObuff, 0, true, &need_clear);
+ msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii?
}
@@ -1028,7 +1028,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
msg_start();
msg_putchar(':');
msg_putchar('!');
- msg_outtrans(newcmd, 0);
+ msg_outtrans(newcmd, 0, false);
msg_clr_eos();
ui_cursor_goto(msg_row, msg_col);
@@ -1469,7 +1469,7 @@ void print_line_no_prefix(linenr_T lnum, int use_number, bool list)
if (curwin->w_p_nu || use_number) {
vim_snprintf(numbuf, sizeof(numbuf), "%*" PRIdLINENR " ",
number_width(curwin), lnum);
- msg_puts_attr(numbuf, HL_ATTR(HLF_N)); // Highlight line nrs.
+ msg_puts_hl(numbuf, HLF_N + 1, false); // Highlight line nrs.
}
msg_prt_line(ml_get(lnum), list);
}
@@ -2134,7 +2134,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
if (sfname == NULL) {
sfname = ffname;
}
-#ifdef USE_FNAME_CASE
+#ifdef CASE_INSENSITIVE_FILENAME
if (sfname != NULL) {
path_fix_case(sfname); // set correct case for sfname
}
@@ -2261,7 +2261,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
if (buf == NULL) {
goto theend;
}
- // autocommands try to edit a file that is goind to be removed, abort
+ // autocommands try to edit a file that is going to be removed, abort
if (buf_locked(buf)) {
// window was split, but not editing the new buffer, reset b_nwindows again
if (oldwin == NULL
@@ -3805,7 +3805,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
msg_no_more = true;
msg_ext_set_kind("confirm_sub");
// Same highlight as wait_return().
- smsg(HL_ATTR(HLF_R), _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
+ smsg(HLF_R, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
msg_no_more = false;
msg_scroll = i;
if (!ui_has(kUIMessages)) {
@@ -4434,11 +4434,11 @@ void ex_global(exarg_T *eap)
delim = *cmd; // get the delimiter
cmd++; // skip delimiter if there is one
pat = cmd; // remember start of pattern
- patlen = strlen(pat);
cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL);
if (cmd[0] == delim) { // end delimiter found
*cmd++ = NUL; // replace it with a NUL
}
+ patlen = strlen(pat);
}
char *used_pat;
@@ -4796,7 +4796,7 @@ void ex_oldfiles(exarg_T *eap)
if (!message_filtered(fname)) {
msg_outnum(nr);
msg_puts(": ");
- msg_outtrans(tv_get_string(TV_LIST_ITEM_TV(li)), 0);
+ msg_outtrans(tv_get_string(TV_LIST_ITEM_TV(li)), 0, false);
msg_clr_eos();
msg_putchar('\n');
os_breakcheck();
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index aff9dce7c1..e37c37e8e6 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -450,7 +450,7 @@ int buf_write_all(buf_T *buf, bool forceit)
1, buf->b_ml.ml_line_count, NULL,
false, forceit, true, false));
if (curbuf != old_curbuf) {
- msg_source(HL_ATTR(HLF_W));
+ msg_source(HLF_W);
msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"), 0);
}
return retval;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 293aaac036..f5ecedf827 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5165,6 +5165,177 @@ static void ex_wrongmodifier(exarg_T *eap)
eap->errmsg = _(e_invcmd);
}
+/// callback function for 'findfunc'
+static Callback ffu_cb;
+
+static Callback *get_findfunc_callback(void)
+{
+ return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb;
+}
+
+/// Call 'findfunc' to obtain a list of file names.
+static list_T *call_findfunc(char *pat, BoolVarValue cmdcomplete)
+{
+ const sctx_T saved_sctx = current_sctx;
+
+ typval_T args[3];
+ args[0].v_type = VAR_STRING;
+ args[0].vval.v_string = pat;
+ args[1].v_type = VAR_BOOL;
+ args[1].vval.v_bool = cmdcomplete;
+ args[2].v_type = VAR_UNKNOWN;
+
+ // Lock the text to prevent weird things from happening. Also disallow
+ // switching to another window, it should not be needed and may end up in
+ // Insert mode in another buffer.
+ textlock++;
+
+ sctx_T *ctx = get_option_sctx(kOptFindfunc);
+ if (ctx != NULL) {
+ current_sctx = *ctx;
+ }
+
+ Callback *cb = get_findfunc_callback();
+ typval_T rettv;
+ int retval = callback_call(cb, 2, args, &rettv);
+
+ current_sctx = saved_sctx;
+
+ textlock--;
+
+ list_T *retlist = NULL;
+
+ if (retval == OK) {
+ if (rettv.v_type == VAR_LIST) {
+ retlist = tv_list_copy(NULL, rettv.vval.v_list, false, get_copyID());
+ } else {
+ emsg(_(e_invalid_return_type_from_findfunc));
+ }
+
+ tv_clear(&rettv);
+ }
+
+ return retlist;
+}
+
+/// Find file names matching "pat" using 'findfunc' and return it in "files".
+/// Used for expanding the :find, :sfind and :tabfind command argument.
+/// Returns OK on success and FAIL otherwise.
+int expand_findfunc(char *pat, char ***files, int *numMatches)
+{
+ *numMatches = 0;
+ *files = NULL;
+
+ list_T *l = call_findfunc(pat, kBoolVarTrue);
+ if (l == NULL) {
+ return FAIL;
+ }
+
+ int len = tv_list_len(l);
+ if (len == 0) { // empty List
+ return FAIL;
+ }
+
+ *files = xmalloc(sizeof(char *) * (size_t)len);
+
+ // Copy all the List items
+ int idx = 0;
+ TV_LIST_ITER_CONST(l, li, {
+ if (TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) {
+ (*files)[idx] = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string);
+ idx++;
+ }
+ });
+
+ *numMatches = idx;
+ tv_list_free(l);
+
+ return OK;
+}
+
+/// Use 'findfunc' to find file 'findarg'. The 'count' argument is used to find
+/// the n'th matching file.
+static char *findfunc_find_file(char *findarg, size_t findarg_len, int count)
+{
+ char *ret_fname = NULL;
+
+ const char cc = findarg[findarg_len];
+ findarg[findarg_len] = NUL;
+
+ list_T *fname_list = call_findfunc(findarg, kBoolVarFalse);
+ int fname_count = tv_list_len(fname_list);
+
+ if (fname_count == 0) {
+ semsg(_(e_cant_find_file_str_in_path), findarg);
+ } else {
+ if (count > fname_count) {
+ semsg(_(e_no_more_file_str_found_in_path), findarg);
+ } else {
+ listitem_T *li = tv_list_find(fname_list, count - 1);
+ if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) {
+ ret_fname = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string);
+ }
+ }
+ }
+
+ if (fname_list != NULL) {
+ tv_list_free(fname_list);
+ }
+
+ findarg[findarg_len] = cc;
+
+ return ret_fname;
+}
+
+/// Process the 'findfunc' option value.
+/// Returns NULL on success and an error message on failure.
+const char *did_set_findfunc(optset_T *args)
+{
+ buf_T *buf = (buf_T *)args->os_buf;
+ int retval;
+
+ if (args->os_flags & OPT_LOCAL) {
+ // buffer-local option set
+ retval = option_set_callback_func(buf->b_p_ffu, &buf->b_ffu_cb);
+ } else {
+ // global option set
+ retval = option_set_callback_func(p_ffu, &ffu_cb);
+ // when using :set, free the local callback
+ if (!(args->os_flags & OPT_GLOBAL)) {
+ callback_free(&buf->b_ffu_cb);
+ }
+ }
+
+ if (retval == FAIL) {
+ return e_invarg;
+ }
+
+ // If the option value starts with <SID> or s:, then replace that with
+ // the script identifier.
+ char **varp = (char **)args->os_varp;
+ char *name = get_scriptlocal_funcname(*varp);
+ if (name != NULL) {
+ free_string_option(*varp);
+ *varp = name;
+ }
+
+ return NULL;
+}
+
+void free_findfunc_option(void)
+{
+ callback_free(&ffu_cb);
+}
+
+/// Mark the global 'findfunc' callback with "copyID" so that it is not
+/// garbage collected.
+bool set_ref_in_findfunc(int copyID)
+{
+ bool abort = false;
+ abort = set_ref_in_callback(&ffu_cb, copyID, NULL, NULL);
+ return abort;
+}
+
/// :sview [+command] file split window with new file, read-only
/// :split [[+command] file] split window with current or new file
/// :vsplit [[+command] file] split window vertically with current or new file
@@ -5196,13 +5367,17 @@ void ex_splitview(exarg_T *eap)
}
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
- char *file_to_find = NULL;
- char *search_ctx = NULL;
- fname = find_file_in_path(eap->arg, strlen(eap->arg),
- FNAME_MESS, true, curbuf->b_ffname,
- &file_to_find, &search_ctx);
- xfree(file_to_find);
- vim_findfile_cleanup(search_ctx);
+ if (*get_findfunc() != NUL) {
+ fname = findfunc_find_file(eap->arg, strlen(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+ } else {
+ char *file_to_find = NULL;
+ char *search_ctx = NULL;
+ fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true,
+ curbuf->b_ffname, &file_to_find, &search_ctx);
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
+ }
if (fname == NULL) {
goto theend;
}
@@ -5326,12 +5501,14 @@ static void ex_tabs(exarg_T *eap)
msg_putchar('\n');
vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++);
- msg_outtrans(IObuff, HL_ATTR(HLF_T));
+ msg_outtrans(IObuff, HLF_T, false);
os_breakcheck();
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (got_int) {
break;
+ } else if (!wp->w_config.focusable) {
+ continue;
}
msg_putchar('\n');
@@ -5344,7 +5521,7 @@ static void ex_tabs(exarg_T *eap)
} else {
home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true);
}
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
os_breakcheck();
}
}
@@ -5398,23 +5575,28 @@ static void ex_find(exarg_T *eap)
return;
}
- char *file_to_find = NULL;
- char *search_ctx = NULL;
- char *fname = find_file_in_path(eap->arg, strlen(eap->arg),
- FNAME_MESS, true, curbuf->b_ffname,
- &file_to_find, &search_ctx);
- if (eap->addr_count > 0) {
- // Repeat finding the file "count" times. This matters when it appears
- // several times in the path.
- linenr_T count = eap->line2;
- while (fname != NULL && --count > 0) {
- xfree(fname);
- fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname,
- &file_to_find, &search_ctx);
+ char *fname = NULL;
+ if (*get_findfunc() != NUL) {
+ fname = findfunc_find_file(eap->arg, strlen(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+ } else {
+ char *file_to_find = NULL;
+ char *search_ctx = NULL;
+ fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true,
+ curbuf->b_ffname, &file_to_find, &search_ctx);
+ if (eap->addr_count > 0) {
+ // Repeat finding the file "count" times. This matters when it appears
+ // several times in the path.
+ linenr_T count = eap->line2;
+ while (fname != NULL && --count > 0) {
+ xfree(fname);
+ fname = find_file_in_path(NULL, 0, FNAME_MESS, false,
+ curbuf->b_ffname, &file_to_find, &search_ctx);
+ }
}
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
}
- xfree(file_to_find);
- vim_findfile_cleanup(search_ctx);
if (fname == NULL) {
return;
@@ -7596,7 +7778,7 @@ void verify_command(char *cmd)
if (strcmp("smile", cmd) != 0) {
return; // acceptable non-existing command
}
- int a = HL_ATTR(HLF_E);
+ int a = HLF_E;
msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx"
"xxxxxxnz+, znnnnnnnnnnnnnnnn.", a);
msg(" n###z x####` :x##########W+` ,###"
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 7d87e609ca..ace62ea729 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -125,6 +125,7 @@ typedef struct {
bool gotesc; // true when <ESC> just typed
int do_abbr; // when true check for abbr.
char *lookfor; // string to match
+ int lookforlen;
int hiscnt; // current history line in use
int save_hiscnt; // history line before attempting
// to jump to next match
@@ -385,7 +386,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
if (!use_last_pat) {
char c = *end;
*end = NUL;
- bool empty = empty_pattern_magic(p, strlen(p), magic);
+ bool empty = empty_pattern_magic(p, (size_t)(end - p), magic);
*end = c;
if (empty) {
goto theend;
@@ -538,7 +539,8 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state
if (!use_last_pat) {
next_char = ccline.cmdbuff[skiplen + patlen];
ccline.cmdbuff[skiplen + patlen] = NUL;
- if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) {
+ if (empty_pattern(ccline.cmdbuff + skiplen, (size_t)patlen, search_delim)
+ && !no_hlsearch) {
redraw_all_later(UPD_SOME_VALID);
set_no_hlsearch(true);
}
@@ -809,7 +811,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
if (!tl_ret && ERROR_SET(&err)) {
msg_putchar('\n');
msg_scroll = true;
- msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST);
+ msg_puts_hl(err.msg, HLF_E, true);
api_clear_error(&err);
redrawcmd();
}
@@ -900,12 +902,11 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
&& ccline.cmdlen
&& s->firstc != NUL
&& (s->some_key_typed || s->histype == HIST_SEARCH)) {
- size_t cmdbufflen = strlen(ccline.cmdbuff);
- add_to_history(s->histype, ccline.cmdbuff, cmdbufflen, true,
+ add_to_history(s->histype, ccline.cmdbuff, (size_t)ccline.cmdlen, true,
s->histype == HIST_SEARCH ? s->firstc : NUL);
if (s->firstc == ':') {
xfree(new_last_cmdline);
- new_last_cmdline = xstrnsave(ccline.cmdbuff, cmdbufflen);
+ new_last_cmdline = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen);
}
}
@@ -1262,6 +1263,7 @@ static int command_line_execute(VimState *state, int key)
&& s->c != K_LEFT && s->c != K_RIGHT
&& (s->xpc.xp_numfiles > 0 || (s->c != Ctrl_P && s->c != Ctrl_N))) {
XFREE_CLEAR(s->lookfor);
+ s->lookforlen = 0;
}
// When there are matching completions to select <S-Tab> works like
@@ -1440,7 +1442,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s
return FAIL;
}
skiplen = 0;
- patlen = (int)strlen(pat);
+ patlen = (int)last_search_pattern_len();
} else {
pat = ccline.cmdbuff + skiplen;
}
@@ -1574,7 +1576,8 @@ static int command_line_erase_chars(CommandLineState *s)
return CMDLINE_NOT_CHANGED;
}
- XFREE_CLEAR(ccline.cmdbuff); // no commandline to return
+ dealloc_cmdbuff(); // no commandline to return
+
if (!cmd_silent && !ui_has(kUICmdline)) {
msg_col = 0;
msg_putchar(' '); // delete ':'
@@ -1702,7 +1705,6 @@ static void command_line_left_right_mouse(CommandLineState *s)
static void command_line_next_histidx(CommandLineState *s, bool next_match)
{
- int j = (int)strlen(s->lookfor);
while (true) {
// one step backwards
if (!next_match) {
@@ -1746,7 +1748,7 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match)
if ((s->c != K_UP && s->c != K_DOWN)
|| s->hiscnt == s->save_hiscnt
|| strncmp(get_histentry(s->histype)[s->hiscnt].hisstr,
- s->lookfor, (size_t)j) == 0) {
+ s->lookfor, (size_t)s->lookforlen) == 0) {
break;
}
}
@@ -1765,30 +1767,34 @@ static int command_line_browse_history(CommandLineState *s)
// save current command string so it can be restored later
if (s->lookfor == NULL) {
- s->lookfor = xstrdup(ccline.cmdbuff);
+ s->lookfor = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen);
s->lookfor[ccline.cmdpos] = NUL;
+ s->lookforlen = ccline.cmdpos;
}
bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N
|| s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
command_line_next_histidx(s, next_match);
- if (s->hiscnt != s->save_hiscnt) {
- // jumped to other entry
+ if (s->hiscnt != s->save_hiscnt) { // jumped to other entry
char *p;
+ int plen;
int old_firstc;
- XFREE_CLEAR(ccline.cmdbuff);
+ dealloc_cmdbuff();
+
s->xpc.xp_context = EXPAND_NOTHING;
if (s->hiscnt == get_hislen()) {
p = s->lookfor; // back to the old one
+ plen = s->lookforlen;
} else {
p = get_histentry(s->histype)[s->hiscnt].hisstr;
+ plen = (int)get_histentry(s->histype)[s->hiscnt].hisstrlen;
}
if (s->histype == HIST_SEARCH
&& p != s->lookfor
- && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) {
+ && (old_firstc = (uint8_t)p[plen + 1]) != s->firstc) {
int len = 0;
// Correct for the separator character used when
// adding the history entry vs the one used now.
@@ -1827,12 +1833,13 @@ static int command_line_browse_history(CommandLineState *s)
}
}
ccline.cmdbuff[len] = NUL;
+ ccline.cmdpos = ccline.cmdlen = len;
} else {
- alloc_cmdbuff((int)strlen(p));
+ alloc_cmdbuff(plen);
STRCPY(ccline.cmdbuff, p);
+ ccline.cmdpos = ccline.cmdlen = plen;
}
- ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff);
redrawcmd();
return CMDLINE_CHANGED;
}
@@ -2201,18 +2208,17 @@ static int command_line_not_changed(CommandLineState *s)
/// Guess that the pattern matches everything. Only finds specific cases, such
/// as a trailing \|, which can happen while typing a pattern.
-static bool empty_pattern(char *p, int delim)
+static bool empty_pattern(char *p, size_t len, int delim)
{
- size_t n = strlen(p);
magic_T magic_val = MAGIC_ON;
- if (n > 0) {
+ if (len > 0) {
skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val);
} else {
return true;
}
- return empty_pattern_magic(p, n, magic_val);
+ return empty_pattern_magic(p, len, magic_val);
}
static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val)
@@ -2225,11 +2231,9 @@ static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val)
// true, if the pattern is empty, or the pattern ends with \| and magic is
// set (or it ends with '|' and very magic is set)
- return len == 0 || (len > 1
- && ((p[len - 2] == '\\'
- && p[len - 1] == '|' && magic_val == MAGIC_ON)
- || (p[len - 2] != '\\'
- && p[len - 1] == '|' && magic_val == MAGIC_ALL)));
+ return len == 0 || (len > 1 && p[len - 1] == '|'
+ && ((p[len - 2] == '\\' && magic_val == MAGIC_ON)
+ || (p[len - 2] != '\\' && magic_val == MAGIC_ALL)));
}
handle_T cmdpreview_get_bufnr(void)
@@ -2546,6 +2550,9 @@ static bool cmdpreview_may_show(CommandLineState *s)
goto end;
}
+ // Cursor may be at the end of the message grid rather than at cmdspos.
+ // Place it there in case preview callback flushes it. #30696
+ cursorcmd();
// Flush now: external cmdline may itself wish to update the screen which is
// currently disallowed during cmdpreview(no longer needed in case that changes).
cmdline_ui_flush();
@@ -2653,7 +2660,7 @@ static void do_autocmd_cmdlinechanged(int firstc)
if (!tl_ret && ERROR_SET(&err)) {
msg_putchar('\n');
msg_scroll = true;
- msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST);
+ msg_puts_hl(err.msg, HLF_E, true);
api_clear_error(&err);
redrawcmd();
}
@@ -2710,7 +2717,7 @@ static int command_line_changed(CommandLineState *s)
/// Abandon the command line.
static void abandon_cmdline(void)
{
- XFREE_CLEAR(ccline.cmdbuff);
+ dealloc_cmdbuff();
ccline.redraw_state = kCmdRedrawNone;
if (msg_scrolled == 0) {
compute_cmdrow();
@@ -2751,13 +2758,13 @@ char *getcmdline(int firstc, int count, int indent, bool do_concat FUNC_ATTR_UNU
///
/// @param[in] firstc Prompt type: e.g. '@' for input(), '>' for debug.
/// @param[in] prompt Prompt string: what is displayed before the user text.
-/// @param[in] attr Prompt highlighting.
+/// @param[in] hl_id Prompt highlight id.
/// @param[in] xp_context Type of expansion.
/// @param[in] xp_arg User-defined expansion argument.
/// @param[in] highlight_callback Callback used for highlighting user input.
///
/// @return [allocated] Command line or NULL.
-char *getcmdline_prompt(const int firstc, const char *const prompt, const int attr,
+char *getcmdline_prompt(const int firstc, const char *const prompt, const int hl_id,
const int xp_context, const char *const xp_arg,
const Callback highlight_callback)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
@@ -2775,7 +2782,7 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at
}
ccline.prompt_id = last_prompt_id++;
ccline.cmdprompt = (char *)prompt;
- ccline.cmdattr = attr;
+ ccline.hl_id = hl_id;
ccline.xp_context = xp_context;
ccline.xp_arg = (char *)xp_arg;
ccline.input_fn = (firstc == '@');
@@ -3000,8 +3007,15 @@ bool cmdline_at_end(void)
return (ccline.cmdpos >= ccline.cmdlen);
}
-// Allocate a new command line buffer.
-// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
+/// Deallocate a command line buffer, updating the buffer size and length.
+static void dealloc_cmdbuff(void)
+{
+ XFREE_CLEAR(ccline.cmdbuff);
+ ccline.cmdlen = ccline.cmdbufflen = 0;
+}
+
+/// Allocate a new command line buffer.
+/// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
static void alloc_cmdbuff(int len)
{
// give some extra space to avoid having to allocate all the time
@@ -3023,6 +3037,7 @@ void realloc_cmdbuff(int len)
}
char *p = ccline.cmdbuff;
+
alloc_cmdbuff(len); // will get some more
// There isn't always a NUL after the command, but it may need to be
// there, thus copy up to the NUL and add a NUL.
@@ -3083,15 +3098,13 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)prev_end,
.end = (int)chunk.start.col,
- .attr = 0,
+ .hl_id = 0,
}));
}
- const int id = syn_name2id(chunk.group);
- const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)chunk.start.col,
.end = (int)chunk.end_col,
- .attr = attr,
+ .hl_id = syn_name2id(chunk.group),
}));
prev_end = chunk.end_col;
}
@@ -3099,7 +3112,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)prev_end,
.end = colored_ccline->cmdlen,
- .attr = 0,
+ .hl_id = 0,
}));
}
kvi_destroy(colors);
@@ -3128,7 +3141,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
#define PRINT_ERRMSG(...) \
do { \
msg_putchar('\n'); \
- msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, __VA_ARGS__); \
+ msg_printf_hl(HLF_E, __VA_ARGS__); \
printed_errmsg = true; \
} while (0)
bool ret = true;
@@ -3263,7 +3276,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)prev_end,
.end = (int)start,
- .attr = 0,
+ .hl_id = 0,
}));
}
const varnumber_T end =
@@ -3287,12 +3300,10 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
if (group == NULL) {
goto color_cmdline_error;
}
- const int id = syn_name2id(group);
- const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)start,
.end = (int)end,
- .attr = attr,
+ .hl_id = syn_name2id(group),
}));
i++;
});
@@ -3300,7 +3311,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)prev_end,
.end = colored_ccline->cmdlen,
- .attr = 0,
+ .hl_id = 0,
}));
}
prev_prompt_errors = 0;
@@ -3362,10 +3373,10 @@ static void draw_cmdline(int start, int len)
continue;
}
const int chunk_start = MAX(chunk.start, start);
- msg_outtrans_len(ccline.cmdbuff + chunk_start, chunk.end - chunk_start, chunk.attr);
+ msg_outtrans_len(ccline.cmdbuff + chunk_start, chunk.end - chunk_start, chunk.hl_id, false);
}
} else {
- msg_outtrans_len(ccline.cmdbuff + start, len, 0);
+ msg_outtrans_len(ccline.cmdbuff + start, len, 0, false);
}
}
}
@@ -3391,7 +3402,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) {
CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i);
Array item = arena_array(&arena, 2);
- ADD_C(item, INTEGER_OBJ(chunk.attr));
+ ADD_C(item, INTEGER_OBJ(chunk.hl_id == 0 ? 0 : syn_id2attr(chunk.hl_id)));
assert(chunk.end >= chunk.start);
ADD_C(item, STRING_OBJ(cbuf_as_string(line->cmdbuff + chunk.start,
@@ -3581,38 +3592,14 @@ void put_on_cmdline(const char *str, int len, bool redraw)
memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
ccline.cmdbuff[ccline.cmdlen] = NUL;
- {
- // When the inserted text starts with a composing character,
- // backup to the character before it. There could be two of them.
- int i = 0;
- int c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
- // TODO(bfredl): this can be corrected/simplified as utf_head_off implements the
- // correct grapheme cluster breaks
- while (ccline.cmdpos > 0 && utf_iscomposing_legacy(c)) {
- i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1;
+ // When the inserted text starts with a composing character,
+ // backup to the character before it.
+ if (ccline.cmdpos > 0 && (uint8_t)ccline.cmdbuff[ccline.cmdpos] >= 0x80) {
+ int i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos);
+ if (i != 0) {
ccline.cmdpos -= i;
len += i;
- c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
- }
- if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c)) {
- // Check the previous character for Arabic combining pair.
- i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1;
- if (arabic_combine(utf_ptr2char(ccline.cmdbuff + ccline.cmdpos - i), c)) {
- ccline.cmdpos -= i;
- len += i;
- } else {
- i = 0;
- }
- }
- if (i != 0) {
- // Also backup the cursor position.
- i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
- ccline.cmdspos -= i;
- msg_col -= i;
- if (msg_col < 0) {
- msg_col += Columns;
- msg_row--;
- }
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
}
}
@@ -3801,7 +3788,7 @@ static void redrawcmdprompt(void)
msg_putchar(ccline.cmdfirstc);
}
if (ccline.cmdprompt != NULL) {
- msg_puts_attr(ccline.cmdprompt, ccline.cmdattr);
+ msg_puts_hl(ccline.cmdprompt, ccline.hl_id, false);
ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
// do the reverse of cmd_startcol()
if (ccline.cmdfirstc != NUL) {
@@ -4074,14 +4061,44 @@ static char *get_cmdline_str(void)
return xstrnsave(p->cmdbuff, (size_t)p->cmdlen);
}
+/// Get the current command-line completion pattern.
+static char *get_cmdline_completion_pattern(void)
+{
+ if (cmdline_star > 0) {
+ return NULL;
+ }
+
+ CmdlineInfo *p = get_ccline_ptr();
+ if (p == NULL || p->xpc == NULL) {
+ return NULL;
+ }
+
+ int xp_context = p->xpc->xp_context;
+ if (xp_context == EXPAND_NOTHING) {
+ set_expand_context(p->xpc);
+ xp_context = p->xpc->xp_context;
+ p->xpc->xp_context = EXPAND_NOTHING;
+ }
+ if (xp_context == EXPAND_UNSUCCESSFUL) {
+ return NULL;
+ }
+
+ char *compl_pat = p->xpc->xp_pattern;
+ if (compl_pat == NULL) {
+ return NULL;
+ }
+
+ return xstrdup(compl_pat);
+}
+
/// Get the current command-line completion type.
static char *get_cmdline_completion(void)
{
if (cmdline_star > 0) {
return NULL;
}
- CmdlineInfo *p = get_ccline_ptr();
+ CmdlineInfo *p = get_ccline_ptr();
if (p == NULL || p->xpc == NULL) {
return NULL;
}
@@ -4111,6 +4128,13 @@ static char *get_cmdline_completion(void)
return xstrdup(cmd_compl);
}
+/// "getcmdcomplpat()" function
+void f_getcmdcomplpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = get_cmdline_completion_pattern();
+}
+
/// "getcmdcompltype()" function
void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -4509,17 +4533,20 @@ static int open_cmdwin(void)
cmdwin_result = Ctrl_C;
}
// Set the new command line from the cmdline buffer.
- xfree(ccline.cmdbuff);
+ dealloc_cmdbuff();
+
if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed
const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
+ size_t plen = (cmdwin_result == K_XF2) ? 2 : 3;
if (histtype == HIST_CMD) {
// Execute the command directly.
- ccline.cmdbuff = xstrdup(p);
+ ccline.cmdbuff = xmemdupz(p, plen);
+ ccline.cmdlen = (int)plen;
+ ccline.cmdbufflen = (int)plen + 1;
cmdwin_result = CAR;
} else {
// First need to cancel what we were doing.
- ccline.cmdbuff = NULL;
stuffcharReadbuff(':');
stuffReadbuff(p);
stuffcharReadbuff(CAR);
@@ -4529,17 +4556,18 @@ static int open_cmdwin(void)
// and don't modify the cmd window.
ccline.cmdbuff = NULL;
} else {
- ccline.cmdbuff = xstrdup(get_cursor_line_ptr());
+ ccline.cmdlen = get_cursor_line_len();
+ ccline.cmdbufflen = ccline.cmdlen + 1;
+ ccline.cmdbuff = xstrnsave(get_cursor_line_ptr(), (size_t)ccline.cmdlen);
}
+
if (ccline.cmdbuff == NULL) {
- ccline.cmdbuff = xstrdup("");
+ ccline.cmdbuff = xmemdupz("", 0);
ccline.cmdlen = 0;
ccline.cmdbufflen = 1;
ccline.cmdpos = 0;
cmdwin_result = Ctrl_C;
} else {
- ccline.cmdlen = (int)strlen(ccline.cmdbuff);
- ccline.cmdbufflen = ccline.cmdlen + 1;
ccline.cmdpos = curwin->w_cursor.col;
// If the cursor is on the last character, it probably should be after it.
if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) {
@@ -4748,7 +4776,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
p = lastnl + 1;
msg_start();
msg_clr_eos();
- msg_puts_len(prompt, p - prompt, get_echo_attr());
+ msg_puts_len(prompt, p - prompt, get_echo_hl_id(), false);
msg_didout = false;
msg_starthere();
}
@@ -4759,7 +4787,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
const int save_ex_normal_busy = ex_normal_busy;
ex_normal_busy = 0;
- rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(),
+ rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_hl_id(),
xp_type, xp_arg, input_callback);
ex_normal_busy = save_ex_normal_busy;
callback_free(&input_callback);
diff --git a/src/nvim/ex_getln_defs.h b/src/nvim/ex_getln_defs.h
index daba6cabb8..584c360450 100644
--- a/src/nvim/ex_getln_defs.h
+++ b/src/nvim/ex_getln_defs.h
@@ -10,8 +10,8 @@
/// Defines a region which has the same highlighting.
typedef struct {
int start; ///< Colored chunk start.
- int end; ///< Colored chunk end (exclusive, > start).
- int attr; ///< Highlight attr.
+ int end; ///< Colored chunk end (exclusive, > start).
+ int hl_id; ///< Highlight id.
} CmdlineColorChunk;
/// Command-line colors
@@ -49,7 +49,7 @@ struct cmdline_info {
int cmdfirstc; ///< ':', '/', '?', '=', '>' or NUL
int cmdindent; ///< number of spaces before cmdline
char *cmdprompt; ///< message in front of cmdline
- int cmdattr; ///< attributes for prompt
+ int hl_id; ///< highlight id for prompt
int overstrike; ///< Typing mode on the command line. Shared by
///< getcmdline() and put_on_cmdline().
expand_T *xpc; ///< struct being used for expansion, xp_pattern
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index cdfd281718..d183978d2d 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1489,15 +1489,15 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch
if (file_name == NULL && (options & FNAME_MESS)) {
if (first == true) {
if (find_what == FINDFILE_DIR) {
- semsg(_("E344: Can't find directory \"%s\" in cdpath"), *file_to_find);
+ semsg(_(e_cant_find_directory_str_in_cdpath), *file_to_find);
} else {
- semsg(_("E345: Can't find file \"%s\" in path"), *file_to_find);
+ semsg(_(e_cant_find_file_str_in_path), *file_to_find);
}
} else {
if (find_what == FINDFILE_DIR) {
- semsg(_("E346: No more directory \"%s\" found in cdpath"), *file_to_find);
+ semsg(_(e_no_more_directory_str_found_in_cdpath), *file_to_find);
} else {
- semsg(_("E347: No more file \"%s\" found in path"), *file_to_find);
+ semsg(_(e_no_more_file_str_found_in_path), *file_to_find);
}
}
}
@@ -1648,7 +1648,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len)
{
const sctx_T save_sctx = current_sctx;
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
- current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptIncludeexpr].script_ctx;
char *res = eval_to_string_safe(curbuf->b_p_inex,
was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 724d754ca7..fc7fabc009 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -99,7 +99,7 @@
static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
-void filemess(buf_T *buf, char *name, char *s, int attr)
+void filemess(buf_T *buf, char *name, char *s)
{
int prev_msg_col = msg_col;
@@ -129,7 +129,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr)
msg_scroll = msg_scroll_save;
msg_scrolled_ign = true;
// may truncate the message to avoid a hit-return prompt
- msg_outtrans(msg_may_trunc(false, IObuff), attr);
+ msg_outtrans(msg_may_trunc(false, IObuff), 0, false);
msg_clr_eos();
ui_flush();
msg_scrolled_ign = false;
@@ -335,7 +335,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// If the name is too long we might crash further on, quit here.
if (namelen >= MAXPATHL) {
- filemess(curbuf, fname, _("Illegal file name"), 0);
+ filemess(curbuf, fname, _("Illegal file name"));
msg_end();
msg_scroll = msg_save;
goto theend;
@@ -346,7 +346,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// swap file may destroy it! Reported on MS-DOS and Win 95.
if (after_pathsep(fname, fname + namelen)) {
if (!silent) {
- filemess(curbuf, fname, _(msg_is_a_directory), 0);
+ filemess(curbuf, fname, _(msg_is_a_directory));
}
msg_end();
msg_scroll = msg_save;
@@ -374,11 +374,11 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
) {
if (S_ISDIR(perm)) {
if (!silent) {
- filemess(curbuf, fname, _(msg_is_a_directory), 0);
+ filemess(curbuf, fname, _(msg_is_a_directory));
}
retval = NOTDONE;
} else {
- filemess(curbuf, fname, _("is not a file"), 0);
+ filemess(curbuf, fname, _("is not a file"));
}
msg_end();
msg_scroll = msg_save;
@@ -467,9 +467,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
}
if (!silent) {
if (dir_of_file_exists(fname)) {
- filemess(curbuf, sfname, _("[New]"), 0);
+ filemess(curbuf, sfname, _("[New]"));
} else {
- filemess(curbuf, sfname, _("[New DIRECTORY]"), 0);
+ filemess(curbuf, sfname, _("[New DIRECTORY]"));
}
}
// Even though this is a new file, it might have been
@@ -497,10 +497,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// open() does not set
// EOVERFLOW
(fd == -EOVERFLOW) ? _("[File too big]")
- : _("[Permission Denied]")), 0);
+ : _("[Permission Denied]")));
#else
filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]")
- : _("[Permission Denied]")), 0);
+ : _("[Permission Denied]")));
#endif
curbuf->b_p_ro = true; // must use "w!" now
@@ -658,7 +658,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (!recoverymode && !filtering && !(flags & READ_DUMMY) && !silent) {
if (!read_stdin && !read_buffer) {
- filemess(curbuf, sfname, "", 0);
+ filemess(curbuf, sfname, "");
}
}
@@ -1685,7 +1685,7 @@ failed:
if (got_int) {
if (!(flags & READ_DUMMY)) {
- filemess(curbuf, sfname, _(e_interr), 0);
+ filemess(curbuf, sfname, _(e_interr));
if (newfile) {
curbuf->b_p_ro = true; // must use "w!" now
}
@@ -3035,9 +3035,9 @@ int buf_check_timestamp(buf_T *buf)
} else {
if (!autocmd_busy) {
msg_start();
- msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
+ msg_puts_hl(tbuf, HLF_E, true);
if (*mesg2 != NUL) {
- msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
+ msg_puts_hl(mesg2, HLF_W, true);
}
msg_clr_eos();
msg_end();
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index e7231c31ab..c9699cb161 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1731,7 +1731,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo
curwin = wp;
curbuf = wp->w_buffer;
- current_sctx = wp->w_p_script_ctx[WV_FDT].script_ctx;
+ current_sctx = wp->w_p_script_ctx[kWinOptFoldtext].script_ctx;
emsg_off++; // handle exceptions, but don't display errors
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 9e0aa407a1..a78f746fee 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -750,7 +750,7 @@ local function process_function(fn)
write_shifted_output(
[[
if (!nlua_is_deferred_safe()) {
- return luaL_error(lstate, e_luv_api_disabled, "%s");
+ return luaL_error(lstate, e_fast_api_disabled, "%s");
}
]],
fn.name
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 3e8ae19c9a..30a83330eb 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -136,8 +136,8 @@ for i = 1, #events do
call_output:write(' }\n')
call_output:write(' entered = true;\n')
write_arglist(call_output, ev)
- call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n')
- call_output:write(' entered = false;\n')
+ call_output:write((' ui_call_event("%s", %s, %s)'):format(ev.name, tostring(ev.fast), args))
+ call_output:write(';\n entered = false;\n')
elseif ev.compositor_impl then
call_output:write(' ui_comp_' .. ev.name)
write_signature(call_output, ev, '', true)
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 591a6b93df..02f3ac3257 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -1,6 +1,10 @@
local options_file = arg[1]
+local options_enum_file = arg[2]
+local options_map_file = arg[3]
local opt_fd = assert(io.open(options_file, 'w'))
+local opt_enum_fd = assert(io.open(options_enum_file, 'w'))
+local opt_map_fd = assert(io.open(options_map_file, 'w'))
local w = function(s)
if s:match('^ %.') then
@@ -10,30 +14,29 @@ local w = function(s)
end
end
+--- @param s string
+local function enum_w(s)
+ opt_enum_fd:write(s .. '\n')
+end
+
+--- @param s string
+local function map_w(s)
+ opt_map_fd:write(s .. '\n')
+end
+
--- @module 'nvim.options'
local options = require('options')
+local options_meta = options.options
local cstr = options.cstr
+local valid_scopes = options.valid_scopes
-local redraw_flags = {
- ui_option = 'P_UI_OPTION',
- tabline = 'P_RTABL',
- statuslines = 'P_RSTAT',
- current_window = 'P_RWIN',
- current_buffer = 'P_RBUF',
- all_windows = 'P_RALL',
- curswant = 'P_CURSWANT',
- highlight_only = 'P_HLONLY',
-}
-
-local list_flags = {
- comma = 'P_COMMA',
- onecomma = 'P_ONECOMMA',
- commacolon = 'P_COMMA|P_COLON',
- onecommacolon = 'P_ONECOMMA|P_COLON',
- flags = 'P_FLAGLIST',
- flagscomma = 'P_COMMA|P_FLAGLIST',
-}
+--- Options for each scope.
+--- @type table<string, vim.option_meta[]>
+local scope_options = {}
+for _, scope in ipairs(valid_scopes) do
+ scope_options[scope] = {}
+end
--- @param s string
--- @return string
@@ -41,6 +44,120 @@ local lowercase_to_titlecase = function(s)
return s:sub(1, 1):upper() .. s:sub(2)
end
+-- Generate options enum file
+enum_w('// IWYU pragma: private, include "nvim/option_defs.h"')
+enum_w('')
+
+--- Map of option name to option index
+--- @type table<string, string>
+local option_index = {}
+
+-- Generate option index enum and populate the `option_index` and `scope_option` dicts.
+enum_w('typedef enum {')
+enum_w(' kOptInvalid = -1,')
+
+for i, o in ipairs(options_meta) do
+ local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name)
+ enum_w((' %s = %u,'):format(enum_val_name, i - 1))
+
+ option_index[o.full_name] = enum_val_name
+
+ if o.abbreviation then
+ option_index[o.abbreviation] = enum_val_name
+ end
+
+ if o.alias then
+ o.alias = type(o.alias) == 'string' and { o.alias } or o.alias
+
+ for _, v in ipairs(o.alias) do
+ option_index[v] = enum_val_name
+ end
+ end
+
+ for _, scope in ipairs(o.scope) do
+ table.insert(scope_options[scope], o)
+ end
+end
+
+enum_w(' // Option count')
+enum_w('#define kOptCount ' .. tostring(#options_meta))
+enum_w('} OptIndex;')
+
+--- @param scope string
+--- @param option_name string
+--- @return string
+local get_scope_option = function(scope, option_name)
+ return ('k%sOpt%s'):format(lowercase_to_titlecase(scope), lowercase_to_titlecase(option_name))
+end
+
+-- Generate option index enum for each scope
+for _, scope in ipairs(valid_scopes) do
+ enum_w('')
+
+ local scope_name = lowercase_to_titlecase(scope)
+ enum_w('typedef enum {')
+ enum_w((' %s = -1,'):format(get_scope_option(scope, 'Invalid')))
+
+ for idx, option in ipairs(scope_options[scope]) do
+ enum_w((' %s = %u,'):format(get_scope_option(scope, option.full_name), idx - 1))
+ end
+
+ enum_w((' // %s option count'):format(scope_name))
+ enum_w(('#define %s %d'):format(get_scope_option(scope, 'Count'), #scope_options[scope]))
+ enum_w(('} %sOptIndex;'):format(scope_name))
+end
+
+-- Generate reverse lookup from option scope index to option index for each scope.
+for _, scope in ipairs(valid_scopes) do
+ enum_w('')
+ enum_w(('EXTERN const OptIndex %s_opt_idx[] INIT( = {'):format(scope))
+ for _, option in ipairs(scope_options[scope]) do
+ local idx = option_index[option.full_name]
+ enum_w((' [%s] = %s,'):format(get_scope_option(scope, option.full_name), idx))
+ end
+ enum_w('});')
+end
+
+opt_enum_fd:close()
+
+-- Generate option index map.
+local hashy = require('generators.hashy')
+local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx)
+ return ('option_hash_elems[%s].name'):format(idx)
+end)
+
+map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {')
+
+for _, name in ipairs(neworder) do
+ assert(option_index[name] ~= nil)
+ map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name]))
+end
+
+map_w('};\n')
+map_w('static ' .. hashfun)
+
+opt_map_fd:close()
+
+local redraw_flags = {
+ ui_option = 'kOptFlagUIOption',
+ tabline = 'kOptFlagRedrTabl',
+ statuslines = 'kOptFlagRedrStat',
+ current_window = 'kOptFlagRedrWin',
+ current_buffer = 'kOptFlagRedrBuf',
+ all_windows = 'kOptFlagRedrAll',
+ curswant = 'kOptFlagCurswant',
+ highlight_only = 'kOptFlagHLOnly',
+}
+
+local list_flags = {
+ comma = 'kOptFlagComma',
+ onecomma = 'kOptFlagOneComma',
+ commacolon = 'kOptFlagComma|kOptFlagColon',
+ onecommacolon = 'kOptFlagOneComma|kOptFlagColon',
+ flags = 'kOptFlagFlagList',
+ flagscomma = 'kOptFlagComma|kOptFlagFlagList',
+}
+
--- @param o vim.option_meta
--- @return string
local function get_flags(o)
@@ -61,28 +178,27 @@ local function get_flags(o)
end
end
if o.expand then
- add_flag('P_EXPAND')
+ add_flag('kOptFlagExpand')
if o.expand == 'nodefault' then
- add_flag('P_NO_DEF_EXP')
+ add_flag('kOptFlagNoDefExp')
end
end
for _, flag_desc in ipairs({
- { 'alloced' },
- { 'nodefault' },
- { 'no_mkrc' },
+ { 'nodefault', 'NoDefault' },
+ { 'no_mkrc', 'NoMkrc' },
{ 'secure' },
{ 'gettext' },
- { 'noglob' },
- { 'normal_fname_chars', 'P_NFNAME' },
- { 'normal_dname_chars', 'P_NDNAME' },
- { 'pri_mkrc' },
- { 'deny_in_modelines', 'P_NO_ML' },
- { 'deny_duplicates', 'P_NODUP' },
- { 'modelineexpr', 'P_MLE' },
+ { 'noglob', 'NoGlob' },
+ { 'normal_fname_chars', 'NFname' },
+ { 'normal_dname_chars', 'NDname' },
+ { 'pri_mkrc', 'PriMkrc' },
+ { 'deny_in_modelines', 'NoML' },
+ { 'deny_duplicates', 'NoDup' },
+ { 'modelineexpr', 'MLE' },
{ 'func' },
}) do
local key_name = flag_desc[1]
- local def_name = flag_desc[2] or ('P_' .. key_name:upper())
+ local def_name = 'kOptFlag' .. (flag_desc[2] or lowercase_to_titlecase(key_name))
if o[key_name] then
add_flag(def_name)
end
@@ -90,6 +206,18 @@ local function get_flags(o)
return flags
end
+--- @param opt_type vim.option_type
+--- @return string
+local function opt_type_enum(opt_type)
+ return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type))
+end
+
+--- @param scope vim.option_scope
+--- @return string
+local function opt_scope_enum(scope)
+ return ('kOptScope%s'):format(lowercase_to_titlecase(scope))
+end
+
--- @param o vim.option_meta
--- @return string
local function get_type_flags(o)
@@ -99,12 +227,41 @@ local function get_type_flags(o)
for _, opt_type in ipairs(opt_types) do
assert(type(opt_type) == 'string')
- type_flags = ('%s | (1 << kOptValType%s)'):format(type_flags, lowercase_to_titlecase(opt_type))
+ type_flags = ('%s | (1 << %s)'):format(type_flags, opt_type_enum(opt_type))
end
return type_flags
end
+--- @param o vim.option_meta
+--- @return string
+local function get_scope_flags(o)
+ local scope_flags = '0'
+
+ for _, scope in ipairs(o.scope) do
+ scope_flags = ('%s | (1 << %s)'):format(scope_flags, opt_scope_enum(scope))
+ end
+
+ return scope_flags
+end
+
+--- @param o vim.option_meta
+--- @return string
+local function get_scope_idx(o)
+ --- @type string[]
+ local strs = {}
+
+ for _, scope in pairs(valid_scopes) do
+ local has_scope = vim.tbl_contains(o.scope, scope)
+ strs[#strs + 1] = (' [%s] = %s'):format(
+ opt_scope_enum(scope),
+ get_scope_option(scope, has_scope and o.full_name or 'Invalid')
+ )
+ end
+
+ return ('{\n%s\n }'):format(table.concat(strs, ',\n'))
+end
+
--- @param c string|string[]
--- @param base_string? string
--- @return string
@@ -125,32 +282,49 @@ local function get_cond(c, base_string)
return cond_string
end
+--- @param s string
+--- @return string
+local static_cstr_as_string = function(s)
+ return ('{ .data = %s, .size = sizeof(%s) - 1 }'):format(s, s)
+end
+
+--- @param v vim.option_value|function
+--- @return string
+local get_opt_val = function(v)
+ --- @type vim.option_type
+ local v_type
+
+ if type(v) == 'function' then
+ v, v_type = v() --[[ @as string, vim.option_type ]]
+
+ if v_type == 'string' then
+ v = static_cstr_as_string(v)
+ end
+ else
+ v_type = type(v) --[[ @as vim.option_type ]]
+
+ if v_type == 'boolean' then
+ v = v and 'true' or 'false'
+ elseif v_type == 'number' then
+ v = ('%iL'):format(v)
+ elseif v_type == 'string' then
+ v = static_cstr_as_string(cstr(v))
+ end
+ end
+
+ return ('{ .type = %s, .data.%s = %s }'):format(opt_type_enum(v_type), v_type, v)
+end
+
+--- @param d vim.option_value|function
+--- @param n string
+--- @return string
local get_defaults = function(d, n)
if d == nil then
error("option '" .. n .. "' should have a default value")
end
-
- local value_dumpers = {
- ['function'] = function(v)
- return v()
- end,
- string = function(v)
- return '.string=' .. cstr(v)
- end,
- boolean = function(v)
- return '.boolean=' .. (v and 'true' or 'false')
- end,
- number = function(v)
- return ('.number=%iL'):format(v)
- end,
- }
-
- return value_dumpers[type(d)](d)
+ return get_opt_val(d)
end
---- @type [string,string][]
-local defines = {}
-
--- @param i integer
--- @param o vim.option_meta
local function dump_option(i, o)
@@ -161,48 +335,28 @@ local function dump_option(i, o)
end
w(' .flags=' .. get_flags(o))
w(' .type_flags=' .. get_type_flags(o))
+ w(' .scope_flags=' .. get_scope_flags(o))
+ w(' .scope_idx=' .. get_scope_idx(o))
if o.enable_if then
w(get_cond(o.enable_if))
end
- -- An option cannot be both hidden and immutable.
- assert(not o.hidden or not o.immutable)
+ local is_window_local = #o.scope == 1 and o.scope[1] == 'win'
- local has_var = true
- if o.varname then
- w(' .var=&' .. o.varname)
- elseif o.hidden or o.immutable then
- -- Hidden and immutable options can directly point to the default value.
- w((' .var=&options[%u].def_val'):format(i - 1))
- elseif #o.scope == 1 and o.scope[1] == 'window' then
- w(' .var=VAR_WIN')
+ if not is_window_local then
+ if o.varname then
+ w(' .var=&' .. o.varname)
+ elseif o.immutable then
+ -- Immutable options can directly point to the default value.
+ w((' .var=&options[%u].def_val.data'):format(i - 1))
+ else
+ -- Option must be immutable or have a variable.
+ assert(false)
+ end
else
- has_var = false
+ w(' .var=NULL')
end
- -- `enable_if = false` should be present iff there is no variable.
- assert((o.enable_if == false) == not has_var)
- w(' .hidden=' .. (o.hidden and 'true' or 'false'))
w(' .immutable=' .. (o.immutable and 'true' or 'false'))
- if #o.scope == 1 and o.scope[1] == 'global' then
- w(' .indir=PV_NONE')
- else
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local pv_name = (
- 'OPT_'
- .. min_scope:sub(1, 3):upper()
- .. '('
- .. (min_scope:sub(1, 1):upper() .. 'V_' .. varname:sub(3):upper())
- .. ')'
- )
- if #o.scope == 2 then
- pv_name = 'OPT_BOTH(' .. pv_name .. ')'
- end
- table.insert(defines, { 'PV_' .. varname:sub(3):upper(), pv_name })
- w(' .indir=' .. pv_name)
- end
if o.cb then
w(' .opt_did_set_cb=' .. o.cb)
end
@@ -211,27 +365,33 @@ local function dump_option(i, o)
end
if o.enable_if then
w('#else')
- w(' .var=NULL')
- w(' .indir=PV_NONE')
+ -- Hidden option directly points to default value.
+ w((' .var=&options[%u].def_val.data'):format(i - 1))
+ -- Option is always immutable on the false branch of `enable_if`.
+ w(' .immutable=true')
w('#endif')
end
if o.defaults then
if o.defaults.condition then
w(get_cond(o.defaults.condition))
end
- w(' .def_val' .. get_defaults(o.defaults.if_true, o.full_name))
+ w(' .def_val=' .. get_defaults(o.defaults.if_true, o.full_name))
if o.defaults.condition then
if o.defaults.if_false then
w('#else')
- w(' .def_val' .. get_defaults(o.defaults.if_false, o.full_name))
+ w(' .def_val=' .. get_defaults(o.defaults.if_false, o.full_name))
end
w('#endif')
end
+ else
+ w(' .def_val=NIL_OPTVAL')
end
w(' },')
end
+-- Generate options[] array.
w([[
+#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/insexpand.h"
#include "nvim/mapping.h"
@@ -248,8 +408,3 @@ for i, o in ipairs(options.options) do
dump_option(i, o)
end
w('};')
-w('')
-
-for _, v in ipairs(defines) do
- w('#define ' .. v[1] .. ' ' .. v[2])
-end
diff --git a/src/nvim/generators/gen_options_enum.lua b/src/nvim/generators/gen_options_enum.lua
deleted file mode 100644
index d1419137d3..0000000000
--- a/src/nvim/generators/gen_options_enum.lua
+++ /dev/null
@@ -1,129 +0,0 @@
--- Generates option index enum and map of option name to option index.
--- Handles option full name, short name and aliases.
--- Also generates BV_ and WV_ enum constants.
-
-local options_enum_file = arg[1]
-local options_map_file = arg[2]
-local options_enum_fd = assert(io.open(options_enum_file, 'w'))
-local options_map_fd = assert(io.open(options_map_file, 'w'))
-
---- @param s string
-local function enum_w(s)
- options_enum_fd:write(s .. '\n')
-end
-
---- @param s string
-local function map_w(s)
- options_map_fd:write(s .. '\n')
-end
-
-enum_w('// IWYU pragma: private, include "nvim/option_defs.h"')
-enum_w('')
-
---- @param s string
---- @return string
-local lowercase_to_titlecase = function(s)
- return s:sub(1, 1):upper() .. s:sub(2)
-end
-
---- @type vim.option_meta[]
-local options = require('options').options
-
--- Generate BV_ enum constants.
-enum_w('/// "indir" values for buffer-local options.')
-enum_w('/// These need to be defined globally, so that the BV_COUNT can be used with')
-enum_w('/// b_p_script_stx[].')
-enum_w('enum {')
-
-local bv_val = 0
-
-for _, o in ipairs(options) do
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- if min_scope == 'buffer' then
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local bv_name = 'BV_' .. varname:sub(3):upper()
- enum_w((' %s = %u,'):format(bv_name, bv_val))
- bv_val = bv_val + 1
- end
-end
-
-enum_w((' BV_COUNT = %u, ///< must be the last one'):format(bv_val))
-enum_w('};')
-enum_w('')
-
--- Generate WV_ enum constants.
-enum_w('/// "indir" values for window-local options.')
-enum_w('/// These need to be defined globally, so that the WV_COUNT can be used in the')
-enum_w('/// window structure.')
-enum_w('enum {')
-
-local wv_val = 0
-
-for _, o in ipairs(options) do
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- if min_scope == 'window' then
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local wv_name = 'WV_' .. varname:sub(3):upper()
- enum_w((' %s = %u,'):format(wv_name, wv_val))
- wv_val = wv_val + 1
- end
-end
-
-enum_w((' WV_COUNT = %u, ///< must be the last one'):format(wv_val))
-enum_w('};')
-enum_w('')
-
---- @type { [string]: string }
-local option_index = {}
-
--- Generate option index enum and populate the `option_index` dict.
-enum_w('typedef enum {')
-enum_w(' kOptInvalid = -1,')
-
-for i, o in ipairs(options) do
- local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name)
- enum_w((' %s = %u,'):format(enum_val_name, i - 1))
-
- option_index[o.full_name] = enum_val_name
-
- if o.abbreviation then
- option_index[o.abbreviation] = enum_val_name
- end
-
- if o.alias then
- o.alias = type(o.alias) == 'string' and { o.alias } or o.alias
-
- for _, v in ipairs(o.alias) do
- option_index[v] = enum_val_name
- end
- end
-end
-
-enum_w(' // Option count, used when iterating through options')
-enum_w('#define kOptIndexCount ' .. tostring(#options))
-enum_w('} OptIndex;')
-enum_w('')
-
-options_enum_fd:close()
-
---- Generate option index map.
-local hashy = require('generators.hashy')
-local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx)
- return ('option_hash_elems[%s].name'):format(idx)
-end)
-
-map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {')
-
-for _, name in ipairs(neworder) do
- assert(option_index[name] ~= nil)
- map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name]))
-end
-
-map_w('};\n')
-map_w('static ' .. hashfun)
-
-options_map_fd:close()
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 472bc3a850..82abd2888a 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -95,15 +95,15 @@ static FileDescriptor scriptin[NSCRIPT] = { 0 };
#define MINIMAL_SIZE 20 // minimal size for b_str
-static buffheader_T redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
-static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
-static buffheader_T recordbuff = { { NULL, { NUL } }, NULL, 0, 0 };
+static buffheader_T redobuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false };
+static buffheader_T old_redobuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false };
+static buffheader_T recordbuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false };
/// First read ahead buffer. Used for translated commands.
-static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 };
+static buffheader_T readbuf1 = { { NULL, 0, { NUL } }, NULL, 0, 0, false };
/// Second read ahead buffer. Used for redo.
-static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
+static buffheader_T readbuf2 = { { NULL, 0, { NUL } }, NULL, 0, 0, false };
/// Buffer used to store typed characters for vim.on_key().
static kvec_withinit_t(char, MAXMAPLEN + 1) on_key_buf = KVI_INITIAL_VALUE(on_key_buf);
@@ -183,15 +183,17 @@ static void free_buff(buffheader_T *buf)
/// K_SPECIAL in the returned string is escaped.
///
/// @param dozero count == zero is not an error
-static char *get_buffcont(buffheader_T *buffer, int dozero)
+/// @param len the length of the returned buffer
+static char *get_buffcont(buffheader_T *buffer, int dozero, size_t *len)
{
size_t count = 0;
char *p = NULL;
+ size_t i = 0;
// compute the total length of the string
for (const buffblock_T *bp = buffer->bh_first.b_next;
bp != NULL; bp = bp->b_next) {
- count += strlen(bp->b_str);
+ count += bp->b_strlen;
}
if (count > 0 || dozero) {
@@ -204,7 +206,13 @@ static char *get_buffcont(buffheader_T *buffer, int dozero)
}
}
*p2 = NUL;
+ i = (size_t)(p2 - p);
}
+
+ if (len != NULL) {
+ *len = i;
+ }
+
return p;
}
@@ -213,12 +221,12 @@ static char *get_buffcont(buffheader_T *buffer, int dozero)
/// K_SPECIAL in the returned string is escaped.
char *get_recorded(void)
{
- char *p = get_buffcont(&recordbuff, true);
+ size_t len;
+ char *p = get_buffcont(&recordbuff, true, &len);
free_buff(&recordbuff);
// Remove the characters that were added the last time, these must be the
// (possibly mapped) characters that stopped the recording.
- size_t len = strlen(p);
if (len >= last_recorded_len) {
len -= last_recorded_len;
p[len] = NUL;
@@ -237,7 +245,7 @@ char *get_recorded(void)
/// K_SPECIAL in the returned string is escaped.
char *get_inserted(void)
{
- return get_buffcont(&redobuff, false);
+ return get_buffcont(&redobuff, false, NULL);
}
/// Add string after the current block of the given buffer
@@ -257,27 +265,31 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
}
if (buf->bh_first.b_next == NULL) { // first add to list
- buf->bh_space = 0;
buf->bh_curr = &(buf->bh_first);
+ buf->bh_create_newblock = true;
} else if (buf->bh_curr == NULL) { // buffer has already been read
iemsg(_("E222: Add to read buffer"));
return;
} else if (buf->bh_index != 0) {
memmove(buf->bh_first.b_next->b_str,
buf->bh_first.b_next->b_str + buf->bh_index,
- strlen(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
+ (buf->bh_first.b_next->b_strlen - buf->bh_index) + 1);
+ buf->bh_first.b_next->b_strlen -= buf->bh_index;
+ buf->bh_space += buf->bh_index;
}
buf->bh_index = 0;
- if (buf->bh_space >= (size_t)slen) {
- size_t len = strlen(buf->bh_curr->b_str);
- xmemcpyz(buf->bh_curr->b_str + len, s, (size_t)slen);
+ if (!buf->bh_create_newblock && buf->bh_space >= (size_t)slen) {
+ xmemcpyz(buf->bh_curr->b_str + buf->bh_curr->b_strlen, s, (size_t)slen);
+ buf->bh_curr->b_strlen += (size_t)slen;
buf->bh_space -= (size_t)slen;
} else {
size_t len = MAX(MINIMAL_SIZE, (size_t)slen);
buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1);
- buf->bh_space = len - (size_t)slen;
xmemcpyz(p->b_str, s, (size_t)slen);
+ p->b_strlen = (size_t)slen;
+ buf->bh_space = len - (size_t)slen;
+ buf->bh_create_newblock = false;
p->b_next = buf->bh_curr->b_next;
buf->bh_curr->b_next = p;
@@ -292,12 +304,12 @@ static void delete_buff_tail(buffheader_T *buf, int slen)
if (buf->bh_curr == NULL) {
return; // nothing to delete
}
- int len = (int)strlen(buf->bh_curr->b_str);
- if (len < slen) {
+ if (buf->bh_curr->b_strlen < (size_t)slen) {
return;
}
- buf->bh_curr->b_str[len - slen] = NUL;
+ buf->bh_curr->b_str[buf->bh_curr->b_strlen - (size_t)slen] = NUL;
+ buf->bh_curr->b_strlen -= (size_t)slen;
buf->bh_space += (size_t)slen;
}
@@ -305,8 +317,8 @@ static void delete_buff_tail(buffheader_T *buf, int slen)
static void add_num_buff(buffheader_T *buf, int n)
{
char number[32];
- snprintf(number, sizeof(number), "%d", n);
- add_buff(buf, number, -1);
+ int numberlen = snprintf(number, sizeof(number), "%d", n);
+ add_buff(buf, number, numberlen);
}
/// Add byte or special key 'c' to buffer "buf".
@@ -314,17 +326,20 @@ static void add_num_buff(buffheader_T *buf, int n)
static void add_byte_buff(buffheader_T *buf, int c)
{
char temp[4];
+ ptrdiff_t templen;
if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) {
// Translate special key code into three byte sequence.
temp[0] = (char)K_SPECIAL;
temp[1] = (char)K_SECOND(c);
temp[2] = (char)K_THIRD(c);
temp[3] = NUL;
+ templen = 3;
} else {
temp[0] = (char)c;
temp[1] = NUL;
+ templen = 1;
}
- add_buff(buf, temp, -1);
+ add_buff(buf, temp, templen);
}
/// Add character 'c' to buffer "buf".
@@ -385,11 +400,11 @@ static void start_stuff(void)
{
if (readbuf1.bh_first.b_next != NULL) {
readbuf1.bh_curr = &(readbuf1.bh_first);
- readbuf1.bh_space = 0;
+ readbuf1.bh_create_newblock = true; // force a new block to be created (see add_buff())
}
if (readbuf2.bh_first.b_next != NULL) {
readbuf2.bh_curr = &(readbuf2.bh_first);
- readbuf2.bh_space = 0;
+ readbuf2.bh_create_newblock = true; // force a new block to be created (see add_buff())
}
}
@@ -498,12 +513,13 @@ void saveRedobuff(save_redo_T *save_redo)
old_redobuff.bh_first.b_next = NULL;
// Make a copy, so that ":normal ." in a function works.
- char *const s = get_buffcont(&save_redo->sr_redobuff, false);
+ size_t slen;
+ char *const s = get_buffcont(&save_redo->sr_redobuff, false, &slen);
if (s == NULL) {
return;
}
- add_buff(&redobuff, s, -1);
+ add_buff(&redobuff, s, (ptrdiff_t)slen);
xfree(s);
}
@@ -1772,7 +1788,9 @@ int vgetc(void)
// Execute Lua on_key callbacks.
kvi_push(on_key_buf, NUL);
- nlua_execute_on_key(c, on_key_buf.items);
+ if (nlua_execute_on_key(c, on_key_buf.items)) {
+ c = K_IGNORE;
+ }
kvi_destroy(on_key_buf);
kvi_init(on_key_buf);
@@ -1919,9 +1937,9 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
i += utf_char2bytes((int)n, temp + i);
}
assert(i < 10);
- temp[i++] = NUL;
+ temp[i] = NUL;
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xstrdup(temp);
+ rettv->vval.v_string = xmemdupz(temp, (size_t)i);
if (is_mouse_key((int)n)) {
int row = mouse_row;
@@ -1974,9 +1992,9 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
i += utf_char2bytes((int)n, temp);
}
assert(i < 7);
- temp[i++] = NUL;
+ temp[i] = NUL;
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xstrdup(temp);
+ rettv->vval.v_string = xmemdupz(temp, (size_t)i);
}
/// "getcharmod()" function
@@ -2371,7 +2389,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
buf[1] = (char)KS_EXTRA;
buf[2] = KE_IGNORE;
buf[3] = NUL;
- map_str = xstrdup(buf);
+ map_str = xmemdupz(buf, 3);
if (State & MODE_CMDLINE) {
// redraw the command below the error
msg_didout = true;
diff --git a/src/nvim/getchar_defs.h b/src/nvim/getchar_defs.h
index abf812fad3..fdfd0a9942 100644
--- a/src/nvim/getchar_defs.h
+++ b/src/nvim/getchar_defs.h
@@ -9,6 +9,7 @@
/// structure used to store one block of the stuff/redo/recording buffers
typedef struct buffblock {
struct buffblock *b_next; ///< pointer to next buffblock
+ size_t b_strlen; ///< length of b_str, excluding the NUL
char b_str[1]; ///< contents (actually longer)
} buffblock_T;
@@ -18,6 +19,7 @@ typedef struct {
buffblock_T *bh_curr; ///< buffblock for appending
size_t bh_index; ///< index for reading
size_t bh_space; ///< space in bh_curr for appending
+ bool bh_create_newblock; ///< create a new block?
} buffheader_T;
typedef struct {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 45a31ce6b0..472b77ccbe 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -156,7 +156,7 @@ EXTERN bool msg_scrolled_ign INIT( = false);
EXTERN bool msg_did_scroll INIT( = false);
EXTERN char *keep_msg INIT( = NULL); // msg to be shown after redraw
-EXTERN int keep_msg_attr INIT( = 0); // highlight attr for keep_msg
+EXTERN int keep_msg_hl_id INIT( = 0); // highlight id for keep_msg
EXTERN bool need_fileinfo INIT( = false); // do fileinfo() after redraw
EXTERN int msg_scroll INIT( = false); // msg_start() will scroll
EXTERN bool msg_didout INIT( = false); // msg_outstr() was used in line
@@ -713,12 +713,6 @@ EXTERN char *escape_chars INIT( = " \t\\\"|"); // need backslash in cmd line
EXTERN bool keep_help_flag INIT( = false); // doing :ta from help file
-// When a string option is NULL (which only happens in out-of-memory situations), it is set to
-// empty_string_option, to avoid having to check for NULL everywhere.
-//
-// TODO(famiu): Remove this when refcounted strings are used for string options.
-EXTERN char *empty_string_option INIT( = "");
-
EXTERN bool redir_off INIT( = false); // no redirection for a moment
EXTERN FILE *redir_fd INIT( = NULL); // message redirection file
EXTERN int redir_reg INIT( = 0); // message redirection register
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index ac67f42fe0..8fa3092fd6 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -7,10 +7,6 @@
#include "nvim/pos_defs.h"
#include "nvim/types_defs.h"
-// Includes final NUL. MAX_MCO is no longer used, but at least 4*(MAX_MCO+1)+1=29
-// ensures we can fit all composed chars which did fit before.
-#define MAX_SCHAR_SIZE 32
-
enum {
kZIndexDefaultGrid = 0,
kZIndexFloatDefault = 50,
@@ -80,8 +76,8 @@ struct ScreenGrid {
// whether the compositor should blend the grid with the background grid
bool blending;
- // whether the grid can be focused with mouse clicks.
- bool focusable;
+ // whether the grid interacts with mouse events.
+ bool mouse_enabled;
// z-index: the order in the stack of grids.
int zindex;
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index d39ffcd177..5f0a2e0e4e 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -48,7 +48,7 @@ static Set(cstr_t) urls = SET_INIT;
/// highlight entries private to a namespace
static Map(ColorKey, ColorItem) ns_hls;
-typedef int NSHlAttr[HLF_COUNT + 1];
+typedef int NSHlAttr[HLF_COUNT];
static PMap(int) ns_hl_attr;
void highlight_init(void)
@@ -371,8 +371,8 @@ void update_window_hl(win_T *wp, bool invalid)
bool float_win = wp->w_floating && !wp->w_config.external;
if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) {
wp->w_hl_attr_normal = hl_def[HLF_NFLOAT];
- } else if (hl_def[HLF_COUNT] > 0) {
- wp->w_hl_attr_normal = hl_def[HLF_COUNT];
+ } else if (hl_def[HLF_NONE] > 0) {
+ wp->w_hl_attr_normal = hl_def[HLF_NONE];
} else if (float_win) {
wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0
? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT];
@@ -433,7 +433,7 @@ void update_ns_hl(int ns_id)
}
int *hl_attrs = **alloc;
- for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
+ for (int hlf = 1; hlf < HLF_COUNT; hlf++) {
int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf]));
bool optional = (hlf == HLF_INACTIVE || hlf == HLF_NFLOAT);
hl_attrs[hlf] = hl_get_ui_attr(ns_id, hlf, id, optional);
@@ -444,7 +444,7 @@ void update_ns_hl(int ns_id)
//
// haha, tema engine go brrr
int normality = syn_check_group(S_LEN("Normal"));
- hl_attrs[HLF_COUNT] = hl_get_ui_attr(ns_id, -1, normality, true);
+ hl_attrs[HLF_NONE] = hl_get_ui_attr(ns_id, -1, normality, true);
// hl_get_ui_attr might have invalidated the decor provider
p = get_decor_provider(ns_id, true);
@@ -461,7 +461,7 @@ int win_bg_attr(win_T *wp)
}
if (wp == curwin || hl_attr_active[HLF_INACTIVE] == 0) {
- return hl_attr_active[HLF_COUNT];
+ return hl_attr_active[HLF_NONE];
} else {
return hl_attr_active[HLF_INACTIVE];
}
diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h
index 2ba6cf5371..1be70100de 100644
--- a/src/nvim/highlight.h
+++ b/src/nvim/highlight.h
@@ -84,7 +84,7 @@ EXTERN const char *hlf_names[] INIT( = {
[HLF_TSNC] = "StatusLineTermNC",
});
-EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context.
+EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index e0cce81166..a3c4062714 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -58,7 +58,8 @@ typedef struct {
/// Values for index in highlight_attr[].
/// When making changes, also update hlf_names in highlight.h!
typedef enum {
- HLF_8 = 0, ///< Meta & special keys listed with ":map", text that is
+ HLF_NONE = 0, ///< no UI highlight active
+ HLF_8, ///< Meta & special keys listed with ":map", text that is
///< displayed different from what it is
HLF_EOB, ///< after the last line in the buffer
HLF_TERM, ///< terminal cursor focused
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 1a0ae3ac49..b3c4aca1af 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -144,6 +144,8 @@ static const char e_missing_argument_str[]
static const char *highlight_init_both[] = {
"Cursor guifg=bg guibg=fg",
"CursorLineNr gui=bold cterm=bold",
+ "PmenuMatch gui=bold cterm=bold",
+ "PmenuMatchSel gui=bold cterm=bold",
"PmenuSel gui=reverse cterm=reverse,underline blend=0",
"RedrawDebugNormal gui=reverse cterm=reverse",
"TabLineSel gui=bold cterm=bold",
@@ -170,8 +172,6 @@ static const char *highlight_init_both[] = {
"default link PmenuExtraSel PmenuSel",
"default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel",
- "default link PmenuMatch Pmenu",
- "default link PmenuMatchSel PmenuSel",
"default link PmenuSbar Pmenu",
"default link Substitute Search",
"default link StatusLineTerm StatusLine",
@@ -215,6 +215,7 @@ static const char *highlight_init_both[] = {
"default link LspReferenceRead LspReferenceText",
"default link LspReferenceText Visual",
"default link LspReferenceWrite LspReferenceText",
+ "default link LspReferenceTarget LspReferenceText",
"default link LspSignatureActiveParameter Visual",
"default link SnippetTabstop Visual",
@@ -1621,9 +1622,9 @@ static void highlight_list_one(const int id)
if (sgp->sg_link && !got_int) {
syn_list_header(didh, 0, id, true);
didh = true;
- msg_puts_attr("links to", HL_ATTR(HLF_D));
+ msg_puts_hl("links to", HLF_D, false);
msg_putchar(' ');
- msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name, 0);
+ msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name, 0, false);
}
if (!didh) {
@@ -1751,10 +1752,10 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg
didh = true;
if (!got_int) {
if (*name != NUL) {
- msg_puts_attr(name, HL_ATTR(HLF_D));
- msg_puts_attr("=", HL_ATTR(HLF_D));
+ msg_puts_hl(name, HLF_D, false);
+ msg_puts_hl("=", HLF_D, false);
}
- msg_outtrans(ts, 0);
+ msg_outtrans(ts, 0, false);
}
return didh;
}
@@ -1884,7 +1885,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool
if (got_int) {
return true;
}
- msg_outtrans(hl_table[id - 1].sg_name, 0);
+ msg_outtrans(hl_table[id - 1].sg_name, 0, false);
name_col = msg_col;
endcol = 15;
} else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
@@ -1915,7 +1916,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool
if (endcol == Columns - 1 && endcol <= name_col) {
msg_putchar(' ');
}
- msg_puts_attr("xxx", syn_id2attr(id));
+ msg_puts_hl("xxx", id, false);
msg_putchar(' ');
}
@@ -2047,7 +2048,7 @@ static int syn_add_group(const char *name, size_t len)
return 0;
} else if (!ASCII_ISALNUM(c) && c != '_' && c != '.' && c != '@' && c != '-') {
// '.' and '@' are allowed characters for use with treesitter capture names.
- msg_source(HL_ATTR(HLF_W));
+ msg_source(HLF_W);
emsg(_(e_highlight_group_name_invalid_char));
return 0;
}
@@ -2246,8 +2247,11 @@ void highlight_changed(void)
need_highlight_changed = false;
+ // sentinel value. used when no highlight is active
+ highlight_attr[HLF_NONE] = 0;
+
/// Translate builtin highlight groups into attributes for quick lookup.
- for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
+ for (int hlf = 1; hlf < HLF_COUNT; hlf++) {
int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf]));
if (id == 0) {
abort();
@@ -2275,9 +2279,6 @@ void highlight_changed(void)
}
}
- // sentinel value. used when no highlight namespace is active
- highlight_attr[HLF_COUNT] = 0;
-
// Setup the user highlights
//
// Temporarily utilize 10 more hl entries:
@@ -2361,16 +2362,16 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
static void highlight_list(void)
{
for (int i = 10; --i >= 0;) {
- highlight_list_two(i, HL_ATTR(HLF_D));
+ highlight_list_two(i, HLF_D);
}
for (int i = 40; --i >= 0;) {
highlight_list_two(99, 0);
}
}
-static void highlight_list_two(int cnt, int attr)
+static void highlight_list_two(int cnt, int id)
{
- msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr);
+ msg_puts_hl(&("N \bI \b! \b"[cnt / 11]), id, false);
msg_clr_eos();
ui_flush();
os_delay(cnt == 99 ? 40 : (uint64_t)cnt * 50, false);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index b7e3842aad..e487728901 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -769,9 +769,15 @@ int get_number_indent(linenr_T lnum)
return (int)col;
}
+/// Check "briopt" as 'breakindentopt' and update the members of "wp".
/// This is called when 'breakindentopt' is changed and when a window is
/// initialized
-bool briopt_check(win_T *wp)
+///
+/// @param briopt when NULL: use "wp->w_p_briopt"
+/// @param wp when NULL: only check "briopt"
+///
+/// @return FAIL for failure, OK otherwise.
+bool briopt_check(char *briopt, win_T *wp)
{
int bri_shift = 0;
int bri_min = 20;
@@ -779,7 +785,13 @@ bool briopt_check(win_T *wp)
int bri_list = 0;
int bri_vcol = 0;
- char *p = wp->w_p_briopt;
+ char *p = empty_string_option;
+ if (briopt != NULL) {
+ p = briopt;
+ } else if (wp != NULL) {
+ p = wp->w_p_briopt;
+ }
+
while (*p != NUL) {
// Note: Keep this in sync with p_briopt_values
if (strncmp(p, "shift:", 6) == 0
@@ -807,6 +819,10 @@ bool briopt_check(win_T *wp)
}
}
+ if (wp == NULL) {
+ return OK;
+ }
+
wp->w_briopt_shift = bri_shift;
wp->w_briopt_min = bri_min;
wp->w_briopt_sbr = bri_sbr;
@@ -1166,7 +1182,7 @@ int get_expr_indent(void)
sandbox++;
}
textlock++;
- current_sctx = curbuf->b_p_script_ctx[BV_INDE].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr].script_ctx;
// Need to make a copy, the 'indentexpr' option could be changed while
// evaluating it.
diff --git a/src/nvim/input.c b/src/nvim/input.c
index ef400710fe..3d3240c59f 100644
--- a/src/nvim/input.c
+++ b/src/nvim/input.c
@@ -55,7 +55,7 @@ int ask_yesno(const char *const str, const bool direct)
int r = ' ';
while (r != 'y' && r != 'n') {
// same highlighting as for wait_return()
- smsg(HL_ATTR(HLF_R), "%s (y/n)?", str);
+ smsg(HLF_R, "%s (y/n)?", str);
if (direct) {
r = get_keystroke(NULL);
} else {
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 84dd55fa78..bd7ee55722 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -164,7 +164,7 @@ struct compl_S {
int cp_flags; ///< CP_ values
int cp_number; ///< sequence number
int cp_score; ///< fuzzy match score
- int cp_user_hlattr; ///< highlight attribute to combine with
+ int cp_user_abbr_hlattr; ///< highlight attribute for abbr
int cp_user_kind_hlattr; ///< highlight attribute for kind
};
@@ -473,7 +473,7 @@ bool check_compl_option(bool dict_opt)
ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
msg((dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")),
- HL_ATTR(HLF_E));
+ HLF_E);
if (emsg_silent == 0 && !in_assert_fails) {
vim_beep(BO_COMPL);
setcursor();
@@ -798,7 +798,7 @@ static inline void free_cptext(char *const *const cptext)
/// returned in case of error.
static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext,
const bool cptext_allocated, typval_T *user_data, const Direction cdir,
- int flags_arg, const bool adup, int user_hlattr, int user_kind_hlattr)
+ int flags_arg, const bool adup, int user_abbr_hlattr, int user_kind_hlattr)
FUNC_ATTR_NONNULL_ARG(1)
{
compl_T *match;
@@ -864,7 +864,7 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match->cp_fname = NULL;
}
match->cp_flags = flags;
- match->cp_user_hlattr = user_hlattr;
+ match->cp_user_abbr_hlattr = user_abbr_hlattr;
match->cp_user_kind_hlattr = user_kind_hlattr;
if (cptext != NULL) {
@@ -1268,7 +1268,7 @@ static int ins_compl_build_pum(void)
compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
compl_match_array[i].pum_score = comp->cp_score;
- compl_match_array[i].pum_user_hlattr = comp->cp_user_hlattr;
+ compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr;
compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr;
if (comp->cp_text[CPT_MENU] != NULL) {
compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
@@ -1564,7 +1564,7 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags,
msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE,
_("Scanning dictionary: %s"), files[i]);
- msg_trunc(IObuff, true, HL_ATTR(HLF_R));
+ msg_trunc(IObuff, true, HLF_R);
}
if (fp == NULL) {
@@ -2368,13 +2368,13 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb)
/// Invoked when the 'completefunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-const char *did_set_completefunc(optset_T *args FUNC_ATTR_UNUSED)
+const char *did_set_completefunc(optset_T *args)
{
- if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) {
+ buf_T *buf = (buf_T *)args->os_buf;
+ if (option_set_callback_func(buf->b_p_cfu, &cfu_cb) == FAIL) {
return e_invarg;
}
-
- set_buflocal_cfu_callback(curbuf);
+ set_buflocal_cfu_callback(buf);
return NULL;
}
@@ -2412,14 +2412,19 @@ void set_buflocal_ofu_callback(buf_T *buf)
/// lambda expression.
const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED)
{
+ buf_T *buf = (buf_T *)args->os_buf;
int retval;
- if (*curbuf->b_p_tsrfu != NUL) {
+ if (args->os_flags & OPT_LOCAL) {
// buffer-local option set
- retval = option_set_callback_func(curbuf->b_p_tsrfu, &curbuf->b_tsrfu_cb);
+ retval = option_set_callback_func(buf->b_p_tsrfu, &buf->b_tsrfu_cb);
} else {
// global option set
retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
+ // when using :set, free the local callback
+ if (!(args->os_flags & OPT_GLOBAL)) {
+ callback_free(&buf->b_tsrfu_cb);
+ }
}
return retval == FAIL ? e_invarg : NULL;
@@ -2567,9 +2572,9 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
bool empty = false;
int flags = fast ? CP_FAST : 0;
char *(cptext[CPT_COUNT]);
- char *user_hlname = NULL;
+ char *user_abbr_hlname = NULL;
+ int user_abbr_hlattr = -1;
char *user_kind_hlname = NULL;
- int user_hlattr = -1;
int user_kind_hlattr = -1;
typval_T user_data;
@@ -2581,8 +2586,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
- user_hlname = tv_dict_get_string(tv->vval.v_dict, "hl_group", false);
- user_hlattr = get_user_highlight_attr(user_hlname);
+ user_abbr_hlname = tv_dict_get_string(tv->vval.v_dict, "abbr_hlgroup", false);
+ user_abbr_hlattr = get_user_highlight_attr(user_abbr_hlname);
user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false);
user_kind_hlattr = get_user_highlight_attr(user_kind_hlname);
@@ -2608,7 +2613,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
return FAIL;
}
int status = ins_compl_add((char *)word, -1, NULL, cptext, true,
- &user_data, dir, flags, dup, user_hlattr, user_kind_hlattr);
+ &user_data, dir, flags, dup,
+ user_abbr_hlattr, user_kind_hlattr);
if (status != OK) {
tv_clear(&user_data);
}
@@ -3040,7 +3046,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
: st->ins_buf->b_sfname == NULL
? st->ins_buf->b_fname
: st->ins_buf->b_sfname);
- msg_trunc(IObuff, true, HL_ATTR(HLF_R));
+ msg_trunc(IObuff, true, HLF_R);
}
} else if (*st->e_cpt == NUL) {
status = INS_COMPL_CPT_END;
@@ -3068,7 +3074,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
if (!shortmess(SHM_COMPLETIONSCAN)) {
msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags."));
- msg_trunc(IObuff, true, HL_ATTR(HLF_R));
+ msg_trunc(IObuff, true, HLF_R);
}
}
@@ -4562,7 +4568,7 @@ static void ins_compl_show_statusmsg(void)
if (!p_smd) {
msg_hist_off = true;
msg(edit_submode_extra, (edit_submode_highl < HLF_COUNT
- ? HL_ATTR(edit_submode_highl) : 0));
+ ? (int)edit_submode_highl + 1 : 0));
msg_hist_off = false;
}
} else {
diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c
index 8943e6e8a6..39dfb8eeb9 100644
--- a/src/nvim/linematch.c
+++ b/src/nvim/linematch.c
@@ -150,7 +150,9 @@ static int count_n_matched_chars(mmfile_t **sp, const size_t n, bool iwhite)
mmfile_t fastforward_buf_to_lnum(mmfile_t s, linenr_T lnum)
{
for (int i = 0; i < lnum - 1; i++) {
- s.ptr = strnchr(s.ptr, (size_t *)&s.size, '\n');
+ size_t n = (size_t)s.size;
+ s.ptr = strnchr(s.ptr, &n, '\n');
+ s.size = (int)n;
if (!s.ptr) {
break;
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index d4940f3add..c4fa8b0fff 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -187,7 +187,7 @@ static void nlua_luv_error_event(void **argv)
msg_ext_set_kind("lua_error");
switch (type) {
case kCallback:
- semsg_multiline("Error executing luv callback:\n%s", error);
+ semsg_multiline("Error executing callback:\n%s", error);
break;
case kThread:
semsg_multiline("Error in luv thread:\n%s", error);
@@ -201,13 +201,13 @@ static void nlua_luv_error_event(void **argv)
xfree(error);
}
-static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags)
+/// Execute callback in "fast" context. Used for luv and some vim.ui_event
+/// callbacks where using the API directly is not safe.
+static int nlua_fast_cfpcall(lua_State *lstate, int nargs, int nresult, int flags)
FUNC_ATTR_NONNULL_ALL
{
int retval;
- // luv callbacks might be executed at any os_breakcheck/line_breakcheck
- // call, so using the API directly here is not safe.
in_fast_callback++;
int top = lua_gettop(lstate);
@@ -366,11 +366,13 @@ static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg
static void nlua_schedule_event(void **argv)
{
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
+ uint32_t ns_id = (uint32_t)(ptrdiff_t)argv[1];
lua_State *const lstate = global_lstate;
nlua_pushref(lstate, cb);
nlua_unref_global(lstate, cb);
if (nlua_pcall(lstate, 0, 0)) {
nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s"));
+ ui_remove_cb(ns_id, true);
}
}
@@ -392,8 +394,9 @@ static int nlua_schedule(lua_State *const lstate)
}
LuaRef cb = nlua_ref_global(lstate, 1);
-
- multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb);
+ // Pass along UI event handler to disable on error.
+ multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb,
+ (void *)(ptrdiff_t)ui_event_ns_id);
return 0;
}
@@ -425,7 +428,7 @@ static int nlua_wait(lua_State *lstate)
FUNC_ATTR_NONNULL_ALL
{
if (in_fast_callback) {
- return luaL_error(lstate, e_luv_api_disabled, "vim.wait");
+ return luaL_error(lstate, e_fast_api_disabled, "vim.wait");
}
intptr_t timeout = luaL_checkinteger(lstate, 1);
@@ -598,7 +601,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan
luv_set_cthread(lstate, nlua_luv_thread_cfcpcall);
} else {
luv_set_loop(lstate, &main_loop.uv);
- luv_set_callback(lstate, nlua_luv_cfpcall);
+ luv_set_callback(lstate, nlua_fast_cfpcall);
}
luaopen_luv(lstate);
lua_pushvalue(lstate, -1);
@@ -724,7 +727,7 @@ static int nlua_ui_detach(lua_State *lstate)
return luaL_error(lstate, "invalid ns_id");
}
- ui_remove_cb(ns_id);
+ ui_remove_cb(ns_id, false);
return 0;
}
@@ -951,41 +954,10 @@ static void nlua_common_free_all_mem(lua_State *lstate)
static void nlua_print_event(void **argv)
{
- char *str = argv[0];
- const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL
-
- for (size_t i = 0; i < len;) {
- if (got_int) {
- break;
- }
- const size_t start = i;
- while (i < len) {
- switch (str[i]) {
- case NUL:
- str[i] = NL;
- i++;
- continue;
- case NL:
- // TODO(bfredl): use proper multiline msg? Probably should implement
- // print() in lua in terms of nvim_message(), when it is available.
- str[i] = NUL;
- i++;
- break;
- default:
- i++;
- continue;
- }
- break;
- }
- msg(str + start, 0);
- if (msg_silent == 0) {
- msg_didout = true; // Make blank lines work properly
- }
- }
- if (len && str[len - 1] == NUL) { // Last was newline
- msg("", 0);
- }
- xfree(str);
+ HlMessage msg = KV_INITIAL_VALUE;
+ HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 };
+ kv_push(msg, chunk);
+ msg_multihl(msg, "lua_print", true);
}
/// Print as a Vim message
@@ -1174,7 +1146,7 @@ int nlua_call(lua_State *lstate)
size_t name_len;
const char *name = luaL_checklstring(lstate, 1, &name_len);
if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) {
- return luaL_error(lstate, e_luv_api_disabled, "Vimscript function");
+ return luaL_error(lstate, e_fast_api_disabled, "Vimscript function");
}
int nargs = lua_gettop(lstate) - 1;
@@ -1231,7 +1203,7 @@ free_vim_args:
static int nlua_rpcrequest(lua_State *lstate)
{
if (!nlua_is_deferred_safe()) {
- return luaL_error(lstate, e_luv_api_disabled, "rpcrequest");
+ return luaL_error(lstate, e_fast_api_disabled, "rpcrequest");
}
return nlua_rpc(lstate, true);
}
@@ -1594,6 +1566,12 @@ bool nlua_ref_is_function(LuaRef ref)
Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, Arena *arena,
Error *err)
{
+ return nlua_call_ref_ctx(false, ref, name, args, mode, arena, err);
+}
+
+Object nlua_call_ref_ctx(bool fast, LuaRef ref, const char *name, Array args, LuaRetMode mode,
+ Arena *arena, Error *err)
+{
lua_State *const lstate = global_lstate;
nlua_pushref(lstate, ref);
int nargs = (int)args.size;
@@ -1605,7 +1583,13 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode,
nlua_push_Object(lstate, &args.items[i], 0);
}
- if (nlua_pcall(lstate, nargs, 1)) {
+ if (fast) {
+ if (nlua_fast_cfpcall(lstate, nargs, 1, -1) < 0) {
+ // error is already scheduled, set anyways to convey failure.
+ api_set_error(err, kErrorTypeException, "fast context failure");
+ }
+ return NIL;
+ } else if (nlua_pcall(lstate, nargs, 1)) {
// if err is passed, the caller will deal with the error.
if (err) {
size_t len;
@@ -2063,8 +2047,16 @@ char *nlua_register_table_as_callable(const typval_T *const arg)
return name;
}
-void nlua_execute_on_key(int c, char *typed_buf)
+/// @return true to discard the key
+bool nlua_execute_on_key(int c, char *typed_buf)
{
+ static bool recursive = false;
+
+ if (recursive) {
+ return false;
+ }
+ recursive = true;
+
char buf[MB_MAXBYTES * 3 + 4];
size_t buf_len = special_to_buf(c, mod_mask, false, buf);
vim_unescape_ks(typed_buf);
@@ -2090,9 +2082,15 @@ void nlua_execute_on_key(int c, char *typed_buf)
int save_got_int = got_int;
got_int = false; // avoid interrupts when the key typed is Ctrl-C
- if (nlua_pcall(lstate, 2, 0)) {
- nlua_error(lstate,
- _("Error executing vim.on_key Lua callback: %.*s"));
+ bool discard = false;
+ // Do not use nlua_pcall here to avoid duplicate stack trace information
+ if (lua_pcall(lstate, 2, 1, 0)) {
+ nlua_error(lstate, _("Error executing vim.on_key() callbacks: %.*s"));
+ } else {
+ if (lua_isboolean(lstate, -1)) {
+ discard = lua_toboolean(lstate, -1);
+ }
+ lua_pop(lstate, 1);
}
got_int |= save_got_int;
@@ -2103,6 +2101,9 @@ void nlua_execute_on_key(int c, char *typed_buf)
// [ ]
assert(top == lua_gettop(lstate));
#endif
+
+ recursive = false;
+ return discard;
}
// Sets the editor "script context" during Lua execution. Used by :verbose.
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index ee0eabbebb..e719d99640 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -181,7 +181,9 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
} else {
idx = luaL_checkinteger(lstate, 2);
if (idx < 0 || idx > (intptr_t)s1_len) {
- return luaL_error(lstate, "index out of range");
+ lua_pushnil(lstate);
+ lua_pushnil(lstate);
+ return 2;
}
}
@@ -272,7 +274,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
intptr_t idx = luaL_checkinteger(lstate, 2);
if (idx < 0) {
- return luaL_error(lstate, "index out of range");
+ lua_pushnil(lstate);
+ return 1;
}
bool use_utf16 = false;
if (lua_gettop(lstate) >= 3) {
@@ -281,7 +284,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
ssize_t byteidx = mb_utf_index_to_bytes(s1, s1_len, (size_t)idx, use_utf16);
if (byteidx == -1) {
- return luaL_error(lstate, "index out of range");
+ lua_pushnil(lstate);
+ return 1;
}
lua_pushinteger(lstate, (lua_Integer)byteidx);
@@ -695,10 +699,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
lua_setfield(lstate, -2, "stricmp");
// str_utfindex
lua_pushcfunction(lstate, &nlua_str_utfindex);
- lua_setfield(lstate, -2, "str_utfindex");
+ lua_setfield(lstate, -2, "_str_utfindex");
// str_byteindex
lua_pushcfunction(lstate, &nlua_str_byteindex);
- lua_setfield(lstate, -2, "str_byteindex");
+ lua_setfield(lstate, -2, "_str_byteindex");
// str_utf_pos
lua_pushcfunction(lstate, &nlua_str_utf_pos);
lua_setfield(lstate, -2, "str_utf_pos");
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index ab97704dfe..c80e7b7672 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -271,12 +271,16 @@ int tslua_inspect_lang(lua_State *L)
// not used by the API
continue;
}
- lua_createtable(L, 2, 0); // [retval, symbols, elem]
- lua_pushstring(L, ts_language_symbol_name(lang, (TSSymbol)i));
- lua_rawseti(L, -2, 1);
- lua_pushboolean(L, t == TSSymbolTypeRegular);
- lua_rawseti(L, -2, 2); // [retval, symbols, elem]
- lua_rawseti(L, -2, (int)i); // [retval, symbols]
+ const char *name = ts_language_symbol_name(lang, (TSSymbol)i);
+ bool named = t != TSSymbolTypeAnonymous;
+ lua_pushboolean(L, named); // [retval, symbols, is_named]
+ if (!named) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "\"%s\"", name);
+ lua_setfield(L, -2, buf); // [retval, symbols]
+ } else {
+ lua_setfield(L, -2, name); // [retval, symbols]
+ }
}
lua_setfield(L, -2, "symbols"); // [retval]
@@ -828,6 +832,7 @@ static struct luaL_Reg node_meta[] = {
{ "parent", node_parent },
{ "__has_ancestor", __has_ancestor },
{ "child_containing_descendant", node_child_containing_descendant },
+ { "child_with_descendant", node_child_with_descendant },
{ "iter_children", node_iter_children },
{ "next_sibling", node_next_sibling },
{ "prev_sibling", node_prev_sibling },
@@ -1146,7 +1151,7 @@ static int __has_ancestor(lua_State *L)
int const pred_len = (int)lua_objlen(L, 2);
TSNode node = ts_tree_root_node(descendant.tree);
- while (!ts_node_is_null(node)) {
+ while (node.id != descendant.id && !ts_node_is_null(node)) {
char const *node_type = ts_node_type(node);
size_t node_type_len = strlen(node_type);
@@ -1163,7 +1168,7 @@ static int __has_ancestor(lua_State *L)
lua_pop(L, 1);
}
- node = ts_node_child_containing_descendant(node, descendant);
+ node = ts_node_child_with_descendant(node, descendant);
}
lua_pushboolean(L, false);
@@ -1179,6 +1184,15 @@ static int node_child_containing_descendant(lua_State *L)
return 1;
}
+static int node_child_with_descendant(lua_State *L)
+{
+ TSNode node = node_check(L, 1);
+ TSNode descendant = node_check(L, 2);
+ TSNode child = ts_node_child_with_descendant(node, descendant);
+ push_node(L, child, 1);
+ return 1;
+}
+
static int node_next_sibling(lua_State *L)
{
TSNode node = node_check(L, 1);
@@ -1514,10 +1528,25 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err
|| error_type == TSQueryErrorField
|| error_type == TSQueryErrorCapture) {
const char *suffix = src + error_offset;
+ bool is_anonymous = error_type == TSQueryErrorNodeType && suffix[-1] == '"';
int suffix_len = 0;
char c = suffix[suffix_len];
- while (isalnum(c) || c == '_' || c == '-' || c == '.') {
- c = suffix[++suffix_len];
+ if (is_anonymous) {
+ int backslashes = 0;
+ // Stop when we hit an unescaped double quote
+ while (c != '"' || backslashes % 2 != 0) {
+ if (c == '\\') {
+ backslashes += 1;
+ } else {
+ backslashes = 0;
+ }
+ c = suffix[++suffix_len];
+ }
+ } else {
+ // Stop when we hit the end of the identifier
+ while (isalnum(c) || c == '_' || c == '-' || c == '.') {
+ c = suffix[++suffix_len];
+ }
}
snprintf(err, errlen, "\"%.*s\":\n", suffix_len, suffix);
offset = strlen(err);
diff --git a/src/nvim/main.c b/src/nvim/main.c
index dc102f6f6d..695bd4c95a 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -678,12 +678,14 @@ void os_exit(int r)
} else {
ui_flush();
ui_call_stop();
- ml_close_all(true); // remove all memfiles
}
if (!event_teardown() && r == 0) {
r = 1; // Exit with error if main_loop did not teardown gracefully.
}
+ if (!ui_client_channel_id) {
+ ml_close_all(true); // remove all memfiles
+ }
if (used_stdin) {
stream_set_blocking(STDIN_FILENO, true); // normalize stream (#2598)
}
@@ -775,7 +777,11 @@ void getout(int exitval)
}
}
- if (p_shada && *p_shada != NUL) {
+ if (
+#ifdef EXITFREE
+ !entered_free_all_mem &&
+#endif
+ p_shada && *p_shada != NUL) {
// Write out the registers, history, marks etc, to the ShaDa file
shada_write_file(NULL, false);
}
@@ -1448,7 +1454,7 @@ scripterror:
p = r;
}
-#ifdef USE_FNAME_CASE
+#ifdef CASE_INSENSITIVE_FILENAME
// Make the case of the file name match the actual file.
path_fix_case(p);
#endif
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index e055ebc2fa..1a6b2c3581 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -239,9 +239,9 @@ static void showmap(mapblock_T *mp, bool local)
} while (len < 12);
if (mp->m_noremap == REMAP_NONE) {
- msg_puts_attr("*", HL_ATTR(HLF_8));
+ msg_puts_hl("*", HLF_8, false);
} else if (mp->m_noremap == REMAP_SCRIPT) {
- msg_puts_attr("&", HL_ATTR(HLF_8));
+ msg_puts_hl("&", HLF_8, false);
} else {
msg_putchar(' ');
}
@@ -256,10 +256,10 @@ static void showmap(mapblock_T *mp, bool local)
// the rhs, and not M-x etc, true gets both -- webb
if (mp->m_luaref != LUA_NOREF) {
char *str = nlua_funcref_str(mp->m_luaref, NULL);
- msg_puts_attr(str, HL_ATTR(HLF_8));
+ msg_puts_hl(str, HLF_8, false);
xfree(str);
} else if (mp->m_str[0] == NUL) {
- msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
+ msg_puts_hl("<Nop>", HLF_8, false);
} else {
msg_outtrans_special(mp->m_str, false, 0);
}
@@ -568,6 +568,12 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr;
mapblock_T *mp_result[2] = { NULL, NULL };
+ bool unmap_lhs_only = false;
+ if (maptype == MAPTYPE_UNMAP_LHS) {
+ unmap_lhs_only = true;
+ maptype = MAPTYPE_UNMAP;
+ }
+
// For ":noremap" don't remap, otherwise do remap.
int noremap = args->script ? REMAP_SCRIPT
: maptype == MAPTYPE_NOREMAP ? REMAP_NONE : REMAP_YES;
@@ -720,8 +726,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
// entry with a matching 'to' part. This was done to allow ":ab foo bar"
// to be unmapped by typing ":unab foo", where "foo" will be replaced by
// "bar" because of the abbreviation.
- for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
- && !did_it && !got_int; round++) {
+ const int num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1;
+ for (int round = 0; round < num_rounds && !did_it && !got_int; round++) {
int hash_start, hash_end;
if ((round == 0 && has_lhs) || is_abbrev) {
// just use one hash
@@ -935,9 +941,11 @@ theend:
/// for :cabbr mode is MODE_CMDLINE
/// ```
///
-/// @param maptype MAPTYPE_MAP for |:map|
-/// MAPTYPE_UNMAP for |:unmap|
-/// MAPTYPE_NOREMAP for |:noremap|.
+/// @param maptype MAPTYPE_MAP for |:map| or |:abbr|
+/// MAPTYPE_UNMAP for |:unmap| or |:unabbr|
+/// MAPTYPE_NOREMAP for |:noremap| or |:noreabbr|
+/// MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match
+/// with {rhs} if there is no match with {lhs}.
/// @param arg C-string containing the arguments of the map/abbrev
/// command, i.e. everything except the initial `:[X][nore]map`.
/// - Cannot be a read-only string; it will be modified.
@@ -2348,7 +2356,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
MapArguments unmap_args = MAP_ARGUMENTS_INIT;
set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, p_cpo, &unmap_args);
unmap_args.buffer = buffer;
- buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, is_abbr, curbuf);
+ buf_do_map(MAPTYPE_UNMAP_LHS, &unmap_args, mode, is_abbr, curbuf);
xfree(unmap_args.rhs);
xfree(unmap_args.orig_rhs);
@@ -2649,7 +2657,7 @@ void ex_map(exarg_T *eap)
// If we are in a secure mode we print the mappings for security reasons.
if (secure) {
secure = 2;
- msg_outtrans(eap->cmd, 0);
+ msg_outtrans(eap->cmd, 0, false);
msg_putchar('\n');
}
do_exmap(eap, false);
diff --git a/src/nvim/mapping.h b/src/nvim/mapping.h
index b82117ea86..fc120b683c 100644
--- a/src/nvim/mapping.h
+++ b/src/nvim/mapping.h
@@ -19,9 +19,10 @@
/// Used for the first argument of do_map()
enum {
- MAPTYPE_MAP = 0,
- MAPTYPE_UNMAP = 1,
- MAPTYPE_NOREMAP = 2,
+ MAPTYPE_MAP = 0,
+ MAPTYPE_UNMAP = 1,
+ MAPTYPE_NOREMAP = 2,
+ MAPTYPE_UNMAP_LHS = 3,
};
/// Adjust chars in a language according to 'langmap' option.
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index a09ade2b03..3dbcbbd47b 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -957,9 +957,9 @@ static void show_one_mark(int c, char *arg, pos_T *p, char *name_arg, int curren
msg_putchar('\n');
if (!got_int) {
snprintf(IObuff, IOSIZE, " %c %6" PRIdLINENR " %4d ", c, p->lnum, p->col);
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
if (name != NULL) {
- msg_outtrans(name, current ? HL_ATTR(HLF_D) : 0);
+ msg_outtrans(name, current ? HLF_D : 0, false);
}
}
}
@@ -1082,9 +1082,8 @@ void ex_jumps(exarg_T *eap)
i == curwin->w_jumplistidx ? '>' : ' ',
i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx : curwin->w_jumplistidx - i,
curwin->w_jumplist[i].fmark.mark.lnum, curwin->w_jumplist[i].fmark.mark.col);
- msg_outtrans(IObuff, 0);
- msg_outtrans(name,
- curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HL_ATTR(HLF_D) : 0);
+ msg_outtrans(IObuff, 0, false);
+ msg_outtrans(name, curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HLF_D : 0, false);
xfree(name);
os_breakcheck();
}
@@ -1119,9 +1118,9 @@ void ex_changes(exarg_T *eap)
curwin->w_changelistidx ? i - curwin->w_changelistidx : curwin->w_changelistidx - i,
curbuf->b_changelist[i].mark.lnum,
curbuf->b_changelist[i].mark.col);
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
char *name = mark_line(&curbuf->b_changelist[i].mark, 17);
- msg_outtrans(name, HL_ATTR(HLF_D));
+ msg_outtrans(name, HLF_D, false);
xfree(name);
os_breakcheck();
}
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 01e720283e..65f718f925 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -454,9 +454,6 @@ static bool prop_is_emojilike(const utf8proc_property_t *prop)
/// Is only correct for characters >= 0x80.
/// When p_ambw is "double", return 2 for a character with East Asian Width
/// class 'A'(mbiguous).
-///
-/// @note Tables `doublewidth` and `ambiguous` are generated by
-/// gen_unicode_tables.lua, which must be manually invoked as needed.
int utf_char2cells(int c)
{
if (c < 0x80) {
@@ -842,6 +839,13 @@ bool utf_composinglike(const char *p1, const char *p2, GraphemeState *state)
return arabic_combine(first, second);
}
+/// same as utf_composinglike but operating on UCS-4 values
+bool utf_iscomposing(int c1, int c2, GraphemeState *state)
+{
+ return (!utf8proc_grapheme_break_stateful(c1, c2, state)
+ || arabic_combine(c1, c2));
+}
+
/// Get the screen char at the beginning of a string
///
/// Caller is expected to check for things like unprintable chars etc
@@ -1855,8 +1859,7 @@ StrCharInfo utfc_next_impl(StrCharInfo cur)
while (true) {
uint8_t const next_len = utf8len_tab[*next];
int32_t const next_code = utf_ptr2CharInfo_impl(next, (uintptr_t)next_len);
- if (utf8proc_grapheme_break_stateful(prev_code, next_code, &state)
- && !arabic_combine(prev_code, next_code)) {
+ if (!utf_iscomposing(prev_code, next_code, &state)) {
return (StrCharInfo){
.ptr = (char *)next,
.chr = (CharInfo){ .value = next_code, .len = (next_code < 0 ? 1 : next_len) },
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 92e2ef2b55..bfe90bb680 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -775,7 +775,6 @@ void ml_recover(bool checkext)
recoverymode = true;
int called_from_main = (curbuf->b_ml.ml_mfp == NULL);
- int attr = HL_ATTR(HLF_E);
// If the file name ends in ".s[a-w][a-z]" we assume this is the swapfile.
// Otherwise a search is done to find the swapfile(s).
@@ -853,40 +852,39 @@ void ml_recover(bool checkext)
// be set to the real value below.
mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
+ int hl_id = HLF_E;
// try to read block 0
if ((hp = mf_get(mfp, 0, 1)) == NULL) {
msg_start();
- msg_puts_attr(_("Unable to read block 0 from "), attr | MSG_HIST);
- msg_outtrans(mfp->mf_fname, attr | MSG_HIST);
- msg_puts_attr(_("\nMaybe no changes were made or Vim did not update the swap file."),
- attr | MSG_HIST);
+ msg_puts_hl(_("Unable to read block 0 from "), hl_id, true);
+ msg_outtrans(mfp->mf_fname, hl_id, true);
+ msg_puts_hl(_("\nMaybe no changes were made or Nvim did not update the swap file."), hl_id,
+ true);
msg_end();
goto theend;
}
ZeroBlock *b0p = hp->bh_data;
if (strncmp(b0p->b0_version, "VIM 3.0", 7) == 0) {
msg_start();
- msg_outtrans(mfp->mf_fname, MSG_HIST);
- msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
- MSG_HIST);
- msg_puts_attr(_("Use Vim version 3.0.\n"), MSG_HIST);
+ msg_outtrans(mfp->mf_fname, 0, true);
+ msg_puts_hl(_(" cannot be used with this version of Nvim.\n"), 0, true);
+ msg_puts_hl(_("Use Vim version 3.0.\n"), 0, true);
msg_end();
goto theend;
}
if (ml_check_b0_id(b0p) == FAIL) {
- semsg(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
+ semsg(_("E307: %s does not look like a Nvim swap file"), mfp->mf_fname);
goto theend;
}
if (b0_magic_wrong(b0p)) {
msg_start();
- msg_outtrans(mfp->mf_fname, attr | MSG_HIST);
- msg_puts_attr(_(" cannot be used on this computer.\n"),
- attr | MSG_HIST);
- msg_puts_attr(_("The file was created on "), attr | MSG_HIST);
+ msg_outtrans(mfp->mf_fname, hl_id, true);
+ msg_puts_hl(_(" cannot be used on this computer.\n"), hl_id, true);
+ msg_puts_hl(_("The file was created on "), hl_id, true);
// avoid going past the end of a corrupted hostname
b0p->b0_fname[0] = NUL;
- msg_puts_attr(b0p->b0_hname, attr | MSG_HIST);
- msg_puts_attr(_(",\nor the file has been damaged."), attr | MSG_HIST);
+ msg_puts_hl(b0p->b0_hname, hl_id, true);
+ msg_puts_hl(_(",\nor the file has been damaged."), hl_id, true);
msg_end();
goto theend;
}
@@ -899,9 +897,8 @@ void ml_recover(bool checkext)
mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
if (mfp->mf_page_size < previous_page_size) {
msg_start();
- msg_outtrans(mfp->mf_fname, attr | MSG_HIST);
- msg_puts_attr(_(" has been damaged (page size is smaller than minimum value).\n"),
- attr | MSG_HIST);
+ msg_outtrans(mfp->mf_fname, hl_id, true);
+ msg_puts_hl(_(" has been damaged (page size is smaller than minimum value).\n"), hl_id, true);
msg_end();
goto theend;
}
@@ -1521,7 +1518,7 @@ static time_t swapfile_info(char *fname)
// print name of owner of the file
if (os_get_uname((uv_uid_t)file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) {
msg_puts(_(" owned by: "));
- msg_outtrans(uname, 0);
+ msg_outtrans(uname, 0, false);
msg_puts(_(" dated: "));
} else {
msg_puts(_(" dated: "));
@@ -1541,7 +1538,7 @@ static time_t swapfile_info(char *fname)
if (strncmp(b0.b0_version, "VIM 3.0", 7) == 0) {
msg_puts(_(" [from Vim version 3.0]"));
} else if (ml_check_b0_id(&b0) == FAIL) {
- msg_puts(_(" [does not look like a Vim swap file]"));
+ msg_puts(_(" [does not look like a Nvim swap file]"));
} else if (!ml_check_b0_strings(&b0)) {
msg_puts(_(" [garbled strings (not nul terminated)]"));
} else {
@@ -1549,7 +1546,7 @@ static time_t swapfile_info(char *fname)
if (b0.b0_fname[0] == NUL) {
msg_puts(_("[No Name]"));
} else {
- msg_outtrans(b0.b0_fname, 0);
+ msg_outtrans(b0.b0_fname, 0, false);
}
msg_puts(_("\n modified: "));
@@ -1557,7 +1554,7 @@ static time_t swapfile_info(char *fname)
if (*(b0.b0_uname) != NUL) {
msg_puts(_("\n user name: "));
- msg_outtrans(b0.b0_uname, 0);
+ msg_outtrans(b0.b0_uname, 0, false);
}
if (*(b0.b0_hname) != NUL) {
@@ -1566,7 +1563,7 @@ static time_t swapfile_info(char *fname)
} else {
msg_puts(_("\n host name: "));
}
- msg_outtrans(b0.b0_hname, 0);
+ msg_outtrans(b0.b0_hname, 0, false);
}
if (char_to_long(b0.b0_pid) != 0) {
@@ -3259,7 +3256,7 @@ static void attention_message(buf_T *buf, char *fname)
msg_puts("\"\n");
const time_t swap_mtime = swapfile_info(fname);
msg_puts(_("While opening file \""));
- msg_outtrans(buf->b_fname, 0);
+ msg_outtrans(buf->b_fname, 0, false);
msg_puts("\"\n");
FileInfo file_info;
if (!os_fileinfo(buf->b_fname, &file_info)) {
@@ -3281,10 +3278,10 @@ static void attention_message(buf_T *buf, char *fname)
" Quit, or continue with caution.\n"));
msg_puts(_("(2) An edit session for this file crashed.\n"));
msg_puts(_(" If this is the case, use \":recover\" or \"nvim -r "));
- msg_outtrans(buf->b_fname, 0);
+ msg_outtrans(buf->b_fname, 0, false);
msg_puts(_("\"\n to recover the changes (see \":help recovery\").\n"));
msg_puts(_(" If you did this already, delete the swap file \""));
- msg_outtrans(fname, 0);
+ msg_outtrans(fname, 0, false);
msg_puts(_("\"\n to avoid this message.\n"));
cmdline_row = msg_row;
no_wait_return--;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index c33d3cc712..4d3058ee44 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -808,7 +808,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
msg_puts(" ");
}
// Same highlighting as for directories!?
- msg_outtrans(menu->name, HL_ATTR(HLF_D));
+ msg_outtrans(menu->name, HLF_D, false);
}
if (menu != NULL && menu->children == NULL) {
@@ -841,7 +841,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
}
msg_puts(" ");
if (*menu->strings[bit] == NUL) {
- msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
+ msg_puts_hl("<Nop>", HLF_8, false);
} else {
msg_outtrans_special(menu->strings[bit], false, 0);
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 79e6bc8be7..47f33c8967 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -36,6 +36,7 @@
#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/input.h"
#include "nvim/keycodes.h"
@@ -73,7 +74,7 @@ struct msgchunk_S {
msgchunk_T *sb_prev;
char sb_eol; // true when line ends after this text
int sb_msg_col; // column in which text starts
- int sb_attr; // text attributes
+ int sb_hl_id; // text highlight id
char sb_text[]; // text to be displayed
};
@@ -118,7 +119,7 @@ bool keep_msg_more = false; // keep_msg was set by msgmore()
// msg_scrolled How many lines the screen has been scrolled (because of
// messages). Used in update_screen() to scroll the screen
// back. Incremented each time the screen scrolls a line.
-// msg_scrolled_ign true when msg_scrolled is non-zero and msg_puts_attr()
+// msg_scrolled_ign true when msg_scrolled is non-zero and msg_puts_hl_id()
// writes something without scrolling should not make
// need_wait_return to be set. This is a hack to make ":ts"
// work without an extra prompt.
@@ -138,6 +139,7 @@ static const char *msg_ext_kind = NULL;
static Array *msg_ext_chunks = NULL;
static garray_T msg_ext_last_chunk = GA_INIT(sizeof(char), 40);
static sattr_T msg_ext_last_attr = -1;
+static int msg_ext_last_hl_id;
static size_t msg_ext_cur_len = 0;
static bool msg_ext_overwrite = false; ///< will overwrite last message
@@ -199,7 +201,7 @@ void msg_grid_validate(void)
ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows);
msg_scrolled_at_flush = msg_scrolled;
- msg_grid.focusable = false;
+ msg_grid.mouse_enabled = false;
msg_grid_adj.target = &msg_grid;
} else if (!should_alloc && msg_grid.chars) {
ui_comp_remove_grid(&msg_grid);
@@ -231,7 +233,7 @@ void msg_grid_validate(void)
int verb_msg(const char *s)
{
verbose_enter();
- int n = msg_attr_keep(s, 0, false, false);
+ int n = msg_hl_keep(s, 0, false, false);
verbose_leave();
return n;
@@ -241,45 +243,43 @@ int verb_msg(const char *s)
/// When terminal not initialized (yet) printf("%s", ..) is used.
///
/// @return true if wait_return() not called
-bool msg(const char *s, const int attr)
+bool msg(const char *s, const int hl_id)
FUNC_ATTR_NONNULL_ARG(1)
{
- return msg_attr_keep(s, attr, false, false);
+ return msg_hl_keep(s, hl_id, false, false);
}
-/// Similar to msg_outtrans, but support newlines and tabs.
-void msg_multiline(const char *s, int attr, bool check_int, bool *need_clear)
+/// Similar to msg_outtrans_len, but support newlines and tabs.
+void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
- const char *next_spec = s;
-
- while (next_spec != NULL) {
+ const char *s = str.data;
+ const char *chunk = s;
+ while ((size_t)(s - str.data) < str.size) {
if (check_int && got_int) {
return;
}
- next_spec = strpbrk(s, "\t\n\r");
-
- if (next_spec != NULL) {
- // Printing all char that are before the char found by strpbrk
- msg_outtrans_len(s, (int)(next_spec - s), attr);
+ if (*s == '\n' || *s == TAB || *s == '\r') {
+ // Print all chars before the delimiter
+ msg_outtrans_len(chunk, (int)(s - chunk), hl_id, hist);
- if (*next_spec != TAB && *need_clear) {
+ if (*s != TAB && *need_clear) {
msg_clr_eos();
*need_clear = false;
}
- msg_putchar_attr((uint8_t)(*next_spec), attr);
- s = next_spec + 1;
+ msg_putchar_hl((uint8_t)(*s), hl_id);
+ chunk = s + 1;
}
+ s++;
}
- // Print the rest of the message. We know there is no special
- // character because strpbrk returned NULL
- if (*s != NUL) {
- msg_outtrans(s, attr);
+ // Print the rest of the message
+ if (*chunk != NUL) {
+ msg_outtrans_len(chunk, (int)(str.size - (size_t)(chunk - str.data)), hl_id, hist);
}
}
-void msg_multiattr(HlMessage hl_msg, const char *kind, bool history)
+void msg_multihl(HlMessage hl_msg, const char *kind, bool history)
{
no_wait_return++;
msg_start();
@@ -288,17 +288,17 @@ void msg_multiattr(HlMessage hl_msg, const char *kind, bool history)
msg_ext_set_kind(kind);
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i);
- msg_multiline(chunk.text.data, chunk.attr, true, &need_clear);
+ msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear);
}
if (history && kv_size(hl_msg)) {
- add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg);
+ add_msg_hist_multihl(NULL, 0, 0, true, hl_msg);
}
no_wait_return--;
msg_end();
}
/// @param keep set keep_msg if it doesn't scroll
-bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
+bool msg_hl_keep(const char *s, int hl_id, bool keep, bool multiline)
FUNC_ATTR_NONNULL_ALL
{
static int entered = 0;
@@ -316,7 +316,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
return true;
}
- if (attr == 0) {
+ if (hl_id == 0) {
set_vim_var_string(VV_STATUSMSG, s, -1);
}
@@ -335,7 +335,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
&& last_msg_hist != NULL
&& last_msg_hist->msg != NULL
&& strcmp(s, last_msg_hist->msg) != 0)) {
- add_msg_hist(s, -1, attr, multiline);
+ add_msg_hist(s, -1, hl_id, multiline);
}
// Truncate the message if needed.
@@ -347,9 +347,9 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
bool need_clear = true;
if (multiline) {
- msg_multiline(s, attr, false, &need_clear);
+ msg_multiline(cstr_as_string(s), hl_id, false, false, &need_clear);
} else {
- msg_outtrans(s, attr);
+ msg_outtrans(s, hl_id, false);
}
if (need_clear) {
msg_clr_eos();
@@ -484,7 +484,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen)
}
}
-/// Shows a printf-style message with attributes.
+/// Shows a printf-style message with highlight id.
///
/// Note: Caller must check the resulting string is shorter than IOSIZE!!!
///
@@ -492,7 +492,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen)
/// @see swmsg
///
/// @param s printf-style format message
-int smsg(int attr, const char *s, ...)
+int smsg(int hl_id, const char *s, ...)
FUNC_ATTR_PRINTF(2, 3)
{
va_list arglist;
@@ -500,10 +500,10 @@ int smsg(int attr, const char *s, ...)
va_start(arglist, s);
vim_vsnprintf(IObuff, IOSIZE, s, arglist);
va_end(arglist);
- return msg(IObuff, attr);
+ return msg(IObuff, hl_id);
}
-int smsg_attr_keep(int attr, const char *s, ...)
+int smsg_hl_keep(int hl_id, const char *s, ...)
FUNC_ATTR_PRINTF(2, 3)
{
va_list arglist;
@@ -511,7 +511,7 @@ int smsg_attr_keep(int attr, const char *s, ...)
va_start(arglist, s);
vim_vsnprintf(IObuff, IOSIZE, s, arglist);
va_end(arglist);
- return msg_attr_keep(IObuff, attr, true, false);
+ return msg_hl_keep(IObuff, hl_id, true, false);
}
// Remember the last sourcing name/lnum used in an error message, so that it
@@ -588,7 +588,7 @@ static char *get_emsg_lnum(void)
/// Display name and line number for the source of an error.
/// Remember the file name and line number, so that for the next error the info
/// is only displayed if it changed.
-void msg_source(int attr)
+void msg_source(int hl_id)
{
static bool recursive = false;
@@ -602,12 +602,12 @@ void msg_source(int attr)
char *p = get_emsg_source();
if (p != NULL) {
msg_scroll = true; // this will take more than one line
- msg(p, attr);
+ msg(p, hl_id);
xfree(p);
}
p = get_emsg_lnum();
if (p != NULL) {
- msg(p, HL_ATTR(HLF_N));
+ msg(p, HLF_N);
xfree(p);
last_sourcing_lnum = SOURCING_LNUM; // only once for each line
}
@@ -736,7 +736,7 @@ bool emsg_multiline(const char *s, bool multiline)
}
emsg_on_display = true; // remember there is an error message
- int attr = HL_ATTR(HLF_E); // set highlight mode for error messages
+ int hl_id = HLF_E; // set highlight mode for error messages
if (msg_scrolled != 0) {
need_wait_return = true; // needed in case emsg() is called after
} // wait_return() has reset need_wait_return
@@ -748,11 +748,11 @@ bool emsg_multiline(const char *s, bool multiline)
// Display name and line number for the source of the error.
msg_scroll = true;
- msg_source(attr);
+ msg_source(hl_id);
// Display the error message itself.
msg_nowait = false; // Wait for this msg.
- return msg_attr_keep(s, attr, false, multiline);
+ return msg_hl_keep(s, hl_id, false, multiline);
}
/// emsg() - display an error message
@@ -907,15 +907,15 @@ void msg_schedule_semsg_multiline(const char *const fmt, ...)
/// Careful: The string may be changed by msg_may_trunc()!
///
/// @return a pointer to the printed message, if wait_return() not called.
-char *msg_trunc(char *s, bool force, int attr)
+char *msg_trunc(char *s, bool force, int hl_id)
{
// Add message to history before truncating.
- add_msg_hist(s, -1, attr, false);
+ add_msg_hist(s, -1, hl_id, false);
char *ts = msg_may_trunc(force, s);
msg_hist_off = true;
- bool n = msg(ts, attr);
+ bool n = msg(ts, hl_id);
msg_hist_off = false;
if (n) {
@@ -965,21 +965,21 @@ void hl_msg_free(HlMessage hl_msg)
}
/// @param[in] len Length of s or -1.
-static void add_msg_hist(const char *s, int len, int attr, bool multiline)
+static void add_msg_hist(const char *s, int len, int hl_id, bool multiline)
{
- add_msg_hist_multiattr(s, len, attr, multiline, (HlMessage)KV_INITIAL_VALUE);
+ add_msg_hist_multihl(s, len, hl_id, multiline, (HlMessage)KV_INITIAL_VALUE);
}
-static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multiline,
- HlMessage multiattr)
+static void add_msg_hist_multihl(const char *s, int len, int hl_id, bool multiline,
+ HlMessage multihl)
{
if (msg_hist_off || msg_silent != 0) {
- hl_msg_free(multiattr);
+ hl_msg_free(multihl);
return;
}
// Don't let the message history get too big
- while (msg_hist_len > MAX_MSG_HIST_LEN) {
+ while (msg_hist_len > p_mhi) {
delete_first_msg();
}
@@ -1002,9 +1002,9 @@ static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multil
p->msg = NULL;
}
p->next = NULL;
- p->attr = attr;
+ p->hl_id = hl_id;
p->multiline = multiline;
- p->multiattr = multiattr;
+ p->multihl = multihl;
p->kind = msg_ext_kind;
if (last_msg_hist != NULL) {
last_msg_hist->next = p;
@@ -1031,7 +1031,7 @@ int delete_first_msg(void)
last_msg_hist = NULL;
}
xfree(p->msg);
- hl_msg_free(p->multiattr);
+ hl_msg_free(p->multihl);
xfree(p);
msg_hist_len--;
return OK;
@@ -1077,22 +1077,24 @@ void ex_messages(exarg_T *eap)
}
Array entries = ARRAY_DICT_INIT;
for (; p != NULL; p = p->next) {
- if (kv_size(p->multiattr) || (p->msg && p->msg[0])) {
+ if (kv_size(p->multihl) || (p->msg && p->msg[0])) {
Array entry = ARRAY_DICT_INIT;
ADD(entry, CSTR_TO_OBJ(p->kind));
Array content = ARRAY_DICT_INIT;
- if (kv_size(p->multiattr)) {
- for (uint32_t i = 0; i < kv_size(p->multiattr); i++) {
- HlMessageChunk chunk = kv_A(p->multiattr, i);
+ if (kv_size(p->multihl)) {
+ for (uint32_t i = 0; i < kv_size(p->multihl); i++) {
+ HlMessageChunk chunk = kv_A(p->multihl, i);
Array content_entry = ARRAY_DICT_INIT;
- ADD(content_entry, INTEGER_OBJ(chunk.attr));
+ ADD(content_entry, INTEGER_OBJ(chunk.hl_id ? syn_id2attr(chunk.hl_id) : 0));
ADD(content_entry, STRING_OBJ(copy_string(chunk.text, NULL)));
+ ADD(content_entry, INTEGER_OBJ(chunk.hl_id));
ADD(content, ARRAY_OBJ(content_entry));
}
} else if (p->msg && p->msg[0]) {
Array content_entry = ARRAY_DICT_INIT;
- ADD(content_entry, INTEGER_OBJ(p->attr));
+ ADD(content_entry, INTEGER_OBJ(p->hl_id ? syn_id2attr(p->hl_id) : 0));
ADD(content_entry, CSTR_TO_OBJ(p->msg));
+ ADD(content_entry, INTEGER_OBJ(p->hl_id));
ADD(content, ARRAY_OBJ(content_entry));
}
ADD(entry, ARRAY_OBJ(content));
@@ -1106,10 +1108,10 @@ void ex_messages(exarg_T *eap)
} else {
msg_hist_off = true;
for (; p != NULL && !got_int; p = p->next) {
- if (kv_size(p->multiattr)) {
- msg_multiattr(p->multiattr, p->kind, false);
+ if (kv_size(p->multihl)) {
+ msg_multihl(p->multihl, p->kind, false);
} else if (p->msg != NULL) {
- msg_attr_keep(p->msg, p->attr, false, p->multiline);
+ msg_hl_keep(p->msg, p->hl_id, false, p->multiline);
}
}
msg_hist_off = false;
@@ -1338,7 +1340,7 @@ static void hit_return_msg(bool newline_sb)
msg_puts(_("Interrupt: "));
}
- msg_puts_attr(_("Press ENTER or type command to continue"), HL_ATTR(HLF_R));
+ msg_puts_hl(_("Press ENTER or type command to continue"), HLF_R, false);
if (!msg_use_printf()) {
msg_clr_eos();
}
@@ -1346,7 +1348,7 @@ static void hit_return_msg(bool newline_sb)
}
/// Set "keep_msg" to "s". Free the old value and check for NULL pointer.
-void set_keep_msg(const char *s, int attr)
+void set_keep_msg(const char *s, int hl_id)
{
xfree(keep_msg);
if (s != NULL && msg_silent == 0) {
@@ -1355,7 +1357,7 @@ void set_keep_msg(const char *s, int attr)
keep_msg = NULL;
}
keep_msg_more = false;
- keep_msg_attr = attr;
+ keep_msg_hl_id = hl_id;
}
/// Return true if printing messages should currently be done.
@@ -1480,10 +1482,10 @@ void msg_starthere(void)
void msg_putchar(int c)
{
- msg_putchar_attr(c, 0);
+ msg_putchar_hl(c, 0);
}
-void msg_putchar_attr(int c, int attr)
+void msg_putchar_hl(int c, int hl_id)
{
char buf[MB_MAXCHAR + 1];
@@ -1495,7 +1497,7 @@ void msg_putchar_attr(int c, int attr)
} else {
buf[utf_char2bytes(c, buf)] = NUL;
}
- msg_puts_attr(buf, attr);
+ msg_puts_hl(buf, hl_id, false);
}
void msg_outnum(int n)
@@ -1508,48 +1510,42 @@ void msg_outnum(int n)
void msg_home_replace(const char *fname)
{
- msg_home_replace_attr(fname, 0);
-}
-
-void msg_home_replace_hl(const char *fname)
-{
- msg_home_replace_attr(fname, HL_ATTR(HLF_D));
+ msg_home_replace_hl(fname, 0);
}
-static void msg_home_replace_attr(const char *fname, int attr)
+static void msg_home_replace_hl(const char *fname, int hl_id)
{
char *name = home_replace_save(NULL, fname);
- msg_outtrans(name, attr);
+ msg_outtrans(name, hl_id, false);
xfree(name);
}
-/// Output 'len' characters in 'str' (including NULs) with translation
-/// if 'len' is -1, output up to a NUL character.
-/// Use attributes 'attr'.
+/// Output "len" characters in "str" (including NULs) with translation
+/// if "len" is -1, output up to a NUL character. Use highlight "hl_id".
///
/// @return the number of characters it takes on the screen.
-int msg_outtrans(const char *str, int attr)
+int msg_outtrans(const char *str, int hl_id, bool hist)
{
- return msg_outtrans_len(str, (int)strlen(str), attr);
+ return msg_outtrans_len(str, (int)strlen(str), hl_id, hist);
}
/// Output one character at "p".
/// Handles multi-byte characters.
///
/// @return pointer to the next character.
-const char *msg_outtrans_one(const char *p, int attr)
+const char *msg_outtrans_one(const char *p, int hl_id, bool hist)
{
int l;
if ((l = utfc_ptr2len(p)) > 1) {
- msg_outtrans_len(p, l, attr);
+ msg_outtrans_len(p, l, hl_id, hist);
return p + l;
}
- msg_puts_attr(transchar_byte_buf(NULL, (uint8_t)(*p)), attr);
+ msg_puts_hl(transchar_byte_buf(NULL, (uint8_t)(*p)), hl_id, hist);
return p + 1;
}
-int msg_outtrans_len(const char *msgstr, int len, int attr)
+int msg_outtrans_len(const char *msgstr, int len, int hl_id, bool hist)
{
int retval = 0;
const char *str = msgstr;
@@ -1561,10 +1557,8 @@ int msg_outtrans_len(const char *msgstr, int len, int attr)
// Only quit when got_int was set in here.
got_int = false;
- // if MSG_HIST flag set, add message to history
- if (attr & MSG_HIST) {
- add_msg_hist(str, len, attr, false);
- attr &= ~MSG_HIST;
+ if (hist) {
+ add_msg_hist(str, len, hl_id, false);
}
// When drawing over the command line no need to clear it later or remove
@@ -1588,10 +1582,10 @@ int msg_outtrans_len(const char *msgstr, int len, int attr)
// Unprintable multi-byte char: print the printable chars so
// far and the translation of the unprintable char.
if (str > plain_start) {
- msg_puts_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, hl_id, hist);
}
plain_start = str + mb_l;
- msg_puts_attr(transchar_buf(NULL, c), attr == 0 ? HL_ATTR(HLF_8) : attr);
+ msg_puts_hl(transchar_buf(NULL, c), hl_id == 0 ? HLF_8 : hl_id, false);
retval += char2cells(c);
}
len -= mb_l - 1;
@@ -1602,10 +1596,10 @@ int msg_outtrans_len(const char *msgstr, int len, int attr)
// Unprintable char: print the printable chars so far and the
// translation of the unprintable char.
if (str > plain_start) {
- msg_puts_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, hl_id, hist);
}
plain_start = str + 1;
- msg_puts_attr(s, attr == 0 ? HL_ATTR(HLF_8) : attr);
+ msg_puts_hl(s, hl_id == 0 ? HLF_8 : hl_id, false);
retval += (int)strlen(s);
} else {
retval++;
@@ -1616,7 +1610,7 @@ int msg_outtrans_len(const char *msgstr, int len, int attr)
if (str > plain_start && !got_int) {
// Print the printable chars at the end.
- msg_puts_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, hl_id, hist);
}
got_int |= save_got_int;
@@ -1666,7 +1660,7 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen)
}
const char *str = strstart;
int retval = 0;
- int attr = HL_ATTR(HLF_8);
+ int hl_id = HLF_8;
while (*str != NUL) {
const char *text;
@@ -1686,9 +1680,7 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen)
break;
}
// Highlight special keys
- msg_puts_attr(text, (len > 1
- && utfc_ptr2len(text) <= 1
- ? attr : 0));
+ msg_puts_hl(text, (len > 1 && utfc_ptr2len(text) <= 1 ? hl_id : 0), false);
retval += len;
}
return retval;
@@ -1856,7 +1848,7 @@ void msg_prt_line(const char *s, bool list)
schar_T sc_final = 0;
const char *p_extra = NULL; // init to make SASC shut up. ASCII only!
int n;
- int attr = 0;
+ int hl_id = 0;
const char *lead = NULL;
bool in_multispace = false;
int multispace_pos = 0;
@@ -1920,7 +1912,7 @@ void msg_prt_line(const char *s, bool list)
s += l;
continue;
} else {
- attr = 0;
+ hl_id = 0;
int c = (uint8_t)(*s++);
sc_extra = NUL;
sc_final = NUL;
@@ -1944,13 +1936,13 @@ void msg_prt_line(const char *s, bool list)
: curwin->w_p_lcs_chars.tab1;
sc_extra = curwin->w_p_lcs_chars.tab2;
sc_final = curwin->w_p_lcs_chars.tab3;
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
}
} else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) {
p_extra = "";
n_extra = 1;
sc = curwin->w_p_lcs_chars.eol;
- attr = HL_ATTR(HLF_AT);
+ hl_id = HLF_AT;
s--;
} else if (c != NUL && (n = byte2cells(c)) > 1) {
n_extra = n - 1;
@@ -1958,7 +1950,7 @@ void msg_prt_line(const char *s, bool list)
sc = schar_from_ascii(*p_extra++);
// Use special coloring to be able to distinguish <hex> from
// the same in plain text.
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else if (c == ' ') {
if (lead != NULL && s <= lead && in_multispace
&& curwin->w_p_lcs_chars.leadmultispace != NULL) {
@@ -1966,23 +1958,23 @@ void msg_prt_line(const char *s, bool list)
if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else if (lead != NULL && s <= lead && curwin->w_p_lcs_chars.lead != NUL) {
sc = curwin->w_p_lcs_chars.lead;
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else if (trail != NULL && s > trail) {
sc = curwin->w_p_lcs_chars.trail;
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else if (in_multispace
&& curwin->w_p_lcs_chars.multispace != NULL) {
sc = curwin->w_p_lcs_chars.multispace[multispace_pos++];
if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else if (list && curwin->w_p_lcs_chars.space != NUL) {
sc = curwin->w_p_lcs_chars.space;
- attr = HL_ATTR(HLF_0);
+ hl_id = HLF_0;
} else {
sc = schar_from_ascii(' '); // SPACE!
}
@@ -1998,7 +1990,7 @@ void msg_prt_line(const char *s, bool list)
// TODO(bfredl): this is such baloney. need msg_put_schar
char buf[MAX_SCHAR_SIZE];
schar_get(buf, sc);
- msg_puts_attr(buf, attr);
+ msg_puts_hl(buf, hl_id, false);
col++;
}
msg_clr_eos();
@@ -2008,42 +2000,42 @@ void msg_prt_line(const char *s, bool list)
/// Update msg_row and msg_col for the next message.
void msg_puts(const char *s)
{
- msg_puts_attr(s, 0);
+ msg_puts_hl(s, 0, false);
}
void msg_puts_title(const char *s)
{
- msg_puts_attr(s, HL_ATTR(HLF_T));
+ msg_puts_hl(s, HLF_T, false);
}
/// Show a message in such a way that it always fits in the line. Cut out a
/// part in the middle and replace it with "..." when necessary.
/// Does not handle multi-byte characters!
-void msg_outtrans_long(const char *longstr, int attr)
+void msg_outtrans_long(const char *longstr, int hl_id)
{
int len = (int)strlen(longstr);
int slen = len;
int room = Columns - msg_col;
if (len > room && room >= 20) {
slen = (room - 3) / 2;
- msg_outtrans_len(longstr, slen, attr);
- msg_puts_attr("...", HL_ATTR(HLF_8));
+ msg_outtrans_len(longstr, slen, hl_id, false);
+ msg_puts_hl("...", HLF_8, false);
}
- msg_outtrans_len(longstr + len - slen, slen, attr);
+ msg_outtrans_len(longstr + len - slen, slen, hl_id, len);
}
-/// Basic function for writing a message with highlight attributes.
-void msg_puts_attr(const char *const s, const int attr)
+/// Basic function for writing a message with highlight id.
+void msg_puts_hl(const char *const s, const int hl_id, const bool hist)
{
- msg_puts_len(s, -1, attr);
+ msg_puts_len(s, -1, hl_id, hist);
}
-/// Write a message with highlight attributes
+/// Write a message with highlight id.
///
/// @param[in] str NUL-terminated message string.
/// @param[in] len Length of the string or -1.
-/// @param[in] attr Highlight attribute.
-void msg_puts_len(const char *const str, const ptrdiff_t len, int attr)
+/// @param[in] hl_id Highlight id.
+void msg_puts_len(const char *const str, const ptrdiff_t len, int hl_id, bool hist)
FUNC_ATTR_NONNULL_ALL
{
assert(len < 0 || memchr(str, 0, (size_t)len) == NULL);
@@ -2055,10 +2047,8 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr)
return;
}
- // if MSG_HIST flag set, add message to history
- if (attr & MSG_HIST) {
- add_msg_hist(str, (int)len, attr, false);
- attr &= ~MSG_HIST;
+ if (hist) {
+ add_msg_hist(str, (int)len, hl_id, false);
}
// When writing something to the screen after it has scrolled, requires a
@@ -2095,7 +2085,7 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr)
}
}
if (!msg_use_printf() || (headless_mode && default_grid.chars)) {
- msg_puts_display(str, (int)len, attr, false);
+ msg_puts_display(str, (int)len, hl_id, false);
}
need_fileinfo = false;
@@ -2104,11 +2094,11 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr)
/// Print a formatted message
///
/// Message printed is limited by #IOSIZE. Must not be used from inside
-/// msg_puts_attr().
+/// msg_puts_hl_id().
///
-/// @param[in] attr Highlight attributes.
+/// @param[in] hl_id Highlight id.
/// @param[in] fmt Format string.
-void msg_printf_attr(const int attr, const char *const fmt, ...)
+void msg_printf_hl(const int hl_id, const char *const fmt, ...)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PRINTF(2, 3)
{
static char msgbuf[IOSIZE];
@@ -2119,7 +2109,7 @@ void msg_printf_attr(const int attr, const char *const fmt, ...)
va_end(ap);
msg_scroll = true;
- msg_puts_len(msgbuf, (ptrdiff_t)len, attr);
+ msg_puts_len(msgbuf, (ptrdiff_t)len, hl_id, true);
}
static void msg_ext_emit_chunk(void)
@@ -2136,16 +2126,18 @@ static void msg_ext_emit_chunk(void)
msg_ext_last_attr = -1;
String text = ga_take_string(&msg_ext_last_chunk);
ADD(chunk, STRING_OBJ(text));
+ ADD(chunk, INTEGER_OBJ(msg_ext_last_hl_id));
ADD(*msg_ext_chunks, ARRAY_OBJ(chunk));
}
/// The display part of msg_puts_len().
/// May be called recursively to display scroll-back text.
-static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
+static void msg_puts_display(const char *str, int maxlen, int hl_id, int recurse)
{
const char *s = str;
const char *sb_str = str;
int sb_col = msg_col;
+ int attr = hl_id ? syn_id2attr(hl_id) : 0;
did_wait_return = false;
@@ -2153,6 +2145,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
if (attr != msg_ext_last_attr) {
msg_ext_emit_chunk();
msg_ext_last_attr = attr;
+ msg_ext_last_hl_id = hl_id;
}
// Concat pieces with the same highlight
size_t len = maxlen < 0 ? strlen(str) : strnlen(str, (size_t)maxlen);
@@ -2172,7 +2165,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
if (msg_col >= Columns) {
if (p_more && !recurse) {
// Store text for scrolling back.
- store_sb_text(&sb_str, s, attr, &sb_col, true);
+ store_sb_text(&sb_str, s, hl_id, &sb_col, true);
}
if (msg_no_more && lines_left == 0) {
break;
@@ -2262,7 +2255,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
msg_row++;
if (p_more && !recurse) {
// Store text for scrolling back.
- store_sb_text(&sb_str, s, attr, &sb_col, true);
+ store_sb_text(&sb_str, s, hl_id, &sb_col, true);
}
} else if (c == '\r') { // go to column 0
msg_col = 0;
@@ -2291,7 +2284,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
msg_cursor_goto(msg_row, msg_col);
if (p_more && !recurse) {
- store_sb_text(&sb_str, s, attr, &sb_col, false);
+ store_sb_text(&sb_str, s, hl_id, &sb_col, false);
}
msg_check();
@@ -2481,7 +2474,7 @@ static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE;
/// @param sb_str start of string
/// @param s just after string
/// @param finish line ends
-static void store_sb_text(const char **sb_str, const char *s, int attr, int *sb_col, int finish)
+static void store_sb_text(const char **sb_str, const char *s, int hl_id, int *sb_col, int finish)
{
msgchunk_T *mp;
@@ -2499,7 +2492,7 @@ static void store_sb_text(const char **sb_str, const char *s, int attr, int *sb_
mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1);
mp->sb_eol = (char)finish;
mp->sb_msg_col = *sb_col;
- mp->sb_attr = attr;
+ mp->sb_hl_id = hl_id;
memcpy(mp->sb_text, *sb_str, (size_t)(s - *sb_str));
mp->sb_text[s - *sb_str] = NUL;
@@ -2637,7 +2630,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
msg_row = row;
msg_col = mp->sb_msg_col;
char *p = mp->sb_text;
- msg_puts_display(p, -1, mp->sb_attr, true);
+ msg_puts_display(p, -1, mp->sb_hl_id, true);
if (mp->sb_eol || mp->sb_next == NULL) {
break;
}
@@ -2694,12 +2687,13 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
// primitive way to compute the current column
if (*s == '\r' || *s == '\n') {
msg_col = 0;
+ msg_didout = false;
} else {
msg_col += cw;
+ msg_didout = true;
}
s += len;
}
- msg_didout = true; // assume that line is not empty
}
/// Show the more-prompt and handle the user response.
@@ -3321,17 +3315,17 @@ void give_warning(const char *message, bool hl)
set_vim_var_string(VV_WARNINGMSG, message, -1);
XFREE_CLEAR(keep_msg);
if (hl) {
- keep_msg_attr = HL_ATTR(HLF_W);
+ keep_msg_hl_id = HLF_W;
} else {
- keep_msg_attr = 0;
+ keep_msg_hl_id = 0;
}
if (msg_ext_kind == NULL) {
msg_ext_set_kind("wmsg");
}
- if (msg(message, keep_msg_attr) && msg_scrolled == 0) {
- set_keep_msg(message, keep_msg_attr);
+ if (msg(message, keep_msg_hl_id) && msg_scrolled == 0) {
+ set_keep_msg(message, keep_msg_hl_id);
}
msg_didout = false; // Overwrite this message.
msg_nowait = true; // Don't wait for this message.
@@ -3664,7 +3658,7 @@ void display_confirm_msg(void)
confirm_msg_used++;
if (confirm_msg != NULL) {
msg_ext_set_kind("confirm");
- msg_puts_attr(confirm_msg, HL_ATTR(HLF_M));
+ msg_puts_hl(confirm_msg, HLF_M, false);
}
confirm_msg_used--;
}
diff --git a/src/nvim/message.h b/src/nvim/message.h
index c11c33c039..13746406f9 100644
--- a/src/nvim/message.h
+++ b/src/nvim/message.h
@@ -28,8 +28,6 @@ enum {
VIM_DISCARDALL = 6,
};
-enum { MSG_HIST = 0x1000, }; ///< special attribute addition: Put message in history
-
/// First message
extern MessageHistoryEntry *first_msg_hist;
/// Last message
diff --git a/src/nvim/message_defs.h b/src/nvim/message_defs.h
index e60e60b3be..8d23b79385 100644
--- a/src/nvim/message_defs.h
+++ b/src/nvim/message_defs.h
@@ -6,7 +6,7 @@
typedef struct {
String text;
- int attr;
+ int hl_id;
} HlMessageChunk;
typedef kvec_t(HlMessageChunk) HlMessage;
@@ -16,7 +16,7 @@ typedef struct msg_hist {
struct msg_hist *next; ///< Next message.
char *msg; ///< Message text.
const char *kind; ///< Message kind (for msg_ext)
- int attr; ///< Message highlighting.
+ int hl_id; ///< Message highlighting.
bool multiline; ///< Multiline message.
- HlMessage multiattr; ///< multiattr message.
+ HlMessage multihl; ///< Multihl message.
} MessageHistoryEntry;
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 884bc88d73..1289adfabb 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -1740,7 +1740,7 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
} else if (*gridp > 1) {
win_T *wp = get_win_by_grid_handle(*gridp);
if (wp && wp->w_grid_alloc.chars
- && !(wp->w_floating && !wp->w_config.focusable)) {
+ && !(wp->w_floating && !wp->w_config.mouse)) {
*rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1);
*colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1);
return wp;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index be9987cc7f..55aa385b33 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -693,7 +693,7 @@ static void normal_redraw_mode_message(NormalState *s)
keep_msg = kmsg;
kmsg = xstrdup(keep_msg);
- msg(kmsg, keep_msg_attr);
+ msg(kmsg, keep_msg_hl_id);
xfree(kmsg);
}
setcursor();
@@ -835,21 +835,29 @@ static void normal_get_additional_char(NormalState *s)
// because if it's put back with vungetc() it's too late to apply
// mapping.
no_mapping--;
+ GraphemeState state = GRAPHEME_STATE_INIT;
+ int prev_code = s->ca.nchar;
+
while ((s->c = vpeekc()) > 0
&& (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) {
s->c = plain_vgetc();
- // TODO(bfredl): only allowing up to two composing chars is cringe af.
- // Could reuse/abuse schar_T to at least allow us to input anything we are able
- // to display and use the stateful utf8proc algorithm like utf_composinglike
- if (!utf_iscomposing_legacy(s->c)) {
+
+ if (!utf_iscomposing(prev_code, s->c, &state)) {
vungetc(s->c); // it wasn't, put it back
break;
- } else if (s->ca.ncharC1 == 0) {
- s->ca.ncharC1 = s->c;
- } else {
- s->ca.ncharC2 = s->c;
}
+
+ // first composing char, first put base char into buffer
+ if (s->ca.nchar_len == 0) {
+ s->ca.nchar_len = utf_char2bytes(s->ca.nchar, s->ca.nchar_composing);
+ }
+
+ if (s->ca.nchar_len + utf_char2len(s->c) < (int)sizeof(s->ca.nchar_composing)) {
+ s->ca.nchar_len += utf_char2bytes(s->c, s->ca.nchar_composing + s->ca.nchar_len);
+ }
+ prev_code = s->c;
}
+ s->ca.nchar_composing[s->ca.nchar_len] = NUL;
no_mapping++;
// Vim may be in a different mode when the user types the next key,
// but when replaying a recording the next key is already in the
@@ -1380,7 +1388,7 @@ static void normal_redraw(NormalState *s)
// check for duplicates. Never put this message in
// history.
msg_hist_off = true;
- msg(p, keep_msg_attr);
+ msg(p, keep_msg_hl_id);
msg_hist_off = false;
xfree(p);
}
@@ -1735,7 +1743,12 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text
static void prep_redo_cmd(cmdarg_T *cap)
{
prep_redo(cap->oap->regname, cap->count0,
- NUL, cap->cmdchar, NUL, NUL, cap->nchar);
+ NUL, cap->cmdchar, NUL, NUL, NUL);
+ if (cap->nchar_len > 0) {
+ AppendToRedobuff(cap->nchar_composing);
+ } else {
+ AppendCharToRedobuff(cap->nchar);
+ }
}
/// Prepare for redo of any command.
@@ -2068,11 +2081,12 @@ static void display_showcmd(void)
if (ui_has(kUIMessages)) {
MAXSIZE_TEMP_ARRAY(content, 1);
- MAXSIZE_TEMP_ARRAY(chunk, 2);
+ MAXSIZE_TEMP_ARRAY(chunk, 3);
if (!showcmd_is_clear) {
// placeholder for future highlight support
ADD_C(chunk, INTEGER_OBJ(0));
ADD_C(chunk, CSTR_AS_OBJ(showcmd_buf));
+ ADD_C(chunk, INTEGER_OBJ(0));
ADD_C(content, ARRAY_OBJ(chunk));
}
ui_call_msg_showcmd(content);
@@ -4548,17 +4562,15 @@ static void nv_replace(cmdarg_T *cap)
// Give 'r' to edit(), to get the redo command right.
invoke_edit(cap, true, 'r', false);
} else {
- prep_redo(cap->oap->regname, cap->count1,
- NUL, 'r', NUL, had_ctrl_v, cap->nchar);
+ prep_redo(cap->oap->regname, cap->count1, NUL, 'r', NUL, had_ctrl_v, 0);
curbuf->b_op_start = curwin->w_cursor;
const int old_State = State;
- if (cap->ncharC1 != 0) {
- AppendCharToRedobuff(cap->ncharC1);
- }
- if (cap->ncharC2 != 0) {
- AppendCharToRedobuff(cap->ncharC2);
+ if (cap->nchar_len > 0) {
+ AppendToRedobuff(cap->nchar_composing);
+ } else {
+ AppendCharToRedobuff(cap->nchar);
}
// This is slow, but it handles replacing a single-byte with a
@@ -4576,15 +4588,13 @@ static void nv_replace(cmdarg_T *cap)
curwin->w_cursor.col++;
}
} else {
- ins_char(cap->nchar);
+ if (cap->nchar_len) {
+ ins_char_bytes(cap->nchar_composing, (size_t)cap->nchar_len);
+ } else {
+ ins_char(cap->nchar);
+ }
}
State = old_State;
- if (cap->ncharC1 != 0) {
- ins_char(cap->ncharC1);
- }
- if (cap->ncharC2 != 0) {
- ins_char(cap->ncharC2);
- }
}
curwin->w_cursor.col--; // cursor on the last replaced char
// if the character on the left of the current cursor is a multi-byte
@@ -5239,6 +5249,12 @@ void nv_g_home_m_cmd(cmdarg_T *cap)
curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = true;
+ if (hasAnyFolding(curwin)) {
+ validate_cheight(curwin);
+ if (curwin->w_cline_folded) {
+ update_curswant_force();
+ }
+ }
adjust_skipcol();
}
diff --git a/src/nvim/normal_defs.h b/src/nvim/normal_defs.h
index 0309f6bc80..7b49b28a0f 100644
--- a/src/nvim/normal_defs.h
+++ b/src/nvim/normal_defs.h
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "nvim/pos_defs.h"
+#include "nvim/types_defs.h"
/// Motion types, used for operators and for yank/delete registers.
///
@@ -47,8 +48,8 @@ typedef struct {
int prechar; ///< prefix character (optional, always 'g')
int cmdchar; ///< command character
int nchar; ///< next command character (optional)
- int ncharC1; ///< first composing character (optional)
- int ncharC2; ///< second composing character (optional)
+ char nchar_composing[MAX_SCHAR_SIZE]; ///< next char with composing chars (optional)
+ int nchar_len; ///< len of nchar_composing (when zero, use nchar instead)
int extra_char; ///< yet another character (optional)
int opcount; ///< count before an operator
int count0; ///< count before command, default 0
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 4b8382c971..7dd3f665ba 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -12,6 +12,7 @@
#include <uv.h>
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/autocmd.h"
@@ -273,7 +274,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount)
vim_snprintf(IObuff, IOSIZE,
NGETTEXT(msg_line_single, msg_line_plural, oap->line_count),
(int64_t)oap->line_count, op, amount);
- msg_attr_keep(IObuff, 0, true, false);
+ msg_hl_keep(IObuff, 0, true, false);
}
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
@@ -871,18 +872,22 @@ static void typval_to_yankreg(yankreg_T* yankreg, typval_T* val)
if (tv_dict_get_tv(dict, "lines", &tv) == OK) {
if (tv.v_type == VAR_STRING) {
- yankreg->y_array = (char**) xcalloc(sizeof(char*), 1);
- yankreg->y_array[0] = strdup(tv.vval.v_string);
+ yankreg->y_array = (String*) xcalloc(1, sizeof(String));
+ yankreg->y_array[0].data = strdup(tv.vval.v_string);
+ yankreg->y_array[0].size = strlen(tv.vval.v_string);
} else if (tv.v_type == VAR_LIST) {
yankreg->y_array =
- (char**) xcalloc(sizeof(char*), (size_t) tv_list_len(tv.vval.v_list));
+ (String*) xcalloc((size_t) tv_list_len(tv.vval.v_list), sizeof(String));
i = 0;
TV_LIST_ITER_CONST(tv.vval.v_list, li, {
if (li->li_tv.v_type == VAR_STRING) {
- yankreg->y_array[i] = strdup(tv_get_string(&li->li_tv));
+ char* tmp = strdup(tv_get_string(&li->li_tv));
+ yankreg->y_array[i].data = tmp;
+ yankreg->y_array[i].size = strlen(tmp);
} else {
- yankreg->y_array[i] = NULL;
+ yankreg->y_array[i].data = NULL;
+ yankreg->y_array[i].size = 0;
}
++ i;
});
@@ -903,11 +908,13 @@ static void typval_to_yankreg(yankreg_T* yankreg, typval_T* val)
case VAR_LIST:
yankreg->y_type = kMTLineWise;
sz = (size_t) tv_list_len(val->vval.v_list);
- yankreg->y_array = (char**) xcalloc(sizeof(char*), sz);
+ yankreg->y_array = (String*) xcalloc(sz, sizeof(String));
yankreg->y_size = sz;
i = 0;
TV_LIST_ITER_CONST(val->vval.v_list, li, {
- yankreg->y_array[i] = strdup(tv_get_string(&li->li_tv));
+ char* tmp = strdup(tv_get_string(&li->li_tv));
+ yankreg->y_array[i].data = tmp;
+ yankreg->y_array[i].size = strlen(tmp);
i ++;
});
break;
@@ -917,8 +924,10 @@ static void typval_to_yankreg(yankreg_T* yankreg, typval_T* val)
yankreg->y_size = 1;
if (val->vval.v_string) {
- yankreg->y_array = (char**) xcalloc(sizeof(char*), 1);
- yankreg->y_array[0] = strdup(tv_get_string(val));
+ yankreg->y_array = (String*) xcalloc(1, sizeof(String));
+ char* tmp = strdup(tv_get_string(val));
+ yankreg->y_array[0].data = tmp;
+ yankreg->y_array[0].size = strlen(tmp);
} else {
yankreg->y_array = NULL;
}
@@ -1024,9 +1033,9 @@ yankreg_T *copy_register(int name)
if (copy->y_size == 0) {
copy->y_array = NULL;
} else {
- copy->y_array = (char**) xcalloc(copy->y_size, sizeof(char *));
+ copy->y_array = xcalloc(copy->y_size, sizeof(String));
for (size_t i = 0; i < copy->y_size; i++) {
- copy->y_array[i] = xstrdup(reg->y_array[i]);
+ copy->y_array[i] = copy_string(reg->y_array[i], NULL);
}
}
return copy;
@@ -1129,23 +1138,24 @@ static int stuff_yank(int regname, char *p)
xfree(p);
return OK;
}
+
+ const size_t plen = strlen(p);
yankreg_T *reg = get_yank_register(regname, YREG_YANK);
if (is_append_register(regname) && reg->y_array != NULL) {
- char **pp = &(reg->y_array[reg->y_size - 1]);
- const size_t ppl = strlen(*pp);
- const size_t pl = strlen(p);
- char *lp = xmalloc(ppl + pl + 1);
- memcpy(lp, *pp, ppl);
- memcpy(lp + ppl, p, pl);
- *(lp + ppl + pl) = NUL;
+ String *pp = &(reg->y_array[reg->y_size - 1]);
+ const size_t tmplen = pp->size + plen;
+ char *tmp = xmalloc(tmplen + 1);
+ memcpy(tmp, pp->data, pp->size);
+ memcpy(tmp + pp->size, p, plen);
+ *(tmp + tmplen) = NUL;
xfree(p);
- xfree(*pp);
- *pp = lp;
+ xfree(pp->data);
+ *pp = cbuf_as_string(tmp, tmplen);
} else {
free_register(reg);
reg->additional_data = NULL;
- reg->y_array = xmalloc(sizeof(char *));
- reg->y_array[0] = p;
+ reg->y_array = xmalloc(sizeof(String));
+ reg->y_array[0] = cbuf_as_string(p, plen);
reg->y_size = 1;
reg->y_type = kMTCharWise;
}
@@ -1169,7 +1179,7 @@ static int execreg_lastc = NUL;
/// with a \. Lines that start with a comment "\ character are ignored.
/// @returns the concatenated line. The index of the line that should be
/// processed next is returned in idx.
-static char *execreg_line_continuation(char **lines, size_t *idx)
+static char *execreg_line_continuation(String *lines, size_t *idx)
{
size_t i = *idx;
assert(i > 0);
@@ -1182,7 +1192,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
// Any line not starting with \ or "\ is the start of the
// command.
while (--i > 0) {
- char *p = skipwhite(lines[i]);
+ char *p = skipwhite(lines[i].data);
if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
break;
}
@@ -1190,9 +1200,9 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
const size_t cmd_start = i;
// join all the lines
- ga_concat(&ga, lines[cmd_start]);
+ ga_concat(&ga, lines[cmd_start].data);
for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
- char *p = skipwhite(lines[j]);
+ char *p = skipwhite(lines[j].data);
if (*p == '\\') {
// Adjust the growsize to the current length to
// speed up concatenating many lines.
@@ -1203,7 +1213,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
}
}
ga_append(&ga, NUL);
- char *str = xstrdup(ga.ga_data);
+ char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len);
ga_clear(&ga);
*idx = i;
@@ -1296,7 +1306,7 @@ int do_execreg(int regname, int colon, int addcr, int silent)
}
// Handle line-continuation for :@<register>
- char *str = reg->y_array[i];
+ char *str = reg->y_array[i].data;
bool free_str = false;
if (colon && i > 0) {
char *p = skipwhite(str);
@@ -1434,7 +1444,7 @@ int insert_reg(int regname, bool literally_arg)
if (u_save_cursor() == FAIL) {
return FAIL;
}
- del_chars(mb_charlen(reg->y_array[0]), true);
+ del_chars(mb_charlen(reg->y_array[0].data), true);
curpos = curwin->w_cursor;
if (oneright() == FAIL) {
// hit end of line, need to put forward (after the current position)
@@ -1447,7 +1457,7 @@ int insert_reg(int regname, bool literally_arg)
AppendCharToRedobuff(regname);
do_put(regname, NULL, dir, 1, PUT_CURSEND);
} else {
- stuffescaped(reg->y_array[i], literally);
+ stuffescaped(reg->y_array[i].data, literally);
}
// Insert a newline between lines and after last line if
// y_type is kMTLineWise.
@@ -1494,7 +1504,7 @@ static dict_T* yankreg_to_dict(yankreg_T* yankreg) {
size_t i;
for (i = 0; i < yankreg->y_size; ++ i) {
tv_list_append_string(
- lines, yankreg->y_array[i], (long)strlen(yankreg->y_array[i]));
+ lines, yankreg->y_array[i].data, (long)yankreg->y_array[i].size);
}
tv_dict_add_list(dict, S_LEN("lines"), lines);
@@ -1657,7 +1667,7 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
}
for (size_t i = 0; i < reg->y_size; i++) {
- cmdline_paste_str(reg->y_array[i], literally);
+ cmdline_paste_str(reg->y_array[i].data, literally);
// Insert ^M between lines, unless `remcr` is true.
if (i < reg->y_size - 1 && !remcr) {
@@ -2786,7 +2796,7 @@ void free_register(yankreg_T *reg)
}
for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included
- xfree(reg->y_array[i]);
+ API_CLEAR_STRING(reg->y_array[i]);
}
XFREE_CLEAR(reg->y_array);
}
@@ -2823,7 +2833,6 @@ bool op_yank(oparg_T *oap, bool message)
set_clipboard(oap->regname, reg);
do_autocmd_textyankpost(oap, reg);
-
return true;
}
@@ -2859,7 +2868,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
reg->y_size = yanklines;
reg->y_type = yank_type; // set the yank register type
reg->y_width = 0;
- reg->y_array = xcalloc(yanklines, sizeof(char *));
+ reg->y_array = xcalloc(yanklines, sizeof(String));
reg->additional_data = NULL;
reg->timestamp = os_time();
@@ -2883,11 +2892,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
break;
case kMTLineWise:
- reg->y_array[y_idx] = xstrdup(ml_get(lnum));
+ reg->y_array[y_idx] = cbuf_to_string(ml_get(lnum), (size_t)ml_get_len(lnum));
break;
case kMTCharWise:
charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive);
+ // make sure bd.textlen is not longer than the text
+ int tmp = (int)strlen(bd.textstart);
+ if (tmp < bd.textlen) {
+ bd.textlen = tmp;
+ }
yank_copy_line(reg, &bd, y_idx, false);
break;
@@ -2899,7 +2913,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
if (curr != reg) { // append the new block to the old block
size_t j;
- char **new_ptr = xmalloc(sizeof(char *) * (curr->y_size + reg->y_size));
+ String *new_ptr = xmalloc(sizeof(String) * (curr->y_size + reg->y_size));
for (j = 0; j < curr->y_size; j++) {
new_ptr[j] = curr->y_array[j];
}
@@ -2915,13 +2929,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
// the new block, unless being Vi compatible.
if (curr->y_type == kMTCharWise
&& vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) {
- char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1])
- + strlen(reg->y_array[0]) + 1);
- STRCPY(pnew, curr->y_array[--j]);
- strcat(pnew, reg->y_array[0]);
- xfree(curr->y_array[j]);
- xfree(reg->y_array[0]);
- curr->y_array[j++] = pnew;
+ char *pnew = xmalloc(curr->y_array[curr->y_size - 1].size
+ + reg->y_array[0].size + 1);
+ j--;
+ STRCPY(pnew, curr->y_array[j].data);
+ STRCPY(pnew + curr->y_array[j].size, reg->y_array[0].data);
+ xfree(curr->y_array[j].data);
+ curr->y_array[j] = cbuf_as_string(pnew,
+ curr->y_array[j].size + reg->y_array[0].size);
+ j++;
+ API_CLEAR_STRING(reg->y_array[0]);
y_idx = 1;
} else {
y_idx = 0;
@@ -2992,7 +3009,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
int size = bd->startspaces + bd->endspaces + bd->textlen;
assert(size >= 0);
char *pnew = xmallocz((size_t)size);
- reg->y_array[y_idx] = pnew;
+ reg->y_array[y_idx].data = pnew;
memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces;
memmove(pnew, bd->textstart, (size_t)bd->textlen);
@@ -3008,6 +3025,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
}
}
*pnew = NUL;
+ reg->y_array[y_idx].size = (size_t)(pnew - reg->y_array[y_idx].data);
}
/// Execute autocommands for TextYankPost.
@@ -3034,7 +3052,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
// The yanked text contents.
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
for (size_t i = 0; i < reg->y_size; i++) {
- tv_list_append_string(list, reg->y_array[i], -1);
+ tv_list_append_string(list, reg->y_array[i].data, -1);
}
tv_list_set_lock(list, VAR_FIXED);
tv_dict_add_list(dict, S_LEN("regcontents"), list);
@@ -3096,7 +3114,7 @@ static void do_autocmd_textput(int regname, yankreg_T *reg, enum auto_event evt)
// The yanked text contents.
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
for (size_t i = 0; i < reg->y_size; i++) {
- tv_list_append_string(list, (const char *)reg->y_array[i], -1);
+ tv_list_append_string(list, reg->y_array[i].data, reg->y_array[i].size);
}
tv_list_set_lock(list, VAR_FIXED);
(void)tv_dict_add_list(dict, S_LEN("regcontents"), list);
@@ -3138,16 +3156,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
size_t y_size;
int y_width = 0;
colnr_T vcol = 0;
- int incr = 0;
- struct block_def bd;
- char **y_array = NULL;
+ String *y_array = NULL;
linenr_T nr_lines = 0;
- int indent;
- int orig_indent = 0; // init for gcc
- int indent_diff = 0; // init for gcc
- bool first_indent = true;
- int lendiff = 0;
- char *insert_string = NULL;
bool allocated = false;
const pos_T orig_start = curbuf->b_op_start;
const pos_T orig_end = curbuf->b_op_end;
@@ -3157,10 +3167,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
do_autocmd_textput(regname, reg, EVENT_TEXTPUTPRE);
}
- if (flags & PUT_FIXINDENT) {
- orig_indent = get_indent();
- }
-
curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
curbuf->b_op_end = curwin->w_cursor; // default for '] mark
@@ -3248,8 +3254,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// For special registers '%' (file name), '#' (alternate file name) and
// ':' (last command line), etc. we have to create a fake yank register.
- if (!reg && get_spec_reg(regname, &insert_string, &allocated, true)) {
- if (insert_string == NULL) {
+ String insert_string = STRING_INIT;
+ if (!reg && get_spec_reg(regname, &insert_string.data, &allocated, true)) {
+ if (insert_string.data == NULL) {
return;
}
}
@@ -3262,7 +3269,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
}
}
- if (insert_string != NULL) {
+ if (insert_string.data != NULL) {
+ insert_string.size = strlen(insert_string.data);
y_type = kMTCharWise;
if (regname == '=') {
// For the = register we need to split the string at NL
@@ -3270,29 +3278,37 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Loop twice: count the number of lines and save them.
while (true) {
y_size = 0;
- char *ptr = insert_string;
+ char *ptr = insert_string.data;
+ size_t ptrlen = insert_string.size;
while (ptr != NULL) {
if (y_array != NULL) {
- y_array[y_size] = ptr;
+ y_array[y_size].data = ptr;
}
y_size++;
- ptr = vim_strchr(ptr, '\n');
- if (ptr != NULL) {
+ char *tmp = vim_strchr(ptr, '\n');
+ if (tmp == NULL) {
if (y_array != NULL) {
- *ptr = NUL;
+ y_array[y_size - 1].size = ptrlen;
}
- ptr++;
+ } else {
+ if (y_array != NULL) {
+ *tmp = NUL;
+ y_array[y_size - 1].size = (size_t)(tmp - ptr);
+ ptrlen -= y_array[y_size - 1].size + 1;
+ }
+ tmp++;
// A trailing '\n' makes the register linewise.
- if (*ptr == NUL) {
+ if (*tmp == NUL) {
y_type = kMTLineWise;
break;
}
}
+ ptr = tmp;
}
if (y_array != NULL) {
break;
}
- y_array = xmalloc(y_size * sizeof(char *));
+ y_array = xmalloc(y_size * sizeof(String));
}
} else {
y_size = 1; // use fake one-line yank register
@@ -3330,14 +3346,16 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
goto end;
}
char *curline = get_cursor_line_ptr();
- char *p = curline + curwin->w_cursor.col;
+ char *p = get_cursor_pos_ptr();
+ char *const p_orig = p;
+ const size_t plen = (size_t)get_cursor_pos_len();
if (dir == FORWARD && *p != NUL) {
MB_PTR_ADV(p);
}
// we need this later for the correct extmark_splice() event
split_pos = (colnr_T)(p - curline);
- char *ptr = xstrdup(p);
+ char *ptr = xmemdupz(p, plen - (size_t)(p - p_orig));
ml_append(curwin->w_cursor.lnum, ptr, 0, false);
xfree(ptr);
@@ -3401,8 +3419,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
goto end;
}
- int yanklen = (int)strlen(y_array[0]);
-
if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) {
if (gchar_cursor() == TAB) {
int viscol = getviscol();
@@ -3426,6 +3442,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Block mode
if (y_type == kMTBlockWise) {
+ int incr = 0;
+ struct block_def bd;
int c = gchar_cursor();
colnr_T endcol2 = 0;
@@ -3518,14 +3536,14 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
}
}
- yanklen = (int)strlen(y_array[i]);
+ const int yanklen = (int)y_array[i].size;
if ((flags & PUT_BLOCK_INNER) == 0) {
// calculate number of spaces required to fill right side of block
spaces = y_width + 1;
- cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i]);
- ci = utf_ptr2StrCharInfo(y_array[i]);
+ cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i].data);
+ ci = utf_ptr2StrCharInfo(y_array[i].data);
while (*ci.ptr != NUL) {
spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width;
ci = utfc_next(ci);
@@ -3556,7 +3574,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// insert the new text
for (int j = 0; j < count; j++) {
- memmove(ptr, y_array[i], (size_t)yanklen);
+ memmove(ptr, y_array[i].data, (size_t)yanklen);
ptr += yanklen;
// insert block's trailing spaces only if there's text behind
@@ -3608,6 +3626,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
curwin->w_cursor.lnum = lnum;
}
} else {
+ const int yanklen = (int)y_array[0].size;
+
// Character or Line mode
if (y_type == kMTCharWise) {
// if type is kMTCharWise, FORWARD is the same as BACKWARD on the next
@@ -3680,10 +3700,10 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
memmove(newp, oldp, (size_t)col);
char *ptr = newp + col;
for (size_t i = 0; i < (size_t)count; i++) {
- memmove(ptr, y_array[0], (size_t)yanklen);
+ memmove(ptr, y_array[0].data, (size_t)yanklen);
ptr += yanklen;
}
- STRMOVE(ptr, oldp + col);
+ memmove(ptr, oldp + col, (size_t)(oldlen - col) + 1); // +1 for NUL
ml_replace(lnum, newp, false);
// compute the byte offset for the last character
@@ -3721,6 +3741,15 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
}
} else {
linenr_T new_lnum = new_cursor.lnum;
+ int indent;
+ int orig_indent = 0;
+ int indent_diff = 0; // init for gcc
+ bool first_indent = true;
+ int lendiff = 0;
+
+ if (flags & PUT_FIXINDENT) {
+ orig_indent = get_indent();
+ }
// Insert at least one line. When y_type is kMTCharWise, break the first
// line in two.
@@ -3732,10 +3761,11 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Then append y_array[0] to first line.
lnum = new_cursor.lnum;
char *ptr = ml_get(lnum) + col;
- totlen = strlen(y_array[y_size - 1]);
- char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1);
- STRCPY(newp, y_array[y_size - 1]);
- strcat(newp, ptr);
+ size_t ptrlen = (size_t)ml_get_len(lnum) - (size_t)col;
+ totlen = y_array[y_size - 1].size;
+ char *newp = xmalloc(ptrlen + totlen + 1);
+ STRCPY(newp, y_array[y_size - 1].data);
+ STRCPY(newp + totlen, ptr);
// insert second line
ml_append(lnum, newp, 0, false);
new_lnum++;
@@ -3746,7 +3776,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// copy first part of line
memmove(newp, oldp, (size_t)col);
// append to first line
- memmove(newp + col, y_array[0], (size_t)yanklen + 1);
+ memmove(newp + col, y_array[0].data, (size_t)yanklen + 1);
ml_replace(lnum, newp, false);
curwin->w_cursor.lnum = lnum;
@@ -3755,7 +3785,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
for (; i < y_size; i++) {
if ((y_type != kMTCharWise || i < y_size - 1)) {
- if (ml_append(lnum, y_array[i], 0, false) == FAIL) {
+ if (ml_append(lnum, y_array[i].data, 0, false) == FAIL) {
goto error;
}
new_lnum++;
@@ -3794,9 +3824,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
if (y_type == kMTCharWise
|| (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) {
for (i = 0; i < y_size - 1; i++) {
- totsize += (bcount_t)strlen(y_array[i]) + 1;
+ totsize += (bcount_t)y_array[i].size + 1;
}
- lastsize = (int)strlen(y_array[y_size - 1]);
+ lastsize = (int)y_array[y_size - 1].size;
totsize += lastsize;
}
if (y_type == kMTCharWise) {
@@ -3840,13 +3870,13 @@ error:
// Put the '] mark on the first byte of the last inserted character.
// Correct the length for change in indent.
curbuf->b_op_end.lnum = new_lnum;
- size_t len = strlen(y_array[y_size - 1]);
- col = (colnr_T)len - lendiff;
+ col = (colnr_T)y_array[y_size - 1].size - lendiff;
if (col > 1) {
curbuf->b_op_end.col = col - 1;
- if (len > 0) {
- curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1],
- y_array[y_size - 1] + len - 1);
+ if (y_array[y_size - 1].size > 0) {
+ curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1].data,
+ y_array[y_size - 1].data
+ + y_array[y_size - 1].size - 1);
}
} else {
curbuf->b_op_end.col = 0;
@@ -3908,7 +3938,7 @@ end:
curbuf->b_op_end = orig_end;
}
if (allocated) {
- xfree(insert_string);
+ xfree(insert_string.data);
}
if (regname == '=') {
xfree(y_array);
@@ -3989,7 +4019,7 @@ void ex_display(exarg_T *eap)
if (arg != NULL && *arg == NUL) {
arg = NULL;
}
- int attr = HL_ATTR(HLF_8);
+ int hl_id = HLF_8;
// Highlight title
msg_puts_title(_("\nType Name Content"));
@@ -4030,7 +4060,7 @@ void ex_display(exarg_T *eap)
bool do_show = false;
for (size_t j = 0; !do_show && j < yb->y_size; j++) {
- do_show = !message_filtered(yb->y_array[j]);
+ do_show = !message_filtered(yb->y_array[j].data);
}
if (do_show || yb->y_size == 0) {
@@ -4045,18 +4075,18 @@ void ex_display(exarg_T *eap)
int n = Columns - 11;
for (size_t j = 0; j < yb->y_size && n > 1; j++) {
if (j) {
- msg_puts_attr("^J", attr);
+ msg_puts_hl("^J", hl_id, false);
n -= 2;
}
- for (p = yb->y_array[j];
+ for (p = yb->y_array[j].data;
*p != NUL && (n -= ptr2cells(p)) >= 0; p++) {
int clen = utfc_ptr2len(p);
- msg_outtrans_len(p, clen, 0);
+ msg_outtrans_len(p, clen, 0, false);
p += clen - 1;
}
}
if (n > 1 && yb->y_type == kMTLineWise) {
- msg_puts_attr("^J", attr);
+ msg_puts_hl("^J", hl_id, false);
}
}
os_breakcheck();
@@ -4126,10 +4156,10 @@ static void dis_msg(const char *p, bool skip_esc)
&& (n -= ptr2cells(p)) >= 0) {
int l;
if ((l = utfc_ptr2len(p)) > 1) {
- msg_outtrans_len(p, l, 0);
+ msg_outtrans_len(p, l, 0, false);
p += l;
} else {
- msg_outtrans_len(p++, 1, 0);
+ msg_outtrans_len(p++, 1, 0, false);
}
}
os_breakcheck();
@@ -5207,7 +5237,7 @@ void *get_reg_contents(int regname, int flags)
if (flags & kGRegList) {
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
for (size_t i = 0; i < reg->y_size; i++) {
- tv_list_append_string(list, reg->y_array[i], -1);
+ tv_list_append_string(list, reg->y_array[i].data, -1);
}
return list;
@@ -5216,9 +5246,8 @@ void *get_reg_contents(int regname, int flags)
// Compute length of resulting string.
size_t len = 0;
for (size_t i = 0; i < reg->y_size; i++) {
- len += strlen(reg->y_array[i]);
- // Insert a newline between lines and after last line if
- // y_type is kMTLineWise.
+ len += reg->y_array[i].size;
+ // Insert a newline between lines and after last line if y_type is kMTLineWise.
if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
len++;
}
@@ -5229,11 +5258,10 @@ void *get_reg_contents(int regname, int flags)
// Copy the lines of the yank register into the string.
len = 0;
for (size_t i = 0; i < reg->y_size; i++) {
- STRCPY(retval + len, reg->y_array[i]);
- len += strlen(retval + len);
+ STRCPY(retval + len, reg->y_array[i].data);
+ len += reg->y_array[i].size;
- // Insert a NL between lines and after the last line if y_type is
- // kMTLineWise.
+ // Insert a newline between lines and after the last line if y_type is kMTLineWise.
if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
retval[len++] = '\n';
}
@@ -5355,8 +5383,7 @@ void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_app
semsg(_(e_nobufnr), (int64_t)num);
}
} else {
- buf = buflist_findnr(buflist_findpat(str, str + strlen(str),
- true, false, false));
+ buf = buflist_findnr(buflist_findpat(str, str + len, true, false, false));
}
if (buf == NULL) {
return;
@@ -5452,7 +5479,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
}
// Grow the register array to hold the pointers to the new lines.
- char **pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(char *));
+ String *pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(String));
y_ptr->y_array = pp;
size_t lnum = y_ptr->y_size; // The current line number.
@@ -5464,7 +5491,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
if (str_list) {
for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) {
size_t ss_len = strlen(*ss);
- pp[lnum] = xmemdupz(*ss, ss_len);
+ pp[lnum] = cbuf_to_string(*ss, ss_len);
maxlen = MAX(maxlen, ss_len);
}
} else {
@@ -5477,22 +5504,22 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
maxlen = MAX(maxlen, line_len);
// When appending, copy the previous line and free it after.
- size_t extra = append ? strlen(pp[--lnum]) : 0;
+ size_t extra = append ? pp[--lnum].size : 0;
char *s = xmallocz(line_len + extra);
if (extra > 0) {
- memcpy(s, pp[lnum], extra);
+ memcpy(s, pp[lnum].data, extra);
}
memcpy(s + extra, start, line_len);
size_t s_len = extra + line_len;
if (append) {
- xfree(pp[lnum]);
+ xfree(pp[lnum].data);
append = false; // only first line is appended
}
- pp[lnum] = s;
+ pp[lnum] = cbuf_as_string(s, s_len);
// Convert NULs to '\n' to prevent truncation.
- memchrsub(pp[lnum], NUL, '\n', s_len);
+ memchrsub(pp[lnum].data, NUL, '\n', s_len);
}
}
y_ptr->y_type = yank_type;
@@ -6783,7 +6810,7 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
{
- if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) {
+ if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
// a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) {
@@ -6803,7 +6830,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
if (reg->y_type == kMTBlockWise) {
size_t maxlen = 0;
for (size_t i = 0; i < reg->y_size; i++) {
- size_t rowlen = strlen(reg->y_array[i]);
+ size_t rowlen = reg->y_array[i].size;
maxlen = MAX(maxlen, rowlen);
}
assert(maxlen <= INT_MAX);
@@ -6873,7 +6900,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
reg->y_type = kMTUnknown;
}
- reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(char *));
+ reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(String));
reg->y_size = (size_t)tv_list_len(lines);
reg->additional_data = NULL;
reg->timestamp = 0;
@@ -6885,14 +6912,15 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
goto err;
}
- reg->y_array[tv_idx++] = xstrdupnul(TV_LIST_ITEM_TV(li)->vval.v_string);
+ const char *s = TV_LIST_ITEM_TV(li)->vval.v_string;
+ reg->y_array[tv_idx++] = cstr_to_string(s != NULL ? s : "");
});
- if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) {
+ if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
// a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) {
- xfree(reg->y_array[reg->y_size - 1]);
+ xfree(reg->y_array[reg->y_size - 1].data);
reg->y_size--;
if (reg->y_type == kMTUnknown) {
reg->y_type = kMTLineWise;
@@ -6907,7 +6935,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (reg->y_type == kMTBlockWise) {
size_t maxlen = 0;
for (size_t i = 0; i < reg->y_size; i++) {
- size_t rowlen = strlen(reg->y_array[i]);
+ size_t rowlen = reg->y_array[i].size;
maxlen = MAX(maxlen, rowlen);
}
assert(maxlen <= INT_MAX);
@@ -6920,7 +6948,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
err:
if (reg->y_array) {
for (size_t i = 0; i < reg->y_size; i++) {
- xfree(reg->y_array[i]);
+ xfree(reg->y_array[i].data);
}
xfree(reg->y_array);
}
@@ -6944,7 +6972,7 @@ static void set_clipboard(int name, yankreg_T *reg)
list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
for (size_t i = 0; i < reg->y_size; i++) {
- tv_list_append_string(lines, reg->y_array[i], -1);
+ tv_list_append_string(lines, reg->y_array[i].data, -1);
}
char regtype;
@@ -7028,7 +7056,7 @@ static inline bool reg_empty(const yankreg_T *const reg)
|| reg->y_size == 0
|| (reg->y_size == 1
&& reg->y_type == kMTCharWise
- && *(reg->y_array[0]) == NUL));
+ && reg->y_array[0].size == 0));
}
/// Iterate over global registers.
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 3cca52572f..35ee1e76dd 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -111,7 +111,7 @@ enum GRegFlags {
/// Definition of one register
typedef struct {
- char **y_array; ///< Pointer to an array of line pointers.
+ String *y_array; ///< Pointer to an array of Strings.
size_t y_size; ///< Number of lines in y_array.
MotionType y_type; ///< Register type
colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise).
diff --git a/src/nvim/option.c b/src/nvim/option.c
index ff0c0e2acf..bb86d10425 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -176,7 +176,7 @@ static int p_paste_dep_opts[] = {
void set_init_tablocal(void)
{
// susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal!
- p_ch = options[kOptCmdheight].def_val.number;
+ p_ch = options[kOptCmdheight].def_val.data.number;
}
/// Initialize the 'shell' option to a default value.
@@ -291,8 +291,8 @@ static void set_init_default_cdpath(void)
}
}
buf[j] = NUL;
- options[kOptCdpath].def_val.string = buf;
- options[kOptCdpath].flags |= P_DEF_ALLOCED;
+ change_option_default(kOptCdpath, CSTR_AS_OPTVAL(buf));
+
xfree(cdpath);
}
@@ -301,29 +301,22 @@ static void set_init_default_cdpath(void)
/// only happen for non-indirect options.
/// Also set the default to the expanded value, so ":set" does not list
/// them.
-/// Don't set the P_ALLOCED flag, because we don't want to free the
-/// default.
static void set_init_expand_env(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
vimoption_T *opt = &options[opt_idx];
- if (opt->flags & P_NO_DEF_EXP) {
+ if (opt->flags & kOptFlagNoDefExp) {
continue;
}
char *p;
- if ((opt->flags & P_GETTEXT) && opt->var != NULL) {
+ if ((opt->flags & kOptFlagGettext) && opt->var != NULL) {
p = _(*(char **)opt->var);
} else {
p = option_expand(opt_idx, NULL);
}
if (p != NULL) {
- p = xstrdup(p);
- *(char **)opt->var = p;
- if (opt->flags & P_DEF_ALLOCED) {
- xfree(opt->def_val.string);
- }
- opt->def_val.string = p;
- opt->flags |= P_DEF_ALLOCED;
+ set_option_varp(opt_idx, opt->var, CSTR_TO_OPTVAL(p), true);
+ change_option_default(opt_idx, CSTR_TO_OPTVAL(p));
}
}
}
@@ -354,6 +347,9 @@ void set_init_1(bool clean_arg)
{
langmap_init();
+ // Allocate the default option values.
+ alloc_options_default();
+
set_init_default_shell();
set_init_default_backupskip();
set_init_default_cdpath();
@@ -430,71 +426,73 @@ void set_init_1(bool clean_arg)
set_helplang_default(get_mess_lang());
}
-/// Set an option to its default value.
-/// This does not take care of side effects!
+/// Get default value for option, based on the option's type and scope.
///
-/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL.
+/// @param opt_idx Option index in options[] table.
+/// @param opt_flags Option flags.
///
-/// TODO(famiu): Refactor this when def_val uses OptVal.
-static void set_option_default(const OptIndex opt_idx, int opt_flags)
+/// @return Default value of option for the scope specified in opt_flags.
+static OptVal get_option_default(const OptIndex opt_idx, int opt_flags)
{
- bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
-
- // pointer to variable for current option
vimoption_T *opt = &options[opt_idx];
- void *varp = get_varp_scope(opt, both ? OPT_LOCAL : opt_flags);
- uint32_t flags = opt->flags;
- if (varp != NULL) { // skip hidden option, nothing to do for it
- if (option_has_type(opt_idx, kOptValTypeString)) {
- // Use set_option_direct() for local options to handle freeing and allocating the value.
- if (opt->indir != PV_NONE) {
- set_option_direct(opt_idx, CSTR_AS_OPTVAL(opt->def_val.string), opt_flags, 0);
- } else {
- if (flags & P_ALLOCED) {
- free_string_option(*(char **)(varp));
- }
- *(char **)varp = opt->def_val.string;
- opt->flags &= ~P_ALLOCED;
- }
- } else if (option_has_type(opt_idx, kOptValTypeNumber)) {
- if (opt->indir == PV_SCROLL) {
- win_comp_scroll(curwin);
- } else {
- OptInt def_val = opt->def_val.number;
- if ((OptInt *)varp == &curwin->w_p_so
- || (OptInt *)varp == &curwin->w_p_siso) {
- // 'scrolloff' and 'sidescrolloff' local values have a
- // different default value than the global default.
- *(OptInt *)varp = -1;
- } else {
- *(OptInt *)varp = def_val;
- }
- // May also set global value for local option.
- if (both) {
- *(OptInt *)get_varp_scope(opt, OPT_GLOBAL) = def_val;
- }
- }
- } else { // boolean
- *(int *)varp = opt->def_val.boolean;
+ bool is_global_local_option = option_is_global_local(opt_idx);
+
#ifdef UNIX
- // 'modeline' defaults to off for root
- if (opt->indir == PV_ML && getuid() == ROOT_UID) {
- *(int *)varp = false;
- }
+ if (opt_idx == kOptModeline && getuid() == ROOT_UID) {
+ // 'modeline' defaults to off for root.
+ return BOOLEAN_OPTVAL(false);
+ }
#endif
- // May also set global value for local option.
- if (both) {
- *(int *)get_varp_scope(opt, OPT_GLOBAL) =
- *(int *)varp;
- }
- }
- // The default value is not insecure.
- uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags);
- *flagsp = *flagsp & ~P_INSECURE;
+ if ((opt_flags & OPT_LOCAL) && is_global_local_option) {
+ // Use unset local value instead of default value for local scope of global-local options.
+ return get_option_unset_value(opt_idx);
+ } else if (option_has_type(opt_idx, kOptValTypeString) && !(opt->flags & kOptFlagNoDefExp)) {
+ // For string options, expand environment variables and ~ since the default value was already
+ // expanded, only required when an environment variable was set later.
+ char *s = option_expand(opt_idx, opt->def_val.data.string.data);
+ return s == NULL ? opt->def_val : CSTR_AS_OPTVAL(s);
+ } else {
+ return opt->def_val;
}
+}
- set_option_sctx(opt_idx, opt_flags, current_sctx);
+/// Allocate the default values for all options by copying them from the stack.
+/// This ensures that we don't need to always check if the option default is allocated or not.
+static void alloc_options_default(void)
+{
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
+ options[opt_idx].def_val = optval_copy(options[opt_idx].def_val);
+ }
+}
+
+/// Change the default value for an option.
+///
+/// @param opt_idx Option index in options[] table.
+/// @param value New default value. Must be allocated.
+static void change_option_default(const OptIndex opt_idx, OptVal value)
+{
+ optval_free(options[opt_idx].def_val);
+ options[opt_idx].def_val = value;
+}
+
+/// Set an option to its default value.
+/// This does not take care of side effects!
+///
+/// @param opt_idx Option index in options[] table.
+/// @param opt_flags Option flags.
+static void set_option_default(const OptIndex opt_idx, int opt_flags)
+{
+ OptVal def_val = get_option_default(opt_idx, opt_flags);
+ set_option_direct(opt_idx, def_val, opt_flags, current_sctx.sc_sid);
+
+ if (opt_idx == kOptScroll) {
+ win_comp_scroll(curwin);
+ }
+
+ // The default value is not insecure.
+ uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags);
+ *flagsp = *flagsp & ~(unsigned)kOptFlagInsecure;
}
/// Set all options (except terminal options) to their default value.
@@ -502,8 +500,8 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags)
/// @param opt_flags Option flags.
static void set_options_default(int opt_flags)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
- if (!(options[opt_idx].flags & P_NODEFAULT)) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
+ if (!(options[opt_idx].flags & kOptFlagNoDefault)) {
set_option_default(opt_idx, opt_flags);
}
}
@@ -522,20 +520,13 @@ static void set_options_default(int opt_flags)
/// @param opt_idx Option index in options[] table.
/// @param val The value of the option.
/// @param allocated If true, do not copy default as it was already allocated.
+///
+/// TODO(famiu): Remove this.
static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
FUNC_ATTR_NONNULL_ALL
{
- if (opt_idx == kOptInvalid) {
- return;
- }
-
- vimoption_T *opt = &options[opt_idx];
- if (opt->flags & P_DEF_ALLOCED) {
- xfree(opt->def_val.string);
- }
-
- opt->def_val.string = allocated ? val : xstrdup(val);
- opt->flags |= P_DEF_ALLOCED;
+ assert(opt_idx != kOptInvalid);
+ change_option_default(opt_idx, CSTR_AS_OPTVAL(allocated ? val : xstrdup(val)));
}
/// For an option value that contains comma separated items, find "newval" in
@@ -551,9 +542,9 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva
int bs = 0;
for (char *s = origval; *s != NUL; s++) {
- if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
+ if ((!(flags & kOptFlagComma) || s == origval || (s[-1] == ',' && !(bs & 1)))
&& strncmp(s, newval, newvallen) == 0
- && (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
+ && (!(flags & kOptFlagComma) || s[newvallen] == ',' || s[newvallen] == NUL)) {
return s;
}
// Count backslashes. Only a comma with an even number of backslashes
@@ -569,35 +560,28 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva
return NULL;
}
-/// Set the Vi-default value of a number option.
-/// Used for 'lines' and 'columns'.
-void set_number_default(OptIndex opt_idx, OptInt val)
-{
- if (opt_idx != kOptInvalid) {
- options[opt_idx].def_val.number = val;
- }
-}
-
#if defined(EXITFREE)
/// Free all options.
void free_all_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
- if (options[opt_idx].indir == PV_NONE) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
+ bool hidden = is_option_hidden(opt_idx);
+
+ if (option_is_global_only(opt_idx) || hidden) {
// global option: free value and default value.
- if ((options[opt_idx].flags & P_ALLOCED) && options[opt_idx].var != NULL) {
+ // hidden option: free default value only.
+ if (!hidden) {
optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
- if (options[opt_idx].flags & P_DEF_ALLOCED) {
- optval_free(optval_from_varp(opt_idx, &options[opt_idx].def_val));
- }
- } else if (options[opt_idx].var != VAR_WIN) {
- // buffer-local option: free global value
+ } else if (!option_is_window_local(opt_idx)) {
+ // buffer-local option: free global value.
optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
+ optval_free(options[opt_idx].def_val);
}
free_operatorfunc_option();
free_tagfunc_option();
+ free_findfunc_option();
XFREE_CLEAR(fenc_default);
XFREE_CLEAR(p_term);
XFREE_CLEAR(p_ttytype);
@@ -612,7 +596,7 @@ void set_init_2(bool headless)
// 'scroll' defaults to half the window height. The stored default is zero,
// which results in the actual value computed from the window height.
- if (!(options[kOptScroll].flags & P_WAS_SET)) {
+ if (!(options[kOptScroll].flags & kOptFlagWasSet)) {
set_option_default(kOptScroll, OPT_LOCAL);
}
comp_col();
@@ -622,7 +606,7 @@ void set_init_2(bool headless)
if (!option_was_set(kOptWindow)) {
p_window = Rows - 1;
}
- set_number_default(kOptWindow, Rows - 1);
+ change_option_default(kOptWindow, NUMBER_OPTVAL(Rows - 1));
}
/// Initialize the options, part three: After reading the .vimrc
@@ -633,56 +617,40 @@ void set_init_3(void)
// Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
// This is done after other initializations, where 'shell' might have been
// set, but only if they have not been set before.
- bool do_srr = !(options[kOptShellredir].flags & P_WAS_SET);
- bool do_sp = !(options[kOptShellpipe].flags & P_WAS_SET);
+ bool do_srr = !(options[kOptShellredir].flags & kOptFlagWasSet);
+ bool do_sp = !(options[kOptShellpipe].flags & kOptFlagWasSet);
size_t len = 0;
char *p = (char *)invocation_path_tail(p_sh, &len);
p = xmemdupz(p, len);
- {
- //
- // Default for p_sp is "| tee", for p_srr is ">".
- // For known shells it is changed here to include stderr.
- //
- if (path_fnamecmp(p, "csh") == 0
- || path_fnamecmp(p, "tcsh") == 0) {
- if (do_sp) {
- p_sp = "|& tee";
- options[kOptShellpipe].def_val.string = p_sp;
- }
- if (do_srr) {
- p_srr = ">&";
- options[kOptShellredir].def_val.string = p_srr;
- }
- } else if (path_fnamecmp(p, "sh") == 0
- || path_fnamecmp(p, "ksh") == 0
- || path_fnamecmp(p, "mksh") == 0
- || path_fnamecmp(p, "pdksh") == 0
- || path_fnamecmp(p, "zsh") == 0
- || path_fnamecmp(p, "zsh-beta") == 0
- || path_fnamecmp(p, "bash") == 0
- || path_fnamecmp(p, "fish") == 0
- || path_fnamecmp(p, "ash") == 0
- || path_fnamecmp(p, "dash") == 0) {
- // Always use POSIX shell style redirection if we reach this
- if (do_sp) {
- p_sp = "2>&1| tee";
- options[kOptShellpipe].def_val.string = p_sp;
- }
- if (do_srr) {
- p_srr = ">%s 2>&1";
- options[kOptShellredir].def_val.string = p_srr;
- }
+ bool is_csh = path_fnamecmp(p, "csh") == 0 || path_fnamecmp(p, "tcsh") == 0;
+ bool is_known_shell = path_fnamecmp(p, "sh") == 0 || path_fnamecmp(p, "ksh") == 0
+ || path_fnamecmp(p, "mksh") == 0 || path_fnamecmp(p, "pdksh") == 0
+ || path_fnamecmp(p, "zsh") == 0 || path_fnamecmp(p, "zsh-beta") == 0
+ || path_fnamecmp(p, "bash") == 0 || path_fnamecmp(p, "fish") == 0
+ || path_fnamecmp(p, "ash") == 0 || path_fnamecmp(p, "dash") == 0;
+
+ // Default for p_sp is "| tee", for p_srr is ">".
+ // For known shells it is changed here to include stderr.
+ if (is_csh || is_known_shell) {
+ if (do_sp) {
+ const OptVal sp =
+ is_csh ? STATIC_CSTR_AS_OPTVAL("|& tee") : STATIC_CSTR_AS_OPTVAL("2>&1| tee");
+ set_option_direct(kOptShellpipe, sp, 0, SID_NONE);
+ change_option_default(kOptShellpipe, optval_copy(sp));
+ }
+ if (do_srr) {
+ const OptVal srr = is_csh ? STATIC_CSTR_AS_OPTVAL(">&") : STATIC_CSTR_AS_OPTVAL(">%s 2>&1");
+ set_option_direct(kOptShellredir, srr, 0, SID_NONE);
+ change_option_default(kOptShellredir, optval_copy(srr));
}
- xfree(p);
}
+ xfree(p);
if (buf_is_empty(curbuf)) {
- int idx_ffs = find_option("ffs");
-
// Apply the first entry of 'fileformats' to the initial buffer.
- if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) {
+ if (options[kOptFileformats].flags & kOptFlagWasSet) {
set_fileformat(default_fileformat(), OPT_LOCAL);
}
}
@@ -702,13 +670,11 @@ void set_helplang_default(const char *lang)
if (lang_len < 2) { // safety check
return;
}
- if (options[kOptHelplang].flags & P_WAS_SET) {
+ if (options[kOptHelplang].flags & kOptFlagWasSet) {
return;
}
- if (options[kOptHelplang].flags & P_ALLOCED) {
- free_string_option(p_hlg);
- }
+ free_string_option(p_hlg);
p_hlg = xmemdupz(lang, lang_len);
// zh_CN becomes "cn", zh_TW becomes "tw".
if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
@@ -720,7 +686,6 @@ void set_helplang_default(const char *lang)
p_hlg[1] = 'n';
}
p_hlg[2] = NUL;
- options[kOptHelplang].flags |= P_ALLOCED;
}
/// 'title' and 'icon' only default to true if they have not been set or reset
@@ -733,13 +698,13 @@ void set_title_defaults(void)
// If GUI is (going to be) used, we can always set the window title and
// icon name. Saves a bit of time, because the X11 display server does
// not need to be contacted.
- if (!(options[kOptTitle].flags & P_WAS_SET)) {
- options[kOptTitle].def_val.boolean = false;
- p_title = false;
+ if (!(options[kOptTitle].flags & kOptFlagWasSet)) {
+ change_option_default(kOptTitle, BOOLEAN_OPTVAL(false));
+ p_title = 0;
}
- if (!(options[kOptIcon].flags & P_WAS_SET)) {
- options[kOptIcon].def_val.boolean = false;
- p_icon = false;
+ if (!(options[kOptIcon].flags & kOptFlagWasSet)) {
+ change_option_default(kOptIcon, BOOLEAN_OPTVAL(false));
+ p_icon = 0;
}
}
@@ -758,27 +723,6 @@ void ex_set(exarg_T *eap)
do_set(eap->arg, flags);
}
-/// Get the default value for a string option.
-static char *stropt_get_default_val(OptIndex opt_idx, uint64_t flags)
-{
- char *newval = options[opt_idx].def_val.string;
- // expand environment variables and ~ since the default value was
- // already expanded, only required when an environment variable was set
- // later
- if (newval == NULL) {
- newval = empty_string_option;
- } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) {
- char *s = option_expand(opt_idx, newval);
- if (s == NULL) {
- s = newval;
- }
- newval = xstrdup(s);
- } else {
- newval = xstrdup(newval);
- }
- return newval;
-}
-
/// Copy the new string value into allocated memory for the option.
/// Can't use set_option_direct(), because we need to remove the backslashes.
static char *stropt_copy_value(char *origval, char **argp, set_op_T op,
@@ -802,7 +746,7 @@ static char *stropt_copy_value(char *origval, char **argp, set_op_T op,
while (*arg != NUL && !ascii_iswhite(*arg)) {
if (*arg == '\\' && arg[1] != NUL
#ifdef BACKSLASH_IN_FILENAME
- && !((flags & P_EXPAND)
+ && !((flags & kOptFlagExpand)
&& vim_isfilec((uint8_t)arg[1])
&& !ascii_iswhite(arg[1])
&& (arg[1] != '\\'
@@ -851,12 +795,12 @@ static char *stropt_expand_envvar(OptIndex opt_idx, char *origval, char *newval,
static void stropt_concat_with_comma(char *origval, char *newval, set_op_T op, uint32_t flags)
{
int len = 0;
- int comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL);
+ int comma = ((flags & kOptFlagComma) && *origval != NUL && *newval != NUL);
if (op == OP_ADDING) {
len = (int)strlen(origval);
// Strip a trailing comma, would get 2.
if (comma && len > 1
- && (flags & P_ONECOMMA) == P_ONECOMMA
+ && (flags & kOptFlagOneComma) == kOptFlagOneComma
&& origval[len - 1] == ','
&& origval[len - 2] != '\\') {
len--;
@@ -881,7 +825,7 @@ static void stropt_remove_val(char *origval, char *newval, uint32_t flags, char
STRCPY(newval, origval);
if (*strval) {
// may need to remove a comma
- if (flags & P_COMMA) {
+ if (flags & kOptFlagComma) {
if (strval == origval) {
// include comma after string
if (strval[len] == ',') {
@@ -903,8 +847,8 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags)
char *s = newval;
// Remove flags that appear twice.
for (s = newval; *s;) {
- // if options have P_FLAGLIST and P_ONECOMMA such as 'whichwrap'
- if (flags & P_ONECOMMA) {
+ // if options have kOptFlagFlagList and kOptFlagOneComma such as 'whichwrap'
+ if (flags & kOptFlagOneComma) {
if (*s != ',' && *(s + 1) == ','
&& vim_strchr(s + 2, (uint8_t)(*s)) != NULL) {
// Remove the duplicated value and the next comma.
@@ -912,7 +856,7 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags)
continue;
}
} else {
- if ((!(flags & P_COMMA) || *s != ',')
+ if ((!(flags & kOptFlagComma) || *s != ',')
&& vim_strchr(s + 1, (uint8_t)(*s)) != NULL) {
STRMOVE(s, s + 1);
continue;
@@ -922,10 +866,7 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags)
}
}
-/// Get the string value specified for a ":set" command. The following set
-/// options are supported:
-/// set {opt}&
-/// set {opt}<
+/// Get the string value specified for a ":set" command. The following set options are supported:
/// set {opt}={val}
/// set {opt}:{val}
static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void *varp,
@@ -936,61 +877,56 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
char *save_arg = NULL;
char *newval;
char *s = NULL;
- if (nextchar == '&') { // set to default val
- newval = stropt_get_default_val(opt_idx, flags);
- } else if (nextchar == '<') { // set to global val
- newval = xstrdup(*(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL));
- } else {
- arg++; // jump to after the '=' or ':'
- // Set 'keywordprg' to ":help" if an empty
- // value was passed to :set by the user.
- if (varp == &p_kp && (*arg == NUL || *arg == ' ')) {
- save_arg = arg;
- arg = ":help";
- }
+ arg++; // jump to after the '=' or ':'
- // Copy the new string into allocated memory.
- newval = stropt_copy_value(origval, &arg, op, flags);
+ // Set 'keywordprg' to ":help" if an empty
+ // value was passed to :set by the user.
+ if (varp == &p_kp && (*arg == NUL || *arg == ' ')) {
+ save_arg = arg;
+ arg = ":help";
+ }
- // Expand environment variables and ~.
- // Don't do it when adding without inserting a comma.
- if (op == OP_NONE || (flags & P_COMMA)) {
- newval = stropt_expand_envvar(opt_idx, origval, newval, op);
- }
+ // Copy the new string into allocated memory.
+ newval = stropt_copy_value(origval, &arg, op, flags);
- // locate newval[] in origval[] when removing it
- // and when adding to avoid duplicates
- int len = 0;
- if (op == OP_REMOVING || (flags & P_NODUP)) {
- len = (int)strlen(newval);
- s = find_dup_item(origval, newval, (size_t)len, flags);
+ // Expand environment variables and ~.
+ // Don't do it when adding without inserting a comma.
+ if (op == OP_NONE || (flags & kOptFlagComma)) {
+ newval = stropt_expand_envvar(opt_idx, origval, newval, op);
+ }
- // do not add if already there
- if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
- op = OP_NONE;
- STRCPY(newval, origval);
- }
+ // locate newval[] in origval[] when removing it
+ // and when adding to avoid duplicates
+ int len = 0;
+ if (op == OP_REMOVING || (flags & kOptFlagNoDup)) {
+ len = (int)strlen(newval);
+ s = find_dup_item(origval, newval, (size_t)len, flags);
- // if no duplicate, move pointer to end of original value
- if (s == NULL) {
- s = origval + (int)strlen(origval);
- }
+ // do not add if already there
+ if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
+ op = OP_NONE;
+ STRCPY(newval, origval);
}
- // concatenate the two strings; add a ',' if needed
- if (op == OP_ADDING || op == OP_PREPENDING) {
- stropt_concat_with_comma(origval, newval, op, flags);
- } else if (op == OP_REMOVING) {
- // Remove newval[] from origval[]. (Note: "len" has been set above
- // and is used here).
- stropt_remove_val(origval, newval, flags, s, len);
+ // if no duplicate, move pointer to end of original value
+ if (s == NULL) {
+ s = origval + (int)strlen(origval);
}
+ }
- if (flags & P_FLAGLIST) {
- // Remove flags that appear twice.
- stropt_remove_dupflags(newval, flags);
- }
+ // concatenate the two strings; add a ',' if needed
+ if (op == OP_ADDING || op == OP_PREPENDING) {
+ stropt_concat_with_comma(origval, newval, op, flags);
+ } else if (op == OP_REMOVING) {
+ // Remove newval[] from origval[]. (Note: "len" has been set above
+ // and is used here).
+ stropt_remove_val(origval, newval, flags, s, len);
+ }
+
+ if (flags & kOptFlagFlagList) {
+ // Remove flags that appear twice.
+ stropt_remove_dupflags(newval, flags);
}
if (save_arg != NULL) {
@@ -1041,38 +977,35 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_
// Skip all options that are not window-local (used when showing
// an already loaded buffer in a window).
- if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || options[opt_idx].var != VAR_WIN)) {
+ if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || !option_is_window_local(opt_idx))) {
return FAIL;
}
// Skip all options that are window-local (used for :vimgrep).
- if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && options[opt_idx].var == VAR_WIN) {
+ if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && option_is_window_local(opt_idx)) {
return FAIL;
}
// Disallow changing some options from modelines.
if (opt_flags & OPT_MODELINE) {
- if (flags & (P_SECURE | P_NO_ML)) {
+ if (flags & (kOptFlagSecure | kOptFlagNoML)) {
*errmsg = e_not_allowed_in_modeline;
return FAIL;
}
- if ((flags & P_MLE) && !p_mle) {
+ if ((flags & kOptFlagMLE) && !p_mle) {
*errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
return FAIL;
}
// In diff mode some options are overruled. This avoids that
// 'foldmethod' becomes "marker" instead of "diff" and that
// "wrap" gets set.
- if (win->w_p_diff
- && opt_idx != kOptInvalid // shut up coverity warning
- && (options[opt_idx].indir == PV_FDM
- || options[opt_idx].indir == PV_WRAP)) {
+ if (win->w_p_diff && (opt_idx == kOptFoldmethod || opt_idx == kOptWrap)) {
return FAIL;
}
}
// Disallow changing some options in the sandbox
- if (sandbox != 0 && (flags & P_SECURE)) {
+ if (sandbox != 0 && (flags & kOptFlagSecure)) {
*errmsg = e_sandbox;
return FAIL;
}
@@ -1152,6 +1085,7 @@ const char *find_option_end(const char *arg, OptIndex *opt_idxp)
}
/// Get new option value from argp. Allocated OptVal must be freed by caller.
+/// Can unset local value of an option when ":set {option}<" is used.
static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T prefix, char **argp,
int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf,
const size_t errbuflen, const char **errmsg)
@@ -1162,10 +1096,24 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
vimoption_T *opt = &options[opt_idx];
char *arg = *argp;
// When setting the local value of a global option, the old value may be the global value.
- const bool oldval_is_global = ((int)opt->indir & PV_BOTH) && (opt_flags & OPT_LOCAL);
+ const bool oldval_is_global = option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL);
OptVal oldval = optval_from_varp(opt_idx, oldval_is_global ? get_varp(opt) : varp);
OptVal newval = NIL_OPTVAL;
+ if (nextchar == '&') {
+ // ":set opt&": Reset to default value.
+ // NOTE: Use OPT_GLOBAL instead of opt_flags to ensure we don't use the unset local value for
+ // global-local options when OPT_LOCAL is used.
+ return optval_copy(get_option_default(opt_idx, OPT_GLOBAL));
+ } else if (nextchar == '<') {
+ // ":set opt<": Reset to global value.
+ // ":setlocal opt<": Copy global value to local value.
+ if (option_is_global_local(opt_idx) && !(opt_flags & OPT_LOCAL)) {
+ unset_option_local_value(opt_idx);
+ }
+ return get_option_value(opt_idx, OPT_GLOBAL);
+ }
+
switch (oldval.type) {
case kOptValTypeNil:
abort();
@@ -1173,8 +1121,6 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
TriState newval_bool;
// ":set opt!": invert
- // ":set opt&": reset to default value
- // ":set opt<": reset to global value
if (nextchar == '!') {
switch (oldval.data.boolean) {
case kNone:
@@ -1187,15 +1133,6 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
newval_bool = kTrue;
break;
}
- } else if (nextchar == '&') {
- newval_bool = TRISTATE_FROM_INT(options[opt_idx].def_val.boolean);
- } else if (nextchar == '<') {
- // For 'autoread', kNone means to use global value.
- if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) {
- newval_bool = kNone;
- } else {
- newval_bool = TRISTATE_FROM_INT(*(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL));
- }
} else {
// ":set invopt": invert
// ":set opt" or ":set noopt": set or reset
@@ -1214,31 +1151,15 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
OptInt newval_num;
// Different ways to set a number option:
- // & set to default value
- // < set to global value
// <xx> accept special key codes for 'wildchar' or 'wildcharm'
// ^x accept ctrl key codes for 'wildchar' or 'wildcharm'
// c accept any non-digit for 'wildchar' or 'wildcharm'
// [-]0-9 set number
// other error
arg++;
- if (nextchar == '&') {
- newval_num = options[opt_idx].def_val.number;
- } else if (nextchar == '<') {
- if ((OptInt *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) {
- // for 'undolevels' NO_LOCAL_UNDOLEVEL means using the global newval_num
- newval_num = NO_LOCAL_UNDOLEVEL;
- } else if (opt_flags == OPT_LOCAL
- && ((OptInt *)varp == &curwin->w_p_siso || (OptInt *)varp == &curwin->w_p_so)) {
- // for 'scrolloff'/'sidescrolloff' -1 means using the global newval_num
- newval_num = -1;
- } else {
- newval_num = *(OptInt *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
- }
- } else if (((OptInt *)varp == &p_wc || (OptInt *)varp == &p_wcm)
- && (*arg == '<' || *arg == '^'
- || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1]))
- && !ascii_isdigit(*arg)))) {
+ if (((OptInt *)varp == &p_wc || (OptInt *)varp == &p_wcm)
+ && (*arg == '<' || *arg == '^'
+ || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) && !ascii_isdigit(*arg)))) {
newval_num = string_to_key(arg);
if (newval_num == 0) {
*errmsg = e_invarg;
@@ -1318,21 +1239,10 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
}
uint8_t nextchar = (uint8_t)(*p); // next non-white char after option name
- uint32_t flags = 0; // flags for current option
- void *varp = NULL; // pointer to variable for current option
-
- if (options[opt_idx].var == NULL) { // hidden option: skip
- // Only give an error message when requesting the value of
- // a hidden option, ignore setting it.
- if (vim_strchr("=:!&<", nextchar) == NULL
- && (!option_has_type(opt_idx, kOptValTypeBoolean) || nextchar == '?')) {
- *errmsg = e_unsupportedoption;
- }
- return;
- }
-
- flags = options[opt_idx].flags;
- varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+ // flags for current option
+ uint32_t flags = options[opt_idx].flags;
+ // pointer to variable for current option
+ void *varp = get_varp_scope(&(options[opt_idx]), opt_flags);
if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) {
return;
@@ -1372,10 +1282,10 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
// Mention where the option was last set.
if (varp == options[opt_idx].var) {
option_last_set_msg(options[opt_idx].last_set);
- } else if ((int)options[opt_idx].indir & PV_WIN) {
- option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
- } else if ((int)options[opt_idx].indir & PV_BUF) {
- option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
+ } else if (option_has_scope(opt_idx, kOptScopeWin)) {
+ option_last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]);
+ } else if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ option_last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]);
}
}
@@ -1402,11 +1312,6 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
}
}
- // Don't try to change hidden option.
- if (varp == NULL) {
- return;
- }
-
OptVal newval = get_option_newval(opt_idx, opt_flags, prefix, argp, nextchar, op, flags, varp,
errbuf, errbuflen, errmsg);
@@ -1414,8 +1319,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
return;
}
- *errmsg = set_option(opt_idx, varp, newval, opt_flags, 0, false, op == OP_NONE, errbuf,
- errbuflen);
+ *errmsg = set_option(opt_idx, newval, opt_flags, 0, false, op == OP_NONE, errbuf, errbuflen);
}
/// Parse 'arg' for option settings.
@@ -1664,7 +1568,7 @@ char *find_shada_parameter(int type)
static char *option_expand(OptIndex opt_idx, char *val)
{
// if option doesn't need expansion nothing to do
- if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) {
+ if (!(options[opt_idx].flags & kOptFlagExpand) || is_option_hidden(opt_idx)) {
return NULL;
}
@@ -1705,7 +1609,7 @@ static void didset_options(void)
spell_check_msm();
spell_check_sps();
compile_cap_prog(curwin->w_s);
- did_set_spell_option(true);
+ did_set_spell_option();
// set cedit_key
did_set_cedit(NULL);
// initialize the table for 'breakat'.
@@ -1736,7 +1640,7 @@ static void didset_options2(void)
/// Check for string options that are NULL (normally only termcap options).
void check_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
if ((option_has_type(opt_idx, kOptValTypeString)) && options[opt_idx].var != NULL) {
check_string_option((char **)get_varp(&(options[opt_idx])));
}
@@ -1755,10 +1659,10 @@ int was_set_insecurely(win_T *const wp, OptIndex opt_idx, int opt_flags)
assert(opt_idx != kOptInvalid);
uint32_t *flagp = insecure_flag(wp, opt_idx, opt_flags);
- return (*flagp & P_INSECURE) != 0;
+ return (*flagp & kOptFlagInsecure) != 0;
}
-/// Get a pointer to the flags used for the P_INSECURE flag of option
+/// Get a pointer to the flags used for the kOptFlagInsecure flag of option
/// "opt_idx". For some local options a local flags field is used.
/// NOTE: Caller must make sure that "wp" is set to the window from which
/// the option is used.
@@ -1766,24 +1670,25 @@ uint32_t *insecure_flag(win_T *const wp, OptIndex opt_idx, int opt_flags)
{
if (opt_flags & OPT_LOCAL) {
assert(wp != NULL);
- switch ((int)options[opt_idx].indir) {
- case PV_STL:
+ switch (opt_idx) {
+ case kOptStatusline:
return &wp->w_p_stl_flags;
- case PV_WBR:
+ case kOptWinbar:
return &wp->w_p_wbr_flags;
- case PV_FDE:
+ case kOptFoldexpr:
return &wp->w_p_fde_flags;
- case PV_FDT:
+ case kOptFoldtext:
return &wp->w_p_fdt_flags;
- case PV_INDE:
+ case kOptIndentexpr:
return &wp->w_buffer->b_p_inde_flags;
- case PV_FEX:
+ case kOptFormatexpr:
return &wp->w_buffer->b_p_fex_flags;
- case PV_INEX:
+ case kOptIncludeexpr:
return &wp->w_buffer->b_p_inex_flags;
+ default:
+ break;
}
}
-
// Nothing special, return global flags field.
return &options[opt_idx].flags;
}
@@ -1816,12 +1721,22 @@ void check_blending(win_T *wp)
}
/// Handle setting `winhighlight' in window "wp"
-bool parse_winhl_opt(win_T *wp)
+///
+/// @param winhl when NULL: use "wp->w_p_winhl"
+/// @param wp when NULL: only parse "winhl"
+///
+/// @return whether the option value is valid.
+bool parse_winhl_opt(const char *winhl, win_T *wp)
{
- const char *p = wp->w_p_winhl;
+ const char *p = empty_string_option;
+ if (winhl != NULL) {
+ p = winhl;
+ } else if (wp != NULL) {
+ p = wp->w_p_winhl;
+ }
if (!*p) {
- if (wp->w_ns_hl_winhl && wp->w_ns_hl == wp->w_ns_hl_winhl) {
+ if (wp != NULL && wp->w_ns_hl_winhl && wp->w_ns_hl == wp->w_ns_hl_winhl) {
wp->w_ns_hl = 0;
wp->w_hl_needs_update = true;
}
@@ -1829,39 +1744,49 @@ bool parse_winhl_opt(win_T *wp)
return true;
}
- if (wp->w_ns_hl_winhl == 0) {
- wp->w_ns_hl_winhl = (int)nvim_create_namespace(NULL_STRING);
- } else {
- // namespace already exist. invalidate existing items
- DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true);
- dp->hl_valid++;
+ int ns_hl = 0;
+ if (wp != NULL) {
+ if (wp->w_ns_hl_winhl == 0) {
+ wp->w_ns_hl_winhl = (int)nvim_create_namespace(NULL_STRING);
+ } else {
+ // Namespace already exists. Invalidate existing items.
+ DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true);
+ dp->hl_valid++;
+ }
+ wp->w_ns_hl = wp->w_ns_hl_winhl;
+ ns_hl = wp->w_ns_hl;
}
- wp->w_ns_hl = wp->w_ns_hl_winhl;
- int ns_hl = wp->w_ns_hl;
while (*p) {
- char *colon = strchr(p, ':');
+ const char *colon = strchr(p, ':');
if (!colon) {
return false;
}
size_t nlen = (size_t)(colon - p);
- char *hi = colon + 1;
- char *commap = xstrchrnul(hi, ',');
+ const char *hi = colon + 1;
+ const char *commap = xstrchrnul(hi, ',');
size_t len = (size_t)(commap - hi);
int hl_id = len ? syn_check_group(hi, len) : -1;
if (hl_id == 0) {
return false;
}
int hl_id_link = nlen ? syn_check_group(p, nlen) : 0;
+ if (hl_id_link == 0) {
+ return false;
+ }
- HlAttrs attrs = HLATTRS_INIT;
- attrs.rgb_ae_attr |= HL_GLOBAL;
- ns_hl_def(ns_hl, hl_id_link, attrs, hl_id, NULL);
+ if (wp != NULL) {
+ HlAttrs attrs = HLATTRS_INIT;
+ attrs.rgb_ae_attr |= HL_GLOBAL;
+ ns_hl_def(ns_hl, hl_id_link, attrs, hl_id, NULL);
+ }
p = *commap ? commap + 1 : "";
}
- wp->w_hl_needs_update = true;
+ if (wp != NULL) {
+ wp->w_hl_needs_update = true;
+ }
return true;
}
@@ -1877,7 +1802,6 @@ sctx_T *get_option_sctx(OptIndex opt_idx)
void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
{
bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- int indir = (int)options[opt_idx].indir;
nlua_set_sctx(&script_ctx);
LastSet last_set = {
.script_ctx = script_ctx,
@@ -1891,17 +1815,17 @@ void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
- if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) {
+ if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) {
options[opt_idx].last_set = last_set;
}
if (both || (opt_flags & OPT_LOCAL)) {
- if (indir & PV_BUF) {
- curbuf->b_p_script_ctx[indir & PV_MASK] = last_set;
- } else if (indir & PV_WIN) {
- curwin->w_p_script_ctx[indir & PV_MASK] = last_set;
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = last_set;
+ } else if ((option_has_scope(opt_idx, kOptScopeWin))) {
+ curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
if (both) {
// also setting the "all buffers" value
- curwin->w_allbuf_opt.wo_script_ctx[indir & PV_MASK] = last_set;
+ curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
}
}
}
@@ -1959,7 +1883,7 @@ static const char *did_set_arabic(optset_T *args)
// set rightleft mode
if (!win->w_p_rl) {
win->w_p_rl = true;
- changed_window_setting(curwin);
+ changed_window_setting(win);
}
// Enable Arabic shaping (major part of what Arabic requires)
@@ -1974,8 +1898,8 @@ static const char *did_set_arabic(optset_T *args)
if (strcmp(p_enc, "utf-8") != 0) {
static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
- msg_source(HL_ATTR(HLF_W));
- msg(_(w_arabic), HL_ATTR(HLF_W));
+ msg_source(HLF_W);
+ msg(_(w_arabic), HLF_W);
set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1);
}
@@ -1990,7 +1914,7 @@ static const char *did_set_arabic(optset_T *args)
// reset rightleft mode
if (win->w_p_rl) {
win->w_p_rl = false;
- changed_window_setting(curwin);
+ changed_window_setting(win);
}
// 'arabicshape' isn't reset, it is a global option and
@@ -2001,8 +1925,8 @@ static const char *did_set_arabic(optset_T *args)
// window may still want it "on".
// Revert to the default keymap
- curbuf->b_p_iminsert = B_IMODE_NONE;
- curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
+ win->w_buffer->b_p_iminsert = B_IMODE_NONE;
+ win->w_buffer->b_p_imsearch = B_IMODE_USE_INSERT;
}
return errmsg;
@@ -2124,9 +2048,7 @@ static const char *did_set_helpheight(optset_T *args)
{
// Change window height NOW
if (!ONE_WINDOW) {
- buf_T *buf = (buf_T *)args->os_buf;
- win_T *win = (win_T *)args->os_win;
- if (buf->b_help && win->w_height < p_hh) {
+ if (curbuf->b_help && curwin->w_height < p_hh) {
win_setheight((int)p_hh);
}
}
@@ -2278,7 +2200,7 @@ static const char *did_set_number_relativenumber(optset_T *args)
// When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width.
win->w_nrwidth_line_count = 0;
}
- check_signcolumn(win);
+ check_signcolumn(NULL, win);
return NULL;
}
@@ -2455,14 +2377,16 @@ static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED)
/// Process the updated 'readonly' option value.
static const char *did_set_readonly(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+
// when 'readonly' is reset globally, also reset readonlymode
- if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) {
+ if (!buf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) {
readonlymode = false;
}
// when 'readonly' is set may give W10 again
- if (curbuf->b_p_ro) {
- curbuf->b_did_warn = false;
+ if (buf->b_p_ro) {
+ buf->b_did_warn = false;
}
redraw_titles();
@@ -2578,8 +2502,7 @@ static const char *did_set_swapfile(optset_T *args)
if (buf->b_p_swf && p_uc) {
ml_open_file(buf); // create the swap file
} else {
- // no need to reset curbuf->b_may_swap, ml_open_file() will check
- // buf->b_p_swf
+ // no need to reset buf->b_may_swap, ml_open_file() will check buf->b_p_swf
mf_close_file(buf, true); // remove the swap file
}
return NULL;
@@ -2589,7 +2512,7 @@ static const char *did_set_swapfile(optset_T *args)
static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
- check_colorcolumn(wp);
+ check_colorcolumn(NULL, wp);
}
return NULL;
@@ -2619,8 +2542,10 @@ static const char *did_set_titlelen(optset_T *args)
/// Process the updated 'undofile' option value.
static const char *did_set_undofile(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+
// Only take action when the option was set.
- if (!curbuf->b_p_udf && !p_udf) {
+ if (!buf->b_p_udf && !p_udf) {
return NULL;
}
@@ -2633,7 +2558,7 @@ static const char *did_set_undofile(optset_T *args)
// only for the current buffer: Try to read in the undofile,
// if one exists, the buffer wasn't changed and the buffer was
// loaded
- if ((curbuf == bp
+ if ((buf == bp
|| (args->os_flags & OPT_GLOBAL) || args->os_flags == 0)
&& !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) {
u_compute_hash(bp, hash);
@@ -2673,7 +2598,7 @@ static const char *did_set_undolevels(optset_T *args)
if (pp == &p_ul) { // global 'undolevels'
did_set_global_undolevels(args->os_newval.number, args->os_oldval.number);
- } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels'
+ } else if (pp == &buf->b_p_ul) { // buffer local 'undolevels'
did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number);
}
@@ -2738,8 +2663,7 @@ static const char *did_set_winheight(optset_T *args)
{
// Change window height NOW
if (!ONE_WINDOW) {
- win_T *win = (win_T *)args->os_win;
- if (win->w_height < p_wh) {
+ if (curwin->w_height < p_wh) {
win_setheight((int)p_wh);
}
}
@@ -2750,9 +2674,7 @@ static const char *did_set_winheight(optset_T *args)
/// Process the new 'winwidth' option value.
static const char *did_set_winwidth(optset_T *args)
{
- win_T *win = (win_T *)args->os_win;
-
- if (!ONE_WINDOW && win->w_width < p_wiw) {
+ if (!ONE_WINDOW && curwin->w_width < p_wiw) {
win_setwidth((int)p_wiw);
}
return NULL;
@@ -2815,15 +2737,14 @@ static void do_spelllang_source(win_T *win)
/// Check the bounds of numeric options.
///
/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
-/// @param[in] varp Pointer to option variable.
/// @param[in,out] newval Pointer to new option value. Will be set to bound checked value.
/// @param[out] errbuf Buffer for error message. Cannot be NULL.
/// @param errbuflen Length of error buffer.
///
/// @return Error message, if any.
-static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt *newval,
- char *errbuf, size_t errbuflen)
- FUNC_ATTR_NONNULL_ARG(4)
+static const char *check_num_option_bounds(OptIndex opt_idx, OptInt *newval, char *errbuf,
+ size_t errbuflen)
+ FUNC_ATTR_NONNULL_ARG(3)
{
const char *errmsg = NULL;
@@ -2856,9 +2777,7 @@ static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt
}
break;
case kOptScroll:
- if (varp == &(curwin->w_p_scr)
- && (*newval <= 0
- || (*newval > curwin->w_height_inner && curwin->w_height_inner > 0))
+ if ((*newval <= 0 || (*newval > curwin->w_height_inner && curwin->w_height_inner > 0))
&& full_screen) {
if (*newval != 0) {
errmsg = e_scroll;
@@ -2876,13 +2795,12 @@ static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt
/// Validate and bound check option value.
///
/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
-/// @param[in] varp Pointer to option variable.
/// @param[in,out] newval Pointer to new option value. Will be set to bound checked value.
/// @param[out] errbuf Buffer for error message. Cannot be NULL.
/// @param errbuflen Length of error buffer.
///
/// @return Error message, if any.
-static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *newval, char *errbuf,
+static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *errbuf,
size_t errbuflen)
{
OptInt value = *newval;
@@ -2892,167 +2810,168 @@ static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *new
return e_invarg;
}
- if (varp == &p_wh) {
+ switch (opt_idx) {
+ case kOptHelpheight:
+ case kOptTitlelen:
+ case kOptUpdatecount:
+ case kOptReport:
+ case kOptUpdatetime:
+ case kOptSidescroll:
+ case kOptFoldlevel:
+ case kOptShiftwidth:
+ case kOptTextwidth:
+ case kOptWritedelay:
+ case kOptTimeoutlen:
+ if (value < 0) {
+ return e_positive;
+ }
+ break;
+ case kOptWinheight:
if (value < 1) {
return e_positive;
} else if (p_wmh > value) {
return e_winheight;
}
- } else if (varp == &p_hh) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_wmh) {
+ break;
+ case kOptWinminheight:
if (value < 0) {
return e_positive;
} else if (value > p_wh) {
return e_winheight;
}
- } else if (varp == &p_wiw) {
+ break;
+ case kOptWinwidth:
if (value < 1) {
return e_positive;
} else if (p_wmw > value) {
return e_winwidth;
}
- } else if (varp == &p_wmw) {
+ break;
+ case kOptWinminwidth:
if (value < 0) {
return e_positive;
} else if (value > p_wiw) {
return e_winwidth;
}
- } else if (varp == &p_titlelen) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_uc) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_ch) {
+ break;
+ case kOptMaxcombine:
+ *newval = MAX_MCO;
+ break;
+ case kOptCmdheight:
if (value < 0) {
return e_positive;
} else {
p_ch_was_zero = value == 0;
}
- } else if (varp == &p_tm) {
+ break;
+ case kOptHistory:
if (value < 0) {
return e_positive;
+ } else if (value > 10000) {
+ return e_invarg;
}
- } else if (varp == &p_hi) {
+ break;
+ case kOptMsghistory:
if (value < 0) {
return e_positive;
} else if (value > 10000) {
return e_invarg;
}
- } else if (varp == &p_pyx) {
+ break;
+ case kOptPyxversion:
if (value == 0) {
*newval = 3;
} else if (value != 3) {
return e_invarg;
}
- } else if (varp == &p_re) {
+ break;
+ case kOptRegexpengine:
if (value < 0 || value > 2) {
return e_invarg;
}
- } else if (varp == &p_report) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_so) {
+ break;
+ case kOptScrolloff:
if (value < 0 && full_screen) {
return e_positive;
}
- } else if (varp == &p_siso) {
+ break;
+ case kOptSidescrolloff:
if (value < 0 && full_screen) {
return e_positive;
}
- } else if (varp == &p_cwh) {
+ break;
+ case kOptCmdwinheight:
if (value < 1) {
return e_positive;
}
- } else if (varp == &p_ut) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_ss) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &curwin->w_p_fdl || varp == &curwin->w_allbuf_opt.wo_fdl) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &curwin->w_p_cole || varp == &curwin->w_allbuf_opt.wo_cole) {
+ break;
+ case kOptConceallevel:
if (value < 0) {
return e_positive;
} else if (value > 3) {
return e_invarg;
}
- } else if (varp == &curwin->w_p_nuw || varp == &curwin->w_allbuf_opt.wo_nuw) {
+ break;
+ case kOptNumberwidth:
if (value < 1) {
return e_positive;
} else if (value > MAX_NUMBERWIDTH) {
return e_invarg;
}
- } else if (varp == &curbuf->b_p_iminsert || varp == &p_iminsert) {
+ break;
+ case kOptIminsert:
if (value < 0 || value > B_IMODE_LAST) {
return e_invarg;
}
- } else if (varp == &curbuf->b_p_imsearch || varp == &p_imsearch) {
+ break;
+ case kOptImsearch:
if (value < -1 || value > B_IMODE_LAST) {
return e_invarg;
}
- } else if (varp == &curbuf->b_p_channel || varp == &p_channel) {
+ break;
+ case kOptChannel:
return e_invarg;
- } else if (varp == &curbuf->b_p_scbk || varp == &p_scbk) {
+ case kOptScrollback:
if (value < -1 || value > SB_MAX) {
return e_invarg;
}
- } else if (varp == &curbuf->b_p_sw || varp == &p_sw) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &curbuf->b_p_ts || varp == &p_ts) {
+ break;
+ case kOptTabstop:
if (value < 1) {
return e_positive;
} else if (value > TABSTOP_MAX) {
return e_invarg;
}
- } else if (varp == &curbuf->b_p_tw || varp == &p_tw) {
- if (value < 0) {
- return e_positive;
- }
- } else if (varp == &p_wd) {
- if (value < 0) {
- return e_positive;
- }
+ break;
+ default:
+ break;
}
- return check_num_option_bounds(opt_idx, varp, newval, errbuf, errbuflen);
+ return check_num_option_bounds(opt_idx, newval, errbuf, errbuflen);
}
/// Called after an option changed: check if something needs to be redrawn.
void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags)
{
- // Careful: P_RALL is a combination of other P_ flags
- bool all = (flags & P_RALL) == P_RALL;
+ // Careful: kOptFlagRedrAll is a combination of other redraw flags
+ bool all = (flags & kOptFlagRedrAll) == kOptFlagRedrAll;
- if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty
+ if ((flags & kOptFlagRedrStat) || all) { // mark all status lines and window bars dirty
status_redraw_all();
}
- if ((flags & P_RTABL) || all) { // mark tablines dirty
+ if ((flags & kOptFlagRedrTabl) || all) { // mark tablines dirty
redraw_tabline = true;
}
- if ((flags & P_RBUF) || (flags & P_RWIN) || all) {
- if (flags & P_HLONLY) {
+ if ((flags & kOptFlagRedrBuf) || (flags & kOptFlagRedrWin) || all) {
+ if (flags & kOptFlagHLOnly) {
redraw_later(win, UPD_NOT_VALID);
} else {
changed_window_setting(win);
}
}
- if (flags & P_RBUF) {
+ if (flags & kOptFlagRedrBuf) {
redraw_buf_later(buf, UPD_NOT_VALID);
}
if (all) {
@@ -3193,11 +3112,25 @@ bool optval_equal(OptVal o1, OptVal o2)
return o1.data.number == o2.data.number;
case kOptValTypeString:
return o1.data.string.size == o2.data.string.size
- && strnequal(o1.data.string.data, o2.data.string.data, o1.data.string.size);
+ && (o1.data.string.data == o2.data.string.data
+ || strnequal(o1.data.string.data, o2.data.string.data, o1.data.string.size));
}
UNREACHABLE;
}
+/// Get type of option. Does not support multitype options.
+static OptValType option_get_type(const OptIndex opt_idx)
+{
+ assert(!option_is_multitype(opt_idx));
+
+ // If the option only supports a single type, it means that the index of the option's type flag
+ // corresponds to the value of the type enum. So get the index of the type flag using xctz() and
+ // use that as the option's type.
+ OptValType type = xctz(options[opt_idx].type_flags);
+ assert(type > kOptValTypeNil && type < kOptValTypeSize);
+ return type;
+}
+
/// Create OptVal from var pointer.
///
/// @param opt_idx Option index in options[] table.
@@ -3205,6 +3138,7 @@ bool optval_equal(OptVal o1, OptVal o2)
///
/// @return Option value stored in varp.
OptVal optval_from_varp(OptIndex opt_idx, void *varp)
+ FUNC_ATTR_NONNULL_ARG(2)
{
// Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc'
// changed.
@@ -3214,24 +3148,20 @@ OptVal optval_from_varp(OptIndex opt_idx, void *varp)
if (option_is_multitype(opt_idx)) {
// Multitype options are stored as OptVal.
- return varp == NULL ? NIL_OPTVAL : *(OptVal *)varp;
+ return *(OptVal *)varp;
}
- // If the option only supports a single type, it means that the index of the option's type flag
- // corresponds to the value of the type enum. So get the index of the type flag using xctz() and
- // use that as the option's type.
- OptValType type = xctz(options[opt_idx].type_flags);
- assert(type > kOptValTypeNil && type < kOptValTypeSize);
+ OptValType type = option_get_type(opt_idx);
switch (type) {
case kOptValTypeNil:
return NIL_OPTVAL;
case kOptValTypeBoolean:
- return BOOLEAN_OPTVAL(varp == NULL ? false : TRISTATE_FROM_INT(*(int *)varp));
+ return BOOLEAN_OPTVAL(TRISTATE_FROM_INT(*(int *)varp));
case kOptValTypeNumber:
- return NUMBER_OPTVAL(varp == NULL ? 0 : *(OptInt *)varp);
+ return NUMBER_OPTVAL(*(OptInt *)varp);
case kOptValTypeString:
- return STRING_OPTVAL(varp == NULL ? (String)STRING_INIT : cstr_as_string(*(char **)varp));
+ return STRING_OPTVAL(cstr_as_string(*(char **)varp));
}
UNREACHABLE;
}
@@ -3334,7 +3264,7 @@ OptVal object_as_optval(Object o, bool *error)
/// Get an allocated string containing a list of valid types for an option.
/// For options with a singular type, it returns the name of the type. For options with multiple
/// possible types, it returns a slash separated list of types. For example, if an option can be a
-/// number, boolean or string, the function returns "Number/Boolean/String"
+/// number, boolean or string, the function returns "number/boolean/string"
static char *option_get_valid_types(OptIndex opt_idx)
{
StringBuilder str = KV_INITIAL_VALUE;
@@ -3356,8 +3286,6 @@ static char *option_get_valid_types(OptIndex opt_idx)
// Ensure that the string is NUL-terminated.
kv_push(str, NUL);
return str.items;
-
-#undef OPTION_ADD_TYPE
}
/// Check if option is hidden.
@@ -3367,7 +3295,74 @@ static char *option_get_valid_types(OptIndex opt_idx)
/// @return True if option is hidden, false otherwise. Returns false if option name is invalid.
bool is_option_hidden(OptIndex opt_idx)
{
- return opt_idx == kOptInvalid ? false : get_varp(&options[opt_idx]) == NULL;
+ // Hidden options are always immutable and point to their default value
+ return opt_idx != kOptInvalid && options[opt_idx].immutable
+ && options[opt_idx].var == &options[opt_idx].def_val.data;
+}
+
+/// Check if option is multitype (supports multiple types).
+static bool option_is_multitype(OptIndex opt_idx)
+{
+ const OptTypeFlags type_flags = get_option(opt_idx)->type_flags;
+ assert(type_flags != 0);
+ return !is_power_of_two(type_flags);
+}
+
+/// Check if option supports a specific type.
+bool option_has_type(OptIndex opt_idx, OptValType type)
+{
+ // Ensure that type flags variable can hold all types.
+ STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8,
+ "Option type_flags cannot fit all option types");
+ // Ensure that the type is valid before accessing type_flags.
+ assert(type > kOptValTypeNil && type < kOptValTypeSize);
+ // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in
+ // the type_flags bit field.
+ return get_option(opt_idx)->type_flags & (1 << type);
+}
+
+/// Check if option supports a specific scope.
+bool option_has_scope(OptIndex opt_idx, OptScope scope)
+{
+ // Ensure that scope flags variable can hold all scopes.
+ STATIC_ASSERT(kOptScopeSize <= sizeof(OptScopeFlags) * 8,
+ "Option scope_flags cannot fit all option scopes");
+ // Ensure that the scope is valid before accessing scope_flags.
+ assert(scope >= kOptScopeGlobal && scope < kOptScopeSize);
+ // Bitshift 1 by the value of scope to get the scope's corresponding flag, and check if it's set
+ // in the scope_flags bit field.
+ return get_option(opt_idx)->scope_flags & (1 << scope);
+}
+
+/// Check if option is global-local.
+static inline bool option_is_global_local(OptIndex opt_idx)
+{
+ // Global-local options have at least two types, so their type flag cannot be a power of two.
+ return opt_idx != kOptInvalid && !is_power_of_two(options[opt_idx].scope_flags);
+}
+
+/// Check if option only supports global scope.
+static inline bool option_is_global_only(OptIndex opt_idx)
+{
+ // For an option to be global-only, it has to only have a single scope, which means the scope
+ // flags must be a power of two, and it must have the global scope.
+ return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags)
+ && option_has_scope(opt_idx, kOptScopeGlobal);
+}
+
+/// Check if option only supports window scope.
+static inline bool option_is_window_local(OptIndex opt_idx)
+{
+ // For an option to be window-local it has to only have a single scope, which means the scope
+ // flags must be a power of two, and it must have the window scope.
+ return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags)
+ && option_has_scope(opt_idx, kOptScopeWin);
+}
+
+/// Get option index for scope.
+ssize_t option_scope_idx(OptIndex opt_idx, OptScope scope)
+{
+ return options[opt_idx].scope_idx[scope];
}
/// Get option flags.
@@ -3418,7 +3413,7 @@ static OptVal get_option_unset_value(OptIndex opt_idx)
vimoption_T *opt = &options[opt_idx];
// For global-local options, use the unset value of the local value.
- if (opt->indir & PV_BOTH) {
+ if (option_is_global_local(opt_idx)) {
// String global-local options always use an empty string for the unset value.
if (option_has_type(opt_idx, kOptValTypeString)) {
return STATIC_CSTR_AS_OPTVAL("");
@@ -3450,7 +3445,7 @@ static bool is_option_local_value_unset(OptIndex opt_idx)
vimoption_T *opt = get_option(opt_idx);
// Local value of option that isn't global-local is always considered set.
- if (!((int)opt->indir & PV_BOTH)) {
+ if (!option_is_global_local(opt_idx)) {
return false;
}
@@ -3484,7 +3479,6 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
vimoption_T *opt = &options[opt_idx];
const char *errmsg = NULL;
bool restore_chartab = false;
- bool free_oldval = (opt->flags & P_ALLOCED);
bool value_changed = false;
bool value_checked = false;
@@ -3503,15 +3497,15 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
.os_win = curwin
};
- if (direct || opt->hidden) {
- // Don't do any extra processing if setting directly or if option is hidden.
+ if (direct) {
+ // Don't do any extra processing if setting directly.
}
// Disallow changing immutable options.
else if (opt->immutable && !optval_equal(old_value, new_value)) {
errmsg = e_unsupportedoption;
}
// Disallow changing some options from secure mode.
- else if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) {
+ else if ((secure || sandbox != 0) && (opt->flags & kOptFlagSecure)) {
errmsg = e_secure;
}
// Check for a "normal" directory or file name in some string options.
@@ -3533,7 +3527,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
// If option is hidden or if an error is detected, restore the previous value and don't do any
// further processing.
- if (opt->hidden || errmsg != NULL) {
+ if (errmsg != NULL) {
set_option_varp(opt_idx, varp, old_value, true);
// When resetting some values, need to act on it.
if (restore_chartab) {
@@ -3560,18 +3554,12 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
set_option_sctx(opt_idx, opt_flags, script_ctx);
}
- // Free options that are in allocated memory.
- // Use "free_oldval", because recursiveness may change the flags (esp. init_highlight()).
- if (free_oldval) {
- optval_free(old_value);
- }
- opt->flags |= P_ALLOCED;
+ optval_free(old_value);
const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- const bool opt_is_global_local = opt->indir & PV_BOTH;
if (scope_both) {
- if (opt_is_global_local) {
+ if (option_is_global_local(opt_idx)) {
// Global option with local value set to use global value.
// Free the local value and clear it.
void *varp_local = get_varp_scope(opt, OPT_LOCAL);
@@ -3618,7 +3606,8 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
}
if (curwin->w_curswant != MAXCOL
- && (opt->flags & (P_CURSWANT | P_RALL)) != 0 && (opt->flags & P_HLONLY) == 0) {
+ && (opt->flags & (kOptFlagCurswant | kOptFlagRedrAll)) != 0
+ && (opt->flags & kOptFlagHLOnly) == 0) {
curwin->w_set_curswant = true;
}
@@ -3626,14 +3615,14 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
if (errmsg == NULL) {
uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags);
- opt->flags |= P_WAS_SET;
+ opt->flags |= kOptFlagWasSet;
- // When an option is set in the sandbox, from a modeline or in secure mode set the P_INSECURE
+ // When an option is set in the sandbox, from a modeline or in secure mode set the kOptFlagInsecure
// flag. Otherwise, if a new value is stored reset the flag.
if (!value_checked && (secure || sandbox != 0 || (opt_flags & OPT_MODELINE))) {
- *p |= P_INSECURE;
+ *p |= kOptFlagInsecure;
} else if (value_replaced) {
- *p &= ~P_INSECURE;
+ *p &= ~(unsigned)kOptFlagInsecure;
}
}
@@ -3643,14 +3632,19 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
/// Validate the new value for an option.
///
/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
-/// @param varp Pointer to option variable.
/// @param newval[in,out] New option value. Might be modified.
-static const char *validate_option_value(const OptIndex opt_idx, void *varp, OptVal *newval,
- int opt_flags, char *errbuf, size_t errbuflen)
+static const char *validate_option_value(const OptIndex opt_idx, OptVal *newval, int opt_flags,
+ char *errbuf, size_t errbuflen)
{
const char *errmsg = NULL;
vimoption_T *opt = &options[opt_idx];
+ // Always allow unsetting local value of global-local option.
+ if (option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL)
+ && optval_equal(*newval, get_option_unset_value(opt_idx))) {
+ return NULL;
+ }
+
if (newval->type == kOptValTypeNil) {
// Don't try to unset local value if scope is global.
// TODO(famiu): Change this to forbid changing all non-local scopes when the API scope bug is
@@ -3658,7 +3652,6 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt
if (opt_flags == OPT_GLOBAL) {
errmsg = _("Cannot unset global option value");
} else {
- optval_free(*newval);
*newval = optval_copy(get_option_unset_value(opt_idx));
}
} else if (!option_has_type(opt_idx, newval->type)) {
@@ -3671,7 +3664,7 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt
errmsg = errbuf;
} else if (newval->type == kOptValTypeNumber) {
// Validate and bound check num option values.
- errmsg = validate_num_option(opt_idx, varp, &newval->data.number, errbuf, errbuflen);
+ errmsg = validate_num_option(opt_idx, &newval->data.number, errbuf, errbuflen);
}
return errmsg;
@@ -3680,7 +3673,6 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt
/// Set the value of an option using an OptVal.
///
/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
-/// @param[in] varp Option variable pointer, cannot be NULL.
/// @param value New option value. Might get freed.
/// @param opt_flags Option flags.
/// @param set_sid Script ID. Special values:
@@ -3692,35 +3684,35 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt
/// @param errbuflen Length of error buffer.
///
/// @return NULL on success, an untranslated error message on error.
-static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, int opt_flags,
- scid_T set_sid, const bool direct, const bool value_replaced,
- char *errbuf, size_t errbuflen)
- FUNC_ATTR_NONNULL_ARG(2)
+static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid,
+ const bool direct, const bool value_replaced, char *errbuf,
+ size_t errbuflen)
{
assert(opt_idx != kOptInvalid);
- const char *errmsg = validate_option_value(opt_idx, varp, &value, opt_flags, errbuf, errbuflen);
+ const char *errmsg = NULL;
- if (errmsg != NULL) {
- optval_free(value);
- return errmsg;
+ if (!direct) {
+ errmsg = validate_option_value(opt_idx, &value, opt_flags, errbuf, errbuflen);
+
+ if (errmsg != NULL) {
+ optval_free(value);
+ return errmsg;
+ }
}
vimoption_T *opt = &options[opt_idx];
const bool scope_local = opt_flags & OPT_LOCAL;
const bool scope_global = opt_flags & OPT_GLOBAL;
const bool scope_both = !scope_local && !scope_global;
- const bool opt_is_global_local = opt->indir & PV_BOTH;
// Whether local value of global-local option is unset.
- // NOTE: When this is true, it also implies that opt_is_global_local is true.
+ // NOTE: When this is true, it also implies that the option is global-local.
const bool is_opt_local_unset = is_option_local_value_unset(opt_idx);
// When using ":set opt=val" for a global option with a local value the local value will be reset,
- // use the global value here.
- if (scope_both && opt_is_global_local) {
- varp = opt->var;
- }
-
+ // use the global value in that case.
+ void *varp
+ = scope_both && option_is_global_local(opt_idx) ? opt->var : get_varp_scope(opt, opt_flags);
void *varp_local = get_varp_scope(opt, OPT_LOCAL);
void *varp_global = get_varp_scope(opt, OPT_GLOBAL);
@@ -3749,9 +3741,9 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value,
const int secure_saved = secure;
// When an option is set in the sandbox, from a modeline or in secure mode, then deal with side
- // effects in secure mode. Also when the value was set with the P_INSECURE flag and is not
+ // effects in secure mode. Also when the value was set with the kOptFlagInsecure flag and is not
// completely replaced.
- if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!value_replaced && (*p & P_INSECURE))) {
+ if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!value_replaced && (*p & kOptFlagInsecure))) {
secure = 1;
}
@@ -3768,7 +3760,7 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value,
apply_optionset_autocmd(opt_idx, opt_flags, saved_used_value, saved_old_global_value,
saved_old_local_value, saved_new_value, errmsg);
}
- if (opt->flags & P_UI_OPTION) {
+ if (opt->flags & kOptFlagUIOption) {
ui_call_option_set(cstr_as_string(opt->fullname), optval_as_object(saved_new_value));
}
}
@@ -3794,17 +3786,14 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set
{
static char errbuf[IOSIZE];
- vimoption_T *opt = get_option(opt_idx);
-
- if (opt->var == NULL) {
+ if (is_option_hidden(opt_idx)) {
return;
}
- const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- void *varp = get_varp_scope(opt, scope_both ? OPT_LOCAL : opt_flags);
-
- set_option(opt_idx, varp, optval_copy(value), opt_flags, set_sid, true, true, errbuf,
- sizeof(errbuf));
+ const char *errmsg = set_option(opt_idx, optval_copy(value), opt_flags, set_sid, true, true,
+ errbuf, sizeof(errbuf));
+ assert(errmsg == NULL);
+ (void)errmsg; // ignore unused warning
}
/// Set option value directly for buffer / window, without processing any side effects.
@@ -3815,10 +3804,10 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set
/// @param set_sid Script ID. Special values:
/// 0: Use current script ID.
/// SID_NONE: Don't set script ID.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid,
- OptReqScope req_scope, void *const from)
+ OptScope req_scope, void *const from)
{
buf_T *save_curbuf = curbuf;
win_T *save_curwin = curwin;
@@ -3827,15 +3816,15 @@ void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T
// side-effects when setting an option directly. Just change the values of curbuf and curwin if
// needed, no need to properly switch the window / buffer.
switch (req_scope) {
- case kOptReqGlobal:
- break;
- case kOptReqBuf:
- curbuf = (buf_T *)from;
+ case kOptScopeGlobal:
break;
- case kOptReqWin:
+ case kOptScopeWin:
curwin = (win_T *)from;
curbuf = curwin->w_buffer;
break;
+ case kOptScopeBuf:
+ curbuf = (buf_T *)from;
+ break;
}
set_option_direct(opt_idx, value, opt_flags, set_sid);
@@ -3859,18 +3848,22 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt
uint32_t flags = options[opt_idx].flags;
// Disallow changing some options in the sandbox
- if (sandbox > 0 && (flags & P_SECURE)) {
+ if (sandbox > 0 && (flags & kOptFlagSecure)) {
return _(e_sandbox);
}
- void *varp = get_varp_scope(&(options[opt_idx]), opt_flags);
- if (varp == NULL) {
- // hidden option is not changed
- return NULL;
- }
+ return set_option(opt_idx, optval_copy(value), opt_flags, 0, false, true, errbuf, sizeof(errbuf));
+}
- return set_option(opt_idx, varp, optval_copy(value), opt_flags, 0, false, true, errbuf,
- sizeof(errbuf));
+/// Unset the local value of a global-local option.
+///
+/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
+///
+/// @return NULL on success, an untranslated error message on error.
+static inline const char *unset_option_local_value(const OptIndex opt_idx)
+{
+ assert(option_is_global_local(opt_idx));
+ return set_option_value(opt_idx, get_option_unset_value(opt_idx), OPT_LOCAL);
}
/// Set the value of an option. Supports TTY options, unlike set_option_value().
@@ -3918,16 +3911,17 @@ void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_fla
/// Switch current context to get/set option value for window/buffer.
///
/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
///
/// @return true if context was switched, false otherwise.
-static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *const from,
- Error *err)
+static bool switch_option_context(void *const ctx, OptScope req_scope, void *const from, Error *err)
{
switch (req_scope) {
- case kOptReqWin: {
+ case kOptScopeGlobal:
+ return false;
+ case kOptScopeWin: {
win_T *const win = (win_T *)from;
switchwin_T *const switchwin = (switchwin_T *)ctx;
@@ -3947,7 +3941,7 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *
}
return true;
}
- case kOptReqBuf: {
+ case kOptScopeBuf: {
buf_T *const buf = (buf_T *)from;
aco_save_T *const aco = (aco_save_T *)ctx;
@@ -3957,150 +3951,44 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *
aucmd_prepbuf(aco, buf);
return true;
}
- case kOptReqGlobal:
- return false;
}
UNREACHABLE;
}
/// Restore context after getting/setting option for window/buffer. See switch_option_context() for
/// params.
-static void restore_option_context(void *const ctx, OptReqScope req_scope)
+static void restore_option_context(void *const ctx, OptScope req_scope)
{
switch (req_scope) {
- case kOptReqWin:
+ case kOptScopeGlobal:
+ break;
+ case kOptScopeWin:
restore_win_noblock((switchwin_T *)ctx, true);
break;
- case kOptReqBuf:
+ case kOptScopeBuf:
aucmd_restbuf((aco_save_T *)ctx);
break;
- case kOptReqGlobal:
- break;
}
}
-/// Get attributes for an option.
-///
-/// @param opt_idx Option index in options[] table.
-///
-/// @return Option attributes.
-/// 0 for hidden or unknown option.
-/// See SOPT_* in option_defs.h for other flags.
-int get_option_attrs(OptIndex opt_idx)
-{
- if (opt_idx == kOptInvalid) {
- return 0;
- }
-
- vimoption_T *opt = get_option(opt_idx);
-
- // Hidden option
- if (opt->var == NULL) {
- return 0;
- }
-
- int attrs = 0;
-
- if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) {
- attrs |= SOPT_GLOBAL;
- }
- if (opt->indir & PV_WIN) {
- attrs |= SOPT_WIN;
- } else if (opt->indir & PV_BUF) {
- attrs |= SOPT_BUF;
- }
-
- return attrs;
-}
-
-/// Check if option has a value in the requested scope.
-///
-/// @param opt_idx Option index in options[] table.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
-///
-/// @return true if option has a value in the requested scope, false otherwise.
-static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope)
-{
- if (opt_idx == kOptInvalid) {
- return false;
- }
-
- vimoption_T *opt = get_option(opt_idx);
-
- // Hidden option.
- if (opt->var == NULL) {
- return false;
- }
- // TTY option.
- if (is_tty_option(opt->fullname)) {
- return req_scope == kOptReqGlobal;
- }
-
- switch (req_scope) {
- case kOptReqGlobal:
- return opt->var != VAR_WIN;
- case kOptReqBuf:
- return opt->indir & PV_BUF;
- case kOptReqWin:
- return opt->indir & PV_WIN;
- }
- UNREACHABLE;
-}
-
-/// Get the option value in the requested scope.
-///
-/// @param opt_idx Option index in options[] table.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
-/// @param[in] from Pointer to buffer or window for local option value.
-/// @param[out] err Error message, if any.
-///
-/// @return Option value in the requested scope. Returns a Nil option value if option is not found,
-/// hidden or if it isn't present in the requested scope. (i.e. has no global, window-local or
-/// buffer-local value depending on opt_scope).
-OptVal get_option_value_strict(OptIndex opt_idx, OptReqScope req_scope, void *from, Error *err)
-{
- if (opt_idx == kOptInvalid || !option_has_scope(opt_idx, req_scope)) {
- return NIL_OPTVAL;
- }
-
- vimoption_T *opt = get_option(opt_idx);
- switchwin_T switchwin;
- aco_save_T aco;
- void *ctx = req_scope == kOptReqWin ? (void *)&switchwin
- : (req_scope == kOptReqBuf ? (void *)&aco : NULL);
- bool switched = switch_option_context(ctx, req_scope, from, err);
- if (ERROR_SET(err)) {
- return NIL_OPTVAL;
- }
-
- char *varp = get_varp_scope(opt, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL);
- OptVal retv = optval_from_varp(opt_idx, varp);
-
- if (switched) {
- restore_option_context(ctx, req_scope);
- }
-
- return retv;
-}
-
/// Get option value for buffer / window.
///
/// @param opt_idx Option index in options[] table.
-/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL).
+/// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL).
/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination).
/// @param[out] hidden Whether option is hidden.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
///
/// @return Option value. Must be freed by caller.
-OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_scope,
- void *const from, Error *err)
+OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptScope req_scope, void *const from,
+ Error *err)
{
switchwin_T switchwin;
aco_save_T aco;
- void *ctx = req_scope == kOptReqWin ? (void *)&switchwin
- : (req_scope == kOptReqBuf ? (void *)&aco : NULL);
+ void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin
+ : (req_scope == kOptScopeBuf ? (void *)&aco : NULL);
bool switched = switch_option_context(ctx, req_scope, from, err);
if (ERROR_SET(err)) {
@@ -4122,17 +4010,17 @@ OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_s
/// @param opt_idx Option index in options[] table.
/// @param[in] value Option value.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags,
- const OptReqScope req_scope, void *const from, Error *err)
+ const OptScope req_scope, void *const from, Error *err)
FUNC_ATTR_NONNULL_ARG(1)
{
switchwin_T switchwin;
aco_save_T aco;
- void *ctx = req_scope == kOptReqWin ? (void *)&switchwin
- : (req_scope == kOptReqBuf ? (void *)&aco : NULL);
+ void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin
+ : (req_scope == kOptScopeBuf ? (void *)&aco : NULL);
bool switched = switch_option_context(ctx, req_scope, from, err);
if (ERROR_SET(err)) {
@@ -4177,7 +4065,7 @@ static void showoptions(bool all, int opt_flags)
// collect the items in items[]
int item_count = 0;
vimoption_T *opt;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
opt = &options[opt_idx];
// apply :filter /pat/
if (message_filtered(opt->fullname)) {
@@ -4186,7 +4074,7 @@ static void showoptions(bool all, int opt_flags)
void *varp = NULL;
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) {
- if (opt->indir != PV_NONE) {
+ if (!option_is_global_only(opt_idx)) {
varp = get_varp_scope(opt, opt_flags);
}
} else {
@@ -4247,13 +4135,13 @@ static int optval_default(OptIndex opt_idx, void *varp)
{
vimoption_T *opt = &options[opt_idx];
- // Hidden or immutable options always use their default value.
- if (varp == NULL || opt->hidden || opt->immutable) {
+ // Hidden options always use their default value.
+ if (is_option_hidden(opt_idx)) {
return true;
}
OptVal current_val = optval_from_varp(opt_idx, varp);
- OptVal default_val = optval_from_varp(opt_idx, &opt->def_val);
+ OptVal default_val = opt->def_val;
return optval_equal(current_val, default_val);
}
@@ -4261,9 +4149,9 @@ static int optval_default(OptIndex opt_idx, void *varp)
/// Send update to UIs with values of UI relevant options
void ui_refresh_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
uint32_t flags = options[opt_idx].flags;
- if (!(flags & P_UI_OPTION)) {
+ if (!(flags & kOptFlagUIOption)) {
continue;
}
String name = cstr_as_string(options[opt_idx].fullname);
@@ -4303,7 +4191,7 @@ static void showoneopt(vimoption_T *opt, int opt_flags)
msg_putchar('=');
// put value string in NameBuff
option_value2string(opt, opt_flags);
- msg_outtrans(NameBuff, 0);
+ msg_outtrans(NameBuff, 0, false);
}
silent_mode = save_silent;
@@ -4338,22 +4226,22 @@ int makeset(FILE *fd, int opt_flags, int local_only)
// - Hidden options.
//
// Do the loop over "options[]" twice: once for options with the
- // P_PRI_MKRC flag and once without.
+ // kOptFlagPriMkrc flag and once without.
for (int pri = 1; pri >= 0; pri--) {
vimoption_T *opt;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
opt = &options[opt_idx];
- if (!(opt->flags & P_NO_MKRC)
- && ((pri == 1) == ((opt->flags & P_PRI_MKRC) != 0))) {
+ if (!(opt->flags & kOptFlagNoMkrc)
+ && ((pri == 1) == ((opt->flags & kOptFlagPriMkrc) != 0))) {
// skip global option when only doing locals
- if (opt->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) {
+ if (option_is_global_only(opt_idx) && !(opt_flags & OPT_GLOBAL)) {
continue;
}
// Do not store options like 'bufhidden' and 'syntax' in a vimrc
// file, they are always buffer-specific.
- if ((opt_flags & OPT_GLOBAL) && (opt->flags & P_NOGLOB)) {
+ if ((opt_flags & OPT_GLOBAL) && (opt->flags & kOptFlagNoGlob)) {
continue;
}
@@ -4374,21 +4262,19 @@ int makeset(FILE *fd, int opt_flags, int local_only)
int round = 2;
void *varp_local = NULL; // fresh value
- if (opt->indir != PV_NONE) {
- if (opt->var == VAR_WIN) {
- // skip window-local option when only doing globals
- if (!(opt_flags & OPT_LOCAL)) {
- continue;
- }
- // When fresh value of window-local option is not at the
- // default, need to write it too.
- if (!(opt_flags & OPT_GLOBAL) && !local_only) {
- void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value
- if (!optval_default(opt_idx, varp_fresh)) {
- round = 1;
- varp_local = varp;
- varp = varp_fresh;
- }
+ if (option_is_window_local(opt_idx)) {
+ // skip window-local option when only doing globals
+ if (!(opt_flags & OPT_LOCAL)) {
+ continue;
+ }
+ // When fresh value of window-local option is not at the
+ // default, need to write it too.
+ if (!(opt_flags & OPT_GLOBAL) && !local_only) {
+ void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value
+ if (!optval_default(opt_idx, varp_fresh)) {
+ round = 1;
+ varp_local = varp;
+ varp = varp_fresh;
}
}
}
@@ -4403,35 +4289,24 @@ int makeset(FILE *fd, int opt_flags, int local_only)
cmd = "setlocal";
}
- if (option_has_type(opt_idx, kOptValTypeBoolean)) {
- if (put_setbool(fd, cmd, opt->fullname, *(int *)varp) == FAIL) {
- return FAIL;
- }
- } else if (option_has_type(opt_idx, kOptValTypeNumber)) {
- if (put_setnum(fd, cmd, opt->fullname, (OptInt *)varp) == FAIL) {
+ bool do_endif = false;
+ // Don't set 'syntax' and 'filetype' again if the value is already right, avoids reloading
+ // the syntax file.
+ if (opt_idx == kOptSyntax || opt_idx == kOptFiletype) {
+ if (fprintf(fd, "if &%s != '%s'", opt->fullname,
+ *(char **)(varp)) < 0
+ || put_eol(fd) < 0) {
return FAIL;
}
- } else { // string
- bool do_endif = false;
-
- // Don't set 'syntax' and 'filetype' again if the value is
- // already right, avoids reloading the syntax file.
- if (opt->indir == PV_SYN || opt->indir == PV_FT) {
- if (fprintf(fd, "if &%s != '%s'", opt->fullname,
- *(char **)(varp)) < 0
- || put_eol(fd) < 0) {
- return FAIL;
- }
- do_endif = true;
- }
- if (put_setstring(fd, cmd, opt->fullname, (char **)varp, opt->flags) == FAIL) {
+ do_endif = true;
+ }
+ if (put_set(fd, cmd, opt_idx, varp) == FAIL) {
+ return FAIL;
+ }
+ if (do_endif) {
+ if (put_line(fd, "endif") == FAIL) {
return FAIL;
}
- if (do_endif) {
- if (put_line(fd, "endif") == FAIL) {
- return FAIL;
- }
- }
}
}
}
@@ -4444,110 +4319,133 @@ int makeset(FILE *fd, int opt_flags, int local_only)
/// 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
int makefoldset(FILE *fd)
{
- if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL
- || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) == FAIL
- || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) == FAIL
- || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) == FAIL
- || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL
- || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL
- || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL
- || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL) {
+ if (put_set(fd, "setlocal", kOptFoldmethod, &curwin->w_p_fdm) == FAIL
+ || put_set(fd, "setlocal", kOptFoldexpr, &curwin->w_p_fde) == FAIL
+ || put_set(fd, "setlocal", kOptFoldmarker, &curwin->w_p_fmr) == FAIL
+ || put_set(fd, "setlocal", kOptFoldignore, &curwin->w_p_fdi) == FAIL
+ || put_set(fd, "setlocal", kOptFoldlevel, &curwin->w_p_fdl) == FAIL
+ || put_set(fd, "setlocal", kOptFoldminlines, &curwin->w_p_fml) == FAIL
+ || put_set(fd, "setlocal", kOptFoldnestmax, &curwin->w_p_fdn) == FAIL
+ || put_set(fd, "setlocal", kOptFoldenable, &curwin->w_p_fen) == FAIL) {
return FAIL;
}
return OK;
}
-static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_t flags)
+/// Print the ":set" command to set a single option to file.
+///
+/// @param fd File descriptor.
+/// @param cmd Command name.
+/// @param opt_idx Option index in options[] table.
+/// @param varp Pointer to option variable.
+///
+/// @return FAIL on error, OK otherwise.
+static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp)
{
- if (fprintf(fd, "%s %s=", cmd, name) < 0) {
- return FAIL;
+ OptVal value = optval_from_varp(opt_idx, varp);
+ vimoption_T *opt = &options[opt_idx];
+ char *name = opt->fullname;
+ uint64_t flags = opt->flags;
+
+ if (option_is_global_local(opt_idx) && varp != opt->var
+ && optval_equal(value, get_option_unset_value(opt_idx))) {
+ // Processing unset local value of global-local option. Do nothing.
+ return OK;
+ }
+
+ switch (value.type) {
+ case kOptValTypeNil:
+ abort();
+ case kOptValTypeBoolean: {
+ assert(value.data.boolean != kNone);
+ bool value_bool = TRISTATE_TO_BOOL(value.data.boolean, false);
+
+ if (fprintf(fd, "%s %s%s", cmd, value_bool ? "" : "no", name) < 0) {
+ return FAIL;
+ }
+ break;
+ }
+ case kOptValTypeNumber: {
+ if (fprintf(fd, "%s %s=", cmd, name) < 0) {
+ return FAIL;
+ }
+
+ OptInt value_num = value.data.number;
+
+ OptInt wc;
+ if (wc_use_keyname(varp, &wc)) {
+ // print 'wildchar' and 'wildcharm' as a key name
+ if (fputs(get_special_key_name((int)wc, 0), fd) < 0) {
+ return FAIL;
+ }
+ } else if (fprintf(fd, "%" PRId64, value_num) < 0) {
+ return FAIL;
+ }
+ break;
}
+ case kOptValTypeString: {
+ if (fprintf(fd, "%s %s=", cmd, name) < 0) {
+ return FAIL;
+ }
- char *buf = NULL;
- char *part = NULL;
+ char *value_str = value.data.string.data;
+ char *buf = NULL;
+ char *part = NULL;
- if (*valuep != NULL) {
- if ((flags & P_EXPAND) != 0) {
- size_t size = (size_t)strlen(*valuep) + 1;
+ if (value_str != NULL) {
+ if ((flags & kOptFlagExpand) != 0) {
+ size_t size = (size_t)strlen(value_str) + 1;
- // replace home directory in the whole option value into "buf"
- buf = xmalloc(size);
- home_replace(NULL, *valuep, buf, size, false);
+ // replace home directory in the whole option value into "buf"
+ buf = xmalloc(size);
+ home_replace(NULL, value_str, buf, size, false);
- // If the option value is longer than MAXPATHL, we need to append
- // each comma separated part of the option separately, so that it
- // can be expanded when read back.
- if (size >= MAXPATHL && (flags & P_COMMA) != 0
- && vim_strchr(*valuep, ',') != NULL) {
- part = xmalloc(size);
+ // If the option value is longer than MAXPATHL, we need to append
+ // each comma separated part of the option separately, so that it
+ // can be expanded when read back.
+ if (size >= MAXPATHL && (flags & kOptFlagComma) != 0
+ && vim_strchr(value_str, ',') != NULL) {
+ part = xmalloc(size);
- // write line break to clear the option, e.g. ':set rtp='
- if (put_eol(fd) == FAIL) {
- goto fail;
- }
- char *p = buf;
- while (*p != NUL) {
- // for each comma separated option part, append value to
- // the option, :set rtp+=value
- if (fprintf(fd, "%s %s+=", cmd, name) < 0) {
+ // write line break to clear the option, e.g. ':set rtp='
+ if (put_eol(fd) == FAIL) {
goto fail;
}
- copy_option_part(&p, part, size, ",");
- if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) {
- goto fail;
+ char *p = buf;
+ while (*p != NUL) {
+ // for each comma separated option part, append value to
+ // the option, :set rtp+=value
+ if (fprintf(fd, "%s %s+=", cmd, name) < 0) {
+ goto fail;
+ }
+ copy_option_part(&p, part, size, ",");
+ if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) {
+ goto fail;
+ }
}
+ xfree(buf);
+ xfree(part);
+ return OK;
+ }
+ if (put_escstr(fd, buf, 2) == FAIL) {
+ xfree(buf);
+ return FAIL;
}
xfree(buf);
- xfree(part);
- return OK;
- }
- if (put_escstr(fd, buf, 2) == FAIL) {
- xfree(buf);
+ } else if (put_escstr(fd, value_str, 2) == FAIL) {
return FAIL;
}
- xfree(buf);
- } else if (put_escstr(fd, *valuep, 2) == FAIL) {
- return FAIL;
}
- }
- if (put_eol(fd) < 0) {
- return FAIL;
- }
- return OK;
-fail:
- xfree(buf);
- xfree(part);
- return FAIL;
-}
-
-static int put_setnum(FILE *fd, char *cmd, char *name, OptInt *valuep)
-{
- if (fprintf(fd, "%s %s=", cmd, name) < 0) {
- return FAIL;
- }
- OptInt wc;
- if (wc_use_keyname(valuep, &wc)) {
- // print 'wildchar' and 'wildcharm' as a key name
- if (fputs(get_special_key_name((int)wc, 0), fd) < 0) {
- return FAIL;
- }
- } else if (fprintf(fd, "%" PRId64, (int64_t)(*valuep)) < 0) {
+ break;
+ fail:
+ xfree(buf);
+ xfree(part);
return FAIL;
}
- if (put_eol(fd) < 0) {
- return FAIL;
}
- return OK;
-}
-static int put_setbool(FILE *fd, char *cmd, char *name, int value)
-{
- if (value < 0) { // global/local option using global value
- return OK;
- }
- if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0
- || put_eol(fd) < 0) {
+ if (put_eol(fd) < 0) {
return FAIL;
}
return OK;
@@ -4555,74 +4453,80 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value)
void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
{
- if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) {
- if (p->var == VAR_WIN) {
+ OptIndex opt_idx = get_opt_idx(p);
+
+ if ((scope & OPT_GLOBAL) && !option_is_global_only(opt_idx)) {
+ if (option_is_window_local(opt_idx)) {
return GLOBAL_WO(get_varp_from(p, buf, win));
}
return p->var;
}
- if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) {
- switch ((int)p->indir) {
- case PV_FP:
+
+ if ((scope & OPT_LOCAL) && option_is_global_local(opt_idx)) {
+ switch (opt_idx) {
+ case kOptFormatprg:
return &(buf->b_p_fp);
- case PV_EFM:
+ case kOptFindfunc:
+ return &(buf->b_p_ffu);
+ case kOptErrorformat:
return &(buf->b_p_efm);
- case PV_GP:
+ case kOptGrepprg:
return &(buf->b_p_gp);
- case PV_MP:
+ case kOptMakeprg:
return &(buf->b_p_mp);
- case PV_EP:
+ case kOptEqualprg:
return &(buf->b_p_ep);
- case PV_KP:
+ case kOptKeywordprg:
return &(buf->b_p_kp);
- case PV_PATH:
+ case kOptPath:
return &(buf->b_p_path);
- case PV_AR:
+ case kOptAutoread:
return &(buf->b_p_ar);
- case PV_TAGS:
+ case kOptTags:
return &(buf->b_p_tags);
- case PV_TC:
+ case kOptTagcase:
return &(buf->b_p_tc);
- case PV_SISO:
+ case kOptSidescrolloff:
return &(win->w_p_siso);
- case PV_SO:
+ case kOptScrolloff:
return &(win->w_p_so);
- case PV_DEF:
+ case kOptDefine:
return &(buf->b_p_def);
- case PV_INC:
+ case kOptInclude:
return &(buf->b_p_inc);
- case PV_COT:
+ case kOptCompleteopt:
return &(buf->b_p_cot);
- case PV_DICT:
+ case kOptDictionary:
return &(buf->b_p_dict);
- case PV_TSR:
+ case kOptThesaurus:
return &(buf->b_p_tsr);
- case PV_TSRFU:
+ case kOptThesaurusfunc:
return &(buf->b_p_tsrfu);
- case PV_TFU:
+ case kOptTagfunc:
return &(buf->b_p_tfu);
- case PV_SBR:
+ case kOptShowbreak:
return &(win->w_p_sbr);
- case PV_STL:
+ case kOptStatusline:
return &(win->w_p_stl);
- case PV_WBR:
+ case kOptWinbar:
return &(win->w_p_wbr);
- case PV_UL:
+ case kOptUndolevels:
return &(buf->b_p_ul);
- case PV_LW:
+ case kOptLispwords:
return &(buf->b_p_lw);
- case PV_BKC:
+ case kOptBackupcopy:
return &(buf->b_p_bkc);
- case PV_MENC:
+ case kOptMakeencoding:
return &(buf->b_p_menc);
- case PV_FCS:
+ case kOptFillchars:
return &(win->w_p_fcs);
- case PV_LCS:
+ case kOptListchars:
return &(win->w_p_lcs);
- case PV_VE:
+ case kOptVirtualedit:
return &(win->w_p_ve);
+ default:
+ abort();
}
- return NULL; // "cannot happen"
}
return get_varp_from(p, buf, win);
}
@@ -4644,291 +4548,292 @@ void *get_option_varp_scope_from(OptIndex opt_idx, int scope, buf_T *buf, win_T
void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
{
- // hidden option, always return NULL
- if (p->var == NULL) {
- return NULL;
- }
+ OptIndex opt_idx = get_opt_idx(p);
- switch ((int)p->indir) {
- case PV_NONE:
+ // Hidden options and global-only options always use the same var pointer
+ if (is_option_hidden(opt_idx) || option_is_global_only(opt_idx)) {
return p->var;
+ }
+ switch (opt_idx) {
// global option with local value: use local value if it's been set
- case PV_EP:
+ case kOptEqualprg:
return *buf->b_p_ep != NUL ? &buf->b_p_ep : p->var;
- case PV_KP:
+ case kOptKeywordprg:
return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var;
- case PV_PATH:
+ case kOptPath:
return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var;
- case PV_AR:
+ case kOptAutoread:
return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var;
- case PV_TAGS:
+ case kOptTags:
return *buf->b_p_tags != NUL ? &(buf->b_p_tags) : p->var;
- case PV_TC:
+ case kOptTagcase:
return *buf->b_p_tc != NUL ? &(buf->b_p_tc) : p->var;
- case PV_SISO:
+ case kOptSidescrolloff:
return win->w_p_siso >= 0 ? &(win->w_p_siso) : p->var;
- case PV_SO:
+ case kOptScrolloff:
return win->w_p_so >= 0 ? &(win->w_p_so) : p->var;
- case PV_BKC:
+ case kOptBackupcopy:
return *buf->b_p_bkc != NUL ? &(buf->b_p_bkc) : p->var;
- case PV_DEF:
+ case kOptDefine:
return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var;
- case PV_INC:
+ case kOptInclude:
return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var;
- case PV_COT:
+ case kOptCompleteopt:
return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var;
- case PV_DICT:
+ case kOptDictionary:
return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var;
- case PV_TSR:
+ case kOptThesaurus:
return *buf->b_p_tsr != NUL ? &(buf->b_p_tsr) : p->var;
- case PV_TSRFU:
+ case kOptThesaurusfunc:
return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var;
- case PV_FP:
+ case kOptFormatprg:
return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var;
- case PV_EFM:
+ case kOptFindfunc:
+ return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var;
+ case kOptErrorformat:
return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var;
- case PV_GP:
+ case kOptGrepprg:
return *buf->b_p_gp != NUL ? &(buf->b_p_gp) : p->var;
- case PV_MP:
+ case kOptMakeprg:
return *buf->b_p_mp != NUL ? &(buf->b_p_mp) : p->var;
- case PV_SBR:
+ case kOptShowbreak:
return *win->w_p_sbr != NUL ? &(win->w_p_sbr) : p->var;
- case PV_STL:
+ case kOptStatusline:
return *win->w_p_stl != NUL ? &(win->w_p_stl) : p->var;
- case PV_WBR:
+ case kOptWinbar:
return *win->w_p_wbr != NUL ? &(win->w_p_wbr) : p->var;
- case PV_UL:
+ case kOptUndolevels:
return buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(buf->b_p_ul) : p->var;
- case PV_LW:
+ case kOptLispwords:
return *buf->b_p_lw != NUL ? &(buf->b_p_lw) : p->var;
- case PV_MENC:
+ case kOptMakeencoding:
return *buf->b_p_menc != NUL ? &(buf->b_p_menc) : p->var;
- case PV_FCS:
+ case kOptFillchars:
return *win->w_p_fcs != NUL ? &(win->w_p_fcs) : p->var;
- case PV_LCS:
+ case kOptListchars:
return *win->w_p_lcs != NUL ? &(win->w_p_lcs) : p->var;
- case PV_VE:
+ case kOptVirtualedit:
return *win->w_p_ve != NUL ? &win->w_p_ve : p->var;
- case PV_ARAB:
+ case kOptArabic:
return &(win->w_p_arab);
- case PV_LIST:
+ case kOptList:
return &(win->w_p_list);
- case PV_SPELL:
+ case kOptSpell:
return &(win->w_p_spell);
- case PV_CUC:
+ case kOptCursorcolumn:
return &(win->w_p_cuc);
- case PV_CUL:
+ case kOptCursorline:
return &(win->w_p_cul);
- case PV_CULOPT:
+ case kOptCursorlineopt:
return &(win->w_p_culopt);
- case PV_CC:
+ case kOptColorcolumn:
return &(win->w_p_cc);
- case PV_DIFF:
+ case kOptDiff:
return &(win->w_p_diff);
- case PV_FDC:
+ case kOptFoldcolumn:
return &(win->w_p_fdc);
- case PV_FEN:
+ case kOptFoldenable:
return &(win->w_p_fen);
- case PV_FDI:
+ case kOptFoldignore:
return &(win->w_p_fdi);
- case PV_FDL:
+ case kOptFoldlevel:
return &(win->w_p_fdl);
- case PV_FDM:
+ case kOptFoldmethod:
return &(win->w_p_fdm);
- case PV_FML:
+ case kOptFoldminlines:
return &(win->w_p_fml);
- case PV_FDN:
+ case kOptFoldnestmax:
return &(win->w_p_fdn);
- case PV_FDE:
+ case kOptFoldexpr:
return &(win->w_p_fde);
- case PV_FDT:
+ case kOptFoldtext:
return &(win->w_p_fdt);
- case PV_FMR:
+ case kOptFoldmarker:
return &(win->w_p_fmr);
- case PV_NU:
+ case kOptNumber:
return &(win->w_p_nu);
- case PV_RNU:
+ case kOptRelativenumber:
return &(win->w_p_rnu);
- case PV_NUW:
+ case kOptNumberwidth:
return &(win->w_p_nuw);
- case PV_WFB:
+ case kOptWinfixbuf:
return &(win->w_p_wfb);
- case PV_WFH:
+ case kOptWinfixheight:
return &(win->w_p_wfh);
- case PV_WFW:
+ case kOptWinfixwidth:
return &(win->w_p_wfw);
- case PV_PVW:
+ case kOptPreviewwindow:
return &(win->w_p_pvw);
- case PV_RL:
+ case kOptRightleft:
return &(win->w_p_rl);
- case PV_RLC:
+ case kOptRightleftcmd:
return &(win->w_p_rlc);
- case PV_SCROLL:
+ case kOptScroll:
return &(win->w_p_scr);
- case PV_SMS:
+ case kOptSmoothscroll:
return &(win->w_p_sms);
- case PV_WRAP:
+ case kOptWrap:
return &(win->w_p_wrap);
- case PV_LBR:
+ case kOptLinebreak:
return &(win->w_p_lbr);
- case PV_BRI:
+ case kOptBreakindent:
return &(win->w_p_bri);
- case PV_BRIOPT:
+ case kOptBreakindentopt:
return &(win->w_p_briopt);
- case PV_SCBIND:
+ case kOptScrollbind:
return &(win->w_p_scb);
- case PV_CRBIND:
+ case kOptCursorbind:
return &(win->w_p_crb);
- case PV_COCU:
+ case kOptConcealcursor:
return &(win->w_p_cocu);
- case PV_COLE:
+ case kOptConceallevel:
return &(win->w_p_cole);
- case PV_AI:
+ case kOptAutoindent:
return &(buf->b_p_ai);
- case PV_BIN:
+ case kOptBinary:
return &(buf->b_p_bin);
- case PV_BOMB:
+ case kOptBomb:
return &(buf->b_p_bomb);
- case PV_BH:
+ case kOptBufhidden:
return &(buf->b_p_bh);
- case PV_BT:
+ case kOptBuftype:
return &(buf->b_p_bt);
- case PV_BL:
+ case kOptBuflisted:
return &(buf->b_p_bl);
- case PV_CHANNEL:
+ case kOptChannel:
return &(buf->b_p_channel);
- case PV_CI:
+ case kOptCopyindent:
return &(buf->b_p_ci);
- case PV_CIN:
+ case kOptCindent:
return &(buf->b_p_cin);
- case PV_CINK:
+ case kOptCinkeys:
return &(buf->b_p_cink);
- case PV_CINO:
+ case kOptCinoptions:
return &(buf->b_p_cino);
- case PV_CINSD:
+ case kOptCinscopedecls:
return &(buf->b_p_cinsd);
- case PV_CINW:
+ case kOptCinwords:
return &(buf->b_p_cinw);
- case PV_COM:
+ case kOptComments:
return &(buf->b_p_com);
- case PV_CMS:
+ case kOptCommentstring:
return &(buf->b_p_cms);
- case PV_CPT:
+ case kOptComplete:
return &(buf->b_p_cpt);
#ifdef BACKSLASH_IN_FILENAME
- case PV_CSL:
+ case kOptCompleteslash:
return &(buf->b_p_csl);
#endif
- case PV_CFU:
+ case kOptCompletefunc:
return &(buf->b_p_cfu);
- case PV_OFU:
+ case kOptOmnifunc:
return &(buf->b_p_ofu);
- case PV_URF:
+ case kOptUserregfunc:
return &(buf->b_p_urf);
- case PV_EOF:
+ case kOptEndoffile:
return &(buf->b_p_eof);
- case PV_EOL:
+ case kOptEndofline:
return &(buf->b_p_eol);
- case PV_FIXEOL:
+ case kOptFixendofline:
return &(buf->b_p_fixeol);
- case PV_ET:
+ case kOptExpandtab:
return &(buf->b_p_et);
- case PV_FENC:
+ case kOptFileencoding:
return &(buf->b_p_fenc);
- case PV_FF:
+ case kOptFileformat:
return &(buf->b_p_ff);
- case PV_FT:
+ case kOptFiletype:
return &(buf->b_p_ft);
- case PV_FO:
+ case kOptFormatoptions:
return &(buf->b_p_fo);
- case PV_FLP:
+ case kOptFormatlistpat:
return &(buf->b_p_flp);
- case PV_IMI:
+ case kOptIminsert:
return &(buf->b_p_iminsert);
- case PV_IMS:
+ case kOptImsearch:
return &(buf->b_p_imsearch);
- case PV_INF:
+ case kOptInfercase:
return &(buf->b_p_inf);
- case PV_ISK:
+ case kOptIskeyword:
return &(buf->b_p_isk);
- case PV_INEX:
+ case kOptIncludeexpr:
return &(buf->b_p_inex);
- case PV_INDE:
+ case kOptIndentexpr:
return &(buf->b_p_inde);
- case PV_INDK:
+ case kOptIndentkeys:
return &(buf->b_p_indk);
- case PV_FEX:
+ case kOptFormatexpr:
return &(buf->b_p_fex);
- case PV_LISP:
+ case kOptLisp:
return &(buf->b_p_lisp);
- case PV_LOP:
+ case kOptLispoptions:
return &(buf->b_p_lop);
- case PV_ML:
+ case kOptModeline:
return &(buf->b_p_ml);
- case PV_MPS:
+ case kOptMatchpairs:
return &(buf->b_p_mps);
- case PV_MA:
+ case kOptModifiable:
return &(buf->b_p_ma);
- case PV_MOD:
+ case kOptModified:
return &(buf->b_changed);
- case PV_NF:
+ case kOptNrformats:
return &(buf->b_p_nf);
- case PV_PI:
+ case kOptPreserveindent:
return &(buf->b_p_pi);
- case PV_QE:
+ case kOptQuoteescape:
return &(buf->b_p_qe);
- case PV_RO:
+ case kOptReadonly:
return &(buf->b_p_ro);
- case PV_SCBK:
+ case kOptScrollback:
return &(buf->b_p_scbk);
- case PV_SI:
+ case kOptSmartindent:
return &(buf->b_p_si);
- case PV_STS:
+ case kOptSofttabstop:
return &(buf->b_p_sts);
- case PV_SUA:
+ case kOptSuffixesadd:
return &(buf->b_p_sua);
- case PV_SWF:
+ case kOptSwapfile:
return &(buf->b_p_swf);
- case PV_SMC:
+ case kOptSynmaxcol:
return &(buf->b_p_smc);
- case PV_SYN:
+ case kOptSyntax:
return &(buf->b_p_syn);
- case PV_SPC:
+ case kOptSpellcapcheck:
return &(win->w_s->b_p_spc);
- case PV_SPF:
+ case kOptSpellfile:
return &(win->w_s->b_p_spf);
- case PV_SPL:
+ case kOptSpelllang:
return &(win->w_s->b_p_spl);
- case PV_SPO:
+ case kOptSpelloptions:
return &(win->w_s->b_p_spo);
- case PV_SW:
+ case kOptShiftwidth:
return &(buf->b_p_sw);
- case PV_TFU:
+ case kOptTagfunc:
return &(buf->b_p_tfu);
- case PV_TS:
+ case kOptTabstop:
return &(buf->b_p_ts);
- case PV_TW:
+ case kOptTextwidth:
return &(buf->b_p_tw);
- case PV_UDF:
+ case kOptUndofile:
return &(buf->b_p_udf);
- case PV_WM:
+ case kOptWrapmargin:
return &(buf->b_p_wm);
- case PV_VSTS:
+ case kOptVarsofttabstop:
return &(buf->b_p_vsts);
- case PV_VTS:
+ case kOptVartabstop:
return &(buf->b_p_vts);
- case PV_KMAP:
+ case kOptKeymap:
return &(buf->b_p_keymap);
- case PV_SCL:
+ case kOptSigncolumn:
return &(win->w_p_scl);
- case PV_WINHL:
+ case kOptWinhighlight:
return &(win->w_p_winhl);
- case PV_WINBL:
+ case kOptWinblend:
return &(win->w_p_winbl);
- case PV_STC:
+ case kOptStatuscolumn:
return &(win->w_p_stc);
default:
iemsg(_("E356: get_varp ERROR"));
@@ -4959,6 +4864,15 @@ char *get_equalprg(void)
return curbuf->b_p_ep;
}
+/// Get the value of 'findfunc', either the buffer-local one or the global one.
+char *get_findfunc(void)
+{
+ if (*curbuf->b_p_ffu == NUL) {
+ return p_ffu;
+ }
+ return curbuf->b_p_ffu;
+}
+
/// Copy options from one window to another.
/// Used when splitting a window.
void win_copy_options(win_T *wp_from, win_T *wp_to)
@@ -5110,38 +5024,20 @@ void didset_window_options(win_T *wp, bool valid_cursor)
} else {
wp->w_skipcol = 0;
}
- check_colorcolumn(wp);
- briopt_check(wp);
+ check_colorcolumn(NULL, wp);
+ briopt_check(NULL, wp);
fill_culopt_flags(NULL, wp);
set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0);
set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0);
- parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
+ parse_winhl_opt(NULL, wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp);
set_winbar_win(wp, false, valid_cursor);
- check_signcolumn(wp);
+ check_signcolumn(NULL, wp);
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
}
-/// Index into the options table for a buffer-local option enum.
-static OptIndex buf_opt_idx[BV_COUNT];
#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set
-/// Initialize buf_opt_idx[] if not done already.
-static void init_buf_opt_idx(void)
-{
- static bool did_init_buf_opt_idx = false;
-
- if (did_init_buf_opt_idx) {
- return;
- }
- did_init_buf_opt_idx = true;
- for (OptIndex i = 0; i < kOptIndexCount; i++) {
- if (options[i].indir & PV_BUF) {
- buf_opt_idx[options[i].indir & PV_MASK] = i;
- }
- }
-}
-
/// Copy global option values to local options for one buffer.
/// Used when creating a new buffer and sometimes when entering a buffer.
/// flags:
@@ -5179,7 +5075,6 @@ void buf_copy_options(buf_T *buf, int flags)
if (should_copy || (flags & BCO_ALWAYS)) {
CLEAR_FIELD(buf->b_p_script_ctx);
- init_buf_opt_idx();
// Don't copy the options specific to a help buffer when
// BCO_NOHELP is given or the options were initialized already
// (jumping back to a help file with CTRL-T or CTRL-O)
@@ -5196,13 +5091,13 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_fenc = xstrdup(p_fenc);
switch (*p_ffs) {
case 'm':
- buf->b_p_ff = xstrdup(FF_MAC);
+ buf->b_p_ff = xstrdup("mac");
break;
case 'd':
- buf->b_p_ff = xstrdup(FF_DOS);
+ buf->b_p_ff = xstrdup("dos");
break;
case 'u':
- buf->b_p_ff = xstrdup(FF_UNIX);
+ buf->b_p_ff = xstrdup("unix");
break;
default:
buf->b_p_ff = xstrdup(p_ff);
@@ -5215,63 +5110,63 @@ void buf_copy_options(buf_T *buf, int flags)
}
buf->b_p_ai = p_ai;
- COPY_OPT_SCTX(buf, BV_AI);
+ COPY_OPT_SCTX(buf, kBufOptAutoindent);
buf->b_p_ai_nopaste = p_ai_nopaste;
buf->b_p_sw = p_sw;
- COPY_OPT_SCTX(buf, BV_SW);
+ COPY_OPT_SCTX(buf, kBufOptShiftwidth);
buf->b_p_scbk = p_scbk;
- COPY_OPT_SCTX(buf, BV_SCBK);
+ COPY_OPT_SCTX(buf, kBufOptScrollback);
buf->b_p_tw = p_tw;
- COPY_OPT_SCTX(buf, BV_TW);
+ COPY_OPT_SCTX(buf, kBufOptTextwidth);
buf->b_p_tw_nopaste = p_tw_nopaste;
buf->b_p_tw_nobin = p_tw_nobin;
buf->b_p_wm = p_wm;
- COPY_OPT_SCTX(buf, BV_WM);
+ COPY_OPT_SCTX(buf, kBufOptWrapmargin);
buf->b_p_wm_nopaste = p_wm_nopaste;
buf->b_p_wm_nobin = p_wm_nobin;
buf->b_p_bin = p_bin;
- COPY_OPT_SCTX(buf, BV_BIN);
+ COPY_OPT_SCTX(buf, kBufOptBinary);
buf->b_p_bomb = p_bomb;
- COPY_OPT_SCTX(buf, BV_BOMB);
+ COPY_OPT_SCTX(buf, kBufOptBomb);
buf->b_p_et = p_et;
- COPY_OPT_SCTX(buf, BV_ET);
+ COPY_OPT_SCTX(buf, kBufOptExpandtab);
buf->b_p_fixeol = p_fixeol;
- COPY_OPT_SCTX(buf, BV_FIXEOL);
+ COPY_OPT_SCTX(buf, kBufOptFixendofline);
buf->b_p_et_nobin = p_et_nobin;
buf->b_p_et_nopaste = p_et_nopaste;
buf->b_p_ml = p_ml;
- COPY_OPT_SCTX(buf, BV_ML);
+ COPY_OPT_SCTX(buf, kBufOptModeline);
buf->b_p_ml_nobin = p_ml_nobin;
buf->b_p_inf = p_inf;
- COPY_OPT_SCTX(buf, BV_INF);
+ COPY_OPT_SCTX(buf, kBufOptInfercase);
if (cmdmod.cmod_flags & CMOD_NOSWAPFILE) {
buf->b_p_swf = false;
} else {
buf->b_p_swf = p_swf;
- COPY_OPT_SCTX(buf, BV_SWF);
+ COPY_OPT_SCTX(buf, kBufOptSwapfile);
}
buf->b_p_cpt = xstrdup(p_cpt);
- COPY_OPT_SCTX(buf, BV_CPT);
+ COPY_OPT_SCTX(buf, kBufOptComplete);
#ifdef BACKSLASH_IN_FILENAME
buf->b_p_csl = xstrdup(p_csl);
- COPY_OPT_SCTX(buf, BV_CSL);
+ COPY_OPT_SCTX(buf, kBufOptCompleteslash);
#endif
buf->b_p_cfu = xstrdup(p_cfu);
- COPY_OPT_SCTX(buf, BV_CFU);
+ COPY_OPT_SCTX(buf, kBufOptCompletefunc);
set_buflocal_cfu_callback(buf);
buf->b_p_ofu = xstrdup(p_ofu);
- COPY_OPT_SCTX(buf, BV_OFU);
+ COPY_OPT_SCTX(buf, kBufOptOmnifunc);
buf->b_p_urf = xstrdup(p_urf);
- COPY_OPT_SCTX(buf, BV_URF);
set_buflocal_ofu_callback(buf);
+ COPY_OPT_SCTX(buf, kBufOptUserregfunc);
buf->b_p_tfu = xstrdup(p_tfu);
- COPY_OPT_SCTX(buf, BV_TFU);
+ COPY_OPT_SCTX(buf, kBufOptTagfunc);
set_buflocal_tfu_callback(buf);
buf->b_p_sts = p_sts;
- COPY_OPT_SCTX(buf, BV_STS);
+ COPY_OPT_SCTX(buf, kBufOptSofttabstop);
buf->b_p_sts_nopaste = p_sts_nopaste;
buf->b_p_vsts = xstrdup(p_vsts);
- COPY_OPT_SCTX(buf, BV_VSTS);
+ COPY_OPT_SCTX(buf, kBufOptVarsofttabstop);
if (p_vsts && p_vsts != empty_string_option) {
tabstop_set(p_vsts, &buf->b_p_vsts_array);
} else {
@@ -5279,74 +5174,75 @@ void buf_copy_options(buf_T *buf, int flags)
}
buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL;
buf->b_p_com = xstrdup(p_com);
- COPY_OPT_SCTX(buf, BV_COM);
+ COPY_OPT_SCTX(buf, kBufOptComments);
buf->b_p_cms = xstrdup(p_cms);
- COPY_OPT_SCTX(buf, BV_CMS);
+ COPY_OPT_SCTX(buf, kBufOptCommentstring);
buf->b_p_fo = xstrdup(p_fo);
- COPY_OPT_SCTX(buf, BV_FO);
+ COPY_OPT_SCTX(buf, kBufOptFormatoptions);
buf->b_p_flp = xstrdup(p_flp);
- COPY_OPT_SCTX(buf, BV_FLP);
+ COPY_OPT_SCTX(buf, kBufOptFormatlistpat);
buf->b_p_nf = xstrdup(p_nf);
- COPY_OPT_SCTX(buf, BV_NF);
+ COPY_OPT_SCTX(buf, kBufOptNrformats);
buf->b_p_mps = xstrdup(p_mps);
- COPY_OPT_SCTX(buf, BV_MPS);
+ COPY_OPT_SCTX(buf, kBufOptMatchpairs);
buf->b_p_si = p_si;
- COPY_OPT_SCTX(buf, BV_SI);
+ COPY_OPT_SCTX(buf, kBufOptSmartindent);
buf->b_p_channel = 0;
buf->b_p_ci = p_ci;
- COPY_OPT_SCTX(buf, BV_CI);
+ COPY_OPT_SCTX(buf, kBufOptCopyindent);
buf->b_p_cin = p_cin;
- COPY_OPT_SCTX(buf, BV_CIN);
+ COPY_OPT_SCTX(buf, kBufOptCindent);
buf->b_p_cink = xstrdup(p_cink);
- COPY_OPT_SCTX(buf, BV_CINK);
+ COPY_OPT_SCTX(buf, kBufOptCinkeys);
buf->b_p_cino = xstrdup(p_cino);
- COPY_OPT_SCTX(buf, BV_CINO);
+ COPY_OPT_SCTX(buf, kBufOptCinoptions);
buf->b_p_cinsd = xstrdup(p_cinsd);
- COPY_OPT_SCTX(buf, BV_CINSD);
+ COPY_OPT_SCTX(buf, kBufOptCinscopedecls);
buf->b_p_lop = xstrdup(p_lop);
- COPY_OPT_SCTX(buf, BV_LOP);
+ COPY_OPT_SCTX(buf, kBufOptLispoptions);
// Don't copy 'filetype', it must be detected
buf->b_p_ft = empty_string_option;
buf->b_p_pi = p_pi;
- COPY_OPT_SCTX(buf, BV_PI);
+ COPY_OPT_SCTX(buf, kBufOptPreserveindent);
buf->b_p_cinw = xstrdup(p_cinw);
- COPY_OPT_SCTX(buf, BV_CINW);
+ COPY_OPT_SCTX(buf, kBufOptCinwords);
buf->b_p_lisp = p_lisp;
- COPY_OPT_SCTX(buf, BV_LISP);
+ COPY_OPT_SCTX(buf, kBufOptLisp);
// Don't copy 'syntax', it must be set
buf->b_p_syn = empty_string_option;
buf->b_p_smc = p_smc;
- COPY_OPT_SCTX(buf, BV_SMC);
+ COPY_OPT_SCTX(buf, kBufOptSynmaxcol);
buf->b_s.b_syn_isk = empty_string_option;
buf->b_s.b_p_spc = xstrdup(p_spc);
- COPY_OPT_SCTX(buf, BV_SPC);
+ COPY_OPT_SCTX(buf, kBufOptSpellcapcheck);
compile_cap_prog(&buf->b_s);
buf->b_s.b_p_spf = xstrdup(p_spf);
- COPY_OPT_SCTX(buf, BV_SPF);
+ COPY_OPT_SCTX(buf, kBufOptSpellfile);
buf->b_s.b_p_spl = xstrdup(p_spl);
- COPY_OPT_SCTX(buf, BV_SPL);
+ COPY_OPT_SCTX(buf, kBufOptSpelllang);
buf->b_s.b_p_spo = xstrdup(p_spo);
- COPY_OPT_SCTX(buf, BV_SPO);
+ COPY_OPT_SCTX(buf, kBufOptSpelloptions);
+ buf->b_s.b_p_spo_flags = spo_flags;
buf->b_p_inde = xstrdup(p_inde);
- COPY_OPT_SCTX(buf, BV_INDE);
+ COPY_OPT_SCTX(buf, kBufOptIndentexpr);
buf->b_p_indk = xstrdup(p_indk);
- COPY_OPT_SCTX(buf, BV_INDK);
+ COPY_OPT_SCTX(buf, kBufOptIndentkeys);
buf->b_p_fp = empty_string_option;
buf->b_p_fex = xstrdup(p_fex);
- COPY_OPT_SCTX(buf, BV_FEX);
+ COPY_OPT_SCTX(buf, kBufOptFormatexpr);
buf->b_p_sua = xstrdup(p_sua);
- COPY_OPT_SCTX(buf, BV_SUA);
+ COPY_OPT_SCTX(buf, kBufOptSuffixesadd);
buf->b_p_keymap = xstrdup(p_keymap);
- COPY_OPT_SCTX(buf, BV_KMAP);
+ COPY_OPT_SCTX(buf, kBufOptKeymap);
buf->b_kmap_state |= KEYMAP_INIT;
// This isn't really an option, but copying the langmap and IME
// state from the current buffer is better than resetting it.
buf->b_p_iminsert = p_iminsert;
- COPY_OPT_SCTX(buf, BV_IMI);
+ COPY_OPT_SCTX(buf, kBufOptIminsert);
buf->b_p_imsearch = p_imsearch;
- COPY_OPT_SCTX(buf, BV_IMS);
+ COPY_OPT_SCTX(buf, kBufOptImsearch);
// options that are normally global but also have a local value
// are not copied, start using the global value
@@ -5358,6 +5254,7 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_mp = empty_string_option;
buf->b_p_efm = empty_string_option;
buf->b_p_ep = empty_string_option;
+ buf->b_p_ffu = empty_string_option;
buf->b_p_kp = empty_string_option;
buf->b_p_path = empty_string_option;
buf->b_p_tags = empty_string_option;
@@ -5366,16 +5263,16 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_def = empty_string_option;
buf->b_p_inc = empty_string_option;
buf->b_p_inex = xstrdup(p_inex);
- COPY_OPT_SCTX(buf, BV_INEX);
+ COPY_OPT_SCTX(buf, kBufOptIncludeexpr);
buf->b_p_cot = empty_string_option;
buf->b_cot_flags = 0;
buf->b_p_dict = empty_string_option;
buf->b_p_tsr = empty_string_option;
buf->b_p_tsrfu = empty_string_option;
buf->b_p_qe = xstrdup(p_qe);
- COPY_OPT_SCTX(buf, BV_QE);
+ COPY_OPT_SCTX(buf, kBufOptQuoteescape);
buf->b_p_udf = p_udf;
- COPY_OPT_SCTX(buf, BV_UDF);
+ COPY_OPT_SCTX(buf, kBufOptUndofile);
buf->b_p_lw = empty_string_option;
buf->b_p_menc = empty_string_option;
@@ -5392,12 +5289,12 @@ void buf_copy_options(buf_T *buf, int flags)
}
} else {
buf->b_p_isk = xstrdup(p_isk);
- COPY_OPT_SCTX(buf, BV_ISK);
+ COPY_OPT_SCTX(buf, kBufOptIskeyword);
did_isk = true;
buf->b_p_ts = p_ts;
- COPY_OPT_SCTX(buf, BV_TS);
+ COPY_OPT_SCTX(buf, kBufOptTabstop);
buf->b_p_vts = xstrdup(p_vts);
- COPY_OPT_SCTX(buf, BV_VTS);
+ COPY_OPT_SCTX(buf, kBufOptVartabstop);
if (p_vts && p_vts != empty_string_option && !buf->b_p_vts_array) {
tabstop_set(p_vts, &buf->b_p_vts_array);
} else {
@@ -5408,7 +5305,7 @@ void buf_copy_options(buf_T *buf, int flags)
clear_string_option(&buf->b_p_bt);
}
buf->b_p_ma = p_ma;
- COPY_OPT_SCTX(buf, BV_MA);
+ COPY_OPT_SCTX(buf, kBufOptModifiable);
}
}
@@ -5430,7 +5327,7 @@ void reset_modifiable(void)
{
curbuf->b_p_ma = false;
p_ma = false;
- options[kOptModifiable].def_val.boolean = false;
+ change_option_default(kOptModifiable, BOOLEAN_OPTVAL(false));
}
/// Set the global value for 'iminsert' to the local value.
@@ -5537,7 +5434,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
}
nextchar = *p;
opt_idx = find_option_len(arg, (size_t)(p - arg));
- if (opt_idx == kOptInvalid || options[opt_idx].var == NULL) {
+ if (opt_idx == kOptInvalid || is_option_hidden(opt_idx)) {
xp->xp_context = EXPAND_NOTHING;
return;
}
@@ -5613,8 +5510,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// Only string options below
- // Options that have P_EXPAND are considered to all use file/dir expansion.
- if (flags & P_EXPAND) {
+ // Options that have kOptFlagExpand are considered to all use file/dir expansion.
+ if (flags & kOptFlagExpand) {
p = options[opt_idx].var;
if (p == (char *)&p_bdir
|| p == (char *)&p_dir
@@ -5638,7 +5535,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
xp->xp_backslash = XP_BS_ONE;
}
}
- if (flags & P_COMMA) {
+ if (flags & kOptFlagComma) {
xp->xp_backslash |= XP_BS_COMMA;
}
}
@@ -5648,21 +5545,21 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// pattern, while accounting for backslash-escaped space/commas/colons.
// Triple-backslashed escaped file names (e.g. 'path') can also be
// delimited by space.
- if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
+ if ((flags & kOptFlagExpand) || (flags & kOptFlagComma) || (flags & kOptFlagColon)) {
for (p = argend - 1; p > xp->xp_pattern; p--) {
// count number of backslashes before ' ' or ','
- if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
+ if (*p == ' ' || *p == ',' || (*p == ':' && (flags & kOptFlagColon))) {
char *s = p;
while (s > xp->xp_pattern && *(s - 1) == '\\') {
s--;
}
if ((*p == ' ' && ((xp->xp_backslash & XP_BS_THREE) && (p - s) < 3))
#if defined(BACKSLASH_IN_FILENAME)
- || (*p == ',' && (flags & P_COMMA) && (p - s) < 1)
+ || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 1)
#else
- || (*p == ',' && (flags & P_COMMA) && (p - s) < 2)
+ || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 2)
#endif
- || (*p == ':' && (flags & P_COLON))) {
+ || (*p == ':' && (flags & kOptFlagColon))) {
xp->xp_pattern = p + 1;
break;
}
@@ -5672,7 +5569,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// An option that is a list of single-character flags should always start
// at the end as we don't complete words.
- if (flags & P_FLAGLIST) {
+ if (flags & kOptFlagFlagList) {
xp->xp_pattern = argend;
}
@@ -5759,9 +5656,9 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM
}
}
char *str;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
str = options[opt_idx].fullname;
- if (options[opt_idx].var == NULL) {
+ if (is_option_hidden(opt_idx)) {
continue;
}
if (xp->xp_context == EXPAND_BOOL_SETTINGS
@@ -5825,7 +5722,7 @@ static char *escape_option_str_cmdline(char *var)
for (var = buf; *var != NUL; MB_PTR_ADV(var)) {
if (var[0] == '\\' && var[1] == '\\'
&& expand_option_idx != kOptInvalid
- && (options[expand_option_idx].flags & P_EXPAND)
+ && (options[expand_option_idx].flags & kOptFlagExpand)
&& vim_isfilec((uint8_t)var[2])
&& (var[2] != '\\' || (var == buf && var[4] != '\\'))) {
STRMOVE(var, var + 1);
@@ -5911,11 +5808,11 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
if (option_has_type(expand_option_idx, kOptValTypeNumber)) {
return ExpandOldSetting(numMatches, matches);
- } else if (option_flags & P_COMMA) {
+ } else if (option_flags & kOptFlagComma) {
// Split the option by comma, then present each option to the user if
// it matches the pattern.
// This condition needs to go first, because 'whichwrap' has both
- // P_COMMA and P_FLAGLIST.
+ // kOptFlagComma and kOptFlagFlagList.
if (*option_val == NUL) {
return FAIL;
@@ -5962,7 +5859,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
*matches = ga.ga_data;
*numMatches = ga.ga_len;
return OK;
- } else if (option_flags & P_FLAGLIST) {
+ } else if (option_flags & kOptFlagFlagList) {
// Only present the flags that are set on the option as the other flags
// are not meaningful to do set-= on.
@@ -6009,6 +5906,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
static void option_value2string(vimoption_T *opt, int scope)
{
void *varp = get_varp_scope(opt, scope);
+ assert(varp != NULL);
if (option_has_type(get_opt_idx(opt), kOptValTypeNumber)) {
OptInt wc = 0;
@@ -6025,9 +5923,8 @@ static void option_value2string(vimoption_T *opt, int scope)
}
} else { // string
varp = *(char **)(varp);
- if (varp == NULL) { // Just in case.
- NameBuff[0] = NUL;
- } else if (opt->flags & P_EXPAND) {
+
+ if (opt->flags & kOptFlagExpand) {
home_replace(NULL, varp, NameBuff, MAXPATHL, false);
} else {
xstrlcpy(NameBuff, varp, MAXPATHL);
@@ -6088,7 +5985,7 @@ void vimrc_found(char *fname, char *envname)
bool option_was_set(OptIndex opt_idx)
{
assert(opt_idx != kOptInvalid);
- return options[opt_idx].flags & P_WAS_SET;
+ return options[opt_idx].flags & kOptFlagWasSet;
}
/// Reset the flag indicating option "name" was set.
@@ -6097,7 +5994,7 @@ bool option_was_set(OptIndex opt_idx)
void reset_option_was_set(OptIndex opt_idx)
{
assert(opt_idx != kOptInvalid);
- options[opt_idx].flags &= ~P_WAS_SET;
+ options[opt_idx].flags &= ~(unsigned)kOptFlagWasSet;
}
/// fill_culopt_flags() -- called when 'culopt' changes value
@@ -6331,13 +6228,13 @@ void set_fileformat(int eol_style, int opt_flags)
switch (eol_style) {
case EOL_UNIX:
- p = FF_UNIX;
+ p = "unix";
break;
case EOL_MAC:
- p = FF_MAC;
+ p = "mac";
break;
case EOL_DOS:
- p = FF_DOS;
+ p = "dos";
break;
}
@@ -6420,11 +6317,11 @@ dict_T *get_winbuf_options(const int bufopt)
{
dict_T *const d = tv_dict_alloc();
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
vimoption_T *opt = &options[opt_idx];
- if ((bufopt && (opt->indir & PV_BUF))
- || (!bufopt && (opt->indir & PV_WIN))) {
+ if ((bufopt && (option_has_scope(opt_idx, kOptScopeBuf)))
+ || (!bufopt && (option_has_scope(opt_idx, kOptScopeWin)))) {
void *varp = get_varp(opt);
if (varp != NULL) {
@@ -6467,8 +6364,8 @@ Dict get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena,
Dict get_all_vimoptions(Arena *arena)
{
- Dict retval = arena_dict(arena, kOptIndexCount);
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ Dict retval = arena_dict(arena, kOptCount);
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena);
PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict));
}
@@ -6477,15 +6374,16 @@ Dict get_all_vimoptions(Arena *arena)
static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, Arena *arena)
{
+ OptIndex opt_idx = get_opt_idx(opt);
Dict dict = arena_dict(arena, 13);
PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname));
PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname));
const char *scope;
- if (opt->indir & PV_BUF) {
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
scope = "buf";
- } else if (opt->indir & PV_WIN) {
+ } else if (option_has_scope(opt_idx, kOptScopeWin)) {
scope = "win";
} else {
scope = "global";
@@ -6494,22 +6392,22 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w
PUT_C(dict, "scope", CSTR_AS_OBJ(scope));
// welcome to the jungle
- PUT_C(dict, "global_local", BOOLEAN_OBJ(opt->indir & PV_BOTH));
- PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & P_COMMA));
- PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & P_FLAGLIST));
+ PUT_C(dict, "global_local", BOOLEAN_OBJ(option_is_global_local(opt_idx)));
+ PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & kOptFlagComma));
+ PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & kOptFlagFlagList));
- PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & P_WAS_SET));
+ PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & kOptFlagWasSet));
LastSet last_set = { .channel_id = 0 };
if (req_scope == OPT_GLOBAL) {
last_set = opt->last_set;
} else {
// Scope is either OPT_LOCAL or a fallback mode was requested.
- if (opt->indir & PV_BUF) {
- last_set = buf->b_p_script_ctx[opt->indir & PV_MASK];
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ last_set = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]];
}
- if (opt->indir & PV_WIN) {
- last_set = win->w_p_script_ctx[opt->indir & PV_MASK];
+ if (option_has_scope(opt_idx, kOptScopeWin)) {
+ last_set = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]];
}
if (req_scope != OPT_LOCAL && last_set.script_ctx.sc_sid == 0) {
last_set = opt->last_set;
@@ -6520,33 +6418,9 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w
PUT_C(dict, "last_set_linenr", INTEGER_OBJ(last_set.script_ctx.sc_lnum));
PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)last_set.channel_id));
- // TODO(bfredl): do you even nocp?
- OptVal def = optval_from_varp(get_opt_idx(opt), &opt->def_val);
-
- PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(def.type)));
- PUT_C(dict, "default", optval_as_object(def));
- PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & P_NODUP)));
+ PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt)))));
+ PUT_C(dict, "default", optval_as_object(opt->def_val));
+ PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & kOptFlagNoDup)));
return dict;
}
-
-/// Check if option is multitype (supports multiple types).
-static bool option_is_multitype(OptIndex opt_idx)
-{
- const OptTypeFlags type_flags = get_option(opt_idx)->type_flags;
- assert(type_flags != 0);
- return !is_power_of_two(type_flags);
-}
-
-/// Check if option supports a specific type.
-bool option_has_type(OptIndex opt_idx, OptValType type)
-{
- // Ensure that type flags variable can hold all types.
- STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8,
- "Option type_flags cannot fit all option types");
- // Ensure that the type is valid before accessing type_flags.
- assert(type > kOptValTypeNil && type < kOptValTypeSize);
- // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in
- // the type_flags bit field.
- return get_option(opt_idx)->type_flags & (1 << type);
-}
diff --git a/src/nvim/option.h b/src/nvim/option.h
index 19764c0121..cba5b00d95 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -13,63 +13,6 @@
#include "nvim/option_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
-/// The options that are local to a window or buffer have "indir" set to one of
-/// these values. Special values:
-/// PV_NONE: global option.
-/// PV_WIN is added: window-local option
-/// PV_BUF is added: buffer-local option
-/// PV_BOTH is added: global option which also has a local value.
-enum {
- PV_BOTH = 0x1000,
- PV_WIN = 0x2000,
- PV_BUF = 0x4000,
- PV_MASK = 0x0fff,
-};
-#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x))
-#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x))
-#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x))
-
-/// WV_ and BV_ values get typecasted to this for the "indir" field
-typedef enum {
- PV_NONE = 0,
- PV_MAXVAL = 0xffff, ///< to avoid warnings for value out of range
-} idopt_T;
-
-// Options local to a window have a value local to a buffer and global to all
-// buffers. Indicate this by setting "var" to VAR_WIN.
-#define VAR_WIN ((char *)-1)
-
-typedef struct {
- char *fullname; ///< full option name
- char *shortname; ///< permissible abbreviation
- uint32_t flags; ///< see above
- OptTypeFlags type_flags; ///< option type flags, see OptValType
- void *var; ///< global option: pointer to variable;
- ///< window-local option: VAR_WIN;
- ///< buffer-local option: global value
- idopt_T indir; ///< global option: PV_NONE;
- ///< local option: indirect option index
- bool hidden; ///< option is hidden, any attempt to set its value will be ignored.
- bool immutable; ///< option is immutable, trying to set its value will give an error.
-
- /// callback function to invoke after an option is modified to validate and
- /// apply the new value.
- opt_did_set_cb_T opt_did_set_cb;
-
- /// callback function to invoke when expanding possible values on the
- /// cmdline. Only useful for string options.
- opt_expand_cb_T opt_expand_cb;
-
- // TODO(famiu): Use OptVal for def_val.
- union {
- int boolean;
- OptInt number;
- char *string;
- } def_val; ///< default value for variable
-
- LastSet last_set; ///< script in which the option was last set
-} vimoption_T;
-
/// flags for buf_copy_options()
enum {
BCO_ENTER = 1, ///< going to enter the buffer
@@ -92,13 +35,6 @@ typedef enum {
OPT_SKIPRTP = 0x80, ///< "skiprtp" in 'sessionoptions'
} OptionSetFlags;
-/// Return value from get_option_attrs().
-enum {
- SOPT_GLOBAL = 0x01, ///< Option has global value
- SOPT_WIN = 0x02, ///< Option has window-local value
- SOPT_BUF = 0x04, ///< Option has buffer-local value
-};
-
/// Get name of OptValType as a string.
static inline const char *optval_type_get_name(const OptValType type)
{
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index ae9ccd371c..832e03148a 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -11,6 +11,40 @@
# include "options_enum.generated.h"
#endif
+/// Option flags.
+typedef enum {
+ kOptFlagExpand = 1 << 0, ///< Environment expansion.
+ ///< NOTE: kOptFlagExpand can never be used for local or hidden options.
+ kOptFlagNoDefExp = 1 << 1, ///< Don't expand default value.
+ kOptFlagNoDefault = 1 << 2, ///< Don't set to default value.
+ kOptFlagWasSet = 1 << 3, ///< Option has been set/reset.
+ kOptFlagNoMkrc = 1 << 4, ///< Don't include in :mkvimrc output.
+ kOptFlagUIOption = 1 << 5, ///< Send option to remote UI.
+ kOptFlagRedrTabl = 1 << 6, ///< Redraw tabline.
+ kOptFlagRedrStat = 1 << 7, ///< Redraw status lines.
+ kOptFlagRedrWin = 1 << 8, ///< Redraw current window and recompute text.
+ kOptFlagRedrBuf = 1 << 9, ///< Redraw current buffer and recompute text.
+ kOptFlagRedrAll = kOptFlagRedrBuf | kOptFlagRedrWin, ///< Redraw all windows and recompute text.
+ kOptFlagRedrClear = kOptFlagRedrAll | kOptFlagRedrStat, ///< Clear and redraw all and recompute text.
+ kOptFlagComma = 1 << 10, ///< Comma-separated list.
+ kOptFlagOneComma = (1 << 11) | kOptFlagComma, ///< Comma-separated list that cannot have two consecutive commas.
+ kOptFlagNoDup = 1 << 12, ///< Don't allow duplicate strings.
+ kOptFlagFlagList = 1 << 13, ///< List of single-char flags.
+ kOptFlagSecure = 1 << 14, ///< Cannot change in modeline or secure mode.
+ kOptFlagGettext = 1 << 15, ///< Expand default value with _().
+ kOptFlagNoGlob = 1 << 16, ///< Do not use local value for global vimrc.
+ kOptFlagNFname = 1 << 17, ///< Only normal file name chars allowed.
+ kOptFlagInsecure = 1 << 18, ///< Option was set from a modeline.
+ kOptFlagPriMkrc = 1 << 19, ///< Priority for :mkvimrc (setting option has side effects).
+ kOptFlagNoML = 1 << 20, ///< Not allowed in modeline.
+ kOptFlagCurswant = 1 << 21, ///< Update curswant required; not needed when there is a redraw flag.
+ kOptFlagNDname = 1 << 22, ///< Only normal directory name chars allowed.
+ kOptFlagHLOnly = 1 << 23, ///< Option only changes highlight, not text.
+ kOptFlagMLE = 1 << 24, ///< Under control of 'modelineexpr'.
+ kOptFlagFunc = 1 << 25, ///< Accept a function reference or a lambda.
+ kOptFlagColon = 1 << 26, ///< Values use colons to create sublists.
+} OptFlags;
+
/// Option value type.
/// These types are also used as type flags by using the type value as an index for the type_flags
/// bit field (@see option_has_type()).
@@ -20,12 +54,20 @@ typedef enum {
kOptValTypeNumber,
kOptValTypeString,
} OptValType;
-
/// Always update this whenever a new option type is added.
#define kOptValTypeSize (kOptValTypeString + 1)
-
typedef uint32_t OptTypeFlags;
+/// Scopes that an option can support.
+typedef enum {
+ kOptScopeGlobal = 0, ///< Request global option value
+ kOptScopeWin, ///< Request window-local option value
+ kOptScopeBuf, ///< Request buffer-local option value
+} OptScope;
+/// Always update this whenever a new option scope is added.
+#define kOptScopeSize (kOptScopeBuf + 1)
+typedef uint8_t OptScopeFlags;
+
typedef union {
// boolean options are actually tri-states because they have a third "None" value.
TriState boolean;
@@ -62,7 +104,7 @@ typedef struct {
/// New value of the option.
OptValData os_newval;
- /// Option value was checked to be safe, no need to set P_INSECURE
+ /// Option value was checked to be safe, no need to set kOptFlagInsecure
/// Used for the 'keymap', 'filetype' and 'syntax' options.
bool os_value_checked;
/// Option value changed. Used for the 'filetype' and 'syntax' options.
@@ -127,9 +169,26 @@ typedef struct {
/// caller.
typedef int (*opt_expand_cb_T)(optexpand_T *args, int *numMatches, char ***matches);
-/// Requested option scopes for various functions in option.c
-typedef enum {
- kOptReqGlobal = 0, ///< Request global option value
- kOptReqWin = 1, ///< Request window-local option value
- kOptReqBuf = 2, ///< Request buffer-local option value
-} OptReqScope;
+typedef struct {
+ char *fullname; ///< full option name
+ char *shortname; ///< permissible abbreviation
+ uint32_t flags; ///< see above
+ OptTypeFlags type_flags; ///< option type flags, see OptValType
+ OptScopeFlags scope_flags; ///< option scope flags, see OptScope
+ void *var; ///< global option: pointer to variable;
+ ///< window-local option: NULL;
+ ///< buffer-local option: global value
+ ssize_t scope_idx[kOptScopeSize]; ///< index of option at every scope.
+ bool immutable; ///< option is immutable, trying to set it will give an error.
+
+ /// callback function to invoke after an option is modified to validate and
+ /// apply the new value.
+ opt_did_set_cb_T opt_did_set_cb;
+
+ /// callback function to invoke when expanding possible values on the
+ /// cmdline. Only useful for string options.
+ opt_expand_cb_T opt_expand_cb;
+
+ OptVal def_val; ///< default value
+ LastSet last_set; ///< script in which the option was last set
+} vimoption_T;
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
index 6b78007253..9ed24c4c9c 100644
--- a/src/nvim/option_vars.h
+++ b/src/nvim/option_vars.h
@@ -7,51 +7,6 @@
// option_vars.h: definition of global variables for settable options
-// Option Flags
-#define P_ALLOCED 0x01U ///< the option is in allocated memory,
- ///< must use free_string_option() when
- ///< assigning new value. Not set if default is
- ///< the same.
-#define P_EXPAND 0x02U ///< environment expansion. NOTE: P_EXPAND can
- ///< never be used for local or hidden options
-#define P_NO_DEF_EXP 0x04U ///< do not expand default value
-#define P_NODEFAULT 0x08U ///< don't set to default value
-#define P_DEF_ALLOCED 0x10U ///< default value is in allocated memory, must
- ///< use free() when assigning new value
-#define P_WAS_SET 0x20U ///< option has been set/reset
-#define P_NO_MKRC 0x40U ///< don't include in :mkvimrc output
-
-// when option changed, what to display:
-#define P_UI_OPTION 0x80U ///< send option to remote UI
-#define P_RTABL 0x100U ///< redraw tabline
-#define P_RSTAT 0x200U ///< redraw status lines
-#define P_RWIN 0x400U ///< redraw current window and recompute text
-#define P_RBUF 0x800U ///< redraw current buffer and recompute text
-#define P_RALL 0xC00U ///< redraw all windows and recompute text
-#define P_RCLR 0xE00U ///< clear and redraw all and recompute text
-
-#define P_COMMA 0x1000U ///< comma separated list
-#define P_ONECOMMA 0x3000U ///< P_COMMA and cannot have two consecutive
- ///< commas
-#define P_NODUP 0x4000U ///< don't allow duplicate strings
-#define P_FLAGLIST 0x8000U ///< list of single-char flags
-
-#define P_SECURE 0x10000U ///< cannot change in modeline or secure mode
-#define P_GETTEXT 0x20000U ///< expand default value with _()
-#define P_NOGLOB 0x40000U ///< do not use local value for global vimrc
-#define P_NFNAME 0x80000U ///< only normal file name chars allowed
-#define P_INSECURE 0x100000U ///< option was set from a modeline
-#define P_PRI_MKRC 0x200000U ///< priority for :mkvimrc (setting option
- ///< has side effects)
-#define P_NO_ML 0x400000U ///< not allowed in modeline
-#define P_CURSWANT 0x800000U ///< update curswant required; not needed
- ///< when there is a redraw flag
-#define P_NDNAME 0x1000000U ///< only normal dir name chars allowed
-#define P_HLONLY 0x2000000U ///< option only changes highlight, not text
-#define P_MLE 0x4000000U ///< under control of 'modelineexpr'
-#define P_FUNC 0x8000000U ///< accept a function reference or a lambda
-#define P_COLON 0x10000000U ///< values use colons to create sublists
-
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
"i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \
@@ -76,21 +31,6 @@
#define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m"
-// default values for b_p_ff 'fileformat' and p_ffs 'fileformats'
-#define FF_DOS "dos"
-#define FF_MAC "mac"
-#define FF_UNIX "unix"
-
-#ifdef USE_CRNL
-# define DFLT_FF "dos"
-# define DFLT_FFS_VIM "dos,unix"
-# define DFLT_FFS_VI "dos,unix" // also autodetect in compatible mode
-#else
-# define DFLT_FF "unix"
-# define DFLT_FFS_VIM "unix,dos"
-# define DFLT_FFS_VI ""
-#endif
-
// Possible values for 'encoding'
#define ENC_UCSBOM "ucs-bom" // check for BOM at start of file
@@ -348,6 +288,12 @@ enum {
#define LISPWORD_VALUE \
"defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object"
+// When a string option is NULL, it is set to empty_string_option,
+// to avoid having to check for NULL everywhere.
+//
+// TODO(famiu): Remove this when refcounted strings are used for string options.
+EXTERN char empty_string_option[] INIT( = "");
+
// The following are actual variables for the options
EXTERN char *p_ambw; ///< 'ambiwidth'
@@ -403,7 +349,8 @@ EXTERN unsigned bo_flags;
#define BO_REG 0x8000
#define BO_SH 0x10000
#define BO_SPELL 0x20000
-#define BO_WILD 0x40000
+#define BO_TERM 0x40000
+#define BO_WILD 0x80000
EXTERN char *p_bsk; ///< 'backupskip'
EXTERN char *p_breakat; ///< 'breakat'
@@ -489,6 +436,7 @@ EXTERN char *p_ffs; ///< 'fileformats'
EXTERN int p_fic; ///< 'fileignorecase'
EXTERN char *p_ft; ///< 'filetype'
EXTERN char *p_fcs; ///< 'fillchar'
+EXTERN char *p_ffu; ///< 'findfunc'
EXTERN int p_fixeol; ///< 'fixendofline'
EXTERN char *p_fcl; ///< 'foldclose'
EXTERN OptInt p_fdls; ///< 'foldlevelstart'
@@ -567,6 +515,7 @@ EXTERN char *p_mef; ///< 'makeef'
EXTERN char *p_mp; ///< 'makeprg'
EXTERN char *p_mps; ///< 'matchpairs'
EXTERN OptInt p_mat; ///< 'matchtime'
+EXTERN OptInt p_mco; ///< 'maxcombine'
EXTERN OptInt p_mfd; ///< 'maxfuncdepth'
EXTERN OptInt p_mmd; ///< 'maxmapdepth'
EXTERN OptInt p_mmp; ///< 'maxmempattern'
@@ -587,6 +536,7 @@ EXTERN OptInt p_mousescroll_vert INIT( = MOUSESCROLL_VERT_DFLT);
EXTERN OptInt p_mousescroll_hor INIT( = MOUSESCROLL_HOR_DFLT);
EXTERN OptInt p_mouset; ///< 'mousetime'
EXTERN int p_more; ///< 'more'
+EXTERN OptInt p_mhi; ///< 'msghistory'
EXTERN char *p_nf; ///< 'nrformats'
EXTERN char *p_opfunc; ///< 'operatorfunc'
EXTERN char *p_para; ///< 'paragraphs'
@@ -770,7 +720,7 @@ EXTERN unsigned ve_flags;
#define VE_NONEU 32U // "NONE"
EXTERN OptInt p_verbose; ///< 'verbose'
#ifdef IN_OPTION_C
-char *p_vfile = ""; ///< used before options are initialized
+char *p_vfile = empty_string_option; ///< used before options are initialized
#else
extern char *p_vfile; ///< 'verbosefile'
#endif
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 932d8f8d0e..9f86ef7489 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -7,14 +7,12 @@
--- @field alias? string|string[]
--- @field short_desc? string|fun(): string
--- @field varname? string
---- @field pv_name? string
---- @field type 'boolean'|'number'|'string'
---- @field hidden? boolean
+--- @field type vim.option_type|vim.option_type[]
--- @field immutable? boolean
--- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma'
--- @field scope vim.option_scope[]
--- @field deny_duplicates? boolean
---- @field enable_if? string|false
+--- @field enable_if? string
--- @field defaults? vim.option_defaults
--- @field secure? true
--- @field noglob? true
@@ -42,7 +40,9 @@
--- @field doc? string Default to show in options.txt
--- @field meta? integer|boolean|string Default to use in Lua meta files
---- @alias vim.option_scope 'global'|'buffer'|'window'
+--- @alias vim.option_scope 'global'|'buf'|'win'
+--- @alias vim.option_type 'boolean'|'number'|'string'
+--- @alias vim.option_value boolean|number|string
--- @alias vim.option_redraw
--- |'statuslines'
@@ -61,18 +61,11 @@ local function cstr(s)
end
--- @param s string
---- @return fun(): string
-local function macros(s)
- return function()
- return '.string=' .. s
- end
-end
-
---- @param s string
---- @return fun(): string
-local function imacros(s)
+--- @param t vim.option_type
+--- @return fun(): string, vim.option_type
+local function macros(s, t)
return function()
- return '.number=' .. s
+ return s, t
end
end
@@ -87,17 +80,19 @@ end
-- luacheck: ignore 621
return {
cstr = cstr,
+ --- @type string[]
+ valid_scopes = { 'global', 'buf', 'win' },
--- @type vim.option_meta[]
--- The order of the options MUST be alphabetic for ":set all".
options = {
{
abbreviation = 'al',
defaults = { if_true = 224 },
- enable_if = false,
full_name = 'aleph',
scope = { 'global' },
short_desc = N_('ASCII code of the letter Aleph (Hebrew)'),
type = 'number',
+ immutable = true,
},
{
abbreviation = 'ari',
@@ -179,7 +174,7 @@ return {
]=],
full_name = 'arabic',
redraw = { 'curswant' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Arabic as a default second language'),
type = 'boolean',
},
@@ -242,7 +237,7 @@ return {
a different way.
]=],
full_name = 'autoindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('take indent for new line from previous line'),
type = 'boolean',
varname = 'p_ai',
@@ -262,7 +257,7 @@ return {
<
]=],
full_name = 'autoread',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('autom. read file when changed outside of Vim'),
type = 'boolean',
varname = 'p_ar',
@@ -435,12 +430,13 @@ return {
useful for example in source trees where all the files are symbolic or
hard links and any changes should stay in the local source tree, not
be propagated back to the original source.
- *crontab*
+ *crontab*
One situation where "no" and "auto" will cause problems: A program
that opens a file, invokes Vim to edit that file, and then tests if
the open file was changed (through the file descriptor) will check the
backup file instead of the newly created file. "crontab -e" is an
- example.
+ example, as are several |file-watcher| daemons like inotify. In that
+ case you probably want to switch this option.
When a copy is made, the original file is truncated and then filled
with the new text. This means that protection bits, owner and
@@ -462,7 +458,7 @@ return {
expand_cb = 'expand_set_backupcopy',
full_name = 'backupcopy',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_("make backup as a copy, don't rename the file"),
type = 'string',
varname = 'p_bkc',
@@ -597,6 +593,7 @@ return {
separated list of items. For each item that is present, the bell
will be silenced. This is most useful to specify specific events in
insert mode to be silenced.
+ You can also make it flash by using 'visualbell'.
item meaning when present ~
all All events.
@@ -620,6 +617,7 @@ return {
register Unknown register after <C-R> in |Insert-mode|.
shell Bell from shell output |:!|.
spell Error happened on spell suggest.
+ term Bell from |:terminal| output.
wildmode More matches in |cmdline-completion| available
(depends on the 'wildmode' setting).
@@ -670,7 +668,7 @@ return {
]=],
full_name = 'binary',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('read/write/edit file in binary mode'),
type = 'boolean',
varname = 'p_bin',
@@ -698,7 +696,7 @@ return {
full_name = 'bomb',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('a Byte Order Mark to the file'),
type = 'boolean',
varname = 'p_bomb',
@@ -732,13 +730,12 @@ return {
]=],
full_name = 'breakindent',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('wrapped line repeats indent'),
type = 'boolean',
},
{
abbreviation = 'briopt',
- alloced = true,
cb = 'did_set_breakindentopt',
defaults = { if_true = '' },
deny_duplicates = true,
@@ -775,7 +772,7 @@ return {
full_name = 'breakindentopt',
list = 'onecomma',
redraw = { 'current_buffer' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("settings for 'breakindent'"),
type = 'string',
},
@@ -793,15 +790,14 @@ return {
current Use the current directory.
{path} Use the specified directory
]=],
- enable_if = false,
full_name = 'browsedir',
scope = { 'global' },
short_desc = N_('which directory to start browsing in'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'bh',
- alloced = true,
cb = 'did_set_bufhidden',
defaults = { if_true = '' },
desc = [=[
@@ -828,7 +824,7 @@ return {
expand_cb = 'expand_set_bufhidden',
full_name = 'bufhidden',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('what to do when buffer is no longer in window'),
type = 'string',
varname = 'p_bh',
@@ -846,7 +842,7 @@ return {
]=],
full_name = 'buflisted',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('whether the buffer shows up in the buffer list'),
tags = { 'E85' },
type = 'boolean',
@@ -854,7 +850,6 @@ return {
},
{
abbreviation = 'bt',
- alloced = true,
cb = 'did_set_buftype',
defaults = { if_true = '' },
desc = [=[
@@ -906,7 +901,7 @@ return {
expand_cb = 'expand_set_buftype',
full_name = 'buftype',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
tags = { 'E382' },
short_desc = N_('special type of buffer'),
type = 'string',
@@ -991,7 +986,7 @@ return {
{
cb = 'did_set_cedit',
defaults = {
- if_true = macros('CTRL_F_STR'),
+ if_true = macros('CTRL_F_STR', 'string'),
doc = 'CTRL-F',
},
desc = [=[
@@ -1021,7 +1016,7 @@ return {
full_name = 'channel',
no_mkrc = true,
nodefault = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('Channel connected to the buffer'),
type = 'number',
varname = 'p_channel',
@@ -1099,14 +1094,13 @@ return {
option or 'indentexpr'.
]=],
full_name = 'cindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('do C program indenting'),
type = 'boolean',
varname = 'p_cin',
},
{
abbreviation = 'cink',
- alloced = true,
defaults = { if_true = '0{,0},0),0],:,0#,!^F,o,O,e' },
deny_duplicates = true,
desc = [=[
@@ -1118,14 +1112,13 @@ return {
]=],
full_name = 'cinkeys',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("keys that trigger indent when 'cindent' is set"),
type = 'string',
varname = 'p_cink',
},
{
abbreviation = 'cino',
- alloced = true,
cb = 'did_set_cinoptions',
defaults = { if_true = '' },
deny_duplicates = true,
@@ -1136,14 +1129,13 @@ return {
]=],
full_name = 'cinoptions',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("how to do indenting when 'cindent' is set"),
type = 'string',
varname = 'p_cino',
},
{
abbreviation = 'cinsd',
- alloced = true,
defaults = { if_true = 'public,protected,private' },
deny_duplicates = true,
desc = [=[
@@ -1155,14 +1147,13 @@ return {
]=],
full_name = 'cinscopedecls',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("words that are recognized by 'cino-g'"),
type = 'string',
varname = 'p_cinsd',
},
{
abbreviation = 'cinw',
- alloced = true,
defaults = { if_true = 'if,else,while,do,for,switch' },
deny_duplicates = true,
desc = [=[
@@ -1175,7 +1166,7 @@ return {
]=],
full_name = 'cinwords',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("words where 'si' and 'cin' add an indent"),
type = 'string',
varname = 'p_cinw',
@@ -1277,7 +1268,7 @@ return {
full_name = 'colorcolumn',
list = 'onecomma',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('columns to highlight'),
type = 'string',
},
@@ -1285,7 +1276,7 @@ return {
abbreviation = 'co',
cb = 'did_set_lines_or_columns',
defaults = {
- if_true = imacros('DFLT_COLS'),
+ if_true = macros('DFLT_COLS', 'number'),
doc = '80 or terminal width',
},
desc = [=[
@@ -1312,7 +1303,6 @@ return {
},
{
abbreviation = 'com',
- alloced = true,
cb = 'did_set_comments',
defaults = { if_true = 's1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-,fb:•' },
deny_duplicates = true,
@@ -1323,7 +1313,7 @@ return {
]=],
full_name = 'comments',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('patterns that can start a comment line'),
tags = { 'E524', 'E525' },
type = 'string',
@@ -1331,7 +1321,6 @@ return {
},
{
abbreviation = 'cms',
- alloced = true,
cb = 'did_set_commentstring',
defaults = { if_true = '' },
desc = [=[
@@ -1340,7 +1329,7 @@ return {
Used for |commenting| and to add markers for folding, see |fold-marker|.
]=],
full_name = 'commentstring',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('template for comments; used for fold marker'),
tags = { 'E537' },
type = 'string',
@@ -1357,7 +1346,6 @@ return {
},
{
abbreviation = 'cpt',
- alloced = true,
cb = 'did_set_complete',
defaults = { if_true = '.,w,b,u,t' },
deny_duplicates = true,
@@ -1398,7 +1386,7 @@ return {
expand_cb = 'expand_set_complete',
full_name = 'complete',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('specify how Insert mode completion works'),
tags = { 'E535' },
type = 'string',
@@ -1406,7 +1394,6 @@ return {
},
{
abbreviation = 'cfu',
- alloced = true,
cb = 'did_set_completefunc',
defaults = { if_true = '' },
desc = [=[
@@ -1421,7 +1408,7 @@ return {
]=],
full_name = 'completefunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function to be used for Insert mode completion'),
type = 'string',
@@ -1497,7 +1484,7 @@ return {
expand_cb = 'expand_set_completeopt',
full_name = 'completeopt',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('options for Insert mode completion'),
type = 'string',
varname = 'p_cot',
@@ -1507,7 +1494,7 @@ return {
cb = 'did_set_completeslash',
defaults = { if_true = '' },
desc = [=[
- only for MS-Windows
+ only modifiable in MS-Windows
When this option is set it overrules 'shellslash' for completion:
- When this option is set to "slash", a forward slash is used for path
completion in insert mode. This is useful when editing HTML tag, or
@@ -1522,13 +1509,12 @@ return {
enable_if = 'BACKSLASH_IN_FILENAME',
expand_cb = 'expand_set_completeslash',
full_name = 'completeslash',
- scope = { 'buffer' },
+ scope = { 'buf' },
type = 'string',
varname = 'p_csl',
},
{
abbreviation = 'cocu',
- alloced = true,
cb = 'did_set_concealcursor',
defaults = { if_true = '' },
desc = [=[
@@ -1552,7 +1538,7 @@ return {
full_name = 'concealcursor',
list = 'flags',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('whether concealable text is hidden in cursor line'),
type = 'string',
},
@@ -1581,7 +1567,7 @@ return {
]=],
full_name = 'conceallevel',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('whether concealable text is shown or hidden'),
type = 'number',
},
@@ -1619,7 +1605,7 @@ return {
See 'preserveindent'.
]=],
full_name = 'copyindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("make 'autoindent' use existing indent structure"),
type = 'boolean',
varname = 'p_ci',
@@ -1627,7 +1613,7 @@ return {
{
abbreviation = 'cpo',
cb = 'did_set_cpoptions',
- defaults = { if_true = macros('CPO_VIM') },
+ defaults = { if_true = macros('CPO_VIM', 'string') },
desc = [=[
A sequence of single character flags. When a character is present
this indicates Vi-compatible behavior. This is used for things where
@@ -1880,8 +1866,7 @@ return {
taken into account.
]=],
full_name = 'cursorbind',
- pv_name = 'p_crbind',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('move cursor in window as it moves in other windows'),
type = 'boolean',
},
@@ -1900,7 +1885,7 @@ return {
]=],
full_name = 'cursorcolumn',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('highlight the screen column of the cursor'),
type = 'boolean',
},
@@ -1915,7 +1900,7 @@ return {
]=],
full_name = 'cursorline',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('highlight the screen line of the cursor'),
type = 'boolean',
},
@@ -1943,7 +1928,7 @@ return {
full_name = 'cursorlineopt',
list = 'onecomma',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("settings for 'cursorline'"),
type = 'string',
},
@@ -1971,7 +1956,6 @@ return {
},
{
abbreviation = 'def',
- alloced = true,
defaults = { if_true = '' },
desc = [=[
Pattern to be used to find a macro definition. It is a search
@@ -1995,7 +1979,7 @@ return {
<
]=],
full_name = 'define',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('pattern to be used to find a macro definition'),
type = 'string',
varname = 'p_def',
@@ -2052,7 +2036,7 @@ return {
full_name = 'dictionary',
list = 'onecomma',
normal_dname_chars = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of file names used for keyword completion'),
type = 'string',
varname = 'p_dict',
@@ -2067,7 +2051,7 @@ return {
full_name = 'diff',
noglob = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('diff mode for the current window'),
type = 'boolean',
},
@@ -2091,7 +2075,6 @@ return {
},
{
abbreviation = 'dip',
- alloced = true,
cb = 'did_set_diffopt',
defaults = { if_true = 'internal,filler,closeoff' },
deny_duplicates = true,
@@ -2365,7 +2348,7 @@ return {
{
abbreviation = 'enc',
cb = 'did_set_encoding',
- defaults = { if_true = macros('ENC_DFLT') },
+ defaults = { if_true = macros('ENC_DFLT', 'string') },
deny_in_modelines = true,
desc = [=[
String-encoding used internally and for |RPC| communication.
@@ -2394,7 +2377,7 @@ return {
full_name = 'endoffile',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('write CTRL-Z for last line in file'),
type = 'boolean',
varname = 'p_eof',
@@ -2420,7 +2403,7 @@ return {
full_name = 'endofline',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('write <EOL> for last line in file'),
type = 'boolean',
varname = 'p_eol',
@@ -2465,7 +2448,7 @@ return {
]=],
expand = true,
full_name = 'equalprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('external program to use for "=" command'),
type = 'string',
@@ -2489,7 +2472,7 @@ return {
},
{
abbreviation = 'ef',
- defaults = { if_true = macros('DFLT_ERRORFILE') },
+ defaults = { if_true = macros('DFLT_ERRORFILE', 'string') },
desc = [=[
Name of the errorfile for the QuickFix mode (see |:cf|).
When the "-q" command-line argument is used, 'errorfile' is set to the
@@ -2511,7 +2494,7 @@ return {
{
abbreviation = 'efm',
defaults = {
- if_true = macros('DFLT_EFM'),
+ if_true = macros('DFLT_EFM', 'string'),
doc = 'is very long',
},
deny_duplicates = true,
@@ -2521,7 +2504,7 @@ return {
]=],
full_name = 'errorformat',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('description of the lines in the error file'),
type = 'string',
varname = 'p_efm',
@@ -2557,7 +2540,7 @@ return {
on, use CTRL-V<Tab>. See also |:retab| and |ins-expandtab|.
]=],
full_name = 'expandtab',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use spaces when <Tab> is inserted'),
type = 'boolean',
varname = 'p_et',
@@ -2586,7 +2569,6 @@ return {
},
{
abbreviation = 'fenc',
- alloced = true,
cb = 'did_set_encoding',
defaults = { if_true = '' },
desc = [=[
@@ -2632,7 +2614,7 @@ return {
full_name = 'fileencoding',
no_mkrc = true,
redraw = { 'statuslines', 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('file encoding for multi-byte text'),
tags = { 'E213' },
type = 'string',
@@ -2700,10 +2682,11 @@ return {
},
{
abbreviation = 'ff',
- alloced = true,
cb = 'did_set_fileformat',
defaults = {
- if_true = macros('DFLT_FF'),
+ condition = 'USE_CRNL',
+ if_true = 'dos',
+ if_false = 'unix',
doc = 'Windows: "dos", Unix: "unix"',
},
desc = [=[
@@ -2727,7 +2710,7 @@ return {
full_name = 'fileformat',
no_mkrc = true,
redraw = { 'curswant', 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('file format used for file I/O'),
type = 'string',
varname = 'p_ff',
@@ -2736,7 +2719,9 @@ return {
abbreviation = 'ffs',
cb = 'did_set_fileformats',
defaults = {
- if_true = macros('DFLT_FFS_VIM'),
+ condition = 'USE_CRNL',
+ if_true = 'dos,unix',
+ if_false = 'unix,dos',
doc = 'Windows: "dos,unix", Unix: "unix,dos"',
},
deny_duplicates = true,
@@ -2816,7 +2801,6 @@ return {
},
{
abbreviation = 'ft',
- alloced = true,
cb = 'did_set_filetype_or_syntax',
defaults = { if_true = '' },
desc = [=[
@@ -2845,14 +2829,13 @@ return {
full_name = 'filetype',
noglob = true,
normal_fname_chars = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('type of file, used for autocommands'),
type = 'string',
varname = 'p_ft',
},
{
abbreviation = 'fcs',
- alloced = true,
cb = 'did_set_chars_option',
defaults = { if_true = '' },
deny_duplicates = true,
@@ -2921,12 +2904,72 @@ return {
full_name = 'fillchars',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('characters to use for displaying special items'),
type = 'string',
varname = 'p_fcs',
},
{
+ abbreviation = 'ffu',
+ cb = 'did_set_findfunc',
+ defaults = { if_true = '' },
+ desc = [=[
+ Function that is called to obtain the filename(s) for the |:find|
+ command. When this option is empty, the internal |file-searching|
+ mechanism is used.
+
+ The value can be the name of a function, a |lambda| or a |Funcref|.
+ See |option-value-function| for more information.
+
+ The function is called with two arguments. The first argument is a
+ |String| and is the |:find| command argument. The second argument is
+ a |Boolean| and is set to |v:true| when the function is called to get
+ a List of command-line completion matches for the |:find| command.
+ The function should return a List of strings.
+
+ The function is called only once per |:find| command invocation.
+ The function can process all the directories specified in 'path'.
+
+ If a match is found, the function should return a |List| containing
+ one or more file names. If a match is not found, the function
+ should return an empty List.
+
+ If any errors are encountered during the function invocation, an
+ empty List is used as the return value.
+
+ It is not allowed to change text or jump to another window while
+ executing the 'findfunc' |textlock|.
+
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+
+ Examples:
+ >vim
+ " Use glob()
+ func FindFuncGlob(cmdarg, cmdcomplete)
+ let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
+ return glob(pat, v:false, v:true)
+ endfunc
+ set findfunc=FindFuncGlob
+
+ " Use the 'git ls-files' output
+ func FindGitFiles(cmdarg, cmdcomplete)
+ let fnames = systemlist('git ls-files')
+ return fnames->filter('v:val =~? a:cmdarg')
+ endfunc
+ set findfunc=FindGitFiles
+ <
+ ]=],
+ full_name = 'findfunc',
+ func = true,
+ scope = { 'global', 'buf' },
+ secure = true,
+ short_desc = N_('function called for :find'),
+ tags = { 'E1514' },
+ type = 'string',
+ varname = 'p_ffu',
+ },
+ {
abbreviation = 'fixeol',
cb = 'did_set_eof_eol_fixeol_bomb',
defaults = { if_true = true },
@@ -2941,7 +2984,7 @@ return {
]=],
full_name = 'fixendofline',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('make sure last line in file has <EOL>'),
type = 'boolean',
varname = 'p_fixeol',
@@ -2967,7 +3010,6 @@ return {
},
{
abbreviation = 'fdc',
- alloced = true,
cb = 'did_set_foldcolumn',
defaults = { if_true = '0' },
desc = [=[
@@ -2982,7 +3024,7 @@ return {
expand_cb = 'expand_set_foldcolumn',
full_name = 'foldcolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('width of the column used to indicate folds'),
type = 'string',
},
@@ -3000,13 +3042,12 @@ return {
]=],
full_name = 'foldenable',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('set to display all folds open'),
type = 'boolean',
},
{
abbreviation = 'fde',
- alloced = true,
cb = 'did_set_foldexpr',
defaults = { if_true = '0' },
desc = [=[
@@ -3026,13 +3067,12 @@ return {
full_name = 'foldexpr',
modelineexpr = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('expression used when \'foldmethod\' is "expr"'),
type = 'string',
},
{
abbreviation = 'fdi',
- alloced = true,
cb = 'did_set_foldignore',
defaults = { if_true = '#' },
desc = [=[
@@ -3043,7 +3083,7 @@ return {
]=],
full_name = 'foldignore',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('ignore lines when \'foldmethod\' is "indent"'),
type = 'string',
},
@@ -3060,7 +3100,7 @@ return {
]=],
full_name = 'foldlevel',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('close folds with a level higher than this'),
type = 'number',
},
@@ -3087,7 +3127,6 @@ return {
},
{
abbreviation = 'fmr',
- alloced = true,
cb = 'did_set_foldmarker',
defaults = { if_true = '{{{,}}}' },
deny_duplicates = true,
@@ -3100,14 +3139,13 @@ return {
full_name = 'foldmarker',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('markers used when \'foldmethod\' is "marker"'),
tags = { 'E536' },
type = 'string',
},
{
abbreviation = 'fdm',
- alloced = true,
cb = 'did_set_foldmethod',
defaults = { if_true = 'manual' },
desc = [=[
@@ -3122,7 +3160,7 @@ return {
expand_cb = 'expand_set_foldmethod',
full_name = 'foldmethod',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('folding type'),
type = 'string',
},
@@ -3141,7 +3179,7 @@ return {
]=],
full_name = 'foldminlines',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('minimum number of lines for a fold to be closed'),
type = 'number',
},
@@ -3156,7 +3194,7 @@ return {
]=],
full_name = 'foldnestmax',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('maximum fold depth'),
type = 'number',
},
@@ -3208,7 +3246,6 @@ return {
},
{
abbreviation = 'fdt',
- alloced = true,
cb = 'did_set_optexpr',
defaults = { if_true = 'foldtext()' },
desc = [=[
@@ -3230,13 +3267,12 @@ return {
full_name = 'foldtext',
modelineexpr = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('expression used to display for a closed fold'),
type = 'string',
},
{
abbreviation = 'fex',
- alloced = true,
cb = 'did_set_optexpr',
defaults = { if_true = '' },
desc = [=[
@@ -3283,14 +3319,13 @@ return {
]=],
full_name = 'formatexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used with "gq" command'),
type = 'string',
varname = 'p_fex',
},
{
abbreviation = 'flp',
- alloced = true,
defaults = { if_true = '^\\s*\\d\\+[\\]:.)}\\t ]\\s*' },
desc = [=[
A pattern that is used to recognize a list header. This is used for
@@ -3304,16 +3339,15 @@ return {
character and white space.
]=],
full_name = 'formatlistpat',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pattern used to recognize a list header'),
type = 'string',
varname = 'p_flp',
},
{
abbreviation = 'fo',
- alloced = true,
cb = 'did_set_formatoptions',
- defaults = { if_true = macros('DFLT_FO_VIM') },
+ defaults = { if_true = macros('DFLT_FO_VIM', 'string') },
desc = [=[
This is a sequence of letters which describes how automatic
formatting is to be done.
@@ -3325,7 +3359,7 @@ return {
expand_cb = 'expand_set_formatoptions',
full_name = 'formatoptions',
list = 'flags',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('how automatic formatting is to be done'),
type = 'string',
varname = 'p_fo',
@@ -3348,7 +3382,7 @@ return {
]=],
expand = true,
full_name = 'formatprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('name of external program used with "gq" command'),
type = 'string',
@@ -3406,7 +3440,7 @@ return {
},
{
abbreviation = 'gfm',
- defaults = { if_true = macros('DFLT_GREPFORMAT') },
+ defaults = { if_true = macros('DFLT_GREPFORMAT', 'string') },
deny_duplicates = true,
desc = [=[
Format to recognize for the ":grep" command output.
@@ -3456,7 +3490,7 @@ return {
]=],
expand = true,
full_name = 'grepprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for ":grep"'),
type = 'string',
@@ -3761,15 +3795,16 @@ return {
try to keep 'lines' and 'columns' the same when adding and
removing GUI components.
]=],
- enable_if = false,
full_name = 'guioptions',
list = 'flags',
scope = { 'global' },
short_desc = N_('GUI: Which components and options are used'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'gtl',
+ defaults = { if_true = '' },
desc = [=[
When non-empty describes the text to use in a label of the GUI tab
pages line. When empty and when the result is empty Vim will use a
@@ -3785,16 +3820,17 @@ return {
present in 'guioptions'. For the non-GUI tab pages line 'tabline' is
used.
]=],
- enable_if = false,
full_name = 'guitablabel',
modelineexpr = true,
redraw = { 'current_window' },
scope = { 'global' },
short_desc = N_('GUI: custom label for a tab page'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'gtt',
+ defaults = { if_true = '' },
desc = [=[
When non-empty describes the text to use in a tooltip for the GUI tab
pages line. When empty Vim will use a default tooltip.
@@ -3803,18 +3839,18 @@ return {
let &guitabtooltip = "line one\nline two"
<
]=],
- enable_if = false,
full_name = 'guitabtooltip',
redraw = { 'current_window' },
scope = { 'global' },
short_desc = N_('GUI: custom tooltip for a tab page'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'hf',
cb = 'did_set_helpfile',
defaults = {
- if_true = macros('DFLT_HELPFILE'),
+ if_true = macros('DFLT_HELPFILE', 'string'),
doc = [[(MS-Windows) "$VIMRUNTIME\doc\help.txt"
(others) "$VIMRUNTIME/doc/help.txt"]],
},
@@ -3911,7 +3947,7 @@ return {
{
abbreviation = 'hl',
cb = 'did_set_highlight',
- defaults = { if_true = macros('HIGHLIGHT_INIT') },
+ defaults = { if_true = macros('HIGHLIGHT_INIT', 'string') },
deny_duplicates = true,
full_name = 'highlight',
list = 'onecomma',
@@ -3926,7 +3962,8 @@ return {
desc = [=[
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
- each of these histories (see |cmdline-editing|).
+ each of these histories (see |cmdline-editing| and 'msghistory' for
+ the number of messages to remember).
The maximum value is 10000.
]=],
full_name = 'history',
@@ -4050,11 +4087,11 @@ return {
English characters directly, e.g., when it's used to type accented
characters with dead keys.
]=],
- enable_if = false,
full_name = 'imcmdline',
scope = { 'global' },
short_desc = N_('use IM when starting to edit a command line'),
type = 'boolean',
+ immutable = true,
},
{
abbreviation = 'imd',
@@ -4068,16 +4105,16 @@ return {
Currently this option is on by default for SGI/IRIX machines. This
may change in later releases.
]=],
- enable_if = false,
full_name = 'imdisable',
scope = { 'global' },
short_desc = N_('do not use the IM in any mode'),
type = 'boolean',
+ immutable = true,
},
{
abbreviation = 'imi',
cb = 'did_set_iminsert',
- defaults = { if_true = imacros('B_IMODE_NONE') },
+ defaults = { if_true = macros('B_IMODE_NONE', 'number') },
desc = [=[
Specifies whether :lmap or an Input Method (IM) is to be used in
Insert mode. Valid values:
@@ -4095,15 +4132,14 @@ return {
It is also used for the argument of commands like "r" and "f".
]=],
full_name = 'iminsert',
- pv_name = 'p_imi',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use :lmap or IM in Insert mode'),
type = 'number',
varname = 'p_iminsert',
},
{
abbreviation = 'ims',
- defaults = { if_true = imacros('B_IMODE_USE_INSERT') },
+ defaults = { if_true = macros('B_IMODE_USE_INSERT', 'number') },
desc = [=[
Specifies whether :lmap or an Input Method (IM) is to be used when
entering a search pattern. Valid values:
@@ -4118,8 +4154,7 @@ return {
option to a valid keymap name.
]=],
full_name = 'imsearch',
- pv_name = 'p_ims',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use :lmap or IM when typing a search pattern'),
type = 'number',
varname = 'p_imsearch',
@@ -4152,7 +4187,6 @@ return {
},
{
abbreviation = 'inc',
- alloced = true,
defaults = { if_true = '' },
desc = [=[
Pattern to be used to find an include command. It is a search
@@ -4167,14 +4201,13 @@ return {
See |option-backslash| about including spaces and backslashes.
]=],
full_name = 'include',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('pattern to be used to find an include file'),
type = 'string',
varname = 'p_inc',
},
{
abbreviation = 'inex',
- alloced = true,
cb = 'did_set_optexpr',
defaults = { if_true = '' },
desc = [=[
@@ -4210,7 +4243,7 @@ return {
]=],
full_name = 'includeexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used to process an include line'),
type = 'string',
varname = 'p_inex',
@@ -4259,7 +4292,6 @@ return {
},
{
abbreviation = 'inde',
- alloced = true,
cb = 'did_set_optexpr',
defaults = { if_true = '' },
desc = [=[
@@ -4306,14 +4338,13 @@ return {
]=],
full_name = 'indentexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used to obtain the indent of a line'),
type = 'string',
varname = 'p_inde',
},
{
abbreviation = 'indk',
- alloced = true,
defaults = { if_true = '0{,0},0),0],:,0#,!^F,o,O,e' },
deny_duplicates = true,
desc = [=[
@@ -4324,7 +4355,7 @@ return {
]=],
full_name = 'indentkeys',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("keys that trigger indenting with 'indentexpr'"),
type = 'string',
varname = 'p_indk',
@@ -4343,7 +4374,7 @@ return {
With 'noinfercase' the match is used as-is.
]=],
full_name = 'infercase',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('adjust case of match for keyword completion'),
type = 'boolean',
varname = 'p_inf',
@@ -4455,8 +4486,7 @@ return {
},
{
abbreviation = 'isk',
- alloced = true,
- cb = 'did_set_isopt',
+ cb = 'did_set_iskeyword',
defaults = { if_true = '@,48-57,_,192-255' },
deny_duplicates = true,
desc = [=[
@@ -4475,7 +4505,7 @@ return {
]=],
full_name = 'iskeyword',
list = 'comma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('characters included in keywords'),
type = 'string',
varname = 'p_isk',
@@ -4564,7 +4594,6 @@ return {
},
{
abbreviation = 'kmp',
- alloced = true,
cb = 'did_set_keymap',
defaults = { if_true = '' },
desc = [=[
@@ -4577,9 +4606,8 @@ return {
full_name = 'keymap',
normal_fname_chars = true,
pri_mkrc = true,
- pv_name = 'p_kmap',
redraw = { 'statuslines', 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('name of a keyboard mapping'),
type = 'string',
varname = 'p_keymap',
@@ -4631,7 +4659,7 @@ return {
]=],
expand = true,
full_name = 'keywordprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for the "K" command'),
type = 'string',
@@ -4802,14 +4830,14 @@ return {
]=],
full_name = 'linebreak',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('wrap long lines at a blank'),
type = 'boolean',
},
{
cb = 'did_set_lines_or_columns',
defaults = {
- if_true = imacros('DFLT_ROWS'),
+ if_true = macros('DFLT_ROWS', 'number'),
doc = '24 or terminal height',
},
desc = [=[
@@ -4866,7 +4894,7 @@ return {
calling an external program if 'equalprg' is empty.
]=],
full_name = 'lisp',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('indenting for Lisp'),
type = 'boolean',
varname = 'p_lisp',
@@ -4888,8 +4916,7 @@ return {
expand_cb = 'expand_set_lispoptions',
full_name = 'lispoptions',
list = 'onecomma',
- pv_name = 'p_lop',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('options for lisp indenting'),
type = 'string',
varname = 'p_lop',
@@ -4897,7 +4924,7 @@ return {
{
abbreviation = 'lw',
defaults = {
- if_true = macros('LISPWORD_VALUE'),
+ if_true = macros('LISPWORD_VALUE', 'string'),
doc = 'is very long',
},
deny_duplicates = true,
@@ -4907,8 +4934,7 @@ return {
]=],
full_name = 'lispwords',
list = 'onecomma',
- pv_name = 'p_lw',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('words that change how lisp indenting works'),
type = 'string',
varname = 'p_lispwords',
@@ -4935,13 +4961,12 @@ return {
]=],
full_name = 'list',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('<Tab> and <EOL>'),
type = 'boolean',
},
{
abbreviation = 'lcs',
- alloced = true,
cb = 'did_set_chars_option',
defaults = { if_true = 'tab:> ,trail:-,nbsp:+' },
deny_duplicates = true,
@@ -5047,7 +5072,7 @@ return {
full_name = 'listchars',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('characters for displaying in list mode'),
type = 'string',
varname = 'p_lcs',
@@ -5128,7 +5153,7 @@ return {
]=],
expand_cb = 'expand_set_encoding',
full_name = 'makeencoding',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('Converts the output of external commands'),
type = 'string',
varname = 'p_menc',
@@ -5155,7 +5180,7 @@ return {
]=],
expand = true,
full_name = 'makeprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for the ":make" command'),
type = 'string',
@@ -5163,7 +5188,6 @@ return {
},
{
abbreviation = 'mps',
- alloced = true,
cb = 'did_set_matchpairs',
defaults = { if_true = '(:),{:},[:]' },
deny_duplicates = true,
@@ -5186,7 +5210,7 @@ return {
]=],
full_name = 'matchpairs',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pairs of characters that "%" can match'),
type = 'string',
varname = 'p_mps',
@@ -5207,12 +5231,12 @@ return {
},
{
abbreviation = 'mco',
- defaults = { if_true = imacros('MAX_MCO') },
+ defaults = { if_true = macros('MAX_MCO', 'number') },
full_name = 'maxcombine',
scope = { 'global' },
short_desc = N_('maximum nr of combining characters displayed'),
type = 'number',
- hidden = true,
+ varname = 'p_mco',
},
{
abbreviation = 'mfd',
@@ -5348,7 +5372,7 @@ return {
no lines are checked. See |modeline|.
]=],
full_name = 'modeline',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('recognize modelines at start or end of file'),
type = 'boolean',
varname = 'p_ml',
@@ -5396,7 +5420,7 @@ return {
]=],
full_name = 'modifiable',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('changes to the text are not possible'),
tags = { 'E21' },
type = 'boolean',
@@ -5432,7 +5456,7 @@ return {
full_name = 'modified',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('buffer has been modified'),
type = 'boolean',
varname = 'p_mod',
@@ -5708,13 +5732,13 @@ return {
indicate no input when the hit-enter prompt is displayed (since
clicking the mouse has no effect in this state.)
]=],
- enable_if = false,
full_name = 'mouseshape',
list = 'onecomma',
scope = { 'global' },
short_desc = N_('shape of the mouse pointer in different modes'),
tags = { 'E547' },
type = 'string',
+ immutable = true,
},
{
abbreviation = 'mouset',
@@ -5730,8 +5754,20 @@ return {
varname = 'p_mouset',
},
{
+ abbreviation = 'mhi',
+ defaults = { if_true = 500 },
+ desc = [=[
+ Determines how many entries are remembered in the |:messages| history.
+ The maximum value is 10000.
+ ]=],
+ full_name = 'msghistory',
+ scope = { 'global' },
+ short_desc = N_('how many messages are remembered'),
+ type = 'number',
+ varname = 'p_mhi',
+ },
+ {
abbreviation = 'nf',
- alloced = true,
cb = 'did_set_nrformats',
defaults = { if_true = 'bin,hex' },
deny_duplicates = true,
@@ -5780,7 +5816,7 @@ return {
expand_cb = 'expand_set_nrformats',
full_name = 'nrformats',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number formats recognized for CTRL-A command'),
type = 'string',
varname = 'p_nf',
@@ -5814,7 +5850,7 @@ return {
]=],
full_name = 'number',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('print the line number in front of each line'),
type = 'boolean',
},
@@ -5836,13 +5872,12 @@ return {
]=],
full_name = 'numberwidth',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('number of columns used for the line number'),
type = 'number',
},
{
abbreviation = 'ofu',
- alloced = true,
cb = 'did_set_omnifunc',
defaults = { if_true = '' },
desc = [=[
@@ -5859,7 +5894,7 @@ return {
]=],
full_name = 'omnifunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function for filetype-specific completion'),
type = 'string',
@@ -5876,11 +5911,11 @@ return {
Note that on Windows editing "aux.h", "lpt1.txt" and the like also
result in editing a device.
]=],
- enable_if = false,
full_name = 'opendevice',
scope = { 'global' },
short_desc = N_('allow reading/writing devices on MS-Windows'),
type = 'boolean',
+ immutable = true,
},
{
abbreviation = 'opfunc',
@@ -5953,11 +5988,11 @@ return {
{
abbreviation = 'pt',
defaults = { if_true = '' },
- enable_if = false,
full_name = 'pastetoggle',
scope = { 'global' },
short_desc = N_('No description'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'pex',
@@ -6062,7 +6097,7 @@ return {
expand = true,
full_name = 'path',
list = 'comma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of directories searched with "gf" et.al.'),
tags = { 'E343', 'E345', 'E347', 'E854' },
type = 'string',
@@ -6086,7 +6121,7 @@ return {
Use |:retab| to clean up white space.
]=],
full_name = 'preserveindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('preserve the indent structure when reindenting'),
type = 'boolean',
varname = 'p_pi',
@@ -6116,7 +6151,7 @@ return {
full_name = 'previewwindow',
noglob = true,
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('identifies the preview window'),
tags = { 'E590' },
type = 'boolean',
@@ -6226,7 +6261,6 @@ return {
},
{
abbreviation = 'qe',
- alloced = true,
defaults = { if_true = '\\' },
desc = [=[
The characters that are used to escape quotes in a string. Used for
@@ -6236,7 +6270,7 @@ return {
text "foo\"bar\\" considered to be one string.
]=],
full_name = 'quoteescape',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('escape characters used in a string'),
type = 'string',
varname = 'p_qe',
@@ -6258,7 +6292,7 @@ return {
full_name = 'readonly',
noglob = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('disallow writing the buffer'),
type = 'boolean',
varname = 'p_ro',
@@ -6374,7 +6408,7 @@ return {
]=],
full_name = 'relativenumber',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('show relative line number in front of each line'),
type = 'boolean',
},
@@ -6431,13 +6465,12 @@ return {
]=],
full_name = 'rightleft',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('window is right-to-left oriented'),
type = 'boolean',
},
{
abbreviation = 'rlc',
- alloced = true,
cb = 'did_set_rightleftcmd',
defaults = { if_true = 'search' },
desc = [=[
@@ -6452,7 +6485,7 @@ return {
expand_cb = 'expand_set_rightleftcmd',
full_name = 'rightleftcmd',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('commands for which editing works right-to-left'),
type = 'string',
},
@@ -6492,7 +6525,6 @@ return {
},
{
abbreviation = 'ruf',
- alloced = true,
cb = 'did_set_rulerformat',
defaults = { if_true = '' },
desc = [=[
@@ -6635,8 +6667,7 @@ return {
]=],
full_name = 'scroll',
no_mkrc = true,
- pv_name = 'p_scroll',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('lines to scroll with CTRL-U and CTRL-D'),
type = 'number',
},
@@ -6658,7 +6689,7 @@ return {
]=],
full_name = 'scrollback',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('lines to scroll with CTRL-U and CTRL-D'),
type = 'number',
varname = 'p_scbk',
@@ -6679,8 +6710,7 @@ return {
with scroll-binding, but ":split file" does not.
]=],
full_name = 'scrollbind',
- pv_name = 'p_scbind',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('scroll in window as other windows scroll'),
type = 'boolean',
},
@@ -6717,7 +6747,7 @@ return {
< For scrolling horizontally see 'sidescrolloff'.
]=],
full_name = 'scrolloff',
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('minimum nr. of lines above and below cursor'),
type = 'number',
varname = 'p_so',
@@ -7093,7 +7123,7 @@ return {
*shell-powershell*
To use PowerShell: >vim
let &shell = executable('pwsh') ? 'pwsh' : 'powershell'
- let &shellcmdflag = '-NoLogo -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
+ let &shellcmdflag = '-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';$PSStyle.OutputRendering=''plaintext'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;'
let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode'
let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode'
set shellquote= shellxquote=
@@ -7251,9 +7281,14 @@ return {
{
abbreviation = 'ssl',
cb = 'did_set_shellslash',
- defaults = { if_true = false },
+ defaults = {
+ condition = 'MSWIN',
+ if_true = false,
+ if_false = true,
+ doc = 'on, Windows: off',
+ },
desc = [=[
- only for MS-Windows
+ only modifiable in MS-Windows
When set, a forward slash is used when expanding file names. This is
useful when a Unix-like shell is used instead of cmd.exe. Backward
slashes can still be typed, but they are changed to forward slashes by
@@ -7362,7 +7397,7 @@ return {
function to get the effective shiftwidth value.
]=],
full_name = 'shiftwidth',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces to use for (auto)indent step'),
type = 'number',
varname = 'p_sw',
@@ -7460,7 +7495,7 @@ return {
]=],
full_name = 'showbreak',
redraw = { 'all_windows' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('string to use at the start of wrapped lines'),
tags = { 'E595' },
type = 'string',
@@ -7634,14 +7669,13 @@ return {
<
]=],
full_name = 'sidescrolloff',
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('min. nr. of columns to left and right of cursor'),
type = 'number',
varname = 'p_siso',
},
{
abbreviation = 'scl',
- alloced = true,
cb = 'did_set_signcolumn',
defaults = { if_true = 'auto' },
desc = [=[
@@ -7665,7 +7699,7 @@ return {
expand_cb = 'expand_set_signcolumn',
full_name = 'signcolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('when to display the sign column'),
type = 'string',
},
@@ -7711,7 +7745,7 @@ return {
right.
]=],
full_name = 'smartindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('smart autoindenting for C programs'),
type = 'boolean',
varname = 'p_si',
@@ -7751,9 +7785,8 @@ return {
NOTE: partly implemented, doesn't work yet for |gj| and |gk|.
]=],
full_name = 'smoothscroll',
- pv_name = 'p_sms',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("scroll by screen lines when 'wrap' is set"),
type = 'boolean',
},
@@ -7778,7 +7811,7 @@ return {
to anything other than an empty string.
]=],
full_name = 'softtabstop',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces that <Tab> uses while editing'),
type = 'number',
varname = 'p_sts',
@@ -7792,13 +7825,12 @@ return {
]=],
full_name = 'spell',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('spell checking'),
type = 'boolean',
},
{
abbreviation = 'spc',
- alloced = true,
cb = 'did_set_spellcapcheck',
defaults = { if_true = '[.?!]\\_[\\])\'"\\t ]\\+' },
desc = [=[
@@ -7814,14 +7846,13 @@ return {
]=],
full_name = 'spellcapcheck',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pattern to locate end of a sentence'),
type = 'string',
varname = 'p_spc',
},
{
abbreviation = 'spf',
- alloced = true,
cb = 'did_set_spellfile',
defaults = { if_true = '' },
deny_duplicates = true,
@@ -7851,7 +7882,7 @@ return {
expand = true,
full_name = 'spellfile',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('files where |zg| and |zw| store words'),
type = 'string',
@@ -7859,7 +7890,6 @@ return {
},
{
abbreviation = 'spl',
- alloced = true,
cb = 'did_set_spelllang',
defaults = { if_true = 'en' },
deny_duplicates = true,
@@ -7905,7 +7935,7 @@ return {
full_name = 'spelllang',
list = 'onecomma',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('language(s) to do spell checking for'),
type = 'string',
varname = 'p_spl',
@@ -7930,7 +7960,7 @@ return {
full_name = 'spelloptions',
list = 'onecomma',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
type = 'string',
varname = 'p_spo',
@@ -8093,7 +8123,6 @@ return {
},
{
abbreviation = 'stc',
- alloced = true,
cb = 'did_set_statuscolumn',
defaults = { if_true = '' },
desc = [=[
@@ -8152,14 +8181,13 @@ return {
]=],
full_name = 'statuscolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
secure = true,
short_desc = N_('custom format for the status column'),
type = 'string',
},
{
abbreviation = 'stl',
- alloced = true,
cb = 'did_set_statusline',
defaults = { if_true = '' },
desc = [=[
@@ -8356,7 +8384,7 @@ return {
Examples:
Emulate standard status line with 'ruler' set >vim
- set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+ set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P
< Similar, but add ASCII value of char under the cursor (like "ga") >vim
set statusline=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
< Display byte count and byte value, modified flag in red. >vim
@@ -8377,7 +8405,7 @@ return {
full_name = 'statusline',
modelineexpr = true,
redraw = { 'statuslines' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('custom format for the status line'),
tags = { 'E540', 'E542' },
type = 'string',
@@ -8408,7 +8436,6 @@ return {
},
{
abbreviation = 'sua',
- alloced = true,
defaults = { if_true = '' },
deny_duplicates = true,
desc = [=[
@@ -8419,7 +8446,7 @@ return {
]=],
full_name = 'suffixesadd',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('suffixes added when searching for a file'),
type = 'string',
varname = 'p_sua',
@@ -8450,7 +8477,7 @@ return {
]=],
full_name = 'swapfile',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('whether to use a swapfile for a buffer'),
type = 'boolean',
varname = 'p_swf',
@@ -8510,14 +8537,13 @@ return {
]=],
full_name = 'synmaxcol',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('maximum column to find syntax items'),
type = 'number',
varname = 'p_smc',
},
{
abbreviation = 'syn',
- alloced = true,
cb = 'did_set_filetype_or_syntax',
defaults = { if_true = '' },
desc = [=[
@@ -8548,7 +8574,7 @@ return {
full_name = 'syntax',
noglob = true,
normal_fname_chars = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('syntax to be loaded for current buffer'),
type = 'string',
varname = 'p_syn',
@@ -8671,7 +8697,7 @@ return {
]=],
full_name = 'tabstop',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces that <Tab> in file uses'),
type = 'number',
varname = 'p_ts',
@@ -8750,7 +8776,7 @@ return {
]=],
expand_cb = 'expand_set_tagcase',
full_name = 'tagcase',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('how to handle case when searching in tags files'),
type = 'string',
varname = 'p_tc',
@@ -8771,7 +8797,7 @@ return {
]=],
full_name = 'tagfunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function used to perform tag searches'),
type = 'string',
@@ -8828,7 +8854,7 @@ return {
expand = true,
full_name = 'tags',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of file names used by the tag command'),
tags = { 'E433' },
type = 'string',
@@ -8874,11 +8900,11 @@ return {
{
abbreviation = 'tenc',
defaults = { if_true = '' },
- enable_if = false,
full_name = 'termencoding',
scope = { 'global' },
short_desc = N_('Terminal encoding'),
type = 'string',
+ immutable = true,
},
{
abbreviation = 'tgc',
@@ -8968,7 +8994,7 @@ return {
]=],
full_name = 'textwidth',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('maximum width of text that is being inserted'),
type = 'number',
varname = 'p_tw',
@@ -8997,14 +9023,13 @@ return {
full_name = 'thesaurus',
list = 'onecomma',
normal_dname_chars = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of thesaurus files for keyword completion'),
type = 'string',
varname = 'p_tsr',
},
{
abbreviation = 'tsrfu',
- alloced = true,
cb = 'did_set_thesaurusfunc',
defaults = { if_true = '' },
desc = [=[
@@ -9018,7 +9043,7 @@ return {
]=],
full_name = 'thesaurusfunc',
func = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('function used for thesaurus completion'),
type = 'string',
@@ -9129,7 +9154,9 @@ return {
window. This happens only when the 'title' option is on.
When this option contains printf-style '%' items, they will be
- expanded according to the rules used for 'statusline'.
+ expanded according to the rules used for 'statusline'. If it contains
+ an invalid '%' format, the value is used as-is and no error or warning
+ will be given when the value is set.
This option cannot be set in a modeline when 'modelineexpr' is off.
Example: >vim
@@ -9250,7 +9277,7 @@ return {
When 'undofile' is turned off the undo file is NOT deleted.
]=],
full_name = 'undofile',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('save undo information in a file'),
type = 'boolean',
varname = 'p_udf',
@@ -9279,7 +9306,7 @@ return {
Also see |clear-undo|.
]=],
full_name = 'undolevels',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('maximum number of changes that can be undone'),
type = 'number',
varname = 'p_ul',
@@ -9397,7 +9424,8 @@ return {
<
]=],
short_desc=N_("Function used to define behavior of user-defined registers."),
- type='string', scope={'buffer'},
+ type='string',
+ scope={'buf'},
varname='p_urf',
defaults={if_true=""}
},
@@ -9424,7 +9452,7 @@ return {
]=],
full_name = 'varsofttabstop',
list = 'comma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('list of numbers of spaces that <Tab> uses while editing'),
type = 'string',
varname = 'p_vsts',
@@ -9447,7 +9475,7 @@ return {
full_name = 'vartabstop',
list = 'comma',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('list of numbers of spaces that <Tab> in file uses'),
type = 'string',
varname = 'p_vts',
@@ -9593,7 +9621,7 @@ return {
full_name = 'virtualedit',
list = 'onecomma',
redraw = { 'curswant' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('when to use virtual editing'),
type = 'string',
varname = 'p_ve',
@@ -9666,7 +9694,7 @@ return {
abbreviation = 'wc',
cb = 'did_set_wildchar',
defaults = {
- if_true = imacros('TAB'),
+ if_true = macros('TAB', 'number'),
doc = '<Tab>',
},
desc = [=[
@@ -9920,7 +9948,6 @@ return {
},
{
abbreviation = 'wbr',
- alloced = true,
cb = 'did_set_winbar',
defaults = { if_true = '' },
desc = [=[
@@ -9941,7 +9968,7 @@ return {
full_name = 'winbar',
modelineexpr = true,
redraw = { 'statuslines' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('custom format for the window bar'),
type = 'string',
varname = 'p_wbr',
@@ -9959,7 +9986,7 @@ return {
]=],
full_name = 'winblend',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Controls transparency level for floating windows'),
type = 'number',
},
@@ -9998,8 +10025,7 @@ return {
command has a "!" modifier, it can force switching buffers.
]=],
full_name = 'winfixbuf',
- pv_name = 'p_wfb',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('pin a window to a specific buffer'),
type = 'boolean',
},
@@ -10014,7 +10040,7 @@ return {
]=],
full_name = 'winfixheight',
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('keep window height when opening/closing windows'),
type = 'boolean',
},
@@ -10028,7 +10054,7 @@ return {
]=],
full_name = 'winfixwidth',
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('keep window width when opening/closing windows'),
type = 'boolean',
},
@@ -10063,7 +10089,6 @@ return {
},
{
abbreviation = 'winhl',
- alloced = true,
cb = 'did_set_winhighlight',
defaults = { if_true = '' },
deny_duplicates = true,
@@ -10090,7 +10115,7 @@ return {
full_name = 'winhighlight',
list = 'onecommacolon',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Setup window-local highlights'),
type = 'string',
},
@@ -10181,7 +10206,7 @@ return {
]=],
full_name = 'wrap',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('lines wrap and continue on the next line'),
type = 'boolean',
},
@@ -10198,7 +10223,7 @@ return {
See also 'formatoptions' and |ins-textwidth|.
]=],
full_name = 'wrapmargin',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('chars from the right where wrapping starts'),
type = 'number',
varname = 'p_wm',
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index c8f19d7ccf..bfb26a0be6 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -72,8 +72,9 @@ static char *(p_ambw_values[]) = { "single", "double", NULL };
static char *(p_bg_values[]) = { "light", "dark", NULL };
static char *(p_bkc_values[]) = { "yes", "auto", "no", "breaksymlink", "breakhardlink", NULL };
static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete", "copy", "ctrlg", "error",
- "esc", "ex", "hangul", "lang", "mess", "showmatch", "operator",
- "register", "shell", "spell", "wildmode", NULL };
+ "esc", "ex", "hangul", "insertmode", "lang", "mess", "showmatch",
+ "operator", "register", "shell", "spell", "term", "wildmode",
+ NULL };
// Note: Keep this in sync with briopt_check()
static char *(p_briopt_values[]) = { "shift:", "min:", "sbr", "list:", "column:", NULL };
// Note: Keep this in sync with diffopt_changed()
@@ -83,7 +84,7 @@ static char *(p_dip_values[]) = { "filler", "context:", "iblank", "icase",
"indent-heuristic", "linematch:", "algorithm:", NULL };
static char *(p_dip_algorithm_values[]) = { "myers", "minimal", "patience", "histogram", NULL };
static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", "blank", NULL };
-static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
+static char *(p_ff_values[]) = { "unix", "dos", "mac", NULL };
static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
static char *(p_cmp_values[]) = { "internal", "keepascii", NULL };
// Note: Keep this in sync with fill_culopt_flags()
@@ -234,6 +235,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_ep);
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
+ check_string_option(&buf->b_p_ffu);
check_string_option(&buf->b_p_tfu);
check_string_option(&buf->b_p_tc);
check_string_option(&buf->b_p_dict);
@@ -249,7 +251,6 @@ void check_buf_options(buf_T *buf)
/// Free the string allocated for an option.
/// Checks for the string being empty_string_option. This may happen if we're out of memory,
/// xstrdup() returned NULL, which was replaced by empty_string_option by check_options().
-/// Does NOT check for P_ALLOCED flag!
void free_string_option(char *p)
{
if (p != empty_string_option) {
@@ -282,15 +283,27 @@ static bool valid_filetype(const char *val)
/// Handle setting 'signcolumn' for value 'val'. Store minimum and maximum width.
///
+/// @param wcl when NULL: use "wp->w_p_scl"
+/// @param wp when NULL: only parse "scl"
+///
/// @return OK when the value is valid, FAIL otherwise
-int check_signcolumn(win_T *wp)
+int check_signcolumn(char *scl, win_T *wp)
{
- char *val = wp->w_p_scl;
+ char *val = empty_string_option;
+ if (scl != NULL) {
+ val = scl;
+ } else if (wp != NULL) {
+ val = wp->w_p_scl;
+ }
+
if (*val == NUL) {
return FAIL;
}
if (check_opt_strings(val, p_scl_values, false) == OK) {
+ if (wp == NULL) {
+ return OK;
+ }
if (!strncmp(val, "no", 2)) { // no
wp->w_minscwidth = wp->w_maxscwidth = SCL_NO;
} else if (!strncmp(val, "nu", 2) && (wp->w_p_nu || wp->w_p_rnu)) { // number
@@ -320,6 +333,9 @@ int check_signcolumn(win_T *wp)
if (min < 1 || max < 2 || min > 8 || min >= max) {
return FAIL;
}
+ if (wp == NULL) {
+ return OK;
+ }
wp->w_minscwidth = min;
wp->w_maxscwidth = max;
}
@@ -404,9 +420,9 @@ const char *check_stl_option(char *s)
/// often illegal in a file name. Be more permissive if "secure" is off.
bool check_illegal_path_names(char *val, uint32_t flags)
{
- return (((flags & P_NFNAME)
+ return (((flags & kOptFlagNFname)
&& strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
- || ((flags & P_NDNAME)
+ || ((flags & kOptFlagNDname)
&& strpbrk(val, "*?[|;&<>\r\n") != NULL));
}
@@ -639,6 +655,9 @@ const char *did_set_backupcopy(optset_T *args)
if (opt_flags & OPT_LOCAL) {
bkc = buf->b_p_bkc;
flags = &buf->b_bkc_flags;
+ } else if (!(opt_flags & OPT_GLOBAL)) {
+ // When using :set, clear the local flags.
+ buf->b_bkc_flags = 0;
}
if ((opt_flags & OPT_LOCAL) && *bkc == NUL) {
@@ -716,11 +735,14 @@ const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED)
const char *did_set_breakindentopt(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
- if (briopt_check(win) == FAIL) {
+ char **varp = (char **)args->os_varp;
+
+ if (briopt_check(*varp, varp == &win->w_p_briopt ? win : NULL) == FAIL) {
return e_invarg;
}
+
// list setting requires a redraw
- if (win == curwin && win->w_briopt_list) {
+ if (varp == &win->w_p_briopt && win->w_briopt_list) {
redraw_all_later(UPD_NOT_VALID);
}
@@ -870,10 +892,11 @@ int expand_set_chars_option(optexpand_T *args, int *numMatches, char ***matches)
}
/// The 'cinoptions' option is changed.
-const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED)
+const char *did_set_cinoptions(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
// TODO(vim): recognize errors
- parse_cino(curbuf);
+ parse_cino(buf);
return NULL;
}
@@ -897,7 +920,8 @@ int expand_set_clipboard(optexpand_T *args, int *numMatches, char ***matches)
const char *did_set_colorcolumn(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
- return check_colorcolumn(win);
+ char **varp = (char **)args->os_varp;
+ return check_colorcolumn(*varp, varp == &win->w_p_cc ? win : NULL);
}
/// The 'comments' option is changed.
@@ -1050,6 +1074,9 @@ const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED)
if (args->os_flags & OPT_LOCAL) {
cot = buf->b_p_cot;
flags = &buf->b_cot_flags;
+ } else if (!(args->os_flags & OPT_GLOBAL)) {
+ // When using :set, clear the local flags.
+ buf->b_cot_flags = 0;
}
if (check_opt_strings(cot, p_cot_values, true) != OK) {
@@ -1358,7 +1385,7 @@ const char *did_set_filetype_or_syntax(optset_T *args)
args->os_value_changed = strcmp(args->os_oldval.string.data, *varp) != 0;
- // Since we check the value, there is no need to set P_INSECURE,
+ // Since we check the value, there is no need to set kOptFlagInsecure,
// even when the value comes from a modeline.
args->os_value_checked = true;
@@ -1447,8 +1474,7 @@ const char *did_set_foldmethod(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
char **varp = (char **)args->os_varp;
- if (check_opt_strings(*varp, p_fdm_values, false) != OK
- || *win->w_p_fdm == NUL) {
+ if (check_opt_strings(*varp, p_fdm_values, false) != OK || **varp == NUL) {
return e_invarg;
}
foldUpdateAll(win);
@@ -1572,12 +1598,28 @@ int expand_set_inccommand(optexpand_T *args, int *numMatches, char ***matches)
matches);
}
+/// The 'iskeyword' option is changed.
+const char *did_set_iskeyword(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ if (varp == &p_isk) { // only check for global-value
+ if (check_isopt(*varp) == FAIL) {
+ return e_invarg;
+ }
+ } else { // fallthrough for local-value
+ return did_set_isopt(args);
+ }
+
+ return NULL;
+}
+
/// The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is
/// changed.
const char *did_set_isopt(optset_T *args)
{
buf_T *buf = (buf_T *)args->os_buf;
- // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
+ // 'isident', 'iskeyword', 'isprint' or 'isfname' option: refill g_chartab[]
// If the new option is invalid, use old value.
// 'lisp' option: refill g_chartab[] for '-' char
if (buf_init_chartab(buf, true) == FAIL) {
@@ -1624,7 +1666,7 @@ const char *did_set_keymap(optset_T *args)
secure = secure_save;
- // Since we check the value, there is no need to set P_INSECURE,
+ // Since we check the value, there is no need to set kOptFlagInsecure,
// even when the value comes from a modeline.
args->os_value_checked = true;
@@ -2079,8 +2121,9 @@ int expand_set_showcmdloc(optexpand_T *args, int *numMatches, char ***matches)
const char *did_set_signcolumn(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
const char *oldval = args->os_oldval.string.data;
- if (check_signcolumn(win) != OK) {
+ if (check_signcolumn(*varp, varp == &win->w_p_scl ? win : NULL) != OK) {
return e_invarg;
}
// When changing the 'signcolumn' to or from 'number', recompute the
@@ -2115,10 +2158,10 @@ const char *did_set_spellfile(optset_T *args)
// When there is a window for this buffer in which 'spell'
// is set load the wordlists.
- if ((!valid_spellfile(*varp))) {
+ if (!valid_spellfile(*varp)) {
return e_invarg;
}
- return did_set_spell_option(true);
+ return did_set_spell_option();
}
/// The 'spelllang' option is changed.
@@ -2131,15 +2174,22 @@ const char *did_set_spelllang(optset_T *args)
if (!valid_spelllang(*varp)) {
return e_invarg;
}
- return did_set_spell_option(false);
+ return did_set_spell_option();
}
/// The 'spelloptions' option is changed.
const char *did_set_spelloptions(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
- if (opt_strings_flags(win->w_s->b_p_spo, p_spo_values, &(win->w_s->b_p_spo_flags),
- true) != OK) {
+ int opt_flags = args->os_flags;
+ const char *val = args->os_newval.string.data;
+
+ if (!(opt_flags & OPT_LOCAL)
+ && opt_strings_flags(val, p_spo_values, &spo_flags, true) != OK) {
+ return e_invarg;
+ }
+ if (!(opt_flags & OPT_GLOBAL)
+ && opt_strings_flags(val, p_spo_values, &win->w_s->b_p_spo_flags, true) != OK) {
return e_invarg;
}
return NULL;
@@ -2541,7 +2591,8 @@ const char *did_set_winbar(optset_T *args)
const char *did_set_winhighlight(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
- if (!parse_winhl_opt(win)) {
+ char **varp = (char **)args->os_varp;
+ if (!parse_winhl_opt(*varp, varp == &win->w_p_winhl ? win : NULL)) {
return e_invarg;
}
return NULL;
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 7c5293a8b8..2d17581bac 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -289,9 +289,10 @@ size_t input_enqueue(String keys)
unsigned new_size
= trans_special(&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, NULL);
- if (new_size) {
- new_size = handle_mouse_event(&ptr, buf, new_size);
- input_enqueue_raw((char *)buf, new_size);
+ if (new_size > 0) {
+ if ((new_size = handle_mouse_event(&ptr, buf, new_size)) > 0) {
+ input_enqueue_raw((char *)buf, new_size);
+ }
continue;
}
@@ -326,7 +327,7 @@ size_t input_enqueue(String keys)
return rv;
}
-static uint8_t check_multiclick(int code, int grid, int row, int col)
+static uint8_t check_multiclick(int code, int grid, int row, int col, bool *skip_event)
{
static int orig_num_clicks = 0;
static int orig_mouse_code = 0;
@@ -335,24 +336,29 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
static int orig_mouse_row = 0;
static uint64_t orig_mouse_time = 0; // time of previous mouse click
- if ((code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) || code == KE_MOUSEMOVE) {
+ if (code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) {
return 0;
}
- // For click events the number of clicks is updated.
- if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE
- || code == KE_X1MOUSE || code == KE_X2MOUSE) {
+ bool no_move = orig_mouse_grid == grid && orig_mouse_col == col && orig_mouse_row == row;
+
+ if (code == KE_MOUSEMOVE) {
+ if (no_move) {
+ *skip_event = true;
+ return 0;
+ }
+ } else if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE
+ || code == KE_X1MOUSE || code == KE_X2MOUSE) {
+ // For click events the number of clicks is updated.
uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns)
- // compute the time elapsed since the previous mouse click and
- // convert p_mouse from ms to ns
+ // Compute the time elapsed since the previous mouse click.
uint64_t timediff = mouse_time - orig_mouse_time;
+ // Convert 'mousetime' from ms to ns.
uint64_t mouset = (uint64_t)p_mouset * 1000000;
if (code == orig_mouse_code
+ && no_move
&& timediff < mouset
- && orig_num_clicks != 4
- && orig_mouse_grid == grid
- && orig_mouse_col == col
- && orig_mouse_row == row) {
+ && orig_num_clicks != 4) {
orig_num_clicks++;
} else {
orig_num_clicks = 1;
@@ -367,12 +373,14 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
orig_mouse_row = row;
uint8_t modifiers = 0;
- if (orig_num_clicks == 2) {
- modifiers |= MOD_MASK_2CLICK;
- } else if (orig_num_clicks == 3) {
- modifiers |= MOD_MASK_3CLICK;
- } else if (orig_num_clicks == 4) {
- modifiers |= MOD_MASK_4CLICK;
+ if (code != KE_MOUSEMOVE) {
+ if (orig_num_clicks == 2) {
+ modifiers |= MOD_MASK_2CLICK;
+ } else if (orig_num_clicks == 3) {
+ modifiers |= MOD_MASK_3CLICK;
+ } else if (orig_num_clicks == 4) {
+ modifiers |= MOD_MASK_4CLICK;
+ }
}
return modifiers;
}
@@ -399,7 +407,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
return bufsize;
}
- // a <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col
+ // A <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col
// global variables. This is ugly but its how the rest of the code expects to
// find mouse coordinates, and it would be too expensive to refactor this
// now.
@@ -421,8 +429,12 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
*ptr += advance;
}
+ bool skip_event = false;
uint8_t modifiers = check_multiclick(mouse_code, mouse_grid,
- mouse_row, mouse_col);
+ mouse_row, mouse_col, &skip_event);
+ if (skip_event) {
+ return 0;
+ }
if (modifiers) {
if (buf[1] != KS_MODIFIER) {
@@ -443,7 +455,11 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
{
- modifier |= check_multiclick(code, grid, row, col);
+ bool skip_event = false;
+ modifier |= check_multiclick(code, grid, row, col, &skip_event);
+ if (skip_event) {
+ return;
+ }
uint8_t buf[7];
uint8_t *p = buf;
if (modifier) {
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index efcdee9c8b..81b75dc4d3 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -885,9 +885,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
// Failed, probably 'shell' is not executable.
if (!silent) {
msg_puts(_("\nshell failed to start: "));
- msg_outtrans(os_strerror(status), 0);
+ msg_outtrans(os_strerror(status), 0, false);
msg_puts(": ");
- msg_outtrans(prog, 0);
+ msg_outtrans(prog, 0, false);
msg_putchar('\n');
}
multiqueue_free(events);
@@ -1102,7 +1102,7 @@ static void out_data_append_to_screen(const char *output, size_t *count, bool eo
const char *end = output + *count;
while (p < end) {
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
- msg_putchar_attr((uint8_t)(*p), 0);
+ msg_putchar_hl((uint8_t)(*p), 0);
p++;
} else {
// Note: this is not 100% precise:
@@ -1118,7 +1118,7 @@ static void out_data_append_to_screen(const char *output, size_t *count, bool eo
goto end;
}
- msg_outtrans_len(p, i, 0);
+ msg_outtrans_len(p, i, 0, false);
p += i;
}
}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 9cce504831..80890acb7d 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1538,6 +1538,13 @@ void simplify_filename(char *filename)
} while (vim_ispathsep(*p));
}
char *start = p; // remember start after "c:/" or "/" or "///"
+#ifdef UNIX
+ // Posix says that "//path" is unchanged but "///path" is "/path".
+ if (start > filename + 2) {
+ STRMOVE(filename + 1, p);
+ start = p = filename + 1;
+ }
+#endif
do {
// At this point "p" is pointing to the char following a single "/"
@@ -1827,7 +1834,7 @@ char *fix_fname(const char *fname)
fname = xstrdup(fname);
-# ifdef USE_FNAME_CASE
+# ifdef CASE_INSENSITIVE_FILENAME
path_fix_case((char *)fname); // set correct case for file name
# endif
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index ddcb819054..7df6a1a5d7 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -480,13 +480,19 @@ static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr)
for (int i = 0; i < ga->ga_len; i++) {
if (char_pos == ((uint32_t *)ga->ga_data)[i]) {
new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
+ new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr);
+ new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr);
break;
}
}
} else if (matched_start && ptr < text + leader_len) {
new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
+ new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr);
+ new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr);
}
+ new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), new_attr);
+
if (user_hlattr > 0) {
new_attr = hl_combine_attr(new_attr, user_hlattr);
}
@@ -629,6 +635,7 @@ void pum_redraw(void)
const hlf_T *const hlfs = (idx == pum_selected) ? hlfsSel : hlfsNorm;
hlf_T hlf = hlfs[0]; // start with "word" highlight
int attr = win_hl_attr(curwin, (int)hlf);
+ attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr);
grid_line_start(&pum_grid, row);
@@ -650,15 +657,21 @@ void pum_redraw(void)
pum_align_order(order);
int basic_width = items_width_array[order[0]]; // first item width
bool last_isabbr = order[2] == CPT_ABBR;
+ int orig_attr = -1;
+
for (int j = 0; j < 3; j++) {
int item_type = order[j];
hlf = hlfs[item_type];
attr = win_hl_attr(curwin, (int)hlf);
- if (pum_array[idx].pum_user_hlattr > 0) {
- attr = hl_combine_attr(attr, pum_array[idx].pum_user_hlattr);
+ attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr);
+ orig_attr = attr;
+ int user_abbr_hlattr = pum_array[idx].pum_user_abbr_hlattr;
+ int user_kind_hlattr = pum_array[idx].pum_user_kind_hlattr;
+ if (item_type == CPT_ABBR && user_abbr_hlattr > 0) {
+ attr = hl_combine_attr(attr, user_abbr_hlattr);
}
- if (item_type == CPT_KIND && pum_array[idx].pum_user_kind_hlattr > 0) {
- attr = hl_combine_attr(attr, pum_array[idx].pum_user_kind_hlattr);
+ if (item_type == CPT_KIND && user_kind_hlattr > 0) {
+ attr = hl_combine_attr(attr, user_kind_hlattr);
}
int width = 0;
char *s = NULL;
@@ -684,8 +697,10 @@ void pum_redraw(void)
*p = saved;
}
- int user_hlattr = pum_array[idx].pum_user_hlattr;
- int *attrs = pum_compute_text_attrs(st, hlf, user_hlattr);
+ int *attrs = NULL;
+ if (item_type == CPT_ABBR) {
+ attrs = pum_compute_text_attrs(st, hlf, user_abbr_hlattr);
+ }
if (pum_rl) {
char *rt = reverse_text(st);
@@ -727,7 +742,9 @@ void pum_redraw(void)
grid_col += width;
}
- xfree(attrs);
+ if (attrs != NULL) {
+ XFREE_CLEAR(attrs);
+ }
if (*p != TAB) {
break;
@@ -769,19 +786,21 @@ void pum_redraw(void)
}
if (pum_rl) {
- grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr);
+ grid_line_fill(col_off - basic_width - n + 1, grid_col + 1,
+ schar_from_ascii(' '), orig_attr);
grid_col = col_off - basic_width - n;
} else {
- grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), attr);
+ grid_line_fill(grid_col, col_off + basic_width + n,
+ schar_from_ascii(' '), orig_attr);
grid_col = col_off + basic_width + n;
}
totwidth = basic_width + n;
}
if (pum_rl) {
- grid_line_fill(col_off - pum_width + 1, grid_col + 1, schar_from_ascii(' '), attr);
+ grid_line_fill(col_off - pum_width + 1, grid_col + 1, schar_from_ascii(' '), orig_attr);
} else {
- grid_line_fill(grid_col, col_off + pum_width, schar_from_ascii(' '), attr);
+ grid_line_fill(grid_col, col_off + pum_width, schar_from_ascii(' '), orig_attr);
}
if (pum_scrollbar > 0) {
@@ -1341,14 +1360,15 @@ static void pum_select_mouse_pos(void)
if (mouse_grid == pum_grid.handle) {
pum_selected = mouse_row;
return;
- } else if (mouse_grid != pum_anchor_grid) {
+ } else if (mouse_grid != pum_anchor_grid || mouse_col < pum_grid.comp_col
+ || mouse_col >= pum_grid.comp_col + pum_grid.comp_width) {
pum_selected = -1;
return;
}
- int idx = mouse_row - pum_row;
+ int idx = mouse_row - pum_grid.comp_row;
- if (idx < 0 || idx >= pum_height) {
+ if (idx < 0 || idx >= pum_grid.comp_height) {
pum_selected = -1;
} else if (*pum_array[idx].pum_text != NUL) {
pum_selected = idx;
diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h
index f7eb0240ae..40bd42ee17 100644
--- a/src/nvim/popupmenu.h
+++ b/src/nvim/popupmenu.h
@@ -16,7 +16,7 @@ typedef struct {
char *pum_info; ///< extra info
int pum_score; ///< fuzzy match score
int pum_idx; ///< index of item before sorting by score
- int pum_user_hlattr; ///< highlight attribute to combine with
+ int pum_user_abbr_hlattr; ///< highlight attribute for abbr
int pum_user_kind_hlattr; ///< highlight attribute for kind
} pumitem_T;
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index 81207b4e39..1b4f4a2029 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -956,7 +956,7 @@ void time_init(const char *fname, const char *proc_name)
const size_t bufsize = 8192; // Big enough for the entire --startuptime report.
time_fd = fopen(fname, "a");
if (time_fd == NULL) {
- semsg(_(e_notopen), fname);
+ fprintf(stderr, _(e_notopen), fname);
return;
}
startuptime_buf = xmalloc(sizeof(char) * (bufsize + 1));
@@ -968,8 +968,7 @@ void time_init(const char *fname, const char *proc_name)
XFREE_CLEAR(startuptime_buf);
fclose(time_fd);
time_fd = NULL;
- ELOG("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
- semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r));
+ fprintf(stderr, "time_init: setvbuf failed: %d %s", r, uv_err_name(r));
return;
}
fprintf(time_fd, "--- Startup times for process: %s ---\n", proc_name);
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index ddf2a7247f..6526b0d0bf 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2937,7 +2937,7 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
msg_scroll = false;
}
msg_ext_set_kind("quickfix");
- msg_attr_keep(gap->ga_data, 0, true, false);
+ msg_hl_keep(gap->ga_data, 0, true, false);
msg_scroll = (int)i;
qfga_clear();
@@ -3144,10 +3144,10 @@ theend:
decr_quickfix_busy();
}
-// Highlight attributes used for displaying entries from the quickfix list.
-static int qfFileAttr;
-static int qfSepAttr;
-static int qfLineAttr;
+// Highlight ids used for displaying entries from the quickfix list.
+static int qfFile_hl_id;
+static int qfSep_hl_id;
+static int qfLine_hl_id;
/// Display information about a single entry from the quickfix/location list.
/// Used by ":clist/:llist" commands.
@@ -3195,10 +3195,10 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
}
msg_putchar('\n');
- msg_outtrans(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
+ msg_outtrans(IObuff, cursel ? HLF_QFL : qfFile_hl_id, false);
if (qfp->qf_lnum != 0) {
- msg_puts_attr(":", qfSepAttr);
+ msg_puts_hl(":", qfSep_hl_id, false);
}
garray_T *gap = qfga_get();
if (qfp->qf_lnum != 0) {
@@ -3206,14 +3206,14 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
}
ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
ga_append(gap, NUL);
- msg_puts_attr(gap->ga_data, qfLineAttr);
- msg_puts_attr(":", qfSepAttr);
+ msg_puts_hl(gap->ga_data, qfLine_hl_id, false);
+ msg_puts_hl(":", qfSep_hl_id, false);
if (qfp->qf_pattern != NULL) {
gap = qfga_get();
qf_fmt_text(gap, qfp->qf_pattern);
ga_append(gap, NUL);
msg_puts(gap->ga_data);
- msg_puts_attr(":", qfSepAttr);
+ msg_puts_hl(":", qfSep_hl_id, false);
}
msg_puts(" ");
@@ -3275,17 +3275,17 @@ void qf_list(exarg_T *eap)
// Get the attributes for the different quickfix highlight items. Note
// that this depends on syntax items defined in the qf.vim syntax file
- qfFileAttr = syn_name2attr("qfFileName");
- if (qfFileAttr == 0) {
- qfFileAttr = HL_ATTR(HLF_D);
+ qfFile_hl_id = syn_name2id("qfFileName");
+ if (qfFile_hl_id == 0) {
+ qfFile_hl_id = HLF_D;
}
- qfSepAttr = syn_name2attr("qfSeparator");
- if (qfSepAttr == 0) {
- qfSepAttr = HL_ATTR(HLF_D);
+ qfSep_hl_id = syn_name2id("qfSeparator");
+ if (qfSep_hl_id == 0) {
+ qfSep_hl_id = HLF_D;
}
- qfLineAttr = syn_name2attr("qfLineNr");
- if (qfLineAttr == 0) {
- qfLineAttr = HL_ATTR(HLF_N);
+ qfLine_hl_id = syn_name2id("qfLineNr");
+ if (qfLine_hl_id == 0) {
+ qfLine_hl_id = HLF_N;
}
if (qfl->qf_nonevalid) {
@@ -4396,7 +4396,7 @@ static char *make_get_fullcmd(const char *makecmd, const char *fname)
}
msg_start();
msg_puts(":!");
- msg_outtrans(cmd, 0); // show what we are doing
+ msg_outtrans(cmd, 0, false); // show what we are doing
return cmd;
}
@@ -5243,9 +5243,9 @@ static void vgr_display_fname(char *fname)
msg_start();
char *p = msg_strtrunc(fname, true);
if (p == NULL) {
- msg_outtrans(fname, 0);
+ msg_outtrans(fname, 0, false);
} else {
- msg_outtrans(p, 0);
+ msg_outtrans(p, 0, false);
xfree(p);
}
msg_clr_eos();
@@ -6462,6 +6462,64 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, dict_T *d, bool first_entry, b
return status;
}
+/// Check if `entry` is closer to the target than `other_entry`.
+///
+/// Only returns true if `entry` is definitively closer. If it's further
+/// away, or there's not enough information to tell, return false.
+static bool entry_is_closer_to_target(qfline_T *entry, qfline_T *other_entry, int target_fnum,
+ int target_lnum, int target_col)
+{
+ // First, compare entries to target file.
+ if (!target_fnum) {
+ // Without a target file, we can't know which is closer.
+ return false;
+ }
+
+ bool is_target_file = entry->qf_fnum && entry->qf_fnum == target_fnum;
+ bool other_is_target_file = other_entry->qf_fnum && other_entry->qf_fnum == target_fnum;
+ if (!is_target_file && other_is_target_file) {
+ return false;
+ } else if (is_target_file && !other_is_target_file) {
+ return true;
+ }
+
+ // Both entries are pointing at the exact same file. Now compare line numbers.
+ if (!target_lnum) {
+ // Without a target line number, we can't know which is closer.
+ return false;
+ }
+
+ int line_distance = entry->qf_lnum
+ ? abs(entry->qf_lnum - target_lnum) : INT_MAX;
+ int other_line_distance = other_entry->qf_lnum
+ ? abs(other_entry->qf_lnum - target_lnum) : INT_MAX;
+ if (line_distance > other_line_distance) {
+ return false;
+ } else if (line_distance < other_line_distance) {
+ return true;
+ }
+
+ // Both entries are pointing at the exact same line number (or no line
+ // number at all). Now compare columns.
+ if (!target_col) {
+ // Without a target column, we can't know which is closer.
+ return false;
+ }
+
+ int column_distance = entry->qf_col
+ ? abs(entry->qf_col - target_col) : INT_MAX;
+ int other_column_distance = other_entry->qf_col
+ ? abs(other_entry->qf_col - target_col) : INT_MAX;
+ if (column_distance > other_column_distance) {
+ return false;
+ } else if (column_distance < other_column_distance) {
+ return true;
+ }
+
+ // It's a complete tie! The exact same file, line, and column.
+ return false;
+}
+
/// Add list of entries to quickfix/location list. Each list entry is
/// a dictionary with item information.
static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, int action)
@@ -6471,19 +6529,48 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title,
int retval = OK;
bool valid_entry = false;
+ // If there's an entry selected in the quickfix list, remember its location
+ // (file, line, column), so we can select the nearest entry in the updated
+ // quickfix list.
+ int prev_fnum = 0;
+ int prev_lnum = 0;
+ int prev_col = 0;
+ if (qfl->qf_ptr) {
+ prev_fnum = qfl->qf_ptr->qf_fnum;
+ prev_lnum = qfl->qf_ptr->qf_lnum;
+ prev_col = qfl->qf_ptr->qf_col;
+ }
+
+ bool select_first_entry = false;
+ bool select_nearest_entry = false;
+
if (action == ' ' || qf_idx == qi->qf_listcount) {
+ select_first_entry = true;
// make place for a new list
qf_new_list(qi, title);
qf_idx = qi->qf_curlist;
qfl = qf_get_list(qi, qf_idx);
- } else if (action == 'a' && !qf_list_empty(qfl)) {
- // Adding to existing list, use last entry.
- old_last = qfl->qf_last;
+ } else if (action == 'a') {
+ if (qf_list_empty(qfl)) {
+ // Appending to empty list, select first entry.
+ select_first_entry = true;
+ } else {
+ // Adding to existing list, use last entry.
+ old_last = qfl->qf_last;
+ }
} else if (action == 'r') {
+ select_first_entry = true;
+ qf_free_items(qfl);
+ qf_store_title(qfl, title);
+ } else if (action == 'u') {
+ select_nearest_entry = true;
qf_free_items(qfl);
qf_store_title(qfl, title);
}
+ qfline_T *entry_to_select = NULL;
+ int entry_to_select_index = 0;
+
TV_LIST_ITER_CONST(list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) {
continue; // Skip non-dict items.
@@ -6498,6 +6585,16 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title,
if (retval == QF_FAIL) {
break;
}
+
+ qfline_T *entry = qfl->qf_last;
+ if ((select_first_entry && entry_to_select == NULL)
+ || (select_nearest_entry
+ && (entry_to_select == NULL
+ || entry_is_closer_to_target(entry, entry_to_select, prev_fnum,
+ prev_lnum, prev_col)))) {
+ entry_to_select = entry;
+ entry_to_select_index = qfl->qf_count;
+ }
});
// Check if any valid error entries are added to the list.
@@ -6507,16 +6604,10 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title,
qfl->qf_nonevalid = true;
}
- // If not appending to the list, set the current error to the first entry
- if (action != 'a') {
- qfl->qf_ptr = qfl->qf_start;
- }
-
- // Update the current error index if not appending to the list or if the
- // list was empty before and it is not empty now.
- if ((action != 'a' || qfl->qf_index == 0)
- && !qf_list_empty(qfl)) {
- qfl->qf_index = 1;
+ // Set the current error.
+ if (entry_to_select) {
+ qfl->qf_ptr = entry_to_select;
+ qfl->qf_index = entry_to_select_index;
}
// Don't update the cursor in quickfix window when appending entries
@@ -6632,7 +6723,7 @@ static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T *
return FAIL;
}
- if (action == 'r') {
+ if (action == 'r' || action == 'u') {
qf_free_items(&qi->qf_lists[qf_idx]);
}
if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
@@ -6789,10 +6880,11 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
}
}
-// Populate the quickfix list with the items supplied in the list
-// of dictionaries. "title" will be copied to w:quickfix_title
-// "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
-// When "what" is not NULL then only set some properties.
+/// Populate the quickfix list with the items supplied in the list
+/// of dictionaries. "title" will be copied to w:quickfix_title
+/// "action" is 'a' for add, 'r' for replace, 'u' for update. Otherwise
+/// create a new list.
+/// When "what" is not NULL then only set some properties.
int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what)
{
qf_info_T *qi = &ql_info;
@@ -7256,7 +7348,6 @@ void ex_helpgrep(exarg_T *eap)
bool updated = false;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *const save_cpo = p_cpo;
- const bool save_cpo_allocated = (get_option(kOptCpoptions)->flags & P_ALLOCED);
p_cpo = empty_string_option;
bool new_qi = false;
@@ -7296,9 +7387,7 @@ void ex_helpgrep(exarg_T *eap)
if (*p_cpo == NUL) {
set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0);
}
- if (save_cpo_allocated) {
- free_string_option(save_cpo);
- }
+ free_string_option(save_cpo);
}
if (updated) {
@@ -7433,7 +7522,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
return;
}
const char *const act = tv_get_string_chk(action_arg);
- if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f')
+ if ((*act == 'a' || *act == 'r' || *act == 'u' || *act == ' ' || *act == 'f')
&& act[1] == NUL) {
action = *act;
} else {
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 030bda4fa5..3f00b74e61 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -2348,7 +2348,7 @@ void ex_scriptnames(exarg_T *eap)
vim_snprintf(IObuff, IOSIZE, "%3d: %s", i, NameBuff);
if (!message_filtered(IObuff)) {
msg_putchar('\n');
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
line_breakcheck();
}
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index ff6e135df1..debc5697d1 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -113,7 +113,7 @@ static int last_idx = 0; // index in spats[] for RE_LAST
static uint8_t lastc[2] = { NUL, NUL }; // last character searched for
static Direction lastcdir = FORWARD; // last direction of character search
static bool last_t_cmd = true; // last search t_cmd
-static char lastc_bytes[MB_MAXBYTES + 1];
+static char lastc_bytes[MAX_SCHAR_SIZE + 1];
static int lastc_bytelen = 1; // >1 for multi-byte char
// copy of spats[], for keeping the search patterns while executing autocmds
@@ -380,6 +380,11 @@ char *last_search_pattern(void)
return spats[RE_SEARCH].pat;
}
+size_t last_search_pattern_len(void)
+{
+ return spats[RE_SEARCH].patlen;
+}
+
/// Return true when case should be ignored for search pattern "pat".
/// Uses the 'ignorecase' and 'smartcase' options.
int ignorecase(char *pat)
@@ -1299,7 +1304,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen
memset(msgbuf + pat_len, ' ', (size_t)(r - msgbuf));
}
}
- msg_outtrans(msgbuf, 0);
+ msg_outtrans(msgbuf, 0, false);
msg_clr_eos();
msg_check();
@@ -1545,14 +1550,11 @@ int searchc(cmdarg_T *cap, bool t_cmd)
*lastc = (uint8_t)c;
set_csearch_direction(dir);
set_csearch_until(t_cmd);
- lastc_bytelen = utf_char2bytes(c, lastc_bytes);
- if (cap->ncharC1 != 0) {
- lastc_bytelen += utf_char2bytes(cap->ncharC1,
- lastc_bytes + lastc_bytelen);
- if (cap->ncharC2 != 0) {
- lastc_bytelen += utf_char2bytes(cap->ncharC2,
- lastc_bytes + lastc_bytelen);
- }
+ if (cap->nchar_len) {
+ lastc_bytelen = cap->nchar_len;
+ memcpy(lastc_bytes, cap->nchar_composing, (size_t)cap->nchar_len);
+ } else {
+ lastc_bytelen = utf_char2bytes(c, lastc_bytes);
}
}
} else { // repeat previous search
@@ -3729,7 +3731,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
&& action == ACTION_SHOW_ALL && files[i].matched) {
msg_putchar('\n'); // cursor below last one
if (!got_int) { // don't display if 'q' typed at "--more--" message
- msg_home_replace_hl(new_fname);
+ msg_home_replace(new_fname);
msg_puts(_(" (includes previously listed match)"));
prev_fname = NULL;
}
@@ -3770,7 +3772,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
if (new_fname != NULL) {
// using "new_fname" is more reliable, e.g., when
// 'includeexpr' is set.
- msg_outtrans(new_fname, HL_ATTR(HLF_D));
+ msg_outtrans(new_fname, HLF_D, false);
} else {
// Isolate the file name.
// Include the surrounding "" or <> if present.
@@ -3804,7 +3806,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
}
char save_char = p[i];
p[i] = NUL;
- msg_outtrans(p, HL_ATTR(HLF_D));
+ msg_outtrans(p, HLF_D, false);
p[i] = save_char;
}
@@ -3856,7 +3858,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
vim_snprintf(IObuff, IOSIZE,
_("Scanning included file: %s"),
new_fname);
- msg_trunc(IObuff, true, HL_ATTR(HLF_R));
+ msg_trunc(IObuff, true, HLF_R);
} else if (p_verbose >= 5) {
verbose_enter();
smsg(0, _("Searching included file %s"), new_fname);
@@ -4030,7 +4032,7 @@ search_line:
}
if (!got_int) { // don't display if 'q' typed
// at "--more--" message
- msg_home_replace_hl(curr_fname);
+ msg_home_replace(curr_fname);
}
prev_fname = curr_fname;
}
@@ -4231,7 +4233,7 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI
msg_puts(IObuff);
snprintf(IObuff, IOSIZE, "%4" PRIdLINENR, *lnum); // Show line nr.
// Highlight line numbers.
- msg_puts_attr(IObuff, HL_ATTR(HLF_N));
+ msg_puts_hl(IObuff, HLF_N, false);
msg_puts(" ");
}
msg_prt_line(line, false);
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 2b401fa106..2961b35a29 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -246,7 +246,7 @@ typedef struct {
struct reg { // yankreg_T
char name;
MotionType type;
- char **contents;
+ String *contents;
bool is_unnamed;
size_t contents_size;
size_t width;
@@ -658,7 +658,7 @@ static const void *shada_hist_iter(const void *const iter, const uint8_t history
.histtype = history_type,
.string = hist_he.hisstr,
.sep = (char)(history_type == HIST_SEARCH
- ? hist_he.hisstr[strlen(hist_he.hisstr) + 1]
+ ? hist_he.hisstr[hist_he.hisstrlen + 1]
: 0),
}
},
@@ -784,6 +784,7 @@ static inline void hms_to_he_array(const HistoryMergerState *const hms_p,
hist->timestamp = cur_entry->data.timestamp;
hist->hisnum = (int)(hist - hist_array) + 1;
hist->hisstr = cur_entry->data.data.history_item.string;
+ hist->hisstrlen = strlen(cur_entry->data.data.history_item.string);
hist->additional_data = cur_entry->data.additional_data;
hist++;
})
@@ -1490,7 +1491,7 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
PACK_KEY(REG_KEY_CONTENTS);
mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size);
for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
- mpack_bin(cstr_as_string(entry.data.reg.contents[i]), &sbuf);
+ mpack_bin(entry.data.reg.contents[i], &sbuf);
}
PACK_KEY(KEY_NAME_CHAR);
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name);
@@ -2929,7 +2930,7 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
break;
case kSDItemRegister:
for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
- xfree(entry->data.reg.contents[i]);
+ api_free_string(entry->data.reg.contents[i]);
}
xfree(entry->data.reg.contents);
break;
@@ -3311,9 +3312,9 @@ shada_read_next_item_start:
goto shada_read_next_item_error;
}
entry->data.reg.contents_size = it.rc.size;
- entry->data.reg.contents = xmalloc(it.rc.size * sizeof(char *));
+ entry->data.reg.contents = xmalloc(it.rc.size * sizeof(String));
for (size_t j = 0; j < it.rc.size; j++) {
- entry->data.reg.contents[j] = xmemdupz(it.rc.items[j].data, it.rc.items[j].size);
+ entry->data.reg.contents[j] = copy_string(it.rc.items[j], NULL);
}
kv_destroy(it.rc);
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index b4ba7833e9..f8e7eeaca4 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -270,7 +270,7 @@ static void sign_list_placed(buf_T *rbuf, char *group)
while (buf != NULL && !got_int) {
if (buf_has_signs(buf)) {
vim_snprintf(lbuf, MSG_BUF_LEN, _("Signs for %s:"), buf->b_fname);
- msg_puts_attr(lbuf, HL_ATTR(HLF_D));
+ msg_puts_hl(lbuf, HLF_D, false);
msg_putchar('\n');
}
@@ -481,14 +481,14 @@ static void sign_list_defined(sign_T *sp)
smsg(0, "sign %s", sp->sn_name);
if (sp->sn_icon != NULL) {
msg_puts(" icon=");
- msg_outtrans(sp->sn_icon, 0);
+ msg_outtrans(sp->sn_icon, 0, false);
msg_puts(_(" (not supported)"));
}
if (sp->sn_text[0]) {
msg_puts(" text=");
char buf[SIGN_WIDTH * MAX_SCHAR_SIZE];
describe_sign_text(buf, sp->sn_text);
- msg_outtrans(buf, 0);
+ msg_outtrans(buf, 0, false);
}
if (sp->sn_priority > 0) {
char lbuf[MSG_BUF_LEN];
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 8ec28c7f61..a0fdd46b04 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2091,7 +2091,7 @@ char *parse_spelllang(win_T *wp)
int_wordlist_spl(spf_name);
} else {
// One entry in 'spellfile'.
- copy_option_part(&spf, spf_name, MAXPATHL - 5, ",");
+ copy_option_part(&spf, spf_name, MAXPATHL - 4, ",");
strcat(spf_name, ".spl");
int c;
@@ -3664,30 +3664,26 @@ bool valid_spelllang(const char *val)
bool valid_spellfile(const char *val)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- for (const char *s = val; *s != NUL; s++) {
- if (!vim_is_fname_char((uint8_t)(*s))) {
+ char spf_name[MAXPATHL];
+ char *spf = (char *)val;
+ while (*spf != NUL) {
+ size_t l = copy_option_part(&spf, spf_name, MAXPATHL, ",");
+ if (l >= MAXPATHL - 4 || l < 4 || strcmp(spf_name + l - 4, ".add") != 0) {
return false;
}
+ for (char *s = spf_name; *s != NUL; s++) {
+ if (!vim_is_fname_char((uint8_t)(*s))) {
+ return false;
+ }
+ }
}
return true;
}
-const char *did_set_spell_option(bool is_spellfile)
+const char *did_set_spell_option(void)
{
const char *errmsg = NULL;
- if (is_spellfile) {
- int l = (int)strlen(curwin->w_s->b_p_spf);
- if (l > 0
- && (l < 4 || strcmp(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
- errmsg = e_invarg;
- }
- }
-
- if (errmsg != NULL) {
- return errmsg;
- }
-
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer == curbuf && wp->w_p_spell) {
errmsg = parse_spelllang(wp);
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index 07bb7dd69a..4e78067d46 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -430,7 +430,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
if (hltab[n].userhl == 0) {
curattr = attr;
} else if (hltab[n].userhl < 0) {
- curattr = syn_id2attr(-hltab[n].userhl);
+ curattr = hl_combine_attr(attr, syn_id2attr(-hltab[n].userhl));
} else if (wp != NULL && wp != curwin && wp->w_status_height != 0) {
curattr = highlight_stlnc[hltab[n].userhl - 1];
} else {
@@ -582,9 +582,11 @@ void win_redr_ruler(win_T *wp)
if (ui_has(kUIMessages) && !part_of_status) {
MAXSIZE_TEMP_ARRAY(content, 1);
- MAXSIZE_TEMP_ARRAY(chunk, 2);
+ MAXSIZE_TEMP_ARRAY(chunk, 3);
ADD_C(chunk, INTEGER_OBJ(attr));
ADD_C(chunk, CSTR_AS_OBJ(buffer));
+ ADD_C(chunk, INTEGER_OBJ(HLF_MSG));
+ assert(attr == HL_ATTR(HLF_MSG));
ADD_C(content, ARRAY_OBJ(chunk));
ui_call_msg_ruler(content);
did_show_ext_ruler = true;
@@ -758,7 +760,9 @@ void draw_tabline(void)
bool modified = false;
for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) {
- if (bufIsChanged(wp->w_buffer)) {
+ if (!wp->w_config.focusable) {
+ wincount--;
+ } else if (bufIsChanged(wp->w_buffer)) {
modified = true;
}
}
@@ -1630,7 +1634,7 @@ stcsign:
schar_T fold_buf[9];
fill_foldcolumn(wp, stcp->foldinfo, (linenr_T)get_vim_var_nr(VV_LNUM),
0, fdc, NULL, fold_buf);
- stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLF : HLF_FC) + 1);
+ stl_items[curitem].minwid = -(stcp->use_cul ? HLF_CLF : HLF_FC);
size_t buflen = 0;
// TODO(bfredl): this is very backwards. we must support schar_T
// being used directly in 'statuscolumn'
@@ -1651,7 +1655,7 @@ stcsign:
buf_tmp[signlen++] = ' ';
buf_tmp[signlen++] = ' ';
buf_tmp[signlen] = NUL;
- stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLS : HLF_SC) + 1);
+ stl_items[curitem].minwid = -(stcp->use_cul ? HLF_CLS : HLF_SC);
}
}
stl_items[curitem++].type = Highlight;
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 118abbae6d..2de65391cc 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -2838,10 +2838,10 @@ void f_strpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) {
- int off;
+ int64_t off;
// length in characters
- for (off = (int)n; off < (int)slen && len > 0; len--) {
+ for (off = n; off < (int64_t)slen && len > 0; len--) {
off += utfc_ptr2len(p + off);
}
len = off - n;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 9eeed3fbd2..03f20047a5 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -2928,9 +2928,9 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
msg_puts("\n");
if (curwin->w_s->b_syn_isk != empty_string_option) {
msg_puts("syntax iskeyword ");
- msg_outtrans(curwin->w_s->b_syn_isk, 0);
+ msg_outtrans(curwin->w_s->b_syn_isk, 0, false);
} else {
- msg_outtrans(_("syntax iskeyword not set"), 0);
+ msg_outtrans(_("syntax iskeyword not set"), 0, false);
}
} else {
if (STRNICMP(arg, "clear", 5) == 0) {
@@ -3346,13 +3346,12 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only)
KEYVALUE_ENTRY(HL_SKIPEMPTY, "skipempty"),
};
- const int attr = HL_ATTR(HLF_D); // highlight like directories
+ const int hl_id = HLF_D; // highlight like directories
// list the keywords for "id"
if (!syncing) {
- did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, false, attr);
- did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic,
- did_header, attr);
+ did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, false, hl_id);
+ did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic, did_header, hl_id);
}
// list the patterns for "id"
@@ -3368,46 +3367,46 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only)
did_header = true;
last_matchgroup = 0;
if (spp->sp_type == SPTYPE_MATCH) {
- put_pattern("match", ' ', spp, attr);
+ put_pattern("match", ' ', spp, hl_id);
msg_putchar(' ');
} else if (spp->sp_type == SPTYPE_START) {
while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START) {
- put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id);
}
if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP) {
- put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id);
}
while (idx < curwin->w_s->b_syn_patterns.ga_len
&& SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END) {
- put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id);
}
idx--;
msg_putchar(' ');
}
- syn_list_flags(namelist1, ARRAY_SIZE(namelist1), spp->sp_flags, attr);
+ syn_list_flags(namelist1, ARRAY_SIZE(namelist1), spp->sp_flags, hl_id);
if (spp->sp_cont_list != NULL) {
- put_id_list("contains", spp->sp_cont_list, attr);
+ put_id_list("contains", spp->sp_cont_list, hl_id);
}
if (spp->sp_syn.cont_in_list != NULL) {
- put_id_list("containedin", spp->sp_syn.cont_in_list, attr);
+ put_id_list("containedin", spp->sp_syn.cont_in_list, hl_id);
}
if (spp->sp_next_list != NULL) {
- put_id_list("nextgroup", spp->sp_next_list, attr);
- syn_list_flags(namelist2, ARRAY_SIZE(namelist2), spp->sp_flags, attr);
+ put_id_list("nextgroup", spp->sp_next_list, hl_id);
+ syn_list_flags(namelist2, ARRAY_SIZE(namelist2), spp->sp_flags, hl_id);
}
if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE)) {
if (spp->sp_flags & HL_SYNC_HERE) {
- msg_puts_attr("grouphere", attr);
+ msg_puts_hl("grouphere", hl_id, false);
} else {
- msg_puts_attr("groupthere", attr);
+ msg_puts_hl("groupthere", hl_id, false);
}
msg_putchar(' ');
if (spp->sp_sync_idx >= 0) {
msg_outtrans(highlight_group_name(SYN_ITEMS(curwin->w_s)
- [spp->sp_sync_idx].sp_syn.id - 1), 0);
+ [spp->sp_sync_idx].sp_syn.id - 1), 0, false);
} else {
msg_puts("NONE");
}
@@ -3418,17 +3417,17 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only)
// list the link, if there is one
if (highlight_link_id(id - 1) && (did_header || link_only) && !got_int) {
syn_list_header(did_header, 0, id, true);
- msg_puts_attr("links to", attr);
+ msg_puts_hl("links to", hl_id, false);
msg_putchar(' ');
- msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1), 0);
+ msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1), 0, false);
}
}
-static void syn_list_flags(keyvalue_T *nlist, size_t nr_entries, int flags, int attr)
+static void syn_list_flags(keyvalue_T *nlist, size_t nr_entries, int flags, int hl_id)
{
for (size_t i = 0; i < nr_entries; i++) {
if (flags & nlist[i].key) {
- msg_puts_attr(nlist[i].value, attr);
+ msg_puts_hl(nlist[i].value, hl_id, false);
msg_putchar(' ');
}
}
@@ -3441,7 +3440,7 @@ static void syn_list_cluster(int id)
// slight hack: roughly duplicate the guts of syn_list_header()
msg_putchar('\n');
- msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name, 0);
+ msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name, 0, false);
if (msg_col >= endcol) { // output at least one space
endcol = msg_col + 1;
@@ -3452,16 +3451,16 @@ static void syn_list_cluster(int id)
msg_advance(endcol);
if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL) {
- put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HL_ATTR(HLF_D));
+ put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HLF_D);
} else {
- msg_puts_attr("cluster", HL_ATTR(HLF_D));
+ msg_puts_hl("cluster", HLF_D, false);
msg_puts("=NONE");
}
}
-static void put_id_list(const char *const name, const int16_t *const list, const int attr)
+static void put_id_list(const char *const name, const int16_t *const list, const int hl_id)
{
- msg_puts_attr(name, attr);
+ msg_puts_hl(name, hl_id, false);
msg_putchar('=');
for (const int16_t *p = list; *p; p++) {
if (*p >= SYNID_ALLBUT && *p < SYNID_TOP) {
@@ -3478,9 +3477,9 @@ static void put_id_list(const char *const name, const int16_t *const list, const
int scl_id = *p - SYNID_CLUSTER;
msg_putchar('@');
- msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name, 0);
+ msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name, 0, false);
} else {
- msg_outtrans(highlight_group_name(*p - 1), 0);
+ msg_outtrans(highlight_group_name(*p - 1), 0, false);
}
if (p[1]) {
msg_putchar(',');
@@ -3489,7 +3488,8 @@ static void put_id_list(const char *const name, const int16_t *const list, const
msg_putchar(' ');
}
-static void put_pattern(const char *const s, const int c, const synpat_T *const spp, const int attr)
+static void put_pattern(const char *const s, const int c, const synpat_T *const spp,
+ const int hl_id)
{
static const char *const sepchars = "/+=-#@\"|'^&";
int i;
@@ -3497,18 +3497,18 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const
// May have to write "matchgroup=group"
if (last_matchgroup != spp->sp_syn_match_id) {
last_matchgroup = spp->sp_syn_match_id;
- msg_puts_attr("matchgroup", attr);
+ msg_puts_hl("matchgroup", hl_id, false);
msg_putchar('=');
if (last_matchgroup == 0) {
- msg_outtrans("NONE", 0);
+ msg_outtrans("NONE", 0, false);
} else {
- msg_outtrans(highlight_group_name(last_matchgroup - 1), 0);
+ msg_outtrans(highlight_group_name(last_matchgroup - 1), 0, false);
}
msg_putchar(' ');
}
// Output the name of the pattern and an '=' or ' '.
- msg_puts_attr(s, attr);
+ msg_puts_hl(s, hl_id, false);
msg_putchar(c);
// output the pattern, in between a char that is not in the pattern
@@ -3519,7 +3519,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const
}
}
msg_putchar(sepchars[i]);
- msg_outtrans(spp->sp_pattern, 0);
+ msg_outtrans(spp->sp_pattern, 0, false);
msg_putchar(sepchars[i]);
// output any pattern options
@@ -3558,7 +3558,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const
///
/// @return true if the header has been printed.
static bool syn_list_keywords(const int id, const hashtab_T *const ht, bool did_header,
- const int attr)
+ const int hl_id)
{
int prev_contained = 0;
const int16_t *prev_next_list = NULL;
@@ -3600,36 +3600,36 @@ static bool syn_list_keywords(const int id, const hashtab_T *const ht, bool did_
}
did_header = true;
if (prev_contained != (kp->flags & HL_CONTAINED)) {
- msg_puts_attr("contained", attr);
+ msg_puts_hl("contained", hl_id, false);
msg_putchar(' ');
prev_contained = (kp->flags & HL_CONTAINED);
}
if (kp->k_syn.cont_in_list != prev_cont_in_list) {
- put_id_list("containedin", kp->k_syn.cont_in_list, attr);
+ put_id_list("containedin", kp->k_syn.cont_in_list, hl_id);
msg_putchar(' ');
prev_cont_in_list = kp->k_syn.cont_in_list;
}
if (kp->next_list != prev_next_list) {
- put_id_list("nextgroup", kp->next_list, attr);
+ put_id_list("nextgroup", kp->next_list, hl_id);
msg_putchar(' ');
prev_next_list = kp->next_list;
if (kp->flags & HL_SKIPNL) {
- msg_puts_attr("skipnl", attr);
+ msg_puts_hl("skipnl", hl_id, false);
msg_putchar(' ');
prev_skipnl = (kp->flags & HL_SKIPNL);
}
if (kp->flags & HL_SKIPWHITE) {
- msg_puts_attr("skipwhite", attr);
+ msg_puts_hl("skipwhite", hl_id, false);
msg_putchar(' ');
prev_skipwhite = (kp->flags & HL_SKIPWHITE);
}
if (kp->flags & HL_SKIPEMPTY) {
- msg_puts_attr("skipempty", attr);
+ msg_puts_hl("skipempty", hl_id, false);
msg_putchar(' ');
prev_skipempty = (kp->flags & HL_SKIPEMPTY);
}
}
- msg_outtrans(kp->keyword, 0);
+ msg_outtrans(kp->keyword, 0, false);
}
}
}
@@ -5649,7 +5649,7 @@ static void syntime_report(void)
msg_puts(profile_msg(p->average));
msg_puts(" ");
msg_advance(50);
- msg_outtrans(highlight_group_name(p->id - 1), 0);
+ msg_outtrans(highlight_group_name(p->id - 1), 0, false);
msg_puts(" ");
msg_advance(69);
@@ -5661,7 +5661,7 @@ static void syntime_report(void)
}
int patlen = (int)strlen(p->pattern);
len = MIN(len, patlen);
- msg_outtrans_len(p->pattern, len, 0);
+ msg_outtrans_len(p->pattern, len, 0, false);
msg_puts("\n");
}
ga_clear(&ga);
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 7a0c1cd810..3e0bb32391 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -736,7 +736,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose)
}
if ((num_matches > prev_num_matches || new_tag)
&& num_matches > 1) {
- msg(IObuff, ic ? HL_ATTR(HLF_W) : 0);
+ msg(IObuff, ic ? HLF_W : 0);
msg_scroll = true; // Don't overwrite this message.
} else {
give_warning(IObuff, ic);
@@ -815,10 +815,10 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
msg_didout = false; // overwrite previous message
}
msg_start();
- msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
+ msg_puts_hl(_(" # pri kind tag"), HLF_T, false);
msg_clr_eos();
taglen_advance(taglen);
- msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
+ msg_puts_hl(_("file\n"), HLF_T, false);
for (int i = 0; i < num_matches && !got_int; i++) {
parse_match(matches[i], &tagp);
@@ -836,10 +836,10 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
mt_names[matches[i][0] & MT_MASK]);
msg_puts(IObuff);
if (tagp.tagkind != NULL) {
- msg_outtrans_len(tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind), 0);
+ msg_outtrans_len(tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind), 0, false);
}
msg_advance(13);
- msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HL_ATTR(HLF_T));
+ msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HLF_T, false);
msg_putchar(' ');
taglen_advance(taglen);
@@ -847,7 +847,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
// it and put "..." in the middle
const char *p = tag_full_fname(&tagp);
if (p != NULL) {
- msg_outtrans(p, HL_ATTR(HLF_D));
+ msg_outtrans(p, HLF_D, false);
XFREE_CLEAR(p);
}
if (msg_col > 0) {
@@ -880,7 +880,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
continue;
}
// print all other extra fields
- int attr = HL_ATTR(HLF_CM);
+ int hl_id = HLF_CM;
while (*p && *p != '\r' && *p != '\n') {
if (msg_col + ptr2cells(p) >= Columns) {
msg_putchar('\n');
@@ -889,13 +889,13 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
}
msg_advance(15);
}
- p = msg_outtrans_one(p, attr);
+ p = msg_outtrans_one(p, hl_id, false);
if (*p == TAB) {
- msg_puts_attr(" ", attr);
+ msg_puts_hl(" ", hl_id, false);
break;
}
if (*p == ':') {
- attr = 0;
+ hl_id = 0;
}
}
}
@@ -947,7 +947,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
msg_putchar(' ');
p++;
} else {
- p = msg_outtrans_one(p, 0);
+ p = msg_outtrans_one(p, 0, false);
}
// don't display the "$/;\"" and "$?;\""
@@ -1125,8 +1125,8 @@ void do_tags(exarg_T *eap)
tagstack[i].cur_match + 1,
tagstack[i].tagname,
tagstack[i].fmark.mark.lnum);
- msg_outtrans(IObuff, 0);
- msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HL_ATTR(HLF_D) : 0);
+ msg_outtrans(IObuff, 0, false);
+ msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HLF_D : 0, false);
xfree(name);
}
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index b916660024..5ff7f721ba 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -895,13 +895,13 @@ static bool is_filter_char(int c)
return !!(tpf_flags & flag);
}
-void terminal_paste(int count, char **y_array, size_t y_size)
+void terminal_paste(int count, String *y_array, size_t y_size)
{
if (y_size == 0) {
return;
}
vterm_keyboard_start_paste(curbuf->terminal->vt);
- size_t buff_len = strlen(y_array[0]);
+ size_t buff_len = y_array[0].size;
char *buff = xmalloc(buff_len);
for (int i = 0; i < count; i++) {
// feed the lines to the terminal
@@ -914,13 +914,13 @@ void terminal_paste(int count, char **y_array, size_t y_size)
terminal_send(curbuf->terminal, "\n", 1);
#endif
}
- size_t len = strlen(y_array[j]);
+ size_t len = y_array[j].size;
if (len > buff_len) {
buff = xrealloc(buff, len);
buff_len = len;
}
char *dst = buff;
- char *src = y_array[j];
+ char *src = y_array[j].data;
while (*src != NUL) {
len = (size_t)utf_ptr2len(src);
int c = utf_ptr2char(src);
@@ -1178,9 +1178,10 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
return 1;
}
+/// Called when the terminal wants to ring the system bell.
static int term_bell(void *data)
{
- ui_call_bell();
+ vim_beep(BO_TERM);
return 1;
}
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index 9095d4e8c9..06b3aa0411 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -863,7 +863,7 @@ int fex_format(linenr_T lnum, long count, int c)
// Make a copy, the option could be changed while calling it.
char *fex = xstrdup(curbuf->b_p_fex);
- current_sctx = curbuf->b_p_script_ctx[BV_FEX].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr].script_ctx;
// Evaluate the function.
if (use_sandbox) {
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index fa50a8252d..2839a665da 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -134,11 +134,12 @@ struct TUIData {
int resize_screen;
int reset_scroll_region;
int set_cursor_style, reset_cursor_style;
- int save_title, restore_title;
+ int save_title, restore_title, set_title;
int set_underline_style;
int set_underline_color;
int sync;
} unibi_ext;
+ char *set_title;
char *space_buf;
size_t space_buf_len;
bool stopped;
@@ -536,6 +537,7 @@ static void terminfo_stop(TUIData *tui)
abort();
}
unibi_destroy(tui->ut);
+ XFREE_CLEAR(tui->set_title);
}
static void tui_terminal_start(TUIData *tui)
@@ -1567,8 +1569,7 @@ void tui_suspend(TUIData *tui)
void tui_set_title(TUIData *tui, String title)
{
- if (!(unibi_get_str(tui->ut, unibi_to_status_line)
- && unibi_get_str(tui->ut, unibi_from_status_line))) {
+ if (!unibi_get_ext_str(tui->ut, (unsigned)tui->unibi_ext.set_title)) {
return;
}
if (title.size > 0) {
@@ -1577,9 +1578,9 @@ void tui_set_title(TUIData *tui, String title)
unibi_out_ext(tui, tui->unibi_ext.save_title);
tui->title_enabled = true;
}
- unibi_out(tui, unibi_to_status_line);
- out(tui, title.data, title.size);
- unibi_out(tui, unibi_from_status_line);
+ UNIBI_SET_NUM_VAR(tui->params[0], 0);
+ UNIBI_SET_STR_VAR(tui->params[1], title.data);
+ unibi_out_ext(tui, tui->unibi_ext.set_title);
} else if (tui->title_enabled) {
// Restore title/icon from the "stack". #4063
unibi_out_ext(tui, tui->unibi_ext.restore_title);
@@ -1803,12 +1804,17 @@ static void unibi_goto(TUIData *tui, int row, int col)
memset(&vars, 0, sizeof(vars)); \
tui->cork = true; \
retry: \
+ /* Copy parameters on every retry, as unibi_format() may modify them. */ \
memcpy(params, tui->params, sizeof(params)); \
unibi_format(vars, vars + 26, str, params, out, tui, pad, tui); \
if (tui->overflow) { \
tui->bufpos = orig_pos; \
- flush_buf(tui); \
- goto retry; \
+ /* If orig_pos is 0, there's nothing to flush and retrying won't work. */ \
+ /* TODO(zeertzjq): should this situation still be handled? */ \
+ if (orig_pos > 0) { \
+ flush_buf(tui); \
+ goto retry; \
+ } \
} \
tui->cork = false; \
} \
@@ -1840,6 +1846,7 @@ static void out(void *ctx, const char *str, size_t len)
}
flush_buf(tui);
}
+ // TODO(zeertzjq): handle string longer than buffer size? #30794
memcpy(tui->buf + tui->bufpos, str, len);
tui->bufpos += len;
@@ -2378,6 +2385,19 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in
tui->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t");
tui->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t");
+ const char *tsl = unibi_get_str(ut, unibi_to_status_line);
+ const char *fsl = unibi_get_str(ut, unibi_from_status_line);
+ if (tsl != NULL && fsl != NULL) {
+ // Add a single extended capability for the whole sequence to set title,
+ // as it is usually an OSC sequence that cannot be cut in half.
+ // Use %p2 for the title string, as to_status_line may take an argument.
+ size_t set_title_len = strlen(tsl) + strlen("%p2%s") + strlen(fsl);
+ char *set_title = xmallocz(set_title_len);
+ snprintf(set_title, set_title_len + 1, "%s%s%s", tsl, "%p2%s", fsl);
+ tui->unibi_ext.set_title = (int)unibi_add_ext_str(ut, "ext.set_title", set_title);
+ tui->set_title = set_title;
+ }
+
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
tui->unibi_ext.enable_lr_margin =
diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h
index 2dd2b01adf..bec0950653 100644
--- a/src/nvim/types_defs.h
+++ b/src/nvim/types_defs.h
@@ -12,6 +12,10 @@ typedef int32_t sattr_T;
// must be at least as big as the biggest of schar_T, sattr_T, colnr_T
typedef int32_t sscratch_T;
+// Includes final NUL. MAX_MCO is no longer used, but at least 4*(MAX_MCO+1)+1=29
+// ensures we can fit all composed chars which did fit before.
+#define MAX_SCHAR_SIZE 32
+
// Opaque handle used by API clients to refer to various objects in vim
typedef int handle_T;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 365aa5c74f..7c81110ae9 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -44,6 +44,7 @@
typedef struct {
LuaRef cb;
+ uint8_t errors;
bool ext_widgets[kUIGlobalCount];
} UIEventCallback;
@@ -212,21 +213,20 @@ void ui_refresh(void)
cursor_row = cursor_col = 0;
pending_cursor_update = true;
+ bool had_message = ui_ext[kUIMessages];
for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
+ ui_ext[i] = ext_widgets[i] | ui_cb_ext[i];
if (i < kUIGlobalCount) {
- ext_widgets[i] |= ui_cb_ext[i];
+ ui_call_option_set(cstr_as_string(ui_ext_names[i]), BOOLEAN_OBJ(ui_ext[i]));
}
- // Set 'cmdheight' to zero for all tabpages when ext_messages becomes active.
- if (i == kUIMessages && !ui_ext[i] && ext_widgets[i]) {
- set_option_value(kOptCmdheight, NUMBER_OPTVAL(0), 0);
- command_height();
- FOR_ALL_TABS(tp) {
- tp->tp_ch_used = 0;
- }
- }
- ui_ext[i] = ext_widgets[i];
- if (i < kUIGlobalCount) {
- ui_call_option_set(cstr_as_string(ui_ext_names[i]), BOOLEAN_OBJ(ext_widgets[i]));
+ }
+
+ // Reset 'cmdheight' for all tabpages when ext_messages toggles.
+ if (had_message != ui_ext[kUIMessages]) {
+ set_option_value(kOptCmdheight, NUMBER_OPTVAL(had_message), 0);
+ command_height();
+ FOR_ALL_TABS(tp) {
+ tp->tp_ch_used = had_message;
}
}
@@ -358,8 +358,8 @@ void vim_beep(unsigned val)
// a script or executing a function give the user a hint where the beep
// comes from.
if (vim_strchr(p_debug, 'e') != NULL) {
- msg_source(HL_ATTR(HLF_W));
- msg(_("Beep!"), HL_ATTR(HLF_W));
+ msg_source(HLF_W);
+ msg(_("Beep!"), HLF_W);
}
}
@@ -713,13 +713,22 @@ void ui_grid_resize(handle_T grid_handle, int width, int height, Error *err)
}
}
-void ui_call_event(char *name, Array args)
+void ui_call_event(char *name, bool fast, Array args)
{
- UIEventCallback *event_cb;
bool handled = false;
- map_foreach_value(&ui_event_cbs, event_cb, {
+ UIEventCallback *event_cb;
+
+ // Prompt messages should be shown immediately so must be safe
+ if (strcmp(name, "msg_show") == 0) {
+ char *kind = args.items[0].data.string.data;
+ fast = !kind || (strncmp(kind, "confirm", 7) != 0 && strcmp(kind, "return_prompt") != 0);
+ }
+
+ map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, {
Error err = ERROR_INIT;
- Object res = nlua_call_ref(event_cb->cb, name, args, kRetNilBool, NULL, &err);
+ uint32_t ns_id = ui_event_ns_id;
+ Object res = nlua_call_ref_ctx(fast, event_cb->cb, name, args, kRetNilBool, NULL, &err);
+ ui_event_ns_id = 0;
// TODO(bfredl/luukvbaal): should this be documented or reconsidered?
// Why does truthy return from Lua callback mean remote UI should not receive
// the event.
@@ -728,6 +737,7 @@ void ui_call_event(char *name, Array args)
}
if (ERROR_SET(&err)) {
ELOG("Error executing UI event callback: %s", err.msg);
+ ui_remove_cb(ns_id, true);
}
api_clear_error(&err);
})
@@ -780,12 +790,16 @@ void ui_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets)
ui_refresh();
}
-void ui_remove_cb(uint32_t ns_id)
+void ui_remove_cb(uint32_t ns_id, bool checkerr)
{
- if (map_has(uint32_t, &ui_event_cbs, ns_id)) {
- UIEventCallback *item = pmap_del(uint32_t)(&ui_event_cbs, ns_id, NULL);
+ UIEventCallback *item = pmap_get(uint32_t)(&ui_event_cbs, ns_id);
+ if (item && (!checkerr || ++item->errors > 10)) {
+ pmap_del(uint32_t)(&ui_event_cbs, ns_id, NULL);
free_ui_event_callback(item);
+ ui_cb_update_ext();
+ ui_refresh();
+ if (checkerr) {
+ msg_schedule_semsg("Excessive errors in vim.ui_attach() callback from ns: %d.", ns_id);
+ }
}
- ui_cb_update_ext();
- ui_refresh();
}
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 8718c7b506..4aeb8ffda9 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -18,4 +18,6 @@ EXTERN Array noargs INIT(= ARRAY_DICT_INIT);
#endif
// uncrustify:on
-EXTERN MultiQueue *resize_events;
+// vim.ui_attach() namespace of currently executed callback.
+EXTERN uint32_t ui_event_ns_id INIT( = 0);
+EXTERN MultiQueue *resize_events INIT( = NULL);
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 6e89894e0b..e28e8d4da7 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -275,7 +275,7 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col)
{
for (ssize_t i = (ssize_t)kv_size(layers) - 1; i > 0; i--) {
ScreenGrid *grid = kv_A(layers, i);
- if (grid->focusable
+ if (grid->mouse_enabled
&& row >= grid->comp_row && row < grid->comp_row + grid->rows
&& col >= grid->comp_col && col < grid->comp_col + grid->cols) {
return grid;
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 15c8e0b283..0f8857a6bd 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2595,13 +2595,12 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet)
check_pos(curbuf, &VIsual);
}
- smsg_attr_keep(0,
- _("%" PRId64 " %s; %s #%" PRId64 " %s"),
- u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount,
- _(msgstr),
- did_undo ? _("before") : _("after"),
- uhp == NULL ? 0 : (int64_t)uhp->uh_seq,
- msgbuf);
+ smsg_hl_keep(0, _("%" PRId64 " %s; %s #%" PRId64 " %s"),
+ u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount,
+ _(msgstr),
+ did_undo ? _("before") : _("after"),
+ uhp == NULL ? 0 : (int64_t)uhp->uh_seq,
+ msgbuf);
}
/// Put the timestamp of an undo header in "buf[buflen]" in a nice format.
@@ -2713,8 +2712,7 @@ void ex_undolist(exarg_T *eap)
sort_strings(ga.ga_data, ga.ga_len);
msg_start();
- msg_puts_attr(_("number changes when saved"),
- HL_ATTR(HLF_T));
+ msg_puts_hl(_("number changes when saved"), HLF_T, false);
for (int i = 0; i < ga.ga_len && !got_int; i++) {
msg_putchar('\n');
if (got_int) {
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index d32e0ee319..d27899b10f 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -91,6 +91,7 @@ static const char *command_complete[] = {
[EXPAND_PACKADD] = "packadd",
[EXPAND_RUNTIME] = "runtime",
[EXPAND_SHELLCMD] = "shellcmd",
+ [EXPAND_SHELLCMDLINE] = "shellcmdline",
[EXPAND_SIGN] = "sign",
[EXPAND_TAGS] = "tag",
[EXPAND_TAGS_LISTFILES] = "tag_listfiles",
@@ -285,8 +286,7 @@ const char *set_context_in_user_cmdarg(const char *cmd FUNC_ATTR_UNUSED, const c
}
if (argt & EX_XFILE) {
- // EX_XFILE: file names are handled above.
- xp->xp_context = context;
+ // EX_XFILE: file names are handled before this call.
return NULL;
}
@@ -464,8 +464,7 @@ static void uc_list(char *name, size_t name_len)
// Put out the title first time
if (!found) {
- msg_puts_title(_("\n Name Args Address "
- "Complete Definition"));
+ msg_puts_title(_("\n Name Args Address Complete Definition"));
}
found = true;
msg_putchar('\n');
@@ -495,7 +494,7 @@ static void uc_list(char *name, size_t name_len)
msg_putchar(' ');
}
- msg_outtrans(cmd->uc_name, HL_ATTR(HLF_D));
+ msg_outtrans(cmd->uc_name, HLF_D, false);
len = strlen(cmd->uc_name) + 4;
do {
@@ -582,11 +581,11 @@ static void uc_list(char *name, size_t name_len)
} while ((int64_t)len < 25 - over);
IObuff[len] = NUL;
- msg_outtrans(IObuff, 0);
+ msg_outtrans(IObuff, 0, false);
if (cmd->uc_luaref != LUA_NOREF) {
char *fn = nlua_funcref_str(cmd->uc_luaref, NULL);
- msg_puts_attr(fn, HL_ATTR(HLF_8));
+ msg_puts_hl(fn, HLF_8, false);
xfree(fn);
// put the description on a new line
if (*cmd->uc_rep != NUL) {
@@ -675,7 +674,8 @@ int parse_compl_arg(const char *value, int vallen, int *complp, uint32_t *argt,
*complp = i;
if (i == EXPAND_BUFFERS) {
*argt |= EX_BUFNAME;
- } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES) {
+ } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES
+ || i == EXPAND_SHELLCMDLINE) {
*argt |= EX_XFILE;
}
break;
diff --git a/src/nvim/vim_defs.h b/src/nvim/vim_defs.h
index f6b348e009..72aaa77533 100644
--- a/src/nvim/vim_defs.h
+++ b/src/nvim/vim_defs.h
@@ -2,7 +2,6 @@
// Some defines from the old feature.h
#define SESSION_FILE "Session.vim"
-#define MAX_MSG_HIST_LEN 200
#define SYS_OPTWIN_FILE "$VIMRUNTIME/optwin.vim"
#define RUNTIME_DIRNAME "runtime"
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index 2f43f8b32b..5fc014a50c 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -41,6 +41,15 @@ M.vars = {
included here, because it will be executed anyway.
]=],
},
+ cmdbang = {
+ type = 'integer',
+ desc = [=[
+ Set like v:cmdarg for a file read/write command. When a "!"
+ was used the value is 1, otherwise it is 0. Note that this
+ can only be used in autocommands. For user commands |<bang>|
+ can be used.
+ ]=],
+ },
collate = {
type = 'string',
desc = [=[
@@ -53,15 +62,6 @@ M.vars = {
See |multi-lang|.
]=],
},
- cmdbang = {
- type = 'integer',
- desc = [=[
- Set like v:cmdarg for a file read/write command. When a "!"
- was used the value is 1, otherwise it is 0. Note that this
- can only be used in autocommands. For user commands |<bang>|
- can be used.
- ]=],
- },
completed_item = {
desc = [=[
Dictionary containing the |complete-items| for the most
@@ -118,15 +118,6 @@ M.vars = {
VimLeave autocommands will not be executed.
]=],
},
- exiting = {
- desc = [=[
- Exit code, or |v:null| before invoking the |VimLeavePre|
- and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
- Example: >vim
- :au VimLeave * echo "Exit value is " .. v:exiting
- <
- ]=],
- },
echospace = {
type = 'integer',
desc = [=[
@@ -180,13 +171,14 @@ M.vars = {
an aborting condition (e.g. |c_Esc| or
|c_CTRL-C| for |CmdlineLeave|).
chan |channel-id|
+ info Dict of arbitrary event data.
cmdlevel Level of cmdline.
cmdtype Type of cmdline, |cmdline-char|.
cwd Current working directory.
inclusive Motion is |inclusive|, else exclusive.
scope Event-specific scope name.
operator Current |operator|. Also set for Ex
- commands (unlike |v:operator|). For
+ commands (unlike |v:operator|). For
example if |TextYankPost| is triggered
by the |:yank| Ex command then
`v:event.operator` is "y".
@@ -243,18 +235,13 @@ M.vars = {
or |expr7| when used with numeric operators). Read-only.
]=],
},
- fcs_reason = {
- type = 'string',
+ exiting = {
desc = [=[
- The reason why the |FileChangedShell| event was triggered.
- Can be used in an autocommand to decide what to do and/or what
- to set v:fcs_choice to. Possible values:
- deleted file no longer exists
- conflict file contents, mode or timestamp was
- changed and buffer is modified
- changed file contents has changed
- mode mode of file changed
- time only file timestamp changed
+ Exit code, or |v:null| before invoking the |VimLeavePre|
+ and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
+ Example: >vim
+ :au VimLeave * echo "Exit value is " .. v:exiting
+ <
]=],
},
fcs_choice = {
@@ -280,6 +267,20 @@ M.vars = {
Vim behaves like it is empty, there is no warning message.
]=],
},
+ fcs_reason = {
+ type = 'string',
+ desc = [=[
+ The reason why the |FileChangedShell| event was triggered.
+ Can be used in an autocommand to decide what to do and/or what
+ to set v:fcs_choice to. Possible values:
+ deleted file no longer exists
+ conflict file contents, mode or timestamp was
+ changed and buffer is modified
+ changed file contents has changed
+ mode mode of file changed
+ time only file timestamp changed
+ ]=],
+ },
fname = {
type = 'string',
desc = [=[
@@ -287,6 +288,13 @@ M.vars = {
detected. Empty otherwise.
]=],
},
+ fname_diff = {
+ type = 'string',
+ desc = [=[
+ The name of the diff (patch) file. Only valid while
+ evaluating 'patchexpr'.
+ ]=],
+ },
fname_in = {
type = 'string',
desc = [=[
@@ -298,6 +306,13 @@ M.vars = {
And set to the swap file name for |SwapExists|.
]=],
},
+ fname_new = {
+ type = 'string',
+ desc = [=[
+ The name of the new version of the file. Only valid while
+ evaluating 'diffexpr'.
+ ]=],
+ },
fname_out = {
type = 'string',
desc = [=[
@@ -313,20 +328,6 @@ M.vars = {
file and different from v:fname_in.
]=],
},
- fname_new = {
- type = 'string',
- desc = [=[
- The name of the new version of the file. Only valid while
- evaluating 'diffexpr'.
- ]=],
- },
- fname_diff = {
- type = 'string',
- desc = [=[
- The name of the diff (patch) file. Only valid while
- evaluating 'patchexpr'.
- ]=],
- },
folddashes = {
type = 'string',
desc = [=[
@@ -335,17 +336,17 @@ M.vars = {
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
- foldlevel = {
+ foldend = {
type = 'integer',
desc = [=[
- Used for 'foldtext': foldlevel of closed fold.
+ Used for 'foldtext': last line of closed fold.
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
- foldend = {
+ foldlevel = {
type = 'integer',
desc = [=[
- Used for 'foldtext': last line of closed fold.
+ Used for 'foldtext': foldlevel of closed fold.
Read-only in the |sandbox|. |fold-foldtext|
]=],
},
@@ -435,19 +436,12 @@ M.vars = {
2147483647 on all systems.
]=],
},
- mouse_win = {
- type = 'integer',
- desc = [=[
- Window number for a mouse click obtained with |getchar()|.
- First window has number 1, like with |winnr()|. The value is
- zero when there was no mouse button click.
- ]=],
- },
- mouse_winid = {
+ mouse_col = {
type = 'integer',
desc = [=[
- |window-ID| for a mouse click obtained with |getchar()|.
- The value is zero when there was no mouse button click.
+ Column number for a mouse click obtained with |getchar()|.
+ This is the screen column number, like with |virtcol()|. The
+ value is zero when there was no mouse button click.
]=],
},
mouse_lnum = {
@@ -458,12 +452,19 @@ M.vars = {
value is zero when there was no mouse button click.
]=],
},
- mouse_col = {
+ mouse_win = {
type = 'integer',
desc = [=[
- Column number for a mouse click obtained with |getchar()|.
- This is the screen column number, like with |virtcol()|. The
- value is zero when there was no mouse button click.
+ Window number for a mouse click obtained with |getchar()|.
+ First window has number 1, like with |winnr()|. The value is
+ zero when there was no mouse button click.
+ ]=],
+ },
+ mouse_winid = {
+ type = 'integer',
+ desc = [=[
+ |window-ID| for a mouse click obtained with |getchar()|.
+ The value is zero when there was no mouse button click.
]=],
},
msgpack_types = {
@@ -516,6 +517,35 @@ M.vars = {
than String this will cause trouble.
]=],
},
+ operator = {
+ type = 'string',
+ desc = [=[
+ The last operator given in Normal mode. This is a single
+ character except for commands starting with <g> or <z>,
+ in which case it is two characters. Best used alongside
+ |v:prevcount| and |v:register|. Useful if you want to cancel
+ Operator-pending mode and then use the operator, e.g.: >vim
+ :omap O <Esc>:call MyMotion(v:operator)<CR>
+ <
+ The value remains set until another operator is entered, thus
+ don't expect it to be empty.
+ v:operator is not set for |:delete|, |:yank| or other Ex
+ commands.
+ Read-only.
+ ]=],
+ },
+ option_command = {
+ type = 'string',
+ desc = [=[
+ Command used to set the option. Valid while executing an
+ |OptionSet| autocommand.
+ value option was set via ~
+ "setlocal" |:setlocal| or `:let l:xxx`
+ "setglobal" |:setglobal| or `:let g:xxx`
+ "set" |:set| or |:let|
+ "modeline" |modeline|
+ ]=],
+ },
option_new = {
desc = [=[
New value of the option. Valid while executing an |OptionSet|
@@ -530,15 +560,15 @@ M.vars = {
global old value.
]=],
},
- option_oldlocal = {
+ option_oldglobal = {
desc = [=[
- Old local value of the option. Valid while executing an
+ Old global value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
- option_oldglobal = {
+ option_oldlocal = {
desc = [=[
- Old global value of the option. Valid while executing an
+ Old local value of the option. Valid while executing an
|OptionSet| autocommand.
]=],
},
@@ -549,35 +579,6 @@ M.vars = {
|OptionSet| autocommand. Can be either "global" or "local"
]=],
},
- option_command = {
- type = 'string',
- desc = [=[
- Command used to set the option. Valid while executing an
- |OptionSet| autocommand.
- value option was set via ~
- "setlocal" |:setlocal| or `:let l:xxx`
- "setglobal" |:setglobal| or `:let g:xxx`
- "set" |:set| or |:let|
- "modeline" |modeline|
- ]=],
- },
- operator = {
- type = 'string',
- desc = [=[
- The last operator given in Normal mode. This is a single
- character except for commands starting with <g> or <z>,
- in which case it is two characters. Best used alongside
- |v:prevcount| and |v:register|. Useful if you want to cancel
- Operator-pending mode and then use the operator, e.g.: >vim
- :omap O <Esc>:call MyMotion(v:operator)<CR>
- <
- The value remains set until another operator is entered, thus
- don't expect it to be empty.
- v:operator is not set for |:delete|, |:yank| or other Ex
- commands.
- Read-only.
- ]=],
- },
prevcount = {
type = 'integer',
desc = [=[
@@ -641,6 +642,17 @@ M.vars = {
hit-enter prompt.
]=],
},
+ searchforward = {
+ type = 'integer',
+ desc = [=[
+ Search direction: 1 after a forward search, 0 after a
+ backward search. It is reset to forward when directly setting
+ the last search pattern, see |quote/|.
+ Note that the value is restored when returning from a
+ function. |function-search-undo|.
+ Read-write.
+ ]=],
+ },
servername = {
type = 'string',
desc = [=[
@@ -664,17 +676,6 @@ M.vars = {
Note the contents of $NVIM may change in the future.
]=],
},
- searchforward = {
- type = 'integer',
- desc = [=[
- Search direction: 1 after a forward search, 0 after a
- backward search. It is reset to forward when directly setting
- the last search pattern, see |quote/|.
- Note that the value is restored when returning from a
- function. |function-search-undo|.
- Read-write.
- ]=],
- },
shell_error = {
type = 'integer',
desc = [=[
@@ -709,14 +710,6 @@ M.vars = {
<
]=],
},
- swapname = {
- type = 'string',
- desc = [=[
- Name of the swapfile found.
- Only valid during |SwapExists| event.
- Read-only.
- ]=],
- },
swapchoice = {
type = 'string',
desc = [=[
@@ -743,6 +736,14 @@ M.vars = {
For ":edit +cmd file" the value is ":cmd\r".
]=],
},
+ swapname = {
+ type = 'string',
+ desc = [=[
+ Name of the swapfile found.
+ Only valid during |SwapExists| event.
+ Read-only.
+ ]=],
+ },
t_blob = {
type = 'integer',
tags = { 'v:t_TYPE' },
@@ -776,22 +777,22 @@ M.vars = {
type = 'integer',
desc = 'Value of |String| type. Read-only. See: |type()|',
},
- termresponse = {
+ termrequest = {
type = 'string',
desc = [=[
The value of the most recent OSC or DCS control sequence
- received by Nvim from the terminal. This can be read in a
- |TermResponse| event handler after querying the terminal using
- another escape sequence.
+ sent from a process running in the embedded |terminal|.
+ This can be read in a |TermRequest| event handler to respond
+ to queries from embedded applications.
]=],
},
- termrequest = {
+ termresponse = {
type = 'string',
desc = [=[
The value of the most recent OSC or DCS control sequence
- sent from a process running in the embedded |terminal|.
- This can be read in a |TermRequest| event handler to respond
- to queries from embedded applications.
+ received by Nvim from the terminal. This can be read in a
+ |TermResponse| event handler after querying the terminal using
+ another escape sequence.
]=],
},
testing = {
@@ -849,20 +850,20 @@ M.vars = {
<
]=],
},
- virtnum = {
+ vim_did_enter = {
type = 'integer',
desc = [=[
- Virtual line number for the 'statuscolumn' expression.
- Negative when drawing the status column for virtual lines, zero
- when drawing an actual buffer line, and positive when drawing
- the wrapped part of a buffer line.
+ 0 during startup, 1 just before |VimEnter|.
Read-only.
]=],
},
- vim_did_enter = {
+ virtnum = {
type = 'integer',
desc = [=[
- 0 during startup, 1 just before |VimEnter|.
+ Virtual line number for the 'statuscolumn' expression.
+ Negative when drawing the status column for virtual lines, zero
+ when drawing an actual buffer line, and positive when drawing
+ the wrapped part of a buffer line.
Read-only.
]=],
},
diff --git a/src/nvim/window.c b/src/nvim/window.c
index d3280a3478..c3f3e075f1 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -857,7 +857,7 @@ void ui_ext_win_position(win_T *wp, bool validate)
String anchor = cstr_as_string(float_anchor_str[c.anchor]);
if (!c.hide) {
ui_call_win_float_pos(wp->w_grid_alloc.handle, wp->handle, anchor,
- grid->handle, row, col, c.focusable,
+ grid->handle, row, col, c.mouse,
wp->w_grid_alloc.zindex);
} else {
ui_call_win_hide(wp->w_grid_alloc.handle);
@@ -889,7 +889,7 @@ void ui_ext_win_position(win_T *wp, bool validate)
ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col,
wp->w_height_outer, wp->w_width_outer, valid, false);
ui_check_cursor_grid(wp->w_grid_alloc.handle);
- wp->w_grid_alloc.focusable = wp->w_config.focusable;
+ wp->w_grid_alloc.mouse_enabled = wp->w_config.mouse;
if (!valid) {
wp->w_grid_alloc.valid = false;
redraw_later(wp, UPD_NOT_VALID);
@@ -4044,6 +4044,7 @@ void win_alloc_aucmd_win(int idx)
fconfig.width = Columns;
fconfig.height = 5;
fconfig.focusable = false;
+ fconfig.mouse = false;
aucmd_win[idx].auc_win = win_new_float(NULL, true, fconfig, &err);
aucmd_win[idx].auc_win->w_buffer->b_nwindows--;
RESET_BINDING(aucmd_win[idx].auc_win);
@@ -6754,8 +6755,8 @@ void win_comp_scroll(win_T *wp)
if (wp->w_p_scr != old_w_p_scr) {
// Used by "verbose set scroll".
- wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_sid = SID_WINLAYOUT;
- wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_lnum = 0;
+ wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_sid = SID_WINLAYOUT;
+ wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_lnum = 0;
}
}
@@ -6813,11 +6814,13 @@ void command_height(void)
// Recompute window positions.
win_comp_pos();
- // clear the lines added to cmdline
- if (full_screen) {
- grid_clear(&default_grid, cmdline_row, Rows, 0, Columns, 0);
+ if (!need_wait_return) {
+ // clear the lines added to cmdline
+ if (full_screen) {
+ grid_clear(&default_grid, cmdline_row, Rows, 0, Columns, 0);
+ }
+ msg_row = cmdline_row;
}
- msg_row = cmdline_row;
redraw_cmdline = true;
return;
}
@@ -7370,18 +7373,37 @@ static int int_cmp(const void *pa, const void *pb)
return a == b ? 0 : a < b ? -1 : 1;
}
-/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
+/// Check "cc" as 'colorcolumn' and update the members of "wp".
+/// This is called when 'colorcolumn' or 'textwidth' is changed.
+///
+/// @param cc when NULL: use "wp->w_p_cc"
+/// @param wp when NULL: only parse "cc"
///
/// @return error message, NULL if it's OK.
-const char *check_colorcolumn(win_T *wp)
+const char *check_colorcolumn(char *cc, win_T *wp)
{
- if (wp->w_buffer == NULL) {
+ if (wp != NULL && wp->w_buffer == NULL) {
return NULL; // buffer was closed
}
+ char *s = empty_string_option;
+ if (cc != NULL) {
+ s = cc;
+ } else if (wp != NULL) {
+ s = wp->w_p_cc;
+ }
+
+ OptInt tw;
+ if (wp != NULL) {
+ tw = wp->w_buffer->b_p_tw;
+ } else {
+ // buffer-local value not set, assume zero
+ tw = 0;
+ }
+
unsigned count = 0;
int color_cols[256];
- for (char *s = wp->w_p_cc; *s != NUL && count < 255;) {
+ while (*s != NUL && count < 255) {
int col;
if (*s == '-' || *s == '+') {
// -N and +N: add to 'textwidth'
@@ -7391,16 +7413,12 @@ const char *check_colorcolumn(win_T *wp)
return e_invarg;
}
col = col * getdigits_int(&s, true, 0);
- if (wp->w_buffer->b_p_tw == 0) {
+ if (tw == 0) {
goto skip; // 'textwidth' not set, skip this item
}
- assert((col >= 0
- && wp->w_buffer->b_p_tw <= INT_MAX - col
- && wp->w_buffer->b_p_tw + col >= INT_MIN)
- || (col < 0
- && wp->w_buffer->b_p_tw >= INT_MIN - col
- && wp->w_buffer->b_p_tw + col <= INT_MAX));
- col += (int)wp->w_buffer->b_p_tw;
+ assert((col >= 0 && tw <= INT_MAX - col && tw + col >= INT_MIN)
+ || (col < 0 && tw >= INT_MIN - col && tw + col <= INT_MAX));
+ col += (int)tw;
if (col < 0) {
goto skip;
}
@@ -7422,6 +7440,10 @@ skip:
}
}
+ if (wp == NULL) {
+ return NULL; // only parse "cc"
+ }
+
xfree(wp->w_p_cc_cols);
if (count == 0) {
wp->w_p_cc_cols = NULL;
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
index fdb65ad614..b8a51d686d 100644
--- a/src/nvim/winfloat.c
+++ b/src/nvim/winfloat.c
@@ -137,7 +137,7 @@ void win_set_minimal_style(win_T *wp)
? xstrdup("EndOfBuffer:")
: concat_str(old, ",EndOfBuffer:"));
free_string_option(old);
- parse_winhl_opt(wp);
+ parse_winhl_opt(NULL, wp);
// signcolumn: use 'auto'
if (wp->w_p_scl[0] != 'a' || strlen(wp->w_p_scl) >= 8) {
@@ -389,6 +389,7 @@ win_T *win_float_create(bool enter, bool new_buf)
config.row = curwin->w_wrow;
config.relative = kFloatRelativeEditor;
config.focusable = false;
+ config.mouse = false;
config.anchor = 0; // NW
config.noautocmd = true;
config.hide = true;
@@ -411,8 +412,8 @@ win_T *win_float_create(bool enter, bool new_buf)
return handle_error_and_cleanup(wp, &err);
}
buf->b_p_bl = false; // unlist
- set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
+ set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
win_set_buf(wp, buf, &err);
if (ERROR_SET(&err)) {
return handle_error_and_cleanup(wp, &err);
diff --git a/src/nvim/yankmap.c b/src/nvim/yankmap.c
index 591bcffe33..12b70fed65 100644
--- a/src/nvim/yankmap.c
+++ b/src/nvim/yankmap.c
@@ -20,7 +20,7 @@ yankreg_T* yankmap_get(yankmap_T* yankmap, int reg)
if (ret) {
if (is_new) {
- *ret = xcalloc(sizeof(yankreg_T), 1);
+ *ret = xcalloc(1, sizeof(yankreg_T));
}
/* Add the back-reference */
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
index 50cee638af..91a72fa318 100644
--- a/src/uncrustify.cfg
+++ b/src/uncrustify.cfg
@@ -1,4 +1,4 @@
-# Uncrustify-0.79.0_f
+# Uncrustify-0.80.1_f
#
# General options
@@ -422,6 +422,10 @@ sp_invariant_paren = ignore # ignore/add/remove/force
sp_after_invariant_paren = ignore # ignore/add/remove/force
# Add or remove space before empty statement ';' on 'if', 'for' and 'while'.
+# examples:
+# if (b) <here> ;
+# for (a=1; a<10; a++) <here> ;
+# while (*p++ = ' ') <here> ;
sp_special_semi = ignore # ignore/add/remove/force
# Add or remove space before ';'.
@@ -1103,6 +1107,10 @@ sp_after_emb_cmt = force # ignore/add/remove/force
# Default: 1
sp_num_after_emb_cmt = 1 # unsigned number
+# Embedded comment spacing options have higher priority (== override)
+# than other spacing options (comma, parenthesis, braces, ...)
+sp_emb_cmt_priority = false # true/false
+
# (Java) Add or remove space between an annotation and the open parenthesis.
sp_annotation_paren = ignore # ignore/add/remove/force
@@ -1127,6 +1135,9 @@ force_tab_after_define = false # true/false
# Add or remove space between two strings.
sp_string_string = force # ignore/add/remove/force
+# Add or remove space 'struct' and a type.
+sp_struct_type = ignore # ignore/add/remove/force
+
#
# Indenting options
#
diff --git a/src/vterm/vterm.c b/src/vterm/vterm.c
index 870a61566e..e8c87929e2 100644
--- a/src/vterm/vterm.c
+++ b/src/vterm/vterm.c
@@ -1,8 +1,9 @@
#include "vterm_internal.h"
+#include "auto/config.h"
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
/*****************
@@ -429,3 +430,509 @@ void vterm_check_version(int major, int minor)
// Happy
}
+
+// For unit tests.
+#ifndef NDEBUG
+
+int parser_text(const char bytes[], size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "text ");
+ int i;
+ for(i = 0; i < len; i++) {
+ unsigned char b = bytes[i];
+ if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) {
+ break;
+ }
+ fprintf(f, i ? ",%x" : "%x", b);
+ }
+ fprintf(f, "\n");
+ fclose(f);
+
+ return i;
+}
+
+static void printchars(const char *s, size_t len, FILE *f)
+{
+ while(len--) {
+ fprintf(f, "%c", (s++)[0]);
+ }
+}
+
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "csi %02x", command);
+
+ if(leader && leader[0]) {
+ fprintf(f, " L=");
+ for(int i = 0; leader[i]; i++) {
+ fprintf(f, "%02x", leader[i]);
+ }
+ }
+
+ for(int i = 0; i < argcount; i++) {
+ char sep = i ? ',' : ' ';
+
+ if(args[i] == CSI_ARG_MISSING) {
+ fprintf(f, "%c*", sep);
+ } else {
+ fprintf(f, "%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
+ }
+ }
+
+ if(intermed && intermed[0]) {
+ fprintf(f, " I=");
+ for(int i = 0; intermed[i]; i++) {
+ fprintf(f, "%02x", intermed[i]);
+ }
+ }
+
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int parser_osc(int command, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "osc ");
+
+ if(frag.initial) {
+ if(command == -1) {
+ fprintf(f, "[");
+ } else {
+ fprintf(f, "[%d;", command);
+ }
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "dcs ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ for(int i = 0; i < commandlen; i++) {
+ fprintf(f, "%c", command[i]);
+ }
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_apc(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "apc ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_pm(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "pm ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_sos(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sos ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "selection-set mask=%04X ", mask);
+ if(frag.initial) {
+ fprintf(f, "[");
+}
+ printchars(frag.str, frag.len, f);
+ if(frag.final) {
+ fprintf(f, "]");
+}
+ fprintf(f,"\n");
+
+ fclose(f);
+ return 1;
+}
+
+int selection_query(VTermSelectionMask mask, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"selection-query mask=%04X\n", mask);
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_putglyph;
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
+{
+ if(!want_state_putglyph) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "putglyph ");
+ for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
+ fprintf(f, i ? ",%x" : "%x", info->chars[i]);
+ }
+ fprintf(f, " %d %d,%d", info->width, pos.row, pos.col);
+ if(info->protected_cell) {
+ fprintf(f, " prot");
+ }
+ if(info->dwl) {
+ fprintf(f, " dwl");
+ }
+ if(info->dhl) {
+ fprintf(f, " dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" );
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+bool want_state_movecursor;
+VTermPos state_pos;
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ state_pos = pos;
+
+ if(want_state_movecursor) {
+ fprintf(f,"movecursor %d,%d\n", pos.row, pos.col);
+ }
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_scrollrect;
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user)
+{
+ if(!want_state_scrollrect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f,"scrollrect %d..%d,%d..%d => %+d,%+d\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ downward, rightward);
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_moverect;
+int state_moverect(VTermRect dest, VTermRect src, void *user)
+{
+ if(!want_state_moverect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
+ src.start_row, src.end_row, src.start_col, src.end_col,
+ dest.start_row, dest.end_row, dest.start_col, dest.end_col);
+
+ fclose(f);
+ return 1;
+}
+
+void print_color(const VTermColor *col)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ if (VTERM_COLOR_IS_RGB(col)) {
+ fprintf(f,"rgb(%d,%d,%d", col->rgb.red, col->rgb.green, col->rgb.blue);
+ }
+ else if (VTERM_COLOR_IS_INDEXED(col)) {
+ fprintf(f,"idx(%d", col->indexed.idx);
+ }
+ else {
+ fprintf(f,"invalid(%d", col->type);
+ }
+ if (VTERM_COLOR_IS_DEFAULT_FG(col)) {
+ fprintf(f,",is_default_fg");
+ }
+ if (VTERM_COLOR_IS_DEFAULT_BG(col)) {
+ fprintf(f,",is_default_bg");
+ }
+ fprintf(f,")");
+ fclose(f);
+}
+
+bool want_state_settermprop;
+int state_settermprop(VTermProp prop, VTermValue *val, void *user)
+{
+ if(!want_state_settermprop) {
+ return 1;
+ }
+
+ int errcode = 0;
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ VTermValueType type = vterm_get_prop_type(prop);
+ switch(type) {
+ case VTERM_VALUETYPE_BOOL:
+ fprintf(f,"settermprop %d %s\n", prop, val->boolean ? "true" : "false");
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_INT:
+ fprintf(f,"settermprop %d %d\n", prop, val->number);
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_STRING:
+ fprintf(f,"settermprop %d %s\"%.*s\"%s\n", prop,
+ val->string.initial ? "[" : "", (int)val->string.len, val->string.str, val->string.final ? "]" : "");
+ errcode=0;
+ goto end;
+ case VTERM_VALUETYPE_COLOR:
+ fprintf(f,"settermprop %d ", prop);
+ print_color(&val->color);
+ fprintf(f,"\n");
+ errcode=1;
+ goto end;
+ case VTERM_N_VALUETYPES:
+ goto end;
+ }
+
+end:
+ fclose(f);
+ return errcode;
+}
+
+bool want_state_erase;
+int state_erase(VTermRect rect, int selective, void *user)
+{
+ if(!want_state_erase) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f,"erase %d..%d,%d..%d%s\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ selective ? " selective" : "");
+
+ fclose(f);
+ return 1;
+}
+
+struct {
+ int bold;
+ int underline;
+ int italic;
+ int blink;
+ int reverse;
+ int conceal;
+ int strike;
+ int font;
+ int small;
+ int baseline;
+ VTermColor foreground;
+ VTermColor background;
+} state_pen;
+
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
+{
+ switch(attr) {
+ case VTERM_ATTR_BOLD:
+ state_pen.bold = val->boolean;
+ break;
+ case VTERM_ATTR_UNDERLINE:
+ state_pen.underline = val->number;
+ break;
+ case VTERM_ATTR_ITALIC:
+ state_pen.italic = val->boolean;
+ break;
+ case VTERM_ATTR_BLINK:
+ state_pen.blink = val->boolean;
+ break;
+ case VTERM_ATTR_REVERSE:
+ state_pen.reverse = val->boolean;
+ break;
+ case VTERM_ATTR_CONCEAL:
+ state_pen.conceal = val->boolean;
+ break;
+ case VTERM_ATTR_STRIKE:
+ state_pen.strike = val->boolean;
+ break;
+ case VTERM_ATTR_FONT:
+ state_pen.font = val->number;
+ break;
+ case VTERM_ATTR_SMALL:
+ state_pen.small = val->boolean;
+ break;
+ case VTERM_ATTR_BASELINE:
+ state_pen.baseline = val->number;
+ break;
+ case VTERM_ATTR_FOREGROUND:
+ state_pen.foreground = val->color;
+ break;
+ case VTERM_ATTR_BACKGROUND:
+ state_pen.background = val->color;
+ break;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+bool want_state_scrollback;
+int state_sb_clear(void *user) {
+ if(!want_state_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"sb_clear\n");
+ fclose(f);
+
+ return 0;
+}
+
+bool want_screen_scrollback;
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ if(!want_screen_scrollback) {
+ return 1;
+ }
+
+ int eol = cols;
+ while(eol && !cells[eol-1].chars[0]) {
+ eol--;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_pushline %d =", cols);
+ for(int c = 0; c < eol; c++) {
+ fprintf(f, " %02X", cells[c].chars[0]);
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
+{
+ if(!want_screen_scrollback) {
+ return 0;
+ }
+
+ // All lines of scrollback contain "ABCDE"
+ for(int col = 0; col < cols; col++) {
+ if(col < 5) {
+ cells[col].chars[0] = 'A' + col;
+ } else {
+ cells[col].chars[0] = 0;
+ }
+
+ cells[col].width = 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"sb_popline %d\n", cols);
+ fclose(f);
+ return 1;
+}
+
+int screen_sb_clear(void *user)
+{
+ if(!want_screen_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_clear\n");
+ fclose(f);
+ return 0;
+}
+
+void term_output(const char *s, size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "output ");
+ for(int i = 0; i < len; i++) {
+ fprintf(f, "%x%s", (unsigned char)s[i], i < len-1 ? "," : "\n");
+ }
+ fclose(f);
+}
+
+#endif
diff --git a/src/vterm/vterm.h b/src/vterm/vterm.h
index 929418c63a..df6878f744 100644
--- a/src/vterm/vterm.h
+++ b/src/vterm/vterm.h
@@ -9,6 +9,7 @@ extern "C" {
#include <stdlib.h>
#include <stdbool.h>
+#include "nvim/macros_defs.h"
#include "vterm_keycodes.h"
#define VTERM_VERSION_MAJOR 0
@@ -21,7 +22,7 @@ extern "C" {
/* Any cell can contain at most one basic printing character and 5 combining
* characters. This number could be changed but will be ABI-incompatible if
* you do */
-#define VTERM_MAX_CHARS_PER_CELL 6
+enum{ VTERM_MAX_CHARS_PER_CELL=6};
typedef struct VTerm VTerm;
typedef struct VTermState VTermState;
@@ -634,6 +635,40 @@ void vterm_copy_cells(VTermRect dest,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user);
+#ifndef NDEBUG
+int parser_text(const char bytes[], size_t len, void *user);
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
+int parser_osc(int command, VTermStringFragment frag, void *user);
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
+int parser_apc(VTermStringFragment frag, void *user);
+int parser_pm(VTermStringFragment frag, void *user);
+int parser_sos(VTermStringFragment frag, void *user);
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user);
+int selection_query(VTermSelectionMask mask, void *user);
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user);
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user);
+int state_moverect(VTermRect dest, VTermRect src, void *user);
+int state_settermprop(VTermProp prop, VTermValue *val, void *user);
+int state_erase(VTermRect rect, int selective, void *user);
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user);
+int state_sb_clear(void *user);
+void print_color(const VTermColor *col);
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user);
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user);
+int screen_sb_clear(void *user);
+void term_output(const char *s, size_t len, void *user);
+EXTERN VTermPos state_pos;
+EXTERN bool want_state_putglyph INIT (=false);
+EXTERN bool want_state_movecursor INIT(= false);
+EXTERN bool want_state_erase INIT(= false);
+EXTERN bool want_state_scrollrect INIT(= false);
+EXTERN bool want_state_moverect INIT(= false);
+EXTERN bool want_state_settermprop INIT(= false);
+EXTERN bool want_state_scrollback INIT(= false);
+EXTERN bool want_screen_scrollback INIT(= false);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/test/cmakeconfig/paths.lua.in b/test/cmakeconfig/paths.lua.in
index ce0eb870e0..78c66a4eac 100644
--- a/test/cmakeconfig/paths.lua.in
+++ b/test/cmakeconfig/paths.lua.in
@@ -5,6 +5,7 @@ for p in ("${TEST_INCLUDE_DIRS}" .. ";"):gmatch("[^;]+") do
table.insert(M.include_paths, p)
end
+M.vterm_test_file = "${VTERM_TEST_FILE}"
M.test_build_dir = "${CMAKE_BINARY_DIR}"
M.test_source_path = "${CMAKE_SOURCE_DIR}"
M.test_lua_prg = "${LUA_PRG}"
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 3775c8c7b7..0cc875bb51 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -125,7 +125,6 @@ describe('api/buf', function()
it('cursor position is maintained consistently with viewport', function()
local screen = Screen.new(20, 12)
- screen:attach()
local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' }
local buf = api.nvim_get_current_buf()
@@ -211,7 +210,6 @@ describe('api/buf', function()
local screen
before_each(function()
screen = Screen.new(20, 12)
- screen:attach()
api.nvim_buf_set_lines(
0,
0,
@@ -735,7 +733,6 @@ describe('api/buf', function()
it("set_lines of invisible buffer doesn't move cursor in current window", function()
local screen = Screen.new(20, 5)
- screen:attach()
insert([[
Who would win?
@@ -1689,7 +1686,6 @@ describe('api/buf', function()
it('correctly marks changed region for redraw #13890', function()
local screen = Screen.new(20, 5)
- screen:attach()
insert([[
AAA
@@ -1742,7 +1738,6 @@ describe('api/buf', function()
local screen
before_each(function()
screen = Screen.new(20, 12)
- screen:attach()
api.nvim_buf_set_lines(
0,
0,
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 52d8fd5097..43be0c0e43 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -455,7 +455,6 @@ describe('API/extmarks', function()
it('join works when no marks are present', function()
screen = Screen.new(15, 10)
- screen:attach()
feed('a<cr>1<esc>')
feed('kJ')
-- This shouldn't seg fault
@@ -508,7 +507,6 @@ describe('API/extmarks', function()
it('marks move with char inserts', function()
-- insertchar in edit.c (the ins_str branch)
screen = Screen.new(15, 10)
- screen:attach()
set_extmark(ns, marks[1], 0, 3)
feed('0')
insert('abc')
@@ -759,7 +757,7 @@ describe('API/extmarks', function()
{
Ïf (!nlua_is_deferred_safe(lstate)) {
// strictly not allowed
- Яetörn luaL_error(lstate, e_luv_api_disabled, "rpcrequest");
+ Яetörn luaL_error(lstate, e_fast_api_disabled, "rpcrequest");
}
return nlua_rpc(lstate, true);
}]])
@@ -1726,7 +1724,6 @@ describe('API/extmarks', function()
it('invalidated marks are deleted', function()
screen = Screen.new(40, 6)
- screen:attach()
feed('dd6iaaa bbb ccc<CR><ESC>gg')
api.nvim_set_option_value('signcolumn', 'auto:2', {})
set_extmark(ns, 1, 0, 0, { invalidate = true, sign_text = 'S1', end_row = 1 })
@@ -1811,7 +1808,6 @@ describe('API/extmarks', function()
it('respects priority', function()
screen = Screen.new(15, 10)
- screen:attach()
set_extmark(ns, marks[1], 0, 0, {
hl_group = 'Comment',
@@ -1983,7 +1979,6 @@ describe('API/win_extmark', function()
it('sends and only sends ui-watched marks to ui', function()
screen = Screen.new(20, 4)
- screen:attach()
-- should send this
set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
-- should not send this
@@ -2006,7 +2001,6 @@ describe('API/win_extmark', function()
it('sends multiple ui-watched marks to ui', function()
screen = Screen.new(20, 4)
- screen:attach()
feed('15A!<Esc>')
-- should send all of these
set_extmark(ns, marks[1], 1, 0, { ui_watched = true, virt_text_pos = 'overlay' })
@@ -2052,7 +2046,6 @@ describe('API/win_extmark', function()
it('updates ui-watched marks', function()
screen = Screen.new(20, 4)
- screen:attach()
-- should send this
set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
-- should not send this
@@ -2096,8 +2089,7 @@ describe('API/win_extmark', function()
end)
it('sends ui-watched to splits', function()
- screen = Screen.new(20, 8)
- screen:attach({ ext_multigrid = true })
+ screen = Screen.new(20, 8, { ext_multigrid = true })
-- should send this
set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
-- should not send this
diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua
index 76eef164c9..7556a5bc3f 100644
--- a/test/functional/api/menu_spec.lua
+++ b/test/functional/api/menu_spec.lua
@@ -11,7 +11,6 @@ describe('update_menu notification', function()
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
end)
local function expect_sent(expected)
diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua
index 2145db7f8a..5976610af1 100644
--- a/test/functional/api/ui_spec.lua
+++ b/test/functional/api/ui_spec.lua
@@ -18,8 +18,7 @@ describe('nvim_ui_attach()', function()
end)
it('handles very large width/height #2180', function()
- local screen = Screen.new(999, 999)
- screen:attach()
+ local _ = Screen.new(999, 999)
eq(999, eval('&lines'))
eq(999, eval('&columns'))
end)
@@ -64,8 +63,7 @@ describe('nvim_ui_attach()', function()
eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_set_option', 'rgb', true))
eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_detach'))
- local screen = Screen.new()
- screen:attach({ rgb = false })
+ local _ = Screen.new(nil, nil, { rgb = false })
eq(
'UI already attached to channel: 1',
pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb = false })
@@ -82,7 +80,6 @@ it('autocmds UIEnter/UILeave', function()
autocmd VimEnter * call add(g:evs, "VimEnter")
]])
local screen = Screen.new()
- screen:attach()
eq({ chan = 1 }, eval('g:uienter_ev'))
screen:detach()
eq({ chan = 1 }, eval('g:uileave_ev'))
@@ -96,7 +93,6 @@ end)
it('autocmds VimSuspend/VimResume #22041', function()
clear()
local screen = Screen.new()
- screen:attach()
exec([[
let g:ev = []
autocmd VimResume * :call add(g:ev, 'r')
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index af4d4854f5..3f1e378bc1 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -366,7 +366,6 @@ describe('API', function()
it('displays messages when opts.output=false', function()
local screen = Screen.new(40, 8)
- screen:attach()
api.nvim_exec2("echo 'hello'", { output = false })
screen:expect {
grid = [[
@@ -379,7 +378,6 @@ describe('API', function()
it("doesn't display messages when output=true", function()
local screen = Screen.new(40, 6)
- screen:attach()
api.nvim_exec2("echo 'hello'", { output = true })
screen:expect {
grid = [[
@@ -1278,7 +1276,6 @@ describe('API', function()
end)
it('pasting with empty last chunk in Cmdline mode', function()
local screen = Screen.new(20, 4)
- screen:attach()
feed(':')
api.nvim_paste('Foo', true, 1)
api.nvim_paste('', true, 3)
@@ -1290,7 +1287,6 @@ describe('API', function()
end)
it('pasting text with control characters in Cmdline mode', function()
local screen = Screen.new(20, 4)
- screen:attach()
feed(':')
api.nvim_paste('normal! \023\022\006\027', true, -1)
screen:expect([[
@@ -1675,7 +1671,6 @@ describe('API', function()
eq({ 1, 5 }, api.nvim_win_get_cursor(0))
local screen = Screen.new(60, 3)
- screen:attach()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
@@ -2130,7 +2125,6 @@ describe('API', function()
it('does not complete ("interrupt") `d` #3732', function()
local screen = Screen.new(20, 4)
- screen:attach()
command('set listchars=eol:$')
command('set list')
feed('ia<cr>b<cr>c<cr><Esc>kkk')
@@ -2391,7 +2385,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
- screen:attach()
end)
it('prints long messages correctly #20534', function()
@@ -2461,7 +2454,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
- screen:attach()
end)
it('can show one line', function()
@@ -2543,7 +2535,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
- screen:attach()
end)
it('shows only one return prompt after all lines are shown', function()
@@ -3100,8 +3091,7 @@ describe('API', function()
eq({}, api.nvim_list_uis())
end)
it('returns attached UIs', function()
- local screen = Screen.new(20, 4)
- screen:attach({ override = true })
+ local screen = Screen.new(20, 4, { override = true })
local expected = {
{
chan = 1,
@@ -3129,8 +3119,7 @@ describe('API', function()
eq(expected, api.nvim_list_uis())
screen:detach()
- screen = Screen.new(44, 99)
- screen:attach({ rgb = false })
+ screen = Screen.new(44, 99, { rgb = false }) -- luacheck: ignore
expected[1].rgb = false
expected[1].override = false
expected[1].width = 44
@@ -3165,7 +3154,6 @@ describe('API', function()
eq(1, api.nvim_get_current_buf())
local screen = Screen.new(20, 4)
- screen:attach()
api.nvim_buf_set_lines(2, 0, -1, true, { 'some text' })
api.nvim_set_current_buf(2)
screen:expect(
@@ -3229,7 +3217,6 @@ describe('API', function()
eq(1, api.nvim_get_current_buf())
local screen = Screen.new(20, 4)
- screen:attach()
--
-- Editing a scratch-buffer does NOT change its properties.
@@ -3591,11 +3578,19 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
- screen:attach()
command('highlight Statement gui=bold guifg=Brown')
command('highlight Special guifg=SlateBlue')
end)
+ it('validation', function()
+ eq("Invalid 'chunk': expected Array, got String", pcall_err(api.nvim_echo, { 'msg' }, 1, {}))
+ eq(
+ 'Invalid chunk: expected Array with 1 or 2 Strings',
+ pcall_err(api.nvim_echo, { { '', '', '' } }, 1, {})
+ )
+ eq('Invalid hl_group: text highlight', pcall_err(api.nvim_echo, { { '', false } }, 1, {}))
+ end)
+
it('should clear cmdline message before echo', function()
feed(':call nvim_echo([["msg"]], v:false, {})<CR>')
screen:expect {
@@ -3620,6 +3615,18 @@ describe('API', function()
msg_a{15:msg_b}{16:msg_c} |
]],
}
+ async_meths.nvim_echo({
+ { 'msg_d' },
+ { 'msg_e', api.nvim_get_hl_id_by_name('Statement') },
+ { 'msg_f', api.nvim_get_hl_id_by_name('Special') },
+ }, true, {})
+ screen:expect {
+ grid = [[
+ ^ |
+ {1:~ }|*6
+ msg_d{15:msg_e}{16:msg_f} |
+ ]],
+ }
end)
it('can show highlighted multiline', function()
@@ -3654,7 +3661,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(100, 35)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { background = tonumber('0xffff40'), bg_indexed = true },
[101] = {
@@ -3933,7 +3939,6 @@ describe('API', function()
command('set readonly')
eq({ str = '[RO]', width = 4 }, api.nvim_eval_statusline('%r', { maxwidth = 5 }))
local screen = Screen.new(80, 24)
- screen:attach()
command('set showcmd')
feed('1234')
screen:expect({ any = '1234' })
@@ -4591,7 +4596,6 @@ describe('API', function()
end)
it('does not interfere with printing line in Ex mode #19400', function()
local screen = Screen.new(60, 7)
- screen:attach()
insert([[
foo
bar]])
@@ -5048,7 +5052,6 @@ describe('API', function()
it("doesn't display messages when output=true", function()
local screen = Screen.new(40, 6)
- screen:attach()
api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true })
screen:expect {
grid = [[
@@ -5131,7 +5134,6 @@ describe('API', function()
it('nvim__redraw', function()
local screen = Screen.new(60, 5)
- screen:attach()
eq('at least one action required', pcall_err(api.nvim__redraw, {}))
eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 }))
eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 }))
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 5ce93f9e04..92999f383a 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -170,7 +170,6 @@ describe('API/win', function()
it('updates the screen, and also when the window is unfocused', function()
local screen = Screen.new(30, 9)
- screen:attach()
insert('prologue')
feed('100o<esc>')
@@ -281,7 +280,6 @@ describe('API/win', function()
it('updates cursorline and statusline ruler in non-current window', function()
local screen = Screen.new(60, 8)
- screen:attach()
command('set ruler')
command('set cursorline')
insert([[
@@ -314,7 +312,6 @@ describe('API/win', function()
it('updates cursorcolumn in non-current window', function()
local screen = Screen.new(60, 8)
- screen:attach()
command('set cursorcolumn')
insert([[
aaa
@@ -857,7 +854,6 @@ describe('API/win', function()
it('with two diff windows', function()
local X = api.nvim_get_vvar('maxcol')
local screen = Screen.new(45, 22)
- screen:attach()
exec([[
set diffopt+=context:2 number
let expr = 'printf("%08d", v:val) .. repeat("!", v:val)'
@@ -975,7 +971,6 @@ describe('API/win', function()
it('with wrapped lines', function()
local X = api.nvim_get_vvar('maxcol')
local screen = Screen.new(45, 22)
- screen:attach()
exec([[
set number cpoptions+=n
call setline(1, repeat([repeat('foobar-', 36)], 3))
@@ -2557,7 +2552,6 @@ describe('API/win', function()
it('updates statusline when moving bottom split', function()
local screen = Screen.new(10, 10)
- screen:attach()
exec([[
set laststatus=0
belowright split
diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
index 5e4beb7684..7b40b0a25b 100644
--- a/test/functional/autocmd/autocmd_oldtest_spec.lua
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -102,7 +102,6 @@ describe('oldtests', function()
-- oldtest: Test_delete_ml_get_errors()
it('no ml_get error with TextChanged autocommand and delete', function()
local screen = Screen.new(75, 10)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { background = Screen.colors.Cyan1 },
}
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 0429cfee89..c62e4752e0 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -258,7 +258,6 @@ describe('autocmd', function()
-- Check redrawing and API accesses to this window.
local screen = Screen.new(50, 10)
- screen:attach()
source([[
function! Doit()
@@ -333,7 +332,6 @@ describe('autocmd', function()
it('`aucmd_win` cannot be changed into a normal window #13699', function()
local screen = Screen.new(50, 10)
- screen:attach()
-- Create specific layout and ensure it's left unchanged.
-- Use vim._with on a hidden buffer so aucmd_win is used.
@@ -498,7 +496,6 @@ describe('autocmd', function()
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
- screen:attach()
feed(':doautocmd User Foo<cr>')
screen:expect {
diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua
index ca137debb8..7e13c0f349 100644
--- a/test/functional/autocmd/cmdline_spec.lua
+++ b/test/functional/autocmd/cmdline_spec.lua
@@ -60,7 +60,6 @@ describe('cmdline autocommands', function()
it('handles errors correctly', function()
clear()
local screen = Screen.new(72, 8)
- screen:attach()
command("autocmd CmdlineEnter * echoerr 'FAIL'")
command("autocmd CmdlineLeave * echoerr 'very error'")
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
index 10d242527f..fcac706349 100644
--- a/test/functional/autocmd/show_spec.lua
+++ b/test/functional/autocmd/show_spec.lua
@@ -46,7 +46,6 @@ describe(':autocmd', function()
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Magenta, bold = true },
}
- screen:attach()
exec([[
set more
autocmd! BufEnter
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index 64f16cf779..baf2bb6071 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -198,8 +198,11 @@ it('autocmd TermEnter, TermLeave', function()
end)
describe('autocmd TextChangedT', function()
- clear()
- local screen = tt.setup_screen()
+ local screen
+ before_each(function()
+ clear()
+ screen = tt.setup_screen()
+ end)
it('works', function()
command('autocmd TextChangedT * ++once let g:called = 1')
diff --git a/test/functional/autocmd/win_scrolled_resized_spec.lua b/test/functional/autocmd/win_scrolled_resized_spec.lua
index 72bbc1e469..23de83e3dc 100644
--- a/test/functional/autocmd/win_scrolled_resized_spec.lua
+++ b/test/functional/autocmd/win_scrolled_resized_spec.lua
@@ -225,8 +225,7 @@ end)
describe('WinScrolled', function()
-- oldtest: Test_WinScrolled_mouse()
it('is triggered by mouse scrolling in another window', function()
- local screen = Screen.new(75, 10)
- screen:attach()
+ local _ = Screen.new(75, 10)
exec([[
set nowrap scrolloff=0
set mouse=a
@@ -304,7 +303,6 @@ describe('WinScrolled', function()
it('is triggered by mouse scrolling in unfocused floating window #18222', function()
local screen = Screen.new(80, 24)
- screen:attach()
exec([[
let g:scrolled = 0
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index d33710a63d..cf9715f848 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -59,7 +59,6 @@ describe('fileio', function()
local screen_nvim = spawn(argv)
set_session(screen_nvim)
local screen = Screen.new(70, 10)
- screen:attach()
screen:set_default_attr_ids({
[1] = { foreground = Screen.colors.NvimDarkGrey4 },
[2] = { background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3 },
@@ -276,7 +275,6 @@ describe('fileio', function()
write_file('Xtest-overwrite-forced', 'foobar')
command('set nofixendofline')
local screen = Screen.new(40, 4)
- screen:attach()
command('set shortmess-=F')
command('e Xtest-overwrite-forced')
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 68ac0a50f6..618c294566 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -498,7 +498,6 @@ describe('jobs', function()
it('can redefine callbacks being used by a job', function()
local screen = Screen.new()
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue },
})
@@ -524,7 +523,6 @@ describe('jobs', function()
it('requires funcrefs for script-local (s:) functions', function()
local screen = Screen.new(60, 5)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
@@ -910,7 +908,6 @@ describe('jobs', function()
it('hides cursor and flushes messages before blocking', function()
local screen = Screen.new(50, 6)
- screen:attach()
command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]])
source([[
func PrintAndWait()
@@ -1223,7 +1220,6 @@ describe('pty process teardown', function()
before_each(function()
clear()
screen = Screen.new(30, 6)
- screen:attach()
screen:expect([[
^ |
{1:~ }|*4
diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua
index a952730779..57dfd6364c 100644
--- a/test/functional/core/log_spec.lua
+++ b/test/functional/core/log_spec.lua
@@ -15,6 +15,7 @@ describe('log', function()
after_each(function()
expect_exit(command, 'qa!')
+ vim.uv.sleep(10) -- Wait for Nvim to fully exit
os.remove(testlog)
end)
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index a6e917b4b2..a445423efc 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -89,7 +89,6 @@ describe('command-line option', function()
it('does not crash after reading from stdin in non-headless mode', function()
skip(is_os('win'))
local screen = Screen.new(40, 8)
- screen:attach()
local args = {
nvim_prog_abs(),
'-u',
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index f48bcb9360..7062211187 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -55,7 +55,6 @@ describe('startup', function()
clear()
local screen
screen = Screen.new(84, 3)
- screen:attach()
fn.termopen({ nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' })
screen:expect([[
^Cannot attach UI of :terminal child to its parent. (Unset $NVIM to skip this check) |
@@ -74,11 +73,29 @@ describe('startup', function()
assert_log("require%('vim%._editor'%)", testfile, 100)
end)
+ it('--startuptime does not crash on error #31125', function()
+ eq(
+ "E484: Can't open file .",
+ fn.system({
+ nvim_prog,
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--headless',
+ '--startuptime',
+ '.',
+ '-c',
+ '42cquit',
+ })
+ )
+ eq(42, api.nvim_get_vvar('shell_error'))
+ end)
+
it('-D does not hang #12647', function()
clear()
local screen
screen = Screen.new(60, 7)
- screen:attach()
-- not the same colors on windows for some reason
screen._default_attr_ids = nil
local id = fn.termopen({
@@ -260,10 +277,8 @@ describe('startup', function()
-- nvim <vim args> -l foo.lua <vim args>
assert_l_out(
- -- luacheck: ignore 611 (Line contains only whitespaces)
[[
wrap
-
bufs:
nvim args: 7
lua args: { "-c", "set wrap?",
@@ -327,7 +342,6 @@ describe('startup', function()
it('with --embed: has("ttyin")==0 has("ttyout")==0', function()
local screen = Screen.new(25, 3)
-- Remote UI connected by --embed.
- screen:attach()
-- TODO: a lot of tests in this file already use the new default color scheme.
-- once we do the batch update of tests to use it, remove this workarond
screen._default_attr_ids = nil
@@ -341,7 +355,6 @@ describe('startup', function()
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
local screen = Screen.new(25, 4)
- screen:attach()
screen._default_attr_ids = nil
if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
@@ -436,7 +449,6 @@ describe('startup', function()
it('input from pipe (implicit) #7679', function()
clear({ env = { NVIM_LOG_FILE = testlog } })
local screen = Screen.new(25, 4)
- screen:attach()
screen._default_attr_ids = nil
if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
@@ -601,7 +613,6 @@ describe('startup', function()
it('ENTER dismisses early message #7967', function()
local screen
screen = Screen.new(60, 6)
- screen:attach()
screen._default_attr_ids = nil
local id = fn.termopen({
nvim_prog,
@@ -699,7 +710,6 @@ describe('startup', function()
it('-e/-E interactive #7679', function()
clear('-e')
local screen = Screen.new(25, 3)
- screen:attach()
feed("put ='from -e'<CR>")
screen:expect([[
:put ='from -e' |
@@ -709,7 +719,6 @@ describe('startup', function()
clear('-E')
screen = Screen.new(25, 3)
- screen:attach()
feed("put ='from -E'<CR>")
screen:expect([[
:put ='from -E' |
@@ -719,9 +728,8 @@ describe('startup', function()
end)
it('-e sets ex mode', function()
- local screen = Screen.new(25, 3)
clear('-e')
- screen:attach()
+ local screen = Screen.new(25, 3)
-- Verify we set the proper mode both before and after :vi.
feed('put =mode(1)<CR>vi<CR>:put =mode(1)<CR>')
screen:expect([[
@@ -773,7 +781,6 @@ describe('startup', function()
it("sets 'shortmess' when loading other tabs", function()
clear({ args = { '-p', 'a', 'b', 'c' } })
local screen = Screen.new(25, 4)
- screen:attach()
screen:expect({
grid = [[
{1: a }{2: b c }{3: }{2:X}|
@@ -1136,7 +1143,6 @@ describe('user config init', function()
eq('---', eval('g:exrc_file'))
local screen = Screen.new(50, 8)
- screen:attach()
screen._default_attr_ids = nil
fn.termopen({ nvim_prog }, {
env = {
@@ -1412,7 +1418,6 @@ describe('inccommand on ex mode', function()
clear()
local screen
screen = Screen.new(60, 10)
- screen:attach()
local id = fn.termopen({
nvim_prog,
'-u',
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index d543de4acd..030181764d 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -17,7 +17,6 @@ describe('completion', function()
before_each(function()
clear()
screen = Screen.new(60, 8)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow },
[101] = { background = Screen.colors.Gray0 },
diff --git a/test/functional/editor/ctrl_c_spec.lua b/test/functional/editor/ctrl_c_spec.lua
index e1258c7df8..cb6bc57681 100644
--- a/test/functional/editor/ctrl_c_spec.lua
+++ b/test/functional/editor/ctrl_c_spec.lua
@@ -13,7 +13,6 @@ describe('CTRL-C (mapped)', function()
before_each(function()
clear()
screen = Screen.new(52, 6)
- screen:attach()
end)
it('interrupts :global', function()
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
index 47fd177f7b..82d285cc9a 100644
--- a/test/functional/editor/defaults_spec.lua
+++ b/test/functional/editor/defaults_spec.lua
@@ -35,7 +35,6 @@ describe('default', function()
args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' },
}
local screen = Screen.new(40, 8)
- screen:attach()
n.insert([[
1 line 1
2 https://example.com
@@ -58,7 +57,6 @@ describe('default', function()
it('right-click on URL shows "Open in web browser"', function()
n.clear()
local screen = Screen.new(40, 8)
- screen:attach()
n.insert([[
1 line 1
2 https://example.com
@@ -95,6 +93,157 @@ describe('default', function()
end)
end)
- -- describe('key mappings', function()
- -- end)
+ describe('key mappings', function()
+ describe('unimpaired-style mappings', function()
+ it('do not show a full stack trace #30625', function()
+ n.clear({ args_rm = { '--cmd' } })
+ local screen = Screen.new(40, 8)
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.NvimDarkGray4 },
+ [2] = {
+ background = Screen.colors.NvimLightGrey3,
+ foreground = Screen.colors.NvimDarkGray3,
+ },
+ [3] = { foreground = Screen.colors.NvimLightRed },
+ [4] = { foreground = Screen.colors.NvimLightCyan },
+ })
+
+ n.feed('[a')
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }|*4
+ {2: }|
+ {3:E163: There is only one file to edit} |
+ {4:Press ENTER or type command to continue}^ |
+ ]],
+ })
+
+ n.feed('[q')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*5
+ {2:[No Name] 0,0-1 All}|
+ {3:E42: No Errors} |
+ ]],
+ })
+
+ n.feed('[l')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*5
+ {2:[No Name] 0,0-1 All}|
+ {3:E776: No location list} |
+ ]],
+ })
+
+ n.feed('[t')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*5
+ {2:[No Name] 0,0-1 All}|
+ {3:E73: Tag stack empty} |
+ ]],
+ })
+ end)
+
+ describe('[<Space>', function()
+ it('adds an empty line above the current line', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('[<Space>')
+ n.expect([[
+
+ first line]])
+ end)
+
+ it('works with a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('5[<Space>')
+ n.expect([[
+
+
+
+
+
+ first line]])
+ end)
+
+ it('supports dot repetition', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('[<Space>')
+ n.feed('.')
+ n.expect([[
+
+
+ first line]])
+ end)
+
+ it('supports dot repetition and a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('[<Space>')
+ n.feed('3.')
+ n.expect([[
+
+
+
+
+ first line]])
+ end)
+ end)
+
+ describe(']<Space>', function()
+ it('adds an empty line below the current line', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed(']<Space>')
+ n.expect([[
+ first line
+ ]])
+ end)
+
+ it('works with a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('5]<Space>')
+ n.expect([[
+ first line
+
+
+
+
+ ]])
+ end)
+
+ it('supports dot repetition', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed(']<Space>')
+ n.feed('.')
+ n.expect([[
+ first line
+
+ ]])
+ end)
+
+ it('supports dot repetition and a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed(']<Space>')
+ n.feed('2.')
+ n.expect([[
+ first line
+
+
+ ]])
+ end)
+ end)
+ end)
+ end)
end)
diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua
index ab4cefaf84..dab8fb3fda 100644
--- a/test/functional/editor/jump_spec.lua
+++ b/test/functional/editor/jump_spec.lua
@@ -56,7 +56,6 @@ describe('jumplist', function()
write_file(fname2, 'baz')
local screen = Screen.new(5, 25)
- screen:attach()
command('set number')
command('edit ' .. fname1)
feed('35gg')
@@ -386,7 +385,6 @@ describe('jumpoptions=view', function()
it('restores the view', function()
local screen = Screen.new(5, 8)
- screen:attach()
command('edit ' .. file1)
feed('12Gztj')
feed('gg<C-o>')
@@ -404,7 +402,6 @@ describe('jumpoptions=view', function()
it('restores the view across files', function()
local screen = Screen.new(5, 5)
- screen:attach()
command('args ' .. file1 .. ' ' .. file2)
feed('12Gzt')
command('next')
@@ -428,7 +425,6 @@ describe('jumpoptions=view', function()
it('restores the view across files with <C-^>', function()
local screen = Screen.new(5, 5)
- screen:attach()
command('args ' .. file1 .. ' ' .. file2)
feed('12Gzt')
command('next')
@@ -452,7 +448,6 @@ describe('jumpoptions=view', function()
it("falls back to standard behavior when view can't be recovered", function()
local screen = Screen.new(5, 8)
- screen:attach()
command('edit ' .. file1)
feed('7GzbG')
api.nvim_buf_set_lines(0, 0, 2, true, {})
@@ -477,7 +472,6 @@ describe('jumpoptions=view', function()
it('falls back to standard behavior for a mark without a view', function()
local screen = Screen.new(5, 8)
- screen:attach()
command('edit ' .. file1)
feed('10ggzzvwy')
screen:expect([[
diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua
index 69cb95e1c3..08f90b088d 100644
--- a/test/functional/editor/mark_spec.lua
+++ b/test/functional/editor/mark_spec.lua
@@ -348,7 +348,6 @@ describe('named marks view', function()
it('is restored in normal mode but not op-pending mode', function()
local screen = Screen.new(5, 8)
- screen:attach()
command('edit ' .. file1)
feed('<C-e>jWma')
feed("G'a")
@@ -390,7 +389,6 @@ describe('named marks view', function()
it('is restored across files', function()
local screen = Screen.new(5, 5)
- screen:attach()
command('args ' .. file1 .. ' ' .. file2)
feed('<C-e>mA')
local mark_view = [[
@@ -415,7 +413,6 @@ describe('named marks view', function()
it("fallback to standard behavior when view can't be recovered", function()
local screen = Screen.new(10, 10)
- screen:attach()
command('edit ' .. file1)
feed('7GzbmaG') -- Seven lines from the top
command('new') -- Screen size for window is now half the height can't be restored
@@ -434,7 +431,6 @@ describe('named marks view', function()
it('fallback to standard behavior when mark is loaded from shada', function()
local screen = Screen.new(10, 6)
- screen:attach()
command('edit ' .. file1)
feed('G')
feed('mA')
diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua
index efd7a37c0b..52f2bf7f8c 100644
--- a/test/functional/editor/mode_cmdline_spec.lua
+++ b/test/functional/editor/mode_cmdline_spec.lua
@@ -38,6 +38,26 @@ describe('cmdline', function()
feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
eq('foo\nbar\rbaz', fn.getcmdline())
end)
+
+ it('pasting handles composing chars properly', function()
+ local screen = Screen.new(60, 4)
+ -- 'arabicshape' cheats and always redraws everything which trivially works,
+ -- this test is for partial redraws in 'noarabicshape' mode.
+ command('set noarabicshape')
+ fn.setreg('a', '💻')
+ feed(':test 🧑‍')
+ screen:expect([[
+ |
+ {1:~ }|*2
+ :test 🧑‍^ |
+ ]])
+ feed('<c-r><c-r>a')
+ screen:expect([[
+ |
+ {1:~ }|*2
+ :test 🧑‍💻^ |
+ ]])
+ end)
end)
it('Ctrl-Shift-V supports entering unsimplified key notations', function()
@@ -48,7 +68,6 @@ describe('cmdline', function()
it('redraws statusline when toggling overstrike', function()
local screen = Screen.new(60, 4)
- screen:attach()
command('set laststatus=2 statusline=%!mode(1)')
feed(':')
screen:expect {
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index 87d5c46134..a9fa93590f 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -55,7 +55,6 @@ describe('insert-mode', function()
it('double quote is removed after hit-enter prompt #22609', function()
local screen = Screen.new(50, 6)
- screen:attach()
feed('i<C-R>')
screen:expect([[
{18:^"} |
@@ -180,7 +179,6 @@ describe('insert-mode', function()
it('multi-char mapping updates screen properly #25626', function()
local screen = Screen.new(60, 6)
- screen:attach()
command('vnew')
insert('foo\nfoo\nfoo')
command('wincmd w')
@@ -228,8 +226,7 @@ describe('insert-mode', function()
end
it('works with tabs and spaces', function()
- local screen = Screen.new(30, 2)
- screen:attach()
+ local _ = Screen.new(30, 2)
command('setl ts=4 sw=4')
set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
feed('$i')
@@ -246,8 +243,7 @@ describe('insert-mode', function()
end)
it('works with varsofttabstop', function()
- local screen = Screen.new(30, 2)
- screen:attach()
+ local _ = Screen.new(30, 2)
command('setl vsts=6,2,5,3')
set_lines(0, 1, 'a\t' .. s(4) .. '\t a')
feed('$i')
@@ -263,8 +259,7 @@ describe('insert-mode', function()
end)
it('works with tab as ^I', function()
- local screen = Screen.new(30, 2)
- screen:attach()
+ local _ = Screen.new(30, 2)
command('set list listchars=space:.')
command('setl ts=4 sw=4')
set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
@@ -280,8 +275,7 @@ describe('insert-mode', function()
end)
it('works in replace mode', function()
- local screen = Screen.new(50, 2)
- screen:attach()
+ local _ = Screen.new(50, 2)
command('setl ts=8 sw=8 sts=8')
set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
feed('$R')
@@ -296,8 +290,7 @@ describe('insert-mode', function()
end)
it('works with breakindent', function()
- local screen = Screen.new(17, 4)
- screen:attach()
+ local _ = Screen.new(17, 4)
command('setl ts=4 sw=4 bri briopt=min:5')
set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
feed('$i')
@@ -314,8 +307,7 @@ describe('insert-mode', function()
end)
it('works with inline virtual text', function()
- local screen = Screen.new(50, 2)
- screen:attach()
+ local _ = Screen.new(50, 2)
command('setl ts=4 sw=4')
set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
local ns = api.nvim_create_namespace('')
@@ -335,8 +327,7 @@ describe('insert-mode', function()
end)
it("works with 'revins'", function()
- local screen = Screen.new(30, 3)
- screen:attach()
+ local _ = Screen.new(30, 3)
command('setl ts=4 sw=4 revins')
set_lines(0, 1, ('a'):rep(16), s(3) .. '\t' .. s(4) .. '\t a')
feed('j$i')
@@ -354,7 +345,6 @@ describe('insert-mode', function()
it('backspace after replacing multibyte chars', function()
local screen = Screen.new(30, 3)
- screen:attach()
api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' })
feed('^Rabcdefghi')
screen:expect([[
diff --git a/test/functional/editor/mode_normal_spec.lua b/test/functional/editor/mode_normal_spec.lua
index b3ef4866dc..5237f51237 100644
--- a/test/functional/editor/mode_normal_spec.lua
+++ b/test/functional/editor/mode_normal_spec.lua
@@ -9,6 +9,7 @@ local feed = n.feed
local fn = n.fn
local command = n.command
local eq = t.eq
+local api = n.api
describe('Normal mode', function()
before_each(clear)
@@ -25,7 +26,6 @@ describe('Normal mode', function()
it('&showcmd does not crash with :startinsert #28419', function()
local screen = Screen.new(60, 17)
- screen:attach()
fn.termopen(
{ n.nvim_prog, '--clean', '--cmd', 'startinsert' },
{ env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } }
@@ -41,4 +41,22 @@ describe('Normal mode', function()
attr_ids = {},
})
end)
+
+ it('replacing with ZWJ emoji sequences', function()
+ local screen = Screen.new(30, 8)
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'abcdefg' })
+ feed('05r🧑‍🌾') -- ZWJ
+ screen:expect([[
+ 🧑‍🌾🧑‍🌾🧑‍🌾🧑‍🌾^🧑‍🌾fg |
+ {1:~ }|*6
+ |
+ ]])
+
+ feed('2r🏳️‍⚧️') -- ZWJ and variant selectors
+ screen:expect([[
+ 🧑‍🌾🧑‍🌾🧑‍🌾🧑‍🌾🏳️‍⚧️^🏳️‍⚧️g |
+ {1:~ }|*6
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index 0f6936cd31..79f9d97bc5 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -883,7 +883,6 @@ describe('put command', function()
local screen
setup(function()
screen = Screen.new()
- screen:attach()
end)
local function bell_test(actions, should_ring)
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index c20a6e5cb5..b6fbebb20c 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -105,7 +105,6 @@ describe('tabpage', function()
screen:add_extra_attr_ids {
[100] = { bold = true, foreground = Screen.colors.Fuchsia },
}
- screen:attach()
command('tabnew')
command('tabprev')
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index df62aecc7f..59862d5e77 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -65,7 +65,6 @@ describe('the first line is redrawn correctly after inserting text in an empty b
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { bold = true, reverse = true },
})
- screen:attach()
end)
it('using :append', function()
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 6c1ac8eae5..17156e483b 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -37,7 +37,6 @@ describe('mappings with <Cmd>', function()
[9] = { background = Screen.colors.LightMagenta },
[10] = { foreground = Screen.colors.Red },
})
- screen:attach()
cmdmap('<F3>', 'let m = mode(1)')
cmdmap('<F4>', 'normal! ww')
diff --git a/test/functional/ex_cmds/debug_spec.lua b/test/functional/ex_cmds/debug_spec.lua
index ebb3cdd38a..d657f9aa6d 100644
--- a/test/functional/ex_cmds/debug_spec.lua
+++ b/test/functional/ex_cmds/debug_spec.lua
@@ -15,7 +15,6 @@ describe(':debug', function()
[3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
})
- screen:attach()
end)
it('scrolls messages correctly', function()
feed(':echoerr bork<cr>')
diff --git a/test/functional/ex_cmds/digraphs_spec.lua b/test/functional/ex_cmds/digraphs_spec.lua
index fde25c028f..c45378e494 100644
--- a/test/functional/ex_cmds/digraphs_spec.lua
+++ b/test/functional/ex_cmds/digraphs_spec.lua
@@ -19,7 +19,6 @@ describe(':digraphs', function()
[6] = { foreground = Screen.colors.Blue1 },
[7] = { bold = true, reverse = true },
})
- screen:attach()
end)
it('displays digraphs', function()
diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua
index 54ddd79a35..d341c823b9 100644
--- a/test/functional/ex_cmds/drop_spec.lua
+++ b/test/functional/ex_cmds/drop_spec.lua
@@ -11,7 +11,6 @@ describe(':drop', function()
before_each(function()
clear()
screen = Screen.new(35, 10)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { bold = true, reverse = true },
diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua
index 3cb6cc2579..58709f314f 100644
--- a/test/functional/ex_cmds/highlight_spec.lua
+++ b/test/functional/ex_cmds/highlight_spec.lua
@@ -10,12 +10,9 @@ local fn = n.fn
local api = n.api
describe(':highlight', function()
- local screen
-
before_each(function()
clear()
- screen = Screen.new()
- screen:attach()
+ local _ = Screen.new()
end)
it('invalid color name', function()
diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua
index 9ef0a8ec2e..954dae9335 100644
--- a/test/functional/ex_cmds/map_spec.lua
+++ b/test/functional/ex_cmds/map_spec.lua
@@ -103,7 +103,6 @@ describe('Screen', function()
before_each(function()
clear()
screen = Screen.new(20, 5)
- screen:attach()
end)
it('cursor is restored after :map <expr> which calls input()', function()
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 8f09e802eb..95e118d570 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -201,8 +201,7 @@ describe(':mksession', function()
local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
local session_path = cwd_dir .. '/' .. session_file
- screen = Screen.new(50, 6)
- screen:attach({ rgb = false })
+ screen = Screen.new(50, 6, { rgb = false })
local expected_screen = [[
^/ |
|
@@ -222,8 +221,7 @@ describe(':mksession', function()
-- Create a new test instance of Nvim.
clear()
- screen = Screen.new(50, 6)
- screen:attach({ rgb = false })
+ screen = Screen.new(50, 6, { rgb = false })
command('silent source ' .. session_path)
-- Verify that the terminal's working directory is "/".
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 927d780181..6f81878f2d 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -38,7 +38,6 @@ describe(':oldfiles', function()
it('shows most recently used files', function()
local screen = Screen.new(100, 5)
- screen:attach()
screen._default_attr_ids = nil
feed_command('edit testfile1')
feed_command('edit testfile2')
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
index 9c47b1f05f..c1592d85d0 100644
--- a/test/functional/ex_cmds/quickfix_commands_spec.lua
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -199,7 +199,6 @@ describe('quickfix', function()
it('jump message does not scroll with cmdheight=0 and shm+=O #29597', function()
local screen = Screen.new(40, 6)
- screen:attach()
command('set cmdheight=0')
local file = file_base .. '_reuse_qfbuf_BufAdd'
write_file(file, 'foobar')
@@ -226,7 +225,6 @@ it(':vimgrep can specify Unicode pattern without delimiters', function()
[0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = { reverse = true }, -- IncSearch
})
- screen:attach()
feed('i→<Esc>:vimgrep →')
screen:expect([[
{1:→} |
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 5bb2a0181e..2820cc9663 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -114,7 +114,6 @@ describe("preserve and (R)ecover with custom 'directory'", function()
it('killing TUI process without :preserve #22096', function()
t.skip(t.is_os('win'))
local screen0 = Screen.new()
- screen0:attach()
local child_server = new_pipename()
fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
@@ -171,7 +170,6 @@ describe('swapfile detection', function()
local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true, nil, true)
set_session(nvim2)
local screen2 = Screen.new(256, 40)
- screen2:attach()
screen2._default_attr_ids = nil
exec(init)
command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
@@ -254,7 +252,6 @@ describe('swapfile detection', function()
local nvim1 = spawn(new_argv(), true, nil, true)
set_session(nvim1)
local screen = Screen.new(75, 18)
- screen:attach()
exec(init)
feed(':edit Xfile1\n')
@@ -325,7 +322,6 @@ describe('swapfile detection', function()
[1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
[2] = { background = Screen.colors.Red, foreground = Screen.colors.White }, -- ErrorMsg
})
- screen:attach()
exec(init)
if not swapexists then
diff --git a/test/functional/example_spec.lua b/test/functional/example_spec.lua
index 8db5c3d867..25554c5a7d 100644
--- a/test/functional/example_spec.lua
+++ b/test/functional/example_spec.lua
@@ -14,7 +14,6 @@ describe('example', function()
before_each(function()
clear()
screen = Screen.new(20, 5)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { bold = true, foreground = Screen.colors.Brown },
@@ -47,8 +46,7 @@ describe('example', function()
-- The UI must declare that it wants to handle the UI events.
-- For this example, we enable `ext_tabline`:
screen:detach()
- screen = Screen.new(25, 5)
- screen:attach({ rgb = true, ext_tabline = true })
+ screen = Screen.new(25, 5, { rgb = true, ext_tabline = true })
-- From ":help ui" we find that `tabline_update` receives `curtab` and
-- `tabs` objects. So we declare the UI handler like this:
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index 5c9185982f..d6f2203aa2 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -15,7 +15,6 @@ local clear = n.clear
local insert = n.insert
local command = n.command
local write_file = t.write_file
-local expect_exit = n.expect_exit
local mkdir = t.mkdir
local function ls_dir_sorted(dirname)
@@ -44,7 +43,9 @@ describe("'directory' option", function()
clear()
end)
teardown(function()
- expect_exit(command, 'qall!')
+ command('%bwipe!')
+ api.nvim_set_option_value('swapfile', false, {})
+ api.nvim_set_option_value('directory', '.', {})
n.rmdir('Xtest.je')
n.rmdir('Xtest2')
os.remove('Xtest1')
@@ -58,7 +59,6 @@ describe("'directory' option", function()
end of testfile]])
api.nvim_set_option_value('swapfile', true, {})
- api.nvim_set_option_value('swapfile', true, {})
api.nvim_set_option_value('directory', '.', {})
-- sanity check: files should not exist yet.
diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua
index 7515bcf182..639a97f68f 100644
--- a/test/functional/legacy/063_match_and_matchadd_spec.lua
+++ b/test/functional/legacy/063_match_and_matchadd_spec.lua
@@ -11,7 +11,6 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
it('is working', function()
local screen = Screen.new(40, 5)
- screen:attach()
command('highlight MyGroup1 term=bold ctermbg=red guibg=red')
command('highlight MyGroup2 term=italic ctermbg=green guibg=green')
diff --git a/test/functional/legacy/074_global_var_in_viminfo_spec.lua b/test/functional/legacy/074_global_var_in_viminfo_spec.lua
index d56a2654e3..eb5e36120f 100644
--- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua
+++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua
@@ -150,5 +150,7 @@ describe('storing global variables in ShaDa files', function()
teardown(function()
os.remove(tempname)
+ command('set shadafile=NONE')
+ os.remove('Xviminfo')
end)
end)
diff --git a/test/functional/legacy/078_swapfile_recover_spec.lua b/test/functional/legacy/078_swapfile_recover_spec.lua
index fa53482393..6ff7539940 100644
--- a/test/functional/legacy/078_swapfile_recover_spec.lua
+++ b/test/functional/legacy/078_swapfile_recover_spec.lua
@@ -45,7 +45,7 @@ describe('78', function()
silent recover Xtest
call delete(g:swapname)
- new
+ noswapfile new
call append(0, 'recovery start')
wincmd w
diff --git a/test/functional/legacy/107_adjust_window_and_contents_spec.lua b/test/functional/legacy/107_adjust_window_and_contents_spec.lua
index 57ecf76f3a..e97c9c074b 100644
--- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua
+++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua
@@ -13,7 +13,6 @@ describe('107', function()
it('is working', function()
local screen = Screen.new()
- screen:attach()
insert('start:')
poke_eventloop()
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index ac2a39a381..4c083a8a4b 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -20,7 +20,6 @@ describe('argument list commands', function()
it(':confirm quit with unedited files in arglist', function()
local screen = Screen.new(60, 6)
- screen:attach()
command('set nomore')
command('args a b c')
feed(':confirm quit\n')
diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua
index 8c3d73b17b..db27e19e50 100644
--- a/test/functional/legacy/breakindent_spec.lua
+++ b/test/functional/legacy/breakindent_spec.lua
@@ -17,7 +17,6 @@ describe('breakindent', function()
[1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue }, -- SignColumn
[2] = { bold = true }, -- ModeMsg
})
- screen:attach()
exec([[
set listchars=eol:$
let &signcolumn = 'yes'
@@ -68,7 +67,6 @@ describe('breakindent', function()
setlocal breakindent
call setline(1, "\t" .. join(range(100)))
]])
- screen:attach()
feed('v$')
screen:expect([[
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index 2e0e52117d..bf146e1322 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -15,7 +15,6 @@ describe('cmdline', function()
-- oldtest: Test_cmdlineclear_tabenter()
it('is cleared when switching tabs', function()
local screen = Screen.new(30, 10)
- screen:attach()
feed_command([[call setline(1, range(30))]])
screen:expect([[
@@ -79,7 +78,6 @@ describe('cmdline', function()
-- oldtest: Test_verbose_option()
it('prints every executed Ex command if verbose >= 16', function()
local screen = Screen.new(60, 12)
- screen:attach()
exec([[
command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
call feedkeys("\r", 't') " for the hit-enter prompt
@@ -104,7 +102,6 @@ describe('cmdline', function()
-- oldtest: Test_cmdline_redraw_tabline()
it('tabline is redrawn on entering cmdline', function()
local screen = Screen.new(30, 6)
- screen:attach()
exec([[
set showtabline=2
autocmd CmdlineEnter * set tabline=foo
@@ -121,7 +118,6 @@ describe('cmdline', function()
-- oldtest: Test_redraw_in_autocmd()
it('cmdline cursor position is correct after :redraw with cmdheight=2', function()
local screen = Screen.new(30, 6)
- screen:attach()
exec([[
set cmdheight=2
autocmd CmdlineChanged * redraw
@@ -143,11 +139,17 @@ describe('cmdline', function()
]])
end)
- it("setting 'cmdheight' works after outputting two messages vim-patch:9.0.0665", function()
+ -- oldtest: Test_changing_cmdheight()
+ it("changing 'cmdheight'", function()
local screen = Screen.new(60, 8)
- screen:attach()
exec([[
set cmdheight=1 laststatus=2
+ func EchoOne()
+ set laststatus=2 cmdheight=1
+ echo 'foo'
+ echo 'bar'
+ set cmdheight=2
+ endfunc
func EchoTwo()
set laststatus=2
set cmdheight=5
@@ -156,6 +158,8 @@ describe('cmdline', function()
set cmdheight=1
endfunc
]])
+
+ -- setting 'cmdheight' works after outputting two messages
feed(':call EchoTwo()')
screen:expect([[
|
@@ -170,12 +174,22 @@ describe('cmdline', function()
{3:[No Name] }|
|
]])
+
+ -- increasing 'cmdheight' doesn't clear the messages that need hit-enter
+ feed(':call EchoOne()<CR>')
+ screen:expect([[
+ |
+ {1:~ }|*3
+ {3: }|
+ foo |
+ bar |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
end)
-- oldtest: Test_cmdheight_tabline()
it("changing 'cmdheight' when there is a tabline", function()
local screen = Screen.new(60, 8)
- screen:attach()
api.nvim_set_option_value('laststatus', 2, {})
api.nvim_set_option_value('showtabline', 2, {})
api.nvim_set_option_value('cmdheight', 1, {})
@@ -191,7 +205,6 @@ describe('cmdline', function()
-- oldtest: Test_rulerformat_position()
it("ruler has correct position with 'rulerformat' set", function()
local screen = Screen.new(20, 3)
- screen:attach()
api.nvim_set_option_value('ruler', true, {})
api.nvim_set_option_value('rulerformat', 'longish', {})
api.nvim_set_option_value('laststatus', 0, {})
@@ -218,7 +231,6 @@ describe('cmdwin', function()
[3] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
[4] = { bold = true }, -- ModeMsg
})
- screen:attach()
command('set more')
command('autocmd WinNew * highlight')
feed('q:')
diff --git a/test/functional/legacy/conceal_spec.lua b/test/functional/legacy/conceal_spec.lua
index f4c1983bb7..66a99fe684 100644
--- a/test/functional/legacy/conceal_spec.lua
+++ b/test/functional/legacy/conceal_spec.lua
@@ -21,7 +21,6 @@ describe('Conceal', function()
-- oldtest: Test_conceal_two_windows()
it('works', function()
local screen = Screen.new(75, 12)
- screen:attach()
exec([[
let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"]
call setline(1, lines)
@@ -382,12 +381,9 @@ describe('Conceal', function()
-- oldtest: Test_conceal_with_cursorcolumn()
it('CursorColumn and ColorColumn on wrapped line', function()
local screen = Screen.new(40, 10)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { background = Screen.colors.Grey90 }, -- CursorColumn
- [2] = { background = Screen.colors.LightRed }, -- ColorColumn
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.LightRed },
+ }
-- Check that cursorcolumn and colorcolumn don't get broken in presence of
-- wrapped lines containing concealed text
-- luacheck: push ignore 613 (trailing whitespace in a string)
@@ -408,12 +404,12 @@ describe('Conceal', function()
-- luacheck: pop
screen:expect([[
- one one one one one one {1:o}ne |
- {0: >>> }one {2:o}ne one one |
+ one one one one one one {21:o}ne |
+ {1: >>> }one {100:o}ne one one |
two two two two |hidden| ^here two two |
- three three three three {1:t}hree |
- {0: >>> }thre{2:e} three three three |
- {0:~ }|*4
+ three three three three {21:t}hree |
+ {1: >>> }thre{100:e} three three three |
+ {1:~ }|*4
/here |
]])
@@ -421,11 +417,11 @@ describe('Conceal', function()
feed('$')
screen:expect([[
one one one one one one one |
- {0: >>> }one {2:o}ne one one |
+ {1: >>> }one {100:o}ne one one |
two two two two |hidden| here two tw^o |
three three three three three |
- {0: >>> }thre{2:e} three three three |
- {0:~ }|*4
+ {1: >>> }thre{100:e} three three three |
+ {1:~ }|*4
/here |
]])
end)
@@ -433,12 +429,9 @@ describe('Conceal', function()
-- oldtest: Test_conceal_wrapped_cursorline_wincolor()
it('CursorLine highlight on wrapped lines', function()
local screen = Screen.new(40, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { background = Screen.colors.Green }, -- CursorLine (low-priority)
- [2] = { foreground = Screen.colors.Red }, -- CursorLine (high-priority)
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.WebGreen },
+ }
exec([[
call setline(1, 'one one one |hidden| one one one one one one one one')
syntax match test /|hidden|/ conceal
@@ -447,16 +440,16 @@ describe('Conceal', function()
hi! CursorLine guibg=Green
]])
screen:expect([[
- {1:one one one one one one one on^e }|
- {1: one one one }|
- {0:~ }|
+ {100:one one one one one one one on^e }|
+ {100: one one one }|
+ {1:~ }|
|
]])
command('hi! CursorLine guibg=NONE guifg=Red')
screen:expect([[
- {2:one one one one one one one on^e }|
- {2: one one one }|
- {0:~ }|
+ {19:one one one one one one one on^e }|
+ {19: one one one }|
+ {1:~ }|
|
]])
end)
@@ -464,12 +457,9 @@ describe('Conceal', function()
-- oldtest: Test_conceal_wrapped_cursorline_wincolor_rightleft()
it('CursorLine highlight on wrapped lines with rightleft', function()
local screen = Screen.new(40, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { background = Screen.colors.Green }, -- CursorLine (low-priority)
- [2] = { foreground = Screen.colors.Red }, -- CursorLine (high-priority)
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.WebGreen },
+ }
exec([[
call setline(1, 'one one one |hidden| one one one one one one one one')
syntax match test /|hidden|/ conceal
@@ -478,16 +468,16 @@ describe('Conceal', function()
hi! CursorLine guibg=Green
]])
screen:expect([[
- {1: ^eno eno eno eno eno eno eno eno}|
- {1: eno eno eno }|
- {0: ~}|
+ {100: ^eno eno eno eno eno eno eno eno}|
+ {100: eno eno eno }|
+ {1: ~}|
|
]])
command('hi! CursorLine guibg=NONE guifg=Red')
screen:expect([[
- {2: ^eno eno eno eno eno eno eno eno}|
- {2: eno eno eno }|
- {0: ~}|
+ {19: ^eno eno eno eno eno eno eno eno}|
+ {19: eno eno eno }|
+ {1: ~}|
|
]])
end)
@@ -495,7 +485,6 @@ describe('Conceal', function()
-- oldtest: Test_conceal_resize_term()
it('resize editor', function()
local screen = Screen.new(75, 6)
- screen:attach()
exec([[
call setline(1, '`one` `two` `three` `four` `five`, the backticks should be concealed')
setl cocu=n cole=3
@@ -519,7 +508,6 @@ describe('Conceal', function()
-- oldtest: Test_conceal_linebreak()
it('with linebreak', function()
local screen = Screen.new(75, 8)
- screen:attach()
exec([[
let &wrap = v:true
let &conceallevel = 2
@@ -625,10 +613,6 @@ describe('Conceal', function()
local function test_conceal_virtualedit_after_eol(wrap)
local screen = Screen.new(60, 3)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- })
- screen:attach()
api.nvim_set_option_value('wrap', wrap, {})
exec([[
call setline(1, 'abcdefgh|hidden|ijklmnpop')
@@ -638,31 +622,31 @@ describe('Conceal', function()
]])
screen:expect([[
abcdefghijklmnpo^p |
- {0:~ }|
+ {1:~ }|
|
]])
feed('l')
screen:expect([[
abcdefghijklmnpop^ |
- {0:~ }|
+ {1:~ }|
|
]])
feed('l')
screen:expect([[
abcdefghijklmnpop ^ |
- {0:~ }|
+ {1:~ }|
|
]])
feed('l')
screen:expect([[
abcdefghijklmnpop ^ |
- {0:~ }|
+ {1:~ }|
|
]])
feed('rr')
screen:expect([[
abcdefghijklmnpop ^r |
- {0:~ }|
+ {1:~ }|
|
]])
end
@@ -679,10 +663,6 @@ describe('Conceal', function()
local function test_conceal_virtualedit_after_eol_rightleft(wrap)
local screen = Screen.new(60, 3)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- })
- screen:attach()
api.nvim_set_option_value('wrap', wrap, {})
exec([[
call setline(1, 'abcdefgh|hidden|ijklmnpop')
@@ -692,31 +672,31 @@ describe('Conceal', function()
]])
screen:expect([[
^popnmlkjihgfedcba|
- {0: ~}|
+ {1: ~}|
|
]])
feed('h')
screen:expect([[
^ popnmlkjihgfedcba|
- {0: ~}|
+ {1: ~}|
|
]])
feed('h')
screen:expect([[
^ popnmlkjihgfedcba|
- {0: ~}|
+ {1: ~}|
|
]])
feed('h')
screen:expect([[
^ popnmlkjihgfedcba|
- {0: ~}|
+ {1: ~}|
|
]])
feed('rr')
screen:expect([[
^r popnmlkjihgfedcba|
- {0: ~}|
+ {1: ~}|
|
]])
end
@@ -733,12 +713,9 @@ describe('Conceal', function()
local function test_conceal_double_width(wrap)
local screen = Screen.new(60, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey },
- [2] = { background = Screen.colors.LightRed },
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.LightRed },
+ }
api.nvim_set_option_value('wrap', wrap, {})
exec([[
call setline(1, ['aaaaa口=口bbbbb口=口ccccc', 'foobar'])
@@ -747,30 +724,30 @@ describe('Conceal', function()
normal! $
]])
screen:expect([[
- aaaaa{1:β}bbbbb{1:β}cccc^c {2: } |
- foobar {2: } |
- {0:~ }|
+ aaaaa{14:β}bbbbb{14:β}cccc^c {100: } |
+ foobar {100: } |
+ {1:~ }|
|
]])
feed('gM')
screen:expect([[
- aaaaa{1:β}bb^bbb{1:β}ccccc {2: } |
- foobar {2: } |
- {0:~ }|
+ aaaaa{14:β}bb^bbb{14:β}ccccc {100: } |
+ foobar {100: } |
+ {1:~ }|
|
]])
command('set conceallevel=3')
screen:expect([[
- aaaaabb^bbbccccc {2: } |
- foobar {2: } |
- {0:~ }|
+ aaaaabb^bbbccccc {100: } |
+ foobar {100: } |
+ {1:~ }|
|
]])
feed('$')
screen:expect([[
- aaaaabbbbbcccc^c {2: } |
- foobar {2: } |
- {0:~ }|
+ aaaaabbbbbcccc^c {100: } |
+ foobar {100: } |
+ {1:~ }|
|
]])
end
@@ -788,12 +765,9 @@ describe('Conceal', function()
-- oldtest: Test_conceal_double_width_wrap()
it('line wraps correctly when double-width chars are concealed', function()
local screen = Screen.new(20, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey },
- [2] = { background = Screen.colors.LightRed },
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.LightRed },
+ }
exec([[
call setline(1, 'aaaaaaaaaa口=口bbbbbbbbbb口=口cccccccccc')
syntax match test /口=口/ conceal cchar=β
@@ -801,30 +775,30 @@ describe('Conceal', function()
normal! $
]])
screen:expect([[
- aaaaaaaaaa{1:β}bbbbb |
- bbbbb{1:β}ccccccccc^c |
- {0:~ }|
+ aaaaaaaaaa{14:β}bbbbb |
+ bbbbb{14:β}ccccccccc^c |
+ {1:~ }|
|
]])
feed('gM')
screen:expect([[
- aaaaaaaaaa{1:β}bbbbb |
- ^bbbbb{1:β}cccccccccc |
- {0:~ }|
+ aaaaaaaaaa{14:β}bbbbb |
+ ^bbbbb{14:β}cccccccccc |
+ {1:~ }|
|
]])
command('set conceallevel=3')
screen:expect([[
aaaaaaaaaabbbbb |
^bbbbbcccccccccc |
- {0:~ }|
+ {1:~ }|
|
]])
feed('$')
screen:expect([[
aaaaaaaaaabbbbb |
bbbbbccccccccc^c |
- {0:~ }|
+ {1:~ }|
|
]])
end)
diff --git a/test/functional/legacy/cpoptions_spec.lua b/test/functional/legacy/cpoptions_spec.lua
index 56b0e72c72..bd1390c874 100644
--- a/test/functional/legacy/cpoptions_spec.lua
+++ b/test/functional/legacy/cpoptions_spec.lua
@@ -10,7 +10,6 @@ before_each(clear)
describe('cpoptions', function()
it('$', function()
local screen = Screen.new(30, 6)
- screen:attach()
command('set cpo+=$')
command([[call setline(1, 'one two three')]])
feed('c2w')
diff --git a/test/functional/legacy/debugger_spec.lua b/test/functional/legacy/debugger_spec.lua
index c6f552ab51..624e797f1c 100644
--- a/test/functional/legacy/debugger_spec.lua
+++ b/test/functional/legacy/debugger_spec.lua
@@ -14,7 +14,6 @@ describe('debugger', function()
before_each(function()
screen = Screen.new(999, 10)
- screen:attach()
end)
-- oldtest: Test_Debugger_breakadd_expr()
diff --git a/test/functional/legacy/digraph_spec.lua b/test/functional/legacy/digraph_spec.lua
index ed1071079c..a90eb48f17 100644
--- a/test/functional/legacy/digraph_spec.lua
+++ b/test/functional/legacy/digraph_spec.lua
@@ -10,7 +10,6 @@ describe('digraph', function()
-- oldtest: Test_entering_digraph()
it('characters displayed on the screen', function()
local screen = Screen.new(10, 6)
- screen:attach()
feed('i<C-K>')
screen:expect([[
{18:^?} |
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index 98b9596847..945cd21710 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -12,7 +12,6 @@ describe('display', function()
-- oldtest: Test_display_scroll_at_topline()
it('scroll when modified at topline vim-patch:8.2.1488', function()
local screen = Screen.new(20, 4)
- screen:attach()
command([[call setline(1, repeat('a', 21))]])
feed('O')
@@ -27,7 +26,6 @@ describe('display', function()
-- oldtest: Test_display_scroll_update_visual()
it('scrolling when modified at topline in Visual mode vim-patch:8.2.4626', function()
local screen = Screen.new(60, 8)
- screen:attach()
exec([[
set scrolloff=0
@@ -52,7 +50,6 @@ describe('display', function()
[2] = { bold = true, reverse = true }, -- StatusLine
[3] = { reverse = true }, -- StatusLineNC
})
- screen:attach()
exec([[
call setline(1, ['aaa', 'b'->repeat(200)])
set display=truncate
@@ -131,7 +128,6 @@ describe('display', function()
-- oldtest: Test_display_long_lastline()
it('"lastline" shows correct text when end of wrapped line is deleted', function()
local screen = Screen.new(35, 14)
- screen:attach()
exec([[
set display=lastline smoothscroll scrolloff=0
call setline(1, [
@@ -183,7 +179,6 @@ describe('display', function()
-- oldtest: Test_display_cursor_long_line()
it("correctly shows line that doesn't fit in the window", function()
local screen = Screen.new(75, 8)
- screen:attach()
exec([[
call setline(1, ['a', 'b ' .. 'bbbbb'->repeat(150), 'c'])
norm $j
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index 2d98188f9b..d2ce80efda 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -31,7 +31,6 @@ describe('edit', function()
-- oldtest: Test_edit_insert_reg()
it('inserting a register using CTRL-R', function()
local screen = Screen.new(10, 6)
- screen:attach()
feed('a<C-R>')
screen:expect([[
{18:^"} |
@@ -55,7 +54,6 @@ describe('edit', function()
-- oldtest: Test_edit_ctrl_r_failed()
it('positioning cursor after CTRL-R expression failed', function()
local screen = Screen.new(60, 6)
- screen:attach()
feed('i<C-R>')
screen:expect([[
diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua
index e033898d7a..af4490e7f2 100644
--- a/test/functional/legacy/ex_mode_spec.lua
+++ b/test/functional/legacy/ex_mode_spec.lua
@@ -47,7 +47,6 @@ describe('Ex mode', function()
it('substitute confirmation prompt', function()
command('set noincsearch nohlsearch inccommand=')
local screen = Screen.new(60, 6)
- screen:attach()
command([[call setline(1, repeat(['foo foo'], 4))]])
command([[set number]])
feed('gQ')
@@ -134,7 +133,6 @@ describe('Ex mode', function()
it('pressing Ctrl-C in :append inside a loop in Ex mode does not hang', function()
local screen = Screen.new(60, 6)
- screen:attach()
feed('gQ')
feed('for i in range(1)<CR>')
feed('append<CR>')
diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua
index 753a45ee05..24b648c3c5 100644
--- a/test/functional/legacy/excmd_spec.lua
+++ b/test/functional/legacy/excmd_spec.lua
@@ -19,7 +19,6 @@ describe(':confirm command dialog', function()
local function start_new()
clear()
screen = Screen.new(75, 20)
- screen:attach()
end
-- Test for the :confirm command dialog
diff --git a/test/functional/legacy/fold_spec.lua b/test/functional/legacy/fold_spec.lua
index 4fea1ef113..2bad70e384 100644
--- a/test/functional/legacy/fold_spec.lua
+++ b/test/functional/legacy/fold_spec.lua
@@ -14,7 +14,6 @@ describe('folding', function()
n.clear()
screen = Screen.new(45, 8)
- screen:attach()
end)
it('creation, opening, moving (to the end) and closing', function()
diff --git a/test/functional/legacy/global_spec.lua b/test/functional/legacy/global_spec.lua
index 718fd421b0..a39e7d5d38 100644
--- a/test/functional/legacy/global_spec.lua
+++ b/test/functional/legacy/global_spec.lua
@@ -12,7 +12,6 @@ describe(':global', function()
-- oldtest: Test_interrupt_global()
it('can be interrupted using Ctrl-C in cmdline mode vim-patch:9.0.0082', function()
local screen = Screen.new(75, 6)
- screen:attach()
exec([[
set nohlsearch noincsearch
diff --git a/test/functional/legacy/highlight_spec.lua b/test/functional/legacy/highlight_spec.lua
index 35afd9bb4a..e663931bd7 100644
--- a/test/functional/legacy/highlight_spec.lua
+++ b/test/functional/legacy/highlight_spec.lua
@@ -15,7 +15,6 @@ before_each(clear)
describe(':highlight', function()
it('is working', function()
local screen = Screen.new(35, 10)
- screen:attach()
-- Basic test if ":highlight" doesn't crash
feed_command('set more')
feed(':highlight<CR>')
@@ -101,7 +100,6 @@ describe('Visual selection highlight', function()
-- oldtest: Test_visual_sbr()
it("when 'showbreak' is set", function()
local screen = Screen.new(60, 6)
- screen:attach()
exec([[
set showbreak=>
call setline(1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.')
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index db9ec7fc9d..b4d07e03ef 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -103,7 +103,6 @@ describe("'listchars'", function()
it('"exceeds" character does not appear in foldcolumn vim-patch:8.2.3121', function()
local screen = Screen.new(60, 10)
- screen:attach()
exec([[
call setline(1, ['aaa', '', 'a', 'aaaaaa'])
vsplit
diff --git a/test/functional/legacy/listlbr_spec.lua b/test/functional/legacy/listlbr_spec.lua
index da641c3b6f..09835bf97d 100644
--- a/test/functional/legacy/listlbr_spec.lua
+++ b/test/functional/legacy/listlbr_spec.lua
@@ -205,7 +205,6 @@ describe('listlbr', function()
-- oldtest: Test_linebreak_reset_restore()
it('cursor position is drawn correctly after operator', function()
local screen = Screen.new(60, 6)
- screen:attach()
-- f_wincol() calls validate_cursor()
source([[
diff --git a/test/functional/legacy/listlbr_utf8_spec.lua b/test/functional/legacy/listlbr_utf8_spec.lua
index 74cc594cc1..3a0aa7b2b3 100644
--- a/test/functional/legacy/listlbr_utf8_spec.lua
+++ b/test/functional/legacy/listlbr_utf8_spec.lua
@@ -215,7 +215,6 @@ describe('linebreak', function()
-- oldtest: Test_visual_ends_before_showbreak()
it("Visual area is correct when it ends before multibyte 'showbreak'", function()
local screen = Screen.new(60, 8)
- screen:attach()
exec([[
let &wrap = v:true
let &linebreak = v:true
diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua
index 3fc324f66a..8593868c83 100644
--- a/test/functional/legacy/mapping_spec.lua
+++ b/test/functional/legacy/mapping_spec.lua
@@ -196,7 +196,6 @@ describe('mapping', function()
-- oldtest: Test_showcmd_part_map()
it("'showcmd' with a partial mapping", function()
local screen = Screen.new(60, 6)
- screen:attach()
exec([[
set notimeout showcmd
nnoremap ,a <Ignore>
diff --git a/test/functional/legacy/match_spec.lua b/test/functional/legacy/match_spec.lua
index 0fc8708244..64e223ab8c 100644
--- a/test/functional/legacy/match_spec.lua
+++ b/test/functional/legacy/match_spec.lua
@@ -11,7 +11,6 @@ describe('matchaddpos()', function()
-- oldtest: Test_matchaddpos_dump()
it('can add more than 8 match positions vim-patch:9.0.0620', function()
local screen = Screen.new(60, 14)
- screen:attach()
exec([[
call setline(1, ['1234567890123']->repeat(14))
call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
@@ -39,7 +38,6 @@ describe('match highlighting', function()
-- oldtest: Test_match_in_linebreak()
it('does not continue in linebreak vim-patch:8.2.3698', function()
local screen = Screen.new(75, 10)
- screen:attach()
exec([=[
set breakindent linebreak breakat+=]
call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1)
@@ -55,7 +53,6 @@ describe('match highlighting', function()
it('is shown with incsearch vim-patch:8.2.3940', function()
local screen = Screen.new(75, 6)
- screen:attach()
exec([[
set incsearch
call setline(1, range(20))
@@ -82,7 +79,6 @@ describe('match highlighting', function()
it('on a Tab vim-patch:8.2.4062', function()
local screen = Screen.new(75, 10)
- screen:attach()
exec([[
set linebreak
call setline(1, "\tix")
diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua
index df0d80f0ab..d992420c30 100644
--- a/test/functional/legacy/matchparen_spec.lua
+++ b/test/functional/legacy/matchparen_spec.lua
@@ -11,7 +11,6 @@ describe('matchparen', function()
-- oldtest: Test_visual_block_scroll()
it('redraws properly after scrolling with scrolloff=1', function()
local screen = Screen.new(30, 7)
- screen:attach()
exec([[
source $VIMRUNTIME/plugin/matchparen.vim
set scrolloff=1
@@ -34,20 +33,18 @@ describe('matchparen', function()
-- oldtest: Test_matchparen_clear_highlight()
it('matchparen highlight is cleared when switching buffer', function()
local screen = Screen.new(20, 5)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.Cyan },
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Cyan1 },
+ }
local screen1 = [[
- {1:^()} |
- {0:~ }|*3
+ {100:^()} |
+ {1:~ }|*3
|
]]
local screen2 = [[
^aa |
- {0:~ }|*3
+ {1:~ }|*3
|
]]
@@ -77,12 +74,9 @@ describe('matchparen', function()
-- oldtest: Test_matchparen_win_execute()
it('matchparen highlight when switching buffer in win_execute()', function()
local screen = Screen.new(20, 5)
- screen:set_default_attr_ids({
- [1] = { background = Screen.colors.Cyan },
- [2] = { reverse = true, bold = true },
- [3] = { reverse = true },
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Cyan1 },
+ }
exec([[
source $VIMRUNTIME/plugin/matchparen.vim
@@ -95,10 +89,10 @@ describe('matchparen', function()
endfunc
]])
screen:expect([[
- {1:^{}} |
- {2:[No Name] [+] }|
- {} |
+ {100:^{}} |
{3:[No Name] [+] }|
+ {} |
+ {2:[No Name] [+] }|
|
]])
@@ -110,7 +104,6 @@ describe('matchparen', function()
-- oldtest: Test_matchparen_pum_clear()
it('is cleared when completion popup is shown', function()
local screen = Screen.new(30, 9)
- screen:attach()
exec([[
source $VIMRUNTIME/plugin/matchparen.vim
@@ -136,12 +129,9 @@ describe('matchparen', function()
-- oldtest: Test_matchparen_mbyte()
it("works with multibyte chars in 'matchpairs'", function()
local screen = Screen.new(30, 10)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.Cyan },
- [2] = { bold = true },
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Cyan1 },
+ }
exec([[
source $VIMRUNTIME/plugin/matchparen.vim
@@ -152,57 +142,57 @@ describe('matchparen', function()
screen:expect([[
^aaaaaaaa( |
bbbb)cc |
- {0:~ }|*7
+ {1:~ }|*7
|
]])
feed('$')
screen:expect([[
- aaaaaaaa{1:^(} |
- bbbb{1:)}cc |
- {0:~ }|*7
+ aaaaaaaa{100:^(} |
+ bbbb{100:)}cc |
+ {1:~ }|*7
|
]])
feed('j')
screen:expect([[
aaaaaaaa( |
bbbb)c^c |
- {0:~ }|*7
+ {1:~ }|*7
|
]])
feed('2h')
screen:expect([[
- aaaaaaaa{1:(} |
- bbbb{1:^)}cc |
- {0:~ }|*7
+ aaaaaaaa{100:(} |
+ bbbb{100:^)}cc |
+ {1:~ }|*7
|
]])
feed('0')
screen:expect([[
aaaaaaaa( |
^bbbb)cc |
- {0:~ }|*7
+ {1:~ }|*7
|
]])
feed('kA')
screen:expect([[
- aaaaaaaa{1:(}^ |
- bbbb{1:)}cc |
- {0:~ }|*7
- {2:-- INSERT --} |
+ aaaaaaaa{100:(}^ |
+ bbbb{100:)}cc |
+ {1:~ }|*7
+ {5:-- INSERT --} |
]])
feed('<Down>')
screen:expect([[
aaaaaaaa( |
bbbb)cc^ |
- {0:~ }|*7
- {2:-- INSERT --} |
+ {1:~ }|*7
+ {5:-- INSERT --} |
]])
feed('<C-W>')
screen:expect([[
- aaaaaaaa{1:(} |
- bbbb{1:)}^ |
- {0:~ }|*7
- {2:-- INSERT --} |
+ aaaaaaaa{100:(} |
+ bbbb{100:)}^ |
+ {1:~ }|*7
+ {5:-- INSERT --} |
]])
end)
end)
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
index 2f3693b5ad..bc58551a34 100644
--- a/test/functional/legacy/messages_spec.lua
+++ b/test/functional/legacy/messages_spec.lua
@@ -17,7 +17,6 @@ describe('messages', function()
-- oldtest: Test_warning_scroll()
it('a warning causes scrolling if and only if it has a stacktrace', function()
screen = Screen.new(75, 6)
- screen:attach()
-- When the warning comes from a script, messages are scrolled so that the
-- stacktrace is visible.
@@ -45,7 +44,6 @@ describe('messages', function()
-- oldtest: Test_message_not_cleared_after_mode()
it('clearing mode does not remove message', function()
screen = Screen.new(60, 10)
- screen:attach()
exec([[
nmap <silent> gx :call DebugSilent('normal')<CR>
vmap <silent> gx :call DebugSilent('visual')<CR>
@@ -101,7 +99,6 @@ describe('messages', function()
[1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
[2] = { foreground = Screen.colors.Brown }, -- LineNr
})
- screen:attach()
command('call setline(1, range(1, 100))')
@@ -394,7 +391,6 @@ describe('messages', function()
-- oldtest: Test_echo_verbose_system()
it('verbose message before echo command', function()
screen = Screen.new(60, 10)
- screen:attach()
command('cd ' .. nvim_dir)
api.nvim_set_option_value('shell', './shell-test', {})
@@ -494,7 +490,6 @@ describe('messages', function()
-- oldtest: Test_quit_long_message()
it('with control characters can be quit vim-patch:8.2.1844', function()
screen = Screen.new(40, 10)
- screen:attach()
feed([[:echom range(9999)->join("\x01")<CR>]])
screen:expect([[
@@ -521,7 +516,6 @@ describe('messages', function()
describe('mode is cleared when', function()
before_each(function()
screen = Screen.new(40, 6)
- screen:attach()
end)
-- oldtest: Test_mode_message_at_leaving_insert_by_ctrl_c()
@@ -591,7 +585,6 @@ describe('messages', function()
-- oldtest: Test_ask_yesno()
it('y/n prompt works', function()
screen = Screen.new(75, 6)
- screen:attach()
command('set noincsearch nohlsearch inccommand=')
command('call setline(1, range(1, 2))')
@@ -644,7 +637,6 @@ describe('messages', function()
-- oldtest: Test_fileinfo_tabpage_cmdheight()
it("fileinfo works when 'cmdheight' has just decreased", function()
screen = Screen.new(40, 6)
- screen:attach()
exec([[
set shortmess-=o
@@ -673,7 +665,6 @@ describe('messages', function()
-- oldtest: Test_fileinfo_after_echo()
it('fileinfo does not overwrite echo message vim-patch:8.2.4156', function()
screen = Screen.new(40, 6)
- screen:attach()
exec([[
set shortmess-=F
diff --git a/test/functional/legacy/move_spec.lua b/test/functional/legacy/move_spec.lua
index c2be8bb3eb..ae01193049 100644
--- a/test/functional/legacy/move_spec.lua
+++ b/test/functional/legacy/move_spec.lua
@@ -11,7 +11,6 @@ describe(':move', function()
-- oldtest: Test_move_undo()
it('redraws correctly when undone', function()
local screen = Screen.new(60, 10)
- screen:attach()
fn.setline(1, { 'First', 'Second', 'Third', 'Fourth' })
feed('gg:move +1<CR>')
diff --git a/test/functional/legacy/normal_spec.lua b/test/functional/legacy/normal_spec.lua
index 5158ca3009..1ae22a83bd 100644
--- a/test/functional/legacy/normal_spec.lua
+++ b/test/functional/legacy/normal_spec.lua
@@ -15,7 +15,6 @@ describe('normal', function()
before_each(function()
clear()
screen = Screen.new(40, 19)
- screen:attach()
end)
-- oldtest: Test_normal_j_below_botline()
@@ -103,4 +102,33 @@ describe('normal', function()
]],
})
end)
+
+ -- oldtest: Test_normal_gm()
+ it('gm sets curswant correctly', function()
+ screen:try_resize(75, 10)
+ exec([[
+ call setline(1, repeat([" abcd\tefgh\tij"], 10))
+ call cursor(1, 1)
+ ]])
+ feed('jVjzf')
+ -- gm
+ feed('gmk')
+ eq(18, fn.virtcol('.'))
+ -- g0
+ feed('gj0k')
+ eq(1, fn.virtcol('.'))
+ -- g^
+ feed('jg^k')
+ eq(3, fn.virtcol('.'))
+ exec('call cursor(10, 1)')
+ -- gm
+ feed('gmk')
+ eq(18, fn.virtcol('.'))
+ -- g0
+ feed('gj0k')
+ eq(1, fn.virtcol('.'))
+ -- g^
+ feed('jg^k')
+ eq(3, fn.virtcol('.'))
+ end)
end)
diff --git a/test/functional/legacy/number_spec.lua b/test/functional/legacy/number_spec.lua
index 0ebd731f65..4636cd0369 100644
--- a/test/functional/legacy/number_spec.lua
+++ b/test/functional/legacy/number_spec.lua
@@ -17,7 +17,6 @@ describe("'number' and 'relativenumber'", function()
[2] = { foreground = Screen.colors.Blue },
[3] = { foreground = Screen.colors.Green },
})
- screen:attach()
exec([[
call setline(1, range(200))
111
@@ -86,7 +85,6 @@ describe("'number' and 'relativenumber'", function()
[3] = { background = Screen.colors.Green, foreground = Screen.colors.Black },
[4] = { bold = true, foreground = Screen.colors.Blue },
})
- screen:attach()
exec([[
set display=lastline scrolloff=0
call setline(1, range(200)->map('v:val->string()->repeat(40)'))
@@ -215,7 +213,6 @@ describe("'number' and 'relativenumber'", function()
-- oldtest: Test_relativenumber_callback()
it('relative line numbers are updated if cursor is moved from timer', function()
local screen = Screen.new(50, 8)
- screen:attach()
exec([[
call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
set relativenumber
@@ -253,7 +250,6 @@ describe("'number' and 'relativenumber'", function()
-- oldtest: Test_number_insert_delete_lines()
it('line numbers are updated when deleting/inserting lines', function()
local screen = Screen.new(50, 8)
- screen:attach()
exec([[
call setline(1, range(1, 7))
set number
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index e9a3b73cf7..fa84e0db66 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -32,8 +32,7 @@ describe('set', function()
end)
it('winminheight works', function()
- local screen = Screen.new(20, 11)
- screen:attach()
+ local _ = Screen.new(20, 11)
source([[
set wmh=0 stal=2
below sp | wincmd _
@@ -45,8 +44,7 @@ describe('set', function()
end)
it('winminheight works with tabline', function()
- local screen = Screen.new(20, 11)
- screen:attach()
+ local _ = Screen.new(20, 11)
source([[
set wmh=0 stal=2
split
@@ -60,7 +58,6 @@ describe('set', function()
it('scroll works', function()
local screen = Screen.new(42, 16)
- screen:attach()
source([[
set scroll=2
set laststatus=2
diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
index 72ec420b15..6a4d5fe7f7 100644
--- a/test/functional/legacy/prompt_buffer_spec.lua
+++ b/test/functional/legacy/prompt_buffer_spec.lua
@@ -18,7 +18,6 @@ describe('prompt buffer', function()
before_each(function()
clear()
screen = Screen.new(25, 10)
- screen:attach()
command('set laststatus=0 nohidden')
end)
@@ -68,10 +67,6 @@ describe('prompt buffer', function()
]])
end
- after_each(function()
- screen:detach()
- end)
-
-- oldtest: Test_prompt_basic()
it('works', function()
source_script()
diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
index 8b9b495679..2656142176 100644
--- a/test/functional/legacy/put_spec.lua
+++ b/test/functional/legacy/put_spec.lua
@@ -10,7 +10,6 @@ describe('put', function()
-- oldtest: Test_put_other_window()
it('above topline in buffer in two splits', function()
local screen = Screen.new(80, 10)
- screen:attach()
source([[
40vsplit
0put ='some text at the top'
@@ -36,7 +35,6 @@ describe('put', function()
-- oldtest: Test_put_in_last_displayed_line()
it('in last displayed line', function()
local screen = Screen.new(75, 10)
- screen:attach()
source([[
autocmd CursorMoved * eval line('w$')
let @a = 'x'->repeat(&columns * 2 - 2)
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index ec1dc59d53..a92b95731e 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -13,7 +13,6 @@ describe('smoothscroll', function()
before_each(function()
screen = Screen.new(40, 12)
- screen:attach()
end)
-- oldtest: Test_CtrlE_CtrlY_stop_at_end()
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index d421a96579..db7d6bc34b 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -18,7 +18,6 @@ describe('search cmdline', function()
clear()
command('set nohlsearch inccommand=')
screen = Screen.new(20, 3)
- screen:attach()
screen:set_default_attr_ids({
inc = { reverse = true },
err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
@@ -747,7 +746,6 @@ describe('Search highlight', function()
-- oldtest: Test_hlsearch_dump()
it('beyond line end vim-patch:8.2.2542', function()
local screen = Screen.new(50, 6)
- screen:attach()
exec([[
set hlsearch noincsearch cursorline
call setline(1, ["xxx", "xxx", "xxx"])
@@ -773,7 +771,6 @@ describe('Search highlight', function()
[4] = { background = Screen.colors.Yellow, bold = true }, -- Search
[5] = { background = Screen.colors.LightGrey, bold = true, foreground = Screen.colors.Black },
})
- screen:attach()
exec([[
set hlsearch noincsearch
call setline(1, repeat(["xxx yyy zzz"], 3))
diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua
index 7779b8bef1..1ffae89b0c 100644
--- a/test/functional/legacy/search_stat_spec.lua
+++ b/test/functional/legacy/search_stat_spec.lua
@@ -15,7 +15,6 @@ describe('search stat', function()
[4] = { reverse = true }, -- IncSearch, TabLineFill
[5] = { foreground = Screen.colors.Red }, -- WarningMsg
})
- screen:attach()
end)
-- oldtest: Test_search_stat_screendump()
diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua
index 27145f4c91..ac7c8cd0bc 100644
--- a/test/functional/legacy/signs_spec.lua
+++ b/test/functional/legacy/signs_spec.lua
@@ -26,7 +26,6 @@ describe('signs', function()
-- oldtest: Test_sign_cursor_position()
it('are drawn correctly', function()
local screen = Screen.new(75, 6)
- screen:attach()
exec([[
call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
call cursor(2,1)
diff --git a/test/functional/legacy/source_spec.lua b/test/functional/legacy/source_spec.lua
index a910dc3d43..7358ba2d57 100644
--- a/test/functional/legacy/source_spec.lua
+++ b/test/functional/legacy/source_spec.lua
@@ -18,7 +18,6 @@ describe(':source!', function()
]]
)
local screen = Screen.new(75, 6)
- screen:attach()
feed(':source! Xscript.vim\n')
screen:expect([[
^ |
diff --git a/test/functional/legacy/statusline_spec.lua b/test/functional/legacy/statusline_spec.lua
index 148166fdc3..0bc77fe67e 100644
--- a/test/functional/legacy/statusline_spec.lua
+++ b/test/functional/legacy/statusline_spec.lua
@@ -12,7 +12,6 @@ describe('statusline', function()
before_each(function()
screen = Screen.new(50, 7)
- screen:attach()
end)
it('is updated in cmdline mode when using window-local statusline vim-patch:8.2.2737', function()
diff --git a/test/functional/legacy/substitute_spec.lua b/test/functional/legacy/substitute_spec.lua
index 647d62782c..0081371f7f 100644
--- a/test/functional/legacy/substitute_spec.lua
+++ b/test/functional/legacy/substitute_spec.lua
@@ -211,7 +211,6 @@ describe(':substitute', function()
it('first char is highlighted with confirmation dialog and empty match', function()
local screen = Screen.new(60, 8)
- screen:attach()
exec([[
set nohlsearch noincsearch
call setline(1, ['one', 'two', 'three'])
diff --git a/test/functional/legacy/tabline_spec.lua b/test/functional/legacy/tabline_spec.lua
index 4ce32f2fdd..949bec6dea 100644
--- a/test/functional/legacy/tabline_spec.lua
+++ b/test/functional/legacy/tabline_spec.lua
@@ -12,7 +12,6 @@ describe('tabline', function()
before_each(function()
screen = Screen.new(50, 7)
- screen:attach()
end)
-- oldtest: Test_tabline_showcmd()
diff --git a/test/functional/legacy/vimscript_spec.lua b/test/functional/legacy/vimscript_spec.lua
index 66054810a6..e2e3493be8 100644
--- a/test/functional/legacy/vimscript_spec.lua
+++ b/test/functional/legacy/vimscript_spec.lua
@@ -12,7 +12,6 @@ describe('Vim script', function()
-- oldtest: Test_deep_nest()
it('Error when if/for/while/try/function is nested too deep', function()
local screen = Screen.new(80, 24)
- screen:attach()
api.nvim_set_option_value('laststatus', 2, {})
exec([[
" Deep nesting of if ... endif
@@ -84,7 +83,6 @@ describe('Vim script', function()
-- oldtest: Test_typed_script_var()
it('using s: with a typed command', function()
local screen = Screen.new(80, 24)
- screen:attach()
feed(":echo get(s:, 'foo', 'x')\n")
screen:expect({ any = 'E116: ' })
end)
diff --git a/test/functional/legacy/visual_spec.lua b/test/functional/legacy/visual_spec.lua
index ab2213b2fc..e52d12bba9 100644
--- a/test/functional/legacy/visual_spec.lua
+++ b/test/functional/legacy/visual_spec.lua
@@ -12,7 +12,6 @@ describe('Visual highlight', function()
before_each(function()
screen = Screen.new(50, 6)
- screen:attach()
end)
-- oldtest: Test_visual_block_with_virtualedit()
diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua
index 332240d04a..d68c780f49 100644
--- a/test/functional/legacy/window_cmd_spec.lua
+++ b/test/functional/legacy/window_cmd_spec.lua
@@ -11,7 +11,6 @@ local feed = n.feed
it('scrolling with laststatus=0 and :botright split', function()
clear('--cmd', 'set ruler')
local screen = Screen.new(40, 10)
- screen:attach()
exec([[
set laststatus=0
call setline(1, range(1, 100))
@@ -38,7 +37,6 @@ describe('splitkeep', function()
before_each(function()
clear('--cmd', 'set splitkeep=screen')
screen = Screen.new()
- screen:attach()
end)
-- oldtest: Test_splitkeep_cursor()
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index f277868b1c..7d034222c8 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -344,7 +344,6 @@ describe('lua buffer event callbacks: on_lines', function()
it('setting extmark in on_lines callback works', function()
local screen = Screen.new(40, 6)
- screen:attach()
api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' })
exec_lua(function()
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index 456ee13da2..1fd01cfd5a 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -111,7 +111,6 @@ describe(':lua', function()
it('can show multiline error messages', function()
local screen = Screen.new(40, 10)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { bold = true, reverse = true },
@@ -204,7 +203,6 @@ describe(':lua', function()
it('with range', function()
local screen = Screen.new(40, 10)
- screen:attach()
api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' })
-- ":{range}lua" fails on invalid Lua code.
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 4ae1146703..eb1ac3e6a1 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -111,6 +111,19 @@ describe('vim.diagnostic', function()
{ details = true }
)
end
+
+ ---@param ns integer
+ function _G.get_underline_extmarks(ns)
+ ---@type integer
+ local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns
+ return vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ underline_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ end
end)
exec_lua(function()
@@ -1813,6 +1826,21 @@ describe('vim.diagnostic', function()
_G.make_info('Info', 4, 4, 4, 4),
})
+ function _G.get_highest_underline_hl(severity_sort)
+ vim.diagnostic.config({
+ underline = true,
+ severity_sort = severity_sort,
+ })
+
+ local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns)
+
+ table.sort(extmarks, function(a, b)
+ return a[4].priority > b[4].priority
+ end)
+
+ return extmarks[1][4].hl_group
+ end
+
function _G.get_virt_text_and_signs(severity_sort)
vim.diagnostic.config({
severity_sort = severity_sort,
@@ -1864,6 +1892,12 @@ describe('vim.diagnostic', function()
result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]]
eq({ 'Error', 'Warn', 'Info' }, result[1])
eq({ 'Info', 'Warn', 'Error' }, result[2])
+
+ local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]]
+ eq('DiagnosticUnderlineError', underline_hl)
+
+ underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]]
+ eq('DiagnosticUnderlineInfo', underline_hl)
end)
it('can show diagnostic sources in virtual text', function()
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 574c837f92..b6011d5268 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -161,6 +161,18 @@ describe('vim.filetype', function()
end
end
end)
+
+ it('.get_option() cleans up buffer on error', function()
+ api.nvim_create_autocmd('FileType', { pattern = 'foo', command = 'lua error()' })
+
+ local buf = api.nvim_get_current_buf()
+
+ exec_lua(function()
+ pcall(vim.filetype.get_option, 'foo', 'lisp')
+ end)
+
+ eq(buf, api.nvim_get_current_buf())
+ end)
end)
describe('filetype.lua', function()
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/hl_spec.lua
index c048949df8..89881973bf 100644
--- a/test/functional/lua/highlight_spec.lua
+++ b/test/functional/lua/hl_spec.lua
@@ -9,7 +9,7 @@ local command = n.command
local clear = n.clear
local api = n.api
-describe('vim.highlight.range', function()
+describe('vim.hl.range', function()
local screen
before_each(function()
@@ -18,7 +18,6 @@ describe('vim.highlight.range', function()
screen:add_extra_attr_ids({
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true },
})
- screen:attach()
api.nvim_set_option_value('list', true, {})
api.nvim_set_option_value('listchars', 'eol:$', {})
api.nvim_buf_set_lines(0, 0, -1, true, {
@@ -33,7 +32,7 @@ describe('vim.highlight.range', function()
it('works with charwise selection', function()
exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
- vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 })
+ vim.hl.range(0, ns, 'Search', { 1, 5 }, { 3, 10 })
end)
screen:expect([[
^asdfghjkl{1:$} |
@@ -48,7 +47,7 @@ describe('vim.highlight.range', function()
it('works with linewise selection', function()
exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
- vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' })
+ vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' })
end)
screen:expect([[
{10:^asdfghjkl}{100:$} |
@@ -63,7 +62,7 @@ describe('vim.highlight.range', function()
it('works with blockwise selection', function()
exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
- vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' })
+ vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' })
end)
screen:expect([[
{10:^asdf}ghjkl{1:$} |
@@ -78,7 +77,7 @@ describe('vim.highlight.range', function()
it('works with blockwise selection with width', function()
exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
- vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' })
+ vim.hl.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' })
end)
screen:expect([[
^asdf{10:ghjkl}{1:$} |
@@ -93,8 +92,8 @@ describe('vim.highlight.range', function()
it('can use -1 or v:maxcol to indicate end of line', function()
exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
- vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
- vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
+ vim.hl.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
+ vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
end)
screen:expect([[
^asdf{10:ghjkl}{100:$} |
@@ -107,7 +106,7 @@ describe('vim.highlight.range', function()
end)
end)
-describe('vim.highlight.on_yank', function()
+describe('vim.hl.on_yank', function()
before_each(function()
clear()
end)
@@ -115,7 +114,7 @@ describe('vim.highlight.on_yank', function()
it('does not show errors even if buffer is wiped before timeout', function()
command('new')
exec_lua(function()
- vim.highlight.on_yank({
+ vim.hl.on_yank({
timeout = 10,
on_macro = true,
event = { operator = 'y', regtype = 'v' },
@@ -129,10 +128,10 @@ describe('vim.highlight.on_yank', function()
it('does not close timer twice', function()
exec_lua(function()
- vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
+ vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
vim.uv.sleep(10)
vim.schedule(function()
- vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
+ vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
end)
end)
eq('', eval('v:errmsg'))
@@ -143,7 +142,7 @@ describe('vim.highlight.on_yank', function()
exec_lua(function()
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
- vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
end)
local ns = api.nvim_create_namespace('hlyank')
local win = api.nvim_get_current_win()
@@ -157,7 +156,7 @@ describe('vim.highlight.on_yank', function()
exec_lua(function()
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
- vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
end)
local ns = api.nvim_create_namespace('hlyank')
eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
@@ -165,7 +164,7 @@ describe('vim.highlight.on_yank', function()
exec_lua(function()
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
- vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
end)
local win = api.nvim_get_current_win()
eq({ win }, api.nvim__ns_get(ns).wins)
diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua
index de8200a5f1..52a8fec0bf 100644
--- a/test/functional/lua/loop_spec.lua
+++ b/test/functional/lua/loop_spec.lua
@@ -65,7 +65,6 @@ describe('vim.uv', function()
it('is API safe', function()
local screen = Screen.new(50, 10)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { bold = true, reverse = true },
@@ -88,9 +87,9 @@ describe('vim.uv', function()
screen:expect([[
|
{2: }|
- {3:Error executing luv callback:} |
+ {3:Error executing callback:} |
{3:[string "<nvim>"]:5: E5560: nvim_set_var must not }|
- {3:be called in a lua loop callback} |
+ {3:be called in a fast event context} |
{3:stack traceback:} |
{3: [C]: in function 'nvim_set_var'} |
{3: [string "<nvim>"]:5: in function <[string }|
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 2b23f72c7d..5fea79141c 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -510,7 +510,6 @@ describe('v:lua', function()
it('works in func options', function()
local screen = Screen.new(60, 8)
- screen:attach()
api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {})
feed('isome st<c-x><c-o>')
screen:expect{grid=[[
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 33a2813200..2f332d2c10 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -158,7 +158,6 @@ describe('print', function()
it('blank line in message works', function()
local screen = Screen.new(40, 8)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { bold = true, foreground = Screen.colors.SeaGreen },
@@ -196,7 +195,6 @@ describe('debug.debug', function()
before_each(function()
screen = Screen.new()
- screen:attach()
screen:set_default_attr_ids {
[0] = { bold = true, foreground = 255 },
[1] = { bold = true, reverse = true },
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
index f63363d6d9..6705dff847 100644
--- a/test/functional/lua/runtime_spec.lua
+++ b/test/functional/lua/runtime_spec.lua
@@ -21,7 +21,9 @@ describe('runtime:', function()
exec('set rtp+=' .. plug_dir)
exec([[
set shell=doesnotexist
- set completeslash=slash
+ if exists('+completeslash')
+ set completeslash=slash
+ endif
set isfname+=(,)
]])
end)
diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua
index c58fd689b7..b40b084ef9 100644
--- a/test/functional/lua/secure_spec.lua
+++ b/test/functional/lua/secure_spec.lua
@@ -39,7 +39,6 @@ describe('vim.secure', function()
it('works', function()
local screen = Screen.new(80, 8)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { bold = true, reverse = true },
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index 482bfcf1a9..afbada007d 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -9,7 +9,7 @@ local function system_sync(cmd, opts)
return exec_lua(function()
local obj = vim.system(cmd, opts)
- if opts.timeout then
+ if opts and opts.timeout then
-- Minor delay before calling wait() so the timeout uv timer can have a headstart over the
-- internal call to vim.wait() in wait().
vim.wait(10)
@@ -75,7 +75,7 @@ describe('vim.system', function()
it('kill processes', function()
exec_lua(function()
- local signal
+ local signal --- @type integer?
local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r)
signal = r.signal
end) -- run forever
@@ -112,4 +112,12 @@ describe('vim.system', function()
)
eq(true, exec_lua([[return _G.processed]]))
end)
+
+ if t.is_os('win') then
+ it('can resolve windows command extentions.', function()
+ t.write_file('test.bat', 'echo hello world')
+ system_sync({ 'chmod', '+x', 'test.bat' })
+ system_sync({ './test' })
+ end)
+ end
end)
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
index cbf23517dc..310705fd97 100644
--- a/test/functional/lua/thread_spec.lua
+++ b/test/functional/lua/thread_spec.lua
@@ -17,7 +17,6 @@ describe('thread', function()
before_each(function()
clear()
screen = Screen.new(50, 10)
- screen:attach()
end)
it('entry func is executed in protected mode', function()
@@ -257,7 +256,6 @@ describe('threadpool', function()
it('with invalid return value', function()
local screen = Screen.new(50, 10)
- screen:attach()
exec_lua [[
local work = vim.uv.new_work(function() return {} end, function() end)
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
index 0a6deaa41c..c8616e3e11 100644
--- a/test/functional/lua/ui_event_spec.lua
+++ b/test/functional/lua/ui_event_spec.lua
@@ -32,16 +32,6 @@ describe('vim.ui_attach', function()
]]
screen = Screen.new(40, 5)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true },
- [3] = { background = Screen.colors.Grey },
- [4] = { background = Screen.colors.LightMagenta },
- [5] = { reverse = true },
- [6] = { reverse = true, bold = true },
- [7] = { background = Screen.colors.Yellow1 },
- })
- screen:attach()
end)
local function expect_events(expected)
@@ -56,7 +46,7 @@ describe('vim.ui_attach', function()
grid = [[
fo^ |
{1:~ }|*3
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
}
@@ -65,7 +55,7 @@ describe('vim.ui_attach', function()
grid = [[
food^ |
{1:~ }|*3
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
}
expect_events {
@@ -84,7 +74,7 @@ describe('vim.ui_attach', function()
grid = [[
foobar^ |
{1:~ }|*3
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
}
expect_events {
@@ -106,10 +96,10 @@ describe('vim.ui_attach', function()
screen:expect {
grid = [[
food^ |
- {3:food }{1: }|
+ {12:food }{1: }|
{4:foobar }{1: }|
{4:foo }{1: }|
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
}
expect_events {}
@@ -151,9 +141,9 @@ describe('vim.ui_attach', function()
{
'msg_history_show',
{
- { 'echomsg', { { 0, 'message1' } } },
- { '', { { 0, 'message2' } } },
- { 'echomsg', { { 0, 'message3' } } },
+ { 'echomsg', { { 0, 'message1', 0 } } },
+ { 'lua_print', { { 0, 'message2', 0 } } },
+ { 'echomsg', { { 0, 'message3', 0 } } },
},
},
}, actual, vim.inspect(actual))
@@ -181,12 +171,17 @@ describe('vim.ui_attach', function()
exec_lua([[
_G.cmdline = 0
vim.ui_attach(ns, { ext_messages = true }, function(ev)
- vim.cmd.redraw()
+ if ev == 'msg_show' then
+ vim.schedule(function() vim.cmd.redraw() end)
+ else
+ vim.cmd.redraw()
+ end
_G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0)
end
)]])
feed(':')
- eq(1, exec_lua('return _G.cmdline'))
+ n.assert_alive()
+ eq(2, exec_lua('return _G.cmdline'))
n.assert_alive()
feed('version<CR><CR>v<Esc>')
n.assert_alive()
@@ -212,9 +207,9 @@ describe('vim.ui_attach', function()
screen:expect({
grid = [[
cmdline |
- {5:cmdline [+] }|
+ {2:cmdline [+] }|
fooba^r |
- {6:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
})
@@ -223,9 +218,9 @@ describe('vim.ui_attach', function()
screen:expect({
grid = [[
foo |
- {5:cmdline [+] }|
- {5:foo}ba^r |
- {6:[No Name] [+] }|
+ {2:cmdline [+] }|
+ {2:foo}ba^r |
+ {3:[No Name] [+] }|
|
]],
})
@@ -234,25 +229,78 @@ describe('vim.ui_attach', function()
screen:expect({
grid = [[
%s/bar/baz |
- {5:cmdline [+] }|
- foo{7:ba^z} |
- {6:[No Name] [+] }|
+ {2:cmdline [+] }|
+ foo{10:ba^z} |
+ {3:[No Name] [+] }|
|
]],
})
end)
+
+ it('msg_show in fast context', function()
+ exec_lua([[
+ vim.ui_attach(ns, { ext_messages = true }, function(event, _, content)
+ if event == "msg_show" then
+ vim.api.nvim_get_runtime_file("foo", false)
+ -- non-"fast-api" is not allowed in msg_show callback and should be scheduled
+ local _, err = pcall(vim.api.nvim_buf_set_lines, 0, -2, -1, false, { content[1][2] })
+ pcall(vim.api.nvim__redraw, { flush = true })
+ vim.schedule(function()
+ vim.api.nvim_buf_set_lines(0, -2, -1, false, { content[1][2], err })
+ end)
+ end
+ end)
+ ]])
+ -- "fast-api" does not prevent aborting :function
+ feed(':func Foo()<cr>bar<cr>endf<cr>:func Foo()<cr>')
+ screen:expect({
+ grid = [[
+ ^E122: Function Foo already exists, add !|
+ to replace it |
+ E5560: nvim_buf_set_lines must not be ca|
+ lled in a fast event context |
+ {1:~ }|
+ ]],
+ messages = {
+ {
+ content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 7 } },
+ kind = 'emsg',
+ },
+ },
+ })
+ -- No fast context for prompt message kinds
+ feed(':%s/Function/Replacement/c<cr>')
+ screen:expect({
+ grid = [[
+ ^E122: {10:Function} Foo already exists, add !|
+ to replace it |
+ replace with Replacement (y/n/a/q/l/^E/^|
+ Y)? |
+ {1:~ }|
+ ]],
+ messages = {
+ {
+ content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 19 } },
+ kind = 'confirm_sub',
+ },
+ },
+ })
+ end)
end)
describe('vim.ui_attach', function()
+ local screen
+ before_each(function()
+ clear({ env = { NVIM_LOG_FILE = testlog } })
+ screen = Screen.new(40, 5)
+ end)
+
after_each(function()
check_close()
os.remove(testlog)
end)
it('error in callback is logged', function()
- clear({ env = { NVIM_LOG_FILE = testlog } })
- local screen = Screen.new()
- screen:attach()
exec_lua([[
local ns = vim.api.nvim_create_namespace('testspace')
vim.ui_attach(ns, { ext_popupmenu = true }, function() error(42) end)
@@ -260,4 +308,83 @@ describe('vim.ui_attach', function()
feed('ifoo<CR>foobar<CR>fo<C-X><C-N>')
assert_log('Error executing UI event callback: Error executing lua: .*: 42', testlog, 100)
end)
+
+ it('detaches after excessive errors', function()
+ screen:add_extra_attr_ids({ [100] = { bold = true, foreground = Screen.colors.SeaGreen } })
+ exec_lua([[
+ vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function()
+ vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] })
+ end)
+ ]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ })
+ feed('ifoo')
+ screen:expect({
+ grid = [[
+ foo^ |
+ {1:~ }|*4
+ ]],
+ showmode = { { '-- INSERT --', 5, 12 } },
+ })
+ feed('<esc>:1mes clear<cr>:mes<cr>')
+ screen:expect({
+ grid = [[
+ foo |
+ {3: }|
+ {9:Excessive errors in vim.ui_attach() call}|
+ {9:back from ns: 1.} |
+ {100:Press ENTER or type command to continue}^ |
+ ]],
+ })
+ feed('<cr>')
+ -- Also when scheduled
+ exec_lua([[
+ vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function()
+ vim.schedule(function() vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) end)
+ end)
+ ]])
+ screen:expect({
+ any = 'fo^o',
+ messages = {
+ {
+ content = {
+ {
+ 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
+ 9,
+ 7,
+ },
+ },
+ kind = 'lua_error',
+ },
+ {
+ content = {
+ {
+ 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
+ 9,
+ 7,
+ },
+ },
+ kind = 'lua_error',
+ },
+ {
+ content = { { 'Press ENTER or type command to continue', 100, 19 } },
+ kind = 'return_prompt',
+ },
+ },
+ })
+ feed('<esc>:1mes clear<cr>:mes<cr>')
+ screen:expect({
+ grid = [[
+ foo |
+ {3: }|
+ {9:Excessive errors in vim.ui_attach() call}|
+ {9:back from ns: 2.} |
+ {100:Press ENTER or type command to continue}^ |
+ ]],
+ })
+ end)
end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
index d5eede2885..5c727b3347 100644
--- a/test/functional/lua/ui_spec.lua
+++ b/test/functional/lua/ui_spec.lua
@@ -153,7 +153,7 @@ describe('vim.ui', function()
vim.fn.executable = function() return 0 end
]]
eq(
- 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)',
+ 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open, lemonade)',
exec_lua [[local _, err = vim.ui.open('foo') ; return err]]
)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 3c65ec664e..3cfbfe167a 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -28,6 +28,7 @@ local rmdir = n.rmdir
local write_file = t.write_file
local poke_eventloop = n.poke_eventloop
local assert_alive = n.assert_alive
+local expect = n.expect
describe('lua stdlib', function()
before_each(clear)
@@ -155,10 +156,10 @@ describe('lua stdlib', function()
end)
it('plugin=nil, no error if soft-deprecated', function()
- eq(
- vim.NIL,
- exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.99.0')
- )
+ eq(vim.NIL, exec_lua [[return vim.deprecate('old1', 'new1', '0.99.0')]])
+ -- Major version > current Nvim major is always "soft-deprecated".
+ -- XXX: This is also a reminder to update the hardcoded `nvim_major`, when Nvim reaches 1.0.
+ eq(vim.NIL, exec_lua [[return vim.deprecate('old2', 'new2', '1.0.0')]])
end)
it('plugin=nil, show error if hard-deprecated', function()
@@ -175,13 +176,6 @@ describe('lua stdlib', function()
)
end)
- it('plugin=nil, to be deleted in the next major version (1.0)', function()
- eq(
- [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]],
- exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]]
- )
- end)
-
it('plugin specified', function()
-- When `plugin` is specified, don't show ":help deprecated". #22235
eq(
@@ -319,21 +313,106 @@ describe('lua stdlib', function()
49,
51,
}
+ local indices8 = {
+ [0] = 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ }
for i, k in pairs(indices32) do
eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., false)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", ...)', i), i)
end
for i, k in pairs(indices16) do
eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", ...)', i), i)
end
- eq(
+ for i, k in pairs(indices8) do
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", ...)', i), i)
+ end
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1)
)
- eq(
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1)
)
- local i32, i16 = 0, 0
+ matches(
+ 'index out of range',
+ pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-16", ...)', #indices16 + 1)
+ )
+ matches(
+ 'index out of range',
+ pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-32", ...)', #indices32 + 1)
+ )
+ matches(
+ 'invalid encoding',
+ pcall_err(exec_lua, 'return vim.str_byteindex("hello", "madeupencoding", 1)')
+ )
+ eq(
+ indices32[#indices32],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", 99999, false)')
+ )
+ eq(
+ indices16[#indices16],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", 99999, false)')
+ )
+ eq(
+ indices8[#indices8],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", 99999, false)')
+ )
+ eq(2, exec_lua('return vim.str_byteindex("é", "utf-16", 2, false)'))
+ local i32, i16, i8 = 0, 0, 0
local len = 51
for k = 0, len do
if indices32[i32] < k then
@@ -345,9 +424,29 @@ describe('lua stdlib', function()
i16 = i16 + 1
end
end
+ if indices8[i8] < k then
+ i8 = i8 + 1
+ end
eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k)
+ eq({ i32 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-32", ...)}', k), k)
+ eq({ i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-16", ...)}', k), k)
+ eq({ i8 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-8", ...)}', k), k)
end
- eq(
+
+ eq({ #indices32, #indices16 }, exec_lua('return {vim.str_utfindex(_G.test_text)}'))
+
+ eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32", math.huge, false)'))
+ eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16", math.huge, false)'))
+ eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8", math.huge, false)'))
+
+ eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32")'))
+ eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16")'))
+ eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8")'))
+ matches(
+ 'invalid encoding',
+ pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, "madeupencoding", ...)', 1)
+ )
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1)
)
@@ -538,7 +637,6 @@ describe('lua stdlib', function()
matches('big failure\nvery async', remove_trace(eval('v:errmsg')))
local screen = Screen.new(60, 5)
- screen:attach()
screen:expect {
grid = [[
^ |
@@ -1304,7 +1402,6 @@ describe('lua stdlib', function()
end)
local screen = Screen.new(50, 7)
- screen:attach()
exec_lua([[
timer = vim.uv.new_timer()
timer:start(20, 0, function ()
@@ -1317,7 +1414,7 @@ describe('lua stdlib', function()
screen:expect {
grid = [[
{9:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
- {9: called in a lua loop callback} |
+ {9: called in a fast event context} |
{9:stack traceback:} |
{9: [C]: in function 'rpcrequest'} |
{9: [string "<nvim>"]:6: in function <[string }|
@@ -1326,7 +1423,9 @@ describe('lua stdlib', function()
]],
}
feed('<cr>')
- eq({ 3, NIL }, api.nvim_get_var('yy'))
+ retry(10, nil, function()
+ eq({ 3, NIL }, api.nvim_get_var('yy'))
+ end)
exec_lua([[timer:close()]])
end)
@@ -1363,7 +1462,79 @@ describe('lua stdlib', function()
eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]]))
end)
- it('vim.validate', function()
+ it('vim.validate (fast form)', function()
+ exec_lua("vim.validate('arg1', {}, 'table')")
+ exec_lua("vim.validate('arg1', nil, 'table', true)")
+ exec_lua("vim.validate('arg1', { foo='foo' }, 'table')")
+ exec_lua("vim.validate('arg1', { 'foo' }, 'table')")
+ exec_lua("vim.validate('arg1', 'foo', 'string')")
+ exec_lua("vim.validate('arg1', nil, 'string', true)")
+ exec_lua("vim.validate('arg1', 1, 'number')")
+ exec_lua("vim.validate('arg1', 0, 'number')")
+ exec_lua("vim.validate('arg1', 0.1, 'number')")
+ exec_lua("vim.validate('arg1', nil, 'number', true)")
+ exec_lua("vim.validate('arg1', true, 'boolean')")
+ exec_lua("vim.validate('arg1', false, 'boolean')")
+ exec_lua("vim.validate('arg1', nil, 'boolean', true)")
+ exec_lua("vim.validate('arg1', function()end, 'function')")
+ exec_lua("vim.validate('arg1', nil, 'function', true)")
+ exec_lua("vim.validate('arg1', nil, 'nil')")
+ exec_lua("vim.validate('arg1', nil, 'nil', true)")
+ exec_lua("vim.validate('arg1', coroutine.create(function()end), 'thread')")
+ exec_lua("vim.validate('arg1', nil, 'thread', true)")
+ exec_lua("vim.validate('arg1', 2, function(a) return (a % 2) == 0 end, 'even number')")
+ exec_lua("vim.validate('arg1', 5, {'number', 'string'})")
+ exec_lua("vim.validate('arg2', 'foo', {'number', 'string'})")
+
+ matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
+ matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
+ matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
+ matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
+ matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
+ matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
+ matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
+ matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
+ matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate('arg1', 1, 'x')"))
+ matches('invalid validator: 1', pcall_err(exec_lua, "vim.validate('arg1', 1, 1)"))
+ matches('invalid arguments', pcall_err(exec_lua, "vim.validate('arg1', { 1 })"))
+
+ -- Validated parameters are required by default.
+ matches(
+ 'arg1: expected string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, 'string')")
+ )
+ -- Explicitly required.
+ matches(
+ 'arg1: expected string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, 'string', false)")
+ )
+
+ matches(
+ 'arg1: expected table, got number',
+ pcall_err(exec_lua, "vim.validate('arg1', 1, 'table')")
+ )
+
+ matches(
+ 'arg1: expected even number, got 3',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end, 'even number')")
+ )
+ matches(
+ 'arg1: expected %?, got 3',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end)")
+ )
+ matches(
+ 'arg1: expected number|string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, {'number', 'string'})")
+ )
+
+ -- Pass an additional message back.
+ matches(
+ 'arg1: expected %?, got 3. Info: TEST_MSG',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1, 'TEST_MSG' end)")
+ )
+ end)
+
+ it('vim.validate (spec form)', function()
exec_lua("vim.validate{arg1={{}, 'table' }}")
exec_lua("vim.validate{arg1={{}, 't' }}")
exec_lua("vim.validate{arg1={nil, 't', true }}")
@@ -1392,29 +1563,11 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
- vim.validate('arg1', 5, 'number')
- vim.validate('arg1', '5', 'string')
- vim.validate('arg1', { 5 }, 'table')
- vim.validate('arg1', function()
- return 5
- end, 'function')
- vim.validate('arg1', nil, 'number', true)
- vim.validate('arg1', nil, 'string', true)
- vim.validate('arg1', nil, 'table', true)
- vim.validate('arg1', nil, 'function', true)
- matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
- matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
- matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
- matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
- matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
- matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
- matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
- matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
- matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
- matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
- matches('invalid type name: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}'))
+ matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
+ matches('invalid validator: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
+ matches('invalid validator: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}'))
-- Validated parameters are required by default.
matches(
@@ -1975,7 +2128,6 @@ describe('lua stdlib', function()
eq({ 1, 5 }, api.nvim_win_get_cursor(0))
local screen = Screen.new(60, 3)
- screen:attach()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
@@ -3157,10 +3309,17 @@ describe('lua stdlib', function()
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
end)
- it('skips any function that caused an error', function()
+ it('skips any function that caused an error and shows stacktrace', function()
insert([[hello world]])
exec_lua [[
+ local function ErrF2()
+ error("Dumb Error")
+ end
+ local function ErrF1()
+ ErrF2()
+ end
+
keys = {}
return vim.on_key(function(buf)
@@ -3171,7 +3330,7 @@ describe('lua stdlib', function()
table.insert(keys, buf)
if buf == 'l' then
- error("Dumb Error")
+ ErrF1()
end
end)
]]
@@ -3181,6 +3340,19 @@ describe('lua stdlib', function()
-- Only the first letter gets added. After that we remove the callback
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
+
+ local errmsg = api.nvim_get_vvar('errmsg')
+ matches(
+ [[
+^Error executing vim%.on%_key%(%) callbacks:.*
+With ns%_id %d+: .*: Dumb Error
+stack traceback:
+.*: in function 'error'
+.*: in function 'ErrF2'
+.*: in function 'ErrF1'
+.*]],
+ errmsg
+ )
end)
it('argument 1 is keys after mapping, argument 2 is typed keys', function()
@@ -3223,6 +3395,109 @@ describe('lua stdlib', function()
feed('<C-C>')
eq('/', exec_lua([[return _G.ctrl_c_cmdtype]]))
end)
+
+ it('callback is not invoked recursively #30752', function()
+ local screen = Screen.new(60, 10)
+ exec_lua([[
+ vim.on_key(function(key, typed)
+ vim.api.nvim_echo({
+ { 'key_cb\n' },
+ { ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) },
+ }, false, {})
+ end)
+ ]])
+ feed('^')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {3: }|
+ key_cb |
+ KEYCB: key '^', typed '^' |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<C-C>')
+ screen:expect([[
+ |
+ {1:~ }|*3
+ {3: }|
+ key_cb |
+ KEYCB: key '^', typed '^' |
+ key_cb |
+ KEYCB: key '{18:^C}', typed '{18:^C}' |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<C-C>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*8
+ |
+ ]])
+ end)
+
+ it('can discard input', function()
+ clear()
+ -- discard every other normal 'x' command
+ exec_lua [[
+ n_key = 0
+
+ vim.on_key(function(buf, typed_buf)
+ if typed_buf == 'x' then
+ n_key = n_key + 1
+ end
+ return (n_key % 2 == 0) and "" or nil
+ end)
+ ]]
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
+
+ feed('x')
+ expect('4321')
+ feed('x')
+ expect('4321')
+ feed('x')
+ expect('321')
+ feed('x')
+ expect('321')
+ end)
+
+ it('callback invalid return', function()
+ clear()
+ -- second key produces an error which removes the callback
+ exec_lua [[
+ n_call = 0
+
+ vim.on_key(function(buf, typed_buf)
+ if typed_buf == 'x' then
+ n_call = n_call + 1
+ end
+ return n_call >= 2 and '!' or nil
+ end)
+ ]]
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
+
+ local function cleanup_msg(msg)
+ return msg:gsub('^Error .*\nWith ns%_id %d+: ', '')
+ end
+
+ feed('x')
+ eq(1, exec_lua [[ return n_call ]])
+
+ eq(1, exec_lua [[ return vim.on_key(nil, nil) ]])
+
+ eq('', cleanup_msg(eval('v:errmsg')))
+ feed('x')
+ eq(2, exec_lua [[ return n_call ]])
+ eq('return string must be empty', cleanup_msg(eval('v:errmsg')))
+ command('let v:errmsg = ""')
+
+ eq(0, exec_lua [[ return vim.on_key(nil, nil) ]])
+
+ feed('x')
+ eq(2, exec_lua [[ return n_call ]])
+ expect('21')
+ eq('', cleanup_msg(eval('v:errmsg')))
+ end)
end)
describe('vim.wait', function()
@@ -3500,7 +3775,6 @@ describe('lua stdlib', function()
it('fails in fast callbacks #26122', function()
local screen = Screen.new(80, 10)
- screen:attach()
exec_lua([[
local timer = vim.uv.new_timer()
timer:start(0, 0, function()
@@ -3509,7 +3783,7 @@ describe('lua stdlib', function()
end)
]])
screen:expect({
- any = pesc('E5560: vim.wait must not be called in a lua loop callback'),
+ any = pesc('E5560: vim.wait must not be called in a fast event context'),
})
feed('<CR>')
assert_alive()
@@ -3518,7 +3792,6 @@ describe('lua stdlib', function()
it('vim.notify_once', function()
local screen = Screen.new(60, 5)
- screen:attach()
screen:expect {
grid = [[
^ |
@@ -3715,7 +3988,6 @@ describe('lua stdlib', function()
it('updates ruler if cursor moved', function()
-- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too!
local screen = Screen.new(30, 5)
- screen:attach()
exec_lua [[
_G.api = vim.api
vim.opt.ruler = true
@@ -3858,7 +4130,6 @@ describe('lua stdlib', function()
it('vim.lua_omnifunc', function()
local screen = Screen.new(60, 5)
- screen:attach()
command [[ set omnifunc=v:lua.vim.lua_omnifunc ]]
-- Note: the implementation is shared with lua command line completion.
@@ -4060,11 +4331,16 @@ describe('vim.keymap', function()
)
matches(
- 'opts: expected table, got function',
+ 'rhs: expected string|function, got number',
pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]])
)
matches(
+ 'opts: expected table, got function',
+ pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 'x', function() end)]])
+ )
+
+ matches(
'rhs: expected string|function, got number',
pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]])
)
diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua
index 99b80ef749..6127e83619 100644
--- a/test/functional/lua/with_spec.lua
+++ b/test/functional/lua/with_spec.lua
@@ -1029,7 +1029,6 @@ describe('vim._with', function()
[1] = { bold = true, reverse = true },
[2] = { bold = true, foreground = Screen.colors.Blue },
}
- screen:attach()
exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]]
screen:expect [[
^ |
@@ -1178,7 +1177,6 @@ describe('vim._with', function()
[1] = { reverse = true },
[2] = { bold = true, reverse = true },
}
- screen:attach()
exec_lua [[
vim.opt.ruler = true
local lines = {}
diff --git a/test/functional/options/belloff_spec.lua b/test/functional/options/belloff_spec.lua
new file mode 100644
index 0000000000..575e79d1a9
--- /dev/null
+++ b/test/functional/options/belloff_spec.lua
@@ -0,0 +1,78 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+local clear = n.clear
+local command = n.command
+local api = n.api
+local feed = n.feed
+local poke_eventloop = n.poke_eventloop
+local eq = t.eq
+local retry = t.retry
+
+describe("'belloff'", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(42, 5)
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ |
+ ]])
+ end)
+
+ it('various flags work properly', function()
+ command('set cpoptions+=E')
+
+ local map = {
+ backspace = 'i<BS><Esc>',
+ cursor = 'i<Up><Esc>',
+ copy = 'i<C-Y><Esc>',
+ ctrlg = 'i<C-G><C-G><Esc>',
+ error = 'J',
+ esc = '<Esc>',
+ operator = 'y0',
+ register = 'i<C-R>@<Esc>',
+ }
+
+ local items = {} ---@type string[]
+ local inputs = {} ---@type string[]
+ for item, input in pairs(map) do
+ table.insert(items, item)
+ table.insert(inputs, input)
+ end
+
+ local values = {} ---@type string[]
+ for i, _ in ipairs(items) do
+ -- each tested 'belloff' value enables at most one item
+ local parts = vim.deepcopy(items)
+ table.remove(parts, i)
+ local value = table.concat(parts, ',')
+ table.insert(values, value)
+ end
+ table.insert(values, 'all')
+
+ for i, value in ipairs(values) do
+ api.nvim_set_option_value('belloff', value, {})
+
+ for j, input in ipairs(inputs) do
+ screen.bell = false
+ local beep = value ~= 'all' and i == j
+ -- Nvim avoids beeping more than 3 times in half a second,
+ -- so retry if beeping is expected but not received.
+ retry(not beep and 1 or nil, 1000, function()
+ feed(input)
+ poke_eventloop()
+ screen:expect({
+ condition = function()
+ eq(beep, screen.bell, ('%s with belloff=%s'):format(items[j], value))
+ end,
+ unchanged = not beep,
+ })
+ end)
+ end
+ end
+ end)
+end)
diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua
index 8e63e07e09..42ca41a145 100644
--- a/test/functional/options/chars_spec.lua
+++ b/test/functional/options/chars_spec.lua
@@ -16,7 +16,6 @@ describe("'fillchars'", function()
before_each(function()
clear()
screen = Screen.new(25, 5)
- screen:attach()
end)
describe('"eob" flag', function()
@@ -157,7 +156,6 @@ describe("'listchars'", function()
before_each(function()
clear()
screen = Screen.new(50, 5)
- screen:attach()
end)
it('has global value', function()
diff --git a/test/functional/options/cursorbind_spec.lua b/test/functional/options/cursorbind_spec.lua
index 19551b928f..21e0ba8e75 100644
--- a/test/functional/options/cursorbind_spec.lua
+++ b/test/functional/options/cursorbind_spec.lua
@@ -18,7 +18,6 @@ describe("'cursorbind'", function()
[3] = { reverse = true }, -- StatusLineNC
[4] = { background = Screen.colors.Grey90 }, -- CursorLine, CursorColumn
})
- screen:attach()
exec([[
call setline(1, 'aa bb cc dd ee ff gg hh ii jj kk ll mm' ..
\ ' nn oo pp qq rr ss tt uu vv ww xx yy zz')
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index e3d15fa30f..e7f47ef4e9 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -34,7 +34,6 @@ describe('startup defaults', function()
describe(':filetype', function()
local function expect_filetype(expected)
local screen = Screen.new(50, 4)
- screen:attach()
command('filetype')
screen:expect([[
^ |
@@ -127,7 +126,6 @@ describe('startup defaults', function()
it('vert/fold flags', function()
clear()
local screen = Screen.new(50, 5)
- screen:attach()
command('set laststatus=0')
insert([[
1
diff --git a/test/functional/options/shortmess_spec.lua b/test/functional/options/shortmess_spec.lua
index dcbf9d15e0..04dbada7d8 100644
--- a/test/functional/options/shortmess_spec.lua
+++ b/test/functional/options/shortmess_spec.lua
@@ -14,7 +14,6 @@ describe("'shortmess'", function()
before_each(function()
clear()
screen = Screen.new(42, 5)
- screen:attach()
end)
describe('"F" flag', function()
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 7089313303..753da64522 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -155,7 +155,6 @@ describe('vim.health', function()
it('highlights OK, ERROR', function()
local screen = Screen.new(50, 12)
- screen:attach()
screen:set_default_attr_ids({
h1 = { reverse = true },
h2 = { foreground = tonumber('0x6a0dad') },
@@ -222,7 +221,7 @@ describe(':checkhealth window', function()
end)
it('opens directly if no buffer created', function()
- local screen = Screen.new(50, 12)
+ local screen = Screen.new(50, 12, { ext_multigrid = true })
screen:set_default_attr_ids {
h1 = { reverse = true },
h2 = { foreground = tonumber('0x6a0dad') },
@@ -230,7 +229,6 @@ describe(':checkhealth window', function()
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
- screen:attach({ ext_multigrid = true })
command('checkhealth success1')
screen:expect {
grid = [[
@@ -256,7 +254,7 @@ describe(':checkhealth window', function()
end)
local function test_health_vsplit(left, emptybuf, mods)
- local screen = Screen.new(50, 20)
+ local screen = Screen.new(50, 20, { ext_multigrid = true })
screen:set_default_attr_ids {
h1 = { reverse = true },
h2 = { foreground = tonumber('0x6a0dad') },
@@ -264,7 +262,6 @@ describe(':checkhealth window', function()
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
- screen:attach({ ext_multigrid = true })
if not emptybuf then
insert('hello')
end
@@ -322,8 +319,7 @@ describe(':checkhealth window', function()
end
local function test_health_split(top, emptybuf, mods)
- local screen = Screen.new(50, 25)
- screen:attach({ ext_multigrid = true })
+ local screen = Screen.new(50, 25, { ext_multigrid = true })
screen._default_attr_ids = nil
if not emptybuf then
insert('hello')
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 4df8d77d44..39b6ddc105 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -134,10 +134,14 @@ describe('vim.lsp.completion: item conversion', function()
eq(expected, result)
end)
- it('filters on label if filterText is missing', function()
+ it('does not filter if there is a textEdit', function()
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
local completion_list = {
- { label = 'foo' },
- { label = 'bar' },
+ { label = 'foo', textEdit = { newText = 'foo', range = range0 } },
+ { label = 'bar', textEdit = { newText = 'bar', range = range0 } },
}
local result = complete('fo|', completion_list)
local expected = {
@@ -145,6 +149,10 @@ describe('vim.lsp.completion: item conversion', function()
abbr = 'foo',
word = 'foo',
},
+ {
+ abbr = 'bar',
+ word = 'bar',
+ },
}
result = vim.tbl_map(function(x)
return {
@@ -152,7 +160,259 @@ describe('vim.lsp.completion: item conversion', function()
word = x.word,
}
end, result.items)
+ local sorter = function(a, b)
+ return a.word > b.word
+ end
+ table.sort(expected, sorter)
+ table.sort(result, sorter)
+ eq(expected, result)
+ end)
+
+ ---@param prefix string
+ ---@param items lsp.CompletionItem[]
+ ---@param expected table[]
+ local assert_completion_matches = function(prefix, items, expected)
+ local result = complete(prefix .. '|', items)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ local sorter = function(a, b)
+ return a.word > b.word
+ end
+ table.sort(expected, sorter)
+ table.sort(result, sorter)
eq(expected, result)
+ end
+
+ describe('when completeopt has fuzzy matching enabled', function()
+ before_each(function()
+ exec_lua(function()
+ vim.opt.completeopt:append('fuzzy')
+ end)
+ end)
+ after_each(function()
+ exec_lua(function()
+ vim.opt.completeopt:remove('fuzzy')
+ end)
+ end)
+
+ it('fuzzy matches on filterText', function()
+ assert_completion_matches('fo', {
+ { label = '?.foo', filterText = 'foo' },
+ { label = 'faz other', filterText = 'faz other' },
+ { label = 'bar', filterText = 'bar' },
+ }, {
+ {
+ abbr = 'faz other',
+ word = 'faz other',
+ },
+ {
+ abbr = '?.foo',
+ word = '?.foo',
+ },
+ })
+ end)
+
+ it('fuzzy matches on label when filterText is missing', function()
+ assert_completion_matches('fo', {
+ { label = 'foo' },
+ { label = 'faz other' },
+ { label = 'bar' },
+ }, {
+ {
+ abbr = 'faz other',
+ word = 'faz other',
+ },
+ {
+ abbr = 'foo',
+ word = 'foo',
+ },
+ })
+ end)
+ end)
+
+ describe('when smartcase is enabled', function()
+ before_each(function()
+ exec_lua(function()
+ vim.opt.smartcase = true
+ end)
+ end)
+ after_each(function()
+ exec_lua(function()
+ vim.opt.smartcase = false
+ end)
+ end)
+
+ it('matches filterText case sensitively', function()
+ assert_completion_matches('Fo', {
+ { label = 'foo', filterText = 'foo' },
+ { label = '?.Foo', filterText = 'Foo' },
+ { label = 'Faz other', filterText = 'Faz other' },
+ { label = 'faz other', filterText = 'faz other' },
+ { label = 'bar', filterText = 'bar' },
+ }, {
+ {
+ abbr = '?.Foo',
+ word = '?.Foo',
+ },
+ })
+ end)
+
+ it('matches label case sensitively when filterText is missing', function()
+ assert_completion_matches('Fo', {
+ { label = 'foo' },
+ { label = 'Foo' },
+ { label = 'Faz other' },
+ { label = 'faz other' },
+ { label = 'bar' },
+ }, {
+ {
+ abbr = 'Foo',
+ word = 'Foo',
+ },
+ })
+ end)
+
+ describe('when ignorecase is enabled', function()
+ before_each(function()
+ exec_lua(function()
+ vim.opt.ignorecase = true
+ end)
+ end)
+ after_each(function()
+ exec_lua(function()
+ vim.opt.ignorecase = false
+ end)
+ end)
+
+ it('matches filterText case insensitively if prefix is lowercase', function()
+ assert_completion_matches('fo', {
+ { label = '?.foo', filterText = 'foo' },
+ { label = '?.Foo', filterText = 'Foo' },
+ { label = 'Faz other', filterText = 'Faz other' },
+ { label = 'faz other', filterText = 'faz other' },
+ { label = 'bar', filterText = 'bar' },
+ }, {
+ {
+ abbr = '?.Foo',
+ word = '?.Foo',
+ },
+ {
+ abbr = '?.foo',
+ word = '?.foo',
+ },
+ })
+ end)
+
+ it(
+ 'matches label case insensitively if prefix is lowercase and filterText is missing',
+ function()
+ assert_completion_matches('fo', {
+ { label = 'foo' },
+ { label = 'Foo' },
+ { label = 'Faz other' },
+ { label = 'faz other' },
+ { label = 'bar' },
+ }, {
+ {
+ abbr = 'Foo',
+ word = 'Foo',
+ },
+ {
+ abbr = 'foo',
+ word = 'foo',
+ },
+ })
+ end
+ )
+
+ it('matches filterText case sensitively if prefix has uppercase letters', function()
+ assert_completion_matches('Fo', {
+ { label = 'foo', filterText = 'foo' },
+ { label = '?.Foo', filterText = 'Foo' },
+ { label = 'Faz other', filterText = 'Faz other' },
+ { label = 'faz other', filterText = 'faz other' },
+ { label = 'bar', filterText = 'bar' },
+ }, {
+ {
+ abbr = '?.Foo',
+ word = '?.Foo',
+ },
+ })
+ end)
+
+ it(
+ 'matches label case sensitively if prefix has uppercase letters and filterText is missing',
+ function()
+ assert_completion_matches('Fo', {
+ { label = 'foo' },
+ { label = 'Foo' },
+ { label = 'Faz other' },
+ { label = 'faz other' },
+ { label = 'bar' },
+ }, {
+ {
+ abbr = 'Foo',
+ word = 'Foo',
+ },
+ })
+ end
+ )
+ end)
+ end)
+
+ describe('when ignorecase is enabled', function()
+ before_each(function()
+ exec_lua(function()
+ vim.opt.ignorecase = true
+ end)
+ end)
+ after_each(function()
+ exec_lua(function()
+ vim.opt.ignorecase = false
+ end)
+ end)
+
+ it('matches filterText case insensitively', function()
+ assert_completion_matches('Fo', {
+ { label = '?.foo', filterText = 'foo' },
+ { label = '?.Foo', filterText = 'Foo' },
+ { label = 'Faz other', filterText = 'Faz other' },
+ { label = 'faz other', filterText = 'faz other' },
+ { label = 'bar', filterText = 'bar' },
+ }, {
+ {
+ abbr = '?.Foo',
+ word = '?.Foo',
+ },
+ {
+ abbr = '?.foo',
+ word = '?.foo',
+ },
+ })
+ end)
+
+ it('matches label case insensitively when filterText is missing', function()
+ assert_completion_matches('Fo', {
+ { label = 'foo' },
+ { label = 'Foo' },
+ { label = 'Faz other' },
+ { label = 'faz other' },
+ { label = 'bar' },
+ }, {
+ {
+ abbr = 'Foo',
+ word = 'Foo',
+ },
+ {
+ abbr = 'foo',
+ word = 'foo',
+ },
+ })
+ end)
end)
it('works on non word prefix', function()
@@ -320,7 +580,7 @@ describe('vim.lsp.completion: item conversion', function()
info = '',
kind = 'Module',
menu = '',
- hl_group = '',
+ abbr_hlgroup = '',
word = 'this_thread',
}
local result = complete(' std::this|', completion_list)
@@ -376,7 +636,7 @@ describe('vim.lsp.completion: item conversion', function()
info = '',
kind = 'Module',
menu = '',
- hl_group = '',
+ abbr_hlgroup = '',
word = 'this_thread',
}
local result = complete(' std::this|is', completion_list)
@@ -471,6 +731,39 @@ describe('vim.lsp.completion: item conversion', function()
)
end)
+--- @param completion_result lsp.CompletionList
+--- @return integer
+local function create_server(completion_result)
+ return exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ completionProvider = {
+ triggerCharacters = { '.' },
+ },
+ },
+ handlers = {
+ ['textDocument/completion'] = function(_, _, callback)
+ callback(nil, completion_result)
+ end,
+ },
+ })
+
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ return vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ on_attach = function(client, bufnr0)
+ vim.lsp.completion.enable(true, client.id, bufnr0, {
+ convert = function(item)
+ return { abbr = item.label:gsub('%b()', '') }
+ end,
+ })
+ end,
+ })
+ end)
+end
+
describe('vim.lsp.completion: protocol', function()
before_each(function()
clear()
@@ -487,39 +780,6 @@ describe('vim.lsp.completion: protocol', function()
after_each(clear)
- --- @param completion_result lsp.CompletionList
- --- @return integer
- local function create_server(completion_result)
- return exec_lua(function()
- local server = _G._create_server({
- capabilities = {
- completionProvider = {
- triggerCharacters = { '.' },
- },
- },
- handlers = {
- ['textDocument/completion'] = function(_, _, callback)
- callback(nil, completion_result)
- end,
- },
- })
-
- local bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- return vim.lsp.start({
- name = 'dummy',
- cmd = server.cmd,
- on_attach = function(client, bufnr0)
- vim.lsp.completion.enable(true, client.id, bufnr0, {
- convert = function(item)
- return { abbr = item.label:gsub('%b()', '') }
- end,
- })
- end,
- })
- end)
- end
-
local function assert_matches(fn)
retry(nil, nil, function()
fn(exec_lua('return _G.capture.matches'))
@@ -570,7 +830,7 @@ describe('vim.lsp.completion: protocol', function()
info = '',
kind = 'Unknown',
menu = '',
- hl_group = '',
+ abbr_hlgroup = '',
user_data = {
nvim = {
lsp = {
@@ -591,7 +851,7 @@ describe('vim.lsp.completion: protocol', function()
info = '',
kind = 'Unknown',
menu = '',
- hl_group = 'DiagnosticDeprecated',
+ abbr_hlgroup = 'DiagnosticDeprecated',
user_data = {
nvim = {
lsp = {
@@ -613,7 +873,7 @@ describe('vim.lsp.completion: protocol', function()
info = '',
kind = 'Unknown',
menu = '',
- hl_group = 'DiagnosticDeprecated',
+ abbr_hlgroup = 'DiagnosticDeprecated',
user_data = {
nvim = {
lsp = {
@@ -726,3 +986,58 @@ describe('vim.lsp.completion: protocol', function()
end)
end)
end)
+
+describe('vim.lsp.completion: integration', function()
+ before_each(function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ vim.fn.complete = vim.schedule_wrap(vim.fn.complete)
+ end)
+ end)
+
+ after_each(clear)
+
+ it('puts cursor at the end of completed word', function()
+ local completion_list = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ insertText = '${1:hello} friends',
+ insertTextFormat = 2,
+ },
+ },
+ }
+ exec_lua(function()
+ vim.o.completeopt = 'menuone,noselect'
+ end)
+ create_server(completion_list)
+ feed('i world<esc>0ih<c-x><c-o>')
+ retry(nil, nil, function()
+ eq(
+ 1,
+ exec_lua(function()
+ return vim.fn.pumvisible()
+ end)
+ )
+ end)
+ feed('<C-n><C-y>')
+ eq(
+ { true, { 'hello friends world' } },
+ exec_lua(function()
+ return {
+ vim.snippet.active({ direction = 1 }),
+ vim.api.nvim_buf_get_lines(0, 0, -1, true),
+ }
+ end)
+ )
+ feed('<tab>')
+ eq(
+ #'hello friends',
+ exec_lua(function()
+ return vim.api.nvim_win_get_cursor(0)[2]
+ end)
+ )
+ end)
+end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 78c684083b..5afbe22793 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -120,85 +120,6 @@ describe('vim.lsp.diagnostic', function()
end)
describe('vim.lsp.diagnostic.on_publish_diagnostics', function()
- it('allows configuring the virtual text via vim.lsp.with', function()
- local expected_spacing = 10
- local extmarks = exec_lua(function()
- _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
- virtual_text = {
- spacing = expected_spacing,
- },
- })
-
- _G.PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
- },
- }, { client_id = client_id })
-
- return _G.get_extmarks(diagnostic_bufnr, client_id)
- end)
-
- local spacing = extmarks[1][4].virt_text[1][1]
-
- eq(expected_spacing, #spacing)
- end)
-
- it('allows configuring the virtual text via vim.lsp.with using a function', function()
- local expected_spacing = 10
- local extmarks = exec_lua(function()
- _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
- virtual_text = function()
- return {
- spacing = expected_spacing,
- }
- end,
- })
-
- _G.PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
- },
- }, { client_id = client_id })
-
- return _G.get_extmarks(diagnostic_bufnr, client_id)
- end)
-
- local spacing = extmarks[1][4].virt_text[1][1]
-
- eq(expected_spacing, #spacing)
- end)
-
- it('allows filtering via severity limit', function()
- local get_extmark_count_with_severity = function(severity_limit)
- return exec_lua(function()
- _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
- underline = false,
- virtual_text = {
- severity = { min = severity_limit },
- },
- })
-
- _G.PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
- },
- }, { client_id = client_id })
-
- return #_G.get_extmarks(diagnostic_bufnr, client_id)
- end, client_id, fake_uri, severity_limit)
- end
-
- -- No messages with Error or higher
- eq(0, get_extmark_count_with_severity('ERROR'))
-
- -- But now we don't filter it
- eq(1, get_extmark_count_with_severity('WARN'))
- eq(1, get_extmark_count_with_severity('HINT'))
- end)
-
it('correctly handles UTF-16 offsets', function()
local line = 'All 💼 and no 🎉 makes Jack a dull 👦'
local result = exec_lua(function()
@@ -219,13 +140,13 @@ describe('vim.lsp.diagnostic', function()
eq(1, #result)
eq(
exec_lua(function()
- return vim.str_byteindex(line, 7, true)
+ return vim.str_byteindex(line, 'utf-16', 7)
end),
result[1].col
)
eq(
exec_lua(function()
- return vim.str_byteindex(line, 8, true)
+ return vim.str_byteindex(line, 'utf-16', 8)
end),
result[1].end_col
)
@@ -380,34 +301,6 @@ describe('vim.lsp.diagnostic', function()
eq(1, diagnostics[1].severity)
end)
- it('allows configuring the virtual text via vim.lsp.with', function()
- local expected_spacing = 10
- local extmarks = exec_lua(function()
- _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
- virtual_text = {
- spacing = expected_spacing,
- },
- })
-
- _G.Diagnostic(nil, {
- kind = 'full',
- items = {
- _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
- },
- }, {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
- }, {})
-
- return _G.get_extmarks(diagnostic_bufnr, client_id)
- end)
- eq(2, #extmarks)
- eq(expected_spacing, #extmarks[1][4].virt_text[1][1])
- end)
-
it('clears diagnostics when client detaches', function()
exec_lua(function()
vim.lsp.diagnostic.on_diagnostic(nil, {
diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua
index 471f2cc3e8..fc6c3f46f7 100644
--- a/test/functional/plugin/lsp/inlay_hint_spec.lua
+++ b/test/functional/plugin/lsp/inlay_hint_spec.lua
@@ -67,7 +67,6 @@ int main() {
before_each(function()
clear_notrace()
screen = Screen.new(50, 9)
- screen:attach()
bufnr = n.api.nvim_get_current_buf()
exec_lua(create_server_definition)
@@ -339,7 +338,6 @@ test text
before_each(function()
clear_notrace()
screen = Screen.new(50, 3)
- screen:attach()
exec_lua(create_server_definition)
bufnr = n.api.nvim_get_current_buf()
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index f72aab7e0b..280bd27207 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -28,7 +28,6 @@ describe('semantic token highlighting', function()
local screen --- @type test.functional.ui.screen
before_each(function()
screen = Screen.new(40, 16)
- screen:attach()
screen:set_default_attr_ids {
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.DarkCyan },
diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua
index 64d58eeffd..813b8de812 100644
--- a/test/functional/plugin/lsp/utils_spec.lua
+++ b/test/functional/plugin/lsp/utils_spec.lua
@@ -181,11 +181,9 @@ describe('vim.lsp.util', function()
eq(expected_anchor, string.sub(opts.anchor, 1, 1))
end
- local screen --- @type test.functional.ui.screen
before_each(function()
n.clear()
- screen = Screen.new(80, 80)
- screen:attach()
+ local _ = Screen.new(80, 80)
feed('79i<CR><Esc>') -- fill screen with empty lines
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 9956fdf628..5222216faf 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -2586,7 +2586,7 @@ describe('LSP', function()
},
},
}
- eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16'))
eq(false, vim.uv.fs_stat(tmpfile) ~= nil)
end)
end)
@@ -3134,44 +3134,6 @@ describe('LSP', function()
end)
end)
- describe('lsp.util._get_symbol_kind_name', function()
- it('returns the name specified by protocol', function()
- eq(
- 'File',
- exec_lua(function()
- return vim.lsp.util._get_symbol_kind_name(1)
- end)
- )
- eq(
- 'TypeParameter',
- exec_lua(function()
- return vim.lsp.util._get_symbol_kind_name(26)
- end)
- )
- end)
-
- it('returns the name not specified by protocol', function()
- eq(
- 'Unknown',
- exec_lua(function()
- return vim.lsp.util._get_symbol_kind_name(nil)
- end)
- )
- eq(
- 'Unknown',
- exec_lua(function()
- return vim.lsp.util._get_symbol_kind_name(vim.NIL)
- end)
- )
- eq(
- 'Unknown',
- exec_lua(function()
- return vim.lsp.util._get_symbol_kind_name(1000)
- end)
- )
- end)
- end)
-
describe('lsp.util.jump_to_location', function()
local target_bufnr --- @type integer
@@ -3519,6 +3481,30 @@ describe('LSP', function()
local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' }
eq(expected, result)
end)
+
+ it('highlights active parameters in multiline signature labels', function()
+ local _, hl = exec_lua(function()
+ local signature_help = {
+ activeSignature = 0,
+ signatures = {
+ {
+ activeParameter = 1,
+ label = 'fn bar(\n _: void,\n _: void,\n) void',
+ parameters = {
+ { label = '_: void' },
+ { label = '_: void' },
+ },
+ },
+ },
+ }
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'zig', { '(' })
+ end)
+ -- Note that although the higlight positions below are 0-indexed, the 2nd parameter
+ -- corresponds to the 3rd line because the first line is the ``` from the
+ -- Markdown block.
+ local expected = { 3, 4, 3, 11 }
+ eq(expected, hl)
+ end)
end)
describe('lsp.util.get_effective_tabstop', function()
@@ -5090,6 +5076,91 @@ describe('LSP', function()
end)
end)
+ describe('lsp.buf.definition', function()
+ it('jumps to single location', function()
+ exec_lua(create_server_definition)
+ local result = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ local server = _G._create_server({
+ capabilities = {
+ definitionProvider = true,
+ },
+ handlers = {
+ ['textDocument/definition'] = function(_, _, callback)
+ local location = {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ },
+ uri = vim.uri_from_bufnr(bufnr),
+ }
+ callback(nil, location)
+ end,
+ },
+ })
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' })
+ vim.api.nvim_win_set_cursor(win, { 3, 6 })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
+ vim.lsp.buf.definition()
+ vim.lsp.stop_client(client_id)
+ return {
+ cursor = vim.api.nvim_win_get_cursor(win),
+ messages = server.messages,
+ tagstack = vim.fn.gettagstack(win),
+ }
+ end)
+ eq('textDocument/definition', result.messages[3].method)
+ eq({ 1, 0 }, result.cursor)
+ eq(1, #result.tagstack.items)
+ eq('x', result.tagstack.items[1].tagname)
+ eq(3, result.tagstack.items[1].from[2])
+ eq(7, result.tagstack.items[1].from[3])
+ end)
+ it('merges results from multiple servers', function()
+ exec_lua(create_server_definition)
+ local result = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ local function serveropts(character)
+ return {
+ capabilities = {
+ definitionProvider = true,
+ },
+ handlers = {
+ ['textDocument/definition'] = function(_, _, callback)
+ local location = {
+ range = {
+ start = { line = 0, character = character },
+ ['end'] = { line = 0, character = character },
+ },
+ uri = vim.uri_from_bufnr(bufnr),
+ }
+ callback(nil, location)
+ end,
+ },
+ }
+ end
+ local server1 = _G._create_server(serveropts(0))
+ local server2 = _G._create_server(serveropts(7))
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' })
+ vim.api.nvim_win_set_cursor(win, { 3, 6 })
+ local client_id1 = assert(vim.lsp.start({ name = 'dummy', cmd = server1.cmd }))
+ local client_id2 = assert(vim.lsp.start({ name = 'dummy', cmd = server2.cmd }))
+ local response
+ vim.lsp.buf.definition({
+ on_list = function(r)
+ response = r
+ end,
+ })
+ vim.lsp.stop_client(client_id1)
+ vim.lsp.stop_client(client_id2)
+ return response
+ end)
+ eq(2, #result.items)
+ end)
+ end)
+
describe('vim.lsp.tagfunc', function()
before_each(function()
clear()
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 6f0eeff748..8906e60dce 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -60,7 +60,6 @@ describe(':Man', function()
c = { foreground = Screen.colors.Blue }, -- control chars
eob = { bold = true, foreground = Screen.colors.Blue }, -- empty line '~'s
})
- screen:attach()
end)
it('clears backspaces from text and adds highlights', function()
diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua
index ae718ac1bd..b2bbdb2ef6 100644
--- a/test/functional/plugin/matchparen_spec.lua
+++ b/test/functional/plugin/matchparen_spec.lua
@@ -14,7 +14,6 @@ describe('matchparen', function()
before_each(function()
clear { args = { '-u', 'NORC' } }
screen = Screen.new(20, 5)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = 255 },
[1] = { bold = true },
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index c9d49f7d01..f33819f364 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -3053,7 +3053,6 @@ describe('syntax/shada.vim', function()
[7] = { bold = true, reverse = true },
[8] = { bold = true, foreground = Screen.colors.Blue },
}
- screen:attach()
api.nvim_buf_set_lines(0, 0, 1, true, {
'Header with timestamp ' .. epoch .. ':',
diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua
index 1d05f4d6b4..afd4169006 100644
--- a/test/functional/plugin/tohtml_spec.lua
+++ b/test/functional/plugin/tohtml_spec.lua
@@ -185,8 +185,7 @@ describe(':TOhtml', function()
local screen
before_each(function()
clear({ args = { '--clean' } })
- screen = Screen.new(80, 80)
- screen:attach({ term_name = 'xterm' })
+ screen = Screen.new(80, 80, { term_name = 'xterm' })
exec('colorscheme default')
end)
diff --git a/test/functional/plugin/tutor_spec.lua b/test/functional/plugin/tutor_spec.lua
index 9f381d45db..09cd22ab6c 100644
--- a/test/functional/plugin/tutor_spec.lua
+++ b/test/functional/plugin/tutor_spec.lua
@@ -24,7 +24,6 @@ describe(':Tutor', function()
[5] = { bold = true, foreground = Screen.colors.Magenta1 },
[6] = { italic = true },
})
- screen:attach()
end)
it('applies {unix:…,win:…} transform', function()
diff --git a/test/functional/plugin/vim_syntax_spec.lua b/test/functional/plugin/vim_syntax_spec.lua
index d99a69eab9..bdb4534cba 100644
--- a/test/functional/plugin/vim_syntax_spec.lua
+++ b/test/functional/plugin/vim_syntax_spec.lua
@@ -21,7 +21,6 @@ describe('Vimscript syntax highlighting', function()
[1] = { foreground = Screen.colors.Brown, bold = true },
[2] = { foreground = tonumber('0x6a0dad') },
})
- screen:attach()
end)
it('prefixed boolean options are highlighted properly', function()
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 1094f9f4e5..722442acbd 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -94,7 +94,6 @@ describe('clipboard', function()
before_each(function()
clear()
screen = Screen.new(72, 4)
- screen:attach()
end)
it('unnamed register works without provider', function()
@@ -318,7 +317,6 @@ describe('clipboard (with fake clipboard.vim)', function()
it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function()
local screen = Screen.new(72, 4)
- screen:attach()
feed_command('redir @+> | bogus_cmd | redir END')
screen:expect([[
^ |
@@ -641,7 +639,6 @@ describe('clipboard (with fake clipboard.vim)', function()
it('supports "+ and "* in registers', function()
local screen = Screen.new(60, 10)
- screen:attach()
feed_command("let g:test_clip['*'] = ['some', 'star data','']")
feed_command("let g:test_clip['+'] = ['such', 'plus', 'stuff']")
feed_command('registers')
@@ -709,7 +706,6 @@ describe('clipboard (with fake clipboard.vim)', function()
feed_command('set mouse=a')
local screen = Screen.new(30, 5)
- screen:attach()
insert([[
the source
a target]])
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 7a30367917..05258a9e50 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -411,7 +411,6 @@ describe(':terminal buffer', function()
it('handles split UTF-8 sequences #16245', function()
local screen = Screen.new(50, 7)
- screen:attach()
fn.termopen({ testprg('shell-test'), 'UTF-8' })
screen:expect([[
^å |
@@ -422,6 +421,43 @@ describe(':terminal buffer', function()
|*2
]])
end)
+
+ it("handles bell respecting 'belloff' and 'visualbell'", function()
+ local screen = Screen.new(50, 7)
+ local chan = api.nvim_open_term(0, {})
+
+ command('set belloff=')
+ api.nvim_chan_send(chan, '\a')
+ screen:expect(function()
+ eq({ true, false }, { screen.bell, screen.visual_bell })
+ end)
+ screen.bell = false
+
+ command('set visualbell')
+ api.nvim_chan_send(chan, '\a')
+ screen:expect(function()
+ eq({ false, true }, { screen.bell, screen.visual_bell })
+ end)
+ screen.visual_bell = false
+
+ command('set belloff=term')
+ api.nvim_chan_send(chan, '\a')
+ screen:expect({
+ condition = function()
+ eq({ false, false }, { screen.bell, screen.visual_bell })
+ end,
+ unchanged = true,
+ })
+
+ command('set belloff=all')
+ api.nvim_chan_send(chan, '\a')
+ screen:expect({
+ condition = function()
+ eq({ false, false }, { screen.bell, screen.visual_bell })
+ end,
+ unchanged = true,
+ })
+ end)
end)
describe('on_lines does not emit out-of-bounds line indexes when', function()
@@ -662,7 +698,6 @@ describe('termopen()', function()
local function test_term_colorterm(expected, opts)
local screen = Screen.new(50, 4)
- screen:attach()
fn.termopen({
nvim_prog,
'-u',
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 774ff01291..9912c1ff7b 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -21,7 +21,6 @@ describe('terminal channel is closed and later released if', function()
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
end)
it('opened by nvim_open_term() and deleted by :bdelete!', function()
@@ -122,7 +121,6 @@ end)
it('chansend sends lines to terminal channel in proper order', function()
clear({ args = { '--cmd', 'set laststatus=2' } })
local screen = Screen.new(100, 20)
- screen:attach()
screen._default_attr_ids = nil
local shells = is_os('win') and { 'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop' } or { 'sh' }
for _, sh in ipairs(shells) do
@@ -149,7 +147,6 @@ describe('no crash when TermOpen autocommand', function()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
})
- screen:attach()
end)
it('processes job exit event when using termopen()', function()
@@ -231,7 +228,6 @@ describe('nvim_open_term', function()
before_each(function()
clear()
screen = Screen.new(8, 10)
- screen:attach()
end)
it('with force_crlf=true converts newlines', function()
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index 0c5de45829..f223cdd417 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -122,13 +122,12 @@ describe('cursor with customized highlighting', function()
clear()
command('highlight TermCursor ctermfg=45 ctermbg=46 cterm=NONE')
command('highlight TermCursorNC ctermfg=55 ctermbg=56 cterm=NONE')
- screen = Screen.new(50, 7)
+ screen = Screen.new(50, 7, { rgb = false })
screen:set_default_attr_ids({
[1] = { foreground = 45, background = 46 },
[2] = { foreground = 55, background = 56 },
[3] = { bold = true },
})
- screen:attach({ rgb = false })
command('call termopen(["' .. testprg('tty-test') .. '"])')
feed('i')
poke_eventloop()
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index 24c5eb28e5..dcd566d04a 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local screen = require('test.functional.ui.screen')
+local Screen = require('test.functional.ui.screen')
local testprg = n.testprg
local command = n.command
@@ -13,12 +13,6 @@ local matches = t.matches
local pesc = vim.pesc
describe(':edit term://*', function()
- local get_screen = function(columns, lines)
- local scr = screen.new(columns, lines)
- scr:attach({ rgb = false })
- return scr
- end
-
before_each(function()
clear()
api.nvim_set_option_value('shell', testprg('shell-test'), {})
@@ -37,7 +31,7 @@ describe(':edit term://*', function()
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
local columns, lines = 20, 4
- local scr = get_screen(columns, lines)
+ local scr = Screen.new(columns, lines, { rgb = false })
local rep = 97
api.nvim_set_option_value('shellcmdflag', 'REP ' .. rep, {})
command('set shellxquote=') -- win: avoid extra quotes
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 1039572210..5ebe7bd4fc 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -21,8 +21,7 @@ describe(':terminal', function()
before_each(function()
clear()
- screen = Screen.new(50, 4)
- screen:attach({ rgb = false })
+ screen = Screen.new(50, 4, { rgb = false })
screen._default_attr_ids = nil
end)
@@ -169,8 +168,7 @@ local function test_terminal_with_fake_shell(backslash)
before_each(function()
clear()
- screen = Screen.new(50, 4)
- screen:attach({ rgb = false })
+ screen = Screen.new(50, 4, { rgb = false })
screen._default_attr_ids = nil
api.nvim_set_option_value('shell', shell_path, {})
api.nvim_set_option_value('shellcmdflag', 'EXE', {})
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 05d68f6754..7822a27b93 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -17,7 +17,7 @@ describe(':terminal highlight', function()
before_each(function()
clear()
- screen = Screen.new(50, 7)
+ screen = Screen.new(50, 7, { rgb = false })
screen:set_default_attr_ids({
[1] = { foreground = 45 },
[2] = { background = 46 },
@@ -33,7 +33,6 @@ describe(':terminal highlight', function()
[12] = { bold = true, underdouble = true },
[13] = { italic = true, undercurl = true },
})
- screen:attach({ rgb = false })
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
@@ -130,7 +129,7 @@ end)
it(':terminal highlight has lower precedence than editor #9964', function()
clear()
- local screen = Screen.new(30, 4)
+ local screen = Screen.new(30, 4, { rgb = true })
screen:set_default_attr_ids({
-- "Normal" highlight emitted by the child nvim process.
N_child = {
@@ -150,7 +149,6 @@ it(':terminal highlight has lower precedence than editor #9964', function()
bg_indexed = true,
},
})
- screen:attach({ rgb = true })
-- Child nvim process in :terminal (with cterm colors).
fn.termopen({
nvim_prog_abs(),
@@ -202,7 +200,6 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
[4] = { background = Screen.colors.Grey90, reverse = true },
[5] = { background = Screen.colors.Red },
})
- screen:attach()
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
screen:expect([[
^tty ready |
@@ -308,7 +305,6 @@ describe(':terminal highlight forwarding', function()
[3] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
[4] = { { foreground = tonumber('0xff8000') }, {} },
})
- screen:attach()
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
@@ -343,7 +339,7 @@ describe(':terminal highlight with custom palette', function()
before_each(function()
clear()
- screen = Screen.new(50, 7)
+ screen = Screen.new(50, 7, { rgb = true })
screen:set_default_attr_ids({
[1] = { foreground = tonumber('0x123456') }, -- no fg_indexed when overridden
[2] = { foreground = 12 },
@@ -354,7 +350,6 @@ describe(':terminal highlight with custom palette', function()
[8] = { background = 11 },
[9] = { bold = true },
})
- screen:attach({ rgb = true })
api.nvim_set_var('terminal_color_3', '#123456')
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
@@ -389,7 +384,6 @@ describe(':terminal', function()
screen:add_extra_attr_ids {
[100] = { url = 'https://example.com' },
}
- screen:attach()
local chan = api.nvim_open_term(0, {})
api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\')
screen:expect({
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index da0bd97270..1751db1aa9 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -354,8 +354,7 @@ end)
describe(':terminal prints more lines than the screen height and exits', function()
it('will push extra lines to scrollback', function()
clear()
- local screen = Screen.new(30, 7)
- screen:attach({ rgb = false })
+ local screen = Screen.new(30, 7, { rgb = false })
command(("call termopen(['%s', '10']) | startinsert"):format(testprg('tty-test')))
screen:expect([[
line6 |
@@ -580,7 +579,6 @@ describe('pending scrollback line handling', function()
before_each(function()
clear()
screen = Screen.new(30, 7)
- screen:attach()
screen:set_default_attr_ids {
[1] = { foreground = Screen.colors.Brown },
[2] = { reverse = true },
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index a7d87bb231..ded0cd99d3 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -13,7 +13,6 @@ local eq = t.eq
local feed_data = tt.feed_data
local clear = n.clear
local command = n.command
-local dedent = t.dedent
local exec = n.exec
local exec_lua = n.exec_lua
local testprg = n.testprg
@@ -87,6 +86,21 @@ describe('TUI', function()
end)
end
+ -- Ensure both child client and child server have processed pending events.
+ local function poke_both_eventloop()
+ child_exec_lua([[
+ _G.termresponse = nil
+ vim.api.nvim_create_autocmd('TermResponse', {
+ once = true,
+ callback = function(ev) _G.termresponse = ev.data end,
+ })
+ ]])
+ feed_data('\027P0$r\027\\')
+ retry(nil, nil, function()
+ eq('\027P0$r', child_exec_lua('return _G.termresponse'))
+ end)
+ end
+
it('rapid resize #7572 #7628', function()
-- Need buffer rows to provoke the behavior.
feed_data(':edit test/functional/fixtures/bigfile.txt\n')
@@ -975,6 +989,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
feed_data('\027[201~') -- End paste.
+ poke_both_eventloop()
screen:expect_unchanged()
feed_data('\027[27u') -- ESC: go to Normal mode.
wait_for_mode('n')
@@ -1157,6 +1172,7 @@ describe('TUI', function()
feed_data('\027[200~line 1\nline 2\n')
wait_for_mode('c')
feed_data('line 3\nline 4\n\027[201~')
+ poke_both_eventloop()
wait_for_mode('c')
screen:expect([[
foo |
@@ -1201,22 +1217,19 @@ describe('TUI', function()
expect_cmdline('"stuff 1 more"')
-- End the paste sequence.
feed_data('\027[201~')
+ poke_both_eventloop()
expect_cmdline('"stuff 1 more"')
feed_data(' typed')
expect_cmdline('"stuff 1 more typed"')
end)
it('paste: recovers from vim.paste() failure', function()
- child_session:request(
- 'nvim_exec_lua',
- [[
+ child_exec_lua([[
_G.save_paste_fn = vim.paste
-- Stack traces for this test are non-deterministic, so disable them
_G.debug.traceback = function(msg) return msg end
vim.paste = function(lines, phase) error("fake fail") end
- ]],
- {}
- )
+ ]])
-- Prepare something for dot-repeat/redo.
feed_data('ifoo\n\027[27u')
wait_for_mode('n')
@@ -1269,7 +1282,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
-- Paste works if vim.paste() succeeds.
- child_session:request('nvim_exec_lua', [[vim.paste = _G.save_paste_fn]], {})
+ child_exec_lua([[vim.paste = _G.save_paste_fn]])
feed_data('\027[200~line A\nline B\n\027[201~')
screen:expect([[
foo |
@@ -1285,13 +1298,9 @@ describe('TUI', function()
it('paste: vim.paste() cancel (retval=false) #10865', function()
-- This test only exercises the "cancel" case. Use-case would be "dangling
-- paste", but that is not implemented yet. #10865
- child_session:request(
- 'nvim_exec_lua',
- [[
+ child_exec_lua([[
vim.paste = function(lines, phase) return false end
- ]],
- {}
- )
+ ]])
feed_data('\027[200~line A\nline B\n\027[201~')
expect_child_buf_lines({ '' })
feed_data('ifoo\n\027[27u')
@@ -1299,22 +1308,18 @@ describe('TUI', function()
end)
it('paste: vim.paste() cancel (retval=false) with streaming #30462', function()
- child_session:request(
- 'nvim_exec_lua',
- [[
- vim.paste = (function(overridden)
- return function(lines, phase)
- for i, line in ipairs(lines) do
- if line:find('!') then
- return false
- end
+ child_exec_lua([[
+ vim.paste = (function(overridden)
+ return function(lines, phase)
+ for i, line in ipairs(lines) do
+ if line:find('!') then
+ return false
end
- return overridden(lines, phase)
end
- end)(vim.paste)
- ]],
- {}
- )
+ return overridden(lines, phase)
+ end
+ end)(vim.paste)
+ ]])
feed_data('A')
wait_for_mode('i')
feed_data('\027[200~aaa')
@@ -1324,6 +1329,7 @@ describe('TUI', function()
feed_data('ccc!') -- This chunk is cancelled.
expect_child_buf_lines({ 'aaabbb' })
feed_data('ddd\027[201~') -- This chunk is ignored.
+ poke_both_eventloop()
expect_child_buf_lines({ 'aaabbb' })
feed_data('\027[27u')
wait_for_mode('n')
@@ -1334,15 +1340,11 @@ describe('TUI', function()
end)
it("paste: 'nomodifiable' buffer", function()
- child_session:request('nvim_command', 'set nomodifiable')
- child_session:request(
- 'nvim_exec_lua',
- [[
+ child_exec_lua([[
+ vim.bo.modifiable = false
-- Truncate the error message to hide the line number
_G.debug.traceback = function(msg) return msg:sub(-49) end
- ]],
- {}
- )
+ ]])
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
screen:expect([[
|
@@ -1354,7 +1356,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
feed_data('\n') -- <Enter> to dismiss hit-enter prompt
- child_session:request('nvim_command', 'set modifiable')
+ child_exec_lua('vim.bo.modifiable = true')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
screen:expect([[
success 1 |
@@ -1509,9 +1511,7 @@ describe('TUI', function()
end)
it('paste: streamed paste with isolated "stop paste" code', function()
- child_session:request(
- 'nvim_exec_lua',
- [[
+ child_exec_lua([[
_G.paste_phases = {}
vim.paste = (function(overridden)
return function(lines, phase)
@@ -1519,9 +1519,7 @@ describe('TUI', function()
overridden(lines, phase)
end
end)(vim.paste)
- ]],
- {}
- )
+ ]])
feed_data('i')
wait_for_mode('i')
feed_data('\027[200~pasted') -- phase 1
@@ -1542,8 +1540,9 @@ describe('TUI', function()
]])
-- Send isolated "stop paste" sequence.
feed_data('\027[201~') -- phase 3
+ poke_both_eventloop()
screen:expect_unchanged()
- local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {})
+ local rv = child_exec_lua('return _G.paste_phases')
-- In rare cases there may be multiple chunks of phase 2 because of timing.
eq({ 1, 2, 3 }, { rv[1], rv[2], rv[#rv] })
end)
@@ -1729,9 +1728,7 @@ describe('TUI', function()
eq(expected, rv)
---@type table
- local expected_version = ({
- child_session:request('nvim_exec_lua', 'return vim.version()', {}),
- })[2]
+ local expected_version = child_exec_lua('return vim.version()')
-- vim.version() returns `prerelease` string. Coerce it to boolean.
expected_version.prerelease = not not expected_version.prerelease
@@ -1855,45 +1852,73 @@ describe('TUI', function()
end)
it('draws correctly when cursor_address overflows #21643', function()
- t.skip(is_os('mac'), 'FIXME: crashes/errors on macOS')
- screen:try_resize(77, 855)
+ screen:try_resize(70, 333)
retry(nil, nil, function()
- eq({ true, 852 }, { child_session:request('nvim_win_get_height', 0) })
+ eq({ true, 330 }, { child_session:request('nvim_win_get_height', 0) })
end)
+ child_session:request('nvim_set_option_value', 'cursorline', true, {})
-- Use full screen message so that redrawing afterwards is more deterministic.
child_session:notify('nvim_command', 'intro')
- screen:expect({ any = 'Nvim' })
+ screen:expect({ any = 'Nvim is open source and freely distributable' })
-- Going to top-left corner needs 3 bytes.
-- Setting underline attribute needs 9 bytes.
- -- The whole line needs 3 + 9 + 65513 + 3 = 65528 bytes.
+ -- A Ꝩ character takes 3 bytes.
+ -- The whole line needs 3 + 9 + 3 * 21838 + 3 = 65529 bytes.
-- The cursor_address that comes after will overflow the 65535-byte buffer.
- local line = ('a'):rep(65513) .. '℃'
- child_session:notify(
- 'nvim_exec_lua',
- [[
- vim.api.nvim_buf_set_lines(0, 0, -1, true, {...})
- vim.o.cursorline = true
- ]],
- { line, 'b' }
- )
+ local line = ('Ꝩ'):rep(21838) .. '℃'
+ child_session:notify('nvim_buf_set_lines', 0, 0, -1, true, { line, 'b' })
-- Close the :intro message and redraw the lines.
feed_data('\n')
- screen:expect(
- '{13:a}{12:'
- .. ('a'):rep(76)
- .. '}|\n'
- .. ('{12:' .. ('a'):rep(77) .. '}|\n'):rep(849)
- .. '{12:'
- .. ('a'):rep(63)
- .. '℃'
- .. (' '):rep(13)
- .. '}|\n'
- .. dedent([[
- b |
- {5:[No Name] [+] }|
- |
- {3:-- TERMINAL --} |]])
- )
+ screen:expect([[
+ {13:Ꝩ}{12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|
+ {12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|*310
+ {12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ℃ }|
+ b |
+ {4:~ }|*17
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
+ it('draws correctly when setting title overflows #30793', function()
+ screen:try_resize(67, 327)
+ retry(nil, nil, function()
+ eq({ true, 324 }, { child_session:request('nvim_win_get_height', 0) })
+ end)
+ child_exec_lua([[
+ vim.o.cmdheight = 0
+ vim.o.laststatus = 0
+ vim.o.ruler = false
+ vim.o.showcmd = false
+ vim.o.termsync = false
+ vim.o.title = true
+ ]])
+ retry(nil, nil, function()
+ eq('[No Name] - Nvim', api.nvim_buf_get_var(0, 'term_title'))
+ eq({ true, 326 }, { child_session:request('nvim_win_get_height', 0) })
+ end)
+ -- Use full screen message so that redrawing afterwards is more deterministic.
+ child_session:notify('nvim_command', 'intro')
+ screen:expect({ any = 'Nvim is open source and freely distributable' })
+ -- Going to top-left corner needs 3 bytes.
+ -- A Ꝩ character takes 3 bytes.
+ -- The whole line needs 3 + 3 * 21842 = 65529 bytes.
+ -- The title will be updated because the buffer is now modified.
+ -- The start of the OSC 0 sequence to set title can fit in the 65535-byte buffer,
+ -- but the title string cannot.
+ local line = ('Ꝩ'):rep(21842)
+ child_session:notify('nvim_buf_set_lines', 0, 0, -1, true, { line })
+ -- Close the :intro message and redraw the lines.
+ feed_data('\n')
+ screen:expect([[
+ {1:Ꝩ}ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|
+ ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|*325
+ {3:-- TERMINAL --} |
+ ]])
+ retry(nil, nil, function()
+ eq('[No Name] + - Nvim', api.nvim_buf_get_var(0, 'term_title'))
+ end)
end)
it('visual bell (padding) does not crash #21610', function()
@@ -2089,7 +2114,6 @@ describe('TUI', function()
[5] = { bold = true, reverse = true },
[6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen },
})
- screen:attach()
fn.termopen({
nvim_prog,
'--clean',
@@ -2122,7 +2146,6 @@ describe('TUI', function()
for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do
it('has no black flicker when clearing regions during startup with ' .. guicolors, function()
local screen = Screen.new(50, 10)
- screen:attach()
fn.termopen({
nvim_prog,
'--clean',
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index e9218e9a3b..272fc513af 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -30,10 +30,6 @@ describe(':terminal', function()
command('highlight VertSplit NONE')
end)
- after_each(function()
- screen:detach()
- end)
-
it('next to a closing window', function()
command('split')
command('terminal')
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 8a2281e2a1..60b2f872fc 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -920,36 +920,38 @@ function M.exec_lua(code, ...)
return M.api.nvim_exec_lua(code, { ... })
end
- assert(session)
+ assert(session, 'no Nvim session')
if not session.exec_lua_setup then
- M.api.nvim_exec_lua(
- [[
- _G.__test_exec_lua = {
- get_upvalues = loadstring((select(1,...))),
- set_upvalues = loadstring((select(2,...))),
- handler = loadstring((select(3,...)))
- }
- setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua })
- ]],
- { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
+ assert(
+ session:request(
+ 'nvim_exec_lua',
+ [[
+ _G.__test_exec_lua = {
+ get_upvalues = loadstring((select(1,...))),
+ set_upvalues = loadstring((select(2,...))),
+ handler = loadstring((select(3,...)))
+ }
+ setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua })
+ ]],
+ { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
+ )
)
session.exec_lua_setup = true
end
+ local stat, rv = session:request(
+ 'nvim_exec_lua',
+ 'return { _G.__test_exec_lua:handler(...) }',
+ { string.dump(code), get_upvalues(code), ... }
+ )
+
+ if not stat then
+ error(rv[2])
+ end
+
--- @type any[], table<string,any>
- local ret, upvalues = unpack(M.api.nvim_exec_lua(
- [[
- return {
- _G.__test_exec_lua:handler(...)
- }
- ]],
- {
- string.dump(code),
- get_upvalues(code),
- ...,
- }
- ))
+ local ret, upvalues = unpack(rv)
-- Update upvalues
if next(upvalues) then
diff --git a/test/functional/testterm.lua b/test/functional/testterm.lua
index e46ae0793c..3aadcc59a7 100644
--- a/test/functional/testterm.lua
+++ b/test/functional/testterm.lua
@@ -112,7 +112,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0')
api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8')
- local screen = Screen.new(cols, 7 + extra_rows)
+ local screen = Screen.new(cols, 7 + extra_rows, screen_opts or { rgb = false })
screen:set_default_attr_ids({
[1] = { reverse = true }, -- focused cursor
[2] = { background = 11 }, -- unfocused cursor
@@ -134,8 +134,6 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
[18] = { background = 2, foreground = 8 }, -- StatusLineTermNC
})
- screen:attach(screen_opts or { rgb = false })
-
api.nvim_command('enew')
api.nvim_call_function('termopen', { cmd, env and { env = env } or nil })
api.nvim_input('<CR>')
diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua
index 24b085920c..e38e58ff92 100644
--- a/test/functional/treesitter/fold_spec.lua
+++ b/test/functional/treesitter/fold_spec.lua
@@ -442,7 +442,6 @@ t3]])
it('updates folds in all windows', function()
local screen = Screen.new(60, 48)
- screen:attach()
screen:set_default_attr_ids({
[1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
[2] = { bold = true, foreground = Screen.colors.Blue1 },
@@ -603,7 +602,6 @@ t3]])
it("doesn't open folds in diff mode", function()
local screen = Screen.new(60, 36)
- screen:attach()
parse('c')
command(
@@ -660,7 +658,6 @@ t3]])
it('does not extend closed fold with `o`/`O`', function()
local screen = Screen.new(60, 24)
- screen:attach()
insert(test_text)
parse('c')
@@ -727,7 +724,6 @@ t3]])
[3] = { foreground = Screen.colors.Blue1, bold = true },
[4] = { bold = true },
})
- screen:attach()
insert([[
# h1
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index b5a6cb5c17..5c6be869c6 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -161,7 +161,6 @@ describe('treesitter highlighting (C)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- screen:attach()
screen:set_default_attr_ids {
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Blue1 },
@@ -848,7 +847,6 @@ describe('treesitter highlighting (lua)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- screen:attach()
screen:set_default_attr_ids {
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { foreground = Screen.colors.DarkCyan },
@@ -887,7 +885,6 @@ describe('treesitter highlighting (help)', function()
before_each(function()
clear()
screen = Screen.new(40, 6)
- screen:attach()
screen:set_default_attr_ids {
[1] = { foreground = Screen.colors.Blue1 },
[2] = { bold = true, foreground = Screen.colors.Blue1 },
@@ -1025,7 +1022,6 @@ describe('treesitter highlighting (nested injections)', function()
before_each(function()
clear()
screen = Screen.new(80, 7)
- screen:attach()
screen:set_default_attr_ids {
[1] = { foreground = Screen.colors.SlateBlue },
[2] = { bold = true, foreground = Screen.colors.Brown },
@@ -1093,7 +1089,6 @@ describe('treesitter highlighting (markdown)', function()
before_each(function()
clear()
screen = Screen.new(40, 6)
- screen:attach()
exec_lua(function()
vim.bo.filetype = 'markdown'
vim.treesitter.start()
@@ -1161,7 +1156,6 @@ it('starting and stopping treesitter highlight in init.lua works #29541', functi
eq('', api.nvim_get_vvar('errmsg'))
local screen = Screen.new(65, 18)
- screen:attach()
screen:set_default_attr_ids {
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Blue1 },
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index e1e34fcecc..120a15d7f9 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -51,7 +51,7 @@ describe('treesitter language API', function()
it('inspects language', function()
local keys, fields, symbols = unpack(exec_lua(function()
local lang = vim.treesitter.language.inspect('c')
- local keys, symbols = {}, {}
+ local keys = {}
for k, v in pairs(lang) do
if type(v) == 'boolean' then
keys[k] = v
@@ -60,12 +60,7 @@ describe('treesitter language API', function()
end
end
- -- symbols array can have "holes" and is thus not a valid msgpack array
- -- but we don't care about the numbers here (checked in the parser test)
- for _, v in pairs(lang.symbols) do
- table.insert(symbols, v)
- end
- return { keys, lang.fields, symbols }
+ return { keys, lang.fields, lang.symbols }
end))
eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys)
@@ -78,17 +73,22 @@ describe('treesitter language API', function()
eq(true, fset['directive'])
eq(true, fset['initializer'])
- local has_named, has_anonymous
- for _, s in pairs(symbols) do
- eq('string', type(s[1]))
- eq('boolean', type(s[2]))
- if s[1] == 'for_statement' and s[2] == true then
+ local has_named, has_anonymous, has_supertype
+ for symbol, named in pairs(symbols) do
+ eq('string', type(symbol))
+ eq('boolean', type(named))
+ if symbol == 'for_statement' and named == true then
has_named = true
- elseif s[1] == '|=' and s[2] == false then
+ elseif symbol == '"|="' and named == false then
has_anonymous = true
+ elseif symbol == 'statement' and named == true then
+ has_supertype = true
end
end
- eq({ true, true }, { has_named, has_anonymous })
+ eq(
+ { has_named = true, has_anonymous = true, has_supertype = true },
+ { has_named = has_named, has_anonymous = has_anonymous, has_supertype = has_supertype }
+ )
end)
it(
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index d07ed35368..c87a56b160 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -186,4 +186,28 @@ describe('treesitter node API', function()
)
eq(vim.NIL, lua_eval('declarator:child_containing_descendant(value)'))
end)
+
+ it('child_with_descendant() works', function()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
+ _G.root = assert(tree:root())
+ _G.main = assert(_G.root:child(0))
+ _G.body = assert(_G.main:child(2))
+ _G.statement = assert(_G.body:child(1))
+ _G.declarator = assert(_G.statement:child(1))
+ _G.value = assert(_G.declarator:child(1))
+ end)
+
+ eq(lua_eval('main:type()'), lua_eval('root:child_with_descendant(value):type()'))
+ eq(lua_eval('body:type()'), lua_eval('main:child_with_descendant(value):type()'))
+ eq(lua_eval('statement:type()'), lua_eval('body:child_with_descendant(value):type()'))
+ eq(lua_eval('declarator:type()'), lua_eval('statement:child_with_descendant(value):type()'))
+ eq(lua_eval('value:type()'), lua_eval('declarator:child_with_descendant(value):type()'))
+ eq(vim.NIL, lua_eval('value:child_with_descendant(value)'))
+ end)
end)
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index c8829f4785..2f8d204d36 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -42,13 +42,13 @@ describe('treesitter parser API', function()
eq('function_definition', exec_lua('return child:type()'))
eq(true, exec_lua('return child:named()'))
eq('number', type(exec_lua('return child:symbol()')))
- eq({ 'function_definition', true }, exec_lua('return lang.symbols[child:symbol()]'))
+ eq(true, exec_lua('return lang.symbols[child:type()]'))
exec_lua('anon = root:descendant_for_range(0,8,0,9)')
eq('(', exec_lua('return anon:type()'))
eq(false, exec_lua('return anon:named()'))
eq('number', type(exec_lua('return anon:symbol()')))
- eq({ '(', false }, exec_lua('return lang.symbols[anon:symbol()]'))
+ eq(false, exec_lua([=[return lang.symbols[string.format('"%s"', anon:type())]]=]))
exec_lua('descendant = root:descendant_for_range(1,2,1,12)')
eq('<node declaration>', exec_lua('return tostring(descendant)'))
diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua
index c97619c913..634f8af83d 100644
--- a/test/functional/treesitter/query_spec.lua
+++ b/test/functional/treesitter/query_spec.lua
@@ -405,6 +405,20 @@ void ui_refresh(void)
{ 'literal', 'number_literal', { 0, 8, 0, 11 }, '123' },
{ 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' },
}, result)
+
+ result = exec_lua(
+ get_query_result,
+ [[((number_literal) @literal (#has-ancestor? @literal "enumerator"))]]
+ )
+ eq({
+ { 'literal', 'number_literal', { 1, 13, 1, 16 }, '124' },
+ }, result)
+
+ result = exec_lua(
+ get_query_result,
+ [[((number_literal) @literal (#has-ancestor? @literal "number_literal"))]]
+ )
+ eq({}, result)
end)
it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function()
@@ -708,7 +722,25 @@ void ui_refresh(void)
eq(exp, pcall_err(exec_lua, "vim.treesitter.query.parse('c', ...)", cquery))
end
- -- Invalid node type
+ -- Invalid node types
+ test(
+ '.../query.lua:0: Query error at 1:2. Invalid node type ">\\">>":\n'
+ .. '">\\">>" @operator\n'
+ .. ' ^',
+ '">\\">>" @operator'
+ )
+ test(
+ '.../query.lua:0: Query error at 1:2. Invalid node type "\\\\":\n'
+ .. '"\\\\" @operator\n'
+ .. ' ^',
+ '"\\\\" @operator'
+ )
+ test(
+ '.../query.lua:0: Query error at 1:2. Invalid node type ">>>":\n'
+ .. '">>>" @operator\n'
+ .. ' ^',
+ '">>>" @operator'
+ )
test(
'.../query.lua:0: Query error at 1:2. Invalid node type "dentifier":\n'
.. '(dentifier) @variable\n'
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 5590db5bc4..b7cf8504ff 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -16,7 +16,6 @@ describe('Buffer highlighting', function()
clear()
command('syntax on')
screen = Screen.new(40, 8)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { foreground = Screen.colors.Fuchsia }, -- String
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 1c6f19245a..0ee994ba0a 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -24,7 +24,6 @@ end
before_each(function()
clear()
screen = Screen.new(40, 8)
- screen:attach()
source([[
highlight RBP1 guibg=Red
highlight RBP2 guibg=Yellow
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 6edfb4a49c..0221c1e0b0 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -13,30 +13,12 @@ local eq = t.eq
local is_os = t.is_os
local api = n.api
-local function new_screen(opt)
- local screen = Screen.new(25, 5)
- screen:attach(opt)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { reverse = true },
- [3] = { bold = true, reverse = true },
- [4] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [5] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [6] = { foreground = Screen.colors.Magenta },
- [7] = { bold = true, foreground = Screen.colors.Brown },
- [8] = { foreground = Screen.colors.Black, background = Screen.colors.LightGrey },
- [9] = { bold = true },
- [10] = { background = Screen.colors.Yellow1 },
- })
- return screen
-end
-
local function test_cmdline(linegrid)
local screen
before_each(function()
clear()
- screen = new_screen({ rgb = true, ext_cmdline = true, ext_linegrid = linegrid })
+ screen = Screen.new(25, 5, { rgb = true, ext_cmdline = true, ext_linegrid = linegrid })
end)
it('works', function()
@@ -189,7 +171,7 @@ local function test_cmdline(linegrid)
},
{
firstc = '=',
- content = { { '1', 6 }, { '+', 7 }, { '2', 6 } },
+ content = { { '1', 26 }, { '+', 15 }, { '2', 26 } },
pos = 3,
},
}
@@ -503,29 +485,24 @@ local function test_cmdline(linegrid)
map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr>
"map <f5> :let x = input({'prompt':'>'})<cr>
]])
- screen:set_default_attr_ids({
- RBP1 = { background = Screen.colors.Red },
- RBP2 = { background = Screen.colors.Yellow },
- EOB = { bold = true, foreground = Screen.colors.Blue1 },
- })
feed('<f5>(a(b)a)')
screen:expect {
grid = [[
^ |
- {EOB:~ }|*3
+ {1:~ }|*3
|
]],
cmdline = {
{
prompt = '>',
content = {
- { '(', 'RBP1' },
+ { '(', 30 },
{ 'a' },
- { '(', 'RBP2' },
+ { '(', 10 },
{ 'b' },
- { ')', 'RBP2' },
+ { ')', 10 },
{ 'a' },
- { ')', 'RBP1' },
+ { ')', 30 },
},
pos = 7,
},
@@ -865,7 +842,7 @@ describe('cmdline redraw', function()
local screen
before_each(function()
clear()
- screen = new_screen({ rgb = true })
+ screen = Screen.new(25, 5, { rgb = true })
end)
it('with timer', function()
@@ -929,17 +906,17 @@ describe('cmdline redraw', function()
|
{1:~ }|*3
{2:[No Name] }|
- {1::}^a{8:bc} |
+ {1::}^a{17:bc} |
{1:~ }|*2
{3:[Command Line] }|
- {9:-- VISUAL --} |
+ {5:-- VISUAL --} |
]])
feed('<C-C>')
screen:expect([[
|
{1:~ }|*3
{2:[No Name] }|
- {1::}a{8:bc} |
+ {1::}a{17:bc} |
{1:~ }|*2
{3:[Command Line] }|
:^abc |
@@ -1030,7 +1007,7 @@ describe('statusline is redrawn on entering cmdline', function()
before_each(function()
clear()
- screen = new_screen()
+ screen = Screen.new(25, 5)
command('set laststatus=2')
end)
@@ -1093,61 +1070,61 @@ describe('statusline is redrawn on entering cmdline', function()
feed(':echoerr doesnotexist<cr>')
screen:expect {
grid = [[
- {9:c1 }|
+ {5:c1 }|
|
{3:c1 }|
|
{1:~ }|*5
{3: }|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {5:inue}^ |
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {6:inue}^ |
]],
}
feed(':echoerr doesnotexist<cr>')
screen:expect {
grid = [[
- {9:c2 }|
+ {5:c2 }|
|
{3:c2 }|
|
{1:~ }|*2
{3: }|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {5:inue}^ |
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {6:inue}^ |
]],
}
feed(':echoerr doesnotexist<cr>')
screen:expect {
grid = [[
- {9:c3 }|
+ {5:c3 }|
|
{3:c3 }|
{3: }|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {4:E121: Undefined variable: doesnotex}|
- {4:ist} |
- {5:Press ENTER or type command to cont}|
- {5:inue}^ |
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {9:E121: Undefined variable: doesnotex}|
+ {9:ist} |
+ {6:Press ENTER or type command to cont}|
+ {6:inue}^ |
]],
}
feed('<cr>')
screen:expect {
grid = [[
- {9:n3 }|
+ {5:n3 }|
^ |
{3:n3 }|
|
@@ -1202,12 +1179,6 @@ end)
it('tabline is not redrawn in Ex mode #24122', function()
clear()
local screen = Screen.new(60, 5)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- MsgSeparator
- [2] = { reverse = true }, -- TabLineFill
- })
- screen:attach()
exec([[
set showtabline=2
@@ -1224,7 +1195,7 @@ it('tabline is not redrawn in Ex mode #24122', function()
grid = [[
{2:foo }|
|
- {1: }|
+ {3: }|
Entering Ex mode. Type "visual" to go to Normal mode. |
:^ |
]],
@@ -1233,7 +1204,7 @@ it('tabline is not redrawn in Ex mode #24122', function()
feed('echo 1<CR>')
screen:expect {
grid = [[
- {1: }|
+ {3: }|
Entering Ex mode. Type "visual" to go to Normal mode. |
:echo 1 |
1 |
@@ -1247,7 +1218,6 @@ describe('cmdline height', function()
it('does not crash resized screen #14263', function()
local screen = Screen.new(25, 10)
- screen:attach()
command('set cmdheight=9999')
screen:try_resize(25, 5)
assert_alive()
@@ -1268,7 +1238,6 @@ describe('cmdheight=0', function()
before_each(function()
clear()
screen = Screen.new(25, 5)
- screen:attach()
end)
it('with redrawdebug=invalid resize -1', function()
@@ -1535,7 +1504,7 @@ describe('cmdheight=0', function()
it('with silent! at startup', function()
clear { args = { '-c', 'set cmdheight=0', '-c', 'autocmd VimEnter * silent! call Foo()' } }
- screen:attach()
+ screen = Screen.new(25, 5)
-- doesn't crash while not displaying silent! error message
screen:expect {
grid = [[
@@ -1547,7 +1516,7 @@ describe('cmdheight=0', function()
it('with multigrid', function()
clear { args = { '--cmd', 'set cmdheight=0' } }
- screen:attach { ext_multigrid = true }
+ screen = Screen.new(25, 5, { ext_multigrid = true })
api.nvim_buf_set_lines(0, 0, -1, true, { 'p' })
screen:expect {
grid = [[
@@ -1710,7 +1679,7 @@ describe('cmdheight=0', function()
it('can be resized with external messages', function()
clear()
- screen = new_screen({ rgb = true, ext_messages = true })
+ screen = Screen.new(25, 5, { rgb = true, ext_messages = true })
command('set laststatus=2 mouse=a')
command('resize -1')
screen:expect([[
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 619153724b..d7c0657820 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -12,7 +12,6 @@ describe('ui/cursor', function()
before_each(function()
clear()
screen = Screen.new(25, 5)
- screen:attach()
end)
it("'guicursor' is published as a UI event", function()
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 042975f898..fbf16f3afe 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -20,7 +20,6 @@ describe('decorations providers', function()
before_each(function()
clear()
screen = Screen.new(40, 8)
- screen:attach()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
@@ -766,7 +765,6 @@ describe('extmark decorations', function()
before_each( function()
clear()
screen = Screen.new(50, 15)
- screen:attach()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
[2] = {foreground = Screen.colors.Brown};
@@ -1964,7 +1962,7 @@ describe('extmark decorations', function()
]]}
end)
- pending('highlight applies to a full TAB in visual block mode', function()
+ it('highlight applies to a full TAB in visual block mode', function()
screen:try_resize(50, 8)
command('hi! Visual guifg=NONE guibg=LightGrey')
api.nvim_buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'})
@@ -2501,7 +2499,6 @@ describe('decorations: inline virtual text', function()
before_each( function()
clear()
screen = Screen.new(50, 3)
- screen:attach()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
[2] = {foreground = Screen.colors.Brown};
@@ -4121,7 +4118,6 @@ describe('decorations: virtual lines', function()
before_each(function()
clear()
screen = Screen.new(50, 12)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
}
@@ -5046,7 +5042,6 @@ describe('decorations: signs', function()
before_each(function()
clear()
screen = Screen.new(50, 10)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
}
@@ -5662,7 +5657,6 @@ describe('decorations: virt_text', function()
before_each(function()
clear()
screen = Screen.new(50, 10)
- screen:attach()
end)
it('avoids regression in #17638', function()
@@ -5737,7 +5731,6 @@ describe('decorations: window scoped', function()
before_each(function()
clear()
screen = Screen.new(20, 10)
- screen:attach()
screen:add_extra_attr_ids {
[100] = { special = Screen.colors.Red, undercurl = true },
[101] = { url = 'https://example.com' },
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index d6a04f90f6..95159011f1 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -53,7 +53,6 @@ describe('Diff mode screen', function()
feed('<c-w>w:diffthis<cr><c-w>w')
screen = Screen.new(40, 16)
- screen:attach()
end)
it('Add a line in beginning of file 2', function()
@@ -1172,7 +1171,6 @@ end)
it('win_update redraws lines properly', function()
local screen
screen = Screen.new(50, 10)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
@@ -1250,7 +1248,6 @@ end)
-- oldtest: Test_diff_rnu()
it('diff updates line numbers below filler lines', function()
local screen = Screen.new(40, 14)
- screen:attach()
exec([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
vnew
@@ -1310,7 +1307,6 @@ end)
-- oldtest: Test_diff_with_scroll_and_change()
it('Align the filler lines when changing text in diff mode', function()
local screen = Screen.new(40, 20)
- screen:attach()
exec([[
call setline(1, range(1, 15))
vnew
@@ -1376,7 +1372,6 @@ end)
it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function()
local screen = Screen.new(60, 6)
- screen:attach()
eq('0', api.nvim_get_option_value('foldcolumn', {}))
command('diffsplit | bd')
screen:expect([[
@@ -1389,7 +1384,6 @@ end)
it("'relativenumber' doesn't draw beyond end of window in diff mode #29403", function()
local screen = Screen.new(60, 12)
- screen:attach()
command('set relativenumber')
feed('10aa<CR><Esc>gg')
command('vnew')
@@ -1433,7 +1427,6 @@ it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', fun
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Blue, bold = true, background = Screen.colors.Red },
}
- screen:attach()
exec([[
call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g'])
vnew
@@ -1510,7 +1503,6 @@ end)
-- oldtest: Test_diff_breakindent_after_filler()
it("diff mode draws 'breakindent' correctly after filler lines", function()
local screen = Screen.new(45, 8)
- screen:attach()
exec([[
set laststatus=0 diffopt+=followwrap breakindent breakindentopt=min:0
call setline(1, ['a', ' ' .. repeat('c', 50)])
@@ -1562,7 +1554,6 @@ it('diff mode overlapped diff blocks will be merged', function()
]])
local screen = Screen.new(35, 20)
- screen:attach()
command('set winwidth=10 diffopt=filler,internal')
command('args Xdifile1 Xdifile2 | vert all | windo diffthis')
@@ -2054,3 +2045,108 @@ it('diff mode overlapped diff blocks will be merged', function()
|
]])
end)
+
+-- oldtest: Test_diff_topline_noscroll()
+it('diff mode does not scroll with line("w0")', function()
+ local screen = Screen.new(45, 20)
+ exec([[
+ set scrolloff=5
+ call setline(1, range(1,60))
+ vnew
+ call setline(1, range(1,10) + range(50,60))
+ windo diffthis
+ norm! G
+ exe "norm! 30\<C-y>"
+ ]])
+ screen:expect([[
+ {7: }9 │{7: }9 |
+ {7: }10 │{7: }10 |
+ {7: }{23:--------------------}│{7: }{22:11 }|
+ {7: }{23:--------------------}│{7: }{22:12 }|
+ {7: }{23:--------------------}│{7: }{22:13 }|
+ {7: }{23:--------------------}│{7: }{22:14 }|
+ {7: }{23:--------------------}│{7: }{22:15 }|
+ {7: }{23:--------------------}│{7: }{22:16 }|
+ {7: }{23:--------------------}│{7: }{22:17 }|
+ {7: }{23:--------------------}│{7: }{22:18 }|
+ {7: }{23:--------------------}│{7: }{22:19 }|
+ {7: }{23:--------------------}│{7: }{22:20 }|
+ {7: }{23:--------------------}│{7: }{22:^21 }|
+ {7: }{23:--------------------}│{7: }{22:22 }|
+ {7: }{23:--------------------}│{7: }{22:23 }|
+ {7: }{23:--------------------}│{7: }{22:24 }|
+ {7: }{23:--------------------}│{7: }{22:25 }|
+ {7: }{23:--------------------}│{7: }{22:26 }|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command([[echo line('w0', 1001)]])
+ screen:expect([[
+ {7: }9 │{7: }9 |
+ {7: }10 │{7: }10 |
+ {7: }{23:--------------------}│{7: }{22:11 }|
+ {7: }{23:--------------------}│{7: }{22:12 }|
+ {7: }{23:--------------------}│{7: }{22:13 }|
+ {7: }{23:--------------------}│{7: }{22:14 }|
+ {7: }{23:--------------------}│{7: }{22:15 }|
+ {7: }{23:--------------------}│{7: }{22:16 }|
+ {7: }{23:--------------------}│{7: }{22:17 }|
+ {7: }{23:--------------------}│{7: }{22:18 }|
+ {7: }{23:--------------------}│{7: }{22:19 }|
+ {7: }{23:--------------------}│{7: }{22:20 }|
+ {7: }{23:--------------------}│{7: }{22:^21 }|
+ {7: }{23:--------------------}│{7: }{22:22 }|
+ {7: }{23:--------------------}│{7: }{22:23 }|
+ {7: }{23:--------------------}│{7: }{22:24 }|
+ {7: }{23:--------------------}│{7: }{22:25 }|
+ {7: }{23:--------------------}│{7: }{22:26 }|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ 9 |
+ ]])
+ feed('<C-W>p')
+ screen:expect([[
+ {7: }{23:--------------------}│{7: }{22:39 }|
+ {7: }{23:--------------------}│{7: }{22:40 }|
+ {7: }{23:--------------------}│{7: }{22:41 }|
+ {7: }{23:--------------------}│{7: }{22:42 }|
+ {7: }{23:--------------------}│{7: }{22:43 }|
+ {7: }{23:--------------------}│{7: }{22:44 }|
+ {7: }{23:--------------------}│{7: }{22:45 }|
+ {7: }{23:--------------------}│{7: }{22:46 }|
+ {7: }{23:--------------------}│{7: }{22:47 }|
+ {7: }{23:--------------------}│{7: }{22:48 }|
+ {7: }{23:--------------------}│{7: }{22:49 }|
+ {7: }^50 │{7: }50 |
+ {7: }51 │{7: }51 |
+ {7: }52 │{7: }52 |
+ {7: }53 │{7: }53 |
+ {7: }54 │{7: }54 |
+ {7: }55 │{7: }55 |
+ {7:+ }{13:+-- 5 lines: 56····}│{7:+ }{13:+-- 5 lines: 56····}|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ 9 |
+ ]])
+ feed('<C-W>p')
+ screen:expect([[
+ {7: }{23:--------------------}│{7: }{22:39 }|
+ {7: }{23:--------------------}│{7: }{22:40 }|
+ {7: }{23:--------------------}│{7: }{22:41 }|
+ {7: }{23:--------------------}│{7: }{22:42 }|
+ {7: }{23:--------------------}│{7: }{22:43 }|
+ {7: }{23:--------------------}│{7: }{22:^44 }|
+ {7: }{23:--------------------}│{7: }{22:45 }|
+ {7: }{23:--------------------}│{7: }{22:46 }|
+ {7: }{23:--------------------}│{7: }{22:47 }|
+ {7: }{23:--------------------}│{7: }{22:48 }|
+ {7: }{23:--------------------}│{7: }{22:49 }|
+ {7: }50 │{7: }50 |
+ {7: }51 │{7: }51 |
+ {7: }52 │{7: }52 |
+ {7: }53 │{7: }53 |
+ {7: }54 │{7: }54 |
+ {7: }55 │{7: }55 |
+ {7:+ }{13:+-- 5 lines: 56····}│{7:+ }{13:+-- 5 lines: 56····}|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ 9 |
+ ]])
+end)
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
index e1abd43e20..977141ae3e 100644
--- a/test/functional/ui/embed_spec.lua
+++ b/test/functional/ui/embed_spec.lua
@@ -25,34 +25,31 @@ local function test_embed(ext_linegrid)
clear { args_rm = { '--headless' }, args = { ... } }
-- attach immediately after startup, for early UI
- screen = Screen.new(60, 8)
- screen:attach { ext_linegrid = ext_linegrid }
- screen:set_default_attr_ids({
- [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [2] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [3] = { bold = true, foreground = Screen.colors.Blue1 },
- [4] = { bold = true, foreground = Screen.colors.Green },
- [5] = { bold = true, reverse = true },
- [6] = { foreground = Screen.colors.NvimLightGrey3, background = Screen.colors.NvimDarkGrey3 },
- [7] = { foreground = Screen.colors.NvimDarkRed },
- [8] = { foreground = Screen.colors.NvimDarkCyan },
- })
+ screen = Screen.new(60, 8, { ext_linegrid = ext_linegrid })
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.NvimDarkCyan },
+ [101] = { foreground = Screen.colors.NvimDarkRed },
+ [102] = {
+ background = Screen.colors.NvimDarkGrey3,
+ foreground = Screen.colors.NvimLightGrey3,
+ },
+ }
end
it('can display errors', function()
startup('--cmd', 'echoerr invalid+')
screen:expect([[
|*4
- {6: }|
- {7:Error detected while processing pre-vimrc command line:} |
- {7:E121: Undefined variable: invalid} |
- {8:Press ENTER or type command to continue}^ |
+ {102: }|
+ {9:Error detected while processing pre-vimrc command line:} |
+ {9:E121: Undefined variable: invalid} |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
screen:expect([[
^ |
- {3:~ }|*6
+ {1:~ }|*6
|
]])
end)
@@ -64,11 +61,11 @@ local function test_embed(ext_linegrid)
startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
screen:expect([[
|*3
- {6: }|
- {7:Error detected while processing pre-vimrc command line:} |
- {7:foo} |
- {7:bar} |
- {8:Press ENTER or type command to continue}^ |
+ {102: }|
+ {9:Error detected while processing pre-vimrc command line:} |
+ {9:foo} |
+ {101:bar} |
+ {100:Press ENTER or type command to continue}^ |
]])
end)
@@ -77,11 +74,11 @@ local function test_embed(ext_linegrid)
screen:expect {
grid = [[
|*3
- {6: }|
- {7:Error detected while processing pre-vimrc command line:} |
- {7:foo} |
- {7:bar} |
- {8:Press ENTER or type command to continue}^ |
+ {102: }|
+ {9:Error detected while processing pre-vimrc command line:} |
+ {9:foo} |
+ {9:bar} |
+ {6:Press ENTER or type command to continue}^ |
]],
condition = function()
eq(Screen.colors.Green, screen.default_colors.rgb_bg)
@@ -112,13 +109,10 @@ describe('--embed UI', function()
clear { args_rm = { '--headless' }, io_extra = pipe.read, env = { NVIM_LOG_FILE = testlog } }
-- attach immediately after startup, for early UI
- local screen = Screen.new(40, 8)
+ -- rpc_async: Avoid hanging. #24888
+ local screen = Screen.new(40, 8, { stdin_fd = 3 }, false)
screen.rpc_async = true -- Avoid hanging. #24888
- screen:attach { stdin_fd = 3 }
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true },
- }
+ screen:attach()
writer:write 'hello nvim\nfrom external input\n'
writer:shutdown(function()
@@ -139,7 +133,7 @@ describe('--embed UI', function()
^ |
from external input |
{1:~ }|*4
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]]
if not is_os('win') then
@@ -170,13 +164,9 @@ describe('--embed UI', function()
clear { args_rm = { '--headless' }, args = { '-q', '-' }, io_extra = pipe.read }
-- attach immediately after startup, for early UI
- local screen = Screen.new(60, 8)
+ local screen = Screen.new(60, 8, { stdin_fd = 3 }, false)
screen.rpc_async = true -- Avoid hanging. #24888
- screen:attach { stdin_fd = 3 }
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true },
- }
+ screen:attach()
writer:write [[Xbadfile.c:4:12: error: expected ';' before '}' token]]
writer:shutdown(function()
@@ -202,7 +192,7 @@ describe('--embed UI', function()
return 666^ |
} |
{1:~ }|*2
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]]
eq('-', api.nvim_get_option_value('errorfile', {}))
@@ -222,7 +212,6 @@ describe('--embed UI', function()
-- attach immediately after startup, for early UI
screen = Screen.new(40, 8)
screen._handle_default_colors_set = handle_default_colors_set
- screen:attach()
end
startup()
@@ -249,7 +238,6 @@ describe('--embed UI', function()
clear { args_rm = { '--headless' } }
local screen = Screen.new(40, 8)
- screen:attach()
screen:expect {
condition = function()
@@ -336,8 +324,7 @@ describe('--embed --listen UI', function()
ok(var_ok)
eq({}, var)
- local child_screen = Screen.new(40, 6)
- child_screen:attach(nil, child_session)
+ local child_screen = Screen.new(40, 6, nil, child_session)
child_screen:expect {
grid = [[
^ |
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 9b77cb4014..57ef9bcff6 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -640,8 +640,7 @@ describe('float window', function()
end)
it('tp_curwin updated if external window is moved into split', function()
- local screen = Screen.new(20, 7)
- screen:attach { ext_multigrid = true }
+ local _ = Screen.new(20, 7, { ext_multigrid = true })
command('tabnew')
local external_win = api.nvim_open_win(0, true, {external = true, width = 5, height = 5})
@@ -658,8 +657,6 @@ describe('float window', function()
command('tabnext')
eq(2, fn.tabpagenr())
neq(external_win, api.nvim_get_current_win())
-
- screen:detach()
end)
it('no crash with relative="win" after %bdelete #30569', function()
@@ -1018,8 +1015,7 @@ describe('float window', function()
local function with_ext_multigrid(multigrid)
local screen, attrs
before_each(function()
- screen = Screen.new(40,7)
- screen:attach {ext_multigrid=multigrid}
+ screen = Screen.new(40,7, {ext_multigrid=multigrid})
attrs = {
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {background = Screen.colors.LightMagenta},
@@ -1278,7 +1274,7 @@ describe('float window', function()
it('return their configuration', function()
local buf = api.nvim_create_buf(false, false)
local win = api.nvim_open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5, zindex=60})
- local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false}
+ local expected = {anchor='NW', col=5, external=false, focusable=true, mouse=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false}
eq(expected, api.nvim_win_get_config(win))
eq(true, exec_lua([[
local expected, win = ...
@@ -1290,11 +1286,11 @@ describe('float window', function()
end
return true]], expected, win))
- eq({external=false, focusable=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0))
+ eq({external=false, focusable=true, mouse=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0))
if multigrid then
api.nvim_win_set_config(win, {external=true, width=10, height=1})
- eq({external=true,focusable=true,width=10,height=1,relative='',hide=false}, api.nvim_win_get_config(win))
+ eq({external=true,focusable=true,mouse=true,width=10,height=1,relative='',hide=false}, api.nvim_win_get_config(win))
end
end)
@@ -3988,7 +3984,7 @@ describe('float window', function()
]]}
end
eq({relative='win', width=12, height=1, bufpos={1,32}, anchor='NW', hide=false,
- external=false, col=0, row=1, win=firstwin, focusable=true, zindex=50}, api.nvim_win_get_config(win))
+ external=false, col=0, row=1, win=firstwin, focusable=true, mouse=true, zindex=50}, api.nvim_win_get_config(win))
feed('<c-e>')
if multigrid then
@@ -5606,7 +5602,7 @@ describe('float window', function()
end
end)
- it("focus by mouse", function()
+ local function test_float_mouse_focus()
if multigrid then
api.nvim_input_mouse('left', 'press', '', 4, 0, 0)
screen:expect{grid=[[
@@ -5660,10 +5656,18 @@ describe('float window', function()
|
]])
end
+ end
+
+ it("focus by mouse (focusable=true)", function()
+ test_float_mouse_focus()
end)
- it("focus by mouse (focusable=false)", function()
- api.nvim_win_set_config(win, {focusable=false})
+ it("focus by mouse (focusable=false, mouse=true)", function()
+ api.nvim_win_set_config(win, {focusable=false, mouse=true})
+ test_float_mouse_focus()
+ end)
+
+ local function test_float_mouse_no_focus()
api.nvim_buf_set_lines(0, -1, -1, true, {"a"})
expected_pos[4][6] = false
if multigrid then
@@ -5721,6 +5725,16 @@ describe('float window', function()
|
]])
end
+ end
+
+ it("focus by mouse (focusable=false)", function()
+ api.nvim_win_set_config(win, {focusable=false})
+ test_float_mouse_no_focus()
+ end)
+
+ it("focus by mouse (focusable=true, mouse=false)", function()
+ api.nvim_win_set_config(win, {mouse=false})
+ test_float_mouse_no_focus()
end)
it("j", function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 2712e5ff48..aea629df07 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -28,8 +28,7 @@ describe('folded lines', function()
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
- screen = Screen.new(45, 8)
- screen:attach({ rgb = true, ext_multigrid = multigrid })
+ screen = Screen.new(45, 8, { rgb = true, ext_multigrid = multigrid })
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { reverse = true },
@@ -55,6 +54,8 @@ describe('folded lines', function()
},
[19] = { background = Screen.colors.Yellow, foreground = Screen.colors.DarkBlue },
[20] = { background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue },
+ [21] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Green },
+ [22] = { background = Screen.colors.Red, foreground = Screen.colors.Green },
})
end)
@@ -2625,6 +2626,8 @@ describe('folded lines', function()
command('hi! CursorLine guibg=NONE guifg=Red gui=NONE')
command('hi F0 guibg=Red guifg=Black')
command('hi F1 guifg=White')
+ command([[syn match Keyword /\<sentence\>/]])
+ command('hi! Keyword guibg=NONE guifg=Green')
api.nvim_set_option_value('cursorline', true, {})
api.nvim_set_option_value('foldcolumn', '4', {})
api.nvim_set_option_value('foldtext', '', {})
@@ -2662,7 +2665,7 @@ describe('folded lines', function()
## grid 2
{7: }This is a |
{7:- }valid English |
- {7:│+ }{5:sentence composed by······}|
+ {7:│+ }{21:sentence}{5: composed by······}|
{7:│+ }{13:^in his cave.··············}|
{1:~ }|*2
## grid 3
@@ -2672,7 +2675,7 @@ describe('folded lines', function()
screen:expect([[
{7: }This is a |
{7:- }valid English |
- {7:│+ }{5:sentence composed by······}|
+ {7:│+ }{21:sentence}{5: composed by······}|
{7:│+ }{13:^in his cave.··············}|
{1:~ }|*2
|
@@ -2689,7 +2692,7 @@ describe('folded lines', function()
## grid 2
{7: }This is a |
{7:- }^v{14:alid English} |
- {7:│+ }{15:sentence composed by······}|
+ {7:│+ }{22:sentence}{15: composed by······}|
{7:│+ }{15:in his cave.··············}|
{1:~ }|*2
## grid 3
@@ -2699,7 +2702,7 @@ describe('folded lines', function()
screen:expect([[
{7: }This is a |
{7:- }^v{14:alid English} |
- {7:│+ }{15:sentence composed by······}|
+ {7:│+ }{22:sentence}{15: composed by······}|
{7:│+ }{15:in his cave.··············}|
{1:~ }|*2
{11:-- VISUAL LINE --} |
@@ -2715,7 +2718,7 @@ describe('folded lines', function()
## grid 2
a si sihT{7: }|
{14:hsilgnE dila}^v{7: -}|
- {15:······yb desopmoc ecnetnes}{7: +│}|
+ {15:······yb desopmoc }{22:ecnetnes}{7: +│}|
{15:··············.evac sih ni}{7: +│}|
{1: ~}|*2
## grid 3
@@ -2725,7 +2728,7 @@ describe('folded lines', function()
screen:expect([[
a si sihT{7: }|
{14:hsilgnE dila}^v{7: -}|
- {15:······yb desopmoc ecnetnes}{7: +│}|
+ {15:······yb desopmoc }{22:ecnetnes}{7: +│}|
{15:··············.evac sih ni}{7: +│}|
{1: ~}|*2
{11:-- VISUAL LINE --} |
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 87d66fa604..0f4696f3d3 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -32,7 +32,6 @@ describe('highlight: `:syntax manual`', function()
before_each(function()
clear()
screen = Screen.new(20, 5)
- screen:attach()
-- syntax highlight for vimscript's "echo"
end)
@@ -93,7 +92,6 @@ describe('highlight defaults', function()
[100] = { foreground = Screen.colors.Red, background = Screen.colors.WebGreen },
[101] = { italic = true },
}
- screen:attach()
end)
it('window status bar', function()
@@ -303,7 +301,6 @@ describe('highlight', function()
it('Visual', function()
local screen = Screen.new(45, 5)
- screen:attach()
insert([[
line1 foo bar
abcdefghijklmnopqrs
@@ -428,7 +425,6 @@ describe('highlight', function()
it('cterm=standout gui=standout', function()
local screen = Screen.new(20, 5)
- screen:attach()
screen:add_extra_attr_ids {
[100] = {
foreground = Screen.colors.Blue1,
@@ -454,7 +450,6 @@ describe('highlight', function()
it('strikethrough', function()
local screen = Screen.new(25, 6)
- screen:attach()
feed_command('syntax on')
feed_command('syn keyword TmpKeyword foo')
feed_command('hi! Awesome cterm=strikethrough gui=strikethrough')
@@ -490,7 +485,6 @@ describe('highlight', function()
background = Screen.colors.Yellow,
},
}
- screen:attach()
feed_command('syntax on')
feed_command('hi! Underlined cterm=underline gui=underline')
feed_command('syn keyword Underlined foobar')
@@ -532,7 +526,6 @@ describe('highlight', function()
it('guisp (special/undercurl)', function()
local screen = Screen.new(25, 10)
- screen:attach()
feed_command('syntax on')
feed_command('syn keyword TmpKeyword neovim')
feed_command('syn keyword TmpKeyword1 special')
@@ -585,7 +578,6 @@ describe('highlight', function()
it("'diff', syntax and extmark #23722", function()
local screen = Screen.new(25, 10)
- screen:attach()
exec([[
new
call setline(1, ['', '01234 6789'])
@@ -631,7 +623,6 @@ describe("'listchars' highlight", function()
before_each(function()
clear()
screen = Screen.new(20, 5)
- screen:attach()
end)
it("'cursorline' and 'cursorcolumn'", function()
@@ -873,7 +864,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[100] = { background = Screen.colors.LightRed },
[101] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 },
}
- screen:attach()
command('filetype on')
command('syntax on')
@@ -906,7 +896,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[102] = { foreground = Screen.colors.Grey0, background = Screen.colors.Grey100 },
[103] = { foreground = Screen.colors.Yellow1, background = Screen.colors.Grey100 },
}
- screen:attach()
feed_command('set wrap cursorline')
feed_command('set showbreak=>>>')
@@ -957,7 +946,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[102] = { foreground = Screen.colors.Black, background = Screen.colors.Grey100 },
[103] = { foreground = Screen.colors.WebGreen, background = Screen.colors.Red },
}
- screen:attach()
command('set wrap cursorline cursorlineopt=screenline')
command('set showbreak=>>>')
@@ -1081,7 +1069,6 @@ describe('CursorLine and CursorLineNr highlights', function()
-- oldtest: Test_cursorline_screenline_resize()
it("'cursorlineopt' screenline is updated on window resize", function()
local screen = Screen.new(75, 8)
- screen:attach()
exec([[
50vnew
call setline(1, repeat('xyz ', 30))
@@ -1123,7 +1110,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[100] = { background = Screen.colors.LightRed },
[101] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 },
}
- screen:attach()
command('set cursorline relativenumber')
command('call setline(1, ["","1","2","3",""])')
feed('Gy3k')
@@ -1151,7 +1137,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[100] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 },
[101] = { background = Screen.colors.LightRed },
}
- screen:attach()
command('set cursorline')
command('call setline(1, repeat(["abc"], 50))')
feed('V<C-f>zbkkjk')
@@ -1166,7 +1151,6 @@ describe('CursorLine and CursorLineNr highlights', function()
-- oldtest: Test_cursorline_callback()
it('is updated if cursor is moved up from timer vim-patch:8.2.4591', function()
local screen = Screen.new(50, 8)
- screen:attach()
exec([[
call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
set cursorline
@@ -1207,7 +1191,6 @@ describe('CursorLine and CursorLineNr highlights', function()
[100] = { background = Screen.colors.Plum1, underline = true },
[101] = { background = Screen.colors.Red1, bold = true, underline = true },
}
- screen:attach()
command('hi CursorLine ctermbg=red ctermfg=white guibg=red guifg=white')
command('set cursorline')
@@ -1267,7 +1250,6 @@ describe('CursorLine and CursorLineNr highlights', function()
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Black, bold = true, background = Screen.colors.Grey100 },
}
- screen:attach()
command('hi CursorLine guibg=red guifg=white')
command('hi CursorLineNr guibg=white guifg=black gui=bold')
@@ -1308,7 +1290,6 @@ describe('CursorColumn highlight', function()
screen:add_extra_attr_ids {
[100] = { background = Screen.colors.Blue1 },
}
- screen:attach()
end)
it('is updated when pressing "i" on a TAB character', function()
@@ -1435,7 +1416,6 @@ describe('ColorColumn highlight', function()
[101] = { background = Screen.colors.LightRed },
[102] = { foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightRed },
}
- screen:attach()
end)
-- oldtest: Test_colorcolumn()
@@ -1538,7 +1518,6 @@ describe('MsgSeparator highlight and msgsep fillchar', function()
[12] = { background = Screen.colors.Gray60, bold = true, foreground = tonumber('0x297d4e') },
[13] = { background = tonumber('0xff4cff'), bold = true, foreground = tonumber('0xb200ff') },
})
- screen:attach()
end)
it('works', function()
@@ -1653,7 +1632,6 @@ describe("'winhighlight' highlight", function()
before_each(function()
clear()
screen = Screen.new(20, 8)
- screen:attach()
screen:set_default_attr_ids {
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { background = Screen.colors.DarkBlue },
@@ -1691,6 +1669,7 @@ describe("'winhighlight' highlight", function()
[29] = { foreground = Screen.colors.Blue1, background = Screen.colors.Red, bold = true },
[30] = { background = tonumber('0xff8800') },
[31] = { background = tonumber('0xff8800'), bold = true, foreground = Screen.colors.Blue },
+ [32] = { bold = true, reverse = true, background = Screen.colors.DarkGreen },
}
command('hi Background1 guibg=DarkBlue')
command('hi Background2 guibg=DarkGreen')
@@ -2253,10 +2232,10 @@ describe("'winhighlight' highlight", function()
some text |
more tex^t |
{0:~ }|
- {3:[No Name] }{1:2,9 All}|
+ {3:[No Name] }{11:2,9 All}|
some text |
more text |
- {4:[No Name] }{1:1,1 All}|
+ {4:[No Name] }{14:1,1 All}|
|
]],
}
@@ -2267,10 +2246,10 @@ describe("'winhighlight' highlight", function()
some text |
more tex^t |
{0:~ }|
- {3:[No Name] }{5:2,9 All}|
+ {3:[No Name] }{32:2,9 All}|
some text |
more text |
- {4:[No Name] }{1:1,1 All}|
+ {4:[No Name] }{14:1,1 All}|
|
]],
}
@@ -2281,10 +2260,10 @@ describe("'winhighlight' highlight", function()
some tex^t |
more text |
{0:~ }|
- {3:[No Name] }{5:1,9 All}|
+ {3:[No Name] }{32:1,9 All}|
some text |
more text |
- {4:[No Name] }{1:1,1 All}|
+ {4:[No Name] }{14:1,1 All}|
|
]],
}
@@ -2316,7 +2295,6 @@ describe('highlight namespaces', function()
before_each(function()
clear()
screen = Screen.new(25, 10)
- screen:attach()
screen:set_default_attr_ids {
[1] = { foreground = Screen.colors.Blue, bold = true },
[2] = { background = Screen.colors.DarkGrey },
@@ -2425,16 +2403,24 @@ describe('highlight namespaces', function()
end)
it('winhl does not accept invalid value #24586', function()
- local res = exec_lua([[
- local curwin = vim.api.nvim_get_current_win()
- vim.api.nvim_command("set winhl=Normal:Visual")
- local _, msg = pcall(vim.api.nvim_command,"set winhl='Normal:Wrong'")
- return { msg, vim.wo[curwin].winhl }
- ]])
- eq({
- 'Vim(set):E5248: Invalid character in group name',
- 'Normal:Visual',
- }, res)
+ command('set winhl=Normal:Visual')
+ for _, cmd in ipairs({
+ [[set winhl='Normal:Wrong']],
+ [[set winhl=Normal:Wrong']],
+ [[set winhl='Normal:Wrong]],
+ }) do
+ local res = exec_lua(
+ [[
+ local _, msg = pcall(vim.api.nvim_command, ...)
+ return { msg, vim.wo.winhl }
+ ]],
+ cmd
+ )
+ eq({
+ 'Vim(set):E5248: Invalid character in group name',
+ 'Normal:Visual',
+ }, res)
+ end
end)
it('Normal in set_hl #25474', function()
@@ -2458,10 +2444,8 @@ describe('highlight namespaces', function()
end)
describe('synIDattr()', function()
- local screen
before_each(function()
clear()
- screen = Screen.new(50, 7)
command('highlight Normal ctermfg=252 guifg=#ff0000 guibg=Black')
-- Salmon #fa8072 Maroon #800000
command(
@@ -2486,7 +2470,7 @@ describe('synIDattr()', function()
end)
it('returns gui-color if RGB-capable UI is attached', function()
- screen:attach({ rgb = true })
+ local _ = Screen.new(50, 7, { rgb = true })
eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")'))
eq('Black', eval('synIDattr(hlID("Normal"), "bg")'))
eq('Salmon', eval('synIDattr(hlID("Keyword"), "fg")'))
@@ -2494,15 +2478,15 @@ describe('synIDattr()', function()
end)
it('returns #RRGGBB value for fg#/bg#/sp#', function()
- screen:attach({ rgb = true })
+ local _ = Screen.new(50, 7, { rgb = true })
eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg#")'))
eq('#000000', eval('synIDattr(hlID("Normal"), "bg#")'))
eq('#fa8072', eval('synIDattr(hlID("Keyword"), "fg#")'))
eq('#800000', eval('synIDattr(hlID("Keyword"), "sp#")'))
end)
- it('returns color number if non-GUI', function()
- screen:attach({ rgb = false })
+ it('returns color number if non-RGB GUI', function()
+ local _ = Screen.new(50, 7, { rgb = false })
eq('252', eval('synIDattr(hlID("Normal"), "fg")'))
eq('79', eval('synIDattr(hlID("Keyword"), "fg")'))
end)
@@ -2527,10 +2511,8 @@ describe('synIDattr()', function()
end)
describe('fg/bg special colors', function()
- local screen
before_each(function()
clear()
- screen = Screen.new(50, 7)
command('highlight Normal ctermfg=145 ctermbg=16 guifg=#ff0000 guibg=Black')
command('highlight Visual ctermfg=bg ctermbg=fg guifg=bg guibg=fg guisp=bg')
end)
@@ -2549,7 +2531,7 @@ describe('fg/bg special colors', function()
end)
it('resolve to "Normal" values in RGB-capable UI', function()
- screen:attach({ rgb = true })
+ local _ = Screen.new(50, 7, { rgb = true })
eq('bg', eval('synIDattr(hlID("Visual"), "fg")'))
eq(eval('synIDattr(hlID("Normal"), "bg#")'), eval('synIDattr(hlID("Visual"), "fg#")'))
eq('fg', eval('synIDattr(hlID("Visual"), "bg")'))
@@ -2559,7 +2541,7 @@ describe('fg/bg special colors', function()
end)
it('resolve after the "Normal" group is modified', function()
- screen:attach({ rgb = true })
+ local _ = Screen.new(50, 7, { rgb = true })
local new_guibg = '#282c34'
local new_guifg = '#abb2bf'
command('highlight Normal guifg=' .. new_guifg .. ' guibg=' .. new_guibg)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index a255047ed7..f8f5ee9488 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -17,12 +17,7 @@ describe('ext_hlstate detailed highlights', function()
clear()
command('syntax on')
command('hi VertSplit gui=reverse')
- screen = Screen.new(40, 8)
- screen:attach({ ext_hlstate = true })
- end)
-
- after_each(function()
- screen:detach()
+ screen = Screen.new(40, 8, { ext_hlstate = true })
end)
it('work with combined UI and syntax highlights', function()
@@ -33,42 +28,42 @@ describe('ext_hlstate detailed highlights', function()
api.nvim_buf_add_highlight(0, -1, 'Statement', 1, 5, -1)
command('/th co')
- screen:expect(
- [[
+ screen:expect {
+ grid = [[
these are {1:some} lines |
^wi{2:th }{4:co}{3:lorful text} |
{5:~ }|*5
- {8:search hit BOTTOM, continuing at TOP}{7: }|
+ {8:search hit BOTTOM, continuing at TOP}{6: }|
]],
- {
+ attr_ids = {
[1] = {
- { foreground = Screen.colors.Magenta },
- { { hi_name = 'Constant', kind = 'syntax' } },
+ { foreground = Screen.colors.Magenta1 },
+ { { kind = 'syntax', hi_name = 'Constant' } },
},
[2] = {
- { background = Screen.colors.Yellow },
- { { hi_name = 'Search', ui_name = 'Search', kind = 'ui' } },
+ { background = Screen.colors.Yellow1 },
+ { { kind = 'ui', ui_name = 'Search', hi_name = 'Search' } },
},
[3] = {
- { bold = true, foreground = Screen.colors.Brown },
- { { hi_name = 'Statement', kind = 'syntax' } },
+ { foreground = Screen.colors.Brown, bold = true },
+ { { kind = 'syntax', hi_name = 'Statement' } },
},
[4] = {
- { bold = true, background = Screen.colors.Yellow, foreground = Screen.colors.Brown },
+ { background = Screen.colors.Yellow1, bold = true, foreground = Screen.colors.Brown },
{ 3, 2 },
},
[5] = {
- { bold = true, foreground = Screen.colors.Blue1 },
- { { hi_name = 'NonText', ui_name = 'EndOfBuffer', kind = 'ui' } },
+ { foreground = Screen.colors.Blue, bold = true },
+ { { kind = 'ui', ui_name = 'EndOfBuffer', hi_name = 'NonText' } },
},
- [6] = {
- { foreground = Screen.colors.Red },
- { { hi_name = 'WarningMsg', ui_name = 'WarningMsg', kind = 'ui' } },
+ [6] = { {}, { { kind = 'ui', ui_name = 'MsgArea', hi_name = 'MsgArea' } } },
+ [7] = {
+ { foreground = Screen.colors.Red1 },
+ { { kind = 'syntax', hi_name = 'WarningMsg' } },
},
- [7] = { {}, { { hi_name = 'MsgArea', ui_name = 'MsgArea', kind = 'ui' } } },
- [8] = { { foreground = Screen.colors.Red }, { 7, 6 } },
- }
- )
+ [8] = { { foreground = Screen.colors.Red1 }, { 6, 7 } },
+ },
+ }
end)
it('work with cleared UI highlights', function()
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index c11e009fef..37dc0f5195 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -66,7 +66,6 @@ local function common_setup(screen, inccommand, text)
command('syntax on')
command('set nohlsearch')
command('hi Substitute guifg=red guibg=yellow')
- screen:attach()
screen:add_extra_attr_ids {
[100] = { underline = true },
@@ -556,10 +555,9 @@ describe(":substitute, 'inccommand' preserves undo", function()
end)
it('with undolevels=1', function()
- local screen = Screen.new(20, 10)
-
for _, case in pairs(cases) do
clear()
+ local screen = Screen.new(20, 10)
common_setup(screen, case, default_text)
screen:expect([[
Inc substitution on |
@@ -617,10 +615,9 @@ describe(":substitute, 'inccommand' preserves undo", function()
end)
it('with undolevels=2', function()
- local screen = Screen.new(20, 10)
-
for _, case in pairs(cases) do
clear()
+ local screen = Screen.new(20, 10)
common_setup(screen, case, default_text)
command('set undolevels=2')
@@ -697,10 +694,9 @@ describe(":substitute, 'inccommand' preserves undo", function()
end)
it('with undolevels=-1', function()
- local screen = Screen.new(20, 10)
-
for _, case in pairs(cases) do
clear()
+ local screen = Screen.new(20, 10)
common_setup(screen, case, default_text)
command('set undolevels=-1')
@@ -728,6 +724,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
-- repeat with an interrupted substitution
clear()
+ screen = Screen.new(20, 10)
common_setup(screen, case, default_text)
command('set undolevels=-1')
@@ -2510,7 +2507,7 @@ describe(':substitute', function()
end)
it("doesn't prompt to swap cmd range", function()
- screen = Screen.new(50, 8) -- wide to avoid hit-enter prompt
+ screen:try_resize(50, 8) -- wide to avoid hit-enter prompt
common_setup(screen, 'split', default_text)
feed(':2,1s/tw/MO/g')
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 12f3640b54..2d26d2c5e0 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -239,7 +239,6 @@ describe("'inccommand' for user commands", function()
before_each(function()
clear()
screen = Screen.new(40, 17)
- screen:attach()
exec_lua(setup_replace_cmd)
command('set cmdwinheight=5')
insert [[
@@ -508,6 +507,39 @@ describe("'inccommand' for user commands", function()
feed(':Test')
eq('nosplit', api.nvim_get_option_value('inccommand', {}))
end)
+
+ it('does not flush intermediate cursor position at end of message grid', function()
+ exec_lua([[
+ vim.api.nvim_create_user_command('Test', function() end, {
+ nargs = '*',
+ preview = function(_, _, _)
+ vim.api.nvim_buf_set_text(0, 0, 0, 1, -1, { "Preview" })
+ vim.cmd.sleep("1m")
+ return 1
+ end
+ })
+ ]])
+ local cursor_goto = screen._handle_grid_cursor_goto
+ screen._handle_grid_cursor_goto = function(...)
+ cursor_goto(...)
+ assert(screen._cursor.col < 12)
+ end
+ feed(':Test baz<Left><Left>arb')
+ screen:expect({
+ grid = [[
+ Preview |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
+ |
+ {1:~ }|*8
+ :Test barb^az |
+ ]],
+ })
+ end)
end)
describe("'inccommand' with multiple buffers", function()
@@ -516,7 +548,6 @@ describe("'inccommand' with multiple buffers", function()
before_each(function()
clear()
screen = Screen.new(40, 17)
- screen:attach()
exec_lua(setup_replace_cmd)
command('set cmdwinheight=10')
insert [[
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index f377939458..90e0b3e380 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -282,7 +282,6 @@ end)
it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2.0839', function()
local screen = Screen.new(60, 8)
- screen:attach()
command([[nnoremap <C-6> <Cmd>echo 'hit ctrl-6'<CR>]])
feed_command('ls')
screen:expect([[
@@ -328,7 +327,6 @@ describe('input non-printable chars', function()
it("doesn't crash when echoing them back", function()
write_file('Xtest-overwrite', [[foobar]])
local screen = Screen.new(60, 8)
- screen:attach()
command('set shortmess-=F')
feed_command('e Xtest-overwrite')
@@ -428,7 +426,6 @@ describe('display is updated', function()
local screen
before_each(function()
screen = Screen.new(60, 8)
- screen:attach()
end)
it('in Insert mode after <Nop> mapping #17911', function()
diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua
index 03eed5a49c..b564c01eaa 100644
--- a/test/functional/ui/linematch_spec.lua
+++ b/test/functional/ui/linematch_spec.lua
@@ -38,7 +38,6 @@ describe('Diff mode screen with 3 diffs open', function()
feed(':windo diffthis<cr>')
screen = Screen.new(100, 16)
- screen:attach()
feed('<c-w>=')
feed(':windo set nu!<cr>')
end)
@@ -217,7 +216,6 @@ describe('Diff mode screen with 2 diffs open', function()
feed(':windo diffthis<cr>')
screen = Screen.new(100, 20)
- screen:attach()
feed('<c-w>=')
feed(':windo set nu!<cr>')
end)
@@ -1093,7 +1091,6 @@ describe('regressions', function()
clear()
feed(':set diffopt+=linematch:30<cr>')
screen = Screen.new(100, 20)
- screen:attach()
-- line must be greater than MATCH_CHAR_MAX_LEN
n.api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', 1000) .. 'hello' })
n.exec 'vnew'
@@ -1105,7 +1102,6 @@ describe('regressions', function()
clear()
feed(':set diffopt+=linematch:10<cr>')
screen = Screen.new(100, 20)
- screen:attach()
local lines = {}
for i = 0, 29 do
lines[#lines + 1] = tostring(i)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index a3e5068e55..734877d262 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -30,8 +30,7 @@ describe('ui/ext_messages', function()
before_each(function()
clear()
- screen = Screen.new(25, 5)
- screen:attach({ rgb = true, ext_messages = true, ext_popupmenu = true })
+ screen = Screen.new(25, 5, { rgb = true, ext_messages = true, ext_popupmenu = true })
screen:add_extra_attr_ids {
[100] = { undercurl = true, special = Screen.colors.Red },
}
@@ -50,7 +49,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { '\ntest\n[O]k: ', 6 } },
+ content = { { '\ntest\n[O]k: ', 6, 11 } },
kind = 'confirm',
},
},
@@ -78,7 +77,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { '\ntest\n[O]k: ', 6 } },
+ content = { { '\ntest\n[O]k: ', 6, 11 } },
kind = 'confirm',
},
},
@@ -92,7 +91,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { '\ntest\n[O]k: ', 6 } },
+ content = { { '\ntest\n[O]k: ', 6, 11 } },
kind = 'confirm',
},
{
@@ -100,7 +99,7 @@ describe('ui/ext_messages', function()
kind = 'echo',
},
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -117,7 +116,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6 } },
+ content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6, 19 } },
kind = 'confirm_sub',
},
},
@@ -136,7 +135,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'W10: Warning: Changing a readonly file', 19 } },
+ content = { { 'W10: Warning: Changing a readonly file', 19, 27 } },
kind = 'wmsg',
},
},
@@ -152,7 +151,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'search hit BOTTOM, continuing at TOP', 19 } },
+ content = { { 'search hit BOTTOM, continuing at TOP', 19, 27 } },
kind = 'wmsg',
},
},
@@ -168,15 +167,15 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'Error detected while processing :', 9 } },
+ content = { { 'Error detected while processing :', 9, 7 } },
kind = 'emsg',
},
{
- content = { { 'E605: Exception not caught: foo', 9 } },
+ content = { { 'E605: Exception not caught: foo', 9, 7 } },
kind = '',
},
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -209,7 +208,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
- content = { { 'raa', 9 } },
+ content = { { 'raa', 9, 7 } },
kind = 'echoerr',
} },
}
@@ -236,15 +235,15 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'bork', 9 } },
+ content = { { 'bork', 9, 7 } },
kind = 'echoerr',
},
{
- content = { { 'fail', 9 } },
+ content = { { 'fail', 9, 7 } },
kind = 'echoerr',
},
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -258,19 +257,19 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'bork', 9 } },
+ content = { { 'bork', 9, 7 } },
kind = 'echoerr',
},
{
- content = { { 'fail', 9 } },
+ content = { { 'fail', 9, 7 } },
kind = 'echoerr',
},
{
- content = { { 'extrafail', 9 } },
+ content = { { 'extrafail', 9, 7 } },
kind = 'echoerr',
},
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -292,7 +291,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
- content = { { 'problem', 9 } },
+ content = { { 'problem', 9, 7 } },
kind = 'echoerr',
} },
cmdline = {
@@ -320,15 +319,15 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
msg_history = {
- { kind = 'echoerr', content = { { 'raa', 9 } } },
- { kind = 'echoerr', content = { { 'bork', 9 } } },
- { kind = 'echoerr', content = { { 'fail', 9 } } },
- { kind = 'echoerr', content = { { 'extrafail', 9 } } },
- { kind = 'echoerr', content = { { 'problem', 9 } } },
+ { kind = 'echoerr', content = { { 'raa', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'bork', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'fail', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'extrafail', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'problem', 9, 7 } } },
},
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -351,10 +350,12 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'bork\nfail', 9 } },
- kind = 'echoerr',
- } },
+ messages = {
+ {
+ content = { { 'bork\nfail', 9, 7 } },
+ kind = 'echoerr',
+ },
+ },
}
feed(':messages<cr>')
@@ -365,13 +366,13 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
msg_history = {
{
- content = { { 'bork\nfail', 9 } },
+ content = { { 'bork\nfail', 9, 7 } },
kind = 'echoerr',
},
},
@@ -418,15 +419,15 @@ describe('ui/ext_messages', function()
{
content = {
{ '\nErrorMsg ' },
- { 'xxx', 9 },
+ { 'xxx', 9, 7 },
{ ' ' },
- { 'ctermfg=', 18 },
+ { 'ctermfg=', 18, 6 },
{ '15 ' },
- { 'ctermbg=', 18 },
+ { 'ctermbg=', 18, 6 },
{ '1 ' },
- { 'guifg=', 18 },
+ { 'guifg=', 18, 6 },
{ 'White ' },
- { 'guibg=', 18 },
+ { 'guibg=', 18, 6 },
{ 'Red' },
},
kind = '',
@@ -446,7 +447,10 @@ describe('ui/ext_messages', function()
messages = {
{ content = { { 'x #1' } }, kind = '' },
{ content = { { 'y #2' } }, kind = '' },
- { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' },
+ {
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ kind = 'return_prompt',
+ },
},
}
end)
@@ -459,7 +463,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --', 5 } },
+ showmode = { { '-- INSERT --', 5, 12 } },
}
feed('alphpabet<cr>alphanum<cr>')
@@ -470,7 +474,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
- showmode = { { '-- INSERT --', 5 } },
+ showmode = { { '-- INSERT --', 5, 12 } },
}
feed('<c-x>')
@@ -481,7 +485,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
- showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5 } },
+ showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 12 } },
}
feed('<c-p>')
@@ -497,7 +501,7 @@ describe('ui/ext_messages', function()
items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } },
pos = 1,
},
- showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 1 of 2', 6 } },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
}
-- echomsg and showmode don't overwrite each other, this is the same
@@ -519,7 +523,7 @@ describe('ui/ext_messages', function()
content = { { 'stuff' } },
kind = 'echomsg',
} },
- showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 1 of 2', 6 } },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
}
feed('<c-p>')
@@ -539,7 +543,7 @@ describe('ui/ext_messages', function()
content = { { 'stuff' } },
kind = 'echomsg',
} },
- showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 2 of 2', 6 } },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 2 of 2', 6, 19 } },
}
feed('<esc>:messages<cr>')
@@ -556,7 +560,7 @@ describe('ui/ext_messages', function()
} },
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -570,7 +574,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5 } },
+ showmode = { { 'recording @q', 5, 12 } },
}
feed('i')
@@ -579,7 +583,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --recording @q', 5 } },
+ showmode = { { '-- INSERT --recording @q', 5, 12 } },
}
feed('<esc>')
@@ -588,7 +592,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5 } },
+ showmode = { { 'recording @q', 5, 12 } },
}
feed('q')
@@ -607,7 +611,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5 } },
+ showmode = { { 'recording @q', 5, 12 } },
mode = 'normal',
}
@@ -617,7 +621,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5 } },
+ showmode = { { 'recording @q', 5, 12 } },
mode = 'insert',
}
@@ -627,7 +631,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5 } },
+ showmode = { { 'recording @q', 5, 12 } },
mode = 'normal',
}
@@ -643,20 +647,22 @@ describe('ui/ext_messages', function()
it('supports &showcmd and &ruler', function()
command('set showcmd ruler')
- screen:expect {
+ command('hi link MsgArea ErrorMsg')
+ screen:expect({
grid = [[
- ^ |
- {1:~ }|*4
- ]],
- ruler = { { '0,0-1 All' } },
- }
+ ^ |
+ {1:~ }|*4
+ ]],
+ ruler = { { '0,0-1 All', 9, 62 } },
+ })
+ command('hi clear MsgArea')
feed('i')
screen:expect {
grid = [[
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --', 5 } },
+ showmode = { { '-- INSERT --', 5, 12 } },
ruler = { { '0,1 All' } },
}
feed('abcde<cr>12345<esc>')
@@ -694,7 +700,7 @@ describe('ui/ext_messages', function()
{17:123}45 |
{1:~ }|*3
]],
- showmode = { { '-- VISUAL BLOCK --', 5 } },
+ showmode = { { '-- VISUAL BLOCK --', 5, 12 } },
showcmd = { { '2x3' } },
ruler = { { '1,3 All' } },
})
@@ -775,7 +781,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
- content = { { 'bork', 9 } },
+ content = { { 'bork', 9, 7 } },
kind = 'echoerr',
} },
}
@@ -800,7 +806,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
- content = { { 'E117: Unknown function: nosuchfunction', 9 } },
+ content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } },
kind = 'emsg',
},
},
@@ -815,12 +821,12 @@ describe('ui/ext_messages', function()
msg_history = {
{ kind = 'echomsg', content = { { 'howdy' } } },
{ kind = '', content = { { 'Type :qa and press <Enter> to exit Nvim' } } },
- { kind = 'echoerr', content = { { 'bork', 9 } } },
- { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9 } } },
+ { kind = 'echoerr', content = { { 'bork', 9, 7 } } },
+ { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } } },
},
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6 } },
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
},
},
@@ -893,6 +899,7 @@ stack traceback:
[C]: in function 'error'
[string ":lua"]:1: in main chunk]],
9,
+ 7,
},
},
kind = 'lua_error',
@@ -912,7 +919,7 @@ stack traceback:
messages = {
{
content = {
- { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9 },
+ { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 7 },
},
kind = 'rpc_error',
},
@@ -937,7 +944,7 @@ stack traceback:
{
content = {
{ '\nn Q @@\nn Y y$\nn j ' },
- { '*', 18 },
+ { '*', 18, 1 },
{ ' k' },
},
kind = '',
@@ -1035,7 +1042,10 @@ stack traceback:
{1:~ }|*4
]],
messages = {
- { content = { { 'wow, ', 10 }, { 'such\n\nvery ', 9 }, { 'color', 8 } }, kind = 'echomsg' },
+ {
+ content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
+ kind = 'echomsg',
+ },
},
}
@@ -1057,10 +1067,16 @@ stack traceback:
{1:~ }|*4
]],
messages = {
- { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' },
+ {
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ kind = 'return_prompt',
+ },
},
msg_history = {
- { content = { { 'wow, ', 10 }, { 'such\n\nvery ', 9 }, { 'color', 8 } }, kind = 'echomsg' },
+ {
+ content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
+ kind = 'echomsg',
+ },
},
}
@@ -1097,14 +1113,40 @@ stack traceback:
})
eq(showmode, 1)
end)
+
+ it('emits single message for multiline print())', function()
+ exec_lua([[print("foo\nbar\nbaz")]])
+ screen:expect({
+ messages = {
+ {
+ content = { { 'foo\nbar\nbaz' } },
+ kind = 'lua_print',
+ },
+ },
+ })
+ exec_lua([[print(vim.inspect({ foo = "bar" }))]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ messages = {
+ {
+ content = { { '{\n foo = "bar"\n}' } },
+ kind = 'lua_print',
+ },
+ },
+ })
+ exec_lua([[vim.print({ foo = "bar" })]])
+ screen:expect_unchanged()
+ end)
end)
describe('ui/builtin messages', function()
local screen
before_each(function()
clear()
- screen = Screen.new(60, 7)
- screen:attach({ rgb = true, ext_popupmenu = true })
+ screen = Screen.new(60, 7, { rgb = true, ext_popupmenu = true })
screen:add_extra_attr_ids {
[100] = { background = Screen.colors.LightRed },
[101] = { background = Screen.colors.Grey20 },
@@ -1652,8 +1694,7 @@ describe('ui/ext_messages', function()
before_each(function()
clear { args_rm = { '--headless' }, args = { '--cmd', 'set shortmess-=I' } }
- screen = Screen.new(80, 24)
- screen:attach({ rgb = true, ext_messages = true, ext_popupmenu = true })
+ screen = Screen.new(80, 24, { rgb = true, ext_messages = true, ext_popupmenu = true })
end)
it('supports intro screen', function()
@@ -1678,7 +1719,7 @@ describe('ui/ext_messages', function()
{1:~ }type :help iccf{18:<Enter>} for information {1: }|
{1:~ }|*5
]]
- local showmode = { { '-- INSERT --', 5 } }
+ local showmode = { { '-- INSERT --', 5, 12 } }
screen:expect(introscreen)
-- <c-l> (same as :mode) does _not_ clear intro message
@@ -1752,7 +1793,10 @@ describe('ui/ext_messages', function()
|*5
]],
messages = {
- { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' },
+ {
+ content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ kind = 'return_prompt',
+ },
},
}
@@ -1875,8 +1919,7 @@ end)
it('ui/ext_multigrid supports intro screen', function()
clear { args_rm = { '--headless' }, args = { '--cmd', 'set shortmess-=I' } }
- local screen = Screen.new(80, 24)
- screen:attach({ rgb = true, ext_multigrid = true })
+ local screen = Screen.new(80, 24, { rgb = true, ext_multigrid = true })
screen:expect {
grid = [[
@@ -1951,7 +1994,6 @@ describe('ui/msg_puts_printf', function()
clear({ env = { LANG = 'ja_JP.UTF-8' } })
screen = Screen.new(25, 5)
- screen:attach()
if is_os('win') then
if os.execute('chcp 932 > NUL 2>&1') ~= 0 then
@@ -1992,7 +2034,6 @@ describe('pager', function()
before_each(function()
clear()
screen = Screen.new(35, 8)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
@@ -2048,8 +2089,6 @@ aliquip ex ea commodo consequat.]]
end)
it('can be quit with Lua #11224 #16537', function()
- -- NOTE: adds "4" to message history, although not displayed initially
- -- (triggered the more prompt).
screen:try_resize(40, 5)
feed(':lua for i=0,10 do print(i) end<cr>')
screen:expect {
@@ -2079,13 +2118,13 @@ aliquip ex ea commodo consequat.]]
{4:-- More --}^ |
]],
}
- feed('j')
+ feed('G')
screen:expect {
grid = [[
- 1 |
- 2 |
- 3 |
- 4 |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
{4:Press ENTER or type command to continue}^ |
]],
}
@@ -2788,8 +2827,7 @@ it('pager works in headless mode with UI attached', function()
end)
local child_session = n.connect(child_server)
- local child_screen = Screen.new(40, 6)
- child_screen:attach(nil, child_session)
+ local child_screen = Screen.new(40, 6, nil, child_session)
child_screen._default_attr_ids = nil -- TODO: unskip with new color scheme
child_session:notify('nvim_command', [[echo range(100)->join("\n")]])
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index f623cfda06..8c6a284cd6 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -11,8 +11,7 @@ describe('ui mode_change event', function()
before_each(function()
clear()
- screen = Screen.new(25, 4)
- screen:attach({ rgb = true })
+ screen = Screen.new(25, 4, { rgb = true })
end)
it('works in normal mode', function()
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index bc18680749..3ee4d429c7 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -21,30 +21,20 @@ describe('ui/mouse/input', function()
command('set listchars=eol:$')
command('setl listchars=nbsp:x')
screen = Screen.new(25, 5)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black },
- [2] = { bold = true },
- [3] = {
- foreground = Screen.colors.Blue,
- background = Screen.colors.LightGrey,
+ screen:add_extra_attr_ids {
+ [100] = {
bold = true,
+ background = Screen.colors.LightGrey,
+ foreground = Screen.colors.Blue1,
},
- [4] = { reverse = true },
- [5] = { bold = true, reverse = true },
- [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [7] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [8] = { foreground = Screen.colors.Brown },
- [9] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey },
- })
+ }
command('set mousemodel=extend')
feed('itesting<cr>mouse<cr>support and selection<esc>')
screen:expect([[
testing |
mouse |
support and selectio^n |
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -56,7 +46,7 @@ describe('ui/mouse/input', function()
testing |
mo^use |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]],
mouse_enabled = true,
@@ -66,7 +56,7 @@ describe('ui/mouse/input', function()
^testing |
mouse |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -79,7 +69,7 @@ describe('ui/mouse/input', function()
testing |
mo^use |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]],
mouse_enabled = false,
@@ -89,7 +79,7 @@ describe('ui/mouse/input', function()
^testing |
mouse |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -100,11 +90,11 @@ describe('ui/mouse/input', function()
feed('<LeftMouse><0,0>')
feed('<LeftRelease><0,0>')
screen:expect([[
- {1:testin}^g |
+ {17:testin}^g |
mouse |
support and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
end)
@@ -116,11 +106,11 @@ describe('ui/mouse/input', function()
feed('<LeftMouse><0,0>')
feed('<LeftRelease><0,0>')
screen:expect([[
- ^t{1:esting} |
+ ^t{17:esting} |
mouse |
support and selection |
- {0:~ }|
- {2:-- VISUAL LINE --} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
]])
end)
@@ -137,44 +127,35 @@ describe('ui/mouse/input', function()
^testing |
mouse |
support and selection |
- {0:~ }|
- {2:-- VISUAL BLOCK --} |
+ {1:~ }|
+ {5:-- VISUAL BLOCK --} |
]])
end)
describe('tab drag', function()
- before_each(function()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- tab = { background = Screen.colors.LightGrey, underline = true },
- sel = { bold = true },
- fill = { reverse = true },
- })
- end)
-
it('in tabline on filler space moves tab to the end', function()
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><4,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftDrag><14,0>')
screen:expect([[
- {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ {24: + bar }{5: + foo }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end)
@@ -185,9 +166,9 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><11,0>')
@@ -196,18 +177,18 @@ describe('ui/mouse/input', function()
poke_eventloop()
screen:expect {
grid = [[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]],
unchanged = true,
}
feed('<LeftDrag><6,0>')
screen:expect([[
- {sel: + bar }{tab: + foo }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {5: + bar }{24: + foo }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
end)
@@ -218,23 +199,23 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><4,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftDrag><7,0>')
screen:expect([[
- {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ {24: + bar }{5: + foo }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end)
@@ -245,33 +226,33 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><4,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftDrag><4,1>')
screen:expect {
grid = [[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]],
unchanged = true,
}
feed('<LeftDrag><14,1>')
screen:expect([[
- {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ {24: + bar }{5: + foo }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end)
@@ -282,9 +263,9 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><11,0>')
@@ -293,9 +274,9 @@ describe('ui/mouse/input', function()
poke_eventloop()
screen:expect {
grid = [[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]],
unchanged = true,
@@ -303,18 +284,18 @@ describe('ui/mouse/input', function()
feed('<LeftDrag><11,1>')
screen:expect {
grid = [[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]],
unchanged = true,
}
feed('<LeftDrag><6,1>')
screen:expect([[
- {sel: + bar }{tab: + foo }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {5: + bar }{24: + foo }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
end)
@@ -325,73 +306,64 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><4,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftDrag><4,1>')
screen:expect {
grid = [[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]],
unchanged = true,
}
feed('<LeftDrag><7,1>')
screen:expect([[
- {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ {24: + bar }{5: + foo }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end)
end)
describe('tabline', function()
- before_each(function()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- tab = { background = Screen.colors.LightGrey, underline = true },
- sel = { bold = true },
- fill = { reverse = true },
- })
- end)
-
it('left click in default tabline (tabpage label) switches to tab', function()
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><4,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftMouse><6,0>')
screen:expect_unchanged()
feed('<LeftMouse><10,0>')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><12,0>')
@@ -404,23 +376,23 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><20,0>')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<LeftMouse><22,0>')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
end)
@@ -432,15 +404,15 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<LeftMouse><24,0>')
screen:expect([[
this is fo^o |
- {0:~ }|*3
+ {1:~ }|*3
|
]])
end)
@@ -451,44 +423,44 @@ describe('ui/mouse/input', function()
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<2-LeftMouse><4,0>')
screen:expect([[
- {sel: Name] }{tab: + foo + bar }{fill: }{tab:X}|
- {0:^$} |
- {0:~ }|*2
+ {5: Name] }{24: + foo + bar }{2: }{24:X}|
+ {1:^$} |
+ {1:~ }|*2
|
]])
command('tabclose')
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
this is fo^o |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<2-LeftMouse><20,0>')
screen:expect([[
- {tab: + foo + bar }{sel: Name] }{fill: }{tab:X}|
- {0:^$} |
- {0:~ }|*2
+ {24: + foo + bar }{5: Name] }{2: }{24:X}|
+ {1:^$} |
+ {1:~ }|*2
|
]])
command('tabclose')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ this is ba^r{1:$} |
+ {1:~ }|*2
|
]])
feed('<2-LeftMouse><10,0>')
screen:expect([[
- {tab: + foo }{sel: Name] }{tab: + bar }{fill: }{tab:X}|
- {0:^$} |
- {0:~ }|*2
+ {24: + foo }{5: Name] }{24: + bar }{2: }{24:X}|
+ {1:^$} |
+ {1:~ }|*2
|
]])
end)
@@ -509,7 +481,7 @@ describe('ui/mouse/input', function()
api.nvim_set_option_value('tabline', '%@Test@test%X-%5@Test2@test2', {})
api.nvim_set_option_value('showtabline', 2, {})
screen:expect([[
- {fill:test-test2 }|
+ {2:test-test2 }|
testing |
mouse |
support and selectio^n |
@@ -594,48 +566,41 @@ describe('ui/mouse/input', function()
testing |
mo^use |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]])
feed('<LeftDrag><4,1>')
screen:expect([[
testing |
- mo{1:us}^e |
+ mo{17:us}^e |
support and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
feed('<LeftDrag><2,2>')
screen:expect([[
testing |
- mo{1:use} |
- {1:su}^pport and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ mo{17:use} |
+ {17:su}^pport and selection |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
feed('<LeftDrag><0,0>')
screen:expect([[
- ^t{1:esting} |
- {1:mou}se |
+ ^t{17:esting} |
+ {17:mou}se |
support and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
end)
it('left drag changes visual selection after tab click', function()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- tab = { background = Screen.colors.LightGrey, underline = true },
- sel = { bold = true },
- fill = { reverse = true },
- vis = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black },
- })
feed_command('silent file foo | tabnew | file bar')
insert('this is bar')
feed_command('tabprevious') -- go to first tab
screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ {5: + foo }{24: + bar }{2: }{24:X}|
testing |
mouse |
support and selectio^n |
@@ -645,17 +610,17 @@ describe('ui/mouse/input', function()
n.poke_eventloop()
feed('<LeftMouse><0,1>')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- ^this is bar{0:$} |
- {0:~ }|*2
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ ^this is bar{1:$} |
+ {1:~ }|*2
:tabprevious |
]])
feed('<LeftDrag><4,1>')
screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- {vis:this}^ is bar{0:$} |
- {0:~ }|*2
- {sel:-- VISUAL --} |
+ {24: + foo }{5: + bar }{2: }{24:X}|
+ {17:this}^ is bar{1:$} |
+ {1:~ }|*2
+ {5:-- VISUAL --} |
]])
end)
@@ -673,12 +638,12 @@ describe('ui/mouse/input', function()
testing │testing |
mouse │mouse |
support and selection │support and selection |
- {0:~ }│{0:~ }|*2
- {0:~ }│{4:[No Name] [+] }|
- {0:~ }│foo{0:$} |
- {0:~ }│ba^r{0:$} |
- {0:~ }│{0:~ }|*4
- {4:[No Name] [+] }{5:[No Name] [+] }|
+ {1:~ }│{1:~ }|*2
+ {1:~ }│{2:[No Name] [+] }|
+ {1:~ }│foo{1:$} |
+ {1:~ }│ba^r{1:$} |
+ {1:~ }│{1:~ }|*4
+ {2:[No Name] [+] }{3:[No Name] [+] }|
|
]],
}
@@ -689,12 +654,12 @@ describe('ui/mouse/input', function()
testing │testing |
mouse │mouse |
support and selection │support and selection |
- {0:~ }│{0:~ }|*2
- {0:~ }│{4:[No Name] [+] }|
- {0:~ }│^foo{0:$} |
- {0:~ }│bar{0:$} |
- {0:~ }│{0:~ }|*4
- {4:[No Name] [+] }{5:[No Name] [+] }|
+ {1:~ }│{1:~ }|*2
+ {1:~ }│{2:[No Name] [+] }|
+ {1:~ }│^foo{1:$} |
+ {1:~ }│bar{1:$} |
+ {1:~ }│{1:~ }|*4
+ {2:[No Name] [+] }{3:[No Name] [+] }|
|
]],
}
@@ -705,13 +670,13 @@ describe('ui/mouse/input', function()
testing │testing |
mouse │mouse |
support and selection │support and selection |
- {0:~ }│{0:~ }|*2
- {0:~ }│{4:[No Name] [+] }|
- {0:~ }│{1:foo}{3:$} |
- {0:~ }│{1:bar}{0:^$} |
- {0:~ }│{0:~ }|*4
- {4:[No Name] [+] }{5:[No Name] [+] }|
- {2:-- VISUAL --} |
+ {1:~ }│{1:~ }|*2
+ {1:~ }│{2:[No Name] [+] }|
+ {1:~ }│{17:foo}{100:$} |
+ {1:~ }│{17:bar}{1:^$} |
+ {1:~ }│{1:~ }|*4
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ {5:-- VISUAL --} |
]],
}
end)
@@ -723,33 +688,33 @@ describe('ui/mouse/input', function()
screen:expect([[
testing |
mouse |
- {1:suppor}^t and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ {17:suppor}^t and selection |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
feed('<LeftDrag><0,1>')
screen:expect([[
testing |
- ^m{1:ouse} |
- {1:support} and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ ^m{17:ouse} |
+ {17:support} and selection |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
feed('<LeftDrag><4,0>')
screen:expect([[
- ^t{1:esting} |
- {1:mouse} |
- {1:support} and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ ^t{17:esting} |
+ {17:mouse} |
+ {17:support} and selection |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
feed('<LeftDrag><14,2>')
screen:expect([[
testing |
mouse |
- {1:support and selectio}^n |
- {0:~ }|
- {2:-- VISUAL --} |
+ {17:support and selectio}^n |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
end)
@@ -762,33 +727,33 @@ describe('ui/mouse/input', function()
screen:expect([[
testing |
mouse |
- {1:su}^p{1:port and selection} |
- {0:~ }|
- {2:-- VISUAL LINE --} |
+ {17:su}^p{17:port and selection} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
]])
feed('<LeftDrag><0,1>')
screen:expect([[
testing |
- ^m{1:ouse} |
- {1:support and selection} |
- {0:~ }|
- {2:-- VISUAL LINE --} |
+ ^m{17:ouse} |
+ {17:support and selection} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
]])
feed('<LeftDrag><4,0>')
screen:expect([[
- {1:test}^i{1:ng} |
- {1:mouse} |
- {1:support and selection} |
- {0:~ }|
- {2:-- VISUAL LINE --} |
+ {17:test}^i{17:ng} |
+ {17:mouse} |
+ {17:support and selection} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
]])
feed('<LeftDrag><14,2>')
screen:expect([[
testing |
mouse |
- {1:support and se}^l{1:ection} |
- {0:~ }|
- {2:-- VISUAL LINE --} |
+ {17:support and se}^l{17:ection} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
]])
end)
@@ -804,32 +769,32 @@ describe('ui/mouse/input', function()
testing |
mouse |
su^pport and selection |
- {0:~ }|
- {2:-- VISUAL BLOCK --} |
+ {1:~ }|
+ {5:-- VISUAL BLOCK --} |
]])
feed('<LeftDrag><0,1>')
screen:expect([[
testing |
- ^m{1:ou}se |
- {1:sup}port and selection |
- {0:~ }|
- {2:-- VISUAL BLOCK --} |
+ ^m{17:ou}se |
+ {17:sup}port and selection |
+ {1:~ }|
+ {5:-- VISUAL BLOCK --} |
]])
feed('<LeftDrag><4,0>')
screen:expect([[
- te{1:st}^ing |
- mo{1:use} |
- su{1:ppo}rt and selection |
- {0:~ }|
- {2:-- VISUAL BLOCK --} |
+ te{17:st}^ing |
+ mo{17:use} |
+ su{17:ppo}rt and selection |
+ {1:~ }|
+ {5:-- VISUAL BLOCK --} |
]])
feed('<LeftDrag><14,2>')
screen:expect([[
testing |
mouse |
- su{1:pport and se}^lection |
- {0:~ }|
- {2:-- VISUAL BLOCK --} |
+ su{17:pport and se}^lection |
+ {1:~ }|
+ {5:-- VISUAL BLOCK --} |
]])
end)
@@ -839,16 +804,16 @@ describe('ui/mouse/input', function()
^testing |
mouse |
support and selection |
- {0:~ }|
+ {1:~ }|
|
]])
feed('<RightMouse><2,2>')
screen:expect([[
- {1:testing} |
- {1:mouse} |
- {1:su}^pport and selection |
- {0:~ }|
- {2:-- VISUAL --} |
+ {17:testing} |
+ {17:mouse} |
+ {17:su}^pport and selection |
+ {1:~ }|
+ {5:-- VISUAL --} |
]])
end)
@@ -856,11 +821,11 @@ describe('ui/mouse/input', function()
api.nvim_set_option_value('tags', './non-existent-tags-file', {})
feed('<C-LeftMouse><0,0>')
screen:expect([[
- {6:E433: No tags file} |
- {6:E426: Tag not found: test}|
- {6:ing} |
- {7:Press ENTER or type comma}|
- {7:nd to continue}^ |
+ {9:E433: No tags file} |
+ {9:E426: Tag not found: test}|
+ {9:ing} |
+ {6:Press ENTER or type comma}|
+ {6:nd to continue}^ |
]])
feed('<cr>')
end)
@@ -890,54 +855,54 @@ describe('ui/mouse/input', function()
local oldwin = api.nvim_get_current_win()
command('rightbelow vnew')
screen:expect([[
- testing │{0:^$} |
- mouse │{0:~ }|
- support and selection │{0:~ }|
- {4:[No Name] [+] }{5:[No Name] }|
+ testing │{1:^$} |
+ mouse │{1:~ }|
+ support and selection │{1:~ }|
+ {2:[No Name] [+] }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 22)
poke_eventloop()
api.nvim_input_mouse('left', 'drag', '', 0, 1, 12)
screen:expect([[
- testing │{0:^$} |
- mouse │{0:~ }|
- support and │{0:~ }|
- {4:< Name] [+] }{5:[No Name] }|
+ testing │{1:^$} |
+ mouse │{1:~ }|
+ support and │{1:~ }|
+ {2:< Name] [+] }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'drag', '', 0, 2, 2)
screen:expect([[
- te│{0:^$} |
- mo│{0:~ }|
- su│{0:~ }|
- {4:< }{5:[No Name] }|
+ te│{1:^$} |
+ mo│{1:~ }|
+ su│{1:~ }|
+ {2:< }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'release', '', 0, 2, 2)
api.nvim_set_option_value('statuscolumn', 'foobar', { win = oldwin })
screen:expect([[
- {8:fo}│{0:^$} |
- {8:fo}│{0:~ }|*2
- {4:< }{5:[No Name] }|
+ {8:fo}│{1:^$} |
+ {8:fo}│{1:~ }|*2
+ {2:< }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 2)
poke_eventloop()
api.nvim_input_mouse('left', 'drag', '', 0, 1, 12)
screen:expect([[
- {8:foobar}testin│{0:^$} |
- {8:foobar}mouse │{0:~ }|
- {8:foobar}suppor│{0:~ }|
- {4:< Name] [+] }{5:[No Name] }|
+ {8:foobar}testin│{1:^$} |
+ {8:foobar}mouse │{1:~ }|
+ {8:foobar}suppor│{1:~ }|
+ {2:< Name] [+] }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'drag', '', 0, 2, 22)
screen:expect([[
- {8:foobar}testing │{0:^$} |
- {8:foobar}mouse │{0:~ }|
- {8:foobar}support and sele│{0:~ }|
- {4:[No Name] [+] }{5:[No Name] }|
+ {8:foobar}testing │{1:^$} |
+ {8:foobar}mouse │{1:~ }|
+ {8:foobar}support and sele│{1:~ }|
+ {2:[No Name] [+] }{3:[No Name] }|
|
]])
api.nvim_input_mouse('left', 'release', '', 0, 2, 22)
@@ -964,14 +929,14 @@ describe('ui/mouse/input', function()
test │test |
^mouse scrolling │mouse scrolling |
│ |
- {0:~ }│{0:~ }|
- {5:[No Name] [+] }{4:[No Name] [+] }|
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- {0:~ }|
- {4:[No Name] [+] }|
+ {1:~ }|
+ {2:[No Name] [+] }|
:vsp |
]])
if use_api then
@@ -982,17 +947,17 @@ describe('ui/mouse/input', function()
screen:expect([[
^mouse scrolling │lines |
│to |
- {0:~ }│test |
- {0:~ }│mouse scrolling |
- {0:~ }│ |
- {0:~ }│{0:~ }|
- {5:[No Name] [+] }{4:[No Name] [+] }|
+ {1:~ }│test |
+ {1:~ }│mouse scrolling |
+ {1:~ }│ |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- {0:~ }|
- {4:[No Name] [+] }|
+ {1:~ }|
+ {2:[No Name] [+] }|
:vsp |
]])
if use_api then
@@ -1003,17 +968,17 @@ describe('ui/mouse/input', function()
screen:expect([[
^mouse scrolling │text |
│with |
- {0:~ }│many |
- {0:~ }│lines |
- {0:~ }│to |
- {0:~ }│test |
- {5:[No Name] [+] }{4:[No Name] [+] }|
+ {1:~ }│many |
+ {1:~ }│lines |
+ {1:~ }│to |
+ {1:~ }│test |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- {0:~ }|
- {4:[No Name] [+] }|
+ {1:~ }|
+ {2:[No Name] [+] }|
:vsp |
]])
if use_api then
@@ -1025,17 +990,17 @@ describe('ui/mouse/input', function()
screen:expect([[
^mouse scrolling │text |
│with |
- {0:~ }│many |
- {0:~ }│lines |
- {0:~ }│to |
- {0:~ }│test |
- {5:[No Name] [+] }{4:[No Name] [+] }|
+ {1:~ }│many |
+ {1:~ }│lines |
+ {1:~ }│to |
+ {1:~ }│test |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
Inserting |
text |
with |
many |
lines |
- {4:[No Name] [+] }|
+ {2:[No Name] [+] }|
:vsp |
]])
end
@@ -1056,7 +1021,7 @@ describe('ui/mouse/input', function()
screen:expect([[
|*2
bbbbbbbbbbbbbbb^b |
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1064,7 +1029,7 @@ describe('ui/mouse/input', function()
screen:expect([[
|*2
n bbbbbbbbbbbbbbbbbbb^b |
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1073,7 +1038,7 @@ describe('ui/mouse/input', function()
g |
|
^t and selection bbbbbbbbb|
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -1086,7 +1051,7 @@ describe('ui/mouse/input', function()
screen:expect([[
|*2
bbbbbbbbbbbbbbb^b |
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1094,7 +1059,7 @@ describe('ui/mouse/input', function()
screen:expect([[
|*2
n bbbbbbbbbbbbbbbbbbb^b |
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1104,7 +1069,7 @@ describe('ui/mouse/input', function()
g |
|
^t and selection bbbbbbbbb|
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -1118,7 +1083,7 @@ describe('ui/mouse/input', function()
testing |
mouse |
^bbbbbbbbbbbbbbbbbbbb supp|
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1127,7 +1092,7 @@ describe('ui/mouse/input', function()
g |
|
bbbb^bbbbbbbbbb support an|
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1138,7 +1103,7 @@ describe('ui/mouse/input', function()
testing |
mouse |
^bbbbbbbbbbbbbbbbbbbb supp|
- {0:~ }|
+ {1:~ }|
|
]])
@@ -1147,7 +1112,7 @@ describe('ui/mouse/input', function()
g |
|
bb^bbbbbbbbbbbb support an|
- {0:~ }|
+ {1:~ }|
|
]])
end)
@@ -1158,71 +1123,71 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><0,0>')
screen:expect([[
- ^Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}|
+ ^Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><1,0>')
screen:expect([[
- S^ection{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}|
+ S^ection{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><21,0>')
screen:expect([[
- Section{0:>>--->--->---}{c: }^t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}|
+ Section{1:>>--->--->---}{14: }^t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><21,1>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t^3{c: } {c: }|
- {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}|
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t^3{14: } {14: }|
+ {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><0,2>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:^>} 私は猫が大好き{0:>---}{c: X } {0:>}|
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:^>} 私は猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><7,2>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:>} 私は^猫が大好き{0:>---}{c: X } {0:>}|
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:>} 私は^猫が大好き{1:>---}{14: X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><21,2>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- {c:>} 私は猫が大好き{0:>---}{c: ^X } {0:>}|
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ {14:>} 私は猫が大好き{1:>---}{14: ^X } {1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end) -- level 1 - non wrapped
@@ -1232,51 +1197,51 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><24,1>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c:^ }|
- t4{c: } |
- {c:>} 私は猫が大好き{0:>---}{c: X} |
- {c: } ✨🐈✨ |
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14:^ }|
+ t4{14: } |
+ {14:>} 私は猫が大好き{1:>---}{14: X} |
+ {14: } ✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><0,2>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- ^t4{c: } |
- {c:>} 私は猫が大好き{0:>---}{c: X} |
- {c: } ✨🐈✨ |
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ ^t4{14: } |
+ {14:>} 私は猫が大好き{1:>---}{14: X} |
+ {14: } ✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><8,3>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- t4{c: } |
- {c:>} 私は猫^が大好き{0:>---}{c: X} |
- {c: } ✨🐈✨ |
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ t4{14: } |
+ {14:>} 私は猫^が大好き{1:>---}{14: X} |
+ {14: } ✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><21,3>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- t4{c: } |
- {c:>} 私は猫が大好き{0:>---}{c: ^X} |
- {c: } ✨🐈✨ |
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ t4{14: } |
+ {14:>} 私は猫が大好き{1:>---}{14: ^X} |
+ {14: } ✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><4,4>')
screen:expect([[
- Section{0:>>--->--->---}{c: }t1{c: } |
- {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }|
- t4{c: } |
- {c:>} 私は猫が大好き{0:>---}{c: X} |
- {c: } ✨^🐈✨ |
+ Section{1:>>--->--->---}{14: }t1{14: } |
+ {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }|
+ t4{14: } |
+ {14:>} 私は猫が大好き{1:>---}{14: X} |
+ {14: } ✨^🐈✨ |
|*2
]])
end) -- level 1 - wrapped
@@ -1286,61 +1251,61 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><20,0>')
screen:expect([[
- Section{0:>>--->--->---}^t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}^t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><14,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} ^t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} ^t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><18,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t^3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t^3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><0,2>') -- Weirdness
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:^>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:^>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><8,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫^が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫^が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><20,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:^X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:^X} ✨{1:>}|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end) -- level 2 - non wrapped
@@ -1350,62 +1315,62 @@ describe('ui/mouse/input', function()
feed('<esc>i<LeftMouse><20,0>')
screen:expect([[
- Section{0:>>--->--->---}^t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}^t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
feed('<LeftMouse><14,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} ^t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} ^t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
feed('<LeftMouse><18,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t^3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t^3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
feed('<LeftMouse><0,2>') -- Weirdness
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:^>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:^>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
feed('<LeftMouse><8,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫^が大好き{0:>---}{c:X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫^が大好き{1:>---}{14:X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
feed('<LeftMouse><20,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- {c:>} 私は猫が大好き{0:>---}{c:^X} ✨{0:>}|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ {14:>} 私は猫が大好き{1:>---}{14:^X} ✨{1:>}|
|
- {0:~ }|*2
- {sm:-- INSERT --} |
+ {1:~ }|*2
+ {5:-- INSERT --} |
]])
end) -- level 2 - non wrapped (insert mode)
@@ -1414,30 +1379,30 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><20,0>')
screen:expect([[
- Section{0:>>--->--->---}^t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}^t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><14,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} ^t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} ^t2 t3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><18,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t^3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t^3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
@@ -1450,60 +1415,60 @@ describe('ui/mouse/input', function()
-- reevaluated.
feed('<esc><LeftMouse><0,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 ^ |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 ^ |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><1,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t^4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><0,3>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- {c:^>} 私は猫が大好き{0:>---}{c:X} |
+ {14:^>} 私は猫が大好き{1:>---}{14:X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><20,3>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:^X} |
+ {14:>} 私は猫が大好き{1:>---}{14:^X} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><1,4>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
^✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><5,4>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- {c:>} 私は猫が大好き{0:>---}{c:X} |
+ {14:>} 私は猫が大好き{1:>---}{14:X} |
✨🐈^✨ |
|*2
]])
@@ -1514,42 +1479,42 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><0,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- ^ 私は猫が大好き{0:>----} ✨🐈|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ ^ 私は猫が大好き{1:>----} ✨🐈|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><1,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- ^私は猫が大好き{0:>----} ✨🐈|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ ^私は猫が大好き{1:>----} ✨🐈|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><13,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- 私は猫が大好^き{0:>----} ✨🐈|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ 私は猫が大好^き{1:>----} ✨🐈|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
feed('<esc><LeftMouse><20,2>')
feed('zH') -- FIXME: unnecessary horizontal scrolling
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 t4 |
- 私は猫が大好き{0:>----}^ ✨🐈|
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 t4 |
+ 私は猫が大好き{1:>----}^ ✨🐈|
|
- {0:~ }|*2
+ {1:~ }|*2
|
]])
end) -- level 3 - non wrapped
@@ -1559,80 +1524,80 @@ describe('ui/mouse/input', function()
feed('<esc><LeftMouse><14,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} ^t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} ^t2 t3 |
t4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><18,1>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t^3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t^3 |
t4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><1,2>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t^4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><0,3>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- ^ 私は猫が大好き{0:>----} |
+ ^ 私は猫が大好き{1:>----} |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><20,3>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- 私は猫が大好き{0:>----}^ |
+ 私は猫が大好き{1:>----}^ |
✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><1,4>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
^✨🐈✨ |
|*2
]])
feed('<esc><LeftMouse><3,4>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
✨^🐈✨ |
|*2
]])
feed('<esc><LeftMouse><5,4>')
screen:expect([[
- Section{0:>>--->--->---}t1 |
- {0:>--->--->---} t2 t3 |
+ Section{1:>>--->--->---}t1 |
+ {1:>--->--->---} t2 t3 |
t4 |
- 私は猫が大好き{0:>----} |
+ 私は猫が大好き{1:>----} |
✨🐈^✨ |
|*2
]])
@@ -1645,11 +1610,6 @@ describe('ui/mouse/input', function()
before_each(function()
screen:try_resize(25, 7)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
- sm = { bold = true },
- })
feed('ggdG')
command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]])
@@ -1712,23 +1672,23 @@ describe('ui/mouse/input', function()
command('syntax match test /|hidden|/ conceal cchar=X')
command('set conceallevel=2 concealcursor=n virtualedit=all')
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbbb |
- bbb{9:X}ccccccccc^c |
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbbb |
+ bbb{14:X}ccccccccc^c |
+ {1:~ }|*2
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 22)
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbb^b |
- bbb{9:X}cccccccccc |
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbb^b |
+ bbb{14:X}cccccccccc |
+ {1:~ }|*2
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 1, 16)
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbbb |
- bbb{9:X}cccccccccc ^ |
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbbb |
+ bbb{14:X}cccccccccc ^ |
+ {1:~ }|*2
|
]])
@@ -1738,23 +1698,23 @@ describe('ui/mouse/input', function()
virt_text_repeat_linebreak = true,
})
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbbb {6:?}|
- bbb{9:X}cccccccccc ^ {6:?}|
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbbb {9:?}|
+ bbb{14:X}cccccccccc ^ {9:?}|
+ {1:~ }|*2
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 22)
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbb^b {6:?}|
- bbb{9:X}cccccccccc {6:?}|
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbb^b {9:?}|
+ bbb{14:X}cccccccccc {9:?}|
+ {1:~ }|*2
|
]])
api.nvim_input_mouse('left', 'press', '', 0, 1, 16)
screen:expect([[
- aaaaaaaaaa{9:X}bbbbbbb {6:?}|
- bbb{9:X}cccccccccc ^ {6:?}|
- {0:~ }|*2
+ aaaaaaaaaa{14:X}bbbbbbb {9:?}|
+ bbb{14:X}cccccccccc ^ {9:?}|
+ {1:~ }|*2
|
]])
end)
@@ -1908,19 +1868,40 @@ describe('ui/mouse/input', function()
eq(0, api.nvim_get_var('mouse_up2'))
end)
- it('<MouseMove> is not translated into multiclicks and can be mapped', function()
+ it('<MouseMove> to different locations can be mapped', function()
api.nvim_set_var('mouse_move', 0)
api.nvim_set_var('mouse_move2', 0)
command('nnoremap <MouseMove> <Cmd>let g:mouse_move += 1<CR>')
command('nnoremap <2-MouseMove> <Cmd>let g:mouse_move2 += 1<CR>')
- feed('<MouseMove><0,0>')
- feed('<MouseMove><0,0>')
- api.nvim_input_mouse('move', '', '', 0, 0, 0)
- api.nvim_input_mouse('move', '', '', 0, 0, 0)
+ feed('<MouseMove><1,0>')
+ feed('<MouseMove><2,0>')
+ api.nvim_input_mouse('move', '', '', 0, 0, 3)
+ api.nvim_input_mouse('move', '', '', 0, 0, 4)
eq(4, api.nvim_get_var('mouse_move'))
eq(0, api.nvim_get_var('mouse_move2'))
end)
+ it('<MouseMove> to same location does not generate events #31103', function()
+ api.nvim_set_var('mouse_move', 0)
+ api.nvim_set_var('mouse_move2', 0)
+ command('nnoremap <MouseMove> <Cmd>let g:mouse_move += 1<CR>')
+ command('nnoremap <2-MouseMove> <Cmd>let g:mouse_move2 += 1<CR>')
+ api.nvim_input_mouse('move', '', '', 0, 0, 3)
+ eq(1, api.nvim_get_var('mouse_move'))
+ eq(0, api.nvim_get_var('mouse_move2'))
+ feed('<MouseMove><3,0>')
+ feed('<MouseMove><3,0>')
+ api.nvim_input_mouse('move', '', '', 0, 0, 3)
+ api.nvim_input_mouse('move', '', '', 0, 0, 3)
+ eq(1, api.nvim_get_var('mouse_move'))
+ eq(0, api.nvim_get_var('mouse_move2'))
+ eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
+ feed('<MouseMove><3,0><Insert>')
+ eq(1, api.nvim_get_var('mouse_move'))
+ eq(0, api.nvim_get_var('mouse_move2'))
+ eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
+ end)
+
it('feeding <MouseMove> in Normal mode does not use uninitialized memory #19480', function()
feed('<MouseMove>')
n.poke_eventloop()
diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua
index f16f750ea1..001d3cb430 100644
--- a/test/functional/ui/multibyte_spec.lua
+++ b/test/functional/ui/multibyte_spec.lua
@@ -16,8 +16,7 @@ describe('multibyte rendering', function()
local screen
before_each(function()
clear()
- screen = Screen.new(60, 6)
- screen:attach({ rgb = true })
+ screen = Screen.new(60, 6, { rgb = true })
end)
it('works with composed char at start of line', function()
@@ -384,7 +383,6 @@ describe('multibyte rendering: statusline', function()
before_each(function()
clear()
screen = Screen.new(40, 4)
- screen:attach()
command('set laststatus=2')
end)
@@ -474,26 +472,42 @@ describe('multibyte rendering: statusline', function()
end)
it('emoji with ZWJ in filename with custom stl', function()
+ screen:add_extra_attr_ids {
+ [100] = {
+ bold = true,
+ reverse = true,
+ foreground = Screen.colors.Gray100,
+ background = Screen.colors.Red,
+ },
+ }
command('set statusline=xx%#ErrorMsg#%f%##yy')
command('file 🧑‍💻')
screen:expect {
grid = [[
^ |
{1:~ }|
- {3:xx}{9:🧑‍💻}{3:yy }|
+ {3:xx}{100:🧑‍💻}{3:yy }|
|
]],
}
end)
it('unprintable chars in filename with custom stl', function()
+ screen:add_extra_attr_ids {
+ [100] = {
+ bold = true,
+ reverse = true,
+ foreground = Screen.colors.Gray100,
+ background = Screen.colors.Red,
+ },
+ }
command('set statusline=xx%#ErrorMsg#%f%##yy')
command('file 🧑​💻')
screen:expect {
grid = [[
^ |
{1:~ }|
- {3:xx}{9:🧑<200b>💻}{3:yy }|
+ {3:xx}{100:🧑<200b>💻}{3:yy }|
|
]],
}
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index e009ed0a29..3afda0c4af 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -16,8 +16,7 @@ describe('ext_multigrid', function()
before_each(function()
clear{args_rm={'--headless'}, args={'--cmd', 'set laststatus=2'}}
- screen = Screen.new(53,14)
- screen:attach({ext_multigrid=true})
+ screen = Screen.new(53,14, {ext_multigrid=true})
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Magenta},
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index b40ff29dec..211fc1dc77 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -44,8 +44,7 @@ describe('UI receives option updates', function()
clear_opts.args_rm = clear_opts.args_rm or {}
table.insert(clear_opts.args_rm or {}, '--cmd')
clear(clear_opts)
- screen = Screen.new(20, 5)
- screen:attach(screen_opts)
+ screen = Screen.new(20, 5, screen_opts)
-- NB: UI test suite can be run in both "linegrid" and legacy grid mode.
-- In both cases check that the received value is the one requested.
defaults.ext_linegrid = screen._options.ext_linegrid or false
@@ -70,7 +69,6 @@ describe('UI receives option updates', function()
function screen:_handle_mouse_off()
table.insert(evs, 'mouse_off')
end
- screen:attach()
screen:expect(function()
eq({ 'mouse_on' }, evs)
end)
@@ -215,24 +213,22 @@ describe('UI receives option updates', function()
end)
describe('UI can set terminal option', function()
- local screen
before_each(function()
-- by default we implicitly "--cmd 'set bg=light'" which ruins everything
clear { args_rm = { '--cmd' } }
- screen = Screen.new(20, 5)
end)
it('term_name', function()
eq('nvim', eval '&term')
- screen:attach { term_name = 'xterm' }
+ local _ = Screen.new(20, 5, { term_name = 'xterm' })
eq('xterm', eval '&term')
end)
it('term_colors', function()
eq('256', eval '&t_Co')
- screen:attach { term_colors = 8 }
+ local _ = Screen.new(20, 5, { term_colors = 8 })
eq('8', eval '&t_Co')
end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 220af06f53..b5a09d814c 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -109,7 +109,6 @@ describe('shell command :!', function()
it('handles control codes', function()
skip(is_os('win'), 'missing printf')
local screen = Screen.new(50, 4)
- screen:attach()
-- Print TAB chars. #2958
feed([[:!printf '1\t2\t3'<CR>]])
screen:expect {
@@ -167,7 +166,6 @@ describe('shell command :!', function()
write_file('bang_filter_spec/f2', 'f2')
write_file('bang_filter_spec/f3', 'f3')
screen = Screen.new(53, 10)
- screen:attach()
end)
after_each(function()
@@ -241,7 +239,6 @@ describe('shell command :!', function()
it('powershell supports literal strings', function()
set_shell_powershell()
local screen = Screen.new(45, 4)
- screen:attach()
feed_command([[!'Write-Output $a']])
screen:expect([[
:!'Write-Output $a' |
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index f84362ede8..8fe8975b4a 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -19,18 +19,7 @@ describe('ui/ext_popupmenu', function()
local screen
before_each(function()
clear()
- screen = Screen.new(60, 8)
- screen:attach({ rgb = true, ext_popupmenu = true })
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue },
- [2] = { bold = true },
- [3] = { reverse = true },
- [4] = { bold = true, reverse = true },
- [5] = { bold = true, foreground = Screen.colors.SeaGreen },
- [6] = { background = Screen.colors.WebGray },
- [7] = { background = Screen.colors.LightMagenta },
- [8] = { foreground = Screen.colors.Red },
- })
+ screen = Screen.new(60, 8, { rgb = true, ext_popupmenu = true })
source([[
function! TestComplete() abort
call complete(1, [{'word':'foo', 'abbr':'fo', 'menu':'the foo', 'info':'foo-y', 'kind':'x'}, 'bar', 'spam'])
@@ -52,7 +41,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -67,7 +56,7 @@ describe('ui/ext_popupmenu', function()
|
^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -83,7 +72,7 @@ describe('ui/ext_popupmenu', function()
|
^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -98,7 +87,7 @@ describe('ui/ext_popupmenu', function()
|
bar^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
}
end)
@@ -110,7 +99,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -125,7 +114,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -140,7 +129,7 @@ describe('ui/ext_popupmenu', function()
|
spam^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -154,7 +143,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<c-w><C-r>=TestComplete()<CR>')
@@ -163,7 +152,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -178,7 +167,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -193,7 +182,7 @@ describe('ui/ext_popupmenu', function()
|
bar^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -208,7 +197,7 @@ describe('ui/ext_popupmenu', function()
|
^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -223,7 +212,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -237,7 +226,7 @@ describe('ui/ext_popupmenu', function()
|
^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
command('set wildmenu')
@@ -332,7 +321,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -347,7 +336,7 @@ describe('ui/ext_popupmenu', function()
|
spam^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -362,7 +351,7 @@ describe('ui/ext_popupmenu', function()
|
spam^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -376,7 +365,7 @@ describe('ui/ext_popupmenu', function()
|
bar^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<Esc>:sign <Tab>')
@@ -440,33 +429,33 @@ describe('ui/ext_popupmenu', function()
screen:expect([[
|
foo^ |
- {6:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
+ {12:fo x the foo }{1: }|
+ {4:bar }{1: }|
+ {4:spam }{1: }|
{1:~ }|*2
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<f1>')
screen:expect([[
|
spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {6:spam }{1: }|
+ {4:fo x the foo }{1: }|
+ {4:bar }{1: }|
+ {12:spam }{1: }|
{1:~ }|*2
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<f2>')
screen:expect([[
|
spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
+ {4:fo x the foo }{1: }|
+ {4:bar }{1: }|
+ {4:spam }{1: }|
{1:~ }|*2
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<f3>')
@@ -474,42 +463,42 @@ describe('ui/ext_popupmenu', function()
|
bar^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
feed('<Esc>:sign <Tab>')
screen:expect([[
|
- bar {6: define } |
- {1:~ }{7: jump }{1: }|
- {1:~ }{7: list }{1: }|
- {1:~ }{7: place }{1: }|
- {1:~ }{7: undefine }{1: }|
- {1:~ }{7: unplace }{1: }|
+ bar {12: define } |
+ {1:~ }{4: jump }{1: }|
+ {1:~ }{4: list }{1: }|
+ {1:~ }{4: place }{1: }|
+ {1:~ }{4: undefine }{1: }|
+ {1:~ }{4: unplace }{1: }|
:sign define^ |
]])
feed('<f1>')
screen:expect([[
|
- bar {7: define } |
- {1:~ }{7: jump }{1: }|
- {1:~ }{6: list }{1: }|
- {1:~ }{7: place }{1: }|
- {1:~ }{7: undefine }{1: }|
- {1:~ }{7: unplace }{1: }|
+ bar {4: define } |
+ {1:~ }{4: jump }{1: }|
+ {1:~ }{12: list }{1: }|
+ {1:~ }{4: place }{1: }|
+ {1:~ }{4: undefine }{1: }|
+ {1:~ }{4: unplace }{1: }|
:sign list^ |
]])
feed('<f2>')
screen:expect([[
|
- bar {7: define } |
- {1:~ }{7: jump }{1: }|
- {1:~ }{7: list }{1: }|
- {1:~ }{7: place }{1: }|
- {1:~ }{7: undefine }{1: }|
- {1:~ }{7: unplace }{1: }|
+ bar {4: define } |
+ {1:~ }{4: jump }{1: }|
+ {1:~ }{4: list }{1: }|
+ {1:~ }{4: place }{1: }|
+ {1:~ }{4: undefine }{1: }|
+ {1:~ }{4: unplace }{1: }|
:sign ^ |
]])
@@ -542,33 +531,33 @@ describe('ui/ext_popupmenu', function()
screen:expect([[
aa bb cc |
aa^ |
- {6:aa }{1: }|
- {7:bb }{1: }|
- {7:cc }{1: }|
+ {12:aa }{1: }|
+ {4:bb }{1: }|
+ {4:cc }{1: }|
{1:~ }|*2
- {2:-- Keyword Local completion (^N^P) }{5:match 1 of 3} |
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} |
]])
feed('<f1>')
screen:expect([[
aa bb cc |
cc^ |
- {7:aa }{1: }|
- {7:bb }{1: }|
- {6:cc }{1: }|
+ {4:aa }{1: }|
+ {4:bb }{1: }|
+ {12:cc }{1: }|
{1:~ }|*2
- {2:-- Keyword Local completion (^N^P) }{5:match 3 of 3} |
+ {5:-- Keyword Local completion (^N^P) }{6:match 3 of 3} |
]])
feed('<f2>')
screen:expect([[
aa bb cc |
cc^ |
- {7:aa }{1: }|
- {7:bb }{1: }|
- {7:cc }{1: }|
+ {4:aa }{1: }|
+ {4:bb }{1: }|
+ {4:cc }{1: }|
{1:~ }|*2
- {2:-- Keyword Local completion (^N^P) }{8:Back at original} |
+ {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
]])
feed('<f3>')
@@ -576,7 +565,7 @@ describe('ui/ext_popupmenu', function()
aa bb cc |
bb^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
end)
@@ -619,7 +608,7 @@ describe('ui/ext_popupmenu', function()
|
January^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = month_expected,
@@ -671,7 +660,7 @@ describe('ui/ext_popupmenu', function()
|
January^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = month_expected,
@@ -726,7 +715,7 @@ describe('ui/ext_popupmenu', function()
|
January^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = month_expected,
@@ -740,7 +729,7 @@ describe('ui/ext_popupmenu', function()
|
January^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = month_expected,
@@ -832,10 +821,10 @@ describe('ui/ext_popupmenu', function()
grid = [[
|
{1:~ }|*3
- {4:långfile2 }|
+ {3:långfile2 }|
|
{1:~ }|*2
- {3:långfile1 }|
+ {2:långfile1 }|
:b långfile1^ |
]],
popupmenu = {
@@ -863,7 +852,7 @@ describe('ui/ext_popupmenu', function()
|
foo^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -878,7 +867,7 @@ describe('ui/ext_popupmenu', function()
|
^ |
{1:~ }|*5
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]],
popupmenu = {
items = expected,
@@ -899,9 +888,9 @@ describe('ui/ext_popupmenu', function()
feed('<RightMouse><0,0>')
screen:expect([[
|
- {7:^foo } |
- {7:bar }{1: }|
- {7:baz }{1: }|
+ {4:^foo } |
+ {4:bar }{1: }|
+ {4:baz }{1: }|
{1:~ }|*3
|
]])
@@ -967,7 +956,6 @@ describe("builtin popupmenu 'pumblend'", function()
[44] = { foreground = tonumber('0x3f3f3f'), background = tonumber('0x7f5d7f') },
[45] = { background = Screen.colors.WebGray, blend = 0 },
})
- screen:attach()
command('syntax on')
command('set mouse=a')
command('set pumblend=10')
@@ -1117,7 +1105,7 @@ describe("builtin popupmenu 'pumblend'", function()
end)
it('256-color (non-RGB)', function()
- local screen = Screen.new(60, 8)
+ local screen = Screen.new(60, 8, { rgb = false })
screen:set_default_attr_ids({
[1] = { foreground = Screen.colors.Grey0, background = tonumber('0x000007') },
[2] = { foreground = tonumber('0x000055'), background = tonumber('0x000007') },
@@ -1130,7 +1118,6 @@ describe("builtin popupmenu 'pumblend'", function()
[9] = { bold = true },
[10] = { foreground = tonumber('0x000002') },
})
- screen:attach({ rgb = false })
command('set pumblend=10')
insert([[
Lorem ipsum dolor sit amet, consectetur
@@ -1159,7 +1146,7 @@ describe('builtin popupmenu', function()
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
- screen = Screen.new(32, 20)
+ screen = Screen.new(32, 20, { ext_multigrid = multigrid })
screen:set_default_attr_ids({
-- popup selected item / scrollbar track
s = { background = Screen.colors.Grey },
@@ -1204,7 +1191,6 @@ describe('builtin popupmenu', function()
underline = true,
},
})
- screen:attach({ ext_multigrid = multigrid })
end)
it('with preview-window above', function()
@@ -3636,6 +3622,58 @@ describe('builtin popupmenu', function()
:sign un^ |
]])
end)
+
+ it(
+ 'cascading highlights for matched text (PmenuMatch, PmenuMatchSel) in cmdline pum',
+ function()
+ screen:add_extra_attr_ids {
+ [100] = {
+ background = Screen.colors.Grey,
+ italic = true,
+ underline = true,
+ foreground = Screen.colors.White,
+ },
+ [101] = {
+ strikethrough = true,
+ foreground = Screen.colors.Grey0,
+ italic = true,
+ bold = true,
+ underline = true,
+ background = Screen.colors.White,
+ },
+ [102] = {
+ strikethrough = true,
+ foreground = Screen.colors.Red,
+ italic = true,
+ underline = true,
+ background = Screen.colors.Grey,
+ },
+ [103] = {
+ foreground = Screen.colors.Yellow,
+ italic = true,
+ bold = true,
+ underline = true,
+ background = Screen.colors.Pink,
+ },
+ }
+ exec([[
+ set wildoptions=pum,fuzzy
+ hi Pmenu guifg=White guibg=Grey gui=underline,italic
+ hi PmenuSel guifg=Red gui=strikethrough
+ hi PmenuMatch guifg=Yellow guibg=Pink gui=bold
+ hi PmenuMatchSel guifg=Black guibg=White
+ ]])
+
+ feed(':sign plc<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{102: }{101:pl}{102:a}{101:c}{102:e }{1: }|
+ {1:~ }{100: un}{103:pl}{100:a}{103:c}{100:e }{1: }|
+ :sign place^ |
+ ]])
+ end
+ )
end
it("'pumheight'", function()
@@ -4453,9 +4491,10 @@ describe('builtin popupmenu', function()
:let g:menustr = 'foo' |
]])
end
+ local no_menu_screen ---@type string|test.function.ui.screen.Expect
if multigrid then
api.nvim_input_mouse('left', 'press', '', 4, 1, 2)
- screen:expect({
+ no_menu_screen = {
grid = [[
## grid 1
[2:--------------------------------]|*2
@@ -4474,19 +4513,189 @@ describe('builtin popupmenu', function()
{2:WINBAR }|
^popup menu test |
]],
- })
+ }
else
feed('<LeftMouse><31,2>')
- screen:expect([[
+ no_menu_screen = {
+ grid = [[
popup menu test |
{1:~ }|
{3:[No Name] [+] }|
popup menu test│{2:WINBAR }|
{1:~ }│^popup menu test |
:let g:menustr = 'bar' |
- ]])
+ ]],
+ }
end
+ screen:expect(no_menu_screen)
eq('bar', api.nvim_get_var('menustr'))
+
+ local no_sel_screen ---@type string|test.function.ui.screen.Expect
+ if multigrid then
+ no_sel_screen = {
+ grid = [[
+ ## grid 1
+ [2:--------------------------------]|*2
+ {3:[No Name] [+] }|
+ [5:---------------]│[6:----------------]|*2
+ [3:--------------------------------]|
+ ## grid 2
+ popup menu test |
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'bar' |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {n: baz }|
+ ## grid 5
+ popup menu test|
+ {1:~ }|
+ ## grid 6
+ {2:WINBAR }|
+ ^popup menu test |
+ ]],
+ float_pos = { [4] = { -1, 'NW', 1, 1, 19, false, 250 } },
+ }
+ else
+ no_sel_screen = {
+ grid = [[
+ popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {3:[No Name] [+] }{n: bar }{3: }|
+ popup menu test│{2:WIN}{n: baz }{2: }|
+ {1:~ }│^popup menu test |
+ :let g:menustr = 'bar' |
+ ]],
+ }
+ end
+ local sel_screens = {} ---@type (string|test.function.ui.screen.Expect)[]
+ for i, s in ipairs({ 'foo', 'bar', 'baz' }) do
+ local sel_screen = vim.deepcopy(no_sel_screen)
+ local grid = assert(sel_screen.grid)
+ grid = grid:gsub(vim.pesc(('{n: %s }'):format(s)), ('{s: %s }'):format(s))
+ sel_screen.grid = grid
+ sel_screens[i] = sel_screen
+ end
+
+ command([[let g:menustr = '']])
+ local g = multigrid and 1 or 0
+
+ api.nvim_input_mouse('right', 'press', '', g, 0, 20)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 1, 19)
+ screen:expect(sel_screens[1])
+ api.nvim_input_mouse('move', '', '', g, 1, 18)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 2, 23)
+ screen:expect(sel_screens[2])
+ api.nvim_input_mouse('move', '', '', g, 2, 24)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 3, 19)
+ screen:expect(sel_screens[3])
+ api.nvim_input_mouse('left', 'press', '', g, 3, 18)
+ screen:expect(no_menu_screen)
+ eq('', api.nvim_get_var('menustr'))
+
+ command('wincmd t | set rightleft')
+ if multigrid then
+ no_menu_screen = {
+ grid = [[
+ ## grid 1
+ [2:--------------------------------]|*2
+ {4:[No Name] [+] }|
+ [5:---------------]│[6:----------------]|*2
+ [3:--------------------------------]|
+ ## grid 2
+ tset unem pupo^p|
+ {1: ~}|
+ ## grid 3
+ :let g:menustr = 'bar' |
+ ## grid 5
+ popup menu test|
+ {1:~ }|
+ ## grid 6
+ {2:WINBAR }|
+ popup menu test |
+ ]],
+ }
+ else
+ no_menu_screen = {
+ grid = [[
+ tset unem pupo^p|
+ {1: ~}|
+ {4:[No Name] [+] }|
+ popup menu test│{2:WINBAR }|
+ {1:~ }│popup menu test |
+ :let g:menustr = 'bar' |
+ ]],
+ }
+ end
+ screen:expect(no_menu_screen)
+
+ if multigrid then
+ no_sel_screen = {
+ grid = [[
+ ## grid 1
+ [2:--------------------------------]|*2
+ {4:[No Name] [+] }|
+ [5:---------------]│[6:----------------]|*2
+ [3:--------------------------------]|
+ ## grid 2
+ tset unem pupo^p|
+ {1: ~}|
+ ## grid 3
+ :let g:menustr = 'bar' |
+ ## grid 4
+ {n: oof }|
+ {n: rab }|
+ {n: zab }|
+ ## grid 5
+ popup menu test|
+ {1:~ }|
+ ## grid 6
+ {2:WINBAR }|
+ popup menu test |
+ ]],
+ float_pos = { [4] = { -1, 'NW', 1, 1, 17, false, 250 } },
+ }
+ else
+ no_sel_screen = {
+ grid = [[
+ tset unem pupo^p|
+ {1: }{n: oof }{1: ~}|
+ {4:[No Name] [+] }{n: rab }{4: }|
+ popup menu test│{2:W}{n: zab }{2: }|
+ {1:~ }│popup menu test |
+ :let g:menustr = 'bar' |
+ ]],
+ }
+ end
+ for i, s in ipairs({ 'oof', 'rab', 'zab' }) do
+ local sel_screen = vim.deepcopy(no_sel_screen)
+ local grid = assert(sel_screen.grid)
+ grid = grid:gsub(vim.pesc(('{n: %s }'):format(s)), ('{s: %s }'):format(s))
+ sel_screen.grid = grid
+ sel_screens[i] = sel_screen
+ end
+
+ api.nvim_input_mouse('right', 'press', '', g, 0, 20)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 1, 21)
+ screen:expect(sel_screens[1])
+ api.nvim_input_mouse('move', '', '', g, 1, 22)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 2, 17)
+ screen:expect(sel_screens[2])
+ api.nvim_input_mouse('move', '', '', g, 2, 16)
+ screen:expect(no_sel_screen)
+ api.nvim_input_mouse('move', '', '', g, 3, 21)
+ screen:expect(sel_screens[3])
+ api.nvim_input_mouse('left', 'press', '', g, 3, 22)
+ screen:expect(no_menu_screen)
+ eq('', api.nvim_get_var('menustr'))
+
+ command('set norightleft')
end)
if not multigrid then
@@ -4963,20 +5172,31 @@ describe('builtin popupmenu', function()
feed('<C-E><Esc>')
end)
- -- oldtest: Test_pum_user_hl_group()
- it('custom hl_group override', function()
+ -- oldtest: Test_pum_user_abbr_hlgroup()
+ it('custom abbr_hlgroup override', function()
exec([[
- func CompleteFunc( findstart, base )
+ let s:var = 0
+ func CompleteFunc(findstart, base)
if a:findstart
return 0
endif
+ if s:var == 1
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'abbr_hlgroup': 'StrikeFake' },
+ \ { 'word': '你好', 'abbr_hlgroup': 'StrikeFake' },
+ \]}
+ endif
return {
\ 'words': [
- \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
- \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' },
\]}
endfunc
+ func ChangeVar()
+ let s:var = 1
+ endfunc
set completeopt=menu
set completefunc=CompleteFunc
@@ -4990,9 +5210,9 @@ describe('builtin popupmenu', function()
feed('Saw<C-X><C-U>')
screen:expect([[
aword1^ |
- {ds:aword1 W extra text 1 }{1: }|
+ {ds:aword1}{s: W extra text 1 }{1: }|
{n:aword2 W extra text 2 }{1: }|
- {dn:你好 W extra text 3 }{1: }|
+ {dn:你好}{n: W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
@@ -5003,22 +5223,33 @@ describe('builtin popupmenu', function()
feed('Saw<C-X><C-U>')
screen:expect([[
aword1^ |
- {uds:aw}{ds:ord1 W extra text 1 }{1: }|
+ {uds:aw}{ds:ord1}{s: W extra text 1 }{1: }|
{umn:aw}{n:ord2 W extra text 2 }{1: }|
- {dn:你好 W extra text 3 }{1: }|
+ {dn:你好}{n: W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-N>')
screen:expect([[
aword2^ |
- {udn:aw}{dn:ord1 W extra text 1 }{1: }|
+ {udn:aw}{dn:ord1}{n: W extra text 1 }{1: }|
{ums:aw}{s:ord2 W extra text 2 }{1: }|
- {dn:你好 W extra text 3 }{1: }|
+ {dn:你好}{n: W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 2 of 3} |
]])
feed('<C-E><Esc>')
+
+ command('call ChangeVar()')
+ feed('S<C-X><C-U>')
+ screen:expect([[
+ aword1^ |
+ {ds:aword1}{s: }{1: }|
+ {dn:你好}{n: }{1: }|
+ {1:~ }|*16
+ {2:-- }{5:match 1 of 2} |
+ ]])
+ feed('<C-E><Esc>')
end)
-- oldtest: Test_pum_user_kind_hlgroup()
@@ -5030,7 +5261,7 @@ describe('builtin popupmenu', function()
endif
return {
\ 'words': [
- \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'abbr_hlgroup': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' },
\ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' },
\]}
@@ -5053,9 +5284,9 @@ describe('builtin popupmenu', function()
feed('S<C-X><C-U>')
screen:expect([[
aword1^ |
- {ds:aword1 }{kvs:variable }{ds:extra text 1 }{1: }|
- {n:aword2 }{kfn:function }{n:extra text 2 }{1: }|
- {n:你好 }{kcn:class }{n:extra text 3 }{1: }|
+ {ds:aword1}{s: }{kvs:variable}{s: extra text 1 }{1: }|
+ {n:aword2 }{kfn:function}{n: extra text 2 }{1: }|
+ {n:你好 }{kcn:class}{n: extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua
index 73923a153a..3750ce3d3f 100644
--- a/test/functional/ui/quickfix_spec.lua
+++ b/test/functional/ui/quickfix_spec.lua
@@ -11,7 +11,6 @@ describe('quickfix selection highlight', function()
clear()
screen = Screen.new(25, 10)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { reverse = true },
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index f1891b608e..8e15e6c35f 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -6,23 +6,15 @@
--
-- Example usage:
--
+-- -- Attach a screen to the current Nvim instance.
-- local screen = Screen.new(25, 10)
--- -- Attach the screen to the current Nvim instance.
--- screen:attach()
-- -- Enter insert-mode and type some text.
-- feed('ihello screen')
-- -- Assert the expected screen state.
-- screen:expect([[
--- hello screen |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- -- INSERT -- |
+-- hello screen^ |
+-- {1:~ }|*8
+-- {5:-- INSERT --} |
-- ]]) -- <- Last line is stripped
--
-- Since screen updates are received asynchronously, expect() actually specifies
@@ -36,36 +28,19 @@
-- * If the timeout expires, the last match error will be reported and the
-- test will fail.
--
--- Continuing the above example, say we want to assert that "-- INSERT --" is
--- highlighted with the bold attribute. The expect() call should look like this:
---
--- NonText = Screen.colors.Blue
--- screen:expect([[
--- hello screen |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- ~ |
--- {b:-- INSERT --} |
--- ]], {b = {bold = true}}, {{bold = true, foreground = NonText}})
---
--- In this case "b" is a string associated with the set composed of one
--- attribute: bold. Note that since the {b:} markup is not a real part of the
+-- The 30 most common highlight groups are predefined, see init_colors() below.
+-- In this case "5" is a predefined highlight associated with the set composed of one
+-- attribute: bold. Note that since the {5:} markup is not a real part of the
-- screen, the delimiter "|" moved to the right. Also, the highlighting of the
--- NonText markers "~" is ignored in this test.
+-- NonText markers "~" is visible.
--
--- Tests will often share a group of attribute sets to expect(). Those can be
+-- Tests will often share a group of extra attribute sets to expect(). Those can be
-- defined at the beginning of a test:
--
--- NonText = Screen.colors.Blue
--- screen:set_default_attr_ids( {
--- [1] = {reverse = true, bold = true},
--- [2] = {reverse = true}
--- })
+-- screen:add_extra_attr_ids {
+-- [100] = { background = Screen.colors.Plum1, underline = true },
+-- [101] = { background = Screen.colors.Red1, bold = true, underline = true },
+-- }
--
-- To help write screen tests, see Screen:snapshot_util().
-- To debug screen tests, see Screen:redraw_debug().
@@ -180,14 +155,30 @@ local function _init_colors()
}
end
+--- @class test.functional.ui.screen.Opts
+--- @field ext_linegrid? boolean
+--- @field ext_multigrid? boolean
+--- @field ext_newgrid? boolean
+--- @field ext_popupmenu? boolean
+--- @field ext_wildmenu? boolean
+--- @field rgb? boolean
+--- @field _debug_float? boolean
+
--- @param width? integer
--- @param height? integer
+--- @param options? test.functional.ui.screen.Opts
+--- @param session? test.Session|false
--- @return test.functional.ui.screen
-function Screen.new(width, height)
+function Screen.new(width, height, options, session)
if not Screen.colors then
_init_colors()
end
+ options = options or {}
+ if options.ext_linegrid == nil then
+ options.ext_linegrid = true
+ end
+
local self = setmetatable({
timeout = default_screen_timeout,
title = '',
@@ -227,6 +218,7 @@ function Screen.new(width, height)
_new_attrs = false,
_width = width or 53,
_height = height or 14,
+ _options = options,
_grids = {},
_grid_win_extmarks = {},
_cursor = {
@@ -250,6 +242,11 @@ function Screen.new(width, height)
self.uimeths = create_callindex(ui)
+ -- session is often nil, which implies the default session
+ if session ~= false then
+ self:attach(session)
+ end
+
return self
end
@@ -277,20 +274,10 @@ function Screen:set_rgb_cterm(val)
self._rgb_cterm = val
end
---- @class test.functional.ui.screen.Opts
---- @field ext_linegrid? boolean
---- @field ext_multigrid? boolean
---- @field ext_newgrid? boolean
---- @field ext_popupmenu? boolean
---- @field ext_wildmenu? boolean
---- @field rgb? boolean
---- @field _debug_float? boolean
-
---- @param options? test.functional.ui.screen.Opts
--- @param session? test.Session
-function Screen:attach(options, session)
+function Screen:attach(session)
session = session or get_session()
- options = options or {}
+ local options = self._options
if options.ext_linegrid == nil then
options.ext_linegrid = true
@@ -1524,7 +1511,7 @@ end
function Screen:_chunks_repr(chunks, attr_state)
local repr_chunks = {}
for i, chunk in ipairs(chunks) do
- local hl, text = unpack(chunk)
+ local hl, text, id = unpack(chunk)
local attrs
if self._options.ext_linegrid then
attrs = self._attr_table[hl][1]
@@ -1532,7 +1519,7 @@ function Screen:_chunks_repr(chunks, attr_state)
attrs = hl
end
local attr_id = self:_get_attr_id(attr_state, attrs, hl)
- repr_chunks[i] = { text, attr_id }
+ repr_chunks[i] = { text, attr_id, attr_id and id or nil }
end
return repr_chunks
end
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 85a653df36..f39e9ecc33 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -29,7 +29,6 @@ describe('screen', function()
local screen_nvim = spawn(nvim_argv)
set_session(screen_nvim)
screen = Screen.new()
- screen:attach()
end)
it('default initial screen', function()
@@ -47,8 +46,7 @@ local function screen_tests(linegrid)
before_each(function()
clear()
- screen = Screen.new()
- screen:attach({ rgb = true, ext_linegrid = linegrid })
+ screen = Screen.new(53, 14, { rgb = true, ext_linegrid = linegrid })
screen:set_default_attr_ids({
[0] = { bold = true, foreground = 255 },
[1] = { bold = true, reverse = true },
@@ -717,8 +715,7 @@ describe('Screen default colors', function()
}
local screen_nvim = spawn(nvim_argv)
set_session(screen_nvim)
- screen = Screen.new()
- screen:attach(termcolors and { rgb = true, ext_termcolors = true } or { rgb = true })
+ screen = Screen.new(53, 14, { rgb = true, ext_termcolors = termcolors or nil })
end
it('are dark per default', function()
@@ -777,7 +774,6 @@ end)
it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function()
clear()
local screen = Screen.new(100, 100)
- screen:attach()
eq(100, api.nvim_get_option_value('lines', {}))
eq(99, api.nvim_get_option_value('window', {}))
eq(99, api.nvim_win_get_height(0))
@@ -810,7 +806,6 @@ end)
it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", function()
clear()
local screen = Screen.new(30, 2)
- screen:attach()
command('set showcmd redrawdebug=compositor')
feed('d')
screen:expect {
@@ -824,7 +819,6 @@ end)
it("scrolling in narrow window doesn't draw over separator #29033", function()
clear()
local screen = Screen.new(60, 8)
- screen:attach()
feed('100Oa<Esc>gg')
exec([[
set number nowrap
diff --git a/test/functional/ui/scrollbind_spec.lua b/test/functional/ui/scrollbind_spec.lua
index 9e70b25efa..84316762e4 100644
--- a/test/functional/ui/scrollbind_spec.lua
+++ b/test/functional/ui/scrollbind_spec.lua
@@ -10,7 +10,6 @@ describe('Scrollbind', function()
before_each(function()
screen = Screen.new(40, 12)
- screen:attach()
end)
it('works with one buffer with virtual lines', function()
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index eab265cbb1..86490b4527 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -16,7 +16,6 @@ describe('search highlighting', function()
before_each(function()
clear()
screen = Screen.new(40, 7)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { background = Screen.colors.Yellow }, -- Search
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 30da79af47..7874c04c39 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -12,21 +12,9 @@ describe('Signs', function()
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = 255 },
- [1] = { background = Screen.colors.Yellow },
- [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey },
- [3] = { background = Screen.colors.Gray90 },
- [4] = { bold = true, reverse = true },
- [5] = { reverse = true },
- [6] = { foreground = Screen.colors.Brown },
- [7] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
- [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [9] = { bold = true, foreground = Screen.colors.Magenta },
- [10] = { foreground = Screen.colors.Blue1 },
- [11] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- })
+ screen:add_extra_attr_ids {
+ [100] = { bold = true, foreground = Screen.colors.Magenta1 },
+ }
end)
describe(':sign place', function()
@@ -39,10 +27,10 @@ describe('Signs', function()
sign place 2 line=2 name=piet2 buffer=1
]])
screen:expect([[
- {1:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a |
- {1:𠜎̀́̂̃̄̅}b |
- {2: }^ |
- {0:~ }|*10
+ {10:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a |
+ {10:𠜎̀́̂̃̄̅}b |
+ {7: }^ |
+ {1:~ }|*10
|
]])
end)
@@ -57,11 +45,11 @@ describe('Signs', function()
sign place 3 line=1 name=pietx buffer=1
]])
screen:expect([[
- {1:>!}a |
- {2: }b |
- {1:>>}c |
- {2: }^ |
- {0:~ }|*9
+ {10:>!}a |
+ {7: }b |
+ {10:>>}c |
+ {7: }^ |
+ {1:~ }|*9
|
]])
end)
@@ -74,7 +62,7 @@ describe('Signs', function()
a |
b |
^ |
- {0:~ }|*10
+ {1:~ }|*10
|
]])
end)
@@ -91,18 +79,18 @@ describe('Signs', function()
sign place 3 line=2 name=piet buffer=1
]])
screen:expect([[
- {2: }{3:^a }|
- {1:>>}b |
- {2: }c |
- {2: } |
- {0:~ }|*2
- {4:[No Name] [+] }|
- {2: }{3:a }|
- {1:>>}b |
- {2: }c |
- {2: } |
- {0:~ }|
- {5:[No Name] [+] }|
+ {7: }{21:^a }|
+ {10:>>}b |
+ {7: }c |
+ {7: } |
+ {1:~ }|*2
+ {3:[No Name] [+] }|
+ {7: }{21:a }|
+ {10:>>}b |
+ {7: }c |
+ {7: } |
+ {1:~ }|
+ {2:[No Name] [+] }|
|
]])
end)
@@ -122,11 +110,11 @@ describe('Signs', function()
sign place 6 line=4 name=pietxx buffer=1
]])
screen:expect([[
- {1:>>}{6: 1 }a |
- {2: }{6: 2 }{8:b }|
- {2: }{7: 3 }c |
- {1:>>}{7: 4 }{8:^ }|
- {0:~ }|*9
+ {10:>>}{8: 1 }a |
+ {7: }{8: 2 }{9:b }|
+ {7: }{13: 3 }c |
+ {10:>>}{13: 4 }{9:^ }|
+ {1:~ }|*9
|
]])
-- Check that 'statuscolumn' correctly applies numhl
@@ -144,45 +132,45 @@ describe('Signs', function()
set cursorline
]])
screen:expect([[
- {1:>>}a |
- {1:>>}b |
- {8:>>}{3:^c }|
- {0:~ }|*10
+ {10:>>}a |
+ {10:>>}b |
+ {9:>>}{21:^c }|
+ {1:~ }|*10
|
]])
feed('k')
screen:expect([[
- {1:>>}a |
- {8:>>}{3:^b }|
- {1:>>}c |
- {0:~ }|*10
+ {10:>>}a |
+ {9:>>}{21:^b }|
+ {10:>>}c |
+ {1:~ }|*10
|
]])
exec('set nocursorline')
screen:expect([[
- {1:>>}a |
- {1:>>}^b |
- {1:>>}c |
- {0:~ }|*10
+ {10:>>}a |
+ {10:>>}^b |
+ {10:>>}c |
+ {1:~ }|*10
|
]])
exec('set cursorline cursorlineopt=line')
screen:expect([[
- {1:>>}a |
- {1:>>}{3:^b }|
- {1:>>}c |
- {0:~ }|*10
+ {10:>>}a |
+ {10:>>}{21:^b }|
+ {10:>>}c |
+ {1:~ }|*10
|
]])
exec('set cursorlineopt=number')
exec('hi! link SignColumn IncSearch')
feed('Go<esc>2G')
screen:expect([[
- {1:>>}a |
- {8:>>}^b |
- {1:>>}c |
- {5: } |
- {0:~ }|*9
+ {10:>>}a |
+ {9:>>}^b |
+ {10:>>}c |
+ {2: } |
+ {1:~ }|*9
|
]])
-- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726)
@@ -206,11 +194,11 @@ describe('Signs', function()
-- of signs, the ones with the highest Ids are being picked,
-- and presented by their sorted Id order.
screen:expect([[
- {2: }{6: 1 }a |
- {2: }{6: 2 }b |
- WW{1:>>}{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {7: }{8: 1 }a |
+ {7: }{8: 2 }b |
+ WW{10:>>}{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
exec([[
@@ -221,42 +209,42 @@ describe('Signs', function()
sign place 3 line=2 name=pietError buffer=1
]])
screen:expect([[
- {8:XX}{1:>>}{6: 1 }a |
- {1:>>}{8:XX}{6: 2 }b |
- WW{1:>>}{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {9:XX}{10:>>}{8: 1 }a |
+ {10:>>}{9:XX}{8: 2 }b |
+ WW{10:>>}{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- With the default setting, we get the sign with the top id.
exec('set signcolumn=yes:1')
screen:expect([[
- {8:XX}{6: 1 }a |
- {1:>>}{6: 2 }b |
- WW{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {9:XX}{8: 1 }a |
+ {10:>>}{8: 2 }b |
+ WW{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- "auto:3" accommodates all the signs we defined so far.
exec('set signcolumn=auto:3')
local s3 = [[
- {8:XX}{1:>>}{2: }{6: 1 }a |
- {1:>>}{8:XX}{2: }{6: 2 }b |
- WW{1:>>}{8:XX}{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {9:XX}{10:>>}{7: }{8: 1 }a |
+ {10:>>}{9:XX}{7: }{8: 2 }b |
+ WW{10:>>}{9:XX}{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]]
screen:expect(s3)
-- Check "yes:9".
exec('set signcolumn=yes:9')
screen:expect([[
- {8:XX}{1:>>}{2: }{6: 1 }a |
- {1:>>}{8:XX}{2: }{6: 2 }b |
- WW{1:>>}{8:XX}{2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {9:XX}{10:>>}{7: }{8: 1 }a |
+ {10:>>}{9:XX}{7: }{8: 2 }b |
+ WW{10:>>}{9:XX}{7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- Check "auto:N" larger than the maximum number of signs defined in
@@ -267,19 +255,19 @@ describe('Signs', function()
exec('3move1')
exec('2d')
screen:expect([[
- {8:XX}{1:>>}{6: 1 }a |
- {1:>>}{8:XX}{6: 2 }^b |
- {2: }{6: 3 } |
- {0:~ }|*10
+ {9:XX}{10:>>}{8: 1 }a |
+ {10:>>}{9:XX}{8: 2 }^b |
+ {7: }{8: 3 } |
+ {1:~ }|*10
|
]])
-- character deletion does not delete signs.
feed('x')
screen:expect([[
- {8:XX}{1:>>}{6: 1 }a |
- {1:>>}{8:XX}{6: 2 }^ |
- {2: }{6: 3 } |
- {0:~ }|*10
+ {9:XX}{10:>>}{8: 1 }a |
+ {10:>>}{9:XX}{8: 2 }^ |
+ {7: }{8: 3 } |
+ {1:~ }|*10
|
]])
end)
@@ -290,21 +278,21 @@ describe('Signs', function()
-- sign column should always accommodate at the minimum size
exec('set signcolumn=auto:1-3')
screen:expect([[
- {2: }{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {7: }{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- should support up to 8 signs at minimum
exec('set signcolumn=auto:8-9')
screen:expect([[
- {2: }{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {7: }{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- should keep the same sign size when signs are not exceeding
@@ -313,11 +301,11 @@ describe('Signs', function()
exec('sign define pietSearch text=>> texthl=Search')
exec('sign place 1 line=1 name=pietSearch buffer=1')
screen:expect([[
- {1:>>}{2: }{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {10:>>}{7: }{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- should resize itself when signs are exceeding minimum but
@@ -328,11 +316,11 @@ describe('Signs', function()
sign place 4 line=1 name=pietSearch buffer=1
]])
screen:expect([[
- {1:>>>>>>>>}{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {10:>>>>>>>>}{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
-- should not increase size because sign with existing id is moved
@@ -340,11 +328,11 @@ describe('Signs', function()
screen:expect_unchanged()
exec('sign unplace 4')
screen:expect([[
- {1:>>>>>>}{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {10:>>>>>>}{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
exec('sign place 4 line=1 name=pietSearch buffer=1')
@@ -357,11 +345,11 @@ describe('Signs', function()
sign place 8 line=1 name=pietSearch buffer=1
]])
screen:expect([[
- {1:>>>>>>>>>>}{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {10:>>>>>>>>>>}{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
end)
@@ -377,21 +365,21 @@ describe('Signs', function()
]])
-- no signcolumn with only empty sign
screen:expect([[
- {6: 1 }a |
- {6: 2 }b |
- {6: 3 }c |
- {6: 4 }^ |
- {0:~ }|*9
+ {8: 1 }a |
+ {8: 2 }b |
+ {8: 3 }c |
+ {8: 4 }^ |
+ {1:~ }|*9
|
]])
-- single column with 1 sign with text and one sign without
exec('sign place 1 line=1 name=pietSearch buffer=1')
screen:expect([[
- {1:>>}{6: 1 }a |
- {2: }{6: 2 }b |
- {2: }{6: 3 }c |
- {2: }{6: 4 }^ |
- {0:~ }|*9
+ {10:>>}{8: 1 }a |
+ {7: }{8: 2 }b |
+ {7: }{8: 3 }c |
+ {7: }{8: 4 }^ |
+ {1:~ }|*9
|
]])
end)
@@ -408,23 +396,23 @@ describe('Signs', function()
-- line number should be drawn if sign has no text
-- no signcolumn, line number for "a" is Search, for "b" is Error, for "c" is LineNr
screen:expect([[
- {1: >> }a |
- {8: 2 }b |
- {6: 3 }c |
- {6: 4 }^ |
- {0:~ }|*9
+ {10: >> }a |
+ {9: 2 }b |
+ {8: 3 }c |
+ {8: 4 }^ |
+ {1:~ }|*9
|
]])
-- number column on wrapped part of a line should be empty
feed('gg100aa<Esc>')
screen:expect([[
- {1: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {8: }aa^a |
- {8: 2 }b |
- {6: 3 }c |
- {6: 4 } |
- {0:~ }|*7
+ {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {9: }aa^a |
+ {9: 2 }b |
+ {8: 3 }c |
+ {8: 4 } |
+ {1:~ }|*7
|
]])
api.nvim_buf_set_extmark(0, api.nvim_create_namespace('test'), 0, 0, {
@@ -434,14 +422,14 @@ describe('Signs', function()
feed('<C-Y>')
-- number column on virtual lines should be empty
screen:expect([[
- {6: }VIRT LINES |
- {1: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {8: }aa^a |
- {8: 2 }b |
- {6: 3 }c |
- {6: 4 } |
- {0:~ }|*6
+ {8: }VIRT LINES |
+ {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {9: }aa^a |
+ {9: 2 }b |
+ {8: 3 }c |
+ {8: 4 } |
+ {1:~ }|*6
|
]])
end)
@@ -451,21 +439,21 @@ describe('Signs', function()
exec('sign place 100000 line=1 name=piet buffer=1')
feed(':sign place<cr>')
screen:expect([[
- {1:>>} |
- {0:~ }|*6
- {4: }|
+ {10:>>} |
+ {1:~ }|*6
+ {3: }|
:sign place |
- {9:--- Signs ---} |
- {10:Signs for [NULL]:} |
+ {100:--- Signs ---} |
+ {18:Signs for [NULL]:} |
line=1 id=100000 name=piet priority=10 |
|
- {11:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
screen:expect([[
- {1:>>}^ |
- {0:~ }|*12
+ {10:>>}^ |
+ {1:~ }|*12
|
]])
end)
@@ -479,11 +467,11 @@ describe('Signs', function()
exec('2delete')
exec('sign unplace 10001')
screen:expect([[
- {2: }a |
- {2: }^c |
- {2: }d |
+ {7: }a |
+ {7: }^c |
+ {7: }d |
>>e |
- {0:~ }|*9
+ {1:~ }|*9
|
]])
exec('sign unplace 10002')
@@ -492,7 +480,7 @@ describe('Signs', function()
^c |
d |
e |
- {0:~ }|*9
+ {1:~ }|*9
|
]])
end)
@@ -505,13 +493,13 @@ describe('Signs', function()
exec('copy .')
exec('sign unplace 10001')
screen:expect([[
- {2: }a |
- {2: }^a |
- {2: }b |
- {2: }c |
- {2: }d |
+ {7: }a |
+ {7: }^a |
+ {7: }b |
+ {7: }c |
+ {7: }d |
>>e |
- {0:~ }|*7
+ {1:~ }|*7
|
]])
exec('sign unplace 10002')
@@ -522,7 +510,7 @@ describe('Signs', function()
c |
d |
e |
- {0:~ }|*7
+ {1:~ }|*7
|
]])
end)
@@ -537,9 +525,9 @@ describe('Signs', function()
call sign_place(0, '', 'foo', bufnr(''), { 'lnum':2 })
]])
screen:expect([[
- {8: 1 }^line1 |
- {8: 2 }line2 |
- {6: 3 }line3 |
+ {9: 1 }^line1 |
+ {9: 2 }line2 |
+ {8: 3 }line3 |
|
]])
end)
@@ -561,11 +549,11 @@ describe('Signs', function()
exec('norm 2Gdd')
exec('silent undo')
screen:expect([[
- {2: }1 |
+ {7: }1 |
S1^2 |
- {2: }3 |
- {2: }4 |
- {0:~ }|*9
+ {7: }3 |
+ {7: }4 |
+ {1:~ }|*9
|
]])
end)
@@ -590,7 +578,7 @@ describe('Signs', function()
local s1 = {
grid = [[
S2^ |
- {0:~ }|*12
+ {1:~ }|*12
|
]],
}
@@ -600,7 +588,7 @@ describe('Signs', function()
screen:expect({
grid = [[
S2S1^ |
- {0:~ }|*12
+ {1:~ }|*12
|
]],
})
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index da112148cd..86d5a362e5 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -17,7 +17,6 @@ describe("'spell'", function()
before_each(function()
clear()
screen = Screen.new(80, 8)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { special = Screen.colors.Red, undercurl = true },
@@ -377,4 +376,83 @@ describe("'spell'", function()
|
]])
end)
+
+ it('overrides syntax when Visual selection is active', function()
+ screen:try_resize(43, 3)
+ screen:set_default_attr_ids({
+ [0] = { bold = true, foreground = Screen.colors.Blue },
+ [1] = { foreground = Screen.colors.Blue },
+ [2] = { foreground = Screen.colors.Red },
+ [3] = { foreground = Screen.colors.Blue, underline = true },
+ [4] = { foreground = Screen.colors.Red, underline = true },
+ [5] = { bold = true },
+ })
+ exec([[
+ hi! Comment guibg=NONE guifg=Blue gui=NONE guisp=NONE
+ hi! SpellBad guibg=NONE guifg=Red gui=NONE guisp=NONE
+ hi! Visual guibg=NONE guifg=NONE gui=underline guisp=NONE
+ syn match Comment "//.*"
+ call setline(1, '// Here is a misspeld word.')
+ set spell
+ ]])
+ screen:expect([[
+ {1:^// Here is a }{2:misspeld}{1: word.} |
+ {0:~ }|
+ |
+ ]])
+ feed('V')
+ screen:expect([[
+ {1:^/}{3:/ Here is a }{4:misspeld}{3: word.} |
+ {0:~ }|
+ {5:-- VISUAL LINE --} |
+ ]])
+ end)
+
+ it("global value works properly for 'spelloptions'", function()
+ screen:try_resize(43, 3)
+ exec('set spell')
+ -- :setglobal applies to future buffers but not current buffer
+ exec('setglobal spelloptions=camel')
+ insert('Here is TheCamelWord being spellchecked')
+ screen:expect([[
+ Here is {1:TheCamelWord} being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ exec('enew')
+ insert('There is TheCamelWord being spellchecked')
+ screen:expect([[
+ There is TheCamelWord being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ -- :setlocal applies to current buffer but not future buffers
+ exec('setlocal spelloptions=')
+ screen:expect([[
+ There is {1:TheCamelWord} being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ exec('enew')
+ insert('What is TheCamelWord being spellchecked')
+ screen:expect([[
+ What is TheCamelWord being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ -- :set applies to both current buffer and future buffers
+ exec('set spelloptions=')
+ screen:expect([[
+ What is {1:TheCamelWord} being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ exec('enew')
+ insert('Where is TheCamelWord being spellchecked')
+ screen:expect([[
+ Where is {1:TheCamelWord} being spellchecke^d |
+ {0:~ }|
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index b4d4c94a5e..268e7173e6 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -20,7 +20,6 @@ describe('statuscolumn', function()
before_each(function()
clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM')
screen = Screen.new()
- screen:attach()
exec_lua('ns = vim.api.nvim_create_namespace("")')
end)
@@ -235,30 +234,24 @@ describe('statuscolumn', function()
it('works with wrapped lines, signs and folds', function()
command([[set stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]])
command("call setline(1,repeat([repeat('aaaaa',10)],16))")
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.Brown },
- [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey },
- [3] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
- [4] = { bold = true, foreground = Screen.colors.Brown },
- [5] = { foreground = Screen.colors.Red },
- [6] = { foreground = Screen.colors.Red, background = Screen.colors.LightGrey },
- })
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Red, background = Screen.colors.LightGray },
+ }
command('hi! CursorLine guifg=Red guibg=NONE')
screen:expect([[
- {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1: │ }a |
- {1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
+ {8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8: │ }a |
+ {8:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:@@@}|
|
]])
command([[set stc=%C%s%=%l│\ ]])
@@ -271,108 +264,108 @@ describe('statuscolumn', function()
command('sign place 3 line=6 name=piet1 buffer=1')
command('sign place 4 line=6 name=piet2 buffer=1')
screen:expect([[
- {1:>>}{2: }{1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {0:>!}{2: }{1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {0:>!}{1:>> 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {2: }{1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {2: }{1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {2: }{1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │ }aaaaa |
- {2: }{1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
+ {8:>>}{7: }{8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {1:>!}{7: }{8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {1:>!}{8:>> 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {7: }{8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {7: }{8: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {7: }{8: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │ }aaaaa |
+ {7: }{8:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:@@@}|
|
]])
command('norm zf$')
-- Check that alignment works properly with signs after %=
command([[set stc=%C%=%{v:virtnum?'':v:lnum}│%s\ ]])
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2:+}{1: 8│}{2: }{1: }{3:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7:+}{8: 8│}{7: }{8: }{13:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
|
]])
command('set cursorline')
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2:+}{4: 8│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
- {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7:+}{15: 8│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
+ {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaa |
|
]])
-- v:lnum is the same value on wrapped lines
command([[set stc=%C%=%{v:lnum}│%s\ ]])
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 4│}{2: }{1: }aaaaaa |
- {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 5│}{2: }{1: }aaaaaa |
- {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 6│}{2: }{1: }aaaaaa |
- {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 7│}{2: }{1: }aaaaaa |
- {2:+}{4: 8│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 9│}{2: }{1: }aaaaaa |
- {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1:10│}{2: }{1: }aaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{7: }{8: }aaaaaa |
+ {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 5│}{7: }{8: }aaaaaa |
+ {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 6│}{7: }{8: }aaaaaa |
+ {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 7│}{7: }{8: }aaaaaa |
+ {7:+}{15: 8│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 9│}{7: }{8: }aaaaaa |
+ {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8:10│}{7: }{8: }aaaaaa |
|
]])
-- v:relnum is the same value on wrapped lines
command([[set stc=%C%=\ %{v:relnum}│%s\ ]])
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 4│}{2: }{1: }aaaaaaa |
- {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 3│}{2: }{1: }aaaaaaa |
- {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 2│}{2: }{1: }aaaaaaa |
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 1│}{2: }{1: }aaaaaaa |
- {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 1│}{2: }{1: }aaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: 2│}{2: }{1: }aaaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{7: }{8: }aaaaaaa |
+ {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 3│}{7: }{8: }aaaaaaa |
+ {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{7: }{8: }aaaaaaa |
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 1│}{7: }{8: }aaaaaaa |
+ {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 1│}{7: }{8: }aaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{7: }{8: }aaaaaaa |
|
]])
command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]])
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
- {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
- {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
- {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
+ {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
+ {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
+ {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaa |
|
]])
-- Up to 9 signs in a line
@@ -385,75 +378,75 @@ describe('statuscolumn', function()
command('sign place 10 line=6 name=piet2 buffer=1')
command('sign place 11 line=6 name=piet1 buffer=1')
screen:expect([[
- {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
- {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaa}|
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
+ {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
-- Also test fold and sign column when 'cpoptions' includes "n"
command('set cpoptions+=n')
feed('Hgjg0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:^aaaaaaaaaaaaaaaaaaaaa }|
- {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{19:^aaaaaaaaaaaaaaaaaaaaa }|
+ {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7:+}{8: 4│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('set breakindent')
command('sign unplace 2')
feed('J2gjg0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: } {5:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}|
- {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: } {5:^aaaaaaaaaaaaaa }|
- {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
- {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: } {19:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}|
+ {7: } {19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: } {19:^aaaaaaaaaaaaaa }|
+ {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: } aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: } aaaaaaaaaaaaaaaaaaaaa |
+ {7:+}{8: 3│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {7: }{8: 4│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: } aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 5│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: } aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('set nobreakindent')
feed('$g0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}|
- {2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:^aaaa }|
- {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
- {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{19:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}|
+ {7: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{19:^aaaa }|
+ {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7:+}{8: 3│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {7: }{8: 4│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
+ {7: }{8: 5│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('silent undo')
@@ -467,38 +460,38 @@ describe('statuscolumn', function()
]])
command('set foldcolumn=0 signcolumn=number stc=%l')
screen:expect([[
- {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1: }virt_line |
- {1: }virt_line above |
- {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {4: 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {1: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
- {1:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8: }virt_line |
+ {8: }virt_line above |
+ {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {15: 8}{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {8: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {8:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
|
]])
command(
[[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]]
)
screen:expect([[
- {1:buffer 0 4}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 4}aaaaaaaa |
- {1:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 5}aaaaaaaa |
- {1:virtual-2 5}virt_line |
- {1:virtual-1 5}virt_line above |
- {1:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 6}aaaaaaaa |
- {1:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 7}aaaaaaaa |
- {4:buffer 0 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 9}aaaaaaaa |
+ {8:buffer 0 4}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 4}aaaaaaaa |
+ {8:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 5}aaaaaaaa |
+ {8:virtual-2 5}virt_line |
+ {8:virtual-1 5}virt_line above |
+ {8:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 6}aaaaaaaa |
+ {8:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 7}aaaaaaaa |
+ {15:buffer 0 8}{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {8:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 9}aaaaaaaa |
|
]])
-- Also test virt_lines at the end of buffer
@@ -507,17 +500,17 @@ describe('statuscolumn', function()
]])
feed('GkJzz')
screen:expect([[
- {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 12}aaaaaaaaa |
- {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 13}aaaaaaaaa |
- {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 14}aaaaaaaaa |
- {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {4:wrapped 1 15}{5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {4:wrapped 2 15}{5:aaaaaaaaaaaaaaaaaaa }|
- {1:virtual-1 15}END |
- {0:~ }|*3
+ {8:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 12}aaaaaaaaa |
+ {8:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 13}aaaaaaaaa |
+ {8:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 14}aaaaaaaaa |
+ {15:buffer 0 15}{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {15:wrapped 1 15}{19:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {15:wrapped 2 15}{19:aaaaaaaaaaaaaaaaaaa }|
+ {8:virtual-1 15}END |
+ {1:~ }|*3
|
]])
-- Also test virt_lines when 'cpoptions' includes "n"
@@ -527,19 +520,19 @@ describe('statuscolumn', function()
vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line2", ""}}} })
]])
screen:expect([[
- {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaa |
- {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaa |
- {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaa |
- {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {5:aaaaaaa }|
- {1:virtual-3 15}virt_line1 |
- {1:virtual-2 15}virt_line2 |
- {1:virtual-1 15}END |
- {0:~ }|
+ {15:buffer 0 15}{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {19:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {19:aaaaaaa }|
+ {8:virtual-3 15}virt_line1 |
+ {8:virtual-2 15}virt_line2 |
+ {8:virtual-1 15}END |
+ {1:~ }|
|
]])
-- Also test "col_rows" code path for 'relativenumber' cursor movement
@@ -548,36 +541,36 @@ describe('statuscolumn', function()
set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum.'\ '.v:relnum}
]])
screen:expect([[
- {1:buffer 0 12 3}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 12 3}aaaaaaaaaaa |
- {1:buffer 0 13 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 13 2}aaaaaaaaaaa |
- {1:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 14 1}aaaaaaaaaaa |
- {1:buffer 0 15 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 15 0}aaaaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 2 15 0}aaaaaaaaaaaaaaaaaaaaaaa |
- {1:virtual-3 15 0}virt_line1 |
- {1:virtual-2 15 0}virt_line2 |
- {1:virtual-1 15 0}END |
- {0:~ }|
+ {8:buffer 0 12 3}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 12 3}aaaaaaaaaaa |
+ {8:buffer 0 13 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 13 2}aaaaaaaaaaa |
+ {8:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 14 1}aaaaaaaaaaa |
+ {8:buffer 0 15 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 15 0}aaaaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 2 15 0}aaaaaaaaaaaaaaaaaaaaaaa |
+ {8:virtual-3 15 0}virt_line1 |
+ {8:virtual-2 15 0}virt_line2 |
+ {8:virtual-1 15 0}END |
+ {1:~ }|
|
]])
feed('kk')
screen:expect([[
- {1:buffer 0 12 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 12 1}aaaaaaaaaaa |
- {1:buffer 0 13 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 13 0}aaaaaaaaaa^a |
- {1:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 14 1}aaaaaaaaaaa |
- {1:buffer 0 15 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 1 15 2}aaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {1:wrapped 2 15 2}aaaaaaaaaaaaaaaaaaaaaaa |
- {1:virtual-3 15 2}virt_line1 |
- {1:virtual-2 15 2}virt_line2 |
- {1:virtual-1 15 2}END |
- {0:~ }|
+ {8:buffer 0 12 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 12 1}aaaaaaaaaaa |
+ {8:buffer 0 13 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 13 0}aaaaaaaaaa^a |
+ {8:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 14 1}aaaaaaaaaaa |
+ {8:buffer 0 15 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 1 15 2}aaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {8:wrapped 2 15 2}aaaaaaaaaaaaaaaaaaaaaaa |
+ {8:virtual-3 15 2}virt_line1 |
+ {8:virtual-2 15 2}virt_line2 |
+ {8:virtual-1 15 2}END |
+ {1:~ }|
|
]])
end)
@@ -680,10 +673,6 @@ describe('statuscolumn', function()
it('popupmenu callback does not drag mouse on close', function()
screen:try_resize(screen._width, 2)
- screen:set_default_attr_ids({
- [0] = { foreground = Screen.colors.Brown },
- [1] = { background = Screen.colors.Plum1 },
- })
api.nvim_set_option_value('statuscolumn', '%0@MyClickFunc@%l%T', {})
exec([[
function! MyClickFunc(minwid, clicks, button, mods)
@@ -695,26 +684,26 @@ describe('statuscolumn', function()
-- clicking an item does not drag mouse
api.nvim_input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
- {0: 8}^aaaaa |
- {1: Echo } |
+ {8: 8}^aaaaa |
+ {4: Echo } |
]])
api.nvim_input_mouse('left', 'press', '', 0, 1, 5)
api.nvim_input_mouse('left', 'release', '', 0, 1, 5)
screen:expect([[
- {0: 8}^aaaaa |
+ {8: 8}^aaaaa |
0 1 l 8 |
]])
command('echo')
-- clicking outside to close the menu does not drag mouse
api.nvim_input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
- {0: 8}^aaaaa |
- {1: Echo } |
+ {8: 8}^aaaaa |
+ {4: Echo } |
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 10)
api.nvim_input_mouse('left', 'release', '', 0, 0, 10)
screen:expect([[
- {0: 8}^aaaaa |
+ {8: 8}^aaaaa |
|
]])
end)
@@ -943,16 +932,15 @@ describe('statuscolumn', function()
it('does not wrap multibyte characters at the end of a line', function()
screen:try_resize(33, 4)
- screen:set_default_attr_ids {
- [8] = { foreground = Screen.colors.Brown },
- [31] = { undercurl = true, special = Screen.colors.Red },
+ screen:add_extra_attr_ids {
+ [100] = { undercurl = true, special = Screen.colors.Red },
}
command([[set spell stc=%l\ ]])
command('call setline(8, "This is a line that contains ᶏ multibyte character.")')
screen:expect([[
- {8: 8 }^This is a line that contains {31:ᶏ}|
- {8: } {31:multibyte} character. |
- {8: 9 }{31:aaaaa} |
+ {8: 8 }^This is a line that contains {100:ᶏ}|
+ {8: } {100:multibyte} character. |
+ {8: 9 }{100:aaaaa} |
|
]])
end)
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 937e709d66..1d0f181244 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -24,11 +24,9 @@ for _, model in ipairs(mousemodels) do
before_each(function()
clear()
screen = Screen.new(40, 8)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- StatusLine
- })
- screen:attach()
+ screen:add_extra_attr_ids {
+ [100] = { bold = true, reverse = true, foreground = Screen.colors.Blue },
+ }
command('set laststatus=2 mousemodel=' .. model)
exec([=[
function! MyClickFunc(minwid, clicks, button, mods)
@@ -86,8 +84,8 @@ for _, model in ipairs(mousemodels) do
screen:expect {
grid = [[
^ |
- {0:~ }|*5
- {1:^I}{0:^A^I^A^I}{1:^A }|
+ {1:~ }|*5
+ {3:^I}{100:^A^I^A^I}{3:^A }|
|
]],
}
@@ -210,8 +208,8 @@ for _, model in ipairs(mousemodels) do
screen:expect {
grid = [[
^ │ |
- {0:~ }│{0:~ }|*5
- {1:Clicky stuff Clicky stuff}|
+ {1:~ }│{1:~ }|*5
+ {3:Clicky stuff Clicky stuff}|
|
]],
}
@@ -255,14 +253,9 @@ describe('global statusline', function()
before_each(function()
clear()
screen = Screen.new(60, 16)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue },
- [2] = { bold = true, reverse = true },
- [3] = { bold = true },
- [4] = { reverse = true },
- [5] = { bold = true, foreground = Screen.colors.Fuchsia },
- })
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Magenta1, bold = true },
+ }
command('set laststatus=3')
command('set ruler')
end)
@@ -271,7 +264,7 @@ describe('global statusline', function()
screen:expect([[
^ |
{1:~ }|*13
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
@@ -280,8 +273,8 @@ describe('global statusline', function()
|*2
^ |
{1:~ }|*11
- {2:[No Name] [+] 3,1 All}|
- {3:-- INSERT --} |
+ {3:[No Name] [+] 3,1 All}|
+ {5:-- INSERT --} |
]])
end)
@@ -298,7 +291,7 @@ describe('global statusline', function()
────────────────────┴────────────────┴─┤{1:~ }|
│{1:~ }|
{1:~ }│{1:~ }|*3
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
end)
@@ -315,7 +308,7 @@ describe('global statusline', function()
screen:expect([[
^ |
{1:~ }|*13
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
@@ -324,15 +317,15 @@ describe('global statusline', function()
screen:expect([[
│ │ │^ |
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
- {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│{2:< Name] 0,0-1 }│{1:~}│{1:~ }|
{1:~ }│ │{1:~}│{1:~ }|
{1:~ }│{1:~ }│{1:~}│{1:~ }|
- {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│{3:<No Name] 0,0-1 All}|
{1:~ }│{1:~ }│{1:~}│ |
- {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ {2:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
│{1:~ }|
{1:~ }│{1:~ }|*3
- {4:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ {2:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
|
]])
@@ -348,7 +341,7 @@ describe('global statusline', function()
────────────────────┴────────────────┴─┤{1:~ }|
│{1:~ }|
{1:~ }│{1:~ }|*3
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
@@ -356,12 +349,12 @@ describe('global statusline', function()
screen:expect([[
│ │ │^ |
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
- {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│{2:< Name] 0,0-1 }│{1:~}│{1:~ }|
{1:~ }│ │{1:~}│{1:~ }|
{1:~ }│{1:~ }│{1:~}│{1:~ }|
- {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│{3:<No Name] 0,0-1 All}|
{1:~ }│{1:~ }│{1:~}│ |
- {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ {2:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
│{1:~ }|
{1:~ }│{1:~ }|*4
0,0-1 All |
@@ -379,7 +372,7 @@ describe('global statusline', function()
────────────────────┴────────────────┴─┤{1:~ }|
│{1:~ }|
{1:~ }│{1:~ }|*3
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
end)
@@ -429,7 +422,7 @@ describe('global statusline', function()
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
^0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
- {2:test/functional/fixtures/bigfile.txt 7,1 Top}|
+ {3:test/functional/fixtures/bigfile.txt 7,1 Top}|
|
]])
feed('j')
@@ -444,12 +437,12 @@ describe('global statusline', function()
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
- {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ {3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
]])
api.nvim_set_option_value('showtabline', 2, {})
screen:expect([[
- {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
{1:~ }|*5
────────────────────────────────────────────────────────────|
@@ -459,12 +452,12 @@ describe('global statusline', function()
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
- {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ {3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
]])
api.nvim_set_option_value('cmdheight', 0, {})
screen:expect([[
- {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
{1:~ }|*5
────────────────────────────────────────────────────────────|
@@ -475,11 +468,11 @@ describe('global statusline', function()
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
- {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ {3:test/functional/fixtures/bigfile.txt 8,1 0%}|
]])
api.nvim_set_option_value('cmdheight', 1, {})
screen:expect([[
- {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
{1:~ }|*5
────────────────────────────────────────────────────────────|
@@ -489,7 +482,7 @@ describe('global statusline', function()
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
- {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ {3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
]])
end)
@@ -508,7 +501,7 @@ describe('global statusline', function()
────────────────────────────────────────────────────────────|
^ |
{1:~ }|*6
- {2:[No Name] 0,0-1 All}|
+ {3:[No Name] 0,0-1 All}|
|
]])
end)
@@ -525,11 +518,6 @@ end)
it('statusline is redrawn with :resize from <Cmd> mapping #19629', function()
clear()
local screen = Screen.new(40, 8)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- StatusLine
- })
- screen:attach()
exec([[
set laststatus=2
nnoremap <Up> <cmd>resize -1<CR>
@@ -538,15 +526,15 @@ it('statusline is redrawn with :resize from <Cmd> mapping #19629', function()
feed('<Up>')
screen:expect([[
^ |
- {0:~ }|*4
- {1:[No Name] }|
+ {1:~ }|*4
+ {3:[No Name] }|
|*2
]])
feed('<Down>')
screen:expect([[
^ |
- {0:~ }|*5
- {1:[No Name] }|
+ {1:~ }|*5
+ {3:[No Name] }|
|
]])
end)
@@ -554,19 +542,13 @@ end)
it('showcmdloc=statusline does not show if statusline is too narrow', function()
clear()
local screen = Screen.new(40, 8)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- StatusLine
- [2] = { reverse = true }, -- StatusLineNC
- })
- screen:attach()
command('set showcmd')
command('set showcmdloc=statusline')
command('1vsplit')
screen:expect([[
^ │ |
- {0:~}│{0:~ }|*5
- {1:< }{2:[No Name] }|
+ {1:~}│{1:~ }|*5
+ {3:< }{2:[No Name] }|
|
]])
feed('1234')
@@ -575,8 +557,7 @@ end)
it('K_EVENT does not trigger a statusline redraw unnecessarily', function()
clear()
- local screen = Screen.new(40, 8)
- screen:attach()
+ local _ = Screen.new(40, 8)
-- does not redraw on vim.schedule (#17937)
command([[
set laststatus=2
@@ -608,7 +589,6 @@ end)
it('statusline is redrawn on various state changes', function()
clear()
local screen = Screen.new(40, 4)
- screen:attach()
-- recording state change #22683
command('set ls=2 stl=%{repeat(reg_recording(),5)}')
@@ -674,7 +654,6 @@ end)
it('ruler is redrawn in cmdline with redrawstatus #22804', function()
clear()
local screen = Screen.new(40, 2)
- screen:attach()
command([[
let g:n = 'initial value'
set ls=1 ru ruf=%{g:n}
@@ -691,12 +670,6 @@ end)
it('shows correct ruler in cmdline with no statusline', function()
clear()
local screen = Screen.new(30, 8)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [2] = { bold = true, reverse = true }, -- StatusLine
- [3] = { reverse = true }, -- StatusLineNC
- }
- screen:attach()
-- Use long ruler to check 'ruler' with 'rulerformat' set has correct width.
command [[
set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10
@@ -713,7 +686,7 @@ it('shows correct ruler in cmdline with no statusline', function()
screen:expect [[
^ |
{1:~ }|*2
- {2:[No Name] 1longlonglong }|
+ {3:[No Name] 1longlonglong }|
│ |
{1:~ }│{1:~ }|*2
3longlonglong |
@@ -724,7 +697,7 @@ it('shows correct ruler in cmdline with no statusline', function()
screen:expect [[
|
{1:~ }|*2
- {3:[No Name] 1longlonglong }|
+ {2:[No Name] 1longlonglong }|
^ │ |
{1:~ }│{1:~ }|*2
2longlonglong |
@@ -734,7 +707,7 @@ it('shows correct ruler in cmdline with no statusline', function()
screen:expect [[
|
{1:~ }|*2
- {3:[No Name] 1longlonglong }|
+ {2:[No Name] 1longlonglong }|
│^ |
{1:~ }│{1:~ }|*2
3longlonglong |
@@ -744,10 +717,6 @@ end)
it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function()
clear()
local screen = Screen.new(53, 4)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- })
command('hi clear StatusLine')
command('hi clear StatusLineNC')
command('vsplit')
@@ -764,19 +733,13 @@ end)
it('showcmdloc=statusline works with vertical splits', function()
clear()
local screen = Screen.new(53, 4)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [2] = { bold = true, reverse = true }, -- StatusLine
- [3] = { reverse = true }, -- StatusLineNC
- }
- screen:attach()
command('rightbelow vsplit')
command('set showcmd showcmdloc=statusline')
feed('1234')
screen:expect([[
│^ |
{1:~ }│{1:~ }|
- {3:[No Name] }{2:[No Name] 1234 }|
+ {2:[No Name] }{3:[No Name] 1234 }|
|
]])
feed('<Esc>')
@@ -785,7 +748,7 @@ it('showcmdloc=statusline works with vertical splits', function()
screen:expect([[
│^ |
{1:~ }│{1:~ }|
- {2:[No Name] 1234 }|
+ {3:[No Name] 1234 }|
|
]])
end)
@@ -793,25 +756,19 @@ end)
it('keymap is shown with vertical splits #27269', function()
clear()
local screen = Screen.new(53, 4)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [2] = { bold = true, reverse = true }, -- StatusLine
- [3] = { reverse = true }, -- StatusLineNC
- }
- screen:attach()
command('setlocal keymap=dvorak')
command('rightbelow vsplit')
screen:expect([[
│^ |
{1:~ }│{1:~ }|
- {3:[No Name] <en-dv> }{2:[No Name] <en-dv> }|
+ {2:[No Name] <en-dv> }{3:[No Name] <en-dv> }|
|
]])
command('set laststatus=3')
screen:expect([[
│^ |
{1:~ }│{1:~ }|
- {2:[No Name] <en-dv> }|
+ {3:[No Name] <en-dv> }|
|
]])
end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index be35e9bf4f..57d76e54df 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -14,7 +14,6 @@ describe('Screen', function()
before_each(function()
clear()
screen = Screen.new(nil, 10)
- screen:attach()
screen:set_default_attr_ids({
[0] = { bold = true, foreground = Screen.colors.Blue },
[1] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index 5cda70df21..6d212823eb 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -13,8 +13,7 @@ describe('ui/ext_tabline', function()
before_each(function()
clear()
- screen = Screen.new(25, 5)
- screen:attach({ rgb = true, ext_tabline = true })
+ screen = Screen.new(25, 5, { rgb = true, ext_tabline = true })
function screen:_handle_tabline_update(curtab, tabs, curbuf, buffers)
event_curtab = curtab
event_tabs = tabs
@@ -100,7 +99,6 @@ describe('tabline', function()
before_each(function()
clear()
screen = Screen.new(42, 5)
- screen:attach()
end)
it('redraws when tabline option is set', function()
@@ -125,6 +123,26 @@ describe('tabline', function()
}
end)
+ it('combines highlight attributes', function()
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.Blue1, bold = true }, -- StatusLine
+ [2] = { bold = true, italic = true }, -- StatusLine
+ [3] = { bold = true, italic = true, foreground = Screen.colors.Red }, -- NonText combined with StatusLine
+ })
+ command('hi TabLineFill gui=bold,italic')
+ command('hi Identifier guifg=red')
+ command('set tabline=Test%#Identifier#here')
+ command('set showtabline=2')
+ screen:expect {
+ grid = [[
+ {2:Test}{3:here }|
+ ^ |
+ {1:~ }|*2
+ |
+ ]],
+ }
+ end)
+
it('click definitions do not leak memory #21765', function()
command('set tabline=%@MyClickFunc@MyClickText%T')
command('set showtabline=2')
@@ -196,4 +214,43 @@ describe('tabline', function()
api.nvim_input_mouse('middle', 'press', '', 0, 0, 1)
eq({ 1, 1 }, api.nvim_eval('[tabpagenr(), tabpagenr("$")]'))
end)
+
+ it('does not show floats with focusable=false', function()
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Plum1 },
+ [2] = { underline = true, background = Screen.colors.LightGrey },
+ [3] = { bold = true },
+ [4] = { reverse = true },
+ [5] = { bold = true, foreground = Screen.colors.Blue1 },
+ [6] = { foreground = Screen.colors.Fuchsia, bold = true },
+ [7] = { foreground = Screen.colors.SeaGreen, bold = true },
+ })
+ command('tabnew')
+ api.nvim_open_win(0, false, {
+ focusable = false,
+ relative = 'editor',
+ height = 1,
+ width = 1,
+ row = 0,
+ col = 0,
+ })
+ screen:expect {
+ grid = [[
+ {1: }{2:[No Name] }{3: [No Name] }{4: }{2:X}|
+ ^ |
+ {5:~ }|*2
+ |
+ ]],
+ }
+ command('tabs')
+ screen:expect {
+ grid = [[
+ {6:Tab page 1} |
+ # [No Name] |
+ {6:Tab page 2} |
+ > [No Name] |
+ {7:Press ENTER or type command to continue}^ |
+ ]],
+ }
+ end)
end)
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
index 3189232957..66eb15478b 100644
--- a/test/functional/ui/title_spec.lua
+++ b/test/functional/ui/title_spec.lua
@@ -18,7 +18,6 @@ describe('title', function()
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
end)
it('has correct default title with unnamed file', function()
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 4d01b7a779..94710bfb74 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -19,7 +19,6 @@ describe("'wildmenu'", function()
screen:add_extra_attr_ids {
[100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
}
- screen:attach()
end)
-- oldtest: Test_wildmenu_screendump()
@@ -492,7 +491,6 @@ describe('command line completion', function()
screen:add_extra_attr_ids {
[100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
}
- screen:attach()
end)
after_each(function()
os.remove('Xtest-functional-viml-compl-dir')
@@ -592,8 +590,7 @@ describe('ui/ext_wildmenu', function()
before_each(function()
clear()
- screen = Screen.new(25, 5)
- screen:attach({ rgb = true, ext_wildmenu = true })
+ screen = Screen.new(25, 5, { rgb = true, ext_wildmenu = true })
end)
it('works with :sign <tab>', function()
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index fb907026a5..d1fd273dc1 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -18,7 +18,6 @@ describe('winbar', function()
before_each(function()
clear()
screen = Screen.new(60, 13)
- screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true },
[2] = { reverse = true },
@@ -40,6 +39,16 @@ describe('winbar', function()
bold = true,
foreground = Screen.colors.Magenta,
},
+ [12] = {
+ underline = true,
+ background = Screen.colors.Red,
+ },
+ [13] = {
+ underline = true,
+ bold = true,
+ foreground = Screen.colors.Blue,
+ background = Screen.colors.Red,
+ },
})
api.nvim_set_option_value('winbar', 'Set Up The Bars', {})
end)
@@ -182,6 +191,18 @@ describe('winbar', function()
]])
end)
+ it('works with combined highlight attributes', function()
+ command('hi Winbar guibg=red gui=underline')
+ command('hi Identifier guifg=blue gui=bold')
+ command('set winbar=Lookatmy%#Identifier#highlights')
+ screen:expect([[
+ {12:Lookatmy}{13:highlights }|
+ ^ |
+ {3:~ }|*10
+ |
+ ]])
+ end)
+
it('can be ruler', function()
insert [[
just some
@@ -526,7 +547,6 @@ describe('local winbar with tabs', function()
before_each(function()
clear()
screen = Screen.new(60, 10)
- screen:attach()
api.nvim_set_option_value('winbar', 'foo', { scope = 'local', win = 0 })
end)
@@ -604,7 +624,6 @@ it('winbar works properly when redrawing is postponed #23534', function()
},
})
local screen = Screen.new(60, 6)
- screen:attach()
screen:expect([[
{5:(winbar) }|
^ |
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index 30d6c969ca..5db8c24120 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -129,8 +129,6 @@ describe('eval-API', function()
end)
it('use buffer numbers and windows ids as handles', function()
- local screen = Screen.new(40, 8)
- screen:attach()
local bnr = eval("bufnr('')")
local bhnd = eval('nvim_get_current_buf()')
local wid = eval('win_getid()')
@@ -192,14 +190,6 @@ describe('eval-API', function()
it('are highlighted by vim.vim syntax file', function()
local screen = Screen.new(40, 8)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Brown },
- [2] = { foreground = Screen.colors.DarkCyan },
- [3] = { foreground = Screen.colors.SlateBlue },
- [4] = { foreground = Screen.colors.Fuchsia },
- [5] = { bold = true, foreground = Screen.colors.Blue },
- })
command('set ft=vim')
command('set rtp^=build/runtime/')
@@ -210,10 +200,10 @@ describe('eval-API', function()
call not_a_function(42)]])
screen:expect([[
- {1:call} {2:bufnr}{3:(}{4:'%'}{3:)} |
- {1:call} {2:nvim_input}{3:(}{4:'typing...'}{3:)} |
- {1:call} not_a_function{3:(}{4:42}{3:^)} |
- {5:~ }|*4
+ {15:call} {25:bufnr}{16:(}{26:'%'}{16:)} |
+ {15:call} {25:nvim_input}{16:(}{26:'typing...'}{16:)} |
+ {15:call} not_a_function{16:(}{26:42}{16:^)} |
+ {1:~ }|*4
|
]])
end)
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index 0c812d968e..2a4835f7e1 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -25,8 +25,6 @@ local command = n.command
local write_file = t.write_file
local api = n.api
local sleep = vim.uv.sleep
-local matches = t.matches
-local pcall_err = t.pcall_err
local assert_alive = n.assert_alive
local poke_eventloop = n.poke_eventloop
local feed = n.feed
@@ -189,12 +187,6 @@ describe('uncaught exception', function()
it('multiline exception remains multiline #25350', function()
local screen = Screen.new(80, 11)
- screen:set_default_attr_ids({
- [1] = { bold = true, reverse = true }, -- MsgSeparator
- [2] = { foreground = Screen.colors.White, background = Screen.colors.Red }, -- ErrorMsg
- [3] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
- })
- screen:attach()
exec_lua([[
function _G.Oops()
error("oops")
@@ -203,17 +195,17 @@ describe('uncaught exception', function()
feed(':try\rlua _G.Oops()\rendtry\r')
screen:expect {
grid = [[
- {1: }|
+ {3: }|
:try |
: lua _G.Oops() |
: endtry |
- {2:Error detected while processing :} |
- {2:E5108: Error executing lua [string "<nvim>"]:2: oops} |
- {2:stack traceback:} |
- {2: [C]: in function 'error'} |
- {2: [string "<nvim>"]:2: in function 'Oops'} |
- {2: [string ":lua"]:1: in main chunk} |
- {3:Press ENTER or type command to continue}^ |
+ {9:Error detected while processing :} |
+ {9:E5108: Error executing lua [string "<nvim>"]:2: oops} |
+ {9:stack traceback:} |
+ {9: [C]: in function 'error'} |
+ {9: [string "<nvim>"]:2: in function 'Oops'} |
+ {9: [string ":lua"]:1: in main chunk} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -233,74 +225,6 @@ describe('listing functions using :function', function()
exec_capture(('function <lambda>%s'):format(num))
)
end)
-
- it('does not crash if another function is deleted while listing', function()
- local screen = Screen.new(80, 24)
- screen:attach()
- matches(
- 'Vim%(function%):E454: Function list was modified$',
- pcall_err(
- exec_lua,
- [=[
- vim.cmd([[
- func Func1()
- endfunc
- func Func2()
- endfunc
- func Func3()
- endfunc
- ]])
-
- local ns = vim.api.nvim_create_namespace('test')
-
- vim.ui_attach(ns, { ext_messages = true }, function(event, _, content)
- if event == 'msg_show' and content[1][2] == 'function Func1()' then
- vim.cmd('delfunc Func3')
- end
- end)
-
- vim.cmd('function')
-
- vim.ui_detach(ns)
- ]=]
- )
- )
- assert_alive()
- end)
-
- it('does not crash if the same function is deleted while listing', function()
- local screen = Screen.new(80, 24)
- screen:attach()
- matches(
- 'Vim%(function%):E454: Function list was modified$',
- pcall_err(
- exec_lua,
- [=[
- vim.cmd([[
- func Func1()
- endfunc
- func Func2()
- endfunc
- func Func3()
- endfunc
- ]])
-
- local ns = vim.api.nvim_create_namespace('test')
-
- vim.ui_attach(ns, { ext_messages = true }, function(event, _, content)
- if event == 'msg_show' and content[1][2] == 'function Func1()' then
- vim.cmd('delfunc Func2')
- end
- end)
-
- vim.cmd('function')
-
- vim.ui_detach(ns)
- ]=]
- )
- )
- assert_alive()
- end)
end)
it('no double-free in garbage collection #16287', function()
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index 8caaea39a7..2404538e77 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -114,7 +114,6 @@ describe('execute()', function()
it('does not corrupt the command display #5422', function()
local screen = Screen.new(70, 7)
- screen:attach()
feed(':echo execute("hi ErrorMsg")<CR>')
screen:expect(
[[
@@ -136,7 +135,6 @@ describe('execute()', function()
it('places cursor correctly #6035', function()
local screen = Screen.new(40, 6)
- screen:attach()
source([=[
" test 1: non-silenced output goes as usual
function! Test1()
@@ -263,7 +261,6 @@ describe('execute()', function()
describe('{silent} argument', function()
it('captures & displays output for ""', function()
local screen = Screen.new(40, 5)
- screen:attach()
command('let g:mes = execute("echon 42", "")')
screen:expect([[
^ |
@@ -287,7 +284,6 @@ describe('execute()', function()
it('captures but does not display output for "silent"', function()
local screen = Screen.new(40, 5)
- screen:attach()
command('let g:mes = execute("echon 42")')
screen:expect([[
^ |
diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua
index 1d2187be6b..ff90edfe30 100644
--- a/test/functional/vimscript/has_spec.lua
+++ b/test/functional/vimscript/has_spec.lua
@@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen')
local clear = n.clear
local connect = n.connect
+local get_session = n.get_session
local eq = t.eq
local fn = n.fn
local is_os = t.is_os
@@ -74,12 +75,12 @@ describe('has()', function()
it('"gui_running"', function()
eq(0, fn.has('gui_running'))
- local tui = Screen.new(50, 15)
+ local tui_session = get_session()
local gui_session = connect(fn.serverstart())
- local gui = Screen.new(50, 15)
eq(0, fn.has('gui_running'))
- tui:attach({ ext_linegrid = true, rgb = true, stdin_tty = true, stdout_tty = true })
- gui:attach({ ext_multigrid = true, rgb = true }, gui_session)
+ local tui = Screen.new(50, 5, { rgb = true, stdin_tty = true, stdout_tty = true }, tui_session)
+ eq(0, fn.has('gui_running'))
+ local gui = Screen.new(50, 15, { ext_multigrid = true, rgb = true }, gui_session)
eq(1, fn.has('gui_running'))
tui:detach()
eq(1, fn.has('gui_running'))
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 0b774404eb..1995b033b9 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -17,7 +17,6 @@ local screen
before_each(function()
clear()
screen = Screen.new(25, 5)
- screen:attach()
source([[
hi Test ctermfg=Red guifg=Red term=bold
function CustomCompl(...)
diff --git a/test/functional/vimscript/match_functions_spec.lua b/test/functional/vimscript/match_functions_spec.lua
index 87c57f1c15..46c876da99 100644
--- a/test/functional/vimscript/match_functions_spec.lua
+++ b/test/functional/vimscript/match_functions_spec.lua
@@ -174,7 +174,6 @@ describe('matchaddpos()', function()
end)
it('works with zero length', function()
local screen = Screen.new(40, 5)
- screen:attach()
fn.setline(1, 'abcdef')
command('hi PreProc guifg=Red')
eq(4, fn.matchaddpos('PreProc', { { 1, 2, 0 } }, 3, 4))
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 792e4c46c3..b5c4972d7b 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -132,7 +132,6 @@ describe('system()', function()
before_each(function()
screen = Screen.new()
- screen:attach()
end)
if is_os('win') then
@@ -430,11 +429,6 @@ describe('systemlist()', function()
before_each(function()
screen = Screen.new()
- screen:attach()
- end)
-
- after_each(function()
- screen:detach()
end)
it('`echo` and waits for its return', function()
@@ -567,7 +561,6 @@ describe('shell :!', function()
it(':{range}! with powershell filter/redirect #16271 #19250', function()
local screen = Screen.new(500, 8)
- screen:attach()
local found = n.set_shell_powershell(true)
insert([[
3
@@ -598,7 +591,6 @@ describe('shell :!', function()
it(':{range}! without redirecting to buffer', function()
local screen = Screen.new(500, 10)
- screen:attach()
insert([[
3
1
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index f075e382bc..d1b8bfe5d9 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -108,10 +108,6 @@ describe('timers', function()
it('can invoke redraw in blocking getchar() call', function()
local screen = Screen.new(40, 6)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue },
- })
api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' })
source([[
@@ -228,8 +224,6 @@ describe('timers', function()
it("doesn't mess up the cmdline", function()
local screen = Screen.new(40, 6)
- screen:attach()
- screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 } })
source([[
let g:val = 0
func! MyHandler(timer)
@@ -247,7 +241,7 @@ describe('timers', function()
feed(':good')
screen:expect([[
|
- {0:~ }|*4
+ {1:~ }|*4
:good^ |
]])
command('let g:val = 1')
@@ -267,7 +261,6 @@ describe('timers', function()
it('can be triggered after an empty string <expr> mapping #17257', function()
local screen = Screen.new(40, 6)
- screen:attach()
command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
feed('i<F2>')
screen:expect({ any = 'E605: Exception not caught: x' })
diff --git a/test/old/testdir/Makefile b/test/old/testdir/Makefile
index 20272a24c7..d73571f463 100644
--- a/test/old/testdir/Makefile
+++ b/test/old/testdir/Makefile
@@ -55,6 +55,8 @@ else
endif
endif
+default: nongui
+
nongui: nolog $(FIXFF) newtests report
.gdbinit:
@@ -112,6 +114,7 @@ CLEAN_FILES := *.out \
*.rej \
*.orig \
*.tlog \
+ opt_test.vim \
test_result.log \
$(CLEANUP_FILES) \
$(RM_ON_RUN) \
@@ -151,6 +154,18 @@ newtests: newtestssilent
newtestssilent: $(NEW_TESTS_RES)
+GEN_OPT_DEPS = gen_opt_test.vim ../../../src/nvim/options.lua ../../../runtime/doc/options.txt
+
+opt_test.vim: $(GEN_OPT_DEPS)
+ $(NVIM_PRG) -e -s -u NONE $(NO_INITS) -S $(GEN_OPT_DEPS)
+ @if test -f test.log; then \
+ cat test.log; \
+ exit 1; \
+ fi
+
+# Explicit dependencies.
+test_options_all.res: opt_test.vim
+
%.res: %.vim .gdbinit
@echo "[OLDTEST] Running" $*
@rm -rf $*.failed test.ok $(RM_ON_RUN)
diff --git a/test/old/testdir/gen_opt_test.vim b/test/old/testdir/gen_opt_test.vim
new file mode 100644
index 0000000000..be5a7e6ee4
--- /dev/null
+++ b/test/old/testdir/gen_opt_test.vim
@@ -0,0 +1,507 @@
+" Script to generate test/old/testdir/opt_test.vim from src/nvim/options.lua
+" and runtime/doc/options.txt
+
+set cpo&vim
+
+" Only do this when build with the +eval feature.
+if 1
+
+try
+
+set nomore
+
+const K_KENTER = -16715
+
+" Get global-local options.
+" "key" is full-name of the option.
+" "value" is the local value to switch back to the global value.
+b options.txt
+call cursor(1, 1)
+let global_locals = {}
+while search("^'[^']*'.*\\n.*|global-local", 'W')
+ let fullname = getline('.')->matchstr("^'\\zs[^']*")
+ let global_locals[fullname] = ''
+endwhile
+call extend(global_locals, #{
+ \ scrolloff: -1,
+ \ sidescrolloff: -1,
+ \ undolevels: -123456,
+ \})
+
+" Get local-noglobal options.
+" "key" is full-name of the option.
+" "value" is no used.
+b options.txt
+call cursor(1, 1)
+let local_noglobals = {}
+while search("^'[^']*'.*\\n.*|local-noglobal", 'W')
+ let fullname = getline('.')->matchstr("^'\\zs[^']*")
+ let local_noglobals[fullname] = v:true
+endwhile
+
+" Options to skip `setglobal` tests.
+" "key" is full-name of the option.
+" "value" is the reason.
+let skip_setglobal_reasons = #{
+ \ iminsert: 'The global value is always overwritten by the local value',
+ \ imsearch: 'The global value is always overwritten by the local value',
+ \}
+
+" Script header.
+" The test values contains multibyte characters.
+let script = [
+ \ '" DO NOT EDIT: Generated with gen_opt_test.vim',
+ \ '" Used by test_options_all.vim.',
+ \ '',
+ \ 'scriptencoding utf-8',
+ \ ]
+
+let options = luaeval('loadfile("../../../src/nvim/options.lua")().options')
+
+" font name that works everywhere (hopefully)
+let fontname = has('win32') ? 'fixedsys' : 'fixed'
+
+" Two lists with values: values that work and values that fail.
+" When not listed, "othernum" or "otherstring" is used.
+" When both lists are empty, skip tests for the option.
+" For boolean options, if non-empty a fixed test will be run, otherwise skipped.
+let test_values = {
+ "\ Nvim-only options
+ \ 'channel': [[], []],
+ \ 'inccommand': [['', 'nosplit', 'split'], ['xxx']],
+ \ 'mousescroll': [['ver:1', 'hor:2', 'ver:1,hor:2', 'hor:1,ver:2'],
+ \ ['xxx', 'ver:1,xxx', 'hor:2,xxx']],
+ \ 'redrawdebug': [[''], ['xxx']],
+ \ 'shada': [['', '''50', '"30'], ['xxx']],
+ \ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'],
+ \ ['xxx', 'C0,C1,xxx']],
+ \ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'],
+ \ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']],
+ \
+ "\ Options for which Nvim has different allowed values
+ \ 'backspace': [[2, '', 'indent', 'eol', 'start', 'nostop',
+ \ 'eol,start', 'indent,eol,nostop'],
+ \ [-1, 4, 'xxx']],
+ \ 'buftype': [['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help',
+ \ 'prompt'],
+ \ ['xxx', 'help,nofile']],
+ \ 'clipboard': [['', 'unnamed'], ['xxx', '\ze*', 'exclude:\\%(']],
+ \ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
+ \ 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
+ \ ['xxx', 'menu,,,longest,']],
+ \ 'encoding': [['utf8'], []],
+ \ 'foldcolumn': [[0, 1, 4, 'auto', 'auto:1', 'auto:9'], [-1, 13, 999]],
+ \ 'foldlevel': [[0, 100], [-1, '']],
+ \ 'highlight': [[&highlight], []],
+ \ 'iminsert': [[0, 1], [-1, 2, 3, 999]],
+ \ 'imsearch': [[-1, 0, 1], [-2, 2, 3, 999]],
+ \ 'signcolumn': [['auto', 'no', 'yes', 'number', 'yes:1', 'auto:1-9'],
+ \ ['', 'xxx', 'no,yes', 'auto:0-9', 'auto:9-1', 'auto:1-@']],
+ \ 'writedelay': [[0, 100], [-1, '']],
+ \
+ "\ boolean options
+ \ 'termguicolors': [
+ \ has('vtp') && !has('vcon') && !has('gui_running') ? [] : [1],
+ \ []],
+ \
+ "\ number options
+ \ 'cmdheight': [[0, 1, 2, 10], [-1]],
+ \ 'cmdwinheight': [[1, 2, 10], [-1, 0]],
+ \ 'columns': [[12, 80, 10000], [-1, 0, 10]],
+ \ 'conceallevel': [[0, 1, 2, 3], [-1, 4, 99]],
+ "\ 'foldcolumn': [[0, 1, 4, 12], [-1, 13, 999]],
+ \ 'helpheight': [[0, 10, 100], [-1]],
+ \ 'history': [[0, 1, 100, 10000], [-1, 10001]],
+ "\ 'iminsert': [[0, 1, 2], [-1, 3, 999]],
+ "\ 'imsearch': [[-1, 0, 1, 2], [-2, 3, 999]],
+ "\ 'imstyle': [[0, 1], [-1, 2, 999]],
+ \ 'lines': [[2, 24, 1000], [-1, 0, 1]],
+ \ 'linespace': [[-1, 0, 2, 4, 999], ['']],
+ \ 'msghistory': [[0, 1, 100, 10000], [-1, 10001]],
+ \ 'numberwidth': [[1, 4, 8, 10, 11, 20], [-1, 0, 21]],
+ \ 'regexpengine': [[0, 1, 2], [-1, 3, 999]],
+ \ 'report': [[0, 1, 2, 9999], [-1]],
+ \ 'scroll': [[0, 1, 2, 20], [-1, 999]],
+ \ 'scrolljump': [[-100, -1, 0, 1, 2, 20], [-101, 999]],
+ \ 'scrolloff': [[0, 1, 8, 999], [-1]],
+ \ 'shiftwidth': [[0, 1, 8, 999], [-1]],
+ \ 'sidescroll': [[0, 1, 8, 999], [-1]],
+ \ 'sidescrolloff': [[0, 1, 8, 999], [-1]],
+ \ 'tabstop': [[1, 4, 8, 12, 9999], [-1, 0, 10000]],
+ \ 'textwidth': [[0, 1, 8, 99], [-1]],
+ \ 'timeoutlen': [[0, 8, 99999], [-1]],
+ \ 'titlelen': [[0, 1, 8, 9999], [-1]],
+ \ 'updatecount': [[0, 1, 8, 9999], [-1]],
+ \ 'updatetime': [[0, 1, 8, 9999], [-1]],
+ \ 'verbose': [[-1, 0, 1, 8, 9999], ['']],
+ \ 'wildchar': [[-1, 0, 100, 'x', '^Y', '^@', '<Esc>', '<t_xx>', '<', '^'],
+ \ ['', 'xxx', '<xxx>', '<t_xxx>', '<Esc', '<t_xx', '<C-C>',
+ \ '<NL>', '<CR>', K_KENTER]],
+ \ 'wildcharm': [[-1, 0, 100, 'x', '^Y', '^@', '<Esc>', '<', '^'],
+ \ ['', 'xxx', '<xxx>', '<t_xxx>', '<Esc', '<t_xx', '<C-C>',
+ \ '<NL>', '<CR>', K_KENTER]],
+ \ 'winheight': [[1, 10, 999], [-1, 0]],
+ \ 'winminheight': [[0, 1], [-1]],
+ \ 'winminwidth': [[0, 1, 10], [-1]],
+ \ 'winwidth': [[1, 10, 999], [-1, 0]],
+ \
+ "\ string options
+ \ 'ambiwidth': [['', 'single', 'double'], ['xxx']],
+ \ 'background': [['', 'light', 'dark'], ['xxx']],
+ "\ 'backspace': [[0, 1, 2, 3, '', 'indent', 'eol', 'start', 'nostop',
+ "\ " 'eol,start', 'indent,eol,nostop'],
+ "\ " [-1, 4, 'xxx']],
+ \ 'backupcopy': [['yes', 'no', 'auto'], ['', 'xxx', 'yes,no']],
+ \ 'backupext': [['xxx'], [&patchmode, '*']],
+ \ 'belloff': [['', 'all', 'backspace', 'cursor', 'complete', 'copy',
+ \ 'ctrlg', 'error', 'esc', 'ex', 'hangul', 'insertmode', 'lang',
+ \ 'mess', 'showmatch', 'operator', 'register', 'shell', 'spell',
+ \ 'term', 'wildmode', 'copy,error,shell'],
+ \ ['xxx']],
+ \ 'breakindentopt': [['', 'min:3', 'shift:4', 'shift:-2', 'sbr', 'list:5',
+ \ 'list:-1', 'column:10', 'column:-5', 'min:1,sbr,shift:2'],
+ \ ['xxx', 'min', 'min:x', 'min:-1', 'shift:x', 'sbr:1', 'list:x',
+ \ 'column:x']],
+ \ 'browsedir': [['', 'last', 'buffer', 'current', './Xdir\ with\ space'],
+ \ ['xxx']],
+ \ 'bufhidden': [['', 'hide', 'unload', 'delete', 'wipe'],
+ \ ['xxx', 'hide,wipe']],
+ "\ 'buftype': [['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help',
+ "\ " 'terminal', 'prompt', 'popup'],
+ "\ " ['xxx', 'help,nofile']],
+ \ 'casemap': [['', 'internal', 'keepascii', 'internal,keepascii'],
+ \ ['xxx']],
+ \ 'cedit': [['', '^Y', '^@', '<Esc>', '<t_xx>'],
+ \ ['xxx', 'f', '<xxx>', '<t_xxx>', '<Esc', '<t_xx']],
+ "\ 'clipboard': [['', 'unnamed', 'unnamedplus', 'autoselect',
+ "\ " 'autoselectplus', 'autoselectml', 'html', 'exclude:vimdisplay',
+ "\ " 'autoselect,unnamed', 'unnamed,exclude:.*'],
+ "\ " ['xxx', 'exclude:\\ze*', 'exclude:\\%(']],
+ \ 'colorcolumn': [['', '8', '+2', '1,+1,+3'], ['xxx', '-a', '1,', '1;']],
+ \ 'comments': [['', 'b:#', 'b:#,:%'], ['xxx', '-']],
+ \ 'commentstring': [['', '/*\ %s\ */'], ['xxx']],
+ \ 'complete': [['', '.', 'w', 'b', 'u', 'U', 'i', 'd', ']', 't',
+ \ 'k', 'kspell', 'k/tmp/dir\\\ with\\\ space/*',
+ \ 's', 's/tmp/dir\\\ with\\\ space/*',
+ \ 'w,b,k/tmp/dir\\\ with\\\ space/*,s'],
+ \ ['xxx']],
+ \ 'concealcursor': [['', 'n', 'v', 'i', 'c', 'nvic'], ['xxx']],
+ "\ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
+ "\ " 'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
+ "\ " ['xxx', 'menu,,,longest,']],
+ \ 'completeitemalign': [['abbr,kind,menu', 'menu,abbr,kind'],
+ \ ['', 'xxx', 'abbr', 'abbr,menu', 'abbr,menu,kind,abbr',
+ \ 'abbr1234,kind,menu']],
+ "\ 'completepopup': [['', 'height:13', 'width:20', 'highlight:That',
+ "\ " 'align:item', 'align:menu', 'border:on', 'border:off',
+ "\ " 'width:10,height:234,highlight:Mine'],
+ "\ " ['xxx', 'xxx:99', 'height:yes', 'width:no', 'align:xxx',
+ "\ " 'border:maybe', 'border:1', 'border:']],
+ \ 'completeslash': [['', 'slash', 'backslash'], ['xxx']],
+ "\ 'cryptmethod': [['', 'zip'], ['xxx']],
+ "\ 'cscopequickfix': [['', 's-', 'g-', 'd-', 'c-', 't-', 'e-', 'f-', 'i-',
+ "\ " 'a-', 's-,c+,e0'],
+ "\ " ['xxx', 's,g,d']],
+ \ 'cursorlineopt': [['both', 'line', 'number', 'screenline',
+ \ 'line,number'],
+ \ ['', 'xxx', 'line,screenline']],
+ \ 'debug': [['', 'msg', 'throw', 'beep'], ['xxx']],
+ \ 'diffopt': [['', 'filler', 'context:0', 'context:999', 'iblank',
+ \ 'icase', 'iwhite', 'iwhiteall', 'horizontal', 'vertical',
+ \ 'closeoff', 'hiddenoff', 'foldcolumn:0', 'foldcolumn:12',
+ \ 'followwrap', 'internal', 'indent-heuristic', 'algorithm:myers',
+ \ 'algorithm:minimal', 'algorithm:patience',
+ \ 'algorithm:histogram', 'icase,iwhite'],
+ \ ['xxx', 'foldcolumn:xxx', 'algorithm:xxx', 'algorithm:']],
+ \ 'display': [['', 'lastline', 'truncate', 'uhex', 'lastline,uhex'],
+ \ ['xxx']],
+ \ 'eadirection': [['', 'both', 'ver', 'hor'], ['xxx', 'ver,hor']],
+ "\ 'encoding': [['latin1'], ['xxx', '']],
+ \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'],
+ \ ['xxx']],
+ \ 'fileencoding': [['', 'latin1', 'xxx'], []],
+ \ 'fileformat': [['', 'dos', 'unix', 'mac'], ['xxx']],
+ \ 'fileformats': [['', 'dos', 'dos,unix'], ['xxx']],
+ \ 'fillchars': [['', 'stl:x', 'stlnc:x', 'vert:x', 'fold:x', 'foldopen:x',
+ \ 'foldclose:x', 'foldsep:x', 'diff:x', 'eob:x', 'lastline:x',
+ \ 'stl:\ ,vert:\|,fold:\\,diff:x'],
+ \ ['xxx', 'vert:']],
+ \ 'foldclose': [['', 'all'], ['xxx']],
+ \ 'foldmethod': [['manual', 'indent', 'expr', 'marker', 'syntax', 'diff'],
+ \ ['', 'xxx', 'expr,diff']],
+ \ 'foldopen': [['', 'all', 'block', 'hor', 'insert', 'jump', 'mark',
+ \ 'percent', 'quickfix', 'search', 'tag', 'undo', 'hor,jump'],
+ \ ['xxx']],
+ \ 'foldmarker': [['((,))'], ['', 'xxx', '{{{,']],
+ \ 'formatoptions': [['', 't', 'c', 'r', 'o', '/', 'q', 'w', 'a', 'n', '2',
+ \ 'v', 'b', 'l', 'm', 'M', 'B', '1', ']', 'j', 'p', 'vt', 'v,t'],
+ \ ['xxx']],
+ \ 'guicursor': [['', 'n:block-Cursor'], ['xxx']],
+ \ 'guifont': [['', fontname], []],
+ \ 'guifontwide': [['', fontname], []],
+ "\ 'guifontset': [['', fontname], []],
+ \ 'guioptions': [['', '!', 'a', 'P', 'A', 'c', 'd', 'e', 'f', 'i', 'm',
+ \ 'M', 'g', 't', 'T', 'r', 'R', 'l', 'L', 'b', 'h', 'v', 'p', 'F',
+ \ 'k', '!abvR'],
+ \ ['xxx', 'a,b']],
+ \ 'helplang': [['', 'de', 'de,it'], ['xxx']],
+ "\ 'highlight': [['', 'e:Error'], ['xxx']],
+ "\ 'imactivatekey': [['', 'S-space'], ['xxx']],
+ \ 'isfname': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'jumpoptions': [['', 'stack'], ['xxx']],
+ \ 'keymap': [['', 'accents'], ['/']],
+ \ 'keymodel': [['', 'startsel', 'stopsel', 'startsel,stopsel'], ['xxx']],
+ "\ 'keyprotocol': [['', 'xxx:none', 'yyy:mok2', 'zzz:kitty'],
+ "\ " ['xxx', ':none', 'xxx:', 'x:non', 'y:mok3', 'z:kittty']],
+ \ 'langmap': [['', 'xX', 'aA,bB'], ['xxx']],
+ \ 'lispoptions': [['', 'expr:0', 'expr:1'], ['xxx', 'expr:x', 'expr:']],
+ \ 'listchars': [['', 'eol:x', 'tab:xy', 'tab:xyz', 'space:x',
+ \ 'multispace:xxxy', 'lead:x', 'leadmultispace:xxxy', 'trail:x',
+ \ 'extends:x', 'precedes:x', 'conceal:x', 'nbsp:x', 'eol:\\x24',
+ \ 'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'],
+ \ ['xxx', 'eol:']],
+ \ 'matchpairs': [['', '(:)', '(:),<:>'], ['xxx']],
+ \ 'mkspellmem': [['10000,100,12'], ['', 'xxx', '10000,100']],
+ \ 'mouse': [['', 'n', 'v', 'i', 'c', 'h', 'a', 'r', 'nvi'],
+ \ ['xxx', 'n,v,i']],
+ \ 'mousemodel': [['', 'extend', 'popup', 'popup_setpos'], ['xxx']],
+ \ 'mouseshape': [['', 'n:arrow'], ['xxx']],
+ \ 'nrformats': [['', 'alpha', 'octal', 'hex', 'bin', 'unsigned', 'blank',
+ \ 'alpha,hex,bin'],
+ \ ['xxx']],
+ \ 'patchmode': [['', 'xxx', '.x'], [&backupext, '*']],
+ "\ 'previewpopup': [['', 'height:13', 'width:20', 'highlight:That',
+ "\ " 'align:item', 'align:menu', 'border:on', 'border:off',
+ "\ " 'width:10,height:234,highlight:Mine'],
+ "\ " ['xxx', 'xxx:99', 'height:yes', 'width:no', 'align:xxx',
+ "\ " 'border:maybe', 'border:1', 'border:']],
+ "\ 'printmbfont': [['', 'r:some', 'b:some', 'i:some', 'o:some', 'c:yes',
+ "\ " 'c:no', 'a:yes', 'a:no', 'b:Bold,c:yes'],
+ "\ " ['xxx', 'xxx,c:yes', 'xxx:', 'xxx:,c:yes']],
+ "\ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'],
+ "\ " ['xxx', 'header:-1']],
+ \ 'scrollopt': [['', 'ver', 'hor', 'jump', 'ver,hor'], ['xxx']],
+ "\ 'renderoptions': [[''], ['xxx']],
+ \ 'rightleftcmd': [['search'], ['xxx']],
+ \ 'rulerformat': [['', 'xxx'], ['%-', '%(', '%15(%%']],
+ \ 'selection': [['old', 'inclusive', 'exclusive'], ['', 'xxx']],
+ \ 'selectmode': [['', 'mouse', 'key', 'cmd', 'key,cmd'], ['xxx']],
+ \ 'sessionoptions': [['', 'blank', 'curdir', 'sesdir',
+ \ 'help,options,slash'],
+ \ ['xxx', 'curdir,sesdir']],
+ \ 'showcmdloc': [['', 'last', 'statusline', 'tabline'], ['xxx']],
+ "\ 'signcolumn': [['', 'auto', 'no', 'yes', 'number'], ['xxx', 'no,yes']],
+ \ 'spellfile': [['', 'file.en.add', 'xxx.en.add,yyy.gb.add,zzz.ja.add',
+ \ '/tmp/dir\ with\ space/en.utf-8.add',
+ \ '/tmp/dir\\,with\\,comma/en.utf-8.add'],
+ \ ['xxx', '/tmp/file', '/tmp/dir*with:invalid?char/file.en.add',
+ \ ',file.en.add', 'xxx,yyy.en.add', 'xxx.en.add,yyy,zzz.ja.add']],
+ \ 'spelllang': [['', 'xxx', 'sr@latin'], ['not&lang', "that\\\rthere"]],
+ \ 'spelloptions': [['', 'camel'], ['xxx']],
+ \ 'spellsuggest': [['', 'best', 'double', 'fast', '100', 'timeout:100',
+ \ 'timeout:-1', 'file:/tmp/file', 'expr:Func()', 'double,33'],
+ \ ['xxx', '-1', 'timeout:', 'best,double', 'double,fast']],
+ \ 'splitkeep': [['', 'cursor', 'screen', 'topline'], ['xxx']],
+ \ 'statusline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
+ "\ 'swapsync': [['', 'sync', 'fsync'], ['xxx']],
+ \ 'switchbuf': [['', 'useopen', 'usetab', 'split', 'vsplit', 'newtab',
+ \ 'uselast', 'split,newtab'],
+ \ ['xxx']],
+ \ 'tabclose': [['', 'left', 'uselast', 'left,uselast'], ['xxx']],
+ \ 'tabline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
+ \ 'tagcase': [['followic', 'followscs', 'ignore', 'match', 'smart'],
+ \ ['', 'xxx', 'smart,match']],
+ \ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
+ "\ 'termwinkey': [['', 'f', '^Y', '^@', '<Esc>', '<t_xx>', "\u3042", '<',
+ "\ " '^'],
+ "\ " ['<xxx>', '<t_xxx>', '<Esc', '<t_xx']],
+ "\ 'termwinsize': [['', '24x80', '0x80', '32x0', '0x0'],
+ "\ " ['xxx', '80', '8ax9', '24x80b']],
+ "\ 'termwintype': [['', 'winpty', 'conpty'], ['xxx']],
+ "\ 'titlestring': [['', 'xxx', '%('], []],
+ "\ 'toolbar': [['', 'icons', 'text', 'horiz', 'tooltips', 'icons,text'],
+ "\ " ['xxx']],
+ "\ 'toolbariconsize': [['', 'tiny', 'small', 'medium', 'large', 'huge',
+ "\ " 'giant'],
+ "\ " ['xxx']],
+ "\ 'ttymouse': [['', 'xterm'], ['xxx']],
+ \ 'varsofttabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20', '1,']],
+ \ 'vartabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20', '1,']],
+ \ 'verbosefile': [['', './Xfile'], []],
+ \ 'viewoptions': [['', 'cursor', 'folds', 'options', 'localoptions',
+ \ 'slash', 'unix', 'curdir', 'unix,slash'], ['xxx']],
+ \ 'viminfo': [['', '''50', '"30', "'100,<50,s10,h"], ['xxx', 'h']],
+ \ 'virtualedit': [['', 'block', 'insert', 'all', 'onemore', 'none',
+ \ 'NONE', 'all,block'],
+ \ ['xxx']],
+ \ 'whichwrap': [['', 'b', 's', 'h', 'l', '<', '>', '~', '[', ']', 'b,s',
+ \ 'bs'],
+ \ ['xxx']],
+ \ 'wildmode': [['', 'full', 'longest', 'list', 'lastused', 'list:full',
+ \ 'full,longest', 'full,full,full,full'],
+ \ ['xxx', 'a4', 'full,full,full,full,full']],
+ \ 'wildoptions': [['', 'tagfile', 'pum', 'fuzzy'], ['xxx']],
+ \ 'winaltkeys': [['no', 'yes', 'menu'], ['', 'xxx']],
+ \
+ "\ skipped options
+ "\ 'luadll': [[], []],
+ "\ 'perldll': [[], []],
+ "\ 'pythondll': [[], []],
+ "\ 'pythonthreedll': [[], []],
+ \ 'pyxversion': [[], []],
+ "\ 'rubydll': [[], []],
+ "\ 'tcldll': [[], []],
+ \ 'term': [[], []],
+ \ 'ttytype': [[], []],
+ \
+ "\ default behaviours
+ \ 'othernum': [[-1, 0, 100], ['']],
+ \ 'otherstring': [['', 'xxx'], []],
+ \}
+
+" Two lists with values: values that pre- and post-processing in test.
+" Clear out t_WS: we don't want to resize the actual terminal.
+let test_prepost = {
+ \ 'browsedir': [["call mkdir('Xdir with space', 'D')"], []],
+ \ 'columns': [[
+ \ 'set t_WS=',
+ \ 'let save_columns = &columns'
+ \ ], [
+ \ 'let &columns = save_columns',
+ \ 'set t_WS&'
+ \ ]],
+ \ 'lines': [[
+ \ 'set t_WS=',
+ \ 'let save_lines = &lines'
+ \ ], [
+ \ 'let &lines = save_lines',
+ \ 'set t_WS&'
+ \ ]],
+ \ 'verbosefile': [[], ['call delete("Xfile")']],
+ \}
+
+const invalid_options = test_values->keys()
+ \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")})
+if !empty(invalid_options)
+ throw $"Invalid option name in test_values: '{invalid_options->join("', '")}'"
+endif
+
+for option in options
+ let fullname = option.full_name
+ let shortname = get(option, 'abbreviation', fullname)
+
+ if !exists('+' .. fullname)
+ continue
+ endif
+
+ let [valid_values, invalid_values] = test_values[
+ \ has_key(test_values, fullname) ? fullname
+ \ : option.type == 'number' ? 'othernum'
+ \ : 'otherstring']
+
+ if empty(valid_values) && empty(invalid_values)
+ continue
+ endif
+
+ call add(script, $"func Test_opt_set_{fullname}()")
+ call add(script, $"if exists('+{fullname}') && execute('set!') =~# '\\n..{fullname}\\([=\\n]\\|$\\)'")
+ call add(script, $"let l:saved = [&g:{fullname}, &l:{fullname}]")
+ call add(script, 'endif')
+
+ let [pre_processing, post_processing] = get(test_prepost, fullname, [[], []])
+ let script += pre_processing
+
+ if option.type == 'boolean'
+ for opt in [fullname, shortname]
+ for cmd in ['set', 'setlocal', 'setglobal']
+ call add(script, $'{cmd} {opt}')
+ call add(script, $'{cmd} no{opt}')
+ call add(script, $'{cmd} inv{opt}')
+ call add(script, $'{cmd} {opt}!')
+ endfor
+ endfor
+ else " P_NUM || P_STRING
+ " Normal tests
+ for opt in [fullname, shortname]
+ for cmd in ['set', 'setlocal', 'setglobal']
+ for val in valid_values
+ if local_noglobals->has_key(fullname) && cmd ==# 'setglobal'
+ " Skip `:setglobal {option}={val}` for local-noglobal option.
+ " It has no effect.
+ let pre = '" Skip local-noglobal: '
+ else
+ let pre = ''
+ endif
+ call add(script, $'{pre}{cmd} {opt}={val}')
+ endfor
+ endfor
+ " Testing to clear the local value and switch back to the global value.
+ if global_locals->has_key(fullname)
+ let switchback_val = global_locals[fullname]
+ call add(script, $'setlocal {opt}={switchback_val}')
+ call add(script, $'call assert_equal(&g:{fullname}, &{fullname})')
+ endif
+ endfor
+
+ " Failure tests
+ " Setting an option can only fail when it's implemented.
+ call add(script, $"if exists('+{fullname}')")
+ for opt in [fullname, shortname]
+ for cmd in ['set', 'setlocal', 'setglobal']
+ for val in invalid_values
+ if val is# global_locals->get(fullname, {}) && cmd ==# 'setlocal'
+ " Skip setlocal switchback-value to global-local option. It will
+ " not result in failure.
+ let pre = '" Skip global-local: '
+ elseif local_noglobals->has_key(fullname) && cmd ==# 'setglobal'
+ " Skip setglobal to local-noglobal option. It will not result in
+ " failure.
+ let pre = '" Skip local-noglobal: '
+ elseif skip_setglobal_reasons->has_key(fullname) && cmd ==# 'setglobal'
+ " Skip setglobal to reasoned option. It will not result in failure.
+ let reason = skip_setglobal_reasons[fullname]
+ let pre = $'" Skip {reason}: '
+ else
+ let pre = ''
+ endif
+ let cmdline = $'{cmd} {opt}={val}'
+ call add(script, $"{pre}silent! call assert_fails({string(cmdline)})")
+ endfor
+ endfor
+ endfor
+ call add(script, "endif")
+ endif
+
+ " Cannot change 'termencoding' in GTK
+ if fullname != 'termencoding' || !has('gui_gtk')
+ call add(script, $'set {fullname}&')
+ call add(script, $'set {shortname}&')
+ call add(script, $"if exists('l:saved')")
+ call add(script, $"let [&g:{fullname}, &l:{fullname}] = l:saved")
+ call add(script, 'endif')
+ endif
+
+ let script += post_processing
+ call add(script, 'endfunc')
+endfor
+
+call writefile(script, 'opt_test.vim')
+
+" Write error messages if error occurs.
+catch
+ " Append errors to test.log
+ let error = $'Error: {v:exception} in {v:throwpoint}'
+ echo error
+ split test.log
+ call append('$', error)
+ write
+endtry
+
+endif
+
+qa!
+
+" vim:sw=2:ts=8:noet:nosta:
diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim
index e05a78e9ca..058635c332 100644
--- a/test/old/testdir/runtest.vim
+++ b/test/old/testdir/runtest.vim
@@ -174,10 +174,6 @@ func GetAllocId(name)
return lnum - top - 1
endfunc
-if has('reltime')
- let g:func_start = reltime()
-endif
-
" Get the list of swap files in the current directory.
func s:GetSwapFileList()
let save_dir = &directory
@@ -567,6 +563,16 @@ for g:testfunc in sort(s:tests)
" A test can set g:test_is_flaky to retry running the test.
let g:test_is_flaky = 0
+ " A test can set g:max_run_nr to change the max retry count.
+ let g:max_run_nr = 5
+ if has('mac')
+ let g:max_run_nr = 10
+ endif
+
+ " By default, give up if the same error occurs. A test can set
+ " g:giveup_same_error to 0 to not give up on the same error and keep trying.
+ let g:giveup_same_error = 1
+
let starttime = strftime("%H:%M:%S")
call RunTheTest(g:testfunc)
@@ -582,10 +588,15 @@ for g:testfunc in sort(s:tests)
call extend(s:messages, v:errors)
let endtime = strftime("%H:%M:%S")
- call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}:')
+ if has('reltime')
+ let suffix = $' in{reltimestr(reltime(g:func_start))} seconds'
+ else
+ let suffix = ''
+ endif
+ call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}{suffix}:')
call extend(total_errors, v:errors)
- if g:run_nr >= 5 || prev_error == v:errors[0]
+ if g:run_nr >= g:max_run_nr || g:giveup_same_error && prev_error == v:errors[0]
call add(total_errors, 'Flaky test failed too often, giving up')
let v:errors = total_errors
break
@@ -596,7 +607,8 @@ for g:testfunc in sort(s:tests)
" Flakiness is often caused by the system being very busy. Sleep a
" couple of seconds to have a higher chance of succeeding the second
" time.
- sleep 2
+ let delay = g:run_nr * 2
+ exe 'sleep' delay
let prev_error = v:errors[0]
let v:errors = []
diff --git a/test/old/testdir/script_util.vim b/test/old/testdir/script_util.vim
index 28d6a621d6..a300b670c7 100644
--- a/test/old/testdir/script_util.vim
+++ b/test/old/testdir/script_util.vim
@@ -1,4 +1,4 @@
-" Functions shared by the tests for Vim Script
+" Functions shared by the tests for Vim script
" Commands to track the execution path of a script
com! XpathINIT let g:Xpath = ''
diff --git a/test/old/testdir/shared.vim b/test/old/testdir/shared.vim
index e7a5f471e7..bb1a6c8f5b 100644
--- a/test/old/testdir/shared.vim
+++ b/test/old/testdir/shared.vim
@@ -35,12 +35,20 @@ func PythonProg()
if has('unix')
" We also need the job feature or the pkill command to make sure the server
" can be stopped.
- if !(executable('python') && (has('job') || executable('pkill')))
+ if !(has('job') || executable('pkill'))
return ''
endif
- let s:python = 'python'
+ if executable('python3')
+ let s:python = 'python3'
+ elseif executable('python')
+ let s:python = 'python'
+ else
+ return ''
+ end
elseif has('win32')
" Use Python Launcher for Windows (py.exe) if available.
+ " NOTE: if you get a "Python was not found" error, disable the Python
+ " shortcuts in "Windows menu / Settings / Manage App Execution Aliases".
if executable('py.exe')
let s:python = 'py.exe'
elseif executable('python.exe')
@@ -64,7 +72,7 @@ func RunCommand(cmd)
let job = job_start(a:cmd, {"stoponexit": "hup"})
call job_setoptions(job, {"stoponexit": "kill"})
elseif has('win32')
- exe 'silent !start cmd /c start "test_channel" ' . a:cmd
+ exe 'silent !start cmd /D /c start "test_channel" ' . a:cmd
else
exe 'silent !' . a:cmd . '&'
endif
diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim
index 9d06ebb2be..64599c869a 100644
--- a/test/old/testdir/test_autocmd.vim
+++ b/test/old/testdir/test_autocmd.vim
@@ -88,9 +88,9 @@ if has('timers')
" CursorHoldI event.
let g:triggered = 0
au CursorHoldI * let g:triggered += 1
- set updatetime=500
- call job_start(has('win32') ? 'cmd /c echo:' : 'echo',
- \ {'exit_cb': {-> timer_start(1000, 'ExitInsertMode')}})
+ set updatetime=100
+ call job_start(has('win32') ? 'cmd /D /c echo:' : 'echo',
+ \ {'exit_cb': {-> timer_start(200, 'ExitInsertMode')}})
call feedkeys('a', 'x!')
call assert_equal(1, g:triggered)
unlet g:triggered
@@ -2003,7 +2003,10 @@ func Test_Cmdline()
au! CmdlineLeave
let save_shellslash = &shellslash
- set noshellslash
+ " Nvim doesn't allow setting value of a hidden option to non-default value
+ if exists('+shellslash')
+ set noshellslash
+ endif
au! CmdlineEnter / let g:entered = expand('<afile>')
au! CmdlineLeave / let g:left = expand('<afile>')
let g:entered = 0
diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim
index 9f25a42c38..290af4a4ca 100644
--- a/test/old/testdir/test_cmdline.vim
+++ b/test/old/testdir/test_cmdline.vim
@@ -271,6 +271,12 @@ func Test_changing_cmdheight()
let lines =<< trim END
set cmdheight=1 laststatus=2
+ func EchoOne()
+ set laststatus=2 cmdheight=1
+ echo 'foo'
+ echo 'bar'
+ set cmdheight=2
+ endfunc
func EchoTwo()
set laststatus=2
set cmdheight=5
@@ -306,6 +312,10 @@ func Test_changing_cmdheight()
call term_sendkeys(buf, ":call EchoTwo()\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {})
+ " increasing 'cmdheight' doesn't clear the messages that need hit-enter
+ call term_sendkeys(buf, ":call EchoOne()\<CR>")
+ call VerifyScreenDump(buf, 'Test_changing_cmdheight_7', {})
+
" clean up
call StopVimInTerminal(buf)
endfunc
@@ -727,8 +737,8 @@ func Test_fullcommand()
\ ':5s': 'substitute',
\ "'<,'>s": 'substitute',
\ ":'<,'>s": 'substitute',
- \ 'CheckUni': 'CheckUnix',
- \ 'CheckUnix': 'CheckUnix',
+ \ 'CheckLin': 'CheckLinux',
+ \ 'CheckLinux': 'CheckLinux',
\ }
for [in, want] in items(tests)
@@ -1012,8 +1022,7 @@ func Test_cmdline_complete_user_names()
call feedkeys(':e ~' . first_letter . "\<c-a>\<c-B>\"\<cr>", 'tx')
call assert_match('^"e \~.*\<' . whoami . '\>', @:)
endif
- endif
- if has('win32')
+ elseif has('win32')
" Just in case: check that the system has an Administrator account.
let names = system('net user')
if names =~ 'Administrator'
@@ -1022,14 +1031,27 @@ func Test_cmdline_complete_user_names()
call feedkeys(':e ~A' . "\<c-a>\<c-B>\"\<cr>", 'tx')
call assert_match('^"e \~.*Administrator', @:)
endif
+ else
+ throw 'Skipped: does not work on this platform'
endif
endfunc
+func Test_cmdline_complete_shellcmdline()
+ CheckExecutable whoami
+ command -nargs=1 -complete=shellcmdline MyCmd
+
+ call feedkeys(":MyCmd whoam\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^".*\<whoami\>', @:)
+ let l = getcompletion('whoam', 'shellcmdline')
+ call assert_match('\<whoami\>', join(l, ' '))
+
+ delcommand MyCmd
+endfunc
+
func Test_cmdline_complete_bang()
- if executable('whoami')
- call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^".*\<whoami\>', @:)
- endif
+ CheckExecutable whoami
+ call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^".*\<whoami\>', @:)
endfunc
func Test_cmdline_complete_languages()
@@ -2307,6 +2329,7 @@ endfunc
" Test for 'imcmdline' and 'imsearch'
" This test doesn't actually test the input method functionality.
func Test_cmdline_inputmethod()
+ throw 'Skipped: Nvim does not allow setting the value of a hidden option'
new
call setline(1, ['', 'abc', ''])
set imcmdline
@@ -3800,6 +3823,60 @@ func Test_cmdline_complete_substitute_short()
endfor
endfunc
+" Test for shellcmdline command argument completion
+func Test_cmdline_complete_shellcmdline_argument()
+ command -nargs=+ -complete=shellcmdline MyCmd
+
+ set wildoptions=fuzzy
+
+ call feedkeys(":MyCmd vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim test_cmdline.vim', @:)
+ call assert_equal(['test_cmdline.vim'],
+ \ getcompletion('vim test_cmdline.', 'shellcmdline'))
+
+ call feedkeys(":MyCmd vim nonexistentfile\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim nonexistentfile', @:)
+ call assert_equal([],
+ \ getcompletion('vim nonexistentfile', 'shellcmdline'))
+
+ let compl1 = getcompletion('', 'file')[0]
+ let compl2 = getcompletion('', 'file')[1]
+ call feedkeys(":MyCmd vim \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1, @:)
+
+ call feedkeys(":MyCmd vim \<Tab> \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:)
+
+ let compl = getcompletion('', 'file')[1]
+ call feedkeys(":MyCmd vim \<Tab> \<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:)
+
+ set wildoptions&
+ call feedkeys(":MyCmd vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim test_cmdline.vim', @:)
+ call assert_equal(['test_cmdline.vim'],
+ \ getcompletion('vim test_cmdline.', 'shellcmdline'))
+
+ call feedkeys(":MyCmd vim nonexistentfile\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim nonexistentfile', @:)
+ call assert_equal([],
+ \ getcompletion('vim nonexistentfile', 'shellcmdline'))
+
+ let compl1 = getcompletion('', 'file')[0]
+ let compl2 = getcompletion('', 'file')[1]
+ call feedkeys(":MyCmd vim \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1, @:)
+
+ call feedkeys(":MyCmd vim \<Tab> \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:)
+
+ let compl = getcompletion('', 'file')[1]
+ call feedkeys(":MyCmd vim \<Tab> \<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:)
+
+ delcommand MyCmd
+endfunc
+
" Test for :! shell command argument completion
func Test_cmdline_complete_bang_cmd_argument()
set wildoptions=fuzzy
@@ -3811,30 +3888,32 @@ func Test_cmdline_complete_bang_cmd_argument()
endfunc
func Call_cmd_funcs()
- return [getcmdpos(), getcmdscreenpos(), getcmdcompltype()]
+ return [getcmdpos(), getcmdscreenpos(), getcmdcompltype(), getcmdcomplpat()]
endfunc
func Test_screenpos_and_completion()
call assert_equal(0, getcmdpos())
call assert_equal(0, getcmdscreenpos())
call assert_equal('', getcmdcompltype())
+ call assert_equal('', getcmdcomplpat())
cnoremap <expr> <F2> string(Call_cmd_funcs())
call feedkeys(":let a\<F2>\<C-B>\"\<CR>", "xt")
- call assert_equal("\"let a[6, 7, 'var']", @:)
+ call assert_equal("\"let a[6, 7, 'var', 'a']", @:)
call feedkeys(":quit \<F2>\<C-B>\"\<CR>", "xt")
- call assert_equal("\"quit [6, 7, '']", @:)
+ call assert_equal("\"quit [6, 7, '', '']", @:)
call feedkeys(":nosuchcommand \<F2>\<C-B>\"\<CR>", "xt")
- call assert_equal("\"nosuchcommand [15, 16, '']", @:)
+ call assert_equal("\"nosuchcommand [15, 16, '', '']", @:)
- " Check that getcmdcompltype() doesn't interfere with cmdline completion.
+ " Check that getcmdcompltype() and getcmdcomplpat() don't interfere with
+ " cmdline completion.
let g:results = []
cnoremap <F2> <Cmd>let g:results += [[getcmdline()] + Call_cmd_funcs()]<CR>
call feedkeys(":sign un\<Tab>\<F2>\<Tab>\<F2>\<Tab>\<F2>\<C-C>", "xt")
call assert_equal([
- \ ['sign undefine', 14, 15, 'sign'],
- \ ['sign unplace', 13, 14, 'sign'],
- \ ['sign un', 8, 9, 'sign']], g:results)
+ \ ['sign undefine', 14, 15, 'sign', 'undefine'],
+ \ ['sign unplace', 13, 14, 'sign', 'unplace'],
+ \ ['sign un', 8, 9, 'sign', 'un']], g:results)
unlet g:results
cunmap <F2>
@@ -4070,7 +4149,7 @@ func Test_term_option()
let &cpo = _cpo
endfunc
-func Test_cd_bslsh_completion_windows()
+func Test_cd_bslash_completion_windows()
CheckMSWindows
let save_shellslash = &shellslash
set noshellslash
diff --git a/test/old/testdir/test_compiler.vim b/test/old/testdir/test_compiler.vim
index 69420b4b7f..07b57b76d9 100644
--- a/test/old/testdir/test_compiler.vim
+++ b/test/old/testdir/test_compiler.vim
@@ -10,9 +10,12 @@ func Test_compiler()
let save_LC_ALL = $LC_ALL
let $LC_ALL= "C"
- " %:S does not work properly with 'shellslash' set
let save_shellslash = &shellslash
- set noshellslash
+ " Nvim doesn't allow setting value of a hidden option to non-default value
+ if exists('+shellslash')
+ " %:S does not work properly with 'shellslash' set
+ set noshellslash
+ endif
e Xfoo.pl
compiler perl
diff --git a/test/old/testdir/test_curswant.vim b/test/old/testdir/test_curswant.vim
index e54cd4b280..c67cca5f7d 100644
--- a/test/old/testdir/test_curswant.vim
+++ b/test/old/testdir/test_curswant.vim
@@ -1,4 +1,7 @@
-" Tests for curswant not changing when setting an option
+" Tests for not changing curswant
+
+source check.vim
+source term_util.vim
func Test_curswant()
new
@@ -19,5 +22,50 @@ func Test_curswant()
let &ttimeoutlen=&ttimeoutlen
call assert_equal(7, winsaveview().curswant)
- enew!
+ bw!
+endfunc
+
+func Test_normal_gm()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ call setline(1, repeat([" abcd\tefgh\tij"], 10))
+ call cursor(1, 1)
+ END
+ call writefile(lines, 'XtestCurswant', 'D')
+ let buf = RunVimInTerminal('-S XtestCurswant', #{rows: 10})
+ if has("folding")
+ call term_sendkeys(buf, "jVjzf")
+ " gm
+ call term_sendkeys(buf, "gmk")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'})
+ " g0
+ call term_sendkeys(buf, "jg0k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'})
+ " g^
+ call term_sendkeys(buf, "jg^k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'})
+ endif
+ call term_sendkeys(buf, ":call cursor(10, 1)\<cr>")
+ " gm
+ call term_sendkeys(buf, "gmk")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call term_wait(buf)
+ call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'})
+ " g0
+ call term_sendkeys(buf, "g0k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'})
+ " g^
+ call term_sendkeys(buf, "g^k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'})
+ " clean up
+ call StopVimInTerminal(buf)
+ wincmd p
+ wincmd c
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim
index a448ed9b7f..880286d329 100644
--- a/test/old/testdir/test_diffmode.vim
+++ b/test/old/testdir/test_diffmode.vim
@@ -2007,4 +2007,31 @@ func Test_diff_overlapped_diff_blocks_will_be_merged()
call StopVimInTerminal(buf)
endfunc
+" switching windows in diff mode caused an unnecessary scroll
+func Test_diff_topline_noscroll()
+ CheckScreendump
+
+ let content =<< trim END
+ call setline(1, range(1,60))
+ vnew
+ call setline(1, range(1,10) + range(50,60))
+ windo diffthis
+ norm! G
+ exe "norm! 30\<C-y>"
+ END
+ call writefile(content, 'Xcontent', 'D')
+ let buf = RunVimInTerminal('-S Xcontent', {'rows': 20})
+ call VerifyScreenDump(buf, 'Test_diff_topline_1', {})
+ call term_sendkeys(buf, ":echo line('w0', 1001)\<cr>")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_diff_topline_2', {})
+ call term_sendkeys(buf, "\<C-W>p")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_diff_topline_3', {})
+ call term_sendkeys(buf, "\<C-W>p")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_diff_topline_4', {})
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim
index 037282bf1a..9114cf8b11 100644
--- a/test/old/testdir/test_edit.vim
+++ b/test/old/testdir/test_edit.vim
@@ -2035,7 +2035,7 @@ func Test_edit_browse()
au!
augroup END
- " When the USE_FNAME_CASE is defined this used to cause a crash.
+ " When the CASE_INSENSITIVE_FILENAME is defined this used to cause a crash.
browse enew
bwipe!
diff --git a/test/old/testdir/test_expr.vim b/test/old/testdir/test_expr.vim
index 8871e7e7d7..56a4c3bffa 100644
--- a/test/old/testdir/test_expr.vim
+++ b/test/old/testdir/test_expr.vim
@@ -799,10 +799,10 @@ func Test_expr_completion()
call assert_equal('"echo 1 || g:tvar1 g:tvar2', @:)
" completion for options
- call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt')
- call assert_equal('"echo &compatible', @:)
- call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt')
- call assert_equal('"echo 1 && &compatible', @:)
+ "call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt')
+ "call assert_equal('"echo &compatible', @:)
+ "call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt')
+ "call assert_equal('"echo 1 && &compatible', @:)
call feedkeys(":echo &g:equala\<C-A>\<C-B>\"\<CR>", 'xt')
call assert_equal('"echo &g:equalalways', @:)
@@ -883,7 +883,7 @@ func Test_string_interp()
#" String conversion.
call assert_equal('hello from ' .. v:version, $"hello from {v:version}")
call assert_equal('hello from ' .. v:version, $'hello from {v:version}')
- #" Paper over a small difference between VimScript behaviour.
+ #" Paper over a small difference between Vim script behaviour.
call assert_equal(string(v:true), $"{v:true}")
call assert_equal('(1+1=2)', $"(1+1={1 + 1})")
#" Hex-escaped opening brace: char2nr('{') == 0x7b
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index d99656be47..19b7d41552 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -97,8 +97,17 @@ func s:GetFilenameChecks() abort
\ 'ampl': ['file.run'],
\ 'ant': ['build.xml'],
\ 'antlr4': ['parser.g4'],
- \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'],
- \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'],
+ \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf',
+ \ '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf',
+ \ '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com',
+ \ '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file',
+ \ 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file',
+ \ 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf',
+ \ 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'httpd-some.conf',
+ \ 'httpd-some.conf-file', 'srm.conf', 'srm.conf-file', 'proxy-html.conf', 'proxy-html.conf-file', '/etc/httpd/mods-some/file',
+ \ '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'],
+ \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file',
+ \ 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'],
\ 'applescript': ['file.scpt'],
\ 'aptconf': ['apt.conf', '/.aptitude/config', 'any/.aptitude/config'],
\ 'arch': ['.arch-inventory', '=tagging-method'],
@@ -125,7 +134,7 @@ func s:GetFilenameChecks() abort
\ 'bib': ['file.bib'],
\ 'bicep': ['file.bicep', 'file.bicepparam'],
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'],
- \ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'],
+ \ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf', 'project-spec/configs/zynqmp-generic-xczu7ev.conf'],
\ 'blade': ['file.blade.php'],
\ 'blank': ['file.bl'],
\ 'blueprint': ['file.blp'],
@@ -218,7 +227,7 @@ func s:GetFilenameChecks() abort
\ 'dockerfile': ['Containerfile', 'Dockerfile', 'dockerfile', 'file.Dockerfile', 'file.dockerfile', 'Dockerfile.debian', 'Containerfile.something'],
\ 'dosbatch': ['file.bat'],
\ 'dosini': ['/etc/yum.conf', '/etc/nfs.conf', '/etc/nfsmount.conf', 'file.ini',
- \ 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file',
+ \ 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', 'php-fpm.conf', 'php-fpm.conf.default', 'www.conf', 'www.conf.default',
\ '/etc/yum.repos.d/file', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap',
\ 'file.vbp', 'ja2.ini', 'JA2.INI', 'mimeapps.list', 'pip.conf', 'setup.cfg', 'pudb.cfg',
\ '.coveragerc', '.pypirc', '.gitlint', '.oelint.cfg', 'pylintrc', '.pylintrc',
@@ -230,7 +239,7 @@ func s:GetFilenameChecks() abort
\ 'dracula': ['file.drac', 'file.drc', 'file.lvs', 'file.lpe', 'drac.file'],
\ 'dtd': ['file.dtd'],
\ 'dtrace': ['/usr/lib/dtrace/io.d'],
- \ 'dts': ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap'],
+ \ 'dts': ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap', 'file.overlay'],
\ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace', 'dune-file'],
\ 'dylan': ['file.dylan'],
\ 'dylanintr': ['file.intr'],
@@ -349,12 +358,14 @@ func s:GetFilenameChecks() abort
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
\ 'icon': ['file.icn'],
+ \ 'idris2': ['file.idr'],
\ 'indent': ['.indent.pro', 'indentrc'],
\ 'inform': ['file.inf', 'file.INF'],
\ 'initng': ['/etc/initng/any/file.i', 'file.ii', 'any/etc/initng/any/file.i'],
\ 'inittab': ['inittab'],
\ 'inko': ['file.inko'],
\ 'ipfilter': ['ipf.conf', 'ipf6.conf', 'ipf.rules'],
+ \ 'ipkg': ['file.ipkg'],
\ 'iss': ['file.iss'],
\ 'ist': ['file.ist', 'file.mst'],
\ 'j': ['file.ijs'],
@@ -397,10 +408,13 @@ func s:GetFilenameChecks() abort
\ 'lean': ['file.lean'],
\ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'],
\ 'less': ['file.less'],
+ \ 'leo': ['file.leo'],
\ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'],
+ \ 'lf': ['lfrc'],
\ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'],
\ 'lhaskell': ['file.lhs'],
\ 'libao': ['/etc/libao.conf', '/.libao', 'any/.libao', 'any/etc/libao.conf'],
+ \ 'lidris2': ['file.lidr'],
\ 'lifelines': ['file.ll'],
\ 'lilo': ['lilo.conf', 'lilo.conf-file'],
\ 'lilypond': ['file.ly', 'file.ily'],
@@ -477,6 +491,7 @@ func s:GetFilenameChecks() abort
\ 'mgp': ['file.mgp'],
\ 'mib': ['file.mib', 'file.my'],
\ 'mix': ['file.mix', 'file.mixal'],
+ \ 'mlir': ['file.mlir'],
\ 'mma': ['file.nb', 'file.wl'],
\ 'mmp': ['file.mmp'],
\ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'],
@@ -489,6 +504,7 @@ func s:GetFilenameChecks() abort
\ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'],
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
\ 'msidl': ['file.odl', 'file.mof'],
+ \ 'mss': ['file.mss'],
\ 'msql': ['file.msql'],
\ 'mojo': ['file.mojo', 'file.🔥'],
\ 'msmtp': ['.msmtprc'],
@@ -513,6 +529,7 @@ func s:GetFilenameChecks() abort
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
\ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
\ 'ncf': ['file.ncf'],
+ \ 'neomuttlog': ['/home/user/.neomuttdebug1'],
\ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
\ 'netrc': ['.netrc'],
\ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'],
@@ -659,7 +676,7 @@ func s:GetFilenameChecks() abort
\ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh',
\ '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile',
\ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf',
- \ '.devscripts'],
+ \ '.devscripts', 'file.lo', 'file.la', 'file.lai'],
\ 'sieve': ['file.siv', 'file.sieve'],
\ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
@@ -714,6 +731,7 @@ func s:GetFilenameChecks() abort
\ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
+ \ 'sway': ['file.sw'],
\ 'swayconfig': ['/home/user/.sway/config', '/home/user/.config/sway/config', '/etc/sway/config', '/etc/xdg/sway/config'],
\ 'swift': ['file.swift', 'file.swiftinterface'],
\ 'swiftgyb': ['file.swift.gyb'],
@@ -853,7 +871,10 @@ func s:GetFilenameChecks() abort
\ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'],
\ 'xkb': ['/usr/share/X11/xkb/compat/pc', '/usr/share/X11/xkb/geometry/pc', '/usr/share/X11/xkb/keycodes/evdev', '/usr/share/X11/xkb/symbols/pc', '/usr/share/X11/xkb/types/pc'],
\ 'xmath': ['file.msc', 'file.msf'],
- \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', 'file.xpfm', 'file.spfm', 'file.bxml'],
+ \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui',
+ \ 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old',
+ \ 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr',
+ \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
\ 'xpm': ['file.xpm'],
\ 'xpm2': ['file.xpm2'],
@@ -862,7 +883,8 @@ func s:GetFilenameChecks() abort
\ 'xsd': ['file.xsd'],
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
- \ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock'],
+ \ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock',
+ \ '/home/user/.kube/config'],
\ 'yang': ['file.yang'],
\ 'yuck': ['file.yuck'],
\ 'z8a': ['file.z8a'],
@@ -2419,6 +2441,24 @@ func Test_inc_file()
filetype off
endfunc
+func Test_ll_file()
+ filetype on
+
+ " LLVM IR
+ call writefile(['target triple = "nvptx64-nvidia-cuda"'], 'Xfile.ll', 'D')
+ split Xfile.ll
+ call assert_equal('llvm', &filetype)
+ bwipe!
+
+ " lifelines
+ call writefile(['proc main() {}'], 'Xfile.ll', 'D')
+ split Xfile.ll
+ call assert_equal('lifelines', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_lsl_file()
filetype on
@@ -2697,4 +2737,15 @@ func Test_make_file()
filetype off
endfunc
+func Test_org_file()
+ filetype on
+
+ call writefile(['* org Headline', '*some bold text*', '/some italic text/'], 'Xfile.org', 'D')
+ split Xfile.org
+ call assert_equal('org', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_findfile.vim b/test/old/testdir/test_findfile.vim
index 06d781ed69..539c7a661a 100644
--- a/test/old/testdir/test_findfile.vim
+++ b/test/old/testdir/test_findfile.vim
@@ -1,5 +1,8 @@
" Test findfile() and finddir()
+source check.vim
+source vim9.vim
+
let s:files = [ 'Xfinddir1/foo',
\ 'Xfinddir1/bar',
\ 'Xfinddir1/Xdir2/foo',
@@ -286,4 +289,526 @@ func Test_find_non_existing_path()
let &path = save_path
endfunc
+" Test for 'findfunc'
+func Test_findfunc()
+ CheckUnix
+ call assert_equal('', &findfunc)
+ call writefile(['aFile'], 'Xfindfunc1.c', 'D')
+ call writefile(['bFile'], 'Xfindfunc2.c', 'D')
+ call writefile(['cFile'], 'Xfindfunc3.c', 'D')
+
+ " basic tests
+ func FindFuncBasic(pat, cmdcomplete)
+ let fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
+ return fnames->copy()->filter('v:val =~? a:pat')
+ endfunc
+
+ set findfunc=FindFuncBasic
+ find Xfindfunc3
+ call assert_match('Xfindfunc3.c', @%)
+ bw!
+ 2find Xfind
+ call assert_match('Xfindfunc2.c', @%)
+ bw!
+ call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path')
+ call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path')
+
+ sfind Xfindfunc2.c
+ call assert_match('Xfindfunc2.c', @%)
+ call assert_equal(2, winnr('$'))
+ %bw!
+ call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path')
+
+ tabfind Xfindfunc3.c
+ call assert_match('Xfindfunc3.c', @%)
+ call assert_equal(2, tabpagenr())
+ %bw!
+ call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path')
+
+ " Test garbage collection
+ call test_garbagecollect_now()
+ find Xfindfunc2
+ call assert_match('Xfindfunc2.c', @%)
+ bw!
+ delfunc FindFuncBasic
+ call test_garbagecollect_now()
+ call assert_fails('find Xfindfunc2', 'E117: Unknown function: FindFuncBasic')
+
+ " Buffer-local option
+ func GlobalFindFunc(pat, cmdcomplete)
+ return ['global']
+ endfunc
+ func LocalFindFunc(pat, cmdcomplete)
+ return ['local']
+ endfunc
+ set findfunc=GlobalFindFunc
+ new
+ setlocal findfunc=LocalFindFunc
+ find xxxx
+ call assert_equal('local', @%)
+ wincmd w
+ find xxxx
+ call assert_equal('global', @%)
+ aboveleft new
+ call assert_equal("GlobalFindFunc", &findfunc)
+ wincmd k
+ aboveleft new
+ call assert_equal("GlobalFindFunc", &findfunc)
+ %bw!
+ delfunc GlobalFindFunc
+ delfunc LocalFindFunc
+
+ " Assign an expression
+ set findfunc=[]
+ call assert_fails('find xxxx', 'E117: Unknown function: []')
+
+ " Error cases
+
+ " Function that doesn't take any arguments
+ func FindFuncNoArg()
+ endfunc
+ set findfunc=FindFuncNoArg
+ call assert_fails('find Xfindfunc1.c', 'E118: Too many arguments for function: FindFuncNoArg')
+ delfunc FindFuncNoArg
+
+ " Syntax error in the function
+ func FindFuncSyntaxError(pat, cmdcomplete)
+ return l
+ endfunc
+ set findfunc=FindFuncSyntaxError
+ call assert_fails('find Xfindfunc1.c', 'E121: Undefined variable: l')
+ delfunc FindFuncSyntaxError
+
+ " Find function throws an error
+ func FindFuncWithThrow(pat, cmdcomplete)
+ throw 'find error'
+ endfunc
+ set findfunc=FindFuncWithThrow
+ call assert_fails('find Xfindfunc1.c', 'find error')
+ delfunc FindFuncWithThrow
+
+ " Try using a null function
+ "call assert_fails('let &findfunc = test_null_function()', 'E129: Function name required')
+
+ " Try to create a new window from the find function
+ func FindFuncNewWindow(pat, cmdexpand)
+ new
+ return ["foo"]
+ endfunc
+ set findfunc=FindFuncNewWindow
+ call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window')
+ delfunc FindFuncNewWindow
+
+ " Try to modify the current buffer from the find function
+ func FindFuncModifyBuf(pat, cmdexpand)
+ call setline(1, ['abc'])
+ return ["foo"]
+ endfunc
+ set findfunc=FindFuncModifyBuf
+ call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window')
+ delfunc FindFuncModifyBuf
+
+ " Return the wrong type from the function
+ func FindFuncWrongRet(pat, cmdexpand)
+ return 'foo'
+ endfunc
+ set findfunc=FindFuncWrongRet
+ call assert_fails('find Xfindfunc1.c', "E1514: 'findfunc' did not return a List type")
+ delfunc FindFuncWrongRet
+
+ set findfunc&
+endfunc
+
+" Test for using a script-local function for 'findfunc'
+func Test_findfunc_scriptlocal_func()
+ func! s:FindFuncScript(pat, cmdexpand)
+ let g:FindFuncArg = a:pat
+ return ['xxx']
+ endfunc
+
+ set findfunc=s:FindFuncScript
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ new | only
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ set findfunc=<SID>FindFuncScript
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ new | only
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ let &findfunc = 's:FindFuncScript'
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ new | only
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ let &findfunc = '<SID>FindFuncScript'
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ new | only
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ set findfunc=
+ setglobal findfunc=s:FindFuncScript
+ setlocal findfunc=
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ call assert_equal('', &l:findfunc)
+ new | only
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ new | only
+ set findfunc=
+ setglobal findfunc=
+ setlocal findfunc=s:FindFuncScript
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &l:findfunc)
+ call assert_equal('', &g:findfunc)
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ new | only
+ set findfunc=
+ setlocal findfunc=NoSuchFunc
+ setglobal findfunc=s:FindFuncScript
+ call assert_equal('NoSuchFunc', &findfunc)
+ call assert_equal('NoSuchFunc', &l:findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ new | only
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ call assert_equal('', &l:findfunc)
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ new | only
+ set findfunc=
+ setlocal findfunc=NoSuchFunc
+ set findfunc=s:FindFuncScript
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ call assert_equal('', &l:findfunc)
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ new | only
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
+ call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
+ call assert_equal('', &l:findfunc)
+ let g:FindFuncArg = ''
+ find abc
+ call assert_equal('abc', g:FindFuncArg)
+ bw!
+
+ set findfunc=
+ delfunc s:FindFuncScript
+endfunc
+
+" Test for expanding the argument to the :find command using 'findfunc'
+func Test_findfunc_expand_arg()
+ let s:fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
+
+ " 'findfunc' that accepts a regular expression
+ func FindFuncRegexp(pat, cmdcomplete)
+ return s:fnames->copy()->filter('v:val =~? a:pat')
+ endfunc
+
+ " 'findfunc' that accepts a glob
+ func FindFuncGlob(pat_arg, cmdcomplete)
+ let pat = glob2regpat(a:cmdcomplete ? $'*{a:pat_arg}*' : a:pat_arg)
+ return s:fnames->copy()->filter('v:val =~? pat')
+ endfunc
+
+ for regexp in [v:true, v:false]
+ let &findfunc = regexp ? 'FindFuncRegexp' : 'FindFuncGlob'
+
+ call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindfunc1.c', @:)
+
+ call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindfunc2.c', @:)
+
+ call assert_equal(s:fnames, getcompletion('find ', 'cmdline'))
+ call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline'))
+
+ let pat = regexp ? 'X.*1\.c' : 'X*1.c'
+ call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindfunc1.c', @:)
+ call assert_equal(['Xfindfunc1.c'], getcompletion($'find {pat}', 'cmdline'))
+
+ call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindfunc3.c', @:)
+ call assert_equal(['Xfindfunc3.c'], getcompletion($'find 3', 'cmdline'))
+
+ call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindfunc1.c Xfindfunc2.c Xfindfunc3.c', @:)
+
+ call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find abc', @:)
+ call assert_equal([], getcompletion('find abc', 'cmdline'))
+ endfor
+
+ set findfunc&
+ delfunc! FindFuncRegexp
+ delfunc! FindFuncGlob
+ unlet s:fnames
+endfunc
+
+" Test for different ways of setting the 'findfunc' option
+func Test_findfunc_callback()
+ new
+ func FindFunc1(pat, cmdexpand)
+ let g:FindFunc1Args = [a:pat, a:cmdexpand]
+ return ['findfunc1']
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a function name
+ LET &findfunc = 'g:FindFunc1'
+ LET g:FindFunc1Args = []
+ find abc1
+ call assert_equal(['abc1', v:false], g:FindFunc1Args)
+
+ #" Test for using a function()
+ set findfunc=function('g:FindFunc1')
+ LET g:FindFunc1Args = []
+ find abc2
+ call assert_equal(['abc2', v:false], g:FindFunc1Args)
+
+ #" Using a funcref variable to set 'findfunc'
+ VAR Fn = function('g:FindFunc1')
+ LET &findfunc = Fn
+ LET g:FindFunc1Args = []
+ find abc3
+ call assert_equal(['abc3', v:false], g:FindFunc1Args)
+
+ #" Using a string(funcref_variable) to set 'findfunc'
+ LET Fn = function('g:FindFunc1')
+ LET &findfunc = string(Fn)
+ LET g:FindFunc1Args = []
+ find abc4
+ call assert_equal(['abc4', v:false], g:FindFunc1Args)
+
+ #" Test for using a funcref()
+ set findfunc=funcref('g:FindFunc1')
+ LET g:FindFunc1Args = []
+ find abc5
+ call assert_equal(['abc5', v:false], g:FindFunc1Args)
+
+ #" Using a funcref variable to set 'findfunc'
+ LET Fn = funcref('g:FindFunc1')
+ LET &findfunc = Fn
+ LET g:FindFunc1Args = []
+ find abc6
+ call assert_equal(['abc6', v:false], g:FindFunc1Args)
+
+ #" Using a string(funcref_variable) to set 'findfunc'
+ LET Fn = funcref('g:FindFunc1')
+ LET &findfunc = string(Fn)
+ LET g:FindFunc1Args = []
+ find abc7
+ call assert_equal(['abc7', v:false], g:FindFunc1Args)
+
+ #" Test for using a lambda function using set
+ VAR optval = "LSTART pat, cmdexpand LMIDDLE FindFunc1(pat, cmdexpand) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set findfunc=" .. optval
+ LET g:FindFunc1Args = []
+ find abc8
+ call assert_equal(['abc8', v:false], g:FindFunc1Args)
+
+ #" Test for using a lambda function using LET
+ LET &findfunc = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
+ LET g:FindFunc1Args = []
+ find abc9
+ call assert_equal(['abc9', v:false], g:FindFunc1Args)
+
+ #" Set 'findfunc' to a string(lambda expression)
+ LET &findfunc = 'LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND'
+ LET g:FindFunc1Args = []
+ find abc10
+ call assert_equal(['abc10', v:false], g:FindFunc1Args)
+
+ #" Set 'findfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
+ LET &findfunc = Lambda
+ LET g:FindFunc1Args = []
+ find abc11
+ call assert_equal(['abc11', v:false], g:FindFunc1Args)
+
+ #" Set 'findfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
+ LET &findfunc = string(Lambda)
+ LET g:FindFunc1Args = []
+ find abc12
+ call assert_equal(['abc12', v:false], g:FindFunc1Args)
+
+ #" Try to use 'findfunc' after the function is deleted
+ func g:TmpFindFunc(pat, cmdexpand)
+ let g:TmpFindFunc1Args = [a:pat, a:cmdexpand]
+ endfunc
+ LET &findfunc = function('g:TmpFindFunc')
+ delfunc g:TmpFindFunc
+ call test_garbagecollect_now()
+ LET g:TmpFindFunc1Args = []
+ call assert_fails('find abc13', 'E117:')
+ call assert_equal([], g:TmpFindFunc1Args)
+
+ #" Try to use a function with three arguments for 'findfunc'
+ func g:TmpFindFunc2(x, y, z)
+ let g:TmpFindFunc2Args = [a:x, a:y, a:z]
+ endfunc
+ set findfunc=TmpFindFunc2
+ LET g:TmpFindFunc2Args = []
+ call assert_fails('find abc14', 'E119:')
+ call assert_equal([], g:TmpFindFunc2Args)
+ delfunc TmpFindFunc2
+
+ #" Try to use a function with zero arguments for 'findfunc'
+ func g:TmpFindFunc3()
+ let g:TmpFindFunc3Called = v:true
+ endfunc
+ set findfunc=TmpFindFunc3
+ LET g:TmpFindFunc3Called = v:false
+ call assert_fails('find abc15', 'E118:')
+ call assert_equal(v:false, g:TmpFindFunc3Called)
+ delfunc TmpFindFunc3
+
+ #" Try to use a lambda function with three arguments for 'findfunc'
+ LET &findfunc = LSTART a, b, c LMIDDLE FindFunc1(a, v:false) LEND
+ LET g:FindFunc1Args = []
+ call assert_fails('find abc16', 'E119:')
+ call assert_equal([], g:FindFunc1Args)
+
+ #" Test for clearing the 'findfunc' option
+ set findfunc=''
+ set findfunc&
+ call assert_fails("set findfunc=function('abc')", "E700:")
+ call assert_fails("set findfunc=funcref('abc')", "E700:")
+
+ #" set 'findfunc' to a non-existing function
+ LET &findfunc = function('g:FindFunc1')
+ call assert_fails("set findfunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &findfunc = function('NonExistingFunc')", 'E700:')
+ LET g:FindFunc1Args = []
+ find abc17
+ call assert_equal(['abc17', v:false], g:FindFunc1Args)
+ END
+ call CheckTransLegacySuccess(lines)
+
+ " Test for using a script-local function name
+ func s:FindFunc2(pat, cmdexpand)
+ let g:FindFunc2Args = [a:pat, a:cmdexpand]
+ return ['findfunc2']
+ endfunc
+ set findfunc=s:FindFunc2
+ let g:FindFunc2Args = []
+ find abc18
+ call assert_equal(['abc18', v:false], g:FindFunc2Args)
+
+ let &findfunc = 's:FindFunc2'
+ let g:FindFunc2Args = []
+ find abc19
+ call assert_equal(['abc19', v:false], g:FindFunc2Args)
+ delfunc s:FindFunc2
+
+ " Using Vim9 lambda expression in legacy context should fail
+ set findfunc=(pat,\ cmdexpand)\ =>\ FindFunc1(pat,\ v:false)
+ let g:FindFunc1Args = []
+ call assert_fails('find abc20', 'E117:')
+ call assert_equal([], g:FindFunc1Args)
+
+ " set 'findfunc' to a partial with dict.
+ func SetFindFunc()
+ let operator = {'execute': function('FindFuncExecute')}
+ let &findfunc = operator.execute
+ endfunc
+ func FindFuncExecute(pat, cmdexpand) dict
+ return ['findfuncexecute']
+ endfunc
+ call SetFindFunc()
+ call test_garbagecollect_now()
+ set findfunc=
+ delfunc SetFindFunc
+ delfunc FindFuncExecute
+
+ func FindFunc2(pat, cmdexpand)
+ let g:FindFunc2Args = [a:pat, a:cmdexpand]
+ return ['findfunc2']
+ endfunc
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def g:Vim9findFunc(pat: string, cmdexpand: bool): list<string>
+ g:FindFunc1Args = [pat, cmdexpand]
+ return ['vim9findfunc']
+ enddef
+
+ # Test for using a def function with findfunc
+ set findfunc=function('g:Vim9findFunc')
+ g:FindFunc1Args = []
+ find abc21
+ assert_equal(['abc21', false], g:FindFunc1Args)
+
+ # Test for using a global function name
+ &findfunc = g:FindFunc2
+ g:FindFunc2Args = []
+ find abc22
+ assert_equal(['abc22', false], g:FindFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def LocalFindFunc(pat: string, cmdexpand: bool): list<string>
+ g:LocalFindFuncArgs = [pat, cmdexpand]
+ return ['localfindfunc']
+ enddef
+ &findfunc = LocalFindFunc
+ g:LocalFindFuncArgs = []
+ find abc23
+ assert_equal(['abc23', false], g:LocalFindFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " setting 'findfunc' to a script local function outside of a script context
+ " should fail
+ let cleanup =<< trim END
+ call writefile([execute('messages')], 'Xtest.out')
+ qall
+ END
+ call writefile(cleanup, 'Xverify.vim', 'D')
+ call RunVim([], [], "-c \"set findfunc=s:abc\" -S Xverify.vim")
+ call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+ call delete('Xtest.out')
+
+ " cleanup
+ set findfunc&
+ delfunc FindFunc1
+ delfunc FindFunc2
+ unlet g:FindFunc1Args g:FindFunc2Args
+ %bw!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim
index ffe7f3fb39..327ea98e1c 100644
--- a/test/old/testdir/test_functions.vim
+++ b/test/old/testdir/test_functions.vim
@@ -272,17 +272,17 @@ func Test_strftime()
let tz = $TZ
endif
- " Force EST and then UTC, save the current hour (24-hour clock) for each
- let $TZ = 'EST' | let est = strftime('%H')
- let $TZ = 'UTC' | let utc = strftime('%H')
+ " Force different time zones, save the current hour (24-hour clock) for each
+ let $TZ = 'GMT+1' | let one = strftime('%H')
+ let $TZ = 'GMT+2' | let two = strftime('%H')
" Those hours should be two bytes long, and should not be the same; if they
" are, a tzset(3) call may have failed somewhere
- call assert_equal(strlen(est), 2)
- call assert_equal(strlen(utc), 2)
+ call assert_equal(strlen(one), 2)
+ call assert_equal(strlen(two), 2)
" TODO: this fails on MS-Windows
if has('unix')
- call assert_notequal(est, utc)
+ call assert_notequal(one, two)
endif
" If we cached a timezone value, put it back, otherwise clear it
@@ -383,6 +383,12 @@ func Test_simplify()
call assert_equal('/', simplify('/.'))
call assert_equal('/', simplify('/..'))
call assert_equal('/...', simplify('/...'))
+ call assert_equal('//path', simplify('//path'))
+ if has('unix')
+ call assert_equal('/path', simplify('///path'))
+ call assert_equal('/path', simplify('////path'))
+ endif
+
call assert_equal('./dir/file', './dir/file'->simplify())
call assert_equal('./dir/file', simplify('.///dir//file'))
call assert_equal('./dir/file', simplify('./dir/./file'))
@@ -2069,6 +2075,7 @@ endfunc
" Test for the inputdialog() function
func Test_inputdialog()
+ set timeout timeoutlen=10
if has('gui_running')
call assert_fails('let v=inputdialog([], "xx")', 'E730:')
call assert_fails('let v=inputdialog("Q", [])', 'E730:')
@@ -2078,6 +2085,7 @@ func Test_inputdialog()
call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt')
call assert_equal('yy', v)
endif
+ set timeout& timeoutlen&
endfunc
" Test for inputlist()
@@ -3089,7 +3097,7 @@ func Test_range()
call assert_fails('call term_start(range(3, 4))', 'E474:')
let g:terminal_ansi_colors = range(16)
if has('win32')
- let cmd = "cmd /c dir"
+ let cmd = "cmd /D /c dir"
else
let cmd = "ls"
endif
diff --git a/test/old/testdir/test_getvar.vim b/test/old/testdir/test_getvar.vim
index 56f737ab9c..de00281ba3 100644
--- a/test/old/testdir/test_getvar.vim
+++ b/test/old/testdir/test_getvar.vim
@@ -22,6 +22,12 @@ func Test_var()
call assert_equal('Chance', getwinvar(9, '', def_str))
call assert_equal(0, getwinvar(1, '&nu'))
call assert_equal(0, getwinvar(1, '&nu', 1))
+ call assert_match(v:t_dict, type(getwinvar(1, '&')))
+ call assert_match(v:t_dict, type(getwinvar(1, '&', def_str)))
+ call assert_equal('', getwinvar(9, '&'))
+ call assert_equal('Chance', getwinvar(9, '&', def_str))
+ call assert_equal('', getwinvar(1, '&nux'))
+ call assert_equal('Chance', getwinvar(1, '&nux', def_str))
unlet def_str
" test for gettabvar()
@@ -83,7 +89,12 @@ func Test_var()
unlet def_dict
+ call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&')))
+ call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&', 1)))
call assert_equal("", gettabwinvar(9, 2020, ''))
+ call assert_equal(1, gettabwinvar(9, 2020, '', 1))
+ call assert_equal('', gettabwinvar(9, 2020, '&'))
+ call assert_equal(1, gettabwinvar(9, 2020, '&', 1))
call assert_equal('', gettabwinvar(2, 3, '&nux'))
call assert_equal(1, gettabwinvar(2, 3, '&nux', 1))
tabonly
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index 48319f5017..c02aa1db62 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -950,6 +950,46 @@ func Test_completeopt_buffer_local()
call assert_equal('menu', &completeopt)
call assert_equal('menu', &g:completeopt)
+ new | only
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ set completeopt&
+ setlocal completeopt=menu,fuzzy,noinsert
+ setglobal completeopt=menu,longest
+ call assert_equal('menu,fuzzy,noinsert', &completeopt)
+ call assert_equal('menu,fuzzy,noinsert', &l:completeopt)
+ call assert_equal('menu,longest', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix')
+ call assert_equal('foobaz', getline('.'))
+ setlocal bufhidden=wipe
+ new | only!
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ call assert_equal('menu,longest', &completeopt)
+ call assert_equal('menu,longest', &g:completeopt)
+ call assert_equal('', &l:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix')
+ call assert_equal('foo', getline('.'))
+ bwipe!
+
+ new | only
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ set completeopt&
+ setlocal completeopt=menu,fuzzy,noinsert
+ set completeopt=menu,longest
+ call assert_equal('menu,longest', &completeopt)
+ call assert_equal('menu,longest', &g:completeopt)
+ call assert_equal('', &l:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix')
+ call assert_equal('foo', getline('.'))
+ setlocal bufhidden=wipe
+ new | only!
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ call assert_equal('menu,longest', &completeopt)
+ call assert_equal('menu,longest', &g:completeopt)
+ call assert_equal('', &l:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix')
+ call assert_equal('foo', getline('.'))
+ bwipe!
+
set completeopt&
endfunc
@@ -1713,10 +1753,10 @@ func Test_completefunc_callback()
call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
" Using Vim9 lambda expression in legacy context should fail
- " set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b)
+ set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b)
new | only
let g:CompleteFunc1Args = []
- " call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:')
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:')
call assert_equal([], g:CompleteFunc1Args)
" set 'completefunc' to a partial with dict. This used to cause a crash.
@@ -1970,10 +2010,10 @@ func Test_omnifunc_callback()
call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
" Using Vim9 lambda expression in legacy context should fail
- " set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b)
+ set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b)
new | only
let g:OmniFunc1Args = []
- " call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:')
+ call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:')
call assert_equal([], g:OmniFunc1Args)
" set 'omnifunc' to a partial with dict. This used to cause a crash.
@@ -2228,6 +2268,7 @@ func Test_thesaurusfunc_callback()
call add(g:TsrFunc3Args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
+
set tsrfu=s:TsrFunc3
new
call setline(1, 'script1')
@@ -2243,6 +2284,46 @@ func Test_thesaurusfunc_callback()
call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
call assert_equal([[1, ''], [0, 'script2']], g:TsrFunc3Args)
bw!
+
+ new | only
+ set thesaurusfunc=
+ setlocal thesaurusfunc=NoSuchFunc
+ setglobal thesaurusfunc=s:TsrFunc3
+ call assert_equal('NoSuchFunc', &thesaurusfunc)
+ call assert_equal('NoSuchFunc', &l:thesaurusfunc)
+ call assert_equal('s:TsrFunc3', &g:thesaurusfunc)
+ new | only
+ call assert_equal('s:TsrFunc3', &thesaurusfunc)
+ call assert_equal('s:TsrFunc3', &g:thesaurusfunc)
+ call assert_equal('', &l:thesaurusfunc)
+ call setline(1, 'script1')
+ let g:TsrFunc3Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args)
+ bw!
+
+ new | only
+ set thesaurusfunc=
+ setlocal thesaurusfunc=NoSuchFunc
+ set thesaurusfunc=s:TsrFunc3
+ call assert_equal('s:TsrFunc3', &thesaurusfunc)
+ call assert_equal('s:TsrFunc3', &g:thesaurusfunc)
+ call assert_equal('', &l:thesaurusfunc)
+ call setline(1, 'script1')
+ let g:TsrFunc3Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args)
+ setlocal bufhidden=wipe
+ new | only!
+ call assert_equal('s:TsrFunc3', &thesaurusfunc)
+ call assert_equal('s:TsrFunc3', &g:thesaurusfunc)
+ call assert_equal('', &l:thesaurusfunc)
+ call setline(1, 'script1')
+ let g:TsrFunc3Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args)
+ bw!
+
delfunc s:TsrFunc3
" invalid return value
@@ -2250,10 +2331,10 @@ func Test_thesaurusfunc_callback()
call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
" Using Vim9 lambda expression in legacy context should fail
- " set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b)
+ set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b)
new | only
let g:TsrFunc1Args = []
- " call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:')
+ call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:')
call assert_equal([], g:TsrFunc1Args)
bw!
diff --git a/test/old/testdir/test_map_functions.vim b/test/old/testdir/test_map_functions.vim
index 8f7c8bae76..5118063b36 100644
--- a/test/old/testdir/test_map_functions.vim
+++ b/test/old/testdir/test_map_functions.vim
@@ -527,6 +527,25 @@ func Test_map_restore_negative_sid()
call delete('Xresult')
endfunc
+" Check that restoring a mapping doesn't remove a mapping whose {rhs} matches
+" the restored mapping's {lhs}.
+func Test_map_restore_with_rhs_match_lhs()
+ nnoremap <F2> <F3>
+ nnoremap <F3> <F4>
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('<F4>', maparg('<F3>', 'n'))
+ let d = maparg('<F3>', 'n', v:false, v:true)
+ nunmap <F3>
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('', maparg('<F3>', 'n'))
+ call mapset(d)
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('<F4>', maparg('<F3>', 'n'))
+
+ nunmap <F2>
+ nunmap <F3>
+endfunc
+
func Test_maplist()
new
func s:ClearMappingsAbbreviations()
diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim
index e4e446c55c..96fa0304dc 100644
--- a/test/old/testdir/test_mapping.vim
+++ b/test/old/testdir/test_mapping.vim
@@ -6,33 +6,62 @@ source screendump.vim
source term_util.vim
func Test_abbreviation()
+ new
" abbreviation with 0x80 should work
inoreab чкпр vim
call feedkeys("Goчкпр \<Esc>", "xt")
call assert_equal('vim ', getline('$'))
iunab чкпр
- set nomodified
+ bwipe!
+endfunc
+
+func Test_abbreviation_with_noremap()
+ nnoremap <F2> :echo "cheese"
+ cabbr cheese xxx
+ call feedkeys(":echo \"cheese\"\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"echo "xxx"', @:)
+ call feedkeys("\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"echo "cheese"', @:)
+ nnoremap <F2> :echo "cheese<C-]>"
+ call feedkeys("\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"echo "xxx"', @:)
+ nunmap <F2>
+ cunabbr cheese
+
+ new
+ inoremap <buffer> ( <C-]>()
+ iabbr <buffer> fnu fun
+ call feedkeys("ifnu(", 'tx')
+ call assert_equal('fun()', getline(1))
+ bwipe!
endfunc
func Test_abclear()
- abbrev foo foobar
- iabbrev fooi foobari
- cabbrev fooc foobarc
- call assert_equal("\n\nc fooc foobarc\ni fooi foobari\n! foo foobar", execute('abbrev'))
+ abbrev foo foobar
+ iabbrev fooi foobari
+ cabbrev fooc foobarc
+ call assert_equal("\n\n"
+ \ .. "c fooc foobarc\n"
+ \ .. "i fooi foobari\n"
+ \ .. "! foo foobar", execute('abbrev'))
- iabclear
- call assert_equal("\n\nc fooc foobarc\nc foo foobar", execute('abbrev'))
- abbrev foo foobar
- iabbrev fooi foobari
+ iabclear
+ call assert_equal("\n\n"
+ \ .. "c fooc foobarc\n"
+ \ .. "c foo foobar", execute('abbrev'))
+ abbrev foo foobar
+ iabbrev fooi foobari
- cabclear
- call assert_equal("\n\ni fooi foobari\ni foo foobar", execute('abbrev'))
- abbrev foo foobar
- cabbrev fooc foobarc
+ cabclear
+ call assert_equal("\n\n"
+ \ .. "i fooi foobari\n"
+ \ .. "i foo foobar", execute('abbrev'))
+ abbrev foo foobar
+ cabbrev fooc foobarc
- abclear
- call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
- call assert_fails('%abclear', 'E481:')
+ abclear
+ call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
+ call assert_fails('%abclear', 'E481:')
endfunc
func Test_abclear_buffer()
@@ -42,18 +71,24 @@ func Test_abclear_buffer()
new X2
abbrev <buffer> foo2 foobar2
- call assert_equal("\n\n! foo2 @foobar2\n! foo foobar", execute('abbrev'))
+ call assert_equal("\n\n"
+ \ .. "! foo2 @foobar2\n"
+ \ .. "! foo foobar", execute('abbrev'))
abclear <buffer>
- call assert_equal("\n\n! foo foobar", execute('abbrev'))
+ call assert_equal("\n\n"
+ \ .. "! foo foobar", execute('abbrev'))
b X1
- call assert_equal("\n\n! foo1 @foobar1\n! foo foobar", execute('abbrev'))
+ call assert_equal("\n\n"
+ \ .. "! foo1 @foobar1\n"
+ \ .. "! foo foobar", execute('abbrev'))
abclear <buffer>
- call assert_equal("\n\n! foo foobar", execute('abbrev'))
+ call assert_equal("\n\n"
+ \ .. "! foo foobar", execute('abbrev'))
abclear
- call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
+ call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
%bwipe
endfunc
diff --git a/test/old/testdir/test_modeline.vim b/test/old/testdir/test_modeline.vim
index 487a89e038..2cd9e49a12 100644
--- a/test/old/testdir/test_modeline.vim
+++ b/test/old/testdir/test_modeline.vim
@@ -217,6 +217,7 @@ func Test_modeline_fails_always()
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
call s:modeline_fails('exrc', 'exrc=Something()', 'E520:')
+ call s:modeline_fails('findfunc', 'findfunc=Something', 'E520:')
call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:')
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index 46fddd6c1a..c89e73bada 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -692,9 +692,9 @@ func Test_opfunc_callback()
delfunc s:OpFunc3
" Using Vim9 lambda expression in legacy context should fail
- " set opfunc=(a)\ =>\ OpFunc1(24,\ a)
+ set opfunc=(a)\ =>\ OpFunc1(24,\ a)
let g:OpFunc1Args = []
- " call assert_fails('normal! g@l', 'E117:')
+ call assert_fails('normal! g@l', 'E117:')
call assert_equal([], g:OpFunc1Args)
" set 'operatorfunc' to a partial with dict. This used to cause a crash.
@@ -3958,8 +3958,7 @@ func Test_mouse_shape_after_failed_change()
END
call writefile(lines, 'Xmouseshape.vim', 'D')
call RunVim([], [], "-g -S Xmouseshape.vim")
- sleep 300m
- call assert_equal(['busy', 'arrow'], readfile('Xmouseshapes'))
+ call WaitForAssert({-> assert_equal(['busy', 'arrow'], readfile('Xmouseshapes'))}, 300)
call delete('Xmouseshapes')
endfunc
@@ -3990,8 +3989,7 @@ func Test_mouse_shape_after_cancelling_gr()
END
call writefile(lines, 'Xmouseshape.vim', 'D')
call RunVim([], [], "-g -S Xmouseshape.vim")
- sleep 300m
- call assert_equal(['beam', 'arrow'], readfile('Xmouseshapes'))
+ call WaitForAssert({-> assert_equal(['beam', 'arrow'], readfile('Xmouseshapes'))}, 300)
call delete('Xmouseshapes')
endfunc
diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim
index d0ae33605b..b6bdb1be52 100644
--- a/test/old/testdir/test_options.vim
+++ b/test/old/testdir/test_options.vim
@@ -1,8 +1,11 @@
" Test for options
+source shared.vim
source check.vim
source view_util.vim
+scriptencoding utf-8
+
func Test_whichwrap()
set whichwrap=b,s
call assert_equal('b,s', &whichwrap)
@@ -740,6 +743,7 @@ func Test_set_option_errors()
call assert_fails('set backupcopy=', 'E474:')
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
+ call assert_fails('set msghistory=10001', 'E474:')
call assert_fails('set numberwidth=21', 'E474:')
call assert_fails('set colorcolumn=-a', 'E474:')
call assert_fails('set colorcolumn=a', 'E474:')
@@ -753,6 +757,7 @@ func Test_set_option_errors()
endif
call assert_fails('set helpheight=-1', 'E487:')
call assert_fails('set history=-1', 'E487:')
+ call assert_fails('set msghistory=-1', 'E487:')
call assert_fails('set report=-1', 'E487:')
call assert_fails('set shiftwidth=-1', 'E487:')
call assert_fails('set sidescroll=-1', 'E487:')
@@ -766,8 +771,47 @@ func Test_set_option_errors()
call assert_fails('set updatetime=-1', 'E487:')
call assert_fails('set winheight=-1', 'E487:')
call assert_fails('set tabstop!', 'E488:')
+
+ " Test for setting unknown option errors
call assert_fails('set xxx', 'E518:')
- call assert_fails('set beautify?', 'E518:')
+ call assert_fails('setlocal xxx', 'E518:')
+ call assert_fails('setglobal xxx', 'E518:')
+ call assert_fails('set xxx=', 'E518:')
+ call assert_fails('setlocal xxx=', 'E518:')
+ call assert_fails('setglobal xxx=', 'E518:')
+ call assert_fails('set xxx:', 'E518:')
+ call assert_fails('setlocal xxx:', 'E518:')
+ call assert_fails('setglobal xxx:', 'E518:')
+ call assert_fails('set xxx!', 'E518:')
+ call assert_fails('setlocal xxx!', 'E518:')
+ call assert_fails('setglobal xxx!', 'E518:')
+ call assert_fails('set xxx?', 'E518:')
+ call assert_fails('setlocal xxx?', 'E518:')
+ call assert_fails('setglobal xxx?', 'E518:')
+ call assert_fails('set xxx&', 'E518:')
+ call assert_fails('setlocal xxx&', 'E518:')
+ call assert_fails('setglobal xxx&', 'E518:')
+ call assert_fails('set xxx<', 'E518:')
+ call assert_fails('setlocal xxx<', 'E518:')
+ call assert_fails('setglobal xxx<', 'E518:')
+
+ " Test for missing-options errors.
+ " call assert_fails('set autoprint?', 'E519:')
+ " call assert_fails('set beautify?', 'E519:')
+ " call assert_fails('set flash?', 'E519:')
+ " call assert_fails('set graphic?', 'E519:')
+ " call assert_fails('set hardtabs?', 'E519:')
+ " call assert_fails('set mesg?', 'E519:')
+ " call assert_fails('set novice?', 'E519:')
+ " call assert_fails('set open?', 'E519:')
+ " call assert_fails('set optimize?', 'E519:')
+ " call assert_fails('set redraw?', 'E519:')
+ " call assert_fails('set slowopen?', 'E519:')
+ " call assert_fails('set sourceany?', 'E519:')
+ " call assert_fails('set w300?', 'E519:')
+ " call assert_fails('set w1200?', 'E519:')
+ " call assert_fails('set w9600?', 'E519:')
+
call assert_fails('set undolevels=x', 'E521:')
call assert_fails('set tabstop=', 'E521:')
call assert_fails('set comments=-', 'E524:')
@@ -779,12 +823,16 @@ func Test_set_option_errors()
call assert_fails('set rulerformat=%-', 'E539:')
call assert_fails('set rulerformat=%(', 'E542:')
call assert_fails('set rulerformat=%15(%%', 'E542:')
+
+ " Test for 'statusline' errors
call assert_fails('set statusline=%$', 'E539:')
call assert_fails('set statusline=%{', 'E540:')
call assert_fails('set statusline=%{%', 'E540:')
call assert_fails('set statusline=%{%}', 'E539:')
call assert_fails('set statusline=%(', 'E542:')
call assert_fails('set statusline=%)', 'E542:')
+
+ " Test for 'tabline' errors
call assert_fails('set tabline=%$', 'E539:')
call assert_fails('set tabline=%{', 'E540:')
call assert_fails('set tabline=%{%', 'E540:')
@@ -801,6 +849,7 @@ func Test_set_option_errors()
call assert_fails('set guicursor=r-cr:horx', 'E548:')
call assert_fails('set guicursor=r-cr:hor0', 'E549:')
endif
+
if has('mouseshape')
call assert_fails('se mouseshape=i-r:x', 'E547:')
endif
@@ -814,15 +863,19 @@ func Test_set_option_errors()
call assert_equal('.bak', &backupext)
set backupext& patchmode&
+ " 'winheight' cannot be smaller than 'winminheight'
call assert_fails('set winminheight=10 winheight=9', 'E591:')
set winminheight& winheight&
set winheight=10 winminheight=10
call assert_fails('set winheight=9', 'E591:')
set winminheight& winheight&
+
+ " 'winwidth' cannot be smaller than 'winminwidth'
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
set winminwidth& winwidth&
call assert_fails('set winwidth=9 winminwidth=10', 'E592:')
set winwidth& winminwidth&
+
call assert_fails("set showbreak=\x01", 'E595:')
" call assert_fails('set t_foo=', 'E846:')
call assert_fails('set tabstop??', 'E488:')
@@ -842,18 +895,23 @@ func Test_set_option_errors()
call assert_fails('set sessionoptions=curdir,sesdir', 'E474:')
call assert_fails('set foldmarker={{{,', 'E474:')
call assert_fails('set sessionoptions=sesdir,curdir', 'E474:')
+
+ " 'ambiwidth' conflict 'listchars'
setlocal listchars=trail:·
call assert_fails('set ambiwidth=double', 'E834:')
setlocal listchars=trail:-
setglobal listchars=trail:·
call assert_fails('set ambiwidth=double', 'E834:')
set listchars&
+
+ " 'ambiwidth' conflict 'fillchars'
setlocal fillchars=stl:·
call assert_fails('set ambiwidth=double', 'E835:')
setlocal fillchars=stl:-
setglobal fillchars=stl:·
call assert_fails('set ambiwidth=double', 'E835:')
set fillchars&
+
call assert_fails('set fileencoding=latin1,utf-8', 'E474:')
set nomodifiable
call assert_fails('set fileencoding=latin1', 'E21:')
@@ -861,6 +919,8 @@ func Test_set_option_errors()
" call assert_fails('set t_#-&', 'E522:')
call assert_fails('let &formatoptions = "?"', 'E539:')
call assert_fails('call setbufvar("", "&formatoptions", "?")', 'E539:')
+
+ " Should raises only one error if passing a wrong variable type.
call assert_fails('call setwinvar(0, "&scrolloff", [])', ['E745:', 'E745:'])
call assert_fails('call setwinvar(0, "&list", [])', ['E745:', 'E745:'])
call assert_fails('call setwinvar(0, "&listchars", [])', ['E730:', 'E730:'])
@@ -947,6 +1007,7 @@ func Test_set_ttytype()
endif
endfunc
+" Test for :set all
func Test_set_all()
set tw=75
set iskeyword=a-z,A-Z
@@ -958,7 +1019,8 @@ func Test_set_all()
set tw& iskeyword& splitbelow&
endfunc
-func Test_set_one_column()
+" Test for :set! all
+func Test_set_all_one_column()
let out_mult = execute('set all')->split("\n")
let out_one = execute('set! all')->split("\n")
call assert_true(len(out_mult) < len(out_one))
@@ -967,15 +1029,6 @@ func Test_set_one_column()
call assert_equal(sort(copy(options)), options)
endfunc
-func Test_set_values()
- " opt_test.vim is generated from ../optiondefs.h using gen_opt_test.vim
- if filereadable('opt_test.vim')
- source opt_test.vim
- else
- throw 'Skipped: opt_test.vim does not exist'
- endif
-endfunc
-
func Test_renderoptions()
throw 'skipped: Nvim does not support renderoptions'
" Only do this for Windows Vista and later, fails on Windows XP and earlier.
@@ -1335,7 +1388,8 @@ func Test_local_scrolloff()
call assert_equal(5, &so)
wincmd w
call assert_equal(3, &so)
- setlocal so<
+ "setlocal so<
+ set so<
call assert_equal(5, &so)
setglob so=8
call assert_equal(8, &so)
@@ -1352,7 +1406,8 @@ func Test_local_scrolloff()
call assert_equal(7, &siso)
wincmd w
call assert_equal(3, &siso)
- setlocal siso<
+ "setlocal siso<
+ set siso<
call assert_equal(7, &siso)
setglob siso=4
call assert_equal(4, &siso)
@@ -1506,40 +1561,83 @@ endfunc
" Test for changing options in a sandbox
func Test_opt_sandbox()
- for opt in ['backupdir', 'cdpath', 'exrc']
+ for opt in ['backupdir', 'cdpath', 'exrc', 'findfunc']
call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor
call assert_fails('sandbox let &modelineexpr = 1', 'E48:')
endfunc
-" Test for setting an option with local value to global value
-func Test_opt_local_to_global()
+" Test for setting string global-local option value
+func Test_set_string_global_local_option()
setglobal equalprg=gprg
setlocal equalprg=lprg
call assert_equal('gprg', &g:equalprg)
call assert_equal('lprg', &l:equalprg)
call assert_equal('lprg', &equalprg)
+
+ " :set {option}< removes the local value, so that the global value will be used.
set equalprg<
call assert_equal('', &l:equalprg)
call assert_equal('gprg', &equalprg)
+
+ " :setlocal {option}< set the effective value of {option} to its global value.
setglobal equalprg=gnewprg
setlocal equalprg=lnewprg
setlocal equalprg<
call assert_equal('gnewprg', &l:equalprg)
call assert_equal('gnewprg', &equalprg)
+
set equalprg&
+endfunc
+
+" Test for setting number global-local option value
+func Test_set_number_global_local_option()
+ setglobal scrolloff=10
+ setlocal scrolloff=12
+ call assert_equal(10, &g:scrolloff)
+ call assert_equal(12, &l:scrolloff)
+ call assert_equal(12, &scrolloff)
+
+ " :setlocal {option}< set the effective value of {option} to its global value.
+ "set scrolloff<
+ setlocal scrolloff<
+ call assert_equal(10, &l:scrolloff)
+ call assert_equal(10, &scrolloff)
+
+ " :set {option}< removes the local value, so that the global value will be used.
+ setglobal scrolloff=15
+ setlocal scrolloff=18
+ "setlocal scrolloff<
+ set scrolloff<
+ call assert_equal(-1, &l:scrolloff)
+ call assert_equal(15, &scrolloff)
+
+ set scrolloff&
+endfunc
- " Test for setting the global/local value of a boolean option
+" Test for setting boolean global-local option value
+func Test_set_boolean_global_local_option()
setglobal autoread
setlocal noautoread
- call assert_false(&autoread)
- set autoread<
- call assert_true(&autoread)
+ call assert_equal(1, &g:autoread)
+ call assert_equal(0, &l:autoread)
+ call assert_equal(0, &autoread)
+
+ " :setlocal {option}< set the effective value of {option} to its global value.
+ "set autoread<
+ setlocal autoread<
+ call assert_equal(1, &l:autoread)
+ call assert_equal(1, &autoread)
+
+ " :set {option}< removes the local value, so that the global value will be used.
setglobal noautoread
setlocal autoread
- setlocal autoread<
- call assert_false(&autoread)
+ "setlocal autoread<
+ set autoread<
+ call assert_equal(-1, &l:autoread)
+ call assert_equal(0, &autoread)
+
set autoread&
endfunc
@@ -1565,32 +1663,437 @@ func Test_set_in_sandbox()
set filetype&
endfunc
-" Test for incrementing, decrementing and multiplying a number option value
-func Test_opt_num_op()
+" Test for setting string option value
+func Test_set_string_option()
+ " :set {option}=
+ set makeprg=
+ call assert_equal('', &mp)
+ set makeprg=abc
+ call assert_equal('abc', &mp)
+
+ " :set {option}:
+ set makeprg:
+ call assert_equal('', &mp)
+ set makeprg:abc
+ call assert_equal('abc', &mp)
+
+ " Let string
+ let &makeprg = ''
+ call assert_equal('', &mp)
+ let &makeprg = 'abc'
+ call assert_equal('abc', &mp)
+
+ " Let number converts to string
+ let &makeprg = 42
+ call assert_equal('42', &mp)
+
+ " Appending
+ set makeprg=abc
+ set makeprg+=def
+ call assert_equal('abcdef', &mp)
+ set makeprg+=def
+ call assert_equal('abcdefdef', &mp, ':set+= appends a value even if it already contained')
+ let &makeprg .= 'gh'
+ call assert_equal('abcdefdefgh', &mp)
+ let &makeprg ..= 'ij'
+ call assert_equal('abcdefdefghij', &mp)
+
+ " Removing
+ set makeprg=abcdefghi
+ set makeprg-=def
+ call assert_equal('abcghi', &mp)
+ set makeprg-=def
+ call assert_equal('abcghi', &mp, ':set-= does not remove a value if it is not contained')
+
+ " Prepending
+ set makeprg=abc
+ set makeprg^=def
+ call assert_equal('defabc', &mp)
+ set makeprg^=def
+ call assert_equal('defdefabc', &mp, ':set+= prepends a value even if it already contained')
+
+ set makeprg&
+endfunc
+
+" Test for setting string comma-separated list option value
+func Test_set_string_comma_list_option()
+ " :set {option}=
+ set wildignore=
+ call assert_equal('', &wildignore)
+ set wildignore=*.png
+ call assert_equal('*.png', &wildignore)
+
+ " :set {option}:
+ set wildignore:
+ call assert_equal('', &wildignore)
+ set wildignore:*.png
+ call assert_equal('*.png', &wildignore)
+
+ " Let string
+ let &wildignore = ''
+ call assert_equal('', &wildignore)
+ let &wildignore = '*.png'
+ call assert_equal('*.png', &wildignore)
+
+ " Let number converts to string
+ let &wildignore = 42
+ call assert_equal('42', &wildignore)
+
+ " Appending
+ set wildignore=*.png
+ set wildignore+=*.jpg
+ call assert_equal('*.png,*.jpg', &wildignore, ':set+= prepends a comma to append a value')
+ set wildignore+=*.jpg
+ call assert_equal('*.png,*.jpg', &wildignore, ':set+= does not append a value if it already contained')
+ set wildignore+=jpg
+ call assert_equal('*.png,*.jpg,jpg', &wildignore, ':set+= prepends a comma to append a value if it is not exactly match to item')
+ let &wildignore .= 'foo'
+ call assert_equal('*.png,*.jpg,jpgfoo', &wildignore, ':let-& .= appends a value without a comma')
+ let &wildignore ..= 'bar'
+ call assert_equal('*.png,*.jpg,jpgfoobar', &wildignore, ':let-& ..= appends a value without a comma')
+
+ " Removing
+ set wildignore=*.png,*.jpg,*.obj
+ set wildignore-=*.jpg
+ call assert_equal('*.png,*.obj', &wildignore)
+ set wildignore-=*.jpg
+ call assert_equal('*.png,*.obj', &wildignore, ':set-= does not remove a value if it is not contained')
+ set wildignore-=jpg
+ call assert_equal('*.png,*.obj', &wildignore, ':set-= does not remove a value if it is not exactly match to item')
+
+ " Prepending
+ set wildignore=*.png
+ set wildignore^=*.jpg
+ call assert_equal('*.jpg,*.png', &wildignore)
+ set wildignore^=*.jpg
+ call assert_equal('*.jpg,*.png', &wildignore, ':set+= does not prepend a value if it already contained')
+ set wildignore^=jpg
+ call assert_equal('jpg,*.jpg,*.png', &wildignore, ':set+= prepend a value if it is not exactly match to item')
+
+ set wildignore&
+endfunc
+
+" Test for setting string flags option value
+func Test_set_string_flags_option()
+ " :set {option}=
+ set formatoptions=
+ call assert_equal('', &fo)
+ set formatoptions=abc
+ call assert_equal('abc', &fo)
+
+ " :set {option}:
+ set formatoptions:
+ call assert_equal('', &fo)
+ set formatoptions:abc
+ call assert_equal('abc', &fo)
+
+ " Let string
+ let &formatoptions = ''
+ call assert_equal('', &fo)
+ let &formatoptions = 'abc'
+ call assert_equal('abc', &fo)
+
+ " Let number converts to string
+ let &formatoptions = 12
+ call assert_equal('12', &fo)
+
+ " Appending
+ set formatoptions=abc
+ set formatoptions+=pqr
+ call assert_equal('abcpqr', &fo)
+ set formatoptions+=pqr
+ call assert_equal('abcpqr', &fo, ':set+= does not append a value if it already contained')
+ let &formatoptions .= 'r'
+ call assert_equal('abcpqrr', &fo, ':let-& .= appends a value even if it already contained')
+ let &formatoptions ..= 'r'
+ call assert_equal('abcpqrrr', &fo, ':let-& ..= appends a value even if it already contained')
+
+ " Removing
+ set formatoptions=abcpqr
+ set formatoptions-=cp
+ call assert_equal('abqr', &fo)
+ set formatoptions-=cp
+ call assert_equal('abqr', &fo, ':set-= does not remove a value if it is not contained')
+ set formatoptions-=ar
+ call assert_equal('abqr', &fo, ':set-= does not remove a value if it is not exactly match')
+
+ " Prepending
+ set formatoptions=abc
+ set formatoptions^=pqr
+ call assert_equal('pqrabc', &fo)
+ set formatoptions^=qr
+ call assert_equal('pqrabc', &fo, ':set+= does not prepend a value if it already contained')
+
+ set formatoptions&
+endfunc
+
+" Test for setting number option value
+func Test_set_number_option()
+ " :set {option}=
+ set scrolljump=5
+ call assert_equal(5, &sj)
+ set scrolljump=-3
+ call assert_equal(-3, &sj)
+
+ " :set {option}:
+ set scrolljump:7
+ call assert_equal(7, &sj)
+ set scrolljump:-5
+ call assert_equal(-5, &sj)
+
+ " Set hex
+ set scrolljump=0x10
+ call assert_equal(16, &sj)
+ set scrolljump=-0x10
+ call assert_equal(-16, &sj)
+ set scrolljump=0X12
+ call assert_equal(18, &sj)
+ set scrolljump=-0X12
+ call assert_equal(-18, &sj)
+
+ " Set octal
+ set scrolljump=010
+ call assert_equal(8, &sj)
+ set scrolljump=-010
+ call assert_equal(-8, &sj)
+ set scrolljump=0o12
+ call assert_equal(10, &sj)
+ set scrolljump=-0o12
+ call assert_equal(-10, &sj)
+ set scrolljump=0O15
+ call assert_equal(13, &sj)
+ set scrolljump=-0O15
+ call assert_equal(-13, &sj)
+
+ " Let number
+ let &scrolljump = 4
+ call assert_equal(4, &sj)
+ let &scrolljump = -6
+ call assert_equal(-6, &sj)
+
+ " Let numeric string converts to number
+ let &scrolljump = '7'
+ call assert_equal(7, &sj)
+ let &scrolljump = '-9'
+ call assert_equal(-9, &sj)
+
+ " Incrementing
set shiftwidth=4
set sw+=2
call assert_equal(6, &sw)
+ let &shiftwidth += 2
+ call assert_equal(8, &sw)
+
+ " Decrementing
+ set shiftwidth=6
set sw-=2
call assert_equal(4, &sw)
+ let &shiftwidth -= 2
+ call assert_equal(2, &sw)
+
+ " Multiplying
+ set shiftwidth=4
set sw^=2
call assert_equal(8, &sw)
+ let &shiftwidth *= 2
+ call assert_equal(16, &sw)
+
+ set scrolljump&
set shiftwidth&
endfunc
-" Test for setting option values using v:false and v:true
-func Test_opt_boolean()
+" Test for setting boolean option value
+func Test_set_boolean_option()
set number&
+
+ " :set {option}
set number
call assert_equal(1, &nu)
+
+ " :set no{option}
set nonu
call assert_equal(0, &nu)
+
+ " :set {option}!
+ set number!
+ call assert_equal(1, &nu)
+ set number!
+ call assert_equal(0, &nu)
+
+ " :set inv{option}
+ set invnumber
+ call assert_equal(1, &nu)
+ set invnumber
+ call assert_equal(0, &nu)
+
+ " Let number
+ let &number = 1
+ call assert_equal(1, &nu)
+ let &number = 0
+ call assert_equal(0, &nu)
+
+ " Let numeric string converts to number
+ let &number = '1'
+ call assert_equal(1, &nu)
+ let &number = '0'
+ call assert_equal(0, &nu)
+
+ " Let v:true and v:false
let &nu = v:true
call assert_equal(1, &nu)
let &nu = v:false
call assert_equal(0, &nu)
+
set number&
endfunc
+" Test for setting string option errors
+func Test_set_string_option_errors()
+ " :set no{option}
+ call assert_fails('set nomakeprg', 'E474:')
+ call assert_fails('setlocal nomakeprg', 'E474:')
+ call assert_fails('setglobal nomakeprg', 'E474:')
+
+ " :set inv{option}
+ call assert_fails('set invmakeprg', 'E474:')
+ call assert_fails('setlocal invmakeprg', 'E474:')
+ call assert_fails('setglobal invmakeprg', 'E474:')
+
+ " :set {option}!
+ call assert_fails('set makeprg!', 'E488:')
+ call assert_fails('setlocal makeprg!', 'E488:')
+ call assert_fails('setglobal makeprg!', 'E488:')
+
+ " Invalid trailing chars
+ call assert_fails('set makeprg??', 'E488:')
+ call assert_fails('setlocal makeprg??', 'E488:')
+ call assert_fails('setglobal makeprg??', 'E488:')
+ call assert_fails('set makeprg&&', 'E488:')
+ call assert_fails('setlocal makeprg&&', 'E488:')
+ call assert_fails('setglobal makeprg&&', 'E488:')
+ call assert_fails('set makeprg<<', 'E488:')
+ call assert_fails('setlocal makeprg<<', 'E488:')
+ call assert_fails('setglobal makeprg<<', 'E488:')
+ call assert_fails('set makeprg@', 'E488:')
+ call assert_fails('setlocal makeprg@', 'E488:')
+ call assert_fails('setglobal makeprg@', 'E488:')
+
+ " Invalid type
+ call assert_fails("let &makeprg = ['xxx']", 'E730:')
+endfunc
+
+" Test for setting number option errors
+func Test_set_number_option_errors()
+ " :set no{option}
+ call assert_fails('set notabstop', 'E474:')
+ call assert_fails('setlocal notabstop', 'E474:')
+ call assert_fails('setglobal notabstop', 'E474:')
+
+ " :set inv{option}
+ call assert_fails('set invtabstop', 'E474:')
+ call assert_fails('setlocal invtabstop', 'E474:')
+ call assert_fails('setglobal invtabstop', 'E474:')
+
+ " :set {option}!
+ call assert_fails('set tabstop!', 'E488:')
+ call assert_fails('setlocal tabstop!', 'E488:')
+ call assert_fails('setglobal tabstop!', 'E488:')
+
+ " Invalid trailing chars
+ call assert_fails('set tabstop??', 'E488:')
+ call assert_fails('setlocal tabstop??', 'E488:')
+ call assert_fails('setglobal tabstop??', 'E488:')
+ call assert_fails('set tabstop&&', 'E488:')
+ call assert_fails('setlocal tabstop&&', 'E488:')
+ call assert_fails('setglobal tabstop&&', 'E488:')
+ call assert_fails('set tabstop<<', 'E488:')
+ call assert_fails('setlocal tabstop<<', 'E488:')
+ call assert_fails('setglobal tabstop<<', 'E488:')
+ call assert_fails('set tabstop@', 'E488:')
+ call assert_fails('setlocal tabstop@', 'E488:')
+ call assert_fails('setglobal tabstop@', 'E488:')
+
+ " Not a number
+ call assert_fails('set tabstop=', 'E521:')
+ call assert_fails('setlocal tabstop=', 'E521:')
+ call assert_fails('setglobal tabstop=', 'E521:')
+ call assert_fails('set tabstop=x', 'E521:')
+ call assert_fails('setlocal tabstop=x', 'E521:')
+ call assert_fails('setglobal tabstop=x', 'E521:')
+ call assert_fails('set tabstop=1x', 'E521:')
+ call assert_fails('setlocal tabstop=1x', 'E521:')
+ call assert_fails('setglobal tabstop=1x', 'E521:')
+ call assert_fails('set tabstop=-x', 'E521:')
+ call assert_fails('setlocal tabstop=-x', 'E521:')
+ call assert_fails('setglobal tabstop=-x', 'E521:')
+ call assert_fails('set tabstop=0x', 'E521:')
+ call assert_fails('setlocal tabstop=0x', 'E521:')
+ call assert_fails('setglobal tabstop=0x', 'E521:')
+ call assert_fails('set tabstop=0o', 'E521:')
+ call assert_fails('setlocal tabstop=0o', 'E521:')
+ call assert_fails('setglobal tabstop=0o', 'E521:')
+ call assert_fails("let &tabstop = 'x'", 'E521:')
+ call assert_fails("let &g:tabstop = 'x'", 'E521:')
+ call assert_fails("let &l:tabstop = 'x'", 'E521:')
+
+ " Invalid type
+ call assert_fails("let &tabstop = 'xxx'", 'E521:')
+endfunc
+
+" Test for setting boolean option errors
+func Test_set_boolean_option_errors()
+ " :set {option}=
+ call assert_fails('set number=', 'E474:')
+ call assert_fails('setlocal number=', 'E474:')
+ call assert_fails('setglobal number=', 'E474:')
+ call assert_fails('set number=1', 'E474:')
+ call assert_fails('setlocal number=1', 'E474:')
+ call assert_fails('setglobal number=1', 'E474:')
+
+ " :set {option}:
+ call assert_fails('set number:', 'E474:')
+ call assert_fails('setlocal number:', 'E474:')
+ call assert_fails('setglobal number:', 'E474:')
+ call assert_fails('set number:1', 'E474:')
+ call assert_fails('setlocal number:1', 'E474:')
+ call assert_fails('setglobal number:1', 'E474:')
+
+ " :set {option}+=
+ call assert_fails('set number+=1', 'E474:')
+ call assert_fails('setlocal number+=1', 'E474:')
+ call assert_fails('setglobal number+=1', 'E474:')
+
+ " :set {option}^=
+ call assert_fails('set number^=1', 'E474:')
+ call assert_fails('setlocal number^=1', 'E474:')
+ call assert_fails('setglobal number^=1', 'E474:')
+
+ " :set {option}-=
+ call assert_fails('set number-=1', 'E474:')
+ call assert_fails('setlocal number-=1', 'E474:')
+ call assert_fails('setglobal number-=1', 'E474:')
+
+ " Invalid trailing chars
+ call assert_fails('set number!!', 'E488:')
+ call assert_fails('setlocal number!!', 'E488:')
+ call assert_fails('setglobal number!!', 'E488:')
+ call assert_fails('set number??', 'E488:')
+ call assert_fails('setlocal number??', 'E488:')
+ call assert_fails('setglobal number??', 'E488:')
+ call assert_fails('set number&&', 'E488:')
+ call assert_fails('setlocal number&&', 'E488:')
+ call assert_fails('setglobal number&&', 'E488:')
+ call assert_fails('set number<<', 'E488:')
+ call assert_fails('setlocal number<<', 'E488:')
+ call assert_fails('setglobal number<<', 'E488:')
+ call assert_fails('set number@', 'E488:')
+ call assert_fails('setlocal number@', 'E488:')
+ call assert_fails('setglobal number@', 'E488:')
+
+ " Invalid type
+ call assert_fails("let &number = 'xxx'", 'E521:')
+endfunc
+
" Test for the 'window' option
func Test_window_opt()
" Needs only one open widow
@@ -2289,4 +2792,24 @@ func Test_delcombine()
bwipe!
endfunc
+" Should not raise errors when set missing-options.
+func Test_set_missing_options()
+ throw 'Skipped: N/A'
+ set autoprint
+ set beautify
+ set flash
+ set graphic
+ set hardtabs=8
+ set mesg
+ set novice
+ set open
+ set optimize
+ set redraw
+ set slowopen
+ set sourceany
+ set w300=23
+ set w1200=23
+ set w9600=23
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_options_all.vim b/test/old/testdir/test_options_all.vim
new file mode 100644
index 0000000000..a2330ecb90
--- /dev/null
+++ b/test/old/testdir/test_options_all.vim
@@ -0,0 +1,13 @@
+" Test for options
+
+" opt_test.vim is generated from src/optiondefs.h and runtime/doc/options.txt
+" using gen_opt_test.vim
+if filereadable('opt_test.vim')
+ source opt_test.vim
+else
+ func Test_set_values()
+ throw 'Skipped: opt_test.vim does not exist'
+ endfunc
+endif
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim
index 472882fb87..601ba6c688 100644
--- a/test/old/testdir/test_popup.vim
+++ b/test/old/testdir/test_popup.vim
@@ -1506,20 +1506,31 @@ func Test_pum_highlights_match()
call StopVimInTerminal(buf)
endfunc
-func Test_pum_user_hl_group()
+func Test_pum_user_abbr_hlgroup()
CheckScreendump
let lines =<< trim END
- func CompleteFunc( findstart, base )
+ let s:var = 0
+ func CompleteFunc(findstart, base)
if a:findstart
return 0
endif
+ if s:var == 1
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'abbr_hlgroup': 'StrikeFake' },
+ \ { 'word': '你好', 'abbr_hlgroup': 'StrikeFake' },
+ \]}
+ endif
return {
\ 'words': [
- \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
- \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' },
\]}
endfunc
+ func ChangeVar()
+ let s:var = 1
+ endfunc
set completeopt=menu
set completefunc=CompleteFunc
@@ -1547,19 +1558,26 @@ func Test_pum_user_hl_group()
call VerifyScreenDump(buf, 'Test_pum_highlights_14', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":call ChangeVar()\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "S\<C-X>\<C-U>")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_17', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
call StopVimInTerminal(buf)
endfunc
func Test_pum_user_kind_hlgroup()
CheckScreendump
let lines =<< trim END
- func CompleteFunc( findstart, base )
+ func CompleteFunc(findstart, base)
if a:findstart
return 0
endif
return {
\ 'words': [
- \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'abbr_hlgroup': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' },
\ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' },
\]}
diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim
index 753875963b..ca48812e7d 100644
--- a/test/old/testdir/test_quickfix.vim
+++ b/test/old/testdir/test_quickfix.vim
@@ -6340,6 +6340,106 @@ func Test_quickfix_buffer_contents()
call setqflist([], 'f')
endfunc
+func XquickfixUpdateTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Setup: populate a couple buffers
+ new
+ call setline(1, range(1, 5))
+ let b1 = bufnr()
+ new
+ call setline(1, range(1, 3))
+ let b2 = bufnr()
+ " Setup: set a quickfix list.
+ let items = [{'bufnr': b1, 'lnum': 1}, {'bufnr': b1, 'lnum': 2}, {'bufnr': b2, 'lnum': 1}, {'bufnr': b2, 'lnum': 2}]
+ call g:Xsetlist(items)
+
+ " Open the quickfix list, select the third entry.
+ Xopen
+ exe "normal jj\<CR>"
+ call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
+
+ " Update the quickfix list. Make sure the third entry is still selected.
+ call g:Xsetlist([], 'u', { 'items': items })
+ call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
+
+ " Update the quickfix list again, but this time with missing line number
+ " information. Confirm that we keep the current buffer selected.
+ call g:Xsetlist([{'bufnr': b1}, {'bufnr': b2}], 'u')
+ call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
+
+ Xclose
+
+ " Cleanup the buffers we allocated during this test.
+ %bwipe!
+endfunc
+
+" Test for updating a quickfix list using the "u" flag in setqflist()
+func Test_quickfix_update()
+ call XquickfixUpdateTests('c')
+ call XquickfixUpdateTests('l')
+endfunc
+
+func Test_quickfix_update_with_missing_coordinate_info()
+ new
+ call setline(1, range(1, 5))
+ let b1 = bufnr()
+
+ new
+ call setline(1, range(1, 3))
+ let b2 = bufnr()
+
+ new
+ call setline(1, range(1, 2))
+ let b3 = bufnr()
+
+ " Setup: set a quickfix list with no coordinate information at all.
+ call setqflist([{}, {}])
+
+ " Open the quickfix list, select the second entry.
+ copen
+ exe "normal j\<CR>"
+ call assert_equal(2, getqflist({'idx' : 0}).idx)
+
+ " Update the quickfix list. As the previously selected entry has no
+ " coordinate information, we expect the first entry to now be selected.
+ call setqflist([{'bufnr': b1}, {'bufnr': b2}, {'bufnr': b3}], 'u')
+ call assert_equal(1, getqflist({'idx' : 0}).idx)
+
+ " Select the second entry in the quickfix list.
+ copen
+ exe "normal j\<CR>"
+ call assert_equal(2, getqflist({'idx' : 0}).idx)
+
+ " Update the quickfix list again. The currently selected entry does not have
+ " a line number, but we should keep the file selected.
+ call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 3}, {'bufnr': b3}], 'u')
+ call assert_equal(2, getqflist({'idx' : 0}).idx)
+
+ " Update the quickfix list again. The currently selected entry (bufnr=b2, lnum=3)
+ " is no longer present. We should pick the nearest entry.
+ call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 1}, {'bufnr': b2, 'lnum': 4}], 'u')
+ call assert_equal(3, getqflist({'idx' : 0}).idx)
+
+ " Set the quickfix list again, with a specific column number. The currently selected entry doesn't have a
+ " column number, but they share a line number.
+ call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 4, 'col': 5}, {'bufnr': b2, 'lnum': 4, 'col': 6}], 'u')
+ call assert_equal(2, getqflist({'idx' : 0}).idx)
+
+ " Set the quickfix list again. The currently selected column number (6) is
+ " no longer present. We should select the nearest column number.
+ call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 4, 'col': 2}, {'bufnr': b2, 'lnum': 4, 'col': 4}], 'u')
+ call assert_equal(3, getqflist({'idx' : 0}).idx)
+
+ " Now set the quickfix list, but without columns. We should still pick the
+ " same line.
+ call setqflist([{'bufnr': b2, 'lnum': 3}, {'bufnr': b2, 'lnum': 4}, {'bufnr': b2, 'lnum': 4}], 'u')
+ call assert_equal(2, getqflist({'idx' : 0}).idx)
+
+ " Cleanup the buffers we allocated during this test.
+ %bwipe!
+endfunc
+
" Test for "%b" in "errorformat"
func Test_efm_format_b()
call setqflist([], 'f')
@@ -6459,8 +6559,8 @@ func Test_cbuffer_range()
call XbufferTests_range('l')
endfunc
-" Test for displaying fname pass from setqflist when the name
-" are hard links to prevent seemly duplicate entries.
+" Test for displaying fname passed from setqflist() when the names include
+" hard links to prevent seemingly duplicate entries.
func Xtest_hardlink_fname(cchar)
call s:setup_commands(a:cchar)
%bwipe
diff --git a/test/old/testdir/test_spellfile.vim b/test/old/testdir/test_spellfile.vim
index 48e46641f4..f356b12370 100644
--- a/test/old/testdir/test_spellfile.vim
+++ b/test/old/testdir/test_spellfile.vim
@@ -1155,7 +1155,7 @@ endfunc
" 'spellfile' accepts '@' on top of 'isfname'.
func Test_spellfile_allow_at_character()
call mkdir('Xtest/the foo@bar,dir', 'p')
- let &spellfile = './Xtest/the foo@bar,dir/Xspellfile.add'
+ let &spellfile = './Xtest/the foo@bar\,dir/Xspellfile.add'
let &spellfile = ''
call delete('Xtest', 'rf')
endfunc
diff --git a/test/old/testdir/test_swap.vim b/test/old/testdir/test_swap.vim
index 8a1b3ce133..e174356ed7 100644
--- a/test/old/testdir/test_swap.vim
+++ b/test/old/testdir/test_swap.vim
@@ -420,7 +420,7 @@ func s:get_unused_pid(base)
if has('job')
" Execute 'echo' as a temporary job, and return its pid as an unused pid.
if has('win32')
- let cmd = 'cmd /c echo'
+ let cmd = 'cmd /D /c echo'
else
let cmd = 'echo'
endif
diff --git a/test/old/testdir/test_tagfunc.vim b/test/old/testdir/test_tagfunc.vim
index 812603a430..ec1f93e9be 100644
--- a/test/old/testdir/test_tagfunc.vim
+++ b/test/old/testdir/test_tagfunc.vim
@@ -291,10 +291,10 @@ func Test_tagfunc_callback()
call assert_fails("echo taglist('a')", "E987:")
" Using Vim9 lambda expression in legacy context should fail
- " set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c)
+ set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c)
new
let g:TagFunc1Args = []
- " call assert_fails("tag a17", "E117:")
+ call assert_fails("tag a17", "E117:")
call assert_equal([], g:TagFunc1Args)
bw!
diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim
index a207f4f4e0..d876277850 100644
--- a/test/old/testdir/test_undo.vim
+++ b/test/old/testdir/test_undo.vim
@@ -187,7 +187,8 @@ func Test_global_local_undolevels()
" Resetting the local 'undolevels' value to use the global value
setlocal undolevels=5
- setlocal undolevels<
+ "setlocal undolevels<
+ set undolevels<
call assert_equal(-123456, &l:undolevels)
" Drop created windows
diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim
index 50da2beb40..8048fa6ff8 100644
--- a/test/old/testdir/test_window_cmd.vim
+++ b/test/old/testdir/test_window_cmd.vim
@@ -539,7 +539,7 @@ func Test_equalalways_on_close()
1wincmd w
split
4wincmd w
- resize + 5
+ resize +5
" left column has three windows, equalized heights.
" right column has two windows, top one a bit higher
let height_1 = winheight(1)
diff --git a/test/old/testdir/test_windows_home.vim b/test/old/testdir/test_windows_home.vim
index 3c2db01444..0f86124d3e 100644
--- a/test/old/testdir/test_windows_home.vim
+++ b/test/old/testdir/test_windows_home.vim
@@ -105,7 +105,7 @@ func Test_WindowsHome()
RestoreEnv
let $HOME = save_home
let env = ''
- let job = job_start('cmd /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}})
+ let job = job_start('cmd /D /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}})
sleep 1
let env = filter(split(env, "\n"), 'v:val=="HOME"')
let home = len(env) == 0 ? "" : env[0]
diff --git a/test/testutil.lua b/test/testutil.lua
index a920f658a1..00b30d74d5 100644
--- a/test/testutil.lua
+++ b/test/testutil.lua
@@ -392,9 +392,7 @@ function M.check_logs()
)
end
-local function sysname()
- return uv.os_uname().sysname:lower()
-end
+local sysname = uv.os_uname().sysname:lower()
--- @param s 'win'|'mac'|'freebsd'|'openbsd'|'bsd'
--- @return boolean
@@ -403,48 +401,27 @@ function M.is_os(s)
error('unknown platform: ' .. tostring(s))
end
return not not (
- (s == 'win' and (sysname():find('windows') or sysname():find('mingw')))
- or (s == 'mac' and sysname() == 'darwin')
- or (s == 'freebsd' and sysname() == 'freebsd')
- or (s == 'openbsd' and sysname() == 'openbsd')
- or (s == 'bsd' and sysname():find('bsd'))
+ (s == 'win' and (sysname:find('windows') or sysname:find('mingw')))
+ or (s == 'mac' and sysname == 'darwin')
+ or (s == 'freebsd' and sysname == 'freebsd')
+ or (s == 'openbsd' and sysname == 'openbsd')
+ or (s == 'bsd' and sysname:find('bsd'))
)
end
-local function tmpdir_get()
- return os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP')
-end
-
---- Is temp directory `dir` defined local to the project workspace?
---- @param dir string?
---- @return boolean
-local function tmpdir_is_local(dir)
- return not not (dir and dir:find('Xtest'))
-end
-
local tmpname_id = 0
-local tmpdir = tmpdir_get()
+local tmpdir = os.getenv('TMPDIR') or os.getenv('TEMP')
+local tmpdir_is_local = not not (tmpdir and tmpdir:find('Xtest'))
---- Generates a unique filepath for use by tests, in a test-specific "…/Xtest_tmpdir/T42.7"
---- directory (which is cleaned up by the test runner), and writes the file unless `create=false`.
----
----@param create? boolean (default true) Write the file.
-function M.tmpname(create)
- if tmpdir_is_local(tmpdir) then
+local function get_tmpname()
+ if tmpdir_is_local then
-- Cannot control os.tmpname() dir, so hack our own tmpname() impl.
tmpname_id = tmpname_id + 1
-- "…/Xtest_tmpdir/T42.7"
- local fname = ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), tmpname_id)
- if create ~= false then
- io.open(fname, 'w'):close()
- end
- return fname
+ return ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), tmpname_id)
end
local fname = os.tmpname()
- if create == false then
- os.remove(fname)
- end
if M.is_os('win') and fname:sub(1, 2) == '\\s' then
-- In Windows tmpname() returns a filename starting with
@@ -454,7 +431,20 @@ function M.tmpname(create)
-- In OS X /tmp links to /private/tmp
return '/private' .. fname
end
+ return fname
+end
+--- Generates a unique filepath for use by tests, in a test-specific "…/Xtest_tmpdir/T42.7"
+--- directory (which is cleaned up by the test runner).
+---
+--- @param create? boolean (default true) Create the file.
+--- @return string
+function M.tmpname(create)
+ local fname = get_tmpname()
+ os.remove(fname)
+ if create ~= false then
+ assert(io.open(fname, 'w')):close()
+ end
return fname
end
@@ -479,11 +469,11 @@ function M.check_cores(app, force) -- luacheck: ignore
local random_skip = false
-- Workspace-local $TMPDIR, scrubbed and pattern-escaped.
-- "./Xtest-tmpdir/" => "Xtest%-tmpdir"
- local local_tmpdir = (
- tmpdir_is_local(tmpdir_get())
- and relpath(tmpdir_get()):gsub('^[ ./]+', ''):gsub('%/+$', ''):gsub('([^%w])', '%%%1')
- or nil
- )
+ local local_tmpdir = nil
+ if tmpdir_is_local and tmpdir then
+ local_tmpdir = vim.pesc(relpath(tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', ''))
+ end
+
local db_cmd --- @type string
local test_glob_dir = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
if test_glob_dir and test_glob_dir ~= '' then
diff --git a/test/unit/testutil.lua b/test/unit/testutil.lua
index a6db7beab1..4720d4d730 100644
--- a/test/unit/testutil.lua
+++ b/test/unit/testutil.lua
@@ -151,6 +151,13 @@ local function filter_complex_blocks(body)
or string.find(line, 'mach_vm_range_recipe')
)
then
+ -- HACK: remove bitfields from specific structs as luajit can't seem to handle them.
+ if line:find('struct VTermState') then
+ line = string.gsub(line, 'state : 8;', 'state;')
+ end
+ if line:find('VTermStringFragment') then
+ line = string.gsub(line, 'size_t.*len : 30;', 'size_t len;')
+ end
result[#result + 1] = line
end
end
diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua
new file mode 100644
index 0000000000..4ea5d9c29a
--- /dev/null
+++ b/test/unit/vterm_spec.lua
@@ -0,0 +1,3591 @@
+local t = require('test.unit.testutil')
+local itp = t.gen_itp(it)
+local bit = require('bit')
+
+--- @class vterm
+--- @field ENC_UTF8 integer
+--- @field VTERM_ATTR_BLINK integer
+--- @field VTERM_ATTR_BOLD integer
+--- @field VTERM_ATTR_FONT integer
+--- @field VTERM_ATTR_ITALIC integer
+--- @field VTERM_ATTR_REVERSE integer
+--- @field VTERM_ATTR_UNDERLINE integer
+--- @field VTERM_BASELINE_RAISE integer
+--- @field VTERM_KEY_ENTER integer
+--- @field VTERM_KEY_FUNCTION_0 integer
+--- @field VTERM_KEY_KP_0 integer
+--- @field VTERM_KEY_NONE integer
+--- @field VTERM_KEY_TAB integer
+--- @field VTERM_KEY_UP integer
+--- @field VTERM_MAX_CHARS_PER_CELL integer
+--- @field VTERM_MOD_ALT integer
+--- @field VTERM_MOD_CTRL integer
+--- @field VTERM_MOD_SHIFT integer
+--- @field parser_apc function
+--- @field parser_csi function
+--- @field parser_dcs function
+--- @field parser_osc function
+--- @field parser_pm function
+--- @field parser_sos function
+--- @field parser_text function
+--- @field print_color function
+--- @field screen_sb_clear function
+--- @field screen_sb_popline function
+--- @field screen_sb_pushline function
+--- @field selection_query function
+--- @field selection_set function
+--- @field state_erase function
+--- @field state_movecursor function
+--- @field state_moverect function
+--- @field state_pos function
+--- @field state_putglyph function
+--- @field state_sb_clear function
+--- @field state_scrollrect function
+--- @field state_setpenattr function
+--- @field state_settermprop function
+--- @field term_output function
+--- @field vterm_input_write function
+--- @field vterm_keyboard_end_paste function
+--- @field vterm_keyboard_key function
+--- @field vterm_keyboard_start_paste function
+--- @field vterm_keyboard_unichar function
+--- @field vterm_lookup_encoding fun(any, any):any
+--- @field vterm_mouse_button function
+--- @field vterm_mouse_move function
+--- @field vterm_new fun(any, any):any
+--- @field vterm_obtain_screen fun(any):any
+--- @field vterm_obtain_state fun(any): any
+--- @field vterm_output_set_callback function
+--- @field vterm_parser_set_callbacks fun(any, any, any):any
+--- @field vterm_screen_convert_color_to_rgb function
+--- @field vterm_screen_enable_altscreen function
+--- @field vterm_screen_enable_reflow function
+--- @field vterm_screen_get_attrs_extent function
+--- @field vterm_screen_get_cell function
+--- @field vterm_screen_get_chars fun(any, any, any, any):any
+--- @field vterm_screen_get_text fun(any, any, any, any):any
+--- @field vterm_screen_is_eol fun(any, any):any
+--- @field vterm_screen_reset function
+--- @field vterm_screen_set_callbacks function
+--- @field vterm_set_size function
+--- @field vterm_set_utf8 fun(any, any, any):any
+--- @field vterm_state_focus_in function
+--- @field vterm_state_focus_out function
+--- @field vterm_state_get_cursorpos fun(any, any)
+--- @field vterm_state_get_lineinfo fun(any, any):any
+--- @field vterm_state_get_penattr function
+--- @field vterm_state_reset function
+--- @field vterm_state_set_bold_highbright function
+--- @field vterm_state_set_callbacks function
+--- @field vterm_state_set_selection_callbacks function
+--- @field vterm_state_set_unrecognised_fallbacks function
+local vterm = t.cimport('./src/vterm/vterm.h', './src/vterm/vterm_internal.h')
+
+--- @return string
+local function read_rm()
+ local f = assert(io.open(t.paths.vterm_test_file, 'rb'))
+ local text = f:read('*a')
+ f:close()
+ vim.fs.rm(t.paths.vterm_test_file, { force = true })
+ return text
+end
+
+local function append(str)
+ local f = assert(io.open(t.paths.vterm_test_file, 'a'))
+ f:write(str)
+ f:close()
+ return 1
+end
+
+local function parser_control(control)
+ return append(string.format('control %02x\n', control))
+end
+
+local function parser_escape(bytes)
+ return append(string.format('escape %s\n', t.ffi.string(bytes)))
+end
+
+local function wantparser(vt)
+ assert(vt)
+
+ local parser_cbs = t.ffi.new('VTermParserCallbacks')
+ parser_cbs['text'] = vterm.parser_text
+ parser_cbs['control'] = parser_control
+ parser_cbs['escape'] = parser_escape
+ parser_cbs['csi'] = vterm.parser_csi
+ parser_cbs['osc'] = vterm.parser_osc
+ parser_cbs['dcs'] = vterm.parser_dcs
+ parser_cbs['apc'] = vterm.parser_apc
+ parser_cbs['pm'] = vterm.parser_pm
+ parser_cbs['sos'] = vterm.parser_sos
+
+ vterm.vterm_parser_set_callbacks(vt, parser_cbs, nil)
+end
+
+--- @return any
+local function init()
+ local vt = vterm.vterm_new(25, 80)
+ vterm.vterm_output_set_callback(vt, vterm.term_output, nil)
+ vterm.vterm_set_utf8(vt, true)
+ return vt
+end
+
+local function state_setlineinfo()
+ return 1
+end
+
+--- @return any
+local function wantstate(vt, opts)
+ opts = opts or {}
+ assert(vt)
+ local state = vterm.vterm_obtain_state(vt)
+
+ local state_cbs = t.ffi.new('VTermStateCallbacks')
+ state_cbs['putglyph'] = vterm.state_putglyph
+ state_cbs['movecursor'] = vterm.state_movecursor
+ state_cbs['scrollrect'] = vterm.state_scrollrect
+ state_cbs['moverect'] = vterm.state_moverect
+ state_cbs['erase'] = vterm.state_erase
+ state_cbs['setpenattr'] = vterm.state_setpenattr
+ state_cbs['settermprop'] = vterm.state_settermprop
+ state_cbs['setlineinfo'] = state_setlineinfo
+ state_cbs['sb_clear'] = vterm.state_sb_clear
+
+ local selection_cbs = t.ffi.new('VTermSelectionCallbacks')
+ selection_cbs['set'] = vterm.selection_set
+ selection_cbs['query'] = vterm.selection_query
+
+ vterm.vterm_state_set_callbacks(state, state_cbs, nil)
+
+ -- In some tests we want to check the behaviour of overflowing the buffer, so make it nicely small
+ vterm.vterm_state_set_selection_callbacks(state, selection_cbs, nil, nil, 16)
+ vterm.vterm_state_set_bold_highbright(state, 1)
+ vterm.vterm_state_reset(state, 1)
+
+ local fallbacks = t.ffi.new('VTermStateFallbacks')
+ fallbacks['control'] = parser_control
+ fallbacks['csi'] = vterm.parser_csi
+ fallbacks['osc'] = vterm.parser_osc
+ fallbacks['dcs'] = vterm.parser_dcs
+ fallbacks['apc'] = vterm.parser_apc
+ fallbacks['pm'] = vterm.parser_pm
+ fallbacks['sos'] = vterm.parser_sos
+
+ vterm.want_state_scrollback = opts.b or false
+ vterm.want_state_erase = opts.e or false
+ vterm.vterm_state_set_unrecognised_fallbacks(state, opts.f and fallbacks or nil, nil)
+ vterm.want_state_putglyph = opts.g or false
+ vterm.want_state_moverect = opts.m or false
+ vterm.want_state_settermprop = opts.p or false
+ vterm.want_state_scrollrect = opts.s or false
+
+ return state
+end
+
+--- @return any
+local function wantscreen(vt, opts)
+ opts = opts or {}
+ local screen = vterm.vterm_obtain_screen(vt)
+ local screen_cbs = t.ffi.new('VTermScreenCallbacks')
+
+ -- TODO(dundargoc): fix
+ -- screen_cbs['damage'] = vterm.screen_damage
+ screen_cbs['moverect'] = vterm.state_moverect
+ screen_cbs['movecursor'] = vterm.state_movecursor
+ screen_cbs['settermprop'] = vterm.state_settermprop
+ screen_cbs['sb_pushline'] = vterm.screen_sb_pushline
+ screen_cbs['sb_popline'] = vterm.screen_sb_popline
+ screen_cbs['sb_clear'] = vterm.screen_sb_clear
+
+ vterm.vterm_screen_set_callbacks(screen, screen_cbs, nil)
+
+ if opts.a then
+ vterm.vterm_screen_enable_altscreen(screen, 1)
+ end
+ vterm.want_screen_scrollback = opts.b or false
+ vterm.want_state_movecursor = opts.c or false
+ -- TODO(dundargoc): fix
+ -- vterm.want_screen_damage = opts.d or opts.D or false
+ -- vterm.want_screen_cells = opts.D or false
+ vterm.want_state_moverect = opts.m or false
+ vterm.want_state_settermprop = opts.p or false
+ if opts.r then
+ vterm.vterm_screen_enable_reflow(screen, true)
+ end
+
+ return screen
+end
+
+local function reset(state, screen)
+ if state then
+ vterm.vterm_state_reset(state, 1)
+ vterm.vterm_state_get_cursorpos(state, vterm.state_pos)
+ end
+ if screen then
+ vterm.vterm_screen_reset(screen, 1)
+ end
+end
+
+local function push(input, vt)
+ vterm.vterm_input_write(vt, input, string.len(input))
+end
+
+local function expect(expected)
+ local actual = read_rm()
+ t.eq(expected .. '\n', actual)
+end
+
+local function expect_output(expected_preformat)
+ local actual = read_rm()
+ local expected = 'output '
+
+ for c in string.gmatch(expected_preformat, '.') do
+ if expected ~= 'output ' then
+ expected = expected .. ','
+ end
+ expected = string.format('%s%x', expected, string.byte(c))
+ end
+
+ t.eq(expected .. '\n', actual)
+end
+
+local function cursor(row, col, state)
+ local pos = t.ffi.new('VTermPos') --- @type {row: integer, col: integer}
+ vterm.vterm_state_get_cursorpos(state, pos)
+ t.eq(row, pos.row)
+ t.eq(col, pos.col)
+end
+
+local function lineinfo(row, expected, state)
+ local info = vterm.vterm_state_get_lineinfo(state, row)
+ local dwl = info.doublewidth == 1
+ local dhl = info.doubleheight == 1
+ local cont = info.continuation == 1
+
+ t.eq(dwl, expected.dwl or false)
+ t.eq(dhl, expected.dhl or false)
+ t.eq(cont, expected.cont or false)
+end
+
+local function pen(attribute, expected, state)
+ local is_bool = { bold = true, italic = true, blink = true, reverse = true }
+ local vterm_attribute = {
+ bold = vterm.VTERM_ATTR_BOLD,
+ underline = vterm.VTERM_ATTR_UNDERLINE,
+ italic = vterm.VTERM_ATTR_ITALIC,
+ blink = vterm.VTERM_ATTR_BLINK,
+ reverse = vterm.VTERM_ATTR_REVERSE,
+ font = vterm.VTERM_ATTR_FONT,
+ }
+
+ local val = t.ffi.new('VTermValue') --- @type {boolean: integer}
+ vterm.vterm_state_get_penattr(state, vterm_attribute[attribute], val)
+ local actual = val.boolean --- @type integer|boolean
+ if is_bool[attribute] then
+ actual = val.boolean == 1
+ end
+ t.eq(expected, actual)
+end
+
+local function resize(rows, cols, vt)
+ vterm.vterm_set_size(vt, rows, cols)
+end
+
+local function screen_chars(start_row, start_col, end_row, end_col, expected, screen)
+ local rect = t.ffi.new('VTermRect')
+ rect['start_row'] = start_row
+ rect['start_col'] = start_col
+ rect['end_row'] = end_row
+ rect['end_col'] = end_col
+
+ local len = vterm.vterm_screen_get_chars(screen, nil, 0, rect)
+
+ local chars = t.ffi.new('uint32_t[?]', len)
+ vterm.vterm_screen_get_chars(screen, chars, len, rect)
+
+ local actual = ''
+ for i = 0, tonumber(len) - 1 do
+ actual = actual .. string.char(chars[i])
+ end
+
+ t.eq(expected, actual)
+end
+
+local function screen_text(start_row, start_col, end_row, end_col, expected, screen)
+ local rect = t.ffi.new('VTermRect')
+ rect['start_row'] = start_row
+ rect['start_col'] = start_col
+ rect['end_row'] = end_row
+ rect['end_col'] = end_col
+
+ local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
+
+ local text = t.ffi.new('unsigned char[?]', len)
+ vterm.vterm_screen_get_text(screen, text, len, rect)
+
+ local actual = ''
+ for i = 0, tonumber(len) - 1 do
+ actual = string.format('%s%02x,', actual, text[i])
+ end
+ actual = actual:sub(1, -2)
+
+ t.eq(expected, actual)
+end
+
+--- @param row integer
+local function screen_row(row, expected, screen, end_col)
+ local rect = t.ffi.new('VTermRect')
+ rect['start_row'] = row
+ rect['start_col'] = 0
+ rect['end_row'] = row + 1
+ rect['end_col'] = end_col or 80
+
+ local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
+
+ local text = t.ffi.new('unsigned char[?]', len)
+ vterm.vterm_screen_get_text(screen, text, len, rect)
+
+ t.eq(expected, t.ffi.string(text))
+end
+
+local function screen_cell(row, col, expected, screen)
+ local pos = t.ffi.new('VTermPos')
+ pos['row'] = row
+ pos['col'] = col
+
+ local cell = t.ffi.new('VTermScreenCell')
+ vterm.vterm_screen_get_cell(screen, pos, cell)
+
+ local actual = '{'
+ for i = 0, vterm.VTERM_MAX_CHARS_PER_CELL - 1 do
+ if cell['chars'][i] ~= 0 then
+ if i > 0 then
+ actual = actual .. ','
+ end
+ actual = string.format('%s%02x', actual, cell['chars'][i])
+ end
+ end
+ actual = string.format('%s} width=%d attrs={', actual, cell['width'])
+ actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '')
+ actual = actual
+ .. (cell['attrs'].underline ~= 0 and string.format('U%d', cell['attrs'].underline) or '')
+ actual = actual .. (cell['attrs'].italic ~= 0 and 'I' or '')
+ actual = actual .. (cell['attrs'].blink ~= 0 and 'K' or '')
+ actual = actual .. (cell['attrs'].reverse ~= 0 and 'R' or '')
+ actual = actual .. (cell['attrs'].font ~= 0 and string.format('F%d', cell['attrs'].font) or '')
+ actual = actual .. (cell['attrs'].small ~= 0 and 'S' or '')
+ if cell['attrs'].baseline ~= 0 then
+ actual = actual .. (cell['attrs'].baseline == vterm.VTERM_BASELINE_RAISE and '^' or '_')
+ end
+ actual = actual .. '} '
+
+ actual = actual .. (cell['attrs'].dwl ~= 0 and 'dwl ' or '')
+ if cell['attrs'].dhl ~= 0 then
+ actual = actual .. string.format('dhl-%s ', cell['attrs'].dhl == 2 and 'bottom' or 'top')
+ end
+
+ actual = string.format('%sfg=', actual)
+ vterm.vterm_screen_convert_color_to_rgb(screen, cell['fg'])
+ vterm.print_color(cell['fg'])
+
+ actual = actual .. read_rm()
+ actual = actual .. ' bg='
+
+ vterm.vterm_screen_convert_color_to_rgb(screen, cell['bg'])
+ vterm.print_color(cell['bg'])
+
+ actual = actual .. read_rm()
+
+ t.eq(expected, actual)
+end
+
+local function screen_eol(row, col, expected, screen)
+ local pos = t.ffi.new('VTermPos')
+ pos['row'] = row
+ pos['col'] = col
+
+ local is_eol = vterm.vterm_screen_is_eol(screen, pos)
+ t.eq(expected, is_eol)
+end
+
+local function screen_attrs_extent(row, col, expected, screen)
+ local pos = t.ffi.new('VTermPos')
+ pos['row'] = row
+ pos['col'] = col
+
+ local rect = t.ffi.new('VTermRect')
+ rect['start_col'] = 0
+ rect['end_col'] = -1
+ vterm.vterm_screen_get_attrs_extent(screen, rect, pos, 1)
+
+ local actual = string.format(
+ '%d,%d-%d,%d',
+ rect['start_row'],
+ rect['start_col'],
+ rect['end_row'],
+ rect['end_col']
+ )
+
+ t.eq(expected, actual)
+end
+
+local function wantencoding()
+ local encoding = t.ffi.new('VTermEncodingInstance')
+ encoding['enc'] = vterm.vterm_lookup_encoding(vterm.ENC_UTF8, string.byte('u'))
+ if encoding.enc.init then
+ encoding.enc.init(encoding.enc, encoding['data'])
+ end
+ return encoding
+end
+
+local function encin(input, encoding)
+ local len = string.len(input)
+
+ local cp = t.ffi.new('uint32_t[?]', len)
+ local cpi = t.ffi.new('int[1]')
+ local pos = t.ffi.new('size_t[1]', 0)
+
+ encoding.enc.decode(encoding.enc, encoding.data, cp, cpi, len, input, pos, len)
+
+ local f = assert(io.open(t.paths.vterm_test_file, 'w'))
+ if tonumber(cpi[0]) > 0 then
+ f:write('encout ')
+ for i = 0, cpi[0] - 1 do
+ if i == 0 then
+ f:write(string.format('%x', cp[i]))
+ else
+ f:write(string.format(',%x', cp[i]))
+ end
+ end
+ f:write('\n')
+ end
+ f:close()
+end
+
+local function strpe_modifiers(input_mod)
+ local mod = t.ffi.new('VTermModifier') ---@type any
+ if input_mod.C then
+ mod = bit.bor(mod, vterm.VTERM_MOD_CTRL)
+ end
+ if input_mod.S then
+ mod = bit.bor(mod, vterm.VTERM_MOD_SHIFT)
+ end
+ if input_mod.A then
+ mod = bit.bor(mod, vterm.VTERM_MOD_ALT)
+ end
+ return mod
+end
+
+local function strp_key(input_key)
+ if input_key == 'up' then
+ return vterm.VTERM_KEY_UP
+ end
+
+ if input_key == 'tab' then
+ return vterm.VTERM_KEY_TAB
+ end
+
+ if input_key == 'enter' then
+ return vterm.VTERM_KEY_ENTER
+ end
+
+ if input_key == 'f1' then
+ return vterm.VTERM_KEY_FUNCTION_0 + 1
+ end
+
+ if input_key == 'kp0' then
+ return vterm.VTERM_KEY_KP_0
+ end
+
+ return vterm.VTERM_KEY_NONE
+end
+
+local function mousemove(row, col, vt, input_mod)
+ input_mod = input_mod or {}
+ local mod = strpe_modifiers(input_mod)
+ vterm.vterm_mouse_move(vt, row, col, mod)
+end
+
+local function mousebtn(press, button, vt, input_mod)
+ input_mod = input_mod or {}
+ local mod = strpe_modifiers(input_mod)
+ local flag = press == 'd' or press == 'D'
+ vterm.vterm_mouse_button(vt, button, flag, mod)
+end
+
+local function inchar(c, vt, input_mod)
+ input_mod = input_mod or {}
+ local mod = strpe_modifiers(input_mod)
+ vterm.vterm_keyboard_unichar(vt, c, mod)
+end
+
+local function inkey(input_key, vt, input_mod)
+ input_mod = input_mod or {}
+ local mod = strpe_modifiers(input_mod)
+ local key = strp_key(input_key)
+ vterm.vterm_keyboard_key(vt, key, mod)
+end
+
+before_each(function()
+ vim.fs.rm(t.paths.vterm_test_file, { force = true })
+end)
+
+describe('vterm', function()
+ itp('02parser', function()
+ local vt = init()
+ vterm.vterm_set_utf8(vt, false)
+ wantparser(vt)
+
+ -- Basic text
+ push('hello', vt)
+ expect('text 68,65,6c,6c,6f')
+
+ -- C0
+ push('\x03', vt)
+ expect('control 03')
+ push('\x1f', vt)
+ expect('control 1f')
+
+ -- C1 8bit
+ push('\x83', vt)
+ expect('control 83')
+ push('\x99', vt)
+ expect('control 99')
+
+ -- C1 7bit
+ push('\x1b\x43', vt)
+ expect('control 83')
+ push('\x1b\x59', vt)
+ expect('control 99')
+
+ -- High bytes
+ push('\xa0\xcc\xfe', vt)
+ expect('text a0,cc,fe')
+
+ -- Mixed
+ push('1\n2', vt)
+ expect('text 31\ncontrol 0a\ntext 32')
+
+ -- Escape
+ push('\x1b=', vt)
+ expect('escape =')
+
+ -- Escape 2-byte
+ push('\x1b(X', vt)
+ expect('escape (X')
+
+ -- Split write Escape
+ push('\x1b(', vt)
+ push('Y', vt)
+ expect('escape (Y')
+
+ -- Escape cancels Escape, starts another
+ push('\x1b(\x1b)Z', vt)
+ expect('escape )Z')
+
+ -- CAN cancels Escape, returns to normal mode
+ push('\x1b(\x18AB', vt)
+ expect('text 41,42')
+
+ -- C0 in Escape interrupts and continues
+ push('\x1b(\nX', vt)
+ expect('control 0a\nescape (X')
+
+ -- CSI 0 args
+ push('\x1b[a', vt)
+ expect('csi 61 *')
+
+ -- CSI 1 arg
+ push('\x1b[9b', vt)
+ expect('csi 62 9')
+
+ -- CSI 2 args
+ push('\x1b[3;4c', vt)
+ expect('csi 63 3,4')
+
+ -- CSI 1 arg 1 sub
+ push('\x1b[1:2c', vt)
+ expect('csi 63 1+,2')
+
+ -- CSI many digits
+ push('\x1b[678d', vt)
+ expect('csi 64 678')
+
+ -- CSI leading zero
+ push('\x1b[007e', vt)
+ expect('csi 65 7')
+
+ -- CSI qmark
+ push('\x1b[?2;7f', vt)
+ expect('csi 66 L=3f 2,7')
+
+ -- CSI greater
+ push('\x1b[>c', vt)
+ expect('csi 63 L=3e *')
+
+ -- CSI SP
+ push('\x1b[12 q', vt)
+ expect('csi 71 12 I=20')
+
+ -- Mixed CSI
+ push('A\x1b[8mB', vt)
+ expect('text 41\ncsi 6d 8\ntext 42')
+
+ -- Split write
+ push('\x1b', vt)
+ push('[a', vt)
+ expect('csi 61 *')
+ push('foo\x1b[', vt)
+ expect('text 66,6f,6f')
+ push('4b', vt)
+ expect('csi 62 4')
+ push('\x1b[12;', vt)
+ push('3c', vt)
+ expect('csi 63 12,3')
+
+ -- Escape cancels CSI, starts Escape
+ push('\x1b[123\x1b9', vt)
+ expect('escape 9')
+
+ -- CAN cancels CSI, returns to normal mode
+ push('\x1b[12\x18AB', vt)
+ expect('text 41,42')
+
+ -- C0 in Escape interrupts and continues
+ push('\x1b(\nX', vt)
+ expect('control 0a\nescape (X')
+
+ -- OSC BEL
+ push('\x1b]1;Hello\x07', vt)
+ expect('osc [1;Hello]')
+
+ -- OSC ST (7bit)
+ push('\x1b]1;Hello\x1b\\', vt)
+ expect('osc [1;Hello]')
+
+ -- OSC ST (8bit)
+ push('\x9d1;Hello\x9c', vt)
+ expect('osc [1;Hello]')
+
+ -- OSC in parts
+ push('\x1b]52;abc', vt)
+ expect('osc [52;abc')
+ push('def', vt)
+ expect('osc def')
+ push('ghi\x1b\\', vt)
+ expect('osc ghi]')
+
+ -- OSC BEL without semicolon
+ push('\x1b]1234\x07', vt)
+ expect('osc [1234;]')
+
+ -- OSC ST without semicolon
+ push('\x1b]1234\x1b\\', vt)
+ expect('osc [1234;]')
+
+ -- Escape cancels OSC, starts Escape
+ push('\x1b]Something\x1b9', vt)
+ expect('escape 9')
+
+ -- CAN cancels OSC, returns to normal mode
+ push('\x1b]12\x18AB', vt)
+ expect('text 41,42')
+
+ -- C0 in OSC interrupts and continues
+ push('\x1b]2;\nBye\x07', vt)
+ expect('osc [2;\ncontrol 0a\nosc Bye]')
+
+ -- DCS BEL
+ push('\x1bPHello\x07', vt)
+ expect('dcs [Hello]')
+
+ -- DCS ST (7bit)
+ push('\x1bPHello\x1b\\', vt)
+ expect('dcs [Hello]')
+
+ -- DCS ST (8bit)
+ push('\x90Hello\x9c', vt)
+ expect('dcs [Hello]')
+
+ -- Split write of 7bit ST
+ push('\x1bPABC\x1b', vt)
+ expect('dcs [ABC')
+ push('\\', vt)
+ expect('dcs ]')
+
+ -- Escape cancels DCS, starts Escape
+ push('\x1bPSomething\x1b9', vt)
+ expect('escape 9')
+
+ -- CAN cancels DCS, returns to normal mode
+ push('\x1bP12\x18AB', vt)
+ expect('text 41,42')
+
+ -- C0 in OSC interrupts and continues
+ push('\x1bPBy\ne\x07', vt)
+ expect('dcs [By\ncontrol 0a\ndcs e]')
+
+ -- APC BEL
+ push('\x1b_Hello\x07', vt)
+ expect('apc [Hello]')
+
+ -- APC ST (7bit)
+ push('\x1b_Hello\x1b\\', vt)
+ expect('apc [Hello]')
+
+ -- APC ST (8bit)
+ push('\x9fHello\x9c', vt)
+ expect('apc [Hello]')
+
+ -- PM BEL
+ push('\x1b^Hello\x07', vt)
+ expect('pm [Hello]')
+
+ -- PM ST (7bit)
+ push('\x1b^Hello\x1b\\', vt)
+ expect('pm [Hello]')
+
+ -- PM ST (8bit)
+ push('\x9eHello\x9c', vt)
+ expect('pm [Hello]')
+
+ -- SOS BEL
+ push('\x1bXHello\x07', vt)
+ expect('sos [Hello]')
+
+ -- SOS ST (7bit)
+ push('\x1bXHello\x1b\\', vt)
+ expect('sos [Hello]')
+
+ -- SOS ST (8bit)
+ push('\x98Hello\x9c', vt)
+ expect('sos [Hello]')
+
+ push('\x1bXABC\x01DEF\x1b\\', vt)
+ expect('sos [ABC\x01DEF]')
+ push('\x1bXABC\x99DEF\x1b\\', vt)
+ expect('sos [ABC\x99DEF]')
+
+ -- NUL ignored
+ push('\x00', vt)
+
+ -- NUL ignored within CSI
+ push('\x1b[12\x003m', vt)
+ expect('csi 6d 123')
+
+ -- DEL ignored
+ push('\x7f', vt)
+
+ -- DEL ignored within CSI
+ push('\x1b[12\x7f3m', vt)
+ expect('csi 6d 123')
+
+ -- DEL inside text"
+ push('AB\x7fC', vt)
+ expect('text 41,42\ntext 43')
+ end)
+
+ itp('03encoding_utf8', function()
+ local encoding = wantencoding()
+
+ -- Low
+ encin('123', encoding)
+ expect('encout 31,32,33')
+
+ -- We want to prove the UTF-8 parser correctly handles all the sequences.
+ -- Easy way to do this is to check it does low/high boundary cases, as that
+ -- leaves only two for each sequence length
+ --
+ -- These ranges are therefore:
+ --
+ -- Two bytes:
+ -- U+0080 = 000 10000000 => 00010 000000
+ -- => 11000010 10000000 = C2 80
+ -- U+07FF = 111 11111111 => 11111 111111
+ -- => 11011111 10111111 = DF BF
+ --
+ -- Three bytes:
+ -- U+0800 = 00001000 00000000 => 0000 100000 000000
+ -- => 11100000 10100000 10000000 = E0 A0 80
+ -- U+FFFD = 11111111 11111101 => 1111 111111 111101
+ -- => 11101111 10111111 10111101 = EF BF BD
+ -- (We avoid U+FFFE and U+FFFF as they're invalid codepoints)
+ --
+ -- Four bytes:
+ -- U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000
+ -- => 11110000 10010000 10000000 10000000 = F0 90 80 80
+ -- U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111
+ -- => 11110111 10111111 10111111 10111111 = F7 BF BF BF
+
+ -- 2 byte
+ encin('\xC2\x80\xDF\xBF', encoding)
+ expect('encout 80,7ff')
+
+ -- 3 byte
+ encin('\xE0\xA0\x80\xEF\xBF\xBD', encoding)
+ expect('encout 800,fffd')
+
+ -- 4 byte
+ encin('\xF0\x90\x80\x80\xF7\xBF\xBF\xBF', encoding)
+ expect('encout 10000,1fffff')
+
+ -- Next up, we check some invalid sequences
+ -- + Early termination (back to low bytes too soon)
+ -- + Early restart (another sequence introduction before the previous one was finished)
+
+ -- Early termination
+ encin('\xC2!', encoding)
+ expect('encout fffd,21')
+
+ encin('\xE0!\xE0\xA0!', encoding)
+ expect('encout fffd,21,fffd,21')
+
+ encin('\xF0!\xF0\x90!\xF0\x90\x80!', encoding)
+ expect('encout fffd,21,fffd,21,fffd,21')
+
+ -- Early restart
+ encin('\xC2\xC2\x90', encoding)
+ expect('encout fffd,90')
+
+ encin('\xE0\xC2\x90\xE0\xA0\xC2\x90', encoding)
+ expect('encout fffd,90,fffd,90')
+
+ encin('\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90', encoding)
+ expect('encout fffd,90,fffd,90,fffd,90')
+
+ -- Test the overlong sequences by giving an overlong encoding of U+0000 and
+ -- an encoding of the highest codepoint still too short
+ --
+ -- Two bytes:
+ -- U+0000 = C0 80
+ -- U+007F = 000 01111111 => 00001 111111 =>
+ -- => 11000001 10111111 => C1 BF
+ --
+ -- Three bytes:
+ -- U+0000 = E0 80 80
+ -- U+07FF = 00000111 11111111 => 0000 011111 111111
+ -- => 11100000 10011111 10111111 = E0 9F BF
+ --
+ -- Four bytes:
+ -- U+0000 = F0 80 80 80
+ -- U+FFFF = 11111111 11111111 => 000 001111 111111 111111
+ -- => 11110000 10001111 10111111 10111111 = F0 8F BF BF
+
+ -- Overlong
+ encin('\xC0\x80\xC1\xBF', encoding)
+ expect('encout fffd,fffd')
+
+ encin('\xE0\x80\x80\xE0\x9F\xBF', encoding)
+ expect('encout fffd,fffd')
+
+ encin('\xF0\x80\x80\x80\xF0\x8F\xBF\xBF', encoding)
+ expect('encout fffd,fffd')
+
+ -- UTF-16 surrogates U+D800 and U+DFFF
+ -- UTF-16 Surrogates
+ encin('\xED\xA0\x80\xED\xBF\xBF', encoding)
+ expect('encout fffd,fffd')
+
+ -- Split write
+ encin('\xC2', encoding)
+ encin('\xA0', encoding)
+ expect('encout a0')
+
+ encin('\xE0', encoding)
+ encin('\xA0\x80', encoding)
+ expect('encout 800')
+ encin('\xE0\xA0', encoding)
+ encin('\x80', encoding)
+ expect('encout 800')
+
+ encin('\xF0', encoding)
+ encin('\x90\x80\x80', encoding)
+ expect('encout 10000')
+ encin('\xF0\x90', encoding)
+ encin('\x80\x80', encoding)
+ expect('encout 10000')
+ encin('\xF0\x90\x80', encoding)
+ encin('\x80', encoding)
+ expect('encout 10000')
+ end)
+
+ itp('10state_putglyph', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true })
+
+ -- Low
+ reset(state, nil)
+ push('ABC', vt)
+ expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,2')
+
+ -- UTF-8 1 char
+ -- U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
+ -- U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
+ reset(state, nil)
+ push('\xC3\x81\xC3\xA9', vt)
+ expect('putglyph c1 1 0,0\nputglyph e9 1 0,1')
+
+ -- UTF-8 split writes
+ reset(state, nil)
+ push('\xC3', vt)
+ push('\x81', vt)
+ expect('putglyph c1 1 0,0')
+
+ -- UTF-8 wide char
+ -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO
+ reset(state, nil)
+ push('\xEF\xBC\x90 ', vt)
+ expect('putglyph ff10 2 0,0\nputglyph 20 1 0,2')
+
+ -- UTF-8 emoji wide char
+ -- U+1F600 = F0 9F 98 80 name: GRINNING FACE
+ reset(state, nil)
+ push('\xF0\x9F\x98\x80 ', vt)
+ expect('putglyph 1f600 2 0,0\nputglyph 20 1 0,2')
+
+ -- UTF-8 combining chars
+ -- U+0301 = CC 81 name: COMBINING ACUTE
+ reset(state, nil)
+ push('e\xCC\x81Z', vt)
+ expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1')
+
+ -- Combining across buffers
+ reset(state, nil)
+ push('e', vt)
+ expect('putglyph 65 1 0,0')
+ push('\xCC\x81Z', vt)
+ expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1')
+
+ -- Spare combining chars get truncated
+ reset(state, nil)
+ push('e' .. string.rep('\xCC\x81', 10), vt)
+ expect('putglyph 65,301,301,301,301,301 1 0,0') -- and nothing more
+
+ reset(state, nil)
+ push('e', vt)
+ expect('putglyph 65 1 0,0')
+ push('\xCC\x81', vt)
+ expect('putglyph 65,301 1 0,0')
+ push('\xCC\x82', vt)
+ expect('putglyph 65,301,302 1 0,0')
+
+ -- DECSCA protected
+ reset(state, nil)
+ push('A\x1b[1"qB\x1b[2"qC', vt)
+ expect('putglyph 41 1 0,0\nputglyph 42 1 0,1 prot\nputglyph 43 1 0,2')
+ end)
+
+ itp('11state_movecursor', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ -- Implicit
+ push('ABC', vt)
+ cursor(0, 3, state)
+
+ -- Backspace
+ push('\b', vt)
+ cursor(0, 2, state)
+ -- Horizontal Tab
+ push('\t', vt)
+ cursor(0, 8, state)
+ -- Carriage Return
+ push('\r', vt)
+ cursor(0, 0, state)
+ -- Linefeed
+ push('\n', vt)
+ cursor(1, 0, state)
+
+ -- Backspace bounded by lefthand edge
+ push('\x1b[4;2H', vt)
+ cursor(3, 1, state)
+ push('\b', vt)
+ cursor(3, 0, state)
+ push('\b', vt)
+ cursor(3, 0, state)
+
+ -- Backspace cancels phantom
+ push('\x1b[4;80H', vt)
+ cursor(3, 79, state)
+ push('X', vt)
+ cursor(3, 79, state)
+ push('\b', vt)
+ cursor(3, 78, state)
+
+ -- HT bounded by righthand edge
+ push('\x1b[1;78H', vt)
+ cursor(0, 77, state)
+ push('\t', vt)
+ cursor(0, 79, state)
+ push('\t', vt)
+ cursor(0, 79, state)
+
+ reset(state, nil)
+
+ -- Index
+ push('ABC\x1bD', vt)
+ cursor(1, 3, state)
+ -- Reverse Index
+ push('\x1bM', vt)
+ cursor(0, 3, state)
+ -- Newline
+ push('\x1bE', vt)
+ cursor(1, 0, state)
+
+ reset(state, nil)
+
+ -- Cursor Forward
+ push('\x1b[B', vt)
+ cursor(1, 0, state)
+ push('\x1b[3B', vt)
+ cursor(4, 0, state)
+ push('\x1b[0B', vt)
+ cursor(5, 0, state)
+
+ -- Cursor Down
+ push('\x1b[C', vt)
+ cursor(5, 1, state)
+ push('\x1b[3C', vt)
+ cursor(5, 4, state)
+ push('\x1b[0C', vt)
+ cursor(5, 5, state)
+
+ -- Cursor Up
+ push('\x1b[A', vt)
+ cursor(4, 5, state)
+ push('\x1b[3A', vt)
+ cursor(1, 5, state)
+ push('\x1b[0A', vt)
+ cursor(0, 5, state)
+
+ -- Cursor Backward
+ push('\x1b[D', vt)
+ cursor(0, 4, state)
+ push('\x1b[3D', vt)
+ cursor(0, 1, state)
+ push('\x1b[0D', vt)
+ cursor(0, 0, state)
+
+ -- Cursor Next Line
+ push(' ', vt)
+ cursor(0, 3, state)
+ push('\x1b[E', vt)
+ cursor(1, 0, state)
+ push(' ', vt)
+ cursor(1, 3, state)
+ push('\x1b[2E', vt)
+ cursor(3, 0, state)
+ push('\x1b[0E', vt)
+ cursor(4, 0, state)
+
+ -- Cursor Previous Line
+ push(' ', vt)
+ cursor(4, 3, state)
+ push('\x1b[F', vt)
+ cursor(3, 0, state)
+ push(' ', vt)
+ cursor(3, 3, state)
+ push('\x1b[2F', vt)
+ cursor(1, 0, state)
+ push('\x1b[0F', vt)
+ cursor(0, 0, state)
+
+ -- Cursor Horizonal Absolute
+ push('\n', vt)
+ cursor(1, 0, state)
+ push('\x1b[20G', vt)
+ cursor(1, 19, state)
+ push('\x1b[G', vt)
+ cursor(1, 0, state)
+
+ -- Cursor Position
+ push('\x1b[10;5H', vt)
+ cursor(9, 4, state)
+ push('\x1b[8H', vt)
+ cursor(7, 0, state)
+ push('\x1b[H', vt)
+ cursor(0, 0, state)
+
+ -- Cursor Position cancels phantom
+ push('\x1b[10;78H', vt)
+ cursor(9, 77, state)
+ push('ABC', vt)
+ cursor(9, 79, state)
+ push('\x1b[10;80H', vt)
+ push('C', vt)
+ cursor(9, 79, state)
+ push('X', vt)
+ cursor(10, 1, state)
+
+ reset(state, nil)
+
+ -- Bounds Checking
+ push('\x1b[A', vt)
+ cursor(0, 0, state)
+ push('\x1b[D', vt)
+ cursor(0, 0, state)
+ push('\x1b[25;80H', vt)
+ cursor(24, 79, state)
+ push('\x1b[B', vt)
+ cursor(24, 79, state)
+ push('\x1b[C', vt)
+ cursor(24, 79, state)
+ push('\x1b[E', vt)
+ cursor(24, 0, state)
+ push('\x1b[H', vt)
+ cursor(0, 0, state)
+ push('\x1b[F', vt)
+ cursor(0, 0, state)
+ push('\x1b[999G', vt)
+ cursor(0, 79, state)
+ push('\x1b[99;99H', vt)
+ cursor(24, 79, state)
+
+ reset(state, nil)
+
+ -- Horizontal Position Absolute
+ push('\x1b[5`', vt)
+ cursor(0, 4, state)
+
+ -- Horizontal Position Relative
+ push('\x1b[3a', vt)
+ cursor(0, 7, state)
+
+ -- Horizontal Position Backward
+ push('\x1b[3j', vt)
+ cursor(0, 4, state)
+
+ -- Horizontal and Vertical Position
+ push('\x1b[3;3f', vt)
+ cursor(2, 2, state)
+
+ -- Vertical Position Absolute
+ push('\x1b[5d', vt)
+ cursor(4, 2, state)
+
+ -- Vertical Position Relative
+ push('\x1b[2e', vt)
+ cursor(6, 2, state)
+
+ -- Vertical Position Backward
+ push('\x1b[2k', vt)
+ cursor(4, 2, state)
+
+ reset(state, nil)
+
+ -- Horizontal Tab
+ push('\t', vt)
+ cursor(0, 8, state)
+ push(' ', vt)
+ cursor(0, 11, state)
+ push('\t', vt)
+ cursor(0, 16, state)
+ push(' ', vt)
+ cursor(0, 23, state)
+ push('\t', vt)
+ cursor(0, 24, state)
+ push(' ', vt)
+ cursor(0, 32, state)
+ push('\t', vt)
+ cursor(0, 40, state)
+
+ -- Cursor Horizontal Tab
+ push('\x1b[I', vt)
+ cursor(0, 48, state)
+ push('\x1b[2I', vt)
+ cursor(0, 64, state)
+
+ -- Cursor Backward Tab
+ push('\x1b[Z', vt)
+ cursor(0, 56, state)
+ push('\x1b[2Z', vt)
+ cursor(0, 40, state)
+ end)
+
+ itp('12state_scroll', function()
+ local vt = init()
+ local state = wantstate(vt, { s = true })
+
+ -- Linefeed
+ push(string.rep('\n', 24), vt)
+ cursor(24, 0, state)
+ push('\n', vt)
+ expect('scrollrect 0..25,0..80 => +1,+0')
+ cursor(24, 0, state)
+
+ reset(state, nil)
+
+ -- Index
+ push('\x1b[25H', vt)
+ push('\x1bD', vt)
+ expect('scrollrect 0..25,0..80 => +1,+0')
+
+ reset(state, nil)
+
+ -- Reverse Index
+ push('\x1bM', vt)
+ expect('scrollrect 0..25,0..80 => -1,+0')
+
+ reset(state, nil)
+
+ -- Linefeed in DECSTBM
+ push('\x1b[1;10r', vt)
+ cursor(0, 0, state)
+ push(string.rep('\n', 9), vt)
+ cursor(9, 0, state)
+ push('\n', vt)
+ expect('scrollrect 0..10,0..80 => +1,+0')
+ cursor(9, 0, state)
+
+ -- Linefeed outside DECSTBM
+ push('\x1b[20H', vt)
+ cursor(19, 0, state)
+ push('\n', vt)
+ cursor(20, 0, state)
+
+ -- Index in DECSTBM
+ push('\x1b[9;10r', vt)
+ push('\x1b[10H', vt)
+ push('\x1bM', vt)
+ cursor(8, 0, state)
+ push('\x1bM', vt)
+ expect('scrollrect 8..10,0..80 => -1,+0')
+
+ -- Reverse Index in DECSTBM
+ push('\x1b[25H', vt)
+ cursor(24, 0, state)
+ push('\n', vt)
+ -- no scrollrect
+ cursor(24, 0, state)
+
+ -- Linefeed in DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[3;10r\x1b[10;40s', vt)
+ push('\x1b[10;10H\n', vt)
+ expect('scrollrect 2..10,9..40 => +1,+0')
+
+ -- IND/RI in DECSTBM+DECSLRM
+ push('\x1bD', vt)
+ expect('scrollrect 2..10,9..40 => +1,+0')
+ push('\x1b[3;10H\x1bM', vt)
+ expect('scrollrect 2..10,9..40 => -1,+0')
+
+ -- DECRQSS on DECSTBM
+ push('\x1bP$qr\x1b\\', vt)
+ expect_output('\x1bP1$r3;10r\x1b\\')
+
+ -- DECRQSS on DECSLRM
+ push('\x1bP$qs\x1b\\', vt)
+ expect_output('\x1bP1$r10;40s\x1b\\')
+
+ -- Setting invalid DECSLRM with !DECVSSM is still rejected
+ push('\x1b[?69l\x1b[;0s\x1b[?69h', vt)
+
+ reset(state, nil)
+
+ -- Scroll Down
+ push('\x1b[S', vt)
+ expect('scrollrect 0..25,0..80 => +1,+0')
+ cursor(0, 0, state)
+ push('\x1b[2S', vt)
+ expect('scrollrect 0..25,0..80 => +2,+0')
+ cursor(0, 0, state)
+ push('\x1b[100S', vt)
+ expect('scrollrect 0..25,0..80 => +25,+0')
+
+ -- Scroll Up
+ push('\x1b[T', vt)
+ expect('scrollrect 0..25,0..80 => -1,+0')
+ cursor(0, 0, state)
+ push('\x1b[2T', vt)
+ expect('scrollrect 0..25,0..80 => -2,+0')
+ cursor(0, 0, state)
+ push('\x1b[100T', vt)
+ expect('scrollrect 0..25,0..80 => -25,+0')
+
+ -- SD/SU in DECSTBM
+ push('\x1b[5;20r', vt)
+ push('\x1b[S', vt)
+ expect('scrollrect 4..20,0..80 => +1,+0')
+ push('\x1b[T', vt)
+ expect('scrollrect 4..20,0..80 => -1,+0')
+
+ reset(state, nil)
+
+ -- SD/SU in DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[3;10r\x1b[10;40s', vt)
+ cursor(0, 0, state)
+ push('\x1b[3;10H', vt)
+ cursor(2, 9, state)
+ push('\x1b[S', vt)
+ expect('scrollrect 2..10,9..40 => +1,+0')
+ push('\x1b[?69l', vt)
+ push('\x1b[S', vt)
+ expect('scrollrect 2..10,0..80 => +1,+0')
+
+ -- Invalid boundaries
+ reset(state, nil)
+
+ push('\x1b[100;105r\x1bD', vt)
+ push('\x1b[5;2r\x1bD', vt)
+
+ reset(state, nil)
+ state = wantstate(vt, { m = true, e = true })
+
+ -- Scroll Down move+erase emulation
+ push('\x1b[S', vt)
+ expect('moverect 1..25,0..80 -> 0..24,0..80\nerase 24..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[2S', vt)
+ expect('moverect 2..25,0..80 -> 0..23,0..80\nerase 23..25,0..80')
+ cursor(0, 0, state)
+
+ -- Scroll Up move+erase emulation
+ push('\x1b[T', vt)
+ expect('moverect 0..24,0..80 -> 1..25,0..80\nerase 0..1,0..80')
+ cursor(0, 0, state)
+ push('\x1b[2T', vt)
+ expect('moverect 0..23,0..80 -> 2..25,0..80\nerase 0..2,0..80')
+ cursor(0, 0, state)
+
+ -- DECSTBM resets cursor position
+ push('\x1b[5;5H', vt)
+ cursor(4, 4, state)
+ push('\x1b[r', vt)
+ cursor(0, 0, state)
+ end)
+
+ itp('13state_edit', function()
+ local vt = init()
+ local state = wantstate(vt, { s = true, e = true, b = true })
+
+ -- ICH
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ACD', vt)
+ push('\x1b[2D', vt)
+ cursor(0, 1, state)
+ push('\x1b[@', vt)
+ expect('scrollrect 0..1,1..80 => +0,-1')
+ cursor(0, 1, state)
+ push('B', vt)
+ cursor(0, 2, state)
+ push('\x1b[3@', vt)
+ expect('scrollrect 0..1,2..80 => +0,-3')
+
+ -- ICH with DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[;50s', vt)
+ push('\x1b[20G\x1b[@', vt)
+ expect('scrollrect 0..1,19..50 => +0,-1')
+
+ -- ICH outside DECSLRM
+ push('\x1b[70G\x1b[@', vt)
+ -- nothing happens
+
+ -- DCH
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABBC', vt)
+ push('\x1b[3D', vt)
+ cursor(0, 1, state)
+ push('\x1b[P', vt)
+ expect('scrollrect 0..1,1..80 => +0,+1')
+ cursor(0, 1, state)
+ push('\x1b[3P', vt)
+ expect('scrollrect 0..1,1..80 => +0,+3')
+ cursor(0, 1, state)
+
+ -- DCH with DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[;50s', vt)
+ push('\x1b[20G\x1b[P', vt)
+ expect('scrollrect 0..1,19..50 => +0,+1')
+
+ -- DCH outside DECSLRM
+ push('\x1b[70G\x1b[P', vt)
+ -- nothing happens
+
+ -- ECH
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABC', vt)
+ push('\x1b[2D', vt)
+ cursor(0, 1, state)
+ push('\x1b[X', vt)
+ expect('erase 0..1,1..2')
+ cursor(0, 1, state)
+ push('\x1b[3X', vt)
+ expect('erase 0..1,1..4')
+ cursor(0, 1, state)
+ -- ECH more columns than there are should be bounded
+ push('\x1b[100X', vt)
+ expect('erase 0..1,1..80')
+
+ -- IL
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('A\r\nC', vt)
+ cursor(1, 1, state)
+ push('\x1b[L', vt)
+ expect('scrollrect 1..25,0..80 => -1,+0')
+ -- TODO(libvterm): ECMA-48 says we should move to line home, but neither xterm nor xfce4-terminal do this
+ cursor(1, 1, state)
+ push('\rB', vt)
+ cursor(1, 1, state)
+ push('\x1b[3L', vt)
+ expect('scrollrect 1..25,0..80 => -3,+0')
+
+ -- IL with DECSTBM
+ push('\x1b[5;15r', vt)
+ push('\x1b[5H\x1b[L', vt)
+ expect('scrollrect 4..15,0..80 => -1,+0')
+
+ -- IL outside DECSTBM
+ push('\x1b[20H\x1b[L', vt)
+ -- nothing happens
+
+ -- IL with DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[10;50s', vt)
+ push('\x1b[5;10H\x1b[L', vt)
+ expect('scrollrect 4..15,9..50 => -1,+0')
+
+ -- DL
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('A\r\nB\r\nB\r\nC', vt)
+ cursor(3, 1, state)
+ push('\x1b[2H', vt)
+ cursor(1, 0, state)
+ push('\x1b[M', vt)
+ expect('scrollrect 1..25,0..80 => +1,+0')
+ cursor(1, 0, state)
+ push('\x1b[3M', vt)
+ expect('scrollrect 1..25,0..80 => +3,+0')
+ cursor(1, 0, state)
+
+ -- DL with DECSTBM
+ push('\x1b[5;15r', vt)
+ push('\x1b[5H\x1b[M', vt)
+ expect('scrollrect 4..15,0..80 => +1,+0')
+
+ -- DL outside DECSTBM
+ push('\x1b[20H\x1b[M', vt)
+ -- nothing happens
+
+ -- DL with DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[10;50s', vt)
+ push('\x1b[5;10H\x1b[M', vt)
+ expect('scrollrect 4..15,9..50 => +1,+0')
+
+ -- DECIC
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ push("\x1b[20G\x1b[5'}", vt)
+ expect('scrollrect 0..25,19..80 => +0,-5')
+
+ -- DECIC with DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[4;20r\x1b[20;60s', vt)
+ push("\x1b[4;20H\x1b[3'}", vt)
+ expect('scrollrect 3..20,19..60 => +0,-3')
+
+ -- DECIC outside DECSLRM
+ push("\x1b[70G\x1b['}", vt)
+ -- nothing happens
+
+ -- DECDC
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ push("\x1b[20G\x1b[5'~", vt)
+ expect('scrollrect 0..25,19..80 => +0,+5')
+
+ -- DECDC with DECSTBM+DECSLRM
+ push('\x1b[?69h', vt)
+ push('\x1b[4;20r\x1b[20;60s', vt)
+ push("\x1b[4;20H\x1b[3'~", vt)
+ expect('scrollrect 3..20,19..60 => +0,+3')
+
+ -- DECDC outside DECSLRM
+ push("\x1b[70G\x1b['~", vt)
+ -- nothing happens
+
+ -- EL 0
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABCDE', vt)
+ push('\x1b[3D', vt)
+ cursor(0, 2, state)
+ push('\x1b[0K', vt)
+ expect('erase 0..1,2..80')
+ cursor(0, 2, state)
+
+ -- EL 1
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABCDE', vt)
+ push('\x1b[3D', vt)
+ cursor(0, 2, state)
+ push('\x1b[1K', vt)
+ expect('erase 0..1,0..3')
+ cursor(0, 2, state)
+
+ -- EL 2
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABCDE', vt)
+ push('\x1b[3D', vt)
+ cursor(0, 2, state)
+ push('\x1b[2K', vt)
+ expect('erase 0..1,0..80')
+ cursor(0, 2, state)
+
+ -- SEL
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[11G', vt)
+ cursor(0, 10, state)
+ push('\x1b[?0K', vt)
+ expect('erase 0..1,10..80 selective')
+ cursor(0, 10, state)
+ push('\x1b[?1K', vt)
+ expect('erase 0..1,0..11 selective')
+ cursor(0, 10, state)
+ push('\x1b[?2K', vt)
+ expect('erase 0..1,0..80 selective')
+ cursor(0, 10, state)
+
+ -- ED 0
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[2;2H', vt)
+ cursor(1, 1, state)
+ push('\x1b[0J', vt)
+ expect('erase 1..2,1..80\nerase 2..25,0..80')
+ cursor(1, 1, state)
+
+ -- ED 1
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[2;2H', vt)
+ cursor(1, 1, state)
+ push('\x1b[1J', vt)
+ expect('erase 0..1,0..80\nerase 1..2,0..2')
+ cursor(1, 1, state)
+
+ -- ED 2
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[2;2H', vt)
+ cursor(1, 1, state)
+ push('\x1b[2J', vt)
+ expect('erase 0..25,0..80')
+ cursor(1, 1, state)
+
+ -- ED 3
+ push('\x1b[3J', vt)
+ expect('sb_clear')
+
+ -- SED
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ push('\x1b[5;5H', vt)
+ cursor(4, 4, state)
+ push('\x1b[?0J', vt)
+ expect('erase 4..5,4..80 selective\nerase 5..25,0..80 selective')
+ cursor(4, 4, state)
+ push('\x1b[?1J', vt)
+ expect('erase 0..4,0..80 selective\nerase 4..5,0..5 selective')
+ cursor(4, 4, state)
+ push('\x1b[?2J', vt)
+ expect('erase 0..25,0..80 selective')
+ cursor(4, 4, state)
+
+ -- DECRQSS on DECSCA
+ push('\x1b[2"q', vt)
+ push('\x1bP$q"q\x1b\\', vt)
+ expect_output('\x1bP1$r2"q\x1b\\')
+
+ state = wantstate(vt, { m = true, e = true, b = true })
+ expect('erase 0..25,0..80') -- TODO(dundargoc): strange, this should not be needed according to the original code
+
+ -- ICH move+erase emuation
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ACD', vt)
+ push('\x1b[2D', vt)
+ cursor(0, 1, state)
+ push('\x1b[@', vt)
+ expect('moverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2')
+ cursor(0, 1, state)
+ push('B', vt)
+ cursor(0, 2, state)
+ push('\x1b[3@', vt)
+ expect('moverect 0..1,2..77 -> 0..1,5..80\nerase 0..1,2..5')
+
+ -- DCH move+erase emulation
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('ABBC', vt)
+ push('\x1b[3D', vt)
+ cursor(0, 1, state)
+ push('\x1b[P', vt)
+ expect('moverect 0..1,2..80 -> 0..1,1..79\nerase 0..1,79..80')
+ cursor(0, 1, state)
+ push('\x1b[3P', vt)
+ expect('moverect 0..1,4..80 -> 0..1,1..77\nerase 0..1,77..80')
+ cursor(0, 1, state)
+ end)
+
+ itp('14state_encoding', function()
+ local vt = init()
+ vterm.vterm_set_utf8(vt, false)
+ local state = wantstate(vt, { g = true })
+
+ -- Default
+ reset(state, nil)
+ push('#', vt)
+ expect('putglyph 23 1 0,0')
+
+ -- Designate G0=UK
+ reset(state, nil)
+ push('\x1b(A', vt)
+ push('#', vt)
+ expect('putglyph a3 1 0,0')
+
+ -- Designate G0=DEC drawing
+ reset(state, nil)
+ push('\x1b(0', vt)
+ push('a', vt)
+ expect('putglyph 2592 1 0,0')
+
+ -- Designate G1 + LS1
+ reset(state, nil)
+ push('\x1b)0', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,0')
+ push('\x0e', vt)
+ push('a', vt)
+ expect('putglyph 2592 1 0,1')
+ -- LS0
+ push('\x0f', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,2')
+
+ -- Designate G2 + LS2
+ push('\x1b*0', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,3')
+ push('\x1bn', vt)
+ push('a', vt)
+ expect('putglyph 2592 1 0,4')
+ push('\x0f', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,5')
+
+ -- Designate G3 + LS3
+ push('\x1b+0', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,6')
+ push('\x1bo', vt)
+ push('a', vt)
+ expect('putglyph 2592 1 0,7')
+ push('\x0f', vt)
+ push('a', vt)
+ expect('putglyph 61 1 0,8')
+
+ -- SS2
+ push('a\x8eaa', vt)
+ expect('putglyph 61 1 0,9\nputglyph 2592 1 0,10\nputglyph 61 1 0,11')
+
+ -- SS3
+ push('a\x8faa', vt)
+ expect('putglyph 61 1 0,12\nputglyph 2592 1 0,13\nputglyph 61 1 0,14')
+
+ -- LS1R
+ reset(state, nil)
+ push('\x1b~', vt)
+ push('\xe1', vt)
+ expect('putglyph 61 1 0,0')
+ push('\x1b)0', vt)
+ push('\xe1', vt)
+ expect('putglyph 2592 1 0,1')
+
+ -- LS2R
+ reset(state, nil)
+ push('\x1b}', vt)
+ push('\xe1', vt)
+ expect('putglyph 61 1 0,0')
+ push('\x1b*0', vt)
+ push('\xe1', vt)
+ expect('putglyph 2592 1 0,1')
+
+ -- LS3R
+ reset(state, nil)
+ push('\x1b|', vt)
+ push('\xe1', vt)
+ expect('putglyph 61 1 0,0')
+ push('\x1b+0', vt)
+ push('\xe1', vt)
+ expect('putglyph 2592 1 0,1')
+
+ vterm.vterm_set_utf8(vt, true)
+ -- U+0108 == c4 88
+ reset(state, nil)
+ push('\x1b(B', vt)
+ push('AB\xc4\x88D', vt)
+ expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 108 1 0,2\nputglyph 44 1 0,3')
+ end)
+
+ itp('15state_mode', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true, m = true, e = true })
+
+ -- Insert/Replace Mode
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('AC\x1b[DB', vt)
+ expect('putglyph 41 1 0,0\nputglyph 43 1 0,1\nputglyph 42 1 0,1')
+ push('\x1b[4h', vt)
+ push('\x1b[G', vt)
+ push('AC\x1b[DB', vt)
+ expect(
+ 'moverect 0..1,0..79 -> 0..1,1..80\nerase 0..1,0..1\nputglyph 41 1 0,0\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 43 1 0,1\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 42 1 0,1'
+ )
+
+ -- Insert mode only happens once for UTF-8 combining
+ push('e', vt)
+ expect('moverect 0..1,2..79 -> 0..1,3..80\nerase 0..1,2..3\nputglyph 65 1 0,2')
+ push('\xCC\x81', vt)
+ expect('putglyph 65,301 1 0,2')
+
+ -- Newline/Linefeed mode
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[5G\n', vt)
+ cursor(1, 4, state)
+ push('\x1b[20h', vt)
+ push('\x1b[5G\n', vt)
+ cursor(2, 0, state)
+
+ -- DEC origin mode
+ reset(state, nil)
+ expect('erase 0..25,0..80')
+ cursor(0, 0, state)
+ push('\x1b[5;15r', vt)
+ push('\x1b[H', vt)
+ cursor(0, 0, state)
+ push('\x1b[3;3H', vt)
+ cursor(2, 2, state)
+ push('\x1b[?6h', vt)
+ push('\x1b[H', vt)
+ cursor(4, 0, state)
+ push('\x1b[3;3H', vt)
+ cursor(6, 2, state)
+
+ -- DECRQM on DECOM
+ push('\x1b[?6h', vt)
+ push('\x1b[?6$p', vt)
+ expect_output('\x1b[?6;1$y')
+ push('\x1b[?6l', vt)
+ push('\x1b[?6$p', vt)
+ expect_output('\x1b[?6;2$y')
+
+ -- Origin mode with DECSLRM
+ push('\x1b[?6h', vt)
+ push('\x1b[?69h', vt)
+ push('\x1b[20;60s', vt)
+ push('\x1b[H', vt)
+ cursor(4, 19, state)
+
+ push('\x1b[?69l', vt)
+
+ -- Origin mode bounds cursor to scrolling region
+ push('\x1b[H', vt)
+ push('\x1b[10A', vt)
+ cursor(4, 0, state)
+ push('\x1b[20B', vt)
+ cursor(14, 0, state)
+
+ -- Origin mode without scroll region
+ push('\x1b[?6l', vt)
+ push('\x1b[r\x1b[?6h', vt)
+ cursor(0, 0, state)
+ end)
+
+ itp('16state_resize', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true })
+
+ -- Placement
+ reset(state, nil)
+ push('AB\x1b[79GCDE', vt)
+ expect(
+ 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 1,0'
+ )
+
+ -- Resize
+ reset(state, nil)
+ resize(27, 85, vt)
+ push('AB\x1b[79GCDE', vt)
+ expect(
+ 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 0,80'
+ )
+ cursor(0, 81, state)
+
+ -- Resize without reset
+ resize(28, 90, vt)
+ cursor(0, 81, state)
+ push('FGHI', vt)
+ expect('putglyph 46 1 0,81\nputglyph 47 1 0,82\nputglyph 48 1 0,83\nputglyph 49 1 0,84')
+ cursor(0, 85, state)
+
+ -- Resize shrink moves cursor
+ resize(25, 80, vt)
+ cursor(0, 79, state)
+
+ -- Resize grow doesn't cancel phantom
+ reset(state, nil)
+ push('\x1b[79GAB', vt)
+ expect('putglyph 41 1 0,78\nputglyph 42 1 0,79')
+ cursor(0, 79, state)
+ resize(30, 100, vt)
+ cursor(0, 80, state)
+ push('C', vt)
+ expect('putglyph 43 1 0,80')
+ cursor(0, 81, state)
+ end)
+
+ itp('17state_mouse', function()
+ local vt = init()
+ local state = wantstate(vt, { p = true })
+
+ -- DECRQM on with mouse off
+ push('\x1b[?1000$p', vt)
+ expect_output('\x1b[?1000;2$y')
+ push('\x1b[?1002$p', vt)
+ expect_output('\x1b[?1002;2$y')
+ push('\x1b[?1003$p', vt)
+ expect_output('\x1b[?1003;2$y')
+
+ -- Mouse in simple button report mode
+ reset(state, nil)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ push('\x1b[?1000h', vt)
+ expect('settermprop 8 1')
+
+ -- Press 1
+ mousemove(0, 0, vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\x21\x21')
+
+ -- Release 1
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[M\x23\x21\x21')
+
+ -- Ctrl-Press 1
+ mousebtn('d', 1, vt, { C = true })
+ expect_output('\x1b[M\x30\x21\x21')
+ mousebtn('u', 1, vt, { C = true })
+ expect_output('\x1b[M\x33\x21\x21')
+
+ -- Button 2
+ mousebtn('d', 2, vt)
+ expect_output('\x1b[M\x21\x21\x21')
+ mousebtn('u', 2, vt)
+ expect_output('\x1b[M\x23\x21\x21')
+
+ -- Position
+ mousemove(10, 20, vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\x35\x2b')
+
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[M\x23\x35\x2b')
+ mousemove(10, 21, vt)
+ -- no output
+
+ -- Wheel events
+ mousebtn('d', 4, vt)
+ expect_output('\x1b[M\x60\x36\x2b')
+ mousebtn('d', 4, vt)
+ expect_output('\x1b[M\x60\x36\x2b')
+ mousebtn('d', 5, vt)
+ expect_output('\x1b[M\x61\x36\x2b')
+ mousebtn('d', 6, vt)
+ expect_output('\x1b[M\x62\x36\x2b')
+ mousebtn('d', 7, vt)
+ expect_output('\x1b[M\x63\x36\x2b')
+
+ -- DECRQM on mouse button mode
+ push('\x1b[?1000$p', vt)
+ expect_output('\x1b[?1000;1$y')
+ push('\x1b[?1002$p', vt)
+ expect_output('\x1b[?1002;2$y')
+ push('\x1b[?1003$p', vt)
+ expect_output('\x1b[?1003;2$y')
+
+ -- Drag events
+ reset(state, nil)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ push('\x1b[?1002h', vt)
+ expect('settermprop 8 2')
+
+ mousemove(5, 5, vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\x26\x26')
+ mousemove(5, 6, vt)
+ expect_output('\x1b[M\x40\x27\x26')
+ mousemove(6, 6, vt)
+ expect_output('\x1b[M\x40\x27\x27')
+ mousemove(6, 6, vt)
+ -- no output
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[M\x23\x27\x27')
+ mousemove(6, 7, vt)
+ -- no output
+
+ -- DECRQM on mouse drag mode
+ push('\x1b[?1000$p', vt)
+ expect_output('\x1b[?1000;2$y')
+ push('\x1b[?1002$p', vt)
+ expect_output('\x1b[?1002;1$y')
+ push('\x1b[?1003$p', vt)
+ expect_output('\x1b[?1003;2$y')
+
+ -- Non-drag motion events
+ push('\x1b[?1003h', vt)
+ expect('settermprop 8 3')
+
+ mousemove(6, 8, vt)
+ expect_output('\x1b[M\x43\x29\x27')
+
+ -- DECRQM on mouse motion mode
+ push('\x1b[?1000$p', vt)
+ expect_output('\x1b[?1000;2$y')
+ push('\x1b[?1002$p', vt)
+ expect_output('\x1b[?1002;2$y')
+ push('\x1b[?1003$p', vt)
+ expect_output('\x1b[?1003;1$y')
+
+ -- Bounds checking
+ mousemove(300, 300, vt)
+ expect_output('\x1b[M\x43\xff\xff')
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\xff\xff')
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[M\x23\xff\xff')
+
+ -- DECRQM on standard encoding mode
+ push('\x1b[?1005$p', vt)
+ expect_output('\x1b[?1005;2$y')
+ push('\x1b[?1006$p', vt)
+ expect_output('\x1b[?1006;2$y')
+ push('\x1b[?1015$p', vt)
+ expect_output('\x1b[?1015;2$y')
+
+ -- UTF-8 extended encoding mode
+ -- 300 + 32 + 1 = 333 = U+014d = \xc5\x8d
+ push('\x1b[?1005h', vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\xc5\x8d\xc5\x8d')
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[M\x23\xc5\x8d\xc5\x8d')
+
+ -- DECRQM on UTF-8 extended encoding mode
+ push('\x1b[?1005$p', vt)
+ expect_output('\x1b[?1005;1$y')
+ push('\x1b[?1006$p', vt)
+ expect_output('\x1b[?1006;2$y')
+ push('\x1b[?1015$p', vt)
+ expect_output('\x1b[?1015;2$y')
+
+ -- SGR extended encoding mode
+ push('\x1b[?1006h', vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[<0;301;301M')
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[<0;301;301m')
+
+ -- DECRQM on SGR extended encoding mode
+ push('\x1b[?1005$p', vt)
+ expect_output('\x1b[?1005;2$y')
+ push('\x1b[?1006$p', vt)
+ expect_output('\x1b[?1006;1$y')
+ push('\x1b[?1015$p', vt)
+ expect_output('\x1b[?1015;2$y')
+
+ -- rxvt extended encoding mode
+ push('\x1b[?1015h', vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[0;301;301M')
+ mousebtn('u', 1, vt)
+ expect_output('\x1b[3;301;301M')
+
+ -- DECRQM on rxvt extended encoding mode
+ push('\x1b[?1005$p', vt)
+ expect_output('\x1b[?1005;2$y')
+ push('\x1b[?1006$p', vt)
+ expect_output('\x1b[?1006;2$y')
+ push('\x1b[?1015$p', vt)
+ expect_output('\x1b[?1015;1$y')
+
+ -- Mouse disabled reports nothing
+ reset(state, nil)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ mousemove(0, 0, vt)
+ mousebtn('d', 1, vt)
+ mousebtn('u', 1, vt)
+
+ -- DECSM can set multiple modes at once
+ push('\x1b[?1002;1006h', vt)
+ expect('settermprop 8 2')
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[<0;1;1M')
+ end)
+
+ itp('18state_termprops', function()
+ local vt = init()
+ local state = wantstate(vt, { p = true })
+
+ reset(state, nil)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+
+ -- Cursor visibility
+ push('\x1b[?25h', vt)
+ expect('settermprop 1 true')
+ push('\x1b[?25$p', vt)
+ expect_output('\x1b[?25;1$y')
+ push('\x1b[?25l', vt)
+ expect('settermprop 1 false')
+ push('\x1b[?25$p', vt)
+ expect_output('\x1b[?25;2$y')
+
+ -- Cursor blink
+ push('\x1b[?12h', vt)
+ expect('settermprop 2 true')
+ push('\x1b[?12$p', vt)
+ expect_output('\x1b[?12;1$y')
+ push('\x1b[?12l', vt)
+ expect('settermprop 2 false')
+ push('\x1b[?12$p', vt)
+ expect_output('\x1b[?12;2$y')
+
+ -- Cursor shape
+ push('\x1b[3 q', vt)
+ expect('settermprop 2 true\nsettermprop 7 2')
+
+ -- Title
+ push('\x1b]2;Here is my title\a', vt)
+ expect('settermprop 4 ["Here is my title"]')
+
+ -- Title split write
+ push('\x1b]2;Here is', vt)
+ expect('settermprop 4 ["Here is"')
+ push(' another title\a', vt)
+ expect('settermprop 4 " another title"]')
+ end)
+
+ itp('20state_wrapping', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true, m = true })
+
+ -- 79th Column
+ push('\x1b[75G', vt)
+ push(string.rep('A', 5), vt)
+ expect(
+ 'putglyph 41 1 0,74\nputglyph 41 1 0,75\nputglyph 41 1 0,76\nputglyph 41 1 0,77\nputglyph 41 1 0,78'
+ )
+ cursor(0, 79, state)
+
+ -- 80th Column Phantom
+ push('A', vt)
+ expect('putglyph 41 1 0,79')
+ cursor(0, 79, state)
+
+ -- Line Wraparound
+ push('B', vt)
+ expect('putglyph 42 1 1,0')
+ cursor(1, 1, state)
+
+ -- Line Wraparound during combined write
+ push('\x1b[78G', vt)
+ push('BBBCC', vt)
+ expect(
+ 'putglyph 42 1 1,77\nputglyph 42 1 1,78\nputglyph 42 1 1,79\nputglyph 43 1 2,0\nputglyph 43 1 2,1'
+ )
+ cursor(2, 2, state)
+
+ -- DEC Auto Wrap Mode
+ reset(state, nil)
+ push('\x1b[?7l', vt)
+ push('\x1b[75G', vt)
+ push(string.rep('D', 6), vt)
+ expect(
+ 'putglyph 44 1 0,74\nputglyph 44 1 0,75\nputglyph 44 1 0,76\nputglyph 44 1 0,77\nputglyph 44 1 0,78\nputglyph 44 1 0,79'
+ )
+ cursor(0, 79, state)
+ push('D', vt)
+ expect('putglyph 44 1 0,79')
+ cursor(0, 79, state)
+ push('\x1b[?7h', vt)
+
+ -- 80th column causes linefeed on wraparound
+ push('\x1b[25;78HABC', vt)
+ expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79')
+ cursor(24, 79, state)
+ push('D', vt)
+ expect('moverect 1..25,0..80 -> 0..24,0..80\nputglyph 44 1 24,0')
+
+ -- 80th column phantom linefeed phantom cancelled by explicit cursor move
+ push('\x1b[25;78HABC', vt)
+ expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79')
+ cursor(24, 79, state)
+ push('\x1b[25;1HD', vt)
+ expect('putglyph 44 1 24,0')
+ end)
+
+ itp('21state_tabstops', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true })
+
+ -- Initial
+ reset(state, nil)
+ push('\tX', vt)
+ expect('putglyph 58 1 0,8')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,16')
+ cursor(0, 17, state)
+
+ -- HTS
+ push('\x1b[5G\x1bH', vt)
+ push('\x1b[G\tX', vt)
+ expect('putglyph 58 1 0,4')
+ cursor(0, 5, state)
+
+ -- TBC 0
+ push('\x1b[9G\x1b[g', vt)
+ push('\x1b[G\tX\tX', vt)
+ expect('putglyph 58 1 0,4\nputglyph 58 1 0,16')
+ cursor(0, 17, state)
+
+ -- TBC 3
+ push('\x1b[3g\x1b[50G\x1bH\x1b[G', vt)
+ cursor(0, 0, state)
+ push('\tX', vt)
+ expect('putglyph 58 1 0,49')
+ cursor(0, 50, state)
+
+ -- Tabstops after resize
+ reset(state, nil)
+ resize(30, 100, vt)
+ -- Should be 100/8 = 12 tabstops
+ push('\tX', vt)
+ expect('putglyph 58 1 0,8')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,16')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,24')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,32')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,40')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,48')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,56')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,64')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,72')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,80')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,88')
+ push('\tX', vt)
+ expect('putglyph 58 1 0,96')
+ cursor(0, 97, state)
+ end)
+
+ itp('22state_save', function()
+ local vt = init()
+ local state = wantstate(vt, { p = true })
+
+ reset(state, nil)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+
+ -- Set up state
+ push('\x1b[2;2H', vt)
+ cursor(1, 1, state)
+ push('\x1b[1m', vt)
+ pen('bold', true, state)
+
+ -- Save
+ push('\x1b[?1048h', vt)
+
+ -- Change state
+ push('\x1b[5;5H', vt)
+ cursor(4, 4, state)
+ push('\x1b[4 q', vt)
+ expect('settermprop 2 false\nsettermprop 7 2')
+ push('\x1b[22;4m', vt)
+ pen('bold', false, state)
+ pen('underline', 1, state)
+
+ -- Restore
+ push('\x1b[?1048l', vt)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ cursor(1, 1, state)
+ pen('bold', true, state)
+ pen('underline', 0, state)
+
+ -- Save/restore using DECSC/DECRC
+ push('\x1b[2;2H\x1b7', vt)
+ cursor(1, 1, state)
+
+ push('\x1b[5;5H', vt)
+ cursor(4, 4, state)
+ push('\x1b8', vt)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ cursor(1, 1, state)
+
+ -- Save twice, restore twice happens on both edge transitions
+ push('\x1b[2;10H\x1b[?1048h\x1b[6;10H\x1b[?1048h', vt)
+ push('\x1b[H', vt)
+ cursor(0, 0, state)
+ push('\x1b[?1048l', vt)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ cursor(5, 9, state)
+ push('\x1b[H', vt)
+ cursor(0, 0, state)
+ push('\x1b[?1048l', vt)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+ cursor(5, 9, state)
+ end)
+
+ itp('25state_input', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ -- Unmodified ASCII
+ inchar(41, vt)
+ expect('output 29')
+ inchar(61, vt)
+ expect('output 3d')
+
+ -- Ctrl modifier on ASCII letters
+ inchar(41, vt, { C = true })
+ expect('output 1b,5b,34,31,3b,35,75')
+ inchar(61, vt, { C = true })
+ expect('output 1b,5b,36,31,3b,35,75')
+
+ -- Alt modifier on ASCII letters
+ inchar(41, vt, { A = true })
+ expect('output 1b,29')
+ inchar(61, vt, { A = true })
+ expect('output 1b,3d')
+
+ -- Ctrl-Alt modifier on ASCII letters
+ inchar(41, vt, { C = true, A = true })
+ expect('output 1b,5b,34,31,3b,37,75')
+ inchar(61, vt, { C = true, A = true })
+ expect('output 1b,5b,36,31,3b,37,75')
+
+ -- Special handling of Ctrl-I
+ inchar(49, vt)
+ expect('output 31')
+ inchar(69, vt)
+ expect('output 45')
+ inchar(49, vt, { C = true })
+ expect('output 1b,5b,34,39,3b,35,75')
+ inchar(69, vt, { C = true })
+ expect('output 1b,5b,36,39,3b,35,75')
+ inchar(49, vt, { A = true })
+ expect('output 1b,31')
+ inchar(69, vt, { A = true })
+ expect('output 1b,45')
+ inchar(49, vt, { A = true, C = true })
+ expect('output 1b,5b,34,39,3b,37,75')
+ inchar(69, vt, { A = true, C = true })
+ expect('output 1b,5b,36,39,3b,37,75')
+
+ -- Special handling of Space
+ inchar(20, vt)
+ expect('output 14')
+ inchar(20, vt, { S = true })
+ expect('output 14')
+ inchar(20, vt, { C = true })
+ expect('output 1b,5b,32,30,3b,35,75')
+ inchar(20, vt, { C = true, S = true })
+ expect('output 1b,5b,32,30,3b,35,75')
+ inchar(20, vt, { A = true })
+ expect('output 1b,14')
+ inchar(20, vt, { S = true, A = true })
+ expect('output 1b,14')
+ inchar(20, vt, { C = true, A = true })
+ expect('output 1b,5b,32,30,3b,37,75')
+ inchar(20, vt, { S = true, C = true, A = true })
+ expect('output 1b,5b,32,30,3b,37,75')
+
+ -- Cursor keys in reset (cursor) mode
+ inkey('up', vt)
+ expect_output('\x1b[A')
+ inkey('up', vt, { S = true })
+ expect_output('\x1b[1;2A')
+ inkey('up', vt, { C = true })
+ expect_output('\x1b[1;5A')
+ inkey('up', vt, { S = true, C = true })
+ expect_output('\x1b[1;6A')
+ inkey('up', vt, { A = true })
+ expect_output('\x1b[1;3A')
+ inkey('up', vt, { S = true, A = true })
+ expect_output('\x1b[1;4A')
+ inkey('up', vt, { C = true, A = true })
+ expect_output('\x1b[1;7A')
+ inkey('up', vt, { S = true, C = true, A = true })
+ expect_output('\x1b[1;8A')
+
+ -- Cursor keys in application mode
+ push('\x1b[?1h', vt)
+ -- Plain "Up" should be SS3 A now
+ inkey('up', vt)
+ expect_output('\x1bOA')
+ -- Modified keys should still use CSI
+ inkey('up', vt, { S = true })
+ expect_output('\x1b[1;2A')
+ inkey('up', vt, { C = true })
+ expect_output('\x1b[1;5A')
+
+ -- Shift-Tab should be different
+ inkey('tab', vt)
+ expect_output('\x09')
+ inkey('tab', vt, { S = true })
+ expect_output('\x1b[Z')
+ inkey('tab', vt, { C = true })
+ expect_output('\x1b[9;5u')
+ inkey('tab', vt, { A = true })
+ expect_output('\x1b\x09')
+ inkey('tab', vt, { C = true, A = true })
+ expect_output('\x1b[9;7u')
+
+ -- Enter in linefeed mode
+ inkey('enter', vt)
+ expect_output('\x0d')
+
+ -- Enter in newline mode
+ push('\x1b[20h', vt)
+ inkey('enter', vt)
+ expect_output('\x0d\x0a')
+
+ -- Unmodified F1 is SS3 P
+ inkey('f1', vt)
+ expect_output('\x1bOP')
+
+ -- Modified F1 is CSI P
+ inkey('f1', vt, { S = true })
+ expect_output('\x1b[1;2P')
+ inkey('f1', vt, { A = true })
+ expect_output('\x1b[1;3P')
+ inkey('f1', vt, { C = true })
+ expect_output('\x1b[1;5P')
+
+ -- Keypad in DECKPNM
+ inkey('kp0', vt)
+ expect_output('0')
+
+ -- Keypad in DECKPAM
+ push('\x1b=', vt)
+ inkey('kp0', vt)
+ expect_output('\x1bOp')
+
+ -- Bracketed paste mode off
+ vterm.vterm_keyboard_start_paste(vt)
+ vterm.vterm_keyboard_end_paste(vt)
+
+ -- Bracketed paste mode on
+ push('\x1b[?2004h', vt)
+ vterm.vterm_keyboard_start_paste(vt)
+ expect_output('\x1b[200~')
+ vterm.vterm_keyboard_end_paste(vt)
+ expect_output('\x1b[201~')
+
+ -- Focus reporting disabled
+ vterm.vterm_state_focus_in(state)
+ vterm.vterm_state_focus_out(state)
+
+ -- Focus reporting enabled
+ state = wantstate(vt, { p = true })
+ push('\x1b[?1004h', vt)
+ expect('settermprop 9 true')
+ vterm.vterm_state_focus_in(state)
+ expect_output('\x1b[I')
+ vterm.vterm_state_focus_out(state)
+ expect_output('\x1b[O')
+ end)
+
+ itp('26state_query', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ -- DA
+ reset(state, nil)
+ push('\x1b[c', vt)
+ expect_output('\x1b[?1;2c')
+
+ -- XTVERSION
+ reset(state, nil)
+ push('\x1b[>q', vt)
+ expect_output('\x1bP>|libvterm(0.3)\x1b\\')
+
+ -- DSR
+ reset(state, nil)
+ push('\x1b[5n', vt)
+ expect_output('\x1b[0n')
+
+ -- CPR
+ push('\x1b[6n', vt)
+ expect_output('\x1b[1;1R')
+ push('\x1b[10;10H\x1b[6n', vt)
+ expect_output('\x1b[10;10R')
+
+ -- DECCPR
+ push('\x1b[?6n', vt)
+ expect_output('\x1b[?10;10R')
+
+ -- DECRQSS on DECSCUSR
+ push('\x1b[3 q', vt)
+ push('\x1bP$q q\x1b\\', vt)
+ expect_output('\x1bP1$r3 q\x1b\\')
+
+ -- DECRQSS on SGR
+ push('\x1b[1;5;7m', vt)
+ push('\x1bP$qm\x1b\\', vt)
+ expect_output('\x1bP1$r1;5;7m\x1b\\')
+
+ -- DECRQSS on SGR ANSI colours
+ push('\x1b[0;31;42m', vt)
+ push('\x1bP$qm\x1b\\', vt)
+ expect_output('\x1bP1$r31;42m\x1b\\')
+
+ -- DECRQSS on SGR ANSI hi-bright colours
+ push('\x1b[0;93;104m', vt)
+ push('\x1bP$qm\x1b\\', vt)
+ expect_output('\x1bP1$r93;104m\x1b\\')
+
+ -- DECRQSS on SGR 256-palette colours
+ push('\x1b[0;38:5:56;48:5:78m', vt)
+ push('\x1bP$qm\x1b\\', vt)
+ expect_output('\x1bP1$r38:5:56;48:5:78m\x1b\\')
+
+ -- DECRQSS on SGR RGB8 colours
+ push('\x1b[0;38:2:24:68:112;48:2:13:57:101m', vt)
+ push('\x1bP$qm\x1b\\', vt)
+ expect_output('\x1bP1$r38:2:24:68:112;48:2:13:57:101m\x1b\\')
+
+ -- S8C1T on DSR
+ push('\x1b G', vt)
+ push('\x1b[5n', vt)
+ expect_output('\x9b0n')
+ push('\x1b F', vt)
+ end)
+
+ itp('27state_reset', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ reset(state, nil)
+
+ -- RIS homes cursor
+ push('\x1b[5;5H', vt)
+ cursor(4, 4, state)
+ state = wantstate(vt, { m = true })
+ push('\x1bc', vt)
+ cursor(0, 0, state)
+ wantstate(vt)
+
+ -- RIS cancels scrolling region
+ push('\x1b[5;10r', vt)
+ wantstate(vt, { s = true })
+ push('\x1bc\x1b[25H\n', vt)
+ expect('scrollrect 0..25,0..80 => +1,+0')
+ wantstate(vt)
+
+ -- RIS erases screen
+ push('ABCDE', vt)
+ state = wantstate(vt, { e = true })
+ push('\x1bc', vt)
+ expect('erase 0..25,0..80')
+ wantstate(vt)
+
+ -- RIS clears tabstops
+ push('\x1b[5G\x1bH\x1b[G\t', vt)
+ cursor(0, 4, state)
+ push('\x1bc\t', vt)
+ cursor(0, 8, state)
+ end)
+
+ itp('28state_dbl_wh', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true })
+
+ -- Single Width, Single Height
+ reset(state, nil)
+ push('\x1b#5', vt)
+ push('Hello', vt)
+ expect(
+ 'putglyph 48 1 0,0\nputglyph 65 1 0,1\nputglyph 6c 1 0,2\nputglyph 6c 1 0,3\nputglyph 6f 1 0,4'
+ )
+
+ -- Double Width, Single Height
+ reset(state, nil)
+ push('\x1b#6', vt)
+ push('Hello', vt)
+ expect(
+ 'putglyph 48 1 0,0 dwl\nputglyph 65 1 0,1 dwl\nputglyph 6c 1 0,2 dwl\nputglyph 6c 1 0,3 dwl\nputglyph 6f 1 0,4 dwl'
+ )
+ cursor(0, 5, state)
+ push('\x1b[40GAB', vt)
+ expect('putglyph 41 1 0,39 dwl\nputglyph 42 1 1,0')
+ cursor(1, 1, state)
+
+ -- Double Height
+ reset(state, nil)
+ push('\x1b#3', vt)
+ push('Hello', vt)
+ expect(
+ 'putglyph 48 1 0,0 dwl dhl-top\nputglyph 65 1 0,1 dwl dhl-top\nputglyph 6c 1 0,2 dwl dhl-top\nputglyph 6c 1 0,3 dwl dhl-top\nputglyph 6f 1 0,4 dwl dhl-top'
+ )
+ cursor(0, 5, state)
+ push('\r\n\x1b#4', vt)
+ push('Hello', vt)
+ expect(
+ 'putglyph 48 1 1,0 dwl dhl-bottom\nputglyph 65 1 1,1 dwl dhl-bottom\nputglyph 6c 1 1,2 dwl dhl-bottom\nputglyph 6c 1 1,3 dwl dhl-bottom\nputglyph 6f 1 1,4 dwl dhl-bottom'
+ )
+ cursor(1, 5, state)
+
+ -- Double Width scrolling
+ reset(state, nil)
+ push('\x1b[20H\x1b#6ABC', vt)
+ expect('putglyph 41 1 19,0 dwl\nputglyph 42 1 19,1 dwl\nputglyph 43 1 19,2 dwl')
+ push('\x1b[25H\n', vt)
+ push('\x1b[19;4HDE', vt)
+ expect('putglyph 44 1 18,3 dwl\nputglyph 45 1 18,4 dwl')
+ push('\x1b[H\x1bM', vt)
+ push('\x1b[20;6HFG', vt)
+ expect('putglyph 46 1 19,5 dwl\nputglyph 47 1 19,6 dwl')
+ end)
+
+ itp('29state_fallback', function()
+ local vt = init()
+ local state = wantstate(vt, { f = true })
+ reset(state, nil)
+
+ -- Unrecognised control
+ push('\x03', vt)
+ expect('control 03')
+
+ -- Unrecognised CSI
+ push('\x1b[?15;2z', vt)
+ expect('csi 7a L=3f 15,2')
+
+ -- Unrecognised OSC
+ push('\x1b]27;Something\x1b\\', vt)
+ expect('osc [27;Something]')
+
+ -- Unrecognised DCS
+ push('\x1bPz123\x1b\\', vt)
+ expect('dcs [z123]')
+
+ -- Unrecognised APC
+ push('\x1b_z123\x1b\\', vt)
+ expect('apc [z123]')
+
+ -- Unrecognised PM
+ push('\x1b^z123\x1b\\', vt)
+ expect('pm [z123]')
+
+ -- Unrecognised SOS
+ push('\x1bXz123\x1b\\', vt)
+ expect('sos [z123]')
+ end)
+
+ itp('30state_pen', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ -- Reset
+ push('\x1b[m', vt)
+ pen('bold', false, state)
+ pen('underline', 0, state)
+ pen('italic', false, state)
+ pen('blink', false, state)
+ pen('reverse', false, state)
+ pen('font', 0, state)
+ -- TODO(dundargoc): fix
+ -- ?pen foreground = rgb(240,240,240,is_default_fg)
+ -- ?pen background = rgb(0,0,0,is_default_bg)
+
+ -- Bold
+ push('\x1b[1m', vt)
+ pen('bold', true, state)
+ push('\x1b[22m', vt)
+ pen('bold', false, state)
+ push('\x1b[1m\x1b[m', vt)
+ pen('bold', false, state)
+
+ -- Underline
+ push('\x1b[4m', vt)
+ pen('underline', 1, state)
+ push('\x1b[21m', vt)
+ pen('underline', 2, state)
+ push('\x1b[24m', vt)
+ pen('underline', 0, state)
+ push('\x1b[4m\x1b[4:0m', vt)
+ pen('underline', 0, state)
+ push('\x1b[4:1m', vt)
+ pen('underline', 1, state)
+ push('\x1b[4:2m', vt)
+ pen('underline', 2, state)
+ push('\x1b[4:3m', vt)
+ pen('underline', 3, state)
+ push('\x1b[4m\x1b[m', vt)
+ pen('underline', 0, state)
+
+ -- Italic
+ push('\x1b[3m', vt)
+ pen('italic', true, state)
+ push('\x1b[23m', vt)
+ pen('italic', false, state)
+ push('\x1b[3m\x1b[m', vt)
+ pen('italic', false, state)
+
+ -- Blink
+ push('\x1b[5m', vt)
+ pen('blink', true, state)
+ push('\x1b[25m', vt)
+ pen('blink', false, state)
+ push('\x1b[5m\x1b[m', vt)
+ pen('blink', false, state)
+
+ -- Reverse
+ push('\x1b[7m', vt)
+ pen('reverse', true, state)
+ push('\x1b[27m', vt)
+ pen('reverse', false, state)
+ push('\x1b[7m\x1b[m', vt)
+ pen('reverse', false, state)
+
+ -- Font Selection
+ push('\x1b[11m', vt)
+ pen('font', 1, state)
+ push('\x1b[19m', vt)
+ pen('font', 9, state)
+ push('\x1b[10m', vt)
+ pen('font', 0, state)
+ push('\x1b[11m\x1b[m', vt)
+ pen('font', 0, state)
+
+ -- TODO(dundargoc): fix
+ -- Foreground
+ -- push "\x1b[31m"
+ -- ?pen foreground = idx(1)
+ -- push "\x1b[32m"
+ -- ?pen foreground = idx(2)
+ -- push "\x1b[34m"
+ -- ?pen foreground = idx(4)
+ -- push "\x1b[91m"
+ -- ?pen foreground = idx(9)
+ -- push "\x1b[38:2:10:20:30m"
+ -- ?pen foreground = rgb(10,20,30)
+ -- push "\x1b[38:5:1m"
+ -- ?pen foreground = idx(1)
+ -- push "\x1b[39m"
+ -- ?pen foreground = rgb(240,240,240,is_default_fg)
+ --
+ -- Background
+ -- push "\x1b[41m"
+ -- ?pen background = idx(1)
+ -- push "\x1b[42m"
+ -- ?pen background = idx(2)
+ -- push "\x1b[44m"
+ -- ?pen background = idx(4)
+ -- push "\x1b[101m"
+ -- ?pen background = idx(9)
+ -- push "\x1b[48:2:10:20:30m"
+ -- ?pen background = rgb(10,20,30)
+ -- push "\x1b[48:5:1m"
+ -- ?pen background = idx(1)
+ -- push "\x1b[49m"
+ -- ?pen background = rgb(0,0,0,is_default_bg)
+ --
+ -- Bold+ANSI colour == highbright
+ -- push "\x1b[m\x1b[1;37m"
+ -- ?pen bold = on
+ -- ?pen foreground = idx(15)
+ -- push "\x1b[m\x1b[37;1m"
+ -- ?pen bold = on
+ -- ?pen foreground = idx(15)
+ --
+ -- Super/Subscript
+ -- push "\x1b[73m"
+ -- ?pen small = on
+ -- ?pen baseline = raise
+ -- push "\x1b[74m"
+ -- ?pen small = on
+ -- ?pen baseline = lower
+ -- push "\x1b[75m"
+ -- ?pen small = off
+ -- ?pen baseline = normal
+ --
+ -- DECSTR resets pen attributes
+ -- push "\x1b[1;4m"
+ -- ?pen bold = on
+ -- ?pen underline = 1
+ -- push "\x1b[!p"
+ -- ?pen bold = off
+ -- ?pen underline = 0
+ end)
+
+ itp('31state_rep', function()
+ local vt = init()
+ local state = wantstate(vt, { g = true })
+
+ -- REP no argument
+ reset(state, nil)
+ push('a\x1b[b', vt)
+ expect('putglyph 61 1 0,0\nputglyph 61 1 0,1')
+
+ -- REP zero (zero should be interpreted as one)
+ reset(state, nil)
+ push('a\x1b[0b', vt)
+ expect('putglyph 61 1 0,0\nputglyph 61 1 0,1')
+
+ -- REP lowercase a times two
+ reset(state, nil)
+ push('a\x1b[2b', vt)
+ expect('putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2')
+
+ -- REP with UTF-8 1 char
+ -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
+ reset(state, nil)
+ push('\xC3\xA9\x1b[b', vt)
+ expect('putglyph e9 1 0,0\nputglyph e9 1 0,1')
+
+ -- REP with UTF-8 wide char
+ -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
+ reset(state, nil)
+ push('\xEF\xBC\x90\x1b[b', vt)
+ expect('putglyph ff10 2 0,0\nputglyph ff10 2 0,2')
+
+ -- REP with UTF-8 combining character
+ reset(state, nil)
+ push('e\xCC\x81\x1b[b', vt)
+ expect('putglyph 65,301 1 0,0\nputglyph 65,301 1 0,1')
+
+ -- REP till end of line
+ reset(state, nil)
+ push('a\x1b[1000bb', vt)
+ expect(
+ 'putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2\nputglyph 61 1 0,3\nputglyph 61 1 0,4\nputglyph 61 1 0,5\nputglyph 61 1 0,6\nputglyph 61 1 0,7\nputglyph 61 1 0,8\nputglyph 61 1 0,9\nputglyph 61 1 0,10\nputglyph 61 1 0,11\nputglyph 61 1 0,12\nputglyph 61 1 0,13\nputglyph 61 1 0,14\nputglyph 61 1 0,15\nputglyph 61 1 0,16\nputglyph 61 1 0,17\nputglyph 61 1 0,18\nputglyph 61 1 0,19\nputglyph 61 1 0,20\nputglyph 61 1 0,21\nputglyph 61 1 0,22\nputglyph 61 1 0,23\nputglyph 61 1 0,24\nputglyph 61 1 0,25\nputglyph 61 1 0,26\nputglyph 61 1 0,27\nputglyph 61 1 0,28\nputglyph 61 1 0,29\nputglyph 61 1 0,30\nputglyph 61 1 0,31\nputglyph 61 1 0,32\nputglyph 61 1 0,33\nputglyph 61 1 0,34\nputglyph 61 1 0,35\nputglyph 61 1 0,36\nputglyph 61 1 0,37\nputglyph 61 1 0,38\nputglyph 61 1 0,39\nputglyph 61 1 0,40\nputglyph 61 1 0,41\nputglyph 61 1 0,42\nputglyph 61 1 0,43\nputglyph 61 1 0,44\nputglyph 61 1 0,45\nputglyph 61 1 0,46\nputglyph 61 1 0,47\nputglyph 61 1 0,48\nputglyph 61 1 0,49\nputglyph 61 1 0,50\nputglyph 61 1 0,51\nputglyph 61 1 0,52\nputglyph 61 1 0,53\nputglyph 61 1 0,54\nputglyph 61 1 0,55\nputglyph 61 1 0,56\nputglyph 61 1 0,57\nputglyph 61 1 0,58\nputglyph 61 1 0,59\nputglyph 61 1 0,60\nputglyph 61 1 0,61\nputglyph 61 1 0,62\nputglyph 61 1 0,63\nputglyph 61 1 0,64\nputglyph 61 1 0,65\nputglyph 61 1 0,66\nputglyph 61 1 0,67\nputglyph 61 1 0,68\nputglyph 61 1 0,69\nputglyph 61 1 0,70\nputglyph 61 1 0,71\nputglyph 61 1 0,72\nputglyph 61 1 0,73\nputglyph 61 1 0,74\nputglyph 61 1 0,75\nputglyph 61 1 0,76\nputglyph 61 1 0,77\nputglyph 61 1 0,78\nputglyph 61 1 0,79\nputglyph 62 1 1,0'
+ )
+ end)
+
+ itp('32state_flow', function()
+ local vt = init()
+ local state = wantstate(vt)
+
+ -- Many of these test cases inspired by
+ -- https://blueprints.launchpad.net/libvterm/+spec/reflow-cases
+
+ -- Spillover text marks continuation on second line
+ reset(state, nil)
+ push(string.rep('A', 100), vt)
+ push('\r\n', vt)
+ lineinfo(0, {}, state)
+ lineinfo(1, { cont = true }, state)
+
+ -- CRLF in column 80 does not mark continuation
+ reset(state, nil)
+ push(string.rep('B', 80), vt)
+ push('\r\n', vt)
+ push(string.rep('B', 20), vt)
+ push('\r\n', vt)
+ lineinfo(0, {}, state)
+ lineinfo(1, {}, state)
+
+ -- EL cancels continuation of following line
+ reset(state, nil)
+ push(string.rep('D', 100), vt)
+ lineinfo(1, { cont = true }, state)
+ push('\x1bM\x1b[79G\x1b[K', vt)
+ lineinfo(1, {}, state)
+ end)
+
+ itp('40state_selection', function()
+ local vt = init()
+ wantstate(vt)
+
+ -- Set clipboard; final chunk len 4
+ push('\x1b]52;c;SGVsbG8s\x1b\\', vt)
+ expect('selection-set mask=0001 [Hello,]')
+
+ -- Set clipboard; final chunk len 3
+ push('\x1b]52;c;SGVsbG8sIHc=\x1b\\', vt)
+ expect('selection-set mask=0001 [Hello, w]')
+
+ -- Set clipboard; final chunk len 2
+ push('\x1b]52;c;SGVsbG8sIHdvcmxkCg==\x1b\\', vt)
+ expect('selection-set mask=0001 [Hello, world\n]')
+
+ -- Set clipboard; split between chunks
+ push('\x1b]52;c;SGVs', vt)
+ expect('selection-set mask=0001 [Hel')
+ push('bG8s\x1b\\', vt)
+ expect('selection-set mask=0001 lo,]')
+
+ -- Set clipboard; split within chunk
+ push('\x1b]52;c;SGVsbG', vt)
+ expect('selection-set mask=0001 [Hel')
+ push('8s\x1b\\', vt)
+ expect('selection-set mask=0001 lo,]')
+
+ -- Set clipboard; empty first chunk
+ push('\x1b]52;c;', vt)
+ push('SGVsbG8s\x1b\\', vt)
+ expect('selection-set mask=0001 [Hello,]')
+
+ -- Set clipboard; empty final chunk
+ push('\x1b]52;c;SGVsbG8s', vt)
+ expect('selection-set mask=0001 [Hello,')
+ push('\x1b\\', vt)
+ expect('selection-set mask=0001 ]')
+
+ -- Set clipboard; longer than buffer
+ push('\x1b]52;c;' .. string.rep('LS0t', 10) .. '\x1b\\', vt)
+ expect('selection-set mask=0001 [---------------\nselection-set mask=0001 ---------------]')
+
+ -- Clear clipboard
+ push('\x1b]52;c;\x1b\\', vt)
+ expect('selection-set mask=0001 []')
+
+ -- Set invalid data clears and ignores
+ push('\x1b]52;c;SGVs*SGVsbG8s\x1b\\', vt)
+ expect('selection-set mask=0001 []')
+
+ -- Query clipboard
+ push('\x1b]52;c;?\x1b\\', vt)
+ expect('selection-query mask=0001')
+
+ -- TODO(dundargoc): fix
+ -- Send clipboard; final chunk len 4
+ -- SELECTION 1 ["Hello,"]
+ -- output "\x1b]52;c;"
+ -- output "SGVsbG8s"
+ -- output "\x1b\\"
+ --
+ -- Send clipboard; final chunk len 3
+ -- SELECTION 1 ["Hello, w"]
+ -- output "\x1b]52;c;"
+ -- output "SGVsbG8s"
+ -- output "IHc=\x1b\\"
+ --
+ -- Send clipboard; final chunk len 2
+ -- SELECTION 1 ["Hello, world\n"]
+ -- output "\x1b]52;c;"
+ -- output "SGVsbG8sIHdvcmxk"
+ -- output "Cg==\x1b\\"
+ --
+ -- Send clipboard; split between chunks
+ -- SELECTION 1 ["Hel"
+ -- output "\x1b]52;c;"
+ -- output "SGVs"
+ -- SELECTION 1 "lo,"]
+ -- output "bG8s"
+ -- output "\x1b\\"
+ --
+ -- Send clipboard; split within chunk
+ -- SELECTION 1 ["Hello"
+ -- output "\x1b]52;c;"
+ -- output "SGVs"
+ -- SELECTION 1 ","]
+ -- output "bG8s"
+ -- output "\x1b\\"
+ end)
+
+ itp('60screen_ascii', function()
+ local vt = init()
+ local screen = wantscreen(vt, { a = true, c = true })
+
+ -- Get
+ reset(nil, screen)
+ push('ABC', vt)
+ expect('movecursor 0,3')
+ screen_chars(0, 0, 1, 3, 'ABC', screen)
+ screen_chars(0, 0, 1, 80, 'ABC', screen)
+ screen_text(0, 0, 1, 3, '41,42,43', screen)
+ screen_text(0, 0, 1, 80, '41,42,43', screen)
+ screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 1, '{42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 2, '{43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_row(0, 'ABC', screen)
+ screen_eol(0, 0, 0, screen)
+ screen_eol(0, 2, 0, screen)
+ screen_eol(0, 3, 1, screen)
+ push('\x1b[H', vt)
+ expect('movecursor 0,0')
+ screen_row(0, 'ABC', screen)
+ screen_text(0, 0, 1, 80, '41,42,43', screen)
+ push('E', vt)
+ expect('movecursor 0,1')
+ screen_row(0, 'EBC', screen)
+ screen_text(0, 0, 1, 80, '45,42,43', screen)
+
+ screen = wantscreen(vt, { a = true })
+
+ -- Erase
+ reset(nil, screen)
+ push('ABCDE\x1b[H\x1b[K', vt)
+ -- TODO(dundargoc): fix
+ -- screen_row(0, '', screen)
+ screen_text(0, 0, 1, 80, '', screen)
+
+ -- Copycell
+ reset(nil, screen)
+ push('ABC\x1b[H\x1b[@', vt)
+ push('1', vt)
+ screen_row(0, '1ABC', screen)
+
+ reset(nil, screen)
+ push('ABC\x1b[H\x1b[P', vt)
+ screen_chars(0, 0, 1, 1, 'B', screen)
+ screen_chars(0, 1, 1, 2, 'C', screen)
+ screen_chars(0, 0, 1, 80, 'BC', screen)
+
+ -- Space padding
+ reset(nil, screen)
+ push('Hello\x1b[CWorld', vt)
+ screen_row(0, 'Hello World', screen)
+ screen_text(0, 0, 1, 80, '48,65,6c,6c,6f,20,57,6f,72,6c,64', screen)
+
+ -- Linefeed padding
+ reset(nil, screen)
+ push('Hello\r\nWorld', vt)
+ screen_chars(0, 0, 2, 80, 'Hello\nWorld', screen)
+ screen_text(0, 0, 2, 80, '48,65,6c,6c,6f,0a,57,6f,72,6c,64', screen)
+
+ -- Altscreen
+ reset(nil, screen)
+ push('P', vt)
+ screen_row(0, 'P', screen)
+ -- TODO(dundargoc): fix
+ -- push('\x1b[?1049h', vt)
+ -- screen_row(0, '', screen)
+ -- push('\x1b[2K\x1b[HA', vt)
+ -- screen_row(0, 'A', screen)
+ -- push('\x1b[?1049l', vt)
+ -- screen_row(0, 'P', screen)
+ end)
+
+ itp('61screen_unicode', function()
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ -- Single width UTF-8
+ -- U+00C1 = C3 81 name: LATIN CAPITAL LETTER A WITH ACUTE
+ -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
+ reset(nil, screen)
+ push('\xC3\x81\xC3\xA9', vt)
+ screen_row(0, 'Áé', screen)
+ screen_text(0, 0, 1, 80, 'c3,81,c3,a9', screen)
+ screen_cell(0, 0, '{c1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Wide char
+ -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO
+ reset(nil, screen)
+ push('0123\x1b[H', vt)
+ push('\xEF\xBC\x90', vt)
+ screen_row(0, '023', screen)
+ screen_text(0, 0, 1, 80, 'ef,bc,90,32,33', screen)
+ screen_cell(0, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Combining char
+ -- U+0301 = CC 81 name: COMBINING ACUTE
+ reset(nil, screen)
+ push('0123\x1b[H', vt)
+ push('e\xCC\x81', vt)
+ screen_row(0, 'é123', screen)
+ screen_text(0, 0, 1, 80, '65,cc,81,31,32,33', screen)
+ screen_cell(0, 0, '{65,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- 10 combining accents should not crash
+ reset(nil, screen)
+ push('e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A', vt)
+ screen_cell(
+ 0,
+ 0,
+ '{65,301,302,303,304,305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ screen
+ )
+
+ -- 40 combining accents in two split writes of 20 should not crash
+ reset(nil, screen)
+ push(
+ 'e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81',
+ vt
+ )
+ push(
+ '\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81',
+ vt
+ )
+ screen_cell(
+ 0,
+ 0,
+ '{65,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ screen
+ )
+
+ -- Outputing CJK doublewidth in 80th column should wraparound to next line and not crash"
+ reset(nil, screen)
+ push('\x1b[80G\xEF\xBC\x90', vt)
+ screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ end)
+
+ pending('62screen_damage', function() end)
+
+ itp('63screen_resize', function()
+ local vt = init()
+ local state = wantstate(vt)
+ local screen = wantscreen(vt)
+
+ -- Resize wider preserves cells
+ reset(state, screen)
+ resize(25, 80, vt)
+ push('AB\r\nCD', vt)
+ screen_chars(0, 0, 1, 80, 'AB', screen)
+ screen_chars(1, 0, 2, 80, 'CD', screen)
+ resize(25, 100, vt)
+ screen_chars(0, 0, 1, 100, 'AB', screen)
+ screen_chars(1, 0, 2, 100, 'CD', screen)
+
+ -- Resize wider allows print in new area
+ reset(state, screen)
+ resize(25, 80, vt)
+ push('AB\x1b[79GCD', vt)
+ screen_chars(0, 0, 1, 2, 'AB', screen)
+ screen_chars(0, 78, 1, 80, 'CD', screen)
+ resize(25, 100, vt)
+ screen_chars(0, 0, 1, 2, 'AB', screen)
+ screen_chars(0, 78, 1, 80, 'CD', screen)
+ push('E', vt)
+ screen_chars(0, 78, 1, 81, 'CDE', screen)
+
+ -- Resize shorter with blanks just truncates
+ reset(state, screen)
+ resize(25, 80, vt)
+ push('Top\x1b[10HLine 10', vt)
+ screen_row(0, 'Top', screen)
+ screen_row(9, 'Line 10', screen)
+ cursor(9, 7, state)
+ resize(20, 80, vt)
+ screen_row(0, 'Top', screen)
+ screen_row(9, 'Line 10', screen)
+ cursor(9, 7, state)
+
+ -- Resize shorter with content must scroll
+ reset(state, screen)
+ resize(25, 80, vt)
+ push('Top\x1b[25HLine 25\x1b[15H', vt)
+ screen_row(0, 'Top', screen)
+ screen_row(24, 'Line 25', screen)
+ cursor(14, 0, state)
+ screen = wantscreen(vt, { b = true })
+ resize(20, 80, vt)
+ expect(
+ 'sb_pushline 80 = 54 6F 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
+ )
+ -- TODO(dundargoc): fix or remove
+ -- screen_row( 0 , "",screen)
+ screen_row(19, 'Line 25', screen)
+ cursor(9, 0, state)
+
+ -- Resize shorter does not lose line with cursor
+ -- See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088
+ reset(state, screen)
+ wantscreen(vt)
+ resize(25, 80, vt)
+ screen = wantscreen(vt, { b = true })
+ push('\x1b[24HLine 24\r\nLine 25\r\n', vt)
+ expect('sb_pushline 80 =')
+ screen_row(23, 'Line 25', screen)
+ cursor(24, 0, state)
+ resize(24, 80, vt)
+ expect('sb_pushline 80 =')
+ screen_row(22, 'Line 25', screen)
+ cursor(23, 0, state)
+
+ -- Resize shorter does not send the cursor to a negative row
+ -- See also https://github.com/vim/vim/pull/6141
+ reset(state, screen)
+ wantscreen(vt)
+ resize(25, 80, vt)
+ screen = wantscreen(vt, { b = true })
+ push('\x1b[24HLine 24\r\nLine 25\x1b[H', vt)
+ cursor(0, 0, state)
+ resize(20, 80, vt)
+ expect(
+ 'sb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
+ )
+ cursor(0, 0, state)
+
+ -- Resize taller attempts to pop scrollback
+ reset(state, screen)
+ screen = wantscreen(vt)
+ resize(25, 80, vt)
+ push('Line 1\x1b[25HBottom\x1b[15H', vt)
+ screen_row(0, 'Line 1', screen)
+ screen_row(24, 'Bottom', screen)
+ cursor(14, 0, state)
+ screen = wantscreen(vt, { b = true })
+ resize(30, 80, vt)
+ expect('sb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80')
+ screen_row(0, 'ABCDE', screen)
+ screen_row(5, 'Line 1', screen)
+ screen_row(29, 'Bottom', screen)
+ cursor(19, 0, state)
+ screen = wantscreen(vt)
+
+ -- Resize can operate on altscreen
+ reset(state, screen)
+ screen = wantscreen(vt, { a = true })
+ resize(25, 80, vt)
+ push('Main screen\x1b[?1049h\x1b[HAlt screen', vt)
+ resize(30, 80, vt)
+ screen_row(0, 'Alt screen', screen)
+ push('\x1b[?1049l', vt)
+ screen_row(0, 'Main screen', screen)
+ end)
+
+ itp('64screen_pen', function()
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ reset(nil, screen)
+
+ -- Plain
+ push('A', vt)
+ screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Bold
+ push('\x1b[1mB', vt)
+ screen_cell(0, 1, '{42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Italic
+ push('\x1b[3mC', vt)
+ screen_cell(0, 2, '{43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Underline
+ push('\x1b[4mD', vt)
+ screen_cell(0, 3, '{44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Reset
+ push('\x1b[mE', vt)
+ screen_cell(0, 4, '{45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Font
+ push('\x1b[11mF\x1b[m', vt)
+ screen_cell(0, 5, '{46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Foreground
+ push('\x1b[31mG\x1b[m', vt)
+ screen_cell(0, 6, '{47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen)
+
+ -- Background
+ push('\x1b[42mH\x1b[m', vt)
+ screen_cell(0, 7, '{48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)', screen)
+
+ -- Super/subscript
+ push('x\x1b[74m0\x1b[73m2\x1b[m', vt)
+ screen_cell(0, 8, '{78} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 9, '{30} width=1 attrs={S_} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 10, '{32} width=1 attrs={S^} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- EL sets only colours to end of line, not other attrs
+ push('\x1b[H\x1b[7;33;44m\x1b[K', vt)
+ screen_cell(0, 0, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
+ screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
+
+ -- DECSCNM xors reverse for entire screen
+ push('R\x1b[?5h', vt)
+ screen_cell(0, 0, '{52} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
+ screen_cell(1, 0, '{} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ push('\x1b[?5$p', vt)
+ expect_output('\x1b[?5;1$y')
+ push('\x1b[?5l', vt)
+ screen_cell(0, 0, '{52} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
+ screen_cell(1, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ -- TODO(dundargoc): fix
+ -- push('\x1b[?5$p')
+ -- expect_output('\x1b[?5;2$y')
+
+ -- Set default colours
+ reset(nil, screen)
+ push('ABC\x1b[31mDEF\x1b[m', vt)
+ screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 3, '{44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen)
+ -- TODO(dundargoc): fix
+ -- SETDEFAULTCOL rgb(252,253,254)
+ -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(252,253,254) bg=rgb(0,0,0)
+ -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)
+ -- SETDEFAULTCOL rgb(250,250,250) rgb(10,20,30)
+ -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(250,250,250) bg=rgb(10,20,30)
+ -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(10,20,30)
+ end)
+
+ itp('65screen_protect', function()
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ -- Selective erase
+ reset(nil, screen)
+ push('A\x1b[1"qB\x1b["qC', vt)
+ screen_row(0, 'ABC', screen)
+ push('\x1b[G\x1b[?J', vt)
+ screen_row(0, ' B', screen)
+
+ -- Non-selective erase
+ reset(nil, screen)
+ push('A\x1b[1"qB\x1b["qC', vt)
+ screen_row(0, 'ABC', screen)
+ -- TODO(dundargoc): fix
+ -- push('\x1b[G\x1b[J', vt)
+ -- screen_row(0, '', screen)
+ end)
+
+ itp('66screen_extent', function()
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ -- Bold extent
+ reset(nil, screen)
+ push('AB\x1b[1mCD\x1b[mE', vt)
+ screen_attrs_extent(0, 0, '0,0-1,1', screen)
+ screen_attrs_extent(0, 1, '0,0-1,1', screen)
+ screen_attrs_extent(0, 2, '0,2-1,3', screen)
+ screen_attrs_extent(0, 3, '0,2-1,3', screen)
+ screen_attrs_extent(0, 4, '0,4-1,79', screen)
+ end)
+
+ itp('67screen_dbl_wh', function()
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ reset(nil, screen)
+
+ -- Single Width, Single Height
+ reset(nil, screen)
+ push('\x1b#5', vt)
+ push('abcde', vt)
+ screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Double Width, Single Height
+ reset(nil, screen)
+ push('\x1b#6', vt)
+ push('abcde', vt)
+ screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Double Height
+ reset(nil, screen)
+ push('\x1b#3', vt)
+ push('abcde', vt)
+ push('\r\n\x1b#4', vt)
+ push('abcde', vt)
+ screen_cell(0, 0, '{61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(
+ 1,
+ 0,
+ '{61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ screen
+ )
+
+ -- Late change
+ reset(nil, screen)
+ push('abcde', vt)
+ screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ push('\x1b#6', vt)
+ screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- DWL doesn't spill over on scroll
+ reset(nil, screen)
+ push('\x1b[25H\x1b#6Final\r\n', vt)
+ screen_cell(23, 0, '{46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(24, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ end)
+
+ itp('68screen_termprops', function()
+ local vt = init()
+ local screen = wantscreen(vt, { p = true })
+
+ reset(nil, screen)
+ expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
+
+ -- Cursor visibility
+ push('\x1b[?25h', vt)
+ expect('settermprop 1 true')
+ push('\x1b[?25l', vt)
+ expect('settermprop 1 false')
+
+ -- Title
+ push('\x1b]2;Here is my title\a', vt)
+ expect('settermprop 4 ["Here is my title"]')
+ end)
+
+ itp('69screen_pushline', function()
+ local vt = init()
+ -- Run these tests on a much smaller default screen, so debug output is nowhere near as noisy
+ resize(5, 10, vt)
+ local state = wantstate(vt)
+ local screen = wantscreen(vt, { r = true })
+ reset(state, screen)
+
+ -- Resize wider reflows wide lines
+ reset(state, screen)
+ push(string.rep('A', 12), vt)
+ screen_row(0, 'AAAAAAAAAA', screen, vt.cols)
+ screen_row(1, 'AA', screen, vt.cols)
+ lineinfo(1, { cont = true }, state)
+ cursor(1, 2, state)
+ resize(5, 15, vt)
+ screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row(1, '', screen, vt.cols)
+ lineinfo(1, {}, state)
+ cursor(0, 12, state)
+ resize(5, 20, vt)
+ screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 ,'',screen, vt.cols)
+ lineinfo(1, {}, state)
+ cursor(0, 12, state)
+
+ -- Resize narrower can create continuation lines
+ reset(state, screen)
+ resize(5, 10, vt)
+ push('ABCDEFGHI', vt)
+ screen_row(0, 'ABCDEFGHI', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 , "",screen, vt.cols)
+ lineinfo(1, {}, state)
+ cursor(0, 9, state)
+ resize(5, 8, vt)
+ -- TODO(dundargoc): fix
+ -- screen_row( 0 , "ABCDEFGH",screen,vt.cols)
+ screen_row(1, 'I', screen, vt.cols)
+ lineinfo(1, { cont = true }, state)
+ cursor(1, 1, state)
+ resize(5, 6, vt)
+ screen_row(0, 'ABCDEF', screen, vt.cols)
+ screen_row(1, 'GHI', screen, vt.cols)
+ lineinfo(1, { cont = true }, state)
+ cursor(1, 3, state)
+
+ -- Shell wrapped prompt behaviour
+ reset(state, screen)
+ resize(5, 10, vt)
+ push('PROMPT GOES HERE\r\n> \r\n\r\nPROMPT GOES HERE\r\n> ', vt)
+ screen_row(0, '> ', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 , "",screen,vt.cols)
+ screen_row(2, 'PROMPT GOE', screen, vt.cols)
+ screen_row(3, 'S HERE', screen, vt.cols)
+ lineinfo(3, { cont = true }, state)
+ screen_row(4, '> ', screen, vt.cols)
+ cursor(4, 2, state)
+ resize(5, 11, vt)
+ screen_row(0, '> ', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 , "",screen,vt.cols)
+ screen_row(2, 'PROMPT GOES', screen, vt.cols)
+ screen_row(3, ' HERE', screen, vt.cols)
+ lineinfo(3, { cont = true }, state)
+ screen_row(4, '> ', screen, vt.cols)
+ cursor(4, 2, state)
+ resize(5, 12, vt)
+ screen_row(0, '> ', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 , "",screen,vt.cols)
+ screen_row(2, 'PROMPT GOES ', screen, vt.cols)
+ screen_row(3, 'HERE', screen, vt.cols)
+ lineinfo(3, { cont = true }, state)
+ screen_row(4, '> ', screen, vt.cols)
+ cursor(4, 2, state)
+ resize(5, 16, vt)
+ screen_row(0, '> ', screen, vt.cols)
+ -- TODO(dundargoc): fix
+ -- screen_row( 1 , "",screen,vt.cols)
+ -- screen_row( 2 , "PROMPT GOES HERE",screen,vt.cols)
+ lineinfo(3, {}, state)
+ screen_row(3, '> ', screen, vt.cols)
+ cursor(3, 2, state)
+
+ -- Cursor goes missing
+ -- For more context: https://github.com/neovim/neovim/pull/21124
+ reset(state, screen)
+ resize(5, 5, vt)
+ resize(3, 1, vt)
+ push('\x1b[2;1Habc\r\n\x1b[H', vt)
+ resize(1, 1, vt)
+ cursor(0, 0, state)
+ end)
+
+ pending('90vttest_01-movement-1', function() end)
+ pending('90vttest_01-movement-2', function() end)
+
+ itp('90vttest_01-movement-3', function()
+ -- Test of cursor-control characters inside ESC sequences
+ local vt = init()
+ local state = wantstate(vt)
+ local screen = wantscreen(vt)
+
+ reset(state, screen)
+
+ push('A B C D E F G H I', vt)
+ push('\x0d\x0a', vt)
+ push('A\x1b[2\bCB\x1b[2\bCC\x1b[2\bCD\x1b[2\bCE\x1b[2\bCF\x1b[2\bCG\x1b[2\bCH\x1b[2\bCI', vt)
+ push('\x0d\x0a', vt)
+ push(
+ 'A \x1b[\x0d2CB\x1b[\x0d4CC\x1b[\x0d6CD\x1b[\x0d8CE\x1b[\x0d10CF\x1b[\x0d12CG\x1b[\x0d14CH\x1b[\x0d16CI',
+ vt
+ )
+ push('\x0d\x0a', vt)
+ push(
+ 'A \x1b[1\x0bAB \x1b[1\x0bAC \x1b[1\x0bAD \x1b[1\x0bAE \x1b[1\x0bAF \x1b[1\x0bAG \x1b[1\x0bAH \x1b[1\x0bAI \x1b[1\x0bA',
+ vt
+ )
+
+ -- Output
+
+ for i = 0, 2 do
+ screen_row(i, 'A B C D E F G H I', screen)
+ end
+ screen_row(3, 'A B C D E F G H I ', screen)
+
+ cursor(3, 18, state)
+ end)
+
+ itp('90vttest_01-movement-4', function()
+ -- Test of leading zeroes in ESC sequences
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ reset(nil, screen)
+
+ push('\x1b[00000000004;000000001HT', vt)
+ push('\x1b[00000000004;000000002Hh', vt)
+ push('\x1b[00000000004;000000003Hi', vt)
+ push('\x1b[00000000004;000000004Hs', vt)
+ push('\x1b[00000000004;000000005H ', vt)
+ push('\x1b[00000000004;000000006Hi', vt)
+ push('\x1b[00000000004;000000007Hs', vt)
+ push('\x1b[00000000004;000000008H ', vt)
+ push('\x1b[00000000004;000000009Ha', vt)
+ push('\x1b[00000000004;0000000010H ', vt)
+ push('\x1b[00000000004;0000000011Hc', vt)
+ push('\x1b[00000000004;0000000012Ho', vt)
+ push('\x1b[00000000004;0000000013Hr', vt)
+ push('\x1b[00000000004;0000000014Hr', vt)
+ push('\x1b[00000000004;0000000015He', vt)
+ push('\x1b[00000000004;0000000016Hc', vt)
+ push('\x1b[00000000004;0000000017Ht', vt)
+ push('\x1b[00000000004;0000000018H ', vt)
+ push('\x1b[00000000004;0000000019Hs', vt)
+ push('\x1b[00000000004;0000000020He', vt)
+ push('\x1b[00000000004;0000000021Hn', vt)
+ push('\x1b[00000000004;0000000022Ht', vt)
+ push('\x1b[00000000004;0000000023He', vt)
+ push('\x1b[00000000004;0000000024Hn', vt)
+ push('\x1b[00000000004;0000000025Hc', vt)
+ push('\x1b[00000000004;0000000026He', vt)
+
+ -- Output
+
+ screen_row(3, 'This is a correct sentence', screen)
+ end)
+
+ pending('90vttest_02-screen-1', function() end)
+ pending('90vttest_02-screen-2', function() end)
+
+ itp('90vttest_02-screen-3', function()
+ -- Origin mode
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ reset(nil, screen)
+
+ push('\x1b[?6h', vt)
+ push('\x1b[23;24r', vt)
+ push('\n', vt)
+ push('Bottom', vt)
+ push('\x1b[1;1H', vt)
+ push('Above', vt)
+
+ -- Output
+ screen_row(22, 'Above', screen)
+ screen_row(23, 'Bottom', screen)
+ end)
+
+ itp('90vttest_02-screen-4', function()
+ -- Origin mode (2)
+ local vt = init()
+ local screen = wantscreen(vt)
+
+ reset(nil, screen)
+
+ push('\x1b[?6l', vt)
+ push('\x1b[23;24r', vt)
+ push('\x1b[24;1H', vt)
+ push('Bottom', vt)
+ push('\x1b[1;1H', vt)
+ push('Top', vt)
+
+ -- Output
+ screen_row(23, 'Bottom', screen)
+ screen_row(0, 'Top', screen)
+ end)
+
+ itp('Mouse reporting should not break by idempotent DECSM 1002', function()
+ -- Regression test for https://bugs.launchpad.net/libvterm/+bug/1640917
+ -- Related: https://github.com/neovim/neovim/issues/5583
+ local vt = init()
+ wantstate(vt, {})
+
+ push('\x1b[?1002h', vt)
+ mousemove(0, 0, vt)
+ mousebtn('d', 1, vt)
+ expect_output('\x1b[M\x20\x21\x21')
+ mousemove(1, 0, vt)
+ expect_output('\x1b[M\x40\x21\x22')
+ push('\x1b[?1002h', vt)
+ mousemove(2, 0, vt)
+ expect_output('\x1b[M\x40\x21\x23')
+ end)
+end)