aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml3
-rw-r--r--.gitignore21
-rw-r--r--.travis.yml21
-rw-r--r--CMakeLists.txt4
-rwxr-xr-xci/before_install.sh2
-rw-r--r--ci/build.ps12
-rw-r--r--ci/common/test.sh2
-rwxr-xr-xci/install.sh2
-rw-r--r--ci/snap/.snapcraft_payload194
-rwxr-xr-xci/snap/deploy.sh42
-rwxr-xr-xci/snap/install.sh1
-rwxr-xr-xci/snap/script.sh2
-rw-r--r--cmake/FindLua.cmake2
-rw-r--r--config/CMakeLists.txt1
-rw-r--r--config/config.h.in2
-rw-r--r--runtime/autoload/dist/ft.vim2
-rw-r--r--runtime/autoload/health/provider.vim44
-rw-r--r--runtime/autoload/provider/clipboard.vim72
-rw-r--r--runtime/autoload/provider/node.vim19
-rw-r--r--runtime/autoload/provider/perl.vim28
-rw-r--r--runtime/autoload/provider/pythonx.vim4
-rw-r--r--runtime/autoload/provider/ruby.vim3
-rw-r--r--runtime/autoload/spellfile.vim10
-rw-r--r--runtime/compiler/ts-node.vim29
-rw-r--r--runtime/compiler/tsc.vim26
-rw-r--r--runtime/compiler/xo.vim26
-rw-r--r--runtime/doc/api.txt209
-rw-r--r--runtime/doc/autocmd.txt183
-rw-r--r--runtime/doc/change.txt4
-rw-r--r--runtime/doc/cmdline.txt5
-rw-r--r--runtime/doc/deprecated.txt2
-rw-r--r--runtime/doc/develop.txt6
-rw-r--r--runtime/doc/digraph.txt1
-rw-r--r--runtime/doc/eval.txt183
-rw-r--r--runtime/doc/help.txt4
-rw-r--r--runtime/doc/if_perl.txt268
-rw-r--r--runtime/doc/if_ruby.txt12
-rw-r--r--runtime/doc/index.txt3
-rw-r--r--runtime/doc/insert.txt4
-rw-r--r--runtime/doc/intro.txt95
-rw-r--r--runtime/doc/lsp.txt876
-rw-r--r--runtime/doc/lua.txt475
-rw-r--r--runtime/doc/map.txt50
-rw-r--r--runtime/doc/mbyte.txt208
-rw-r--r--runtime/doc/message.txt2
-rw-r--r--runtime/doc/mlang.txt3
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt2
-rw-r--r--runtime/doc/options.txt119
-rw-r--r--runtime/doc/provider.txt14
-rw-r--r--runtime/doc/quickfix.txt46
-rw-r--r--runtime/doc/quickref.txt2
-rw-r--r--runtime/doc/spell.txt14
-rw-r--r--runtime/doc/starting.txt175
-rw-r--r--runtime/doc/treesitter.txt295
-rw-r--r--runtime/doc/ui.txt4
-rw-r--r--runtime/doc/usr_02.txt2
-rw-r--r--runtime/doc/vim_diff.txt28
-rw-r--r--runtime/doc/visual.txt5
-rw-r--r--runtime/filetype.vim24
-rw-r--r--runtime/ftplugin/markdown.vim46
-rw-r--r--runtime/ftplugin/typescript.vim39
-rw-r--r--runtime/ftplugin/typescriptreact.vim33
-rw-r--r--runtime/indent/typescript.vim4
-rw-r--r--runtime/lua/vim/highlight.lua2
-rw-r--r--runtime/lua/vim/lsp.lua363
-rw-r--r--runtime/lua/vim/lsp/buf.lua144
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua98
-rw-r--r--runtime/lua/vim/lsp/log.lua17
-rw-r--r--runtime/lua/vim/lsp/protocol.lua25
-rw-r--r--runtime/lua/vim/lsp/rpc.lua148
-rw-r--r--runtime/lua/vim/lsp/util.lua377
-rw-r--r--runtime/lua/vim/shared.lua93
-rw-r--r--runtime/lua/vim/treesitter.lua272
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua210
-rw-r--r--runtime/lua/vim/treesitter/language.lua37
-rw-r--r--runtime/lua/vim/treesitter/query.lua335
-rw-r--r--runtime/lua/vim/tshighlighter.lua116
-rw-r--r--runtime/lua/vim/uri.lua20
-rw-r--r--runtime/pack/dist/opt/cfilter/plugin/cfilter.vim39
-rw-r--r--runtime/queries/c/highlights.scm151
-rw-r--r--runtime/syntax/markdown.vim66
-rw-r--r--runtime/syntax/resolv.vim53
-rw-r--r--runtime/syntax/tex.vim53
-rw-r--r--runtime/syntax/typescript.vim2052
-rw-r--r--runtime/syntax/typescriptcommon.vim2067
-rw-r--r--runtime/syntax/typescriptreact.vim160
-rw-r--r--runtime/tools/check_colors.vim51
-rwxr-xr-xscripts/download-unicode-files.sh2
-rwxr-xr-xscripts/gen_vimdoc.py67
-rwxr-xr-xscripts/vim-patch.sh8
-rw-r--r--snap/snapcraft.yaml35
-rwxr-xr-xsrc/clint.py2
-rw-r--r--src/nvim/CMakeLists.txt20
-rw-r--r--src/nvim/api/buffer.c591
-rw-r--r--src/nvim/api/private/helpers.c77
-rw-r--r--src/nvim/api/ui_events.in.h10
-rw-r--r--src/nvim/api/vim.c163
-rw-r--r--src/nvim/ascii.h2
-rw-r--r--src/nvim/auevents.lua3
-rw-r--r--src/nvim/buffer.c24
-rw-r--r--src/nvim/buffer_defs.h15
-rw-r--r--src/nvim/buffer_updates.c42
-rw-r--r--src/nvim/buffer_updates.h1
-rw-r--r--src/nvim/change.c32
-rw-r--r--src/nvim/charset.c46
-rw-r--r--src/nvim/cursor_shape.c41
-rw-r--r--src/nvim/digraph.c1
-rw-r--r--src/nvim/edit.c122
-rw-r--r--src/nvim/eval.c185
-rw-r--r--src/nvim/eval.lua7
-rw-r--r--src/nvim/eval/decode.c2
-rw-r--r--src/nvim/eval/funcs.c186
-rw-r--r--src/nvim/eval/userfunc.c214
-rw-r--r--src/nvim/ex_cmds.c72
-rw-r--r--src/nvim/ex_cmds.lua22
-rw-r--r--src/nvim/ex_cmds2.c67
-rw-r--r--src/nvim/ex_cmds_defs.h4
-rw-r--r--src/nvim/ex_docmd.c879
-rw-r--r--src/nvim/ex_eval.c55
-rw-r--r--src/nvim/ex_getln.c665
-rw-r--r--src/nvim/ex_session.c9
-rw-r--r--src/nvim/extmark.c503
-rw-r--r--src/nvim/extmark.h26
-rw-r--r--src/nvim/extmark_defs.h32
-rw-r--r--src/nvim/fileio.c47
-rw-r--r--src/nvim/fold.c326
-rw-r--r--src/nvim/fold.h1
-rw-r--r--src/nvim/generators/gen_ex_cmds.lua28
-rw-r--r--src/nvim/generators/gen_options.lua9
-rw-r--r--src/nvim/getchar.c28
-rw-r--r--src/nvim/globals.h12
-rw-r--r--src/nvim/hashtab.h1
-rw-r--r--src/nvim/indent.c11
-rw-r--r--src/nvim/keymap.c13
-rw-r--r--src/nvim/log.h15
-rw-r--r--src/nvim/lua/converter.c7
-rw-r--r--src/nvim/lua/executor.c125
-rw-r--r--src/nvim/lua/executor.h9
-rw-r--r--src/nvim/lua/treesitter.c231
-rw-r--r--src/nvim/lua/vim.lua56
-rw-r--r--src/nvim/macros.h25
-rw-r--r--src/nvim/main.c4
-rw-r--r--src/nvim/map.c3
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/marktree.h1
-rw-r--r--src/nvim/mbyte.c144
-rw-r--r--src/nvim/memline.c114
-rw-r--r--src/nvim/memline_defs.h2
-rw-r--r--src/nvim/message.c16
-rw-r--r--src/nvim/misc1.c4
-rw-r--r--src/nvim/move.c5
-rw-r--r--src/nvim/normal.c92
-rw-r--r--src/nvim/ops.c249
-rw-r--r--src/nvim/option.c94
-rw-r--r--src/nvim/option_defs.h10
-rw-r--r--src/nvim/options.lua31
-rw-r--r--src/nvim/os/env.c4
-rw-r--r--src/nvim/os/lang.c16
-rw-r--r--src/nvim/os/signal.c4
-rw-r--r--src/nvim/os/time.c9
-rw-r--r--src/nvim/po/check.vim1
-rw-r--r--src/nvim/po/uk.po1197
-rw-r--r--src/nvim/popupmnu.c85
-rw-r--r--src/nvim/quickfix.c524
-rw-r--r--src/nvim/regexp.c22
-rw-r--r--src/nvim/regexp_nfa.c2
-rw-r--r--src/nvim/screen.c760
-rw-r--r--src/nvim/search.c166
-rw-r--r--src/nvim/shada.c2
-rw-r--r--src/nvim/spell.c32
-rw-r--r--src/nvim/spellfile.c19
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/testdir/check.vim88
-rw-r--r--src/nvim/testdir/runtest.vim101
-rw-r--r--src/nvim/testdir/shared.vim26
-rw-r--r--src/nvim/testdir/summarize.vim1
-rw-r--r--src/nvim/testdir/test_alot.vim2
-rw-r--r--src/nvim/testdir/test_arglist.vim10
-rw-r--r--src/nvim/testdir/test_autocmd.vim46
-rw-r--r--src/nvim/testdir/test_cjk_linebreak.vim97
-rw-r--r--src/nvim/testdir/test_cmdline.vim24
-rw-r--r--src/nvim/testdir/test_compiler.vim4
-rw-r--r--src/nvim/testdir/test_const.vim12
-rw-r--r--src/nvim/testdir/test_debugger.vim125
-rw-r--r--src/nvim/testdir/test_diffmode.vim180
-rw-r--r--src/nvim/testdir/test_display.vim155
-rw-r--r--src/nvim/testdir/test_edit.vim90
-rw-r--r--src/nvim/testdir/test_environ.vim25
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim24
-rw-r--r--src/nvim/testdir/test_expand_func.vim47
-rw-r--r--src/nvim/testdir/test_expr.vim3
-rw-r--r--src/nvim/testdir/test_filetype.vim17
-rw-r--r--src/nvim/testdir/test_filter_map.vim1
-rw-r--r--src/nvim/testdir/test_functions.vim51
-rw-r--r--src/nvim/testdir/test_gf.vim27
-rw-r--r--src/nvim/testdir/test_gn.vim27
-rw-r--r--src/nvim/testdir/test_highlight.vim14
-rw-r--r--src/nvim/testdir/test_ins_complete.vim112
-rw-r--r--src/nvim/testdir/test_interrupt.vim27
-rw-r--r--src/nvim/testdir/test_lambda.vim2
-rw-r--r--src/nvim/testdir/test_listdict.vim8
-rw-r--r--src/nvim/testdir/test_mapping.vim36
-rw-r--r--src/nvim/testdir/test_matchadd_conceal.vim75
-rw-r--r--src/nvim/testdir/test_messages.vim1
-rw-r--r--src/nvim/testdir/test_mksession.vim123
-rw-r--r--src/nvim/testdir/test_options.vim10
-rw-r--r--src/nvim/testdir/test_perl.vim311
-rw-r--r--src/nvim/testdir/test_popup.vim47
-rw-r--r--src/nvim/testdir/test_put.vim26
-rw-r--r--src/nvim/testdir/test_quickfix.vim397
-rw-r--r--src/nvim/testdir/test_ruby.vim376
-rw-r--r--src/nvim/testdir/test_search.vim490
-rw-r--r--src/nvim/testdir/test_search_stat.vim128
-rw-r--r--src/nvim/testdir/test_spell.vim42
-rw-r--r--src/nvim/testdir/test_startup.vim26
-rw-r--r--src/nvim/testdir/test_statusline.vim19
-rw-r--r--src/nvim/testdir/test_swap.vim60
-rw-r--r--src/nvim/testdir/test_syntax.vim102
-rw-r--r--src/nvim/testdir/test_tagjump.vim34
-rw-r--r--src/nvim/testdir/test_textformat.vim20
-rw-r--r--src/nvim/testdir/test_textobjects.vim30
-rw-r--r--src/nvim/testdir/test_timers.vim42
-rw-r--r--src/nvim/testdir/test_undo.vim39
-rw-r--r--src/nvim/testdir/test_usercommands.vim229
-rw-r--r--src/nvim/testdir/test_version.vim12
-rw-r--r--src/nvim/testdir/test_vimscript.vim11
-rw-r--r--src/nvim/testdir/test_visual.vim11
-rw-r--r--src/nvim/testdir/test_window_cmd.vim46
-rw-r--r--src/nvim/tui/tui.c210
-rw-r--r--src/nvim/types.h4
-rw-r--r--src/nvim/ui_bridge.c1
-rw-r--r--src/nvim/undo.c10
-rw-r--r--src/nvim/version.c32
-rw-r--r--src/nvim/viml/parser/expressions.c2
-rw-r--r--src/nvim/window.c21
-rw-r--r--src/tree_sitter/alloc.h6
-rw-r--r--src/tree_sitter/lexer.c2
-rw-r--r--src/tree_sitter/parser.c81
-rw-r--r--src/tree_sitter/query.c416
-rw-r--r--src/tree_sitter/stack.c11
-rw-r--r--src/tree_sitter/treesitter_commit_hash.txt2
-rw-r--r--test/functional/api/buffer_spec.lua20
-rw-r--r--test/functional/api/extmark_spec.lua77
-rw-r--r--test/functional/api/highlight_spec.lua12
-rw-r--r--test/functional/api/vim_spec.lua14
-rw-r--r--test/functional/api/window_spec.lua8
-rw-r--r--test/functional/core/exit_spec.lua4
-rw-r--r--test/functional/core/job_spec.lua5
-rw-r--r--test/functional/eval/interrupt_spec.lua6
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua4
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua20
-rw-r--r--test/functional/helpers.lua37
-rw-r--r--test/functional/legacy/005_bufleave_delete_buffer_spec.lua6
-rw-r--r--test/functional/legacy/006_argument_list_spec.lua8
-rw-r--r--test/functional/legacy/012_directory_spec.lua8
-rw-r--r--test/functional/legacy/023_edit_arguments_spec.lua4
-rw-r--r--test/functional/legacy/030_fileformats_spec.lua34
-rw-r--r--test/functional/legacy/033_lisp_indent_spec.lua4
-rw-r--r--test/functional/legacy/036_regexp_character_classes_spec.lua2
-rw-r--r--test/functional/legacy/045_folding_spec.lua4
-rw-r--r--test/functional/legacy/051_highlight_spec.lua4
-rw-r--r--test/functional/legacy/057_sort_spec.lua62
-rw-r--r--test/functional/legacy/074_global_var_in_viminfo_spec.lua6
-rw-r--r--test/functional/legacy/075_maparg_spec.lua4
-rw-r--r--test/functional/legacy/107_adjust_window_and_contents_spec.lua4
-rw-r--r--test/functional/legacy/arglist_spec.lua13
-rw-r--r--test/functional/legacy/autoformat_join_spec.lua4
-rw-r--r--test/functional/legacy/close_count_spec.lua10
-rw-r--r--test/functional/legacy/display_spec.lua31
-rw-r--r--test/functional/legacy/eval_spec.lua10
-rw-r--r--test/functional/legacy/mapping_spec.lua8
-rw-r--r--test/functional/legacy/memory_usage_spec.lua8
-rw-r--r--test/functional/legacy/search_mbyte_spec.lua4
-rw-r--r--test/functional/legacy/search_spec.lua107
-rw-r--r--test/functional/legacy/utf8_spec.lua4
-rw-r--r--test/functional/legacy/visual_mode_spec.lua42
-rw-r--r--test/functional/legacy/wordcount_spec.lua10
-rw-r--r--test/functional/lua/buffer_updates_spec.lua333
-rw-r--r--test/functional/lua/commands_spec.lua2
-rw-r--r--test/functional/lua/luaeval_spec.lua4
-rw-r--r--test/functional/lua/treesitter_spec.lua326
-rw-r--r--test/functional/lua/vim_spec.lua375
-rw-r--r--test/functional/normal/meta_key_spec.lua22
-rw-r--r--test/functional/options/defaults_spec.lua220
-rw-r--r--test/functional/plugin/lsp_spec.lua122
-rw-r--r--test/functional/provider/clipboard_spec.lua10
-rw-r--r--test/functional/provider/perl_spec.lua50
-rw-r--r--test/functional/provider/ruby_spec.lua22
-rw-r--r--test/functional/terminal/buffer_spec.lua4
-rw-r--r--test/functional/terminal/cursor_spec.lua2
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua14
-rw-r--r--test/functional/terminal/scrollback_spec.lua6
-rw-r--r--test/functional/terminal/window_spec.lua4
-rw-r--r--test/functional/ui/bufhl_spec.lua12
-rw-r--r--test/functional/ui/cmdline_spec.lua32
-rw-r--r--test/functional/ui/cursor_spec.lua17
-rw-r--r--test/functional/ui/decorations_spec.lua118
-rw-r--r--test/functional/ui/float_spec.lua2
-rw-r--r--test/functional/ui/fold_spec.lua46
-rw-r--r--test/functional/ui/inccommand_spec.lua58
-rw-r--r--test/functional/ui/messages_spec.lua2
-rw-r--r--test/functional/ui/mouse_spec.lua2
-rw-r--r--test/functional/ui/multigrid_spec.lua8
-rw-r--r--test/functional/ui/options_spec.lua8
-rw-r--r--test/functional/ui/popupmenu_spec.lua44
-rw-r--r--test/functional/ui/searchhl_spec.lua2
-rw-r--r--test/functional/viml/completion_spec.lua48
-rw-r--r--test/functional/viml/errorlist_spec.lua2
-rw-r--r--test/functional/visual/meta_key_spec.lua22
-rw-r--r--test/helpers.lua73
-rw-r--r--test/symbolic/klee/nvim/charset.c4
-rw-r--r--test/unit/os/env_spec.lua13
-rw-r--r--third-party/CMakeLists.txt4
-rw-r--r--unicode/CaseFolding.txt7
-rw-r--r--unicode/EastAsianWidth.txt115
-rw-r--r--unicode/UnicodeData.txt962
-rw-r--r--unicode/emoji-data.txt1908
317 files changed, 20884 insertions, 9385 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 50ef4e6897..90ba2a6d7a 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1,2 @@
-custom: https://salt.bountysource.com/teams/neovim
+github: neovim
+open_collective: neovim
diff --git a/.gitignore b/.gitignore
index 699d493b59..ab301bd336 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,14 @@
# Tools
-.ropeproject/
+/venv/
compile_commands.json
-# Visual Studio
+
+# IDEs
/.vs/
+/.vscode/
+/.idea/
# Build/deps dir
/build/
-/cmake-build-debug/
-/dist/
/.deps/
/tmp/
/.clangd/
@@ -20,8 +21,6 @@ compile_commands.json
*.o
*.so
-tags
-
/src/nvim/po/vim.pot
/src/nvim/po/*.ck
@@ -57,12 +56,12 @@ tags
# local make targets
local.mk
-# runtime/doc
+# Generated from :help docs
+tags
/runtime/doc/*.html
/runtime/doc/tags.ref
/runtime/doc/errors.log
-# Don't include the mpack files.
-/runtime/doc/*.mpack
-# CLion
-/.idea/
+# Generated by gen_vimdoc.py:
+/runtime/doc/*.mpack
+/tmp-*-doc
diff --git a/.travis.yml b/.travis.yml
index b920f70f45..4aebae3986 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-dist: xenial
+dist: bionic
language: c
@@ -99,12 +99,21 @@ jobs:
- stage: baseline
name: clang-asan
os: linux
- compiler: clang
+ compiler: clang-11
# Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6
env:
- CLANG_SANITIZER=ASAN_UBSAN
- CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ - SYMBOLIZER=asan_symbolize-11
- *common-job-env
+ addons:
+ apt:
+ sources:
+ - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
+ key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
+ packages:
+ - *common-apt-packages
+ - clang-11
- name: gcc-coverage (gcc 9)
os: linux
compiler: gcc-9
@@ -116,15 +125,15 @@ jobs:
- BUSTED_ARGS="--coverage"
- *common-job-env
addons:
+ snaps:
+ - name: powershell
+ confinement: classic
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- - sourceline: 'deb [arch=amd64] https://packages.microsoft.com/ubuntu/16.04/prod xenial main'
- key_url: 'https://packages.microsoft.com/keys/microsoft.asc'
packages:
- *common-apt-packages
- gcc-9
- - powershell
- if: branch = master AND commit_message !~ /\[skip.lint\]/
name: lint
os: linux
@@ -193,6 +202,7 @@ jobs:
- LANG: C.UTF-8
- SNAPCRAFT_ENABLE_SILENT_REPORT: y
- SNAPCRAFT_ENABLE_DEVELOPER_DEBUG: y
+ - SNAPCRAFT_BUILD_ENVIRONMENT: lxd
addons:
snaps:
- name: snapcraft
@@ -221,6 +231,7 @@ jobs:
- LANG: C.UTF-8
- SNAPCRAFT_ENABLE_SILENT_REPORT: y
- SNAPCRAFT_ENABLE_DEVELOPER_DEBUG: y
+ - SNAPCRAFT_BUILD_ENVIRONMENT: lxd
fast_finish: true
before_install: ci/before_install.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a4e49ccfc5..87dff54d06 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -267,8 +267,8 @@ else()
-Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion
-Wmissing-prototypes)
- check_c_compiler_flag(-Wimplicit-fallthrough HAS_WIMPLICIT_FALLTHROUGH_FLAG)
- if(HAS_WIMPLICIT_FALLTHROUGH_FLAG)
+ check_c_compiler_flag(-Wimplicit-fallthrough HAVE_WIMPLICIT_FALLTHROUGH_FLAG)
+ if(HAVE_WIMPLICIT_FALLTHROUGH_FLAG)
add_compile_options(-Wimplicit-fallthrough)
endif()
diff --git a/ci/before_install.sh b/ci/before_install.sh
index 1cf60edf73..c3fd8bdbde 100755
--- a/ci/before_install.sh
+++ b/ci/before_install.sh
@@ -22,7 +22,7 @@ if [[ "${TRAVIS_OS_NAME}" != osx ]] && command -v pyenv; then
echo 'Setting Python versions via pyenv'
# Prefer Python 2 over 3 (more conservative).
- pyenv global 2.7.15:3.7.1
+ pyenv global 2.7:3.8
echo 'Updated Python info:'
(
diff --git a/ci/build.ps1 b/ci/build.ps1
index 36570be7ae..08fc76393d 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -116,7 +116,7 @@ if (-not $NoTests) {
python3 -c "import pynvim; print(str(pynvim))" ; exitIfFailed
$env:PATH = "C:\Ruby24\bin;$env:PATH"
- gem.cmd install neovim
+ gem.cmd install --pre neovim
Get-Command -CommandType Application neovim-ruby-host.bat
npm.cmd install -g neovim
diff --git a/ci/common/test.sh b/ci/common/test.sh
index b2fbeaf2da..4ef6260339 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -82,7 +82,7 @@ valgrind_check() {
check_sanitizer() {
if test -n "${CLANG_SANITIZER}"; then
- check_logs "${1}" "*san.*"
+ check_logs "${1}" "*san.*" | ${SYMBOLIZER:-cat}
fi
}
diff --git a/ci/install.sh b/ci/install.sh
index a4dfc87a1b..efb37cea4e 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -19,7 +19,7 @@ echo "Install neovim module for Python 2."
CC=cc python2 -m pip -q install --user --upgrade pynvim
echo "Install neovim RubyGem."
-gem install --no-document --version ">= 0.8.0" neovim
+gem install --no-document --pre neovim
echo "Install neovim npm package"
source ~/.nvm/nvm.sh
diff --git a/ci/snap/.snapcraft_payload b/ci/snap/.snapcraft_payload
new file mode 100644
index 0000000000..29f895fad6
--- /dev/null
+++ b/ci/snap/.snapcraft_payload
@@ -0,0 +1,194 @@
+{
+ "ref": "refs/heads/master",
+ "before": "66b136c43c12df3dcf8f19ff48f206ad2e4f43fc",
+ "after": "1bf69c32217cc455603ce8aa2b5415d9717f0fa2",
+ "repository": {
+ "id": 292861950,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyOTI4NjE5NTA=",
+ "name": "neovim-snap",
+ "full_name": "hurricanehrndz/neovim-snap",
+ "private": false,
+ "owner": {
+ "name": "hurricanehrndz",
+ "email": "hurricanehrndz@users.noreply.github.com",
+ "login": "hurricanehrndz",
+ "id": 5804237,
+ "node_id": "MDQ6VXNlcjU4MDQyMzc=",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/5804237?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/hurricanehrndz",
+ "html_url": "https://github.com/hurricanehrndz",
+ "followers_url": "https://api.github.com/users/hurricanehrndz/followers",
+ "following_url": "https://api.github.com/users/hurricanehrndz/following{/other_user}",
+ "gists_url": "https://api.github.com/users/hurricanehrndz/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/hurricanehrndz/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/hurricanehrndz/subscriptions",
+ "organizations_url": "https://api.github.com/users/hurricanehrndz/orgs",
+ "repos_url": "https://api.github.com/users/hurricanehrndz/repos",
+ "events_url": "https://api.github.com/users/hurricanehrndz/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/hurricanehrndz/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/hurricanehrndz/neovim-snap",
+ "description": "snap build for neovim",
+ "fork": false,
+ "url": "https://github.com/hurricanehrndz/neovim-snap",
+ "forks_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/forks",
+ "keys_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/teams",
+ "hooks_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/hooks",
+ "issue_events_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/events",
+ "assignees_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/tags",
+ "blobs_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/languages",
+ "stargazers_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/stargazers",
+ "contributors_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/contributors",
+ "subscribers_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/subscribers",
+ "subscription_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/subscription",
+ "commits_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/merges",
+ "archive_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/downloads",
+ "issues_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/labels{/name}",
+ "releases_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/hurricanehrndz/neovim-snap/deployments",
+ "created_at": 1599227980,
+ "updated_at": "2020-09-04T14:02:38Z",
+ "pushed_at": 1599228352,
+ "git_url": "git://github.com/hurricanehrndz/neovim-snap.git",
+ "ssh_url": "git@github.com:hurricanehrndz/neovim-snap.git",
+ "clone_url": "https://github.com/hurricanehrndz/neovim-snap.git",
+ "svn_url": "https://github.com/hurricanehrndz/neovim-snap",
+ "homepage": null,
+ "size": 0,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": true,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": true,
+ "has_pages": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 0,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "stargazers": 0,
+ "master_branch": "master"
+ },
+ "pusher": {
+ "name": "hurricanehrndz",
+ "email": "hurricanehrndz@users.noreply.github.com"
+ },
+ "sender": {
+ "login": "hurricanehrndz",
+ "id": 5804237,
+ "node_id": "MDQ6VXNlcjU4MDQyMzc=",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/5804237?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/hurricanehrndz",
+ "html_url": "https://github.com/hurricanehrndz",
+ "followers_url": "https://api.github.com/users/hurricanehrndz/followers",
+ "following_url": "https://api.github.com/users/hurricanehrndz/following{/other_user}",
+ "gists_url": "https://api.github.com/users/hurricanehrndz/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/hurricanehrndz/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/hurricanehrndz/subscriptions",
+ "organizations_url": "https://api.github.com/users/hurricanehrndz/orgs",
+ "repos_url": "https://api.github.com/users/hurricanehrndz/repos",
+ "events_url": "https://api.github.com/users/hurricanehrndz/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/hurricanehrndz/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "created": false,
+ "deleted": false,
+ "forced": false,
+ "base_ref": null,
+ "compare": "https://github.com/hurricanehrndz/neovim-snap/compare/66b136c43c12...1bf69c32217c",
+ "commits": [
+ {
+ "id": "1bf69c32217cc455603ce8aa2b5415d9717f0fa2",
+ "tree_id": "62ea83a2349be8c930c45fdc199f71b08bf5927e",
+ "distinct": true,
+ "message": "Build of latest tag",
+ "timestamp": "2020-09-04T14:05:40Z",
+ "url": "https://github.com/hurricanehrndz/neovim-snap/commit/1bf69c32217cc455603ce8aa2b5415d9717f0fa2",
+ "author": {
+ "name": "Carlos Hernandez",
+ "email": "carlos@techbyte.ca",
+ "username": "hurricanehrndz"
+ },
+ "committer": {
+ "name": "Carlos Hernandez",
+ "email": "carlos@techbyte.ca",
+ "username": "hurricanehrndz"
+ },
+ "added": [
+
+ ],
+ "removed": [
+
+ ],
+ "modified": [
+ "snap/snapcraft.yaml"
+ ]
+ }
+ ],
+ "head_commit": {
+ "id": "1bf69c32217cc455603ce8aa2b5415d9717f0fa2",
+ "tree_id": "62ea83a2349be8c930c45fdc199f71b08bf5927e",
+ "distinct": true,
+ "message": "Build of latest tag",
+ "timestamp": "2020-09-04T14:05:40Z",
+ "url": "https://github.com/hurricanehrndz/neovim-snap/commit/1bf69c32217cc455603ce8aa2b5415d9717f0fa2",
+ "author": {
+ "name": "Carlos Hernandez",
+ "email": "carlos@techbyte.ca",
+ "username": "hurricanehrndz"
+ },
+ "committer": {
+ "name": "Carlos Hernandez",
+ "email": "carlos@techbyte.ca",
+ "username": "hurricanehrndz"
+ },
+ "added": [
+
+ ],
+ "removed": [
+
+ ],
+ "modified": [
+ "snap/snapcraft.yaml"
+ ]
+ }
+}
diff --git a/ci/snap/deploy.sh b/ci/snap/deploy.sh
index 5fbd52d775..579c48e933 100755
--- a/ci/snap/deploy.sh
+++ b/ci/snap/deploy.sh
@@ -3,19 +3,37 @@
set -e
set -o pipefail
-# not a tagged release, abort
-# [[ "$TRAVIS_TAG" != "$TRAVIS_BRANCH" ]] && exit 0
+SNAP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+WEBHOOK_PAYLOAD="$(cat "${SNAP_DIR}/.snapcraft_payload")"
+PAYLOAD_SIG="${SECRET_SNAP_SIG}"
-mkdir -p .snapcraft
-# shellcheck disable=SC2154
-openssl aes-256-cbc -K "$encrypted_ece1c4844832_key" -iv "$encrypted_ece1c4844832_iv" \
- -in ci/snap/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
-SNAP=$(find ./ -name "*.snap")
+snap_realease_needed() {
+ last_committed_tag="$(git tag -l --sort=refname|head -1)"
+ last_snap_release="$(snap info nvim | awk '$1 == "latest/edge:" { print $2 }' | perl -lpe 's/v\d.\d.\d-//g')"
+ git fetch -f --tags
+ git checkout "${last_committed_tag}" 2> /dev/null
+ last_git_release="$(git describe --first-parent 2> /dev/null | perl -lpe 's/v\d.\d.\d-//g')"
-# TODO(justinmk): This always does `edge` until we enable tagged builds.
-if [[ "$SNAP" =~ "dirty" || "$SNAP" =~ "nightly" ]]; then
- snapcraft push "$SNAP" --release edge
-else
- snapcraft push "$SNAP" --release candidate
+ if [[ -z "$(echo $last_snap_release | perl -ne "print if /${last_git_release}.*/")" ]]; then
+ return 0
+ fi
+ return 1
+}
+
+
+trigger_snapcraft_webhook() {
+ [[ -n "${PAYLOAD_SIG}" ]] || exit
+ echo "Triggering new snap relase via webhook..."
+ curl -X POST \
+ -H "Content-Type: application/json" \
+ -H "X-Hub-Signature: sha1=${PAYLOAD_SIG}" \
+ --data "${WEBHOOK_PAYLOAD}" \
+ https://snapcraft.io/nvim/webhook/notify
+}
+
+
+if $(snap_realease_needed); then
+ echo "New snap release required"
+ trigger_snapcraft_webhook
fi
diff --git a/ci/snap/install.sh b/ci/snap/install.sh
index 23e0bc5eb8..0ceb6f0422 100755
--- a/ci/snap/install.sh
+++ b/ci/snap/install.sh
@@ -4,6 +4,7 @@ set -e
set -o pipefail
sudo apt update
+sudo usermod -aG lxd $USER
sudo /snap/bin/lxd.migrate -yes
sudo /snap/bin/lxd waitready
sudo /snap/bin/lxd init --auto
diff --git a/ci/snap/script.sh b/ci/snap/script.sh
index 647cda4874..f0d45fea00 100755
--- a/ci/snap/script.sh
+++ b/ci/snap/script.sh
@@ -4,5 +4,5 @@ set -e
set -o pipefail
mkdir -p "$TRAVIS_BUILD_DIR/snaps-cache"
-sudo snapcraft --use-lxd
+sg lxd -c snapcraft
diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake
index b669a49f29..7ba13e1f56 100644
--- a/cmake/FindLua.cmake
+++ b/cmake/FindLua.cmake
@@ -42,7 +42,7 @@ unset(_lua_append_versions)
# this is a function only to have all the variables inside go away automatically
function(_lua_set_version_vars)
- set(LUA_VERSIONS5 5.3 5.2 5.1 5.0)
+ set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0)
if (Lua_FIND_VERSION_EXACT)
if (Lua_FIND_VERSION_COUNT GREATER 1)
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 6c9e06d59d..8a70d864c4 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -32,6 +32,7 @@ endif()
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
check_include_files(termios.h HAVE_TERMIOS_H)
check_include_files(sys/uio.h HAVE_SYS_UIO_H)
+check_include_files(sys/sdt.h HAVE_SYS_SDT_H)
# Functions
check_function_exists(fseeko HAVE_FSEEKO)
diff --git a/config/config.h.in b/config/config.h.in
index 0cb87c6b4d..95e2c872a3 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -33,6 +33,7 @@
#cmakedefine HAVE_STRCASECMP
#cmakedefine HAVE_STRINGS_H
#cmakedefine HAVE_STRNCASECMP
+#cmakedefine HAVE_SYS_SDT_H
#cmakedefine HAVE_SYS_UTSNAME_H
#cmakedefine HAVE_SYS_WAIT_H
#cmakedefine HAVE_TERMIOS_H
@@ -60,5 +61,6 @@
#cmakedefine HAVE_EXECINFO_BACKTRACE
#cmakedefine HAVE_BUILTIN_ADD_OVERFLOW
+#cmakedefine HAVE_WIMPLICIT_FALLTHROUGH_FLAG
#endif // AUTO_CONFIG_H
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index e85ffc763b..b6297472c3 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -575,7 +575,7 @@ endfunc
let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
func dist#ft#FTRules()
let path = expand('<amatch>:p')
- if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
+ if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
setf udevrules
return
endif
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 0482cb7f3c..e8e38f581f 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -573,7 +573,7 @@ function! s:check_ruby() abort
endif
call health#report_info('Ruby: '. s:system('ruby -v'))
- let host = provider#ruby#Detect()
+ let [host, err] = provider#ruby#Detect()
if empty(host)
call health#report_warn('`neovim-ruby-host` not found.',
\ ['Run `gem install neovim` to ensure the neovim RubyGem is installed.',
@@ -636,7 +636,7 @@ function! s:check_node() abort
call health#report_warn('node.js on this system does not support --inspect-brk so $NVIM_NODE_HOST_DEBUG is ignored.')
endif
- let host = provider#node#Detect()
+ let [host, err] = provider#node#Detect()
if empty(host)
call health#report_warn('Missing "neovim" npm (or yarn) package.',
\ ['Run in shell: npm install -g neovim',
@@ -689,29 +689,31 @@ function! s:check_perl() abort
return
endif
- if !executable('perl') || !executable('cpanm')
- call health#report_warn(
- \ '`perl` and `cpanm` must be in $PATH.',
- \ ['Install Perl and cpanminus and verify that `perl` and `cpanm` commands work.'])
- return
+ let [perl_exec, perl_errors] = provider#perl#Detect()
+ if empty(perl_exec)
+ if !empty(perl_errors)
+ call health#report_error('perl provider error:', perl_errors)
+ else
+ call health#report_warn('No usable perl executable found')
+ endif
+ return
endif
- let perl_v = get(split(s:system(['perl', '-W', '-e', 'print $^V']), "\n"), 0, '')
- call health#report_info('Perl: '. perl_v)
+
+ call health#report_info('perl executable: '. perl_exec)
+
+ " we cannot use cpanm that is on the path, as it may not be for the perl
+ " set with g:perl_host_prog
+ call s:system([perl_exec, '-W', '-MApp::cpanminus', '-e', ''])
if s:shell_error
- call health#report_warn('Nvim perl host does not support '.perl_v)
- " Skip further checks, they are nonsense if perl is too old.
- return
+ return [perl_exec, '"App::cpanminus" module is not installed']
endif
- let host = provider#perl#Detect()
- if empty(host)
- call health#report_warn('Missing "Neovim::Ext" cpan module.',
- \ ['Run in shell: cpanm Neovim::Ext'])
- return
- endif
- call health#report_info('Nvim perl host: '. host)
+ let latest_cpan_cmd = [perl_exec,
+ \ '-MApp::cpanminus::fatscript', '-e',
+ \ 'my $app = App::cpanminus::script->new;
+ \ $app->parse_options ("--info", "-q", "Neovim::Ext");
+ \ exit $app->doit']
- let latest_cpan_cmd = 'cpanm --info -q Neovim::Ext'
let latest_cpan = s:system(latest_cpan_cmd)
if s:shell_error || empty(latest_cpan)
call health#report_error('Failed to run: '. latest_cpan_cmd,
@@ -735,7 +737,7 @@ function! s:check_perl() abort
return
endif
- let current_cpan_cmd = [host, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION']
+ let current_cpan_cmd = [perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION']
let current_cpan = s:system(current_cpan_cmd)
if s:shell_error
call health#report_error('Failed to run: '. string(current_cpan_cmd),
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index a96a0a61b7..275d18a5a9 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -35,8 +35,7 @@ endfunction
let s:selections = { '*': s:selection, '+': copy(s:selection) }
function! s:try_cmd(cmd, ...) abort
- let argv = split(a:cmd, " ")
- let out = systemlist(argv, (a:0 ? a:1 : ['']), 1)
+ let out = systemlist(a:cmd, (a:0 ? a:1 : ['']), 1)
if v:shell_error
if !exists('s:did_error_try_cmd')
echohl WarningMsg
@@ -55,6 +54,10 @@ function! s:cmd_ok(cmd) abort
return v:shell_error == 0
endfunction
+function! s:split_cmd(cmd) abort
+ return (type(a:cmd) == v:t_string) ? split(a:cmd, " ") : a:cmd
+endfunction
+
let s:cache_enabled = 1
let s:err = ''
@@ -71,44 +74,50 @@ function! provider#clipboard#Executable() abort
return ''
endif
- let s:copy = get(g:clipboard, 'copy', { '+': v:null, '*': v:null })
- let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null })
+ let s:copy = {}
+ let s:copy['+'] = s:split_cmd(get(g:clipboard.copy, '+', v:null))
+ let s:copy['*'] = s:split_cmd(get(g:clipboard.copy, '*', v:null))
+
+ let s:paste = {}
+ let s:paste['+'] = s:split_cmd(get(g:clipboard.paste, '+', v:null))
+ let s:paste['*'] = s:split_cmd(get(g:clipboard.paste, '*', v:null))
+
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
return get(g:clipboard, 'name', 'g:clipboard')
elseif has('mac')
- let s:copy['+'] = 'pbcopy'
- let s:paste['+'] = 'pbpaste'
+ let s:copy['+'] = ['pbcopy']
+ let s:paste['+'] = ['pbpaste']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
let s:cache_enabled = 0
return 'pbcopy'
elseif exists('$WAYLAND_DISPLAY') && executable('wl-copy') && executable('wl-paste')
- let s:copy['+'] = 'wl-copy --foreground --type text/plain'
- let s:paste['+'] = 'wl-paste --no-newline'
- let s:copy['*'] = 'wl-copy --foreground --primary --type text/plain'
- let s:paste['*'] = 'wl-paste --no-newline --primary'
+ let s:copy['+'] = ['wl-copy', '--foreground', '--type', 'text/plain']
+ let s:paste['+'] = ['wl-paste', '--no-newline']
+ let s:copy['*'] = ['wl-copy', '--foreground', '--primary', '--type', 'text/plain']
+ let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
return 'wl-copy'
elseif exists('$DISPLAY') && executable('xclip')
- let s:copy['+'] = 'xclip -quiet -i -selection clipboard'
- let s:paste['+'] = 'xclip -o -selection clipboard'
- let s:copy['*'] = 'xclip -quiet -i -selection primary'
- let s:paste['*'] = 'xclip -o -selection primary'
+ let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
+ let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
+ let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
+ let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
return 'xclip'
elseif exists('$DISPLAY') && executable('xsel') && s:cmd_ok('xsel -o -b')
- let s:copy['+'] = 'xsel --nodetach -i -b'
- let s:paste['+'] = 'xsel -o -b'
- let s:copy['*'] = 'xsel --nodetach -i -p'
- let s:paste['*'] = 'xsel -o -p'
+ let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
+ let s:paste['+'] = ['xsel', '-o', '-b']
+ let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
+ let s:paste['*'] = ['xsel', '-o', '-p']
return 'xsel'
elseif executable('lemonade')
- let s:copy['+'] = 'lemonade copy'
- let s:paste['+'] = 'lemonade paste'
- let s:copy['*'] = 'lemonade copy'
- let s:paste['*'] = 'lemonade paste'
+ let s:copy['+'] = ['lemonade', 'copy']
+ let s:paste['+'] = ['lemonade', 'paste']
+ let s:copy['*'] = ['lemonade', 'copy']
+ let s:paste['*'] = ['lemonade', 'paste']
return 'lemonade'
elseif executable('doitclient')
- let s:copy['+'] = 'doitclient wclip'
- let s:paste['+'] = 'doitclient wclip -r'
+ let s:copy['+'] = ['doitclient', 'wclip']
+ let s:paste['+'] = ['doitclient', 'wclip', '-r']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'doitclient'
@@ -118,14 +127,14 @@ function! provider#clipboard#Executable() abort
else
let win32yank = 'win32yank.exe'
endif
- let s:copy['+'] = win32yank.' -i --crlf'
- let s:paste['+'] = win32yank.' -o --lf'
+ let s:copy['+'] = [win32yank, '-i', '--crlf']
+ let s:paste['+'] = [win32yank, '-o', '--lf']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'win32yank'
elseif exists('$TMUX') && executable('tmux')
- let s:copy['+'] = 'tmux load-buffer -'
- let s:paste['+'] = 'tmux save-buffer -'
+ let s:copy['+'] = ['tmux', 'load-buffer', '-']
+ let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'tmux'
@@ -169,16 +178,15 @@ function! s:clipboard.set(lines, regtype, reg) abort
let s:selections[a:reg] = copy(s:selection)
let selection = s:selections[a:reg]
let selection.data = [a:lines, a:regtype]
- let argv = split(s:copy[a:reg], " ")
- let selection.argv = argv
+ let selection.argv = s:copy[a:reg]
let selection.detach = s:cache_enabled
let selection.cwd = "/"
- let jobid = jobstart(argv, selection)
+ let jobid = jobstart(selection.argv, selection)
if jobid > 0
call jobsend(jobid, a:lines)
call jobclose(jobid, 'stdin')
" xclip does not close stdout when receiving input via stdin
- if argv[0] ==# 'xclip'
+ if selection.argv[0] ==# 'xclip'
call jobclose(jobid, 'stdout')
endif
let selection.owner = jobid
diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim
index c5d5e87729..17b6137816 100644
--- a/runtime/autoload/provider/node.vim
+++ b/runtime/autoload/provider/node.vim
@@ -48,14 +48,15 @@ function! provider#node#can_inspect() abort
endfunction
function! provider#node#Detect() abort
+ let minver = [6, 0]
if exists('g:node_host_prog')
- return expand(g:node_host_prog)
+ return [expand(g:node_host_prog), '']
endif
if !executable('node')
- return ''
+ return ['', 'node not found (or not executable)']
endif
- if !s:is_minimum_version(v:null, 6, 0)
- return ''
+ if !s:is_minimum_version(v:null, minver[0], minver[1])
+ return ['', printf('node version %s.%s not found', minver[0], minver[1])]
endif
let npm_opts = {}
@@ -75,7 +76,7 @@ function! provider#node#Detect() abort
if has('unix')
let yarn_default_path = $HOME . '/.config/yarn/global/' . yarn_opts.entry_point
if filereadable(yarn_default_path)
- return yarn_default_path
+ return [yarn_default_path, '']
endif
endif
let yarn_opts.job_id = jobstart('yarn global dir', yarn_opts)
@@ -85,18 +86,18 @@ function! provider#node#Detect() abort
if !empty(npm_opts)
let result = jobwait([npm_opts.job_id])
if result[0] == 0 && npm_opts.result != ''
- return npm_opts.result
+ return [npm_opts.result, '']
endif
endif
if !empty(yarn_opts)
let result = jobwait([yarn_opts.job_id])
if result[0] == 0 && yarn_opts.result != ''
- return yarn_opts.result
+ return [yarn_opts.result, '']
endif
endif
- return ''
+ return ['', 'failed to detect node']
endfunction
function! provider#node#Prog() abort
@@ -142,7 +143,7 @@ endfunction
let s:err = ''
-let s:prog = provider#node#Detect()
+let [s:prog, s:_] = provider#node#Detect()
let g:loaded_node_provider = empty(s:prog) ? 1 : 2
if g:loaded_node_provider != 2
diff --git a/runtime/autoload/provider/perl.vim b/runtime/autoload/provider/perl.vim
index 36ca2bbf14..24f2b018bb 100644
--- a/runtime/autoload/provider/perl.vim
+++ b/runtime/autoload/provider/perl.vim
@@ -5,15 +5,25 @@ endif
let s:loaded_perl_provider = 1
function! provider#perl#Detect() abort
- " use g:perl_host_prof if set or check if perl is on the path
+ " use g:perl_host_prog if set or check if perl is on the path
let prog = exepath(get(g:, 'perl_host_prog', 'perl'))
if empty(prog)
- return ''
+ return ['', '']
+ endif
+
+ " if perl is available, make sure we have 5.22+
+ call system([prog, '-e', 'use v5.22'])
+ if v:shell_error
+ return ['', 'Perl version is too old, 5.22+ required']
endif
" if perl is available, make sure the required module is available
call system([prog, '-W', '-MNeovim::Ext', '-e', ''])
- return v:shell_error ? '' : prog
+ if v:shell_error
+ return ['', '"Neovim::Ext" cpan module is not installed']
+ endif
+
+ return [prog, '']
endfunction
function! provider#perl#Prog() abort
@@ -46,7 +56,7 @@ function! provider#perl#Call(method, args) abort
if !exists('s:host')
try
- let s:host = remote#host#Require('perl')
+ let s:host = remote#host#Require('legacy-perl-provider')
catch
let s:err = v:exception
echohl WarningMsg
@@ -58,12 +68,16 @@ function! provider#perl#Call(method, args) abort
return call('rpcrequest', insert(insert(a:args, 'perl_'.a:method), s:host))
endfunction
-let s:err = ''
-let s:prog = provider#perl#Detect()
+let [s:prog, s:err] = provider#perl#Detect()
let g:loaded_perl_provider = empty(s:prog) ? 1 : 2
if g:loaded_perl_provider != 2
let s:err = 'Cannot find perl or the required perl module'
endif
-call remote#host#RegisterPlugin('perl-provider', 'perl', [])
+
+" The perl provider plugin will run in a separate instance of the perl
+" host.
+call remote#host#RegisterClone('legacy-perl-provider', 'perl')
+call remote#host#RegisterPlugin('legacy-perl-provider', 'ScriptHost.pm', [])
+
diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim
index e89d519790..550931d8aa 100644
--- a/runtime/autoload/provider/pythonx.vim
+++ b/runtime/autoload/provider/pythonx.vim
@@ -29,8 +29,8 @@ endfunction
function! s:get_python_candidates(major_version) abort
return {
\ 2: ['python2', 'python2.7', 'python2.6', 'python'],
- \ 3: ['python3', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'python3.5',
- \ 'python3.4', 'python3.3', 'python']
+ \ 3: ['python3', 'python3.10', 'python3.9', 'python3.8', 'python3.7',
+ \ 'python3.6', 'python']
\ }[a:major_version]
endfunction
diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim
index f843050df9..1f49c623ac 100644
--- a/runtime/autoload/provider/ruby.vim
+++ b/runtime/autoload/provider/ruby.vim
@@ -5,7 +5,8 @@ endif
let g:loaded_ruby_provider = 1
function! provider#ruby#Detect() abort
- return s:prog
+ let e = empty(s:prog) ? 'missing ruby or ruby-host' : ''
+ return [s:prog, e]
endfunction
function! provider#ruby#Prog() abort
diff --git a/runtime/autoload/spellfile.vim b/runtime/autoload/spellfile.vim
index d098902305..e36e2f936b 100644
--- a/runtime/autoload/spellfile.vim
+++ b/runtime/autoload/spellfile.vim
@@ -1,13 +1,9 @@
" Vim script to download a missing spell file
if !exists('g:spellfile_URL')
- " Prefer using http:// when netrw should be able to use it, since
- " more firewalls let this through.
- if executable("curl") || executable("wget") || executable("fetch")
- let g:spellfile_URL = 'http://ftp.vim.org/pub/vim/runtime/spell'
- else
- let g:spellfile_URL = 'ftp://ftp.vim.org/pub/vim/runtime/spell'
- endif
+ " Always use https:// because it's secure. The certificate is for nluug.nl,
+ " thus we can't use the alias ftp.vim.org here.
+ let g:spellfile_URL = 'https://ftp.nluug.nl/pub/vim/runtime/spell'
endif
let s:spellfile_URL = '' " Start with nothing so that s:donedict is reset.
diff --git a/runtime/compiler/ts-node.vim b/runtime/compiler/ts-node.vim
new file mode 100644
index 0000000000..14f0ea790c
--- /dev/null
+++ b/runtime/compiler/ts-node.vim
@@ -0,0 +1,29 @@
+" Vim compiler file
+" Compiler: TypeScript Runner
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2020 Feb 10
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "node"
+
+if exists(":CompilerSet") != 2 " older Vim always used :setlocal
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=npx\ ts-node
+
+CompilerSet makeprg=ts-node
+CompilerSet errorformat=%f\ %#(%l\\,%c):\ %trror\ TS%n:\ %m,
+ \%E%f:%l,
+ \%+Z%\\w%\\+Error:\ %.%#,
+ \%C%p^%\\+,
+ \%C%.%#,
+ \%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/compiler/tsc.vim b/runtime/compiler/tsc.vim
new file mode 100644
index 0000000000..a246fc7751
--- /dev/null
+++ b/runtime/compiler/tsc.vim
@@ -0,0 +1,26 @@
+" Vim compiler file
+" Compiler: TypeScript Compiler
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2020 Feb 10
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "tsc"
+
+if exists(":CompilerSet") != 2 " older Vim always used :setlocal
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=npx\ tsc
+
+CompilerSet makeprg=tsc
+CompilerSet errorformat=%f\ %#(%l\\,%c):\ %trror\ TS%n:\ %m,
+ \%trror\ TS%n:\ %m,
+ \%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/compiler/xo.vim b/runtime/compiler/xo.vim
new file mode 100644
index 0000000000..525657d4bb
--- /dev/null
+++ b/runtime/compiler/xo.vim
@@ -0,0 +1,26 @@
+" Vim compiler file
+" Compiler: XO
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Jul 10
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "xo"
+
+if exists(":CompilerSet") != 2 " older Vim always used :setlocal
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=npx\ xo\ --reporter\ compact
+
+CompilerSet makeprg=xo\ --reporter\ compact
+CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %trror\ %m,
+ \%f:\ line\ %l\\,\ col\ %c\\,\ %tarning\ %m,
+ \%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index ea3a8242ae..0c726ddd86 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -70,7 +70,7 @@ Nvim instance:
nvim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
result = nvim.call(:nvim_command, 'echo "hello world!"')
<
-A better way is to use the Python REPL with the `neovim` package, where API
+A better way is to use the Python REPL with the "pynvim" package, where API
functions can be called interactively:
>
>>> from pynvim import attach
@@ -336,7 +336,7 @@ callbacks. These callbacks are called frequently in various contexts;
|textlock| prevents changing buffer contents and window layout (use
|vim.schedule| to defer such operations to the main loop instead).
-|nvim_buf_attach| will take keyword args for the callbacks. "on_lines" will
+|nvim_buf_attach()| will take keyword args for the callbacks. "on_lines" will
receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline},
{new_lastline}, {old_byte_size}[, {old_utf32_size}, {old_utf16_size}]).
Unlike remote channel events the text contents are not passed. The new text can
@@ -355,7 +355,7 @@ was changed. The parameters recieved are ("changedtick", {buf}, {changedtick}).
*api-lua-detach*
In-process Lua callbacks can detach by returning `true`. This will detach all
-callbacks attached with the same |nvim_buf_attach| call.
+callbacks attached with the same |nvim_buf_attach()| call.
==============================================================================
@@ -529,13 +529,11 @@ nvim__id_float({flt}) *nvim__id_float()*
nvim__inspect_cell({grid}, {row}, {col}) *nvim__inspect_cell()*
TODO: Documentation
- *nvim__put_attr()*
-nvim__put_attr({id}, {start_row}, {start_col}, {end_row}, {end_col})
- Set attrs in nvim__buf_set_lua_hl callbacks
+nvim__screenshot({path}) *nvim__screenshot()*
+ TODO: Documentation
- TODO(bfredl): This is rather pedestrian. The final interface
- should probably be derived from a reformed bufhl/virttext
- interface with full support for multi-line ranges etc
+ Attributes: ~
+ {fast}
nvim__stats() *nvim__stats()*
Gets internal stats.
@@ -734,13 +732,14 @@ nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
On execution error: does not fail, but updates v:errmsg.
- If you need to input sequences like <C-o> use nvim_replace_termcodes
- to replace the termcodes and then pass the resulting string to
- nvim_feedkeys. You'll also want to enable escape_csi.
+ If you need to input sequences like <C-o> use
+ |nvim_replace_termcodes| to replace the termcodes and then
+ pass the resulting string to nvim_feedkeys. You'll also want
+ to enable escape_csi.
Example: >
- :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
- :call nvim_feedkeys(key, 'n', v:true)
+ :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
+ :call nvim_feedkeys(key, 'n', v:true)
<
Parameters: ~
@@ -1473,6 +1472,53 @@ nvim_set_current_win({window}) *nvim_set_current_win()*
Parameters: ~
{window} Window handle
+ *nvim_set_decoration_provider()*
+nvim_set_decoration_provider({ns_id}, {opts})
+ Set or change decoration provider for a namespace
+
+ This is a very general purpose interface for having lua
+ callbacks being triggered during the redraw code.
+
+ The expected usage is to set extmarks for the currently
+ redrawn buffer. |nvim_buf_set_extmark| can be called to add
+ marks on a per-window or per-lines basis. Use the `ephemeral`
+ key to only use the mark for the current screen redraw (the
+ callback will be called again for the next redraw ).
+
+ Note: this function should not be called often. Rather, the
+ callbacks themselves can be used to throttle unneeded
+ callbacks. the `on_start` callback can return `false` to
+ disable the provider until the next redraw. Similarily, return
+ `false` in `on_win` will skip the `on_lines` calls for that
+ window (but any extmarks set in `on_win` will still be used).
+ A plugin managing multiple sources of decorations should
+ ideally only set one provider, and merge the sources
+ internally. You can use multiple `ns_id` for the extmarks
+ set/modified inside the callback anyway.
+
+ Note: doing anything other than setting extmarks is considered
+ experimental. Doing things like changing options are not
+ expliticly forbidden, but is likely to have unexpected
+ consequences (such as 100% CPU consumption). doing
+ `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite
+ dubious for the moment.
+
+ Parameters: ~
+ {ns_id} Namespace id from |nvim_create_namespace()|
+ {opts} Callbacks invoked during redraw:
+ โ€ข on_start: called first on each screen redraw
+ ["start", tick]
+ โ€ข on_buf: called for each buffer being redrawn
+ (before window callbacks) ["buf", bufnr, tick]
+ โ€ข on_win: called when starting to redraw a
+ specific window. ["win", winid, bufnr, topline,
+ botline_guess]
+ โ€ข on_line: called for each buffer line being
+ redrawn. (The interation with fold lines is
+ subject to change) ["win", winid, bufnr, row]
+ โ€ข on_end: called at the end of a redraw cycle
+ ["end", tick]
+
nvim_set_keymap({mode}, {lhs}, {rhs}, {opts}) *nvim_set_keymap()*
Sets a global |mapping| for the given mode.
@@ -1564,28 +1610,10 @@ affected.
You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()|
to check whether a buffer is loaded.
- *nvim__buf_add_decoration()*
-nvim__buf_add_decoration({buffer}, {ns_id}, {hl_group}, {start_row},
- {start_col}, {end_row}, {end_col},
- {virt_text})
- TODO: Documentation
-
*nvim__buf_redraw_range()*
nvim__buf_redraw_range({buffer}, {first}, {last})
TODO: Documentation
-nvim__buf_set_luahl({buffer}, {opts}) *nvim__buf_set_luahl()*
- Unstabilized interface for defining syntax hl in lua.
-
- This is not yet safe for general use, lua callbacks will need
- to be restricted, like textlock and probably other stuff.
-
- The API on_line/nvim__put_attr is quite raw and not intended
- to be the final shape. Ideally this should operate on chunks
- larger than a single line to reduce interpreter overhead, and
- generate annotation objects (bufhl/virttext) on the fly but
- using the same representation.
-
nvim__buf_stats({buffer}) *nvim__buf_stats()*
TODO: Documentation
@@ -1602,19 +1630,20 @@ nvim_buf_add_highlight({buffer}, {src_id}, {hl_group}, {line},
marks do.
Namespaces are used for batch deletion/updating of a set of
- highlights. To create a namespace, use |nvim_create_namespace|
- which returns a namespace id. Pass it in to this function as
- `ns_id` to add highlights to the namespace. All highlights in
- the same namespace can then be cleared with single call to
- |nvim_buf_clear_namespace|. If the highlight never will be
- deleted by an API call, pass `ns_id = -1` .
+ highlights. To create a namespace, use
+ |nvim_create_namespace()| which returns a namespace id. Pass
+ it in to this function as `ns_id` to add highlights to the
+ namespace. All highlights in the same namespace can then be
+ cleared with single call to |nvim_buf_clear_namespace()|. If
+ the highlight never will be deleted by an API call, pass
+ `ns_id = -1` .
As a shorthand, `ns_id = 0` can be used to create a new
namespace for the highlight, the allocated id is then
returned. If `hl_group` is the empty string no highlight is
added, but a new `ns_id` is still returned. This is supported
for backwards compatibility, new code should use
- |nvim_create_namespace| to create a new empty namespace.
+ |nvim_create_namespace()| to create a new empty namespace.
Parameters: ~
{buffer} Buffer handle, or 0 for current buffer
@@ -1688,6 +1717,29 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
|nvim_buf_detach()|
|api-buffer-updates-lua|
+nvim_buf_call({buffer}, {fun}) *nvim_buf_call()*
+ call a function with buffer as temporary current buffer
+
+ This temporarily switches current buffer to "buffer". If the
+ current window already shows "buffer", the window is not
+ switched If a window inside the current tabpage (including a
+ float) already shows the buffer One of these windows will be
+ set as current window temporarily. Otherwise a temporary
+ scratch window (calleed the "autocmd window" for historical
+ reasons) will be used.
+
+ This is useful e.g. to call vimL functions that only work with
+ the current buffer/window currently, like |termopen()|.
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer
+ {fun} Function to call inside the buffer (currently
+ lua callable only)
+
+ Return: ~
+ Return value of function. NB: will deepcopy lua values
+ currently, use upvalues to send lua references in and out.
+
*nvim_buf_clear_namespace()*
nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end})
Clears namespaced objects (highlights, extmarks, virtual text)
@@ -1731,6 +1783,17 @@ nvim_buf_del_var({buffer}, {name}) *nvim_buf_del_var()*
{buffer} Buffer handle, or 0 for current buffer
{name} Variable name
+nvim_buf_delete({buffer}, {opts}) *nvim_buf_delete()*
+ Deletes the buffer. See |:bwipeout|
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer
+ {opts} Optional parameters. Keys:
+ โ€ข force: Force deletion and ignore unsaved
+ changes.
+ โ€ข unload: Unloaded only, do not delete. See
+ |:bunload|
+
nvim_buf_detach({buffer}) *nvim_buf_detach()*
Deactivates buffer-update events on the channel.
@@ -1765,13 +1828,16 @@ nvim_buf_get_commands({buffer}, {opts}) *nvim_buf_get_commands()*
Map of maps describing commands.
*nvim_buf_get_extmark_by_id()*
-nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id})
+nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts})
Returns position for a given extmark id
Parameters: ~
{buffer} Buffer handle, or 0 for current buffer
{ns_id} Namespace id from |nvim_create_namespace()|
{id} Extmark id
+ {opts} Optional parameters. Keys:
+ โ€ข limit: Maximum number of marks to return
+ โ€ข details Whether to include the details dict
Return: ~
(row, col) tuple or empty list () if extmark id was absent
@@ -1820,6 +1886,7 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
extmark id (whose position defines the bound)
{opts} Optional parameters. Keys:
โ€ข limit: Maximum number of marks to return
+ โ€ข details Whether to include the details dict
Return: ~
List of [extmark_id, row, col] tuples in "traversal
@@ -1918,28 +1985,6 @@ nvim_buf_get_var({buffer}, {name}) *nvim_buf_get_var()*
Return: ~
Variable value
- *nvim_buf_get_virtual_text()*
-nvim_buf_get_virtual_text({buffer}, {line})
- Get the virtual text (annotation) for a buffer line.
-
- The virtual text is returned as list of lists, whereas the
- inner lists have either one or two elements. The first element
- is the actual text, the optional second element is the
- highlight group.
-
- The format is exactly the same as given to
- nvim_buf_set_virtual_text().
-
- If there is no virtual text associated with the given line, an
- empty list is returned.
-
- Parameters: ~
- {buffer} Buffer handle, or 0 for current buffer
- {line} Line to get the virtual text from (zero-indexed)
-
- Return: ~
- List of virtual text chunks
-
nvim_buf_is_loaded({buffer}) *nvim_buf_is_loaded()*
Checks if a buffer is valid and loaded. See |api-buffer| for
more info about unloaded buffers.
@@ -1973,22 +2018,40 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()*
Line count, or 0 for unloaded buffer. |api-buffer|
*nvim_buf_set_extmark()*
-nvim_buf_set_extmark({buffer}, {ns_id}, {id}, {line}, {col}, {opts})
+nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
Creates or updates an extmark.
To create a new extmark, pass id=0. The extmark id will be
- returned. It is also allowed to create a new mark by passing
- in a previously unused id, but the caller must then keep track
- of existing and unused ids itself. (Useful over RPC, to avoid
+ returned. To move an existing mark, pass its id.
+
+ It is also allowed to create a new mark by passing in a
+ previously unused id, but the caller must then keep track of
+ existing and unused ids itself. (Useful over RPC, to avoid
waiting for the return value.)
+ Using the optional arguments, it is possible to use this to
+ highlight a range of text, and also to associate virtual text
+ to the mark.
+
Parameters: ~
{buffer} Buffer handle, or 0 for current buffer
{ns_id} Namespace id from |nvim_create_namespace()|
- {id} Extmark id, or 0 to create new
{line} Line number where to place the mark
{col} Column where to place the mark
- {opts} Optional parameters. Currently not used.
+ {opts} Optional parameters.
+ โ€ข id : id of the extmark to edit.
+ โ€ข end_line : ending line of the mark, 0-based
+ inclusive.
+ โ€ข end_col : ending col of the mark, 0-based
+ inclusive.
+ โ€ข hl_group : name of the highlight group used to
+ highlight this mark.
+ โ€ข virt_text : virtual text to link to this mark.
+ โ€ข ephemeral : for use with
+ |nvim_set_decoration_provider| callbacks. The
+ mark will only be used for the current redraw
+ cycle, and not be permantently stored in the
+ buffer.
Return: ~
Id of the created/updated extmark
@@ -2065,12 +2128,12 @@ nvim_buf_set_virtual_text({buffer}, {src_id}, {line}, {chunks},
Namespaces are used to support batch deletion/updating of
virtual text. To create a namespace, use
- |nvim_create_namespace|. Virtual text is cleared using
- |nvim_buf_clear_namespace|. The same `ns_id` can be used for
+ |nvim_create_namespace()|. Virtual text is cleared using
+ |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
both virtual text and highlights added by
- |nvim_buf_add_highlight|, both can then be cleared with a
- single call to |nvim_buf_clear_namespace|. If the virtual text
- never will be cleared by an API call, pass `ns_id = -1` .
+ |nvim_buf_add_highlight()|, both can then be cleared with a
+ single call to |nvim_buf_clear_namespace()|. If the virtual
+ text never will be cleared by an API call, pass `ns_id = -1` .
As a shorthand, `ns_id = 0` can be used to create a new
namespace for the virtual text, the allocated id is then
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index f1753b75cc..a728593c40 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -206,169 +206,9 @@ autocommands, this doesn't happen.
You can use the 'eventignore' option to ignore a number of events or all
events.
- *autocommand-events* *{event}*
-Vim recognizes the following events. Vim ignores the case of event names
-(e.g., you can use "BUFread" or "bufread" instead of "BufRead").
-
-First an overview by function with a short explanation. Then the list
-alphabetically with full explanations |autocmd-events-abc|.
-
-Name triggered by ~
-
- Reading
-|BufNewFile| starting to edit a file that doesn't exist
-|BufReadPre| starting to edit a new buffer, before reading the file
-|BufRead| starting to edit a new buffer, after reading the file
-|BufReadPost| starting to edit a new buffer, after reading the file
-|BufReadCmd| before starting to edit a new buffer |Cmd-event|
-
-|FileReadPre| before reading a file with a ":read" command
-|FileReadPost| after reading a file with a ":read" command
-|FileReadCmd| before reading a file with a ":read" command |Cmd-event|
-
-|FilterReadPre| before reading a file from a filter command
-|FilterReadPost| after reading a file from a filter command
-
-|StdinReadPre| before reading from stdin into the buffer
-|StdinReadPost| After reading from the stdin into the buffer
-
- Writing
-|BufWrite| starting to write the whole buffer to a file
-|BufWritePre| starting to write the whole buffer to a file
-|BufWritePost| after writing the whole buffer to a file
-|BufWriteCmd| before writing the whole buffer to a file |Cmd-event|
-
-|FileWritePre| starting to write part of a buffer to a file
-|FileWritePost| after writing part of a buffer to a file
-|FileWriteCmd| before writing part of a buffer to a file |Cmd-event|
-
-|FileAppendPre| starting to append to a file
-|FileAppendPost| after appending to a file
-|FileAppendCmd| before appending to a file |Cmd-event|
-
-|FilterWritePre| starting to write a file for a filter command or diff
-|FilterWritePost| after writing a file for a filter command or diff
-
- Buffers
-|BufAdd| just after adding a buffer to the buffer list
-|BufDelete| before deleting a buffer from the buffer list
-|BufWipeout| before completely deleting a buffer
-
-|BufFilePre| before changing the name of the current buffer
-|BufFilePost| after changing the name of the current buffer
-
-|BufEnter| after entering a buffer
-|BufLeave| before leaving to another buffer
-|BufWinEnter| after a buffer is displayed in a window
-|BufWinLeave| before a buffer is removed from a window
-
-|BufUnload| before unloading a buffer
-|BufHidden| just after a buffer has become hidden
-|BufNew| just after creating a new buffer
-
-|SwapExists| detected an existing swap file
-|TermOpen| starting a terminal job
-|TermEnter| entering Terminal-mode
-|TermLeave| leaving Terminal-mode
-|TermClose| stopping a terminal job
-|ChanOpen| after a channel opened
-|ChanInfo| after a channel has its state changed
-
- Options
-|FileType| when the 'filetype' option has been set
-|Syntax| when the 'syntax' option has been set
-|OptionSet| after setting any option
-
- Startup and exit
-|VimEnter| after doing all the startup stuff
-|UIEnter| after a UI attaches
-|UILeave| after a UI detaches
-|TermResponse| after the terminal response to t_RV is received
-|QuitPre| when using `:quit`, before deciding whether to exit
-|ExitPre| when using a command that may make Vim exit
-|VimLeavePre| before exiting Nvim, before writing the shada file
-|VimLeave| before exiting Nvim, after writing the shada file
-|VimResume| after Nvim is resumed
-|VimSuspend| before Nvim is suspended
-
- Various
-|DiffUpdated| after diffs have been updated
-|DirChanged| after the |current-directory| was changed
-
-|FileChangedShell| Vim notices that a file changed since editing started
-|FileChangedShellPost| after handling a file changed since editing started
-|FileChangedRO| before making the first change to a read-only file
-
-|ShellCmdPost| after executing a shell command
-|ShellFilterPost| after filtering with a shell command
-
-|CmdUndefined| a user command is used but it isn't defined
-|FuncUndefined| a user function is used but it isn't defined
-|SpellFileMissing| a spell file is used but it can't be found
-|SourcePre| before sourcing a Vim script
-|SourcePost| after sourcing a Vim script
-|SourceCmd| before sourcing a Vim script |Cmd-event|
-
-|VimResized| after the Vim window size changed
-|FocusGained| Nvim got focus
-|FocusLost| Nvim lost focus
-|CursorHold| the user doesn't press a key for a while
-|CursorHoldI| the user doesn't press a key for a while in Insert mode
-|CursorMoved| the cursor was moved in Normal mode
-|CursorMovedI| the cursor was moved in Insert mode
-
-|WinClosed| after closing a window
-|WinNew| after creating a new window
-|WinEnter| after entering another window
-|WinLeave| before leaving a window
-|TabEnter| after entering another tab page
-|TabLeave| before leaving a tab page
-|TabNew| when creating a new tab page
-|TabNewEntered| after entering a new tab page
-|TabClosed| after closing a tab page
-|CmdlineChanged| after a change was made to the command-line text
-|CmdlineEnter| after entering cmdline mode
-|CmdlineLeave| before leaving cmdline mode
-|CmdwinEnter| after entering the command-line window
-|CmdwinLeave| before leaving the command-line window
-
-|InsertEnter| starting Insert mode
-|InsertChange| when typing <Insert> while in Insert or Replace mode
-|InsertLeave| when leaving Insert mode
-|InsertCharPre| when a character was typed in Insert mode, before
- inserting it
-
-|TextYankPost| when some text is yanked or deleted
-
-|TextChanged| after a change was made to the text in Normal mode
-|TextChangedI| after a change was made to the text in Insert mode
- when popup menu is not visible
-|TextChangedP| after a change was made to the text in Insert mode
- when popup menu visible
-
-|ColorSchemePre| before loading a color scheme
-|ColorScheme| after loading a color scheme
-
-|RemoteReply| a reply from a server Vim was received
-
-|QuickFixCmdPre| before a quickfix command is run
-|QuickFixCmdPost| after a quickfix command is run
-
-|SessionLoadPost| after loading a session file
-
-|MenuPopup| just before showing the popup menu
-|CompleteChanged| after popup menu changed, not fired on popup menu hide
-|CompleteDonePre| after Insert mode completion is done, before clearing
- info
-|CompleteDone| after Insert mode completion is done, after clearing
- info
-
-|User| to be used in combination with ":doautocmd"
-|Signal| after Nvim receives a signal
-
-
-
-The alphabetical list of autocommand events: *autocmd-events-abc*
+
+ *events* *{event}*
+Nvim recognizes the following events. Names are case-insensitive.
*BufAdd*
BufAdd Just after creating a new buffer which is
@@ -642,7 +482,7 @@ CursorHold When the user doesn't press a key for the time
Hint: to force an update of the status lines
use: >
:let &ro = &ro
-
+<
*CursorHoldI*
CursorHoldI Like CursorHold, but in Insert mode. Not
triggered when waiting for another key, e.g.
@@ -860,9 +700,14 @@ InsertEnter Just before starting Insert mode. Also for
The cursor is restored afterwards. If you do
not want that set |v:char| to a non-empty
string.
+ *InsertLeavePre*
+InsertLeavePre Just before leaving Insert mode. Also when
+ using CTRL-O |i_CTRL-O|. Be caseful not to
+ change mode or use `:normal`, it will likely
+ cause trouble.
*InsertLeave*
-InsertLeave When leaving Insert mode. Also when using
- CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
+InsertLeave Just after leaving Insert mode. Also when
+ using CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
*MenuPopup*
MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the
@@ -1111,13 +956,13 @@ VimEnter After doing all the startup stuff, including
if v:vim_did_enter
call s:init()
else
- au VimEnter * call s:init()
+ au VimEnter * call s:init()
endif
< *VimLeave*
VimLeave Before exiting Vim, just after writing the
.shada file. Executed only once, like
VimLeavePre.
-< Use |v:dying| to detect an abnormal exit.
+ Use |v:dying| to detect an abnormal exit.
Use |v:exiting| to get the exit code.
Not triggered if |v:dying| is 2 or more.
*VimLeavePre*
@@ -1126,7 +971,7 @@ VimLeavePre Before exiting Vim, just before writing the
if there is a match with the name of what
happens to be the current buffer when exiting.
Mostly useful with a "*" pattern. >
- :autocmd VimLeavePre * call CleanupStuff()
+ :autocmd VimLeavePre * call CleanupStuff()
< Use |v:dying| to detect an abnormal exit.
Use |v:exiting| to get the exit code.
Not triggered if |v:dying| is 2 or more.
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index dcebbc524c..5c67359002 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1615,6 +1615,10 @@ B When joining lines, don't insert a space between two multi-byte
characters. Overruled by the 'M' flag.
1 Don't break a line after a one-letter word. It's broken before it
instead (if possible).
+] Respect textwidth rigorously. With this flag set, no line can be
+ longer than textwidth, unless line-break-prohibition rules make this
+ impossible. Mainly for CJK scripts and works only if 'encoding' is
+ "utf-8".
j Where it makes sense, remove a comment leader when joining lines. For
example, joining:
int i; // the index ~
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index b31177ce0e..f7a281cb88 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -224,6 +224,10 @@ CTRL-[ *c_CTRL-[* *c_<Esc>* *c_Esc*
present in 'cpoptions', start entered command.
Note: If your <Esc> key is hard to hit on your keyboard, train
yourself to use CTRL-[.
+ *c_META* *c_ALT*
+ ALT (|META|) acts like <Esc> if the chord is not mapped.
+ For example <A-x> acts like <Esc>x if <A-x> does not have a
+ command-line mode mapping.
*c_CTRL-C*
CTRL-C quit command-line without executing
@@ -556,6 +560,7 @@ followed by another Vim command:
:lfdo
:make
:normal
+ :perlfile
:promptfind
:promptrepl
:pyfile
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index ce075e1bee..3b5287ee44 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -77,7 +77,9 @@ Options ~
*'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
*'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed.
*'langnoremap'* Deprecated alias to 'nolangremap'.
+'sessionoptions' Flags "unix", "slash" are ignored and always enabled.
*'vi'*
+'viewoptions' Flags "unix", "slash" are ignored and always enabled.
*'viminfo'* Deprecated alias to 'shada' option.
*'viminfofile'* Deprecated alias to 'shadafile' option.
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 09c5b7c4ad..aec0178da2 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -103,8 +103,10 @@ Examples:
The provider framework invokes VimL from C. It is composed of two functions
in eval.c:
-- eval_call_provider(name, method, arguments): calls provider#{name}#Call
- with the method and arguments.
+- eval_call_provider(name, method, arguments, discard): calls
+ provider#{name}#Call with the method and arguments. If discard is true, any
+ value returned by the provider will be discarded and and empty value be
+ returned.
- eval_has_provider(name): Checks the `g:loaded_{name}_provider` variable
which must be set to 2 by the provider script to indicate that it is
"enabled and working". Called by |has()| to check if features are available.
diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt
index 7f807b5eee..271b8c2597 100644
--- a/runtime/doc/digraph.txt
+++ b/runtime/doc/digraph.txt
@@ -913,6 +913,7 @@ char digraph hex dec official name ~
โ€Ÿ 9" 201F 8223 DOUBLE HIGH-REVERSED-9 QUOTATION MARK
โ€  /- 2020 8224 DAGGER
โ€ก /= 2021 8225 DOUBLE DAGGER
+โ€ข oo 2022 8226 BULLET
โ€ฅ .. 2025 8229 TWO DOT LEADER
โ€ฆ ,. 2026 8230 HORIZONTAL ELLIPSIS
โ€ฐ %0 2030 8240 PER MILLE SIGN
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index efb6272e58..800de63a55 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -38,7 +38,9 @@ List An ordered sequence of items |List|.
Dictionary An associative, unordered array: Each entry has a key and a
value. |Dictionary|
- Example: {'blue': "#0000ff", 'red': "#ff0000"}
+ Examples:
+ {'blue': "#0000ff", 'red': "#ff0000"}
+ #{blue: "#0000ff", red: "#ff0000"}
The Number and String types are converted automatically, depending on how they
are used.
@@ -436,8 +438,14 @@ only appear once. Examples: >
A key is always a String. You can use a Number, it will be converted to a
String automatically. Thus the String '4' and the number 4 will find the same
entry. Note that the String '04' and the Number 04 are different, since the
-Number will be converted to the String '4'. The empty string can be used as a
-key.
+Number will be converted to the String '4'. The empty string can also be used
+as a key.
+ *literal-Dict*
+To avoid having to put quotes around every key the #{} form can be used. This
+does require the key to consist only of ASCII letters, digits, '-' and '_'.
+Example: >
+ let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}
+Note that 333 here is the string "333". Empty keys are not possible with #{}.
A value can be any expression. Using a Dictionary for a value creates a
nested Dictionary: >
@@ -2224,6 +2232,7 @@ inputsecret({prompt} [, {text}])
String like input() but hiding the text
insert({list}, {item} [, {idx}])
List insert {item} in {list} [before {idx}]
+interrupt() none interrupt script execution
invert({expr}) Number bitwise invert
isdirectory({directory}) Number |TRUE| if {directory} is a directory
isinf({expr}) Number determine if {expr} is infinity value
@@ -2287,6 +2296,7 @@ nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
nvim_...({args}...) any call nvim |api| functions
or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path
+perleval({expr}) any evaluate |perl| expression
pow({x}, {y}) Float {x} to the power of {y}
prevnonblank({lnum}) Number line nr of non-blank line <= {lnum}
printf({fmt}, {expr1}...) String format text
@@ -2326,6 +2336,7 @@ repeat({expr}, {count}) String repeat {expr} {count} times
resolve({filename}) String get filename a shortcut points to
reverse({list}) List reverse {list} in-place
round({expr}) Float round off {expr}
+rubyeval({expr}) any evaluate |Ruby| expression
rpcnotify({channel}, {event}[, {args}...])
Sends an |RPC| notification to {channel}
rpcrequest({channel}, {method}[, {args}...])
@@ -2408,7 +2419,8 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
str2nr({expr} [, {base}]) Number convert String to Number
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}])
- String {len} characters of {str} at {start}
+ String {len} characters of {str} at
+ character {start}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String time in specified format
strgetchar({str}, {index}) Number get char {index} from {str}
@@ -2416,8 +2428,9 @@ stridx({haystack}, {needle} [, {start}])
Number index of {needle} in {haystack}
string({expr}) String String representation of {expr} value
strlen({expr}) Number length of the String {expr}
-strpart({str}, {start} [, {len}])
- String {len} characters of {str} at {start}
+strpart({str}, {start} [, {len} [, {chars}]])
+ String {len} bytes/chars of {str} at
+ byte {start}
strridx({haystack}, {needle} [, {start}])
Number last index of {needle} in {haystack}
strtrans({expr}) String translate string to make it printable
@@ -2456,7 +2469,8 @@ tolower({expr}) String the String {expr} switched to lowercase
toupper({expr}) String the String {expr} switched to uppercase
tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr}
to chars in {tostr}
-trim({text} [, {mask}]) String trim characters in {mask} from {text}
+trim({text} [, {mask} [, {dir}]])
+ String trim characters in {mask} from {text}
trunc({expr}) Float truncate Float {expr}
type({name}) Number type of variable {name}
undofile({name}) String undo file name for {name}
@@ -2905,7 +2919,8 @@ byte2line({byte}) *byte2line()*
byteidx({expr}, {nr}) *byteidx()*
Return byte index of the {nr}'th character in the string
- {expr}. Use zero for the first character, it returns zero.
+ {expr}. Use zero for the first character, it then returns
+ zero.
This function is only useful when there are multibyte
characters, otherwise the returned value is equal to {nr}.
Composing characters are not counted separately, their byte
@@ -3826,7 +3841,7 @@ feedkeys({string} [, {mode}]) *feedkeys()*
stuck, waiting for a character to be typed before the
script continues.
Note that if you manage to call feedkeys() while
- executing commands, thus calling it recursively, the
+ executing commands, thus calling it recursively, then
all typehead will be consumed by the last call.
'!' When used with 'x' will not end Insert mode. Can be
used in a test when a timer is set to exit Insert mode
@@ -4629,7 +4644,7 @@ getloclist({nr},[, {what}]) *getloclist()*
If {what} contains 'filewinid', then returns the id of the
window used to display files from the location list. This
field is applicable only when called from a location list
- window.
+ window. See |location-list-file-window| for more details.
getmatches([{win}]) *getmatches()*
Returns a |List| with all matches previously defined for the
@@ -4720,7 +4735,9 @@ getqflist([{what}]) *getqflist()*
id get information for the quickfix list with
|quickfix-ID|; zero means the id for the
current list or the list specified by "nr"
- idx index of the current entry in the list
+ idx index of the current entry in the quickfix
+ list specified by 'id' or 'nr'.
+ See |quickfix-index|
items quickfix list entries
lines parse a list of lines using 'efm' and return
the resulting entries. Only a |List| type is
@@ -4913,6 +4930,19 @@ getwinpos([{timeout}]) *getwinpos()*
{timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used.
+ Use a longer time for a remote terminal.
+ When using a value less than 10 and no response is received
+ within that time, a previously reported position is returned,
+ if available. This can be used to poll for the position and
+ do some work in the meantime: >
+ while 1
+ let res = getwinpos(1)
+ if res[0] >= 0
+ break
+ endif
+ " Do some work here
+ endwhile
+<
*getwinposx()*
getwinposx() The result is a Number, which is the X coordinate in pixels of
the left hand side of the GUI Vim window. The result will be
@@ -5412,6 +5442,19 @@ insert({list}, {item} [, {idx}]) *insert()*
Note that when {item} is a |List| it is inserted as a single
item. Use |extend()| to concatenate |Lists|.
+interrupt() *interrupt()*
+ Interrupt script execution. It works more or less like the
+ user typing CTRL-C, most commands won't execute and control
+ returns to the user. This is useful to abort execution
+ from lower down, e.g. in an autocommand. Example: >
+ :function s:check_typoname(file)
+ : if fnamemodify(a:file, ':t') == '['
+ : echomsg 'Maybe typo'
+ : call interrupt()
+ : endif
+ :endfunction
+ :au BufWritePre * call s:check_typoname(expand('<amatch>'))
+
invert({expr}) *invert()*
Bitwise invert. The argument is converted to a number. A
List, Dict or Float argument causes an error. Example: >
@@ -6237,6 +6280,7 @@ mode([expr]) Return a string that indicates the current mode.
nov Operator-pending (forced charwise |o_v|)
noV Operator-pending (forced linewise |o_V|)
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
+ CTRL-V is one character
niI Normal using |i_CTRL-O| in |Insert-mode|
niR Normal using |i_CTRL-O| in |Replace-mode|
niV Normal using |i_CTRL-O| in |Virtual-Replace-mode|
@@ -6406,6 +6450,21 @@ pathshorten({expr}) *pathshorten()*
< ~/.c/n/a/file1.vim ~
It doesn't matter if the path exists or not.
+perleval({expr}) *perleval()*
+ Evaluate |perl| expression {expr} and return its result
+ converted to Vim data structures.
+ Numbers and strings are returned as they are (strings are
+ copied though).
+ Lists are represented as Vim |List| type.
+ Dictionaries are represented as Vim |Dictionary| type,
+ non-string keys result in error.
+
+ Note: If you want an array or hash, {expr} must return a
+ reference to it.
+ Example: >
+ :echo perleval('[1 .. 4]')
+< [1, 2, 3, 4]
+
pow({x}, {y}) *pow()*
Return the power of {x} to the exponent {y} as a |Float|.
{x} and {y} must evaluate to a |Float| or a |Number|.
@@ -7012,6 +7071,17 @@ rpcstart({prog}[, {argv}]) *rpcstart()*
< with >
:let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true})
+rubyeval({expr}) *rubyeval()*
+ Evaluate Ruby expression {expr} and return its result
+ converted to Vim data structures.
+ Numbers, floats and strings are returned as they are (strings
+ are copied though).
+ Arrays are represented as Vim |List| type.
+ Hashes are represented as Vim |Dictionary| type.
+ Other objects are represented as strings resulted from their
+ "Object#to_s" method.
+ {only available when compiled with the |+ruby| feature}
+
screenattr({row}, {col}) *screenattr()*
Like |screenchar()|, but return the attribute. This is a rather
arbitrary number that can only be used to compare to the
@@ -7581,16 +7651,22 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
efm errorformat to use when parsing text from
"lines". If this is not present, then the
'errorformat' option value is used.
+ See |quickfix-parse|
id quickfix list identifier |quickfix-ID|
+ idx 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|
items list of quickfix entries. Same as the {list}
argument.
lines 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|
nr list number in the quickfix stack; zero
means the current quickfix list and "$" means
- the last quickfix list
- title quickfix list title text
+ the last quickfix list.
+ title quickfix list title text. See |quickfix-title|
Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be
@@ -7737,26 +7813,23 @@ sha256({string}) *sha256()*
shellescape({string} [, {special}]) *shellescape()*
Escape {string} for use as a shell command argument.
- On Windows when 'shellslash' is not set, it
- will enclose {string} in double quotes and double all double
- quotes within {string}.
- Otherwise, it will enclose {string} in single quotes and
- replace all "'" with "'\''".
-
- When the {special} argument is present and it's a non-zero
- Number or a non-empty String (|non-zero-arg|), then special
- items such as "!", "%", "#" and "<cword>" will be preceded by
- a backslash. This backslash will be removed again by the |:!|
- command.
- The "!" character will be escaped (again with a |non-zero-arg|
- {special}) when 'shell' contains "csh" in the tail. That is
- because for csh and tcsh "!" is used for history replacement
- even when inside single quotes.
+ On Windows when 'shellslash' is not set, encloses {string} in
+ double-quotes and doubles all double-quotes within {string}.
+ Otherwise encloses {string} in single-quotes and replaces all
+ "'" with "'\''".
- With a |non-zero-arg| {special} the <NL> character is also
- escaped. When 'shell' containing "csh" in the tail it's
- escaped a second time.
+ If {special} is a ||non-zero-arg|:
+ - Special items such as "!", "%", "#" and "<cword>" will be
+ preceded by a backslash. The backslash will be removed again
+ by the |:!| command.
+ - The <NL> character is escaped.
+
+ If 'shell' contains "csh" in the tail:
+ - The "!" character will be escaped. This is because csh and
+ tcsh use "!" for history replacement even in single-quotes.
+ - The <NL> character is escaped (twice if {special} is
+ a ||non-zero-arg|).
Example of use with a |:!| command: >
:exe '!dir ' . shellescape(expand('<cfile>'), 1)
@@ -8229,15 +8302,13 @@ sqrt({expr}) *sqrt()*
stdioopen({opts}) *stdioopen()*
- In a nvim launched with the |--headless| option, this opens
- stdin and stdout as a |channel|. This function can only be
- invoked once per instance. See |channel-stdio| for more
- information and examples. Note that stderr is not handled by
- this function, see |v:stderr|.
+ With |--headless| this opens stdin and stdout as a |channel|.
+ May be called only once. See |channel-stdio|. stderr is not
+ handled by this function, see |v:stderr|.
- Returns a |channel| ID. Close the stdio descriptors with |chanclose()|.
- Use |chansend()| to send data to stdout, and
- |rpcrequest()| and |rpcnotify()| to communicate over RPC.
+ Close the stdio handles with |chanclose()|. Use |chansend()|
+ to send data to stdout, and |rpcrequest()| and |rpcnotify()|
+ to communicate over RPC.
{opts} is a dictionary with these keys:
|on_stdin| : callback invoked when stdin is written to.
@@ -8245,7 +8316,7 @@ stdioopen({opts}) *stdioopen()*
rpc : If set, |msgpack-rpc| will be used to communicate
over stdio
Returns:
- - The channel ID on success (this is always 1)
+ - |channel-id| on success (value is always 1)
- 0 on invalid arguments
@@ -8424,14 +8495,19 @@ strlen({expr}) The result is a Number, which is the length of the String
{expr} in bytes.
If the argument is a Number it is first converted to a String.
For other types an error is given.
- If you want to count the number of multi-byte characters use
+ If you want to count the number of multibyte characters use
|strchars()|.
Also see |len()|, |strdisplaywidth()| and |strwidth()|.
-strpart({src}, {start} [, {len}]) *strpart()*
+strpart({src}, {start} [, {len} [, {chars}]]) *strpart()*
The result is a String, which is part of {src}, starting from
byte {start}, with the byte length {len}.
- To count characters instead of bytes use |strcharpart()|.
+ When {chars} is present and TRUE then {len} is the number of
+ characters positions (composing characters are not counted
+ separately, thus "1" means one base character and any
+ following composing characters).
+ To count {start} as characters instead of bytes use
+ |strcharpart()|.
When bytes are selected which do not exist, this doesn't
result in an error, the bytes are simply omitted.
@@ -8443,8 +8519,8 @@ strpart({src}, {start} [, {len}]) *strpart()*
strpart("abcdefg", 3) == "defg"
< Note: To get the first character, {start} must be 0. For
- example, to get three bytes under and after the cursor: >
- strpart(getline("."), col(".") - 1, 3)
+ example, to get the character under the cursor: >
+ strpart(getline("."), col(".") - 1, 1, v:true)
<
strridx({haystack}, {needle} [, {start}]) *strridx()*
The result is a Number, which gives the byte index in
@@ -8974,21 +9050,28 @@ tr({src}, {fromstr}, {tostr}) *tr()*
echo tr("<blob>", "<>", "{}")
< returns "{blob}"
-trim({text} [, {mask}]) *trim()*
+trim({text} [, {mask} [, {dir}]]) *trim()*
Return {text} as a String where any character in {mask} is
- removed from the beginning and end of {text}.
+ removed from the beginning and/or end of {text}.
If {mask} is not given, {mask} is all characters up to 0x20,
which includes Tab, space, NL and CR, plus the non-breaking
space character 0xa0.
- This code deals with multibyte characters properly.
-
+ The optional {dir} argument specifies where to remove the
+ characters:
+ 0 remove from the beginning and end of {text}
+ 1 remove only at the beginning of {text}
+ 2 remove only at the end of {text}
+ When omitted both ends are trimmed.
+ This function deals with multibyte characters properly.
Examples: >
echo trim(" some text ")
< returns "some text" >
echo trim(" \r\t\t\r RESERVE \t\n\x0B\xA0") . "_TAIL"
< returns "RESERVE_TAIL" >
echo trim("rm<Xrm<>X>rrm", "rm<>")
-< returns "Xrm<>X" (characters in the middle are not removed)
+< returns "Xrm<>X" (characters in the middle are not removed) >
+ echo trim(" vim ", " ", 2)
+< returns " vim"
trunc({expr}) *trunc()*
Return the largest integral value with magnitude less than or
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index a384b5f876..203699435b 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -137,7 +137,7 @@ Special issues ~
Programming language support ~
|indent.txt| automatic indenting for C and other languages
-|lsp.txt| Language Server Protocol (LSP)
+|lsp.txt| Language Server Protocol (LSP)
|syntax.txt| syntax highlighting
|filetype.txt| settings done specifically for a type of file
|quickfix.txt| commands for a quick edit-compile-fix cycle
@@ -168,9 +168,9 @@ Versions ~
|vi_diff.txt| Main differences between Vim and Vi
*standard-plugin-list*
Standard plugins ~
+|matchit.txt| Extended |%| matching
|pi_gzip.txt| Reading and writing compressed files
|pi_health.txt| Healthcheck framework
-|pi_matchit.txt| Extended |%| matching
|pi_msgpack.txt| msgpack utilities
|pi_netrw.txt| Reading and writing files over a network
|pi_paren.txt| Highlight matching parens
diff --git a/runtime/doc/if_perl.txt b/runtime/doc/if_perl.txt
new file mode 100644
index 0000000000..f1d07ddb20
--- /dev/null
+++ b/runtime/doc/if_perl.txt
@@ -0,0 +1,268 @@
+*if_perl.txt* Nvim
+
+
+ VIM REFERENCE MANUAL by Jacques Germishuys
+
+The perl Interface to Vim *if_perl* *perl*
+
+See |provider-perl| for more information.
+
+ Type |gO| to see the table of contents.
+
+==============================================================================
+1. Commands *perl-commands*
+
+ *:perl*
+:[range]perl {stmt}
+ Execute perl statement {stmt}. The current package is
+ "main". A simple check if the `:perl` command is
+ working: >
+ :perl print "Hello"
+
+:[range]perl << [endmarker]
+{script}
+{endmarker}
+ Execute perl script {script}. Useful for including
+ perl code in Vim scripts. Requires perl, see
+ |script-here|.
+
+The {endmarker} below the {script} must NOT be preceded by any white space.
+
+If [endmarker] is omitted from after the "<<", a dot '.' must be used after
+{script}, like for the |:append| and |:insert| commands.
+
+Example: >
+ function! MyVimMethod()
+ perl << EOF
+ sub my_vim_method
+ {
+ print "Hello World!\n";
+ }
+ EOF
+ endfunction
+
+To see what version of perl you have: >
+
+ :perl print $^V
+<
+ *:perldo*
+:[range]perldo {cmd} Execute perl command {cmd} for each line in the[range],
+ with $_ being set to the test of each line in turn,
+ without a trailing <EOL>. In addition to $_, $line and
+ $linenr is also set to the line content and line number
+ respectively. Setting $_ will change the text, but note
+ that it is not possible to add or delete lines using
+ this command.
+ The default for [range] is the whole file: "1,$".
+
+Examples:
+>
+ :perldo $_ = reverse($_);
+ :perldo $_ = "".$linenr." => $line";
+
+One can use `:perldo` in conjunction with `:perl` to filter a range using
+perl. For example: >
+
+ :perl << EOF
+ sub perl_vim_string_replace
+ {
+ my $line = shift;
+ my $needle = $vim->eval('@a');
+ my $replacement = $vim->eval('@b');
+ $line =~ s/$needle/$replacement/g;
+ return $line;
+ }
+ EOF
+ :let @a='somevalue'
+ :let @b='newvalue'
+ :'<,'>perldo $_ = perl_vim_string_replace($_)
+<
+ *:perlfile*
+:[range]perlfile {file}
+ Execute the perl script in {file}. The whole
+ argument is used as a single file name.
+
+Both of these commands do essentially the same thing - they execute a piece of
+perl code, with the "current range" set to the given line range.
+
+In the case of :perl, the code to execute is in the command-line.
+In the case of :perlfile, the code to execute is the contents of the given file.
+
+perl commands cannot be used in the |sandbox|.
+
+To pass arguments you need to set @ARGV explicitly. Example: >
+
+ :perl @ARGV = ("foo", "bar");
+ :perlfile myscript.pl
+
+Here are some examples *perl-examples* >
+
+ :perl print "Hello"
+ :perl $current->line (uc ($current->line))
+ :perl my $str = $current->buffer->[42]; print "Set \$str to: $str"
+
+Note that changes (such as the "use" statements) persist from one command
+to the next.
+
+==============================================================================
+2. The VIM module *perl-vim*
+
+Perl code gets all of its access to Neovim via the "VIM" module.
+
+Overview >
+ print "Hello" # displays a message
+ VIM::Msg("Hello") # displays a message
+ VIM::SetOption("ai") # sets a vim option
+ $nbuf = VIM::Buffers() # returns the number of buffers
+ @buflist = VIM::Buffers() # returns array of all buffers
+ $mybuf = (VIM::Buffers('a.c'))[0] # returns buffer object for 'a.c'
+ @winlist = VIM::Windows() # returns array of all windows
+ $nwin = VIM::Windows() # returns the number of windows
+ ($success, $v) = VIM::Eval('&path') # $v: option 'path', $success: 1
+ ($success, $v) = VIM::Eval('&xyz') # $v: '' and $success: 0
+ $v = VIM::Eval('expand("<cfile>")') # expands <cfile>
+ $curwin->SetHeight(10) # sets the window height
+ @pos = $curwin->Cursor() # returns (row, col) array
+ @pos = (10, 10)
+ $curwin->Cursor(@pos) # sets cursor to @pos
+ $curwin->Cursor(10,10) # sets cursor to row 10 col 10
+ $mybuf = $curwin->Buffer() # returns the buffer object for window
+ $curbuf->Name() # returns buffer name
+ $curbuf->Number() # returns buffer number
+ $curbuf->Count() # returns the number of lines
+ $l = $curbuf->Get(10) # returns line 10
+ @l = $curbuf->Get(1 .. 5) # returns lines 1 through 5
+ $curbuf->Delete(10) # deletes line 10
+ $curbuf->Delete(10, 20) # delete lines 10 through 20
+ $curbuf->Append(10, "Line") # appends a line
+ $curbuf->Append(10, "L1", "L2", "L3") # appends 3 lines
+ @l = ("L1", "L2", "L3")
+ $curbuf->Append(10, @l) # appends L1, L2 and L3
+ $curbuf->Set(10, "Line") # replaces line 10
+ $curbuf->Set(10, "Line1", "Line2") # replaces lines 10 and 11
+ $curbuf->Set(10, @l) # replaces 3 lines
+
+Module Functions:
+
+ *perl-Msg*
+VIM::Msg({msg})
+ Displays the message {msg}.
+
+ *perl-SetOption*
+VIM::SetOption({arg}) Sets a vim option. {arg} can be any argument that the
+ ":set" command accepts. Note that this means that no
+ spaces are allowed in the argument! See |:set|.
+
+ *perl-Buffers*
+VIM::Buffers([{bn}...]) With no arguments, returns a list of all the buffers
+ in an array context or returns the number of buffers
+ in a scalar context. For a list of buffer names or
+ numbers {bn}, returns a list of the buffers matching
+ {bn}, using the same rules as Vim's internal
+ |bufname()| function.
+ WARNING: the list becomes invalid when |:bwipe| is
+ used.
+
+ *perl-Windows*
+VIM::Windows([{wn}...]) With no arguments, returns a list of all the windows
+ in an array context or returns the number of windows
+ in a scalar context. For a list of window numbers
+ {wn}, returns a list of the windows with those
+ numbers.
+ WARNING: the list becomes invalid when a window is
+ closed.
+
+ *perl-DoCommand*
+VIM::DoCommand({cmd}) Executes Ex command {cmd}.
+
+ *perl-Eval*
+VIM::Eval({expr}) Evaluates {expr} and returns (success, value) in list
+ context or just value in scalar context.
+ success=1 indicates that val contains the value of
+ {expr}; success=0 indicates a failure to evaluate
+ the expression. '@x' returns the contents of register
+ x, '&x' returns the value of option x, 'x' returns the
+ value of internal |variables| x, and '$x' is equivalent
+ to perl's $ENV{x}. All |functions| accessible from
+ the command-line are valid for {expr}.
+ A |List| is turned into a string by joining the items
+ and inserting line breaks.
+
+==============================================================================
+3. VIM::Buffer objects *perl-buffer*
+
+Methods:
+
+ *perl-Buffer-Name*
+Name() Returns the filename for the Buffer.
+
+ *perl-Buffer-Number*
+Number() Returns the number of the Buffer.
+
+ *perl-Buffer-Count*
+Count() Returns the number of lines in the Buffer.
+
+ *perl-Buffer-Get*
+Get({lnum}, {lnum}?, ...)
+ Returns a text string of line {lnum} in the Buffer
+ for each {lnum} specified. An array can be passed
+ with a list of {lnum}'s specified.
+
+ *perl-Buffer-Delete*
+Delete({lnum}, {lnum}?)
+ Deletes line {lnum} in the Buffer. With the second
+ {lnum}, deletes the range of lines from the first
+ {lnum} to the second {lnum}.
+
+ *perl-Buffer-Append*
+Append({lnum}, {line}, {line}?, ...)
+ Appends each {line} string after Buffer line {lnum}.
+ The list of {line}s can be an array.
+
+ *perl-Buffer-Set*
+Set({lnum}, {line}, {line}?, ...)
+ Replaces one or more Buffer lines with specified
+ {lines}s, starting at Buffer line {lnum}. The list of
+ {line}s can be an array. If the arguments are
+ invalid, replacement does not occur.
+
+==============================================================================
+4. VIM::Window objects *perl-window*
+
+Methods:
+ *perl-Window-SetHeight*
+SetHeight({height})
+ Sets the Window height to {height}, within screen
+ limits.
+
+ *perl-Window-GetCursor*
+Cursor({row}?, {col}?)
+ With no arguments, returns a (row, col) array for the
+ current cursor position in the Window. With {row} and
+ {col} arguments, sets the Window's cursor position to
+ {row} and {col}. Note that {col} is numbered from 0,
+ Perl-fashion, and thus is one less than the value in
+ Vim's ruler.
+
+Buffer() *perl-Window-Buffer*
+ Returns the Buffer object corresponding to the given
+ Window.
+
+==============================================================================
+5. Lexical variables *perl-globals*
+
+There are multiple lexical variables.
+
+$curwin The current Window object.
+$curbuf The current Buffer object.
+$vim A Neovim::Ext object.
+$nvim The same as $nvim.
+$current A Neovim::Ext::Current object.
+
+These are also available via the "main" package:
+
+$main::curwin The current Window object.
+$main::curbuf The current Buffer object.
+
+==============================================================================
+ vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index 6468e4c81e..c8d2409549 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -136,7 +136,7 @@ self[{n}] Returns the buffer object for the number {n}. The first number
Methods:
-name Returns the name of the buffer.
+name Returns the full name of the buffer.
number Returns the number of the buffer.
count Returns the number of lines.
length Returns the number of lines.
@@ -172,6 +172,7 @@ height = {n} Sets the window height to {n}.
width Returns the width of the window.
width = {n} Sets the window width to {n}.
cursor Returns a [row, col] array for the cursor position.
+ First line number is 1 and first column number is 0.
cursor = [{row}, {col}]
Sets the cursor position to {row} and {col}.
@@ -184,4 +185,13 @@ $curwin The current window object.
$curbuf The current buffer object.
==============================================================================
+6. rubyeval() Vim function *ruby-rubyeval*
+
+To facilitate bi-directional interface, you can use |rubyeval()| function to
+evaluate Ruby expressions and pass their values to Vim script.
+
+The Ruby value "true", "false" and "nil" are converted to v:true, v:false and
+v:null, respectively.
+
+==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index bdab10c0e4..afcacad460 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -1441,6 +1441,9 @@ tag command action ~
|:packloadall| :packl[oadall] load all packages under 'packpath'
|:pclose| :pc[lose] close preview window
|:pedit| :ped[it] edit file in the preview window
+|:perl| :perl execute perl command
+|:perldo| :perldo execute perl command for each line
+|:perfile| :perlfile execute perl script file
|:print| :p[rint] print lines
|:profdel| :profd[el] stop profiling a function or script
|:profile| :prof[ile] profiling functions and scripts
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index e53af5074b..c4b93a2a27 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -42,9 +42,9 @@ char action ~
abbreviation.
Note: If your <Esc> key is hard to hit, try CTRL-[ instead.
*i_META* *i_ALT*
- ALT (|META|) acts like <Esc> if the chord is not mapped.
+ ALT (|META|) acts like <Esc> if the chord is not mapped.
For example <A-x> acts like <Esc>x if <A-x> does not have an
- insert-mode mapping.
+ insert-mode mapping.
*i_CTRL-C*
CTRL-C Quit insert mode, go back to Normal mode. Do not check for
abbreviations. Does not trigger the |InsertLeave| autocommand
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index 3c3753df78..d858985e3f 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -4,21 +4,15 @@
NVIM REFERENCE MANUAL
-Introduction to Vim *ref* *reference*
+Nvim *ref* *reference*
Type |gO| to see the table of contents.
==============================================================================
Introduction *intro*
-Vim stands for Vi IMproved. It used to be Vi IMitation, but there are so many
-improvements that a name change was appropriate. Vim is a text editor which
-includes almost all the commands from the Unix program "Vi" and a lot of new
-ones. It is very useful for editing programs and other plain text.
- All commands are given with the keyboard. This has the advantage that you
-can keep your fingers on the keyboard and your eyes on the screen. For those
-who want it, there is mouse support and a GUI version with scrollbars and
-menus (see |gui.txt|).
+Vim is a text editor which includes most commands from the Unix program "Vi"
+and many new ones.
An overview of this manual can be found in the file "help.txt", |help.txt|.
It can be accessed from within Vim with the <Help> or <F1> key and with the
@@ -28,16 +22,15 @@ is not located in the default place. You can jump to subjects like with tags:
Use CTRL-] to jump to a subject under the cursor, use CTRL-T to jump back.
*pronounce*
-Vim is pronounced as one word, like Jim. Nvim is pronounced as N-vim, or,
-continuing with the Jim simile, N-Jim, which sounds like Ninja.
+Vim is pronounced as one word, like Jim. So Nvim is N-Jim, which sounds like
+"Ninja". Starting Nvim is like performing a roundhouse kick.
-This manual is a reference for all the Vim commands and options. This is not
-an introduction to the use of Vi or Vim, it gets a bit complicated here and
-there. For beginners, there is a hands-on |tutor|. To learn using Vim, read
-the user manual |usr_toc.txt|.
+This manual is a reference for all Nvim editor and API features. It is not an
+introduction; instead for beginners, there is a hands-on |tutor| and a user
+manual |usr_toc.txt|.
*book*
-There are many books on Vi and Vim. We recommend these books:
+There are many books on Vi and Vim. We recommend:
"Practical Vim" by Drew Neil
"Modern Vim" by Drew Neil
@@ -48,7 +41,7 @@ tasks with Vim. "Modern Vim" explores new features in Nvim and Vim 8.
"Vim - Vi Improved" by Steve Oualline
-This is the first book dedicated to Vim. Parts of it were included in the
+This was the first book dedicated to Vim. Parts of it were included in the
user manual. |frombook| ISBN: 0735710015
For more information try one of these:
https://iccf-holland.org/click5.html
@@ -63,11 +56,9 @@ Nvim on the interwebs *internet*
Nvim FAQ: https://github.com/neovim/neovim/wiki/FAQ
Downloads: https://github.com/neovim/neovim/releases
Vim FAQ: https://vimhelp.appspot.com/vim_faq.txt.html
- Vim home page: https://www.vim.org/
- *bugs* *bug-report* *bugreport.vim* *feature-request*
-
+ *bugs* *bug-report*
Report bugs and request features here:
https://github.com/neovim/neovim/issues
@@ -97,7 +88,7 @@ Neovim development is funded separately from Vim:
https://neovim.io/#sponsor
==============================================================================
-Credits *credits* *author* *Bram* *Moolenaar*
+Credits *credits*
Most of Vim was written by Bram Moolenaar <Bram@vim.org>.
@@ -185,25 +176,21 @@ the ideas from all these people: They keep Vim alive!
*love* *peace* *friendship* *gross-national-happiness*
-In this documentation there are several references to other versions of Vi:
+Documentation may refer to other versions of Vi:
*Vi* *vi*
Vi "the original". Without further remarks this is the version
of Vi that appeared in Sun OS 4.x. ":version" returns
- "Version 3.7, 6/7/85". Sometimes other versions are referred
- to. Only runs under Unix. Source code only available with a
- license.
+ "Version 3.7, 6/7/85". Source code only available with a license.
*Nvi*
Nvi The "New" Vi. The version of Vi that comes with BSD 4.4 and FreeBSD.
Very good compatibility with the original Vi, with a few extensions.
The version used is 1.79. ":version" returns "Version 1.79
- (10/23/96)". There has been no release the last few years, although
- there is a development version 1.81.
- Source code is freely available.
+ (10/23/96)". Source code is freely available.
*Elvis*
Elvis Another Vi clone, made by Steve Kirkendall. Very compact but isn't
- as flexible as Vim.
- The version used is 2.1. It is still being developed. Source code is
- freely available.
+ as flexible as Vim. Source code is freely available.
+
+Vim Nvim is based on Vim. https://www.vim.org/
==============================================================================
Notation *notation*
@@ -387,37 +374,26 @@ notation meaning equivalent decimal value(s) ~
<D-โ€ฆ> command-key or "super" key *<D-*
-----------------------------------------------------------------------
-Note: The shifted cursor keys, the help key, and the undo key are only
-available on a few terminals.
-
-Note: There are two codes for the delete key. 127 is the decimal ASCII value
-for the delete key, which is always recognized. Some delete keys send another
-value, in which case this value is obtained from the |terminfo| entry "key_dc".
-Both values have the same effect.
+Note:
-Note: The keypad keys are used in the same way as the corresponding "normal"
-keys. For example, <kHome> has the same effect as <Home>. If a keypad key
-sends the same raw key code as its non-keypad equivalent, it will be
-recognized as the non-keypad code. For example, when <kHome> sends the same
-code as <Home>, when pressing <kHome> Vim will think <Home> was pressed.
-Mapping <kHome> will not work then.
-
-Note: If numlock is on, the |TUI| receives plain ASCII values, so
-mappings to <k0> - <k9> and <kPoint> will not work.
-
-Note: Nvim supports mapping multibyte chars with modifiers such as `<M-รค>`.
-Which combinations actually are usable depends on the terminal emulator or GUI.
+- Availability of some keys (<Help>, <S-Right>, โ€ฆ) depends on the UI or host
+ terminal.
+- If numlock is on the |TUI| receives plain ASCII values, so mapping <k0>,
+ <k1>, ..., <k9> and <kPoint> will not work.
+- Nvim supports mapping multibyte chars with modifiers such as `<M-รค>`. Which
+ combinations actually work depends on the the UI or host terminal.
+- When a key is pressed using a meta or alt modifier and no mapping exists
+ for that keypress, Nvim behaves as though <Esc> was pressed before the key.
*<>*
Examples are often given in the <> notation. Sometimes this is just to make
clear what you need to type, but often it can be typed literally, e.g., with
the ":map" command. The rules are:
- 1. Any printable characters are typed directly, except backslash and '<'
- 2. A backslash is represented with "\\", double backslash, or "<Bslash>".
- 3. A real '<' is represented with "\<" or "<lt>". When there is no
- confusion possible, a '<' can be used directly.
- 4. "<key>" means the special key typed. This is the notation explained in
- the table above. A few examples:
+ 1. Printable characters are typed directly, except backslash and "<"
+ 2. Backslash is represented with "\\", double backslash, or "<Bslash>".
+ 3. Literal "<" is represented with "\<" or "<lt>". When there is no
+ confusion possible, "<" can be used directly.
+ 4. "<key>" means the special key typed (see the table above). Examples:
<Esc> Escape key
<C-G> CTRL-G
<Up> cursor up key
@@ -437,11 +413,6 @@ one always works.
To get a literal "<lt>" in a mapping: >
:map <C-L> <lt>lt>
-For mapping, abbreviation and menu commands you can then copy-paste the
-examples and use them directly. Or type them literally, including the '<' and
-'>' characters. This does NOT work for other commands, like ":set" and
-":autocmd"!
-
==============================================================================
Modes, introduction *vim-modes-intro* *vim-modes*
@@ -599,7 +570,7 @@ Q or gQ Switch to Ex mode. This is like typing ":" commands
Use the ":vi" command |:visual| to exit this mode.
==============================================================================
-The window contents *window-contents*
+Window contents *window-contents*
In Normal mode and Insert/Replace mode the screen window will show the current
contents of the buffer: What You See Is What You Get. There are two
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index b934d2dfa0..33d65406a1 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -4,7 +4,7 @@
NVIM REFERENCE MANUAL
-LSP client/framework *lsp*
+LSP client/framework *lsp* *LSP*
Nvim supports the Language Server Protocol (LSP), which means it acts as
a client to LSP servers and includes a Lua framework `vim.lsp` for building
@@ -23,14 +23,14 @@ QUICKSTART *lsp-quickstart*
Nvim provides a LSP client, but the servers are provided by third parties.
Follow these steps to get LSP features:
- 1. Install the nvim-lsp plugin. It provides common configuration for
+ 1. Install the nvim-lspconfig plugin. It provides common configuration for
various servers so you can get started quickly.
- https://github.com/neovim/nvim-lsp
+ https://github.com/neovim/nvim-lspconfig
2. Install a language server. Try ":LspInstall <tab>" or use your system
package manager to install the relevant language server:
https://microsoft.github.io/language-server-protocol/implementors/servers/
3. Add `nvim_lsp.xx.setup{โ€ฆ}` to your vimrc, where "xx" is the name of the
- relevant config. See the nvim-lsp README for details.
+ relevant config. See the nvim-lspconfig README for details.
To check LSP clients attached to the current buffer: >
@@ -39,9 +39,10 @@ To check LSP clients attached to the current buffer: >
*lsp-config*
Inline diagnostics are enabled automatically, e.g. syntax errors will be
annotated in the buffer. But you probably want to use other features like
-go-to-definition, hover, etc. Example config: >
+go-to-definition, hover, etc. Full list of features in |vim.lsp.buf|.
+
+Example config: >
- nnoremap <silent> gd <cmd>lua vim.lsp.buf.declaration()<CR>
nnoremap <silent> <c-]> <cmd>lua vim.lsp.buf.definition()<CR>
nnoremap <silent> K <cmd>lua vim.lsp.buf.hover()<CR>
nnoremap <silent> gD <cmd>lua vim.lsp.buf.implementation()<CR>
@@ -50,6 +51,9 @@ go-to-definition, hover, etc. Example config: >
nnoremap <silent> gr <cmd>lua vim.lsp.buf.references()<CR>
nnoremap <silent> g0 <cmd>lua vim.lsp.buf.document_symbol()<CR>
nnoremap <silent> gW <cmd>lua vim.lsp.buf.workspace_symbol()<CR>
+ nnoremap <silent> gd <cmd>lua vim.lsp.buf.declaration()<CR>
+
+Note: Language servers may have limited support for these features.
Nvim provides the |vim.lsp.omnifunc| 'omnifunc' handler which allows
|i_CTRL-X_CTRL-O| to consume LSP completion. Example config (note the use of
@@ -353,9 +357,6 @@ buf_get_clients({bufnr}) *vim.lsp.buf_get_clients()*
{bufnr} (optional, number): Buffer handle, or 0 for
current
-buf_get_full_text({bufnr}) *vim.lsp.buf_get_full_text()*
- TODO: Documentation
-
buf_is_attached({bufnr}, {client_id}) *vim.lsp.buf_is_attached()*
Checks if a buffer is attached for a particular client.
@@ -416,71 +417,69 @@ buf_request_sync({bufnr}, {method}, {params}, {timeout_ms})
error, returns `(nil, err)` where `err` is a string
describing the failure reason.
-cancel_request({id}) *vim.lsp.cancel_request()*
- TODO: Documentation
-
client() *vim.lsp.client*
- LSP client object.
+ LSP client object. You can get an active client object via
+ |vim.lsp.get_client_by_id()| or
+ |vim.lsp.get_active_clients()|.
โ€ข Methods:
- โ€ข request(method, params, [callback]) Send a request to the
- server. If callback is not specified, it will use
+ โ€ข request(method, params, [callback], bufnr) Sends a request
+ to the server. This is a thin wrapper around
+ {client.rpc.request} with some additional checking. If
+ {callback} is not specified, it will use
{client.callbacks} to try to find a callback. If one is
- not found there, then an error will occur. This is a thin
- wrapper around {client.rpc.request} with some additional
- checking. Returns a boolean to indicate if the
- notification was successful. If it is false, then it will
- always be false (the client has shutdown). If it was
- successful, then it will return the request id as the
- second result. You can use this with `notify("$/cancel", {
- id = request_id })` to cancel the request. This helper is
- made automatically with |vim.lsp.buf_request()| Returns:
- status, [client_id]
- โ€ข notify(method, params) This is just {client.rpc.notify}()
- Returns a boolean to indicate if the notification was
- successful. If it is false, then it will always be false
- (the client has shutdown). Returns: status
- โ€ข cancel_request(id) This is just
- {client.rpc.notify}("$/cancelRequest", { id = id })
- Returns the same as `notify()` .
- โ€ข stop([force]) Stop a client, optionally with force. By
+ not found there, then an error will occur. Returns:
+ {status}, {[client_id]}. {status} is a boolean indicating
+ if the notification was successful. If it is `false` ,
+ then it will always be `false` (the client has shutdown).
+ If {status} is `true` , the function returns {request_id}
+ as the second result. You can use this with
+ `client.cancel_request(request_id)` to cancel the request.
+ โ€ข notify(method, params) Sends a notification to an LSP
+ server. Returns: a boolean to indicate if the notification
+ was successful. If it is false, then it will always be
+ false (the client has shutdown).
+ โ€ข cancel_request(id) Cancels a request with a given request
+ id. Returns: same as `notify()` .
+ โ€ข stop([force]) Stops a client, optionally with force. By
default, it will just ask the server to shutdown without
force. If you request to stop a client which has
previously been requested to shutdown, it will
automatically escalate and force shutdown.
- โ€ข is_stopped() Returns true if the client is fully stopped.
+ โ€ข is_stopped() Checks whether a client is stopped. Returns:
+ true if the client is fully stopped.
+ โ€ข on_attach(bufnr) Runs the on_attach function from the
+ client's config if it was defined.
โ€ข Members
- โ€ข id (number): The id allocated to the client.
- โ€ข name (string): If a name is specified on creation, that
+ โ€ข {id} (number): The id allocated to the client.
+ โ€ข {name} (string): If a name is specified on creation, that
will be used. Otherwise it is just the client id. This is
used for logs and messages.
- โ€ข offset_encoding (string): The encoding used for
+ โ€ข {rpc} (table): RPC client object, for low level
+ interaction with the client. See |vim.lsp.rpc.start()|.
+ โ€ข {offset_encoding} (string): The encoding used for
communicating with the server. You can modify this in the
- `on_init` method before text is sent to the server.
- โ€ข callbacks (table): The callbacks used by the client as
+ `config` 's `on_init` method before text is sent to the
+ server.
+ โ€ข {callbacks} (table): The callbacks used by the client as
described in |lsp-callbacks|.
- โ€ข config (table): copy of the table that was passed by the
+ โ€ข {config} (table): copy of the table that was passed by the
user to |vim.lsp.start_client()|.
- โ€ข server_capabilities (table): Response from the server sent
- on `initialize` describing the server's capabilities.
- โ€ข resolved_capabilities (table): Normalized table of
+ โ€ข {server_capabilities} (table): Response from the server
+ sent on `initialize` describing the server's capabilities.
+ โ€ข {resolved_capabilities} (table): Normalized table of
capabilities that we have detected based on the initialize
response from the server in `server_capabilities` .
client_is_stopped({client_id}) *vim.lsp.client_is_stopped()*
- TODO: Documentation
+ Checks whether a client is stopped.
- *vim.lsp.define_default_sign()*
-define_default_sign({name}, {properties})
- TODO: Documentation
-
-err_message({...}) *vim.lsp.err_message()*
- TODO: Documentation
+ Parameters: ~
+ {client_id} (Number)
- *vim.lsp.for_each_buffer_client()*
-for_each_buffer_client({bufnr}, {callback})
- TODO: Documentation
+ Return: ~
+ true if client is stopped, false otherwise.
get_active_clients() *vim.lsp.get_active_clients()*
Gets all active clients.
@@ -489,8 +488,8 @@ get_active_clients() *vim.lsp.get_active_clients()*
Table of |vim.lsp.client| objects
get_client_by_id({client_id}) *vim.lsp.get_client_by_id()*
- Gets an active client by id, or nil if the id is invalid or
- the client is not yet initialized.
+ Gets a client by id, or nil if the id is invalid.
+ The returned client may not yet be fully initialized.
Parameters: ~
{client_id} client id number
@@ -499,25 +498,10 @@ get_client_by_id({client_id}) *vim.lsp.get_client_by_id()*
|vim.lsp.client| object, or nil
get_log_path() *vim.lsp.get_log_path()*
- TODO: Documentation
-
-initialize() *vim.lsp.initialize()*
- TODO: Documentation
-
-is_dir({filename}) *vim.lsp.is_dir()*
- TODO: Documentation
-
-is_stopped() *vim.lsp.is_stopped()*
- TODO: Documentation
+ Gets the path of the logfile used by the LSP client.
-next_client_id() *vim.lsp.next_client_id()*
- TODO: Documentation
-
-notification({method}, {params}) *vim.lsp.notification()*
- TODO: Documentation
-
-notify({...}) *vim.lsp.notify()*
- TODO: Documentation
+ Return: ~
+ (String) Path to logfile.
omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
Implements 'omnifunc' compatible LSP completion.
@@ -538,30 +522,6 @@ omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
|complete-items|
|CompleteDone|
-on_error({code}, {err}) *vim.lsp.on_error()*
- TODO: Documentation
-
-on_exit({code}, {signal}) *vim.lsp.on_exit()*
- TODO: Documentation
-
-once({fn}) *vim.lsp.once()*
- TODO: Documentation
-
-optional_validator({fn}) *vim.lsp.optional_validator()*
- TODO: Documentation
-
-request({method}, {params}, {callback}, {bufnr}) *vim.lsp.request()*
- TODO: Documentation
-
-resolve_bufnr({bufnr}) *vim.lsp.resolve_bufnr()*
- TODO: Documentation
-
-resolve_callback({method}) *vim.lsp.resolve_callback()*
- TODO: Documentation
-
-server_request({method}, {params}) *vim.lsp.server_request()*
- TODO: Documentation
-
set_log_level({level}) *vim.lsp.set_log_level()*
Sets the global log level for LSP logging.
@@ -582,6 +542,9 @@ start_client({config}) *vim.lsp.start_client()*
Parameters `cmd` and `root_dir` are required.
+ The following parameters describe fields in the {config}
+ table.
+
Parameters: ~
{root_dir} (required, string) Directory where the
LSP server will base its rootUri on
@@ -612,13 +575,13 @@ start_client({config}) *vim.lsp.start_client()*
array.
{callbacks} Map of language server method names to `function(err, method, params,
client_id)` handler. Invoked for:
- โ€ข Notifications from the server, where
+ โ€ข Notifications to the server, where
`err` will always be `nil` .
- โ€ข Requests initiated by the server. For
- these you can respond by returning
- two values: `result, err` where err
- must be shaped like a RPC error, i.e.
- `{ code, message, data? }` . Use
+ โ€ข Requests by the server. For these you
+ can respond by returning two values:
+ `result, err` where err must be
+ shaped like a RPC error, i.e. `{
+ code, message, data? }` . Use
|vim.lsp.rpc_response_error()| to
help with this.
โ€ข Default callback for client requests
@@ -647,8 +610,9 @@ start_client({config}) *vim.lsp.start_client()*
where `params` contains the parameters
being sent to the server and `config`
is the config that was passed to
- `start_client()` . You can use this to
- modify parameters before they are sent.
+ |vim.lsp.start_client()|. You can use
+ this to modify parameters before they
+ are sent.
{on_init} Callback (client, initialize_result)
invoked after LSP "initialize", where
`result` is a table of `capabilities`
@@ -680,9 +644,6 @@ start_client({config}) *vim.lsp.start_client()*
error). Use `on_init` to do any actions once the client
has been initialized.
-stop({force}) *vim.lsp.stop()*
- TODO: Documentation
-
stop_client({client_id}, {force}) *vim.lsp.stop_client()*
Stops a client(s).
@@ -690,7 +651,7 @@ stop_client({client_id}, {force}) *vim.lsp.stop_client()*
object. To stop all clients:
>
- vim.lsp.stop_client(lsp.get_active_clients())
+ vim.lsp.stop_client(vim.lsp.get_active_clients())
<
By default asks the server to shutdown, unless stop was
@@ -702,26 +663,10 @@ stop_client({client_id}, {force}) *vim.lsp.stop_client()*
thereof
{force} boolean (optional) shutdown forcefully
- *vim.lsp.text_document_did_open_handler()*
-text_document_did_open_handler({bufnr}, {client})
- TODO: Documentation
-
-unsupported_method({method}) *vim.lsp.unsupported_method()*
- TODO: Documentation
-
-validate_client_config({config}) *vim.lsp.validate_client_config()*
- TODO: Documentation
-
-validate_encoding({encoding}) *vim.lsp.validate_encoding()*
- TODO: Documentation
-
==============================================================================
Lua module: vim.lsp.protocol *lsp-protocol*
-ifnil({a}, {b}) *vim.lsp.protocol.ifnil()*
- TODO: Documentation
-
*vim.lsp.protocol.make_client_capabilities()*
make_client_capabilities()
Gets a new ClientCapabilities object describing the LSP client
@@ -739,28 +684,38 @@ resolve_capabilities({server_capabilities})
characters to match in a path segment (e.g., `example.[!0-9]`
to match on `example.a` , `example.b` , but not `example.0` )
- *vim.lsp.protocol.transform_schema_comments()*
-transform_schema_comments()
- TODO: Documentation
-
- *vim.lsp.protocol.transform_schema_to_table()*
-transform_schema_to_table()
- TODO: Documentation
-
==============================================================================
Lua module: vim.lsp.buf *lsp-buf*
clear_references() *vim.lsp.buf.clear_references()*
- TODO: Documentation
+ Removes document highlights from current buffer.
code_action({context}) *vim.lsp.buf.code_action()*
- TODO: Documentation
+ Selects a code action from the input list that is available at
+ the current cursor position.
+
+ Parameters: ~
+ {context} (table, optional) Valid `CodeActionContext`
+ object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
completion({context}) *vim.lsp.buf.completion()*
Retrieves the completion items at the current cursor position.
Can only be called in Insert mode.
+ Parameters: ~
+ {context} (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.constants.CompletionTriggerKind|
+
declaration() *vim.lsp.buf.declaration()*
Jumps to the declaration of the symbol under the cursor.
@@ -782,22 +737,41 @@ document_symbol() *vim.lsp.buf.document_symbol()*
window.
execute_command({command}) *vim.lsp.buf.execute_command()*
- TODO: Documentation
+ Executes an LSP server command.
+
+ Parameters: ~
+ {command} A valid `ExecuteCommandParams` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
formatting({options}) *vim.lsp.buf.formatting()*
Formats the current buffer.
- The optional {options} table can be used to specify
- FormattingOptions, a list of which is available at https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting . Some unspecified options will be automatically derived from
- the current Neovim options.
+ Parameters: ~
+ {options} (optional, table) Can be used to specify
+ FormattingOptions. Some unspecified options
+ will be automatically derived from the current
+ Neovim options.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
*vim.lsp.buf.formatting_sync()*
formatting_sync({options}, {timeout_ms})
- Perform |vim.lsp.buf.formatting()| synchronously.
+ Performs |vim.lsp.buf.formatting()| synchronously.
Useful for running on save, to make sure buffer is formatted
prior to being saved. {timeout_ms} is passed on to
- |vim.lsp.buf_request_sync()|.
+ |vim.lsp.buf_request_sync()|. Example:
+>
+
+ vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
+<
+
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries
+ {timeout_ms} (number) Request timeout
hover() *vim.lsp.buf.hover()*
Displays hover information about the symbol under the cursor
@@ -808,29 +782,61 @@ implementation() *vim.lsp.buf.implementation()*
Lists all the implementations for the symbol under the cursor
in the quickfix window.
-npcall({fn}, {...}) *vim.lsp.buf.npcall()*
- TODO: Documentation
+incoming_calls() *vim.lsp.buf.incoming_calls()*
+ 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|.
+
+outgoing_calls() *vim.lsp.buf.outgoing_calls()*
+ 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|.
+
+ *vim.lsp.buf.range_code_action()*
+range_code_action({context}, {start_pos}, {end_pos})
+ Performs |vim.lsp.buf.code_action()| for a given range.
-ok_or_nil({status}, {...}) *vim.lsp.buf.ok_or_nil()*
- TODO: Documentation
+ Parameters: ~
+ {context} (table, optional) Valid `CodeActionContext`
+ object
+ {start_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the start of the last
+ visual selection.
+ {end_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the end of the last
+ visual selection.
*vim.lsp.buf.range_formatting()*
range_formatting({options}, {start_pos}, {end_pos})
- TODO: Documentation
+ Formats a given range.
+
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries.
+ {start_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the end of the last
+ visual selection.
references({context}) *vim.lsp.buf.references()*
Lists all the references to the symbol under the cursor in the
quickfix window.
+ Parameters: ~
+ {context} (table) Context for the request
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
+
rename({new_name}) *vim.lsp.buf.rename()*
- Renames all references to the symbol under the cursor. If
- {new_name} is not provided, the user will be prompted for a
- new name using |input()|.
+ Renames all references to the symbol under the cursor.
-request({method}, {params}, {callback}) *vim.lsp.buf.request()*
- TODO: Documentation
+ Parameters: ~
+ {new_name} (string) If not provided, the user will be
+ prompted for a new name using |input()|.
server_ready() *vim.lsp.buf.server_ready()*
+ Checks whether the language servers attached to the current
+ buffer are ready.
+
Return: ~
`true` if server responds.
@@ -846,115 +852,75 @@ workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()*
Lists all symbols in the current workspace in the quickfix
window.
- The list is filtered against the optional argument {query}; if
- the argument is omitted from the call, the user is prompted to
- enter a string on the command line. An empty string means no
- filtering is done.
-
-incoming_calls() *vim.lsp.buf.incoming_calls()*
- 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|.
-
-outgoing_calls() *vim.lsp.buf.outgoing_calls()*
- 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|.
-
-
-==============================================================================
-Lua module: vim.lsp.callbacks *lsp-callbacks*
-
-err_message({...}) *vim.lsp.callbacks.err_message()*
- TODO: Documentation
+ The list is filtered against {query}; if the argument is
+ omitted from the call, the user is prompted to enter a string
+ on the command line. An empty string means no filtering is
+ done.
- *vim.lsp.callbacks.location_callback()*
-location_callback({_}, {method}, {result})
- TODO: Documentation
+ Parameters: ~
+ {query} (string, optional)
==============================================================================
Lua module: vim.lsp.log *lsp-log*
get_filename() *vim.lsp.log.get_filename()*
- TODO: Documentation
+ Returns the log filename.
-path_join({...}) *vim.lsp.log.path_join()*
- TODO: Documentation
+ Return: ~
+ (string) log filename
set_level({level}) *vim.lsp.log.set_level()*
- TODO: Documentation
-
-should_log({level}) *vim.lsp.log.should_log()*
- TODO: Documentation
-
-
-==============================================================================
-Lua module: vim.lsp.rpc *lsp-rpc*
-
-convert_NIL({v}) *vim.lsp.rpc.convert_NIL()*
- TODO: Documentation
+ Sets the current log level.
- *vim.lsp.rpc.create_and_start_client()*
-create_and_start_client({cmd}, {cmd_args}, {handlers},
- {extra_spawn_params})
- TODO: Documentation
+ Parameters: ~
+ {level} (string or number) One of `vim.lsp.log.levels`
-encode_and_send({payload}) *vim.lsp.rpc.encode_and_send()*
- TODO: Documentation
+should_log({level}) *vim.lsp.log.should_log()*
+ Checks whether the level is sufficient for logging.
-env_merge({env}) *vim.lsp.rpc.env_merge()*
- Merges current process env with the given env and returns the
- result as a list of "k=v" strings.
->
+ Parameters: ~
+ {level} number log level
- Example:
-<
+ Return: ~
+ (bool) true if would log, false if not
- > in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
-<
- *vim.lsp.rpc.format_message_with_content_length()*
-format_message_with_content_length({encoded_message})
- TODO: Documentation
+==============================================================================
+Lua module: vim.lsp.rpc *lsp-rpc*
format_rpc_error({err}) *vim.lsp.rpc.format_rpc_error()*
- TODO: Documentation
-
-handle_body({body}) *vim.lsp.rpc.handle_body()*
- TODO: Documentation
-
-is_dir({filename}) *vim.lsp.rpc.is_dir()*
- TODO: Documentation
-
-json_decode({data}) *vim.lsp.rpc.json_decode()*
- TODO: Documentation
+ Constructs an error message from an LSP error object.
-json_encode({data}) *vim.lsp.rpc.json_encode()*
- TODO: Documentation
+ Parameters: ~
+ {err} (table) The error object
-notification({method}, {params}) *vim.lsp.rpc.notification()*
- TODO: Documentation
+ Return: ~
+ (string) The formatted error message
-on_error({errkind}, {...}) *vim.lsp.rpc.on_error()*
- TODO: Documentation
+notify({method}, {params}) *vim.lsp.rpc.notify()*
+ Sends a notification to the LSP server.
-on_exit({code}, {signal}) *vim.lsp.rpc.on_exit()*
- TODO: Documentation
+ Parameters: ~
+ {method} (string) The invoked LSP method
+ {params} (table): Parameters for the invoked LSP method
-onexit({code}, {signal}) *vim.lsp.rpc.onexit()*
- TODO: Documentation
+ Return: ~
+ (bool) `true` if notification could be sent, `false` if
+ not
-parse_headers({header}) *vim.lsp.rpc.parse_headers()*
- TODO: Documentation
+request({method}, {params}, {callback}) *vim.lsp.rpc.request()*
+ Sends a request to the LSP server and runs {callback} upon
+ response.
- *vim.lsp.rpc.pcall_handler()*
-pcall_handler({errkind}, {status}, {head}, {...})
- TODO: Documentation
+ Parameters: ~
+ {method} (string) The invoked LSP method
+ {params} (table) Parameters for the invoked LSP method
+ {callback} (function) Callback to invoke
-request_parser_loop() *vim.lsp.rpc.request_parser_loop()*
- TODO: Documentation
+ Return: ~
+ (bool, number) `(true, message_id)` if request could be
+ sent, `false` if not
*vim.lsp.rpc.rpc_response_error()*
rpc_response_error({code}, {message}, {data})
@@ -966,48 +932,81 @@ rpc_response_error({code}, {message}, {data})
{message} (optional) arbitrary message to send to server
{data} (optional) arbitrary data to send to server
-send_notification({method}, {params}) *vim.lsp.rpc.send_notification()*
- TODO: Documentation
-
- *vim.lsp.rpc.send_request()*
-send_request({method}, {params}, {callback})
- TODO: Documentation
+ *vim.lsp.rpc.start()*
+start({cmd}, {cmd_args}, {handlers}, {extra_spawn_params})
+ Starts an LSP server process and create an LSP RPC client
+ object to interact with it.
- *vim.lsp.rpc.send_response()*
-send_response({request_id}, {err}, {result})
- TODO: Documentation
+ Parameters: ~
+ {cmd} (string) Command to start the LSP
+ server.
+ {cmd_args} (table) List of additional string
+ arguments to pass to {cmd}.
+ {handlers} (table, optional) Handlers for LSP
+ message types. Valid handler names
+ are:
+ โ€ข `"notification"`
+ โ€ข `"server_request"`
+ โ€ข `"on_error"`
+ โ€ข `"on_exit"`
+ {extra_spawn_params} (table, optional) Additional context
+ for the LSP server process. May
+ contain:
+ โ€ข {cwd} (string) Working directory
+ for the LSP server process
+ โ€ข {env} (table) Additional
+ environment variables for LSP
+ server process
-server_request({method}, {params}) *vim.lsp.rpc.server_request()*
- TODO: Documentation
+ Return: ~
+ Client RPC object.
+ Methods:
+ โ€ข `notify()` |vim.lsp.rpc.notify()|
+ โ€ข `request()` |vim.lsp.rpc.request()|
-try_call({errkind}, {fn}, {...}) *vim.lsp.rpc.try_call()*
- TODO: Documentation
+ Members:
+ โ€ข {pid} (number) The LSP server's PID.
+ โ€ข {handle} A handle for low-level interaction with the LSP
+ server process |vim.loop|.
==============================================================================
Lua module: vim.lsp.util *lsp-util*
- *vim.lsp.util.apply_syntax_to_region()*
-apply_syntax_to_region({ft}, {start}, {finish})
- TODO: Documentation
-
*vim.lsp.util.apply_text_document_edit()*
apply_text_document_edit({text_document_edit})
- TODO: Documentation
+ Parameters: ~
+ {text_document_edit} (table) a `TextDocumentEdit` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
*vim.lsp.util.apply_text_edits()*
apply_text_edits({text_edits}, {bufnr})
- TODO: Documentation
+ Applies a list of text edits to a buffer.
+
+ Parameters: ~
+ {text_edits} (table) list of `TextEdit` objects
+ {buf_nr} (number) Buffer id
*vim.lsp.util.apply_workspace_edit()*
apply_workspace_edit({workspace_edit})
- TODO: Documentation
+ Applies a `WorkspaceEdit` .
+
+ Parameters: ~
+ {workspace_edit} (table) `WorkspaceEdit`
buf_clear_diagnostics({bufnr}) *vim.lsp.util.buf_clear_diagnostics()*
- TODO: Documentation
+ Clears diagnostics for a buffer.
+
+ Parameters: ~
+ {bufnr} (number) buffer id
buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
- TODO: Documentation
+ Removes document highlights from a buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
buf_diagnostics_count({kind}) *vim.lsp.util.buf_diagnostics_count()*
Returns the number of diagnostics of given kind for current
@@ -1040,16 +1039,18 @@ buf_diagnostics_count({kind}) *vim.lsp.util.buf_diagnostics_count()*
*vim.lsp.util.buf_diagnostics_save_positions()*
buf_diagnostics_save_positions({bufnr}, {diagnostics})
- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ Saves diagnostics into
+ vim.lsp.util.diagnostics_by_buf[{bufnr}].
Parameters: ~
- {bufnr} bufnr for which the diagnostics are for.
- {diagnostics} Diagnostics[] received from the language
- server.
+ {bufnr} (number) buffer id for which the
+ diagnostics are for
+ {diagnostics} list of `Diagnostic` s received from the
+ LSP server
*vim.lsp.util.buf_diagnostics_signs()*
buf_diagnostics_signs({bufnr}, {diagnostics})
- Place signs for each diagnostic in the sign column.
+ Places signs for each diagnostic in the sign column.
Sign characters can be customized with the following commands:
>
@@ -1061,47 +1062,125 @@ buf_diagnostics_signs({bufnr}, {diagnostics})
*vim.lsp.util.buf_diagnostics_underline()*
buf_diagnostics_underline({bufnr}, {diagnostics})
- TODO: Documentation
+ Highlights a list of diagnostics in a buffer by underlining
+ them.
+
+ Parameters: ~
+ {bufnr} (number) buffer id
+ {diagnostics} (list of `Diagnostic` s)
*vim.lsp.util.buf_diagnostics_virtual_text()*
buf_diagnostics_virtual_text({bufnr}, {diagnostics})
- TODO: Documentation
+ Given a list of diagnostics, sets the corresponding virtual
+ text for a buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
+ {diagnostics} (table) list of `Diagnostic` s
*vim.lsp.util.buf_highlight_references()*
buf_highlight_references({bufnr}, {references})
- TODO: Documentation
+ Shows a list of document highlights for a certain buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
+ {references} List of `DocumentHighlight` objects to
+ highlight
character_offset({buf}, {row}, {col}) *vim.lsp.util.character_offset()*
- TODO: Documentation
+ Returns the UTF-32 and UTF-16 offsets for a position in a
+ certain buffer.
+
+ Parameters: ~
+ {buf} buffer id (0 for current)
+ {row} 0-indexed line
+ {col} 0-indexed byte offset in line
+
+ Return: ~
+ (number, number) UTF-32 and UTF-16 index of the character
+ in line {row} column {col} in buffer {buf}
*vim.lsp.util.close_preview_autocmd()*
close_preview_autocmd({events}, {winnr})
- TODO: Documentation
+ Creates autocommands to close a preview window when events
+ happen.
+
+ Parameters: ~
+ {events} (table) list of events
+ {winnr} (number) window id of preview window
+
+ See also: ~
+ |autocmd-events|
*vim.lsp.util.convert_input_to_markdown_lines()*
convert_input_to_markdown_lines({input}, {contents})
- TODO: Documentation
+ Converts any of `MarkedString` | `MarkedString[]` |
+ `MarkupContent` into a list of lines containing valid
+ markdown. Useful to populate the hover window for
+ `textDocument/hover` , for parsing the result of
+ `textDocument/signatureHelp` , and potentially others.
+
+ Parameters: ~
+ {input} ( `MarkedString` | `MarkedString[]` |
+ `MarkupContent` )
+ {contents} (table, optional, default `{}` ) List of
+ strings to extend with converted lines
+
+ Return: ~
+ {contents}, extended with lines of converted markdown.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
*vim.lsp.util.convert_signature_help_to_markdown_lines()*
convert_signature_help_to_markdown_lines({signature_help})
- TODO: Documentation
+ Converts `textDocument/SignatureHelp` response to markdown
+ lines.
+
+ Parameters: ~
+ {signature_help} Response of `textDocument/SignatureHelp`
+
+ Return: ~
+ list of lines of converted markdown.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
*vim.lsp.util.diagnostics_group_by_line()*
diagnostics_group_by_line({diagnostics})
- TODO: Documentation
+ Groups a list of diagnostics by line.
+
+ Parameters: ~
+ {diagnostics} (table) list of `Diagnostic` s
+
+ Return: ~
+ (table) dictionary mapping lines to lists of diagnostics
+ valid on those lines
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
*vim.lsp.util.extract_completion_items()*
extract_completion_items({result})
- TODO: Documentation
+ Can be used to extract the completion items from a `textDocument/completion` request, which may return one of `CompletionItem[]` , `CompletionList` or null.
+
+ Parameters: ~
+ {result} (table) The result of a
+ `textDocument/completion` request
+
+ Return: ~
+ (table) List of completion items
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
*vim.lsp.util.fancy_floating_markdown()*
fancy_floating_markdown({contents}, {opts})
- Convert markdown into syntax highlighted regions by stripping
+ Converts markdown into syntax highlighted regions by stripping
the code blocks and converting them into highlighted code.
This will by default insert a blank line separator after those
code block regions to improve readability. The result is shown
- in a floating preview TODO: refactor to separate
- stripping/converting and make use of open_floating_preview
+ in a floating preview.
Parameters: ~
{contents} table of lines to show in window
@@ -1110,25 +1189,37 @@ fancy_floating_markdown({contents}, {opts})
Return: ~
width,height size of float
-find_window_by_var({name}, {value}) *vim.lsp.util.find_window_by_var()*
- TODO: Documentation
-
focusable_float({unique_name}, {fn}) *vim.lsp.util.focusable_float()*
- TODO: Documentation
+ Parameters: ~
+ {unique_name} (string) Window variable
+ {fn} (function) should return create a new
+ window and return a tuple of
+ ({focusable_buffer_id}, {window_id}). if
+ {focusable_buffer_id} is a valid buffer id,
+ the newly created window will be the new
+ focus associated with the current buffer
+ via the tag `unique_name` .
+
+ Return: ~
+ (pbufnr, pwinnr) if `fn()` has created a new window; nil
+ otherwise
*vim.lsp.util.focusable_preview()*
focusable_preview({unique_name}, {fn})
- TODO: Documentation
+ Focuses/unfocuses the floating preview window associated with
+ the current buffer via the window variable `unique_name` . If
+ no such preview window exists, makes a new one.
-get_completion_word({item}) *vim.lsp.util.get_completion_word()*
- TODO: Documentation
-
- *vim.lsp.util.get_current_line_to_cursor()*
-get_current_line_to_cursor()
- TODO: Documentation
+ Parameters: ~
+ {unique_name} (string) Window variable
+ {fn} (function) The return values of this
+ function will be passed directly to
+ |vim.lsp.util.open_floating_preview()|, in
+ the case that a new floating window should
+ be created
get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
- Get visual width of tabstop.
+ Returns visual width of tabstop.
Parameters: ~
{bufnr} (optional, number): Buffer handle, defaults to
@@ -1140,52 +1231,125 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
See also: ~
|softtabstop|
- *vim.lsp.util.get_line_byte_from_position()*
-get_line_byte_from_position({bufnr}, {position})
- TODO: Documentation
-
get_line_diagnostics() *vim.lsp.util.get_line_diagnostics()*
- TODO: Documentation
+ Gets list of diagnostics for the current line.
+
+ Return: ~
+ (table) list of `Diagnostic` tables
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
*vim.lsp.util.get_severity_highlight_name()*
get_severity_highlight_name({severity})
- TODO: Documentation
+ Gets the name of a severity's highlight group.
+
+ Parameters: ~
+ {severity} A member of
+ `vim.lsp.protocol.DiagnosticSeverity`
+
+ Return: ~
+ (string) Highlight group name
jump_to_location({location}) *vim.lsp.util.jump_to_location()*
- TODO: Documentation
+ Jumps to a location.
+
+ Parameters: ~
+ {location} ( `Location` | `LocationLink` )
+
+ Return: ~
+ `true` if the jump succeeded
locations_to_items({locations}) *vim.lsp.util.locations_to_items()*
- TODO: Documentation
+ Returns the items with the byte position calculated correctly
+ and in sorted order, for display in quickfix and location
+ lists.
+
+ Parameters: ~
+ {locations} (table) list of `Location` s or
+ `LocationLink` s
+
+ Return: ~
+ (table) list of items
*vim.lsp.util.make_floating_popup_options()*
make_floating_popup_options({width}, {height}, {opts})
- TODO: Documentation
+ Creates a table with sensible default options for a floating
+ window. The table can be passed to |nvim_open_win()|.
+
+ Parameters: ~
+ {width} (number) window width (in character cells)
+ {height} (number) window height (in character cells)
+ {opts} (table, optional)
+
+ Return: ~
+ (table) Options
*vim.lsp.util.make_formatting_params()*
make_formatting_params({options})
- TODO: Documentation
+ Creates a `FormattingOptions` object for the current buffer
+ and cursor position.
+
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries
+
+ Return: ~
+ `FormattingOptions object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
+
+ *vim.lsp.util.make_given_range_params()*
+make_given_range_params({start_pos}, {end_pos})
+ Using the given range in the current buffer, creates an object
+ that is similar to |vim.lsp.util.make_range_params()|.
-make_position_param() *vim.lsp.util.make_position_param()*
- TODO: Documentation
+ Parameters: ~
+ {start_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the start of the last
+ visual selection.
+ {end_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the end of the last
+ visual selection.
+
+ Return: ~
+ { textDocument = { uri = `current_file_uri` }, range = {
+ start = `start_position` , end = `end_position` } }
make_position_params() *vim.lsp.util.make_position_params()*
- TODO: Documentation
+ Creates a `TextDocumentPositionParams` object for the current
+ buffer and cursor position.
+
+ Return: ~
+ `TextDocumentPositionParams` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
make_range_params() *vim.lsp.util.make_range_params()*
- TODO: Documentation
+ Using the current position in the current buffer, creates an
+ object that can be used as a building block for several LSP
+ requests, such as `textDocument/codeAction` ,
+ `textDocument/colorPresentation` ,
+ `textDocument/rangeFormatting` .
+
+ Return: ~
+ { textDocument = { uri = `current_file_uri` }, range = {
+ start = `current_position` , end = `current_position` } }
make_text_document_params() *vim.lsp.util.make_text_document_params()*
- TODO: Documentation
+ Creates a `TextDocumentIdentifier` object for the current
+ buffer.
-npcall({fn}, {...}) *vim.lsp.util.npcall()*
- TODO: Documentation
+ Return: ~
+ `TextDocumentIdentifier`
-ok_or_nil({status}, {...}) *vim.lsp.util.ok_or_nil()*
- TODO: Documentation
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
*vim.lsp.util.open_floating_preview()*
open_floating_preview({contents}, {filetype}, {opts})
- Show contents in a floating window
+ Shows contents in a floating window.
Parameters: ~
{contents} table of lines to show in window
@@ -1193,17 +1357,20 @@ open_floating_preview({contents}, {filetype}, {opts})
{opts} dictionary with optional fields
Return: ~
- bufnr,winnr buffer and window number of floating window or
- nil
+ bufnr,winnr buffer and window number of the newly created
+ floating preview window
parse_snippet({input}) *vim.lsp.util.parse_snippet()*
- TODO: Documentation
+ Parses snippets in a completion entry.
-parse_snippet_rec({input}, {inner}) *vim.lsp.util.parse_snippet_rec()*
- TODO: Documentation
+ Parameters: ~
+ {input} (string) unparsed snippet
+
+ Return: ~
+ (string) parsed snippet
preview_location({location}) *vim.lsp.util.preview_location()*
- Preview a location in a floating windows
+ Previews a location in a floating window
behavior depends on type of location:
โ€ข for Location, range is shown (e.g., function definition)
@@ -1211,52 +1378,91 @@ preview_location({location}) *vim.lsp.util.preview_location()*
function definition)
Parameters: ~
- {location} a single Location or LocationLink
+ {location} a single `Location` or `LocationLink`
Return: ~
- bufnr,winnr buffer and window number of floating window or
- nil
-
- *vim.lsp.util.remove_unmatch_completion_items()*
-remove_unmatch_completion_items({items}, {prefix})
- TODO: Documentation
+ (bufnr,winnr) buffer and window number of floating window
+ or nil
set_lines({lines}, {A}, {B}, {new_lines}) *vim.lsp.util.set_lines()*
- TODO: Documentation
+ Replaces text in a range with new text.
-set_loclist({items}) *vim.lsp.util.set_loclist()*
- TODO: Documentation
+ CAUTION: Changes in-place!
-set_qflist({items}) *vim.lsp.util.set_qflist()*
- TODO: Documentation
+ Parameters: ~
+ {lines} (table) Original list of strings
+ {A} (table) Start position; a 2-tuple of {line,
+ col} numbers
+ {B} (table) End position; a 2-tuple of {line,
+ col} numbers
+ {new_lines} A list of strings to replace the original
-show_line_diagnostics() *vim.lsp.util.show_line_diagnostics()*
- TODO: Documentation
+ Return: ~
+ (table) The modified {lines} object
-sort_by_key({fn}) *vim.lsp.util.sort_by_key()*
- TODO: Documentation
+set_loclist({items}) *vim.lsp.util.set_loclist()*
+ Fills current window's location list with given list of items.
+ Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
-sort_completion_items({items}) *vim.lsp.util.sort_completion_items()*
- TODO: Documentation
+ Parameters: ~
+ {items} (table) list of items
-split_lines({value}) *vim.lsp.util.split_lines()*
- TODO: Documentation
+set_qflist({items}) *vim.lsp.util.set_qflist()*
+ Fills quickfix list with given list of items. Can be obtained
+ with e.g. |vim.lsp.util.locations_to_items()|.
+
+ Parameters: ~
+ {items} (table) list of items
+
+show_line_diagnostics() *vim.lsp.util.show_line_diagnostics()*
+ Displays the diagnostics for the current line in a floating
+ hover window.
symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
- Convert symbols to quickfix list items
+ Converts symbols to quickfix list items.
Parameters: ~
{symbols} DocumentSymbol[] or SymbolInformation[]
*vim.lsp.util.text_document_completion_list_to_complete_items()*
text_document_completion_list_to_complete_items({result}, {prefix})
- TODO: Documentation
+ Turns the result of a `textDocument/completion` request into
+ vim-compatible |complete-items|.
+
+ Parameters: ~
+ {result} The result of a `textDocument/completion` call,
+ e.g. from |vim.lsp.buf.completion()|, which may
+ be one of `CompletionItem[]` , `CompletionList`
+ or `null`
+ {prefix} (string) the prefix to filter the completion
+ items
+
+ Return: ~
+ { matches = complete-items table, incomplete = bool }
+
+ See also: ~
+ |complete-items|
trim_empty_lines({lines}) *vim.lsp.util.trim_empty_lines()*
- TODO: Documentation
+ Removes empty lines from the beginning and end.
+
+ Parameters: ~
+ {lines} (table) list of lines to trim
+
+ Return: ~
+ (table) trimmed list of lines
*vim.lsp.util.try_trim_markdown_code_blocks()*
try_trim_markdown_code_blocks({lines})
- TODO: Documentation
+ Accepts markdown lines and tries to reduce them to a filetype
+ if they comprise just a single code block.
+
+ CAUTION: Modifies the input in-place!
+
+ Parameters: ~
+ {lines} (table) list of lines
+
+ Return: ~
+ (string) filetype or 'markdown' if it was unchanged.
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 60c7a60d25..334bb33c1e 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -9,7 +9,7 @@ Lua engine *lua* *Lua*
Type |gO| to see the table of contents.
==============================================================================
-Introduction *lua-intro*
+INTRODUCTION *lua-intro*
The Lua 5.1 language is builtin and always available. Try this command to get
an idea of what lurks beneath: >
@@ -30,7 +30,7 @@ finds and loads Lua modules. The conventions are similar to VimL plugins,
with some extra features. See |lua-require-example| for a walkthrough.
==============================================================================
-Importing Lua modules *lua-require*
+IMPORTING LUA MODULES *lua-require*
*lua-package-path*
Nvim automatically adjusts `package.path` and `package.cpath` according to
@@ -233,7 +233,7 @@ lua/charblob.lua: >
}
==============================================================================
-Commands *lua-commands*
+COMMANDS *lua-commands*
These commands execute a Lua chunk from either the command line (:lua, :luado)
or a file (:luafile) on the given line [range]. As always in Lua, each chunk
@@ -456,7 +456,7 @@ management. Try this command to see available functions: >
:lua print(vim.inspect(vim.loop))
-Reference: http://docs.libuv.org
+Reference: https://github.com/luvit/luv/blob/master/docs.md
Examples: https://github.com/luvit/luv/tree/master/examples
*E5560* *lua-loop-callbacks*
@@ -551,223 +551,6 @@ Example: TCP echo-server *tcp-server*
print('TCP echo-server listening on port: '..server:getsockname().port)
------------------------------------------------------------------------------
-VIM.TREESITTER *lua-treesitter*
-
-Nvim integrates the tree-sitter library for incremental parsing of buffers.
-
-Currently Nvim does not provide the tree-sitter parsers, instead these must
-be built separately, for instance using the tree-sitter utility. The only
-exception is a C parser being included in official builds for testing
-purposes. Parsers are searched for as `parser/{lang}.*` in any 'runtimepath'
-directory. A parser can also be loaded manually using a full path: >
-
- vim.treesitter.require_language("python", "/path/to/python.so")
-
-<Create a parser for a buffer and a given language (if another plugin uses the
-same buffer/language combination, it will be safely reused). Use >
-
- parser = vim.treesitter.get_parser(bufnr, lang)
-
-<`bufnr=0` can be used for current buffer. `lang` will default to 'filetype' (this
-doesn't work yet for some filetypes like "cpp") Currently, the parser will be
-retained for the lifetime of a buffer but this is subject to change. A plugin
-should keep a reference to the parser object as long as it wants incremental
-updates.
-
-Parser methods *lua-treesitter-parser*
-
-tsparser:parse() *tsparser:parse()*
-Whenever you need to access the current syntax tree, parse the buffer: >
-
- tstree = parser:parse()
-
-<This will return an immutable tree that represents the current state of the
-buffer. When the plugin wants to access the state after a (possible) edit
-it should call `parse()` again. If the buffer wasn't edited, the same tree will
-be returned again without extra work. If the buffer was parsed before,
-incremental parsing will be done of the changed parts.
-
-NB: to use the parser directly inside a |nvim_buf_attach| Lua callback, you must
-call `get_parser()` before you register your callback. But preferably parsing
-shouldn't be done directly in the change callback anyway as they will be very
-frequent. Rather a plugin that does any kind of analysis on a tree should use
-a timer to throttle too frequent updates.
-
-tsparser:set_included_ranges(ranges) *tsparser:set_included_ranges()*
- Changes the ranges the parser should consider. This is used for
- language injection. `ranges` should be of the form (all zero-based): >
- {
- {start_node, end_node},
- ...
- }
-<
- NOTE: `start_node` and `end_node` are both inclusive.
-
-Tree methods *lua-treesitter-tree*
-
-tstree:root() *tstree:root()*
- Return the root node of this tree.
-
-
-Node methods *lua-treesitter-node*
-
-tsnode:parent() *tsnode:parent()*
- Get the node's immediate parent.
-
-tsnode:child_count() *tsnode:child_count()*
- Get the node's number of children.
-
-tsnode:child(N) *tsnode:child()*
- Get the node's child at the given index, where zero represents the
- first child.
-
-tsnode:named_child_count() *tsnode:named_child_count()*
- Get the node's number of named children.
-
-tsnode:named_child(N) *tsnode:named_child()*
- Get the node's named child at the given index, where zero represents
- the first named child.
-
-tsnode:start() *tsnode:start()*
- Get the node's start position. Return three values: the row, column
- and total byte count (all zero-based).
-
-tsnode:end_() *tsnode:end_()*
- Get the node's end position. Return three values: the row, column
- and total byte count (all zero-based).
-
-tsnode:range() *tsnode:range()*
- Get the range of the node. Return four values: the row, column
- of the start position, then the row, column of the end position.
-
-tsnode:type() *tsnode:type()*
- Get the node's type as a string.
-
-tsnode:symbol() *tsnode:symbol()*
- Get the node's type as a numerical id.
-
-tsnode:named() *tsnode:named()*
- Check if the node is named. Named nodes correspond to named rules in
- the grammar, whereas anonymous nodes correspond to string literals
- in the grammar.
-
-tsnode:missing() *tsnode:missing()*
- Check if the node is missing. Missing nodes are inserted by the
- parser in order to recover from certain kinds of syntax errors.
-
-tsnode:has_error() *tsnode:has_error()*
- Check if the node is a syntax error or contains any syntax errors.
-
-tsnode:sexpr() *tsnode:sexpr()*
- Get an S-expression representing the node as a string.
-
-tsnode:descendant_for_range(start_row, start_col, end_row, end_col)
- *tsnode:descendant_for_range()*
- Get the smallest node within this node that spans the given range of
- (row, column) positions
-
-tsnode:named_descendant_for_range(start_row, start_col, end_row, end_col)
- *tsnode:named_descendant_for_range()*
- Get the smallest named node within this node that spans the given
- range of (row, column) positions
-
-Query methods *lua-treesitter-query*
-
-Tree-sitter queries are supported, with some limitations. Currently, the only
-supported match predicate is `eq?` (both comparing a capture against a string
-and two captures against each other).
-
-vim.treesitter.parse_query(lang, query)
- *vim.treesitter.parse_query(()*
- Parse the query as a string. (If the query is in a file, the caller
- should read the contents into a string before calling).
-
-query:iter_captures(node, bufnr, start_row, end_row)
- *query:iter_captures()*
- Iterate over all captures from all matches inside a `node`.
- `bufnr` is needed if the query contains predicates, then the caller
- must ensure to use a freshly parsed tree consistent with the current
- text of the buffer. `start_row` and `end_row` can be used to limit
- matches inside a row range (this is typically used with root node
- as the node, i e to get syntax highlight matches in the current
- viewport)
-
- The iterator returns two values, a numeric id identifying the capture
- and the captured node. The following example shows how to get captures
- by name:
->
- for id, node in query:iter_captures(tree:root(), bufnr, first, last) do
- local name = query.captures[id] -- name of the capture in the query
- -- typically useful info about the node:
- local type = node:type() -- type of the captured node
- local row1, col1, row2, col2 = node:range() -- range of the capture
- ... use the info here ...
- end
-<
-query:iter_matches(node, bufnr, start_row, end_row)
- *query:iter_matches()*
- Iterate over all matches within a node. The arguments are the same as
- for |query:iter_captures()| but the iterated values are different:
- an (1-based) index of the pattern in the query, and a table mapping
- capture indices to nodes. If the query has more than one pattern
- the capture table might be sparse, and e.g. `pairs` should be used and not
- `ipairs`. Here an example iterating over all captures in
- every match:
->
- for pattern, match in cquery:iter_matches(tree:root(), bufnr, first, last) do
- for id,node in pairs(match) do
- local name = query.captures[id]
- -- `node` was captured by the `name` capture in the match
- ... use the info here ...
- end
- end
->
-Treesitter syntax highlighting (WIP) *lua-treesitter-highlight*
-
-NOTE: This is a partially implemented feature, and not usable as a default
-solution yet. What is documented here is a temporary interface indented
-for those who want to experiment with this feature and contribute to
-its development.
-
-Highlights are defined in the same query format as in the tree-sitter highlight
-crate, which some limitations and additions. Set a highlight query for a
-buffer with this code: >
-
- local query = [[
- "for" @keyword
- "if" @keyword
- "return" @keyword
-
- (string_literal) @string
- (number_literal) @number
- (comment) @comment
-
- (preproc_function_def name: (identifier) @function)
-
- ; ... more definitions
- ]]
-
- highlighter = vim.treesitter.TSHighlighter.new(query, bufnr, lang)
- -- alternatively, to use the current buffer and its filetype:
- -- highlighter = vim.treesitter.TSHighlighter.new(query)
-
- -- Don't recreate the highlighter for the same buffer, instead
- -- modify the query like this:
- local query2 = [[ ... ]]
- highlighter:set_query(query2)
-
-As mentioned above the supported predicate is currently only `eq?`. `match?`
-predicates behave like matching always fails. As an addition a capture which
-begin with an upper-case letter like `@WarningMsg` will map directly to this
-highlight group, if defined. Also if the predicate begins with upper-case and
-contains a dot only the part before the first will be interpreted as the
-highlight group. As an example, this warns of a binary expression with two
-identical identifiers, highlighting both as |hl-WarningMsg|: >
-
- ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
- (eq? @WarningMsg.left @WarningMsg.right))
-
-------------------------------------------------------------------------------
VIM.HIGHLIGHT *lua-highlight*
Nvim includes a function for highlighting a selection on yank (see for example
@@ -839,11 +622,6 @@ vim.api.{func}({...}) *vim.api*
Example: call the "nvim_get_current_line()" API function: >
print(tostring(vim.api.nvim_get_current_line()))
-vim.call({func}, {...}) *vim.call()*
- Invokes |vim-function| or |user-function| {func} with arguments {...}.
- See also |vim.fn|. Equivalent to: >
- vim.fn[func]({...})
-
vim.in_fast_event() *vim.in_fast_event()*
Returns true if the code is executing as part of a "fast" event
handler, where most of the API is disabled. These are low-level events
@@ -876,6 +654,34 @@ vim.region({bufnr}, {pos1}, {pos2}, {type}, {inclusive}) *vim.region()*
whether the selection is inclusive or not, into a zero-indexed table
of linewise selections of the form `{linenr = {startcol, endcol}}` .
+ *vim.register_keystroke_callback()*
+vim.register_keystroke_callback({fn}, {ns_id})
+ Register a lua {fn} with an {ns_id} to be run after every keystroke.
+
+ Parameters: ~
+ {fn}: (function): Function to call on keystroke.
+ It should take one argument, which is a string.
+ The string will contain the literal keys typed.
+ See |i_CTRL-V|
+
+ If {fn} is `nil`, it removes the callback for the
+ associated {ns_id}.
+
+ {ns_id}: (number) Namespace ID. If not passed or 0, will generate
+ and return a new namespace ID from |nvim_create_namespace()|
+
+ Return: ~
+ (number) Namespace ID associated with {fn}
+
+ NOTE: {fn} will be automatically removed if an error occurs while
+ calling. This is to prevent the annoying situation of every keystroke
+ erroring while trying to remove a broken callback.
+
+ NOTE: {fn} will receive the keystrokes after mappings have been
+ evaluated
+
+ NOTE: {fn} will *NOT* be cleared from |nvim_buf_clear_namespace()|
+
vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()*
Sends {event} to {channel} via |RPC| and returns immediately.
If {channel} is 0, the event is broadcast to all channels.
@@ -931,13 +737,20 @@ vim.defer_fn({fn}, {timeout}) *vim.defer_fn*
Returns: ~
|vim.loop|.new_timer() object
-vim.wait({time}, {callback} [, {interval}]) *vim.wait()*
+vim.wait({time} [, {callback}, {interval}, {fast_only}]) *vim.wait()*
Wait for {time} in milliseconds until {callback} returns `true`.
Executes {callback} immediately and at approximately {interval}
milliseconds (default 200). Nvim still processes other events during
this time.
+ Parameters: ~
+ {time} Number of milliseconds to wait
+ {callback} Optional callback. Waits until {callback} returns true
+ {interval} (Approximate) number of milliseconds to wait between polls
+ {fast_only} If true, only |api-fast| events will be processed.
+ If called from while in an |api-fast| event, will
+ automatically be set to `true`.
Returns: ~
If {callback} returns `true` during the {time}:
@@ -975,22 +788,6 @@ vim.wait({time}, {callback} [, {interval}]) *vim.wait()*
end
<
-vim.fn.{func}({...}) *vim.fn*
- Invokes |vim-function| or |user-function| {func} with arguments {...}.
- To call autoload functions, use the syntax: >
- vim.fn['some#function']({...})
-<
- Unlike vim.api.|nvim_call_function| this converts directly between Vim
- objects and Lua objects. If the Vim function returns a float, it will
- be represented directly as a Lua number. Empty lists and dictionaries
- both are represented by an empty table.
-
- Note: |v:null| values as part of the return value is represented as
- |vim.NIL| special value
-
- Note: vim.fn keys are generated lazily, thus `pairs(vim.fn)` only
- enumerates functions that were called at least once.
-
vim.type_idx *vim.type_idx*
Type index for use in |lua-special-tbl|. Specifying one of the
values from |vim.types| allows typing the empty table (it is
@@ -1026,64 +823,103 @@ vim.types *vim.types*
`vim.types.dictionary` will not change or that `vim.types` table will
only contain values for these three types.
-==============================================================================
-Vim Internal Variables *lua-vim-internal-variables*
-
-Built-in Vim dictionaries can be accessed and set idiomatically in Lua by each
-of the following tables.
-
-To set a value: >
-
- vim.g.my_global_variable = 5
-<
+------------------------------------------------------------------------------
+LUA-VIMSCRIPT BRIDGE *lua-vimscript*
-To read a value: >
+Nvim Lua provides an interface to Vimscript variables and functions, and
+editor commands and options.
- print(vim.g.my_global_variable)
-<
+vim.call({func}, {...}) *vim.call()*
+ Invokes |vim-function| or |user-function| {func} with arguments {...}.
+ See also |vim.fn|.
+ Equivalent to: >
+ vim.fn[func]({...})
-To delete a value: >
+vim.cmd({cmd}) *vim.cmd()*
+ Invokes an Ex command (the ":" commands, Vimscript statements).
+ See also |ex-cmd-index|.
+ Example: >
+ vim.cmd('echo 42')
- vim.g.my_global_variable = nil
+vim.fn.{func}({...}) *vim.fn*
+ Invokes |vim-function| or |user-function| {func} with arguments {...}.
+ To call autoload functions, use the syntax: >
+ vim.fn['some#function']({...})
<
+ Unlike vim.api.|nvim_call_function| this converts directly between Vim
+ objects and Lua objects. If the Vim function returns a float, it will
+ be represented directly as a Lua number. Empty lists and dictionaries
+ both are represented by an empty table.
-vim.g *vim.g*
- Table with values from |g:|
- Keys with no values set will result in `nil`.
-
-vim.b *vim.b*
- Gets a buffer-scoped (b:) variable for the current buffer.
- Keys with no values set will result in `nil`.
-
-vim.w *vim.w*
- Gets a window-scoped (w:) variable for the current window.
- Keys with no values set will result in `nil`.
+ Note: |v:null| values as part of the return value is represented as
+ |vim.NIL| special value
-vim.t *vim.t*
- Gets a tabpage-scoped (t:) variable for the current table.
- Keys with no values set will result in `nil`.
+ Note: vim.fn keys are generated lazily, thus `pairs(vim.fn)` only
+ enumerates functions that were called at least once.
-vim.v *vim.v*
- Gets a v: variable.
- Keys with no values set will result in `nil`.
+ *lua-vim-variables*
+The Vim editor global dictionaries |g:| |w:| |b:| |t:| |v:| can be accessed
+from Lua conveniently and idiomatically by referencing the `vim.*` Lua tables
+described below. In this way you can easily read and modify global Vimscript
+variables from Lua.
-Vim Internal Options *lua-vim-internal-options*
+Example: >
-Read, set and clear vim |options| in Lua by each of the following tables.
+ vim.g.foo = 5 -- Set the g:foo Vimscript variable.
+ print(vim.g.foo) -- Get and print the g:foo Vimscript variable.
+ vim.g.foo = nil -- Delete (:unlet) the Vimscript variable.
+
+vim.g *vim.g*
+ Global (|g:|) editor variables.
+ Key with no value returns `nil`.
+
+vim.b *vim.b*
+ Buffer-scoped (|b:|) variables for the current buffer.
+ Invalid or unset key returns `nil`.
+
+vim.w *vim.w*
+ Window-scoped (|w:|) variables for the current window.
+ Invalid or unset key returns `nil`.
+
+vim.t *vim.t*
+ Tabpage-scoped (|t:|) variables for the current tabpage.
+ Invalid or unset key returns `nil`.
+
+vim.v *vim.v*
+ |v:| variables.
+ Invalid or unset key returns `nil`.
+
+vim.env *vim.env*
+ Environment variables defined in the editor session.
+ See |expand-env| and |:let-environment| for the Vimscript behavior.
+ Invalid or unset key returns `nil`.
+ Example: >
+ vim.env.FOO = 'bar'
+ print(vim.env.TERM)
+<
+ *lua-vim-options*
+From Lua you can work with editor |options| by reading and setting items in
+these Lua tables:
-vim.o *vim.o*
- Table with values from |options|
- Invalid keys will result in an error.
+vim.o *vim.o*
+ Get or set editor options, like |:set|. Invalid key is an error.
+ Example: >
+ vim.o.cmdheight = 4
+ print(vim.o.columns)
-vim.bo *vim.bo*
- Gets a buffer-scoped option for the current buffer.
- Invalid keys will result in an error.
+vim.bo *vim.bo*
+ Get or set buffer-scoped |local-options|. Invalid key is an error.
+ Example: >
+ vim.bo.buflisted = true
+ print(vim.bo.comments)
-vim.wo *vim.wo*
- Gets a window-scoped option for the current window.
- Invalid keys will result in an error.
+vim.wo *vim.wo*
+ Get or set window-scoped |local-options|. Invalid key is an error.
+ Example: >
+ vim.wo.cursorcolumn = true
+ print(vim.wo.foldmarker)
==============================================================================
@@ -1195,6 +1031,9 @@ is_callable({f}) *vim.is_callable()*
Return: ~
true if `f` is callable, else false
+is_valid({opt}) *vim.is_valid()*
+ TODO: Documentation
+
list_extend({dst}, {src}, {start}, {finish}) *vim.list_extend()*
Extends a list-like table with the values of another list-like
table.
@@ -1339,17 +1178,21 @@ tbl_flatten({t}) *vim.tbl_flatten()*
Fromhttps://github.com/premake/premake-core/blob/master/src/base/table.lua
tbl_isempty({t}) *vim.tbl_isempty()*
+ Checks if a table is empty.
+
+ Parameters: ~
+ {t} Table to check
+
See also: ~
- Fromhttps://github.com/premake/premake-core/blob/master/src/base/table.lua@paramt Table to check
+ https://github.com/premake/premake-core/blob/master/src/base/table.lua
tbl_islist({t}) *vim.tbl_islist()*
- Determine whether a Lua table can be treated as an array.
+ Tests if a Lua table can be treated as an array.
- An empty table `{}` will default to being treated as an array.
- Use `vim.emtpy_dict()` to create a table treated as an empty
- dict. Empty tables returned by `rpcrequest()` and `vim.fn`
- functions can be checked using this function whether they
- represent empty API arrays and vimL lists.
+ Empty table `{}` is assumed to be an array, unless it was
+ created by |vim.empty_dict()| or returned as a dict-like |API|
+ or Vimscript result, for example from |rpcrequest()| or
+ |vim.fn|.
Parameters: ~
{t} Table
@@ -1446,8 +1289,52 @@ validate({opt}) *vim.validate()*
โ€ข arg_value: argument value
โ€ข fn: any function accepting one argument,
returns true if and only if the argument is
- valid
+ valid. Can optionally return an additional
+ informative error message as the second
+ returned value.
โ€ข msg: (optional) error string if validation
fails
+
+==============================================================================
+Lua module: uri *lua-uri*
+
+uri_from_bufnr({bufnr}) *vim.uri_from_bufnr()*
+ Get a URI from a bufnr
+
+ Parameters: ~
+ {bufnr} (number): Buffer number
+
+ Return: ~
+ URI
+
+uri_from_fname({path}) *vim.uri_from_fname()*
+ Get a URI from a file path.
+
+ Parameters: ~
+ {path} (string): Path to file
+
+ Return: ~
+ URI
+
+uri_to_bufnr({uri}) *vim.uri_to_bufnr()*
+ Return or create a buffer for a uri.
+
+ Parameters: ~
+ {uri} (string): The URI
+
+ Return: ~
+ bufnr.
+ Note:
+ Creates buffer but does not load it
+
+uri_to_fname({uri}) *vim.uri_to_fname()*
+ Get a filename from a URI
+
+ Parameters: ~
+ {uri} (string): The URI
+
+ Return: ~
+ Filename
+
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index ed31ecc42e..edec4a8de7 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1078,6 +1078,10 @@ When executing an autocommand or a user command, it will run in the context of
the script it was defined in. This makes it possible that the command calls a
local function or uses a local mapping.
+In case the value is used in a context where <SID> cannot be correctly
+expanded, use the expand() function: >
+ let &includexpr = expand('<SID>') .. 'My_includeexpr()'
+
Otherwise, using "<SID>" outside of a script context is an error.
If you need to get the script number to use in a complicated script, you can
@@ -1132,9 +1136,10 @@ scripts.
:com[mand] *:com* *:command*
List all user-defined commands. When listing commands,
- the characters in the first two columns are
+ the characters in the first columns are:
! Command has the -bang attribute
" Command has the -register attribute
+ | Command has the -bar attribute
b Command is local to current buffer
(see below for details on attributes)
The list can be filtered on command name with
@@ -1162,6 +1167,10 @@ See |:verbose-cmd| for more information.
attributes (see below) are {attr}. If the command
already exists, an error is reported, unless a ! is
specified, in which case the command is redefined.
+ There is one exception: When sourcing a script again,
+ a command that was previously defined in that script
+ will be silently replaced.
+
:delc[ommand] {cmd} *:delc* *:delcommand* *E184*
Delete the user-defined command {cmd}.
@@ -1169,7 +1178,8 @@ See |:verbose-cmd| for more information.
:comc[lear] *:comc* *:comclear*
Delete all user-defined commands.
-Command attributes
+
+Command attributes ~
User-defined commands are treated by Vim just like any other Ex commands. They
can have arguments, or have a range specified. Arguments are subject to
@@ -1180,8 +1190,9 @@ There are a number of attributes, split into four categories: argument
handling, completion behavior, range handling, and special cases. The
attributes are described below, by category.
-Argument handling *E175* *E176* *:command-nargs*
+Argument handling ~
+ *E175* *E176* *:command-nargs*
By default, a user defined command will take no arguments (and an error is
reported if any are supplied). However, it is possible to specify that the
command can take arguments, using the -nargs attribute. Valid cases are:
@@ -1257,9 +1268,9 @@ completion can be enabled:
Note: That some completion methods might expand environment variables.
-Custom completion *:command-completion-custom*
- *:command-completion-customlist*
- *E467* *E468*
+Custom completion ~
+ *:command-completion-custom*
+ *:command-completion-customlist* *E467* *E468*
It is possible to define customized completion schemes via the "custom,{func}"
or the "customlist,{func}" completion argument. The {func} part should be a
function with the following signature: >
@@ -1304,8 +1315,8 @@ the 'path' option: >
This example does not work for file names with spaces!
-Range handling *E177* *E178* *:command-range*
- *:command-count*
+Range handling ~
+ *E177* *E178* *:command-range* *:command-count*
By default, user-defined commands do not accept a line number range. However,
it is possible to specify that the command does take a range (the -range
attribute), or that it takes an arbitrary count value, either in the line
@@ -1332,17 +1343,19 @@ It is possible that the special characters in the range like `.`, `$` or `%`
which by default correspond to the current line, last line and the whole
buffer, relate to arguments, (loaded) buffers, windows or tab pages.
-Possible values are:
- -addr=lines Range of lines (this is the default)
- -addr=arguments Range for arguments
- -addr=buffers Range for buffers (also not loaded buffers)
- -addr=loaded_buffers Range for loaded buffers
- -addr=windows Range for windows
- -addr=tabs Range for tab pages
- -addr=other other kind of range
+Possible values are (second column is the short name used in listing):
+ -addr=lines Range of lines (this is the default)
+ -addr=arguments arg Range for arguments
+ -addr=buffers buf Range for buffers (also not loaded buffers)
+ -addr=loaded_buffers load Range for loaded buffers
+ -addr=windows win Range for windows
+ -addr=tabs tab Range for tab pages
+ -addr=quickfix qf Range for quickfix entries
+ -addr=other ? other kind of range
-Special cases *:command-bang* *:command-bar*
+Special cases ~
+ *:command-bang* *:command-bar*
*:command-register* *:command-buffer*
There are some special cases as well:
@@ -1360,7 +1373,8 @@ replacement text separately.
Note that these arguments can be abbreviated, but that is a deprecated
feature. Use the full name for new scripts.
-Replacement text
+
+Replacement text ~
The replacement text for a user defined command is scanned for special escape
sequences, using <...> notation. Escape sequences are replaced with values
diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt
index 127c46c27d..a6410a09cb 100644
--- a/runtime/doc/mbyte.txt
+++ b/runtime/doc/mbyte.txt
@@ -71,24 +71,15 @@ If you are working in a terminal (emulator) you must make sure it accepts
UTF-8, the encoding which Vim is working with. Otherwise only ASCII can
be displayed and edited correctly.
-For the GUI you must select fonts that work with UTF-8. This
-is the difficult part. It depends on the system you are using, the locale and
-a few other things.
-
-For X11 you can set the 'guifontset' option to a list of fonts that together
-cover the characters that are used. Example for Korean: >
-
- :set guifontset=k12,r12
-
-Alternatively, you can set 'guifont' and 'guifontwide'. 'guifont' is used for
-the single-width characters, 'guifontwide' for the double-width characters.
-Thus the 'guifontwide' font must be exactly twice as wide as 'guifont'.
-Example for UTF-8: >
+For the GUI you must select fonts that work with UTF-8. You can set 'guifont'
+and 'guifontwide'. 'guifont' is used for the single-width characters,
+'guifontwide' for the double-width characters. Thus the 'guifontwide' font
+must be exactly twice as wide as 'guifont'. Example for UTF-8: >
:set guifont=-misc-fixed-medium-r-normal-*-18-120-100-100-c-90-iso10646-1
:set guifontwide=-misc-fixed-medium-r-normal-*-18-120-100-100-c-180-iso10646-1
-You can also set 'guifont' alone, Vim will try to find a matching
+You can also set 'guifont' alone, the Nvim GUI will try to find a matching
'guifontwide' for you.
@@ -267,16 +258,16 @@ Recognized 'fileencoding' values include: *encoding-values*
1 cp1258 Vietnamese
1 cp{number} MS-Windows: any installed single-byte codepage
2 cp932 Japanese (Windows only)
-2 euc-jp Japanese (Unix only)
-2 sjis Japanese (Unix only)
-2 cp949 Korean (Unix and Windows)
-2 euc-kr Korean (Unix only)
+2 euc-jp Japanese
+2 sjis Japanese
+2 cp949 Korean
+2 euc-kr Korean
2 cp936 simplified Chinese (Windows only)
-2 euc-cn simplified Chinese (Unix only)
-2 cp950 traditional Chinese (on Unix alias for big5)
-2 big5 traditional Chinese (on Windows alias for cp950)
-2 euc-tw traditional Chinese (Unix only)
-2 2byte-{name} Unix: any double-byte encoding (Vim specific name)
+2 euc-cn simplified Chinese
+2 cp950 traditional Chinese (alias for big5)
+2 big5 traditional Chinese (alias for cp950)
+2 euc-tw traditional Chinese
+2 2byte-{name} any double-byte encoding (Vim-specific name)
2 cp{number} MS-Windows: any installed double-byte codepage
u utf-8 32 bit UTF-8 encoded Unicode (ISO/IEC 10646-1)
u ucs-2 16 bit UCS-2 encoded Unicode (ISO/IEC 10646-1)
@@ -298,14 +289,14 @@ the same encoding is used and it's called latin1. 'isprint' can be used to
display the characters 0x80 - 0xA0 or not.
Several aliases can be used, they are translated to one of the names above.
-An incomplete list:
+Incomplete list:
1 ansi same as latin1 (obsolete, for backward compatibility)
-2 japan Japanese: on Unix "euc-jp", on MS-Windows cp932
-2 korea Korean: on Unix "euc-kr", on MS-Windows cp949
-2 prc simplified Chinese: on Unix "euc-cn", on MS-Windows cp936
+2 japan Japanese: "euc-jp"
+2 korea Korean: "euc-kr"
+2 prc simplified Chinese: "euc-cn"
2 chinese same as "prc"
-2 taiwan traditional Chinese: on Unix "euc-tw", on MS-Windows cp950
+2 taiwan traditional Chinese: "euc-tw"
u utf8 same as utf-8
u unicode same as ucs-2
u ucs2be same as ucs-2 (big endian)
@@ -394,148 +385,6 @@ conversion needs to be done. These conversions are supported:
request a very large buffer, more than Vim is willing to provide).
Try getting another iconv() implementation.
- *iconv-dynamic*
-On MS-Windows Vim can be compiled with the |+iconv/dyn| feature. This means
-Vim will search for the "iconv.dll" and "libiconv.dll" libraries. When
-neither of them can be found Vim will still work but some conversions won't be
-possible.
-
-==============================================================================
-Fonts on X11 *mbyte-fonts-X11*
-
-Unfortunately, using fonts in X11 is complicated. The name of a single-byte
-font is a long string. For multi-byte fonts we need several of these...
-
-First of all, Vim only accepts fixed-width fonts for displaying text. You
-cannot use proportionally spaced fonts. This excludes many of the available
-(and nicer looking) fonts. However, for menus and tooltips any font can be
-used.
-
-Note that Display and Input are independent. It is possible to see your
-language even though you have no input method for it.
-
-You should get a default font for menus and tooltips that works, but it might
-be ugly. Read the following to find out how to select a better font.
-
-
-X LOGICAL FONT DESCRIPTION (XLFD)
- *XLFD*
-XLFD is the X font name and contains the information about the font size,
-charset, etc. The name is in this format:
-
-FOUNDRY-FAMILY-WEIGHT-SLANT-WIDTH-STYLE-PIXEL-POINT-X-Y-SPACE-AVE-CR-CE
-
-Each field means:
-
-- FOUNDRY: FOUNDRY field. The company that created the font.
-- FAMILY: FAMILY_NAME field. Basic font family name. (helvetica, gothic,
- times, etc)
-- WEIGHT: WEIGHT_NAME field. How thick the letters are. (light, medium,
- bold, etc)
-- SLANT: SLANT field.
- r: Roman (no slant)
- i: Italic
- o: Oblique
- ri: Reverse Italic
- ro: Reverse Oblique
- ot: Other
- number: Scaled font
-- WIDTH: SETWIDTH_NAME field. Width of characters. (normal, condensed,
- narrow, double wide)
-- STYLE: ADD_STYLE_NAME field. Extra info to describe font. (Serif, Sans
- Serif, Informal, Decorated, etc)
-- PIXEL: PIXEL_SIZE field. Height, in pixels, of characters.
-- POINT: POINT_SIZE field. Ten times height of characters in points.
-- X: RESOLUTION_X field. X resolution (dots per inch).
-- Y: RESOLUTION_Y field. Y resolution (dots per inch).
-- SPACE: SPACING field.
- p: Proportional
- m: Monospaced
- c: CharCell
-- AVE: AVERAGE_WIDTH field. Ten times average width in pixels.
-- CR: CHARSET_REGISTRY field. The name of the charset group.
-- CE: CHARSET_ENCODING field. The rest of the charset name. For some
- charsets, such as JIS X 0208, if this field is 0, code points has
- the same value as GL, and GR if 1.
-
-For example, in case of a 16 dots font corresponding to JIS X 0208, it is
-written like:
- -misc-fixed-medium-r-normal--16-110-100-100-c-160-jisx0208.1990-0
-
-
-X FONTSET
- *fontset* *xfontset*
-A single-byte charset is typically associated with one font. For multi-byte
-charsets a combination of fonts is often used. This means that one group of
-characters are used from one font and another group from another font (which
-might be double wide). This collection of fonts is called a fontset.
-
-Which fonts are required in a fontset depends on the current locale. X
-windows maintains a table of which groups of characters are required for a
-locale. You have to specify all the fonts that a locale requires in the
-'guifontset' option.
-
-NOTE: The fontset always uses the current locale, even though 'encoding' may
-be set to use a different charset. In that situation you might want to use
-'guifont' and 'guifontwide' instead of 'guifontset'.
-
-Example:
- |charset| language "groups of characters" ~
- GB2312 Chinese (simplified) ISO-8859-1 and GB 2312
- Big5 Chinese (traditional) ISO-8859-1 and Big5
- CNS-11643 Chinese (traditional) ISO-8859-1, CNS 11643-1 and CNS 11643-2
- EUC-JP Japanese JIS X 0201 and JIS X 0208
- EUC-KR Korean ISO-8859-1 and KS C 5601 (KS X 1001)
-
-You can search for fonts using the xlsfonts command. For example, when you're
-searching for a font for KS C 5601: >
- xlsfonts | grep ksc5601
-
-This is complicated and confusing. You might want to consult the X-Windows
-documentation if there is something you don't understand.
-
- *base_font_name_list*
-When you have found the names of the fonts you want to use, you need to set
-the 'guifontset' option. You specify the list by concatenating the font names
-and putting a comma in between them.
-
-For example, when you use the ja_JP.eucJP locale, this requires JIS X 0201
-and JIS X 0208. You could supply a list of fonts that explicitly specifies
-the charsets, like: >
-
- :set guifontset=-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,
- \-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0
-
-Alternatively, you can supply a base font name list that omits the charset
-name, letting X-Windows select font characters required for the locale. For
-example: >
-
- :set guifontset=-misc-fixed-medium-r-normal--14-130-75-75-c-140,
- \-misc-fixed-medium-r-normal--14-130-75-75-c-70
-
-Alternatively, you can supply a single base font name that allows X-Windows to
-select from all available fonts. For example: >
-
- :set guifontset=-misc-fixed-medium-r-normal--14-*
-
-Alternatively, you can specify alias names. See the fonts.alias file in the
-fonts directory (e.g., /usr/X11R6/lib/X11/fonts/). For example: >
-
- :set guifontset=k14,r14
-<
- *E253*
-Note that in East Asian fonts, the standard character cell is square. When
-mixing a Latin font and an East Asian font, the East Asian font width should
-be twice the Latin font width.
-
-If 'guifontset' is not empty, the "font" argument of the |:highlight| command
-is also interpreted as a fontset. For example, you should use for
-highlighting: >
- :hi Comment font=english_font,your_font
-If you use a wrong "font" argument you will get an error message.
-Also make sure that you set 'guifontset' before setting fonts for highlight
-groups.
-
==============================================================================
Input on X11 *mbyte-XIM*
@@ -647,10 +496,6 @@ Note that Display and Input are independent. It is possible to see your
language even though you have no input method for it. But when your Display
method doesn't match your Input method, the text will be displayed wrong.
- Note: You can not use IM unless you specify 'guifontset'.
- Therefore, Latin users, you have to also use 'guifontset'
- if you use IM.
-
To input your language you should run the |IM-server| which supports your
language and |conversion-server| if needed.
@@ -962,9 +807,9 @@ Vim has comprehensive UTF-8 support. It works well in:
- MS-Windows GUI
- several other platforms
-Double-width characters are supported. This works best with 'guifontwide' or
-'guifontset'. When using only 'guifont' the wide characters are drawn in the
-normal width and a space to fill the gap.
+Double-width characters are supported. Works best with 'guifontwide'. When
+using only 'guifont' the wide characters are drawn in the normal width and
+a space to fill the gap.
*bom-bytes*
When reading a file a BOM (Byte Order Mark) can be used to recognize the
@@ -1031,7 +876,6 @@ this:
1. Set 'guifont' and let Vim find a matching 'guifontwide'
2. Set 'guifont' and 'guifontwide'
-3. Set 'guifontset'
See the documentation for each option for details. Example: >
@@ -1077,10 +921,7 @@ not everybody is able to type a composing character.
==============================================================================
Overview of options *mbyte-options*
-These options are relevant for editing multi-byte files. Check the help in
-options.txt for detailed information.
-
-'encoding' Internal text encoding, always "utf-8".
+These options are relevant for editing multi-byte files.
'fileencoding' Encoding of a file. When it's different from "utf-8"
conversion is done when reading or writing the file.
@@ -1096,9 +937,6 @@ options.txt for detailed information.
languages where a sequence of characters can be broken
anywhere.
-'guifontset' The list of font names used for a multi-byte encoding. When
- this option is not empty, it replaces 'guifont'.
-
'keymap' Specify the name of a keyboard mapping.
==============================================================================
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index 43b1eb5e0c..745160da8a 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -359,7 +359,7 @@ the other way around. It should be used like this: {foo,bar}. This matches
ml_get: invalid lnum: {number}
This is an internal Vim error. Please try to find out how it can be
-reproduced, and submit a bug report |bugreport.vim|.
+reproduced, and submit a |bug-report|.
*E173* >
{number} more files to edit
diff --git a/runtime/doc/mlang.txt b/runtime/doc/mlang.txt
index 2a10a7051d..5217b2c160 100644
--- a/runtime/doc/mlang.txt
+++ b/runtime/doc/mlang.txt
@@ -124,8 +124,7 @@ maintainer of the translation and ask him to update it. You can find the
name and e-mail address of the translator in
"$VIMRUNTIME/lang/menu_<lang>.vim".
-To set the font (or fontset) to use for the menus, use the |:highlight|
-command. Example: >
+To set the font to use for the menus, use the |:highlight| command. Example: >
:highlight Menu font=k12,r12
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index a96d118667..bec2b362ea 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -92,7 +92,7 @@ Mouse input has the following behavior:
the terminal wont lose focus and the hovered window will be scrolled.
==============================================================================
-Configuration *terminal-configuration*
+Configuration *terminal-config*
Options: 'modified', 'scrollback'
Events: |TermOpen|, |TermEnter|, |TermLeave|, |TermClose|
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 29f4abf250..448df31798 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -118,8 +118,7 @@ A few special texts:
Option was set with command line argument |-c|, +, |-S| or
|-q|.
Last set from environment variable ~
- Option was set from an environment variable, $VIMINIT,
- $GVIMINIT or $EXINIT.
+ Option was set from $VIMINIT.
Last set from error handler ~
Option was cleared when evaluating it resulted in an error.
@@ -1387,6 +1386,21 @@ 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.
+ *'completeslash'* *'csl'*
+'completeslash' 'csl' string (default: "")
+ local to buffer
+ {not in Vi} {only for 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
+ Makefile with 'noshellslash' on Windows.
+ - When this option is set to "backslash", backslash is used. This is
+ useful when editing a batch file with 'shellslash' set on Windows.
+ - When this option is empty, same character is used as for
+ 'shellslash'.
+ For Insert mode completion the buffer-local value is used. For
+ command line completion the global value is used.
+
*'completeopt'* *'cot'*
'completeopt' 'cot' string (default: "menu,preview")
global
@@ -2739,21 +2753,26 @@ A jump table for the options with a short description can be found at |Q_op|.
hor{N} horizontal bar, {N} percent of the character height
ver{N} vertical bar, {N} percent of the character width
block block cursor, fills the whole character
- [only one of the above three should be present]
+ - Only one of the above three should be present.
+ - Default is "block" for each mode.
blinkwait{N} *cursor-blinking*
blinkon{N}
blinkoff{N}
blink times for cursor: blinkwait is the delay before
the cursor starts blinking, blinkon is the time that
the cursor is shown and blinkoff is the time that the
- cursor is not shown. The times are in msec. When one
- of the numbers is zero, there is no blinking. E.g.: >
+ cursor is not shown. Times are in msec. When one of
+ the numbers is zero, there is no blinking. E.g.: >
:set guicursor=n:blinkon0
-< {group-name}
- Highlight group name that sets the color and font for
- the cursor. |inverse|/reverse and no group-name are
- interpreted as "the host terminal default cursor
- colors" which usually invert bg and fg colors.
+< - Default is "blinkon0" for each mode.
+ {group-name}
+ Highlight group that decides the color and font of the
+ cursor.
+ In the |TUI|:
+ - |inverse|/reverse and no group-name are interpreted
+ as "host-terminal default cursor colors" which
+ typically means "inverted bg and fg colors".
+ - |ctermfg| and |guifg| are ignored.
{group-name}/{group-name}
Two highlight group names, the first is used when
no language mappings are used, the other when they
@@ -2796,9 +2815,6 @@ A jump table for the options with a short description can be found at |Q_op|.
font names a list can be specified, font names separated with commas.
The first valid font is used.
- On systems where 'guifontset' is supported (X11) and 'guifontset' is
- not empty, then 'guifont' is not used.
-
Spaces after a comma are ignored. To include a comma in a font name
precede it with a backslash. Setting an option requires an extra
backslash before a space and a backslash. See also
@@ -2850,45 +2866,16 @@ A jump table for the options with a short description can be found at |Q_op|.
:set guifont=courier_new:h12:w5:b:cRUSSIAN
:set guifont=Andale_Mono:h7.5:w4.5
<
-
- *'guifontset'* *'gfs'*
- *E250* *E252* *E234* *E597* *E598*
-'guifontset' 'gfs' string (default "")
- global
- When not empty, specifies two (or more) fonts to be used. The first
- one for normal English, the second one for your special language. See
- |xfontset|.
- Setting this option also means that all font names will be handled as
- a fontset name. Also the ones used for the "font" argument of the
- |:highlight| command.
- The fonts must match with the current locale. If fonts for the
- character sets that the current locale uses are not included, setting
- 'guifontset' will fail.
- Note the difference between 'guifont' and 'guifontset': In 'guifont'
- the comma-separated names are alternative names, one of which will be
- used. In 'guifontset' the whole string is one fontset name,
- including the commas. It is not possible to specify alternative
- fontset names.
- This example works on many X11 systems: >
- :set guifontset=-*-*-medium-r-normal--16-*-*-*-c-*-*-*
-<
*'guifontwide'* *'gfw'* *E231* *E533* *E534*
'guifontwide' 'gfw' string (default "")
global
- When not empty, specifies a comma-separated list of fonts to be used
- for double-width characters. The first font that can be loaded is
- used.
+ Comma-separated list of fonts to be used for double-width characters.
+ The first font that can be loaded is used.
Note: The size of these fonts must be exactly twice as wide as the one
specified with 'guifont' and the same height.
- 'guifontwide' is only used when 'guifontset' is empty or invalid.
- When 'guifont' is set and a valid font is found in it and
- 'guifontwide' is empty Vim will attempt to find a matching
- double-width font and set 'guifontwide' to it.
-
- Windows +multibyte only: *guifontwide_win_mbyte*
-
- If set and valid, 'guifontwide' is used for IME instead of 'guifont'.
+ 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))
@@ -4055,7 +4042,6 @@ A jump table for the options with a short description can be found at |Q_op|.
*'mousefocus'* *'mousef'* *'nomousefocus'* *'nomousef'*
'mousefocus' 'mousef' boolean (default off)
global
- {only works in the GUI}
The window that the mouse pointer is on is automatically activated.
When changing the window layout or window focus in another way, the
mouse pointer is moved to the window with keyboard focus. Off is the
@@ -5028,24 +5014,18 @@ A jump table for the options with a short description can be found at |Q_op|.
will become the current directory (useful with
projects accessed over a network from different
systems)
- slash backslashes in file names replaced with forward
- slashes
tabpages all tab pages; without this only the current tab page
is restored, so that you can make a session for each
tab page separately
terminal include terminal windows where the command can be
restored
- unix with Unix end-of-line format (single <NL>), even when
- on Windows or DOS
winpos position of the whole Vim window
winsize window sizes
+ slash |deprecated| Always enabled. Uses "/" in filenames.
+ unix |deprecated| Always enabled. Uses "\n" line endings.
- Don't include both "curdir" and "sesdir".
- When neither "curdir" nor "sesdir" is included, file names are stored
- with absolute paths.
- "slash" and "unix" are useful on Windows when sharing session files
- with Unix. The Unix version of Vim cannot source dos format scripts,
- but the Windows version of Vim can source unix format scripts.
+ Don't include both "curdir" and "sesdir". When neither is included
+ filenames are stored as absolute paths.
*'shada'* *'sd'* *E526* *E527* *E528*
'shada' 'sd' string (Vim default for
@@ -5324,7 +5304,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'shellslash' only works when a backslash can be used as a path
separator. To test if this is so use: >
if exists('+shellslash')
-<
+< Also see 'completeslash'.
+
*'shelltemp'* *'stmp'* *'noshelltemp'* *'nostmp'*
'shelltemp' 'stmp' boolean (Vim default on, Vi default off)
global
@@ -5707,6 +5688,14 @@ A jump table for the options with a short description can be found at |Q_op|.
up to the first character that is not an ASCII letter or number and
not a dash. Also see |set-spc-auto|.
+ *'spelloptions'* *'spo'*
+'spelloptions' 'spo' string (default "")
+ local to buffer
+ A comma separated list of options for spell checking:
+ camel When a word is CamelCased, assume "Cased" is a
+ separate word: every upper-case character in a word
+ that comes after a lower case character indicates the
+ start of a new word.
*'spellsuggest'* *'sps'*
'spellsuggest' 'sps' string (default "best")
@@ -6532,7 +6521,9 @@ A jump table for the options with a short description can be found at |Q_op|.
>= 12 Every executed function.
>= 13 When an exception is thrown, caught, finished, or discarded.
>= 14 Anything pending in a ":finally" clause.
- >= 15 Every executed Ex command (truncated at 200 characters).
+ >= 15 Every executed Ex command from a script (truncated at 200
+ characters).
+ >= 16 Every executed Ex command
This option can also be set with the "-V" argument. See |-V|.
This option is also set by the |:verbose| command.
@@ -6571,14 +6562,8 @@ A jump table for the options with a short description can be found at |Q_op|.
options options and mappings local to a window or buffer (not
global values for local options)
localoptions same as "options"
- slash backslashes in file names replaced with forward
- slashes
- unix with Unix end-of-line format (single <NL>), even when
- on Windows or DOS
-
- "slash" and "unix" are useful on Windows when sharing view files
- with Unix. The Unix version of Vim cannot source dos format scripts,
- but the Windows version of Vim can source unix format scripts.
+ slash |deprecated| Always enabled. Uses "/" in filenames.
+ unix |deprecated| Always enabled. Uses "\n" line endings.
*'virtualedit'* *'ve'*
'virtualedit' 've' string (default "")
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index 0a6cdc60e8..f944689d0b 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -129,9 +129,13 @@ To use the RVM "system" Ruby installation: >
==============================================================================
Perl integration *provider-perl*
-Nvim supports Perl |remote-plugin|s.
+Nvim supports Perl |remote-plugin|s on Unix platforms. Support for polling STDIN
+on MS-Windows is currently lacking from all known event loop implementations.
+The Vim legacy |perl-vim| interface is also supported (which is itself
+implemented as a Nvim remote-plugin).
https://github.com/jacquesg/p5-Neovim-Ext
+Note: Only perl versions from 5.22 onward are supported.
PERL QUICKSTART~
@@ -212,12 +216,12 @@ For example this configuration integrates the tmux clipboard: >
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
- \ '+': 'tmux load-buffer -',
- \ '*': 'tmux load-buffer -',
+ \ '+': ['tmux', 'load-buffer', '-'],
+ \ '*': ['tmux', 'load-buffer', '-'],
\ },
\ 'paste': {
- \ '+': 'tmux save-buffer -',
- \ '*': 'tmux save-buffer -',
+ \ '+': ['tmux', 'save-buffer', '-'],
+ \ '*': ['tmux', 'save-buffer', '-'],
\ },
\ 'cache_enabled': 1,
\ }
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 61e090cc78..9da11a553d 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -43,6 +43,7 @@ A location list is a window-local quickfix list. You get one after commands
like `:lvimgrep`, `:lgrep`, `:lhelpgrep`, `:lmake`, etc., which create a
location list instead of a quickfix list as the corresponding `:vimgrep`,
`:grep`, `:helpgrep`, `:make` do.
+ *location-list-file-window*
A location list is associated with a window and each window can have a
separate location list. A location list can be associated with only one
window. The location list is independent of the quickfix list.
@@ -501,6 +502,29 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
< Otherwise it works the same as `:ldo`.
{not in Vi}
+FILTERING A QUICKFIX OR LOCATION LIST:
+ *cfilter-plugin* *:Cfilter* *:Lfilter*
+If you have too many entries in a quickfix list, you can use the cfilter
+plugin to reduce the number of entries. Load the plugin with: >
+
+ packadd cfilter
+
+Then you can use the following commands to filter a quickfix/location list: >
+
+ :Cfilter[!] /{pat}/
+ :Lfilter[!] /{pat}/
+
+The |:Cfilter| command creates a new quickfix list from the entries matching
+{pat} in the current quickfix list. {pat} is a Vim |regular-expression|
+pattern. Both the file name and the text of the entries are matched against
+{pat}. If the optional ! is supplied, then the entries not matching {pat} are
+used. The pattern can be optionally enclosed using one of the following
+characters: ', ", /. If the pattern is empty, then the last used search
+pattern is used.
+
+The |:Lfilter| command does the same as |:Cfilter| but operates on the current
+location list.
+
=============================================================================
2. The error window *quickfix-window*
@@ -695,6 +719,9 @@ using these functions are below:
" get the location list window id of the third window
:echo getloclist(3, {'winid' : 0}).winid
+
+ " get the file window id of a location list window (winnr: 4)
+ :echo getloclist(4, {'filewinid' : 0}).filewinid
<
*setqflist-examples*
The |setqflist()| and |setloclist()| functions can be used to set the various
@@ -709,6 +736,9 @@ using these functions are below:
" set the title of the current quickfix list
:call setqflist([], 'a', {'title' : 'Mytitle'})
+ " change the current entry in the list specified by an identifier
+ :call setqflist([], 'a', {'id' : qfid, 'idx' : 10})
+
" set the context of a quickfix list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'context' : {'val' : 100}})
@@ -1563,22 +1593,6 @@ The backslashes before the pipe character are required to avoid it to be
recognized as a command separator. The backslash before each space is
required for the set command.
- *cfilter-plugin* *:Cfilter* *:Lfilter*
-If you have too many matching messages, you can use the cfilter plugin to
-reduce the number of entries. Load the plugin with: >
- packadd cfilter
-
-Then you can use these command: >
- :Cfilter[!] /{pat}/
- :Lfilter[!] /{pat}/
-
-:Cfilter creates a new quickfix list from entries matching {pat} in the
-current quickfix list. Both the file name and the text of the entries are
-matched against {pat}. If ! is supplied, then entries not matching {pat} are
-used.
-
-:Lfilter does the same as :Cfilter but operates on the current location list.
-
=============================================================================
8. The directory stack *quickfix-directory-stack*
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 224f14a18b..4a47fd4b57 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -711,7 +711,6 @@ Short explanation of each option: *option-list*
'grepprg' 'gp' program to use for ":grep"
'guicursor' 'gcr' GUI: settings for cursor shape and blinking
'guifont' 'gfn' GUI: Name(s) of font(s) to be used
-'guifontset' 'gfs' GUI: Names of multi-byte fonts to be used
'guifontwide' 'gfw' list of font names for double-wide characters
'guioptions' 'go' GUI: Which components and options are used
'guitablabel' 'gtl' GUI: custom label for a tab page
@@ -1106,7 +1105,6 @@ Context-sensitive completion on the command-line:
------------------------------------------------------------------------------
*Q_st* Starting Vim
-|-vim| vim [options] start editing with an empty buffer
|-file| vim [options] {file} .. start editing one or more files
|--| vim [options] - read file from stdin
|-tag| vim [options] -t {tag} edit the file associated with {tag}
diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt
index b88e26cdff..0eef976819 100644
--- a/runtime/doc/spell.txt
+++ b/runtime/doc/spell.txt
@@ -187,6 +187,9 @@ When there is a line break right after a sentence the highlighting of the next
line may be postponed. Use |CTRL-L| when needed. Also see |set-spc-auto| for
how it can be set automatically when 'spelllang' is set.
+The 'spelloptions' option has a few more flags that influence the way spell
+checking works.
+
Vim counts the number of times a good word is encountered. This is used to
sort the suggestions: words that have been seen before get a small bonus,
words that have been seen often get a bigger bonus. The COMMON item in the
@@ -617,11 +620,12 @@ ask you where to write the file (there must be a writable directory in
'runtimepath' for this).
The plugin has a default place where to look for spell files, on the Vim ftp
-server. If you want to use another location or another protocol, set the
-g:spellfile_URL variable to the directory that holds the spell files. The
-|netrw| plugin is used for getting the file, look there for the specific
-syntax of the URL. Example: >
- let g:spellfile_URL = 'http://ftp.vim.org/vim/runtime/spell'
+server. The protocol used is SSL (https://) for security. If you want to use
+another location or another protocol, set the g:spellfile_URL variable to the
+directory that holds the spell files. You can use http:// or ftp://, but you
+are taking a security risk then. The |netrw| plugin is used for getting the
+file, look there for the specific syntax of the URL. Example: >
+ let g:spellfile_URL = 'https://ftp.nluug.nl/vim/runtime/spell'
You may need to escape special characters.
The plugin will only ask about downloading a language once. If you want to
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 0ded6a9060..d0faeb9cb7 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -9,20 +9,20 @@ Starting Vim *starting*
Type |gO| to see the table of contents.
==============================================================================
-1. Vim arguments *vim-arguments*
+Nvim arguments *vim-arguments*
-Most often, Vim is started to edit a single file with the command
+Most often, Nvim is started to edit a single file with the command: >
- nvim filename *-vim*
+ nvim filename
-More generally, Vim is started with:
+More generally, Nvim is started with: >
nvim [option | filename] ..
Option arguments and file name arguments can be mixed, and any number of them
can be given. However, watch out for options that take an argument.
-The following items may be used to choose how to start editing:
+The following items decide how to start editing:
*-file* *---*
filename One or more file names. The first one will be the current
@@ -231,9 +231,8 @@ argument.
-b Binary mode. File I/O will only recognize <NL> to separate
lines. The 'expandtab' option will be reset. The 'textwidth'
option is set to 0. 'modeline' is reset. The 'binary' option
- is set. This is done after reading the init.vim/exrc files
- but before reading any file in the arglist. See also
- |edit-binary|.
+ is set. This is done after reading the |vimrc| but before
+ reading any file in the arglist. See also |edit-binary|.
*-l*
-l Lisp mode. Sets the 'lisp' and 'showmatch' options on.
@@ -398,7 +397,7 @@ argument.
primary listen address |v:servername| to {addr}. |serverstart()|
==============================================================================
-2. Initialization *initialization* *startup*
+Initialization *initialization* *startup*
At startup, Vim checks environment variables and files and sets values
accordingly. Vim proceeds in this order:
@@ -414,45 +413,47 @@ accordingly. Vim proceeds in this order:
The |-V| argument can be used to display or log what happens next,
useful for debugging the initializations.
-3. Execute Ex commands, from environment variables and/or files
- An environment variable (e.g. $VIMINIT) is read as one Ex command
- line, where multiple commands must be separated with '|' or <NL>.
+3. Wait for UI to connect.
+ Nvim started with |--embed| waits for the UI to connect before
+ proceeding to load user configuration.
+
+4. Load user config (execute Ex commands from files, environment, โ€ฆ).
+ $VIMINIT environment variable is read as one Ex command line (separate
+ multiple commands with '|' or <NL>).
*config* *init.vim* *vimrc* *exrc*
- A file that contains initialization commands is generically called
- a "vimrc" or config file. Each line in a vimrc file is executed as an
- Ex command line. See also |vimrc-intro| and |base-directories|.
+ A file containing init commands is generically called a "vimrc" or
+ "config". Each line in such a file is executed as an Ex command.
+ |vimrc-intro| |base-directories|
- The Nvim config file is named "init.vim", located at:
+ The Nvim config file is "init.vim", located at:
Unix ~/.config/nvim/init.vim
Windows ~/AppData/Local/nvim/init.vim
- Or if |$XDG_CONFIG_HOME| is defined:
+ or if |$XDG_CONFIG_HOME| is defined:
$XDG_CONFIG_HOME/nvim/init.vim
- If Nvim was started with "-u filename", the file "filename" is used.
- All following initializations until 4. are skipped. $MYVIMRC is not
- set.
+ If Nvim was started with "-u {file}" then {file} is used as the config
+ and all initializations until 5. are skipped. $MYVIMRC is not set.
"nvim -u NORC" can be used to skip these initializations without
reading a file. "nvim -u NONE" also skips plugins and syntax
highlighting. |-u|
- If Nvim was started with |-es|, all following initializations until 4.
- are skipped.
+ If Nvim was started with |-es| all initializations until 5. are
+ skipped.
*system-vimrc* *sysinit.vim*
a. The system vimrc file is read for initializations. If
nvim/sysinit.vim file exists in one of $XDG_CONFIG_DIRS, it will be
- used. Otherwise, the system vimrc file is used. The path of this file
- is shown with the ":version" command. Mostly it's "$VIM/sysinit.vim".
+ used. Otherwise the system vimrc file is used. The path of this file
+ is given by the |:version| command. Usually it's "$VIM/sysinit.vim".
*VIMINIT* *EXINIT* *$MYVIMRC*
- b. Four places are searched for initializations. The first that exists
- is used, the others are ignored. The $MYVIMRC environment variable is
- set to the file that was first found, unless $MYVIMRC was already set
- and when using VIMINIT.
- - Environment variable $VIMINIT, used as an Ex command line.
- - User |config| file: $XDG_CONFIG_HOME/nvim/init.vim.
- - Other config file: {xdg_config_dir}/nvim/init.vim where
- {xdg_config_dir} is one of the directories in $XDG_CONFIG_DIRS.
- - Environment variable $EXINIT, used as an Ex command line.
+ b. Locations searched for initializations, in order of preference:
+ - $VIMINIT environment variable (Ex command line).
+ - User |config|: $XDG_CONFIG_HOME/nvim/init.vim.
+ - Other config: {dir}/nvim/init.vim where {dir} is any directory
+ in $XDG_CONFIG_DIRS.
+ - $EXINIT environment variable (Ex command line).
+ |$MYVIMRC| is set to the first valid location unless it was already
+ set or when using $VIMINIT.
c. If the 'exrc' option is on (which is NOT the default), the current
directory is searched for two files. The first that exists is used,
@@ -460,7 +461,7 @@ accordingly. Vim proceeds in this order:
- The file ".nvimrc"
- The file ".exrc"
-4. Enable filetype and indent plugins.
+5. Enable filetype and indent plugins.
This does the same as the commands: >
:runtime! filetype.vim
:runtime! ftplugin.vim
@@ -468,13 +469,13 @@ accordingly. Vim proceeds in this order:
< Skipped if ":filetype โ€ฆ off" was called or if the "-u NONE" command
line argument was given.
-5. Enable syntax highlighting.
+6. Enable syntax highlighting.
This does the same as the command: >
:runtime! syntax/syntax.vim
< Skipped if ":syntax off" was called or if the "-u NONE" command
line argument was given.
-6. Load the plugin scripts. *load-plugins*
+7. Load the plugin scripts. *load-plugins*
This does the same as the command: >
:runtime! plugin/**/*.vim
< The result is that all directories in the 'runtimepath' option will be
@@ -503,26 +504,26 @@ accordingly. Vim proceeds in this order:
if packages have been found, but that should not add a directory
ending in "after".
-7. Set 'shellpipe' and 'shellredir'
+8. Set 'shellpipe' and 'shellredir'
The 'shellpipe' and 'shellredir' options are set according to the
value of the 'shell' option, unless they have been set before.
This means that Vim will figure out the values of 'shellpipe' and
'shellredir' for you, unless you have set them yourself.
-8. Set 'updatecount' to zero, if "-n" command argument used
+9. Set 'updatecount' to zero, if "-n" command argument used
-9. Set binary options
+10. Set binary options
If the "-b" flag was given to Vim, the options for binary editing will
be set now. See |-b|.
-10. Read the ShaDa file
+11. Read the ShaDa file
See |shada-file|.
-11. Read the quickfix file
+12. Read the quickfix file
If the "-q" flag was given to Vim, the quickfix file is read. If this
fails, Vim exits.
-12. Open all windows
+13. Open all windows
When the |-o| flag was given, windows will be opened (but not
displayed yet).
When the |-p| flag was given, tab pages will be created (but not
@@ -531,7 +532,7 @@ accordingly. Vim proceeds in this order:
If the "-q" flag was given to Vim, the first error is jumped to.
Buffers for all windows will be loaded.
-13. Execute startup commands
+14. Execute startup commands
If a "-t" flag was given to Vim, the tag is jumped to.
The commands given with the |-c| and |+cmd| arguments are executed.
If the 'insertmode' option is set, Insert mode is entered.
@@ -540,29 +541,6 @@ accordingly. Vim proceeds in this order:
The |VimEnter| autocommands are executed.
-Some hints on using initializations ~
-
-Standard setup:
-Create a vimrc file to set the default settings and mappings for all your edit
-sessions. Put it in a place so that it will be found by 3b:
- ~/.config/nvim/init.vim (Unix)
- ~/AppData/Local/nvim/init.vim (Win32)
-
-Local setup:
-Put all commands that you need for editing a specific directory only into a
-vimrc file and place it in that directory under the name ".nvimrc" ("_nvimrc"
-for Windows). NOTE: To make Vim look for these special files you
-have to turn on the option 'exrc'. See |trojan-horse| too.
-
-System setup:
-This only applies if you are managing a Unix system with several users and
-want to set the defaults for all users. Create a vimrc file with commands
-for default settings and mappings and put it in the place that is given with
-the ":version" command. NOTE: System vimrc file needs specific compilation
-options (one needs to define SYS_VIMRC_FILE macros). If :version command does
-not show anything like this, consider contacting the nvim package maintainer.
-
-
Saving the current state of Vim to a file ~
Whenever you have changed values of options or when you have created a
@@ -570,20 +548,6 @@ mapping, then you may want to save them in a vimrc file for later use. See
|save-settings| about saving the current state of settings to a file.
-Avoiding setup problems for Vi users ~
-
-Vi uses the variable EXINIT and the file "~/.exrc". So if you do not want to
-interfere with Vi, then use the variable VIMINIT and the file init.vim
-instead.
-
-
-MS-DOS line separators: ~
-
-On Windows systems Vim assumes that all the vimrc files have <CR> <NL> pairs
-as line separators. This will give problems if you have a file with only
-<NL>s and have a line like ":map xx yy^M". The trailing ^M will be ignored.
-
-
Avoiding trojan horses ~
*trojan-horse*
While reading the "vimrc" or the "exrc" file in the current directory, some
@@ -606,7 +570,7 @@ it possible for another user to create a nasty vimrc and make you the owner.
Be careful!
When using tag search commands, executing the search command (the last
part of the line in the tags file) is always done in secure mode. This works
-just like executing a command from a vimrc/exrc in the current directory.
+just like executing a command from a vimrc in the current directory.
If Vim startup is slow ~
@@ -620,27 +584,29 @@ moment (use the Vim argument "-i NONE", |-i|). Try reducing the number of
lines stored in a register with ":set shada='20,<50,s10". |shada-file|.
-Intro message ~
- *:intro*
-When Vim starts without a file name, an introductory message is displayed (for
-those who don't know what Vim is). It is removed as soon as the display is
-redrawn in any way. To see the message again, use the ":intro" command (if
-there is not enough room, you will see only part of it).
- To avoid the intro message on startup, add the 'I' flag to 'shortmess'.
+Troubleshooting broken configurations ~
+ *bisect*
+The extreme flexibility of editors like Vim and Emacs means that any plugin or
+setting can affect the entire editor in ways that are not initially obvious.
- *info-message*
-The |--help| and |--version| arguments cause Nvim to print a message and then
-exit. Normally the message is sent to stdout, thus can be redirected to a
-file with: >
+To find the cause of a problem in your config, you must "bisect" it:
+1. Remove or disable half of your `init.vim`.
+2. Restart Nvim.
+3. If the problem still occurs, goto 1.
+4. If the problem is gone, restore half of the removed lines.
+5. Continue narrowing your config in this way, until you find the setting or
+ plugin causing the issue.
- nvim --help >file
-From inside Nvim: >
-
- :read !nvim --help
+Intro message ~
+ *:intro*
+When Vim starts without a file name, an introductory message is displayed. It
+is removed as soon as the display is redrawn. To see the message again, use
+the ":intro" command. To avoid the intro message on startup, add the "I" flag
+to 'shortmess'.
==============================================================================
-3. $VIM and $VIMRUNTIME
+$VIM and $VIMRUNTIME
*$VIM*
The environment variable "$VIM" is used to locate various user files for Nvim,
such as the user startup script |init.vim|. This depends on the system, see
@@ -683,9 +649,9 @@ greps in the help files) you might be able to use this: >
VIMRUNTIME="$(nvim --clean --headless --cmd 'echo $VIMRUNTIME|q')"
==============================================================================
-4. Suspending *suspend*
+Suspending *suspend*
- *iconize* *iconise* *CTRL-Z* *v_CTRL-Z*
+ *CTRL-Z* *v_CTRL-Z*
CTRL-Z Suspend Nvim, like ":stop".
Works in Normal and in Visual mode. In Insert and
Command-line mode, the CTRL-Z is inserted as a normal
@@ -706,7 +672,7 @@ CTRL-Z Suspend Nvim, like ":stop".
In the GUI, suspending is implementation-defined.
==============================================================================
-5. Exiting *exiting*
+Exiting *exiting*
There are several ways to exit Vim:
- Close the last window with `:quit`. Only when there are no changes.
@@ -719,7 +685,7 @@ When using `:cquit` or when there was an error message Vim exits with exit
code 1. Errors can be avoided by using `:silent!` or with `:catch`.
==============================================================================
-6. Saving settings *save-settings*
+Saving settings *save-settings*
Mostly you will edit your vimrc files manually. This gives you the greatest
flexibility. There are a few commands to generate a vimrc file automatically.
@@ -776,7 +742,7 @@ these steps:
You need to escape special characters, esp. spaces.
==============================================================================
-7. Views and Sessions *views-sessions*
+Views and Sessions *views-sessions*
This is introduced in sections |21.4| and |21.5| of the user manual.
@@ -920,7 +886,7 @@ To automatically save and restore views for *.c files: >
au BufWinEnter *.c silent! loadview
==============================================================================
-8. The ShaDa file *shada* *shada-file*
+Shada ("shared data") file *shada* *shada-file*
If you exit Vim and later start it again, you would normally lose a lot of
information. The ShaDa file can be used to remember that information, which
@@ -1358,7 +1324,7 @@ file when reading and include:
complete MessagePack object.
==============================================================================
-9. Standard Paths *standard-path*
+Standard Paths *standard-path*
Nvim stores configuration and data in standard locations. Plugins are strongly
encouraged to follow this pattern also. Use |stdpath()| to get the paths.
@@ -1389,4 +1355,5 @@ debugging, plugins and RPC clients. >
Usually the file is ~/.local/share/nvim/log unless that path is inaccessible
or if $NVIM_LOG_FILE was set before |startup|.
+
vim:noet:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
new file mode 100644
index 0000000000..7f644486f7
--- /dev/null
+++ b/runtime/doc/treesitter.txt
@@ -0,0 +1,295 @@
+*treesitter.txt* Nvim
+
+
+ NVIM REFERENCE MANUAL
+
+
+Tree-sitter integration *treesitter*
+
+ Type |gO| to see the table of contents.
+
+------------------------------------------------------------------------------
+VIM.TREESITTER *lua-treesitter*
+
+Nvim integrates the tree-sitter library for incremental parsing of buffers.
+
+Currently Nvim does not provide the tree-sitter parsers, instead these must
+be built separately, for instance using the tree-sitter utility. The only
+exception is a C parser being included in official builds for testing
+purposes. Parsers are searched for as `parser/{lang}.*` in any 'runtimepath'
+directory. A parser can also be loaded manually using a full path: >
+
+ vim.treesitter.require_language("python", "/path/to/python.so")
+
+<Create a parser for a buffer and a given language (if another plugin uses the
+same buffer/language combination, it will be safely reused). Use >
+
+ parser = vim.treesitter.get_parser(bufnr, lang)
+
+<`bufnr=0` can be used for current buffer. `lang` will default to 'filetype' (this
+doesn't work yet for some filetypes like "cpp") Currently, the parser will be
+retained for the lifetime of a buffer but this is subject to change. A plugin
+should keep a reference to the parser object as long as it wants incremental
+updates.
+
+Parser files *treesitter-parsers*
+
+Parsers are the heart of tree-sitter. They are libraries that tree-sitter will
+search for in the `parser` runtime directory.
+
+For a parser to be available for a given language, there must be a file named
+`{lang}.so` within the parser directory.
+
+Parser methods *lua-treesitter-parser*
+
+tsparser:parse() *tsparser:parse()*
+Whenever you need to access the current syntax tree, parse the buffer: >
+
+ tstree = parser:parse()
+
+<This will return an immutable tree that represents the current state of the
+buffer. When the plugin wants to access the state after a (possible) edit
+it should call `parse()` again. If the buffer wasn't edited, the same tree will
+be returned again without extra work. If the buffer was parsed before,
+incremental parsing will be done of the changed parts.
+
+NB: to use the parser directly inside a |nvim_buf_attach| Lua callback, you must
+call `get_parser()` before you register your callback. But preferably parsing
+shouldn't be done directly in the change callback anyway as they will be very
+frequent. Rather a plugin that does any kind of analysis on a tree should use
+a timer to throttle too frequent updates.
+
+tsparser:set_included_ranges({ranges}) *tsparser:set_included_ranges()*
+ Changes the ranges the parser should consider. This is used for
+ language injection. {ranges} should be of the form (all zero-based): >
+ {
+ {start_node, end_node},
+ ...
+ }
+<
+ NOTE: `start_node` and `end_node` are both inclusive.
+
+Tree methods *lua-treesitter-tree*
+
+tstree:root() *tstree:root()*
+ Return the root node of this tree.
+
+
+Node methods *lua-treesitter-node*
+
+tsnode:parent() *tsnode:parent()*
+ Get the node's immediate parent.
+
+tsnode:iter_children() *tsnode:iter_children()*
+ Iterates over all the direct children of {tsnode}, regardless of
+ wether they are named or not.
+ Returns the child node plus the eventual field name corresponding to
+ this child node.
+
+tsnode:field({name}) *tsnode:field()*
+ Returns a table of the nodes corresponding to the {name} field.
+
+tsnode:child_count() *tsnode:child_count()*
+ Get the node's number of children.
+
+tsnode:child({index}) *tsnode:child()*
+ Get the node's child at the given {index}, where zero represents the
+ first child.
+
+tsnode:named_child_count() *tsnode:named_child_count()*
+ Get the node's number of named children.
+
+tsnode:named_child({index}) *tsnode:named_child()*
+ Get the node's named child at the given {index}, where zero represents
+ the first named child.
+
+tsnode:start() *tsnode:start()*
+ Get the node's start position. Return three values: the row, column
+ and total byte count (all zero-based).
+
+tsnode:end_() *tsnode:end_()*
+ Get the node's end position. Return three values: the row, column
+ and total byte count (all zero-based).
+
+tsnode:range() *tsnode:range()*
+ Get the range of the node. Return four values: the row, column
+ of the start position, then the row, column of the end position.
+
+tsnode:type() *tsnode:type()*
+ Get the node's type as a string.
+
+tsnode:symbol() *tsnode:symbol()*
+ Get the node's type as a numerical id.
+
+tsnode:named() *tsnode:named()*
+ Check if the node is named. Named nodes correspond to named rules in
+ the grammar, whereas anonymous nodes correspond to string literals
+ in the grammar.
+
+tsnode:missing() *tsnode:missing()*
+ Check if the node is missing. Missing nodes are inserted by the
+ parser in order to recover from certain kinds of syntax errors.
+
+tsnode:has_error() *tsnode:has_error()*
+ Check if the node is a syntax error or contains any syntax errors.
+
+tsnode:sexpr() *tsnode:sexpr()*
+ Get an S-expression representing the node as a string.
+
+tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
+ *tsnode:descendant_for_range()*
+ Get the smallest node within this node that spans the given range of
+ (row, column) positions
+
+tsnode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
+ *tsnode:named_descendant_for_range()*
+ Get the smallest named node within this node that spans the given
+ range of (row, column) positions
+
+Query methods *lua-treesitter-query*
+
+Tree-sitter queries are supported, with some limitations. Currently, the only
+supported match predicate is `eq?` (both comparing a capture against a string
+and two captures against each other).
+
+vim.treesitter.parse_query({lang}, {query})
+ *vim.treesitter.parse_query()*
+ Parse {query} as a string. (If the query is in a file, the caller
+ should read the contents into a string before calling).
+
+query:iter_captures({node}, {bufnr}, {start_row}, {end_row})
+ *query:iter_captures()*
+ Iterate over all captures from all matches inside {node}.
+ {bufnr} is needed if the query contains predicates, then the caller
+ must ensure to use a freshly parsed tree consistent with the current
+ text of the buffer. {start_row} and {end_row} can be used to limit
+ matches inside a row range (this is typically used with root node
+ as the node, i e to get syntax highlight matches in the current
+ viewport)
+
+ The iterator returns two values, a numeric id identifying the capture
+ and the captured node. The following example shows how to get captures
+ by name:
+>
+ for id, node in query:iter_captures(tree:root(), bufnr, first, last) do
+ local name = query.captures[id] -- name of the capture in the query
+ -- typically useful info about the node:
+ local type = node:type() -- type of the captured node
+ local row1, col1, row2, col2 = node:range() -- range of the capture
+ ... use the info here ...
+ end
+<
+query:iter_matches({node}, {bufnr}, {start_row}, {end_row})
+ *query:iter_matches()*
+ Iterate over all matches within a node. The arguments are the same as
+ for |query:iter_captures()| but the iterated values are different:
+ an (1-based) index of the pattern in the query, and a table mapping
+ capture indices to nodes. If the query has more than one pattern
+ the capture table might be sparse, and e.g. `pairs` should be used and not
+ `ipairs`. Here an example iterating over all captures in
+ every match:
+>
+ for pattern, match in cquery:iter_matches(tree:root(), bufnr, first, last) do
+ for id,node in pairs(match) do
+ local name = query.captures[id]
+ -- `node` was captured by the `name` capture in the match
+ ... use the info here ...
+ end
+ end
+
+Treesitter Query Predicates *lua-treesitter-predicates*
+
+When writing queries for treesitter, one might use `predicates`, that is,
+special scheme nodes that are evaluted to verify things on a captured node for
+example, the |eq?| predicate : >
+ ((identifier) @foo (#eq? @foo "foo"))
+
+This will only match identifier corresponding to the `"foo"` text.
+Here is a list of built-in predicates :
+
+ `eq?` *ts-predicate-eq?*
+ This predicate will check text correspondance between nodes or
+ strings : >
+ ((identifier) @foo (#eq? @foo "foo"))
+ ((node1) @left (node2) @right (#eq? @left @right))
+<
+ `match?` *ts-predicate-match?*
+ `vim-match?` *ts-predicate-vim-match?*
+ This will match if the provived vim regex matches the text
+ corresponding to a node : >
+ ((idenfitier) @constant (#match? @constant "^[A-Z_]+$"))
+< Note: the `^` and `$` anchors will respectively match the
+ start and end of the node's text.
+
+ `lua-match?` *ts-predicate-lua-match?*
+ This will match the same way than |match?| but using lua
+ regexes.
+
+ `contains?` *ts-predicate-contains?*
+ Will check if any of the following arguments appears in the
+ text corresponding to the node : >
+ ((identifier) @foo (#contains? @foo "foo"))
+ ((identifier) @foo-bar (#contains @foo-bar "foo" "bar"))
+<
+ *lua-treesitter-not-predicate*
+Each predicate has a `not-` prefixed predicate that is just the negation of
+the predicate.
+
+ *vim.treesitter.query.add_predicate()*
+vim.treesitter.query.add_predicate({name}, {handler})
+
+This adds a predicate with the name {name} to be used in queries.
+{handler} should be a function whose signature will be : >
+ handler(match, pattern, bufnr, predicate)
+<
+ *vim.treesitter.query.list_predicates()*
+vim.treesitter.query.list_predicates()
+
+This lists the currently available predicates to use in queries.
+
+Treesitter syntax highlighting (WIP) *lua-treesitter-highlight*
+
+NOTE: This is a partially implemented feature, and not usable as a default
+solution yet. What is documented here is a temporary interface indented
+for those who want to experiment with this feature and contribute to
+its development.
+
+Highlights are defined in the same query format as in the tree-sitter highlight
+crate, which some limitations and additions. Set a highlight query for a
+buffer with this code: >
+
+ local query = [[
+ "for" @keyword
+ "if" @keyword
+ "return" @keyword
+
+ (string_literal) @string
+ (number_literal) @number
+ (comment) @comment
+
+ (preproc_function_def name: (identifier) @function)
+
+ ; ... more definitions
+ ]]
+
+ highlighter = vim.treesitter.TSHighlighter.new(query, bufnr, lang)
+ -- alternatively, to use the current buffer and its filetype:
+ -- highlighter = vim.treesitter.TSHighlighter.new(query)
+
+ -- Don't recreate the highlighter for the same buffer, instead
+ -- modify the query like this:
+ local query2 = [[ ... ]]
+ highlighter:set_query(query2)
+
+As mentioned above the supported predicate is currently only `eq?`. `match?`
+predicates behave like matching always fails. As an addition a capture which
+begin with an upper-case letter like `@WarningMsg` will map directly to this
+highlight group, if defined. Also if the predicate begins with upper-case and
+contains a dot only the part before the first will be interpreted as the
+highlight group. As an example, this warns of a binary expression with two
+identical identifiers, highlighting both as |hl-WarningMsg|: >
+
+ ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
+ (eq? @WarningMsg.left @WarningMsg.right))
+
+ vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 2817c1015b..e5c6b9b1b7 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -183,9 +183,9 @@ the editor.
'ambiwidth'
'emoji'
'guifont'
- 'guifontset'
'guifontwide'
'linespace'
+ 'mousefocus'
'pumblend'
'showtabline'
'termguicolors'
@@ -719,7 +719,7 @@ events, which the UI must handle.
kind
Name indicating the message kind:
- "" (empty) Unknown, report a |feature-request|
+ "" (empty) Unknown (consider a feature-request: |bugs|)
"confirm" |confirm()| or |:confirm| dialog
"confirm_sub" |:substitute| confirm dialog |:s_c|
"emsg" Error (|errors|, internal error, |:throw|, โ€ฆ)
diff --git a/runtime/doc/usr_02.txt b/runtime/doc/usr_02.txt
index 9ebbd11ac7..c8fd7c3e35 100644
--- a/runtime/doc/usr_02.txt
+++ b/runtime/doc/usr_02.txt
@@ -652,7 +652,7 @@ Summary: *help-summary* >
22) Autocommand events can be found by their name: >
:help BufWinLeave
< To see all possible events: >
- :help autocommand-events
+ :help events
23) Command-line switches always start with "-". So for the help of the -f
command switch of Vim use: >
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 24b562543e..1fcb6611b4 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -13,7 +13,7 @@ the differences.
Type |gO| to see the table of contents.
==============================================================================
-1. Configuration *nvim-configuration*
+1. Configuration *nvim-config*
- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for configuration.
- Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files.
@@ -50,7 +50,7 @@ the differences.
- 'listchars' defaults to "tab:> ,trail:-,nbsp:+"
- 'nrformats' defaults to "bin,hex"
- 'ruler' is enabled
-- 'sessionoptions' excludes "options"
+- 'sessionoptions' includes "unix,slash", excludes "options"
- 'shortmess' includes "F", excludes "S"
- 'showcmd' is enabled
- 'sidescroll' defaults to 1
@@ -60,13 +60,14 @@ the differences.
- 'tags' defaults to "./tags;,tags"
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
+- 'viewoptions' includes "unix,slash"
- 'undodir' defaults to ~/.local/share/nvim/undo (|xdg|), auto-created
- 'viminfo' includes "!"
- 'wildmenu' is enabled
- 'wildoptions' defaults to "pum,tagfile"
-- The |man.vim| plugin is enabled, to provide the |:Man| command.
-- The |matchit| plugin is enabled. To disable it in your config: >
+- |man.vim| plugin is enabled, so |:Man| is available by default.
+- |matchit| plugin is enabled. To disable it in your config: >
:let loaded_matchit = 1
==============================================================================
@@ -172,6 +173,7 @@ Functions:
|msgpackdump()|, |msgpackparse()| provide msgpack de/serialization
|stdpath()|
|system()|, |systemlist()| can run {cmd} directly (without 'shell')
+ |tabpagenr()| "#" argument
Highlight groups:
|highlight-blend| controls blend level for a highlight group
@@ -186,18 +188,18 @@ Highlight groups:
|hl-TermCursorNC|
|hl-Whitespace| highlights 'listchars' whitespace
-Input:
+Input/Mappings:
+ |<Cmd>| pseudokey
+
ALT (|META|) chords always work (even in the |TUI|). Map |<M-| with any key:
<M-1>, <M-BS>, <M-Del>, <M-Ins>, <M-/>, <M-\>, <M-Space>, <M-Enter>, etc.
Case-sensitive: <M-a> and <M-A> are two different keycodes.
- ALT in insert-mode behaves like <Esc> if not mapped. |i_ALT|
-
-Mappings:
- |<Cmd>| pseudokey
+ ALT behaves like <Esc> if not mapped. |i_ALT| |v_ALT| |c_ALT|
Normal commands:
- "Outline": Type |gO| in |:Man| and |:help| pages to see a document outline.
+ |g<Tab>| goes to the last-accessed tabpage.
+ |gO| shows a filetype-defined "outline" of the current buffer.
Options:
'cpoptions' flags: |cpo-_|
@@ -406,7 +408,6 @@ Some legacy Vim features are not implemented:
- |if_lua|: Nvim Lua API is not compatible with Vim's "if_lua"
- *if_mzscheme*
-- *if_perl*
- |if_py|: *python-bindeval* *python-Function* are not supported
- *if_tcl*
@@ -449,6 +450,9 @@ Eval:
*js_decode()*
*v:none* (used by Vim to represent JavaScript "undefined"); use |v:null| instead.
+Events:
+ *SigUSR1* Use |Signal| to detect `SIGUSR1` signal instead.
+
Highlight groups:
*hl-StatusLineTerm* *hl-StatusLineTermNC* are unnecessary because Nvim
supports 'winhighlight' window-local highlights.
@@ -471,6 +475,7 @@ Options:
'encoding' ("utf-8" is always used)
'esckeys'
'guioptions' "t" flag was removed
+ *'guifontset'* *'gfs'* (Use 'guifont' instead.)
*'guipty'* (Nvim uses pipes and PTYs consistently on all platforms.)
'highlight' (Names of builtin |highlight-groups| cannot be changed.)
*'imactivatefunc'* *'imaf'*
@@ -506,7 +511,6 @@ Test functions:
test_alloc_fail()
test_autochdir()
test_disable_char_avail()
- test_garbagecollect_now()
test_null_channel()
test_null_dict()
test_null_job()
diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt
index 0052382044..fd3d93ed98 100644
--- a/runtime/doc/visual.txt
+++ b/runtime/doc/visual.txt
@@ -159,7 +159,10 @@ If you want to highlight exactly the same area as the last time, you can use
*v_<Esc>*
<Esc> In Visual mode: Stop Visual mode.
-
+ *v_META* *v_ALT*
+ ALT (|META|) acts like <Esc> if the chord is not mapped.
+ For example <A-x> acts like <Esc>x if <A-x> does not have a
+ visual-mode mapping.
*v_CTRL-C*
CTRL-C In Visual mode: Stop Visual mode. When insert mode is
pending (the mode message shows
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index c0d656107c..7accc22b3d 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -180,7 +180,7 @@ au BufNewFile,BufRead *.at setf m4
au BufNewFile,BufRead *.ave setf ave
" Awk
-au BufNewFile,BufRead *.awk setf awk
+au BufNewFile,BufRead *.awk,*.gawk setf awk
" B
au BufNewFile,BufRead *.mch,*.ref,*.imp setf b
@@ -236,10 +236,10 @@ au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml
au BufNewFile,BufRead *bsd,*.bsdl setf bsdl
" Bazel (http://bazel.io)
-autocmd BufRead,BufNewFile *.bzl,WORKSPACE,BUILD.bazel setf bzl
+autocmd BufRead,BufNewFile *.bzl,*.bazel,WORKSPACE setf bzl
if has("fname_case")
" There is another check for BUILD further below.
- autocmd BufRead,BufNewFile BUILD setf bzl
+ autocmd BufRead,BufNewFile *.BUILD,BUILD setf bzl
endif
" C or lpc
@@ -313,7 +313,7 @@ au BufNewFile,BufRead *.css setf css
au BufNewFile,BufRead *.con setf cterm
" Changelog
-au BufNewFile,BufRead changelog.Debian,changelog.dch,NEWS.Debian,NEWS.dch
+au BufNewFile,BufRead changelog.Debian,changelog.dch,NEWS.Debian,NEWS.dch,*/debian/changelog
\ setf debchangelog
au BufNewFile,BufRead [cC]hange[lL]og
@@ -1089,6 +1089,9 @@ au BufNewFile,BufRead .netrc setf netrc
" Ninja file
au BufNewFile,BufRead *.ninja setf ninja
+" NPM RC file
+au BufNewFile,BufRead npmrc,.npmrc setf dosini
+
" Novell netware batch files
au BufNewFile,BufRead *.ncf setf ncf
@@ -1155,10 +1158,10 @@ au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp
au BufNewFile,BufRead */etc/passwd,*/etc/passwd-,*/etc/passwd.edit,*/etc/shadow,*/etc/shadow-,*/etc/shadow.edit,*/var/backups/passwd.bak,*/var/backups/shadow.bak setf passwd
" Pascal (also *.p)
-au BufNewFile,BufRead *.pas setf pascal
+au BufNewFile,BufRead *.pas,*.pp setf pascal
-" Delphi project file
-au BufNewFile,BufRead *.dpr setf pascal
+" Delphi or Lazarus program file
+au BufNewFile,BufRead *.dpr,*.lpr setf pascal
" PDF
au BufNewFile,BufRead *.pdf setf pdf
@@ -1195,6 +1198,9 @@ au BufNewFile,BufRead *.pod6 setf pod6
" Also .ctp for Cake template file
au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp setf php
+" PHP config
+au BufNewFile,BufRead php.ini,php.ini-* setf dosini
+
" Pike and Cmod
au BufNewFile,BufRead *.pike,*.pmod setf pike
au BufNewFile,BufRead *.cmod setf cmod
@@ -1726,7 +1732,7 @@ au BufNewFile,BufRead *.texinfo,*.texi,*.txi setf texinfo
au BufNewFile,BufRead texmf.cnf setf texmf
" Tidy config
-au BufNewFile,BufRead .tidyrc,tidyrc setf tidy
+au BufNewFile,BufRead .tidyrc,tidyrc,tidy.conf setf tidy
" TF mud client
au BufNewFile,BufRead *.tf,.tfrc,tfrc setf tf
@@ -2035,7 +2041,7 @@ au BufNewFile,BufRead bzr_log.* setf bzr
" Bazel build file
if !has("fname_case")
- au BufNewFile,BufRead BUILD setf bzl
+ au BufNewFile,BufRead *.BUILD,BUILD setf bzl
endif
" BIND zone
diff --git a/runtime/ftplugin/markdown.vim b/runtime/ftplugin/markdown.vim
index 277ba94e8b..fc1d9e068b 100644
--- a/runtime/ftplugin/markdown.vim
+++ b/runtime/ftplugin/markdown.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
-" Last Change: 2016 Aug 29
+" Last Change: 2019 Dec 05
if exists("b:did_ftplugin")
finish
@@ -9,7 +9,7 @@ endif
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
-setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=>\ %s
+setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--%s-->
setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o
setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:
@@ -19,32 +19,56 @@ else
let b:undo_ftplugin = "setl cms< com< fo< flp<"
endif
-function! MarkdownFold()
+function! s:NotCodeBlock(lnum) abort
+ return synIDattr(synID(v:lnum, 1, 1), 'name') !=# 'markdownCode'
+endfunction
+
+function! MarkdownFold() abort
let line = getline(v:lnum)
- " Regular headers
- let depth = match(line, '\(^#\+\)\@<=\( .*$\)\@=')
- if depth > 0
- return ">" . depth
+ if line =~# '^#\+ ' && s:NotCodeBlock(v:lnum)
+ return ">" . match(line, ' ')
endif
- " Setext style headings
let nextline = getline(v:lnum + 1)
- if (line =~ '^.\+$') && (nextline =~ '^=\+$')
+ if (line =~ '^.\+$') && (nextline =~ '^=\+$') && s:NotCodeBlock(v:lnum + 1)
return ">1"
endif
- if (line =~ '^.\+$') && (nextline =~ '^-\+$')
+ if (line =~ '^.\+$') && (nextline =~ '^-\+$') && s:NotCodeBlock(v:lnum + 1)
return ">2"
endif
return "="
endfunction
+function! s:HashIndent(lnum) abort
+ let hash_header = matchstr(getline(a:lnum), '^#\{1,6}')
+ if len(hash_header)
+ return hash_header
+ else
+ let nextline = getline(a:lnum + 1)
+ if nextline =~# '^=\+\s*$'
+ return '#'
+ elseif nextline =~# '^-\+\s*$'
+ return '##'
+ endif
+ endif
+endfunction
+
+function! MarkdownFoldText() abort
+ let hash_indent = s:HashIndent(v:foldstart)
+ let title = substitute(getline(v:foldstart), '^#\+\s*', '', '')
+ let foldsize = (v:foldend - v:foldstart + 1)
+ let linecount = '['.foldsize.' lines]'
+ return hash_indent.' '.title.' '.linecount
+endfunction
+
if has("folding") && exists("g:markdown_folding")
setlocal foldexpr=MarkdownFold()
setlocal foldmethod=expr
- let b:undo_ftplugin .= " foldexpr< foldmethod<"
+ setlocal foldtext=MarkdownFoldText()
+ let b:undo_ftplugin .= " foldexpr< foldmethod< foldtext<"
endif
" vim:set sw=2:
diff --git a/runtime/ftplugin/typescript.vim b/runtime/ftplugin/typescript.vim
new file mode 100644
index 0000000000..f701ae96cd
--- /dev/null
+++ b/runtime/ftplugin/typescript.vim
@@ -0,0 +1,39 @@
+" Vim filetype plugin file
+" Language: TypeScript
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Aug 30
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo-=C
+
+" Set 'formatoptions' to break comment lines but not other lines,
+" and insert the comment leader when hitting <CR> or using "o".
+setlocal formatoptions-=t formatoptions+=croql
+
+" Set 'comments' to format dashed lists in comments.
+setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+
+setlocal commentstring=//%s
+
+setlocal suffixesadd+=.ts,.d.ts,.tsx,.js,.jsx,.cjs,.mjs
+
+" Change the :browse e filter to primarily show TypeScript-related files.
+if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
+ let b:browsefilter="TypeScript Files (*.ts)\t*.ts\n" .
+ \ "TypeScript Declaration Files (*.d.ts)\t*.d.ts\n" .
+ \ "TSX Files (*.tsx)\t*.tsx\n" .
+ \ "JavaScript Files (*.js)\t*.js\n" .
+ \ "JavaScript Modules (*.es, *.cjs, *.mjs)\t*.es;*.cjs;*.mjs\n" .
+ \ "JSON Files (*.json)\t*.json\n" .
+ \ "All Files (*.*)\t*.*\n"
+endif
+
+let b:undo_ftplugin = "setl fo< com< cms< sua< | unlet! b:browsefilter"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/ftplugin/typescriptreact.vim b/runtime/ftplugin/typescriptreact.vim
new file mode 100644
index 0000000000..3bd6001a18
--- /dev/null
+++ b/runtime/ftplugin/typescriptreact.vim
@@ -0,0 +1,33 @@
+" Vim filetype plugin file
+" Language: TypeScript React
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2020 Aug 09
+
+let s:match_words = ""
+let s:undo_ftplugin = ""
+
+runtime! ftplugin/typescript.vim
+
+let s:cpo_save = &cpo
+set cpo-=C
+
+if exists("b:match_words")
+ let s:match_words = b:match_words
+endif
+if exists("b:undo_ftplugin")
+ let s:undo_ftplugin = b:undo_ftplugin
+endif
+
+" Matchit configuration
+if exists("loaded_matchit")
+ let b:match_ignorecase = 0
+ let b:match_words = s:match_words .
+ \ '<:>,' .
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,' .
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+let b:undo_ftplugin = "unlet! b:match_words b:match_ignorecase | " . s:undo_ftplugin
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/indent/typescript.vim b/runtime/indent/typescript.vim
index 69accaa054..b6b2cb5acf 100644
--- a/runtime/indent/typescript.vim
+++ b/runtime/indent/typescript.vim
@@ -1,7 +1,7 @@
" Vim indent file
" Language: TypeScript
" Maintainer: See https://github.com/HerringtonDarkholme/yats.vim
-" Last Change: 2019 Jun 06
+" Last Change: 2019 Oct 18
" Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org
" 0. Initialization {{{1
@@ -442,7 +442,7 @@ let &cpo = s:cpo_save
unlet s:cpo_save
function! Fixedgq(lnum, count)
- let l:tw = &tw ? &tw : 80;
+ let l:tw = &tw ? &tw : 80
let l:count = a:count
let l:first_char = indent(a:lnum) + 1
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua
index ce0a3de520..705b34dc99 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/highlight.lua
@@ -14,7 +14,7 @@ function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive)
inclusive = inclusive or false
-- sanity check
- if start[2] < 0 or finish[2] < start[2] then return end
+ if start[2] < 0 or finish[1] < start[1] then return end
local region = vim.region(bufnr, start, finish, rtype, inclusive)
for linenr, cols in pairs(region) do
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 6fe1d15b7e..1a0015e2db 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -25,13 +25,44 @@ local lsp = {
-- format_rpc_error = lsp_rpc.format_rpc_error;
}
+-- maps request name to the required resolved_capability in the client.
+lsp._request_name_to_capability = {
+ ['textDocument/hover'] = 'hover';
+ ['textDocument/signatureHelp'] = 'signature_help';
+ ['textDocument/definition'] = 'goto_definition';
+ ['textDocument/implementation'] = 'implementation';
+ ['textDocument/declaration'] = 'declaration';
+ ['textDocument/typeDefinition'] = 'type_definition';
+ ['textDocument/documentSymbol'] = 'document_symbol';
+ ['textDocument/workspaceSymbol'] = 'workspace_symbol';
+ ['textDocument/prepareCallHierarchy'] = 'call_hierarchy';
+ ['textDocument/rename'] = 'rename';
+ ['textDocument/codeAction'] = 'code_action';
+ ['workspace/executeCommand'] = 'execute_command';
+ ['textDocument/references'] = 'find_references';
+ ['textDocument/rangeFormatting'] = 'document_range_formatting';
+ ['textDocument/formatting'] = 'document_formatting';
+ ['textDocument/completion'] = 'completion';
+ ['textDocument/documentHighlight'] = 'document_highlight';
+}
+
-- TODO improve handling of scratch buffers with LSP attached.
+--@private
+--- Concatenates and writes a list of strings to the Vim error buffer.
+---
+--@param {...} (List of strings) List to write to the buffer
local function err_message(...)
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
nvim_command("redraw")
end
+--@private
+--- Returns the buffer number for the given {bufnr}.
+---
+--@param bufnr (number) Buffer number to resolve. Defaults to the current
+---buffer if not given.
+--@returns bufnr (number) Number of requested buffer
local function resolve_bufnr(bufnr)
validate { bufnr = { bufnr, 'n', true } }
if bufnr == nil or bufnr == 0 then
@@ -40,6 +71,21 @@ local function resolve_bufnr(bufnr)
return bufnr
end
+--@private
+--- callback called by the client when trying to call a method that's not
+--- supported in any of the servers registered for the current buffer.
+--@param method (string) name of the method
+function lsp._unsupported_method(method)
+ local msg = string.format("method %s is not supported by any of the servers registered for the current buffer", method)
+ log.warn(msg)
+ return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
+end
+
+--@private
+--- Checks whether a given path is a directory.
+---
+--@param filename (string) path to check
+--@returns true if {filename} exists and is a directory, false otherwise
local function is_dir(filename)
validate{filename={filename,'s'}}
local stat = uv.fs_stat(filename)
@@ -55,6 +101,10 @@ local valid_encodings = {
}
local client_index = 0
+--@private
+--- Returns a new, unused client id.
+---
+--@returns (number) client id
local function next_client_id()
client_index = client_index + 1
return client_index
@@ -64,6 +114,12 @@ local active_clients = {}
local all_buffer_active_clients = {}
local uninitialized_clients = {}
+--@private
+--- Invokes a callback for each LSP client attached to the buffer {bufnr}.
+---
+--@param bufnr (Number) of buffer
+--@param callback (function({client}, {client_id}, {bufnr}) Function to run on
+---each client attached to that buffer.
local function for_each_buffer_client(bufnr, callback)
validate {
callback = { callback, 'f' };
@@ -88,6 +144,11 @@ lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_rever
ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1;
})
+--@private
+--- Normalizes {encoding} to valid LSP encoding names.
+---
+--@param encoding (string) Encoding to normalize
+--@returns (string) normalized encoding name
local function validate_encoding(encoding)
validate {
encoding = { encoding, 's' };
@@ -96,6 +157,13 @@ local function validate_encoding(encoding)
or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding))
end
+--@internal
+--- Parses a command invocation into the command itself and its args. If there
+--- are no arguments, an empty table is returned as the second argument.
+---
+--@param input (List)
+--@returns (string) the command
+--@returns (list of strings) its arguments
function lsp._cmd_parts(input)
vim.validate{cmd={
input,
@@ -114,12 +182,27 @@ function lsp._cmd_parts(input)
return cmd, cmd_args
end
+--@private
+--- Augments a validator function with support for optional (nil) values.
+---
+--@param fn (function(v)) The original validator function; should return a
+---bool.
+--@returns (function(v)) The augmented function. Also returns true if {v} is
+---`nil`.
local function optional_validator(fn)
return function(v)
return v == nil or fn(v)
end
end
+--@private
+--- Validates a client configuration as given to |vim.lsp.start_client()|.
+---
+--@param config (table)
+--@returns (table) "Cleaned" config, containing only the command, its
+---arguments, and a valid encoding.
+---
+--@see |vim.lsp.start_client()|
local function validate_client_config(config)
validate {
config = { config, 't' };
@@ -148,6 +231,11 @@ local function validate_client_config(config)
}
end
+--@private
+--- Returns full text of buffer {bufnr} as a string.
+---
+--@param bufnr (number) Buffer handle, or 0 for current.
+--@returns Buffer text as string.
local function buf_get_full_text(bufnr)
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
if nvim_buf_get_option(bufnr, 'eol') then
@@ -156,6 +244,11 @@ local function buf_get_full_text(bufnr)
return text
end
+--@private
+--- Default handler for the 'textDocument/didOpen' LSP notification.
+---
+--@param bufnr (Number) Number of the buffer, or 0 for current
+--@param client Client object
local function text_document_did_open_handler(bufnr, client)
if not client.resolved_capabilities.text_document_open_close then
return
@@ -176,74 +269,90 @@ local function text_document_did_open_handler(bufnr, client)
util.buf_versions[bufnr] = params.textDocument.version
end
---- LSP client object.
+-- FIXME: DOC: Shouldn't need to use a dummy function
+--
+--- LSP client object. You can get an active client object via
+--- |vim.lsp.get_client_by_id()| or |vim.lsp.get_active_clients()|.
---
--- - Methods:
---
---- - request(method, params, [callback])
---- Send a request to the server. If callback is not specified, it will use
---- {client.callbacks} to try to find a callback. If one is not found there,
---- then an error will occur.
+--- - request(method, params, [callback], bufnr)
+--- Sends a request to the server.
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checking.
---- Returns a boolean to indicate if the notification was successful. If it
---- is false, then it will always be false (the client has shutdown).
---- If it was successful, then it will return the request id as the second
---- result. You can use this with `notify("$/cancel", { id = request_id })`
---- to cancel the request. This helper is made automatically with
---- |vim.lsp.buf_request()|
---- Returns: status, [client_id]
+--- If {callback} is not specified, it will use {client.callbacks} to try to
+--- find a callback. If one is not found there, then an error will occur.
+--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if
+--- the notification was successful. If it is `false`, then it will always
+--- be `false` (the client has shutdown).
+--- If {status} is `true`, the function returns {request_id} as the second
+--- result. You can use this with `client.cancel_request(request_id)`
+--- to cancel the request.
---
--- - notify(method, params)
---- This is just {client.rpc.notify}()
---- Returns a boolean to indicate if the notification was successful. If it
---- is false, then it will always be false (the client has shutdown).
---- Returns: status
+--- Sends a notification to an LSP server.
+--- Returns: a boolean to indicate if the notification was successful. If
+--- it is false, then it will always be false (the client has shutdown).
---
--- - cancel_request(id)
---- This is just {client.rpc.notify}("$/cancelRequest", { id = id })
---- Returns the same as `notify()`.
+--- Cancels a request with a given request id.
+--- Returns: same as `notify()`.
---
--- - stop([force])
---- Stop a client, optionally with force.
+--- Stops a client, optionally with force.
--- By default, it will just ask the server to shutdown without force.
--- If you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
---
--- - is_stopped()
---- Returns true if the client is fully stopped.
+--- Checks whether a client is stopped.
+--- Returns: true if the client is fully stopped.
+---
+--- - on_attach(bufnr)
+--- Runs the on_attach function from the client's config if it was defined.
---
--- - Members
---- - id (number): The id allocated to the client.
+--- - {id} (number): The id allocated to the client.
---
---- - name (string): If a name is specified on creation, that will be
+--- - {name} (string): If a name is specified on creation, that will be
--- used. Otherwise it is just the client id. This is used for
--- logs and messages.
---
---- - offset_encoding (string): The encoding used for communicating
---- with the server. You can modify this in the `on_init` method
+--- - {rpc} (table): RPC client object, for low level interaction with the
+--- client. See |vim.lsp.rpc.start()|.
+---
+--- - {offset_encoding} (string): The encoding used for communicating
+--- with the server. You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
---
---- - callbacks (table): The callbacks used by the client as
+--- - {callbacks} (table): The callbacks used by the client as
--- described in |lsp-callbacks|.
---
---- - config (table): copy of the table that was passed by the user
+--- - {config} (table): copy of the table that was passed by the user
--- to |vim.lsp.start_client()|.
---
---- - server_capabilities (table): Response from the server sent on
+--- - {server_capabilities} (table): Response from the server sent on
--- `initialize` describing the server's capabilities.
---
---- - resolved_capabilities (table): Normalized table of
+--- - {resolved_capabilities} (table): Normalized table of
--- capabilities that we have detected based on the initialize
--- response from the server in `server_capabilities`.
function lsp.client()
error()
end
+-- FIXME: DOC: Currently all methods on the `vim.lsp.client` object are
+-- documented twice: Here, and on the methods themselves (e.g.
+-- `client.request()`). This is a workaround for the vimdoc generator script
+-- not handling method names correctly. If you change the documentation on
+-- either, please make sure to update the other as well.
+--
--- Starts and initializes a client with the given configuration.
---
--- Parameters `cmd` and `root_dir` are required.
---
+--- The following parameters describe fields in the {config} table.
+---
--@param root_dir: (required, string) Directory where the LSP server will base
--- its rootUri on initialization.
---
@@ -271,8 +380,8 @@ end
---
--@param callbacks Map of language server method names to
--- `function(err, method, params, client_id)` handler. Invoked for:
---- - Notifications from the server, where `err` will always be `nil`.
---- - Requests initiated by the server. For these you can respond by returning
+--- - Notifications to the server, where `err` will always be `nil`.
+--- - Requests by the server. For these you can respond by returning
--- two values: `result, err` where err must be shaped like a RPC error,
--- i.e. `{ code, message, data? }`. Use |vim.lsp.rpc_response_error()| to
--- help with this.
@@ -297,7 +406,7 @@ end
--@param before_init Callback with parameters (initialize_params, config)
--- invoked before the LSP "initialize" phase, where `params` contains the
--- parameters being sent to the server and `config` is the config that was
---- passed to `start_client()`. You can use this to modify parameters before
+--- passed to |vim.lsp.start_client()|. You can use this to modify parameters before
--- they are sent.
---
--@param on_init Callback (client, initialize_result) invoked after LSP
@@ -319,9 +428,8 @@ end
--@param trace: "off" | "messages" | "verbose" | nil passed directly to the language
--- server in the initialize request. Invalid/empty values will default to "off"
---
---@returns Client id. |vim.lsp.get_client_by_id()| Note: client is only
---- available after it has been initialized, which may happen after a small
---- delay (or never if there is an error). Use `on_init` to do any actions once
+--@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be
+--- fully initialized. Use `on_init` to do any actions once
--- the client has been initialized.
function lsp.start_client(config)
local cleaned_config = validate_client_config(config)
@@ -335,10 +443,23 @@ function lsp.start_client(config)
local handlers = {}
+ --@private
+ --- Returns the callback associated with an LSP method. Returns the default
+ --- callback if the user hasn't set a custom one.
+ ---
+ --@param method (string) LSP method name
+ --@returns (fn) The callback for the given method, if defined, or the default
+ ---from |lsp-callbacks|
local function resolve_callback(method)
return callbacks[method] or default_callbacks[method]
end
+ --@private
+ --- Handles a notification sent by an LSP server by invoking the
+ --- corresponding callback.
+ ---
+ --@param method (string) LSP method name
+ --@param params (table) The parameters for that method.
function handlers.notification(method, params)
local _ = log.debug() and log.debug('notification', method, params)
local callback = resolve_callback(method)
@@ -348,6 +469,12 @@ function lsp.start_client(config)
end
end
+ --@private
+ --- Handles a request from an LSP server by invoking the corresponding
+ --- callback.
+ ---
+ --@param method (string) LSP method name
+ --@param params (table) The parameters for that method
function handlers.server_request(method, params)
local _ = log.debug() and log.debug('server_request', method, params)
local callback = resolve_callback(method)
@@ -359,6 +486,13 @@ function lsp.start_client(config)
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
+ --@private
+ --- Invoked when the client operation throws an error.
+ ---
+ --@param code (number) Error code
+ --@param err (...) Other arguments may be passed depending on the error kind
+ --@see |vim.lsp.client_errors| for possible errors. Use
+ ---`vim.lsp.client_errors[code]` to get a human-friendly name.
function handlers.on_error(code, err)
local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = err })
err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err))
@@ -371,6 +505,11 @@ function lsp.start_client(config)
end
end
+ --@private
+ --- Invoked on client exit.
+ ---
+ --@param code (number) exit code of the process
+ --@param signal (number) the signal used to terminate (if any)
function handlers.on_exit(code, signal)
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
@@ -411,6 +550,7 @@ function lsp.start_client(config)
-- initialize finishes.
uninitialized_clients[client_id] = client;
+ --@private
local function initialize()
local valid_traces = {
off = 'off'; messages = 'messages'; verbose = 'verbose';
@@ -466,6 +606,15 @@ function lsp.start_client(config)
-- These are the cleaned up capabilities we use for dynamically deciding
-- when to send certain events to clients.
client.resolved_capabilities = protocol.resolve_capabilities(client.server_capabilities)
+ client.supports_method = function(method)
+ local required_capability = lsp._request_name_to_capability[method]
+ -- if we don't know about the method, assume that the client supports it.
+ if not required_capability then
+ return true
+ end
+
+ return client.resolved_capabilities[required_capability]
+ end
if config.on_init then
local status, err = pcall(config.on_init, client, result)
if not status then
@@ -488,43 +637,57 @@ function lsp.start_client(config)
end)
end
- local function unsupported_method(method)
- local msg = "server doesn't support "..method
- local _ = log.warn() and log.warn(msg)
- err_message(msg)
- return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
- end
-
- --- Checks capabilities before rpc.request-ing.
+ --@private
+ --- Sends a request to the server.
+ ---
+ --- This is a thin wrapper around {client.rpc.request} with some additional
+ --- checks for capabilities and callback availability.
+ ---
+ --@param method (string) LSP method name.
+ --@param params (table) LSP request params.
+ --@param callback (function, optional) Response handler for this method.
+ ---If {callback} is not specified, it will use {client.callbacks} to try to
+ ---find a callback. If one is not found there, then an error will occur.
+ --@param bufnr (number) Buffer handle (0 for current).
+ --@returns ({status}, [request_id]): {status} is a bool indicating
+ ---whether the request was successful. If it is `false`, then it will
+ ---always be `false` (the client has shutdown). If it was
+ ---successful, then it will return {request_id} as the
+ ---second result. You can use this with `client.cancel_request(request_id)`
+ ---to cancel the-request.
+ --@see |vim.lsp.buf_request()|
function client.request(method, params, callback, bufnr)
+ -- FIXME: callback is optional, but bufnr is apparently not? Shouldn't that
+ -- require a `select('#', ...)` call?
if not callback then
callback = resolve_callback(method)
or error(string.format("not found: %q request callback for client %q.", method, client.name))
end
local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback, bufnr)
- -- TODO keep these checks or just let it go anyway?
- if (not client.resolved_capabilities.hover and method == 'textDocument/hover')
- or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp')
- or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition')
- or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation')
- or (not client.resolved_capabilities.declaration and method == 'textDocument/declaration')
- or (not client.resolved_capabilities.type_definition and method == 'textDocument/typeDefinition')
- or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol')
- or (not client.resolved_capabilities.workspace_symbol and method == 'textDocument/workspaceSymbol')
- or (not client.resolved_capabilities.call_hierarchy and method == 'textDocument/prepareCallHierarchy')
- then
- callback(unsupported_method(method), method, nil, client_id, bufnr)
- return
- end
return rpc.request(method, params, function(err, result)
callback(err, method, result, client_id, bufnr)
end)
end
+ --@private
+ --- Sends a notification to an LSP server.
+ ---
+ --@param method (string) LSP method name.
+ --@param params (optional, table) LSP request params.
+ --@param bufnr (number) Buffer handle, or 0 for current.
+ --@returns {status} (bool) true if the notification was successful.
+ ---If it is false, then it will always be false
+ ---(the client has shutdown).
function client.notify(...)
return rpc.notify(...)
end
+ --@private
+ --- Cancels a request with a given request id.
+ ---
+ --@param id (number) id of request to cancel
+ --@returns true if any client returns true; false otherwise
+ --@see |vim.lsp.client.notify()|
function client.cancel_request(id)
validate{id = {id, 'n'}}
return rpc.notify("$/cancelRequest", { id = id })
@@ -533,6 +696,14 @@ function lsp.start_client(config)
-- Track this so that we can escalate automatically if we've alredy tried a
-- graceful shutdown
local tried_graceful_shutdown = false
+ --@private
+ --- Stops a client, optionally with force.
+ ---
+ ---By default, it will just ask the - server to shutdown without force. If
+ --- you request to stop a client which has previously been requested to
+ --- shutdown, it will automatically escalate and force shutdown.
+ ---
+ --@param force (bool, optional)
function client.stop(force)
local handle = rpc.handle
if handle:is_closing() then
@@ -554,10 +725,18 @@ function lsp.start_client(config)
end)
end
+ --@private
+ --- Checks whether a client is stopped.
+ ---
+ --@returns (bool) true if client is stopped or in the process of being
+ ---stopped; false otherwise
function client.is_stopped()
return rpc.handle:is_closing()
end
+ --@private
+ --- Runs the on_attach function from the client's config if it was defined.
+ --@param bufnr (number) Buffer number
function client._on_attach(bufnr)
text_document_did_open_handler(bufnr, client)
if config.on_attach then
@@ -571,6 +750,12 @@ function lsp.start_client(config)
return client_id
end
+--@private
+--- Memoizes a function. On first run, the function return value is saved and
+--- immediately returned on subsequent runs.
+---
+--@param fn (function) Function to run
+--@returns (function) Memoized function
local function once(fn)
local value
return function(...)
@@ -579,14 +764,21 @@ local function once(fn)
end
end
+--@private
+--@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size)
+--- Notify all attached clients that a buffer has changed.
local text_document_did_change_handler
do
local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; }
text_document_did_change_handler = function(_, bufnr, changedtick,
firstline, lastline, new_lastline, old_byte_size, old_utf32_size,
old_utf16_size)
- local _ = log.debug() and log.debug("on_lines", bufnr, changedtick, firstline,
- lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size, nvim_buf_get_lines(bufnr, firstline, new_lastline, true))
+
+ local _ = log.debug() and log.debug(
+ string.format("on_lines bufnr: %s, changedtick: %s, firstline: %s, lastline: %s, new_lastline: %s, old_byte_size: %s, old_utf32_size: %s, old_utf16_size: %s",
+ bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size),
+ nvim_buf_get_lines(bufnr, firstline, new_lastline, true)
+ )
-- Don't do anything if there are no clients attached.
if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then
@@ -730,14 +922,14 @@ function lsp.buf_is_attached(bufnr, client_id)
return (all_buffer_active_clients[bufnr] or {})[client_id] == true
end
---- Gets an active client by id, or nil if the id is invalid or the
---- client is not yet initialized.
----
+--- Gets a client by id, or nil if the id is invalid.
+--- The returned client may not yet be fully initialized.
+--
--@param client_id client id number
---
---@return |vim.lsp.client| object, or nil
+--@returns |vim.lsp.client| object, or nil
function lsp.get_client_by_id(client_id)
- return active_clients[client_id]
+ return active_clients[client_id] or uninitialized_clients[client_id]
end
--- Stops a client(s).
@@ -746,7 +938,7 @@ end
--- To stop all clients:
---
--- <pre>
---- vim.lsp.stop_client(lsp.get_active_clients())
+--- vim.lsp.stop_client(vim.lsp.get_active_clients())
--- </pre>
---
--- By default asks the server to shutdown, unless stop was requested
@@ -769,7 +961,7 @@ end
--- Gets all active clients.
---
---@return Table of |vim.lsp.client| objects
+--@returns Table of |vim.lsp.client| objects
function lsp.get_active_clients()
return vim.tbl_values(active_clients)
end
@@ -818,16 +1010,32 @@ function lsp.buf_request(bufnr, method, params, callback)
callback = { callback, 'f', true };
}
local client_request_ids = {}
- for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr)
- local request_success, request_id = client.request(method, params, callback, resolved_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
- client_request_ids[client_id] = request_id
+ local method_supported = false
+ for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr)
+ if client.supports_method(method) then
+ method_supported = true
+ local request_success, request_id = client.request(method, params, callback, resolved_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
+ client_request_ids[client_id] = request_id
+ end
end
end)
+ -- if no clients support the given method, call the callback with the proper
+ -- error message.
+ if not method_supported then
+ local unsupported_err = lsp._unsupported_method(method)
+ local cb = callback or lsp.callbacks[method]
+ if cb then
+ cb(unsupported_err, method, bufnr)
+ end
+ return
+ end
+
local function _cancel_all_requests()
for client_id, request_id in pairs(client_request_ids) do
local client = active_clients[client_id]
@@ -904,7 +1112,7 @@ end
--@param findstart 0 or 1, decides behavior
--@param base If findstart=0, text to match against
---
---@return (number) Decided by `findstart`:
+--@returns (number) Decided by `findstart`:
--- - findstart=0: column where the completion starts, or -2 or -3
--- - findstart=1: list of matches (actually just calls |complete()|)
function lsp.omnifunc(findstart, base)
@@ -948,6 +1156,10 @@ function lsp.omnifunc(findstart, base)
return -2
end
+---Checks whether a client is stopped.
+---
+--@param client_id (Number)
+--@returns true if client is stopped, false otherwise.
function lsp.client_is_stopped(client_id)
return active_clients[client_id] == nil
end
@@ -992,12 +1204,17 @@ function lsp.set_log_level(level)
end
--- Gets the path of the logfile used by the LSP client.
+--@returns (String) Path to logfile.
function lsp.get_log_path()
return log.get_filename()
end
--- Define the LspDiagnostics signs if they're not defined already.
+-- Defines the LspDiagnostics signs if they're not defined already.
do
+ --@private
+ --- Defines a sign if it isn't already defined.
+ --@param name (String) Name of the sign
+ --@param properties (table) Properties to attach to the sign
local function define_default_sign(name, properties)
if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
vim.fn.sign_define(name, properties)
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 2e27617997..c015884f5b 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -1,20 +1,45 @@
local vim = vim
local validate = vim.validate
-local api = vim.api
local vfn = vim.fn
local util = require 'vim.lsp.util'
-local list_extend = vim.list_extend
local M = {}
+--@private
+--- Returns nil if {status} is false or nil, otherwise returns the rest of the
+--- arguments.
local function ok_or_nil(status, ...)
if not status then return end
return ...
end
+
+--@private
+--- Swallows errors.
+---
+--@param fn Function to run
+--@param ... Function arguments
+--@returns Result of `fn(...)` if there are no errors, otherwise nil.
+--- Returns nil if errors occur during {fn}, otherwise returns
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
+--@private
+--- Sends an async request to all active clients attached to the current
+--- buffer.
+---
+--@param method (string) LSP method name
+--@param params (optional, table) Parameters to send to the server
+--@param callback (optional, functionnil) Handler
+-- `function(err, method, params, client_id)` for this request. Defaults
+-- to the client callback in `client.callbacks`. See |lsp-callbacks|.
+--
+--@returns 2-tuple:
+--- - Map of client-id:request-id pairs for all successful 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, callback)
validate {
method = {method, 's'};
@@ -23,9 +48,10 @@ local function request(method, params, callback)
return vim.lsp.buf_request(0, method, params, callback)
end
---- Sends a notification through all clients associated with current buffer.
---
---@return `true` if server responds.
+--- Checks whether the language servers attached to the current buffer are
+--- ready.
+---
+--@returns `true` if server responds.
function M.server_ready()
return not not vim.lsp.buf_notify(0, "window/progress", {})
end
@@ -74,6 +100,12 @@ end
--- Retrieves the completion items at the current cursor position. Can only be
--- called in Insert mode.
+---
+--@param context (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 |vim.lsp.protocol.constants.CompletionTriggerKind|
function M.completion(context)
local params = util.make_position_params()
params.context = context
@@ -82,64 +114,59 @@ end
--- Formats the current buffer.
---
---- The optional {options} table can be used to specify FormattingOptions, a
---- list of which is available at
---- https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting.
+--@param options (optional, table) Can be used to specify FormattingOptions.
--- Some unspecified options will be automatically derived from the current
--- Neovim options.
+--
+--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
function M.formatting(options)
local params = util.make_formatting_params(options)
return request('textDocument/formatting', params)
end
---- Perform |vim.lsp.buf.formatting()| synchronously.
+--- Performs |vim.lsp.buf.formatting()| synchronously.
---
--- Useful for running on save, to make sure buffer is formatted prior to being
---- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|.
+--- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|. Example:
+---
+--- <pre>
+--- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
+--- </pre>
+---
+--@param options Table with valid `FormattingOptions` entries
+--@param timeout_ms (number) Request timeout
function M.formatting_sync(options, timeout_ms)
local params = util.make_formatting_params(options)
local result = vim.lsp.buf_request_sync(0, "textDocument/formatting", params, timeout_ms)
if not result then return end
result = result[1].result
+ if not result then return end
vim.lsp.util.apply_text_edits(result)
end
+--- Formats a given range.
+---
+--@param options Table with valid `FormattingOptions` entries.
+--@param start_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the start of the last visual selection.
+--@param start_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the end of the last visual selection.
function M.range_formatting(options, start_pos, end_pos)
- validate {
- options = {options, 't', true};
- start_pos = {start_pos, 't', true};
- end_pos = {end_pos, 't', true};
- }
+ validate { options = {options, 't', true} }
local sts = vim.bo.softtabstop;
options = vim.tbl_extend('keep', options or {}, {
tabSize = (sts > 0 and sts) or (sts < 0 and vim.bo.shiftwidth) or vim.bo.tabstop;
insertSpaces = vim.bo.expandtab;
})
- local A = list_extend({}, start_pos or api.nvim_buf_get_mark(0, '<'))
- local B = list_extend({}, end_pos or api.nvim_buf_get_mark(0, '>'))
- -- convert to 0-index
- A[1] = A[1] - 1
- B[1] = B[1] - 1
- -- account for encoding.
- if A[2] > 0 then
- A = {A[1], util.character_offset(0, A[1], A[2])}
- end
- if B[2] > 0 then
- B = {B[1], util.character_offset(0, B[1], B[2])}
- end
- local params = {
- textDocument = { uri = vim.uri_from_bufnr(0) };
- range = {
- start = { line = A[1]; character = A[2]; };
- ["end"] = { line = B[1]; character = B[2]; };
- };
- options = options;
- }
+ local params = util.make_given_range_params(start_pos, end_pos)
+ params.options = options
return request('textDocument/rangeFormatting', params)
end
---- Renames all references to the symbol under the cursor. If {new_name} is not
---- provided, the user will be prompted for a new name using |input()|.
+--- Renames all references to the symbol under the cursor.
+---
+--@param new_name (string) If not provided, the user will be prompted for a new
+---name using |input()|.
function M.rename(new_name)
-- TODO(ashkan) use prepareRename
-- * result: [`Range`](#range) \| `{ range: Range, placeholder: string }` \| `null` describing the range of the string to rename and optionally a placeholder text of the string content to be renamed. If `null` is returned then it is deemed that a 'textDocument/rename' request is not valid at the given position.
@@ -152,6 +179,8 @@ end
--- Lists all the references to the symbol under the cursor in the quickfix window.
---
+--@param context (table) Context for the request
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
function M.references(context)
validate { context = { context, 't', true } }
local params = util.make_position_params()
@@ -169,6 +198,7 @@ function M.document_symbol()
request('textDocument/documentSymbol', params)
end
+--@private
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then return end
if #call_hierarchy_items == 1 then
@@ -186,6 +216,9 @@ local function pick_call_hierarchy_item(call_hierarchy_items)
return choice
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()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
@@ -194,6 +227,9 @@ function M.incoming_calls()
end)
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()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
@@ -204,9 +240,11 @@ end
--- Lists all symbols in the current workspace in the quickfix window.
---
---- The list is filtered against the optional argument {query};
---- if the argument is omitted from the call, the user is prompted to enter a string on the command line.
---- An empty string means no filtering is done.
+--- The list is filtered against {query}; if the argument is omitted from the
+--- call, the user is prompted to enter a string on the command line. An empty
+--- string means no filtering is done.
+---
+--@param query (string, optional)
function M.workspace_symbol(query)
query = query or npcall(vfn.input, "Query: ")
local params = {query = query}
@@ -227,10 +265,17 @@ function M.document_highlight()
request('textDocument/documentHighlight', params)
end
+--- Removes document highlights from current buffer.
+---
function M.clear_references()
util.buf_clear_references()
end
+--- Selects a code action from the input list that is available at the current
+--- cursor position.
+--
+--@param context: (table, optional) Valid `CodeActionContext` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
function M.code_action(context)
validate { context = { context, 't', true } }
context = context or { diagnostics = util.get_line_diagnostics() }
@@ -239,6 +284,25 @@ function M.code_action(context)
request('textDocument/codeAction', params)
end
+--- Performs |vim.lsp.buf.code_action()| for a given range.
+---
+--@param context: (table, optional) Valid `CodeActionContext` object
+--@param start_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the start of the last visual selection.
+--@param end_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the end of the last visual selection.
+function M.range_code_action(context, start_pos, end_pos)
+ validate { context = { context, 't', true } }
+ context = context or { diagnostics = util.get_line_diagnostics() }
+ local params = util.make_given_range_params(start_pos, end_pos)
+ params.context = context
+ request('textDocument/codeAction', params)
+end
+
+--- Executes an LSP server command.
+---
+--@param command A valid `ExecuteCommandParams` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
function M.execute_command(command)
validate {
command = { command.command, 's' },
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index 1ed58995d0..3270d1d2a9 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -7,17 +7,24 @@ local buf = require 'vim.lsp.buf'
local M = {}
+-- FIXME: DOC: Expose in vimdocs
+
+--@private
+--- Writes to error buffer.
+--@param ... (table of strings) Will be concatenated before being written
local function err_message(...)
api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
api.nvim_command("redraw")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
M['workspace/executeCommand'] = function(err, _)
if err then
error("Could not execute code action: "..err.message)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
M['textDocument/codeAction'] = function(_, _, actions)
if actions == nil or vim.tbl_isempty(actions) then
print("No code actions available")
@@ -51,6 +58,7 @@ M['textDocument/codeAction'] = function(_, _, actions)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
M['workspace/applyEdit'] = function(_, _, workspace_edit)
if not workspace_edit then return end
-- TODO(ashkan) Do something more with label?
@@ -64,6 +72,7 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
}
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_publishDiagnostics
M['textDocument/publishDiagnostics'] = function(_, _, result)
if not result then return end
local uri = result.uri
@@ -73,18 +82,6 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
return
end
- -- Unloaded buffers should not handle diagnostics.
- -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
- -- This should trigger another publish of the diagnostics.
- --
- -- In particular, this stops a ton of spam when first starting a server for current
- -- unloaded buffers.
- if not api.nvim_buf_is_loaded(bufnr) then
- return
- end
-
- util.buf_clear_diagnostics(bufnr)
-
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
-- The diagnostic's severity. Can be omitted. If omitted it is up to the
-- client to interpret diagnostics as error, warning, info or hint.
@@ -95,13 +92,30 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
end
end
+ util.buf_clear_diagnostics(bufnr)
+
+ -- Always save the diagnostics, even if the buf is not loaded.
+ -- Language servers may report compile or build errors via diagnostics
+ -- Users should be able to find these, even if they're in files which
+ -- are not loaded.
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
+
+ -- Unloaded buffers should not handle diagnostics.
+ -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
+ -- This should trigger another publish of the diagnostics.
+ --
+ -- In particular, this stops a ton of spam when first starting a server for current
+ -- unloaded buffers.
+ if not api.nvim_buf_is_loaded(bufnr) then
+ return
+ end
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
util.buf_diagnostics_signs(bufnr, result.diagnostics)
vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
M['textDocument/references'] = function(_, _, result)
if not result then return end
util.set_qflist(util.locations_to_items(result))
@@ -109,6 +123,13 @@ M['textDocument/references'] = function(_, _, result)
api.nvim_command("wincmd p")
end
+--@private
+--- Prints given list of symbols to the quickfix list.
+--@param _ (not used)
+--@param _ (not used)
+--@param result (list of Symbols) LSP method name
+--@param result (table) result of LSP method; a location or a list of locations.
+---(`textDocument/definition` can return `Location` or `Location[]`
local symbol_callback = function(_, _, result, _, bufnr)
if not result or vim.tbl_isempty(result) then return end
@@ -116,24 +137,30 @@ local symbol_callback = function(_, _, result, _, bufnr)
api.nvim_command("copen")
api.nvim_command("wincmd p")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
M['textDocument/documentSymbol'] = symbol_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
M['workspace/symbol'] = symbol_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
M['textDocument/rename'] = function(_, _, result)
if not result then return end
util.apply_workspace_edit(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
M['textDocument/rangeFormatting'] = function(_, _, result)
if not result then return end
util.apply_text_edits(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
M['textDocument/formatting'] = function(_, _, result)
if not result then return end
util.apply_text_edits(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
M['textDocument/completion'] = function(_, _, result)
if vim.tbl_isempty(result or {}) then return end
local row, col = unpack(api.nvim_win_get_cursor(0))
@@ -146,6 +173,7 @@ M['textDocument/completion'] = function(_, _, result)
vim.fn.complete(textMatch+1, matches)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
M['textDocument/hover'] = function(_, method, result)
util.focusable_float(method, function()
if not (result and result.contents) then
@@ -166,6 +194,12 @@ M['textDocument/hover'] = function(_, method, result)
end)
end
+--@private
+--- Jumps to a location. Used as a callback for multiple LSP methods.
+--@param _ (not used)
+--@param method (string) LSP method name
+--@param result (table) result of LSP method; a location or a list of locations.
+---(`textDocument/definition` can return `Location` or `Location[]`
local function location_callback(_, method, result)
if result == nil or vim.tbl_isempty(result) then
local _ = log.info() and log.info(method, 'No location found')
@@ -188,35 +222,49 @@ local function location_callback(_, method, result)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
M['textDocument/declaration'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
M['textDocument/definition'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
M['textDocument/typeDefinition'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
M['textDocument/implementation'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
M['textDocument/signatureHelp'] = function(_, method, result)
+ -- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp callback
+ -- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
+ if not (result and result.signatures and result.signatures[1]) then
+ print('No signature help available')
+ return
+ end
+ local lines = util.convert_signature_help_to_markdown_lines(result)
+ lines = util.trim_empty_lines(lines)
+ if vim.tbl_isempty(lines) then
+ print('No signature help available')
+ return
+ end
util.focusable_preview(method, function()
- if not (result and result.signatures and result.signatures[1]) then
- return { 'No signature available' }
- end
- -- TODO show popup when signatures is empty?
- local lines = util.convert_signature_help_to_markdown_lines(result)
- lines = util.trim_empty_lines(lines)
- if vim.tbl_isempty(lines) then
- return { 'No signature available' }
- end
return lines, util.try_trim_markdown_code_blocks(lines)
end)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
M['textDocument/documentHighlight'] = function(_, _, result, _)
if not result then return end
local bufnr = api.nvim_get_current_buf()
util.buf_highlight_references(bufnr, result)
end
--- direction is "from" for incoming calls and "to" for outgoing calls
+--@private
+---
+--- Displays call hierarchy in the quickfix window.
+---
+--@param direction `"from"` for incoming calls and `"to"` for outgoing calls
+--@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`,
+--@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`,
local make_call_hierarchy_callback = function(direction)
- -- result is a CallHierarchy{Incoming,Outgoing}Call[]
return function(_, _, result)
if not result then return end
local items = {}
@@ -237,10 +285,13 @@ local make_call_hierarchy_callback = function(direction)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls
M['callHierarchy/incomingCalls'] = make_call_hierarchy_callback('from')
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/outgoingCalls
M['callHierarchy/outgoingCalls'] = make_call_hierarchy_callback('to')
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/logMessage
M['window/logMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message
@@ -261,6 +312,7 @@ M['window/logMessage'] = function(_, _, result, client_id)
return result
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage
M['window/showMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 696ce43a59..587a65cd96 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -2,6 +2,9 @@
local log = {}
+-- FIXME: DOC
+-- Should be exposed in the vim docs.
+--
-- Log level dictionary with reverse lookup as well.
--
-- Can be used to lookup the number from the name or the name from the number.
@@ -21,12 +24,14 @@ local log_date_format = "%FT%H:%M:%S%z"
do
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
+ --@private
local function path_join(...)
return table.concat(vim.tbl_flatten{...}, path_sep)
end
local logfilename = path_join(vim.fn.stdpath('data'), 'lsp.log')
- --- Return the log filename.
+ --- Returns the log filename.
+ --@returns (string) log filename
function log.get_filename()
return logfilename
end
@@ -36,6 +41,9 @@ do
for level, levelnr in pairs(log.levels) do
-- Also export the log level on the root object.
log[level] = levelnr
+ -- FIXME: DOC
+ -- Should be exposed in the vim docs.
+ --
-- Set the lowercase name as the main use function.
-- If called without arguments, it will check whether the log level is
-- greater than or equal to this one. When called with arguments, it will
@@ -74,6 +82,8 @@ end
-- interfere with iterating the levels
vim.tbl_add_reverse_lookup(log.levels)
+--- Sets the current log level.
+--@param level (string or number) One of `vim.lsp.log.levels`
function log.set_level(level)
if type(level) == 'string' then
current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level))
@@ -84,8 +94,9 @@ function log.set_level(level)
end
end
--- Return whether the level is sufficient for logging.
--- @param level number log level
+--- Checks whether the level is sufficient for logging.
+--@param level number log level
+--@returns (bool) 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 ef5e08680e..2773f59b45 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -2,6 +2,11 @@
local protocol = {}
+--@private
+--- Returns {a} if it is not nil, otherwise returns {b}.
+---
+--@param a
+--@param b
local function ifnil(a, b)
if a == nil then return b end
return a
@@ -9,12 +14,14 @@ end
--[=[
--- Useful for interfacing with:
--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
+--@private
+--- Useful for interfacing with:
+--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
function transform_schema_comments()
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
end
+--@private
function transform_schema_to_table()
transform_schema_comments()
nvim.command [[silent! '<,'>s/: \S\+//]]
@@ -696,6 +703,10 @@ function protocol.make_client_capabilities()
};
hierarchicalDocumentSymbolSupport = true;
};
+ rename = {
+ dynamicRegistration = false;
+ prepareSupport = true;
+ };
};
workspace = {
symbol = {
@@ -907,6 +918,7 @@ function protocol.resolve_capabilities(server_capabilities)
return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync))
end
end
+ general_properties.completion = server_capabilities.completionProvider ~= nil
general_properties.hover = server_capabilities.hoverProvider or false
general_properties.goto_definition = server_capabilities.definitionProvider or false
general_properties.find_references = server_capabilities.referencesProvider or false
@@ -916,6 +928,15 @@ function protocol.resolve_capabilities(server_capabilities)
general_properties.document_formatting = server_capabilities.documentFormattingProvider or false
general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider or false
general_properties.call_hierarchy = server_capabilities.callHierarchyProvider or false
+ general_properties.execute_command = server_capabilities.executeCommandProvider ~= nil
+
+ if server_capabilities.renameProvider == nil then
+ general_properties.rename = false
+ elseif type(server_capabilities.renameProvider) == 'boolean' then
+ general_properties.rename = server_capabilities.renameProvider
+ else
+ general_properties.rename = true
+ end
if server_capabilities.codeActionProvider == nil then
general_properties.code_action = false
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 81c92bfe05..749a51fecc 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -5,6 +5,11 @@ local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
-- TODO replace with a better implementation.
+--@private
+--- Encodes to JSON.
+---
+--@param data (table) Data to encode
+--@returns (string) Encoded object
local function json_encode(data)
local status, result = pcall(vim.fn.json_encode, data)
if status then
@@ -13,6 +18,11 @@ local function json_encode(data)
return nil, result
end
end
+--@private
+--- Decodes from JSON.
+---
+--@param data (string) Data to decode
+--@returns (table) Decoded JSON object
local function json_decode(data)
local status, result = pcall(vim.fn.json_decode, data)
if status then
@@ -22,17 +32,26 @@ local function json_decode(data)
end
end
+--@private
+--- Checks whether a given path exists and is a directory.
+--@param filename (string) path to check
+--@returns (bool)
local function is_dir(filename)
local stat = vim.loop.fs_stat(filename)
return stat and stat.type == 'directory' or false
end
local NIL = vim.NIL
+--@private
+--- Returns its argument, but converts `vim.NIL` to Lua `nil`.
+--@param v (any) Argument
+--@returns (any)
local function convert_NIL(v)
if v == NIL then return nil end
return v
end
+--@private
--- Merges current process env with the given env and returns the result as
--- a list of "k=v" strings.
---
@@ -42,6 +61,8 @@ end
--- in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
--- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
--- </pre>
+--@param env (table) table of environment variable assignments
+--@returns (table) list of `"k=v"` strings
local function env_merge(env)
if env == nil then
return env
@@ -56,6 +77,11 @@ local function env_merge(env)
return final_env
end
+--@private
+--- Embeds the given string into a table and correctly computes `Content-Length`.
+---
+--@param encoded_message (string)
+--@returns (table) table containing encoded message and `Content-Length` attribute
local function format_message_with_content_length(encoded_message)
return table.concat {
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
@@ -63,8 +89,11 @@ local function format_message_with_content_length(encoded_message)
}
end
---- Parse an LSP Message's header
--- @param header: The header to parse.
+--@private
+--- Parses an LSP Message's header
+---
+--@param header: The header to parse.
+--@returns Parsed headers
local function parse_headers(header)
if type(header) ~= 'string' then
return nil
@@ -92,6 +121,8 @@ end
-- case insensitive pattern.
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
+--@private
+--- The actual workhorse.
local function request_parser_loop()
local buffer = ''
while true do
@@ -138,6 +169,10 @@ local client_errors = vim.tbl_add_reverse_lookup {
SERVER_RESULT_CALLBACK_ERROR = 7;
}
+--- Constructs an error message from an LSP error object.
+---
+--@param err (table) The error object
+--@returns (string) The formatted error message
local function format_rpc_error(err)
validate {
err = { err, 't' };
@@ -182,23 +217,69 @@ local function rpc_response_error(code, message, data)
end
local default_handlers = {}
+--@private
+--- Default handler for notifications sent to an LSP server.
+---
+--@param method (string) The invoked LSP method
+--@param params (table): Parameters for the invoked LSP method
function default_handlers.notification(method, params)
local _ = log.debug() and log.debug('notification', method, params)
end
+--@private
+--- Default handler for requests sent to an LSP server.
+---
+--@param method (string) The invoked LSP method
+--@param params (table): Parameters for the invoked LSP method
+--@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`.
function default_handlers.server_request(method, params)
local _ = log.debug() and log.debug('server_request', method, params)
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
+--@private
+--- Default handler for when a client exits.
+---
+--@param code (number): Exit code
+--@param signal (number): Number describing the signal used to terminate (if
+---any)
function default_handlers.on_exit(code, signal)
- local _ = log.info() and log.info("client exit", { code = code, signal = signal })
+ local _ = log.info() and log.info("client_exit", { code = code, signal = signal })
end
+--@private
+--- Default handler for client errors.
+---
+--@param code (number): Error code
+--@param err (any): Details about the error
+---any)
function default_handlers.on_error(code, err)
local _ = log.error() and log.error('client_error:', client_errors[code], err)
end
---- Create and start an RPC client.
--- @param cmd [
-local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_params)
+--- Starts an LSP server process and create an LSP RPC client object to
+--- interact with it.
+---
+--@param cmd (string) Command to start the LSP server.
+--@param cmd_args (table) List of additional string arguments to pass to {cmd}.
+--@param handlers (table, optional) Handlers for LSP message types. Valid
+---handler names are:
+--- - `"notification"`
+--- - `"server_request"`
+--- - `"on_error"`
+--- - `"on_exit"`
+--@param extra_spawn_params (table, optional) Additional context for the LSP
+--- server process. May contain:
+--- - {cwd} (string) Working directory for the LSP server process
+--- - {env} (table) Additional environment variables for LSP server process
+--@returns Client RPC object.
+---
+--@returns Methods:
+--- - `notify()` |vim.lsp.rpc.notify()|
+--- - `request()` |vim.lsp.rpc.request()|
+---
+--@returns Members:
+--- - {pid} (number) The LSP server's PID.
+--- - {handle} A handle for low-level interaction with the LSP server process
+--- |vim.loop|.
+local function start(cmd, cmd_args, handlers, extra_spawn_params)
local _ = log.info() and log.info("Starting RPC client", {cmd = cmd, args = cmd_args, extra = extra_spawn_params})
validate {
cmd = { cmd, 's' };
@@ -242,6 +323,11 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
local handle, pid
do
+ --@private
+ --- Callback for |vim.loop.spawn()| Closes all streams and runs the
+ --- `on_exit` handler.
+ --@param code (number) Exit code
+ --@param signal (number) Signal that was used to terminate (if any)
local function onexit(code, signal)
stdin:close()
stdout:close()
@@ -265,6 +351,12 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
handle, pid = uv.spawn(cmd, spawn_params, onexit)
end
+ --@private
+ --- Encodes {payload} into a JSON-RPC message and sends it to the remote
+ --- process.
+ ---
+ --@param payload (table) Converted into a JSON string, see |json_encode()|
+ --@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
local function encode_and_send(payload)
local _ = log.debug() and log.debug("rpc.send.payload", payload)
if handle:is_closing() then return false end
@@ -276,8 +368,14 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
return true
end
- local function send_notification(method, params)
- local _ = log.debug() and log.debug("rpc.notify", method, params)
+ -- FIXME: DOC: Should be placed on the RPC client object returned by
+ -- `start()`
+ --
+ --- Sends a notification to the LSP server.
+ --@param method (string) The invoked LSP method
+ --@param params (table): Parameters for the invoked LSP method
+ --@returns (bool) `true` if notification could be sent, `false` if not
+ local function notify(method, params)
return encode_and_send {
jsonrpc = "2.0";
method = method;
@@ -285,6 +383,8 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
}
end
+ --@private
+ --- sends an error object to the remote LSP process.
local function send_response(request_id, err, result)
return encode_and_send {
id = request_id;
@@ -294,7 +394,16 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
}
end
- local function send_request(method, params, callback)
+ -- FIXME: DOC: Should be placed on the RPC client object returned by
+ -- `start()`
+ --
+ --- Sends a request to the LSP server and runs {callback} upon response.
+ ---
+ --@param method (string) The invoked LSP method
+ --@param params (table) Parameters for the invoked LSP method
+ --@param callback (function) Callback to invoke
+ --@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not
+ local function request(method, params, callback)
validate {
callback = { callback, 'f' };
}
@@ -320,11 +429,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
end
end)
+ --@private
local function on_error(errkind, ...)
assert(client_errors[errkind])
-- TODO what to do if this fails?
pcall(handlers.on_error, errkind, ...)
end
+ --@private
local function pcall_handler(errkind, status, head, ...)
if not status then
on_error(errkind, head, ...)
@@ -332,6 +443,7 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
end
return status, head, ...
end
+ --@private
local function try_call(errkind, fn, ...)
return pcall_handler(errkind, pcall(fn, ...))
end
@@ -340,6 +452,7 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
-- time and log them. This would require storing the timestamp. I could call
-- them with an error then, perhaps.
+ --@private
local function handle_body(body)
local decoded, err = json_decode(body)
if not decoded then
@@ -381,10 +494,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
decoded.error = convert_NIL(decoded.error)
decoded.result = convert_NIL(decoded.result)
- -- Do not surface RequestCancelled to users, it is RPC-internal.
- if decoded.error
- and decoded.error.code == protocol.ErrorCodes.RequestCancelled then
- local _ = log.debug() and log.debug("Received cancellation ack", decoded)
+ -- Do not surface RequestCancelled or ContentModified to users, it is RPC-internal.
+ if decoded.error then
+ if decoded.error.code == protocol.ErrorCodes.RequestCancelled then
+ local _ = log.debug() and log.debug("Received cancellation ack", decoded)
+ elseif decoded.error.code == protocol.ErrorCodes.ContentModified then
+ local _ = log.debug() and log.debug("Received content modified ack", decoded)
+ end
local result_id = tonumber(decoded.id)
-- Clear any callback since this is cancelled now.
-- This is safe to do assuming that these conditions hold:
@@ -458,13 +574,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
return {
pid = pid;
handle = handle;
- request = send_request;
- notify = send_notification;
+ request = request;
+ notify = notify
}
end
return {
- start = create_and_start_client;
+ start = start;
rpc_response_error = rpc_response_error;
format_rpc_error = format_rpc_error;
client_errors = client_errors;
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 33fca29ecd..775932c7fd 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -7,6 +7,7 @@ local highlight = require 'vim.highlight'
local M = {}
+-- FIXME: DOC: Expose in vimdocs
--- Diagnostics received from the server via `textDocument/publishDiagnostics`
-- by buffer.
--
@@ -33,18 +34,30 @@ local M = {}
M.diagnostics_by_buf = {}
local split = vim.split
+--@private
local function split_lines(value)
return split(value, '\n', true)
end
+--@private
local function ok_or_nil(status, ...)
if not status then return end
return ...
end
+--@private
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
+--- Replaces text in a range with new text.
+---
+--- CAUTION: Changes in-place!
+---
+--@param lines (table) Original list of strings
+--@param A (table) Start position; a 2-tuple of {line, col} numbers
+--@param B (table) End position; a 2-tuple of {line, col} numbers
+--@param new_lines A list of strings to replace the original
+--@returns (table) The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
-- 0-indexing to 1-indexing
local i_0 = A[1] + 1
@@ -78,6 +91,7 @@ function M.set_lines(lines, A, B, new_lines)
return lines
end
+--@private
local function sort_by_key(fn)
return function(a,b)
local ka, kb = fn(a), fn(b)
@@ -91,13 +105,15 @@ local function sort_by_key(fn)
return false
end
end
+--@private
local edit_sort_key = sort_by_key(function(e)
return {e.A[1], e.A[2], e.i}
end)
+--@private
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
--- Returns a zero-indexed column, since set_lines() does the conversion to
--- 1-indexed
+--- Returns a zero-indexed column, since set_lines() does the conversion to
+--- 1-indexed
local function get_line_byte_from_position(bufnr, position)
-- LSP's line and characters are 0-indexed
-- Vim's line and columns are 1-indexed
@@ -114,6 +130,9 @@ local function get_line_byte_from_position(bufnr, position)
return col
end
+--- Applies a list of text edits to a buffer.
+--@param text_edits (table) list of `TextEdit` objects
+--@param buf_nr (number) Buffer id
function M.apply_text_edits(text_edits, bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
@@ -168,20 +187,30 @@ end
-- function M.glob_to_regex(glob)
-- end
--- textDocument/completion response returns one of CompletionItem[], CompletionList or null.
--- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
+--- Can be used to extract the completion items from a
+--- `textDocument/completion` request, which may return one of
+--- `CompletionItem[]`, `CompletionList` or null.
+--@param result (table) The result of a `textDocument/completion` request
+--@returns (table) List of completion items
+--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
function M.extract_completion_items(result)
if type(result) == 'table' and result.items then
+ -- result is a `CompletionList`
return result.items
elseif result ~= nil then
+ -- result is `CompletionItem[]`
return result
else
+ -- result is `null`
return {}
end
end
---- Apply the TextDocumentEdit response.
--- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `TextDocumentEdit`, which is a list of changes to a single
+-- document.
+---
+--@param text_document_edit (table) a `TextDocumentEdit` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
@@ -195,6 +224,13 @@ function M.apply_text_document_edit(text_document_edit)
M.apply_text_edits(text_document_edit.edits, bufnr)
end
+--@private
+--- Recursively parses snippets in a completion entry.
+---
+--@param input (string) Snippet text to parse for snippets
+--@param inner (bool) Whether this function is being called recursively
+--@returns 2-tuple of strings: The first is the parsed result, the second is the
+---unparsed rest of the input
local function parse_snippet_rec(input, inner)
local res = ""
@@ -248,25 +284,30 @@ local function parse_snippet_rec(input, inner)
return res, input
end
--- Parse completion entries, consuming snippet tokens
+--- Parses snippets in a completion entry.
+---
+--@param input (string) unparsed snippet
+--@returns (string) parsed snippet
function M.parse_snippet(input)
local res, _ = parse_snippet_rec(input, false)
return res
end
--- Sort by CompletionItem.sortText
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Sorts by CompletionItem.sortText.
+---
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function sort_completion_items(items)
- if items[1] and items[1].sortText then
- table.sort(items, function(a, b) return a.sortText < b.sortText
- end)
- end
+ table.sort(items, function(a, b)
+ return (a.sortText or a.label) < (b.sortText or b.label)
+ end)
end
--- Returns text that should be inserted when selecting completion item. The precedence is as follows:
--- textEdit.newText > insertText > label
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Returns text that should be inserted when selecting completion item. The
+--- precedence is as follows: textEdit.newText > insertText > label
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function get_completion_word(item)
if item.textEdit ~= nil and item.textEdit.newText ~= nil then
if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
@@ -284,8 +325,10 @@ local function get_completion_word(item)
return item.label
end
--- Some language servers return complementary candidates whose prefixes do not match are also returned.
--- So we exclude completion candidates whose prefix does not match.
+--@private
+--- Some language servers return complementary candidates whose prefixes do not
+--- match are also returned. So we exclude completion candidates whose prefix
+--- does not match.
local function remove_unmatch_completion_items(items, prefix)
return vim.tbl_filter(function(item)
local word = get_completion_word(item)
@@ -293,16 +336,26 @@ local function remove_unmatch_completion_items(items, prefix)
end, items)
end
--- Acording to LSP spec, if the client set "completionItemKind.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_completion
+--- Acording to LSP spec, if the client set `completionItemKind.valueSet`,
+--- the client must handle it properly even if it receives a value outside the
+--- specification.
+---
+--@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
+--@returns (`vim.lsp.protocol.completionItemKind`)
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
function M._get_completion_item_kind_name(completion_item_kind)
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
end
---- Getting vim complete-items with incomplete flag.
--- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
--- @return { matches = complete-items table, incomplete = boolean }
+--- Turns the result of a `textDocument/completion` request into vim-compatible
+--- |complete-items|.
+---
+--@param result The result of a `textDocument/completion` call, e.g. from
+---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`,
+--- `CompletionList` or `null`
+--@param prefix (string) the prefix to filter the completion items
+--@returns { matches = complete-items table, incomplete = bool }
+--@see |complete-items|
function M.text_document_completion_list_to_complete_items(result, prefix)
local items = M.extract_completion_items(result)
if vim.tbl_isempty(items) then
@@ -350,7 +403,10 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
return matches
end
--- @params WorkspaceEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `WorkspaceEdit`.
+---
+--@param workspace_edit (table) `WorkspaceEdit`
+-- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit)
if workspace_edit.documentChanges then
for _, change in ipairs(workspace_edit.documentChanges) do
@@ -375,9 +431,15 @@ function M.apply_workspace_edit(workspace_edit)
end
end
---- Convert any of MarkedString | MarkedString[] | MarkupContent into markdown text lines
--- see https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_hover
--- Useful for textDocument/hover, textDocument/signatureHelp, and potentially others.
+--- Converts any of `MarkedString` | `MarkedString[]` | `MarkupContent` into
+--- a list of lines containing valid markdown. Useful to populate the hover
+--- window for `textDocument/hover`, for parsing the result of
+--- `textDocument/signatureHelp`, and potentially others.
+---
+--@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
+--@param contents (table, optional, default `{}`) List of strings to extend with converted lines
+--@returns {contents}, 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)
contents = contents or {}
-- MarkedString variation 1
@@ -416,8 +478,11 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
---- Convert SignatureHelp response to markdown lines.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
+--- Converts `textDocument/SignatureHelp` response to markdown lines.
+---
+--@param signature_help Response of `textDocument/SignatureHelp`
+--@returns list of lines of converted markdown.
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help)
if not signature_help.signatures then
return
@@ -427,7 +492,10 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
--=== 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_signature = signature_help.activeSignature or 0
+ local active_signature = signature_help.activeSignature
+ if active_signature == vim.NIL or active_signature == nil then
+ active_signature = 0
+ end
-- If the activeSignature is not inside the valid range, then clip it.
if active_signature >= #signature_help.signatures then
active_signature = 0
@@ -440,13 +508,13 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
if signature.documentation then
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
- if signature_help.parameters then
+ if signature.parameters and #signature.parameters > 0 then
local active_parameter = signature_help.activeParameter or 0
-- If the activeParameter is not inside the valid range, then clip it.
- if active_parameter >= #signature_help.parameters then
+ if active_parameter >= #signature.parameters then
active_parameter = 0
end
- local parameter = signature.parameters and signature.parameters[active_parameter]
+ local parameter = signature.parameters[active_parameter + 1]
if parameter then
--[=[
--Represents a parameter of a callable-signature. A parameter can
@@ -467,14 +535,21 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
}
--]=]
-- TODO highlight parameter
- if parameter.documentation then
- M.convert_input_help_to_markdown_lines(parameter.documentation, contents)
+ if parameter.documentation and parameter.documentation ~= vim.NIL then
+ M.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
end
return contents
end
+--- Creates a table with sensible default options for a floating window. The
+--- table can be passed to |nvim_open_win()|.
+---
+--@param width (number) window width (in character cells)
+--@param height (number) window height (in character cells)
+--@param opts (table, optional)
+--@returns (table) Options
function M.make_floating_popup_options(width, height, opts)
validate {
opts = { opts, 't', true };
@@ -520,6 +595,10 @@ function M.make_floating_popup_options(width, height, opts)
}
end
+--- Jumps to a location.
+---
+--@param location (`Location`|`LocationLink`)
+--@returns `true` if the jump succeeded
function M.jump_to_location(location)
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
@@ -543,14 +622,14 @@ function M.jump_to_location(location)
return true
end
---- Preview a location in a floating windows
+--- Previews a location in a floating window
---
--- behavior depends on type of location:
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location a single Location or LocationLink
---@return bufnr,winnr buffer and window number of floating window or nil
+--@param location a single `Location` or `LocationLink`
+--@returns (bufnr,winnr) buffer and window number of floating window or nil
function M.preview_location(location)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -565,6 +644,7 @@ function M.preview_location(location)
return M.open_floating_preview(contents, filetype)
end
+--@private
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
@@ -573,19 +653,25 @@ local function find_window_by_var(name, value)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return bufnr, winnr
--- case that a new floating window should be created.
+--- Enters/leaves the focusable window associated with the current buffer via the
+--window - variable `unique_name`. If no such window exists, run the function
+--{fn}.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) should return create a new window and return a tuple of
+---({focusable_buffer_id}, {window_id}). if {focusable_buffer_id} is a valid
+---buffer id, the newly created window will be the new focus associated with
+---the current buffer via the tag `unique_name`.
+--@returns (pbufnr, pwinnr) if `fn()` has created a new window; nil otherwise
function M.focusable_float(unique_name, fn)
+ -- Go back to previous window if we are in a focusable one
if npcall(api.nvim_win_get_var, 0, unique_name) then
return api.nvim_command("wincmd p")
end
local bufnr = api.nvim_get_current_buf()
do
local win = find_window_by_var(unique_name, bufnr)
- if win then
+ if win and api.nvim_win_is_valid(win) and not vim.fn.pumvisible() then
api.nvim_set_current_win(win)
api.nvim_command("stopinsert")
return
@@ -598,18 +684,21 @@ function M.focusable_float(unique_name, fn)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return values will be passed directly to open_floating_preview in the
--- case that a new floating window should be created.
+--- Focuses/unfocuses the floating preview window associated with the current
+--- buffer via the window variable `unique_name`. If no such preview window
+--- exists, makes a new one.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) The return values of this function will be passed
+---directly to |vim.lsp.util.open_floating_preview()|, in the case that a new
+---floating window should be created
function M.focusable_preview(unique_name, fn)
return M.focusable_float(unique_name, function()
return M.open_floating_preview(fn())
end)
end
---- Trim empty lines from input and pad left and right with spaces
+--- Trims empty lines from input and pad left and right with spaces
---
--@param contents table of lines to trim and pad
--@param opts dictionary with optional fields
@@ -617,7 +706,7 @@ end
-- - pad_right number of columns to pad contents at right (default 1)
-- - pad_top number of lines to pad contents at top (default 0)
-- - pad_bottom number of lines to pad contents at bottom (default 0)
---@return contents table of trimmed and padded lines
+--@returns contents table of trimmed and padded lines
function M._trim_and_pad(contents, opts)
validate {
contents = { contents, 't' };
@@ -645,12 +734,13 @@ end
---- Convert markdown into syntax highlighted regions by stripping the code
+-- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--
+--- Converts markdown into syntax highlighted regions by stripping the code
--- blocks and converting them into highlighted code.
--- This will by default insert a blank line separator after those code block
--- regions to improve readability.
---- The result is shown in a floating preview
---- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--- The result is shown in a floating preview.
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -664,7 +754,7 @@ end
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
-- - separator insert separator after code block
---@return width,height size of float
+--@returns width,height size of float
function M.fancy_floating_markdown(contents, opts)
validate {
contents = { contents, 't' };
@@ -713,13 +803,14 @@ function M.fancy_floating_markdown(contents, opts)
local width, height = M._make_floating_popup_size(stripped, opts)
-- Insert blank line separator after code block
- local insert_separator = opts.separator or true
+ local insert_separator = opts.separator
+ if insert_separator == nil then insert_separator = true end
if insert_separator then
for i, h in ipairs(highlights) do
h.start = h.start + i - 1
h.finish = h.finish + i - 1
if h.finish + 1 <= #stripped then
- table.insert(stripped, h.finish + 1, string.rep("โ”€", width))
+ table.insert(stripped, h.finish + 1, string.rep("โ”€", math.min(width, opts.wrap_at or width)))
height = height + 1
end
end
@@ -738,6 +829,7 @@ function M.fancy_floating_markdown(contents, opts)
vim.cmd("ownsyntax markdown")
local idx = 1
+ --@private
local function apply_syntax_to_region(ft, start, finish)
if ft == '' then return end
local name = ft..idx
@@ -763,11 +855,17 @@ function M.fancy_floating_markdown(contents, opts)
return bufnr, winnr
end
+--- Creates autocommands to close a preview window when events happen.
+---
+--@param events (table) list of events
+--@param winnr (number) window id of preview window
+--@see |autocmd-events|
function M.close_preview_autocmd(events, winnr)
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
end
---- Compute size of float needed to show contents (with optional wrapping)
+--@internal
+--- Computes size of float needed to show contents (with optional wrapping)
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -776,7 +874,7 @@ end
-- - wrap_at character to wrap at for computing height
-- - max_width maximal width of floating window
-- - max_height maximal height of floating window
---@return width,height size of float
+--@returns width,height size of float
function M._make_floating_popup_size(contents, opts)
validate {
contents = { contents, 't' };
@@ -827,7 +925,7 @@ function M._make_floating_popup_size(contents, opts)
return width, height
end
---- Show contents in a floating window
+--- Shows contents in a floating window.
---
--@param contents table of lines to show in window
--@param filetype string of filetype to set for opened buffer
@@ -841,7 +939,8 @@ end
-- - pad_right number of columns to pad contents at right
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
---@return bufnr,winnr buffer and window number of floating window or nil
+--@returns bufnr,winnr buffer and window number of the newly created floating
+---preview window
function M.open_floating_preview(contents, filetype, opts)
validate {
contents = { contents, 't' };
@@ -912,6 +1011,9 @@ do
severity_floating_highlights[severity] = floating_highlight_name
end
+ --- Clears diagnostics for a buffer.
+ ---
+ --@param bufnr (number) buffer id
function M.buf_clear_diagnostics(bufnr)
validate { bufnr = {bufnr, 'n', true} }
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
@@ -923,10 +1025,18 @@ do
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
end
+ --- Gets the name of a severity's highlight group.
+ ---
+ --@param severity A member of `vim.lsp.protocol.DiagnosticSeverity`
+ --@returns (string) Highlight group name
function M.get_severity_highlight_name(severity)
return severity_highlights[severity]
end
+ --- Gets list of diagnostics for the current line.
+ ---
+ --@returns (table) list of `Diagnostic` tables
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.get_line_diagnostics()
local bufnr = api.nvim_get_current_buf()
local linenr = api.nvim_win_get_cursor(0)[1] - 1
@@ -941,6 +1051,8 @@ do
return diagnostics_by_line[linenr] or {}
end
+ --- Displays the diagnostics for the current line in a floating hover
+ --- window.
function M.show_line_diagnostics()
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
-- if #marks == 0 then
@@ -977,10 +1089,10 @@ do
return popup_bufnr, winnr
end
- --- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ --- Saves diagnostics into vim.lsp.util.diagnostics_by_buf[{bufnr}].
---
- --@param bufnr bufnr for which the diagnostics are for.
- --@param diagnostics Diagnostics[] received from the language server.
+ --@param bufnr (number) buffer id for which the diagnostics are for
+ --@param diagnostics list of `Diagnostic`s received from the LSP server
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
validate {
bufnr = {bufnr, 'n', true};
@@ -1000,6 +1112,10 @@ do
M.diagnostics_by_buf[bufnr] = diagnostics
end
+ --- Highlights a list of diagnostics in a buffer by underlining them.
+ ---
+ --@param bufnr (number) buffer id
+ --@param diagnostics (list of `Diagnostic`s)
function M.buf_diagnostics_underline(bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range["start"]
@@ -1020,11 +1136,18 @@ do
end
end
+ --- Removes document highlights from a buffer.
+ ---
+ --@param bufnr buffer id
function M.buf_clear_references(bufnr)
validate { bufnr = {bufnr, 'n', true} }
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
end
+ --- Shows a list of document highlights for a certain buffer.
+ ---
+ --@param bufnr buffer id
+ --@param references List of `DocumentHighlight` objects to highlight
function M.buf_highlight_references(bufnr, references)
validate { bufnr = {bufnr, 'n', true} }
for _, reference in ipairs(references) do
@@ -1040,11 +1163,19 @@ do
end
end
+ --- Groups a list of diagnostics by line.
+ ---
+ --@param diagnostics (table) list of `Diagnostic`s
+ --@returns (table) dictionary mapping lines to lists of diagnostics valid on
+ ---those lines
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.diagnostics_group_by_line(diagnostics)
if not diagnostics then return end
local diagnostics_by_line = {}
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range.start
+ -- TODO: Are diagnostics only valid for a single line? I don't understand
+ -- why this would be okay otherwise
local line_diagnostics = diagnostics_by_line[start.line]
if not line_diagnostics then
line_diagnostics = {}
@@ -1055,6 +1186,11 @@ do
return diagnostics_by_line
end
+ --- Given a list of diagnostics, sets the corresponding virtual text for a
+ --- buffer.
+ ---
+ --@param bufnr buffer id
+ --@param diagnostics (table) list of `Diagnostic`s
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
if not diagnostics then
return
@@ -1093,8 +1229,7 @@ do
--- </pre>
---
--@param kind Diagnostic severity kind: See |vim.lsp.protocol.DiagnosticSeverity|
- ---
- --@return Count of diagnostics
+ --@returns Count of diagnostics
function M.buf_diagnostics_count(kind)
local bufnr = vim.api.nvim_get_current_buf()
local diagnostics = M.diagnostics_by_buf[bufnr]
@@ -1115,7 +1250,7 @@ do
[protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
}
- --- Place signs for each diagnostic in the sign column.
+ --- Places signs for each diagnostic in the sign column.
---
--- Sign characters can be customized with the following commands:
---
@@ -1136,8 +1271,11 @@ local position_sort = sort_by_key(function(v)
return {v.start.line, v.start.character}
end)
--- Returns the items with the byte position calculated correctly and in sorted
--- order.
+--- Returns the items with the byte position calculated correctly and in sorted
+--- order, for display in quickfix and location lists.
+---
+--@param locations (table) list of `Location`s or `LocationLink`s
+--@returns (table) list of items
function M.locations_to_items(locations)
local items = {}
local grouped = setmetatable({}, {
@@ -1180,6 +1318,10 @@ function M.locations_to_items(locations)
return items
end
+--- Fills current window's location list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_loclist(items)
vim.fn.setloclist(0, {}, ' ', {
title = 'Language Server';
@@ -1187,6 +1329,10 @@ function M.set_loclist(items)
})
end
+--- Fills quickfix list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_qflist(items)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
@@ -1201,10 +1347,11 @@ function M._get_symbol_kind_name(symbol_kind)
return protocol.SymbolKind[symbol_kind] or "Unknown"
end
---- Convert symbols to quickfix list items
+--- Converts symbols to quickfix list items.
---
--@param symbols DocumentSymbol[] or SymbolInformation[]
function M.symbols_to_items(symbols, bufnr)
+ --@private
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do
if symbol.location then -- SymbolInformation type
@@ -1239,7 +1386,9 @@ function M.symbols_to_items(symbols, bufnr)
return _symbols_to_items(symbols, {}, bufnr)
end
--- Remove empty lines from the beginning and end.
+--- Removes empty lines from the beginning and end.
+--@param lines (table) list of lines to trim
+--@returns (table) trimmed list of lines
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
@@ -1258,11 +1407,13 @@ function M.trim_empty_lines(lines)
return vim.list_extend({}, lines, start, finish)
end
--- Accepts markdown lines and tries to reduce it to a filetype if it is
--- just a single code block.
--- Note: This modifies the input.
---
--- Returns: filetype or 'markdown' if it was unchanged.
+--- Accepts markdown lines and tries to reduce them to a filetype if they
+--- comprise just a single code block.
+---
+--- CAUTION: Modifies the input in-place!
+---
+--@param lines (table) list of lines
+--@returns (string) filetype or 'markdown' if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match("^```(.*)")
if language_id then
@@ -1285,14 +1436,22 @@ function M.try_trim_markdown_code_blocks(lines)
end
local str_utfindex = vim.str_utfindex
+--@private
local function make_position_param()
local row, col = unpack(api.nvim_win_get_cursor(0))
row = row - 1
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
+ if not line then
+ return { line = 0; character = 0; }
+ end
col = str_utfindex(line, col)
return { line = row; character = col; }
end
+--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
+---
+--@returns `TextDocumentPositionParams` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params()
return {
textDocument = M.make_text_document_params();
@@ -1300,19 +1459,65 @@ function M.make_position_params()
}
end
+--- Using the current position in the current buffer, creates an object that
+--- can be used as a building block for several LSP requests, such as
+--- `textDocument/codeAction`, `textDocument/colorPresentation`,
+--- `textDocument/rangeFormatting`.
+---
+--@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---`current_position`, end = `current_position` } }
function M.make_range_params()
local position = make_position_param()
return {
- textDocument = { uri = vim.uri_from_bufnr(0) },
+ textDocument = M.make_text_document_params(),
range = { start = position; ["end"] = position; }
}
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 ({number, number}, optional) mark-indexed position.
+---Defaults to the start of the last visual selection.
+--@param end_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the end of the last visual selection.
+--@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---`start_position`, end = `end_position` } }
+function M.make_given_range_params(start_pos, end_pos)
+ validate {
+ start_pos = {start_pos, 't', true};
+ end_pos = {end_pos, 't', true};
+ }
+ local A = list_extend({}, start_pos or api.nvim_buf_get_mark(0, '<'))
+ local B = list_extend({}, end_pos or api.nvim_buf_get_mark(0, '>'))
+ -- convert to 0-index
+ A[1] = A[1] - 1
+ B[1] = B[1] - 1
+ -- account for encoding.
+ if A[2] > 0 then
+ A = {A[1], M.character_offset(0, A[1], A[2])}
+ end
+ if B[2] > 0 then
+ B = {B[1], M.character_offset(0, B[1], B[2])}
+ end
+ return {
+ textDocument = M.make_text_document_params(),
+ range = {
+ start = {line = A[1], character = A[2]},
+ ['end'] = {line = B[1], character = B[2]}
+ }
+ }
+end
+
+--- Creates a `TextDocumentIdentifier` object for the current buffer.
+---
+--@returns `TextDocumentIdentifier`
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params()
return { uri = vim.uri_from_bufnr(0) }
end
---- Get visual width of tabstop.
+--- Returns visual width of tabstop.
---
--@see |softtabstop|
--@param bufnr (optional, number): Buffer handle, defaults to current
@@ -1324,6 +1529,11 @@ function M.get_effective_tabstop(bufnr)
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
end
+--- Creates a `FormattingOptions` object for the current buffer and cursor position.
+---
+--@param options Table with valid `FormattingOptions` entries
+--@returns `FormattingOptions 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} }
options = vim.tbl_extend('keep', options or {}, {
@@ -1336,9 +1546,12 @@ function M.make_formatting_params(options)
}
end
--- @param buf buffer handle or 0 for current.
--- @param row 0-indexed line
--- @param col 0-indexed byte offset in line
+--- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
+---
+--@param buf buffer id (0 for current)
+--@param row 0-indexed line
+--@param col 0-indexed byte offset in line
+--@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col)
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
-- If the col is past the EOL, use the line length.
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 6e427665f2..995c52e8ed 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -190,10 +190,10 @@ function vim.tbl_contains(t, value)
return false
end
--- Returns true if the table is empty, and contains no indexed or keyed values.
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
+--- Checks if a table is empty.
+---
+--@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---
--@param t Table to check
function vim.tbl_isempty(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
@@ -347,13 +347,11 @@ function vim.tbl_flatten(t)
return result
end
---- Determine whether a Lua table can be treated as an array.
+--- Tests if a Lua table can be treated as an array.
---
---- An empty table `{}` will default to being treated as an array.
---- Use `vim.emtpy_dict()` to create a table treated as an
---- empty dict. Empty tables returned by `rpcrequest()` and
---- `vim.fn` functions can be checked using this function
---- whether they represent empty API arrays and vimL lists.
+--- Empty table `{}` is assumed to be an array, unless it was created by
+--- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
+--- for example from |rpcrequest()| or |vim.fn|.
---
--@param t Table
--@returns `true` if array-like table, else `false`.
@@ -479,48 +477,77 @@ end
--- 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
+--- 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
function vim.validate(opt) end -- luacheck: no unused
-vim.validate = (function()
+
+do
local type_names = {
- t='table', s='string', n='number', b='boolean', f='function', c='callable',
- ['table']='table', ['string']='string', ['number']='number',
- ['boolean']='boolean', ['function']='function', ['callable']='callable',
- ['nil']='nil', ['thread']='thread', ['userdata']='userdata',
+ ['table'] = 'table', t = 'table',
+ ['string'] = 'string', s = 'string',
+ ['number'] = 'number', n = 'number',
+ ['boolean'] = 'boolean', b = 'boolean',
+ ['function'] = 'function', f = 'function',
+ ['callable'] = 'callable', c = 'callable',
+ ['nil'] = 'nil',
+ ['thread'] = 'thread',
+ ['userdata'] = 'userdata',
}
- local function _type_name(t)
- local tname = type_names[t]
- if tname == nil then
- error(string.format('invalid type name: %s', tostring(t)))
- end
- return tname
- end
+
local function _is_type(val, t)
return t == 'callable' and vim.is_callable(val) or type(val) == t
end
- return function(opt)
- assert(type(opt) == 'table', string.format('opt: expected table, got %s', type(opt)))
+ local function is_valid(opt)
+ if type(opt) ~= 'table' then
+ return false, string.format('opt: expected table, got %s', type(opt))
+ end
+
for param_name, spec in pairs(opt) do
- assert(type(spec) == 'table', string.format('%s: expected table, got %s', param_name, type(spec)))
+ if type(spec) ~= 'table' then
+ return false, string.format('opt[%s]: expected table, got %s', param_name, type(spec))
+ end
local val = spec[1] -- Argument value.
local t = spec[2] -- Type name, or callable.
local optional = (true == spec[3])
- if not vim.is_callable(t) then -- Check type name.
- if (not optional or val ~= nil) and not _is_type(val, _type_name(t)) then
- error(string.format("%s: expected %s, got %s", param_name, _type_name(t), type(val)))
+ if type(t) == 'string' then
+ local t_name = type_names[t]
+ if not t_name then
+ return false, string.format('invalid type name: %s', t)
+ end
+
+ if (not optional or val ~= nil) and not _is_type(val, t_name) then
+ return false, string.format("%s: expected %s, got %s", param_name, t_name, type(val))
end
- elseif not t(val) then -- Check user-provided validation function.
- error(string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val))
+ elseif vim.is_callable(t) then
+ -- Check user-provided validation function.
+ local valid, optional_message = t(val)
+ if not valid then
+ local error_message = string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val)
+ if optional_message ~= nil then
+ error_message = error_message .. string.format(". Info: %s", optional_message)
+ end
+
+ return false, error_message
+ end
+ else
+ return false, string.format("invalid type name: %s", tostring(t))
end
end
- return true
+
+ return true, nil
end
-end)()
+ function vim.validate(opt)
+ local ok, err_msg = is_valid(opt)
+ if not ok then
+ error(debug.traceback(err_msg, 2), 2)
+ end
+ end
+end
--- Returns true if object `f` can be called as a function.
---
--@param f Any object
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 927456708c..0de3388356 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -1,4 +1,6 @@
local a = vim.api
+local query = require'vim.treesitter.query'
+local language = require'vim.treesitter.language'
-- TODO(bfredl): currently we retain parsers for the lifetime of the buffer.
-- Consider use weak references to release parser if all plugins are done with
@@ -8,12 +10,20 @@ local parsers = {}
local Parser = {}
Parser.__index = Parser
+--- Parses the buffer if needed and returns a tree.
+--
+-- Calling this will call the on_changedtree callbacks if the tree has changed.
+--
+-- @returns An up to date tree
+-- @returns If the tree changed with this call, the changed ranges
function Parser:parse()
if self.valid then
return self.tree
end
local changes
- self.tree, changes = self._parser:parse_buf(self.bufnr)
+
+ self.tree, changes = self._parser:parse(self:input_source())
+
self.valid = true
if not vim.tbl_isempty(changes) then
@@ -25,61 +35,86 @@ function Parser:parse()
return self.tree, changes
end
-function Parser:_on_lines(bufnr, changed_tick, start_row, old_stop_row, stop_row, old_byte_size)
- local start_byte = a.nvim_buf_get_offset(bufnr,start_row)
- local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row)
- local old_stop_byte = start_byte + old_byte_size
- self._parser:edit(start_byte,old_stop_byte,stop_byte,
- start_row,0,old_stop_row,0,stop_row,0)
+function Parser:input_source()
+ return self.bufnr or self.str
+end
+
+function Parser:_on_bytes(bufnr, changed_tick,
+ start_row, start_col, start_byte,
+ old_row, old_col, old_byte,
+ new_row, new_col, new_byte)
+ local old_end_col = old_col + ((old_row == 0) and start_col or 0)
+ local new_end_col = new_col + ((new_row == 0) and start_col or 0)
+ self._parser:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
+ start_row, start_col,
+ start_row+old_row, old_end_col,
+ start_row+new_row, new_end_col)
self.valid = false
- for _, cb in ipairs(self.lines_cbs) do
- cb(bufnr, changed_tick, start_row, old_stop_row, stop_row, old_byte_size)
+ for _, cb in ipairs(self.bytes_cbs) do
+ cb(bufnr, changed_tick,
+ start_row, start_col, start_byte,
+ old_row, old_col, old_byte,
+ new_row, new_col, new_byte)
end
end
+--- Registers callbacks for the parser
+-- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
+-- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
+-- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
+-- it will only be passed one argument, that is a table of the ranges (as node ranges) that
+-- changed.
+function Parser:register_cbs(cbs)
+ if not cbs then return end
+
+ if cbs.on_changedtree then
+ table.insert(self.changedtree_cbs, cbs.on_changedtree)
+ end
+
+ if cbs.on_bytes then
+ table.insert(self.bytes_cbs, cbs.on_bytes)
+ end
+end
+
+--- Sets the included ranges for the current parser
+--
+-- @param ranges A table of nodes that will be used as the ranges the parser should include.
function Parser:set_included_ranges(ranges)
self._parser:set_included_ranges(ranges)
-- The buffer will need to be parsed again later
self.valid = false
end
-local M = {
- parse_query = vim._ts_parse_query,
-}
+--- Gets the included ranges for the parsers
+function Parser:included_ranges()
+ return self._parser:included_ranges()
+end
+
+local M = vim.tbl_extend("error", query, language)
setmetatable(M, {
__index = function (t, k)
if k == "TSHighlighter" then
- t[k] = require'vim.tshighlighter'
+ a.nvim_err_writeln("vim.TSHighlighter is deprecated, please use vim.treesitter.highlighter")
+ t[k] = require'vim.treesitter.highlighter'
+ return t[k]
+ elseif k == "highlighter" then
+ t[k] = require'vim.treesitter.highlighter'
return t[k]
end
end
})
-function M.require_language(lang, path)
- if vim._ts_has_language(lang) then
- return true
- end
- if path == nil then
- local fname = 'parser/' .. lang .. '.*'
- local paths = a.nvim_get_runtime_file(fname, false)
- if #paths == 0 then
- -- TODO(bfredl): help tag?
- error("no parser for '"..lang.."' language")
- end
- path = paths[1]
- end
- vim._ts_add_language(path, lang)
-end
-
-function M.inspect_language(lang)
- M.require_language(lang)
- return vim._ts_inspect_language(lang)
-end
-
-function M.create_parser(bufnr, lang, id)
- M.require_language(lang)
+--- Creates a new parser.
+--
+-- It is not recommended to use this, use vim.treesitter.get_parser() instead.
+--
+-- @param bufnr The buffer the parser will be tied to
+-- @param lang The language of the parser.
+-- @param id The id the parser will have
+function M._create_parser(bufnr, lang, id)
+ language.require_language(lang)
if bufnr == 0 then
bufnr = a.nvim_get_current_buf()
end
@@ -89,12 +124,12 @@ function M.create_parser(bufnr, lang, id)
local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser)
self._parser = vim._create_ts_parser(lang)
self.changedtree_cbs = {}
- self.lines_cbs = {}
+ self.bytes_cbs = {}
self:parse()
-- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is
-- using it.
- local function lines_cb(_, ...)
- return self:_on_lines(...)
+ local function bytes_cb(_, ...)
+ return self:_on_bytes(...)
end
local detach_cb = nil
if id ~= nil then
@@ -104,157 +139,50 @@ function M.create_parser(bufnr, lang, id)
end
end
end
- a.nvim_buf_attach(self.bufnr, false, {on_lines=lines_cb, on_detach=detach_cb})
+ a.nvim_buf_attach(self.bufnr, false, {on_bytes=bytes_cb, on_detach=detach_cb})
return self
end
-function M.get_parser(bufnr, ft, buf_attach_cbs)
+--- Gets the parser for this bufnr / ft combination.
+--
+-- If needed this will create the parser.
+-- Unconditionnally attach the provided callback
+--
+-- @param bufnr The buffer the parser should be tied to
+-- @param ft The filetype of this parser
+-- @param buf_attach_cbs See Parser:register_cbs
+--
+-- @returns The parser
+function M.get_parser(bufnr, lang, buf_attach_cbs)
if bufnr == nil or bufnr == 0 then
bufnr = a.nvim_get_current_buf()
end
- if ft == nil then
- ft = a.nvim_buf_get_option(bufnr, "filetype")
+ if lang == nil then
+ lang = a.nvim_buf_get_option(bufnr, "filetype")
end
- local id = tostring(bufnr)..'_'..ft
+ local id = tostring(bufnr)..'_'..lang
if parsers[id] == nil then
- parsers[id] = M.create_parser(bufnr, ft, id)
- end
-
- if buf_attach_cbs and buf_attach_cbs.on_changedtree then
- table.insert(parsers[id].changedtree_cbs, buf_attach_cbs.on_changedtree)
+ parsers[id] = M._create_parser(bufnr, lang, id)
end
- if buf_attach_cbs and buf_attach_cbs.on_lines then
- table.insert(parsers[id].lines_cbs, buf_attach_cbs.on_lines)
- end
+ parsers[id]:register_cbs(buf_attach_cbs)
return parsers[id]
end
--- query: pattern matching on trees
--- predicate matching is implemented in lua
-local Query = {}
-Query.__index = Query
+function M.get_string_parser(str, lang)
+ vim.validate {
+ str = { str, 'string' },
+ lang = { lang, 'string' }
+ }
+ language.require_language(lang)
-local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true}
-local function check_magic(str)
- if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then
- return str
- end
- return '\\v'..str
-end
+ local self = setmetatable({str=str, lang=lang, valid=false}, Parser)
+ self._parser = vim._create_ts_parser(lang)
+ self:parse()
-function M.parse_query(lang, query)
- M.require_language(lang)
- local self = setmetatable({}, Query)
- self.query = vim._ts_parse_query(lang, vim.fn.escape(query,'\\'))
- self.info = self.query:inspect()
- self.captures = self.info.captures
- self.regexes = {}
- for id,preds in pairs(self.info.patterns) do
- local regexes = {}
- for i, pred in ipairs(preds) do
- if (pred[1] == "match?" and type(pred[2]) == "number"
- and type(pred[3]) == "string") then
- regexes[i] = vim.regex(check_magic(pred[3]))
- end
- end
- if next(regexes) then
- self.regexes[id] = regexes
- end
- end
return self
end
-local function get_node_text(node, bufnr)
- local start_row, start_col, end_row, end_col = node:range()
- if start_row ~= end_row then
- return nil
- end
- local line = a.nvim_buf_get_lines(bufnr, start_row, start_row+1, true)[1]
- return string.sub(line, start_col+1, end_col)
-end
-
-function Query:match_preds(match, pattern, bufnr)
- local preds = self.info.patterns[pattern]
- if not preds then
- return true
- end
- local regexes = self.regexes[pattern]
- for i, pred in pairs(preds) do
- -- Here we only want to return if a predicate DOES NOT match, and
- -- continue on the other case. This way unknown predicates will not be considered,
- -- which allows some testing and easier user extensibility (#12173).
- -- Also, tree-sitter strips the leading # from predicates for us.
- if pred[1] == "eq?" then
- local node = match[pred[2]]
- local node_text = get_node_text(node, bufnr)
-
- local str
- if type(pred[3]) == "string" then
- -- (#eq? @aa "foo")
- str = pred[3]
- else
- -- (#eq? @aa @bb)
- str = get_node_text(match[pred[3]], bufnr)
- end
-
- if node_text ~= str or str == nil then
- return false
- end
- elseif pred[1] == "match?" then
- if not regexes or not regexes[i] then
- return false
- end
- local node = match[pred[2]]
- local start_row, start_col, end_row, end_col = node:range()
- if start_row ~= end_row then
- return false
- end
- if not regexes[i]:match_line(bufnr, start_row, start_col, end_col) then
- return false
- end
- end
- end
- return true
-end
-
-function Query:iter_captures(node, bufnr, start, stop)
- if bufnr == 0 then
- bufnr = vim.api.nvim_get_current_buf()
- end
- local raw_iter = node:_rawquery(self.query,true,start,stop)
- local function iter()
- local capture, captured_node, match = raw_iter()
- if match ~= nil then
- local active = self:match_preds(match, match.pattern, bufnr)
- match.active = active
- if not active then
- return iter() -- tail call: try next match
- end
- end
- return capture, captured_node
- end
- return iter
-end
-
-function Query:iter_matches(node, bufnr, start, stop)
- if bufnr == 0 then
- bufnr = vim.api.nvim_get_current_buf()
- end
- local raw_iter = node:_rawquery(self.query,false,start,stop)
- local function iter()
- local pattern, match = raw_iter()
- if match ~= nil then
- local active = self:match_preds(match, pattern, bufnr)
- if not active then
- return iter() -- tail call: try next match
- end
- end
- return pattern, match
- end
- return iter
-end
-
return M
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
new file mode 100644
index 0000000000..decde08019
--- /dev/null
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -0,0 +1,210 @@
+local a = vim.api
+
+-- support reload for quick experimentation
+local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {}
+TSHighlighter.__index = TSHighlighter
+
+TSHighlighter.active = TSHighlighter.active or {}
+
+local ns = a.nvim_create_namespace("treesitter/highlighter")
+
+-- These are conventions defined by nvim-treesitter, though it
+-- needs to be user extensible also.
+TSHighlighter.hl_map = {
+ ["error"] = "Error",
+
+-- Miscs
+ ["comment"] = "Comment",
+ ["punctuation.delimiter"] = "Delimiter",
+ ["punctuation.bracket"] = "Delimiter",
+ ["punctuation.special"] = "Delimiter",
+
+-- Constants
+ ["constant"] = "Constant",
+ ["constant.builtin"] = "Special",
+ ["constant.macro"] = "Define",
+ ["string"] = "String",
+ ["string.regex"] = "String",
+ ["string.escape"] = "SpecialChar",
+ ["character"] = "Character",
+ ["number"] = "Number",
+ ["boolean"] = "Boolean",
+ ["float"] = "Float",
+
+-- Functions
+ ["function"] = "Function",
+ ["function.special"] = "Function",
+ ["function.builtin"] = "Special",
+ ["function.macro"] = "Macro",
+ ["parameter"] = "Identifier",
+ ["method"] = "Function",
+ ["field"] = "Identifier",
+ ["property"] = "Identifier",
+ ["constructor"] = "Special",
+
+-- Keywords
+ ["conditional"] = "Conditional",
+ ["repeat"] = "Repeat",
+ ["label"] = "Label",
+ ["operator"] = "Operator",
+ ["keyword"] = "Keyword",
+ ["exception"] = "Exception",
+
+ ["type"] = "Type",
+ ["type.builtin"] = "Type",
+ ["structure"] = "Structure",
+ ["include"] = "Include",
+}
+
+function TSHighlighter.new(parser, query)
+ local self = setmetatable({}, TSHighlighter)
+
+ self.parser = parser
+ parser:register_cbs {
+ on_changedtree = function(...) self:on_changedtree(...) end
+ }
+
+ self:set_query(query)
+ self.edit_count = 0
+ self.redraw_count = 0
+ self.line_count = {}
+ self.root = self.parser:parse():root()
+ a.nvim_buf_set_option(self.buf, "syntax", "")
+
+ -- TODO(bfredl): can has multiple highlighters per buffer????
+ if not TSHighlighter.active[parser.bufnr] then
+ TSHighlighter.active[parser.bufnr] = {}
+ end
+
+ TSHighlighter.active[parser.bufnr][parser.lang] = self
+
+ -- Tricky: if syntax hasn't been enabled, we need to reload color scheme
+ -- but use synload.vim rather than syntax.vim to not enable
+ -- syntax FileType autocmds. Later on we should integrate with the
+ -- `:syntax` and `set syntax=...` machinery properly.
+ if vim.g.syntax_on ~= 1 then
+ vim.api.nvim_command("runtime! syntax/synload.vim")
+ end
+ return self
+end
+
+local function is_highlight_name(capture_name)
+ local firstc = string.sub(capture_name, 1, 1)
+ return firstc ~= string.lower(firstc)
+end
+
+function TSHighlighter:get_hl_from_capture(capture)
+
+ local name = self.query.captures[capture]
+
+ if is_highlight_name(name) then
+ -- From "Normal.left" only keep "Normal"
+ return vim.split(name, '.', true)[1]
+ else
+ -- Default to false to avoid recomputing
+ local hl = TSHighlighter.hl_map[name]
+ return hl and a.nvim_get_hl_id_by_name(hl) or 0
+ end
+end
+
+function TSHighlighter:on_changedtree(changes)
+ for _, ch in ipairs(changes or {}) do
+ a.nvim__buf_redraw_range(self.buf, ch[1], ch[3]+1)
+ end
+end
+
+function TSHighlighter:set_query(query)
+ if type(query) == "string" then
+ query = vim.treesitter.parse_query(self.parser.lang, query)
+ end
+
+ self.query = query
+
+ self.hl_cache = setmetatable({}, {
+ __index = function(table, capture)
+ local hl = self:get_hl_from_capture(capture)
+ rawset(table, capture, hl)
+
+ return hl
+ end
+ })
+
+ a.nvim__buf_redraw_range(self.parser.bufnr, 0, a.nvim_buf_line_count(self.parser.bufnr))
+end
+
+local function iter_active_tshl(buf, fn)
+ for _, hl in pairs(TSHighlighter.active[buf] or {}) do
+ fn(hl)
+ end
+end
+
+local function on_line_impl(self, buf, line)
+ if self.root == nil then
+ return -- parser bought the farm already
+ end
+
+ if self.iter == nil then
+ self.iter = self.query:iter_captures(self.root,buf,line,self.botline)
+ end
+ while line >= self.nextrow do
+ local capture, node = self.iter()
+ if capture == nil then
+ break
+ end
+ local start_row, start_col, end_row, end_col = node:range()
+ local hl = self.hl_cache[capture]
+ if hl and end_row >= line then
+ a.nvim_buf_set_extmark(buf, ns, start_row, start_col,
+ { end_line = end_row, end_col = end_col,
+ hl_group = hl,
+ ephemeral = true
+ })
+ end
+ if start_row > line then
+ self.nextrow = start_row
+ end
+ end
+end
+
+function TSHighlighter._on_line(_, _win, buf, line, highlighter)
+ -- on_line is only called when this is non-nil
+ if highlighter then
+ on_line_impl(highlighter, buf, line)
+ else
+ iter_active_tshl(buf, function(self)
+ on_line_impl(self, buf, line)
+ end)
+ end
+end
+
+function TSHighlighter._on_buf(_, buf)
+ iter_active_tshl(buf, function(self)
+ if self then
+ local tree = self.parser:parse()
+ self.root = (tree and tree:root()) or nil
+ end
+ end)
+end
+
+function TSHighlighter._on_win(_, _win, buf, _topline, botline)
+ iter_active_tshl(buf, function(self)
+ if not self then
+ return false
+ end
+
+ self.iter = nil
+ self.nextrow = 0
+ self.botline = botline
+ self.redraw_count = self.redraw_count + 1
+ return true
+ end)
+ return true
+end
+
+a.nvim_set_decoration_provider(ns, {
+ on_buf = TSHighlighter._on_buf;
+ on_win = TSHighlighter._on_win;
+ on_line = TSHighlighter._on_line;
+})
+
+return TSHighlighter
diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua
new file mode 100644
index 0000000000..a7e36a0b89
--- /dev/null
+++ b/runtime/lua/vim/treesitter/language.lua
@@ -0,0 +1,37 @@
+local a = vim.api
+
+local M = {}
+
+--- Asserts that the provided language is installed, and optionnaly provide a path for the parser
+--
+-- Parsers are searched in the `parser` runtime directory.
+--
+-- @param lang The language the parser should parse
+-- @param path Optionnal path the parser is located at
+function M.require_language(lang, path)
+ if vim._ts_has_language(lang) then
+ return true
+ end
+ if path == nil then
+ local fname = 'parser/' .. lang .. '.*'
+ local paths = a.nvim_get_runtime_file(fname, false)
+ if #paths == 0 then
+ -- TODO(bfredl): help tag?
+ error("no parser for '"..lang.."' language, see :help treesitter-parsers")
+ end
+ path = paths[1]
+ end
+ vim._ts_add_language(path, lang)
+end
+
+--- Inspects the provided language.
+--
+-- Inspecting provides some useful informations on the language like node names, ...
+--
+-- @param lang The language.
+function M.inspect_language(lang)
+ M.require_language(lang)
+ return vim._ts_inspect_language(lang)
+end
+
+return M
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
new file mode 100644
index 0000000000..2903c5905c
--- /dev/null
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -0,0 +1,335 @@
+local a = vim.api
+local language = require'vim.treesitter.language'
+
+-- query: pattern matching on trees
+-- predicate matching is implemented in lua
+local Query = {}
+Query.__index = Query
+
+local M = {}
+
+-- Filter the runtime query files, the spec is like regular runtime files but in the new `queries`
+-- directory. They resemble ftplugins, that is that you can override queries by adding things in the
+-- `queries` directory, and extend using the `after/queries` directory.
+local function filter_files(file_list)
+ local main = nil
+ local after = {}
+
+ for _, fname in ipairs(file_list) do
+ -- Only get the name of the directory containing the queries directory
+ if vim.fn.fnamemodify(fname, ":p:h:h:h:t") == "after" then
+ table.insert(after, fname)
+ -- The first one is the one with most priority
+ elseif not main then
+ main = fname
+ end
+ end
+
+ return { main, unpack(after) }
+end
+
+local function runtime_query_path(lang, query_name)
+ return string.format('queries/%s/%s.scm', lang, query_name)
+end
+
+local function filtered_runtime_queries(lang, query_name)
+ return filter_files(a.nvim_get_runtime_file(runtime_query_path(lang, query_name), true) or {})
+end
+
+local function get_query_files(lang, query_name, is_included)
+ local lang_files = filtered_runtime_queries(lang, query_name)
+ local query_files = lang_files
+
+ if #query_files == 0 then return {} end
+
+ local base_langs = {}
+
+ -- Now get the base languages by looking at the first line of every file
+ -- The syntax is the folowing :
+ -- ;+ inherits: ({language},)*{language}
+ --
+ -- {language} ::= {lang} | ({lang})
+ local MODELINE_FORMAT = "^;+%s*inherits%s*:?%s*([a-z_,()]+)%s*$"
+
+ for _, file in ipairs(query_files) do
+ local modeline = vim.fn.readfile(file, "", 1)
+
+ if #modeline == 1 then
+ local langlist = modeline[1]:match(MODELINE_FORMAT)
+
+ if langlist then
+ for _, incllang in ipairs(vim.split(langlist, ',', true)) do
+ local is_optional = incllang:match("%(.*%)")
+
+ if is_optional then
+ if not is_included then
+ table.insert(base_langs, incllang:sub(2, #incllang - 1))
+ end
+ else
+ table.insert(base_langs, incllang)
+ end
+ end
+ end
+ end
+ end
+
+ for _, base_lang in ipairs(base_langs) do
+ local base_files = get_query_files(base_lang, query_name, true)
+ vim.list_extend(query_files, base_files)
+ end
+
+ return query_files
+end
+
+local function read_query_files(filenames)
+ local contents = {}
+
+ for _,filename in ipairs(filenames) do
+ vim.list_extend(contents, vim.fn.readfile(filename))
+ end
+
+ return table.concat(contents, '\n')
+end
+
+--- Returns the runtime query {query_name} for {lang}.
+--
+-- @param lang The language to use for the query
+-- @param query_name The name of the query (i.e. "highlights")
+--
+-- @return The corresponding query, parsed.
+function M.get_query(lang, query_name)
+ local query_files = get_query_files(lang, query_name)
+ local query_string = read_query_files(query_files)
+
+ if #query_string > 0 then
+ return M.parse_query(lang, query_string)
+ end
+end
+
+--- Parses a query.
+--
+-- @param language The language
+-- @param query A string containing the query (s-expr syntax)
+--
+-- @returns The query
+function M.parse_query(lang, query)
+ language.require_language(lang)
+ local self = setmetatable({}, Query)
+ self.query = vim._ts_parse_query(lang, query)
+ self.info = self.query:inspect()
+ self.captures = self.info.captures
+ return self
+end
+
+-- TODO(vigoux): support multiline nodes too
+
+--- Gets the text corresponding to a given node
+-- @param node the node
+-- @param bufnr the buffer from which the node in extracted.
+function M.get_node_text(node, source)
+ local start_row, start_col, start_byte = node:start()
+ local end_row, end_col, end_byte = node:end_()
+
+ if type(source) == "number" then
+ if start_row ~= end_row then
+ return nil
+ end
+ local line = a.nvim_buf_get_lines(source, start_row, start_row+1, true)[1]
+ return string.sub(line, start_col+1, end_col)
+ elseif type(source) == "string" then
+ return source:sub(start_byte+1, end_byte)
+ end
+end
+
+-- Predicate handler receive the following arguments
+-- (match, pattern, bufnr, predicate)
+local predicate_handlers = {
+ ["eq?"] = function(match, _, source, predicate)
+ local node = match[predicate[2]]
+ local node_text = M.get_node_text(node, source)
+
+ local str
+ if type(predicate[3]) == "string" then
+ -- (#eq? @aa "foo")
+ str = predicate[3]
+ else
+ -- (#eq? @aa @bb)
+ str = M.get_node_text(match[predicate[3]], source)
+ end
+
+ if node_text ~= str or str == nil then
+ return false
+ end
+
+ return true
+ end,
+
+ ["lua-match?"] = function(match, _, source, predicate)
+ local node = match[predicate[2]]
+ local regex = predicate[3]
+ local start_row, _, end_row, _ = node:range()
+ if start_row ~= end_row then
+ return false
+ end
+
+ return string.find(M.get_node_text(node, source), regex)
+ end,
+
+ ["match?"] = (function()
+ local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true}
+ local function check_magic(str)
+ if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then
+ return str
+ end
+ return '\\v'..str
+ end
+
+ local compiled_vim_regexes = setmetatable({}, {
+ __index = function(t, pattern)
+ local res = vim.regex(check_magic(vim.fn.escape(pattern, '\\')))
+ rawset(t, pattern, res)
+ return res
+ end
+ })
+
+ return function(match, _, source, pred)
+ local node = match[pred[2]]
+ local start_row, start_col, end_row, end_col = node:range()
+ if start_row ~= end_row then
+ return false
+ end
+
+ local regex = compiled_vim_regexes[pred[3]]
+ return regex:match_line(source, start_row, start_col, end_col)
+ end
+ end)(),
+
+ ["contains?"] = function(match, _, source, predicate)
+ local node = match[predicate[2]]
+ local node_text = M.get_node_text(node, source)
+
+ for i=3,#predicate do
+ if string.find(node_text, predicate[i], 1, true) then
+ return true
+ end
+ end
+
+ return false
+ end
+}
+
+-- As we provide lua-match? also expose vim-match?
+predicate_handlers["vim-match?"] = predicate_handlers["match?"]
+
+--- Adds a new predicates to be used in queries
+--
+-- @param name the name of the predicate, without leading #
+-- @param handler the handler function to be used
+-- signature will be (match, pattern, bufnr, predicate)
+function M.add_predicate(name, handler, force)
+ if predicate_handlers[name] and not force then
+ a.nvim_err_writeln(string.format("Overriding %s", name))
+ end
+
+ predicate_handlers[name] = handler
+end
+
+--- Returns the list of currently supported predicates
+function M.list_predicates()
+ return vim.tbl_keys(predicate_handlers)
+end
+
+local function xor(x, y)
+ return (x or y) and not (x and y)
+end
+
+function Query:match_preds(match, pattern, source)
+ local preds = self.info.patterns[pattern]
+
+ for _, pred in pairs(preds or {}) do
+ -- Here we only want to return if a predicate DOES NOT match, and
+ -- continue on the other case. This way unknown predicates will not be considered,
+ -- which allows some testing and easier user extensibility (#12173).
+ -- Also, tree-sitter strips the leading # from predicates for us.
+ local pred_name
+ local is_not
+ if string.sub(pred[1], 1, 4) == "not-" then
+ pred_name = string.sub(pred[1], 5)
+ is_not = true
+ else
+ pred_name = pred[1]
+ is_not = false
+ end
+
+ local handler = predicate_handlers[pred_name]
+
+ if not handler then
+ a.nvim_err_writeln(string.format("No handler for %s", pred[1]))
+ return false
+ end
+
+ local pred_matches = handler(match, pattern, source, pred)
+
+ if not xor(is_not, pred_matches) then
+ return false
+ end
+ end
+ return true
+end
+
+--- Iterates of the captures of self on a given range.
+--
+-- @param node The node under witch the search will occur
+-- @param buffer The source buffer to search
+-- @param start The starting line of the search
+-- @param stop The stoping line of the search (end-exclusive)
+--
+-- @returns The matching capture id
+-- @returns The captured node
+function Query:iter_captures(node, source, start, stop)
+ if type(source) == "number" and source == 0 then
+ source = vim.api.nvim_get_current_buf()
+ end
+ local raw_iter = node:_rawquery(self.query, true, start, stop)
+ local function iter()
+ local capture, captured_node, match = raw_iter()
+ if match ~= nil then
+ local active = self:match_preds(match, match.pattern, source)
+ match.active = active
+ if not active then
+ return iter() -- tail call: try next match
+ end
+ end
+ return capture, captured_node
+ end
+ return iter
+end
+
+--- Iterates of the matches of self on a given range.
+--
+-- @param node The node under witch the search will occur
+-- @param buffer The source buffer to search
+-- @param start The starting line of the search
+-- @param stop The stoping line of the search (end-exclusive)
+--
+-- @returns The matching pattern id
+-- @returns The matching match
+function Query:iter_matches(node, source, start, stop)
+ if type(source) == "number" and source == 0 then
+ source = vim.api.nvim_get_current_buf()
+ end
+ local raw_iter = node:_rawquery(self.query, false, start, stop)
+ local function iter()
+ local pattern, match = raw_iter()
+ if match ~= nil then
+ local active = self:match_preds(match, pattern, source)
+ if not active then
+ return iter() -- tail call: try next match
+ end
+ end
+ return pattern, match
+ end
+ return iter
+end
+
+return M
diff --git a/runtime/lua/vim/tshighlighter.lua b/runtime/lua/vim/tshighlighter.lua
deleted file mode 100644
index 6465751ae8..0000000000
--- a/runtime/lua/vim/tshighlighter.lua
+++ /dev/null
@@ -1,116 +0,0 @@
-local a = vim.api
-
--- support reload for quick experimentation
-local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {}
-TSHighlighter.__index = TSHighlighter
-local ts_hs_ns = a.nvim_create_namespace("treesitter_hl")
-
--- These are conventions defined by tree-sitter, though it
--- needs to be user extensible also.
--- TODO(bfredl): this is very much incomplete, we will need to
--- go through a few tree-sitter provided queries and decide
--- on translations that makes the most sense.
-TSHighlighter.hl_map = {
- keyword="Keyword",
- string="String",
- type="Type",
- comment="Comment",
- constant="Constant",
- operator="Operator",
- number="Number",
- label="Label",
- ["function"]="Function",
- ["function.special"]="Function",
-}
-
-function TSHighlighter.new(query, bufnr, ft)
- local self = setmetatable({}, TSHighlighter)
- self.parser = vim.treesitter.get_parser(
- bufnr,
- ft,
- {
- on_changedtree = function(...) self:on_changedtree(...) end,
- on_lines = function() self.root = self.parser:parse():root() end
- }
- )
-
- self.buf = self.parser.bufnr
-
- local tree = self.parser:parse()
- self.root = tree:root()
- self:set_query(query)
- self.edit_count = 0
- self.redraw_count = 0
- self.line_count = {}
- a.nvim_buf_set_option(self.buf, "syntax", "")
-
- -- Tricky: if syntax hasn't been enabled, we need to reload color scheme
- -- but use synload.vim rather than syntax.vim to not enable
- -- syntax FileType autocmds. Later on we should integrate with the
- -- `:syntax` and `set syntax=...` machinery properly.
- if vim.g.syntax_on ~= 1 then
- vim.api.nvim_command("runtime! syntax/synload.vim")
- end
- return self
-end
-
-local function is_highlight_name(capture_name)
- local firstc = string.sub(capture_name, 1, 1)
- return firstc ~= string.lower(firstc)
-end
-
-function TSHighlighter:get_hl_from_capture(capture)
-
- local name = self.query.captures[capture]
-
- if is_highlight_name(name) then
- -- From "Normal.left" only keep "Normal"
- return vim.split(name, '.', true)[1]
- else
- -- Default to false to avoid recomputing
- return TSHighlighter.hl_map[name]
- end
-end
-
-function TSHighlighter:set_query(query)
- if type(query) == "string" then
- query = vim.treesitter.parse_query(self.parser.lang, query)
- end
- self.query = query
-
- self.hl_cache = setmetatable({}, {
- __index = function(table, capture)
- local hl = self:get_hl_from_capture(capture)
- rawset(table, capture, hl)
-
- return hl
- end
- })
-
- self:on_changedtree({{self.root:range()}})
-end
-
-function TSHighlighter:on_changedtree(changes)
- -- Get a fresh root
- self.root = self.parser.tree:root()
-
- for _, ch in ipairs(changes or {}) do
- -- Try to be as exact as possible
- local changed_node = self.root:descendant_for_range(ch[1], ch[2], ch[3], ch[4])
-
- a.nvim_buf_clear_namespace(self.buf, ts_hs_ns, ch[1], ch[3])
-
- for capture, node in self.query:iter_captures(changed_node, self.buf, ch[1], ch[3] + 1) do
- local start_row, start_col, end_row, end_col = node:range()
- local hl = self.hl_cache[capture]
- if hl then
- a.nvim__buf_add_decoration(self.buf, ts_hs_ns, hl,
- start_row, start_col,
- end_row, end_col,
- {})
- end
- end
- end
-end
-
-return TSHighlighter
diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua
index 9c3535c676..f1a12c72ec 100644
--- a/runtime/lua/vim/uri.lua
+++ b/runtime/lua/vim/uri.lua
@@ -7,6 +7,9 @@
local uri_decode
do
local schar = string.char
+
+ --- Convert hex to char
+ --@private
local function hex_to_char(hex)
return schar(tonumber(hex, 16))
end
@@ -34,6 +37,8 @@ do
else
tohex = function(b) return string.format("%02x", b) end
end
+
+ --@private
local function percent_encode_char(char)
return "%"..tohex(sbyte(char), 2)
end
@@ -45,10 +50,14 @@ do
end
+--@private
local function is_windows_file_uri(uri)
return uri:match('^file:///[a-zA-Z]:') ~= nil
end
+--- Get a URI from a file path.
+--@param path (string): Path to file
+--@return URI
local function uri_from_fname(path)
local volume_path, fname = path:match("^([a-zA-Z]:)(.*)")
local is_windows = volume_path ~= nil
@@ -67,6 +76,9 @@ end
local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*)://.*'
+--- Get a URI from a bufnr
+--@param bufnr (number): Buffer number
+--@return URI
local function uri_from_bufnr(bufnr)
local fname = vim.api.nvim_buf_get_name(bufnr)
local scheme = fname:match(URI_SCHEME_PATTERN)
@@ -77,6 +89,9 @@ local function uri_from_bufnr(bufnr)
end
end
+--- Get a filename from a URI
+--@param uri (string): The URI
+--@return Filename
local function uri_to_fname(uri)
local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri)
if scheme ~= 'file' then
@@ -93,7 +108,10 @@ local function uri_to_fname(uri)
return uri
end
--- Return or create a buffer for a uri.
+--- Return or create a buffer for a uri.
+--@param uri (string): The URI
+--@return bufnr.
+--@note Creates buffer but does not load it
local function uri_to_bufnr(uri)
local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri)
if scheme == 'file' then
diff --git a/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim
index 7a6464fc98..fe4455fe2e 100644
--- a/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim
+++ b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim
@@ -1,15 +1,17 @@
" cfilter.vim: Plugin to filter entries from a quickfix/location list
-" Last Change: May 12, 2018
-" Maintainer: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
-" Version: 1.0
+" Last Change: Aug 23, 2018
+" Maintainer: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
+" Version: 1.1
"
" Commands to filter the quickfix list:
-" :Cfilter[!] {pat}
+" :Cfilter[!] /{pat}/
" Create a new quickfix list from entries matching {pat} in the current
" quickfix list. Both the file name and the text of the entries are
" matched against {pat}. If ! is supplied, then entries not matching
-" {pat} are used.
-" :Lfilter[!] {pat}
+" {pat} are used. The pattern can be optionally enclosed using one of
+" the following characters: ', ", /. If the pattern is empty, then the
+" last used search pattern is used.
+" :Lfilter[!] /{pat}/
" Same as :Cfilter but operates on the current location list.
"
if exists("loaded_cfilter")
@@ -17,7 +19,7 @@ if exists("loaded_cfilter")
endif
let loaded_cfilter = 1
-func s:Qf_filter(qf, pat, bang)
+func s:Qf_filter(qf, searchpat, bang)
if a:qf
let Xgetlist = function('getqflist')
let Xsetlist = function('setqflist')
@@ -28,14 +30,31 @@ func s:Qf_filter(qf, pat, bang)
let cmd = ':Lfilter' . a:bang
endif
+ let firstchar = a:searchpat[0]
+ let lastchar = a:searchpat[-1:]
+ if firstchar == lastchar &&
+ \ (firstchar == '/' || firstchar == '"' || firstchar == "'")
+ let pat = a:searchpat[1:-2]
+ if pat == ''
+ " Use the last search pattern
+ let pat = @/
+ endif
+ else
+ let pat = a:searchpat
+ endif
+
+ if pat == ''
+ return
+ endif
+
if a:bang == '!'
- let cond = 'v:val.text !~# a:pat && bufname(v:val.bufnr) !~# a:pat'
+ let cond = 'v:val.text !~# pat && bufname(v:val.bufnr) !~# pat'
else
- let cond = 'v:val.text =~# a:pat || bufname(v:val.bufnr) =~# a:pat'
+ let cond = 'v:val.text =~# pat || bufname(v:val.bufnr) =~# pat'
endif
let items = filter(Xgetlist(), cond)
- let title = cmd . ' ' . a:pat
+ let title = cmd . ' /' . pat . '/'
call Xsetlist([], ' ', {'title' : title, 'items' : items})
endfunc
diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm
new file mode 100644
index 0000000000..96b43cf0d0
--- /dev/null
+++ b/runtime/queries/c/highlights.scm
@@ -0,0 +1,151 @@
+(identifier) @variable
+
+[
+ "const"
+ "default"
+ "enum"
+ "extern"
+ "inline"
+ "return"
+ "sizeof"
+ "static"
+ "struct"
+ "typedef"
+ "union"
+ "volatile"
+ "goto"
+] @keyword
+
+[
+ "while"
+ "for"
+ "do"
+ "continue"
+ "break"
+] @repeat
+
+[
+ "if"
+ "else"
+ "case"
+ "switch"
+] @conditional
+
+"#define" @constant.macro
+[
+ "#if"
+ "#ifdef"
+ "#ifndef"
+ "#else"
+ "#elif"
+ "#endif"
+ (preproc_directive)
+] @keyword
+
+"#include" @include
+
+[
+ "="
+
+ "-"
+ "*"
+ "/"
+ "+"
+ "%"
+
+ "~"
+ "|"
+ "&"
+ "^"
+ "<<"
+ ">>"
+
+ "->"
+
+ "<"
+ "<="
+ ">="
+ ">"
+ "=="
+ "!="
+
+ "!"
+ "&&"
+ "||"
+
+ "-="
+ "+="
+ "*="
+ "/="
+ "%="
+ "|="
+ "&="
+ "^="
+ "--"
+ "++"
+] @operator
+
+[
+ (true)
+ (false)
+] @boolean
+
+[ "." ";" ":" "," ] @punctuation.delimiter
+
+(conditional_expression [ "?" ":" ] @conditional)
+
+
+[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket
+
+(string_literal) @string
+(system_lib_string) @string
+
+(null) @constant.builtin
+(number_literal) @number
+(char_literal) @number
+
+(call_expression
+ function: (identifier) @function)
+(call_expression
+ function: (field_expression
+ field: (field_identifier) @function))
+(function_declarator
+ declarator: (identifier) @function)
+(preproc_function_def
+ name: (identifier) @function.macro)
+[
+ (preproc_arg)
+ (preproc_defined)
+] @function.macro
+; TODO (preproc_arg) @embedded
+
+(field_identifier) @property
+(statement_identifier) @label
+
+[
+(type_identifier)
+(primitive_type)
+(sized_type_specifier)
+(type_descriptor)
+ ] @type
+
+(declaration type: [(identifier) (type_identifier)] @type)
+(cast_expression type: [(identifier) (type_identifier)] @type)
+(sizeof_expression value: (parenthesized_expression (identifier) @type))
+
+((identifier) @constant
+ (#match? @constant "^[A-Z][A-Z0-9_]+$"))
+
+(comment) @comment
+
+;; Parameters
+(parameter_declaration
+ declarator: (identifier) @parameter)
+
+(parameter_declaration
+ declarator: (pointer_declarator) @parameter)
+
+(preproc_params
+ (identifier)) @parameter
+
+(ERROR) @error
diff --git a/runtime/syntax/markdown.vim b/runtime/syntax/markdown.vim
index 1955a7443e..17b61c2fa4 100644
--- a/runtime/syntax/markdown.vim
+++ b/runtime/syntax/markdown.vim
@@ -2,7 +2,7 @@
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Filenames: *.markdown
-" Last Change: 2016 Aug 29
+" Last Change: 2020 Jan 14
if exists("b:current_syntax")
finish
@@ -18,37 +18,46 @@ unlet! b:current_syntax
if !exists('g:markdown_fenced_languages')
let g:markdown_fenced_languages = []
endif
+let s:done_include = {}
for s:type in map(copy(g:markdown_fenced_languages),'matchstr(v:val,"[^=]*$")')
+ if has_key(s:done_include, matchstr(s:type,'[^.]*'))
+ continue
+ endif
if s:type =~ '\.'
let b:{matchstr(s:type,'[^.]*')}_subtype = matchstr(s:type,'\.\zs.*')
endif
exe 'syn include @markdownHighlight'.substitute(s:type,'\.','','g').' syntax/'.matchstr(s:type,'[^.]*').'.vim'
unlet! b:current_syntax
+ let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
+unlet! s:done_include
-syn sync minlines=10
+if !exists('g:markdown_minlines')
+ let g:markdown_minlines = 50
+endif
+execute 'syn sync minlines=' . g:markdown_minlines
syn case ignore
-syn match markdownValid '[<>]\c[a-z/$!]\@!'
-syn match markdownValid '&\%(#\=\w*;\)\@!'
+syn match markdownValid '[<>]\c[a-z/$!]\@!' transparent contains=NONE
+syn match markdownValid '&\%(#\=\w*;\)\@!' transparent contains=NONE
syn match markdownLineStart "^[<@]\@!" nextgroup=@markdownBlock,htmlSpecialChar
syn cluster markdownBlock contains=markdownH1,markdownH2,markdownH3,markdownH4,markdownH5,markdownH6,markdownBlockquote,markdownListMarker,markdownOrderedListMarker,markdownCodeBlock,markdownRule
-syn cluster markdownInline contains=markdownLineBreak,markdownLinkText,markdownItalic,markdownBold,markdownCode,markdownEscape,@htmlTop,markdownError
+syn cluster markdownInline contains=markdownLineBreak,markdownLinkText,markdownItalic,markdownBold,markdownCode,markdownEscape,@htmlTop,markdownError,markdownValid
syn match markdownH1 "^.\+\n=\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownH2 "^.\+\n-\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownHeadingRule "^[=-]\+$" contained
-syn region markdownH1 matchgroup=markdownHeadingDelimiter start="##\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH2 matchgroup=markdownHeadingDelimiter start="###\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH3 matchgroup=markdownHeadingDelimiter start="####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH4 matchgroup=markdownHeadingDelimiter start="#####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH5 matchgroup=markdownHeadingDelimiter start="######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH6 matchgroup=markdownHeadingDelimiter start="#######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH1 matchgroup=markdownH1Delimiter start="##\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH2 matchgroup=markdownH2Delimiter start="###\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH3 matchgroup=markdownH3Delimiter start="####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH4 matchgroup=markdownH4Delimiter start="#####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH5 matchgroup=markdownH5Delimiter start="######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH6 matchgroup=markdownH6Delimiter start="#######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn match markdownBlockquote ">\%(\s\|$\)" contained nextgroup=@markdownBlock
@@ -70,31 +79,40 @@ syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+"+ end=+
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+'+ end=+'+ keepend contained
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+(+ end=+)+ keepend contained
-syn region markdownLinkText matchgroup=markdownLinkTextDelimiter start="!\=\[\%(\_[^]]*]\%( \=[[(]\)\)\@=" end="\]\%( \=[[(]\)\@=" nextgroup=markdownLink,markdownId skipwhite contains=@markdownInline,markdownLineStart
+syn region markdownLinkText matchgroup=markdownLinkTextDelimiter start="!\=\[\%(\%(\_[^][]\|\[\_[^][]*\]\)*]\%( \=[[(]\)\)\@=" end="\]\%( \=[[(]\)\@=" nextgroup=markdownLink,markdownId skipwhite contains=@markdownInline,markdownLineStart
syn region markdownLink matchgroup=markdownLinkDelimiter start="(" end=")" contains=markdownUrl keepend contained
syn region markdownId matchgroup=markdownIdDelimiter start="\[" end="\]" keepend contained
syn region markdownAutomaticLink matchgroup=markdownUrlDelimiter start="<\%(\w\+:\|[[:alnum:]_+-]\+@\)\@=" end=">" keepend oneline
-let s:concealends = has('conceal') ? ' concealends' : ''
-exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=\*\|\*\S\@=" end="\S\@<=\*\|\*\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=_\|_\S\@=" end="\S\@<=_\|_\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=\*\*\|\*\*\S\@=" end="\S\@<=\*\*\|\*\*\S\@=" keepend contains=markdownLineStart,markdownItalic' . s:concealends
-exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=__\|__\S\@=" end="\S\@<=__\|__\S\@=" keepend contains=markdownLineStart,markdownItalic' . s:concealends
-exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=\*\*\*\|\*\*\*\S\@=" end="\S\@<=\*\*\*\|\*\*\*\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=___\|___\S\@=" end="\S\@<=___\|___\S\@=" keepend contains=markdownLineStart' . s:concealends
+let s:concealends = ''
+if has('conceal') && get(g:, 'markdown_syntax_conceal', 1) == 1
+ let s:concealends = ' concealends'
+endif
+exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=\*\|\*\S\@=" end="\S\@<=\*\|\*\S\@=" skip="\\\*" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\w\@<!_\S\@=" end="\S\@<=_\w\@!" skip="\\_" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=\*\*\|\*\*\S\@=" end="\S\@<=\*\*\|\*\*\S\@=" skip="\\\*" contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
+exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\w\@<!__\S\@=" end="\S\@<=__\w\@!" skip="\\_" contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
+exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=\*\*\*\|\*\*\*\S\@=" end="\S\@<=\*\*\*\|\*\*\*\S\@=" skip="\\\*" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\w\@<!___\S\@=" end="\S\@<=___\w\@!" skip="\\_" contains=markdownLineStart,@Spell' . s:concealends
syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart
-syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*```.*$" end="^\s*```\ze\s*$" keepend
+syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*````*.*$" end="^\s*````*\ze\s*$" keepend
syn match markdownFootnote "\[^[^\]]\+\]"
syn match markdownFootnoteDefinition "^\[^[^\]]\+\]:"
if main_syntax ==# 'markdown'
+ let s:done_include = {}
for s:type in g:markdown_fenced_languages
- exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*```\s*'.matchstr(s:type,'[^=]*').'\>.*$" end="^\s*```\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g')
+ if has_key(s:done_include, matchstr(s:type,'[^.]*'))
+ continue
+ endif
+ exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*````*\s*\%({.\{-}\.\)\='.matchstr(s:type,'[^=]*').'}\=\S\@!.*$" end="^\s*````*\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g') . s:concealends
+ let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
+ unlet! s:done_include
endif
syn match markdownEscape "\\[][\\`*_{}()<>#+.!-]"
@@ -107,6 +125,12 @@ hi def link markdownH4 htmlH4
hi def link markdownH5 htmlH5
hi def link markdownH6 htmlH6
hi def link markdownHeadingRule markdownRule
+hi def link markdownH1Delimiter markdownHeadingDelimiter
+hi def link markdownH2Delimiter markdownHeadingDelimiter
+hi def link markdownH3Delimiter markdownHeadingDelimiter
+hi def link markdownH4Delimiter markdownHeadingDelimiter
+hi def link markdownH5Delimiter markdownHeadingDelimiter
+hi def link markdownH6Delimiter markdownHeadingDelimiter
hi def link markdownHeadingDelimiter Delimiter
hi def link markdownOrderedListMarker markdownListMarker
hi def link markdownListMarker htmlTagName
diff --git a/runtime/syntax/resolv.vim b/runtime/syntax/resolv.vim
index a879116a5f..9a2dec51ce 100644
--- a/runtime/syntax/resolv.vim
+++ b/runtime/syntax/resolv.vim
@@ -2,12 +2,19 @@
" Language: resolver configuration file
" Maintainer: Radu Dineiu <radu.dineiu@gmail.com>
" URL: https://raw.github.com/rid9/vim-resolv/master/resolv.vim
-" Last Change: 2013 May 21
-" Version: 1.0
+" Last Change: 2020 Mar 10
+" Version: 1.4
"
" Credits:
" David Necas (Yeti) <yeti@physics.muni.cz>
" Stefano Zacchiroli <zack@debian.org>
+" DJ Lucas <dj@linuxfromscratch.org>
+"
+" Changelog:
+" - 1.4: Added IPv6 support for sortlist.
+" - 1.3: Added IPv6 support for IPv4 dot-decimal notation.
+" - 1.2: Added new options.
+" - 1.1: Added IPv6 support.
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -29,11 +36,47 @@ syn match resolvIP contained /\%(\d\{1,4}\.\)\{3}\d\{1,4}/ contains=@resolvIPClu
syn match resolvIPNetmask contained /\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\%(\%(\d\{1,4}\.\)\{,3}\d\{1,4}\)\)\?/ contains=resolvOperator,@resolvIPCluster
syn match resolvHostname contained /\w\{-}\.[-0-9A-Za-z_\.]*/
-" Particular
+" Nameserver IPv4
syn match resolvIPNameserver contained /\%(\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\s\|$\)\)\+/ contains=@resolvIPCluster
+
+" Nameserver IPv6
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{6}\%(\x\{1,4}:\x\{1,4}\)\>/
+syn match resolvIPNameserver contained /\s\@<=::\%(\x\{1,4}:\)\{,6}\x\{1,4}\>/
+syn match resolvIPNameserver contained /\s\@<=::\%(\x\{1,4}:\)\{,5}\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{1}:\%(\x\{1,4}:\)\{,5}\x\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{1}:\%(\x\{1,4}:\)\{,4}\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{2}:\%(\x\{1,4}:\)\{,4}\x\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{2}:\%(\x\{1,4}:\)\{,3}\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{3}:\%(\x\{1,4}:\)\{,3}\x\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{3}:\%(\x\{1,4}:\)\{,2}\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{4}:\%(\x\{1,4}:\)\{,2}\x\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{4}:\%(\x\{1,4}:\)\{,1}\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{5}:\%(\d\{1,4}\.\)\{3}\d\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{6}:\x\{1,4}\>/
+syn match resolvIPNameserver contained /\<\%(\x\{1,4}:\)\{1,7}:\%(\s\|;\|$\)\@=/
+
+" Search hostname
syn match resolvHostnameSearch contained /\%(\%([-0-9A-Za-z_]\+\.\)*[-0-9A-Za-z_]\+\.\?\%(\s\|$\)\)\+/
+
+" Sortlist IPv4
syn match resolvIPNetmaskSortList contained /\%(\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\%(\%(\d\{1,4}\.\)\{,3}\d\{1,4}\)\)\?\%(\s\|$\)\)\+/ contains=resolvOperator,@resolvIPCluster
+" Sortlist IPv6
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{6}\%(\x\{1,4}:\x\{1,4}\)\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\s\@<=::\%(\x\{1,4}:\)\{,6}\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\s\@<=::\%(\x\{1,4}:\)\{,5}\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{1}:\%(\x\{1,4}:\)\{,5}\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{1}:\%(\x\{1,4}:\)\{,4}\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{2}:\%(\x\{1,4}:\)\{,4}\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{2}:\%(\x\{1,4}:\)\{,3}\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{3}:\%(\x\{1,4}:\)\{,3}\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{3}:\%(\x\{1,4}:\)\{,2}\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{4}:\%(\x\{1,4}:\)\{,2}\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{4}:\%(\x\{1,4}:\)\{,1}\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{5}:\%(\d\{1,4}\.\)\{3}\d\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{6}:\x\{1,4}\%(\/\d\{1,3}\)\?\>/
+syn match resolvIPNetmaskSortList contained /\<\%(\x\{1,4}:\)\{1,7}:\%(\s\|;\|$\)\@=\%(\/\d\{1,3}\)\?/
+
" Identifiers
syn match resolvNameserver /^\s*nameserver\>/ nextgroup=resolvIPNameserver skipwhite
syn match resolvLwserver /^\s*lwserver\>/ nextgroup=resolvIPNameserver skipwhite
@@ -43,13 +86,12 @@ syn match resolvSortList /^\s*sortlist\>/ nextgroup=resolvIPNetmaskSortList skip
syn match resolvOptions /^\s*options\>/ nextgroup=resolvOption skipwhite
" Options
-syn match resolvOption /\<\%(debug\|no_tld_query\|rotate\|no-check-names\|inet6\)\>/ contained nextgroup=resolvOption skipwhite
+syn match resolvOption /\<\%(debug\|no_tld_query\|no-tld-query\|rotate\|no-check-names\|inet6\|ip6-bytestring\|\%(no-\)\?ip6-dotint\|edns0\|single-request\%(-reopen\)\?\|use-vc\)\>/ contained nextgroup=resolvOption skipwhite
syn match resolvOption /\<\%(ndots\|timeout\|attempts\):\d\+\>/ contained contains=resolvOperator nextgroup=resolvOption skipwhite
" Additional errors
syn match resolvError /^search .\{257,}/
-
hi def link resolvIP Number
hi def link resolvIPNetmask Number
hi def link resolvHostname String
@@ -72,7 +114,6 @@ hi def link resolvError Error
hi def link resolvIPError Error
hi def link resolvIPSpecial Special
-
let b:current_syntax = "resolv"
" vim: ts=8 ft=vim
diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim
index b3a8f96b6b..ec0f7b99bd 100644
--- a/runtime/syntax/tex.vim
+++ b/runtime/syntax/tex.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: TeX
" Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
-" Last Change: Jun 07, 2020
-" Version: 118
+" Last Change: Jun 29, 2020
+" Version: 119
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX
"
" Notes: {{{1
@@ -147,6 +147,11 @@ if exists("g:tex_nospell") && g:tex_nospell
else
let s:tex_nospell = 0
endif
+if exists("g:tex_matchcheck")
+ let s:tex_matchcheck= g:tex_matchcheck
+else
+ let s:tex_matchcheck= '[({[]'
+endif
if exists("g:tex_excludematcher")
let s:tex_excludematcher= g:tex_excludematcher
else
@@ -205,27 +210,41 @@ if !exists("g:tex_no_math")
endif
endif
-" Try to flag {} and () mismatches: {{{1
+" Try to flag {}, [], and () mismatches: {{{1
if s:tex_fast =~# 'm'
if !s:tex_no_error
- syn region texMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchGroup,texError
- syn region texMatcher matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchGroup,texError,@NoSpell
- syn region texMatcherNM matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchNMGroup,texError
- syn region texMatcherNM matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchNMGroup,texError,@NoSpell
+ if s:tex_matchcheck =~ '{'
+ syn region texMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchGroup,texError
+ syn region texMatcherNM matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchNMGroup,texError
+ endif
+ if s:tex_matchcheck =~ '\['
+ syn region texMatcher matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchGroup,texError,@NoSpell
+ syn region texMatcherNM matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchNMGroup,texError,@NoSpell
+ endif
else
- syn region texMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchGroup
- syn region texMatcher matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchGroup
- syn region texMatcherNM matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchNMGroup
- syn region texMatcherNM matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchNMGroup
+ if s:tex_matchcheck =~ '{'
+ syn region texMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchGroup
+ syn region texMatcherNM matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchNMGroup
+ endif
+ if s:tex_matchcheck =~ '\['
+ syn region texMatcher matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchGroup
+ syn region texMatcherNM matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchNMGroup
+ endif
endif
- if !s:tex_nospell
- syn region texParen start="(" end=")" transparent contains=@texMatchGroup,@Spell
- else
- syn region texParen start="(" end=")" transparent contains=@texMatchGroup
+ if s:tex_matchcheck =~ '('
+ if !s:tex_nospell
+ syn region texParen start="(" end=")" transparent contains=@texMatchGroup,@Spell
+ else
+ syn region texParen start="(" end=")" transparent contains=@texMatchGroup
+ endif
endif
endif
if !s:tex_no_error
- syn match texError "[}\])]"
+ if s:tex_matchcheck =~ '('
+ syn match texError "[}\]]"
+ else
+ syn match texError "[}\])]"
+ endif
endif
if s:tex_fast =~# 'M'
if !exists("g:tex_no_math")
@@ -756,7 +775,7 @@ if has("conceal") && &enc == 'utf-8'
\ ['ldots' , 'โ€ฆ'],
\ ['le' , 'โ‰ค'],
\ ['left|' , '|'],
- \ ['left\|' , 'โ€–'],
+ \ ['left\\|' , 'โ€–'],
\ ['left(' , '('],
\ ['left\[' , '['],
\ ['left\\{' , '{'],
diff --git a/runtime/syntax/typescript.vim b/runtime/syntax/typescript.vim
index bc382610a9..767ba56d42 100644
--- a/runtime/syntax/typescript.vim
+++ b/runtime/syntax/typescript.vim
@@ -1,10 +1,13 @@
" Vim syntax file
" Language: TypeScript
-" Maintainer: Bram Moolenaar
-" Last Change: 2019 Jun 07
+" Maintainer: Bram Moolenaar, Herrington Darkholme
+" Last Change: 2019 Nov 30
" Based On: Herrington Darkholme's yats.vim
-" Changes: See https:github.com/HerringtonDarkholme/yats.vim
-" Credits: See yats.vim
+" Changes: Go to https:github.com/HerringtonDarkholme/yats.vim for recent changes.
+" Origin: https://github.com/othree/yajs
+" Credits: Kao Wei-Ko(othree), Jose Elera Campana, Zhao Yi, Claudio Fleiner, Scott Shattuck
+" (This file is based on their hard work), gumnos (From the #vim
+" IRC Channel in Freenode)
" This is the same syntax that is in yats.vim, but:
" - flattened into one file
@@ -21,6 +24,7 @@ endif
let s:cpo_save = &cpo
set cpo&vim
+" this region is NOT used in TypeScriptReact
" nextgroup doesn't contain objectLiteral, let outer region contains it
syntax region typescriptTypeCast matchgroup=typescriptTypeBrackets
\ start=/< \@!/ end=/>/
@@ -28,2045 +32,11 @@ syntax region typescriptTypeCast matchgroup=typescriptTypeBrackets
\ nextgroup=@typescriptExpression
\ contained skipwhite oneline
-" runtime syntax/common.vim
-" NOTE: this results in accurate highlighting, but can be slow.
-syntax sync fromstart
+"""""""""""""""""""""""""""""""""""""""""""""""""""
+" Source the part common with typescriptreact.vim
+source <sfile>:h/typescriptcommon.vim
-"Dollar sign is permitted anywhere in an identifier
-setlocal iskeyword-=$
-if main_syntax == 'typescript' || main_syntax == 'typescript.tsx'
- setlocal iskeyword+=$
- " syntax cluster htmlJavaScript contains=TOP
-endif
-
-" lowest priority on least used feature
-syntax match typescriptLabel /[a-zA-Z_$]\k*:/he=e-1 contains=typescriptReserved nextgroup=@typescriptStatement skipwhite skipempty
-
-" other keywords like return,case,yield uses containedin
-syntax region typescriptBlock matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptStatement,@typescriptComments fold
-
-
-"runtime syntax/basic/identifiers.vim
-syntax cluster afterIdentifier contains=
- \ typescriptDotNotation,
- \ typescriptFuncCallArg,
- \ typescriptTemplate,
- \ typescriptIndexExpr,
- \ @typescriptSymbols,
- \ typescriptTypeArguments
-
-syntax match typescriptIdentifierName /\<\K\k*/
- \ nextgroup=@afterIdentifier
- \ transparent
- \ contains=@_semantic
- \ skipnl skipwhite
-
-syntax match typescriptProp contained /\K\k*!\?/
- \ transparent
- \ contains=@props
- \ nextgroup=@afterIdentifier
- \ skipwhite skipempty
-
-syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/rs=s+1 end=/]/he=e-1 contains=@typescriptValue nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty
-
-syntax match typescriptDotNotation /\./ nextgroup=typescriptProp skipnl
-syntax match typescriptDotStyleNotation /\.style\./ nextgroup=typescriptDOMStyle transparent
-" syntax match typescriptFuncCall contained /[a-zA-Z]\k*\ze(/ nextgroup=typescriptFuncCallArg
-syntax region typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty
-syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl
-syntax region typescriptEventFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptEventExpression
-syntax region typescriptEventString contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/ contains=typescriptASCII,@events
-
-"runtime syntax/basic/literal.vim
-"Syntax in the JavaScript code
-
-" String
-syntax match typescriptASCII contained /\\\d\d\d/
-
-syntax region typescriptTemplateSubstitution matchgroup=typescriptTemplateSB
- \ start=/\${/ end=/}/
- \ contains=@typescriptValue
- \ contained
-
-
-syntax region typescriptString
- \ start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+
- \ contains=typescriptSpecial,@Spell
- \ extend
-
-syntax match typescriptSpecial contained "\v\\%(x\x\x|u%(\x{4}|\{\x{4,5}})|c\u|.)"
-
-" From vim runtime
-" <https://github.com/vim/vim/blob/master/runtime/syntax/javascript.vim#L48>
-syntax region typescriptRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gimuy]\{0,5\}\s*$+ end=+/[gimuy]\{0,5\}\s*[;.,)\]}]+me=e-1 nextgroup=typescriptDotNotation oneline
-
-syntax region typescriptTemplate
- \ start=/`/ skip=/\\\\\|\\`\|\n/ end=/`\|$/
- \ contains=typescriptTemplateSubstitution
- \ nextgroup=@typescriptSymbols
- \ skipwhite skipempty
-
-"Array
-syntax region typescriptArray matchgroup=typescriptBraces
- \ start=/\[/ end=/]/
- \ contains=@typescriptValue,@typescriptComments
- \ nextgroup=@typescriptSymbols,typescriptDotNotation
- \ skipwhite skipempty fold
-
-" Number
-syntax match typescriptNumber /\<0[bB][01][01_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
-syntax match typescriptNumber /\<0[oO][0-7][0-7_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
-syntax match typescriptNumber /\<0[xX][0-9a-fA-F][0-9a-fA-F_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
-syntax match typescriptNumber /\d[0-9_]*\.\d[0-9_]*\|\d[0-9_]*\|\.\d[0-9]*/
- \ nextgroup=typescriptExponent,@typescriptSymbols skipwhite skipempty
-syntax match typescriptExponent /[eE][+-]\=\d[0-9]*\>/
- \ nextgroup=@typescriptSymbols skipwhite skipempty contained
-
-
-" runtime syntax/basic/object.vim
-syntax region typescriptObjectLiteral matchgroup=typescriptBraces
- \ start=/{/ end=/}/
- \ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName
- \ fold contained
-
-syntax match typescriptObjectLabel contained /\k\+\_s*/
- \ nextgroup=typescriptObjectColon,@typescriptCallImpl
- \ skipwhite skipempty
-
-syntax region typescriptStringProperty contained
- \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
- \ nextgroup=typescriptObjectColon,@typescriptCallImpl
- \ skipwhite skipempty
-
-" syntax region typescriptPropertyName contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1(/me=e-1 nextgroup=@typescriptCallSignature skipwhite skipempty oneline
-syntax region typescriptComputedPropertyName contained matchgroup=typescriptBraces
- \ start=/\[/rs=s+1 end=/]/
- \ contains=@typescriptValue
- \ nextgroup=typescriptObjectColon,@typescriptCallImpl
- \ skipwhite skipempty
-
-" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*:/he=e-1 contains=@typescriptValue nextgroup=@typescriptValue skipwhite skipempty
-" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*(/me=e-1 contains=@typescriptValue nextgroup=@typescriptCallSignature skipwhite skipempty
-" Value for object, statement for label statement
-syntax match typescriptRestOrSpread /\.\.\./ contained
-syntax match typescriptObjectSpread /\.\.\./ contained containedin=typescriptObjectLiteral,typescriptArray nextgroup=@typescriptValue
-
-syntax match typescriptObjectColon contained /:/ nextgroup=@typescriptValue skipwhite skipempty
-
-"runtime syntax/basic/symbols.vim
-" + - ^ ~
-syntax match typescriptUnaryOp /[+\-~!]/
- \ nextgroup=@typescriptValue
- \ skipwhite
-
-syntax region typescriptTernary matchgroup=typescriptTernaryOp start=/?/ end=/:/ contained contains=@typescriptValue,@typescriptComments nextgroup=@typescriptValue skipwhite skipempty
-
-syntax match typescriptAssign /=/ nextgroup=@typescriptValue
- \ skipwhite skipempty
-
-" 2: ==, ===
-syntax match typescriptBinaryOp contained /===\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 6: >>>=, >>>, >>=, >>, >=, >
-syntax match typescriptBinaryOp contained />\(>>=\|>>\|>=\|>\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 4: <<=, <<, <=, <
-syntax match typescriptBinaryOp contained /<\(<=\|<\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 3: ||, |=, |
-syntax match typescriptBinaryOp contained /|\(|\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 3: &&, &=, &
-syntax match typescriptBinaryOp contained /&\(&\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 2: *=, *
-syntax match typescriptBinaryOp contained /\*=\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 2: %=, %
-syntax match typescriptBinaryOp contained /%=\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 2: /=, /
-syntax match typescriptBinaryOp contained +/\(=\|[^\*/]\@=\)+ nextgroup=@typescriptValue skipwhite skipempty
-syntax match typescriptBinaryOp contained /!==\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 2: !=, !==
-syntax match typescriptBinaryOp contained /+\(+\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 3: +, ++, +=
-syntax match typescriptBinaryOp contained /-\(-\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
-" 3: -, --, -=
-
-" exponentiation operator
-" 2: **, **=
-syntax match typescriptBinaryOp contained /\*\*=\?/ nextgroup=@typescriptValue
-
-syntax cluster typescriptSymbols contains=typescriptBinaryOp,typescriptKeywordOp,typescriptTernary,typescriptAssign,typescriptCastKeyword
-
-"" runtime syntax/basic/reserved.vim
-
-"runtime syntax/basic/keyword.vim
-"Import
-syntax keyword typescriptImport from as import
-syntax keyword typescriptExport export
-syntax keyword typescriptModule namespace module
-
-"this
-
-"JavaScript Prototype
-syntax keyword typescriptPrototype prototype
- \ nextgroup=@afterIdentifier
-
-syntax keyword typescriptCastKeyword as
- \ nextgroup=@typescriptType
- \ skipwhite
-
-"Program Keywords
-syntax keyword typescriptIdentifier arguments this super
- \ nextgroup=@afterIdentifier
-
-syntax keyword typescriptVariable let var
- \ nextgroup=typescriptVariableDeclaration
- \ skipwhite skipempty skipnl
-
-syntax keyword typescriptVariable const
- \ nextgroup=typescriptEnum,typescriptVariableDeclaration
- \ skipwhite
-
-syntax match typescriptVariableDeclaration /[A-Za-z_$]\k*/
- \ nextgroup=typescriptTypeAnnotation,typescriptAssign
- \ contained skipwhite skipempty skipnl
-
-syntax region typescriptEnum matchgroup=typescriptEnumKeyword start=/enum / end=/\ze{/
- \ nextgroup=typescriptBlock
- \ skipwhite
-
-syntax keyword typescriptKeywordOp
- \ contained in instanceof nextgroup=@typescriptValue
-syntax keyword typescriptOperator delete new typeof void
- \ nextgroup=@typescriptValue
- \ skipwhite skipempty
-
-syntax keyword typescriptForOperator contained in of
-syntax keyword typescriptBoolean true false nextgroup=@typescriptSymbols skipwhite skipempty
-syntax keyword typescriptNull null undefined nextgroup=@typescriptSymbols skipwhite skipempty
-syntax keyword typescriptMessage alert confirm prompt status
- \ nextgroup=typescriptDotNotation,typescriptFuncCallArg
-syntax keyword typescriptGlobal self top parent
- \ nextgroup=@afterIdentifier
-
-"Statement Keywords
-syntax keyword typescriptConditional if else switch
- \ nextgroup=typescriptConditionalParen
- \ skipwhite skipempty skipnl
-syntax keyword typescriptConditionalElse else
-syntax keyword typescriptRepeat do while for nextgroup=typescriptLoopParen skipwhite skipempty
-syntax keyword typescriptRepeat for nextgroup=typescriptLoopParen,typescriptAsyncFor skipwhite skipempty
-syntax keyword typescriptBranch break continue containedin=typescriptBlock
-syntax keyword typescriptCase case nextgroup=@typescriptPrimitive skipwhite containedin=typescriptBlock
-syntax keyword typescriptDefault default containedin=typescriptBlock nextgroup=@typescriptValue,typescriptClassKeyword,typescriptInterfaceKeyword skipwhite oneline
-syntax keyword typescriptStatementKeyword with
-syntax keyword typescriptStatementKeyword yield skipwhite nextgroup=@typescriptValue containedin=typescriptBlock
-syntax keyword typescriptStatementKeyword return skipwhite contained nextgroup=@typescriptValue containedin=typescriptBlock
-
-syntax keyword typescriptTry try
-syntax keyword typescriptExceptions catch throw finally
-syntax keyword typescriptDebugger debugger
-
-syntax keyword typescriptAsyncFor await nextgroup=typescriptLoopParen skipwhite skipempty contained
-
-syntax region typescriptLoopParen contained matchgroup=typescriptParens
- \ start=/(/ end=/)/
- \ contains=typescriptVariable,typescriptForOperator,typescriptEndColons,@typescriptValue,@typescriptComments
- \ nextgroup=typescriptBlock
- \ skipwhite skipempty
-syntax region typescriptConditionalParen contained matchgroup=typescriptParens
- \ start=/(/ end=/)/
- \ contains=@typescriptValue,@typescriptComments
- \ nextgroup=typescriptBlock
- \ skipwhite skipempty
-syntax match typescriptEndColons /[;,]/ contained
-
-syntax keyword typescriptAmbientDeclaration declare nextgroup=@typescriptAmbients
- \ skipwhite skipempty
-
-syntax cluster typescriptAmbients contains=
- \ typescriptVariable,
- \ typescriptFuncKeyword,
- \ typescriptClassKeyword,
- \ typescriptAbstract,
- \ typescriptEnumKeyword,typescriptEnum,
- \ typescriptModule
-
-"runtime syntax/basic/doc.vim
-"Syntax coloring for Node.js shebang line
-syntax match shellbang "^#!.*node\>"
-syntax match shellbang "^#!.*iojs\>"
-
-
-"JavaScript comments
-syntax keyword typescriptCommentTodo TODO FIXME XXX TBD
-syntax match typescriptLineComment "//.*"
- \ contains=@Spell,typescriptCommentTodo,typescriptRef
-syntax region typescriptComment
- \ start="/\*" end="\*/"
- \ contains=@Spell,typescriptCommentTodo extend
-syntax cluster typescriptComments
- \ contains=typescriptDocComment,typescriptComment,typescriptLineComment
-
-syntax match typescriptRef +///\s*<reference\s\+.*\/>$+
- \ contains=typescriptString
-syntax match typescriptRef +///\s*<amd-dependency\s\+.*\/>$+
- \ contains=typescriptString
-syntax match typescriptRef +///\s*<amd-module\s\+.*\/>$+
- \ contains=typescriptString
-
-"JSDoc
-syntax case ignore
-
-syntax region typescriptDocComment matchgroup=typescriptComment
- \ start="/\*\*" end="\*/"
- \ contains=typescriptDocNotation,typescriptCommentTodo,@Spell
- \ fold keepend
-syntax match typescriptDocNotation contained /@/ nextgroup=typescriptDocTags
-
-syntax keyword typescriptDocTags contained constant constructor constructs function ignore inner private public readonly static
-syntax keyword typescriptDocTags contained const dict expose inheritDoc interface nosideeffects override protected struct internal
-syntax keyword typescriptDocTags contained example global
-
-" syntax keyword typescriptDocTags contained ngdoc nextgroup=typescriptDocNGDirective
-syntax keyword typescriptDocTags contained ngdoc scope priority animations
-syntax keyword typescriptDocTags contained ngdoc restrict methodOf propertyOf eventOf eventType nextgroup=typescriptDocParam skipwhite
-syntax keyword typescriptDocNGDirective contained overview service object function method property event directive filter inputType error
-
-syntax keyword typescriptDocTags contained abstract virtual access augments
-
-syntax keyword typescriptDocTags contained arguments callback lends memberOf name type kind link mixes mixin tutorial nextgroup=typescriptDocParam skipwhite
-syntax keyword typescriptDocTags contained variation nextgroup=typescriptDocNumParam skipwhite
-
-syntax keyword typescriptDocTags contained author class classdesc copyright default defaultvalue nextgroup=typescriptDocDesc skipwhite
-syntax keyword typescriptDocTags contained deprecated description external host nextgroup=typescriptDocDesc skipwhite
-syntax keyword typescriptDocTags contained file fileOverview overview namespace requires since version nextgroup=typescriptDocDesc skipwhite
-syntax keyword typescriptDocTags contained summary todo license preserve nextgroup=typescriptDocDesc skipwhite
-
-syntax keyword typescriptDocTags contained borrows exports nextgroup=typescriptDocA skipwhite
-syntax keyword typescriptDocTags contained param arg argument property prop module nextgroup=typescriptDocNamedParamType,typescriptDocParamName skipwhite
-syntax keyword typescriptDocTags contained define enum extends implements this typedef nextgroup=typescriptDocParamType skipwhite
-syntax keyword typescriptDocTags contained return returns throws exception nextgroup=typescriptDocParamType,typescriptDocParamName skipwhite
-syntax keyword typescriptDocTags contained see nextgroup=typescriptDocRef skipwhite
-
-syntax keyword typescriptDocTags contained function func method nextgroup=typescriptDocName skipwhite
-syntax match typescriptDocName contained /\h\w*/
-
-syntax keyword typescriptDocTags contained fires event nextgroup=typescriptDocEventRef skipwhite
-syntax match typescriptDocEventRef contained /\h\w*#\(\h\w*\:\)\?\h\w*/
-
-syntax match typescriptDocNamedParamType contained /{.\+}/ nextgroup=typescriptDocParamName skipwhite
-syntax match typescriptDocParamName contained /\[\?0-9a-zA-Z_\.]\+\]\?/ nextgroup=typescriptDocDesc skipwhite
-syntax match typescriptDocParamType contained /{.\+}/ nextgroup=typescriptDocDesc skipwhite
-syntax match typescriptDocA contained /\%(#\|\w\|\.\|:\|\/\)\+/ nextgroup=typescriptDocAs skipwhite
-syntax match typescriptDocAs contained /\s*as\s*/ nextgroup=typescriptDocB skipwhite
-syntax match typescriptDocB contained /\%(#\|\w\|\.\|:\|\/\)\+/
-syntax match typescriptDocParam contained /\%(#\|\w\|\.\|:\|\/\|-\)\+/
-syntax match typescriptDocNumParam contained /\d\+/
-syntax match typescriptDocRef contained /\%(#\|\w\|\.\|:\|\/\)\+/
-syntax region typescriptDocLinkTag contained matchgroup=typescriptDocLinkTag start=/{/ end=/}/ contains=typescriptDocTags
-
-syntax cluster typescriptDocs contains=typescriptDocParamType,typescriptDocNamedParamType,typescriptDocParam
-
-if main_syntax == "typescript"
- syntax sync clear
- syntax sync ccomment typescriptComment minlines=200
-endif
-
-syntax case match
-
-"runtime syntax/basic/type.vim
-" Types
-syntax match typescriptOptionalMark /?/ contained
-
-syntax region typescriptTypeParameters matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/
- \ contains=typescriptTypeParameter
- \ contained
-
-syntax match typescriptTypeParameter /\K\k*/
- \ nextgroup=typescriptConstraint,typescriptGenericDefault
- \ contained skipwhite skipnl
-
-syntax keyword typescriptConstraint extends
- \ nextgroup=@typescriptType
- \ contained skipwhite skipnl
-
-syntax match typescriptGenericDefault /=/
- \ nextgroup=@typescriptType
- \ contained skipwhite
-
-"><
-" class A extend B<T> {} // ClassBlock
-" func<T>() // FuncCallArg
-syntax region typescriptTypeArguments matchgroup=typescriptTypeBrackets
- \ start=/\></ end=/>/
- \ contains=@typescriptType
- \ nextgroup=typescriptFuncCallArg,@typescriptTypeOperator
- \ contained skipwhite
-
-
-syntax cluster typescriptType contains=
- \ @typescriptPrimaryType,
- \ typescriptUnion,
- \ @typescriptFunctionType,
- \ typescriptConstructorType
-
-" array type: A[]
-" type indexing A['key']
-syntax region typescriptTypeBracket contained
- \ start=/\[/ end=/\]/
- \ contains=typescriptString,typescriptNumber
- \ nextgroup=@typescriptTypeOperator
- \ skipwhite skipempty
-
-syntax cluster typescriptPrimaryType contains=
- \ typescriptParenthesizedType,
- \ typescriptPredefinedType,
- \ typescriptTypeReference,
- \ typescriptObjectType,
- \ typescriptTupleType,
- \ typescriptTypeQuery,
- \ typescriptStringLiteralType,
- \ typescriptReadonlyArrayKeyword
-
-syntax region typescriptStringLiteralType contained
- \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/
- \ nextgroup=typescriptUnion
- \ skipwhite skipempty
-
-syntax region typescriptParenthesizedType matchgroup=typescriptParens
- \ start=/(/ end=/)/
- \ contains=@typescriptType
- \ nextgroup=@typescriptTypeOperator
- \ contained skipwhite skipempty fold
-
-syntax match typescriptTypeReference /\K\k*\(\.\K\k*\)*/
- \ nextgroup=typescriptTypeArguments,@typescriptTypeOperator,typescriptUserDefinedType
- \ skipwhite contained skipempty
-
-syntax keyword typescriptPredefinedType any number boolean string void never undefined null object unknown
- \ nextgroup=@typescriptTypeOperator
- \ contained skipwhite skipempty
-
-syntax match typescriptPredefinedType /unique symbol/
- \ nextgroup=@typescriptTypeOperator
- \ contained skipwhite skipempty
-
-syntax region typescriptObjectType matchgroup=typescriptBraces
- \ start=/{/ end=/}/
- \ contains=@typescriptTypeMember,typescriptEndColons,@typescriptComments,typescriptAccessibilityModifier,typescriptReadonlyModifier
- \ nextgroup=@typescriptTypeOperator
- \ contained skipwhite fold
-
-syntax cluster typescriptTypeMember contains=
- \ @typescriptCallSignature,
- \ typescriptConstructSignature,
- \ typescriptIndexSignature,
- \ @typescriptMembers
-
-syntax region typescriptTupleType matchgroup=typescriptBraces
- \ start=/\[/ end=/\]/
- \ contains=@typescriptType
- \ contained skipwhite oneline
-
-syntax cluster typescriptTypeOperator
- \ contains=typescriptUnion,typescriptTypeBracket
-
-syntax match typescriptUnion /|\|&/ contained nextgroup=@typescriptPrimaryType skipwhite skipempty
-
-syntax cluster typescriptFunctionType contains=typescriptGenericFunc,typescriptFuncType
-syntax region typescriptGenericFunc matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/
- \ contains=typescriptTypeParameter
- \ nextgroup=typescriptFuncType
- \ containedin=typescriptFunctionType
- \ contained skipwhite skipnl
-
-syntax region typescriptFuncType matchgroup=typescriptParens
- \ start=/(/ end=/)\s*=>/me=e-2
- \ contains=@typescriptParameterList
- \ nextgroup=typescriptFuncTypeArrow
- \ contained skipwhite skipnl oneline
-
-syntax match typescriptFuncTypeArrow /=>/
- \ nextgroup=@typescriptType
- \ containedin=typescriptFuncType
- \ contained skipwhite skipnl
-
-
-syntax keyword typescriptConstructorType new
- \ nextgroup=@typescriptFunctionType
- \ contained skipwhite skipnl
-
-syntax keyword typescriptUserDefinedType is
- \ contained nextgroup=@typescriptType skipwhite skipempty
-
-syntax keyword typescriptTypeQuery typeof keyof
- \ nextgroup=typescriptTypeReference
- \ contained skipwhite skipnl
-
-syntax cluster typescriptCallSignature contains=typescriptGenericCall,typescriptCall
-syntax region typescriptGenericCall matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/
- \ contains=typescriptTypeParameter
- \ nextgroup=typescriptCall
- \ contained skipwhite skipnl
-syntax region typescriptCall matchgroup=typescriptParens
- \ start=/(/ end=/)/
- \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
- \ nextgroup=typescriptTypeAnnotation,typescriptBlock
- \ contained skipwhite skipnl
-
-syntax match typescriptTypeAnnotation /:/
- \ nextgroup=@typescriptType
- \ contained skipwhite skipnl
-
-syntax cluster typescriptParameterList contains=
- \ typescriptTypeAnnotation,
- \ typescriptAccessibilityModifier,
- \ typescriptOptionalMark,
- \ typescriptRestOrSpread,
- \ typescriptFuncComma,
- \ typescriptDefaultParam
-
-syntax match typescriptFuncComma /,/ contained
-
-syntax match typescriptDefaultParam /=/
- \ nextgroup=@typescriptValue
- \ contained skipwhite
-
-syntax keyword typescriptConstructSignature new
- \ nextgroup=@typescriptCallSignature
- \ contained skipwhite
-
-syntax region typescriptIndexSignature matchgroup=typescriptBraces
- \ start=/\[/ end=/\]/
- \ contains=typescriptPredefinedType,typescriptMappedIn,typescriptString
- \ nextgroup=typescriptTypeAnnotation
- \ contained skipwhite oneline
-
-syntax keyword typescriptMappedIn in
- \ nextgroup=@typescriptType
- \ contained skipwhite skipnl skipempty
-
-syntax keyword typescriptAliasKeyword type
- \ nextgroup=typescriptAliasDeclaration
- \ skipwhite skipnl skipempty
-
-syntax region typescriptAliasDeclaration matchgroup=typescriptUnion
- \ start=/ / end=/=/
- \ nextgroup=@typescriptType
- \ contains=typescriptConstraint,typescriptTypeParameters
- \ contained skipwhite skipempty
-
-syntax keyword typescriptReadonlyArrayKeyword readonly
- \ nextgroup=@typescriptPrimaryType
- \ skipwhite
-
-" extension
-if get(g:, 'yats_host_keyword', 1)
- "runtime syntax/yats.vim
- "runtime syntax/yats/typescript.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Error EvalError
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName arguments
- hi def link typescriptGlobal Structure
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName eval uneval nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isFinite nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isNaN parseFloat nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName parseInt nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURI nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURIComponent nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURI nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURIComponent nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptGlobalMethod
- hi def link typescriptGlobalMethod Structure
-
- "runtime syntax/yats/es6-number.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Number nextgroup=typescriptGlobalNumberDot,typescriptFuncCallArg
- syntax match typescriptGlobalNumberDot /\./ contained nextgroup=typescriptNumberStaticProp,typescriptNumberStaticMethod,typescriptProp
- syntax keyword typescriptNumberStaticProp contained EPSILON MAX_SAFE_INTEGER MAX_VALUE
- syntax keyword typescriptNumberStaticProp contained MIN_SAFE_INTEGER MIN_VALUE NEGATIVE_INFINITY
- syntax keyword typescriptNumberStaticProp contained NaN POSITIVE_INFINITY
- hi def link typescriptNumberStaticProp Keyword
- syntax keyword typescriptNumberStaticMethod contained isFinite isInteger isNaN isSafeInteger nextgroup=typescriptFuncCallArg
- syntax keyword typescriptNumberStaticMethod contained parseFloat parseInt nextgroup=typescriptFuncCallArg
- hi def link typescriptNumberStaticMethod Keyword
- syntax keyword typescriptNumberMethod contained toExponential toFixed toLocaleString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptNumberMethod contained toPrecision toSource toString valueOf nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptNumberMethod
- hi def link typescriptNumberMethod Keyword
-
- "runtime syntax/yats/es6-string.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName String nextgroup=typescriptGlobalStringDot,typescriptFuncCallArg
- syntax match typescriptGlobalStringDot /\./ contained nextgroup=typescriptStringStaticMethod,typescriptProp
- syntax keyword typescriptStringStaticMethod contained fromCharCode fromCodePoint raw nextgroup=typescriptFuncCallArg
- hi def link typescriptStringStaticMethod Keyword
- syntax keyword typescriptStringMethod contained anchor charAt charCodeAt codePointAt nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained concat endsWith includes indexOf lastIndexOf nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained link localeCompare match normalize nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained padStart padEnd repeat replace search nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained slice split startsWith substr substring nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained toLocaleLowerCase toLocaleUpperCase nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained toLowerCase toString toUpperCase trim nextgroup=typescriptFuncCallArg
- syntax keyword typescriptStringMethod contained valueOf nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptStringMethod
- hi def link typescriptStringMethod Keyword
-
- "runtime syntax/yats/es6-array.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Array nextgroup=typescriptGlobalArrayDot,typescriptFuncCallArg
- syntax match typescriptGlobalArrayDot /\./ contained nextgroup=typescriptArrayStaticMethod,typescriptProp
- syntax keyword typescriptArrayStaticMethod contained from isArray of nextgroup=typescriptFuncCallArg
- hi def link typescriptArrayStaticMethod Keyword
- syntax keyword typescriptArrayMethod contained concat copyWithin entries every fill nextgroup=typescriptFuncCallArg
- syntax keyword typescriptArrayMethod contained filter find findIndex forEach indexOf nextgroup=typescriptFuncCallArg
- syntax keyword typescriptArrayMethod contained includes join keys lastIndexOf map nextgroup=typescriptFuncCallArg
- syntax keyword typescriptArrayMethod contained pop push reduce reduceRight reverse nextgroup=typescriptFuncCallArg
- syntax keyword typescriptArrayMethod contained shift slice some sort splice toLocaleString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptArrayMethod contained toSource toString unshift nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptArrayMethod
- hi def link typescriptArrayMethod Keyword
-
- "runtime syntax/yats/es6-object.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Object nextgroup=typescriptGlobalObjectDot,typescriptFuncCallArg
- syntax match typescriptGlobalObjectDot /\./ contained nextgroup=typescriptObjectStaticMethod,typescriptProp
- syntax keyword typescriptObjectStaticMethod contained create defineProperties defineProperty nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectStaticMethod contained entries freeze getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectStaticMethod contained getOwnPropertyDescriptor getOwnPropertyNames nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectStaticMethod contained getOwnPropertySymbols getPrototypeOf nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectStaticMethod contained is isExtensible isFrozen isSealed nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectStaticMethod contained keys preventExtensions values nextgroup=typescriptFuncCallArg
- hi def link typescriptObjectStaticMethod Keyword
- syntax keyword typescriptObjectMethod contained getOwnPropertyDescriptors hasOwnProperty nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectMethod contained isPrototypeOf propertyIsEnumerable nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectMethod contained toLocaleString toString valueOf seal nextgroup=typescriptFuncCallArg
- syntax keyword typescriptObjectMethod contained setPrototypeOf nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptObjectMethod
- hi def link typescriptObjectMethod Keyword
-
- "runtime syntax/yats/es6-symbol.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Symbol nextgroup=typescriptGlobalSymbolDot,typescriptFuncCallArg
- syntax match typescriptGlobalSymbolDot /\./ contained nextgroup=typescriptSymbolStaticProp,typescriptSymbolStaticMethod,typescriptProp
- syntax keyword typescriptSymbolStaticProp contained length iterator match replace
- syntax keyword typescriptSymbolStaticProp contained search split hasInstance isConcatSpreadable
- syntax keyword typescriptSymbolStaticProp contained unscopables species toPrimitive
- syntax keyword typescriptSymbolStaticProp contained toStringTag
- hi def link typescriptSymbolStaticProp Keyword
- syntax keyword typescriptSymbolStaticMethod contained for keyFor nextgroup=typescriptFuncCallArg
- hi def link typescriptSymbolStaticMethod Keyword
-
- "runtime syntax/yats/es6-function.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function
- syntax keyword typescriptFunctionMethod contained apply bind call nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptFunctionMethod
- hi def link typescriptFunctionMethod Keyword
-
- "runtime syntax/yats/es6-math.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Math nextgroup=typescriptGlobalMathDot,typescriptFuncCallArg
- syntax match typescriptGlobalMathDot /\./ contained nextgroup=typescriptMathStaticProp,typescriptMathStaticMethod,typescriptProp
- syntax keyword typescriptMathStaticProp contained E LN10 LN2 LOG10E LOG2E PI SQRT1_2
- syntax keyword typescriptMathStaticProp contained SQRT2
- hi def link typescriptMathStaticProp Keyword
- syntax keyword typescriptMathStaticMethod contained abs acos acosh asin asinh atan nextgroup=typescriptFuncCallArg
- syntax keyword typescriptMathStaticMethod contained atan2 atanh cbrt ceil clz32 cos nextgroup=typescriptFuncCallArg
- syntax keyword typescriptMathStaticMethod contained cosh exp expm1 floor fround hypot nextgroup=typescriptFuncCallArg
- syntax keyword typescriptMathStaticMethod contained imul log log10 log1p log2 max nextgroup=typescriptFuncCallArg
- syntax keyword typescriptMathStaticMethod contained min pow random round sign sin nextgroup=typescriptFuncCallArg
- syntax keyword typescriptMathStaticMethod contained sinh sqrt tan tanh trunc nextgroup=typescriptFuncCallArg
- hi def link typescriptMathStaticMethod Keyword
-
- "runtime syntax/yats/es6-date.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Date nextgroup=typescriptGlobalDateDot,typescriptFuncCallArg
- syntax match typescriptGlobalDateDot /\./ contained nextgroup=typescriptDateStaticMethod,typescriptProp
- syntax keyword typescriptDateStaticMethod contained UTC now parse nextgroup=typescriptFuncCallArg
- hi def link typescriptDateStaticMethod Keyword
- syntax keyword typescriptDateMethod contained getDate getDay getFullYear getHours nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained getMilliseconds getMinutes getMonth nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained getSeconds getTime getTimezoneOffset nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained getUTCDate getUTCDay getUTCFullYear nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained getUTCHours getUTCMilliseconds getUTCMinutes nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained getUTCMonth getUTCSeconds setDate setFullYear nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained setHours setMilliseconds setMinutes nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained setMonth setSeconds setTime setUTCDate nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained setUTCFullYear setUTCHours setUTCMilliseconds nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained setUTCMinutes setUTCMonth setUTCSeconds nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained toDateString toISOString toJSON toLocaleDateString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained toLocaleFormat toLocaleString toLocaleTimeString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained toSource toString toTimeString toUTCString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDateMethod contained valueOf nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptDateMethod
- hi def link typescriptDateMethod Keyword
-
- "runtime syntax/yats/es6-json.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName JSON nextgroup=typescriptGlobalJSONDot,typescriptFuncCallArg
- syntax match typescriptGlobalJSONDot /\./ contained nextgroup=typescriptJSONStaticMethod,typescriptProp
- syntax keyword typescriptJSONStaticMethod contained parse stringify nextgroup=typescriptFuncCallArg
- hi def link typescriptJSONStaticMethod Keyword
-
- "runtime syntax/yats/es6-regexp.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName RegExp nextgroup=typescriptGlobalRegExpDot,typescriptFuncCallArg
- syntax match typescriptGlobalRegExpDot /\./ contained nextgroup=typescriptRegExpStaticProp,typescriptProp
- syntax keyword typescriptRegExpStaticProp contained lastIndex
- hi def link typescriptRegExpStaticProp Keyword
- syntax keyword typescriptRegExpProp contained global ignoreCase multiline source sticky
- syntax cluster props add=typescriptRegExpProp
- hi def link typescriptRegExpProp Keyword
- syntax keyword typescriptRegExpMethod contained exec test nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptRegExpMethod
- hi def link typescriptRegExpMethod Keyword
-
- "runtime syntax/yats/es6-map.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Map WeakMap
- syntax keyword typescriptES6MapProp contained size
- syntax cluster props add=typescriptES6MapProp
- hi def link typescriptES6MapProp Keyword
- syntax keyword typescriptES6MapMethod contained clear delete entries forEach get has nextgroup=typescriptFuncCallArg
- syntax keyword typescriptES6MapMethod contained keys set values nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptES6MapMethod
- hi def link typescriptES6MapMethod Keyword
-
- "runtime syntax/yats/es6-set.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Set WeakSet
- syntax keyword typescriptES6SetProp contained size
- syntax cluster props add=typescriptES6SetProp
- hi def link typescriptES6SetProp Keyword
- syntax keyword typescriptES6SetMethod contained add clear delete entries forEach has nextgroup=typescriptFuncCallArg
- syntax keyword typescriptES6SetMethod contained values nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptES6SetMethod
- hi def link typescriptES6SetMethod Keyword
-
- "runtime syntax/yats/es6-proxy.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Proxy
- syntax keyword typescriptProxyAPI contained getOwnPropertyDescriptor getOwnPropertyNames
- syntax keyword typescriptProxyAPI contained defineProperty deleteProperty freeze seal
- syntax keyword typescriptProxyAPI contained preventExtensions has hasOwn get set enumerate
- syntax keyword typescriptProxyAPI contained iterate ownKeys apply construct
- hi def link typescriptProxyAPI Keyword
-
- "runtime syntax/yats/es6-promise.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Promise nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg
- syntax match typescriptGlobalPromiseDot /\./ contained nextgroup=typescriptPromiseStaticMethod,typescriptProp
- syntax keyword typescriptPromiseStaticMethod contained resolve reject all race nextgroup=typescriptFuncCallArg
- hi def link typescriptPromiseStaticMethod Keyword
- syntax keyword typescriptPromiseMethod contained then catch finally nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptPromiseMethod
- hi def link typescriptPromiseMethod Keyword
-
- "runtime syntax/yats/es6-reflect.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect
- syntax keyword typescriptReflectMethod contained apply construct defineProperty deleteProperty nextgroup=typescriptFuncCallArg
- syntax keyword typescriptReflectMethod contained enumerate get getOwnPropertyDescriptor nextgroup=typescriptFuncCallArg
- syntax keyword typescriptReflectMethod contained getPrototypeOf has isExtensible ownKeys nextgroup=typescriptFuncCallArg
- syntax keyword typescriptReflectMethod contained preventExtensions set setPrototypeOf nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptReflectMethod
- hi def link typescriptReflectMethod Keyword
-
- "runtime syntax/yats/ecma-402.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Intl
- syntax keyword typescriptIntlMethod contained Collator DateTimeFormat NumberFormat nextgroup=typescriptFuncCallArg
- syntax keyword typescriptIntlMethod contained PluralRules nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptIntlMethod
- hi def link typescriptIntlMethod Keyword
-
- "runtime syntax/yats/node.vim
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName global process
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName console Buffer
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName module exports
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setTimeout
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearTimeout
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setInterval
- syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearInterval
- hi def link typescriptNodeGlobal Structure
-
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName describe it test
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName before after
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName beforeEach afterEach
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName beforeAll afterAll
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName expect assert
-
- "runtime syntax/yats/web.vim
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AbortController
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AbstractWorker AnalyserNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName App Apps ArrayBuffer
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ArrayBufferView
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Attr AudioBuffer
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioBufferSourceNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioContext AudioDestinationNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioListener AudioNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioParam BatteryManager
- syntax keyword typescriptBOM containedin=typescriptIdentifierName BiquadFilterNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName BlobEvent BluetoothAdapter
- syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothDevice
- syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothManager
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraCapabilities
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraControl CameraManager
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasGradient CanvasImageSource
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasPattern CanvasRenderingContext2D
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CaretPosition CDATASection
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelMergerNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelSplitterNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CharacterData ChildNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ChromeWorker Comment
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Connection Console
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ContactManager Contacts
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ConvolverNode Coordinates
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSS CSSConditionRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSGroupingRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframeRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframesRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSMediaRule CSSNamespaceRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSPageRule CSSRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSRuleList CSSStyleDeclaration
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSStyleRule CSSStyleSheet
- syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSSupportsRule
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DataTransfer DataView
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DedicatedWorkerGlobalScope
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DelayNode DeviceAcceleration
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceRotationRate
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceStorage DirectoryEntry
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryEntrySync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReader
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReaderSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Document DocumentFragment
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DocumentTouch DocumentType
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMCursor DOMError
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMException DOMHighResTimeStamp
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementation
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementationRegistry
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMParser DOMRequest
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMString DOMStringList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMStringMap DOMTimeStamp
- syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMTokenList DynamicsCompressorNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Element Entry EntrySync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Extensions FileException
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Float32Array Float64Array
- syntax keyword typescriptBOM containedin=typescriptIdentifierName FMRadio FormData
- syntax keyword typescriptBOM containedin=typescriptIdentifierName GainNode Gamepad
- syntax keyword typescriptBOM containedin=typescriptIdentifierName GamepadButton Geolocation
- syntax keyword typescriptBOM containedin=typescriptIdentifierName History HTMLAnchorElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAreaElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAudioElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBaseElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBodyElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBRElement HTMLButtonElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCanvasElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCollection HTMLDataElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDataListElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDivElement HTMLDListElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDocument HTMLElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLEmbedElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFieldSetElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormControlsCollection
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadingElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHRElement HTMLHtmlElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLIFrameElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLImageElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLInputElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLKeygenElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLabelElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLegendElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLIElement HTMLLinkElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMapElement HTMLMediaElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMetaElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMeterElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLModElement HTMLObjectElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOListElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptGroupElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionsCollection
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOutputElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParagraphElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParamElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLPreElement HTMLProgressElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLQuoteElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLScriptElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSelectElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSourceElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSpanElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLStyleElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCaptionElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCellElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableColElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableDataCellElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableHeaderCellElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableRowElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableSectionElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTextAreaElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTimeElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTitleElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTrackElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUListElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUnknownElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLVideoElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursor IDBCursorSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursorWithValue
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBDatabase IDBDatabaseSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBEnvironment IDBEnvironmentSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBFactory IDBFactorySync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBIndex IDBIndexSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBKeyRange IDBObjectStore
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBObjectStoreSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBOpenDBRequest
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBRequest IDBTransaction
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBTransactionSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBVersionChangeEvent
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ImageData IndexedDB
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Int16Array Int32Array
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Int8Array L10n LinkStyle
- syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystem
- syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystemSync
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Location LockedFile
- syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaQueryList MediaQueryListListener
- syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaRecorder MediaSource
- syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaStream MediaStreamTrack
- syntax keyword typescriptBOM containedin=typescriptIdentifierName MutationObserver
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Navigator NavigatorGeolocation
- syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorID NavigatorLanguage
- syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorOnLine
- syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorPlugins
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Node NodeFilter
- syntax keyword typescriptBOM containedin=typescriptIdentifierName NodeIterator NodeList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Notification OfflineAudioContext
- syntax keyword typescriptBOM containedin=typescriptIdentifierName OscillatorNode PannerNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ParentNode Performance
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceNavigation
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceTiming
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Permissions PermissionSettings
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Plugin PluginArray
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Position PositionError
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PositionOptions
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PowerManager ProcessingInstruction
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PromiseResolver
- syntax keyword typescriptBOM containedin=typescriptIdentifierName PushManager Range
- syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCConfiguration
- syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnection
- syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnectionErrorCallback
- syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescription
- syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescriptionCallback
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ScriptProcessorNode
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Selection SettingsLock
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SettingsManager
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SharedWorker StyleSheet
- syntax keyword typescriptBOM containedin=typescriptIdentifierName StyleSheetList SVGAElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAngle SVGAnimateColorElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedAngle
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedBoolean
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedEnumeration
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedInteger
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLength
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLengthList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumber
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumberList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPoints
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPreserveAspectRatio
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedRect
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedString
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedTransformList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateMotionElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateTransformElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimationElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCircleElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGClipPathElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCursorElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGDefsElement SVGDescElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGElement SVGEllipseElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFilterElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontElement SVGFontFaceElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceFormatElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceNameElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceSrcElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceUriElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGForeignObjectElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGElement SVGGlyphElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGradientElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGHKernElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGImageElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLength SVGLengthList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLinearGradientElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLineElement SVGMaskElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMatrix SVGMissingGlyphElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMPathElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGNumber SVGNumberList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPathElement SVGPatternElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPoint SVGPolygonElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPolylineElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPreserveAspectRatio
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRadialGradientElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRect SVGRectElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGScriptElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSetElement SVGStopElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStringList SVGStylable
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStyleElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSVGElement SVGSwitchElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSymbolElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTests SVGTextElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTextPositioningElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTitleElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransform SVGTransformable
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransformList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTRefElement SVGTSpanElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGUseElement SVGViewElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGVKernElement
- syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPServerSocket
- syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPSocket Telephony
- syntax keyword typescriptBOM containedin=typescriptIdentifierName TelephonyCall Text
- syntax keyword typescriptBOM containedin=typescriptIdentifierName TextDecoder TextEncoder
- syntax keyword typescriptBOM containedin=typescriptIdentifierName TextMetrics TimeRanges
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Touch TouchList
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Transferable TreeWalker
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint16Array Uint32Array
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint8Array Uint8ClampedArray
- syntax keyword typescriptBOM containedin=typescriptIdentifierName URLSearchParams
- syntax keyword typescriptBOM containedin=typescriptIdentifierName URLUtilsReadOnly
- syntax keyword typescriptBOM containedin=typescriptIdentifierName UserProximityEvent
- syntax keyword typescriptBOM containedin=typescriptIdentifierName ValidityState VideoPlaybackQuality
- syntax keyword typescriptBOM containedin=typescriptIdentifierName WaveShaperNode WebBluetooth
- syntax keyword typescriptBOM containedin=typescriptIdentifierName WebGLRenderingContext
- syntax keyword typescriptBOM containedin=typescriptIdentifierName WebSMS WebSocket
- syntax keyword typescriptBOM containedin=typescriptIdentifierName WebVTT WifiManager
- syntax keyword typescriptBOM containedin=typescriptIdentifierName Window Worker WorkerConsole
- syntax keyword typescriptBOM containedin=typescriptIdentifierName WorkerLocation WorkerNavigator
- syntax keyword typescriptBOM containedin=typescriptIdentifierName XDomainRequest XMLDocument
- syntax keyword typescriptBOM containedin=typescriptIdentifierName XMLHttpRequestEventTarget
- hi def link typescriptBOM Structure
-
- "runtime syntax/yats/web-window.vim
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName applicationCache
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName closed
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName Components
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName controllers
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName dialogArguments
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName document
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frameElement
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frames
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName fullScreen
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName history
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerHeight
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerWidth
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName length
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName location
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName locationbar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName menubar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName messageManager
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName name navigator
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName opener
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerHeight
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerWidth
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageXOffset
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageYOffset
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName parent
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName performance
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName personalbar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName returnValue
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screen
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenX
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenY
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollbars
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxX
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxY
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollX
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollY
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName self sidebar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName status
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName statusbar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName toolbar
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName top visualViewport
- syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName window
- syntax cluster props add=typescriptBOMWindowProp
- hi def link typescriptBOMWindowProp Structure
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName alert nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName atob nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName blur nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName btoa nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearImmediate nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearInterval nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearTimeout nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName close nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName confirm nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName dispatchEvent nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName find nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName focus nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttention nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttentionWithCycleCount nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getComputedStyle nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getDefaulComputedStyle nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getSelection nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName matchMedia nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName maximize nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveBy nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveTo nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName open nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName openDialog nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName postMessage nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName print nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName prompt nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName removeEventListener nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeBy nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeTo nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName restore nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scroll nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollBy nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByLines nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByPages nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollTo nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setCursor nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setImmediate nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setInterval nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setResizable nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setTimeout nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName showModalDialog nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName sizeToContent nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName stop nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName updateCommands nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptBOMWindowMethod
- hi def link typescriptBOMWindowMethod Structure
- syntax keyword typescriptBOMWindowEvent contained onabort onbeforeunload onblur onchange
- syntax keyword typescriptBOMWindowEvent contained onclick onclose oncontextmenu ondevicelight
- syntax keyword typescriptBOMWindowEvent contained ondevicemotion ondeviceorientation
- syntax keyword typescriptBOMWindowEvent contained ondeviceproximity ondragdrop onerror
- syntax keyword typescriptBOMWindowEvent contained onfocus onhashchange onkeydown onkeypress
- syntax keyword typescriptBOMWindowEvent contained onkeyup onload onmousedown onmousemove
- syntax keyword typescriptBOMWindowEvent contained onmouseout onmouseover onmouseup
- syntax keyword typescriptBOMWindowEvent contained onmozbeforepaint onpaint onpopstate
- syntax keyword typescriptBOMWindowEvent contained onreset onresize onscroll onselect
- syntax keyword typescriptBOMWindowEvent contained onsubmit onunload onuserproximity
- syntax keyword typescriptBOMWindowEvent contained onpageshow onpagehide
- hi def link typescriptBOMWindowEvent Keyword
- syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName DOMParser
- syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName QueryInterface
- syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName XMLSerializer
- hi def link typescriptBOMWindowCons Structure
-
- "runtime syntax/yats/web-navigator.vim
- syntax keyword typescriptBOMNavigatorProp contained battery buildID connection cookieEnabled
- syntax keyword typescriptBOMNavigatorProp contained doNotTrack maxTouchPoints oscpu
- syntax keyword typescriptBOMNavigatorProp contained productSub push serviceWorker
- syntax keyword typescriptBOMNavigatorProp contained vendor vendorSub
- syntax cluster props add=typescriptBOMNavigatorProp
- hi def link typescriptBOMNavigatorProp Keyword
- syntax keyword typescriptBOMNavigatorMethod contained addIdleObserver geolocation nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMNavigatorMethod contained getDeviceStorage getDeviceStorages nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMNavigatorMethod contained getGamepads getUserMedia registerContentHandler nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMNavigatorMethod contained removeIdleObserver requestWakeLock nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMNavigatorMethod contained share vibrate watch registerProtocolHandler nextgroup=typescriptFuncCallArg
- syntax keyword typescriptBOMNavigatorMethod contained sendBeacon nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptBOMNavigatorMethod
- hi def link typescriptBOMNavigatorMethod Keyword
- syntax keyword typescriptServiceWorkerMethod contained register nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptServiceWorkerMethod
- hi def link typescriptServiceWorkerMethod Keyword
-
- "runtime syntax/yats/web-location.vim
- syntax keyword typescriptBOMLocationProp contained href protocol host hostname port
- syntax keyword typescriptBOMLocationProp contained pathname search hash username password
- syntax keyword typescriptBOMLocationProp contained origin
- syntax cluster props add=typescriptBOMLocationProp
- hi def link typescriptBOMLocationProp Keyword
- syntax keyword typescriptBOMLocationMethod contained assign reload replace toString nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptBOMLocationMethod
- hi def link typescriptBOMLocationMethod Keyword
-
- "runtime syntax/yats/web-history.vim
- syntax keyword typescriptBOMHistoryProp contained length current next previous state
- syntax keyword typescriptBOMHistoryProp contained scrollRestoration
- syntax cluster props add=typescriptBOMHistoryProp
- hi def link typescriptBOMHistoryProp Keyword
- syntax keyword typescriptBOMHistoryMethod contained back forward go pushState replaceState nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptBOMHistoryMethod
- hi def link typescriptBOMHistoryMethod Keyword
-
- "runtime syntax/yats/web-console.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName console
- syntax keyword typescriptConsoleMethod contained count dir error group groupCollapsed nextgroup=typescriptFuncCallArg
- syntax keyword typescriptConsoleMethod contained groupEnd info log time timeEnd trace nextgroup=typescriptFuncCallArg
- syntax keyword typescriptConsoleMethod contained warn nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptConsoleMethod
- hi def link typescriptConsoleMethod Keyword
-
- "runtime syntax/yats/web-xhr.vim
- syntax keyword typescriptXHRGlobal containedin=typescriptIdentifierName XMLHttpRequest
- hi def link typescriptXHRGlobal Structure
- syntax keyword typescriptXHRProp contained onreadystatechange readyState response
- syntax keyword typescriptXHRProp contained responseText responseType responseXML status
- syntax keyword typescriptXHRProp contained statusText timeout ontimeout upload withCredentials
- syntax cluster props add=typescriptXHRProp
- hi def link typescriptXHRProp Keyword
- syntax keyword typescriptXHRMethod contained abort getAllResponseHeaders getResponseHeader nextgroup=typescriptFuncCallArg
- syntax keyword typescriptXHRMethod contained open overrideMimeType send setRequestHeader nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptXHRMethod
- hi def link typescriptXHRMethod Keyword
-
- "runtime syntax/yats/web-blob.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Blob BlobBuilder
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName File FileReader
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName FileReaderSync
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName URL nextgroup=typescriptGlobalURLDot,typescriptFuncCallArg
- syntax match typescriptGlobalURLDot /\./ contained nextgroup=typescriptURLStaticMethod,typescriptProp
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName URLUtils
- syntax keyword typescriptFileMethod contained readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptFileMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptFileMethod
- hi def link typescriptFileMethod Keyword
- syntax keyword typescriptFileReaderProp contained error readyState result
- syntax cluster props add=typescriptFileReaderProp
- hi def link typescriptFileReaderProp Keyword
- syntax keyword typescriptFileReaderMethod contained abort readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
- syntax keyword typescriptFileReaderMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptFileReaderMethod
- hi def link typescriptFileReaderMethod Keyword
- syntax keyword typescriptFileListMethod contained item nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptFileListMethod
- hi def link typescriptFileListMethod Keyword
- syntax keyword typescriptBlobMethod contained append getBlob getFile nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptBlobMethod
- hi def link typescriptBlobMethod Keyword
- syntax keyword typescriptURLUtilsProp contained hash host hostname href origin password
- syntax keyword typescriptURLUtilsProp contained pathname port protocol search searchParams
- syntax keyword typescriptURLUtilsProp contained username
- syntax cluster props add=typescriptURLUtilsProp
- hi def link typescriptURLUtilsProp Keyword
- syntax keyword typescriptURLStaticMethod contained createObjectURL revokeObjectURL nextgroup=typescriptFuncCallArg
- hi def link typescriptURLStaticMethod Keyword
-
- "runtime syntax/yats/web-crypto.vim
- syntax keyword typescriptCryptoGlobal containedin=typescriptIdentifierName crypto
- hi def link typescriptCryptoGlobal Structure
- syntax keyword typescriptSubtleCryptoMethod contained encrypt decrypt sign verify nextgroup=typescriptFuncCallArg
- syntax keyword typescriptSubtleCryptoMethod contained digest nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptSubtleCryptoMethod
- hi def link typescriptSubtleCryptoMethod Keyword
- syntax keyword typescriptCryptoProp contained subtle
- syntax cluster props add=typescriptCryptoProp
- hi def link typescriptCryptoProp Keyword
- syntax keyword typescriptCryptoMethod contained getRandomValues nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptCryptoMethod
- hi def link typescriptCryptoMethod Keyword
-
- "runtime syntax/yats/web-fetch.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Headers Request
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Response
- syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName fetch nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptGlobalMethod
- hi def link typescriptGlobalMethod Structure
- syntax keyword typescriptHeadersMethod contained append delete get getAll has set nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptHeadersMethod
- hi def link typescriptHeadersMethod Keyword
- syntax keyword typescriptRequestProp contained method url headers context referrer
- syntax keyword typescriptRequestProp contained mode credentials cache
- syntax cluster props add=typescriptRequestProp
- hi def link typescriptRequestProp Keyword
- syntax keyword typescriptRequestMethod contained clone nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptRequestMethod
- hi def link typescriptRequestMethod Keyword
- syntax keyword typescriptResponseProp contained type url status statusText headers
- syntax keyword typescriptResponseProp contained redirected
- syntax cluster props add=typescriptResponseProp
- hi def link typescriptResponseProp Keyword
- syntax keyword typescriptResponseMethod contained clone nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptResponseMethod
- hi def link typescriptResponseMethod Keyword
-
- "runtime syntax/yats/web-service-worker.vim
- syntax keyword typescriptServiceWorkerProp contained controller ready
- syntax cluster props add=typescriptServiceWorkerProp
- hi def link typescriptServiceWorkerProp Keyword
- syntax keyword typescriptServiceWorkerMethod contained register getRegistration nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptServiceWorkerMethod
- hi def link typescriptServiceWorkerMethod Keyword
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Cache
- syntax keyword typescriptCacheMethod contained match matchAll add addAll put delete nextgroup=typescriptFuncCallArg
- syntax keyword typescriptCacheMethod contained keys nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptCacheMethod
- hi def link typescriptCacheMethod Keyword
-
- "runtime syntax/yats/web-encoding.vim
- syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextEncoder
- syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextDecoder
- hi def link typescriptEncodingGlobal Structure
- syntax keyword typescriptEncodingProp contained encoding fatal ignoreBOM
- syntax cluster props add=typescriptEncodingProp
- hi def link typescriptEncodingProp Keyword
- syntax keyword typescriptEncodingMethod contained encode decode nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptEncodingMethod
- hi def link typescriptEncodingMethod Keyword
-
- "runtime syntax/yats/web-geo.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName Geolocation
- syntax keyword typescriptGeolocationMethod contained getCurrentPosition watchPosition nextgroup=typescriptFuncCallArg
- syntax keyword typescriptGeolocationMethod contained clearWatch nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptGeolocationMethod
- hi def link typescriptGeolocationMethod Keyword
-
- "runtime syntax/yats/web-network.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName NetworkInformation
- syntax keyword typescriptBOMNetworkProp contained downlink downlinkMax effectiveType
- syntax keyword typescriptBOMNetworkProp contained rtt type
- syntax cluster props add=typescriptBOMNetworkProp
- hi def link typescriptBOMNetworkProp Keyword
-
- "runtime syntax/yats/web-payment.vim
- syntax keyword typescriptGlobal containedin=typescriptIdentifierName PaymentRequest
- syntax keyword typescriptPaymentMethod contained show abort canMakePayment nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptPaymentMethod
- hi def link typescriptPaymentMethod Keyword
- syntax keyword typescriptPaymentProp contained shippingAddress shippingOption result
- syntax cluster props add=typescriptPaymentProp
- hi def link typescriptPaymentProp Keyword
- syntax keyword typescriptPaymentEvent contained onshippingaddresschange onshippingoptionchange
- hi def link typescriptPaymentEvent Keyword
- syntax keyword typescriptPaymentResponseMethod contained complete nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptPaymentResponseMethod
- hi def link typescriptPaymentResponseMethod Keyword
- syntax keyword typescriptPaymentResponseProp contained details methodName payerEmail
- syntax keyword typescriptPaymentResponseProp contained payerPhone shippingAddress
- syntax keyword typescriptPaymentResponseProp contained shippingOption
- syntax cluster props add=typescriptPaymentResponseProp
- hi def link typescriptPaymentResponseProp Keyword
- syntax keyword typescriptPaymentAddressProp contained addressLine careOf city country
- syntax keyword typescriptPaymentAddressProp contained country dependentLocality languageCode
- syntax keyword typescriptPaymentAddressProp contained organization phone postalCode
- syntax keyword typescriptPaymentAddressProp contained recipient region sortingCode
- syntax cluster props add=typescriptPaymentAddressProp
- hi def link typescriptPaymentAddressProp Keyword
- syntax keyword typescriptPaymentShippingOptionProp contained id label amount selected
- syntax cluster props add=typescriptPaymentShippingOptionProp
- hi def link typescriptPaymentShippingOptionProp Keyword
-
- "runtime syntax/yats/dom-node.vim
- syntax keyword typescriptDOMNodeProp contained attributes baseURI baseURIObject childNodes
- syntax keyword typescriptDOMNodeProp contained firstChild lastChild localName namespaceURI
- syntax keyword typescriptDOMNodeProp contained nextSibling nodeName nodePrincipal
- syntax keyword typescriptDOMNodeProp contained nodeType nodeValue ownerDocument parentElement
- syntax keyword typescriptDOMNodeProp contained parentNode prefix previousSibling textContent
- syntax cluster props add=typescriptDOMNodeProp
- hi def link typescriptDOMNodeProp Keyword
- syntax keyword typescriptDOMNodeMethod contained appendChild cloneNode compareDocumentPosition nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMNodeMethod contained getUserData hasAttributes hasChildNodes nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMNodeMethod contained insertBefore isDefaultNamespace isEqualNode nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMNodeMethod contained isSameNode isSupported lookupNamespaceURI nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMNodeMethod contained lookupPrefix normalize removeChild nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMNodeMethod contained replaceChild setUserData nextgroup=typescriptFuncCallArg
- syntax match typescriptDOMNodeMethod contained /contains/
- syntax cluster props add=typescriptDOMNodeMethod
- hi def link typescriptDOMNodeMethod Keyword
- syntax keyword typescriptDOMNodeType contained ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE
- syntax keyword typescriptDOMNodeType contained CDATA_SECTION_NODEN_NODE ENTITY_REFERENCE_NODE
- syntax keyword typescriptDOMNodeType contained ENTITY_NODE PROCESSING_INSTRUCTION_NODEN_NODE
- syntax keyword typescriptDOMNodeType contained COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE
- syntax keyword typescriptDOMNodeType contained DOCUMENT_FRAGMENT_NODE NOTATION_NODE
- hi def link typescriptDOMNodeType Keyword
-
- "runtime syntax/yats/dom-elem.vim
- syntax keyword typescriptDOMElemAttrs contained accessKey clientHeight clientLeft
- syntax keyword typescriptDOMElemAttrs contained clientTop clientWidth id innerHTML
- syntax keyword typescriptDOMElemAttrs contained length onafterscriptexecute onbeforescriptexecute
- syntax keyword typescriptDOMElemAttrs contained oncopy oncut onpaste onwheel scrollHeight
- syntax keyword typescriptDOMElemAttrs contained scrollLeft scrollTop scrollWidth tagName
- syntax keyword typescriptDOMElemAttrs contained classList className name outerHTML
- syntax keyword typescriptDOMElemAttrs contained style
- hi def link typescriptDOMElemAttrs Keyword
- syntax keyword typescriptDOMElemFuncs contained getAttributeNS getAttributeNode getAttributeNodeNS
- syntax keyword typescriptDOMElemFuncs contained getBoundingClientRect getClientRects
- syntax keyword typescriptDOMElemFuncs contained getElementsByClassName getElementsByTagName
- syntax keyword typescriptDOMElemFuncs contained getElementsByTagNameNS hasAttribute
- syntax keyword typescriptDOMElemFuncs contained hasAttributeNS insertAdjacentHTML
- syntax keyword typescriptDOMElemFuncs contained matches querySelector querySelectorAll
- syntax keyword typescriptDOMElemFuncs contained removeAttribute removeAttributeNS
- syntax keyword typescriptDOMElemFuncs contained removeAttributeNode requestFullscreen
- syntax keyword typescriptDOMElemFuncs contained requestPointerLock scrollIntoView
- syntax keyword typescriptDOMElemFuncs contained setAttribute setAttributeNS setAttributeNode
- syntax keyword typescriptDOMElemFuncs contained setAttributeNodeNS setCapture supports
- syntax keyword typescriptDOMElemFuncs contained getAttribute
- hi def link typescriptDOMElemFuncs Keyword
-
- "runtime syntax/yats/dom-document.vim
- syntax keyword typescriptDOMDocProp contained activeElement body cookie defaultView
- syntax keyword typescriptDOMDocProp contained designMode dir domain embeds forms head
- syntax keyword typescriptDOMDocProp contained images lastModified links location plugins
- syntax keyword typescriptDOMDocProp contained postMessage readyState referrer registerElement
- syntax keyword typescriptDOMDocProp contained scripts styleSheets title vlinkColor
- syntax keyword typescriptDOMDocProp contained xmlEncoding characterSet compatMode
- syntax keyword typescriptDOMDocProp contained contentType currentScript doctype documentElement
- syntax keyword typescriptDOMDocProp contained documentURI documentURIObject firstChild
- syntax keyword typescriptDOMDocProp contained implementation lastStyleSheetSet namespaceURI
- syntax keyword typescriptDOMDocProp contained nodePrincipal ononline pointerLockElement
- syntax keyword typescriptDOMDocProp contained popupNode preferredStyleSheetSet selectedStyleSheetSet
- syntax keyword typescriptDOMDocProp contained styleSheetSets textContent tooltipNode
- syntax cluster props add=typescriptDOMDocProp
- hi def link typescriptDOMDocProp Keyword
- syntax keyword typescriptDOMDocMethod contained caretPositionFromPoint close createNodeIterator nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained createRange createTreeWalker elementFromPoint nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained getElementsByName adoptNode createAttribute nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained createCDATASection createComment createDocumentFragment nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained createElement createElementNS createEvent nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained createExpression createNSResolver nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained createProcessingInstruction createTextNode nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained enableStyleSheetsForSet evaluate execCommand nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained exitPointerLock getBoxObjectFor getElementById nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained getElementsByClassName getElementsByTagName nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained getElementsByTagNameNS getSelection nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained hasFocus importNode loadOverlay open nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained queryCommandSupported querySelector nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMDocMethod contained querySelectorAll write writeln nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptDOMDocMethod
- hi def link typescriptDOMDocMethod Keyword
-
- "runtime syntax/yats/dom-event.vim
- syntax keyword typescriptDOMEventTargetMethod contained addEventListener removeEventListener nextgroup=typescriptEventFuncCallArg
- syntax keyword typescriptDOMEventTargetMethod contained dispatchEvent waitUntil nextgroup=typescriptEventFuncCallArg
- syntax cluster props add=typescriptDOMEventTargetMethod
- hi def link typescriptDOMEventTargetMethod Keyword
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AnimationEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AudioProcessingEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeInputEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeUnloadEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BlobEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ClipboardEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CloseEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CompositionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CSSFontFaceLoadEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CustomEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceLightEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceMotionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceOrientationEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceProximityEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DOMTransactionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DragEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName EditingBeforeInputEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ErrorEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName FocusEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName GamepadEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName HashChangeEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName IDBVersionChangeEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName KeyboardEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MediaStreamEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MessageEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MouseEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MutationEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName OfflineAudioCompletionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PageTransitionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PointerEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PopStateEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ProgressEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RelatedEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RTCPeerConnectionIceEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SensorEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName StorageEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGZoomEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TimeEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TouchEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TrackEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TransitionEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UIEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UserProximityEvent
- syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName WheelEvent
- hi def link typescriptDOMEventCons Structure
- syntax keyword typescriptDOMEventProp contained bubbles cancelable currentTarget defaultPrevented
- syntax keyword typescriptDOMEventProp contained eventPhase target timeStamp type isTrusted
- syntax keyword typescriptDOMEventProp contained isReload
- syntax cluster props add=typescriptDOMEventProp
- hi def link typescriptDOMEventProp Keyword
- syntax keyword typescriptDOMEventMethod contained initEvent preventDefault stopImmediatePropagation nextgroup=typescriptEventFuncCallArg
- syntax keyword typescriptDOMEventMethod contained stopPropagation respondWith default nextgroup=typescriptEventFuncCallArg
- syntax cluster props add=typescriptDOMEventMethod
- hi def link typescriptDOMEventMethod Keyword
-
- "runtime syntax/yats/dom-storage.vim
- syntax keyword typescriptDOMStorage contained sessionStorage localStorage
- hi def link typescriptDOMStorage Keyword
- syntax keyword typescriptDOMStorageProp contained length
- syntax cluster props add=typescriptDOMStorageProp
- hi def link typescriptDOMStorageProp Keyword
- syntax keyword typescriptDOMStorageMethod contained getItem key setItem removeItem nextgroup=typescriptFuncCallArg
- syntax keyword typescriptDOMStorageMethod contained clear nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptDOMStorageMethod
- hi def link typescriptDOMStorageMethod Keyword
-
- "runtime syntax/yats/dom-form.vim
- syntax keyword typescriptDOMFormProp contained acceptCharset action elements encoding
- syntax keyword typescriptDOMFormProp contained enctype length method name target
- syntax cluster props add=typescriptDOMFormProp
- hi def link typescriptDOMFormProp Keyword
- syntax keyword typescriptDOMFormMethod contained reportValidity reset submit nextgroup=typescriptFuncCallArg
- syntax cluster props add=typescriptDOMFormMethod
- hi def link typescriptDOMFormMethod Keyword
-
- "runtime syntax/yats/css.vim
- syntax keyword typescriptDOMStyle contained alignContent alignItems alignSelf animation
- syntax keyword typescriptDOMStyle contained animationDelay animationDirection animationDuration
- syntax keyword typescriptDOMStyle contained animationFillMode animationIterationCount
- syntax keyword typescriptDOMStyle contained animationName animationPlayState animationTimingFunction
- syntax keyword typescriptDOMStyle contained appearance backfaceVisibility background
- syntax keyword typescriptDOMStyle contained backgroundAttachment backgroundBlendMode
- syntax keyword typescriptDOMStyle contained backgroundClip backgroundColor backgroundImage
- syntax keyword typescriptDOMStyle contained backgroundOrigin backgroundPosition backgroundRepeat
- syntax keyword typescriptDOMStyle contained backgroundSize border borderBottom borderBottomColor
- syntax keyword typescriptDOMStyle contained borderBottomLeftRadius borderBottomRightRadius
- syntax keyword typescriptDOMStyle contained borderBottomStyle borderBottomWidth borderCollapse
- syntax keyword typescriptDOMStyle contained borderColor borderImage borderImageOutset
- syntax keyword typescriptDOMStyle contained borderImageRepeat borderImageSlice borderImageSource
- syntax keyword typescriptDOMStyle contained borderImageWidth borderLeft borderLeftColor
- syntax keyword typescriptDOMStyle contained borderLeftStyle borderLeftWidth borderRadius
- syntax keyword typescriptDOMStyle contained borderRight borderRightColor borderRightStyle
- syntax keyword typescriptDOMStyle contained borderRightWidth borderSpacing borderStyle
- syntax keyword typescriptDOMStyle contained borderTop borderTopColor borderTopLeftRadius
- syntax keyword typescriptDOMStyle contained borderTopRightRadius borderTopStyle borderTopWidth
- syntax keyword typescriptDOMStyle contained borderWidth bottom boxDecorationBreak
- syntax keyword typescriptDOMStyle contained boxShadow boxSizing breakAfter breakBefore
- syntax keyword typescriptDOMStyle contained breakInside captionSide caretColor caretShape
- syntax keyword typescriptDOMStyle contained caret clear clip clipPath color columns
- syntax keyword typescriptDOMStyle contained columnCount columnFill columnGap columnRule
- syntax keyword typescriptDOMStyle contained columnRuleColor columnRuleStyle columnRuleWidth
- syntax keyword typescriptDOMStyle contained columnSpan columnWidth content counterIncrement
- syntax keyword typescriptDOMStyle contained counterReset cursor direction display
- syntax keyword typescriptDOMStyle contained emptyCells flex flexBasis flexDirection
- syntax keyword typescriptDOMStyle contained flexFlow flexGrow flexShrink flexWrap
- syntax keyword typescriptDOMStyle contained float font fontFamily fontFeatureSettings
- syntax keyword typescriptDOMStyle contained fontKerning fontLanguageOverride fontSize
- syntax keyword typescriptDOMStyle contained fontSizeAdjust fontStretch fontStyle fontSynthesis
- syntax keyword typescriptDOMStyle contained fontVariant fontVariantAlternates fontVariantCaps
- syntax keyword typescriptDOMStyle contained fontVariantEastAsian fontVariantLigatures
- syntax keyword typescriptDOMStyle contained fontVariantNumeric fontVariantPosition
- syntax keyword typescriptDOMStyle contained fontWeight grad grid gridArea gridAutoColumns
- syntax keyword typescriptDOMStyle contained gridAutoFlow gridAutoPosition gridAutoRows
- syntax keyword typescriptDOMStyle contained gridColumn gridColumnStart gridColumnEnd
- syntax keyword typescriptDOMStyle contained gridRow gridRowStart gridRowEnd gridTemplate
- syntax keyword typescriptDOMStyle contained gridTemplateAreas gridTemplateRows gridTemplateColumns
- syntax keyword typescriptDOMStyle contained height hyphens imageRendering imageResolution
- syntax keyword typescriptDOMStyle contained imageOrientation imeMode inherit justifyContent
- syntax keyword typescriptDOMStyle contained left letterSpacing lineBreak lineHeight
- syntax keyword typescriptDOMStyle contained listStyle listStyleImage listStylePosition
- syntax keyword typescriptDOMStyle contained listStyleType margin marginBottom marginLeft
- syntax keyword typescriptDOMStyle contained marginRight marginTop marks mask maskType
- syntax keyword typescriptDOMStyle contained maxHeight maxWidth minHeight minWidth
- syntax keyword typescriptDOMStyle contained mixBlendMode objectFit objectPosition
- syntax keyword typescriptDOMStyle contained opacity order orphans outline outlineColor
- syntax keyword typescriptDOMStyle contained outlineOffset outlineStyle outlineWidth
- syntax keyword typescriptDOMStyle contained overflow overflowWrap overflowX overflowY
- syntax keyword typescriptDOMStyle contained overflowClipBox padding paddingBottom
- syntax keyword typescriptDOMStyle contained paddingLeft paddingRight paddingTop pageBreakAfter
- syntax keyword typescriptDOMStyle contained pageBreakBefore pageBreakInside perspective
- syntax keyword typescriptDOMStyle contained perspectiveOrigin pointerEvents position
- syntax keyword typescriptDOMStyle contained quotes resize right shapeImageThreshold
- syntax keyword typescriptDOMStyle contained shapeMargin shapeOutside tableLayout tabSize
- syntax keyword typescriptDOMStyle contained textAlign textAlignLast textCombineHorizontal
- syntax keyword typescriptDOMStyle contained textDecoration textDecorationColor textDecorationLine
- syntax keyword typescriptDOMStyle contained textDecorationStyle textIndent textOrientation
- syntax keyword typescriptDOMStyle contained textOverflow textRendering textShadow
- syntax keyword typescriptDOMStyle contained textTransform textUnderlinePosition top
- syntax keyword typescriptDOMStyle contained touchAction transform transformOrigin
- syntax keyword typescriptDOMStyle contained transformStyle transition transitionDelay
- syntax keyword typescriptDOMStyle contained transitionDuration transitionProperty
- syntax keyword typescriptDOMStyle contained transitionTimingFunction unicodeBidi unicodeRange
- syntax keyword typescriptDOMStyle contained userSelect userZoom verticalAlign visibility
- syntax keyword typescriptDOMStyle contained whiteSpace width willChange wordBreak
- syntax keyword typescriptDOMStyle contained wordSpacing wordWrap writingMode zIndex
- hi def link typescriptDOMStyle Keyword
-
-
-
- let typescript_props = 1
-
- "runtime syntax/yats/event.vim
- syntax keyword typescriptAnimationEvent contained animationend animationiteration
- syntax keyword typescriptAnimationEvent contained animationstart beginEvent endEvent
- syntax keyword typescriptAnimationEvent contained repeatEvent
- syntax cluster events add=typescriptAnimationEvent
- hi def link typescriptAnimationEvent Title
- syntax keyword typescriptCSSEvent contained CssRuleViewRefreshed CssRuleViewChanged
- syntax keyword typescriptCSSEvent contained CssRuleViewCSSLinkClicked transitionend
- syntax cluster events add=typescriptCSSEvent
- hi def link typescriptCSSEvent Title
- syntax keyword typescriptDatabaseEvent contained blocked complete error success upgradeneeded
- syntax keyword typescriptDatabaseEvent contained versionchange
- syntax cluster events add=typescriptDatabaseEvent
- hi def link typescriptDatabaseEvent Title
- syntax keyword typescriptDocumentEvent contained DOMLinkAdded DOMLinkRemoved DOMMetaAdded
- syntax keyword typescriptDocumentEvent contained DOMMetaRemoved DOMWillOpenModalDialog
- syntax keyword typescriptDocumentEvent contained DOMModalDialogClosed unload
- syntax cluster events add=typescriptDocumentEvent
- hi def link typescriptDocumentEvent Title
- syntax keyword typescriptDOMMutationEvent contained DOMAttributeNameChanged DOMAttrModified
- syntax keyword typescriptDOMMutationEvent contained DOMCharacterDataModified DOMContentLoaded
- syntax keyword typescriptDOMMutationEvent contained DOMElementNameChanged DOMNodeInserted
- syntax keyword typescriptDOMMutationEvent contained DOMNodeInsertedIntoDocument DOMNodeRemoved
- syntax keyword typescriptDOMMutationEvent contained DOMNodeRemovedFromDocument DOMSubtreeModified
- syntax cluster events add=typescriptDOMMutationEvent
- hi def link typescriptDOMMutationEvent Title
- syntax keyword typescriptDragEvent contained drag dragdrop dragend dragenter dragexit
- syntax keyword typescriptDragEvent contained draggesture dragleave dragover dragstart
- syntax keyword typescriptDragEvent contained drop
- syntax cluster events add=typescriptDragEvent
- hi def link typescriptDragEvent Title
- syntax keyword typescriptElementEvent contained invalid overflow underflow DOMAutoComplete
- syntax keyword typescriptElementEvent contained command commandupdate
- syntax cluster events add=typescriptElementEvent
- hi def link typescriptElementEvent Title
- syntax keyword typescriptFocusEvent contained blur change DOMFocusIn DOMFocusOut focus
- syntax keyword typescriptFocusEvent contained focusin focusout
- syntax cluster events add=typescriptFocusEvent
- hi def link typescriptFocusEvent Title
- syntax keyword typescriptFormEvent contained reset submit
- syntax cluster events add=typescriptFormEvent
- hi def link typescriptFormEvent Title
- syntax keyword typescriptFrameEvent contained DOMFrameContentLoaded
- syntax cluster events add=typescriptFrameEvent
- hi def link typescriptFrameEvent Title
- syntax keyword typescriptInputDeviceEvent contained click contextmenu DOMMouseScroll
- syntax keyword typescriptInputDeviceEvent contained dblclick gamepadconnected gamepaddisconnected
- syntax keyword typescriptInputDeviceEvent contained keydown keypress keyup MozGamepadButtonDown
- syntax keyword typescriptInputDeviceEvent contained MozGamepadButtonUp mousedown mouseenter
- syntax keyword typescriptInputDeviceEvent contained mouseleave mousemove mouseout
- syntax keyword typescriptInputDeviceEvent contained mouseover mouseup mousewheel MozMousePixelScroll
- syntax keyword typescriptInputDeviceEvent contained pointerlockchange pointerlockerror
- syntax keyword typescriptInputDeviceEvent contained wheel
- syntax cluster events add=typescriptInputDeviceEvent
- hi def link typescriptInputDeviceEvent Title
- syntax keyword typescriptMediaEvent contained audioprocess canplay canplaythrough
- syntax keyword typescriptMediaEvent contained durationchange emptied ended ended loadeddata
- syntax keyword typescriptMediaEvent contained loadedmetadata MozAudioAvailable pause
- syntax keyword typescriptMediaEvent contained play playing ratechange seeked seeking
- syntax keyword typescriptMediaEvent contained stalled suspend timeupdate volumechange
- syntax keyword typescriptMediaEvent contained waiting complete
- syntax cluster events add=typescriptMediaEvent
- hi def link typescriptMediaEvent Title
- syntax keyword typescriptMenuEvent contained DOMMenuItemActive DOMMenuItemInactive
- syntax cluster events add=typescriptMenuEvent
- hi def link typescriptMenuEvent Title
- syntax keyword typescriptNetworkEvent contained datachange dataerror disabled enabled
- syntax keyword typescriptNetworkEvent contained offline online statuschange connectionInfoUpdate
- syntax cluster events add=typescriptNetworkEvent
- hi def link typescriptNetworkEvent Title
- syntax keyword typescriptProgressEvent contained abort error load loadend loadstart
- syntax keyword typescriptProgressEvent contained progress timeout uploadprogress
- syntax cluster events add=typescriptProgressEvent
- hi def link typescriptProgressEvent Title
- syntax keyword typescriptResourceEvent contained cached error load
- syntax cluster events add=typescriptResourceEvent
- hi def link typescriptResourceEvent Title
- syntax keyword typescriptScriptEvent contained afterscriptexecute beforescriptexecute
- syntax cluster events add=typescriptScriptEvent
- hi def link typescriptScriptEvent Title
- syntax keyword typescriptSensorEvent contained compassneedscalibration devicelight
- syntax keyword typescriptSensorEvent contained devicemotion deviceorientation deviceproximity
- syntax keyword typescriptSensorEvent contained orientationchange userproximity
- syntax cluster events add=typescriptSensorEvent
- hi def link typescriptSensorEvent Title
- syntax keyword typescriptSessionHistoryEvent contained pagehide pageshow popstate
- syntax cluster events add=typescriptSessionHistoryEvent
- hi def link typescriptSessionHistoryEvent Title
- syntax keyword typescriptStorageEvent contained change storage
- syntax cluster events add=typescriptStorageEvent
- hi def link typescriptStorageEvent Title
- syntax keyword typescriptSVGEvent contained SVGAbort SVGError SVGLoad SVGResize SVGScroll
- syntax keyword typescriptSVGEvent contained SVGUnload SVGZoom
- syntax cluster events add=typescriptSVGEvent
- hi def link typescriptSVGEvent Title
- syntax keyword typescriptTabEvent contained visibilitychange
- syntax cluster events add=typescriptTabEvent
- hi def link typescriptTabEvent Title
- syntax keyword typescriptTextEvent contained compositionend compositionstart compositionupdate
- syntax keyword typescriptTextEvent contained copy cut paste select text
- syntax cluster events add=typescriptTextEvent
- hi def link typescriptTextEvent Title
- syntax keyword typescriptTouchEvent contained touchcancel touchend touchenter touchleave
- syntax keyword typescriptTouchEvent contained touchmove touchstart
- syntax cluster events add=typescriptTouchEvent
- hi def link typescriptTouchEvent Title
- syntax keyword typescriptUpdateEvent contained checking downloading error noupdate
- syntax keyword typescriptUpdateEvent contained obsolete updateready
- syntax cluster events add=typescriptUpdateEvent
- hi def link typescriptUpdateEvent Title
- syntax keyword typescriptValueChangeEvent contained hashchange input readystatechange
- syntax cluster events add=typescriptValueChangeEvent
- hi def link typescriptValueChangeEvent Title
- syntax keyword typescriptViewEvent contained fullscreen fullscreenchange fullscreenerror
- syntax keyword typescriptViewEvent contained resize scroll
- syntax cluster events add=typescriptViewEvent
- hi def link typescriptViewEvent Title
- syntax keyword typescriptWebsocketEvent contained close error message open
- syntax cluster events add=typescriptWebsocketEvent
- hi def link typescriptWebsocketEvent Title
- syntax keyword typescriptWindowEvent contained DOMWindowCreated DOMWindowClose DOMTitleChanged
- syntax cluster events add=typescriptWindowEvent
- hi def link typescriptWindowEvent Title
- syntax keyword typescriptUncategorizedEvent contained beforeunload message open show
- syntax cluster events add=typescriptUncategorizedEvent
- hi def link typescriptUncategorizedEvent Title
- syntax keyword typescriptServiceWorkerEvent contained install activate fetch
- syntax cluster events add=typescriptServiceWorkerEvent
- hi def link typescriptServiceWorkerEvent Title
-
-
-endif
-
-" patch
-"runtime syntax/basic/patch.vim
-" patch for generated code
-syntax keyword typescriptGlobal Promise
- \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
-syntax keyword typescriptGlobal Map WeakMap
- \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
-
-"runtime syntax/basic/members.vim
-syntax keyword typescriptConstructor contained constructor
- \ nextgroup=@typescriptCallSignature
- \ skipwhite skipempty
-
-
-syntax cluster memberNextGroup contains=typescriptMemberOptionality,typescriptTypeAnnotation,@typescriptCallSignature
-
-syntax match typescriptMember /\K\k*/
- \ nextgroup=@memberNextGroup
- \ contained skipwhite
-
-syntax match typescriptMethodAccessor contained /\v(get|set)\s\K/me=e-1
- \ nextgroup=@typescriptMembers
-
-syntax cluster typescriptPropertyMemberDeclaration contains=
- \ typescriptClassStatic,
- \ typescriptAccessibilityModifier,
- \ typescriptReadonlyModifier,
- \ typescriptMethodAccessor,
- \ @typescriptMembers
- " \ typescriptMemberVariableDeclaration
-
-syntax match typescriptMemberOptionality /?\|!/ contained
- \ nextgroup=typescriptTypeAnnotation,@typescriptCallSignature
- \ skipwhite skipempty
-
-syntax cluster typescriptMembers contains=typescriptMember,typescriptStringMember,typescriptComputedMember
-
-syntax keyword typescriptClassStatic static
- \ nextgroup=@typescriptMembers,typescriptAsyncFuncKeyword,typescriptReadonlyModifier
- \ skipwhite contained
-
-syntax keyword typescriptAccessibilityModifier public private protected contained
-
-syntax keyword typescriptReadonlyModifier readonly contained
-
-syntax region typescriptStringMember contained
- \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
- \ nextgroup=@memberNextGroup
- \ skipwhite skipempty
-
-syntax region typescriptComputedMember contained matchgroup=typescriptProperty
- \ start=/\[/rs=s+1 end=/]/
- \ contains=@typescriptValue,typescriptMember,typescriptMappedIn
- \ nextgroup=@memberNextGroup
- \ skipwhite skipempty
-
-"runtime syntax/basic/class.vim
-"don't add typescriptMembers to nextgroup, let outer scope match it
-" so we won't match abstract method outside abstract class
-syntax keyword typescriptAbstract abstract
- \ nextgroup=typescriptClassKeyword
- \ skipwhite skipnl
-syntax keyword typescriptClassKeyword class
- \ nextgroup=typescriptClassName,typescriptClassExtends,typescriptClassBlock
- \ skipwhite
-
-syntax match typescriptClassName contained /\K\k*/
- \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptClassTypeParameter
- \ skipwhite skipnl
-
-syntax region typescriptClassTypeParameter
- \ start=/</ end=/>/
- \ contains=typescriptTypeParameter
- \ nextgroup=typescriptClassBlock,typescriptClassExtends
- \ contained skipwhite skipnl
-
-syntax keyword typescriptClassExtends contained extends implements nextgroup=typescriptClassHeritage skipwhite skipnl
-
-syntax match typescriptClassHeritage contained /\v(\k|\.|\(|\))+/
- \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptMixinComma,typescriptClassTypeArguments
- \ contains=@typescriptValue
- \ skipwhite skipnl
- \ contained
-
-syntax region typescriptClassTypeArguments matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/
- \ contains=@typescriptType
- \ nextgroup=typescriptClassExtends,typescriptClassBlock,typescriptMixinComma
- \ contained skipwhite skipnl
-
-syntax match typescriptMixinComma /,/ contained nextgroup=typescriptClassHeritage skipwhite skipnl
-
-" we need add arrowFunc to class block for high order arrow func
-" see test case
-syntax region typescriptClassBlock matchgroup=typescriptBraces start=/{/ end=/}/
- \ contains=@typescriptPropertyMemberDeclaration,typescriptAbstract,@typescriptComments,typescriptBlock,typescriptAssign,typescriptDecorator,typescriptAsyncFuncKeyword,typescriptArrowFunc
- \ contained fold
-
-syntax keyword typescriptInterfaceKeyword interface nextgroup=typescriptInterfaceName skipwhite
-syntax match typescriptInterfaceName contained /\k\+/
- \ nextgroup=typescriptObjectType,typescriptInterfaceExtends,typescriptInterfaceTypeParameter
- \ skipwhite skipnl
-syntax region typescriptInterfaceTypeParameter
- \ start=/</ end=/>/
- \ contains=typescriptTypeParameter
- \ nextgroup=typescriptObjectType,typescriptInterfaceExtends
- \ contained
- \ skipwhite skipnl
-
-syntax keyword typescriptInterfaceExtends contained extends nextgroup=typescriptInterfaceHeritage skipwhite skipnl
-
-syntax match typescriptInterfaceHeritage contained /\v(\k|\.)+/
- \ nextgroup=typescriptObjectType,typescriptInterfaceComma,typescriptInterfaceTypeArguments
- \ skipwhite
-
-syntax region typescriptInterfaceTypeArguments matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/ skip=/\s*,\s*/
- \ contains=@typescriptType
- \ nextgroup=typescriptObjectType,typescriptInterfaceComma
- \ contained skipwhite
-
-syntax match typescriptInterfaceComma /,/ contained nextgroup=typescriptInterfaceHeritage skipwhite skipnl
-
-"runtime syntax/basic/cluster.vim
-"Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement DebuggerStatement
-syntax cluster typescriptStatement
- \ contains=typescriptBlock,typescriptVariable,
- \ @typescriptTopExpression,typescriptAssign,
- \ typescriptConditional,typescriptRepeat,typescriptBranch,
- \ typescriptLabel,typescriptStatementKeyword,
- \ typescriptFuncKeyword,
- \ typescriptTry,typescriptExceptions,typescriptDebugger,
- \ typescriptExport,typescriptInterfaceKeyword,typescriptEnum,
- \ typescriptModule,typescriptAliasKeyword,typescriptImport
-
-syntax cluster typescriptPrimitive contains=typescriptString,typescriptTemplate,typescriptRegexpString,typescriptNumber,typescriptBoolean,typescriptNull,typescriptArray
-
-syntax cluster typescriptEventTypes contains=typescriptEventString,typescriptTemplate,typescriptNumber,typescriptBoolean,typescriptNull
-
-" top level expression: no arrow func
-" also no func keyword. funcKeyword is contained in statement
-" funcKeyword allows overloading (func without body)
-" funcImpl requires body
-syntax cluster typescriptTopExpression
- \ contains=@typescriptPrimitive,
- \ typescriptIdentifier,typescriptIdentifierName,
- \ typescriptOperator,typescriptUnaryOp,
- \ typescriptParenExp,typescriptRegexpString,
- \ typescriptGlobal,typescriptAsyncFuncKeyword,
- \ typescriptClassKeyword,typescriptTypeCast
-
-" no object literal, used in type cast and arrow func
-" TODO: change func keyword to funcImpl
-syntax cluster typescriptExpression
- \ contains=@typescriptTopExpression,
- \ typescriptArrowFuncDef,
- \ typescriptFuncImpl
-
-syntax cluster typescriptValue
- \ contains=@typescriptExpression,typescriptObjectLiteral
-
-syntax cluster typescriptEventExpression contains=typescriptArrowFuncDef,typescriptParenExp,@typescriptValue,typescriptRegexpString,@typescriptEventTypes,typescriptOperator,typescriptGlobal,jsxRegion
-
-"runtime syntax/basic/function.vim
-syntax keyword typescriptAsyncFuncKeyword async
- \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef
- \ skipwhite
-
-syntax keyword typescriptAsyncFuncKeyword await
- \ nextgroup=@typescriptValue
- \ skipwhite
-
-syntax keyword typescriptFuncKeyword function
- \ nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature
- \ skipwhite skipempty
-
-syntax match typescriptAsyncFunc contained /*/
- \ nextgroup=typescriptFuncName,@typescriptCallSignature
- \ skipwhite skipempty
-
-syntax match typescriptFuncName contained /\K\k*/
- \ nextgroup=@typescriptCallSignature
- \ skipwhite
-
-" destructuring ({ a: ee }) =>
-syntax match typescriptArrowFuncDef contained /({\_[^}]*}\(:\_[^)]\)\?)\s*=>/
- \ contains=typescriptArrowFuncArg,typescriptArrowFunc
- \ nextgroup=@typescriptExpression,typescriptBlock
- \ skipwhite skipempty
-
-" matches `(a) =>` or `([a]) =>` or
-" `(
-" a) =>`
-syntax match typescriptArrowFuncDef contained /(\(\_s*[a-zA-Z\$_\[]\_[^)]*\)*)\s*=>/
- \ contains=typescriptArrowFuncArg,typescriptArrowFunc
- \ nextgroup=@typescriptExpression,typescriptBlock
- \ skipwhite skipempty
-
-syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/
- \ contains=typescriptArrowFuncArg,typescriptArrowFunc
- \ nextgroup=@typescriptExpression,typescriptBlock
- \ skipwhite skipempty
-
-" TODO: optimize this pattern
-syntax region typescriptArrowFuncDef contained start=/(\_[^)]*):/ end=/=>/
- \ contains=typescriptArrowFuncArg,typescriptArrowFunc,typescriptTypeAnnotation
- \ nextgroup=@typescriptExpression,typescriptBlock
- \ skipwhite skipempty keepend
-
-syntax match typescriptArrowFunc /=>/
-syntax match typescriptArrowFuncArg contained /\K\k*/
-syntax region typescriptArrowFuncArg contained start=/<\|(/ end=/\ze=>/ contains=@typescriptCallSignature
-
-syntax region typescriptReturnAnnotation contained start=/:/ end=/{/me=e-1 contains=@typescriptType nextgroup=typescriptBlock
-
-
-syntax region typescriptFuncImpl contained start=/function/ end=/{/me=e-1
- \ contains=typescriptFuncKeyword
- \ nextgroup=typescriptBlock
-
-syntax cluster typescriptCallImpl contains=typescriptGenericImpl,typescriptParamImpl
-syntax region typescriptGenericImpl matchgroup=typescriptTypeBrackets
- \ start=/</ end=/>/ skip=/\s*,\s*/
- \ contains=typescriptTypeParameter
- \ nextgroup=typescriptParamImpl
- \ contained skipwhite
-syntax region typescriptParamImpl matchgroup=typescriptParens
- \ start=/(/ end=/)/
- \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
- \ nextgroup=typescriptReturnAnnotation,typescriptBlock
- \ contained skipwhite skipnl
-
-"runtime syntax/basic/decorator.vim
-syntax match typescriptDecorator /@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a-zA-Z0-9]*\>/
- \ nextgroup=typescriptArgumentList
- \ contains=@_semantic,typescriptDotNotation
-
-" Define the default highlighting.
-hi def link typescriptReserved Error
-
-hi def link typescriptEndColons Exception
-hi def link typescriptSymbols Normal
-hi def link typescriptBraces Function
-hi def link typescriptParens Normal
-hi def link typescriptComment Comment
-hi def link typescriptLineComment Comment
-hi def link typescriptDocComment Comment
-hi def link typescriptCommentTodo Todo
-hi def link typescriptRef Include
-hi def link typescriptDocNotation SpecialComment
-hi def link typescriptDocTags SpecialComment
-hi def link typescriptDocNGParam typescriptDocParam
-hi def link typescriptDocParam Function
-hi def link typescriptDocNumParam Function
-hi def link typescriptDocEventRef Function
-hi def link typescriptDocNamedParamType Type
-hi def link typescriptDocParamName Type
-hi def link typescriptDocParamType Type
-hi def link typescriptString String
-hi def link typescriptSpecial Special
-hi def link typescriptStringLiteralType String
-hi def link typescriptStringMember String
-hi def link typescriptTemplate String
-hi def link typescriptEventString String
-hi def link typescriptASCII Special
-hi def link typescriptTemplateSB Label
-hi def link typescriptRegexpString String
-hi def link typescriptGlobal Constant
-hi def link typescriptPrototype Type
-hi def link typescriptConditional Conditional
-hi def link typescriptConditionalElse Conditional
-hi def link typescriptCase Conditional
-hi def link typescriptDefault typescriptCase
-hi def link typescriptBranch Conditional
-hi def link typescriptIdentifier Structure
-hi def link typescriptVariable Identifier
-hi def link typescriptEnumKeyword Identifier
-hi def link typescriptRepeat Repeat
-hi def link typescriptForOperator Repeat
-hi def link typescriptStatementKeyword Statement
-hi def link typescriptMessage Keyword
-hi def link typescriptOperator Identifier
-hi def link typescriptKeywordOp Identifier
-hi def link typescriptCastKeyword Special
-hi def link typescriptType Type
-hi def link typescriptNull Boolean
-hi def link typescriptNumber Number
-hi def link typescriptExponent Number
-hi def link typescriptBoolean Boolean
-hi def link typescriptObjectLabel typescriptLabel
-hi def link typescriptLabel Label
-hi def link typescriptStringProperty String
-hi def link typescriptImport Special
-hi def link typescriptAmbientDeclaration Special
-hi def link typescriptExport Special
-hi def link typescriptModule Special
-hi def link typescriptTry Special
-hi def link typescriptExceptions Special
-
-hi def link typescriptMember Function
-hi def link typescriptMethodAccessor Operator
-
-hi def link typescriptAsyncFuncKeyword Keyword
-hi def link typescriptAsyncFor Keyword
-hi def link typescriptFuncKeyword Keyword
-hi def link typescriptAsyncFunc Keyword
-hi def link typescriptArrowFunc Type
-hi def link typescriptFuncName Function
-hi def link typescriptFuncArg PreProc
-hi def link typescriptArrowFuncArg PreProc
-hi def link typescriptFuncComma Operator
-
-hi def link typescriptClassKeyword Keyword
-hi def link typescriptClassExtends Keyword
-" hi def link typescriptClassName Function
-hi def link typescriptAbstract Special
-" hi def link typescriptClassHeritage Function
-" hi def link typescriptInterfaceHeritage Function
-hi def link typescriptClassStatic StorageClass
-hi def link typescriptReadonlyModifier Keyword
-hi def link typescriptInterfaceKeyword Keyword
-hi def link typescriptInterfaceExtends Keyword
-hi def link typescriptInterfaceName Function
-
-hi def link shellbang Comment
-
-hi def link typescriptTypeParameter Identifier
-hi def link typescriptConstraint Keyword
-hi def link typescriptPredefinedType Type
-hi def link typescriptReadonlyArrayKeyword Keyword
-hi def link typescriptUnion Operator
-hi def link typescriptFuncTypeArrow Function
-hi def link typescriptConstructorType Function
-hi def link typescriptTypeQuery Keyword
-hi def link typescriptAccessibilityModifier Keyword
-hi def link typescriptOptionalMark PreProc
-hi def link typescriptFuncType Special
-hi def link typescriptMappedIn Special
-hi def link typescriptCall PreProc
-hi def link typescriptParamImpl PreProc
-hi def link typescriptConstructSignature Identifier
-hi def link typescriptAliasDeclaration Identifier
-hi def link typescriptAliasKeyword Keyword
-hi def link typescriptUserDefinedType Keyword
-hi def link typescriptTypeReference Identifier
-hi def link typescriptConstructor Keyword
-hi def link typescriptDecorator Special
-
-hi link typeScript NONE
let b:current_syntax = "typescript"
if main_syntax == 'typescript'
diff --git a/runtime/syntax/typescriptcommon.vim b/runtime/syntax/typescriptcommon.vim
new file mode 100644
index 0000000000..ff53168329
--- /dev/null
+++ b/runtime/syntax/typescriptcommon.vim
@@ -0,0 +1,2067 @@
+" Vim syntax file
+" Language: TypeScript and TypeScriptReact
+" Maintainer: Bram Moolenaar, Herrington Darkholme
+" Last Change: 2019 Nov 30
+" Based On: Herrington Darkholme's yats.vim
+" Changes: See https:github.com/HerringtonDarkholme/yats.vim
+" Credits: See yats.vim on github
+
+if &cpo =~ 'C'
+ let s:cpo_save = &cpo
+ set cpo&vim
+endif
+
+
+" NOTE: this results in accurate highlighting, but can be slow.
+syntax sync fromstart
+
+"Dollar sign is permitted anywhere in an identifier
+setlocal iskeyword-=$
+if main_syntax == 'typescript' || main_syntax == 'typescriptreact'
+ setlocal iskeyword+=$
+ " syntax cluster htmlJavaScript contains=TOP
+endif
+
+" lowest priority on least used feature
+syntax match typescriptLabel /[a-zA-Z_$]\k*:/he=e-1 contains=typescriptReserved nextgroup=@typescriptStatement skipwhite skipempty
+
+" other keywords like return,case,yield uses containedin
+syntax region typescriptBlock matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptStatement,@typescriptComments fold
+
+
+"runtime syntax/basic/identifiers.vim
+syntax cluster afterIdentifier contains=
+ \ typescriptDotNotation,
+ \ typescriptFuncCallArg,
+ \ typescriptTemplate,
+ \ typescriptIndexExpr,
+ \ @typescriptSymbols,
+ \ typescriptTypeArguments
+
+syntax match typescriptIdentifierName /\<\K\k*/
+ \ nextgroup=@afterIdentifier
+ \ transparent
+ \ contains=@_semantic
+ \ skipnl skipwhite
+
+syntax match typescriptProp contained /\K\k*!\?/
+ \ transparent
+ \ contains=@props
+ \ nextgroup=@afterIdentifier
+ \ skipwhite skipempty
+
+syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/rs=s+1 end=/]/he=e-1 contains=@typescriptValue nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty
+
+syntax match typescriptDotNotation /\.\|?\.\|!\./ nextgroup=typescriptProp skipnl
+syntax match typescriptDotStyleNotation /\.style\./ nextgroup=typescriptDOMStyle transparent
+" syntax match typescriptFuncCall contained /[a-zA-Z]\k*\ze(/ nextgroup=typescriptFuncCallArg
+syntax region typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty
+syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl
+syntax region typescriptEventFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptEventExpression
+syntax region typescriptEventString contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/ contains=typescriptASCII,@events
+
+"runtime syntax/basic/literal.vim
+"Syntax in the JavaScript code
+
+" String
+syntax match typescriptASCII contained /\\\d\d\d/
+
+syntax region typescriptTemplateSubstitution matchgroup=typescriptTemplateSB
+ \ start=/\${/ end=/}/
+ \ contains=@typescriptValue
+ \ contained
+
+
+syntax region typescriptString
+ \ start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+
+ \ contains=typescriptSpecial,@Spell
+ \ extend
+
+syntax match typescriptSpecial contained "\v\\%(x\x\x|u%(\x{4}|\{\x{4,5}})|c\u|.)"
+
+" From vim runtime
+" <https://github.com/vim/vim/blob/master/runtime/syntax/javascript.vim#L48>
+syntax region typescriptRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gimuy]\{0,5\}\s*$+ end=+/[gimuy]\{0,5\}\s*[;.,)\]}]+me=e-1 nextgroup=typescriptDotNotation oneline
+
+syntax region typescriptTemplate
+ \ start=/`/ skip=/\\\\\|\\`\|\n/ end=/`\|$/
+ \ contains=typescriptTemplateSubstitution
+ \ nextgroup=@typescriptSymbols
+ \ skipwhite skipempty
+
+"Array
+syntax region typescriptArray matchgroup=typescriptBraces
+ \ start=/\[/ end=/]/
+ \ contains=@typescriptValue,@typescriptComments
+ \ nextgroup=@typescriptSymbols,typescriptDotNotation
+ \ skipwhite skipempty fold
+
+" Number
+syntax match typescriptNumber /\<0[bB][01][01_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\<0[oO][0-7][0-7_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\<0[xX][0-9a-fA-F][0-9a-fA-F_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\d[0-9_]*\.\d[0-9_]*\|\d[0-9_]*\|\.\d[0-9]*/
+ \ nextgroup=typescriptExponent,@typescriptSymbols skipwhite skipempty
+syntax match typescriptExponent /[eE][+-]\=\d[0-9]*\>/
+ \ nextgroup=@typescriptSymbols skipwhite skipempty contained
+
+
+" runtime syntax/basic/object.vim
+syntax region typescriptObjectLiteral matchgroup=typescriptBraces
+ \ start=/{/ end=/}/
+ \ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName
+ \ fold contained
+
+syntax match typescriptObjectLabel contained /\k\+\_s*/
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+syntax region typescriptStringProperty contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+" syntax region typescriptPropertyName contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1(/me=e-1 nextgroup=@typescriptCallSignature skipwhite skipempty oneline
+syntax region typescriptComputedPropertyName contained matchgroup=typescriptBraces
+ \ start=/\[/rs=s+1 end=/]/
+ \ contains=@typescriptValue
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*:/he=e-1 contains=@typescriptValue nextgroup=@typescriptValue skipwhite skipempty
+" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*(/me=e-1 contains=@typescriptValue nextgroup=@typescriptCallSignature skipwhite skipempty
+" Value for object, statement for label statement
+syntax match typescriptRestOrSpread /\.\.\./ contained
+syntax match typescriptObjectSpread /\.\.\./ contained containedin=typescriptObjectLiteral,typescriptArray nextgroup=@typescriptValue
+
+syntax match typescriptObjectColon contained /:/ nextgroup=@typescriptValue skipwhite skipempty
+
+"runtime syntax/basic/symbols.vim
+" + - ^ ~
+syntax match typescriptUnaryOp /[+\-~!]/
+ \ nextgroup=@typescriptValue
+ \ skipwhite
+
+syntax region typescriptTernary matchgroup=typescriptTernaryOp start=/?[.?]\@!/ end=/:/ contained contains=@typescriptValue,@typescriptComments nextgroup=@typescriptValue skipwhite skipempty
+
+syntax match typescriptAssign /=/ nextgroup=@typescriptValue
+ \ skipwhite skipempty
+
+" 2: ==, ===
+syntax match typescriptBinaryOp contained /===\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 6: >>>=, >>>, >>=, >>, >=, >
+syntax match typescriptBinaryOp contained />\(>>=\|>>\|>=\|>\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 4: <<=, <<, <=, <
+syntax match typescriptBinaryOp contained /<\(<=\|<\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: ||, |=, |
+syntax match typescriptBinaryOp contained /|\(|\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: &&, &=, &
+syntax match typescriptBinaryOp contained /&\(&\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: *=, *
+syntax match typescriptBinaryOp contained /\*=\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: %=, %
+syntax match typescriptBinaryOp contained /%=\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: /=, /
+syntax match typescriptBinaryOp contained +/\(=\|[^\*/]\@=\)+ nextgroup=@typescriptValue skipwhite skipempty
+syntax match typescriptBinaryOp contained /!==\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: !=, !==
+syntax match typescriptBinaryOp contained /+\(+\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: +, ++, +=
+syntax match typescriptBinaryOp contained /-\(-\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: -, --, -=
+
+" exponentiation operator
+" 2: **, **=
+syntax match typescriptBinaryOp contained /\*\*=\?/ nextgroup=@typescriptValue
+
+syntax cluster typescriptSymbols contains=typescriptBinaryOp,typescriptKeywordOp,typescriptTernary,typescriptAssign,typescriptCastKeyword
+
+" runtime syntax/basic/reserved.vim
+
+"runtime syntax/basic/keyword.vim
+"Import
+syntax keyword typescriptImport from as import
+syntax keyword typescriptExport export
+syntax keyword typescriptModule namespace module
+
+"this
+
+"JavaScript Prototype
+syntax keyword typescriptPrototype prototype
+ \ nextgroup=@afterIdentifier
+
+syntax keyword typescriptCastKeyword as
+ \ nextgroup=@typescriptType
+ \ skipwhite
+
+"Program Keywords
+syntax keyword typescriptIdentifier arguments this super
+ \ nextgroup=@afterIdentifier
+
+syntax keyword typescriptVariable let var
+ \ nextgroup=typescriptVariableDeclaration
+ \ skipwhite skipempty skipnl
+
+syntax keyword typescriptVariable const
+ \ nextgroup=typescriptEnum,typescriptVariableDeclaration
+ \ skipwhite
+
+syntax match typescriptVariableDeclaration /[A-Za-z_$]\k*/
+ \ nextgroup=typescriptTypeAnnotation,typescriptAssign
+ \ contained skipwhite skipempty skipnl
+
+syntax region typescriptEnum matchgroup=typescriptEnumKeyword start=/enum / end=/\ze{/
+ \ nextgroup=typescriptBlock
+ \ skipwhite
+
+syntax keyword typescriptKeywordOp
+ \ contained in instanceof nextgroup=@typescriptValue
+syntax keyword typescriptOperator delete new typeof void
+ \ nextgroup=@typescriptValue
+ \ skipwhite skipempty
+
+syntax keyword typescriptForOperator contained in of
+syntax keyword typescriptBoolean true false nextgroup=@typescriptSymbols skipwhite skipempty
+syntax keyword typescriptNull null undefined nextgroup=@typescriptSymbols skipwhite skipempty
+syntax keyword typescriptMessage alert confirm prompt status
+ \ nextgroup=typescriptDotNotation,typescriptFuncCallArg
+syntax keyword typescriptGlobal self top parent
+ \ nextgroup=@afterIdentifier
+
+"Statement Keywords
+syntax keyword typescriptConditional if else switch
+ \ nextgroup=typescriptConditionalParen
+ \ skipwhite skipempty skipnl
+syntax keyword typescriptConditionalElse else
+syntax keyword typescriptRepeat do while for nextgroup=typescriptLoopParen skipwhite skipempty
+syntax keyword typescriptRepeat for nextgroup=typescriptLoopParen,typescriptAsyncFor skipwhite skipempty
+syntax keyword typescriptBranch break continue containedin=typescriptBlock
+syntax keyword typescriptCase case nextgroup=@typescriptPrimitive skipwhite containedin=typescriptBlock
+syntax keyword typescriptDefault default containedin=typescriptBlock nextgroup=@typescriptValue,typescriptClassKeyword,typescriptInterfaceKeyword skipwhite oneline
+syntax keyword typescriptStatementKeyword with
+syntax keyword typescriptStatementKeyword yield skipwhite nextgroup=@typescriptValue containedin=typescriptBlock
+syntax keyword typescriptStatementKeyword return skipwhite contained nextgroup=@typescriptValue containedin=typescriptBlock
+
+syntax keyword typescriptTry try
+syntax keyword typescriptExceptions catch throw finally
+syntax keyword typescriptDebugger debugger
+
+syntax keyword typescriptAsyncFor await nextgroup=typescriptLoopParen skipwhite skipempty contained
+
+syntax region typescriptLoopParen contained matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptVariable,typescriptForOperator,typescriptEndColons,@typescriptValue,@typescriptComments
+ \ nextgroup=typescriptBlock
+ \ skipwhite skipempty
+syntax region typescriptConditionalParen contained matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=@typescriptValue,@typescriptComments
+ \ nextgroup=typescriptBlock
+ \ skipwhite skipempty
+syntax match typescriptEndColons /[;,]/ contained
+
+syntax keyword typescriptAmbientDeclaration declare nextgroup=@typescriptAmbients
+ \ skipwhite skipempty
+
+syntax cluster typescriptAmbients contains=
+ \ typescriptVariable,
+ \ typescriptFuncKeyword,
+ \ typescriptClassKeyword,
+ \ typescriptAbstract,
+ \ typescriptEnumKeyword,typescriptEnum,
+ \ typescriptModule
+
+"runtime syntax/basic/doc.vim
+"Syntax coloring for Node.js shebang line
+syntax match shellbang "^#!.*node\>"
+syntax match shellbang "^#!.*iojs\>"
+
+
+"JavaScript comments
+syntax keyword typescriptCommentTodo TODO FIXME XXX TBD
+syntax match typescriptLineComment "//.*"
+ \ contains=@Spell,typescriptCommentTodo,typescriptRef
+syntax region typescriptComment
+ \ start="/\*" end="\*/"
+ \ contains=@Spell,typescriptCommentTodo extend
+syntax cluster typescriptComments
+ \ contains=typescriptDocComment,typescriptComment,typescriptLineComment
+
+syntax match typescriptRef +///\s*<reference\s\+.*\/>$+
+ \ contains=typescriptString
+syntax match typescriptRef +///\s*<amd-dependency\s\+.*\/>$+
+ \ contains=typescriptString
+syntax match typescriptRef +///\s*<amd-module\s\+.*\/>$+
+ \ contains=typescriptString
+
+"JSDoc
+syntax case ignore
+
+syntax region typescriptDocComment matchgroup=typescriptComment
+ \ start="/\*\*" end="\*/"
+ \ contains=typescriptDocNotation,typescriptCommentTodo,@Spell
+ \ fold keepend
+syntax match typescriptDocNotation contained /@/ nextgroup=typescriptDocTags
+
+syntax keyword typescriptDocTags contained constant constructor constructs function ignore inner private public readonly static
+syntax keyword typescriptDocTags contained const dict expose inheritDoc interface nosideeffects override protected struct internal
+syntax keyword typescriptDocTags contained example global
+syntax keyword typescriptDocTags contained alpha beta defaultValue eventProperty experimental label
+syntax keyword typescriptDocTags contained packageDocumentation privateRemarks remarks sealed typeParam
+
+" syntax keyword typescriptDocTags contained ngdoc nextgroup=typescriptDocNGDirective
+syntax keyword typescriptDocTags contained ngdoc scope priority animations
+syntax keyword typescriptDocTags contained ngdoc restrict methodOf propertyOf eventOf eventType nextgroup=typescriptDocParam skipwhite
+syntax keyword typescriptDocNGDirective contained overview service object function method property event directive filter inputType error
+
+syntax keyword typescriptDocTags contained abstract virtual access augments
+
+syntax keyword typescriptDocTags contained arguments callback lends memberOf name type kind link mixes mixin tutorial nextgroup=typescriptDocParam skipwhite
+syntax keyword typescriptDocTags contained variation nextgroup=typescriptDocNumParam skipwhite
+
+syntax keyword typescriptDocTags contained author class classdesc copyright default defaultvalue nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained deprecated description external host nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained file fileOverview overview namespace requires since version nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained summary todo license preserve nextgroup=typescriptDocDesc skipwhite
+
+syntax keyword typescriptDocTags contained borrows exports nextgroup=typescriptDocA skipwhite
+syntax keyword typescriptDocTags contained param arg argument property prop module nextgroup=typescriptDocNamedParamType,typescriptDocParamName skipwhite
+syntax keyword typescriptDocTags contained define enum extends implements this typedef nextgroup=typescriptDocParamType skipwhite
+syntax keyword typescriptDocTags contained return returns throws exception nextgroup=typescriptDocParamType,typescriptDocParamName skipwhite
+syntax keyword typescriptDocTags contained see nextgroup=typescriptDocRef skipwhite
+
+syntax keyword typescriptDocTags contained function func method nextgroup=typescriptDocName skipwhite
+syntax match typescriptDocName contained /\h\w*/
+
+syntax keyword typescriptDocTags contained fires event nextgroup=typescriptDocEventRef skipwhite
+syntax match typescriptDocEventRef contained /\h\w*#\(\h\w*\:\)\?\h\w*/
+
+syntax match typescriptDocNamedParamType contained /{.\+}/ nextgroup=typescriptDocParamName skipwhite
+syntax match typescriptDocParamName contained /\[\?0-9a-zA-Z_\.]\+\]\?/ nextgroup=typescriptDocDesc skipwhite
+syntax match typescriptDocParamType contained /{.\+}/ nextgroup=typescriptDocDesc skipwhite
+syntax match typescriptDocA contained /\%(#\|\w\|\.\|:\|\/\)\+/ nextgroup=typescriptDocAs skipwhite
+syntax match typescriptDocAs contained /\s*as\s*/ nextgroup=typescriptDocB skipwhite
+syntax match typescriptDocB contained /\%(#\|\w\|\.\|:\|\/\)\+/
+syntax match typescriptDocParam contained /\%(#\|\w\|\.\|:\|\/\|-\)\+/
+syntax match typescriptDocNumParam contained /\d\+/
+syntax match typescriptDocRef contained /\%(#\|\w\|\.\|:\|\/\)\+/
+syntax region typescriptDocLinkTag contained matchgroup=typescriptDocLinkTag start=/{/ end=/}/ contains=typescriptDocTags
+
+syntax cluster typescriptDocs contains=typescriptDocParamType,typescriptDocNamedParamType,typescriptDocParam
+
+if main_syntax == "typescript"
+ syntax sync clear
+ syntax sync ccomment typescriptComment minlines=200
+endif
+
+syntax case match
+
+"runtime syntax/basic/type.vim
+" Types
+syntax match typescriptOptionalMark /?/ contained
+
+syntax region typescriptTypeParameters matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ contained
+
+syntax match typescriptTypeParameter /\K\k*/
+ \ nextgroup=typescriptConstraint,typescriptGenericDefault
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptConstraint extends
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl
+
+syntax match typescriptGenericDefault /=/
+ \ nextgroup=@typescriptType
+ \ contained skipwhite
+
+"><
+" class A extend B<T> {} // ClassBlock
+" func<T>() // FuncCallArg
+syntax region typescriptTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/\></ end=/>/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptFuncCallArg,@typescriptTypeOperator
+ \ contained skipwhite
+
+
+syntax cluster typescriptType contains=
+ \ @typescriptPrimaryType,
+ \ typescriptUnion,
+ \ @typescriptFunctionType,
+ \ typescriptConstructorType
+
+" array type: A[]
+" type indexing A['key']
+syntax region typescriptTypeBracket contained
+ \ start=/\[/ end=/\]/
+ \ contains=typescriptString,typescriptNumber
+ \ nextgroup=@typescriptTypeOperator
+ \ skipwhite skipempty
+
+syntax cluster typescriptPrimaryType contains=
+ \ typescriptParenthesizedType,
+ \ typescriptPredefinedType,
+ \ typescriptTypeReference,
+ \ typescriptObjectType,
+ \ typescriptTupleType,
+ \ typescriptTypeQuery,
+ \ typescriptStringLiteralType,
+ \ typescriptReadonlyArrayKeyword,
+ \ typescriptAssertType
+
+syntax region typescriptStringLiteralType contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/
+ \ nextgroup=typescriptUnion
+ \ skipwhite skipempty
+
+syntax region typescriptParenthesizedType matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=@typescriptType
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty fold
+
+syntax match typescriptTypeReference /\K\k*\(\.\K\k*\)*/
+ \ nextgroup=typescriptTypeArguments,@typescriptTypeOperator,typescriptUserDefinedType
+ \ skipwhite contained skipempty
+
+syntax keyword typescriptPredefinedType any number boolean string void never undefined null object unknown
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty
+
+syntax match typescriptPredefinedType /unique symbol/
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty
+
+syntax region typescriptObjectType matchgroup=typescriptBraces
+ \ start=/{/ end=/}/
+ \ contains=@typescriptTypeMember,typescriptEndColons,@typescriptComments,typescriptAccessibilityModifier,typescriptReadonlyModifier
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite fold
+
+syntax cluster typescriptTypeMember contains=
+ \ @typescriptCallSignature,
+ \ typescriptConstructSignature,
+ \ typescriptIndexSignature,
+ \ @typescriptMembers
+
+syntax region typescriptTupleType matchgroup=typescriptBraces
+ \ start=/\[/ end=/\]/
+ \ contains=@typescriptType,@typescriptComments
+ \ contained skipwhite
+
+syntax cluster typescriptTypeOperator
+ \ contains=typescriptUnion,typescriptTypeBracket
+
+syntax match typescriptUnion /|\|&/ contained nextgroup=@typescriptPrimaryType skipwhite skipempty
+
+syntax cluster typescriptFunctionType contains=typescriptGenericFunc,typescriptFuncType
+syntax region typescriptGenericFunc matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptFuncType
+ \ containedin=typescriptFunctionType
+ \ contained skipwhite skipnl
+
+syntax region typescriptFuncType matchgroup=typescriptParens
+ \ start=/(/ end=/)\s*=>/me=e-2
+ \ contains=@typescriptParameterList
+ \ nextgroup=typescriptFuncTypeArrow
+ \ contained skipwhite skipnl oneline
+
+syntax match typescriptFuncTypeArrow /=>/
+ \ nextgroup=@typescriptType
+ \ containedin=typescriptFuncType
+ \ contained skipwhite skipnl
+
+
+syntax keyword typescriptConstructorType new
+ \ nextgroup=@typescriptFunctionType
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptUserDefinedType is
+ \ contained nextgroup=@typescriptType skipwhite skipempty
+
+syntax keyword typescriptTypeQuery typeof keyof
+ \ nextgroup=typescriptTypeReference
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptAssertType asserts
+ \ nextgroup=typescriptTypeReference
+ \ contained skipwhite skipnl
+
+syntax cluster typescriptCallSignature contains=typescriptGenericCall,typescriptCall
+syntax region typescriptGenericCall matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptCall
+ \ contained skipwhite skipnl
+syntax region typescriptCall matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
+ \ nextgroup=typescriptTypeAnnotation,typescriptBlock
+ \ contained skipwhite skipnl
+
+syntax match typescriptTypeAnnotation /:/
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl
+
+syntax cluster typescriptParameterList contains=
+ \ typescriptTypeAnnotation,
+ \ typescriptAccessibilityModifier,
+ \ typescriptOptionalMark,
+ \ typescriptRestOrSpread,
+ \ typescriptFuncComma,
+ \ typescriptDefaultParam
+
+syntax match typescriptFuncComma /,/ contained
+
+syntax match typescriptDefaultParam /=/
+ \ nextgroup=@typescriptValue
+ \ contained skipwhite
+
+syntax keyword typescriptConstructSignature new
+ \ nextgroup=@typescriptCallSignature
+ \ contained skipwhite
+
+syntax region typescriptIndexSignature matchgroup=typescriptBraces
+ \ start=/\[/ end=/\]/
+ \ contains=typescriptPredefinedType,typescriptMappedIn,typescriptString
+ \ nextgroup=typescriptTypeAnnotation
+ \ contained skipwhite oneline
+
+syntax keyword typescriptMappedIn in
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl skipempty
+
+syntax keyword typescriptAliasKeyword type
+ \ nextgroup=typescriptAliasDeclaration
+ \ skipwhite skipnl skipempty
+
+syntax region typescriptAliasDeclaration matchgroup=typescriptUnion
+ \ start=/ / end=/=/
+ \ nextgroup=@typescriptType
+ \ contains=typescriptConstraint,typescriptTypeParameters
+ \ contained skipwhite skipempty
+
+syntax keyword typescriptReadonlyArrayKeyword readonly
+ \ nextgroup=@typescriptPrimaryType
+ \ skipwhite
+
+" extension
+if get(g:, 'yats_host_keyword', 1)
+ "runtime syntax/yats.vim
+ "runtime syntax/yats/typescript.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Error EvalError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName arguments
+ hi def link typescriptGlobal Structure
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName eval uneval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isFinite nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isNaN parseFloat nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName parseInt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURIComponent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURIComponent nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGlobalMethod
+ hi def link typescriptGlobalMethod Structure
+
+ "runtime syntax/yats/es6-number.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Number nextgroup=typescriptGlobalNumberDot,typescriptFuncCallArg
+ syntax match typescriptGlobalNumberDot /\./ contained nextgroup=typescriptNumberStaticProp,typescriptNumberStaticMethod,typescriptProp
+ syntax keyword typescriptNumberStaticProp contained EPSILON MAX_SAFE_INTEGER MAX_VALUE
+ syntax keyword typescriptNumberStaticProp contained MIN_SAFE_INTEGER MIN_VALUE NEGATIVE_INFINITY
+ syntax keyword typescriptNumberStaticProp contained NaN POSITIVE_INFINITY
+ hi def link typescriptNumberStaticProp Keyword
+ syntax keyword typescriptNumberStaticMethod contained isFinite isInteger isNaN isSafeInteger nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptNumberStaticMethod contained parseFloat parseInt nextgroup=typescriptFuncCallArg
+ hi def link typescriptNumberStaticMethod Keyword
+ syntax keyword typescriptNumberMethod contained toExponential toFixed toLocaleString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptNumberMethod contained toPrecision toSource toString valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptNumberMethod
+ hi def link typescriptNumberMethod Keyword
+
+ "runtime syntax/yats/es6-string.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName String nextgroup=typescriptGlobalStringDot,typescriptFuncCallArg
+ syntax match typescriptGlobalStringDot /\./ contained nextgroup=typescriptStringStaticMethod,typescriptProp
+ syntax keyword typescriptStringStaticMethod contained fromCharCode fromCodePoint raw nextgroup=typescriptFuncCallArg
+ hi def link typescriptStringStaticMethod Keyword
+ syntax keyword typescriptStringMethod contained anchor charAt charCodeAt codePointAt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained concat endsWith includes indexOf lastIndexOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained link localeCompare match normalize nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained padStart padEnd repeat replace search nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained slice split startsWith substr substring nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained toLocaleLowerCase toLocaleUpperCase nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained toLowerCase toString toUpperCase trim nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptStringMethod
+ hi def link typescriptStringMethod Keyword
+
+ "runtime syntax/yats/es6-array.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Array nextgroup=typescriptGlobalArrayDot,typescriptFuncCallArg
+ syntax match typescriptGlobalArrayDot /\./ contained nextgroup=typescriptArrayStaticMethod,typescriptProp
+ syntax keyword typescriptArrayStaticMethod contained from isArray of nextgroup=typescriptFuncCallArg
+ hi def link typescriptArrayStaticMethod Keyword
+ syntax keyword typescriptArrayMethod contained concat copyWithin entries every fill nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained filter find findIndex forEach indexOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained includes join keys lastIndexOf map nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained pop push reduce reduceRight reverse nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained shift slice some sort splice toLocaleString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained toSource toString unshift nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptArrayMethod
+ hi def link typescriptArrayMethod Keyword
+
+ "runtime syntax/yats/es6-object.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Object nextgroup=typescriptGlobalObjectDot,typescriptFuncCallArg
+ syntax match typescriptGlobalObjectDot /\./ contained nextgroup=typescriptObjectStaticMethod,typescriptProp
+ syntax keyword typescriptObjectStaticMethod contained create defineProperties defineProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained entries freeze getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained getOwnPropertyDescriptor getOwnPropertyNames nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained getOwnPropertySymbols getPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained is isExtensible isFrozen isSealed nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained keys preventExtensions values nextgroup=typescriptFuncCallArg
+ hi def link typescriptObjectStaticMethod Keyword
+ syntax keyword typescriptObjectMethod contained getOwnPropertyDescriptors hasOwnProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained isPrototypeOf propertyIsEnumerable nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained toLocaleString toString valueOf seal nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained setPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptObjectMethod
+ hi def link typescriptObjectMethod Keyword
+
+ "runtime syntax/yats/es6-symbol.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Symbol nextgroup=typescriptGlobalSymbolDot,typescriptFuncCallArg
+ syntax match typescriptGlobalSymbolDot /\./ contained nextgroup=typescriptSymbolStaticProp,typescriptSymbolStaticMethod,typescriptProp
+ syntax keyword typescriptSymbolStaticProp contained length iterator match replace
+ syntax keyword typescriptSymbolStaticProp contained search split hasInstance isConcatSpreadable
+ syntax keyword typescriptSymbolStaticProp contained unscopables species toPrimitive
+ syntax keyword typescriptSymbolStaticProp contained toStringTag
+ hi def link typescriptSymbolStaticProp Keyword
+ syntax keyword typescriptSymbolStaticMethod contained for keyFor nextgroup=typescriptFuncCallArg
+ hi def link typescriptSymbolStaticMethod Keyword
+
+ "runtime syntax/yats/es6-function.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function
+ syntax keyword typescriptFunctionMethod contained apply bind call nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFunctionMethod
+ hi def link typescriptFunctionMethod Keyword
+
+ "runtime syntax/yats/es6-math.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Math nextgroup=typescriptGlobalMathDot,typescriptFuncCallArg
+ syntax match typescriptGlobalMathDot /\./ contained nextgroup=typescriptMathStaticProp,typescriptMathStaticMethod,typescriptProp
+ syntax keyword typescriptMathStaticProp contained E LN10 LN2 LOG10E LOG2E PI SQRT1_2
+ syntax keyword typescriptMathStaticProp contained SQRT2
+ hi def link typescriptMathStaticProp Keyword
+ syntax keyword typescriptMathStaticMethod contained abs acos acosh asin asinh atan nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained atan2 atanh cbrt ceil clz32 cos nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained cosh exp expm1 floor fround hypot nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained imul log log10 log1p log2 max nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained min pow random round sign sin nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained sinh sqrt tan tanh trunc nextgroup=typescriptFuncCallArg
+ hi def link typescriptMathStaticMethod Keyword
+
+ "runtime syntax/yats/es6-date.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Date nextgroup=typescriptGlobalDateDot,typescriptFuncCallArg
+ syntax match typescriptGlobalDateDot /\./ contained nextgroup=typescriptDateStaticMethod,typescriptProp
+ syntax keyword typescriptDateStaticMethod contained UTC now parse nextgroup=typescriptFuncCallArg
+ hi def link typescriptDateStaticMethod Keyword
+ syntax keyword typescriptDateMethod contained getDate getDay getFullYear getHours nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getMilliseconds getMinutes getMonth nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getSeconds getTime getTimezoneOffset nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCDate getUTCDay getUTCFullYear nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCHours getUTCMilliseconds getUTCMinutes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCMonth getUTCSeconds setDate setFullYear nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setHours setMilliseconds setMinutes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setMonth setSeconds setTime setUTCDate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setUTCFullYear setUTCHours setUTCMilliseconds nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setUTCMinutes setUTCMonth setUTCSeconds nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toDateString toISOString toJSON toLocaleDateString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toLocaleFormat toLocaleString toLocaleTimeString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toSource toString toTimeString toUTCString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDateMethod
+ hi def link typescriptDateMethod Keyword
+
+ "runtime syntax/yats/es6-json.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName JSON nextgroup=typescriptGlobalJSONDot,typescriptFuncCallArg
+ syntax match typescriptGlobalJSONDot /\./ contained nextgroup=typescriptJSONStaticMethod,typescriptProp
+ syntax keyword typescriptJSONStaticMethod contained parse stringify nextgroup=typescriptFuncCallArg
+ hi def link typescriptJSONStaticMethod Keyword
+
+ "runtime syntax/yats/es6-regexp.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName RegExp nextgroup=typescriptGlobalRegExpDot,typescriptFuncCallArg
+ syntax match typescriptGlobalRegExpDot /\./ contained nextgroup=typescriptRegExpStaticProp,typescriptProp
+ syntax keyword typescriptRegExpStaticProp contained lastIndex
+ hi def link typescriptRegExpStaticProp Keyword
+ syntax keyword typescriptRegExpProp contained global ignoreCase multiline source sticky
+ syntax cluster props add=typescriptRegExpProp
+ hi def link typescriptRegExpProp Keyword
+ syntax keyword typescriptRegExpMethod contained exec test nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptRegExpMethod
+ hi def link typescriptRegExpMethod Keyword
+
+ "runtime syntax/yats/es6-map.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Map WeakMap
+ syntax keyword typescriptES6MapProp contained size
+ syntax cluster props add=typescriptES6MapProp
+ hi def link typescriptES6MapProp Keyword
+ syntax keyword typescriptES6MapMethod contained clear delete entries forEach get has nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptES6MapMethod contained keys set values nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptES6MapMethod
+ hi def link typescriptES6MapMethod Keyword
+
+ "runtime syntax/yats/es6-set.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Set WeakSet
+ syntax keyword typescriptES6SetProp contained size
+ syntax cluster props add=typescriptES6SetProp
+ hi def link typescriptES6SetProp Keyword
+ syntax keyword typescriptES6SetMethod contained add clear delete entries forEach has nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptES6SetMethod contained values nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptES6SetMethod
+ hi def link typescriptES6SetMethod Keyword
+
+ "runtime syntax/yats/es6-proxy.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Proxy
+ syntax keyword typescriptProxyAPI contained getOwnPropertyDescriptor getOwnPropertyNames
+ syntax keyword typescriptProxyAPI contained defineProperty deleteProperty freeze seal
+ syntax keyword typescriptProxyAPI contained preventExtensions has hasOwn get set enumerate
+ syntax keyword typescriptProxyAPI contained iterate ownKeys apply construct
+ hi def link typescriptProxyAPI Keyword
+
+ "runtime syntax/yats/es6-promise.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Promise nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg
+ syntax match typescriptGlobalPromiseDot /\./ contained nextgroup=typescriptPromiseStaticMethod,typescriptProp
+ syntax keyword typescriptPromiseStaticMethod contained resolve reject all race nextgroup=typescriptFuncCallArg
+ hi def link typescriptPromiseStaticMethod Keyword
+ syntax keyword typescriptPromiseMethod contained then catch finally nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPromiseMethod
+ hi def link typescriptPromiseMethod Keyword
+
+ "runtime syntax/yats/es6-reflect.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect
+ syntax keyword typescriptReflectMethod contained apply construct defineProperty deleteProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained enumerate get getOwnPropertyDescriptor nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained getPrototypeOf has isExtensible ownKeys nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained preventExtensions set setPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptReflectMethod
+ hi def link typescriptReflectMethod Keyword
+
+ "runtime syntax/yats/ecma-402.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Intl
+ syntax keyword typescriptIntlMethod contained Collator DateTimeFormat NumberFormat nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptIntlMethod contained PluralRules nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptIntlMethod
+ hi def link typescriptIntlMethod Keyword
+
+ "runtime syntax/yats/node.vim
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName global process
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName console Buffer
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName module exports
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setTimeout
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearTimeout
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setInterval
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearInterval
+ hi def link typescriptNodeGlobal Structure
+
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName describe
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName it test before
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName after beforeEach
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName afterEach
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName beforeAll
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName afterAll
+ syntax keyword typescriptTestGlobal containedin=typescriptIdentifierName expect assert
+
+ "runtime syntax/yats/web.vim
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AbortController
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AbstractWorker AnalyserNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName App Apps ArrayBuffer
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ArrayBufferView
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Attr AudioBuffer
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioBufferSourceNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioContext AudioDestinationNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioListener AudioNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioParam BatteryManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BiquadFilterNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BlobEvent BluetoothAdapter
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothDevice
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraCapabilities
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraControl CameraManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasGradient CanvasImageSource
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasPattern CanvasRenderingContext2D
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CaretPosition CDATASection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelMergerNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelSplitterNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CharacterData ChildNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChromeWorker Comment
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Connection Console
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ContactManager Contacts
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ConvolverNode Coordinates
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSS CSSConditionRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSGroupingRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframeRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframesRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSMediaRule CSSNamespaceRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSPageRule CSSRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSRuleList CSSStyleDeclaration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSStyleRule CSSStyleSheet
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSSupportsRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DataTransfer DataView
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DedicatedWorkerGlobalScope
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DelayNode DeviceAcceleration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceRotationRate
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceStorage DirectoryEntry
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryEntrySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReader
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReaderSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Document DocumentFragment
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DocumentTouch DocumentType
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMCursor DOMError
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMException DOMHighResTimeStamp
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementationRegistry
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMParser DOMRequest
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMString DOMStringList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMStringMap DOMTimeStamp
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMTokenList DynamicsCompressorNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Element Entry EntrySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Extensions FileException
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Float32Array Float64Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName FMRadio FormData
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName GainNode Gamepad
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName GamepadButton Geolocation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName History HTMLAnchorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAreaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAudioElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBaseElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBodyElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBRElement HTMLButtonElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCanvasElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCollection HTMLDataElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDataListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDivElement HTMLDListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDocument HTMLElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLEmbedElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFieldSetElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormControlsCollection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadingElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHRElement HTMLHtmlElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLIFrameElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLImageElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLInputElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLKeygenElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLabelElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLegendElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLIElement HTMLLinkElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMapElement HTMLMediaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMetaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMeterElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLModElement HTMLObjectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptGroupElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionsCollection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOutputElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParagraphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParamElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLPreElement HTMLProgressElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLQuoteElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLScriptElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSelectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSourceElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSpanElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLStyleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCaptionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableColElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableDataCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableHeaderCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableRowElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableSectionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTextAreaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTimeElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTitleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTrackElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUnknownElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLVideoElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursor IDBCursorSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursorWithValue
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBDatabase IDBDatabaseSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBEnvironment IDBEnvironmentSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBFactory IDBFactorySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBIndex IDBIndexSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBKeyRange IDBObjectStore
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBObjectStoreSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBOpenDBRequest
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBRequest IDBTransaction
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBTransactionSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBVersionChangeEvent
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ImageData IndexedDB
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Int16Array Int32Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Int8Array L10n LinkStyle
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystem
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystemSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Location LockedFile
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaQueryList MediaQueryListListener
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaRecorder MediaSource
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaStream MediaStreamTrack
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MutationObserver
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Navigator NavigatorGeolocation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorID NavigatorLanguage
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorOnLine
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorPlugins
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Node NodeFilter
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NodeIterator NodeList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Notification OfflineAudioContext
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName OscillatorNode PannerNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ParentNode Performance
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceNavigation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceTiming
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Permissions PermissionSettings
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Plugin PluginArray
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Position PositionError
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PositionOptions
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PowerManager ProcessingInstruction
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PromiseResolver
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PushManager Range
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCConfiguration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnectionErrorCallback
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescription
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescriptionCallback
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ScriptProcessorNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Selection SettingsLock
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SettingsManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SharedWorker StyleSheet
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName StyleSheetList SVGAElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAngle SVGAnimateColorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedAngle
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedBoolean
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedEnumeration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedInteger
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLength
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLengthList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumber
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumberList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPoints
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPreserveAspectRatio
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedRect
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedString
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedTransformList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateMotionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateTransformElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimationElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCircleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGClipPathElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCursorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGDefsElement SVGDescElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGElement SVGEllipseElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFilterElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontElement SVGFontFaceElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceFormatElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceNameElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceSrcElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceUriElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGForeignObjectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGElement SVGGlyphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGHKernElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGImageElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLength SVGLengthList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLinearGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLineElement SVGMaskElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMatrix SVGMissingGlyphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMPathElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGNumber SVGNumberList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPathElement SVGPatternElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPoint SVGPolygonElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPolylineElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPreserveAspectRatio
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRadialGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRect SVGRectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGScriptElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSetElement SVGStopElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStringList SVGStylable
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStyleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSVGElement SVGSwitchElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSymbolElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTests SVGTextElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTextPositioningElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTitleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransform SVGTransformable
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransformList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTRefElement SVGTSpanElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGUseElement SVGViewElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGVKernElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPServerSocket
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPSocket Telephony
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TelephonyCall Text
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TextDecoder TextEncoder
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TextMetrics TimeRanges
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Touch TouchList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Transferable TreeWalker
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint16Array Uint32Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint8Array Uint8ClampedArray
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName URLSearchParams
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName URLUtilsReadOnly
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName UserProximityEvent
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ValidityState VideoPlaybackQuality
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WaveShaperNode WebBluetooth
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebGLRenderingContext
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebSMS WebSocket
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebVTT WifiManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Window Worker WorkerConsole
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WorkerLocation WorkerNavigator
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName XDomainRequest XMLDocument
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName XMLHttpRequestEventTarget
+ hi def link typescriptBOM Structure
+
+ "runtime syntax/yats/web-window.vim
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName applicationCache
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName closed
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName Components
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName controllers
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName dialogArguments
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName document
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frameElement
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frames
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName fullScreen
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName history
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerHeight
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerWidth
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName length
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName location
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName locationbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName menubar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName messageManager
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName name navigator
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName opener
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerHeight
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerWidth
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageXOffset
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageYOffset
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName parent
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName performance
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName personalbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName returnValue
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screen
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollbars
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName self sidebar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName status
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName statusbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName toolbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName top visualViewport
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName window
+ syntax cluster props add=typescriptBOMWindowProp
+ hi def link typescriptBOMWindowProp Structure
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName alert nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName atob nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName blur nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName btoa nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearImmediate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearInterval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearTimeout nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName close nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName confirm nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName dispatchEvent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName find nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName focus nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttention nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttentionWithCycleCount nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getComputedStyle nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getDefaulComputedStyle nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getSelection nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName matchMedia nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName maximize nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName open nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName openDialog nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName postMessage nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName print nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName prompt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName removeEventListener nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName restore nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scroll nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByLines nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByPages nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setCursor nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setImmediate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setInterval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setResizable nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setTimeout nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName showModalDialog nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName sizeToContent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName stop nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName updateCommands nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMWindowMethod
+ hi def link typescriptBOMWindowMethod Structure
+ syntax keyword typescriptBOMWindowEvent contained onabort onbeforeunload onblur onchange
+ syntax keyword typescriptBOMWindowEvent contained onclick onclose oncontextmenu ondevicelight
+ syntax keyword typescriptBOMWindowEvent contained ondevicemotion ondeviceorientation
+ syntax keyword typescriptBOMWindowEvent contained ondeviceproximity ondragdrop onerror
+ syntax keyword typescriptBOMWindowEvent contained onfocus onhashchange onkeydown onkeypress
+ syntax keyword typescriptBOMWindowEvent contained onkeyup onload onmousedown onmousemove
+ syntax keyword typescriptBOMWindowEvent contained onmouseout onmouseover onmouseup
+ syntax keyword typescriptBOMWindowEvent contained onmozbeforepaint onpaint onpopstate
+ syntax keyword typescriptBOMWindowEvent contained onreset onresize onscroll onselect
+ syntax keyword typescriptBOMWindowEvent contained onsubmit onunload onuserproximity
+ syntax keyword typescriptBOMWindowEvent contained onpageshow onpagehide
+ hi def link typescriptBOMWindowEvent Keyword
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName DOMParser
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName QueryInterface
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName XMLSerializer
+ hi def link typescriptBOMWindowCons Structure
+
+ "runtime syntax/yats/web-navigator.vim
+ syntax keyword typescriptBOMNavigatorProp contained battery buildID connection cookieEnabled
+ syntax keyword typescriptBOMNavigatorProp contained doNotTrack maxTouchPoints oscpu
+ syntax keyword typescriptBOMNavigatorProp contained productSub push serviceWorker
+ syntax keyword typescriptBOMNavigatorProp contained vendor vendorSub
+ syntax cluster props add=typescriptBOMNavigatorProp
+ hi def link typescriptBOMNavigatorProp Keyword
+ syntax keyword typescriptBOMNavigatorMethod contained addIdleObserver geolocation nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained getDeviceStorage getDeviceStorages nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained getGamepads getUserMedia registerContentHandler nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained removeIdleObserver requestWakeLock nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained share vibrate watch registerProtocolHandler nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained sendBeacon nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMNavigatorMethod
+ hi def link typescriptBOMNavigatorMethod Keyword
+ syntax keyword typescriptServiceWorkerMethod contained register nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptServiceWorkerMethod
+ hi def link typescriptServiceWorkerMethod Keyword
+
+ "runtime syntax/yats/web-location.vim
+ syntax keyword typescriptBOMLocationProp contained href protocol host hostname port
+ syntax keyword typescriptBOMLocationProp contained pathname search hash username password
+ syntax keyword typescriptBOMLocationProp contained origin
+ syntax cluster props add=typescriptBOMLocationProp
+ hi def link typescriptBOMLocationProp Keyword
+ syntax keyword typescriptBOMLocationMethod contained assign reload replace toString nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMLocationMethod
+ hi def link typescriptBOMLocationMethod Keyword
+
+ "runtime syntax/yats/web-history.vim
+ syntax keyword typescriptBOMHistoryProp contained length current next previous state
+ syntax keyword typescriptBOMHistoryProp contained scrollRestoration
+ syntax cluster props add=typescriptBOMHistoryProp
+ hi def link typescriptBOMHistoryProp Keyword
+ syntax keyword typescriptBOMHistoryMethod contained back forward go pushState replaceState nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMHistoryMethod
+ hi def link typescriptBOMHistoryMethod Keyword
+
+ "runtime syntax/yats/web-console.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName console
+ syntax keyword typescriptConsoleMethod contained count dir error group groupCollapsed nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptConsoleMethod contained groupEnd info log time timeEnd trace nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptConsoleMethod contained warn nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptConsoleMethod
+ hi def link typescriptConsoleMethod Keyword
+
+ "runtime syntax/yats/web-xhr.vim
+ syntax keyword typescriptXHRGlobal containedin=typescriptIdentifierName XMLHttpRequest
+ hi def link typescriptXHRGlobal Structure
+ syntax keyword typescriptXHRProp contained onreadystatechange readyState response
+ syntax keyword typescriptXHRProp contained responseText responseType responseXML status
+ syntax keyword typescriptXHRProp contained statusText timeout ontimeout upload withCredentials
+ syntax cluster props add=typescriptXHRProp
+ hi def link typescriptXHRProp Keyword
+ syntax keyword typescriptXHRMethod contained abort getAllResponseHeaders getResponseHeader nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptXHRMethod contained open overrideMimeType send setRequestHeader nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptXHRMethod
+ hi def link typescriptXHRMethod Keyword
+
+ "runtime syntax/yats/web-blob.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Blob BlobBuilder
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName File FileReader
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName FileReaderSync
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URL nextgroup=typescriptGlobalURLDot,typescriptFuncCallArg
+ syntax match typescriptGlobalURLDot /\./ contained nextgroup=typescriptURLStaticMethod,typescriptProp
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URLUtils
+ syntax keyword typescriptFileMethod contained readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptFileMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileMethod
+ hi def link typescriptFileMethod Keyword
+ syntax keyword typescriptFileReaderProp contained error readyState result
+ syntax cluster props add=typescriptFileReaderProp
+ hi def link typescriptFileReaderProp Keyword
+ syntax keyword typescriptFileReaderMethod contained abort readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptFileReaderMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileReaderMethod
+ hi def link typescriptFileReaderMethod Keyword
+ syntax keyword typescriptFileListMethod contained item nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileListMethod
+ hi def link typescriptFileListMethod Keyword
+ syntax keyword typescriptBlobMethod contained append getBlob getFile nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBlobMethod
+ hi def link typescriptBlobMethod Keyword
+ syntax keyword typescriptURLUtilsProp contained hash host hostname href origin password
+ syntax keyword typescriptURLUtilsProp contained pathname port protocol search searchParams
+ syntax keyword typescriptURLUtilsProp contained username
+ syntax cluster props add=typescriptURLUtilsProp
+ hi def link typescriptURLUtilsProp Keyword
+ syntax keyword typescriptURLStaticMethod contained createObjectURL revokeObjectURL nextgroup=typescriptFuncCallArg
+ hi def link typescriptURLStaticMethod Keyword
+
+ "runtime syntax/yats/web-crypto.vim
+ syntax keyword typescriptCryptoGlobal containedin=typescriptIdentifierName crypto
+ hi def link typescriptCryptoGlobal Structure
+ syntax keyword typescriptSubtleCryptoMethod contained encrypt decrypt sign verify nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptSubtleCryptoMethod contained digest nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptSubtleCryptoMethod
+ hi def link typescriptSubtleCryptoMethod Keyword
+ syntax keyword typescriptCryptoProp contained subtle
+ syntax cluster props add=typescriptCryptoProp
+ hi def link typescriptCryptoProp Keyword
+ syntax keyword typescriptCryptoMethod contained getRandomValues nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptCryptoMethod
+ hi def link typescriptCryptoMethod Keyword
+
+ "runtime syntax/yats/web-fetch.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Headers Request
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Response
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName fetch nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGlobalMethod
+ hi def link typescriptGlobalMethod Structure
+ syntax keyword typescriptHeadersMethod contained append delete get getAll has set nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptHeadersMethod
+ hi def link typescriptHeadersMethod Keyword
+ syntax keyword typescriptRequestProp contained method url headers context referrer
+ syntax keyword typescriptRequestProp contained mode credentials cache
+ syntax cluster props add=typescriptRequestProp
+ hi def link typescriptRequestProp Keyword
+ syntax keyword typescriptRequestMethod contained clone nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptRequestMethod
+ hi def link typescriptRequestMethod Keyword
+ syntax keyword typescriptResponseProp contained type url status statusText headers
+ syntax keyword typescriptResponseProp contained redirected
+ syntax cluster props add=typescriptResponseProp
+ hi def link typescriptResponseProp Keyword
+ syntax keyword typescriptResponseMethod contained clone nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptResponseMethod
+ hi def link typescriptResponseMethod Keyword
+
+ "runtime syntax/yats/web-service-worker.vim
+ syntax keyword typescriptServiceWorkerProp contained controller ready
+ syntax cluster props add=typescriptServiceWorkerProp
+ hi def link typescriptServiceWorkerProp Keyword
+ syntax keyword typescriptServiceWorkerMethod contained register getRegistration nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptServiceWorkerMethod
+ hi def link typescriptServiceWorkerMethod Keyword
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Cache
+ syntax keyword typescriptCacheMethod contained match matchAll add addAll put delete nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptCacheMethod contained keys nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptCacheMethod
+ hi def link typescriptCacheMethod Keyword
+
+ "runtime syntax/yats/web-encoding.vim
+ syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextEncoder
+ syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextDecoder
+ hi def link typescriptEncodingGlobal Structure
+ syntax keyword typescriptEncodingProp contained encoding fatal ignoreBOM
+ syntax cluster props add=typescriptEncodingProp
+ hi def link typescriptEncodingProp Keyword
+ syntax keyword typescriptEncodingMethod contained encode decode nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptEncodingMethod
+ hi def link typescriptEncodingMethod Keyword
+
+ "runtime syntax/yats/web-geo.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Geolocation
+ syntax keyword typescriptGeolocationMethod contained getCurrentPosition watchPosition nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGeolocationMethod contained clearWatch nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGeolocationMethod
+ hi def link typescriptGeolocationMethod Keyword
+
+ "runtime syntax/yats/web-network.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName NetworkInformation
+ syntax keyword typescriptBOMNetworkProp contained downlink downlinkMax effectiveType
+ syntax keyword typescriptBOMNetworkProp contained rtt type
+ syntax cluster props add=typescriptBOMNetworkProp
+ hi def link typescriptBOMNetworkProp Keyword
+
+ "runtime syntax/yats/web-payment.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName PaymentRequest
+ syntax keyword typescriptPaymentMethod contained show abort canMakePayment nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPaymentMethod
+ hi def link typescriptPaymentMethod Keyword
+ syntax keyword typescriptPaymentProp contained shippingAddress shippingOption result
+ syntax cluster props add=typescriptPaymentProp
+ hi def link typescriptPaymentProp Keyword
+ syntax keyword typescriptPaymentEvent contained onshippingaddresschange onshippingoptionchange
+ hi def link typescriptPaymentEvent Keyword
+ syntax keyword typescriptPaymentResponseMethod contained complete nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPaymentResponseMethod
+ hi def link typescriptPaymentResponseMethod Keyword
+ syntax keyword typescriptPaymentResponseProp contained details methodName payerEmail
+ syntax keyword typescriptPaymentResponseProp contained payerPhone shippingAddress
+ syntax keyword typescriptPaymentResponseProp contained shippingOption
+ syntax cluster props add=typescriptPaymentResponseProp
+ hi def link typescriptPaymentResponseProp Keyword
+ syntax keyword typescriptPaymentAddressProp contained addressLine careOf city country
+ syntax keyword typescriptPaymentAddressProp contained country dependentLocality languageCode
+ syntax keyword typescriptPaymentAddressProp contained organization phone postalCode
+ syntax keyword typescriptPaymentAddressProp contained recipient region sortingCode
+ syntax cluster props add=typescriptPaymentAddressProp
+ hi def link typescriptPaymentAddressProp Keyword
+ syntax keyword typescriptPaymentShippingOptionProp contained id label amount selected
+ syntax cluster props add=typescriptPaymentShippingOptionProp
+ hi def link typescriptPaymentShippingOptionProp Keyword
+
+ "runtime syntax/yats/dom-node.vim
+ syntax keyword typescriptDOMNodeProp contained attributes baseURI baseURIObject childNodes
+ syntax keyword typescriptDOMNodeProp contained firstChild lastChild localName namespaceURI
+ syntax keyword typescriptDOMNodeProp contained nextSibling nodeName nodePrincipal
+ syntax keyword typescriptDOMNodeProp contained nodeType nodeValue ownerDocument parentElement
+ syntax keyword typescriptDOMNodeProp contained parentNode prefix previousSibling textContent
+ syntax cluster props add=typescriptDOMNodeProp
+ hi def link typescriptDOMNodeProp Keyword
+ syntax keyword typescriptDOMNodeMethod contained appendChild cloneNode compareDocumentPosition nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained getUserData hasAttributes hasChildNodes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained insertBefore isDefaultNamespace isEqualNode nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained isSameNode isSupported lookupNamespaceURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained lookupPrefix normalize removeChild nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained replaceChild setUserData nextgroup=typescriptFuncCallArg
+ syntax match typescriptDOMNodeMethod contained /contains/
+ syntax cluster props add=typescriptDOMNodeMethod
+ hi def link typescriptDOMNodeMethod Keyword
+ syntax keyword typescriptDOMNodeType contained ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE
+ syntax keyword typescriptDOMNodeType contained CDATA_SECTION_NODEN_NODE ENTITY_REFERENCE_NODE
+ syntax keyword typescriptDOMNodeType contained ENTITY_NODE PROCESSING_INSTRUCTION_NODEN_NODE
+ syntax keyword typescriptDOMNodeType contained COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE
+ syntax keyword typescriptDOMNodeType contained DOCUMENT_FRAGMENT_NODE NOTATION_NODE
+ hi def link typescriptDOMNodeType Keyword
+
+ "runtime syntax/yats/dom-elem.vim
+ syntax keyword typescriptDOMElemAttrs contained accessKey clientHeight clientLeft
+ syntax keyword typescriptDOMElemAttrs contained clientTop clientWidth id innerHTML
+ syntax keyword typescriptDOMElemAttrs contained length onafterscriptexecute onbeforescriptexecute
+ syntax keyword typescriptDOMElemAttrs contained oncopy oncut onpaste onwheel scrollHeight
+ syntax keyword typescriptDOMElemAttrs contained scrollLeft scrollTop scrollWidth tagName
+ syntax keyword typescriptDOMElemAttrs contained classList className name outerHTML
+ syntax keyword typescriptDOMElemAttrs contained style
+ hi def link typescriptDOMElemAttrs Keyword
+ syntax keyword typescriptDOMElemFuncs contained getAttributeNS getAttributeNode getAttributeNodeNS
+ syntax keyword typescriptDOMElemFuncs contained getBoundingClientRect getClientRects
+ syntax keyword typescriptDOMElemFuncs contained getElementsByClassName getElementsByTagName
+ syntax keyword typescriptDOMElemFuncs contained getElementsByTagNameNS hasAttribute
+ syntax keyword typescriptDOMElemFuncs contained hasAttributeNS insertAdjacentHTML
+ syntax keyword typescriptDOMElemFuncs contained matches querySelector querySelectorAll
+ syntax keyword typescriptDOMElemFuncs contained removeAttribute removeAttributeNS
+ syntax keyword typescriptDOMElemFuncs contained removeAttributeNode requestFullscreen
+ syntax keyword typescriptDOMElemFuncs contained requestPointerLock scrollIntoView
+ syntax keyword typescriptDOMElemFuncs contained setAttribute setAttributeNS setAttributeNode
+ syntax keyword typescriptDOMElemFuncs contained setAttributeNodeNS setCapture supports
+ syntax keyword typescriptDOMElemFuncs contained getAttribute
+ hi def link typescriptDOMElemFuncs Keyword
+
+ "runtime syntax/yats/dom-document.vim
+ syntax keyword typescriptDOMDocProp contained activeElement body cookie defaultView
+ syntax keyword typescriptDOMDocProp contained designMode dir domain embeds forms head
+ syntax keyword typescriptDOMDocProp contained images lastModified links location plugins
+ syntax keyword typescriptDOMDocProp contained postMessage readyState referrer registerElement
+ syntax keyword typescriptDOMDocProp contained scripts styleSheets title vlinkColor
+ syntax keyword typescriptDOMDocProp contained xmlEncoding characterSet compatMode
+ syntax keyword typescriptDOMDocProp contained contentType currentScript doctype documentElement
+ syntax keyword typescriptDOMDocProp contained documentURI documentURIObject firstChild
+ syntax keyword typescriptDOMDocProp contained implementation lastStyleSheetSet namespaceURI
+ syntax keyword typescriptDOMDocProp contained nodePrincipal ononline pointerLockElement
+ syntax keyword typescriptDOMDocProp contained popupNode preferredStyleSheetSet selectedStyleSheetSet
+ syntax keyword typescriptDOMDocProp contained styleSheetSets textContent tooltipNode
+ syntax cluster props add=typescriptDOMDocProp
+ hi def link typescriptDOMDocProp Keyword
+ syntax keyword typescriptDOMDocMethod contained caretPositionFromPoint close createNodeIterator nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createRange createTreeWalker elementFromPoint nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByName adoptNode createAttribute nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createCDATASection createComment createDocumentFragment nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createElement createElementNS createEvent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createExpression createNSResolver nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createProcessingInstruction createTextNode nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained enableStyleSheetsForSet evaluate execCommand nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained exitPointerLock getBoxObjectFor getElementById nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByClassName getElementsByTagName nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByTagNameNS getSelection nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained hasFocus importNode loadOverlay open nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained queryCommandSupported querySelector nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained querySelectorAll write writeln nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMDocMethod
+ hi def link typescriptDOMDocMethod Keyword
+
+ "runtime syntax/yats/dom-event.vim
+ syntax keyword typescriptDOMEventTargetMethod contained addEventListener removeEventListener nextgroup=typescriptEventFuncCallArg
+ syntax keyword typescriptDOMEventTargetMethod contained dispatchEvent waitUntil nextgroup=typescriptEventFuncCallArg
+ syntax cluster props add=typescriptDOMEventTargetMethod
+ hi def link typescriptDOMEventTargetMethod Keyword
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AnimationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AudioProcessingEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeInputEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeUnloadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BlobEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ClipboardEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CloseEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CompositionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CSSFontFaceLoadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CustomEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceLightEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceMotionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceOrientationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceProximityEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DOMTransactionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DragEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName EditingBeforeInputEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ErrorEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName FocusEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName GamepadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName HashChangeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName IDBVersionChangeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName KeyboardEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MediaStreamEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MessageEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MouseEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MutationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName OfflineAudioCompletionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PageTransitionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PointerEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PopStateEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ProgressEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RelatedEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RTCPeerConnectionIceEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SensorEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName StorageEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGZoomEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TimeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TouchEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TrackEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TransitionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UIEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UserProximityEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName WheelEvent
+ hi def link typescriptDOMEventCons Structure
+ syntax keyword typescriptDOMEventProp contained bubbles cancelable currentTarget defaultPrevented
+ syntax keyword typescriptDOMEventProp contained eventPhase target timeStamp type isTrusted
+ syntax keyword typescriptDOMEventProp contained isReload
+ syntax cluster props add=typescriptDOMEventProp
+ hi def link typescriptDOMEventProp Keyword
+ syntax keyword typescriptDOMEventMethod contained initEvent preventDefault stopImmediatePropagation nextgroup=typescriptEventFuncCallArg
+ syntax keyword typescriptDOMEventMethod contained stopPropagation respondWith default nextgroup=typescriptEventFuncCallArg
+ syntax cluster props add=typescriptDOMEventMethod
+ hi def link typescriptDOMEventMethod Keyword
+
+ "runtime syntax/yats/dom-storage.vim
+ syntax keyword typescriptDOMStorage contained sessionStorage localStorage
+ hi def link typescriptDOMStorage Keyword
+ syntax keyword typescriptDOMStorageProp contained length
+ syntax cluster props add=typescriptDOMStorageProp
+ hi def link typescriptDOMStorageProp Keyword
+ syntax keyword typescriptDOMStorageMethod contained getItem key setItem removeItem nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMStorageMethod contained clear nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMStorageMethod
+ hi def link typescriptDOMStorageMethod Keyword
+
+ "runtime syntax/yats/dom-form.vim
+ syntax keyword typescriptDOMFormProp contained acceptCharset action elements encoding
+ syntax keyword typescriptDOMFormProp contained enctype length method name target
+ syntax cluster props add=typescriptDOMFormProp
+ hi def link typescriptDOMFormProp Keyword
+ syntax keyword typescriptDOMFormMethod contained reportValidity reset submit nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMFormMethod
+ hi def link typescriptDOMFormMethod Keyword
+
+ "runtime syntax/yats/css.vim
+ syntax keyword typescriptDOMStyle contained alignContent alignItems alignSelf animation
+ syntax keyword typescriptDOMStyle contained animationDelay animationDirection animationDuration
+ syntax keyword typescriptDOMStyle contained animationFillMode animationIterationCount
+ syntax keyword typescriptDOMStyle contained animationName animationPlayState animationTimingFunction
+ syntax keyword typescriptDOMStyle contained appearance backfaceVisibility background
+ syntax keyword typescriptDOMStyle contained backgroundAttachment backgroundBlendMode
+ syntax keyword typescriptDOMStyle contained backgroundClip backgroundColor backgroundImage
+ syntax keyword typescriptDOMStyle contained backgroundOrigin backgroundPosition backgroundRepeat
+ syntax keyword typescriptDOMStyle contained backgroundSize border borderBottom borderBottomColor
+ syntax keyword typescriptDOMStyle contained borderBottomLeftRadius borderBottomRightRadius
+ syntax keyword typescriptDOMStyle contained borderBottomStyle borderBottomWidth borderCollapse
+ syntax keyword typescriptDOMStyle contained borderColor borderImage borderImageOutset
+ syntax keyword typescriptDOMStyle contained borderImageRepeat borderImageSlice borderImageSource
+ syntax keyword typescriptDOMStyle contained borderImageWidth borderLeft borderLeftColor
+ syntax keyword typescriptDOMStyle contained borderLeftStyle borderLeftWidth borderRadius
+ syntax keyword typescriptDOMStyle contained borderRight borderRightColor borderRightStyle
+ syntax keyword typescriptDOMStyle contained borderRightWidth borderSpacing borderStyle
+ syntax keyword typescriptDOMStyle contained borderTop borderTopColor borderTopLeftRadius
+ syntax keyword typescriptDOMStyle contained borderTopRightRadius borderTopStyle borderTopWidth
+ syntax keyword typescriptDOMStyle contained borderWidth bottom boxDecorationBreak
+ syntax keyword typescriptDOMStyle contained boxShadow boxSizing breakAfter breakBefore
+ syntax keyword typescriptDOMStyle contained breakInside captionSide caretColor caretShape
+ syntax keyword typescriptDOMStyle contained caret clear clip clipPath color columns
+ syntax keyword typescriptDOMStyle contained columnCount columnFill columnGap columnRule
+ syntax keyword typescriptDOMStyle contained columnRuleColor columnRuleStyle columnRuleWidth
+ syntax keyword typescriptDOMStyle contained columnSpan columnWidth content counterIncrement
+ syntax keyword typescriptDOMStyle contained counterReset cursor direction display
+ syntax keyword typescriptDOMStyle contained emptyCells flex flexBasis flexDirection
+ syntax keyword typescriptDOMStyle contained flexFlow flexGrow flexShrink flexWrap
+ syntax keyword typescriptDOMStyle contained float font fontFamily fontFeatureSettings
+ syntax keyword typescriptDOMStyle contained fontKerning fontLanguageOverride fontSize
+ syntax keyword typescriptDOMStyle contained fontSizeAdjust fontStretch fontStyle fontSynthesis
+ syntax keyword typescriptDOMStyle contained fontVariant fontVariantAlternates fontVariantCaps
+ syntax keyword typescriptDOMStyle contained fontVariantEastAsian fontVariantLigatures
+ syntax keyword typescriptDOMStyle contained fontVariantNumeric fontVariantPosition
+ syntax keyword typescriptDOMStyle contained fontWeight grad grid gridArea gridAutoColumns
+ syntax keyword typescriptDOMStyle contained gridAutoFlow gridAutoPosition gridAutoRows
+ syntax keyword typescriptDOMStyle contained gridColumn gridColumnStart gridColumnEnd
+ syntax keyword typescriptDOMStyle contained gridRow gridRowStart gridRowEnd gridTemplate
+ syntax keyword typescriptDOMStyle contained gridTemplateAreas gridTemplateRows gridTemplateColumns
+ syntax keyword typescriptDOMStyle contained height hyphens imageRendering imageResolution
+ syntax keyword typescriptDOMStyle contained imageOrientation imeMode inherit justifyContent
+ syntax keyword typescriptDOMStyle contained left letterSpacing lineBreak lineHeight
+ syntax keyword typescriptDOMStyle contained listStyle listStyleImage listStylePosition
+ syntax keyword typescriptDOMStyle contained listStyleType margin marginBottom marginLeft
+ syntax keyword typescriptDOMStyle contained marginRight marginTop marks mask maskType
+ syntax keyword typescriptDOMStyle contained maxHeight maxWidth minHeight minWidth
+ syntax keyword typescriptDOMStyle contained mixBlendMode objectFit objectPosition
+ syntax keyword typescriptDOMStyle contained opacity order orphans outline outlineColor
+ syntax keyword typescriptDOMStyle contained outlineOffset outlineStyle outlineWidth
+ syntax keyword typescriptDOMStyle contained overflow overflowWrap overflowX overflowY
+ syntax keyword typescriptDOMStyle contained overflowClipBox padding paddingBottom
+ syntax keyword typescriptDOMStyle contained paddingLeft paddingRight paddingTop pageBreakAfter
+ syntax keyword typescriptDOMStyle contained pageBreakBefore pageBreakInside perspective
+ syntax keyword typescriptDOMStyle contained perspectiveOrigin pointerEvents position
+ syntax keyword typescriptDOMStyle contained quotes resize right shapeImageThreshold
+ syntax keyword typescriptDOMStyle contained shapeMargin shapeOutside tableLayout tabSize
+ syntax keyword typescriptDOMStyle contained textAlign textAlignLast textCombineHorizontal
+ syntax keyword typescriptDOMStyle contained textDecoration textDecorationColor textDecorationLine
+ syntax keyword typescriptDOMStyle contained textDecorationStyle textIndent textOrientation
+ syntax keyword typescriptDOMStyle contained textOverflow textRendering textShadow
+ syntax keyword typescriptDOMStyle contained textTransform textUnderlinePosition top
+ syntax keyword typescriptDOMStyle contained touchAction transform transformOrigin
+ syntax keyword typescriptDOMStyle contained transformStyle transition transitionDelay
+ syntax keyword typescriptDOMStyle contained transitionDuration transitionProperty
+ syntax keyword typescriptDOMStyle contained transitionTimingFunction unicodeBidi unicodeRange
+ syntax keyword typescriptDOMStyle contained userSelect userZoom verticalAlign visibility
+ syntax keyword typescriptDOMStyle contained whiteSpace width willChange wordBreak
+ syntax keyword typescriptDOMStyle contained wordSpacing wordWrap writingMode zIndex
+ hi def link typescriptDOMStyle Keyword
+
+
+
+ let typescript_props = 1
+
+ "runtime syntax/yats/event.vim
+ syntax keyword typescriptAnimationEvent contained animationend animationiteration
+ syntax keyword typescriptAnimationEvent contained animationstart beginEvent endEvent
+ syntax keyword typescriptAnimationEvent contained repeatEvent
+ syntax cluster events add=typescriptAnimationEvent
+ hi def link typescriptAnimationEvent Title
+ syntax keyword typescriptCSSEvent contained CssRuleViewRefreshed CssRuleViewChanged
+ syntax keyword typescriptCSSEvent contained CssRuleViewCSSLinkClicked transitionend
+ syntax cluster events add=typescriptCSSEvent
+ hi def link typescriptCSSEvent Title
+ syntax keyword typescriptDatabaseEvent contained blocked complete error success upgradeneeded
+ syntax keyword typescriptDatabaseEvent contained versionchange
+ syntax cluster events add=typescriptDatabaseEvent
+ hi def link typescriptDatabaseEvent Title
+ syntax keyword typescriptDocumentEvent contained DOMLinkAdded DOMLinkRemoved DOMMetaAdded
+ syntax keyword typescriptDocumentEvent contained DOMMetaRemoved DOMWillOpenModalDialog
+ syntax keyword typescriptDocumentEvent contained DOMModalDialogClosed unload
+ syntax cluster events add=typescriptDocumentEvent
+ hi def link typescriptDocumentEvent Title
+ syntax keyword typescriptDOMMutationEvent contained DOMAttributeNameChanged DOMAttrModified
+ syntax keyword typescriptDOMMutationEvent contained DOMCharacterDataModified DOMContentLoaded
+ syntax keyword typescriptDOMMutationEvent contained DOMElementNameChanged DOMNodeInserted
+ syntax keyword typescriptDOMMutationEvent contained DOMNodeInsertedIntoDocument DOMNodeRemoved
+ syntax keyword typescriptDOMMutationEvent contained DOMNodeRemovedFromDocument DOMSubtreeModified
+ syntax cluster events add=typescriptDOMMutationEvent
+ hi def link typescriptDOMMutationEvent Title
+ syntax keyword typescriptDragEvent contained drag dragdrop dragend dragenter dragexit
+ syntax keyword typescriptDragEvent contained draggesture dragleave dragover dragstart
+ syntax keyword typescriptDragEvent contained drop
+ syntax cluster events add=typescriptDragEvent
+ hi def link typescriptDragEvent Title
+ syntax keyword typescriptElementEvent contained invalid overflow underflow DOMAutoComplete
+ syntax keyword typescriptElementEvent contained command commandupdate
+ syntax cluster events add=typescriptElementEvent
+ hi def link typescriptElementEvent Title
+ syntax keyword typescriptFocusEvent contained blur change DOMFocusIn DOMFocusOut focus
+ syntax keyword typescriptFocusEvent contained focusin focusout
+ syntax cluster events add=typescriptFocusEvent
+ hi def link typescriptFocusEvent Title
+ syntax keyword typescriptFormEvent contained reset submit
+ syntax cluster events add=typescriptFormEvent
+ hi def link typescriptFormEvent Title
+ syntax keyword typescriptFrameEvent contained DOMFrameContentLoaded
+ syntax cluster events add=typescriptFrameEvent
+ hi def link typescriptFrameEvent Title
+ syntax keyword typescriptInputDeviceEvent contained click contextmenu DOMMouseScroll
+ syntax keyword typescriptInputDeviceEvent contained dblclick gamepadconnected gamepaddisconnected
+ syntax keyword typescriptInputDeviceEvent contained keydown keypress keyup MozGamepadButtonDown
+ syntax keyword typescriptInputDeviceEvent contained MozGamepadButtonUp mousedown mouseenter
+ syntax keyword typescriptInputDeviceEvent contained mouseleave mousemove mouseout
+ syntax keyword typescriptInputDeviceEvent contained mouseover mouseup mousewheel MozMousePixelScroll
+ syntax keyword typescriptInputDeviceEvent contained pointerlockchange pointerlockerror
+ syntax keyword typescriptInputDeviceEvent contained wheel
+ syntax cluster events add=typescriptInputDeviceEvent
+ hi def link typescriptInputDeviceEvent Title
+ syntax keyword typescriptMediaEvent contained audioprocess canplay canplaythrough
+ syntax keyword typescriptMediaEvent contained durationchange emptied ended ended loadeddata
+ syntax keyword typescriptMediaEvent contained loadedmetadata MozAudioAvailable pause
+ syntax keyword typescriptMediaEvent contained play playing ratechange seeked seeking
+ syntax keyword typescriptMediaEvent contained stalled suspend timeupdate volumechange
+ syntax keyword typescriptMediaEvent contained waiting complete
+ syntax cluster events add=typescriptMediaEvent
+ hi def link typescriptMediaEvent Title
+ syntax keyword typescriptMenuEvent contained DOMMenuItemActive DOMMenuItemInactive
+ syntax cluster events add=typescriptMenuEvent
+ hi def link typescriptMenuEvent Title
+ syntax keyword typescriptNetworkEvent contained datachange dataerror disabled enabled
+ syntax keyword typescriptNetworkEvent contained offline online statuschange connectionInfoUpdate
+ syntax cluster events add=typescriptNetworkEvent
+ hi def link typescriptNetworkEvent Title
+ syntax keyword typescriptProgressEvent contained abort error load loadend loadstart
+ syntax keyword typescriptProgressEvent contained progress timeout uploadprogress
+ syntax cluster events add=typescriptProgressEvent
+ hi def link typescriptProgressEvent Title
+ syntax keyword typescriptResourceEvent contained cached error load
+ syntax cluster events add=typescriptResourceEvent
+ hi def link typescriptResourceEvent Title
+ syntax keyword typescriptScriptEvent contained afterscriptexecute beforescriptexecute
+ syntax cluster events add=typescriptScriptEvent
+ hi def link typescriptScriptEvent Title
+ syntax keyword typescriptSensorEvent contained compassneedscalibration devicelight
+ syntax keyword typescriptSensorEvent contained devicemotion deviceorientation deviceproximity
+ syntax keyword typescriptSensorEvent contained orientationchange userproximity
+ syntax cluster events add=typescriptSensorEvent
+ hi def link typescriptSensorEvent Title
+ syntax keyword typescriptSessionHistoryEvent contained pagehide pageshow popstate
+ syntax cluster events add=typescriptSessionHistoryEvent
+ hi def link typescriptSessionHistoryEvent Title
+ syntax keyword typescriptStorageEvent contained change storage
+ syntax cluster events add=typescriptStorageEvent
+ hi def link typescriptStorageEvent Title
+ syntax keyword typescriptSVGEvent contained SVGAbort SVGError SVGLoad SVGResize SVGScroll
+ syntax keyword typescriptSVGEvent contained SVGUnload SVGZoom
+ syntax cluster events add=typescriptSVGEvent
+ hi def link typescriptSVGEvent Title
+ syntax keyword typescriptTabEvent contained visibilitychange
+ syntax cluster events add=typescriptTabEvent
+ hi def link typescriptTabEvent Title
+ syntax keyword typescriptTextEvent contained compositionend compositionstart compositionupdate
+ syntax keyword typescriptTextEvent contained copy cut paste select text
+ syntax cluster events add=typescriptTextEvent
+ hi def link typescriptTextEvent Title
+ syntax keyword typescriptTouchEvent contained touchcancel touchend touchenter touchleave
+ syntax keyword typescriptTouchEvent contained touchmove touchstart
+ syntax cluster events add=typescriptTouchEvent
+ hi def link typescriptTouchEvent Title
+ syntax keyword typescriptUpdateEvent contained checking downloading error noupdate
+ syntax keyword typescriptUpdateEvent contained obsolete updateready
+ syntax cluster events add=typescriptUpdateEvent
+ hi def link typescriptUpdateEvent Title
+ syntax keyword typescriptValueChangeEvent contained hashchange input readystatechange
+ syntax cluster events add=typescriptValueChangeEvent
+ hi def link typescriptValueChangeEvent Title
+ syntax keyword typescriptViewEvent contained fullscreen fullscreenchange fullscreenerror
+ syntax keyword typescriptViewEvent contained resize scroll
+ syntax cluster events add=typescriptViewEvent
+ hi def link typescriptViewEvent Title
+ syntax keyword typescriptWebsocketEvent contained close error message open
+ syntax cluster events add=typescriptWebsocketEvent
+ hi def link typescriptWebsocketEvent Title
+ syntax keyword typescriptWindowEvent contained DOMWindowCreated DOMWindowClose DOMTitleChanged
+ syntax cluster events add=typescriptWindowEvent
+ hi def link typescriptWindowEvent Title
+ syntax keyword typescriptUncategorizedEvent contained beforeunload message open show
+ syntax cluster events add=typescriptUncategorizedEvent
+ hi def link typescriptUncategorizedEvent Title
+ syntax keyword typescriptServiceWorkerEvent contained install activate fetch
+ syntax cluster events add=typescriptServiceWorkerEvent
+ hi def link typescriptServiceWorkerEvent Title
+
+
+endif
+
+" patch
+"runtime syntax/basic/patch.vim
+" patch for generated code
+syntax keyword typescriptGlobal Promise
+ \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
+syntax keyword typescriptGlobal Map WeakMap
+ \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
+
+"runtime syntax/basic/members.vim
+syntax keyword typescriptConstructor contained constructor
+ \ nextgroup=@typescriptCallSignature
+ \ skipwhite skipempty
+
+
+syntax cluster memberNextGroup contains=typescriptMemberOptionality,typescriptTypeAnnotation,@typescriptCallSignature
+
+syntax match typescriptMember /\K\k*/
+ \ nextgroup=@memberNextGroup
+ \ contained skipwhite
+
+syntax match typescriptMethodAccessor contained /\v(get|set)\s\K/me=e-1
+ \ nextgroup=@typescriptMembers
+
+syntax cluster typescriptPropertyMemberDeclaration contains=
+ \ typescriptClassStatic,
+ \ typescriptAccessibilityModifier,
+ \ typescriptReadonlyModifier,
+ \ typescriptMethodAccessor,
+ \ @typescriptMembers
+ " \ typescriptMemberVariableDeclaration
+
+syntax match typescriptMemberOptionality /?\|!/ contained
+ \ nextgroup=typescriptTypeAnnotation,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax cluster typescriptMembers contains=typescriptMember,typescriptStringMember,typescriptComputedMember
+
+syntax keyword typescriptClassStatic static
+ \ nextgroup=@typescriptMembers,typescriptAsyncFuncKeyword,typescriptReadonlyModifier
+ \ skipwhite contained
+
+syntax keyword typescriptAccessibilityModifier public private protected contained
+
+syntax keyword typescriptReadonlyModifier readonly contained
+
+syntax region typescriptStringMember contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
+ \ nextgroup=@memberNextGroup
+ \ skipwhite skipempty
+
+syntax region typescriptComputedMember contained matchgroup=typescriptProperty
+ \ start=/\[/rs=s+1 end=/]/
+ \ contains=@typescriptValue,typescriptMember,typescriptMappedIn
+ \ nextgroup=@memberNextGroup
+ \ skipwhite skipempty
+
+"runtime syntax/basic/class.vim
+"don't add typescriptMembers to nextgroup, let outer scope match it
+" so we won't match abstract method outside abstract class
+syntax keyword typescriptAbstract abstract
+ \ nextgroup=typescriptClassKeyword
+ \ skipwhite skipnl
+syntax keyword typescriptClassKeyword class
+ \ nextgroup=typescriptClassName,typescriptClassExtends,typescriptClassBlock
+ \ skipwhite
+
+syntax match typescriptClassName contained /\K\k*/
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptClassTypeParameter
+ \ skipwhite skipnl
+
+syntax region typescriptClassTypeParameter
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptClassExtends contained extends implements nextgroup=typescriptClassHeritage skipwhite skipnl
+
+syntax match typescriptClassHeritage contained /\v(\k|\.|\(|\))+/
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptMixinComma,typescriptClassTypeArguments
+ \ contains=@typescriptValue
+ \ skipwhite skipnl
+ \ contained
+
+syntax region typescriptClassTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptClassExtends,typescriptClassBlock,typescriptMixinComma
+ \ contained skipwhite skipnl
+
+syntax match typescriptMixinComma /,/ contained nextgroup=typescriptClassHeritage skipwhite skipnl
+
+" we need add arrowFunc to class block for high order arrow func
+" see test case
+syntax region typescriptClassBlock matchgroup=typescriptBraces start=/{/ end=/}/
+ \ contains=@typescriptPropertyMemberDeclaration,typescriptAbstract,@typescriptComments,typescriptBlock,typescriptAssign,typescriptDecorator,typescriptAsyncFuncKeyword,typescriptArrowFunc
+ \ contained fold
+
+syntax keyword typescriptInterfaceKeyword interface nextgroup=typescriptInterfaceName skipwhite
+syntax match typescriptInterfaceName contained /\k\+/
+ \ nextgroup=typescriptObjectType,typescriptInterfaceExtends,typescriptInterfaceTypeParameter
+ \ skipwhite skipnl
+syntax region typescriptInterfaceTypeParameter
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptObjectType,typescriptInterfaceExtends
+ \ contained
+ \ skipwhite skipnl
+
+syntax keyword typescriptInterfaceExtends contained extends nextgroup=typescriptInterfaceHeritage skipwhite skipnl
+
+syntax match typescriptInterfaceHeritage contained /\v(\k|\.)+/
+ \ nextgroup=typescriptObjectType,typescriptInterfaceComma,typescriptInterfaceTypeArguments
+ \ skipwhite
+
+syntax region typescriptInterfaceTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/ skip=/\s*,\s*/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptObjectType,typescriptInterfaceComma
+ \ contained skipwhite
+
+syntax match typescriptInterfaceComma /,/ contained nextgroup=typescriptInterfaceHeritage skipwhite skipnl
+
+"runtime syntax/basic/cluster.vim
+"Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement DebuggerStatement
+syntax cluster typescriptStatement
+ \ contains=typescriptBlock,typescriptVariable,
+ \ @typescriptTopExpression,typescriptAssign,
+ \ typescriptConditional,typescriptRepeat,typescriptBranch,
+ \ typescriptLabel,typescriptStatementKeyword,
+ \ typescriptFuncKeyword,
+ \ typescriptTry,typescriptExceptions,typescriptDebugger,
+ \ typescriptExport,typescriptInterfaceKeyword,typescriptEnum,
+ \ typescriptModule,typescriptAliasKeyword,typescriptImport
+
+syntax cluster typescriptPrimitive contains=typescriptString,typescriptTemplate,typescriptRegexpString,typescriptNumber,typescriptBoolean,typescriptNull,typescriptArray
+
+syntax cluster typescriptEventTypes contains=typescriptEventString,typescriptTemplate,typescriptNumber,typescriptBoolean,typescriptNull
+
+" top level expression: no arrow func
+" also no func keyword. funcKeyword is contained in statement
+" funcKeyword allows overloading (func without body)
+" funcImpl requires body
+syntax cluster typescriptTopExpression
+ \ contains=@typescriptPrimitive,
+ \ typescriptIdentifier,typescriptIdentifierName,
+ \ typescriptOperator,typescriptUnaryOp,
+ \ typescriptParenExp,typescriptRegexpString,
+ \ typescriptGlobal,typescriptAsyncFuncKeyword,
+ \ typescriptClassKeyword,typescriptTypeCast
+
+" no object literal, used in type cast and arrow func
+" TODO: change func keyword to funcImpl
+syntax cluster typescriptExpression
+ \ contains=@typescriptTopExpression,
+ \ typescriptArrowFuncDef,
+ \ typescriptFuncImpl
+
+syntax cluster typescriptValue
+ \ contains=@typescriptExpression,typescriptObjectLiteral
+
+syntax cluster typescriptEventExpression contains=typescriptArrowFuncDef,typescriptParenExp,@typescriptValue,typescriptRegexpString,@typescriptEventTypes,typescriptOperator,typescriptGlobal,jsxRegion
+
+"runtime syntax/basic/function.vim
+syntax keyword typescriptAsyncFuncKeyword async
+ \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef
+ \ skipwhite
+
+syntax keyword typescriptAsyncFuncKeyword await
+ \ nextgroup=@typescriptValue
+ \ skipwhite
+
+syntax keyword typescriptFuncKeyword function
+ \ nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax match typescriptAsyncFunc contained /*/
+ \ nextgroup=typescriptFuncName,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax match typescriptFuncName contained /\K\k*/
+ \ nextgroup=@typescriptCallSignature
+ \ skipwhite
+
+" destructuring ({ a: ee }) =>
+syntax match typescriptArrowFuncDef contained /({\_[^}]*}\(:\_[^)]\)\?)\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+" matches `(a) =>` or `([a]) =>` or
+" `(
+" a) =>`
+syntax match typescriptArrowFuncDef contained /(\(\_s*[a-zA-Z\$_\[.]\_[^)]*\)*)\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+" TODO: optimize this pattern
+syntax region typescriptArrowFuncDef contained start=/(\_[^)]*):/ end=/=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc,typescriptTypeAnnotation
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty keepend
+
+syntax match typescriptArrowFunc /=>/
+syntax match typescriptArrowFuncArg contained /\K\k*/
+syntax region typescriptArrowFuncArg contained start=/<\|(/ end=/\ze=>/ contains=@typescriptCallSignature
+
+syntax region typescriptReturnAnnotation contained start=/:/ end=/{/me=e-1 contains=@typescriptType nextgroup=typescriptBlock
+
+
+syntax region typescriptFuncImpl contained start=/function/ end=/{/me=e-1
+ \ contains=typescriptFuncKeyword
+ \ nextgroup=typescriptBlock
+
+syntax cluster typescriptCallImpl contains=typescriptGenericImpl,typescriptParamImpl
+syntax region typescriptGenericImpl matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/ skip=/\s*,\s*/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptParamImpl
+ \ contained skipwhite
+syntax region typescriptParamImpl matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
+ \ nextgroup=typescriptReturnAnnotation,typescriptBlock
+ \ contained skipwhite skipnl
+
+"runtime syntax/basic/decorator.vim
+syntax match typescriptDecorator /@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a-zA-Z0-9]*\>/
+ \ nextgroup=typescriptArgumentList,typescriptTypeArguments
+ \ contains=@_semantic,typescriptDotNotation
+
+" Define the default highlighting.
+hi def link typescriptReserved Error
+
+hi def link typescriptEndColons Exception
+hi def link typescriptSymbols Normal
+hi def link typescriptBraces Function
+hi def link typescriptParens Normal
+hi def link typescriptComment Comment
+hi def link typescriptLineComment Comment
+hi def link typescriptDocComment Comment
+hi def link typescriptCommentTodo Todo
+hi def link typescriptRef Include
+hi def link typescriptDocNotation SpecialComment
+hi def link typescriptDocTags SpecialComment
+hi def link typescriptDocNGParam typescriptDocParam
+hi def link typescriptDocParam Function
+hi def link typescriptDocNumParam Function
+hi def link typescriptDocEventRef Function
+hi def link typescriptDocNamedParamType Type
+hi def link typescriptDocParamName Type
+hi def link typescriptDocParamType Type
+hi def link typescriptString String
+hi def link typescriptSpecial Special
+hi def link typescriptStringLiteralType String
+hi def link typescriptStringMember String
+hi def link typescriptTemplate String
+hi def link typescriptEventString String
+hi def link typescriptASCII Special
+hi def link typescriptTemplateSB Label
+hi def link typescriptRegexpString String
+hi def link typescriptGlobal Constant
+hi def link typescriptTestGlobal Function
+hi def link typescriptPrototype Type
+hi def link typescriptConditional Conditional
+hi def link typescriptConditionalElse Conditional
+hi def link typescriptCase Conditional
+hi def link typescriptDefault typescriptCase
+hi def link typescriptBranch Conditional
+hi def link typescriptIdentifier Structure
+hi def link typescriptVariable Identifier
+hi def link typescriptEnumKeyword Identifier
+hi def link typescriptRepeat Repeat
+hi def link typescriptForOperator Repeat
+hi def link typescriptStatementKeyword Statement
+hi def link typescriptMessage Keyword
+hi def link typescriptOperator Identifier
+hi def link typescriptKeywordOp Identifier
+hi def link typescriptCastKeyword Special
+hi def link typescriptType Type
+hi def link typescriptNull Boolean
+hi def link typescriptNumber Number
+hi def link typescriptExponent Number
+hi def link typescriptBoolean Boolean
+hi def link typescriptObjectLabel typescriptLabel
+hi def link typescriptLabel Label
+hi def link typescriptStringProperty String
+hi def link typescriptImport Special
+hi def link typescriptAmbientDeclaration Special
+hi def link typescriptExport Special
+hi def link typescriptModule Special
+hi def link typescriptTry Special
+hi def link typescriptExceptions Special
+
+hi def link typescriptMember Function
+hi def link typescriptMethodAccessor Operator
+
+hi def link typescriptAsyncFuncKeyword Keyword
+hi def link typescriptAsyncFor Keyword
+hi def link typescriptFuncKeyword Keyword
+hi def link typescriptAsyncFunc Keyword
+hi def link typescriptArrowFunc Type
+hi def link typescriptFuncName Function
+hi def link typescriptFuncArg PreProc
+hi def link typescriptArrowFuncArg PreProc
+hi def link typescriptFuncComma Operator
+
+hi def link typescriptClassKeyword Keyword
+hi def link typescriptClassExtends Keyword
+" hi def link typescriptClassName Function
+hi def link typescriptAbstract Special
+" hi def link typescriptClassHeritage Function
+" hi def link typescriptInterfaceHeritage Function
+hi def link typescriptClassStatic StorageClass
+hi def link typescriptReadonlyModifier Keyword
+hi def link typescriptInterfaceKeyword Keyword
+hi def link typescriptInterfaceExtends Keyword
+hi def link typescriptInterfaceName Function
+
+hi def link shellbang Comment
+
+hi def link typescriptTypeParameter Identifier
+hi def link typescriptConstraint Keyword
+hi def link typescriptPredefinedType Type
+hi def link typescriptReadonlyArrayKeyword Keyword
+hi def link typescriptUnion Operator
+hi def link typescriptFuncTypeArrow Function
+hi def link typescriptConstructorType Function
+hi def link typescriptTypeQuery Keyword
+hi def link typescriptAccessibilityModifier Keyword
+hi def link typescriptOptionalMark PreProc
+hi def link typescriptFuncType Special
+hi def link typescriptMappedIn Special
+hi def link typescriptCall PreProc
+hi def link typescriptParamImpl PreProc
+hi def link typescriptConstructSignature Identifier
+hi def link typescriptAliasDeclaration Identifier
+hi def link typescriptAliasKeyword Keyword
+hi def link typescriptUserDefinedType Keyword
+hi def link typescriptTypeReference Identifier
+hi def link typescriptConstructor Keyword
+hi def link typescriptDecorator Special
+hi def link typescriptAssertType Keyword
+
+hi link typeScript NONE
+
+if exists('s:cpo_save')
+ let &cpo = s:cpo_save
+ unlet s:cpo_save
+endif
diff --git a/runtime/syntax/typescriptreact.vim b/runtime/syntax/typescriptreact.vim
new file mode 100644
index 0000000000..f29fe785b9
--- /dev/null
+++ b/runtime/syntax/typescriptreact.vim
@@ -0,0 +1,160 @@
+" Vim syntax file
+" Language: TypeScript with React (JSX)
+" Maintainer: Bram Moolenaar
+" Last Change: 2019 Nov 30
+" Based On: Herrington Darkholme's yats.vim
+" Changes: See https:github.com/HerringtonDarkholme/yats.vim
+" Credits: See yats.vim on github
+
+if !exists("main_syntax")
+ if exists("b:current_syntax")
+ finish
+ endif
+ let main_syntax = 'typescriptreact'
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+syntax region tsxTag
+ \ start=+<\([^/!?<>="':]\+\)\@=+
+ \ skip=+</[^ /!?<>"']\+>+
+ \ end=+/\@<!>+
+ \ end=+\(/>\)\@=+
+ \ contained
+ \ contains=tsxTagName,tsxIntrinsicTagName,tsxAttrib,tsxEscJs,
+ \tsxCloseString,@tsxComment
+
+syntax match tsxTag /<>/ contained
+
+
+" <tag></tag>
+" s~~~~~~~~~e
+" and self close tag
+" <tag/>
+" s~~~~e
+" A big start regexp borrowed from https://git.io/vDyxc
+syntax region tsxRegion
+ \ start=+<\_s*\z([a-zA-Z1-9\$_-]\+\(\.\k\+\)*\)+
+ \ skip=+<!--\_.\{-}-->+
+ \ end=+</\_s*\z1>+
+ \ matchgroup=tsxCloseString end=+/>+
+ \ fold
+ \ contains=tsxRegion,tsxCloseString,tsxCloseTag,tsxTag,tsxCommentInvalid,tsxFragment,tsxEscJs,@Spell
+ \ keepend
+ \ extend
+
+" <> </>
+" s~~~~~~e
+" A big start regexp borrowed from https://git.io/vDyxc
+syntax region tsxFragment
+ \ start=+\(\((\|{\|}\|\[\|,\|&&\|||\|?\|:\|=\|=>\|\Wreturn\|^return\|\Wdefault\|^\|>\)\_s*\)\@<=<>+
+ \ skip=+<!--\_.\{-}-->+
+ \ end=+</>+
+ \ fold
+ \ contains=tsxRegion,tsxCloseString,tsxCloseTag,tsxTag,tsxCommentInvalid,tsxFragment,tsxEscJs,@Spell
+ \ keepend
+ \ extend
+
+" </tag>
+" ~~~~~~
+syntax match tsxCloseTag
+ \ +</\_s*[^/!?<>"']\+>+
+ \ contained
+ \ contains=tsxTagName,tsxIntrinsicTagName
+
+syntax match tsxCloseTag +</>+ contained
+
+syntax match tsxCloseString
+ \ +/>+
+ \ contained
+
+" <!-- -->
+" ~~~~~~~~
+syntax match tsxCommentInvalid /<!--\_.\{-}-->/ display
+
+syntax region tsxBlockComment
+ \ contained
+ \ start="/\*"
+ \ end="\*/"
+
+syntax match tsxLineComment
+ \ "//.*$"
+ \ contained
+ \ display
+
+syntax cluster tsxComment contains=tsxBlockComment,tsxLineComment
+
+syntax match tsxEntity "&[^; \t]*;" contains=tsxEntityPunct
+syntax match tsxEntityPunct contained "[&.;]"
+
+" <tag key={this.props.key}>
+" ~~~
+syntax match tsxTagName
+ \ +[</]\_s*[^/!?<>"'* ]\++hs=s+1
+ \ contained
+ \ nextgroup=tsxAttrib
+ \ skipwhite
+ \ display
+syntax match tsxIntrinsicTagName
+ \ +[</]\_s*[a-z1-9-]\++hs=s+1
+ \ contained
+ \ nextgroup=tsxAttrib
+ \ skipwhite
+ \ display
+
+" <tag key={this.props.key}>
+" ~~~
+syntax match tsxAttrib
+ \ +[a-zA-Z_][-0-9a-zA-Z_]*+
+ \ nextgroup=tsxEqual skipwhite
+ \ contained
+ \ display
+
+" <tag id="sample">
+" ~
+syntax match tsxEqual +=+ display contained
+ \ nextgroup=tsxString skipwhite
+
+" <tag id="sample">
+" s~~~~~~e
+syntax region tsxString contained start=+"+ end=+"+ contains=tsxEntity,@Spell display
+
+" <tag key={this.props.key}>
+" s~~~~~~~~~~~~~~e
+syntax region tsxEscJs
+ \ contained
+ \ contains=@typescriptValue,@tsxComment
+ \ matchgroup=typescriptBraces
+ \ start=+{+
+ \ end=+}+
+ \ extend
+
+
+"""""""""""""""""""""""""""""""""""""""""""""""""""
+" Source the part common with typescriptreact.vim
+source <sfile>:h/typescriptcommon.vim
+
+
+syntax cluster typescriptExpression add=tsxRegion,tsxFragment
+
+hi def link tsxTag htmlTag
+hi def link tsxTagName Function
+hi def link tsxIntrinsicTagName htmlTagName
+hi def link tsxString String
+hi def link tsxNameSpace Function
+hi def link tsxCommentInvalid Error
+hi def link tsxBlockComment Comment
+hi def link tsxLineComment Comment
+hi def link tsxAttrib Type
+hi def link tsxEscJs tsxEscapeJs
+hi def link tsxCloseTag htmlTag
+hi def link tsxCloseString Identifier
+
+let b:current_syntax = "typescriptreact"
+if main_syntax == 'typescriptreact'
+ unlet main_syntax
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/tools/check_colors.vim b/runtime/tools/check_colors.vim
index 57b71b19db..e4acbc33ec 100644
--- a/runtime/tools/check_colors.vim
+++ b/runtime/tools/check_colors.vim
@@ -1,6 +1,6 @@
" 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 colors/tools/check_colors.vim
+" :edit colors/desert.vim | :so tools/check_colors.vim
let s:save_cpo= &cpo
set cpo&vim
@@ -8,7 +8,7 @@ set cpo&vim
func! Test_check_colors()
let l:savedview = winsaveview()
call cursor(1,1)
- let err={}
+ let err = {}
" 1) Check g:colors_name is existing
if !search('\<\%(g:\)\?colors_name\>', 'cnW')
@@ -81,36 +81,39 @@ func! Test_check_colors()
\ 'WarningMsg',
\ 'WildMenu',
\ ]
- let groups={}
+ let groups = {}
for group in hi_groups
- if search('\c@suppress\s\+'.group, 'cnW')
+ if search('\c@suppress\s\+\<' .. group .. '\>', 'cnW')
" skip check, if the script contains a line like
" @suppress Visual:
- let groups[group] = 'Ignoring '.group
continue
endif
- if search('hi\%[ghlight]!\= \+link \+'.group, 'cnW') " Linked group
+ 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
+ if !search('hi\%[ghlight] \+\<' .. group .. '\>', 'cnW')
+ let groups[group] = 'No highlight definition for ' .. group
continue
endif
- if !search('hi\%[ghlight] \+'.group. '.*fg=', 'cnW')
- let groups[group] = 'Missing foreground color for '.group
+ 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')
- let groups[group] = 'Missing bg terminal color for '.group
+ 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')
- let groups[group] = 'Missing guifg definition for '.group
+ 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')
- let groups[group] = 'Missing ctermfg definition for '.group
+ 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
@@ -120,10 +123,10 @@ func! Test_check_colors()
" 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')
+ 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')
@@ -145,7 +148,7 @@ func! Test_check_colors()
" 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'
+ 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
@@ -160,7 +163,7 @@ func! Test_check_colors()
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`
+ let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\w\+\>\ze \+.' " Skips `hi clear`
if search(pat, 'cW')
call add(ft_groups, matchstr(getline('.'), pat))
endif
@@ -172,7 +175,7 @@ func! Test_check_colors()
" 8) Were debugPC and debugBreakpoint defined?
for group in ['debugPC', 'debugBreakpoint']
- let pat='\Chi\%[ghlight]!\= *\%[link] \+\zs'.group.'\>'
+ 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). ' '
diff --git a/scripts/download-unicode-files.sh b/scripts/download-unicode-files.sh
index 5f38d0589a..12474d3c1e 100755
--- a/scripts/download-unicode-files.sh
+++ b/scripts/download-unicode-files.sh
@@ -30,7 +30,7 @@ for filename in $data_files ; do
done
for filename in $emoji_files ; do
- curl -L -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/emoji/latest/$filename"
+ curl -L -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/UNIDATA/emoji/$filename"
(
cd "$UNIDIR"
git add $filename
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index a61690e99f..c42b568220 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -39,6 +39,7 @@ Each function :help block is formatted as follows:
parameter is marked as [out].
- Each function documentation is separated by a single line.
"""
+import argparse
import os
import re
import sys
@@ -57,7 +58,6 @@ if sys.version_info < MIN_PYTHON_VERSION:
sys.exit(1)
DEBUG = ('DEBUG' in os.environ)
-TARGET = os.environ.get('TARGET', None)
INCLUDE_C_DECL = ('INCLUDE_C_DECL' in os.environ)
INCLUDE_DEPRECATED = ('INCLUDE_DEPRECATED' in os.environ)
@@ -68,6 +68,7 @@ base_dir = os.path.dirname(os.path.dirname(script_path))
out_dir = os.path.join(base_dir, 'tmp-{target}-doc')
filter_cmd = '%s %s' % (sys.executable, script_path)
seen_funcs = set()
+msgs = [] # Messages to show on exit.
lua2dox_filter = os.path.join(base_dir, 'scripts', 'lua2dox_filter')
CONFIG = {
@@ -112,10 +113,12 @@ CONFIG = {
'section_order': [
'vim.lua',
'shared.lua',
+ 'uri.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
]),
'file_patterns': '*.lua',
'fn_name_prefix': '',
@@ -128,6 +131,7 @@ CONFIG = {
'module_override': {
# `shared` functions are exposed on the `vim` module.
'shared': 'vim',
+ 'uri': 'vim',
},
'append_only': [
'shared.lua',
@@ -191,7 +195,7 @@ xrefs = set()
# Raises an error with details about `o`, if `cond` is in object `o`,
# or if `cond()` is callable and returns True.
-def debug_this(cond, o):
+def debug_this(o, cond=True):
name = ''
if not isinstance(o, str):
try:
@@ -205,6 +209,23 @@ def debug_this(cond, o):
raise RuntimeError('xxx: {}\n{}'.format(name, o))
+# Appends a message to a list which will be printed on exit.
+def msg(s):
+ msgs.append(s)
+
+
+# Print all collected messages.
+def msg_report():
+ for m in msgs:
+ print(f' {m}')
+
+
+# Print collected messages, then throw an exception.
+def fail(s):
+ msg_report()
+ raise RuntimeError(s)
+
+
def find_first(parent, name):
"""Finds the first matching node within parent."""
sub = parent.getElementsByTagName(name)
@@ -841,7 +862,7 @@ def delete_lines_below(filename, tokenstr):
fp.writelines(lines[0:i])
-def main(config):
+def main(config, args):
"""Generates:
1. Vim :help docs
@@ -850,7 +871,7 @@ def main(config):
Doxygen is called and configured through stdin.
"""
for target in CONFIG:
- if TARGET is not None and target != TARGET:
+ if args.target is not None and target != args.target:
continue
mpack_file = os.path.join(
base_dir, 'runtime', 'doc',
@@ -915,9 +936,10 @@ def main(config):
filename = get_text(find_first(compound, 'name'))
if filename.endswith('.c') or filename.endswith('.lua'):
+ xmlfile = os.path.join(base,
+ '{}.xml'.format(compound.getAttribute('refid')))
# Extract unformatted (*.mpack).
- fn_map, _ = extract_from_xml(os.path.join(base, '{}.xml'.format(
- compound.getAttribute('refid'))), target, width=9999)
+ fn_map, _ = extract_from_xml(xmlfile, target, width=9999)
# Extract formatted (:help).
functions_text, deprecated_text = fmt_doxygen_xml_as_vimhelp(
os.path.join(base, '{}.xml'.format(
@@ -950,7 +972,8 @@ def main(config):
sections[filename] = (title, helptag, doc)
fn_map_full.update(fn_map)
- assert sections
+ if len(sections) == 0:
+ fail(f'no sections for target: {target}')
if len(sections) > len(CONFIG[target]['section_order']):
raise RuntimeError(
'found new modules "{}"; update the "section_order" map'.format(
@@ -960,7 +983,11 @@ def main(config):
i = 0
for filename in CONFIG[target]['section_order']:
- title, helptag, section_doc = sections.pop(filename)
+ try:
+ title, helptag, section_doc = sections.pop(filename)
+ except KeyError:
+ msg(f'warning: empty docs, skipping (target={target}): {filename}')
+ continue
i += 1
if filename not in CONFIG[target]['append_only']:
docs += sep
@@ -983,7 +1010,10 @@ def main(config):
with open(mpack_file, 'wb') as fp:
fp.write(msgpack.packb(fn_map_full, use_bin_type=True))
- shutil.rmtree(output_dir)
+ if not args.keep_tmpfiles:
+ shutil.rmtree(output_dir)
+
+ msg_report()
def filter_source(filename):
@@ -1001,6 +1031,18 @@ def filter_source(filename):
fp.read(), flags=re.M))
+def parse_args():
+ targets = ', '.join(CONFIG.keys())
+ ap = argparse.ArgumentParser()
+ ap.add_argument('source_filter', nargs='*',
+ help="Filter source file(s)")
+ ap.add_argument('-k', '--keep-tmpfiles', action='store_true',
+ help="Keep temporary files")
+ ap.add_argument('-t', '--target',
+ help=f'One of ({targets}), defaults to "all"')
+ return ap.parse_args()
+
+
Doxyfile = textwrap.dedent('''
OUTPUT_DIRECTORY = {output}
INPUT = {input}
@@ -1037,9 +1079,10 @@ Doxyfile = textwrap.dedent('''
''')
if __name__ == "__main__":
- if len(sys.argv) > 1:
- filter_source(sys.argv[1])
+ args = parse_args()
+ if len(args.source_filter) > 0:
+ filter_source(args.source_filter[0])
else:
- main(Doxyfile)
+ main(Doxyfile, args)
# vim: set ft=python ts=4 sw=4 tw=79 et :
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 9c4349abca..8287958ab5 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -346,7 +346,8 @@ submit_pr() {
local patches
# Extract just the "vim-patch:X.Y.ZZZZ" or "vim-patch:sha" portion of each log
patches=("$(git log --grep=vim-patch --reverse --format='%s' "${git_remote}"/master..HEAD | sed 's/: .*//')")
- patches=("${patches[@]//vim-patch:}") # Remove 'vim-patch:' prefix for each item in array.
+ # shellcheck disable=SC2206
+ patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
local pr_title="${patches[*]}" # Create space-separated string from array.
pr_title="${pr_title// /,}" # Replace spaces with commas.
@@ -596,8 +597,11 @@ list_missing_previous_vimpatches_for_patch() {
set -u
local -a missing_unique
+ local stat
while IFS= read -r line; do
- missing_unique+=("$line")
+ local commit="${line%%:*}"
+ stat="$(git -C "${VIM_SOURCE_DIR}" show --format= --shortstat "${commit}")"
+ missing_unique+=("$(printf '%s\n %s' "$line" "$stat")")
done < <(printf '%s\n' "${missing_list[@]}" | sort -u)
msg_err "$(printf '%d missing previous Vim patches:' ${#missing_unique[@]})"
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index da3e74d3e7..57bcb72d5d 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -25,22 +25,47 @@ apps:
parts:
nvim:
- source: .
+ source: https://github.com/neovim/neovim.git
override-pull: |
snapcraftctl pull
+ latest_tag="$(git tag -l --sort=refname|head -1)"
+ git checkout "${latest_tag}"
major="$(awk '/NVIM_VERSION_MAJOR/{gsub(")","",$2); print $2}' CMakeLists.txt)"
minor="$(awk '/NVIM_VERSION_MINOR/{gsub(")","",$2); print $2}' CMakeLists.txt)"
patch="$(awk '/NVIM_VERSION_PATCH/{gsub(")","",$2); print $2}' CMakeLists.txt)"
version_prefix="v$major.$minor.$patch"
git_described="$(git describe --first-parent --dirty 2> /dev/null | perl -lpe 's/v\d.\d.\d-//g')"
git_described="${git_described:-$(git describe --first-parent --tags --always --dirty)}"
- snapcraftctl set-version "${version_prefix}-${git_described}"
+ if [ "${version_prefix}" != "${git_described}" ]; then
+ VERSION="${version_prefix}-${git_described}-${latest_tag}"
+ else
+ VERSION="${version_prefix}-${latest_tag}"
+ fi
+ snapcraftctl set-version "${VERSION}"
plugin: make
make-parameters:
- - CMAKE_BUILD_TYPE=Release
+ - CMAKE_BUILD_TYPE=RelWithDebInfo
- CMAKE_INSTALL_PREFIX=/usr
+ - CMAKE_FLAGS=-DPREFER_LUA=ON
+ - DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_LUA=ON -DUSE_BUNDLED_LUAJIT=OFF"
override-build: |
- snapcraftctl build
+ echo "Building on $SNAP_ARCH"
+ set -x
+ case "$SNAP_ARCH" in
+ "arm64" | "ppc64el" | "s390x")
+ make -j"${SNAPCRAFT_PARALLEL_BUILD_COUNT}" \
+ CMAKE_BUILD_TYPE=RelWithDebInfo \
+ CMAKE_INSTALL_PREFIX=/usr \
+ CMAKE_FLAGS=-DPREFER_LUA=ON \
+ DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_LUA=ON -DUSE_BUNDLED_LUAJIT=OFF"
+ ;;
+ *)
+ make -j"${SNAPCRAFT_PARALLEL_BUILD_COUNT}" \
+ CMAKE_BUILD_TYPE=RelWithDebInfo \
+ CMAKE_INSTALL_PREFIX=/usr
+ ;;
+ esac
+ make DESTDIR="$SNAPCRAFT_PART_INSTALL" install
# Fix Desktop file
sed -i 's|^Exec=nvim|Exec=/snap/bin/nvim.nvim|' ${SNAPCRAFT_PART_INSTALL}/usr/share/applications/nvim.desktop
sed -i 's|^TryExec=nvim|TryExec=/snap/bin/nvim.nvim|' ${SNAPCRAFT_PART_INSTALL}/usr/share/applications/nvim.desktop
@@ -52,11 +77,13 @@ parts:
- autoconf
- automake
- cmake
+ - gawk
- g++
- git
- gettext
- pkg-config
- unzip
+ - wget
prime:
- -usr/share/man
diff --git a/src/clint.py b/src/clint.py
index 8dc41fdb93..9b4128a0c9 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -350,7 +350,7 @@ def IsErrorInSuppressedErrorsList(category, linenum):
category: str, the category of the error.
linenum: int, the current line number.
Returns:
- bool, True iff the error should be suppressed due to presense in
+ bool, True iff the error should be suppressed due to presence in
suppressions file.
"""
return (category, linenum) in _error_suppressions_2
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index c7258dde12..2d98f1a659 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -189,7 +189,11 @@ if(NOT MSVC)
endif()
# tree-sitter: inlined external project, we don't maintain it. #10124
- set_source_files_properties(${TREESITTER_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-pedantic -Wno-shadow -Wno-missing-prototypes -Wno-unused-variable")
+ set(TS_FLAGS "-Wno-conversion -Wno-pedantic -Wno-shadow -Wno-missing-prototypes -Wno-unused-variable")
+ if(HAVE_WIMPLICIT_FALLTHROUGH_FLAG)
+ set(TS_FLAGS "${TS_FLAGS} -Wno-implicit-fallthrough")
+ endif()
+ set_source_files_properties(${TREESITTER_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${TS_FLAGS}")
endif()
if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$")
@@ -620,9 +624,19 @@ if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
check_c_compiler_flag(-fno-sanitize-recover=all SANITIZE_RECOVER_ALL)
if(SANITIZE_RECOVER_ALL)
- set(SANITIZE_RECOVER -fno-sanitize-recover=all) # Clang 3.6+
+ if(TRAVIS_CI_BUILD)
+ # Try to recover from all sanitize issues so we get reports about all failures
+ set(SANITIZE_RECOVER -fsanitize-recover=all) # Clang 3.6+
+ else()
+ set(SANITIZE_RECOVER -fno-sanitize-recover=all) # Clang 3.6+
+ endif()
else()
- set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
+ if(TRAVIS_CI_BUILD)
+ # Try to recover from all sanitize issues so we get reports about all failures
+ set(SANITIZE_RECOVER -fsanitize-recover) # Clang 3.5-
+ else()
+ set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
+ endif()
endif()
set_property(TARGET nvim APPEND PROPERTY COMPILE_DEFINITIONS EXITFREE)
set_property(TARGET nvim APPEND PROPERTY COMPILE_OPTIONS ${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/src/.asan-blacklist)
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 8e61976c4b..cad4c8314f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
+
#include <lauxlib.h>
#include "nvim/api/buffer.h"
@@ -175,8 +176,7 @@ Boolean nvim_buf_attach(uint64_t channel_id,
}
cb.on_lines = v->data.luaref;
v->data.luaref = LUA_NOREF;
- } else if (is_lua && strequal("_on_bytes", k.data)) {
- // NB: undocumented, untested and incomplete interface!
+ } else if (is_lua && strequal("on_bytes", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
goto error;
@@ -213,10 +213,10 @@ Boolean nvim_buf_attach(uint64_t channel_id,
error:
// TODO(bfredl): ASAN build should check that the ref table is empty?
- executor_free_luaref(cb.on_lines);
- executor_free_luaref(cb.on_bytes);
- executor_free_luaref(cb.on_changedtick);
- executor_free_luaref(cb.on_detach);
+ api_free_luaref(cb.on_lines);
+ api_free_luaref(cb.on_bytes);
+ api_free_luaref(cb.on_changedtick);
+ api_free_luaref(cb.on_detach);
return false;
}
@@ -245,78 +245,6 @@ Boolean nvim_buf_detach(uint64_t channel_id,
return true;
}
-static void buf_clear_luahl(buf_T *buf, bool force)
-{
- if (buf->b_luahl || force) {
- executor_free_luaref(buf->b_luahl_start);
- executor_free_luaref(buf->b_luahl_window);
- executor_free_luaref(buf->b_luahl_line);
- executor_free_luaref(buf->b_luahl_end);
- }
- buf->b_luahl_start = LUA_NOREF;
- buf->b_luahl_window = LUA_NOREF;
- buf->b_luahl_line = LUA_NOREF;
- buf->b_luahl_end = LUA_NOREF;
-}
-
-/// Unstabilized interface for defining syntax hl in lua.
-///
-/// This is not yet safe for general use, lua callbacks will need to
-/// be restricted, like textlock and probably other stuff.
-///
-/// The API on_line/nvim__put_attr is quite raw and not intended to be the
-/// final shape. Ideally this should operate on chunks larger than a single
-/// line to reduce interpreter overhead, and generate annotation objects
-/// (bufhl/virttext) on the fly but using the same representation.
-void nvim__buf_set_luahl(uint64_t channel_id, Buffer buffer,
- DictionaryOf(LuaRef) opts, Error *err)
- FUNC_API_LUA_ONLY
-{
- buf_T *buf = find_buffer_by_handle(buffer, err);
-
- if (!buf) {
- return;
- }
-
- redraw_buf_later(buf, NOT_VALID);
- buf_clear_luahl(buf, false);
-
- for (size_t i = 0; i < opts.size; i++) {
- String k = opts.items[i].key;
- Object *v = &opts.items[i].value;
- if (strequal("on_start", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- buf->b_luahl_start = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (strequal("on_window", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- buf->b_luahl_window = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (strequal("on_line", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- buf->b_luahl_line = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else {
- api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
- goto error;
- }
- }
- buf->b_luahl = true;
- return;
-error:
- buf_clear_luahl(buf, true);
- buf->b_luahl = false;
-}
-
void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last,
Error *err)
FUNC_API_LUA_ONLY
@@ -1025,6 +953,53 @@ Boolean nvim_buf_is_loaded(Buffer buffer)
return buf && buf->b_ml.ml_mfp != NULL;
}
+/// Deletes the buffer. See |:bwipeout|
+///
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param opts Optional parameters. Keys:
+/// - force: Force deletion and ignore unsaved changes.
+/// - unload: Unloaded only, do not delete. See |:bunload|
+void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err)
+ FUNC_API_SINCE(7)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (ERROR_SET(err)) {
+ return;
+ }
+
+ bool force = false;
+ bool unload = false;
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object v = opts.items[i].value;
+ if (strequal("force", k.data)) {
+ force = api_coerce_to_bool(v, "force", false, err);
+ } else if (strequal("unload", k.data)) {
+ unload = api_coerce_to_bool(v, "unload", false, err);
+ } else {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ return;
+ }
+ }
+
+ if (ERROR_SET(err)) {
+ return;
+ }
+
+ int result = do_buffer(
+ unload ? DOBUF_UNLOAD : DOBUF_WIPE,
+ DOBUF_FIRST,
+ FORWARD,
+ buf->handle,
+ force);
+
+ if (result == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to unload buffer.");
+ return;
+ }
+}
+
/// Checks if a buffer is valid.
///
/// @note Even if a buffer is valid it may have been unloaded. See |api-buffer|
@@ -1108,15 +1083,67 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
return rv;
}
+static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
+{
+ Array rv = ARRAY_DICT_INIT;
+ if (id) {
+ ADD(rv, INTEGER_OBJ((Integer)extmark.mark_id));
+ }
+ ADD(rv, INTEGER_OBJ(extmark.row));
+ ADD(rv, INTEGER_OBJ(extmark.col));
+
+ if (add_dict) {
+ Dictionary dict = ARRAY_DICT_INIT;
+
+ if (extmark.end_row >= 0) {
+ PUT(dict, "end_row", INTEGER_OBJ(extmark.end_row));
+ PUT(dict, "end_col", INTEGER_OBJ(extmark.end_col));
+ }
+
+ if (extmark.decor) {
+ Decoration *decor = extmark.decor;
+ if (decor->hl_id) {
+ String name = cstr_to_string((const char *)syn_id2name(decor->hl_id));
+ PUT(dict, "hl_group", STRING_OBJ(name));
+ }
+ if (kv_size(decor->virt_text)) {
+ Array chunks = ARRAY_DICT_INIT;
+ for (size_t i = 0; i < decor->virt_text.size; i++) {
+ Array chunk = ARRAY_DICT_INIT;
+ VirtTextChunk *vtc = &decor->virt_text.items[i];
+ ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
+ if (vtc->hl_id > 0) {
+ ADD(chunk,
+ STRING_OBJ(cstr_to_string(
+ (const char *)syn_id2name(vtc->hl_id))));
+ }
+ ADD(chunks, ARRAY_OBJ(chunk));
+ }
+ PUT(dict, "virt_text", ARRAY_OBJ(chunks));
+ }
+ }
+
+ if (dict.size) {
+ ADD(rv, DICTIONARY_OBJ(dict));
+ }
+ }
+
+ return rv;
+}
+
/// Returns position for a given extmark id
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
/// @param id Extmark id
+/// @param opts Optional parameters. Keys:
+/// - limit: Maximum number of marks to return
+/// - details Whether to include the details dict
/// @param[out] err Error details, if any
/// @return (row, col) tuple or empty list () if extmark id was absent
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
- Integer id, Error *err)
+ Integer id, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(7)
{
Array rv = ARRAY_DICT_INIT;
@@ -1132,13 +1159,31 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
return rv;
}
+ bool details = false;
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object *v = &opts.items[i].value;
+ if (strequal("details", k.data)) {
+ if (v->type == kObjectTypeBoolean) {
+ details = v->data.boolean;
+ } else if (v->type == kObjectTypeInteger) {
+ details = v->data.integer;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "details is not an boolean");
+ return rv;
+ }
+ } else {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ return rv;
+ }
+ }
+
+
ExtmarkInfo extmark = extmark_from_id(buf, (uint64_t)ns_id, (uint64_t)id);
if (extmark.row < 0) {
return rv;
}
- ADD(rv, INTEGER_OBJ((Integer)extmark.row));
- ADD(rv, INTEGER_OBJ((Integer)extmark.col));
- return rv;
+ return extmark_to_array(extmark, false, (bool)details);
}
/// Gets extmarks in "traversal order" from a |charwise| region defined by
@@ -1181,10 +1226,12 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
/// (whose position defines the bound)
/// @param opts Optional parameters. Keys:
/// - limit: Maximum number of marks to return
+/// - details Whether to include the details dict
/// @param[out] err Error details, if any
/// @return List of [extmark_id, row, col] tuples in "traversal order".
-Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
- Object end, Dictionary opts, Error *err)
+Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
+ Object start, Object end,
+ Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
Array rv = ARRAY_DICT_INIT;
@@ -1198,7 +1245,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return rv;
}
+
Integer limit = -1;
+ bool details = false;
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
@@ -1209,6 +1258,15 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
return rv;
}
limit = v->data.integer;
+ } else if (strequal("details", k.data)) {
+ if (v->type == kObjectTypeBoolean) {
+ details = v->data.boolean;
+ } else if (v->type == kObjectTypeInteger) {
+ details = v->data.integer;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "details is not an boolean");
+ return rv;
+ }
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
return rv;
@@ -1241,16 +1299,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
}
- ExtmarkArray marks = extmark_get(buf, (uint64_t)ns_id, l_row, l_col, u_row,
- u_col, (int64_t)limit, reverse);
+ ExtmarkInfoArray marks = extmark_get(buf, (uint64_t)ns_id, l_row, l_col,
+ u_row, u_col, (int64_t)limit, reverse);
for (size_t i = 0; i < kv_size(marks); i++) {
- Array mark = ARRAY_DICT_INIT;
- ExtmarkInfo extmark = kv_A(marks, i);
- ADD(mark, INTEGER_OBJ((Integer)extmark.mark_id));
- ADD(mark, INTEGER_OBJ(extmark.row));
- ADD(mark, INTEGER_OBJ(extmark.col));
- ADD(rv, ARRAY_OBJ(mark));
+ ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, (bool)details)));
}
kv_destroy(marks);
@@ -1260,27 +1313,40 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
/// Creates or updates an extmark.
///
/// To create a new extmark, pass id=0. The extmark id will be returned.
-// To move an existing mark, pass its id.
+/// To move an existing mark, pass its id.
///
/// It is also allowed to create a new mark by passing in a previously unused
/// id, but the caller must then keep track of existing and unused ids itself.
/// (Useful over RPC, to avoid waiting for the return value.)
///
+/// Using the optional arguments, it is possible to use this to highlight
+/// a range of text, and also to associate virtual text to the mark.
+///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param id Extmark id, or 0 to create new
/// @param line Line number where to place the mark
/// @param col Column where to place the mark
-/// @param opts Optional parameters. Currently not used.
+/// @param opts Optional parameters.
+/// - id : id of the extmark to edit.
+/// - end_line : ending line of the mark, 0-based inclusive.
+/// - end_col : ending col of the mark, 0-based inclusive.
+/// - hl_group : name of the highlight group used to highlight
+/// this mark.
+/// - virt_text : virtual text to link to this mark.
+/// - ephemeral : for use with |nvim_set_decoration_provider|
+/// callbacks. The mark will only be used for the current
+/// redraw cycle, and not be permantently stored in the
+/// buffer.
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
-Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
+Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
Integer line, Integer col,
Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
+ api_set_error(err, kErrorTypeValidation, "Invalid buffer id");
return 0;
}
@@ -1289,11 +1355,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
return 0;
}
- if (opts.size > 0) {
- api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
- return 0;
- }
-
size_t len = 0;
if (line < 0 || line > buf->b_ml.ml_line_count) {
api_set_error(err, kErrorTypeValidation, "line value outside range");
@@ -1309,18 +1370,138 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
return 0;
}
- uint64_t id_num;
- if (id >= 0) {
- id_num = (uint64_t)id;
+ bool ephemeral = false;
+
+ uint64_t id = 0;
+ int line2 = -1, hl_id = 0;
+ colnr_T col2 = 0;
+ VirtText virt_text = KV_INITIAL_VALUE;
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object *v = &opts.items[i].value;
+ if (strequal("id", k.data)) {
+ if (v->type != kObjectTypeInteger || v->data.integer <= 0) {
+ api_set_error(err, kErrorTypeValidation,
+ "id is not a positive integer");
+ goto error;
+ }
+
+ id = (uint64_t)v->data.integer;
+ } else if (strequal("end_line", k.data)) {
+ if (v->type != kObjectTypeInteger) {
+ api_set_error(err, kErrorTypeValidation,
+ "end_line is not an integer");
+ goto error;
+ }
+ if (v->data.integer < 0 || v->data.integer > buf->b_ml.ml_line_count) {
+ api_set_error(err, kErrorTypeValidation,
+ "end_line value outside range");
+ goto error;
+ }
+
+ line2 = (int)v->data.integer;
+ } else if (strequal("end_col", k.data)) {
+ if (v->type != kObjectTypeInteger) {
+ api_set_error(err, kErrorTypeValidation,
+ "end_col is not an integer");
+ goto error;
+ }
+ if (v->data.integer < 0 || v->data.integer > MAXCOL) {
+ api_set_error(err, kErrorTypeValidation,
+ "end_col value outside range");
+ goto error;
+ }
+
+ col2 = (colnr_T)v->data.integer;
+ } else if (strequal("hl_group", k.data)) {
+ String hl_group;
+ switch (v->type) {
+ case kObjectTypeString:
+ hl_group = v->data.string;
+ hl_id = syn_check_group(
+ (char_u *)(hl_group.data),
+ (int)hl_group.size);
+ break;
+ case kObjectTypeInteger:
+ hl_id = (int)v->data.integer;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation,
+ "hl_group is not valid.");
+ goto error;
+ }
+ } else if (strequal("virt_text", k.data)) {
+ if (v->type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text is not an Array");
+ goto error;
+ }
+ virt_text = parse_virt_text(v->data.array, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ } else if (strequal("ephemeral", k.data)) {
+ ephemeral = api_coerce_to_bool(*v, "ephemeral", false, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ } else {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ goto error;
+ }
+ }
+
+ if (col2 >= 0) {
+ if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
+ len = STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false));
+ } else if (line2 == buf->b_ml.ml_line_count) {
+ // We are trying to add an extmark past final newline
+ len = 0;
+ } else {
+ // reuse len from before
+ line2 = (int)line;
+ }
+ if (col2 > (Integer)len) {
+ api_set_error(err, kErrorTypeValidation, "end_col value outside range");
+ goto error;
+ }
+ } else if (line2 >= 0) {
+ col2 = 0;
+ }
+
+ // TODO(bfredl): synergize these two branches even more
+ if (ephemeral && redrawn_win && redrawn_win->w_buffer == buf) {
+ int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0;
+ VirtText *vt_allocated = NULL;
+ if (kv_size(virt_text)) {
+ vt_allocated = xmalloc(sizeof *vt_allocated);
+ *vt_allocated = virt_text;
+ }
+ decorations_add_ephemeral(attr_id, (int)line, (colnr_T)col,
+ (int)line2, (colnr_T)col2, vt_allocated);
} else {
- api_set_error(err, kErrorTypeValidation, "Invalid mark id");
- return 0;
+ if (ephemeral) {
+ api_set_error(err, kErrorTypeException, "not yet implemented");
+ goto error;
+ }
+ Decoration *decor = NULL;
+ if (kv_size(virt_text)) {
+ decor = xcalloc(1, sizeof(*decor));
+ decor->hl_id = hl_id;
+ decor->virt_text = virt_text;
+ } else if (hl_id) {
+ decor = decoration_hl(hl_id);
+ }
+
+ id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
+ line2, col2, decor, kExtmarkNoUndo);
}
- id_num = extmark_set(buf, (uint64_t)ns_id, id_num,
- (int)line, (colnr_T)col, kExtmarkUndo);
+ return (Integer)id;
- return (Integer)id_num;
+error:
+ clear_virttext(&virt_text);
+ return 0;
}
/// Removes an extmark.
@@ -1358,17 +1539,17 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
/// like signs and marks do.
///
/// Namespaces are used for batch deletion/updating of a set of highlights. To
-/// create a namespace, use |nvim_create_namespace| which returns a namespace
+/// create a namespace, use |nvim_create_namespace()| which returns a namespace
/// id. Pass it in to this function as `ns_id` to add highlights to the
/// namespace. All highlights in the same namespace can then be cleared with
-/// single call to |nvim_buf_clear_namespace|. If the highlight never will be
+/// single call to |nvim_buf_clear_namespace()|. If the highlight never will be
/// deleted by an API call, pass `ns_id = -1`.
///
/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
/// highlight, the allocated id is then returned. If `hl_group` is the empty
/// string no highlight is added, but a new `ns_id` is still returned. This is
/// supported for backwards compatibility, new code should use
-/// |nvim_create_namespace| to create a new empty namespace.
+/// |nvim_create_namespace()| to create a new empty namespace.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id namespace to use or -1 for ungrouped highlight
@@ -1412,9 +1593,9 @@ Integer nvim_buf_add_highlight(Buffer buffer,
return src_id;
}
- int hlg_id = 0;
+ int hl_id = 0;
if (hl_group.size > 0) {
- hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
+ hl_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
} else {
return src_id;
}
@@ -1425,10 +1606,10 @@ Integer nvim_buf_add_highlight(Buffer buffer,
end_line++;
}
- extmark_add_decoration(buf, ns_id, hlg_id,
- (int)line, (colnr_T)col_start,
- end_line, (colnr_T)col_end,
- VIRTTEXT_EMPTY);
+ extmark_set(buf, ns_id, 0,
+ (int)line, (colnr_T)col_start,
+ end_line, (colnr_T)col_end,
+ decoration_hl(hl_id), kExtmarkNoUndo);
return src_id;
}
@@ -1470,7 +1651,7 @@ void nvim_buf_clear_namespace(Buffer buffer,
/// Clears highlights and virtual text from namespace and range of lines
///
-/// @deprecated use |nvim_buf_clear_namespace|.
+/// @deprecated use |nvim_buf_clear_namespace()|.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace to clear, or -1 to clear all.
@@ -1488,43 +1669,6 @@ void nvim_buf_clear_highlight(Buffer buffer,
nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end, err);
}
-static VirtText parse_virt_text(Array chunks, Error *err)
-{
- VirtText virt_text = 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");
- 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");
- goto free_exit;
- }
-
- String str = chunk.items[0].data.string;
- char *text = transstr(str.size > 0 ? str.data : ""); // allocates
-
- int hl_id = 0;
- if (chunk.size == 2) {
- String hl = chunk.items[1].data.string;
- if (hl.size > 0) {
- hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
- }
- }
- kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
- }
-
- return virt_text;
-
-free_exit:
- clear_virttext(&virt_text);
- return virt_text;
-}
-
/// Set the virtual text (annotation) for a buffer line.
///
@@ -1534,11 +1678,11 @@ free_exit:
/// begin one cell (|lcs-eol| or space) after the ordinary text.
///
/// Namespaces are used to support batch deletion/updating of virtual text.
-/// To create a namespace, use |nvim_create_namespace|. Virtual text is
-/// cleared using |nvim_buf_clear_namespace|. The same `ns_id` can be used for
-/// both virtual text and highlights added by |nvim_buf_add_highlight|, both
-/// can then be cleared with a single call to |nvim_buf_clear_namespace|. If the
-/// virtual text never will be cleared by an API call, pass `ns_id = -1`.
+/// To create a namespace, use |nvim_create_namespace()|. Virtual text is
+/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
+/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both
+/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If
+/// the virtual text never will be cleared by an API call, pass `ns_id = -1`.
///
/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
/// virtual text, the allocated id is then returned.
@@ -1592,113 +1736,49 @@ Integer nvim_buf_set_virtual_text(Buffer buffer,
return src_id;
}
- extmark_add_decoration(buf, ns_id, 0,
- (int)line, 0, -1, -1,
- virt_text);
+ Decoration *decor = xcalloc(1, sizeof(*decor));
+ decor->virt_text = virt_text;
+
+ extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, kExtmarkNoUndo);
return src_id;
}
-/// Get the virtual text (annotation) for a buffer line.
-///
-/// The virtual text is returned as list of lists, whereas the inner lists have
-/// either one or two elements. The first element is the actual text, the
-/// optional second element is the highlight group.
+/// call a function with buffer as temporary current buffer
///
-/// The format is exactly the same as given to nvim_buf_set_virtual_text().
+/// This temporarily switches current buffer to "buffer".
+/// If the current window already shows "buffer", the window is not switched
+/// If a window inside the current tabpage (including a float) already shows the
+/// buffer One of these windows will be set as current window temporarily.
+/// Otherwise a temporary scratch window (calleed the "autocmd window" for
+/// historical reasons) will be used.
///
-/// If there is no virtual text associated with the given line, an empty list
-/// is returned.
+/// This is useful e.g. to call vimL functions that only work with the current
+/// buffer/window currently, like |termopen()|.
///
-/// @param buffer Buffer handle, or 0 for current buffer
-/// @param line Line to get the virtual text from (zero-indexed)
-/// @param[out] err Error details, if any
-/// @return List of virtual text chunks
-Array nvim_buf_get_virtual_text(Buffer buffer, Integer line, Error *err)
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param fun Function to call inside the buffer (currently lua callable
+/// only)
+/// @param[out] err Error details, if any
+/// @return Return value of function. NB: will deepcopy lua values
+/// currently, use upvalues to send lua references in and out.
+Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
FUNC_API_SINCE(7)
-{
- Array chunks = ARRAY_DICT_INIT;
-
- buf_T *buf = find_buffer_by_handle(buffer, err);
- if (!buf) {
- return chunks;
- }
-
- if (line < 0 || line >= MAXLNUM) {
- api_set_error(err, kErrorTypeValidation, "Line number outside range");
- return chunks;
- }
-
- VirtText *virt_text = extmark_find_virttext(buf, (int)line, 0);
-
- if (!virt_text) {
- return chunks;
- }
-
- for (size_t i = 0; i < virt_text->size; i++) {
- Array chunk = ARRAY_DICT_INIT;
- VirtTextChunk *vtc = &virt_text->items[i];
- ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
- if (vtc->hl_id > 0) {
- ADD(chunk, STRING_OBJ(cstr_to_string(
- (const char *)syn_id2name(vtc->hl_id))));
- }
- ADD(chunks, ARRAY_OBJ(chunk));
- }
-
- return chunks;
-}
-
-Integer nvim__buf_add_decoration(Buffer buffer, Integer ns_id, String hl_group,
- Integer start_row, Integer start_col,
- Integer end_row, Integer end_col,
- Array virt_text,
- Error *err)
+ FUNC_API_LUA_ONLY
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return 0;
- }
-
- if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
- return 0;
- }
-
-
- if (start_row < 0 || start_row >= MAXLNUM || end_row > MAXCOL) {
- api_set_error(err, kErrorTypeValidation, "Line number outside range");
- return 0;
- }
-
- if (start_col < 0 || start_col > MAXCOL || end_col > MAXCOL) {
- api_set_error(err, kErrorTypeValidation, "Column value outside range");
- return 0;
- }
- if (end_row < 0 || end_col < 0) {
- end_row = -1;
- end_col = -1;
- }
-
- if (start_row >= buf->b_ml.ml_line_count
- || end_row >= buf->b_ml.ml_line_count) {
- // safety check, we can't add marks outside the range
- return 0;
- }
-
- int hlg_id = 0;
- if (hl_group.size > 0) {
- hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
+ return NIL;
}
+ try_start();
+ aco_save_T aco;
+ aucmd_prepbuf(&aco, (buf_T *)buf);
- VirtText vt = parse_virt_text(virt_text, err);
- if (ERROR_SET(err)) {
- return 0;
- }
+ Array args = ARRAY_DICT_INIT;
+ Object res = nlua_call_ref(fun, NULL, args, true, err);
- uint64_t mark_id = extmark_add_decoration(buf, (uint64_t)ns_id, hlg_id,
- (int)start_row, (colnr_T)start_col,
- (int)end_row, (colnr_T)end_col, vt);
- return (Integer)mark_id;
+ aucmd_restbuf(&aco);
+ try_end(err);
+ return res;
}
Dictionary nvim__buf_stats(Buffer buffer, Error *err)
@@ -1721,6 +1801,7 @@ Dictionary nvim__buf_stats(Buffer buffer, Error *err)
// NB: this should be zero at any time API functions are called,
// this exists to debug issues
PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes));
+ PUT(rv, "dirty_bytes2", INTEGER_OBJ((Integer)buf->deleted_bytes2));
u_header_T *uhp = NULL;
if (buf->b_u_curhead != NULL) {
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index f194b6b474..981d41ae6e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -15,6 +15,8 @@
#include "nvim/lua/executor.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
+#include "nvim/charset.h"
+#include "nvim/syntax.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/window.h"
@@ -1198,7 +1200,7 @@ void api_free_object(Object value)
break;
case kObjectTypeLuaRef:
- executor_free_luaref(value.data.luaref);
+ api_free_luaref(value.data.luaref);
break;
default:
@@ -1579,3 +1581,76 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
return false;
}
}
+
+VirtText parse_virt_text(Array chunks, Error *err)
+{
+ VirtText virt_text = 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");
+ 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");
+ goto free_exit;
+ }
+
+ String str = chunk.items[0].data.string;
+ char *text = transstr(str.size > 0 ? str.data : ""); // allocates
+
+ int hl_id = 0;
+ if (chunk.size == 2) {
+ String hl = chunk.items[1].data.string;
+ if (hl.size > 0) {
+ hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
+ }
+ }
+ kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
+ }
+
+ return virt_text;
+
+free_exit:
+ clear_virttext(&virt_text);
+ return virt_text;
+}
+
+/// Force obj to bool.
+/// If it fails, returns false and sets err
+/// @param obj The object to coerce to a boolean
+/// @param what The name of the object, used for error message
+/// @param nil_value What to return if the type is nil.
+/// @param err Set if there was an error in converting to a bool
+bool api_coerce_to_bool(
+ Object obj,
+ const char *what,
+ bool nil_value,
+ Error *err)
+{
+ if (obj.type == kObjectTypeBoolean) {
+ return obj.data.boolean;
+ } else if (obj.type == kObjectTypeInteger) {
+ return obj.data.integer; // C semantics: non-zero int is true
+ } else if (obj.type == kObjectTypeNil) {
+ return nil_value; // caller decides what NIL (missing retval in lua) means
+ } else {
+ api_set_error(err, kErrorTypeValidation, "%s is not an boolean", what);
+ return false;
+ }
+}
+
+const char *describe_ns(NS ns_id)
+{
+ String name;
+ handle_T id;
+ map_foreach(namespace_ids, name, id, {
+ if ((NS)id == ns_id && name.size) {
+ return name.data;
+ }
+ })
+ return "(UNKNOWN PLUGIN)";
+}
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index ab31db39e9..e934d5dc92 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -1,7 +1,7 @@
#ifndef NVIM_API_UI_EVENTS_IN_H
#define NVIM_API_UI_EVENTS_IN_H
-// This file is not compiled, just parsed for definitons
+// This file is not compiled, just parsed for definitions
#ifdef INCLUDE_GENERATED_DECLARATIONS
# error "don't include this file, include nvim/ui.h"
#endif
@@ -36,13 +36,15 @@ void set_title(String title)
FUNC_API_SINCE(3);
void set_icon(String icon)
FUNC_API_SINCE(3);
+void screenshot(String path)
+ FUNC_API_SINCE(7) FUNC_API_REMOTE_IMPL;
void option_set(String name, Object value)
FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL;
// Stop event is not exported as such, represented by EOF in the msgpack stream.
void stop(void)
FUNC_API_NOEXPORT;
-// First revison of the grid protocol, used by default
+// First revision of the grid protocol, used by default
void update_fg(Integer fg)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void update_bg(Integer bg)
@@ -66,7 +68,7 @@ void set_scroll_region(Integer top, Integer bot, Integer left, Integer right)
void scroll(Integer count)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
-// Second revison of the grid protocol, used with ext_linegrid ui option
+// Second revision of the grid protocol, used with ext_linegrid ui option
void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
FUNC_API_SINCE(4) FUNC_API_REMOTE_IMPL;
@@ -89,7 +91,7 @@ void grid_scroll(Integer grid, Integer top, Integer bot,
void grid_destroy(Integer grid)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
-// For perfomance and simplicity, we use the dense screen representation
+// For performance and simplicity, we use the dense screen representation
// in internal code, such as compositor and TUI. The remote_ui module will
// translate this in to the public grid_line format.
void raw_line(Integer grid, Integer row, Integer startcol,
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index d6f95c7a5f..876b052a8e 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -203,10 +203,10 @@ Integer nvim_get_hl_id_by_name(String name)
/// flags. This is a blocking call, unlike |nvim_input()|.
///
/// On execution error: does not fail, but updates v:errmsg.
-//
-// If you need to input sequences like <C-o> use nvim_replace_termcodes
-// to replace the termcodes and then pass the resulting string to
-// nvim_feedkeys. You'll also want to enable escape_csi.
+///
+/// If you need to input sequences like <C-o> use |nvim_replace_termcodes| to
+/// replace the termcodes and then pass the resulting string to nvim_feedkeys.
+/// You'll also want to enable escape_csi.
///
/// Example:
/// <pre>
@@ -475,7 +475,7 @@ Object nvim_execute_lua(String code, Array args, Error *err)
FUNC_API_DEPRECATED_SINCE(7)
FUNC_API_REMOTE_ONLY
{
- return executor_exec_lua_api(code, args, err);
+ return nlua_exec(code, args, err);
}
/// Execute Lua code. Parameters (if any) are available as `...` inside the
@@ -494,7 +494,7 @@ Object nvim_exec_lua(String code, Array args, Error *err)
FUNC_API_SINCE(7)
FUNC_API_REMOTE_ONLY
{
- return executor_exec_lua_api(code, args, err);
+ return nlua_exec(code, args, err);
}
/// Calls a VimL function.
@@ -2477,7 +2477,7 @@ Array nvim_get_proc_children(Integer pid, Error *err)
Array a = ARRAY_DICT_INIT;
ADD(a, INTEGER_OBJ(pid));
String s = cstr_to_string("return vim._os_proc_children(select(1, ...))");
- Object o = nvim_exec_lua(s, a, err);
+ Object o = nlua_exec(s, a, err);
api_free_string(s);
api_free_array(a);
if (o.type == kObjectTypeArray) {
@@ -2523,7 +2523,7 @@ Object nvim_get_proc(Integer pid, Error *err)
Array a = ARRAY_DICT_INIT;
ADD(a, INTEGER_OBJ(pid));
String s = cstr_to_string("return vim._os_proc_info(select(1, ...))");
- Object o = nvim_exec_lua(s, a, err);
+ Object o = nlua_exec(s, a, err);
api_free_string(s);
api_free_array(a);
if (o.type == kObjectTypeArray && o.data.array.size == 0) {
@@ -2604,26 +2604,135 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
return ret;
}
-/// Set attrs in nvim__buf_set_lua_hl callbacks
-///
-/// TODO(bfredl): This is rather pedestrian. The final
-/// interface should probably be derived from a reformed
-/// bufhl/virttext interface with full support for multi-line
-/// ranges etc
-void nvim__put_attr(Integer id, Integer start_row, Integer start_col,
- Integer end_row, Integer end_col)
- FUNC_API_LUA_ONLY
+void nvim__screenshot(String path)
+ FUNC_API_FAST
{
- if (!lua_attr_active) {
- return;
- }
- if (id == 0 || syn_get_final_id((int)id) == 0) {
- return;
+ ui_call_screenshot(path);
+}
+
+static DecorationProvider *get_provider(NS ns_id, bool force)
+{
+ ssize_t i;
+ for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) {
+ DecorationProvider *item = &kv_A(decoration_providers, i);
+ if (item->ns_id == ns_id) {
+ return item;
+ } else if (item->ns_id > ns_id) {
+ break;
+ }
}
- int attr = syn_id2attr((int)id);
- if (attr == 0) {
- return;
+
+ if (!force) {
+ return NULL;
+ }
+
+ for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) {
+ // allocates if needed:
+ (void)kv_a(decoration_providers, (size_t)j+1);
+ kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j);
+ }
+ DecorationProvider *item = &kv_a(decoration_providers, (size_t)i);
+ *item = DECORATION_PROVIDER_INIT(ns_id);
+
+ return item;
+}
+
+static void clear_provider(DecorationProvider *p)
+{
+ NLUA_CLEAR_REF(p->redraw_start);
+ NLUA_CLEAR_REF(p->redraw_buf);
+ NLUA_CLEAR_REF(p->redraw_win);
+ NLUA_CLEAR_REF(p->redraw_line);
+ NLUA_CLEAR_REF(p->redraw_end);
+ p->active = false;
+}
+
+/// Set or change decoration provider for a namespace
+///
+/// This is a very general purpose interface for having lua callbacks
+/// being triggered during the redraw code.
+///
+/// The expected usage is to set extmarks for the currently
+/// redrawn buffer. |nvim_buf_set_extmark| can be called to add marks
+/// on a per-window or per-lines basis. Use the `ephemeral` key to only
+/// use the mark for the current screen redraw (the callback will be called
+/// again for the next redraw ).
+///
+/// Note: this function should not be called often. Rather, the callbacks
+/// themselves can be used to throttle unneeded callbacks. the `on_start`
+/// callback can return `false` to disable the provider until the next redraw.
+/// Similarily, return `false` in `on_win` will skip the `on_lines` calls
+/// for that window (but any extmarks set in `on_win` will still be used).
+/// A plugin managing multiple sources of decorations should ideally only set
+/// one provider, and merge the sources internally. You can use multiple `ns_id`
+/// for the extmarks set/modified inside the callback anyway.
+///
+/// Note: doing anything other than setting extmarks is considered experimental.
+/// Doing things like changing options are not expliticly forbidden, but is
+/// likely to have unexpected consequences (such as 100% CPU consumption).
+/// doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious
+/// for the moment.
+///
+/// @param ns_id Namespace id from |nvim_create_namespace()|
+/// @param opts Callbacks invoked during redraw:
+/// - on_start: called first on each screen redraw
+/// ["start", tick]
+/// - on_buf: called for each buffer being redrawn (before window
+/// callbacks)
+/// ["buf", bufnr, tick]
+/// - on_win: called when starting to redraw a specific window.
+/// ["win", winid, bufnr, topline, botline_guess]
+/// - on_line: called for each buffer line being redrawn. (The
+/// interation with fold lines is subject to change)
+/// ["win", winid, bufnr, row]
+/// - on_end: called at the end of a redraw cycle
+/// ["end", tick]
+void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
+ Error *err)
+ FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
+{
+ DecorationProvider *p = get_provider((NS)ns_id, true);
+ clear_provider(p);
+
+ // regardless of what happens, it seems good idea to redraw
+ redraw_later(NOT_VALID); // TODO(bfredl): too soon?
+
+ struct {
+ const char *name;
+ LuaRef *dest;
+ } cbs[] = {
+ { "on_start", &p->redraw_start },
+ { "on_buf", &p->redraw_buf },
+ { "on_win", &p->redraw_win },
+ { "on_line", &p->redraw_line },
+ { "on_end", &p->redraw_end },
+ { NULL, NULL },
+ };
+
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object *v = &opts.items[i].value;
+ size_t j;
+ for (j = 0; cbs[j].name; j++) {
+ if (strequal(cbs[j].name, k.data)) {
+ if (v->type != kObjectTypeLuaRef) {
+ api_set_error(err, kErrorTypeValidation,
+ "%s is not a function", cbs[j].name);
+ goto error;
+ }
+ *(cbs[j].dest) = v->data.luaref;
+ v->data.luaref = LUA_NOREF;
+ break;
+ }
+ }
+ if (!cbs[j].name) {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ goto error;
+ }
}
- decorations_add_luahl_attr(attr, (int)start_row, (colnr_T)start_col,
- (int)end_row, (colnr_T)end_col);
+
+ p->active = true;
+ return;
+error:
+ clear_provider(p);
}
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 31423e79af..2397af27cc 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -31,9 +31,7 @@
#define CSI 0x9b // Control Sequence Introducer
#define CSI_STR "\233"
#define DCS 0x90 // Device Control String
-#define DCS_STR "\033P"
#define STERM 0x9c // String Terminator
-#define STERM_STR "\033\\"
#define POUND 0xA3
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 4391d997a7..10647c01a4 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -65,7 +65,8 @@ return {
'InsertChange', -- when changing Insert/Replace mode
'InsertCharPre', -- before inserting a char
'InsertEnter', -- when entering Insert mode
- 'InsertLeave', -- when leaving Insert mode
+ 'InsertLeave', -- just after leaving Insert mode
+ 'InsertLeavePre', -- just before leaving Insert mode
'MenuPopup', -- just before popup menu is displayed
'OptionSet', -- after setting any option
'QuickFixCmdPost', -- after :make, :grep etc.
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b3bbdce9d9..8f631ae13b 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -837,7 +837,7 @@ static void clear_wininfo(buf_T *buf)
buf->b_wininfo = wip->wi_next;
if (wip->wi_optset) {
clear_winopt(&wip->wi_opt);
- deleteFoldRecurse(&wip->wi_folds);
+ deleteFoldRecurse(buf, &wip->wi_folds);
}
xfree(wip);
}
@@ -1941,6 +1941,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
vim_regfree(buf->b_s.b_cap_prog);
buf->b_s.b_cap_prog = NULL;
clear_string_option(&buf->b_s.b_p_spl);
+ clear_string_option(&buf->b_s.b_p_spo);
clear_string_option(&buf->b_p_sua);
clear_string_option(&buf->b_p_ft);
clear_string_option(&buf->b_p_cink);
@@ -2502,7 +2503,7 @@ void buflist_setfpos(buf_T *const buf, win_T *const win,
}
if (copy_options && wip->wi_optset) {
clear_winopt(&wip->wi_opt);
- deleteFoldRecurse(&wip->wi_folds);
+ deleteFoldRecurse(buf, &wip->wi_folds);
}
}
if (lnum != 0) {
@@ -2650,7 +2651,7 @@ void buflist_list(exarg_T *eap)
int i;
garray_T buflist;
- buf_T **buflist_data = NULL, **p;
+ buf_T **buflist_data = NULL;
if (vim_strchr(eap->arg, 't')) {
ga_init(&buflist, sizeof(buf_T *), 50);
@@ -2662,13 +2663,14 @@ void buflist_list(exarg_T *eap)
qsort(buflist.ga_data, (size_t)buflist.ga_len,
sizeof(buf_T *), buf_time_compare);
- p = buflist_data = (buf_T **)buflist.ga_data;
- buf = *p;
+ buflist_data = (buf_T **)buflist.ga_data;
+ buf = *buflist_data;
}
+ buf_T **p = buflist_data;
for (;
buf != NULL && !got_int;
- buf = buflist_data
+ buf = buflist_data != NULL
? (++p < buflist_data + buflist.ga_len ? *p : NULL)
: buf->b_next) {
const bool is_terminal = buf->terminal;
@@ -5395,13 +5397,11 @@ bool buf_hide(const buf_T *const buf)
char_u *buf_spname(buf_T *buf)
{
if (bt_quickfix(buf)) {
- win_T *win;
- tabpage_T *tp;
+ win_T *win;
+ tabpage_T *tp;
- /*
- * For location list window, w_llist_ref points to the location list.
- * For quickfix window, w_llist_ref is NULL.
- */
+ // For location list window, w_llist_ref points to the location list.
+ // For quickfix window, w_llist_ref is NULL.
if (find_win_for_buf(buf, &win, &tp) && win->w_llist_ref != NULL) {
return (char_u *)_(msg_loclist);
} else {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 550f8a5e40..8e855cb644 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -91,6 +91,7 @@ typedef struct {
#define BF_READERR 0x40 // got errors while reading the file
#define BF_DUMMY 0x80 // dummy buffer, only used internally
#define BF_PRESERVED 0x100 // ":preserve" was used
+#define BF_SYN_SET 0x200 // 'syntax' option was set
// Mask to check for flags that prevent normal writing
#define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR)
@@ -451,6 +452,7 @@ typedef struct {
regprog_T *b_cap_prog; // program for 'spellcapcheck'
char_u *b_p_spf; // 'spellfile'
char_u *b_p_spl; // 'spelllang'
+ char_u *b_p_spo; // 'spelloptions'
int b_cjk; // all CJK letters as OK
char_u b_syn_chartab[32]; // syntax iskeyword option
char_u *b_syn_isk; // iskeyword option
@@ -543,6 +545,9 @@ struct file_buffer {
long b_mod_xlines; // number of extra buffer lines inserted;
// negative when lines were deleted
wininfo_T *b_wininfo; // list of last used info for each window
+ int b_mod_tick_syn; // last display tick syntax was updated
+ int b_mod_tick_deco; // last display tick decoration providers
+ // where invoked
long b_mtime; // last change time of original file
long b_mtime_read; // last change time when reading
@@ -656,6 +661,9 @@ struct file_buffer {
char_u *b_p_com; ///< 'comments'
char_u *b_p_cms; ///< 'commentstring'
char_u *b_p_cpt; ///< 'complete'
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *b_p_csl; ///< 'completeslash'
+#endif
char_u *b_p_cfu; ///< 'completefunc'
char_u *b_p_ofu; ///< 'omnifunc'
char_u *b_p_tfu; ///< 'tagfunc'
@@ -835,18 +843,13 @@ struct file_buffer {
// tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
// deleted text.
size_t deleted_bytes;
+ size_t deleted_bytes2;
size_t deleted_codepoints;
size_t deleted_codeunits;
// The number for times the current line has been flushed in the memline.
int flush_count;
- bool b_luahl;
- LuaRef b_luahl_start;
- LuaRef b_luahl_window;
- LuaRef b_luahl_line;
- LuaRef b_luahl_end;
-
int b_diff_failed; // internal diff failed for this buffer
};
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index e6393bf02c..fc671ad9e2 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -2,6 +2,7 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "nvim/buffer_updates.h"
+#include "nvim/extmark.h"
#include "nvim/memline.h"
#include "nvim/api/private/helpers.h"
#include "nvim/msgpack_rpc/channel.h"
@@ -157,7 +158,7 @@ void buf_updates_unregister_all(buf_T *buf)
args.items[0] = BUFFER_OBJ(buf->handle);
textlock++;
- executor_exec_lua_cb(cb.on_detach, "detach", args, false, NULL);
+ nlua_call_ref(cb.on_detach, "detach", args, false, NULL);
textlock--;
}
free_update_callbacks(cb);
@@ -265,7 +266,7 @@ void buf_updates_send_changes(buf_T *buf,
args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits);
}
textlock++;
- Object res = executor_exec_lua_cb(cb.on_lines, "lines", args, true, NULL);
+ Object res = nlua_call_ref(cb.on_lines, "lines", args, true, NULL);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
@@ -281,12 +282,14 @@ void buf_updates_send_changes(buf_T *buf,
kv_size(buf->update_callbacks) = j;
}
-void buf_updates_send_splice(buf_T *buf,
- linenr_T start_line, colnr_T start_col,
- linenr_T oldextent_line, colnr_T oldextent_col,
- linenr_T newextent_line, colnr_T newextent_col)
+void buf_updates_send_splice(
+ buf_T *buf,
+ int start_row, colnr_T start_col, bcount_t start_byte,
+ int old_row, colnr_T old_col, bcount_t old_byte,
+ int new_row, colnr_T new_col, bcount_t new_byte)
{
- if (!buf_updates_active(buf)) {
+ if (!buf_updates_active(buf)
+ || (old_byte == 0 && new_byte == 0)) {
return;
}
@@ -296,7 +299,7 @@ void buf_updates_send_splice(buf_T *buf,
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
bool keep = true;
if (cb.on_bytes != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 8);
+ FIXED_TEMP_ARRAY(args, 11);
// the first argument is always the buffer handle
args.items[0] = BUFFER_OBJ(buf->handle);
@@ -304,15 +307,18 @@ void buf_updates_send_splice(buf_T *buf,
// next argument is b:changedtick
args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
- args.items[2] = INTEGER_OBJ(start_line);
+ args.items[2] = INTEGER_OBJ(start_row);
args.items[3] = INTEGER_OBJ(start_col);
- args.items[4] = INTEGER_OBJ(oldextent_line);
- args.items[5] = INTEGER_OBJ(oldextent_col);
- args.items[6] = INTEGER_OBJ(newextent_line);
- args.items[7] = INTEGER_OBJ(newextent_col);
+ args.items[4] = INTEGER_OBJ(start_byte);
+ args.items[5] = INTEGER_OBJ(old_row);
+ args.items[6] = INTEGER_OBJ(old_col);
+ args.items[7] = INTEGER_OBJ(old_byte);
+ args.items[8] = INTEGER_OBJ(new_row);
+ args.items[9] = INTEGER_OBJ(new_col);
+ args.items[10] = INTEGER_OBJ(new_byte);
textlock++;
- Object res = executor_exec_lua_cb(cb.on_bytes, "bytes", args, true, NULL);
+ Object res = nlua_call_ref(cb.on_bytes, "bytes", args, true, NULL);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
@@ -347,8 +353,8 @@ void buf_updates_changedtick(buf_T *buf)
args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
textlock++;
- Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick",
- args, true, NULL);
+ Object res = nlua_call_ref(cb.on_changedtick, "changedtick",
+ args, true, NULL);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
@@ -382,6 +388,6 @@ void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id)
static void free_update_callbacks(BufUpdateCallbacks cb)
{
- executor_free_luaref(cb.on_lines);
- executor_free_luaref(cb.on_changedtick);
+ api_free_luaref(cb.on_lines);
+ api_free_luaref(cb.on_changedtick);
}
diff --git a/src/nvim/buffer_updates.h b/src/nvim/buffer_updates.h
index b2d0a62270..961fec879b 100644
--- a/src/nvim/buffer_updates.h
+++ b/src/nvim/buffer_updates.h
@@ -2,6 +2,7 @@
#define NVIM_BUFFER_UPDATES_H
#include "nvim/buffer_defs.h"
+#include "nvim/extmark.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer_updates.h.generated.h"
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 51afb40b40..be52750c44 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -142,7 +142,6 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
long xtra)
{
int i;
- int cols;
pos_T *p;
int add;
@@ -170,7 +169,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
if (p->lnum != lnum) {
add = true;
} else {
- cols = comp_textwidth(false);
+ int cols = comp_textwidth(false);
if (cols == 0) {
cols = 79;
}
@@ -362,11 +361,10 @@ void changed_bytes(linenr_T lnum, colnr_T col)
/// insert/delete bytes at column
///
/// Like changed_bytes() but also adjust extmark for "new" bytes.
-/// When "new" is negative text was deleted.
-static void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new)
+void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new)
{
if (curbuf_splice_pending == 0) {
- extmark_splice(curbuf, (int)lnum-1, col, 0, old, 0, new, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)lnum-1, col, old, new, kExtmarkUndo);
}
changed_bytes(lnum, col);
@@ -1597,7 +1595,7 @@ int open_line(
if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
|| curwin->w_p_diff) {
mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L,
- kExtmarkUndo);
+ kExtmarkNOOP);
}
did_append = true;
} else {
@@ -1611,6 +1609,7 @@ int open_line(
}
ml_replace(curwin->w_cursor.lnum, p_extra, true);
changed_bytes(curwin->w_cursor.lnum, 0);
+ // TODO(vigoux): extmark_splice_cols here??
curwin->w_cursor.lnum--;
did_append = false;
}
@@ -1676,6 +1675,16 @@ int open_line(
truncate_spaces(saved_line);
}
ml_replace(curwin->w_cursor.lnum, saved_line, false);
+
+ int new_len = (int)STRLEN(saved_line);
+
+ // TODO(vigoux): maybe there is issues there with expandtabs ?
+ if (new_len < curwin->w_cursor.col) {
+ extmark_splice_cols(
+ curbuf, (int)curwin->w_cursor.lnum,
+ new_len, curwin->w_cursor.col - new_len, 0, kExtmarkUndo);
+ }
+
saved_line = NULL;
if (did_append) {
changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
@@ -1691,8 +1700,9 @@ int open_line(
// Always move extmarks - Here we move only the line where the
// cursor is, the previous mark_adjust takes care of the lines after
int cols_added = mincol-1+less_cols_off-less_cols;
- extmark_splice(curbuf, (int)lnum-1, mincol-1, 0, less_cols_off,
- 1, cols_added, kExtmarkUndo);
+ extmark_splice(curbuf, (int)lnum-1, mincol-1,
+ 0, less_cols_off, less_cols_off,
+ 1, cols_added, 1 + cols_added, kExtmarkUndo);
} else {
changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
}
@@ -1704,8 +1714,10 @@ int open_line(
}
if (did_append) {
changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
- extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1,
- 0, 0, 0, 1, 0, kExtmarkUndo);
+ // bail out and just get the final lenght of the line we just manipulated
+ bcount_t extra = (bcount_t)STRLEN(ml_get(curwin->w_cursor.lnum));
+ extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1, 0,
+ 0, 0, 0, 1, 0, 1+extra, kExtmarkUndo);
}
curbuf_splice_pending--;
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index f9d5adbc12..fb158f377a 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -509,7 +509,7 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
-static char_u transchar_buf[11];
+static char_u transchar_charbuf[11];
/// Translate a character into a printable one, leaving printable ASCII intact
///
@@ -520,11 +520,17 @@ static char_u transchar_buf[11];
/// @return translated character into a static buffer.
char_u *transchar(int c)
{
+ return transchar_buf(curbuf, c);
+}
+
+char_u *transchar_buf(const buf_T *buf, int c)
+ FUNC_ATTR_NONNULL_ALL
+{
int i = 0;
if (IS_SPECIAL(c)) {
// special key code, display as ~@ char
- transchar_buf[0] = '~';
- transchar_buf[1] = '@';
+ transchar_charbuf[0] = '~';
+ transchar_charbuf[1] = '@';
i = 2;
c = K_SECOND(c);
}
@@ -532,14 +538,14 @@ char_u *transchar(int c)
if ((!chartab_initialized && (((c >= ' ') && (c <= '~'))))
|| ((c <= 0xFF) && vim_isprintc_strict(c))) {
// printable character
- transchar_buf[i] = (char_u)c;
- transchar_buf[i + 1] = NUL;
+ transchar_charbuf[i] = (char_u)c;
+ transchar_charbuf[i + 1] = NUL;
} else if (c <= 0xFF) {
- transchar_nonprint(transchar_buf + i, c);
+ transchar_nonprint(buf, transchar_charbuf + i, c);
} else {
- transchar_hex((char *)transchar_buf + i, c);
+ transchar_hex((char *)transchar_charbuf + i, c);
}
- return transchar_buf;
+ return transchar_charbuf;
}
/// Like transchar(), but called with a byte instead of a character
@@ -548,13 +554,13 @@ char_u *transchar(int c)
///
/// @param[in] c Byte to translate.
///
-/// @return pointer to translated character in transchar_buf.
+/// @return pointer to translated character in transchar_charbuf.
char_u *transchar_byte(const int c)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c >= 0x80) {
- transchar_nonprint(transchar_buf, c);
- return transchar_buf;
+ transchar_nonprint(curbuf, transchar_charbuf, c);
+ return transchar_charbuf;
}
return transchar(c);
}
@@ -563,16 +569,18 @@ char_u *transchar_byte(const int c)
///
/// @warning Does not work for multi-byte characters, c must be <= 255.
///
-/// @param[out] buf Buffer to store result in, must be able to hold at least
-/// 5 bytes (conversion result + NUL).
+/// @param[in] buf Required to check the file format
+/// @param[out] charbuf Buffer to store result in, must be able to hold
+/// at least 5 bytes (conversion result + NUL).
/// @param[in] c Character to convert. NUL is assumed to be NL according to
/// `:h NL-used-for-NUL`.
-void transchar_nonprint(char_u *buf, int c)
+void transchar_nonprint(const buf_T *buf, char_u *charbuf, int c)
+ FUNC_ATTR_NONNULL_ALL
{
if (c == NL) {
// we use newline in place of a NUL
c = NUL;
- } else if ((c == CAR) && (get_fileformat(curbuf) == EOL_MAC)) {
+ } else if ((c == CAR) && (get_fileformat(buf) == EOL_MAC)) {
// we use CR in place of NL in this case
c = NL;
}
@@ -580,14 +588,14 @@ void transchar_nonprint(char_u *buf, int c)
if (dy_flags & DY_UHEX || c > 0x7f) {
// 'display' has "uhex"
- transchar_hex((char *)buf, c);
+ transchar_hex((char *)charbuf, c);
} else {
// 0x00 - 0x1f and 0x7f
- buf[0] = '^';
+ charbuf[0] = '^';
// DEL displayed as ^?
- buf[1] = (char_u)(c ^ 0x40);
+ charbuf[1] = (char_u)(c ^ 0x40);
- buf[2] = NUL;
+ charbuf[2] = NUL;
}
}
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index 3f06340611..0d21080aa5 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -13,6 +13,10 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ui.h"
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "cursor_shape.c.generated.h"
+#endif
+
/// Handling of cursor and mouse pointer shapes in various modes.
cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{
@@ -77,7 +81,9 @@ Array mode_style_array(void)
return all;
}
-/// Parse the 'guicursor' option
+/// Parses the 'guicursor' option.
+///
+/// Clears `shape_table` if 'guicursor' is empty.
///
/// @param what SHAPE_CURSOR or SHAPE_MOUSE ('mouseshape')
///
@@ -99,11 +105,17 @@ char_u *parse_shape_opt(int what)
// First round: check for errors; second round: do it for real.
for (round = 1; round <= 2; round++) {
+ if (round == 2 || *p_guicursor == NUL) {
+ // Set all entries to default (block, blinkon0, default color).
+ // This is the default for anything that is not set.
+ clear_shape_table();
+ if (*p_guicursor == NUL) {
+ ui_mode_info_set();
+ return NULL;
+ }
+ }
// Repeat for all comma separated parts.
modep = p_guicursor;
- if (*p_guicursor == NUL) {
- modep = (char_u *)"a:block-blinkon0";
- }
while (modep != NULL && *modep != NUL) {
colonp = vim_strchr(modep, ':');
commap = vim_strchr(modep, ',');
@@ -144,14 +156,6 @@ char_u *parse_shape_opt(int what)
if (all_idx >= 0) {
idx = all_idx--;
- } else if (round == 2) {
- {
- // Set the defaults, for the missing parts
- shape_table[idx].shape = SHAPE_BLOCK;
- shape_table[idx].blinkwait = 0L;
- shape_table[idx].blinkon = 0L;
- shape_table[idx].blinkoff = 0L;
- }
}
/* Parse the part after the colon */
@@ -330,3 +334,16 @@ int cursor_get_mode_idx(void)
return SHAPE_IDX_N;
}
}
+
+/// Clears all entries in shape_table to block, blinkon0, and default color.
+static void clear_shape_table(void)
+{
+ for (int idx = 0; idx < SHAPE_IDX_COUNT; idx++) {
+ shape_table[idx].shape = SHAPE_BLOCK;
+ shape_table[idx].blinkwait = 0L;
+ shape_table[idx].blinkon = 0L;
+ shape_table[idx].blinkoff = 0L;
+ shape_table[idx].id = 0;
+ shape_table[idx].id_lm = 0;
+ }
+}
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 65d95ff158..dd32cef1e3 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -856,6 +856,7 @@ static digr_T digraphdefault[] =
{ '9', '"', 0x201f },
{ '/', '-', 0x2020 },
{ '/', '=', 0x2021 },
+ { 'o', 'o', 0x2022 },
{ '.', '.', 0x2025 },
{ ',', '.', 0x2026 },
{ '%', '0', 0x2030 },
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index ea38221dc7..ac0e6cc9f6 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1254,14 +1254,6 @@ check_pum:
normalchar:
// Insert a normal character.
- if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) {
- // Unmapped ALT/META chord behaves like ESC+c. #8213
- stuffcharReadbuff(ESC);
- stuffcharReadbuff(s->c);
- u_sync(false);
- break;
- }
-
if (!p_paste) {
// Trigger InsertCharPre.
char_u *str = do_insert_char_pre(s->c);
@@ -1919,10 +1911,10 @@ change_indent (
// TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
// something? does this even do the right text change then?
int delta = orig_col - new_col;
- extmark_splice(curbuf, curwin->w_cursor.lnum-1, new_col,
- 0, delta < 0 ? -delta : 0,
- 0, delta > 0 ? delta : 0,
- kExtmarkUndo);
+ extmark_splice_cols(curbuf, curwin->w_cursor.lnum-1, new_col,
+ delta < 0 ? -delta : 0,
+ delta > 0 ? delta : 0,
+ kExtmarkUndo);
}
}
@@ -4179,6 +4171,21 @@ static int ins_compl_get_exp(pos_T *ini)
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
// May change home directory back to "~".
tilde_replace(compl_pattern, num_matches, matches);
+#ifdef BACKSLASH_IN_FILENAME
+ if (curbuf->b_p_csl[0] != NUL) {
+ for (int i = 0; i < num_matches; i++) {
+ char_u *ptr = matches[i];
+ while (*ptr != NUL) {
+ if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
+ *ptr = '/';
+ } else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
+ *ptr = '\\';
+ }
+ ptr += utfc_ptr2len(ptr);
+ }
+ }
+ }
+#endif
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
}
break;
@@ -5557,13 +5564,11 @@ void insertchar(
int second_indent // indent for second line if >= 0
)
{
- int textwidth;
char_u *p;
- int fo_ins_blank;
int force_format = flags & INSCHAR_FORMAT;
- textwidth = comp_textwidth(force_format);
- fo_ins_blank = has_format_option(FO_INS_BLANK);
+ const int textwidth = comp_textwidth(force_format);
+ const bool fo_ins_blank = has_format_option(FO_INS_BLANK);
/*
* Try to break the line in two or more pieces when:
@@ -5764,10 +5769,11 @@ internal_format (
int cc;
int save_char = NUL;
bool haveto_redraw = false;
- int fo_ins_blank = has_format_option(FO_INS_BLANK);
- int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
- int fo_white_par = has_format_option(FO_WHITE_PAR);
- int first_line = TRUE;
+ const bool fo_ins_blank = has_format_option(FO_INS_BLANK);
+ const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK);
+ const bool fo_rigor_tw = has_format_option(FO_RIGOROUS_TW);
+ const bool fo_white_par = has_format_option(FO_WHITE_PAR);
+ bool first_line = true;
colnr_T leader_len;
bool no_leader = false;
int do_comments = (flags & INSCHAR_DO_COM);
@@ -5846,6 +5852,7 @@ internal_format (
curwin->w_cursor.col = startcol;
foundcol = 0;
+ int skip_pos = 0;
/*
* Find position to break at.
@@ -5915,7 +5922,11 @@ internal_format (
foundcol = curwin->w_cursor.col;
if (curwin->w_cursor.col <= (colnr_T)wantcol)
break;
- } else if (cc >= 0x100 && fo_multibyte) {
+ } else if ((cc >= 0x100 || !utf_allow_break_before(cc))
+ && fo_multibyte) {
+ int ncc;
+ bool allow_break;
+
// Break after or before a multi-byte character.
if (curwin->w_cursor.col != startcol) {
// Don't break until after the comment leader
@@ -5924,8 +5935,11 @@ internal_format (
}
col = curwin->w_cursor.col;
inc_cursor();
- // Don't change end_foundcol if already set.
- if (foundcol != curwin->w_cursor.col) {
+ ncc = gchar_cursor();
+ allow_break = utf_allow_break(cc, ncc);
+
+ // If we have already checked this position, skip!
+ if (curwin->w_cursor.col != skip_pos && allow_break) {
foundcol = curwin->w_cursor.col;
end_foundcol = foundcol;
if (curwin->w_cursor.col <= (colnr_T)wantcol)
@@ -5937,6 +5951,7 @@ internal_format (
if (curwin->w_cursor.col == 0)
break;
+ ncc = cc;
col = curwin->w_cursor.col;
dec_cursor();
@@ -5945,17 +5960,56 @@ internal_format (
if (WHITECHAR(cc)) {
continue; // break with space
}
- // Don't break until after the comment leader
+ // Don't break until after the comment leader.
if (curwin->w_cursor.col < leader_len) {
break;
}
curwin->w_cursor.col = col;
+ skip_pos = curwin->w_cursor.col;
- foundcol = curwin->w_cursor.col;
- end_foundcol = foundcol;
- if (curwin->w_cursor.col <= (colnr_T)wantcol)
- break;
+ allow_break = utf_allow_break(cc, ncc);
+
+ // Must handle this to respect line break prohibition.
+ if (allow_break) {
+ foundcol = curwin->w_cursor.col;
+ end_foundcol = foundcol;
+ }
+ if (curwin->w_cursor.col <= (colnr_T)wantcol) {
+ const bool ncc_allow_break = utf_allow_break_before(ncc);
+
+ if (allow_break) {
+ break;
+ }
+ if (!ncc_allow_break && !fo_rigor_tw) {
+ // Enable at most 1 punct hang outside of textwidth.
+ if (curwin->w_cursor.col == startcol) {
+ // We are inserting a non-breakable char, postpone
+ // line break check to next insert.
+ end_foundcol = foundcol = 0;
+ break;
+ }
+
+ // Neither cc nor ncc is NUL if we are here, so
+ // it's safe to inc_cursor.
+ col = curwin->w_cursor.col;
+
+ inc_cursor();
+ cc = ncc;
+ ncc = gchar_cursor();
+ // handle insert
+ ncc = (ncc != NUL) ? ncc : c;
+
+ allow_break = utf_allow_break(cc, ncc);
+
+ if (allow_break) {
+ // Break only when we are not at end of line.
+ end_foundcol = foundcol = ncc == NUL? 0 : curwin->w_cursor.col;
+ break;
+ }
+ curwin->w_cursor.col = col;
+ }
+ }
}
if (curwin->w_cursor.col == 0)
break;
@@ -6057,7 +6111,7 @@ internal_format (
}
}
}
- first_line = FALSE;
+ first_line = false;
}
if (State & VREPLACE_FLAG) {
@@ -6244,12 +6298,10 @@ static void check_auto_format(
* Set default to window width (maximum 79) for "gq" operator.
*/
int comp_textwidth(
- int ff // force formatting (for "gq" command)
+ bool ff // force formatting (for "gq" command)
)
{
- int textwidth;
-
- textwidth = curbuf->b_p_tw;
+ int textwidth = curbuf->b_p_tw;
if (textwidth == 0 && curbuf->b_p_wm) {
// The width is the window width minus 'wrapmargin' minus all the
// things that add to the margin.
@@ -7699,6 +7751,10 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
undisplay_dollar();
}
+ if (cmdchar != 'r' && cmdchar != 'v') {
+ ins_apply_autocmds(EVENT_INSERTLEAVEPRE);
+ }
+
// When an autoindent was removed, curswant stays after the
// indent
if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0cad5fd6c1..cccf1e50ff 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -736,7 +736,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
if (s == NULL || *s == NUL) {
return FAIL;
}
- if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
+ if (call_func(s, -1, rettv, argc, argv, NULL,
0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
return FAIL;
}
@@ -746,7 +746,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
if (s == NULL || *s == NUL) {
return FAIL;
}
- if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
+ if (call_func(s, -1, rettv, argc, argv, NULL,
0L, 0L, &dummy, true, partial, NULL) == FAIL) {
return FAIL;
}
@@ -760,7 +760,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
if (eval1_emsg(&s, rettv, true) == FAIL) {
return FAIL;
}
- if (*s != NUL) { // check for trailing chars after expr
+ if (*skipwhite(s) != NUL) { // check for trailing chars after expr
tv_clear(rettv);
emsgf(_(e_invexpr2), s);
return FAIL;
@@ -1679,7 +1679,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
arg = (const char *)find_name_end((char_u *)arg, NULL, NULL,
FNE_INCL_BR | FNE_CHECK_START);
if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) {
- emsg_severe = TRUE;
+ emsg_severe = true;
EMSG(_(e_trailing));
break;
}
@@ -1692,7 +1692,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
/* This is mainly to keep test 49 working: when expanding
* curly braces fails overrule the exception error message. */
if (len < 0 && !aborting()) {
- emsg_severe = TRUE;
+ emsg_severe = true;
EMSG2(_(e_invarg2), arg);
break;
}
@@ -2007,7 +2007,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
* expression evaluation has been cancelled due to an
* aborting error, an interrupt, or an exception. */
if (!aborting() && !quiet) {
- emsg_severe = TRUE;
+ emsg_severe = true;
EMSG2(_(e_invarg2), name);
return NULL;
}
@@ -2086,6 +2086,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
tv_clear(&var1);
return NULL;
}
+ p = skipwhite(p);
}
// Optionally get the second index [ :expr].
@@ -2674,6 +2675,7 @@ void ex_lockvar(exarg_T *eap)
static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep)
{
char_u *arg = argstart;
+ char_u *name_end;
bool error = false;
lval_T lv;
@@ -2686,43 +2688,43 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep)
return;
}
os_unsetenv(name);
- arg = skipwhite(arg);
- continue;
- }
-
- // Parse the name and find the end.
- char_u *const name_end = (char_u *)get_lval(arg, NULL, &lv, true,
- eap->skip || error,
- 0, FNE_CHECK_START);
- if (lv.ll_name == NULL) {
- error = true; // error, but continue parsing.
- }
- if (name_end == NULL || (!ascii_iswhite(*name_end)
- && !ends_excmd(*name_end))) {
- if (name_end != NULL) {
- emsg_severe = TRUE;
- EMSG(_(e_trailing));
+ name_end = arg;
+ } else {
+ // Parse the name and find the end.
+ name_end = get_lval(arg, NULL, &lv, true, eap->skip || error,
+ 0, FNE_CHECK_START);
+ if (lv.ll_name == NULL) {
+ error = true; // error, but continue parsing.
+ }
+ if (name_end == NULL
+ || (!ascii_iswhite(*name_end) && !ends_excmd(*name_end))) {
+ if (name_end != NULL) {
+ emsg_severe = true;
+ EMSG(_(e_trailing));
+ }
+ if (!(eap->skip || error)) {
+ clear_lval(&lv);
+ }
+ break;
}
- if (!(eap->skip || error))
- clear_lval(&lv);
- break;
- }
- if (!error && !eap->skip) {
- if (eap->cmdidx == CMD_unlet) {
- if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL)
- error = TRUE;
- } else {
- if (do_lock_var(&lv, name_end, deep,
- eap->cmdidx == CMD_lockvar) == FAIL) {
- error = true;
+ if (!error && !eap->skip) {
+ if (eap->cmdidx == CMD_unlet) {
+ if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL) {
+ error = true;
+ }
+ } else {
+ if (do_lock_var(&lv, name_end, deep,
+ eap->cmdidx == CMD_lockvar) == FAIL) {
+ error = true;
+ }
}
}
- }
-
- if (!eap->skip)
- clear_lval(&lv);
+ if (!eap->skip) {
+ clear_lval(&lv);
+ }
+ }
arg = skipwhite(name_end);
} while (!ends_excmd(*arg));
@@ -2992,7 +2994,6 @@ char_u *get_user_var_name(expand_T *xp, int idx)
static size_t tdone;
static size_t vidx;
static hashitem_T *hi;
- hashtab_T *ht;
if (idx == 0) {
gdone = bdone = wdone = vidx = 0;
@@ -3013,7 +3014,10 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// b: variables
- ht = &curbuf->b_vars->dv_hashtab;
+ // In cmdwin, the alternative buffer should be used.
+ hashtab_T *ht = (cmdwin_type != 0 && get_cmdline_type() == NUL)
+ ? &prevwin->w_buffer->b_vars->dv_hashtab
+ : &curbuf->b_vars->dv_hashtab;
if (bdone < ht->ht_used) {
if (bdone++ == 0)
hi = ht->ht_array;
@@ -3025,7 +3029,10 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// w: variables
- ht = &curwin->w_vars->dv_hashtab;
+ // In cmdwin, the alternative window should be used.
+ ht = (cmdwin_type != 0 && get_cmdline_type() == NUL)
+ ? &prevwin->w_vars->dv_hashtab
+ : &curwin->w_vars->dv_hashtab;
if (wdone < ht->ht_used) {
if (wdone++ == 0)
hi = ht->ht_array;
@@ -3800,8 +3807,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
*/
for (;; ) {
op = **arg;
- if (op != '*' && op != '/' && op != '%')
+ if (op != '*' && op != '/' && op != '%') {
break;
+ }
if (evaluate) {
if (rettv->v_type == VAR_FLOAT) {
@@ -3903,6 +3911,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
// (expression) nested expression
// [expr, expr] List
// {key: val, key: val} Dictionary
+// #{key: val, key: val} Dictionary with literal keys
//
// Also handle:
// ! in front logical NOT
@@ -4010,11 +4019,21 @@ static int eval7(
case '[': ret = get_list_tv(arg, rettv, evaluate);
break;
+ // Dictionary: #{key: val, key: val}
+ case '#':
+ if ((*arg)[1] == '{') {
+ (*arg)++;
+ ret = dict_get_tv(arg, rettv, evaluate, true);
+ } else {
+ ret = NOTDONE;
+ }
+ break;
+
// Lambda: {arg, arg -> expr}
- // Dictionary: {key: val, key: val}
+ // Dictionary: {'key': val, 'key': val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = dict_get_tv(arg, rettv, evaluate);
+ ret = dict_get_tv(arg, rettv, evaluate, false);
}
break;
@@ -4516,7 +4535,6 @@ int get_option_tv(const char **const arg, typval_T *const rettv,
static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
{
char_u *p;
- char_u *name;
unsigned int extra = 0;
/*
@@ -4524,11 +4542,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
*/
for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) {
if (*p == '\\' && p[1] != NUL) {
- ++p;
- /* A "\<x>" form occupies at least 4 characters, and produces up
- * to 6 characters: reserve space for 2 extra */
- if (*p == '<')
- extra += 2;
+ p++;
+ // A "\<x>" form occupies at least 4 characters, and produces up
+ // to 21 characters (3 * 6 for the char and 3 for a modifier):
+ // reserve space for 18 extra.
+ // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x.
+ if (*p == '<') {
+ extra += 18;
+ }
}
}
@@ -4547,7 +4568,8 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
* Copy the string into allocated memory, handling backslashed
* characters.
*/
- name = xmalloc(p - *arg + extra);
+ const int len = (int)(p - *arg + extra);
+ char_u *name = xmalloc(len);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = name;
@@ -4614,6 +4636,9 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true);
if (extra != 0) {
name += extra;
+ if (name >= rettv->vval.v_string + len) {
+ iemsg("get_string_tv() used more space than allocated");
+ }
break;
}
FALLTHROUGH;
@@ -5339,11 +5364,31 @@ static inline bool set_ref_dict(dict_T *dict, int copyID)
return false;
}
-/*
- * Allocate a variable for a Dictionary and fill it from "*arg".
- * Return OK or FAIL. Returns NOTDONE for {expr}.
- */
-static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
+
+// Get the key for *{key: val} into "tv" and advance "arg".
+// Return FAIL when there is no valid key.
+static int get_literal_key(char_u **arg, typval_T *tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *p;
+
+ if (!ASCII_ISALNUM(**arg) && **arg != '_' && **arg != '-') {
+ return FAIL;
+ }
+ for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {
+ }
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = vim_strnsave(*arg, (int)(p - *arg));
+
+ *arg = skipwhite(p);
+ return OK;
+}
+
+// Allocate a variable for a Dictionary and fill it from "*arg".
+// "literal" is true for *{key: val}
+// Return OK or FAIL. Returns NOTDONE for {expr}.
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate,
+ bool literal)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -5364,7 +5409,7 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
if (eval1(&start, &tv, false) == FAIL) { // recursive!
return FAIL;
}
- if (*start == '}') {
+ if (*skipwhite(start) == '}') {
return NOTDONE;
}
}
@@ -5377,7 +5422,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
*arg = skipwhite(*arg + 1);
while (**arg != '}' && **arg != NUL) {
- if (eval1(arg, &tvkey, evaluate) == FAIL) { // recursive!
+ if ((literal
+ ? get_literal_key(arg, &tvkey)
+ : eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive!
goto failret;
}
if (**arg != ':') {
@@ -6960,9 +7007,10 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append,
if (!append && lnum <= curbuf->b_ml.ml_line_count) {
// Existing line, replace it.
+ int old_len = (int)STRLEN(ml_get(lnum));
if (u_savesub(lnum) == OK
&& ml_replace(lnum, (char_u *)line, true) == OK) {
- changed_bytes(lnum, 0);
+ inserted_bytes(lnum, 0, old_len, STRLEN(line));
if (is_curbuf && lnum == curwin->w_cursor.lnum) {
check_cursor_col();
}
@@ -7073,7 +7121,7 @@ void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
do {
size_t dir_len;
const char *dir;
- iter = vim_env_iter(':', dirs, iter, &dir, &dir_len);
+ iter = vim_env_iter(ENV_SEPCHAR, dirs, iter, &dir, &dir_len);
if (dir != NULL && dir_len > 0) {
char *dir_with_nvim = xmemdupz(dir, dir_len);
dir_with_nvim = concat_fnames_realloc(dir_with_nvim, "nvim", true);
@@ -7261,7 +7309,7 @@ bool callback_call(Callback *const callback, const int argcount_in,
}
int dummy;
- return call_func(name, (int)STRLEN(name), rettv, argcount_in, argvars_in,
+ return call_func(name, -1, rettv, argcount_in, argvars_in,
NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
true, partial, NULL);
}
@@ -8483,7 +8531,7 @@ handle_subscript(
} else {
s = (char_u *)"";
}
- ret = get_func_tv(s, lua ? slen : (int)STRLEN(s), rettv, (char_u **)arg,
+ ret = get_func_tv(s, lua ? slen : -1, rettv, (char_u **)arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, pt, selfdict);
@@ -9044,7 +9092,7 @@ static void set_var_const(const char *name, const size_t name_len,
}
if (is_const) {
- v->di_tv.v_lock |= VAR_LOCKED;
+ tv_item_lock(&v->di_tv, 1, true);
}
}
@@ -10381,10 +10429,13 @@ void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
list_T *args = tv_list_alloc(1);
tv_list_append_string(args, (const char *)argvars[0].vval.v_string, -1);
- *rettv = eval_call_provider(name, "eval", args);
+ *rettv = eval_call_provider(name, "eval", args, false);
}
-typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
+/// @param discard Clears the value returned by the provider and returns
+/// an empty typval_T.
+typval_T eval_call_provider(char *provider, char *method, list_T *arguments,
+ bool discard)
{
if (!eval_has_provider(provider)) {
emsgf("E319: No \"%s\" provider found. Run \":checkhealth provider\"",
@@ -10443,6 +10494,10 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
provider_call_nesting--;
assert(provider_call_nesting >= 0);
+ if (discard) {
+ tv_clear(&rettv);
+ }
+
return rettv;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 023c60f118..6c316bb1fe 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -191,6 +191,7 @@ return {
inputsave={},
inputsecret={args={1, 2}},
insert={args={2, 3}},
+ interrupt={args=0},
invert={args=1},
isdirectory={args=1},
isinf={args=1},
@@ -255,6 +256,7 @@ return {
py3eval={args=1},
pyeval={args=1},
pyxeval={args=1},
+ perleval={args=1},
range={args={1, 3}},
readdir={args={1, 2}},
readfile={args={1, 3}},
@@ -273,6 +275,7 @@ return {
rpcrequest={args=varargs(2)},
rpcstart={args={1, 2}},
rpcstop={args=1},
+ rubyeval={args=1},
screenattr={args=2},
screenchar={args=2},
screencol={},
@@ -335,7 +338,7 @@ return {
stridx={args={2, 3}},
string={args=1},
strlen={args=1},
- strpart={args={2, 3}},
+ strpart={args={2, 4}},
strridx={args={2, 3}},
strtrans={args=1},
strwidth={args=1},
@@ -369,7 +372,7 @@ return {
tolower={args=1},
toupper={args=1},
tr={args=3},
- trim={args={1,2}},
+ trim={args={1,3}},
trunc={args=1, func="float_op_wrapper", data="&trunc"},
type={args=1},
undofile={args=1},
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index daba304f00..638fef331a 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -586,7 +586,7 @@ parse_json_number_check:
if (p == ints) {
emsgf(_("E474: Missing number after minus sign: %.*s"), LENP(s, e));
goto parse_json_number_fail;
- } else if (p == fracs || exps_s == fracs + 1) {
+ } else if (p == fracs || (fracs != NULL && exps_s == fracs + 1)) {
emsgf(_("E474: Missing number after decimal dot: %.*s"), LENP(s, e));
goto parse_json_number_fail;
} else if (p == exps) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1a80d4d4bd..83ef9c8762 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -32,6 +32,7 @@
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
#include "nvim/mark.h"
#include "nvim/math.h"
#include "nvim/memline.h"
@@ -86,8 +87,10 @@ KHASH_MAP_INIT_STR(functions, VimLFuncDef)
#endif
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
+PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
#include "funcs.generated.h"
PRAGMA_DIAG_POP
+PRAGMA_DIAG_POP
#endif
@@ -2068,6 +2071,12 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
expand_T xpc;
bool error = false;
char_u *result;
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *p_csl_save = p_csl;
+
+ // avoid using 'completeslash' here
+ p_csl = empty_option;
+#endif
rettv->v_type = VAR_STRING;
if (argvars[1].v_type != VAR_UNKNOWN
@@ -2120,6 +2129,9 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = NULL;
}
}
+#ifdef BACKSLASH_IN_FILENAME
+ p_csl = p_csl_save;
+#endif
}
@@ -2407,9 +2419,9 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
float_T f;
if (tv_get_float_chk(argvars, &f)) {
- if (f <= -VARNUMBER_MAX + DBL_EPSILON) {
+ if (f <= (float_T)-VARNUMBER_MAX + DBL_EPSILON) {
rettv->vval.v_number = -VARNUMBER_MAX;
- } else if (f >= VARNUMBER_MAX - DBL_EPSILON) {
+ } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
rettv->vval.v_number = VARNUMBER_MAX;
} else {
rettv->vval.v_number = (varnumber_T)f;
@@ -2581,8 +2593,6 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u *text;
char_u buf[FOLD_TEXT_LEN];
- foldinfo_T foldinfo;
- int fold_count;
static bool entered = false;
rettv->v_type = VAR_STRING;
@@ -2596,9 +2606,10 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (lnum < 0) {
lnum = 0;
}
- fold_count = foldedCount(curwin, lnum, &foldinfo);
- if (fold_count > 0) {
- text = get_foldtext(curwin, lnum, lnum + fold_count - 1, &foldinfo, buf);
+
+ foldinfo_T info = fold_info(curwin, lnum);
+ if (info.fi_lines > 0) {
+ text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf);
if (text == buf) {
text = vim_strsave(text);
}
@@ -4005,7 +4016,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "globpath()" function
static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int flags = 0; // Flags for globpath.
+ int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath.
bool error = false;
// Return a string, or a list if the optional third argument is non-zero.
@@ -4717,6 +4728,14 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "interrupt()" function
+static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED,
+ typval_T *rettv FUNC_ATTR_UNUSED,
+ FunPtr fptr FUNC_ATTR_UNUSED)
+{
+ got_int = true;
+}
+
/*
* "invert(expr)" function
*/
@@ -5471,7 +5490,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv);
+ nlua_typval_eval(cstr_as_string((char *)str), &argvars[1], rettv);
}
/*
@@ -6363,6 +6382,20 @@ static void f_pyxeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+///
+/// "perleval()" function
+///
+static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ script_host_eval("perl", argvars, rettv);
+}
+
+// "rubyeval()" function
+static void f_rubyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ script_host_eval("ruby", argvars, rettv);
+}
+
/*
* "range()" function
*/
@@ -6918,7 +6951,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ptrdiff_t len = (ptrdiff_t)strlen(p);
- if (len > 0 && after_pathsep(p, p + len)) {
+ if (len > 1 && after_pathsep(p, p + len)) {
has_trailing_pathsep = true;
p[len - 1] = NUL; // The trailing slash breaks readlink().
}
@@ -7650,7 +7683,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
retval = do_searchpair(
- (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip,
+ spat, mpat, epat, dir, skip,
flags, match_pos, lnum_stop, time_limit);
theend:
@@ -7694,9 +7727,9 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
long
do_searchpair(
- char_u *spat, // start pattern
- char_u *mpat, // middle pattern
- char_u *epat, // end pattern
+ const char *spat, // start pattern
+ const char *mpat, // middle pattern
+ const char *epat, // end pattern
int dir, // BACKWARD or FORWARD
const typval_T *skip, // skip expression
int flags, // SP_SETPCMARK and other SP_ values
@@ -7704,6 +7737,7 @@ do_searchpair(
linenr_T lnum_stop, // stop at this line if not zero
long time_limit // stop after this many msec
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
char_u *save_cpo;
char_u *pat, *pat2 = NULL, *pat3 = NULL;
@@ -7718,8 +7752,6 @@ do_searchpair(
bool use_skip = false;
int options = SEARCH_KEEP;
proftime_T tm;
- size_t pat2_len;
- size_t pat3_len;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo;
@@ -7730,9 +7762,9 @@ do_searchpair(
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
- pat2_len = STRLEN(spat) + STRLEN(epat) + 17;
+ const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
pat2 = xmalloc(pat2_len);
- pat3_len = STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25;
+ const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
pat3 = xmalloc(pat3_len);
snprintf((char *)pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
if (*mpat == NUL) {
@@ -8124,15 +8156,17 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Create quickfix/location list from VimL values
///
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
-/// list_arg, action_arg and what_arg arguments in which case errors out,
-/// including VAR_UNKNOWN parameters.
+/// args argument in which case errors out, including VAR_UNKNOWN parameters.
///
/// @param[in,out] wp Window to create location list for. May be NULL in
/// which case quickfix list will be created.
-/// @param[in] list_arg Quickfix list contents.
-/// @param[in] action_arg Action to perform: append to an existing list,
-/// replace its content or create a new one.
-/// @param[in] title_arg New list title. Defaults to caller function name.
+/// @param[in] args [list, action, what]
+/// @param[in] args[0] Quickfix list contents.
+/// @param[in] args[1] Optional. Action to perform:
+/// append to an existing list, replace its content,
+/// or create a new one.
+/// @param[in] args[2] Optional. Quickfix list properties or title.
+/// Defaults to caller function name.
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(2, 3)
@@ -8142,7 +8176,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
int action = ' ';
static int recursive = 0;
rettv->vval.v_number = -1;
- dict_T *d = NULL;
+ dict_T *what = NULL;
typval_T *list_arg = &args[0];
if (list_arg->v_type != VAR_LIST) {
@@ -8170,18 +8204,18 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
return;
}
- typval_T *title_arg = &args[2];
- if (title_arg->v_type == VAR_UNKNOWN) {
+ typval_T *const what_arg = &args[2];
+ if (what_arg->v_type == VAR_UNKNOWN) {
// Option argument was not given.
goto skip_args;
- } else if (title_arg->v_type == VAR_STRING) {
- title = tv_get_string_chk(title_arg);
+ } else if (what_arg->v_type == VAR_STRING) {
+ title = tv_get_string_chk(what_arg);
if (!title) {
// Type error. Error already printed by tv_get_string_chk().
return;
}
- } else if (title_arg->v_type == VAR_DICT) {
- d = title_arg->vval.v_dict;
+ } else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) {
+ what = what_arg->vval.v_dict;
} else {
EMSG(_(e_dictreq));
return;
@@ -8194,7 +8228,7 @@ skip_args:
recursive++;
list_T *const l = list_arg->vval.v_list;
- if (set_errorlist(wp, l, action, (char_u *)title, d) == OK) {
+ if (set_errorlist(wp, l, action, (char_u *)title, what) == OK) {
rettv->vval.v_number = 0;
}
recursive--;
@@ -9156,7 +9190,7 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
res = call_func((const char_u *)func_name,
- (int)STRLEN(func_name),
+ -1,
&rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
partial, sortinfo->item_compare_selfdict);
tv_clear(&argv[0]);
@@ -9938,6 +9972,16 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
len = slen - n;
}
+ if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) {
+ int off;
+
+ // length in characters
+ for (off = n; off < (int)slen && len > 0; len--) {
+ off += utfc_ptr2len((char_u *)p + off);
+ }
+ len = off - n;
+ }
+
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
}
@@ -10796,52 +10840,72 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char_u *prev;
const char_u *p;
int c1;
+ int dir = 0;
rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
if (head == NULL) {
- rettv->vval.v_string = NULL;
return;
}
if (argvars[1].v_type == VAR_STRING) {
mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+ // leading or trailing characters to trim
+ dir = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (dir < 0 || dir > 2) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
}
- while (*head != NUL) {
- c1 = PTR2CHAR(head);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ if (dir == 0 || dir == 1) {
+ // Trim leading characters
+ while (*head != NUL) {
+ c1 = PTR2CHAR(head);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
}
- if (*p == NUL) {
- break;
- }
+ MB_PTR_ADV(head);
}
- MB_PTR_ADV(head);
}
- for (tail = head + STRLEN(head); tail > head; tail = prev) {
- prev = tail;
- MB_PTR_BACK(head, prev);
- c1 = PTR2CHAR(prev);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ tail = head + STRLEN(head);
+ if (dir == 0 || dir == 2) {
+ // Trim trailing characters
+ for (; tail > head; tail = prev) {
+ prev = tail;
+ MB_PTR_BACK(head, prev);
+ c1 = PTR2CHAR(prev);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
- }
- if (*p == NUL) {
- break;
}
}
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 229f0e8dde..dc94bc698d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -32,7 +32,11 @@
#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
#define FC_SANDBOX 0x40 // function defined in the sandbox
-#define FC_CFUNC 0x80 // C function extension
+#define FC_DEAD 0x80 // function kept only for reference to dfunc
+#define FC_EXPORT 0x100 // "export def Func()"
+#define FC_NOARGS 0x200 // no a: variables in lambda
+#define FC_VIM9 0x400 // defined in vim9 script file
+#define FC_CFUNC 0x800 // C function extension
#ifdef INCLUDE_GENERATED_DECLARATIONS
#include "eval/userfunc.c.generated.h"
@@ -246,6 +250,10 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
STRLCPY(p + 7, s, e - s + 1);
+ if (strstr((char *)p + 7, "a:") == NULL) {
+ // No a: variables are used for sure.
+ flags |= FC_NOARGS;
+ }
fp->uf_refcount = 1;
STRCPY(fp->uf_name, name);
@@ -367,7 +375,7 @@ void emsg_funcname(char *ermsg, const char_u *name)
int
get_func_tv(
const char_u *name, // name of the function
- int len, // length of "name"
+ int len, // length of "name" or -1 to use strlen()
typval_T *rettv,
char_u **arg, // argument, pointing to the '('
linenr_T firstline, // first line of range
@@ -813,17 +821,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
current_funccal = fc;
fc->func = fp;
fc->rettv = rettv;
- rettv->vval.v_number = 0;
- fc->linenr = 0;
- fc->returned = FALSE;
fc->level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0);
fc->dbg_tick = debug_tick;
// Set up fields for closure.
- fc->fc_refcount = 0;
- fc->fc_copyID = 0;
ga_init(&fc->fc_funcs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
@@ -853,37 +856,42 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
++selfdict->dv_refcount;
}
- /*
- * Init a: variables.
- * Set a:0 to "argcount".
- * Set a:000 to a list with room for the "..." arguments.
- */
+ // Init a: variables, unless none found (in lambda).
+ // Set a:0 to "argcount".
+ // Set a:000 to a list with room for the "..." arguments.
init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
- (varnumber_T)(argcount - fp->uf_args.ga_len));
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
+ (varnumber_T)(argcount - fp->uf_args.ga_len));
+ }
fc->l_avars.dv_lock = VAR_FIXED;
- // Use "name" to avoid a warning from some compiler that checks the
- // destination size.
- v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ // Use "name" to avoid a warning from some compiler that checks the
+ // destination size.
+ v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
#ifndef __clang_analyzer__
- name = v->di_key;
- STRCPY(name, "000");
+ name = v->di_key;
+ STRCPY(name, "000");
#endif
- v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_avars, v);
- v->di_tv.v_type = VAR_LIST;
- v->di_tv.v_lock = VAR_FIXED;
- v->di_tv.vval.v_list = &fc->l_varlist;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ tv_dict_add(&fc->l_avars, v);
+ v->di_tv.v_type = VAR_LIST;
+ v->di_tv.v_lock = VAR_FIXED;
+ v->di_tv.vval.v_list = &fc->l_varlist;
+ }
tv_list_init_static(&fc->l_varlist);
tv_list_set_lock(&fc->l_varlist, VAR_FIXED);
// Set a:firstline to "firstline" and a:lastline to "lastline".
// Set a:name to named arguments.
// Set a:N to the "..." arguments.
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
- "firstline", (varnumber_T)firstline);
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
- "lastline", (varnumber_T)lastline);
+ // Skipped when no a: variables used (in lambda).
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "firstline", (varnumber_T)firstline);
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "lastline", (varnumber_T)lastline);
+ }
for (int i = 0; i < argcount; i++) {
bool addlocal = false;
@@ -895,6 +903,10 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
addlocal = true;
}
} else {
+ if ((fp->uf_flags & FC_NOARGS) != 0) {
+ // Bail out if no a: arguments used (in lambda).
+ break;
+ }
// "..." argument a:1, a:2, etc.
snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1);
name = numbuf;
@@ -1034,9 +1046,19 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
save_did_emsg = did_emsg;
did_emsg = FALSE;
- // call do_cmdline() to execute the lines
- do_cmdline(NULL, get_func_line, (void *)fc,
- DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ if (islambda) {
+ char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
+
+ // A Lambda always has the command "return {expr}". It is much faster
+ // to evaluate {expr} directly.
+ ex_nesting_level++;
+ (void)eval1(&p, rettv, true);
+ ex_nesting_level--;
+ } else {
+ // call do_cmdline() to execute the lines
+ do_cmdline(NULL, get_func_line, (void *)fc,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ }
--RedrawingDisabled;
@@ -1291,7 +1313,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
tv_copy(TV_LIST_ITEM_TV(item), &argv[argc++]);
});
- r = call_func(name, (int)STRLEN(name), rettv, argc, argv, NULL,
+ r = call_func(name, -1, rettv, argc, argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&dummy, true, partial, selfdict);
@@ -1304,6 +1326,36 @@ func_call_skip_call:
return r;
}
+// Give an error message for the result of a function.
+// Nothing if "error" is FCERR_NONE.
+static void user_func_error(int error, const char_u *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ switch (error) {
+ case ERROR_UNKNOWN:
+ emsg_funcname(N_("E117: Unknown function: %s"), name);
+ break;
+ case ERROR_DELETED:
+ emsg_funcname(N_("E933: Function was deleted: %s"), name);
+ break;
+ case ERROR_TOOMANY:
+ emsg_funcname(_(e_toomanyarg), name);
+ break;
+ case ERROR_TOOFEW:
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"),
+ name);
+ break;
+ case ERROR_SCRIPT:
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
+ name);
+ break;
+ case ERROR_DICT:
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
+ name);
+ break;
+ }
+}
+
/// Call a function with its resolved parameters
///
/// "argv_func", when not NULL, can be used to fill in arguments only when the
@@ -1316,7 +1368,7 @@ func_call_skip_call:
int
call_func(
const char_u *funcname, // name of the function
- int len, // length of "name"
+ int len, // length of "name" or -1 to use strlen()
typval_T *rettv, // [out] value goes here
int argcount_in, // number of "argvars"
typval_T *argvars_in, // vars for arguments, must have "argcount"
@@ -1333,11 +1385,11 @@ call_func(
{
int ret = FAIL;
int error = ERROR_NONE;
- ufunc_T *fp;
+ ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
- char_u *fname;
- char_u *name;
+ char_u *fname = NULL;
+ char_u *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
dict_T *selfdict = selfdict_in;
@@ -1348,11 +1400,18 @@ call_func(
// even when call_func() returns FAIL.
rettv->v_type = VAR_UNKNOWN;
- // Make a copy of the name, if it comes from a funcref variable it could
- // be changed or deleted in the called function.
- name = vim_strnsave(funcname, len);
-
- fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ if (len <= 0) {
+ len = (int)STRLEN(funcname);
+ }
+ if (partial != NULL) {
+ fp = partial->pt_func;
+ }
+ if (fp == NULL) {
+ // Make a copy of the name, if it comes from a funcref variable it could
+ // be changed or deleted in the called function.
+ name = vim_strnsave(funcname, len);
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ }
*doesrange = false;
@@ -1384,7 +1443,7 @@ call_func(
char_u *rfname = fname;
// Ignore "g:" before a function name.
- if (fname[0] == 'g' && fname[1] == ':') {
+ if (fp == NULL && fname[0] == 'g' && fname[1] == ':') {
rfname = fname + 2;
}
@@ -1395,14 +1454,11 @@ call_func(
if (is_luafunc(partial)) {
if (len > 0) {
error = ERROR_NONE;
- executor_call_lua((const char *)funcname, len,
- argvars, argcount, rettv);
+ nlua_typval_call((const char *)funcname, len, argvars, argcount, rettv);
}
- } else if (!builtin_function((const char *)rfname, -1)) {
+ } else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
- if (partial != NULL && partial->pt_func != NULL) {
- fp = partial->pt_func;
- } else {
+ if (fp == NULL) {
fp = find_func(rfname);
}
@@ -1481,29 +1537,7 @@ theend:
// Report an error unless the argument evaluation or function call has been
// cancelled due to an aborting error, an interrupt, or an exception.
if (!aborting()) {
- switch (error) {
- case ERROR_UNKNOWN:
- emsg_funcname(N_("E117: Unknown function: %s"), name);
- break;
- case ERROR_DELETED:
- emsg_funcname(N_("E933: Function was deleted: %s"), name);
- break;
- case ERROR_TOOMANY:
- emsg_funcname(_(e_toomanyarg), name);
- break;
- case ERROR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"),
- name);
- break;
- case ERROR_SCRIPT:
- emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
- name);
- break;
- case ERROR_DICT:
- emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
- name);
- break;
- }
+ user_func_error(error, (name != NULL) ? name : funcname);
}
while (argv_clear > 0) {
@@ -2854,7 +2888,7 @@ void ex_call(exarg_T *eap)
curwin->w_cursor.coladd = 0;
}
arg = startarg;
- if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
+ if (get_func_tv(name, -1, &rettv, &arg,
eap->line1, eap->line2, &doesrange,
true, partial, fudi.fd_dict) == FAIL) {
failed = true;
@@ -2886,8 +2920,10 @@ void ex_call(exarg_T *eap)
if (!failed || eap->cstack->cs_trylevel > 0) {
// Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
- emsg_severe = TRUE;
- EMSG(_(e_trailing));
+ if (!failed) {
+ emsg_severe = true;
+ EMSG(_(e_trailing));
+ }
} else {
eap->nextcmd = check_nextcmd(arg);
}
@@ -3348,9 +3384,13 @@ bool set_ref_in_previous_funccal(int copyID)
{
bool abort = false;
- for (funccall_T *fc = previous_funccal; fc != NULL; fc = fc->caller) {
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL);
+ for (funccall_T *fc = previous_funccal; !abort && fc != NULL;
+ fc = fc->caller) {
+ fc->fc_copyID = copyID + 1;
+ abort = abort
+ || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL);
}
return abort;
}
@@ -3361,9 +3401,11 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
if (fc->fc_copyID != copyID) {
fc->fc_copyID = copyID;
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
- abort = abort || set_ref_in_func(NULL, fc->func, copyID);
+ abort = abort
+ || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID, NULL)
+ || set_ref_in_func(NULL, fc->func, copyID);
}
return abort;
}
@@ -3373,12 +3415,13 @@ bool set_ref_in_call_stack(int copyID)
{
bool abort = false;
- for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->caller) {
+ for (funccall_T *fc = current_funccal; !abort && fc != NULL;
+ fc = fc->caller) {
abort = abort || set_ref_in_funccal(fc, copyID);
}
// Also go through the funccal_stack.
- for (funccal_entry_T *entry = funccal_stack; entry != NULL;
+ for (funccal_entry_T *entry = funccal_stack; !abort && entry != NULL;
entry = entry->next) {
for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL;
fc = fc->caller) {
@@ -3457,12 +3500,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
{
char_u *name = get_lambda_name();
- ufunc_T *fp = NULL;
-
- fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
- if (fp == NULL) {
- return NULL;
- }
+ ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
fp->uf_refcount = 1;
fp->uf_varargs = true;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 519978f4fb..3669cbbd2d 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -135,7 +135,7 @@ void do_ascii(const exarg_T *const eap)
char buf1[20];
if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) {
char_u buf3[7];
- transchar_nonprint(buf3, c);
+ transchar_nonprint(curbuf, buf3, c);
vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
} else {
buf1[0] = NUL;
@@ -326,14 +326,19 @@ static int linelen(int *has_tab)
int save;
int len;
- /* find the first non-blank character */
+ // Get the line. If it's empty bail out early (could be the empty string
+ // for an unloaded buffer).
line = get_cursor_line_ptr();
+ if (*line == NUL) {
+ return 0;
+ }
+ // find the first non-blank character
first = skipwhite(line);
- /* find the character after the last non-blank character */
+ // find the character after the last non-blank character
for (last = first + STRLEN(first);
- last > first && ascii_iswhite(last[-1]); --last)
- ;
+ last > first && ascii_iswhite(last[-1]); last--) {
+ }
save = *last;
*last = NUL;
// Get line length.
@@ -846,6 +851,11 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
return OK;
}
+ bcount_t start_byte = ml_find_line_or_offset(curbuf, line1, NULL, true);
+ bcount_t end_byte = ml_find_line_or_offset(curbuf, line2+1, NULL, true);
+ bcount_t extent_byte = end_byte-start_byte;
+ bcount_t dest_byte = ml_find_line_or_offset(curbuf, dest+1, NULL, true);
+
num_lines = line2 - line1 + 1;
/*
@@ -880,6 +890,8 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
last_line = curbuf->b_ml.ml_line_count;
mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP);
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
+ int line_off = 0;
+ bcount_t byte_off = 0;
if (dest >= line2) {
mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, kExtmarkNOOP);
FOR_ALL_TAB_WINDOWS(tab, win) {
@@ -889,6 +901,8 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
}
curbuf->b_op_start.lnum = dest - num_lines + 1;
curbuf->b_op_end.lnum = dest;
+ line_off = -num_lines;
+ byte_off = -extent_byte;
} else {
mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, kExtmarkNOOP);
FOR_ALL_TAB_WINDOWS(tab, win) {
@@ -904,11 +918,10 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
-(last_line - dest - extra), 0L, kExtmarkNOOP);
// extmarks are handled separately
- int size = line2-line1+1;
- int off = dest >= line2 ? -size : 0;
- extmark_move_region(curbuf, line1-1, 0,
- line2-line1+1, 0,
- dest+off, 0, kExtmarkUndo);
+ extmark_move_region(curbuf, line1-1, 0, start_byte,
+ line2-line1+1, 0, extent_byte,
+ dest+line_off, 0, dest_byte+byte_off,
+ kExtmarkUndo);
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
@@ -2227,11 +2240,9 @@ int do_ecmd(
goto theend;
}
- /*
- * if the file was changed we may not be allowed to abandon it
- * - if we are going to re-edit the same file
- * - or if we are the only window on this file and if ECMD_HIDE is FALSE
- */
+ // If the file was changed we may not be allowed to abandon it:
+ // - if we are going to re-edit the same file
+ // - or if we are the only window on this file and if ECMD_HIDE is FALSE
if ( ((!other_file && !(flags & ECMD_OLDBUF))
|| (curbuf->b_nwindows == 1
&& !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
@@ -2484,8 +2495,12 @@ int do_ecmd(
new_name = NULL;
}
set_bufref(&bufref, buf);
- if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) {
- // Save all the text, so that the reload can be undone.
+
+ // If the buffer was used before, store the current contents so that
+ // the reload can be undone. Do not do this if the (empty) buffer is
+ // being re-used for another file.
+ if (!(curbuf->b_flags & BF_NEVERLOADED)
+ && (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)) {
// Sync first so that this is a separate undo-able action.
u_sync(false);
if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, true)
@@ -3908,6 +3923,18 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
ADJUST_SUB_FIRSTLNUM();
+ // TODO(bfredl): adjust also in preview, because decorations?
+ // this has some robustness issues, will look into later.
+ bool do_splice = !preview;
+ bcount_t replaced_bytes = 0;
+ lpos_T start = regmatch.startpos[0], end = regmatch.endpos[0];
+ if (do_splice) {
+ for (i = 0; i < nmatch-1; i++) {
+ replaced_bytes += STRLEN(ml_get(lnum_start+i)) + 1;
+ }
+ replaced_bytes += end.col - start.col;
+ }
+
// Now the trick is to replace CTRL-M chars with a real line
// break. This would make it impossible to insert a CTRL-M in
@@ -3951,17 +3978,14 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
current_match.end.col = new_endcol;
current_match.end.lnum = lnum;
- // TODO(bfredl): adjust in preview, because decorations?
- // this has some robustness issues, will look into later.
- if (!preview) {
- lpos_T start = regmatch.startpos[0], end = regmatch.endpos[0];
+ if (do_splice) {
int matchcols = end.col - ((end.lnum == start.lnum)
? start.col : 0);
int subcols = new_endcol - ((lnum == lnum_start) ? start_col : 0);
extmark_splice(curbuf, lnum_start-1, start_col,
- end.lnum-start.lnum, matchcols,
- lnum-lnum_start, subcols, kExtmarkUndo);
- }
+ end.lnum-start.lnum, matchcols, replaced_bytes,
+ lnum-lnum_start, subcols, sublen-1, kExtmarkUndo);
+ }
}
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 252af409c0..d62b00fee1 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -337,7 +337,7 @@ return {
},
{
command='caddexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -409,7 +409,7 @@ return {
},
{
command='cexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR, BANG),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, BANG),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -447,7 +447,7 @@ return {
},
{
command='cgetexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -1299,7 +1299,7 @@ return {
},
{
command='laddexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -1389,7 +1389,7 @@ return {
},
{
command='lexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR, BANG),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, BANG),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -1427,7 +1427,7 @@ return {
},
{
command='lgetexpr',
- flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, TRLBAR),
+ flags=bit.bor(NEEDARG, WORD1, NOTRLCOM),
addr_type=ADDR_LINES,
func='ex_cexpr',
},
@@ -1927,13 +1927,19 @@ return {
command='perl',
flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
- func='ex_script_ni',
+ func='ex_perl',
},
{
command='perldo',
flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
- func='ex_ni',
+ func='ex_perldo',
+ },
+ {
+ command='perlfile',
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
+ addr_type=ADDR_LINES,
+ func='ex_perlfile',
},
{
command='pedit',
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 7f4b01e306..503fd8e0d0 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -935,6 +935,21 @@ void ex_pydo3(exarg_T *eap)
script_host_do_range("python3", eap);
}
+void ex_perl(exarg_T *eap)
+{
+ script_host_execute("perl", eap);
+}
+
+void ex_perlfile(exarg_T *eap)
+{
+ script_host_execute_file("perl", eap);
+}
+
+void ex_perldo(exarg_T *eap)
+{
+ script_host_do_range("perl", eap);
+}
+
// Command line expansion for :profile.
static enum {
PEXP_SUBCMD, ///< expand :profile sub-commands
@@ -1984,9 +1999,16 @@ void ex_argadd(exarg_T *eap)
/// ":argdelete"
void ex_argdelete(exarg_T *eap)
{
- if (eap->addr_count > 0) {
- // ":1,4argdel": Delete all arguments in the range.
- if (eap->line2 > ARGCOUNT) {
+ if (eap->addr_count > 0 || *eap->arg == NUL) {
+ // ":argdel" works like ":.argdel"
+ if (eap->addr_count == 0) {
+ if (curwin->w_arg_idx >= ARGCOUNT) {
+ EMSG(_("E610: No argument to delete"));
+ return;
+ }
+ eap->line1 = eap->line2 = curwin->w_arg_idx + 1;
+ } else if (eap->line2 > ARGCOUNT) {
+ // ":1,4argdel": Delete all arguments in the range.
eap->line2 = ARGCOUNT;
}
linenr_T n = eap->line2 - eap->line1 + 1;
@@ -2016,8 +2038,6 @@ void ex_argdelete(exarg_T *eap)
curwin->w_arg_idx = ARGCOUNT - 1;
}
}
- } else if (*eap->arg == NUL) {
- EMSG(_(e_argreq));
} else {
do_arglist(eap->arg, AL_DEL, 0);
}
@@ -2038,6 +2058,10 @@ void ex_listdo(exarg_T *eap)
// Don't do syntax HL autocommands. Skipping the syntax file is a
// great speed improvement.
save_ei = au_event_disable(",Syntax");
+
+ FOR_ALL_BUFFERS(buf) {
+ buf->b_flags &= ~BF_SYN_SET;
+ }
}
if (eap->cmdidx == CMD_windo
@@ -2232,9 +2256,32 @@ void ex_listdo(exarg_T *eap)
}
if (save_ei != NULL) {
+ buf_T *bnext;
+ aco_save_T aco;
+
au_event_restore(save_ei);
- apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
- curbuf->b_fname, true, curbuf);
+
+ for (buf_T *buf = firstbuf; buf != NULL; buf = bnext) {
+ bnext = buf->b_next;
+ if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) {
+ buf->b_flags &= ~BF_SYN_SET;
+
+ // buffer was opened while Syntax autocommands were disabled,
+ // need to trigger them now.
+ if (buf == curbuf) {
+ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
+ curbuf->b_fname, true, curbuf);
+ } else {
+ aucmd_prepbuf(&aco, buf);
+ apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
+ buf->b_fname, true, buf);
+ aucmd_restbuf(&aco);
+ }
+
+ // start over, in case autocommands messed things up.
+ bnext = firstbuf;
+ }
+ }
}
}
@@ -4152,7 +4199,7 @@ static void script_host_execute(char *name, exarg_T *eap)
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
- (void)eval_call_provider(name, "execute", args);
+ (void)eval_call_provider(name, "execute", args, true);
}
}
@@ -4167,7 +4214,7 @@ static void script_host_execute_file(char *name, exarg_T *eap)
// current range
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
- (void)eval_call_provider(name, "execute_file", args);
+ (void)eval_call_provider(name, "execute_file", args, true);
}
static void script_host_do_range(char *name, exarg_T *eap)
@@ -4176,7 +4223,7 @@ static void script_host_do_range(char *name, exarg_T *eap)
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
tv_list_append_string(args, (const char *)eap->arg, -1);
- (void)eval_call_provider(name, "do_range", args);
+ (void)eval_call_provider(name, "do_range", args, true);
}
/// ":drop"
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 1f0560ae48..ff5088ea5e 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -169,6 +169,10 @@ struct exarg {
LineGetter getline; ///< Function used to get the next line
void *cookie; ///< argument for getline()
cstack_T *cstack; ///< condition stack for ":if" etc.
+ long verbose_save; ///< saved value of p_verbose
+ int save_msg_silent; ///< saved value of msg_silent
+ int did_esilent; ///< how many times emsg_silent was incremented
+ bool did_sandbox; ///< when true did sandbox++
};
#define FORCE_BIN 1 // ":edit ++bin file"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 5bf6aa73c6..211791c19d 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -137,32 +137,6 @@ struct dbg_stuff {
except_T *current_exception;
};
-typedef struct {
- // parsed results
- exarg_T *eap;
- char_u *parsed_upto; // local we've parsed up to so far
- char_u *cmd; // start of command
- char_u *after_modifier;
-
- // errors
- char_u *errormsg;
-
- // globals that need to be updated
- cmdmod_T cmdmod;
- int sandbox;
- int msg_silent;
- int emsg_silent;
- bool ex_pressedreturn;
- long p_verbose;
-
- // other side-effects
- bool set_eventignore;
- long verbose_save;
- int save_msg_silent;
- int did_esilent;
- bool did_sandbox;
-} parse_state_T;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_docmd.c.generated.h"
#endif
@@ -284,6 +258,27 @@ void do_exmode(int improved)
msg_scroll = save_msg_scroll;
}
+// Print the executed command for when 'verbose' is set.
+// When "lnum" is 0 only print the command.
+static void msg_verbose_cmd(linenr_T lnum, char_u *cmd)
+ FUNC_ATTR_NONNULL_ALL
+{
+ no_wait_return++;
+ verbose_enter_scroll();
+
+ if (lnum == 0) {
+ smsg(_("Executing: %s"), cmd);
+ } else {
+ smsg(_("line %" PRIdLINENR ": %s"), lnum, cmd);
+ }
+ if (msg_silent == 0) {
+ msg_puts("\n"); // don't overwrite this
+ }
+
+ verbose_leave_scroll();
+ no_wait_return--;
+}
+
/*
* Execute a simple command line. Used for translated commands like "*".
*/
@@ -593,17 +588,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
}
}
- if (p_verbose >= 15 && sourcing_name != NULL) {
- ++no_wait_return;
- verbose_enter_scroll();
-
- smsg(_("line %" PRIdLINENR ": %s"), sourcing_lnum, cmdline_copy);
- if (msg_silent == 0) {
- msg_puts("\n"); // don't overwrite this either
- }
-
- verbose_leave_scroll();
- --no_wait_return;
+ if ((p_verbose >= 15 && sourcing_name != NULL) || p_verbose >= 16) {
+ msg_verbose_cmd(sourcing_lnum, cmdline_copy);
}
/*
@@ -1235,292 +1221,6 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
return (char_u *)p;
}
-static void parse_state_to_global(const parse_state_T *parse_state)
-{
- cmdmod = parse_state->cmdmod;
- sandbox = parse_state->sandbox;
- msg_silent = parse_state->msg_silent;
- emsg_silent = parse_state->emsg_silent;
- ex_pressedreturn = parse_state->ex_pressedreturn;
- p_verbose = parse_state->p_verbose;
-
- if (parse_state->set_eventignore) {
- set_string_option_direct(
- (char_u *)"ei", -1, (char_u *)"all", OPT_FREE, SID_NONE);
- }
-}
-
-static void parse_state_from_global(parse_state_T *parse_state)
-{
- memset(parse_state, 0, sizeof(*parse_state));
- parse_state->cmdmod = cmdmod;
- parse_state->sandbox = sandbox;
- parse_state->msg_silent = msg_silent;
- parse_state->emsg_silent = emsg_silent;
- parse_state->ex_pressedreturn = ex_pressedreturn;
- parse_state->p_verbose = p_verbose;
-}
-
-//
-// Parse one Ex command.
-//
-// This has no side-effects, except for modifying parameters
-// passed in by pointer.
-//
-// The `out` should be zeroed, and its `ea` member initialised,
-// before calling this function.
-//
-static bool parse_one_cmd(
- char_u **cmdlinep,
- parse_state_T *const out,
- LineGetter fgetline,
- void *fgetline_cookie)
-{
- exarg_T ea = {
- .line1 = 1,
- .line2 = 1,
- };
- *out->eap = ea;
-
- // "#!anything" is handled like a comment.
- if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') {
- return false;
- }
-
- /*
- * Repeat until no more command modifiers are found.
- */
- ea.cmd = *cmdlinep;
- for (;; ) {
- /*
- * 1. Skip comment lines and leading white space and colons.
- */
- while (*ea.cmd == ' '
- || *ea.cmd == '\t'
- || *ea.cmd == ':') {
- ea.cmd++;
- }
-
- // in ex mode, an empty line works like :+
- if (*ea.cmd == NUL && exmode_active
- && (getline_equal(fgetline, fgetline_cookie, getexmodeline)
- || getline_equal(fgetline, fgetline_cookie, getexline))
- && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- ea.cmd = (char_u *)"+";
- out->ex_pressedreturn = true;
- }
-
- // ignore comment and empty lines
- if (*ea.cmd == '"') {
- return false;
- }
- if (*ea.cmd == NUL) {
- out->ex_pressedreturn = true;
- return false;
- }
-
- /*
- * 2. Handle command modifiers.
- */
- char_u *p = skip_range(ea.cmd, NULL);
- switch (*p) {
- // When adding an entry, also modify cmd_exists().
- case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3))
- break;
- out->cmdmod.split |= WSP_ABOVE;
- continue;
-
- case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) {
- out->cmdmod.split |= WSP_BELOW;
- continue;
- }
- if (checkforcmd(&ea.cmd, "browse", 3)) {
- out->cmdmod.browse = true;
- continue;
- }
- if (!checkforcmd(&ea.cmd, "botright", 2)) {
- break;
- }
- out->cmdmod.split |= WSP_BOT;
- continue;
-
- case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4))
- break;
- out->cmdmod.confirm = true;
- continue;
-
- case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) {
- out->cmdmod.keepmarks = true;
- continue;
- }
- if (checkforcmd(&ea.cmd, "keepalt", 5)) {
- out->cmdmod.keepalt = true;
- continue;
- }
- if (checkforcmd(&ea.cmd, "keeppatterns", 5)) {
- out->cmdmod.keeppatterns = true;
- continue;
- }
- if (!checkforcmd(&ea.cmd, "keepjumps", 5)) {
- break;
- }
- out->cmdmod.keepjumps = true;
- continue;
-
- case 'f': { // only accept ":filter {pat} cmd"
- char_u *reg_pat;
-
- if (!checkforcmd(&p, "filter", 4) || *p == NUL || ends_excmd(*p)) {
- break;
- }
- if (*p == '!') {
- out->cmdmod.filter_force = true;
- p = skipwhite(p + 1);
- if (*p == NUL || ends_excmd(*p)) {
- break;
- }
- }
- p = skip_vimgrep_pat(p, &reg_pat, NULL);
- if (p == NULL || *p == NUL) {
- break;
- }
- out->cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
- if (out->cmdmod.filter_regmatch.regprog == NULL) {
- break;
- }
- ea.cmd = p;
- continue;
- }
-
- // ":hide" and ":hide | cmd" are not modifiers
- case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3)
- || *p == NUL || ends_excmd(*p))
- break;
- ea.cmd = p;
- out->cmdmod.hide = true;
- continue;
-
- case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) {
- out->cmdmod.lockmarks = true;
- continue;
- }
-
- if (!checkforcmd(&ea.cmd, "leftabove", 5)) {
- break;
- }
- out->cmdmod.split |= WSP_ABOVE;
- continue;
-
- case 'n':
- if (checkforcmd(&ea.cmd, "noautocmd", 3)) {
- if (out->cmdmod.save_ei == NULL) {
- // Set 'eventignore' to "all". Restore the
- // existing option value later.
- out->cmdmod.save_ei = vim_strsave(p_ei);
- out->set_eventignore = true;
- }
- continue;
- }
- if (!checkforcmd(&ea.cmd, "noswapfile", 3)) {
- break;
- }
- out->cmdmod.noswapfile = true;
- continue;
-
- case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6))
- break;
- out->cmdmod.split |= WSP_BELOW;
- continue;
-
- case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) {
- if (!out->did_sandbox) {
- out->sandbox++;
- }
- out->did_sandbox = true;
- continue;
- }
- if (!checkforcmd(&ea.cmd, "silent", 3)) {
- break;
- }
- if (out->save_msg_silent == -1) {
- out->save_msg_silent = out->msg_silent;
- }
- out->msg_silent++;
- if (*ea.cmd == '!' && !ascii_iswhite(ea.cmd[-1])) {
- // ":silent!", but not "silent !cmd"
- ea.cmd = skipwhite(ea.cmd + 1);
- out->emsg_silent++;
- out->did_esilent++;
- }
- continue;
-
- case 't': if (checkforcmd(&p, "tab", 3)) {
- long tabnr = get_address(
- &ea, &ea.cmd, ADDR_TABS, ea.skip, false, 1);
-
- if (tabnr == MAXLNUM) {
- out->cmdmod.tab = tabpage_index(curtab) + 1;
- } else {
- if (tabnr < 0 || tabnr > LAST_TAB_NR) {
- out->errormsg = (char_u *)_(e_invrange);
- return false;
- }
- out->cmdmod.tab = tabnr + 1;
- }
- ea.cmd = p;
- continue;
- }
- if (!checkforcmd(&ea.cmd, "topleft", 2)) {
- break;
- }
- out->cmdmod.split |= WSP_TOP;
- continue;
-
- case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3))
- break;
- if (out->save_msg_silent == -1) {
- out->save_msg_silent = out->msg_silent;
- }
- out->msg_silent = 0;
- continue;
-
- case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) {
- out->cmdmod.split |= WSP_VERT;
- continue;
- }
- if (!checkforcmd(&p, "verbose", 4))
- break;
- if (out->verbose_save < 0) {
- out->verbose_save = out->p_verbose;
- }
- if (ascii_isdigit(*ea.cmd)) {
- out->p_verbose = atoi((char *)ea.cmd);
- } else {
- out->p_verbose = 1;
- }
- ea.cmd = p;
- continue;
- }
- break;
- }
- out->after_modifier = ea.cmd;
-
- // 3. Skip over the range to find the command. Let "p" point to after it.
- //
- // We need the command to know what kind of range it uses.
-
- out->cmd = ea.cmd;
- ea.cmd = skip_range(ea.cmd, NULL);
- if (*ea.cmd == '*') {
- ea.cmd = skipwhite(ea.cmd + 1);
- }
- out->parsed_upto = find_command(&ea, NULL);
-
- *out->eap = ea;
-
- return true;
-}
-
/*
* Execute one Ex command.
*
@@ -1549,12 +1249,16 @@ static char_u * do_one_cmd(char_u **cmdlinep,
linenr_T lnum;
long n;
char_u *errormsg = NULL; // error message
+ char_u *after_modifier = NULL;
exarg_T ea;
int save_msg_scroll = msg_scroll;
- parse_state_T parsed;
cmdmod_T save_cmdmod;
const int save_reg_executing = reg_executing;
+ char_u *cmd;
+ memset(&ea, 0, sizeof(ea));
+ ea.line1 = 1;
+ ea.line2 = 1;
ex_nesting_level++;
/* When the last file has not been edited :q has to be typed twice. */
@@ -1571,31 +1275,44 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* recursive calls.
*/
save_cmdmod = cmdmod;
- memset(&cmdmod, 0, sizeof(cmdmod));
- parse_state_from_global(&parsed);
- parsed.eap = &ea;
- parsed.verbose_save = -1;
- parsed.save_msg_silent = -1;
- parsed.did_esilent = 0;
- parsed.did_sandbox = false;
- bool parse_success = parse_one_cmd(cmdlinep, &parsed, fgetline, cookie);
- parse_state_to_global(&parsed);
+ // "#!anything" is handled like a comment.
+ if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') {
+ goto doend;
+ }
+
+ // 1. Skip comment lines and leading white space and colons.
+ // 2. Handle command modifiers.
- // Update locals from parse_one_cmd()
- errormsg = parsed.errormsg;
- p = parsed.parsed_upto;
+ // The "ea" structure holds the arguments that can be used.
+ ea.cmd = *cmdlinep;
+ ea.cmdlinep = cmdlinep;
+ ea.getline = fgetline;
+ ea.cookie = cookie;
+ ea.cstack = cstack;
- if (!parse_success) {
+ if (parse_command_modifiers(&ea, &errormsg, false) == FAIL) {
goto doend;
}
+ after_modifier = ea.cmd;
+
ea.skip = (did_emsg
|| got_int
|| current_exception
|| (cstack->cs_idx >= 0
&& !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
+ // 3. Skip over the range to find the command. Let "p" point to after it.
+ //
+ // We need the command to know what kind of range it uses.
+ cmd = ea.cmd;
+ ea.cmd = skip_range(ea.cmd, NULL);
+ if (*ea.cmd == '*') {
+ ea.cmd = skipwhite(ea.cmd + 1);
+ }
+ p = find_command(&ea, NULL);
+
// Count this line for profiling if skip is TRUE.
if (do_profiling == PROF_YES
&& (!ea.skip || cstack->cs_idx == 0
@@ -1665,8 +1382,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
}
- ea.cmd = parsed.cmd;
- if (parse_cmd_address(&ea, &errormsg) == FAIL) {
+ ea.cmd = cmd;
+ if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
goto doend;
}
@@ -1746,8 +1463,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (!(flags & DOCMD_VERBOSE)) {
// If the modifier was parsed OK the error must be in the following
// command
- if (parsed.after_modifier != NULL) {
- append_command(parsed.after_modifier);
+ if (after_modifier != NULL) {
+ append_command(after_modifier);
} else {
append_command(*cmdlinep);
}
@@ -2222,22 +1939,15 @@ static char_u * do_one_cmd(char_u **cmdlinep,
// The :try command saves the emsg_silent flag, reset it here when
// ":silent! try" was used, it should only apply to :try itself.
- if (ea.cmdidx == CMD_try && parsed.did_esilent > 0) {
- emsg_silent -= parsed.did_esilent;
+ if (ea.cmdidx == CMD_try && ea.did_esilent > 0) {
+ emsg_silent -= ea.did_esilent;
if (emsg_silent < 0) {
emsg_silent = 0;
}
- parsed.did_esilent = 0;
+ ea.did_esilent = 0;
}
// 7. Execute the command.
- //
- // The "ea" structure holds the arguments that can be used.
- ea.cmdlinep = cmdlinep;
- ea.getline = fgetline;
- ea.cookie = cookie;
- ea.cstack = cstack;
-
if (IS_USER_CMDIDX(ea.cmdidx)) {
/*
* Execute a user-defined command.
@@ -2293,30 +2003,21 @@ doend:
? cmdnames[(int)ea.cmdidx].cmd_name
: (char_u *)NULL);
- if (parsed.verbose_save >= 0) {
- p_verbose = parsed.verbose_save;
- }
- if (cmdmod.save_ei != NULL) {
- /* Restore 'eventignore' to the value before ":noautocmd". */
- set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
- OPT_FREE, SID_NONE);
- free_string_option(cmdmod.save_ei);
- }
-
- if (cmdmod.filter_regmatch.regprog != NULL) {
- vim_regfree(cmdmod.filter_regmatch.regprog);
+ if (ea.verbose_save >= 0) {
+ p_verbose = ea.verbose_save;
}
+ free_cmdmod();
cmdmod = save_cmdmod;
reg_executing = save_reg_executing;
- if (parsed.save_msg_silent != -1) {
+ if (ea.save_msg_silent != -1) {
// messages could be enabled for a serious error, need to check if the
// counters don't become negative
- if (!did_emsg || msg_silent > parsed.save_msg_silent) {
- msg_silent = parsed.save_msg_silent;
+ if (!did_emsg || msg_silent > ea.save_msg_silent) {
+ msg_silent = ea.save_msg_silent;
}
- emsg_silent -= parsed.did_esilent;
+ emsg_silent -= ea.did_esilent;
if (emsg_silent < 0) {
emsg_silent = 0;
}
@@ -2330,7 +2031,7 @@ doend:
msg_col = 0;
}
- if (parsed.did_sandbox) {
+ if (ea.did_sandbox) {
sandbox--;
}
@@ -2342,9 +2043,281 @@ doend:
return ea.nextcmd;
}
+// Parse and skip over command modifiers:
+// - update eap->cmd
+// - store flags in "cmdmod".
+// - Set ex_pressedreturn for an empty command line.
+// - set msg_silent for ":silent"
+// - set 'eventignore' to "all" for ":noautocmd"
+// - set p_verbose for ":verbose"
+// - Increment "sandbox" for ":sandbox"
+// When "skip_only" is true the global variables are not changed, except for
+// "cmdmod".
+// Return FAIL when the command is not to be executed.
+// May set "errormsg" to an error message.
+int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
+{
+ char_u *p;
+
+ memset(&cmdmod, 0, sizeof(cmdmod));
+ eap->verbose_save = -1;
+ eap->save_msg_silent = -1;
+
+ // Repeat until no more command modifiers are found.
+ for (;; ) {
+ while (*eap->cmd == ' '
+ || *eap->cmd == '\t'
+ || *eap->cmd == ':') {
+ eap->cmd++;
+ }
+
+ // in ex mode, an empty line works like :+
+ if (*eap->cmd == NUL && exmode_active
+ && (getline_equal(eap->getline, eap->cookie, getexmodeline)
+ || getline_equal(eap->getline, eap->cookie, getexline))
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
+ eap->cmd = (char_u *)"+";
+ if (!skip_only) {
+ ex_pressedreturn = true;
+ }
+ }
+
+ // ignore comment and empty lines
+ if (*eap->cmd == '"') {
+ return FAIL;
+ }
+ if (*eap->cmd == NUL) {
+ if (!skip_only) {
+ ex_pressedreturn = true;
+ }
+ return FAIL;
+ }
+
+ p = skip_range(eap->cmd, NULL);
+ switch (*p) {
+ // When adding an entry, also modify cmd_exists().
+ case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3))
+ break;
+ cmdmod.split |= WSP_ABOVE;
+ continue;
+
+ case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) {
+ cmdmod.split |= WSP_BELOW;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "browse", 3)) {
+ cmdmod.browse = true;
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "botright", 2)) {
+ break;
+ }
+ cmdmod.split |= WSP_BOT;
+ continue;
+
+ case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4))
+ break;
+ cmdmod.confirm = true;
+ continue;
+
+ case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) {
+ cmdmod.keepmarks = true;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "keepalt", 5)) {
+ cmdmod.keepalt = true;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "keeppatterns", 5)) {
+ cmdmod.keeppatterns = true;
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "keepjumps", 5)) {
+ break;
+ }
+ cmdmod.keepjumps = true;
+ continue;
+
+ case 'f': { // only accept ":filter {pat} cmd"
+ char_u *reg_pat;
+
+ if (!checkforcmd(&p, "filter", 4) || *p == NUL || ends_excmd(*p)) {
+ break;
+ }
+ if (*p == '!') {
+ cmdmod.filter_force = true;
+ p = skipwhite(p + 1);
+ if (*p == NUL || ends_excmd(*p)) {
+ break;
+ }
+ }
+ if (skip_only) {
+ p = skip_vimgrep_pat(p, NULL, NULL);
+ } else {
+ // NOTE: This puts a NUL after the pattern.
+ p = skip_vimgrep_pat(p, &reg_pat, NULL);
+ }
+ if (p == NULL || *p == NUL) {
+ break;
+ }
+ if (!skip_only) {
+ cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
+ if (cmdmod.filter_regmatch.regprog == NULL) {
+ break;
+ }
+ }
+ eap->cmd = p;
+ continue;
+ }
+
+ // ":hide" and ":hide | cmd" are not modifiers
+ case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3)
+ || *p == NUL || ends_excmd(*p))
+ break;
+ eap->cmd = p;
+ cmdmod.hide = true;
+ continue;
+
+ case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) {
+ cmdmod.lockmarks = true;
+ continue;
+ }
+
+ if (!checkforcmd(&eap->cmd, "leftabove", 5)) {
+ break;
+ }
+ cmdmod.split |= WSP_ABOVE;
+ continue;
+
+ case 'n':
+ if (checkforcmd(&eap->cmd, "noautocmd", 3)) {
+ if (cmdmod.save_ei == NULL && !skip_only) {
+ // Set 'eventignore' to "all". Restore the
+ // existing option value later.
+ cmdmod.save_ei = vim_strsave(p_ei);
+ set_string_option_direct((char_u *)"ei", -1,
+ (char_u *)"all", OPT_FREE, SID_NONE);
+ }
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "noswapfile", 3)) {
+ break;
+ }
+ cmdmod.noswapfile = true;
+ continue;
+
+ case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6))
+ break;
+ cmdmod.split |= WSP_BELOW;
+ continue;
+
+ case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) {
+ if (!skip_only) {
+ if (!eap->did_sandbox) {
+ sandbox++;
+ }
+ eap->did_sandbox = true;
+ }
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "silent", 3)) {
+ break;
+ }
+ if (!skip_only) {
+ if (eap->save_msg_silent == -1) {
+ eap->save_msg_silent = msg_silent;
+ }
+ msg_silent++;
+ }
+ if (*eap->cmd == '!' && !ascii_iswhite(eap->cmd[-1])) {
+ // ":silent!", but not "silent !cmd"
+ eap->cmd = skipwhite(eap->cmd + 1);
+ if (!skip_only) {
+ emsg_silent++;
+ eap->did_esilent++;
+ }
+ }
+ continue;
+
+ case 't': if (checkforcmd(&p, "tab", 3)) {
+ if (!skip_only) {
+ long tabnr = get_address(
+ eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1);
+
+ if (tabnr == MAXLNUM) {
+ cmdmod.tab = tabpage_index(curtab) + 1;
+ } else {
+ if (tabnr < 0 || tabnr > LAST_TAB_NR) {
+ *errormsg = (char_u *)_(e_invrange);
+ return false;
+ }
+ cmdmod.tab = tabnr + 1;
+ }
+ }
+ eap->cmd = p;
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "topleft", 2)) {
+ break;
+ }
+ cmdmod.split |= WSP_TOP;
+ continue;
+
+ case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3))
+ break;
+ if (!skip_only) {
+ if (eap->save_msg_silent == -1) {
+ eap->save_msg_silent = msg_silent;
+ }
+ msg_silent = 0;
+ }
+ continue;
+
+ case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) {
+ cmdmod.split |= WSP_VERT;
+ continue;
+ }
+ if (!checkforcmd(&p, "verbose", 4))
+ break;
+ if (!skip_only) {
+ if (eap->verbose_save < 0) {
+ eap->verbose_save = p_verbose;
+ }
+ if (ascii_isdigit(*eap->cmd)) {
+ p_verbose = atoi((char *)eap->cmd);
+ } else {
+ p_verbose = 1;
+ }
+ }
+ eap->cmd = p;
+ continue;
+ }
+ break;
+ }
+
+ return OK;
+}
+
+// Free contents of "cmdmod".
+static void free_cmdmod(void)
+{
+ if (cmdmod.save_ei != NULL) {
+ /* Restore 'eventignore' to the value before ":noautocmd". */
+ set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
+ OPT_FREE, SID_NONE);
+ free_string_option(cmdmod.save_ei);
+ }
+
+ if (cmdmod.filter_regmatch.regprog != NULL) {
+ vim_regfree(cmdmod.filter_regmatch.regprog);
+ }
+}
+
+
// Parse the address range, if any, in "eap".
+// May set the last search pattern, unless "silent" is true.
// Return FAIL and set "errormsg" or return OK.
-int parse_cmd_address(exarg_T *eap, char_u **errormsg)
+int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
FUNC_ATTR_NONNULL_ALL
{
int address_count = 1;
@@ -2382,7 +2355,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg)
break;
}
eap->cmd = skipwhite(eap->cmd);
- lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip,
+ lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
eap->addr_count == 0, address_count++);
if (eap->cmd == NULL) { // error detected
return FAIL;
@@ -2427,6 +2400,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg)
}
break;
case ADDR_TABS_RELATIVE:
+ case ADDR_OTHER:
*errormsg = (char_u *)_(e_invrange);
return FAIL;
case ADDR_ARGUMENTS:
@@ -3725,18 +3699,18 @@ char_u *skip_range(
return (char_u *)cmd;
}
-/*
- * get a single EX address
- *
- * Set ptr to the next character after the part that was interpreted.
- * Set ptr to NULL when an error is encountered.
- *
- * Return MAXLNUM when no Ex address was found.
- */
+// Get a single EX address
+//
+// Set ptr to the next character after the part that was interpreted.
+// Set ptr to NULL when an error is encountered.
+// This may set the last used search pattern.
+//
+// Return MAXLNUM when no Ex address was found.
static linenr_T get_address(exarg_T *eap,
char_u **ptr,
int addr_type, // flag: one of ADDR_LINES, ...
int skip, // only skip the address, don't use it
+ bool silent, // no errors or side effects
int to_other_file, // flag: may jump to other file
int address_count) // 1 for first, >1 after comma
{
@@ -3868,13 +3842,15 @@ static linenr_T get_address(exarg_T *eap,
if (*cmd == c)
++cmd;
} else {
- pos = curwin->w_cursor; /* save curwin->w_cursor */
- /*
- * When '/' or '?' follows another address, start
- * from there.
- */
- if (lnum != MAXLNUM)
+ int flags;
+
+ pos = curwin->w_cursor; // save curwin->w_cursor
+
+ // When '/' or '?' follows another address, start from
+ // there.
+ if (lnum != MAXLNUM) {
curwin->w_cursor.lnum = lnum;
+ }
// Start a forward search at the end of the line (unless
// before the first line).
@@ -3888,7 +3864,8 @@ static linenr_T get_address(exarg_T *eap,
curwin->w_cursor.col = 0;
}
searchcmdlen = 0;
- if (!do_search(NULL, c, cmd, 1L, SEARCH_HIS | SEARCH_MSG, NULL)) {
+ flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
+ if (!do_search(NULL, c, cmd, 1L, flags, NULL)) {
curwin->w_cursor = pos;
cmd = NULL;
goto error;
@@ -4949,7 +4926,7 @@ check_more(
int n = ARGCOUNT - curwin->w_arg_idx - 1;
if (!forceit && only_one_window()
- && ARGCOUNT > 1 && !arg_had_last && n >= 0 && quitmore == 0) {
+ && ARGCOUNT > 1 && !arg_had_last && n > 0 && quitmore == 0) {
if (message) {
if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL) {
char_u buff[DIALOG_MSG_SIZE];
@@ -5026,8 +5003,13 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
}
if (cmp == 0) {
- if (!force) {
- EMSG(_("E174: Command already exists: add ! to replace it"));
+ // Command can be replaced with "command!" and when sourcing the
+ // same script again, but only once.
+ if (!force
+ && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid
+ || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq)) {
+ EMSG2(_("E174: Command already exists: add ! to replace it: %s"),
+ name);
goto fail;
}
@@ -5076,16 +5058,18 @@ fail:
static struct {
int expand;
char *name;
+ char *shortname;
} addr_type_complete[] =
{
- { ADDR_ARGUMENTS, "arguments" },
- { ADDR_LINES, "lines" },
- { ADDR_LOADED_BUFFERS, "loaded_buffers" },
- { ADDR_TABS, "tabs" },
- { ADDR_BUFFERS, "buffers" },
- { ADDR_WINDOWS, "windows" },
- { ADDR_QUICKFIX, "quickfix" },
- { -1, NULL }
+ { ADDR_ARGUMENTS, "arguments", "arg" },
+ { ADDR_LINES, "lines", "line" },
+ { ADDR_LOADED_BUFFERS, "loaded_buffers", "load" },
+ { ADDR_TABS, "tabs", "tab" },
+ { ADDR_BUFFERS, "buffers", "buf" },
+ { ADDR_WINDOWS, "windows", "win" },
+ { ADDR_QUICKFIX, "quickfix", "qf" },
+ { ADDR_OTHER, "other", "?" },
+ { -1, NULL, NULL }
};
/*
@@ -5170,7 +5154,7 @@ static void uc_list(char_u *name, size_t name_len)
// Put out the title first time
if (!found) {
MSG_PUTS_TITLE(_("\n Name Args Address "
- "Complete Definition"));
+ "Complete Definition"));
}
found = true;
msg_putchar('\n');
@@ -5256,13 +5240,13 @@ static void uc_list(char_u *name, size_t name_len)
do {
IObuff[len++] = ' ';
- } while (len < 9 - over);
+ } while (len < 8 - over);
// Address Type
for (j = 0; addr_type_complete[j].expand != -1; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
- STRCPY(IObuff + len, addr_type_complete[j].name);
+ STRCPY(IObuff + len, addr_type_complete[j].shortname);
len += (int)STRLEN(IObuff + len);
break;
}
@@ -5281,13 +5265,13 @@ static void uc_list(char_u *name, size_t name_len)
do {
IObuff[len++] = ' ';
- } while (len < 24 - over);
+ } while (len < 25 - over);
IObuff[len] = '\0';
msg_outtrans(IObuff);
msg_outtrans_special(cmd->uc_rep, false,
- name_len == 0 ? Columns - 46 : 0);
+ name_len == 0 ? Columns - 47 : 0);
if (p_verbose > 0) {
last_set_msg(cmd->uc_script_ctx);
}
@@ -5416,7 +5400,7 @@ invalid_count:
if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) == FAIL) {
return FAIL;
}
- if (addr_type_arg != ADDR_LINES) {
+ if (*addr_type_arg != ADDR_LINES) {
*argt |= (ZEROR | NOTADR);
}
} else {
@@ -6945,8 +6929,9 @@ void ex_splitview(exarg_T *eap)
{
win_T *old_curwin = curwin;
char_u *fname = NULL;
-
-
+ const bool use_tab = eap->cmdidx == CMD_tabedit
+ || eap->cmdidx == CMD_tabfind
+ || eap->cmdidx == CMD_tabnew;
/* A ":split" in the quickfix window works like ":new". Don't want two
* quickfix windows. But it's OK when doing ":tab split". */
@@ -6968,9 +6953,7 @@ void ex_splitview(exarg_T *eap)
/*
* Either open new tab page or split the window.
*/
- if (eap->cmdidx == CMD_tabedit
- || eap->cmdidx == CMD_tabfind
- || eap->cmdidx == CMD_tabnew) {
+ if (use_tab) {
if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab : eap->addr_count == 0
? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) {
do_exedit(eap, old_curwin);
@@ -7155,14 +7138,14 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_width;
+ n += wp->w_width;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
n = Columns;
}
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_height;
+ n += wp->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
n = Rows-1;
}
@@ -7788,7 +7771,7 @@ static void ex_put(exarg_T *eap)
*/
static void ex_copymove(exarg_T *eap)
{
- long n = get_address(eap, &eap->arg, eap->addr_type, false, false, 1);
+ long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1);
if (eap->arg == NULL) { // error detected
eap->nextcmd = NULL;
return;
@@ -8586,6 +8569,24 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
eap->forceit, TRUE);
}
+enum {
+ SPEC_PERC = 0,
+ SPEC_HASH,
+ SPEC_CWORD,
+ SPEC_CCWORD,
+ SPEC_CEXPR,
+ SPEC_CFILE,
+ SPEC_SFILE,
+ SPEC_SLNUM,
+ SPEC_STACK,
+ SPEC_AFILE,
+ SPEC_ABUF,
+ SPEC_AMATCH,
+ SPEC_SFLNUM,
+ SPEC_SID,
+ // SPEC_CLIENT,
+};
+
/*
* Check "str" for starting with a special cmdline variable.
* If found return one of the SPEC_ values and set "*usedlen" to the length of
@@ -8596,30 +8597,21 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
{
size_t len;
static char *(spec_str[]) = {
- "%",
-#define SPEC_PERC 0
- "#",
-#define SPEC_HASH (SPEC_PERC + 1)
- "<cword>", // cursor word
-#define SPEC_CWORD (SPEC_HASH + 1)
- "<cWORD>", // cursor WORD
-#define SPEC_CCWORD (SPEC_CWORD + 1)
- "<cexpr>", // expr under cursor
-#define SPEC_CEXPR (SPEC_CCWORD + 1)
- "<cfile>", // cursor path name
-#define SPEC_CFILE (SPEC_CEXPR + 1)
- "<sfile>", // ":so" file name
-#define SPEC_SFILE (SPEC_CFILE + 1)
- "<slnum>", // ":so" file line number
-#define SPEC_SLNUM (SPEC_SFILE + 1)
- "<afile>", // autocommand file name
-#define SPEC_AFILE (SPEC_SLNUM + 1)
- "<abuf>", // autocommand buffer number
-#define SPEC_ABUF (SPEC_AFILE + 1)
- "<amatch>", // autocommand match name
-#define SPEC_AMATCH (SPEC_ABUF + 1)
- "<sflnum>", // script file line number
-#define SPEC_SFLNUM (SPEC_AMATCH + 1)
+ [SPEC_PERC] = "%",
+ [SPEC_HASH] = "#",
+ [SPEC_CWORD] = "<cword>", // cursor word
+ [SPEC_CCWORD] = "<cWORD>", // cursor WORD
+ [SPEC_CEXPR] = "<cexpr>", // expr under cursor
+ [SPEC_CFILE] = "<cfile>", // cursor path name
+ [SPEC_SFILE] = "<sfile>", // ":so" file name
+ [SPEC_SLNUM] = "<slnum>", // ":so" file line number
+ [SPEC_STACK] = "<stack>", // call stack
+ [SPEC_AFILE] = "<afile>", // autocommand file name
+ [SPEC_ABUF] = "<abuf>", // autocommand buffer number
+ [SPEC_AMATCH] = "<amatch>", // autocommand match name
+ [SPEC_SFLNUM] = "<sflnum>", // script file line number
+ [SPEC_SID] = "<SID>", // script ID: <SNR>123_
+ // [SPEC_CLIENT] = "<client>",
};
for (size_t i = 0; i < ARRAY_SIZE(spec_str); ++i) {
@@ -8866,6 +8858,16 @@ eval_vars (
result = (char_u *)strbuf;
break;
+ case SPEC_SID:
+ if (current_sctx.sc_sid <= 0) {
+ *errormsg = (char_u *)_(e_usingsid);
+ return NULL;
+ }
+ snprintf(strbuf, sizeof(strbuf), "<SNR>%" PRIdSCID "_",
+ current_sctx.sc_sid);
+ result = (char_u *)strbuf;
+ break;
+
default:
// should not happen
*errormsg = (char_u *)"";
@@ -9309,14 +9311,17 @@ static void ex_match(exarg_T *eap)
static void ex_fold(exarg_T *eap)
{
if (foldManualAllowed(true)) {
- foldCreate(curwin, eap->line1, eap->line2);
+ pos_T start = { eap->line1, 1, 0 };
+ pos_T end = { eap->line2, 1, 0 };
+ foldCreate(curwin, start, end);
}
}
static void ex_foldopen(exarg_T *eap)
{
- opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen,
- eap->forceit, FALSE);
+ pos_T start = { eap->line1, 1, 0 };
+ pos_T end = { eap->line2, 1, 0 };
+ opFoldRange(start, end, eap->cmdidx == CMD_foldopen, eap->forceit, false);
}
static void ex_folddo(exarg_T *eap)
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 81274fcf2a..0c7562980a 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -87,17 +87,16 @@
*/
static int cause_abort = FALSE;
-/*
- * Return TRUE when immediately aborting on error, or when an interrupt
- * occurred or an exception was thrown but not caught. Use for ":{range}call"
- * to check whether an aborted function that does not handle a range itself
- * should be called again for the next line in the range. Also used for
- * cancelling expression evaluation after a function call caused an immediate
- * abort. Note that the first emsg() call temporarily resets "force_abort"
- * until the throw point for error messages has been reached. That is, during
- * cancellation of an expression evaluation after an aborting function call or
- * due to a parsing error, aborting() always returns the same value.
- */
+// Return true when immediately aborting on error, or when an interrupt
+// occurred or an exception was thrown but not caught. Use for ":{range}call"
+// to check whether an aborted function that does not handle a range itself
+// should be called again for the next line in the range. Also used for
+// cancelling expression evaluation after a function call caused an immediate
+// abort. Note that the first emsg() call temporarily resets "force_abort"
+// until the throw point for error messages has been reached. That is, during
+// cancellation of an expression evaluation after an aborting function call or
+// due to a parsing error, aborting() always returns the same value.
+// "got_int" is also set by calling interrupt().
int aborting(void)
{
return (did_emsg && force_abort) || got_int || current_exception;
@@ -139,16 +138,15 @@ int aborted_in_try(void)
return force_abort;
}
-/*
- * cause_errthrow(): Cause a throw of an error exception if appropriate.
- * Return TRUE if the error message should not be displayed by emsg().
- * Sets "ignore", if the emsg() call should be ignored completely.
- *
- * When several messages appear in the same command, the first is usually the
- * most specific one and used as the exception value. The "severe" flag can be
- * set to TRUE, if a later but severer message should be used instead.
- */
-int cause_errthrow(char_u *mesg, int severe, int *ignore)
+// cause_errthrow(): Cause a throw of an error exception if appropriate.
+// Return true if the error message should not be displayed by emsg().
+// Sets "ignore", if the emsg() call should be ignored completely.
+//
+// When several messages appear in the same command, the first is usually the
+// most specific one and used as the exception value. The "severe" flag can be
+// set to true, if a later but severer message should be used instead.
+bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
+ FUNC_ATTR_NONNULL_ALL
{
struct msglist *elem;
struct msglist **plist;
@@ -159,8 +157,9 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* level. Also when no exception can be thrown. The message will be
* displayed by emsg().
*/
- if (suppress_errthrow)
- return FALSE;
+ if (suppress_errthrow) {
+ return false;
+ }
/*
* If emsg() has not been called previously, temporarily reset
@@ -196,8 +195,8 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* not replaced by an interrupt message error exception.
*/
if (mesg == (char_u *)_(e_interr)) {
- *ignore = TRUE;
- return TRUE;
+ *ignore = true;
+ return true;
}
/*
@@ -232,8 +231,8 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* catch clause; just finally clauses are executed before the script
* is terminated.
*/
- return FALSE;
- } else
+ return false;
+ } else // NOLINT(readability/braces)
#endif
{
/*
@@ -272,7 +271,7 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
(*msg_list)->throw_msg = tmsg;
}
}
- return TRUE;
+ return true;
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 93684e8606..d67e9b2d7e 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -137,6 +137,7 @@ struct cmdline_info {
/// Last value of prompt_id, incremented when doing new prompt
static unsigned last_prompt_id = 0;
+// Struct to store the viewstate during 'incsearch' highlighting.
typedef struct {
colnr_T vs_curswant;
colnr_T vs_leftcol;
@@ -146,6 +147,19 @@ typedef struct {
int vs_empty_rows;
} viewstate_T;
+// Struct to store the state of 'incsearch' highlighting.
+typedef struct {
+ pos_T search_start; // where 'incsearch' starts searching
+ pos_T save_cursor;
+ viewstate_T init_viewstate;
+ viewstate_T old_viewstate;
+ pos_T match_start;
+ pos_T match_end;
+ bool did_incsearch;
+ bool incsearch_postponed;
+ int magic_save;
+} incsearch_state_T;
+
typedef struct command_line_state {
VimState state;
int firstc;
@@ -159,14 +173,7 @@ typedef struct command_line_state {
int save_hiscnt; // history line before attempting
// to jump to next match
int histype; // history type to be used
- pos_T search_start; // where 'incsearch' starts searching
- pos_T save_cursor;
- viewstate_T init_viewstate;
- viewstate_T old_viewstate;
- pos_T match_start;
- pos_T match_end;
- int did_incsearch;
- int incsearch_postponed;
+ incsearch_state_T is_state;
int did_wild_list; // did wild_list() recently
int wim_index; // index in wim_flags[]
int res;
@@ -252,6 +259,395 @@ static void restore_viewstate(viewstate_T *vs)
curwin->w_empty_rows = vs->vs_empty_rows;
}
+static void init_incsearch_state(incsearch_state_T *s)
+{
+ s->match_start = curwin->w_cursor;
+ s->did_incsearch = false;
+ s->incsearch_postponed = false;
+ s->magic_save = p_magic;
+ clearpos(&s->match_end);
+ s->save_cursor = curwin->w_cursor; // may be restored later
+ s->search_start = curwin->w_cursor;
+ save_viewstate(&s->init_viewstate);
+ save_viewstate(&s->old_viewstate);
+}
+
+// Return true when 'incsearch' highlighting is to be done.
+// Sets search_first_line and search_last_line to the address range.
+static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
+ int *skiplen, int *patlen)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *cmd;
+ cmdmod_T save_cmdmod = cmdmod;
+ char_u *p;
+ bool delim_optional = false;
+ int delim;
+ char_u *end;
+ char_u *dummy;
+ exarg_T ea;
+ pos_T save_cursor;
+ bool use_last_pat;
+ bool retval = false;
+
+ *skiplen = 0;
+ *patlen = ccline.cmdlen;
+
+ if (!p_is || cmd_silent) {
+ return false;
+ }
+
+ // by default search all lines
+ search_first_line = 0;
+ search_last_line = MAXLNUM;
+
+ if (firstc == '/' || firstc == '?') {
+ return true;
+ }
+ if (firstc != ':') {
+ return false;
+ }
+
+ emsg_off++;
+ memset(&ea, 0, sizeof(ea));
+ ea.line1 = 1;
+ ea.line2 = 1;
+ ea.cmd = ccline.cmdbuff;
+ ea.addr_type = ADDR_LINES;
+
+ parse_command_modifiers(&ea, &dummy, true);
+ cmdmod = save_cmdmod;
+
+ cmd = skip_range(ea.cmd, NULL);
+ if (vim_strchr((char_u *)"sgvl", *cmd) == NULL) {
+ goto theend;
+ }
+
+ // Skip over "substitute" to find the pattern separator.
+ for (p = cmd; ASCII_ISALPHA(*p); p++) {}
+ if (*skipwhite(p) == NUL) {
+ goto theend;
+ }
+
+ if (STRNCMP(cmd, "substitute", p - cmd) == 0
+ || STRNCMP(cmd, "smagic", p - cmd) == 0
+ || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0
+ || STRNCMP(cmd, "vglobal", p - cmd) == 0) {
+ if (*cmd == 's' && cmd[1] == 'm') {
+ p_magic = true;
+ } else if (*cmd == 's' && cmd[1] == 'n') {
+ p_magic = false;
+ }
+ } else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) {
+ // skip over ! and flags
+ if (*p == '!') {
+ p = skipwhite(p + 1);
+ }
+ while (ASCII_ISALPHA(*(p = skipwhite(p)))) {
+ p++;
+ }
+ if (*p == NUL) {
+ goto theend;
+ }
+ } else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
+ || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
+ || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0
+ || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0
+ || STRNCMP(cmd, "global", p - cmd) == 0) {
+ // skip over "!/".
+ if (*p == '!') {
+ p++;
+ if (*skipwhite(p) == NUL) {
+ goto theend;
+ }
+ }
+ if (*cmd != 'g') {
+ delim_optional = true;
+ }
+ } else {
+ goto theend;
+ }
+
+ p = skipwhite(p);
+ delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
+ end = skip_regexp(p, delim, p_magic, NULL);
+
+ use_last_pat = end == p && *end == delim;
+ if (end == p && !use_last_pat) {
+ goto theend;
+ }
+
+ // Don't do 'hlsearch' highlighting if the pattern matches everything.
+ if (!use_last_pat) {
+ char_u c = *end;
+ int empty;
+
+ *end = NUL;
+ empty = empty_pattern(p);
+ *end = c;
+ if (empty) {
+ goto theend;
+ }
+ }
+
+ // found a non-empty pattern or //
+ *skiplen = (int)(p - ccline.cmdbuff);
+ *patlen = (int)(end - p);
+
+ // parse the address range
+ save_cursor = curwin->w_cursor;
+ curwin->w_cursor = s->search_start;
+ parse_cmd_address(&ea, &dummy, true);
+ if (ea.addr_count > 0) {
+ // Allow for reverse match.
+ if (ea.line2 < ea.line1) {
+ search_first_line = ea.line2;
+ search_last_line = ea.line1;
+ } else {
+ search_first_line = ea.line1;
+ search_last_line = ea.line2;
+ }
+ } else if (cmd[0] == 's' && cmd[1] != 'o') {
+ // :s defaults to the current line
+ search_first_line = curwin->w_cursor.lnum;
+ search_last_line = curwin->w_cursor.lnum;
+ }
+
+ curwin->w_cursor = save_cursor;
+ retval = true;
+theend:
+ emsg_off--;
+ return retval;
+}
+
+// May do 'incsearch' highlighting if desired.
+static void may_do_incsearch_highlighting(int firstc, long count,
+ incsearch_state_T *s)
+{
+ pos_T end_pos;
+ proftime_T tm;
+ searchit_arg_T sia;
+ int skiplen, patlen;
+ char_u next_char;
+ char_u use_last_pat;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
+ restore_last_search_pattern();
+ finish_incsearch_highlighting(false, s, true);
+ return;
+ }
+
+ // if there is a character waiting, search and redraw later
+ if (char_avail()) {
+ restore_last_search_pattern();
+ s->incsearch_postponed = true;
+ return;
+ }
+ s->incsearch_postponed = false;
+
+ if (search_first_line == 0) {
+ // start at the original cursor position
+ curwin->w_cursor = s->search_start;
+ } else if (search_first_line > curbuf->b_ml.ml_line_count) {
+ // start after the last line
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.col = MAXCOL;
+ } else {
+ // start at the first line in the range
+ curwin->w_cursor.lnum = search_first_line;
+ curwin->w_cursor.col = 0;
+ }
+ int found; // do_search() result
+
+ // Use the previous pattern for ":s//".
+ next_char = ccline.cmdbuff[skiplen + patlen];
+ use_last_pat = patlen == 0 && skiplen > 0
+ && ccline.cmdbuff[skiplen - 1] == next_char;
+
+ // If there is no pattern, don't do anything.
+ if (patlen == 0 && !use_last_pat) {
+ found = 0;
+ set_no_hlsearch(true); // turn off previous highlight
+ redraw_all_later(SOME_VALID);
+ } else {
+ int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
+ ui_busy_start();
+ ui_flush();
+ emsg_off++; // So it doesn't beep if bad expr
+ // Set the time limit to half a second.
+ tm = profile_setlimit(500L);
+ if (!p_hls) {
+ search_flags += SEARCH_KEEP;
+ }
+ if (search_first_line != 0) {
+ search_flags += SEARCH_START;
+ }
+ ccline.cmdbuff[skiplen + patlen] = NUL;
+ memset(&sia, 0, sizeof(sia));
+ sia.sa_tm = &tm;
+ found = do_search(NULL, firstc == ':' ? '/' : firstc,
+ ccline.cmdbuff + skiplen, count,
+ search_flags, &sia);
+ ccline.cmdbuff[skiplen + patlen] = next_char;
+ emsg_off--;
+ if (curwin->w_cursor.lnum < search_first_line
+ || curwin->w_cursor.lnum > search_last_line) {
+ // match outside of address range
+ found = 0;
+ curwin->w_cursor = s->search_start;
+ }
+
+ // if interrupted while searching, behave like it failed
+ if (got_int) {
+ (void)vpeekc(); // remove <C-C> from input stream
+ got_int = false; // don't abandon the command line
+ found = 0;
+ } else if (char_avail()) {
+ // cancelled searching because a char was typed
+ s->incsearch_postponed = true;
+ }
+ ui_busy_stop();
+ }
+
+ if (found != 0) {
+ highlight_match = true; // highlight position
+ } else {
+ highlight_match = false; // remove highlight
+ }
+
+ // first restore the old curwin values, so the screen is
+ // positioned in the same way as the actual search command
+ restore_viewstate(&s->old_viewstate);
+ changed_cline_bef_curs();
+ update_topline();
+
+ if (found != 0) {
+ pos_T save_pos = curwin->w_cursor;
+
+ s->match_start = curwin->w_cursor;
+ set_search_match(&curwin->w_cursor);
+ validate_cursor();
+ end_pos = curwin->w_cursor;
+ s->match_end = end_pos;
+ curwin->w_cursor = save_pos;
+ } else {
+ end_pos = curwin->w_cursor; // shutup gcc 4
+ }
+ //
+ // Disable 'hlsearch' highlighting if the pattern matches
+ // everything. Avoids a flash when typing "foo\|".
+ if (!use_last_pat) {
+ next_char = ccline.cmdbuff[skiplen + patlen];
+ ccline.cmdbuff[skiplen + patlen] = NUL;
+ if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) {
+ redraw_all_later(SOME_VALID);
+ set_no_hlsearch(true);
+ }
+ ccline.cmdbuff[skiplen + patlen] = next_char;
+ }
+
+ validate_cursor();
+ // May redraw the status line to show the cursor position.
+ if (p_ru && curwin->w_status_height > 0) {
+ curwin->w_redr_status = true;
+ }
+
+ update_screen(SOME_VALID);
+ highlight_match = false;
+ restore_last_search_pattern();
+
+ // Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the
+ // end of the pattern, e.g. for ":s/pat/".
+ if (ccline.cmdbuff[skiplen + patlen] != NUL) {
+ curwin->w_cursor = s->search_start;
+ } else if (found != 0) {
+ curwin->w_cursor = end_pos;
+ }
+
+ msg_starthere();
+ redrawcmdline();
+ s->did_incsearch = true;
+}
+
+// When CTRL-L typed: add character from the match to the pattern.
+// May set "*c" to the added character.
+// Return OK when calling command_line_not_changed.
+static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int skiplen, patlen;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ // Add a character from under the cursor for 'incsearch'
+ if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
+ restore_last_search_pattern();
+ return FAIL;
+ }
+ restore_last_search_pattern();
+
+ if (s->did_incsearch) {
+ curwin->w_cursor = s->match_end;
+ *c = gchar_cursor();
+ if (*c != NUL) {
+ // If 'ignorecase' and 'smartcase' are set and the
+ // command line has no uppercase characters, convert
+ // the character to lowercase
+ if (p_ic && p_scs
+ && !pat_has_uppercase(ccline.cmdbuff + skiplen)) {
+ *c = mb_tolower(*c);
+ }
+ if (*c == firstc
+ || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c)
+ != NULL) {
+ // put a backslash before special characters
+ stuffcharReadbuff(*c);
+ *c = '\\';
+ }
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s,
+ bool call_update_screen)
+{
+ if (s->did_incsearch) {
+ s->did_incsearch = false;
+ if (gotesc) {
+ curwin->w_cursor = s->save_cursor;
+ } else {
+ if (!equalpos(s->save_cursor, s->search_start)) {
+ // put the '" mark at the original position
+ curwin->w_cursor = s->save_cursor;
+ setpcmark();
+ }
+ curwin->w_cursor = s->search_start; // -V519
+ }
+ restore_viewstate(&s->old_viewstate);
+ highlight_match = false;
+
+ // by default search all lines
+ search_first_line = 0;
+ search_last_line = MAXLNUM;
+
+ p_magic = s->magic_save;
+
+ validate_cursor(); // needed for TAB
+ redraw_all_later(SOME_VALID);
+ if (call_update_screen) {
+ update_screen(SOME_VALID);
+ }
+ }
+}
+
/// Internal entry point for cmdline mode.
///
/// caller must use save_cmdline and restore_cmdline. Best is to use
@@ -269,11 +665,10 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
.save_msg_scroll = msg_scroll,
.save_State = State,
.ignore_drag_release = true,
- .match_start = curwin->w_cursor,
};
CommandLineState *s = &state;
s->save_p_icm = vim_strsave(p_icm);
- save_viewstate(&state.init_viewstate);
+ init_incsearch_state(&s->is_state);
if (s->firstc == -1) {
s->firstc = NUL;
@@ -288,10 +683,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
ccline.prompt_id = last_prompt_id++;
ccline.level = cmdline_level;
ccline.overstrike = false; // always start in insert mode
- clearpos(&s->match_end);
- s->save_cursor = curwin->w_cursor; // may be restored later
- s->search_start = curwin->w_cursor;
- save_viewstate(&state.old_viewstate);
assert(indent >= 0);
@@ -455,22 +846,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
close_preview_windows();
}
- if (s->did_incsearch) {
- if (s->gotesc) {
- curwin->w_cursor = s->save_cursor;
- } else {
- if (!equalpos(s->save_cursor, s->search_start)) {
- // put the '" mark at the original position
- curwin->w_cursor = s->save_cursor;
- setpcmark();
- }
- curwin->w_cursor = s->search_start; // -V519
- }
- restore_viewstate(&s->old_viewstate);
- highlight_match = false;
- validate_cursor(); // needed for TAB
- redraw_all_later(SOME_VALID);
- }
+ finish_incsearch_highlighting(s->gotesc, &s->is_state, false);
if (ccline.cmdbuff != NULL) {
// Put line in history buffer (":" and "=" only when it was typed).
@@ -1075,24 +1451,46 @@ static int command_line_execute(VimState *state, int key)
return command_line_handle_key(s);
}
-static void command_line_next_incsearch(CommandLineState *s, bool next_match)
+// May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
+// or previous match.
+// Returns FAIL when calling command_line_not_changed.
+static int may_do_command_line_next_incsearch(int firstc, long count,
+ incsearch_state_T *s,
+ bool next_match)
+ FUNC_ATTR_NONNULL_ALL
{
+ int skiplen, patlen;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
+ restore_last_search_pattern();
+ return OK;
+ }
+ if (patlen == 0 && ccline.cmdbuff[skiplen] == NUL) {
+ restore_last_search_pattern();
+ return FAIL;
+ }
+
ui_busy_start();
ui_flush();
pos_T t;
char_u *pat;
int search_flags = SEARCH_NOOF;
+ char_u save;
- if (s->firstc == ccline.cmdbuff[0]) {
+ if (firstc == ccline.cmdbuff[skiplen]) {
pat = last_search_pattern();
+ skiplen = 0;
+ patlen = (int)STRLEN(pat);
} else {
- pat = ccline.cmdbuff;
+ pat = ccline.cmdbuff + skiplen;
}
- save_last_search_pattern();
-
if (next_match) {
t = s->match_end;
if (lt(s->match_start, s->match_end)) {
@@ -1108,23 +1506,26 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
search_flags += SEARCH_KEEP;
}
emsg_off++;
+ save = pat[patlen];
+ pat[patlen] = NUL;
int found = searchit(curwin, curbuf, &t, NULL,
next_match ? FORWARD : BACKWARD,
- pat, s->count, search_flags,
+ pat, count, search_flags,
RE_SEARCH, NULL);
emsg_off--;
+ pat[patlen] = save;
ui_busy_stop();
if (found) {
s->search_start = s->match_start;
s->match_end = t;
s->match_start = t;
- if (!next_match && s->firstc == '/') {
+ if (!next_match && firstc != '?') {
// move just before the current match, so that
// when nv_search finishes the cursor will be
// put back on the match
s->search_start = t;
(void)decl(&s->search_start);
- } else if (next_match && s->firstc == '?') {
+ } else if (next_match && firstc == '?') {
// move just after the current match, so that
// when nv_search finishes the cursor will be
// put back on the match
@@ -1134,7 +1535,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
if (lt(t, s->search_start) && next_match) {
// wrap around
s->search_start = t;
- if (s->firstc == '?') {
+ if (firstc == '?') {
(void)incl(&s->search_start);
} else {
(void)decl(&s->search_start);
@@ -1149,12 +1550,14 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
highlight_match = true;
save_viewstate(&s->old_viewstate);
update_screen(NOT_VALID);
+ highlight_match = false;
redrawcmdline();
+ curwin->w_cursor = s->match_end;
} else {
vim_beep(BO_ERROR);
}
restore_last_search_pattern();
- return;
+ return FAIL;
}
static void command_line_next_histidx(CommandLineState *s, bool next_match)
@@ -1265,10 +1668,10 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
if (ccline.cmdlen == 0) {
- s->search_start = s->save_cursor;
+ s->is_state.search_start = s->is_state.save_cursor;
// save view settings, so that the screen won't be restored at the
// wrong position
- s->old_viewstate = s->init_viewstate;
+ s->is_state.old_viewstate = s->is_state.init_viewstate;
}
redrawcmd();
} else if (ccline.cmdlen == 0 && s->c != Ctrl_W
@@ -1287,7 +1690,7 @@ static int command_line_handle_key(CommandLineState *s)
}
msg_putchar(' '); // delete ':'
}
- s->search_start = s->save_cursor;
+ s->is_state.search_start = s->is_state.save_cursor;
redraw_cmdline = true;
return 0; // back to cmd mode
}
@@ -1337,7 +1740,7 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
if (ccline.cmdlen == 0) {
- s->search_start = s->save_cursor;
+ s->is_state.search_start = s->is_state.save_cursor;
}
redrawcmd();
return command_line_changed(s);
@@ -1565,31 +1968,7 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_changed(s);
case Ctrl_L:
- if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
- // Add a character from under the cursor for 'incsearch'
- if (s->did_incsearch) {
- curwin->w_cursor = s->match_end;
- if (!equalpos(curwin->w_cursor, s->search_start)) {
- s->c = gchar_cursor();
- // If 'ignorecase' and 'smartcase' are set and the
- // command line has no uppercase characters, convert
- // the character to lowercase
- if (p_ic && p_scs
- && !pat_has_uppercase(ccline.cmdbuff)) {
- s->c = mb_tolower(s->c);
- }
- if (s->c != NUL) {
- if (s->c == s->firstc
- || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), s->c)
- != NULL) {
- // put a backslash before special characters
- stuffcharReadbuff(s->c);
- s->c = '\\';
- }
- break;
- }
- }
- }
+ if (may_add_char_to_search(s->firstc, &s->c, &s->is_state) == OK) {
return command_line_not_changed(s);
}
@@ -1703,10 +2082,8 @@ static int command_line_handle_key(CommandLineState *s)
case Ctrl_G: // next match
case Ctrl_T: // previous match
- if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
- if (ccline.cmdlen != 0) {
- command_line_next_incsearch(s, s->c == Ctrl_G);
- }
+ if (may_do_command_line_next_incsearch(s->firstc, s->count, &s->is_state,
+ s->c == Ctrl_G) == FAIL) {
return command_line_not_changed(s);
}
break;
@@ -1791,7 +2168,7 @@ static int command_line_not_changed(CommandLineState *s)
// command line did not change. Then we only search and redraw if something
// changed in the past.
// Enter command_line_changed() when the command line did change.
- if (!s->incsearch_postponed) {
+ if (!s->is_state.incsearch_postponed) {
return 1;
}
return command_line_changed(s);
@@ -1843,108 +2220,13 @@ static int command_line_changed(CommandLineState *s)
}
// 'incsearch' highlighting.
- if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
- pos_T end_pos;
- proftime_T tm;
- searchit_arg_T sia;
-
- // if there is a character waiting, search and redraw later
- if (char_avail()) {
- s->incsearch_postponed = true;
- return 1;
- }
- s->incsearch_postponed = false;
- curwin->w_cursor = s->search_start; // start at old position
- save_last_search_pattern();
- int i;
-
- // If there is no command line, don't do anything
- if (ccline.cmdlen == 0) {
- i = 0;
- set_no_hlsearch(true); // turn off previous highlight
- redraw_all_later(SOME_VALID);
- } else {
- int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
- ui_busy_start();
- ui_flush();
- ++emsg_off; // So it doesn't beep if bad expr
- // Set the time limit to half a second.
- tm = profile_setlimit(500L);
- if (!p_hls) {
- search_flags += SEARCH_KEEP;
- }
- memset(&sia, 0, sizeof(sia));
- sia.sa_tm = &tm;
- i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
- search_flags, &sia);
- emsg_off--;
- // if interrupted while searching, behave like it failed
- if (got_int) {
- (void)vpeekc(); // remove <C-C> from input stream
- got_int = false; // don't abandon the command line
- i = 0;
- } else if (char_avail()) {
- // cancelled searching because a char was typed
- s->incsearch_postponed = true;
- }
- ui_busy_stop();
- }
-
- if (i != 0) {
- highlight_match = true; // highlight position
- } else {
- highlight_match = false; // remove highlight
- }
-
- // first restore the old curwin values, so the screen is
- // positioned in the same way as the actual search command
- restore_viewstate(&s->old_viewstate);
- changed_cline_bef_curs();
- update_topline();
-
- if (i != 0) {
- pos_T save_pos = curwin->w_cursor;
-
- s->match_start = curwin->w_cursor;
- set_search_match(&curwin->w_cursor);
- validate_cursor();
- end_pos = curwin->w_cursor;
- s->match_end = end_pos;
- curwin->w_cursor = save_pos;
- } else {
- end_pos = curwin->w_cursor; // shutup gcc 4
- }
-
- // Disable 'hlsearch' highlighting if the pattern matches
- // everything. Avoids a flash when typing "foo\|".
- if (empty_pattern(ccline.cmdbuff)) {
- set_no_hlsearch(true);
- }
-
- validate_cursor();
- // May redraw the status line to show the cursor position.
- if (p_ru && curwin->w_status_height > 0) {
- curwin->w_redr_status = true;
- }
-
- update_screen(SOME_VALID);
- restore_last_search_pattern();
-
- // Leave it at the end to make CTRL-R CTRL-W work.
- if (i != 0) {
- curwin->w_cursor = end_pos;
- }
-
- msg_starthere();
- redrawcmdline();
- s->did_incsearch = true;
- } else if (s->firstc == ':'
- && current_sctx.sc_sid == 0 // only if interactive
- && *p_icm != NUL // 'inccommand' is set
- && curbuf->b_p_ma // buffer is modifiable
- && cmdline_star == 0 // not typing a password
- && cmd_can_preview(ccline.cmdbuff)
- && !vpeekc_any()) {
+ if (s->firstc == ':'
+ && current_sctx.sc_sid == 0 // only if interactive
+ && *p_icm != NUL // 'inccommand' is set
+ && curbuf->b_p_ma // buffer is modifiable
+ && cmdline_star == 0 // not typing a password
+ && cmd_can_preview(ccline.cmdbuff)
+ && !vpeekc_any()) {
// Show 'inccommand' preview. It works like this:
// 1. Do the command.
// 2. Command implementation detects CMDPREVIEW state, then:
@@ -1958,8 +2240,8 @@ static int command_line_changed(CommandLineState *s)
emsg_silent--; // Unblock error reporting
// Restore the window "view".
- curwin->w_cursor = s->save_cursor;
- restore_viewstate(&s->old_viewstate);
+ curwin->w_cursor = s->is_state.save_cursor;
+ restore_viewstate(&s->is_state.old_viewstate);
update_topline();
redrawcmdline();
@@ -1968,6 +2250,8 @@ static int command_line_changed(CommandLineState *s)
State = (State & ~CMDPREVIEW);
close_preview_windows();
update_screen(SOME_VALID); // Clear 'inccommand' preview.
+ } else {
+ may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
}
if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) {
@@ -4706,7 +4990,7 @@ ExpandFromContext (
char_u *pat,
int *num_file,
char_u ***file,
- int options /* EW_ flags */
+ int options // WILD_ flags
)
{
regmatch_T regmatch;
@@ -4768,6 +5052,21 @@ ExpandFromContext (
ret = expand_wildcards_eval(&pat, num_file, file, flags);
if (free_pat)
xfree(pat);
+#ifdef BACKSLASH_IN_FILENAME
+ if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) {
+ for (int i = 0; i < *num_file; i++) {
+ char_u *ptr = (*file)[i];
+ while (*ptr != NUL) {
+ if (p_csl[0] == 's' && *ptr == '\\') {
+ *ptr = '/';
+ } else if (p_csl[0] == 'b' && *ptr == '/') {
+ *ptr = '\\';
+ }
+ ptr += utfc_ptr2len(ptr);
+ }
+ }
+ }
+#endif
return ret;
}
@@ -4909,7 +5208,7 @@ ExpandFromContext (
* obtain strings, one by one. The strings are matched against a regexp
* program. Matching strings are copied into an array, which is returned.
*/
-void ExpandGeneric(
+static void ExpandGeneric(
expand_T *xp,
regmatch_T *regmatch,
int *num_file,
@@ -6189,12 +6488,15 @@ static int open_cmdwin(void)
// Save the command line info, can be used recursively.
save_cmdline(&save_ccline);
- /* No Ex mode here! */
+ // No Ex mode here!
exmode_active = 0;
State = NORMAL;
setmouse();
+ // Reset here so it can be set by a CmdWinEnter autocommand.
+ cmdwin_result = 0;
+
// Trigger CmdwinEnter autocommands.
typestr[0] = (char_u)cmdwin_type;
typestr[1] = NUL;
@@ -6210,7 +6512,6 @@ static int open_cmdwin(void)
/*
* Call the main loop until <CR> or CTRL-C is typed.
*/
- cmdwin_result = 0;
normal_enter(true, false);
RedrawingDisabled = i;
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 1b797c6168..6b00b986dc 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -493,7 +493,8 @@ static int put_view(
/// Writes commands for restoring the current buffers, for :mksession.
///
-/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled.
+/// Legacy 'sessionoptions'/'viewoptions' flags SSOP_UNIX, SSOP_SLASH are
+/// always enabled.
///
/// @param dirnow Current directory name
/// @param fd File descriptor to write to
@@ -822,9 +823,9 @@ void ex_loadview(exarg_T *eap)
/// ":mkexrc", ":mkvimrc", ":mkview", ":mksession".
///
-/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled.
-/// - SSOP_UNIX: line-endings are always LF
-/// - SSOP_SLASH: filenames are always written with "/" slash
+/// Legacy 'sessionoptions'/'viewoptions' flags are always enabled:
+/// - SSOP_UNIX: line-endings are LF
+/// - SSOP_SLASH: filenames are written with "/" slash
void ex_mkrc(exarg_T *eap)
{
FILE *fd;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 1457a1172d..0de396fd1f 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -1,29 +1,24 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-// Implements extended marks for plugins. Each mark exists in a btree of
-// lines containing btrees of columns.
+// Implements extended marks for plugins. Marks sit in a MarkTree
+// datastructure which provides both efficient mark insertations/lookups
+// and adjustment to text changes. See marktree.c for more details.
//
-// The btree provides efficient range lookups.
// A map of pointers to the marks is used for fast lookup by mark id.
//
-// Marks are moved by calls to extmark_splice. Additionally mark_adjust
-// might adjust extmarks to line inserts/deletes.
+// Marks are moved by calls to extmark_splice. Some standard interfaces
+// mark_adjust and inserted_bytes already adjust marks, check if these are
+// being used before adding extmark_splice calls!
//
// Undo/Redo of marks is implemented by storing the call arguments to
// extmark_splice. The list of arguments is applied in extmark_apply_undo.
-// The only case where we have to copy extmarks is for the area being effected
-// by a delete.
+// We have to copy extmark positions when the extmarks are within a
+// deleted/changed region.
//
// Marks live in namespaces that allow plugins/users to segregate marks
// from other users.
//
-// For possible ideas for efficency improvements see:
-// http://blog.atom.io/2015/06/16/optimizing-an-important-atom-primitive.html
-// TODO(bfredl): These ideas could be used for an enhanced btree, which
-// wouldn't need separate line and column layers.
-// Other implementations exist in gtk and tk toolkits.
-//
// Deleting marks only happens when explicitly calling extmark_del, deleteing
// over a range of marks will only move the marks. Deleting on a mark will
// leave it in same position unless it is on the EOL of a line.
@@ -48,6 +43,13 @@
# include "extmark.c.generated.h"
#endif
+static PMap(uint64_t) *hl_decors;
+
+void extmark_init(void)
+{
+ hl_decors = pmap_new(uint64_t)();
+}
+
static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
if (!buf->b_extmark_ns) {
if (!put) {
@@ -71,7 +73,8 @@ static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
/// must not be used during iteration!
/// @returns the mark id
uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
- int row, colnr_T col, ExtmarkOp op)
+ int row, colnr_T col, int end_row, colnr_T end_col,
+ Decoration *decor, ExtmarkOp op)
{
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true);
mtpos_t old_pos;
@@ -82,7 +85,7 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
} else {
uint64_t old_mark = map_get(uint64_t, uint64_t)(ns->map, id);
if (old_mark) {
- if (old_mark & MARKTREE_PAIRED_FLAG) {
+ if (old_mark & MARKTREE_PAIRED_FLAG || end_row > -1) {
extmark_del(buf, ns_id, id);
} else {
// TODO(bfredl): we need to do more if "revising" a decoration mark.
@@ -90,7 +93,12 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
old_pos = marktree_lookup(buf->b_marktree, old_mark, itr);
assert(itr->node);
if (old_pos.row == row && old_pos.col == col) {
- map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, old_mark);
+ ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index,
+ old_mark);
+ if (it.decor) {
+ decoration_redraw(buf, row, row, it.decor);
+ free_decoration(it.decor);
+ }
mark = marktree_revise(buf->b_marktree, itr);
goto revised;
}
@@ -101,11 +109,17 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
}
}
- mark = marktree_put(buf->b_marktree, row, col, true);
+ if (end_row > -1) {
+ mark = marktree_put_pair(buf->b_marktree,
+ row, col, true,
+ end_row, end_col, false);
+ } else {
+ mark = marktree_put(buf->b_marktree, row, col, true);
+ }
+
revised:
map_put(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark,
- (ExtmarkItem){ ns_id, id, 0,
- KV_INITIAL_VALUE });
+ (ExtmarkItem){ ns_id, id, decor });
map_put(uint64_t, uint64_t)(ns->map, id, mark);
if (op != kExtmarkNoUndo) {
@@ -114,6 +128,10 @@ revised:
// adding new marks to old undo headers.
u_extmark_set(buf, mark, row, col);
}
+
+ if (decor) {
+ decoration_redraw(buf, row, end_row > -1 ? end_row : row, decor);
+ }
return id;
}
@@ -152,27 +170,23 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
assert(pos.row >= 0);
marktree_del_itr(buf->b_marktree, itr, false);
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
+ mtpos_t pos2 = pos;
if (mark & MARKTREE_PAIRED_FLAG) {
- mtpos_t pos2 = marktree_lookup(buf->b_marktree,
- mark|MARKTREE_END_FLAG, itr);
+ pos2 = marktree_lookup(buf->b_marktree, mark|MARKTREE_END_FLAG, itr);
assert(pos2.row >= 0);
marktree_del_itr(buf->b_marktree, itr, false);
- if (item.hl_id && pos2.row >= pos.row) {
- redraw_buf_range_later(buf, pos.row+1, pos2.row+1);
- }
}
- if (kv_size(item.virt_text)) {
- redraw_buf_line_later(buf, pos.row+1);
+ if (item.decor) {
+ decoration_redraw(buf, pos.row, pos2.row, item.decor);
+ free_decoration(item.decor);
}
- clear_virttext(&item.virt_text);
map_del(uint64_t, uint64_t)(ns->map, id);
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
// TODO(bfredl): delete it from current undo header, opportunistically?
-
return true;
}
@@ -202,9 +216,11 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
}
// the value is either zero or the lnum (row+1) if highlight was present.
- static Map(uint64_t, uint64_t) *delete_set = NULL;
+ static Map(uint64_t, ssize_t) *delete_set = NULL;
+ typedef struct { Decoration *decor; int row1; } DecorItem;
+ static kvec_t(DecorItem) decors;
if (delete_set == NULL) {
- delete_set = map_new(uint64_t, uint64_t)();
+ delete_set = map_new(uint64_t, ssize_t)();
}
MarkTreeIter itr[1] = { 0 };
@@ -216,14 +232,16 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
|| (mark.row == u_row && mark.col > u_col)) {
break;
}
- uint64_t *del_status = map_ref(uint64_t, uint64_t)(delete_set, mark.id,
- false);
+ ssize_t *del_status = map_ref(uint64_t, ssize_t)(delete_set, mark.id,
+ false);
if (del_status) {
marktree_del_itr(buf->b_marktree, itr, false);
- map_del(uint64_t, uint64_t)(delete_set, mark.id);
- if (*del_status > 0) {
- redraw_buf_range_later(buf, (linenr_T)(*del_status), mark.row+1);
+ if (*del_status >= 0) { // we had a decor_id
+ DecorItem it = kv_A(decors, *del_status);
+ decoration_redraw(buf, it.row1, mark.row, it.decor);
+ free_decoration(it.decor);
}
+ map_del(uint64_t, ssize_t)(delete_set, mark.id);
continue;
}
@@ -233,15 +251,21 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
assert(item.ns_id > 0 && item.mark_id > 0);
if (item.mark_id > 0 && (item.ns_id == ns_id || all_ns)) {
- if (kv_size(item.virt_text)) {
- redraw_buf_line_later(buf, mark.row+1);
- }
- clear_virttext(&item.virt_text);
marks_cleared = true;
if (mark.id & MARKTREE_PAIRED_FLAG) {
uint64_t other = mark.id ^ MARKTREE_END_FLAG;
- uint64_t status = item.hl_id ? ((uint64_t)mark.row+1) : 0;
- map_put(uint64_t, uint64_t)(delete_set, other, status);
+ ssize_t decor_id = -1;
+ if (item.decor) {
+ // Save the decoration and the first pos. Clear the decoration
+ // later when we know the full range.
+ decor_id = (ssize_t)kv_size(decors);
+ kv_push(decors,
+ ((DecorItem) { .decor = item.decor, .row1 = mark.row }));
+ }
+ map_put(uint64_t, ssize_t)(delete_set, other, decor_id);
+ } else if (item.decor) {
+ decoration_redraw(buf, mark.row, mark.row, item.decor);
+ free_decoration(item.decor);
}
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
@@ -251,16 +275,20 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
marktree_itr_next(buf->b_marktree, itr);
}
}
- uint64_t id, status;
- map_foreach(delete_set, id, status, {
+ uint64_t id;
+ ssize_t decor_id;
+ map_foreach(delete_set, id, decor_id, {
mtpos_t pos = marktree_lookup(buf->b_marktree, id, itr);
assert(itr->node);
marktree_del_itr(buf->b_marktree, itr, false);
- if (status > 0) {
- redraw_buf_range_later(buf, (linenr_T)status, pos.row+1);
+ if (decor_id >= 0) {
+ DecorItem it = kv_A(decors, decor_id);
+ decoration_redraw(buf, it.row1, pos.row, it.decor);
+ free_decoration(it.decor);
}
});
- map_clear(uint64_t, uint64_t)(delete_set);
+ map_clear(uint64_t, ssize_t)(delete_set);
+ kv_size(decors) = 0;
return marks_cleared;
}
@@ -270,31 +298,44 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
// will be searched to the start, or end
// dir can be set to control the order of the array
// amount = amount of marks to find or -1 for all
-ExtmarkArray extmark_get(buf_T *buf, uint64_t ns_id,
- int l_row, colnr_T l_col,
- int u_row, colnr_T u_col,
- int64_t amount, bool reverse)
+ExtmarkInfoArray extmark_get(buf_T *buf, uint64_t ns_id,
+ int l_row, colnr_T l_col,
+ int u_row, colnr_T u_col,
+ int64_t amount, bool reverse)
{
- ExtmarkArray array = KV_INITIAL_VALUE;
- MarkTreeIter itr[1] = { 0 };
+ ExtmarkInfoArray array = KV_INITIAL_VALUE;
+ MarkTreeIter itr[1];
// Find all the marks
marktree_itr_get_ext(buf->b_marktree, (mtpos_t){ l_row, l_col },
itr, reverse, false, NULL);
int order = reverse ? -1 : 1;
while ((int64_t)kv_size(array) < amount) {
mtmark_t mark = marktree_itr_current(itr);
+ mtpos_t endpos = { -1, -1 };
if (mark.row < 0
|| (mark.row - u_row) * order > 0
|| (mark.row == u_row && (mark.col - u_col) * order > 0)) {
break;
}
+ if (mark.id & MARKTREE_END_FLAG) {
+ goto next_mark;
+ } else if (mark.id & MARKTREE_PAIRED_FLAG) {
+ endpos = marktree_lookup(buf->b_marktree, mark.id | MARKTREE_END_FLAG,
+ NULL);
+ }
+
+
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
mark.id);
if (item.ns_id == ns_id) {
kv_push(array, ((ExtmarkInfo) { .ns_id = item.ns_id,
.mark_id = item.mark_id,
- .row = mark.row, .col = mark.col }));
+ .row = mark.row, .col = mark.col,
+ .end_row = endpos.row,
+ .end_col = endpos.col,
+ .decor = item.decor }));
}
+next_mark:
if (reverse) {
marktree_itr_prev(buf->b_marktree, itr);
} else {
@@ -308,7 +349,7 @@ ExtmarkArray extmark_get(buf_T *buf, uint64_t ns_id,
ExtmarkInfo extmark_from_id(buf_T *buf, uint64_t ns_id, uint64_t id)
{
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, false);
- ExtmarkInfo ret = { 0, 0, -1, -1 };
+ ExtmarkInfo ret = { 0, 0, -1, -1, -1, -1, NULL };
if (!ns) {
return ret;
}
@@ -319,12 +360,22 @@ ExtmarkInfo extmark_from_id(buf_T *buf, uint64_t ns_id, uint64_t id)
}
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, NULL);
+ mtpos_t endpos = { -1, -1 };
+ if (mark & MARKTREE_PAIRED_FLAG) {
+ endpos = marktree_lookup(buf->b_marktree, mark | MARKTREE_END_FLAG, NULL);
+ }
assert(pos.row >= 0);
+ ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
+ mark);
+
ret.ns_id = ns_id;
ret.mark_id = id;
ret.row = pos.row;
ret.col = pos.col;
+ ret.end_row = endpos.row;
+ ret.end_col = endpos.col;
+ ret.decor = item.decor;
return ret;
}
@@ -352,7 +403,7 @@ void extmark_free_all(buf_T *buf)
map_foreach(buf->b_extmark_index, id, item, {
(void)id;
- clear_virttext(&item.virt_text);
+ free_decoration(item.decor);
});
map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index);
buf->b_extmark_index = NULL;
@@ -428,18 +479,18 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
// Undo
ExtmarkSplice splice = undo_info.data.splice;
if (undo) {
- extmark_splice(curbuf,
- splice.start_row, splice.start_col,
- splice.newextent_row, splice.newextent_col,
- splice.oldextent_row, splice.oldextent_col,
- kExtmarkNoUndo);
+ extmark_splice_impl(curbuf,
+ splice.start_row, splice.start_col, splice.start_byte,
+ splice.new_row, splice.new_col, splice.new_byte,
+ splice.old_row, splice.old_col, splice.old_byte,
+ kExtmarkNoUndo);
} else {
- extmark_splice(curbuf,
- splice.start_row, splice.start_col,
- splice.oldextent_row, splice.oldextent_col,
- splice.newextent_row, splice.newextent_col,
- kExtmarkNoUndo);
+ extmark_splice_impl(curbuf,
+ splice.start_row, splice.start_col, splice.start_byte,
+ splice.old_row, splice.old_col, splice.old_byte,
+ splice.new_row, splice.new_col, splice.new_byte,
+ kExtmarkNoUndo);
}
// kExtmarkSavePos
} else if (undo_info.type == kExtmarkSavePos) {
@@ -458,15 +509,15 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
ExtmarkMove move = undo_info.data.move;
if (undo) {
extmark_move_region(curbuf,
- move.new_row, move.new_col,
- move.extent_row, move.extent_col,
- move.start_row, move.start_col,
+ move.new_row, move.new_col, move.new_byte,
+ move.extent_row, move.extent_col, move.extent_byte,
+ move.start_row, move.start_col, move.start_byte,
kExtmarkNoUndo);
} else {
extmark_move_region(curbuf,
- move.start_row, move.start_col,
- move.extent_row, move.extent_col,
- move.new_row, move.new_col,
+ move.start_row, move.start_col, move.start_byte,
+ move.extent_row, move.extent_col, move.extent_byte,
+ move.new_row, move.new_col, move.new_byte,
kExtmarkNoUndo);
}
}
@@ -481,51 +532,84 @@ void extmark_adjust(buf_T *buf,
long amount_after,
ExtmarkOp undo)
{
- if (!curbuf_splice_pending) {
- int old_extent, new_extent;
- if (amount == MAXLNUM) {
- old_extent = (int)(line2 - line1+1);
- new_extent = (int)(amount_after + old_extent);
- } else {
- // A region is either deleted (amount == MAXLNUM) or
- // added (line2 == MAXLNUM). The only other case is :move
- // which is handled by a separate entry point extmark_move_region.
- assert(line2 == MAXLNUM);
- old_extent = 0;
- new_extent = (int)amount;
- }
- extmark_splice(buf,
- (int)line1-1, 0,
- old_extent, 0,
- new_extent, 0, undo);
+ if (curbuf_splice_pending) {
+ return;
+ }
+ bcount_t start_byte = ml_find_line_or_offset(buf, line1, NULL, true);
+ bcount_t old_byte = 0, new_byte = 0;
+ int old_row, new_row;
+ if (amount == MAXLNUM) {
+ old_row = (int)(line2 - line1+1);
+ // TODO(bfredl): ej kasta?
+ old_byte = (bcount_t)buf->deleted_bytes2;
+
+ new_row = (int)(amount_after + old_row);
+ } else {
+ // A region is either deleted (amount == MAXLNUM) or
+ // added (line2 == MAXLNUM). The only other case is :move
+ // which is handled by a separate entry point extmark_move_region.
+ assert(line2 == MAXLNUM);
+ old_row = 0;
+ new_row = (int)amount;
}
+ if (new_row > 0) {
+ new_byte = ml_find_line_or_offset(buf, line1+new_row, NULL, true)
+ - start_byte;
+ }
+ extmark_splice_impl(buf,
+ (int)line1-1, 0, start_byte,
+ old_row, 0, old_byte,
+ new_row, 0, new_byte, undo);
}
void extmark_splice(buf_T *buf,
int start_row, colnr_T start_col,
- int oldextent_row, colnr_T oldextent_col,
- int newextent_row, colnr_T newextent_col,
+ int old_row, colnr_T old_col, bcount_t old_byte,
+ int new_row, colnr_T new_col, bcount_t new_byte,
ExtmarkOp undo)
{
- buf_updates_send_splice(buf, start_row, start_col,
- oldextent_row, oldextent_col,
- newextent_row, newextent_col);
+ long offset = ml_find_line_or_offset(buf, start_row + 1, NULL, true);
+
+ // On empty buffers, when editing the first line, the line is buffered,
+ // causing offset to be < 0. While the buffer is not actually empty, the
+ // buffered line has not been flushed (and should not be) yet, so the call is
+ // valid but an edge case.
+ //
+ // TODO(vigoux): maybe the is a better way of testing that ?
+ if (offset < 0 && buf->b_ml.ml_chunksize == NULL) {
+ offset = 0;
+ }
+ extmark_splice_impl(buf, start_row, start_col, offset + start_col,
+ old_row, old_col, old_byte, new_row, new_col, new_byte,
+ undo);
+}
+
+void extmark_splice_impl(buf_T *buf,
+ int start_row, colnr_T start_col, bcount_t start_byte,
+ int old_row, colnr_T old_col, bcount_t old_byte,
+ int new_row, colnr_T new_col, bcount_t new_byte,
+ ExtmarkOp undo)
+{
+ curbuf->deleted_bytes2 = 0;
+ buf_updates_send_splice(buf, start_row, start_col, start_byte,
+ old_row, old_col, old_byte,
+ new_row, new_col, new_byte);
- if (undo == kExtmarkUndo && (oldextent_row > 0 || oldextent_col > 0)) {
+ if (undo == kExtmarkUndo && (old_row > 0 || old_col > 0)) {
// Copy marks that would be effected by delete
// TODO(bfredl): Be "smart" about gravity here, left-gravity at the
// beginning and right-gravity at the end need not be preserved.
// Also be smart about marks that already have been saved (important for
// merge!)
- int end_row = start_row + oldextent_row;
- int end_col = (oldextent_row ? 0 : start_col) + oldextent_col;
+ int end_row = start_row + old_row;
+ int end_col = (old_row ? 0 : start_col) + old_col;
u_extmark_copy(buf, start_row, start_col, end_row, end_col);
}
marktree_splice(buf->b_marktree, start_row, start_col,
- oldextent_row, oldextent_col,
- newextent_row, newextent_col);
+ old_row, old_col,
+ new_row, new_col);
if (undo == kExtmarkUndo) {
u_header_T *uhp = u_force_get_undo_header(buf);
@@ -537,25 +621,29 @@ void extmark_splice(buf_T *buf,
// TODO(bfredl): this is quite rudimentary. We merge small (within line)
// inserts with each other and small deletes with each other. Add full
// merge algorithm later.
- if (oldextent_row == 0 && newextent_row == 0 && kv_size(uhp->uh_extmark)) {
+ if (old_row == 0 && new_row == 0 && kv_size(uhp->uh_extmark)) {
ExtmarkUndoObject *item = &kv_A(uhp->uh_extmark,
kv_size(uhp->uh_extmark)-1);
if (item->type == kExtmarkSplice) {
ExtmarkSplice *splice = &item->data.splice;
- if (splice->start_row == start_row && splice->oldextent_row == 0
- && splice->newextent_row == 0) {
- if (oldextent_col == 0 && start_col >= splice->start_col
- && start_col <= splice->start_col+splice->newextent_col) {
- splice->newextent_col += newextent_col;
+ if (splice->start_row == start_row && splice->old_row == 0
+ && splice->new_row == 0) {
+ if (old_col == 0 && start_col >= splice->start_col
+ && start_col <= splice->start_col+splice->new_col) {
+ splice->new_col += new_col;
+ splice->new_byte += new_byte;
merged = true;
- } else if (newextent_col == 0
- && start_col == splice->start_col+splice->newextent_col) {
- splice->oldextent_col += oldextent_col;
+ } else if (new_col == 0
+ && start_col == splice->start_col+splice->new_col) {
+ splice->old_col += old_col;
+ splice->old_byte += old_byte;
merged = true;
- } else if (newextent_col == 0
- && start_col + oldextent_col == splice->start_col) {
+ } else if (new_col == 0
+ && start_col + old_col == splice->start_col) {
splice->start_col = start_col;
- splice->oldextent_col += oldextent_col;
+ splice->start_byte = start_byte;
+ splice->old_col += old_col;
+ splice->old_byte += old_byte;
merged = true;
}
}
@@ -566,10 +654,13 @@ void extmark_splice(buf_T *buf,
ExtmarkSplice splice;
splice.start_row = start_row;
splice.start_col = start_col;
- splice.oldextent_row = oldextent_row;
- splice.oldextent_col = oldextent_col;
- splice.newextent_row = newextent_row;
- splice.newextent_col = newextent_col;
+ splice.start_byte = start_byte;
+ splice.old_row = old_row;
+ splice.old_col = old_col;
+ splice.old_byte = old_byte;
+ splice.new_row = new_row;
+ splice.new_col = new_col;
+ splice.new_byte = new_byte;
kv_push(uhp->uh_extmark,
((ExtmarkUndoObject){ .type = kExtmarkSplice,
@@ -584,30 +675,31 @@ void extmark_splice_cols(buf_T *buf,
ExtmarkOp undo)
{
extmark_splice(buf, start_row, start_col,
- 0, old_col,
- 0, new_col, undo);
+ 0, old_col, old_col,
+ 0, new_col, new_col, undo);
}
-void extmark_move_region(buf_T *buf,
- int start_row, colnr_T start_col,
- int extent_row, colnr_T extent_col,
- int new_row, colnr_T new_col,
- ExtmarkOp undo)
+void extmark_move_region(
+ buf_T *buf,
+ int start_row, colnr_T start_col, bcount_t start_byte,
+ int extent_row, colnr_T extent_col, bcount_t extent_byte,
+ int new_row, colnr_T new_col, bcount_t new_byte,
+ ExtmarkOp undo)
{
// TODO(bfredl): this is not synced to the buffer state inside the callback.
// But unless we make the undo implementation smarter, this is not ensured
// anyway.
- buf_updates_send_splice(buf, start_row, start_col,
- extent_row, extent_col,
- 0, 0);
+ buf_updates_send_splice(buf, start_row, start_col, start_byte,
+ extent_row, extent_col, extent_byte,
+ 0, 0, 0);
marktree_move_region(buf->b_marktree, start_row, start_col,
extent_row, extent_col,
new_row, new_col);
- buf_updates_send_splice(buf, new_row, new_col,
- 0, 0,
- extent_row, extent_col);
+ buf_updates_send_splice(buf, new_row, new_col, new_byte,
+ 0, 0, 0,
+ extent_row, extent_col, extent_byte);
if (undo == kExtmarkUndo) {
@@ -619,10 +711,13 @@ void extmark_move_region(buf_T *buf,
ExtmarkMove move;
move.start_row = start_row;
move.start_col = start_col;
+ move.start_byte = start_byte;
move.extent_row = extent_row;
move.extent_col = extent_col;
+ move.extent_byte = extent_byte;
move.new_row = new_row;
move.new_col = new_col;
+ move.new_byte = new_byte;
kv_push(uhp->uh_extmark,
((ExtmarkUndoObject){ .type = kExtmarkMove,
@@ -642,50 +737,6 @@ uint64_t src2ns(Integer *src_id)
}
}
-/// Adds a decoration to a buffer.
-///
-/// Unlike matchaddpos() highlights, these follow changes to the the buffer
-/// texts. Decorations are represented internally and in the API as extmarks.
-///
-/// @param buf The buffer to add decorations to
-/// @param ns_id A valid namespace id.
-/// @param hl_id Id of the highlight group to use (or zero)
-/// @param start_row The line to highlight
-/// @param start_col First column to highlight
-/// @param end_row The line to highlight
-/// @param end_col The last column to highlight
-/// @param virt_text Virtual text (currently placed at the EOL of start_row)
-/// @return The extmark id inside the namespace
-uint64_t extmark_add_decoration(buf_T *buf, uint64_t ns_id, int hl_id,
- int start_row, colnr_T start_col,
- int end_row, colnr_T end_col,
- VirtText virt_text)
-{
- ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true);
- ExtmarkItem item;
- item.ns_id = ns_id;
- item.mark_id = ns->free_id++;
- item.hl_id = hl_id;
- item.virt_text = virt_text;
-
- uint64_t mark;
-
- if (end_row > -1) {
- mark = marktree_put_pair(buf->b_marktree,
- start_row, start_col, true,
- end_row, end_col, false);
- } else {
- mark = marktree_put(buf->b_marktree, start_row, start_col, true);
- }
-
- map_put(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark, item);
- map_put(uint64_t, uint64_t)(ns->map, item.mark_id, mark);
-
- redraw_buf_range_later(buf, start_row+1,
- (end_row >= 0 ? end_row : start_row) + 1);
- return item.mark_id;
-}
-
/// Add highlighting to a buffer, bounded by two cursor positions,
/// with an offset.
///
@@ -705,6 +756,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
{
colnr_T hl_start = 0;
colnr_T hl_end = 0;
+ Decoration *decor = decoration_hl(hl_id);
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
@@ -729,10 +781,44 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
hl_start = pos_start.col + offset;
hl_end = pos_end.col + offset;
}
- (void)extmark_add_decoration(buf, (uint64_t)src_id, hl_id,
- (int)lnum-1, hl_start,
- (int)lnum-1+end_off, hl_end,
- VIRTTEXT_EMPTY);
+ (void)extmark_set(buf, (uint64_t)src_id, 0,
+ (int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
+ decor, kExtmarkNoUndo);
+ }
+}
+
+Decoration *decoration_hl(int hl_id)
+{
+ assert(hl_id > 0);
+ Decoration **dp = (Decoration **)pmap_ref(uint64_t)(hl_decors,
+ (uint64_t)hl_id, true);
+ if (*dp) {
+ return *dp;
+ }
+
+ Decoration *decor = xcalloc(1, sizeof(*decor));
+ decor->hl_id = hl_id;
+ decor->shared = true;
+ *dp = decor;
+ return decor;
+}
+
+void decoration_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
+{
+ if (decor->hl_id && row2 >= row1) {
+ redraw_buf_range_later(buf, row1+1, row2+1);
+ }
+
+ if (kv_size(decor->virt_text)) {
+ redraw_buf_line_later(buf, row1+1);
+ }
+}
+
+void free_decoration(Decoration *decor)
+{
+ if (decor && !decor->shared) {
+ clear_virttext(&decor->virt_text);
+ xfree(decor);
}
}
@@ -757,8 +843,8 @@ VirtText *extmark_find_virttext(buf_T *buf, int row, uint64_t ns_id)
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
mark.id, false);
if (item && (ns_id == 0 || ns_id == item->ns_id)
- && kv_size(item->virt_text)) {
- return &item->virt_text;
+ && item->decor && kv_size(item->decor->virt_text)) {
+ return &item->decor->virt_text;
}
marktree_itr_next(buf->b_marktree, itr);
}
@@ -768,8 +854,15 @@ VirtText *extmark_find_virttext(buf_T *buf, int row, uint64_t ns_id)
bool decorations_redraw_reset(buf_T *buf, DecorationRedrawState *state)
{
state->row = -1;
+ for (size_t i = 0; i < kv_size(state->active); i++) {
+ HlRange item = kv_A(state->active, i);
+ if (item.virt_text_owned) {
+ clear_virttext(item.virt_text);
+ xfree(item.virt_text);
+ }
+ }
kv_size(state->active) = 0;
- return buf->b_extmark_index || buf->b_luahl;
+ return buf->b_extmark_index;
}
@@ -787,7 +880,6 @@ bool decorations_redraw_start(buf_T *buf, int top_row,
if (mark.row < 0) { // || mark.row > end_row
break;
}
- // TODO(bfredl): dedicated flag for being a decoration?
if ((mark.row < top_row && mark.id&MARKTREE_END_FLAG)) {
goto next_mark;
}
@@ -797,25 +889,30 @@ bool decorations_redraw_start(buf_T *buf, int top_row,
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id, false);
+ if (!item || !item->decor) {
+ // TODO(bfredl): dedicated flag for being a decoration?
+ goto next_mark;
+ }
+ Decoration *decor = item->decor;
+
if ((!(mark.id&MARKTREE_END_FLAG) && altpos.row < top_row
- && item && !kv_size(item->virt_text))
+ && item && !kv_size(decor->virt_text))
|| ((mark.id&MARKTREE_END_FLAG) && altpos.row >= top_row)) {
goto next_mark;
}
- if (item && (item->hl_id > 0 || kv_size(item->virt_text))) {
- int attr_id = item->hl_id > 0 ? syn_id2attr(item->hl_id) : 0;
- VirtText *vt = kv_size(item->virt_text) ? &item->virt_text : NULL;
- HlRange range;
- if (mark.id&MARKTREE_END_FLAG) {
- range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
- attr_id, vt };
- } else {
- range = (HlRange){ mark.row, mark.col, altpos.row,
- altpos.col, attr_id, vt };
- }
- kv_push(state->active, range);
+ int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
+ VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
+ HlRange range;
+ if (mark.id&MARKTREE_END_FLAG) {
+ range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
+ attr_id, vt, false };
+ } else {
+ range = (HlRange){ mark.row, mark.col, altpos.row,
+ altpos.col, attr_id, vt, false };
}
+ kv_push(state->active, range);
+
next_mark:
if (marktree_itr_node_done(state->itr)) {
break;
@@ -860,21 +957,24 @@ int decorations_redraw_col(buf_T *buf, int col, DecorationRedrawState *state)
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
mark.id, false);
+ if (!item || !item->decor) {
+ // TODO(bfredl): dedicated flag for being a decoration?
+ goto next_mark;
+ }
+ Decoration *decor = item->decor;
if (endpos.row < mark.row
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
- if (item && !kv_size(item->virt_text)) {
+ if (item && !kv_size(decor->virt_text)) {
goto next_mark;
}
}
- if (item && (item->hl_id > 0 || kv_size(item->virt_text))) {
- int attr_id = item->hl_id > 0 ? syn_id2attr(item->hl_id) : 0;
- VirtText *vt = kv_size(item->virt_text) ? &item->virt_text : NULL;
- kv_push(state->active, ((HlRange){ mark.row, mark.col,
- endpos.row, endpos.col,
- attr_id, vt }));
- }
+ int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
+ VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
+ kv_push(state->active, ((HlRange){ mark.row, mark.col,
+ endpos.row, endpos.col,
+ attr_id, vt, false }));
next_mark:
marktree_itr_next(buf->b_marktree, state->itr);
@@ -908,6 +1008,9 @@ next_mark:
}
if (keep) {
kv_A(state->active, j++) = kv_A(state->active, i);
+ } else if (item.virt_text_owned) {
+ clear_virttext(item.virt_text);
+ xfree(item.virt_text);
}
}
kv_size(state->active) = j;
diff --git a/src/nvim/extmark.h b/src/nvim/extmark.h
index b5eb0db3b6..101527ab4f 100644
--- a/src/nvim/extmark.h
+++ b/src/nvim/extmark.h
@@ -1,6 +1,7 @@
#ifndef NVIM_EXTMARK_H
#define NVIM_EXTMARK_H
+#include "nvim/pos.h"
#include "nvim/buffer_defs.h"
#include "nvim/extmark_defs.h"
#include "nvim/marktree.h"
@@ -13,19 +14,28 @@ typedef struct
uint64_t mark_id;
int row;
colnr_T col;
+ int end_row;
+ colnr_T end_col;
+ Decoration *decor;
} ExtmarkInfo;
-typedef kvec_t(ExtmarkInfo) ExtmarkArray;
+typedef kvec_t(ExtmarkInfo) ExtmarkInfoArray;
+
+// TODO(bfredl): good enough name for now.
+typedef ptrdiff_t bcount_t;
// delete the columns between mincol and endcol
typedef struct {
int start_row;
colnr_T start_col;
- int oldextent_row;
- colnr_T oldextent_col;
- int newextent_row;
- colnr_T newextent_col;
+ int old_row;
+ colnr_T old_col;
+ int new_row;
+ colnr_T new_col;
+ bcount_t start_byte;
+ bcount_t old_byte;
+ bcount_t new_byte;
} ExtmarkSplice;
// adjust marks after :move operation
@@ -36,6 +46,9 @@ typedef struct {
int extent_col;
int new_row;
int new_col;
+ bcount_t start_byte;
+ bcount_t extent_byte;
+ bcount_t new_byte;
} ExtmarkMove;
// extmark was updated
@@ -73,6 +86,7 @@ typedef struct {
int end_col;
int attr_id;
VirtText *virt_text;
+ bool virt_text_owned;
} HlRange;
typedef struct {
@@ -85,6 +99,8 @@ typedef struct {
VirtText *virt_text;
} DecorationRedrawState;
+EXTERN kvec_t(DecorationProvider) decoration_providers INIT(= KV_INITIAL_VALUE);
+EXTERN win_T *redrawn_win INIT(= NULL); // used for ephemeral extmarks
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "extmark.h.generated.h"
diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h
index c927048981..f5ca0ebbb0 100644
--- a/src/nvim/extmark_defs.h
+++ b/src/nvim/extmark_defs.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EXTMARK_DEFS_H
#define NVIM_EXTMARK_DEFS_H
-#include "nvim/pos.h" // for colnr_T
+#include "nvim/types.h"
#include "nvim/lib/kvec.h"
typedef struct {
@@ -14,12 +14,20 @@ typedef kvec_t(VirtTextChunk) VirtText;
typedef struct
{
- uint64_t ns_id;
- uint64_t mark_id;
int hl_id; // highlight group
- // TODO(bfredl): virt_text is pretty larger than the rest,
- // pointer indirection?
VirtText virt_text;
+ // TODO(bfredl): style, signs, etc
+ bool shared; // shared decoration, don't free
+} Decoration;
+
+typedef struct
+{
+ uint64_t ns_id;
+ uint64_t mark_id;
+ // TODO(bfredl): a lot of small allocations. Should probably use
+ // kvec_t(Decoration) as an arena. Alternatively, store ns_id/mark_id
+ // _inline_ in MarkTree and use the map only for decorations.
+ Decoration *decor;
} ExtmarkItem;
typedef struct undo_object ExtmarkUndoObject;
@@ -34,4 +42,18 @@ typedef enum {
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
} ExtmarkOp;
+typedef struct {
+ NS ns_id;
+ bool active;
+ LuaRef redraw_start;
+ LuaRef redraw_buf;
+ LuaRef redraw_win;
+ LuaRef redraw_line;
+ LuaRef redraw_end;
+} DecorationProvider;
+
+#define DECORATION_PROVIDER_INIT(ns_id) (DecorationProvider) \
+ { ns_id, false, LUA_NOREF, LUA_NOREF, \
+ LUA_NOREF, LUA_NOREF, LUA_NOREF }
+
#endif // NVIM_EXTMARK_DEFS_H
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index f922591d0b..ad856b588a 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -210,7 +210,8 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
if (msg_silent != 0) {
return;
}
- add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name);
+ add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)name);
+ // Avoid an over-long translation to cause trouble.
xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
// For the first message may have to start a new line.
// For further ones overwrite the previous one, reset msg_scroll before
@@ -349,6 +350,7 @@ readfile(
char_u *old_b_fname;
int using_b_ffname;
int using_b_fname;
+ static char *msg_is_a_directory = N_("is a directory");
au_did_filetype = false; // reset before triggering any autocommands
@@ -443,21 +445,31 @@ readfile(
else
msg_scroll = TRUE; /* don't overwrite previous file message */
- /*
- * If the name is too long we might crash further on, quit here.
- */
+ // If the name is too long we might crash further on, quit here.
if (fname != NULL && *fname != NUL) {
- if (STRLEN(fname) >= MAXPATHL) {
+ size_t namelen = STRLEN(fname);
+
+ // If the name is too long we might crash further on, quit here.
+ if (namelen >= MAXPATHL) {
filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
msg_end();
msg_scroll = msg_save;
return FAIL;
}
+
+ // If the name ends in a path separator, we can't open it. Check here,
+ // because reading the file may actually work, but then creating the
+ // swap file may destroy it! Reported on MS-DOS and Win 95.
+ if (after_pathsep((const char *)fname, (const char *)(fname + namelen))) {
+ filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
+ msg_end();
+ msg_scroll = msg_save;
+ return FAIL;
+ }
}
if (!read_buffer && !read_stdin && !read_fifo) {
perm = os_getperm((const char *)fname);
-#ifdef UNIX
// On Unix it is possible to read a directory, so we have to
// check for it before os_open().
if (perm >= 0 && !S_ISREG(perm) // not a regular file ...
@@ -473,7 +485,7 @@ readfile(
# endif
) {
if (S_ISDIR(perm)) {
- filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
+ filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
} else {
filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
}
@@ -481,7 +493,6 @@ readfile(
msg_scroll = msg_save;
return S_ISDIR(perm) ? NOTDONE : FAIL;
}
-#endif
}
/* Set default or forced 'fileformat' and 'binary'. */
@@ -540,13 +551,6 @@ readfile(
if (fd < 0) { // cannot open at all
msg_scroll = msg_save;
-#ifndef UNIX
- // On non-unix systems we can't open a directory, check here.
- if (os_isdir(fname)) {
- filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
- curbuf->b_p_ro = true; // must use "w!" now
- } else {
-#endif
if (!newfile) {
return FAIL;
}
@@ -604,9 +608,6 @@ readfile(
return FAIL;
}
-#ifndef UNIX
- }
-#endif
/*
* Only set the 'ro' flag for readonly files the first time they are
@@ -1797,6 +1798,7 @@ failed:
linecnt--;
}
curbuf->deleted_bytes = 0;
+ curbuf->deleted_bytes2 = 0;
curbuf->deleted_codepoints = 0;
curbuf->deleted_codeunits = 0;
linecnt = curbuf->b_ml.ml_line_count - linecnt;
@@ -3591,7 +3593,7 @@ restore_backup:
* the backup file our 'original' file.
*/
if (*p_pm && dobackup) {
- char *org = modname((char *)fname, (char *)p_pm, FALSE);
+ char *const org = modname((char *)fname, (char *)p_pm, false);
if (backup != NULL) {
/*
@@ -5553,7 +5555,6 @@ static void au_del_cmd(AutoCmd *ac)
static void au_cleanup(void)
{
AutoPat *ap, **prev_ap;
- AutoCmd *ac, **prev_ac;
event_T event;
if (autocmd_busy || !au_need_clean) {
@@ -5566,11 +5567,11 @@ static void au_cleanup(void)
// Loop over all autocommand patterns.
prev_ap = &(first_autopat[(int)event]);
for (ap = *prev_ap; ap != NULL; ap = *prev_ap) {
- // Loop over all commands for this pattern.
- prev_ac = &(ap->cmds);
bool has_cmd = false;
- for (ac = *prev_ac; ac != NULL; ac = *prev_ac) {
+ // Loop over all commands for this pattern.
+ AutoCmd **prev_ac = &(ap->cmds);
+ for (AutoCmd *ac = *prev_ac; ac != NULL; ac = *prev_ac) {
// Remove the command if the pattern is to be deleted or when
// the command has been marked for deletion.
if (ap->pat == NULL || ac->cmd == NULL) {
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 61a85171e8..197aedabec 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -153,14 +153,22 @@ bool hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp)
return hasFoldingWin(curwin, lnum, firstp, lastp, true, NULL);
}
-/* hasFoldingWin() {{{2 */
+// hasFoldingWin() {{{2
+/// Search folds starting at lnum
+/// @param lnum first line to search
+/// @param[out] first first line of fold containing lnum
+/// @param[out] lastp last line with a fold
+/// @param cache when true: use cached values of window
+/// @param[out] infop where to store fold info
+///
+/// @return true if range contains folds
bool hasFoldingWin(
win_T *const win,
const linenr_T lnum,
linenr_T *const firstp,
linenr_T *const lastp,
- const bool cache, // when true: use cached values of window
- foldinfo_T *const infop // where to store fold info
+ const bool cache,
+ foldinfo_T *const infop
)
{
bool had_folded = false;
@@ -280,26 +288,31 @@ int foldLevel(linenr_T lnum)
// Return false if line is not folded.
bool lineFolded(win_T *const win, const linenr_T lnum)
{
- return foldedCount(win, lnum, NULL) != 0;
+ return fold_info(win, lnum).fi_lines != 0;
}
-/* foldedCount() {{{2 */
-/*
- * Count the number of lines that are folded at line number "lnum".
- * Normally "lnum" is the first line of a possible fold, and the returned
- * number is the number of lines in the fold.
- * Doesn't use caching from the displayed window.
- * Returns number of folded lines from "lnum", or 0 if line is not folded.
- * When "infop" is not NULL, fills *infop with the fold level info.
- */
-long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop)
+/// fold_info() {{{2
+///
+/// Count the number of lines that are folded at line number "lnum".
+/// Normally "lnum" is the first line of a possible fold, and the returned
+/// number is the number of lines in the fold.
+/// Doesn't use caching from the displayed window.
+///
+/// @return with the fold level info.
+/// fi_lines = number of folded lines from "lnum",
+/// or 0 if line is not folded.
+foldinfo_T fold_info(win_T *win, linenr_T lnum)
{
+ foldinfo_T info;
linenr_T last;
- if (hasFoldingWin(win, lnum, NULL, &last, false, infop)) {
- return (long)(last - lnum + 1);
+ if (hasFoldingWin(win, lnum, NULL, &last, false, &info)) {
+ info.fi_lines = (long)(last - lnum + 1);
+ } else {
+ info.fi_lines = 0;
}
- return 0;
+
+ return info;
}
/* foldmethodIsManual() {{{2 */
@@ -356,23 +369,21 @@ int foldmethodIsDiff(win_T *wp)
return wp->w_p_fdm[0] == 'd';
}
-/* closeFold() {{{2 */
-/*
- * Close fold for current window at line "lnum".
- * Repeat "count" times.
- */
-void closeFold(linenr_T lnum, long count)
+// closeFold() {{{2
+/// Close fold for current window at line "lnum".
+/// Repeat "count" times.
+void closeFold(pos_T pos, long count)
{
- setFoldRepeat(lnum, count, FALSE);
+ setFoldRepeat(pos, count, false);
}
/* closeFoldRecurse() {{{2 */
/*
* Close fold for current window at line "lnum" recursively.
*/
-void closeFoldRecurse(linenr_T lnum)
+void closeFoldRecurse(pos_T pos)
{
- (void)setManualFold(lnum, FALSE, TRUE, NULL);
+ (void)setManualFold(pos, false, true, NULL);
}
/* opFoldRange() {{{2 */
@@ -382,28 +393,32 @@ void closeFoldRecurse(linenr_T lnum)
*/
void
opFoldRange(
- linenr_T first,
- linenr_T last,
+ pos_T firstpos,
+ pos_T lastpos,
int opening, // TRUE to open, FALSE to close
int recurse, // TRUE to do it recursively
int had_visual // TRUE when Visual selection used
)
{
- int done = DONE_NOTHING; /* avoid error messages */
+ int done = DONE_NOTHING; // avoid error messages
+ linenr_T first = firstpos.lnum;
+ linenr_T last = lastpos.lnum;
linenr_T lnum;
linenr_T lnum_next;
for (lnum = first; lnum <= last; lnum = lnum_next + 1) {
+ pos_T temp = { lnum, 0, 0 };
lnum_next = lnum;
/* Opening one level only: next fold to open is after the one going to
* be opened. */
if (opening && !recurse)
(void)hasFolding(lnum, NULL, &lnum_next);
- (void)setManualFold(lnum, opening, recurse, &done);
- /* Closing one level only: next line to close a fold is after just
- * closed fold. */
- if (!opening && !recurse)
+ (void)setManualFold(temp, opening, recurse, &done);
+ // Closing one level only: next line to close a fold is after just
+ // closed fold.
+ if (!opening && !recurse) {
(void)hasFolding(lnum, NULL, &lnum_next);
+ }
}
if (done == DONE_NOTHING)
EMSG(_(e_nofold));
@@ -417,18 +432,18 @@ opFoldRange(
* Open fold for current window at line "lnum".
* Repeat "count" times.
*/
-void openFold(linenr_T lnum, long count)
+void openFold(pos_T pos, long count)
{
- setFoldRepeat(lnum, count, TRUE);
+ setFoldRepeat(pos, count, true);
}
/* openFoldRecurse() {{{2 */
/*
* Open fold for current window at line "lnum" recursively.
*/
-void openFoldRecurse(linenr_T lnum)
+void openFoldRecurse(pos_T pos)
{
- (void)setManualFold(lnum, TRUE, TRUE, NULL);
+ (void)setManualFold(pos, true, true, NULL);
}
/* foldOpenCursor() {{{2 */
@@ -443,9 +458,10 @@ void foldOpenCursor(void)
if (hasAnyFolding(curwin))
for (;; ) {
done = DONE_NOTHING;
- (void)setManualFold(curwin->w_cursor.lnum, TRUE, FALSE, &done);
- if (!(done & DONE_ACTION))
+ (void)setManualFold(curwin->w_cursor, true, false, &done);
+ if (!(done & DONE_ACTION)) {
break;
+ }
}
}
@@ -542,21 +558,21 @@ int foldManualAllowed(int create)
// foldCreate() {{{2
/// Create a fold from line "start" to line "end" (inclusive) in the current
/// window.
-void foldCreate(win_T *wp, linenr_T start, linenr_T end)
+void foldCreate(win_T *wp, pos_T start, pos_T end)
{
fold_T *fp;
garray_T *gap;
garray_T fold_ga;
- int i, j;
+ int i;
int cont;
int use_level = FALSE;
int closed = FALSE;
int level = 0;
- linenr_T start_rel = start;
- linenr_T end_rel = end;
+ pos_T start_rel = start;
+ pos_T end_rel = end;
- if (start > end) {
- /* reverse the range */
+ if (start.lnum > end.lnum) {
+ // reverse the range
end = start_rel;
start = end_rel;
start_rel = start;
@@ -573,60 +589,70 @@ void foldCreate(win_T *wp, linenr_T start, linenr_T end)
// Find the place to insert the new fold
gap = &wp->w_folds;
- for (;; ) {
- if (!foldFind(gap, start_rel, &fp))
- break;
- if (fp->fd_top + fp->fd_len > end_rel) {
- /* New fold is completely inside this fold: Go one level deeper. */
- gap = &fp->fd_nested;
- start_rel -= fp->fd_top;
- end_rel -= fp->fd_top;
- if (use_level || fp->fd_flags == FD_LEVEL) {
- use_level = true;
- if (level >= wp->w_p_fdl) {
+ if (gap->ga_len == 0) {
+ i = 0;
+ } else {
+ for (;;) {
+ if (!foldFind(gap, start_rel.lnum, &fp)) {
+ break;
+ }
+ if (fp->fd_top + fp->fd_len > end_rel.lnum) {
+ // New fold is completely inside this fold: Go one level deeper.
+ gap = &fp->fd_nested;
+ start_rel.lnum -= fp->fd_top;
+ end_rel.lnum -= fp->fd_top;
+ if (use_level || fp->fd_flags == FD_LEVEL) {
+ use_level = true;
+ if (level >= wp->w_p_fdl) {
+ closed = true;
+ }
+ } else if (fp->fd_flags == FD_CLOSED) {
closed = true;
}
- } else if (fp->fd_flags == FD_CLOSED) {
- closed = true;
+ level++;
+ } else {
+ // This fold and new fold overlap: Insert here and move some folds
+ // inside the new fold.
+ break;
}
- level++;
- } else {
- /* This fold and new fold overlap: Insert here and move some folds
- * inside the new fold. */
- break;
}
+ i = (int)(fp - (fold_T *)gap->ga_data);
}
- i = (int)(fp - (fold_T *)gap->ga_data);
ga_grow(gap, 1);
{
fp = (fold_T *)gap->ga_data + i;
ga_init(&fold_ga, (int)sizeof(fold_T), 10);
- /* Count number of folds that will be contained in the new fold. */
- for (cont = 0; i + cont < gap->ga_len; ++cont)
- if (fp[cont].fd_top > end_rel)
+ // Count number of folds that will be contained in the new fold.
+ for (cont = 0; i + cont < gap->ga_len; cont++) {
+ if (fp[cont].fd_top > end_rel.lnum) {
break;
+ }
+ }
if (cont > 0) {
ga_grow(&fold_ga, cont);
/* If the first fold starts before the new fold, let the new fold
* start there. Otherwise the existing fold would change. */
- if (start_rel > fp->fd_top)
- start_rel = fp->fd_top;
-
- /* When last contained fold isn't completely contained, adjust end
- * of new fold. */
- if (end_rel < fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1)
- end_rel = fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1;
- /* Move contained folds to inside new fold. */
+ if (start_rel.lnum > fp->fd_top) {
+ start_rel.lnum = fp->fd_top;
+ }
+
+ // When last contained fold isn't completely contained, adjust end
+ // of new fold.
+ if (end_rel.lnum < fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1) {
+ end_rel.lnum = fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1;
+ }
+ // Move contained folds to inside new fold
memmove(fold_ga.ga_data, fp, sizeof(fold_T) * (size_t)cont);
fold_ga.ga_len += cont;
i += cont;
/* Adjust line numbers in contained folds to be relative to the
* new fold. */
- for (j = 0; j < cont; ++j)
- ((fold_T *)fold_ga.ga_data)[j].fd_top -= start_rel;
+ for (int j = 0; j < cont; j++) {
+ ((fold_T *)fold_ga.ga_data)[j].fd_top -= start_rel.lnum;
+ }
}
/* Move remaining entries to after the new fold. */
if (i < gap->ga_len)
@@ -636,8 +662,8 @@ void foldCreate(win_T *wp, linenr_T start, linenr_T end)
/* insert new fold */
fp->fd_nested = fold_ga;
- fp->fd_top = start_rel;
- fp->fd_len = end_rel - start_rel + 1;
+ fp->fd_top = start_rel.lnum;
+ fp->fd_len = end_rel.lnum - start_rel.lnum + 1;
/* We want the new fold to be closed. If it would remain open because
* of using 'foldlevel', need to adjust fd_flags of containing folds.
@@ -766,7 +792,7 @@ void deleteFold(
*/
void clearFolding(win_T *win)
{
- deleteFoldRecurse(&win->w_folds);
+ deleteFoldRecurse(win->w_buffer, &win->w_folds);
win->w_foldinvalid = false;
}
@@ -788,13 +814,15 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
return;
}
- // Mark all folds from top to bot as maybe-small.
- fold_T *fp;
- (void)foldFind(&wp->w_folds, top, &fp);
- while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
- && fp->fd_top < bot) {
- fp->fd_small = kNone;
- fp++;
+ if (wp->w_folds.ga_len > 0) {
+ // Mark all folds from top to bot as maybe-small.
+ fold_T *fp;
+ (void)foldFind(&wp->w_folds, top, &fp);
+ while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
+ && fp->fd_top < bot) {
+ fp->fd_small = kNone;
+ fp++;
+ }
}
if (foldmethodIsIndent(wp)
@@ -1058,11 +1086,16 @@ void cloneFoldGrowArray(garray_T *from, garray_T *to)
* the first fold below it (careful: it can be beyond the end of the array!).
* Returns FALSE when there is no fold that contains "lnum".
*/
-static int foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
+static bool foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
{
linenr_T low, high;
fold_T *fp;
+ if (gap->ga_len == 0) {
+ *fpp = NULL;
+ return false;
+ }
+
/*
* Perform a binary search.
* "low" is lowest index of possible match.
@@ -1086,7 +1119,7 @@ static int foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
}
}
*fpp = fp + low;
- return FALSE;
+ return false;
}
/* foldLevelWin() {{{2 */
@@ -1131,14 +1164,14 @@ static void checkupdate(win_T *wp)
* Open or close fold for current window at line "lnum".
* Repeat "count" times.
*/
-static void setFoldRepeat(linenr_T lnum, long count, int do_open)
+static void setFoldRepeat(pos_T pos, long count, int do_open)
{
int done;
long n;
for (n = 0; n < count; ++n) {
done = DONE_NOTHING;
- (void)setManualFold(lnum, do_open, FALSE, &done);
+ (void)setManualFold(pos, do_open, false, &done);
if (!(done & DONE_ACTION)) {
/* Only give an error message when no fold could be opened. */
if (n == 0 && !(done & DONE_FOLD))
@@ -1155,12 +1188,13 @@ static void setFoldRepeat(linenr_T lnum, long count, int do_open)
*/
static linenr_T
setManualFold(
- linenr_T lnum,
+ pos_T pos,
int opening, // TRUE when opening, FALSE when closing
int recurse, // TRUE when closing/opening recursive
int *donep
)
{
+ linenr_T lnum = pos.lnum;
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
linenr_T dlnum;
@@ -1220,9 +1254,10 @@ setManualFoldWin(
gap = &wp->w_folds;
for (;; ) {
if (!foldFind(gap, lnum, &fp)) {
- /* If there is a following fold, continue there next time. */
- if (fp < (fold_T *)gap->ga_data + gap->ga_len)
+ // If there is a following fold, continue there next time.
+ if (fp != NULL && fp < (fold_T *)gap->ga_data + gap->ga_len) {
next = fp->fd_top + off;
+ }
break;
}
@@ -1313,7 +1348,7 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
fold_T *fp = (fold_T *)gap->ga_data + idx;
if (recursive || GA_EMPTY(&fp->fd_nested)) {
// recursively delete the contained folds
- deleteFoldRecurse(&fp->fd_nested);
+ deleteFoldRecurse(wp->w_buffer, &fp->fd_nested);
gap->ga_len--;
if (idx < gap->ga_len) {
memmove(fp, fp + 1, sizeof(*fp) * (size_t)(gap->ga_len - idx));
@@ -1355,9 +1390,9 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
/*
* Delete nested folds in a fold.
*/
-void deleteFoldRecurse(garray_T *gap)
+void deleteFoldRecurse(buf_T *bp, garray_T *gap)
{
-# define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(&((fd)->fd_nested))
+# define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
GA_DEEP_CLEAR(gap, fold_T, DELETE_FOLD_NESTED);
}
@@ -1389,6 +1424,10 @@ static void foldMarkAdjustRecurse(
linenr_T last;
linenr_T top;
+ if (gap->ga_len == 0) {
+ return;
+ }
+
/* In Insert mode an inserted line at the top of a fold is considered part
* of the fold, otherwise it isn't. */
if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM)
@@ -1593,7 +1632,7 @@ static void setSmallMaybe(garray_T *gap)
* Create a fold from line "start" to line "end" (inclusive) in the current
* window by adding markers.
*/
-static void foldCreateMarkers(win_T *wp, linenr_T start, linenr_T end)
+static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
{
buf_T *buf = wp->w_buffer;
if (!MODIFIABLE(buf)) {
@@ -1608,13 +1647,13 @@ static void foldCreateMarkers(win_T *wp, linenr_T start, linenr_T end)
/* Update both changes here, to avoid all folds after the start are
* changed when the start marker is inserted and the end isn't. */
// TODO(teto): pass the buffer
- changed_lines(start, (colnr_T)0, end, 0L, false);
+ changed_lines(start.lnum, (colnr_T)0, end.lnum, 0L, false);
// Note: foldAddMarker() may not actually change start and/or end if
// u_save() is unable to save the buffer line, but we send the
// nvim_buf_lines_event anyway since it won't do any harm.
- int64_t num_changed = 1 + end - start;
- buf_updates_send_changes(buf, start, num_changed, num_changed, true);
+ int64_t num_changed = 1 + end.lnum - start.lnum;
+ buf_updates_send_changes(buf, start.lnum, num_changed, num_changed, true);
}
/* foldAddMarker() {{{2 */
@@ -1622,13 +1661,14 @@ static void foldCreateMarkers(win_T *wp, linenr_T start, linenr_T end)
* Add "marker[markerlen]" in 'commentstring' to line "lnum".
*/
static void foldAddMarker(
- buf_T *buf, linenr_T lnum, const char_u *marker, size_t markerlen)
+ buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen)
{
char_u *cms = buf->b_p_cms;
char_u *line;
char_u *newline;
char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s");
bool line_is_comment = false;
+ linenr_T lnum = pos.lnum;
// Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end
line = ml_get_buf(buf, lnum, false);
@@ -1727,19 +1767,23 @@ static void foldDelMarker(
STRCPY(newline + (p - line), p + len);
ml_replace_buf(buf, lnum, newline, false);
extmark_splice_cols(buf, (int)lnum-1, (int)(p - line),
- (int)len,
- 0, kExtmarkUndo);
+ (int)len, 0, kExtmarkUndo);
}
break;
}
}
// get_foldtext() {{{2
-/// Return the text for a closed fold at line "lnum", with last line "lnume".
-/// When 'foldtext' isn't set puts the result in "buf[FOLD_TEXT_LEN]".
+/// Generates text to display
+///
+/// @param buf allocated memory of length FOLD_TEXT_LEN. Used when 'foldtext'
+/// isn't set puts the result in "buf[FOLD_TEXT_LEN]".
+/// @param at line "lnum", with last line "lnume".
+/// @return the text for a closed fold
+///
/// Otherwise the result is in allocated memory.
char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
- foldinfo_T *foldinfo, char_u *buf)
+ foldinfo_T foldinfo, char_u *buf)
FUNC_ATTR_NONNULL_ARG(1)
{
char_u *text = NULL;
@@ -1767,11 +1811,12 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
set_vim_var_nr(VV_FOLDSTART, (varnumber_T) lnum);
set_vim_var_nr(VV_FOLDEND, (varnumber_T) lnume);
- /* Set "v:folddashes" to a string of "level" dashes. */
- /* Set "v:foldlevel" to "level". */
- level = foldinfo->fi_level;
- if (level > (int)sizeof(dashes) - 1)
+ // Set "v:folddashes" to a string of "level" dashes.
+ // Set "v:foldlevel" to "level".
+ level = foldinfo.fi_level;
+ if (level > (int)sizeof(dashes) - 1) {
level = (int)sizeof(dashes) - 1;
+ }
memset(dashes, '-', (size_t)level);
dashes[level] = NUL;
set_vim_var_string(VV_FOLDDASHES, dashes, -1);
@@ -2265,14 +2310,15 @@ static linenr_T foldUpdateIEMSRecurse(
/* Find an existing fold to re-use. Preferably one that
* includes startlnum, otherwise one that ends just before
* startlnum or starts after it. */
- if (foldFind(gap, startlnum, &fp)
- || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
- && fp->fd_top <= firstlnum)
- || foldFind(gap, firstlnum - concat, &fp)
- || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
- && ((lvl < level && fp->fd_top < flp->lnum)
- || (lvl >= level
- && fp->fd_top <= flp->lnum_save)))) {
+ if (gap->ga_len > 0
+ && (foldFind(gap, startlnum, &fp)
+ || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
+ && fp->fd_top <= firstlnum)
+ || foldFind(gap, firstlnum - concat, &fp)
+ || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
+ && ((lvl < level && fp->fd_top < flp->lnum)
+ || (lvl >= level
+ && fp->fd_top <= flp->lnum_save))))) {
if (fp->fd_top + fp->fd_len + concat > firstlnum) {
/* Use existing fold for the new fold. If it starts
* before where we started looking, extend it. If it
@@ -2363,7 +2409,11 @@ static linenr_T foldUpdateIEMSRecurse(
} else {
/* Insert new fold. Careful: ga_data may be NULL and it
* may change! */
- i = (int)(fp - (fold_T *)gap->ga_data);
+ if (gap->ga_len == 0) {
+ i = 0;
+ } else {
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ }
foldInsert(gap, i);
fp = (fold_T *)gap->ga_data + i;
/* The new fold continues until bot, unless we find the
@@ -2559,9 +2609,10 @@ static void foldInsert(garray_T *gap, int i)
ga_grow(gap, 1);
fp = (fold_T *)gap->ga_data + i;
- if (i < gap->ga_len)
+ if (gap->ga_len > 0 && i < gap->ga_len) {
memmove(fp + 1, fp, sizeof(fold_T) * (size_t)(gap->ga_len - i));
- ++gap->ga_len;
+ }
+ gap->ga_len++;
ga_init(&fp->fd_nested, (int)sizeof(fold_T), 10);
}
@@ -2596,17 +2647,18 @@ static void foldSplit(buf_T *buf, garray_T *const gap,
* any between top and bot, they have been removed by the caller. */
garray_T *const gap1 = &fp->fd_nested;
garray_T *const gap2 = &fp[1].fd_nested;
- (void)(foldFind(gap1, bot + 1 - fp->fd_top, &fp2));
- const int len = (int)((fold_T *)gap1->ga_data + gap1->ga_len - fp2);
- if (len > 0) {
- ga_grow(gap2, len);
- for (int idx = 0; idx < len; idx++) {
- ((fold_T *)gap2->ga_data)[idx] = fp2[idx];
- ((fold_T *)gap2->ga_data)[idx].fd_top
- -= fp[1].fd_top - fp->fd_top;
- }
- gap2->ga_len = len;
- gap1->ga_len -= len;
+ if (foldFind(gap1, bot + 1 - fp->fd_top, &fp2)) {
+ const int len = (int)((fold_T *)gap1->ga_data + gap1->ga_len - fp2);
+ if (len > 0) {
+ ga_grow(gap2, len);
+ for (int idx = 0; idx < len; idx++) {
+ ((fold_T *)gap2->ga_data)[idx] = fp2[idx];
+ ((fold_T *)gap2->ga_data)[idx].fd_top
+ -= fp[1].fd_top - fp->fd_top;
+ }
+ gap2->ga_len = len;
+ gap1->ga_len -= len;
+ }
}
fp->fd_len = top - fp->fd_top;
fold_changed = true;
@@ -2641,7 +2693,7 @@ static void foldRemove(
return; // nothing to do
}
- for (;; ) {
+ while (gap->ga_len > 0) {
// Find fold that includes top or a following one.
if (foldFind(gap, top, &fp) && fp->fd_top < top) {
// 2: or 3: need to delete nested folds
@@ -2657,7 +2709,8 @@ static void foldRemove(
fold_changed = true;
continue;
}
- if (fp >= (fold_T *)(gap->ga_data) + gap->ga_len
+ if (gap->ga_data == NULL
+ || fp >= (fold_T *)(gap->ga_data) + gap->ga_len
|| fp->fd_top > bot) {
// 6: Found a fold below bot, can stop looking.
break;
@@ -2738,7 +2791,8 @@ static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end)
}
#define FOLD_END(fp) ((fp)->fd_top + (fp)->fd_len - 1)
-#define VALID_FOLD(fp, gap) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
+#define VALID_FOLD(fp, gap) \
+ ((gap)->ga_len > 0 && (fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
#define FOLD_INDEX(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
void foldMoveRange(
win_T *const wp, garray_T *gap,
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index f35b328fb1..95c4b0c1dc 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -18,6 +18,7 @@ typedef struct foldinfo {
other fields are invalid */
int fi_low_level; /* lowest fold level that starts in the same
line */
+ long fi_lines;
} foldinfo_T;
diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua
index 075d8ba9cc..849c82f50e 100644
--- a/src/nvim/generators/gen_ex_cmds.lua
+++ b/src/nvim/generators/gen_ex_cmds.lua
@@ -24,8 +24,6 @@ local defsfile = io.open(defsfname, 'w')
local defs = require('ex_cmds')
-local first = true
-
local byte_a = string.byte('a')
local byte_z = string.byte('z')
local a_to_z = byte_z - byte_a + 1
@@ -41,8 +39,7 @@ static const uint16_t cmdidxs1[%u] = {
-- fit in a byte.
local cmdidxs2_out = string.format([[
static const char_u cmdidxs2[%u][%u] = {
-/* a b c d e f g h i j k l m n o p q r s t u v w x y z */
-
+ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
]], a_to_z, a_to_z)
enumfile:write([[
@@ -50,10 +47,8 @@ typedef enum CMD_index {
]])
defsfile:write(string.format([[
static const int command_count = %u;
-]], #defs))
-defsfile:write(string.format([[
static CommandDefinition cmdnames[%u] = {
-]], #defs))
+]], #defs, #defs))
local cmds, cmdidxs1, cmdidxs2 = {}, {}, {}
for _, cmd in ipairs(defs) do
local enumname = cmd.enum or ('CMD_' .. cmd.command)
@@ -61,11 +56,6 @@ for _, cmd in ipairs(defs) do
if byte_a <= byte_cmd and byte_cmd <= byte_z then
table.insert(cmds, cmd.command)
end
- if first then
- first = false
- else
- defsfile:write(',\n')
- end
enumfile:write(' ' .. enumname .. ',\n')
defsfile:write(string.format([[
[%s] = {
@@ -73,7 +63,8 @@ for _, cmd in ipairs(defs) do
.cmd_func = (ex_func_T)&%s,
.cmd_argt = %uL,
.cmd_addr_type = %i
- }]], enumname, cmd.command, cmd.func, cmd.flags, cmd.addr_type))
+ },
+]], enumname, cmd.command, cmd.func, cmd.flags, cmd.addr_type))
end
for i = #cmds, 1, -1 do
local cmd = cmds[i]
@@ -104,15 +95,14 @@ for i = byte_a, byte_z do
end
cmdidxs2_out = cmdidxs2_out .. ' },\n'
end
-defsfile:write([[
-
-};
-]])
enumfile:write([[
CMD_SIZE,
CMD_USER = -1,
CMD_USER_BUF = -2
} cmdidx_T;
]])
-defsfile:write(cmdidxs1_out .. '};\n')
-defsfile:write(cmdidxs2_out .. '};\n')
+defsfile:write(string.format([[
+};
+%s};
+%s};
+]], cmdidxs1_out, cmdidxs2_out))
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index a8cf496cb9..d80a6219eb 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -141,9 +141,6 @@ local dump_option = function(i, o)
elseif #o.scope == 1 and o.scope[1] == 'window' then
w(' .var=VAR_WIN')
end
- if o.enable_if then
- w('#endif')
- end
if #o.scope == 1 and o.scope[1] == 'global' then
w(' .indir=PV_NONE')
else
@@ -163,6 +160,12 @@ local dump_option = function(i, o)
defines['PV_' .. varname:sub(3):upper()] = pv_name
w(' .indir=' .. pv_name)
end
+ if o.enable_if then
+ w('#else')
+ w(' .var=NULL')
+ w(' .indir=PV_NONE')
+ w('#endif')
+ end
if o.defaults then
if o.defaults.condition then
w(get_cond(o.defaults.condition))
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 5ab5a7db1b..456979be00 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -27,6 +27,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/func_attr.h"
+#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -455,6 +456,9 @@ void flush_buffers(flush_buffers_T flush_typeahead)
typebuf.tb_silent = 0;
cmd_silent = false;
typebuf.tb_no_abbr_cnt = 0;
+ if (++typebuf.tb_change_cnt == 0) {
+ typebuf.tb_change_cnt = 1;
+ }
}
/*
@@ -1524,6 +1528,17 @@ int vgetc(void)
c = utf_ptr2char(buf);
}
+ // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed
+ // something with a meta- or alt- modifier that was not mapped, interpret
+ // <M-x> as <Esc>x rather than as an unbound meta keypress. #8213
+ if (!no_mapping && KeyTyped
+ && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) {
+ mod_mask = 0;
+ stuffcharReadbuff(c);
+ u_sync(false);
+ c = ESC;
+ }
+
break;
}
}
@@ -1535,6 +1550,9 @@ int vgetc(void)
*/
may_garbage_collect = false;
+ // Exec lua callbacks for on_keystroke
+ nlua_execute_log_keystroke(c);
+
return c;
}
@@ -2037,14 +2055,19 @@ static int vgetorpeek(bool advance)
*/
if (mp->m_expr) {
int save_vgetc_busy = vgetc_busy;
+ const bool save_may_garbage_collect = may_garbage_collect;
vgetc_busy = 0;
+ may_garbage_collect = false;
+
save_m_keys = vim_strsave(mp->m_keys);
save_m_str = vim_strsave(mp->m_str);
s = eval_map_expr(save_m_str, NUL);
vgetc_busy = save_vgetc_busy;
- } else
+ may_garbage_collect = save_may_garbage_collect;
+ } else {
s = mp->m_str;
+ }
/*
* Insert the 'to' part in the typebuf.tb_buf.
@@ -4181,7 +4204,6 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
{
char_u *str = strstart;
int c;
- int modifiers;
// :map xx <Nop>
if (*str == NUL && what == 1) {
@@ -4208,7 +4230,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
* when they are read back.
*/
if (c == K_SPECIAL && what != 2) {
- modifiers = 0x0;
+ int modifiers = 0;
if (str[1] == KS_MODIFIER) {
modifiers = str[2];
str += 3;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index d6d00d6e83..2db8689a56 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -125,8 +125,6 @@ typedef off_t off_T;
EXTERN int mod_mask INIT(= 0x0); // current key modifiers
-EXTERN bool lua_attr_active INIT(= false);
-
// Cmdline_row is the row where the command line starts, just below the
// last window.
// When the cmdline gets longer than the available space the screen gets
@@ -208,7 +206,7 @@ EXTERN int need_clr_eos INIT(= false); // need to clear text before
// displaying a message.
EXTERN int emsg_skip INIT(= 0); // don't display errors for
// expression that is skipped
-EXTERN int emsg_severe INIT(= false); // use message of next of several
+EXTERN bool emsg_severe INIT(= false); // use message of next of several
// emsg() calls for throw
EXTERN int did_endif INIT(= false); // just had ":endif"
EXTERN dict_T vimvardict; // Dictionary with v: variables
@@ -353,9 +351,11 @@ EXTERN int t_colors INIT(= 256); // int value of T_CCO
// position. Search_match_lines is the number of lines after the match (0 for
// a match within one line), search_match_endcol the column number of the
// character just after the match in the last line.
-EXTERN int highlight_match INIT(= false); // show search match pos
-EXTERN linenr_T search_match_lines; // lines of of matched string
-EXTERN colnr_T search_match_endcol; // col nr of match end
+EXTERN bool highlight_match INIT(= false); // show search match pos
+EXTERN linenr_T search_match_lines; // lines of of matched string
+EXTERN colnr_T search_match_endcol; // col nr of match end
+EXTERN linenr_T search_first_line INIT(= 0); // for :{FIRST},{last}s/pat
+EXTERN linenr_T search_last_line INIT(= MAXLNUM); // for :{first},{LAST}s/pat
EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once
diff --git a/src/nvim/hashtab.h b/src/nvim/hashtab.h
index 19633d455f..c82a6cc121 100644
--- a/src/nvim/hashtab.h
+++ b/src/nvim/hashtab.h
@@ -51,6 +51,7 @@ typedef struct hashitem_S {
/// Initial size for a hashtable.
/// Our items are relatively small and growing is expensive, thus start with 16.
/// Must be a power of 2.
+/// This allows for storing 10 items (2/3 of 16) before a resize is needed.
#define HT_INIT_SIZE 16
/// An array-based hashtable.
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index fb277b25fd..bb0fdfec01 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -297,11 +297,12 @@ int set_indent(int size, int flags)
if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) {
ml_replace(curwin->w_cursor.lnum, newline, false);
if (!(flags & SIN_NOMARK)) {
- extmark_splice(curbuf,
- (int)curwin->w_cursor.lnum-1, skipcols,
- 0, (int)(p-oldline) - skipcols,
- 0, (int)(s-newline) - skipcols,
- kExtmarkUndo);
+ extmark_splice_cols(curbuf,
+ (int)curwin->w_cursor.lnum-1,
+ skipcols,
+ (int)(p-oldline) - skipcols,
+ (int)(s-newline) - skipcols,
+ kExtmarkUndo);
}
if (flags & SIN_CHANGED) {
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index a553110552..2b6f022d9d 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -530,13 +530,24 @@ unsigned int trans_special(const char_u **srcp, const size_t src_len,
{
int modifiers = 0;
int key;
- unsigned int dlen = 0;
key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string);
if (key == 0) {
return 0;
}
+ return special_to_buf(key, modifiers, keycode, dst);
+}
+
+/// Put the character sequence for "key" with "modifiers" into "dst" and return
+/// the resulting length.
+/// When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL.
+/// The sequence is not NUL terminated.
+/// This is how characters in a string are encoded.
+unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
+{
+ unsigned int dlen = 0;
+
// Put the appropriate modifier in a string.
if (modifiers != 0) {
dst[dlen++] = K_SPECIAL;
diff --git a/src/nvim/log.h b/src/nvim/log.h
index 17ff095473..f2e74df031 100644
--- a/src/nvim/log.h
+++ b/src/nvim/log.h
@@ -5,6 +5,17 @@
#include <stdbool.h>
#include "auto/config.h"
+#include "nvim/macros.h"
+
+// USDT probes. Example invokation:
+// NVIM_PROBE(nvim_foo_bar, 1, string.data);
+#if defined(HAVE_SYS_SDT_H)
+#include <sys/sdt.h> // NOLINT
+#define NVIM_PROBE(name, n, ...) STAP_PROBE##n(neovim, name, __VA_ARGS__)
+#else
+#define NVIM_PROBE(name, n, ...)
+#endif
+
#define DEBUG_LOG_LEVEL 0
#define INFO_LOG_LEVEL 1
@@ -68,6 +79,10 @@
# define LOG_CALLSTACK_TO_FILE(fp) log_callstack_to_file(fp, __func__, __LINE__)
#endif
+#if NVIM_HAS_INCLUDE("sanitizer/asan_interface.h")
+# include "sanitizer/asan_interface.h"
+#endif
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "log.h.generated.h"
#endif
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 32e804d213..030df69caa 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -1249,6 +1249,13 @@ type_error:
return ret;
}
+LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
+{
+ LuaRef rv = nlua_ref(lstate, -1);
+ lua_pop(lstate, 1);
+ return rv;
+}
+
#define GENERATE_INDEX_FUNCTION(type) \
type nlua_pop_##type(lua_State *lstate, Error *err) \
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 86da517685..5c665920b5 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -299,45 +299,66 @@ static int nlua_wait(lua_State *lstate)
return luaL_error(lstate, "timeout must be > 0");
}
- // Check if condition can be called.
- bool is_function = (lua_type(lstate, 2) == LUA_TFUNCTION);
+ int lua_top = lua_gettop(lstate);
- // Check if condition is callable table
- if (!is_function && luaL_getmetafield(lstate, 2, "__call") != 0) {
- is_function = (lua_type(lstate, -1) == LUA_TFUNCTION);
- lua_pop(lstate, 1);
- }
+ // Check if condition can be called.
+ bool is_function = false;
+ if (lua_top >= 2 && !lua_isnil(lstate, 2)) {
+ is_function = (lua_type(lstate, 2) == LUA_TFUNCTION);
+
+ // Check if condition is callable table
+ if (!is_function && luaL_getmetafield(lstate, 2, "__call") != 0) {
+ is_function = (lua_type(lstate, -1) == LUA_TFUNCTION);
+ lua_pop(lstate, 1);
+ }
- if (!is_function) {
- lua_pushliteral(lstate, "vim.wait: condition must be a function");
- return lua_error(lstate);
+ if (!is_function) {
+ lua_pushliteral(
+ lstate,
+ "vim.wait: if passed, condition must be a function");
+ return lua_error(lstate);
+ }
}
intptr_t interval = 200;
- if (lua_gettop(lstate) >= 3) {
+ if (lua_top >= 3 && !lua_isnil(lstate, 3)) {
interval = luaL_checkinteger(lstate, 3);
if (interval < 0) {
return luaL_error(lstate, "interval must be > 0");
}
}
+ bool fast_only = false;
+ if (lua_top >= 4) {
+ fast_only = lua_toboolean(lstate, 4);
+ }
+
+ MultiQueue *loop_events = fast_only || in_fast_callback > 0
+ ? main_loop.fast_events : main_loop.events;
+
TimeWatcher *tw = xmalloc(sizeof(TimeWatcher));
// Start dummy timer.
time_watcher_init(&main_loop, tw, NULL);
- tw->events = main_loop.events;
+ tw->events = loop_events;
tw->blockable = true;
- time_watcher_start(tw, dummy_timer_due_cb,
- (uint64_t)interval, (uint64_t)interval);
+ time_watcher_start(
+ tw,
+ dummy_timer_due_cb,
+ (uint64_t)interval,
+ (uint64_t)interval);
int pcall_status = 0;
bool callback_result = false;
LOOP_PROCESS_EVENTS_UNTIL(
&main_loop,
- main_loop.events,
+ loop_events,
(int)timeout,
- nlua_wait_condition(lstate, &pcall_status, &callback_result) || got_int);
+ is_function ? nlua_wait_condition(
+ lstate,
+ &pcall_status,
+ &callback_result) : false || got_int);
// Stop dummy timer
time_watcher_stop(tw);
@@ -845,7 +866,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref)
}
}
-void executor_free_luaref(LuaRef ref)
+void api_free_luaref(LuaRef ref)
{
lua_State *const lstate = nlua_enter();
nlua_unref(lstate, ref);
@@ -879,8 +900,8 @@ LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref)
/// @param[out] ret_tv Location where result will be saved.
///
/// @return Result of the execution.
-void executor_eval_lua(const String str, typval_T *const arg,
- typval_T *const ret_tv)
+void nlua_typval_eval(const String str, typval_T *const arg,
+ typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
#define EVALHEADER "local _A=select(1,...) return ("
@@ -902,8 +923,8 @@ void executor_eval_lua(const String str, typval_T *const arg,
}
}
-void executor_call_lua(const char *str, size_t len, typval_T *const args,
- int argcount, typval_T *ret_tv)
+void nlua_typval_call(const char *str, size_t len, typval_T *const args,
+ int argcount, typval_T *ret_tv)
FUNC_ATTR_NONNULL_ALL
{
#define CALLHEADER "return "
@@ -1006,14 +1027,14 @@ int typval_exec_lua_callable(
/// Execute Lua string
///
-/// Used for nvim_exec_lua().
+/// Used for nvim_exec_lua() and internally to execute a lua string.
///
/// @param[in] str String to execute.
/// @param[in] args array of ... args
/// @param[out] err Location where error will be saved.
///
/// @return Return value of the execution.
-Object executor_exec_lua_api(const String str, const Array args, Error *err)
+Object nlua_exec(const String str, const Array args, Error *err)
{
lua_State *const lstate = nlua_enter();
@@ -1040,17 +1061,30 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err)
return nlua_pop_Object(lstate, false, err);
}
-Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args,
- bool retval, Error *err)
+/// call a LuaRef as a function (or table with __call metamethod)
+///
+/// @param ref the reference to call (not consumed)
+/// @param name if non-NULL, sent to callback as first arg
+/// if NULL, only args are used
+/// @param retval if true, convert return value to Object
+/// if false, discard return value
+/// @param err Error details, if any (if NULL, errors are echoed)
+/// @return Return value of function, if retval was set. Otherwise NIL.
+Object nlua_call_ref(LuaRef ref, const char *name, Array args,
+ bool retval, Error *err)
{
lua_State *const lstate = nlua_enter();
nlua_pushref(lstate, ref);
- lua_pushstring(lstate, name);
+ int nargs = (int)args.size;
+ if (name != NULL) {
+ lua_pushstring(lstate, name);
+ nargs++;
+ }
for (size_t i = 0; i < args.size; i++) {
nlua_push_Object(lstate, args.items[i], false);
}
- if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) {
+ if (lua_pcall(lstate, nargs, retval ? 1 : 0, 0)) {
// if err is passed, the caller will deal with the error.
if (err) {
size_t len;
@@ -1465,3 +1499,40 @@ void nlua_free_typval_dict(dict_T *const d)
d->lua_table_ref = LUA_NOREF;
}
}
+
+void nlua_execute_log_keystroke(int c)
+{
+ char_u buf[NUMBUFLEN];
+ size_t buf_len = special_to_buf(c, mod_mask, false, buf);
+
+ lua_State *const lstate = nlua_enter();
+
+#ifndef NDEBUG
+ int top = lua_gettop(lstate);
+#endif
+
+ // [ vim ]
+ lua_getglobal(lstate, "vim");
+
+ // [ vim, vim._log_keystroke ]
+ lua_getfield(lstate, -1, "_log_keystroke");
+ luaL_checktype(lstate, -1, LUA_TFUNCTION);
+
+ // [ vim, vim._log_keystroke, buf ]
+ lua_pushlstring(lstate, (const char *)buf, buf_len);
+
+ if (lua_pcall(lstate, 1, 0, 0)) {
+ nlua_error(
+ lstate,
+ _("Error executing vim.log_keystroke lua callback: %.*s"));
+ }
+
+ // [ vim ]
+ lua_pop(lstate, 1);
+
+#ifndef NDEBUG
+ // [ ]
+ assert(top == lua_gettop(lstate));
+#endif
+}
+
diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h
index 6599b44584..1d7a15d9aa 100644
--- a/src/nvim/lua/executor.h
+++ b/src/nvim/lua/executor.h
@@ -24,6 +24,15 @@ EXTERN LuaRef nlua_empty_dict_ref INIT(= LUA_NOREF);
memcpy(&err_->msg[0], s, sizeof(s)); \
} while (0)
+#define NLUA_CLEAR_REF(x) \
+ do { \
+ /* Take the address to avoid double evaluation. #1375 */ \
+ if ((x) != LUA_NOREF) { \
+ api_free_luaref(x); \
+ (x) = LUA_NOREF; \
+ } \
+ } while (0)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/executor.h.generated.h"
#endif
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 138031237e..5258352e72 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -39,10 +39,11 @@ typedef struct {
static struct luaL_Reg parser_meta[] = {
{ "__gc", parser_gc },
{ "__tostring", parser_tostring },
- { "parse_buf", parser_parse_buf },
+ { "parse", parser_parse },
{ "edit", parser_edit },
{ "tree", parser_tree },
{ "set_included_ranges", parser_set_ranges },
+ { "included_ranges", parser_get_ranges },
{ NULL, NULL }
};
@@ -62,6 +63,7 @@ static struct luaL_Reg node_meta[] = {
{ "end_", node_end },
{ "type", node_type },
{ "symbol", node_symbol },
+ { "field", node_field },
{ "named", node_named },
{ "missing", node_missing },
{ "has_error", node_has_error },
@@ -73,6 +75,7 @@ static struct luaL_Reg node_meta[] = {
{ "descendant_for_range", node_descendant_for_range },
{ "named_descendant_for_range", node_named_descendant_for_range },
{ "parent", node_parent },
+ { "iter_children", node_iter_children },
{ "_rawquery", node_rawquery },
{ NULL, NULL }
};
@@ -84,12 +87,17 @@ static struct luaL_Reg query_meta[] = {
{ NULL, NULL }
};
-// cursor is not exposed, but still needs garbage collection
+// cursors are not exposed, but still needs garbage collection
static struct luaL_Reg querycursor_meta[] = {
{ "__gc", querycursor_gc },
{ NULL, NULL }
};
+static struct luaL_Reg treecursor_meta[] = {
+ { "__gc", treecursor_gc },
+ { NULL, NULL }
+};
+
static PMap(cstr_t) *langs;
static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
@@ -116,6 +124,7 @@ void tslua_init(lua_State *L)
build_meta(L, "treesitter_node", node_meta);
build_meta(L, "treesitter_query", query_meta);
build_meta(L, "treesitter_querycursor", querycursor_meta);
+ build_meta(L, "treesitter_treecursor", treecursor_meta);
}
int tslua_has_language(lua_State *L)
@@ -166,6 +175,14 @@ int tslua_add_language(lua_State *L)
return luaL_error(L, "Failed to load parser: internal error");
}
+ uint32_t lang_version = ts_language_version(lang);
+ if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) {
+ return luaL_error(
+ L,
+ "ABI version mismatch : expected %" PRIu32 ", found %" PRIu32,
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION, lang_version);
+ }
+
pmap_put(cstr_t)(langs, xstrdup(lang_name), lang);
lua_pushboolean(L, true);
@@ -278,43 +295,84 @@ static const char *input_cb(void *payload, uint32_t byte_index,
}
char_u *line = ml_get_buf(bp, position.row+1, false);
size_t len = STRLEN(line);
-
if (position.column > len) {
*bytes_read = 0;
- } else {
- size_t tocopy = MIN(len-position.column, BUFSIZE);
-
- memcpy(buf, line+position.column, tocopy);
- // Translate embedded \n to NUL
- memchrsub(buf, '\n', '\0', tocopy);
- *bytes_read = (uint32_t)tocopy;
- if (tocopy < BUFSIZE) {
- // now add the final \n. If it didn't fit, input_cb will be called again
- // on the same line with advanced column.
- buf[tocopy] = '\n';
- (*bytes_read)++;
- }
+ return "";
+ }
+ size_t tocopy = MIN(len-position.column, BUFSIZE);
+
+ memcpy(buf, line+position.column, tocopy);
+ // Translate embedded \n to NUL
+ memchrsub(buf, '\n', '\0', tocopy);
+ *bytes_read = (uint32_t)tocopy;
+ if (tocopy < BUFSIZE) {
+ // now add the final \n. If it didn't fit, input_cb will be called again
+ // on the same line with advanced column.
+ buf[tocopy] = '\n';
+ (*bytes_read)++;
}
return buf;
#undef BUFSIZE
}
-static int parser_parse_buf(lua_State *L)
+static void push_ranges(lua_State *L,
+ const TSRange *ranges,
+ const unsigned int length)
+{
+ lua_createtable(L, length, 0);
+ for (size_t i = 0; i < length; i++) {
+ lua_createtable(L, 4, 0);
+ lua_pushinteger(L, ranges[i].start_point.row);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, ranges[i].start_point.column);
+ lua_rawseti(L, -2, 2);
+ lua_pushinteger(L, ranges[i].end_point.row);
+ lua_rawseti(L, -2, 3);
+ lua_pushinteger(L, ranges[i].end_point.column);
+ lua_rawseti(L, -2, 4);
+
+ lua_rawseti(L, -2, i+1);
+ }
+}
+
+static int parser_parse(lua_State *L)
{
TSLua_parser *p = parser_check(L);
if (!p) {
return 0;
}
- long bufnr = lua_tointeger(L, 2);
- buf_T *buf = handle_get_buffer(bufnr);
+ TSTree *new_tree;
+ size_t len;
+ const char *str;
+ long bufnr;
+ buf_T *buf;
+ TSInput input;
+
+ // This switch is necessary because of the behavior of lua_isstring, that
+ // consider numbers as strings...
+ switch (lua_type(L, 2)) {
+ case LUA_TSTRING:
+ str = lua_tolstring(L, 2, &len);
+ new_tree = ts_parser_parse_string(p->parser, p->tree, str, len);
+ break;
+
+ case LUA_TNUMBER:
+ bufnr = lua_tointeger(L, 2);
+ buf = handle_get_buffer(bufnr);
+
+ if (!buf) {
+ return luaL_error(L, "invalid buffer handle: %d", bufnr);
+ }
- if (!buf) {
- return luaL_error(L, "invalid buffer handle: %d", bufnr);
- }
+ input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
+ new_tree = ts_parser_parse(p->parser, p->tree, input);
- TSInput input = { (void *)buf, input_cb, TSInputEncodingUTF8 };
- TSTree *new_tree = ts_parser_parse(p->parser, p->tree, input);
+ break;
+
+ default:
+ return luaL_error(L, "invalid argument to parser:parse()");
+ }
uint32_t n_ranges = 0;
TSRange *changed = p->tree ? ts_tree_get_changed_ranges(p->tree, new_tree,
@@ -326,20 +384,8 @@ static int parser_parse_buf(lua_State *L)
tslua_push_tree(L, p->tree);
- lua_createtable(L, n_ranges, 0);
- for (size_t i = 0; i < n_ranges; i++) {
- lua_createtable(L, 4, 0);
- lua_pushinteger(L, changed[i].start_point.row);
- lua_rawseti(L, -2, 1);
- lua_pushinteger(L, changed[i].start_point.column);
- lua_rawseti(L, -2, 2);
- lua_pushinteger(L, changed[i].end_point.row);
- lua_rawseti(L, -2, 3);
- lua_pushinteger(L, changed[i].end_point.column);
- lua_rawseti(L, -2, 4);
+ push_ranges(L, changed, n_ranges);
- lua_rawseti(L, -2, i+1);
- }
xfree(changed);
return 2;
}
@@ -437,6 +483,21 @@ static int parser_set_ranges(lua_State *L)
return 0;
}
+static int parser_get_ranges(lua_State *L)
+{
+ TSLua_parser *p = parser_check(L);
+ if (!p || !p->parser) {
+ return 0;
+ }
+
+ unsigned int len;
+ const TSRange *ranges = ts_parser_included_ranges(p->parser, &len);
+
+ push_ranges(L, ranges, len);
+
+ return 1;
+}
+
// Tree methods
@@ -646,6 +707,34 @@ static int node_symbol(lua_State *L)
return 1;
}
+static int node_field(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+
+ size_t name_len;
+ const char *field_name = luaL_checklstring(L, 2, &name_len);
+
+ TSTreeCursor cursor = ts_tree_cursor_new(node);
+
+ lua_newtable(L); // [table]
+ unsigned int curr_index = 0;
+
+ if (ts_tree_cursor_goto_first_child(&cursor)) {
+ do {
+ if (!STRCMP(field_name, ts_tree_cursor_current_field_name(&cursor))) {
+ push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node]
+ lua_rawseti(L, -2, ++curr_index);
+ }
+ } while (ts_tree_cursor_goto_next_sibling(&cursor));
+ }
+
+ ts_tree_cursor_delete(&cursor);
+ return 1;
+}
+
static int node_named(lua_State *L)
{
TSNode node;
@@ -746,6 +835,74 @@ static int node_named_descendant_for_range(lua_State *L)
return 1;
}
+static int node_next_child(lua_State *L)
+{
+ TSTreeCursor *ud = luaL_checkudata(
+ L, lua_upvalueindex(1), "treesitter_treecursor");
+ if (!ud) {
+ return 0;
+ }
+
+ TSNode source;
+ if (!node_check(L, lua_upvalueindex(2), &source)) {
+ return 0;
+ }
+
+ // First call should return first child
+ if (ts_node_eq(source, ts_tree_cursor_current_node(ud))) {
+ if (ts_tree_cursor_goto_first_child(ud)) {
+ goto push;
+ } else {
+ goto end;
+ }
+ }
+
+ if (ts_tree_cursor_goto_next_sibling(ud)) {
+push:
+ push_node(
+ L,
+ ts_tree_cursor_current_node(ud),
+ lua_upvalueindex(2)); // [node]
+
+ const char * field = ts_tree_cursor_current_field_name(ud);
+
+ if (field != NULL) {
+ lua_pushstring(L, ts_tree_cursor_current_field_name(ud));
+ } else {
+ lua_pushnil(L);
+ } // [node, field_name_or_nil]
+ return 2;
+ }
+
+end:
+ return 0;
+}
+
+static int node_iter_children(lua_State *L)
+{
+ TSNode source;
+ if (!node_check(L, 1, &source)) {
+ return 0;
+ }
+
+ TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata]
+ *ud = ts_tree_cursor_new(source);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_treecursor"); // [udata, mt]
+ lua_setmetatable(L, -2); // [udata]
+ lua_pushvalue(L, 1); // [udata, source_node]
+ lua_pushcclosure(L, node_next_child, 2);
+
+ return 1;
+}
+
+static int treecursor_gc(lua_State *L)
+{
+ TSTreeCursor *ud = luaL_checkudata(L, 1, "treesitter_treecursor");
+ ts_tree_cursor_delete(ud);
+ return 0;
+}
+
static int node_parent(lua_State *L)
{
TSNode node;
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 820b237c4f..bfa8b91208 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -489,4 +489,60 @@ function vim.defer_fn(fn, timeout)
return timer
end
+local on_keystroke_callbacks = {}
+
+--- Register a lua {fn} with an {id} to be run after every keystroke.
+---
+--@param fn function: Function to call. It should take one argument, which is a string.
+--- The string will contain the literal keys typed.
+--- See |i_CTRL-V|
+---
+--- If {fn} is nil, it removes the callback for the associated {ns_id}
+--@param ns_id number? Namespace ID. If not passed or 0, will generate and return a new
+--- namespace ID from |nvim_create_namesapce()|
+---
+--@return number Namespace ID associated with {fn}
+---
+--@note {fn} will be automatically removed if an error occurs while calling.
+--- This is to prevent the annoying situation of every keystroke erroring
+--- while trying to remove a broken callback.
+--@note {fn} will not be cleared from |nvim_buf_clear_namespace()|
+--@note {fn} will receive the keystrokes after mappings have been evaluated
+function vim.register_keystroke_callback(fn, ns_id)
+ vim.validate {
+ fn = { fn, 'c', true},
+ ns_id = { ns_id, 'n', true }
+ }
+
+ if ns_id == nil or ns_id == 0 then
+ ns_id = vim.api.nvim_create_namespace('')
+ end
+
+ on_keystroke_callbacks[ns_id] = fn
+ return ns_id
+end
+
+--- Function that executes the keystroke callbacks.
+--@private
+function vim._log_keystroke(char)
+ local failed_ns_ids = {}
+ local failed_messages = {}
+ for k, v in pairs(on_keystroke_callbacks) do
+ local ok, err_msg = pcall(v, char)
+ if not ok then
+ vim.register_keystroke_callback(nil, k)
+
+ table.insert(failed_ns_ids, k)
+ table.insert(failed_messages, err_msg)
+ end
+ end
+
+ if failed_ns_ids[1] then
+ error(string.format(
+ "Error executing 'on_keystroke' with ns_ids of '%s'\n With messages: %s",
+ table.concat(failed_ns_ids, ", "),
+ table.concat(failed_messages, "\n")))
+ end
+end
+
return module
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 3df7fa768d..07dcb4a8e8 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -1,6 +1,8 @@
#ifndef NVIM_MACROS_H
#define NVIM_MACROS_H
+#include "auto/config.h"
+
// EXTERN is only defined in main.c. That's where global variables are
// actually defined and initialized.
#ifndef EXTERN
@@ -150,6 +152,12 @@
#define STR_(x) #x
#define STR(x) STR_(x)
+#ifndef __has_include
+# define NVIM_HAS_INCLUDE(x) 0
+#else
+# define NVIM_HAS_INCLUDE __has_include
+#endif
+
#ifndef __has_attribute
# define NVIM_HAS_ATTRIBUTE(x) 0
#elif defined(__clang__) && __clang__ == 1 \
@@ -203,16 +211,33 @@
# define PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wmissing-prototypes\"")
+# ifdef HAVE_WIMPLICIT_FALLTHROUGH_FLAG
+# define PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
+# else
+# define PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH \
+ _Pragma("clang diagnostic push")
+# endif
# define PRAGMA_DIAG_POP \
_Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
# define PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"")
+# ifdef HAVE_WIMPLICIT_FALLTHROUGH_FLAG
+# define PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
+# else
+# define PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH \
+ _Pragma("GCC diagnostic push")
+# endif
# define PRAGMA_DIAG_POP \
_Pragma("GCC diagnostic pop")
#else
# define PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
+# define PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
# define PRAGMA_DIAG_POP
#endif
diff --git a/src/nvim/main.c b/src/nvim/main.c
index f79fb57eae..a22df9cc69 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -7,6 +7,8 @@
#include <string.h>
#include <stdbool.h>
+#include <lua.h>
+#include <lauxlib.h>
#include <msgpack.h>
#include "nvim/ascii.h"
@@ -21,6 +23,7 @@
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
@@ -160,6 +163,7 @@ void early_init(mparm_T *paramp)
env_init();
fs_init();
handle_init();
+ extmark_init();
eval_init(); // init global variables
init_path(argv0 ? argv0 : "nvim");
init_normal_cmds(); // Init the table of Normal mode commands.
diff --git a/src/nvim/map.c b/src/nvim/map.c
index cba39f24b3..ca8ea76333 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -183,8 +183,7 @@ MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)
MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER)
#define EXTMARK_NS_INITIALIZER { 0, 0 }
MAP_IMPL(uint64_t, ExtmarkNs, EXTMARK_NS_INITIALIZER)
-#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
-#define EXTMARK_ITEM_INITIALIZER { 0, 0, 0, KVEC_INITIALIZER }
+#define EXTMARK_ITEM_INITIALIZER { 0, 0, NULL }
MAP_IMPL(uint64_t, ExtmarkItem, EXTMARK_ITEM_INITIALIZER)
MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .fast = false }
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 0ad7865bf0..63a18f4129 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -73,6 +73,7 @@ MAP_DECLS(String, handle_T)
#define pmap_has(T) map_has(T, ptr_t)
#define pmap_key(T) map_key(T, ptr_t)
#define pmap_put(T) map_put(T, ptr_t)
+#define pmap_ref(T) map_ref(T, ptr_t)
/// @see pmap_del2
#define pmap_del(T) map_del(T, ptr_t)
#define pmap_clear(T) map_clear(T, ptr_t)
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 0c73e75b2e..8a1c564a6d 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -2,6 +2,7 @@
#define NVIM_MARKTREE_H
#include <stdint.h>
+#include "nvim/pos.h"
#include "nvim/map.h"
#include "nvim/garray.h"
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index e67be60aa6..ec4f4cbc21 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -512,7 +512,7 @@ int utf_ptr2cells(const char_u *p)
{
int c;
- /* Need to convert to a wide character. */
+ // Need to convert to a character number.
if (*p >= 0x80) {
c = utf_ptr2char(p);
/* An illegal byte is displayed as <xx>. */
@@ -582,7 +582,7 @@ size_t mb_string2cells_len(const char_u *str, size_t size)
return clen;
}
-/// Convert a UTF-8 byte sequence to a wide character
+/// Convert a UTF-8 byte sequence to a character number.
///
/// If the sequence is illegal or truncated by a NUL then the first byte is
/// returned.
@@ -1624,6 +1624,146 @@ int utf_head_off(const char_u *base, const char_u *p)
return (int)(p - q);
}
+// Whether space is NOT allowed before/after 'c'.
+bool utf_eat_space(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return (cc >= 0x2000 && cc <= 0x206F) // General punctuations
+ || (cc >= 0x2e00 && cc <= 0x2e7f) // Supplemental punctuations
+ || (cc >= 0x3000 && cc <= 0x303f) // CJK symbols and punctuations
+ || (cc >= 0xff01 && cc <= 0xff0f) // Full width ASCII punctuations
+ || (cc >= 0xff1a && cc <= 0xff20) // ..
+ || (cc >= 0xff3b && cc <= 0xff40) // ..
+ || (cc >= 0xff5b && cc <= 0xff65); // ..
+}
+
+// Whether line break is allowed before "cc".
+bool utf_allow_break_before(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static const int BOL_prohibition_punct[] = {
+ '!',
+ '%',
+ ')',
+ ',',
+ ':',
+ ';',
+ '>',
+ '?',
+ ']',
+ '}',
+ 0x2019, // โ€™ right single quotation mark
+ 0x201d, // โ€ right double quotation mark
+ 0x2020, // โ€  dagger
+ 0x2021, // โ€ก double dagger
+ 0x2026, // โ€ฆ horizontal ellipsis
+ 0x2030, // โ€ฐ per mille sign
+ 0x2031, // โ€ฑ per then thousand sign
+ 0x203c, // โ€ผ double exclamation mark
+ 0x2047, // โ‡ double question mark
+ 0x2048, // โˆ question exclamation mark
+ 0x2049, // โ‰ exclamation question mark
+ 0x2103, // โ„ƒ degree celsius
+ 0x2109, // โ„‰ degree fahrenheit
+ 0x3001, // ใ€ ideographic comma
+ 0x3002, // ใ€‚ ideographic full stop
+ 0x3009, // ใ€‰ right angle bracket
+ 0x300b, // ใ€‹ right double angle bracket
+ 0x300d, // ใ€ right corner bracket
+ 0x300f, // ใ€ right white corner bracket
+ 0x3011, // ใ€‘ right black lenticular bracket
+ 0x3015, // ใ€• right tortoise shell bracket
+ 0x3017, // ใ€— right white lenticular bracket
+ 0x3019, // ใ€™ right white tortoise shell bracket
+ 0x301b, // ใ€› right white square bracket
+ 0xff01, // ๏ผ fullwidth exclamation mark
+ 0xff09, // ๏ผ‰ fullwidth right parenthesis
+ 0xff0c, // ๏ผŒ fullwidth comma
+ 0xff0e, // ๏ผŽ fullwidth full stop
+ 0xff1a, // ๏ผš fullwidth colon
+ 0xff1b, // ๏ผ› fullwidth semicolon
+ 0xff1f, // ๏ผŸ fullwidth question mark
+ 0xff3d, // ๏ผฝ fullwidth right square bracket
+ 0xff5d, // ๏ฝ fullwidth right curly bracket
+ };
+
+ int first = 0;
+ int last = ARRAY_SIZE(BOL_prohibition_punct) - 1;
+
+ while (first < last) {
+ const int mid = (first + last) / 2;
+
+ if (cc == BOL_prohibition_punct[mid]) {
+ return false;
+ } else if (cc > BOL_prohibition_punct[mid]) {
+ first = mid + 1;
+ } else {
+ last = mid - 1;
+ }
+ }
+
+ return cc != BOL_prohibition_punct[first];
+}
+
+// Whether line break is allowed after "cc".
+bool utf_allow_break_after(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static const int EOL_prohibition_punct[] = {
+ '(',
+ '<',
+ '[',
+ '`',
+ '{',
+ // 0x2014, // โ€” em dash
+ 0x2018, // โ€˜ left single quotation mark
+ 0x201c, // โ€œ left double quotation mark
+ // 0x2053, // ๏ฝž swung dash
+ 0x3008, // ใ€ˆ left angle bracket
+ 0x300a, // ใ€Š left double angle bracket
+ 0x300c, // ใ€Œ left corner bracket
+ 0x300e, // ใ€Ž left white corner bracket
+ 0x3010, // ใ€ left black lenticular bracket
+ 0x3014, // ใ€” left tortoise shell bracket
+ 0x3016, // ใ€– left white lenticular bracket
+ 0x3018, // ใ€˜ left white tortoise shell bracket
+ 0x301a, // ใ€š left white square bracket
+ 0xff08, // ๏ผˆ fullwidth left parenthesis
+ 0xff3b, // ๏ผป fullwidth left square bracket
+ 0xff5b, // ๏ฝ› fullwidth left curly bracket
+ };
+
+ int first = 0;
+ int last = ARRAY_SIZE(EOL_prohibition_punct) - 1;
+
+ while (first < last) {
+ const int mid = (first + last)/2;
+
+ if (cc == EOL_prohibition_punct[mid]) {
+ return false;
+ } else if (cc > EOL_prohibition_punct[mid]) {
+ first = mid + 1;
+ } else {
+ last = mid - 1;
+ }
+ }
+
+ return cc != EOL_prohibition_punct[first];
+}
+
+// Whether line break is allowed between "cc" and "ncc".
+bool utf_allow_break(int cc, int ncc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // don't break between two-letter punctuations
+ if (cc == ncc
+ && (cc == 0x2014 // em dash
+ || cc == 0x2026)) { // horizontal ellipsis
+ return false;
+ }
+ return utf_allow_break_after(cc) && utf_allow_break_before(ncc);
+}
+
/// Copy a character, advancing the pointers
///
/// @param[in,out] fp Source of the character to copy.
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index d5788d96b3..57ed0d6588 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -257,11 +257,12 @@ int ml_open(buf_T *buf)
/*
* init fields in memline struct
*/
- buf->b_ml.ml_stack_size = 0; /* no stack yet */
- buf->b_ml.ml_stack = NULL; /* no stack yet */
- buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
- buf->b_ml.ml_locked = NULL; /* no cached block */
- buf->b_ml.ml_line_lnum = 0; /* no cached line */
+ buf->b_ml.ml_stack_size = 0; // no stack yet
+ buf->b_ml.ml_stack = NULL; // no stack yet
+ buf->b_ml.ml_stack_top = 0; // nothing in the stack
+ buf->b_ml.ml_locked = NULL; // no cached block
+ buf->b_ml.ml_line_lnum = 0; // no cached line
+ buf->b_ml.ml_line_offset = 0;
buf->b_ml.ml_chunksize = NULL;
if (cmdmod.noswapfile) {
@@ -831,11 +832,12 @@ void ml_recover(bool checkext)
/*
* init fields in memline struct
*/
- buf->b_ml.ml_stack_size = 0; /* no stack yet */
- buf->b_ml.ml_stack = NULL; /* no stack yet */
- buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
- buf->b_ml.ml_line_lnum = 0; /* no cached line */
- buf->b_ml.ml_locked = NULL; /* no locked block */
+ buf->b_ml.ml_stack_size = 0; // no stack yet
+ buf->b_ml.ml_stack = NULL; // no stack yet
+ buf->b_ml.ml_stack_top = 0; // nothing in the stack
+ buf->b_ml.ml_line_lnum = 0; // no cached line
+ buf->b_ml.ml_line_offset = 0;
+ buf->b_ml.ml_locked = NULL; // no locked block
buf->b_ml.ml_flags = 0;
/*
@@ -1358,7 +1360,7 @@ recover_names (
* Try finding a swap file by simply adding ".swp" to the file name.
*/
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
- char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", TRUE);
+ char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", true);
if (swapname != NULL) {
if (os_path_exists(swapname)) {
files = xmalloc(sizeof(char_u *));
@@ -1636,10 +1638,11 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// May also add the file name with a dot prepended, for swap file in same
// dir as original file.
if (prepend_dot) {
- names[num_names] = (char_u *)modname((char *)path, ".sw?", TRUE);
- if (names[num_names] == NULL)
+ names[num_names] = (char_u *)modname((char *)path, ".sw?", true);
+ if (names[num_names] == NULL) {
return num_names;
- ++num_names;
+ }
+ num_names++;
}
// Form the normal swap file name pattern by appending ".sw?".
@@ -1816,6 +1819,7 @@ ml_get_buf (
linenr_T lnum,
bool will_change // line will be changed
)
+ FUNC_ATTR_NONNULL_ALL
{
bhdr_T *hp;
DATA_BL *dp;
@@ -2403,12 +2407,13 @@ void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len)
if (len == -1) {
len = STRLEN(ptr);
}
- buf->deleted_bytes += len+1;
- if (buf->update_need_codepoints) {
- mb_utflen(ptr, len, &buf->deleted_codepoints,
- &buf->deleted_codeunits);
- buf->deleted_codepoints++; // NL char
- buf->deleted_codeunits++;
+ curbuf->deleted_bytes += len+1;
+ curbuf->deleted_bytes2 += len+1;
+ if (curbuf->update_need_codepoints) {
+ mb_utflen(ptr, len, &curbuf->deleted_codepoints,
+ &curbuf->deleted_codeunits);
+ curbuf->deleted_codepoints++; // NL char
+ curbuf->deleted_codeunits++;
}
}
@@ -2418,17 +2423,17 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
return ml_replace_buf(curbuf, lnum, line, copy);
}
-/*
- * Replace line lnum, with buffering, in current buffer.
- *
- * If "copy" is TRUE, make a copy of the line, otherwise the line has been
- * copied to allocated memory already.
- *
- * Check: The caller of this function should probably also call
- * changed_lines(), unless update_screen(NOT_VALID) is used.
- *
- * return FAIL for failure, OK otherwise
- */
+// Replace line "lnum", with buffering, in current buffer.
+//
+// If "copy" is true, make a copy of the line, otherwise the line has been
+// copied to allocated memory already.
+// If "copy" is false the "line" may be freed to add text properties!
+// Do not use it after calling ml_replace().
+//
+// Check: The caller of this function should probably also call
+// changed_lines(), unless update_screen(NOT_VALID) is used.
+//
+// return FAIL for failure, OK otherwise
int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy)
{
if (line == NULL) /* just checking... */
@@ -2831,6 +2836,7 @@ static void ml_flush_line(buf_T *buf)
}
buf->b_ml.ml_line_lnum = 0;
+ buf->b_ml.ml_line_offset = 0;
}
/*
@@ -3188,6 +3194,12 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
char_u *fname_res = fname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
+
+ // Expand symlink in the file name, so that we put the swap file with the
+ // actual file instead of with the symlink.
+ if (resolve_symlink(fname, fname_buf) == OK) {
+ fname_res = fname_buf;
+ }
#endif
int len = (int)STRLEN(dir_name);
@@ -3196,20 +3208,14 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
&& len > 1
&& s[-1] == s[-2]) { // Ends with '//', Use Full path
r = NULL;
- if ((s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname)) != NULL) {
- r = (char_u *)modname((char *)s, ".swp", FALSE);
+ s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname_res);
+ if (s != NULL) {
+ r = (char_u *)modname((char *)s, ".swp", false);
xfree(s);
}
return r;
}
-#ifdef HAVE_READLINK
- /* Expand symlink in the file name, so that we put the swap file with the
- * actual file instead of with the symlink. */
- if (resolve_symlink(fname, fname_buf) == OK)
- fname_res = fname_buf;
-#endif
-
// Prepend a '.' to the swap file name for the current directory.
r = (char_u *)modname((char *)fname_res, ".swp",
dir_name[0] == '.' && dir_name[1] == NUL);
@@ -3980,10 +3986,10 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
/// Find offset for line or line with offset.
///
/// @param buf buffer to use
-/// @param lnum if > 0, find offset of lnum, store offset in offp
+/// @param lnum if > 0, find offset of lnum, return offset
/// if == 0, return line with offset *offp
-/// @param offp Location where offset of line is stored, or to read offset to
-/// use to find line. In the later case, store remaining offset.
+/// @param offp offset to use to find line, store remaining column offset
+/// Should be NULL when getting offset of line
/// @param no_ff ignore 'fileformat' option, always use one byte for NL.
///
/// @return -1 if information is not available
@@ -4003,8 +4009,22 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
int ffdos = !no_ff && (get_fileformat(buf) == EOL_DOS);
int extra = 0;
- // take care of cached line first
- ml_flush_line(buf);
+ // take care of cached line first. Only needed if the cached line is before
+ // the requested line. Additionally cache the value for the cached line.
+ // This is used by the extmark code which needs the byte offset of the edited
+ // line. So when doing multiple small edits on the same line the value is
+ // only calculated once.
+ //
+ // NB: caching doesn't work with 'fileformat'. This is not a problem for
+ // bytetracking, as bytetracking ignores 'fileformat' option. But calling
+ // line2byte() will invalidate the cache for the time being (this function
+ // was never cached to start with anyway).
+ bool can_cache = (lnum != 0 && !ffdos && buf->b_ml.ml_line_lnum == lnum);
+ if (lnum == 0 || buf->b_ml.ml_line_lnum < lnum || !no_ff) {
+ ml_flush_line(curbuf);
+ } else if (can_cache && buf->b_ml.ml_line_offset > 0) {
+ return buf->b_ml.ml_line_offset;
+ }
if (buf->b_ml.ml_usedchunks == -1
|| buf->b_ml.ml_chunksize == NULL
@@ -4100,6 +4120,10 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
}
}
+ if (can_cache && size > 0) {
+ buf->b_ml.ml_line_offset = size;
+ }
+
return size;
}
diff --git a/src/nvim/memline_defs.h b/src/nvim/memline_defs.h
index edd933b2cd..9a6f29a908 100644
--- a/src/nvim/memline_defs.h
+++ b/src/nvim/memline_defs.h
@@ -57,6 +57,8 @@ typedef struct memline {
linenr_T ml_line_lnum; // line number of cached line, 0 if not valid
char_u *ml_line_ptr; // pointer to cached line
+ size_t ml_line_offset; // cached byte offset of ml_line_lnum
+ int ml_line_offset_ff; // fileformat of cached line
bhdr_T *ml_locked; // block used by last ml_get
linenr_T ml_locked_low; // first line in ml_locked
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 8999365d32..6cd5616acf 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -607,8 +607,7 @@ int emsg_not_now(void)
static bool emsg_multiline(const char *s, bool multiline)
{
int attr;
- int ignore = false;
- int severe;
+ bool ignore = false;
// Skip this if not giving error messages at the moment.
if (emsg_not_now()) {
@@ -617,9 +616,9 @@ static bool emsg_multiline(const char *s, bool multiline)
called_emsg = true;
- // If "emsg_severe" is TRUE: When an error exception is to be thrown,
+ // If "emsg_severe" is true: When an error exception is to be thrown,
// prefer this message over previous messages for the same command.
- severe = emsg_severe;
+ bool severe = emsg_severe;
emsg_severe = false;
if (!emsg_off || vim_strchr(p_debug, 't') != NULL) {
@@ -630,7 +629,7 @@ static bool emsg_multiline(const char *s, bool multiline)
* when the message should be ignored completely (used for the
* interrupt message).
*/
- if (cause_errthrow((char_u *)s, severe, &ignore) == true) {
+ if (cause_errthrow((char_u *)s, severe, &ignore)) {
if (!ignore) {
did_emsg++;
}
@@ -1622,7 +1621,7 @@ const char *str2special(const char **const sp, const bool replace_spaces,
// Check for an illegal byte.
if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
- transchar_nonprint((char_u *)buf, c);
+ transchar_nonprint(curbuf, (char_u *)buf, c);
*sp = str + 1;
return buf;
}
@@ -1887,6 +1886,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
// wait-return prompt later. Needed when scrolling, resetting
// need_wait_return after some prompt, and then outputting something
// without scrolling
+ // Not needed when only using CR to move the cursor.
bool overflow = false;
if (ui_has(kUIMessages)) {
int count = msg_ext_visible + (msg_ext_overwrite ? 0 : 1);
@@ -1898,7 +1898,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
overflow = msg_scrolled != 0;
}
- if (overflow && !msg_scrolled_ign) {
+ if (overflow && !msg_scrolled_ign && strcmp(str, "\r") != 0) {
need_wait_return = true;
}
msg_didany = true; // remember that something was outputted
@@ -2000,7 +2000,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
|| (*s == TAB && msg_col <= 7)
|| (utf_ptr2cells(s) > 1
&& msg_col <= 2))
- : (msg_col + t_col >= Columns - 1
+ : ((*s != '\r' && msg_col + t_col >= Columns - 1)
|| (*s == TAB
&& msg_col + t_col >= ((Columns - 1) & ~7))
|| (utf_ptr2cells(s) > 1
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 6dafbafb3e..1cd9ff2c4d 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -983,7 +983,7 @@ void preserve_exit(void)
FOR_ALL_BUFFERS(buf) {
if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
- mch_errmsg((uint8_t *)"Vim: preserving files...\n");
+ mch_errmsg("Vim: preserving files...\r\n");
ui_flush();
ml_sync_all(false, false, true); // preserve all swap files
break;
@@ -992,7 +992,7 @@ void preserve_exit(void)
ml_close_all(false); // close all memfiles, without deleting
- mch_errmsg("Vim: Finished.\n");
+ mch_errmsg("Vim: Finished.\r\n");
getout(1);
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 8a8a639a52..e2a304efa5 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -641,7 +641,7 @@ void validate_virtcol_win(win_T *wp)
/*
* Validate curwin->w_cline_height only.
*/
-static void validate_cheight(void)
+void validate_cheight(void)
{
check_cursor_moved(curwin);
if (!(curwin->w_valid & VALID_CHEIGHT)) {
@@ -943,6 +943,9 @@ void curs_columns(
redraw_later(SOME_VALID);
}
+ // now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise
+ curwin->w_valid_leftcol = curwin->w_leftcol;
+
curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 968cfde388..1cc400166c 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1977,20 +1977,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
case OP_FOLD:
VIsual_reselect = false; // don't reselect now
- foldCreate(curwin, oap->start.lnum, oap->end.lnum);
+ foldCreate(curwin, oap->start, oap->end);
break;
case OP_FOLDOPEN:
case OP_FOLDOPENREC:
case OP_FOLDCLOSE:
case OP_FOLDCLOSEREC:
- VIsual_reselect = false; /* don't reselect now */
- opFoldRange(oap->start.lnum, oap->end.lnum,
- oap->op_type == OP_FOLDOPEN
- || oap->op_type == OP_FOLDOPENREC,
- oap->op_type == OP_FOLDOPENREC
- || oap->op_type == OP_FOLDCLOSEREC,
- oap->is_VIsual);
+ VIsual_reselect = false; // don't reselect now
+ opFoldRange(oap->start, oap->end,
+ oap->op_type == OP_FOLDOPEN
+ || oap->op_type == OP_FOLDOPENREC,
+ oap->op_type == OP_FOLDOPENREC
+ || oap->op_type == OP_FOLDCLOSEREC,
+ oap->is_VIsual);
break;
case OP_FOLDDEL:
@@ -2483,7 +2483,7 @@ do_mouse (
typval_T rettv;
int doesrange;
(void)call_func((char_u *)tab_page_click_defs[mouse_col].func,
- (int)strlen(tab_page_click_defs[mouse_col].func),
+ -1,
&rettv, ARRAY_SIZE(argv), argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL, NULL);
@@ -2590,14 +2590,16 @@ do_mouse (
&& !is_drag
&& (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
&& which_button == MOUSE_LEFT) {
- /* open or close a fold at this line */
- if (jump_flags & MOUSE_FOLD_OPEN)
- openFold(curwin->w_cursor.lnum, 1L);
- else
- closeFold(curwin->w_cursor.lnum, 1L);
- /* don't move the cursor if still in the same window */
- if (curwin == old_curwin)
+ // open or close a fold at this line
+ if (jump_flags & MOUSE_FOLD_OPEN) {
+ openFold(curwin->w_cursor, 1L);
+ } else {
+ closeFold(curwin->w_cursor, 1L);
+ }
+ // don't move the cursor if still in the same window
+ if (curwin == old_curwin) {
curwin->w_cursor = save_cursor;
+ }
}
@@ -4393,51 +4395,55 @@ dozet:
case 'i': curwin->w_p_fen = !curwin->w_p_fen;
break;
- /* "za": open closed fold or close open fold at cursor */
- case 'a': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
- openFold(curwin->w_cursor.lnum, cap->count1);
- else {
- closeFold(curwin->w_cursor.lnum, cap->count1);
+ // "za": open closed fold or close open fold at cursor
+ case 'a': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ openFold(curwin->w_cursor, cap->count1);
+ } else {
+ closeFold(curwin->w_cursor, cap->count1);
curwin->w_p_fen = true;
}
break;
- /* "zA": open fold at cursor recursively */
- case 'A': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
- openFoldRecurse(curwin->w_cursor.lnum);
- else {
- closeFoldRecurse(curwin->w_cursor.lnum);
+ // "zA": open fold at cursor recursively
+ case 'A': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ openFoldRecurse(curwin->w_cursor);
+ } else {
+ closeFoldRecurse(curwin->w_cursor);
curwin->w_p_fen = true;
}
break;
- /* "zo": open fold at cursor or Visual area */
- case 'o': if (VIsual_active)
+ // "zo": open fold at cursor or Visual area
+ case 'o': if (VIsual_active) {
nv_operator(cap);
- else
- openFold(curwin->w_cursor.lnum, cap->count1);
+ } else {
+ openFold(curwin->w_cursor, cap->count1);
+ }
break;
- /* "zO": open fold recursively */
- case 'O': if (VIsual_active)
+ // "zO": open fold recursively
+ case 'O': if (VIsual_active) {
nv_operator(cap);
- else
- openFoldRecurse(curwin->w_cursor.lnum);
+ } else {
+ openFoldRecurse(curwin->w_cursor);
+ }
break;
- /* "zc": close fold at cursor or Visual area */
- case 'c': if (VIsual_active)
+ // "zc": close fold at cursor or Visual area
+ case 'c': if (VIsual_active) {
nv_operator(cap);
- else
- closeFold(curwin->w_cursor.lnum, cap->count1);
+ } else {
+ closeFold(curwin->w_cursor, cap->count1);
+ }
curwin->w_p_fen = true;
break;
- /* "zC": close fold recursively */
- case 'C': if (VIsual_active)
+ // "zC": close fold recursively
+ case 'C': if (VIsual_active) {
nv_operator(cap);
- else
- closeFoldRecurse(curwin->w_cursor.lnum);
+ } else {
+ closeFoldRecurse(curwin->w_cursor);
+ }
curwin->w_p_fen = true;
break;
@@ -6835,7 +6841,7 @@ static void nv_g_cmd(cmdarg_T *cap)
} else {
if (cap->count1 > 1) {
// if it fails, let the cursor still move to the last char
- cursor_down(cap->count1 - 1, false);
+ (void)cursor_down(cap->count1 - 1, false);
}
i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1;
coladvance((colnr_T)i);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 595a699563..939cde0ba1 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -119,7 +119,7 @@ static char opchars[][3] =
{ 'r', NUL, OPF_CHANGE }, // OP_REPLACE
{ 'I', NUL, OPF_CHANGE }, // OP_INSERT
{ 'A', NUL, OPF_CHANGE }, // OP_APPEND
- { 'z', 'f', OPF_LINES }, // OP_FOLD
+ { 'z', 'f', 0 }, // OP_FOLD
{ 'z', 'o', OPF_LINES }, // OP_FOLDOPEN
{ 'z', 'O', OPF_LINES }, // OP_FOLDOPENREC
{ 'z', 'c', OPF_LINES }, // OP_FOLDCLOSE
@@ -496,9 +496,9 @@ static void shift_block(oparg_T *oap, int amount)
// replace the line
ml_replace(curwin->w_cursor.lnum, newp, false);
changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol);
- extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1, startcol,
- 0, oldlen, 0, newlen,
- kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum-1, startcol,
+ oldlen, newlen,
+ kExtmarkUndo);
State = oldstate;
curwin->w_cursor.col = oldcol;
p_ri = old_p_ri;
@@ -595,9 +595,8 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
STRMOVE(newp + offset, oldp);
ml_replace(lnum, newp, false);
- extmark_splice(curbuf, (int)lnum-1, startcol,
- 0, skipped,
- 0, offset-startcol, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)lnum-1, startcol,
+ skipped, offset-startcol, kExtmarkUndo);
if (lnum == oap->end.lnum) {
/* Set "']" mark to the end of the block instead of the end of
@@ -1534,10 +1533,9 @@ int op_delete(oparg_T *oap)
// replace the line
ml_replace(lnum, newp, false);
- extmark_splice(curbuf, (int)lnum-1, bd.textcol,
- 0, bd.textlen,
- 0, bd.startspaces+bd.endspaces,
- kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)lnum-1, bd.textcol,
+ bd.textlen, bd.startspaces+bd.endspaces,
+ kExtmarkUndo);
}
check_cursor_col();
@@ -1546,10 +1544,10 @@ int op_delete(oparg_T *oap)
oap->line_count = 0; // no lines deleted
} else if (oap->motion_type == kMTLineWise) {
if (oap->op_type == OP_CHANGE) {
- /* Delete the lines except the first one. Temporarily move the
- * cursor to the next line. Save the current line number, if the
- * last line is deleted it may be changed.
- */
+ // Delete the lines except the first one. Temporarily move the
+ // cursor to the next line. Save the current line number, if the
+ // last line is deleted it may be changed.
+
if (oap->line_count > 1) {
lnum = curwin->w_cursor.lnum;
++curwin->w_cursor.lnum;
@@ -1562,12 +1560,21 @@ int op_delete(oparg_T *oap)
beginline(BL_WHITE); // cursor on first non-white
did_ai = true; // delete the indent when ESC hit
ai_col = curwin->w_cursor.col;
- } else
- beginline(0); /* cursor in column 0 */
- truncate_line(FALSE); /* delete the rest of the line */
- /* leave cursor past last char in line */
- if (oap->line_count > 1)
- u_clearline(); /* "U" command not possible after "2cc" */
+ } else {
+ beginline(0); // cursor in column 0
+ }
+
+ int old_len = (int)STRLEN(ml_get(curwin->w_cursor.lnum));
+ truncate_line(false); // delete the rest of the line
+
+ extmark_splice_cols(curbuf,
+ (int)curwin->w_cursor.lnum-1, curwin->w_cursor.col,
+ old_len - curwin->w_cursor.col, 0, kExtmarkUndo);
+
+ // leave cursor past last char in line
+ if (oap->line_count > 1) {
+ u_clearline(); // "U" command not possible after "2cc"
+ }
} else {
del_lines(oap->line_count, TRUE);
beginline(BL_WHITE | BL_FIX);
@@ -1661,17 +1668,20 @@ int op_delete(oparg_T *oap)
curpos = curwin->w_cursor; // remember curwin->w_cursor
curwin->w_cursor.lnum++;
del_lines(oap->line_count - 2, false);
+ bcount_t deleted_bytes = (bcount_t)curbuf->deleted_bytes2 - startpos.col;
// delete from start of line until op_end
n = (oap->end.col + 1 - !oap->inclusive);
curwin->w_cursor.col = 0;
(void)del_bytes((colnr_T)n, !virtual_op,
oap->op_type == OP_DELETE && !oap->is_VIsual);
+ deleted_bytes += n;
curwin->w_cursor = curpos; // restore curwin->w_cursor
(void)do_join(2, false, false, false, false);
curbuf_splice_pending--;
extmark_splice(curbuf, (int)startpos.lnum-1, startpos.col,
- (int)oap->line_count-1, n, 0, 0, kExtmarkUndo);
+ (int)oap->line_count-1, n, deleted_bytes,
+ 0, 0, 0, kExtmarkUndo);
}
}
@@ -1711,7 +1721,7 @@ static inline void pbyte(pos_T lp, int c)
assert(c <= UCHAR_MAX);
*(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c;
if (!curbuf_splice_pending) {
- extmark_splice(curbuf, (int)lp.lnum-1, lp.col, 0, 1, 0, 1, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)lp.lnum-1, lp.col, 1, 1, kExtmarkUndo);
}
}
@@ -1856,6 +1866,7 @@ int op_replace(oparg_T *oap, int c)
}
// replace the line
ml_replace(curwin->w_cursor.lnum, newp, false);
+ curbuf_splice_pending++;
linenr_T baselnum = curwin->w_cursor.lnum;
if (after_p != NULL) {
ml_append(curwin->w_cursor.lnum++, after_p, (int)after_p_len, false);
@@ -1863,9 +1874,10 @@ int op_replace(oparg_T *oap, int c)
oap->end.lnum++;
xfree(after_p);
}
+ curbuf_splice_pending--;
extmark_splice(curbuf, (int)baselnum-1, bd.textcol,
- 0, bd.textlen,
- newrows, newcols, kExtmarkUndo);
+ 0, bd.textlen, bd.textlen,
+ newrows, newcols, newrows+newcols, kExtmarkUndo);
}
} else {
// Characterwise or linewise motion replace.
@@ -2399,9 +2411,8 @@ int op_change(oparg_T *oap)
oldp += bd.textcol;
STRMOVE(newp + offset, oldp);
ml_replace(linenr, newp, false);
- extmark_splice(curbuf, (int)linenr-1, bd.textcol,
- 0, 0,
- 0, vpos.coladd+(int)ins_len, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)linenr-1, bd.textcol,
+ 0, vpos.coladd+(int)ins_len, kExtmarkUndo);
}
}
check_cursor();
@@ -3098,6 +3109,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
for (i = 0; i < y_size; i++) {
int spaces;
char shortline;
+ // can just be 0 or 1, needed for blockwise paste beyond the current
+ // buffer end
+ int lines_appended = 0;
bd.startspaces = 0;
bd.endspaces = 0;
@@ -3111,6 +3125,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
break;
}
nr_lines++;
+ lines_appended = 1;
}
/* get the old line and advance to the position to insert at */
oldp = get_cursor_line_ptr();
@@ -3182,17 +3197,16 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
assert(columns >= 0);
memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
ml_replace(curwin->w_cursor.lnum, newp, false);
- extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1, bd.textcol,
- 0, delcount,
- 0, (int)totlen,
- kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum-1, bd.textcol,
+ delcount, (int)totlen + lines_appended, kExtmarkUndo);
++curwin->w_cursor.lnum;
if (i == 0)
curwin->w_cursor.col += bd.startspaces;
}
- changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines, true);
+ changed_lines(lnum, 0, curbuf->b_op_start.lnum + (linenr_T)y_size
+ - (linenr_T)nr_lines , nr_lines, true);
/* Set '[ mark. */
curbuf->b_op_start = curwin->w_cursor;
@@ -3238,21 +3252,43 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
--lnum;
new_cursor = curwin->w_cursor;
- // simple case: insert into current line
+ // simple case: insert into one line at a time
if (y_type == kMTCharWise && y_size == 1) {
linenr_T end_lnum = 0; // init for gcc
+ linenr_T start_lnum = lnum;
if (VIsual_active) {
end_lnum = curbuf->b_visual.vi_end.lnum;
if (end_lnum < curbuf->b_visual.vi_start.lnum) {
end_lnum = curbuf->b_visual.vi_start.lnum;
}
+ if (end_lnum > start_lnum) {
+ // "col" is valid for the first line, in following lines
+ // the virtual column needs to be used. Matters for
+ // multi-byte characters.
+ pos_T pos = {
+ .lnum = lnum,
+ .col = col,
+ .coladd = 0,
+ };
+ getvcol(curwin, &pos, NULL, &vcol, NULL);
+ }
}
do {
totlen = (size_t)(count * yanklen);
if (totlen > 0) {
oldp = ml_get(lnum);
+ if (lnum > start_lnum) {
+ pos_T pos = {
+ .lnum = lnum,
+ };
+ if (getvpos(&pos, vcol) == OK) {
+ col = pos.col;
+ } else {
+ col = MAXCOL;
+ }
+ }
if (VIsual_active && col > (int)STRLEN(oldp)) {
lnum++;
continue;
@@ -3287,9 +3323,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
++curwin->w_cursor.col;
changed_bytes(lnum, col);
- extmark_splice(curbuf, (int)lnum-1, col,
- 0, 0,
- 0, (int)totlen, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)lnum-1, col,
+ 0, (int)totlen, kExtmarkUndo);
} else {
// Insert at least one line. When y_type is kMTCharWise, break the first
// line in two.
@@ -3353,13 +3388,23 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
}
+ bcount_t totsize = 0;
+ int lastsize = 0;
+ 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;
+ }
+ lastsize = (int)STRLEN(y_array[y_size-1]);
+ totsize += lastsize;
+ }
if (y_type == kMTCharWise) {
- extmark_splice(curbuf, (int)new_cursor.lnum-1, col, 0, 0,
- (int)y_size-1, (int)STRLEN(y_array[y_size-1]),
+ extmark_splice(curbuf, (int)new_cursor.lnum-1, col, 0, 0, 0,
+ (int)y_size-1, lastsize, totsize,
kExtmarkUndo);
} else if (y_type == kMTLineWise && flags & PUT_LINE_SPLIT) {
- extmark_splice(curbuf, (int)new_cursor.lnum-1, col, 0, 0,
- (int)y_size+1, 0, kExtmarkUndo);
+ extmark_splice(curbuf, (int)new_cursor.lnum-1, col, 0, 0, 0,
+ (int)y_size+1, 0, totsize+1, kExtmarkUndo);
}
}
@@ -3788,7 +3833,8 @@ int do_join(size_t count,
&& (!has_format_option(FO_MBYTE_JOIN)
|| (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
&& (!has_format_option(FO_MBYTE_JOIN2)
- || utf_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
+ || (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1))
+ || (endcurr1 < 0x100 && !utf_eat_space(utf_ptr2char(curr))))
) {
/* don't add a space if the line is ending in a space */
if (endcurr1 == ' ')
@@ -3803,9 +3849,10 @@ int do_join(size_t count,
}
if (t > 0 && curbuf_splice_pending == 0) {
+ colnr_T removed = (int)(curr- curr_start);
extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1, sumsize,
- 1, (int)(curr- curr_start),
- 0, spaces[t],
+ 1, removed, removed + 1,
+ 0, spaces[t], spaces[t],
kExtmarkUndo);
}
currsize = (int)STRLEN(curr);
@@ -4112,49 +4159,41 @@ format_lines(
int avoid_fex /* don't use 'formatexpr' */
)
{
- int max_len;
- int is_not_par; /* current line not part of parag. */
- int next_is_not_par; /* next line not part of paragraph */
- int is_end_par; /* at end of paragraph */
- int prev_is_end_par = FALSE; /* prev. line not part of parag. */
- int next_is_start_par = FALSE;
- int leader_len = 0; /* leader len of current line */
- int next_leader_len; /* leader len of next line */
- char_u *leader_flags = NULL; /* flags for leader of current line */
- char_u *next_leader_flags; /* flags for leader of next line */
- int do_comments; /* format comments */
- int do_comments_list = 0; /* format comments with 'n' or '2' */
- int advance = TRUE;
- int second_indent = -1; /* indent for second line (comment
- * aware) */
- int do_second_indent;
- int do_number_indent;
- int do_trail_white;
- int first_par_line = TRUE;
+ bool is_not_par; // current line not part of parag.
+ bool next_is_not_par; // next line not part of paragraph
+ bool is_end_par; // at end of paragraph
+ bool prev_is_end_par = false; // prev. line not part of parag.
+ bool next_is_start_par = false;
+ int leader_len = 0; // leader len of current line
+ int next_leader_len; // leader len of next line
+ char_u *leader_flags = NULL; // flags for leader of current line
+ char_u *next_leader_flags; // flags for leader of next line
+ bool advance = true;
+ int second_indent = -1; // indent for second line (comment aware)
+ bool first_par_line = true;
int smd_save;
long count;
- int need_set_indent = TRUE; /* set indent of next paragraph */
- int force_format = FALSE;
- int old_State = State;
-
- /* length of a line to force formatting: 3 * 'tw' */
- max_len = comp_textwidth(TRUE) * 3;
-
- /* check for 'q', '2' and '1' in 'formatoptions' */
- do_comments = has_format_option(FO_Q_COMS);
- do_second_indent = has_format_option(FO_Q_SECOND);
- do_number_indent = has_format_option(FO_Q_NUMBER);
- do_trail_white = has_format_option(FO_WHITE_PAR);
-
- /*
- * Get info about the previous and current line.
- */
- if (curwin->w_cursor.lnum > 1)
- is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
- , &leader_len, &leader_flags, do_comments
- );
- else
- is_not_par = TRUE;
+ bool need_set_indent = true; // set indent of next paragraph
+ bool force_format = false;
+ const int old_State = State;
+
+ // length of a line to force formatting: 3 * 'tw'
+ const int max_len = comp_textwidth(true) * 3;
+
+ // check for 'q', '2' and '1' in 'formatoptions'
+ const bool do_comments = has_format_option(FO_Q_COMS); // format comments
+ int do_comments_list = 0; // format comments with 'n' or '2'
+ const bool do_second_indent = has_format_option(FO_Q_SECOND);
+ const bool do_number_indent = has_format_option(FO_Q_NUMBER);
+ const bool do_trail_white = has_format_option(FO_WHITE_PAR);
+
+ // Get info about the previous and current line.
+ if (curwin->w_cursor.lnum > 1) {
+ is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1,
+ &leader_len, &leader_flags, do_comments);
+ } else {
+ is_not_par = true;
+ }
next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
, &next_leader_len, &next_leader_flags, do_comments
);
@@ -4179,7 +4218,7 @@ format_lines(
* The last line to be formatted.
*/
if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
- next_is_not_par = TRUE;
+ next_is_not_par = true;
next_leader_len = 0;
next_leader_flags = NULL;
} else {
@@ -4190,7 +4229,7 @@ format_lines(
next_is_start_par =
(get_number_indent(curwin->w_cursor.lnum + 1) > 0);
}
- advance = TRUE;
+ advance = true;
is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
if (!is_end_par && do_trail_white)
is_end_par = !ends_in_white(curwin->w_cursor.lnum);
@@ -4241,7 +4280,7 @@ format_lines(
leader_len, leader_flags,
next_leader_len, next_leader_flags)
)
- is_end_par = TRUE;
+ is_end_par = true;
/*
* If we have got to the end of a paragraph, or the line is
@@ -4278,9 +4317,9 @@ format_lines(
* end of the paragraph. */
if (line_count < 0)
break;
- first_par_line = TRUE;
+ first_par_line = true;
}
- force_format = FALSE;
+ force_format = false;
}
/*
@@ -4288,7 +4327,7 @@ format_lines(
* first delete the leader from the second line.
*/
if (!is_end_par) {
- advance = FALSE;
+ advance = false;
curwin->w_cursor.lnum++;
curwin->w_cursor.col = 0;
if (line_count < 0 && u_save_cursor() == FAIL)
@@ -4311,12 +4350,13 @@ format_lines(
beep_flush();
break;
}
- first_par_line = FALSE;
- /* If the line is getting long, format it next time */
- if (STRLEN(get_cursor_line_ptr()) > (size_t)max_len)
- force_format = TRUE;
- else
- force_format = FALSE;
+ first_par_line = false;
+ // If the line is getting long, format it next time
+ if (STRLEN(get_cursor_line_ptr()) > (size_t)max_len) {
+ force_format = true;
+ } else {
+ force_format = false;
+ }
}
}
line_breakcheck();
@@ -4377,11 +4417,10 @@ static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags,
int paragraph_start(linenr_T lnum)
{
char_u *p;
- int leader_len = 0; /* leader len of current line */
- char_u *leader_flags = NULL; /* flags for leader of current line */
- int next_leader_len = 0; /* leader len of next line */
- char_u *next_leader_flags = NULL; /* flags for leader of next line */
- int do_comments; /* format comments */
+ int leader_len = 0; // leader len of current line
+ char_u *leader_flags = NULL; // flags for leader of current line
+ int next_leader_len = 0; // leader len of next line
+ char_u *next_leader_flags = NULL; // flags for leader of next line
if (lnum <= 1)
return TRUE; /* start of the file */
@@ -4390,7 +4429,7 @@ int paragraph_start(linenr_T lnum)
if (*p == NUL)
return TRUE; /* after empty line */
- do_comments = has_format_option(FO_Q_COMS);
+ const bool do_comments = has_format_option(FO_Q_COMS); // format comments
if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) {
return true; // after non-paragraph line
}
@@ -5897,7 +5936,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
const char regname = (char)name;
tv_list_append_string(args, &regname, 1);
- typval_T result = eval_call_provider("clipboard", "get", args);
+ typval_T result = eval_call_provider("clipboard", "get", args, false);
if (result.v_type != VAR_LIST) {
if (result.v_type == VAR_NUMBER && result.vval.v_number == 0) {
@@ -6045,7 +6084,7 @@ static void set_clipboard(int name, yankreg_T *reg)
tv_list_append_string(args, &regtype, 1); // -V614
tv_list_append_string(args, ((char[]) { (char)name }), 1);
- (void)eval_call_provider("clipboard", "set", args);
+ (void)eval_call_provider("clipboard", "set", args, true);
}
/// Avoid slow things (clipboard) during batch operations (while/for-loops).
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 168160834b..ca902d5669 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -174,6 +174,7 @@ static char_u *p_syn;
static char_u *p_spc;
static char_u *p_spf;
static char_u *p_spl;
+static char_u *p_spo;
static long p_ts;
static long p_tw;
static int p_udf;
@@ -311,6 +312,9 @@ static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
static char *(p_fcl_values[]) = { "all", NULL };
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
"noinsert", "noselect", NULL };
+#ifdef BACKSLASH_IN_FILENAME
+static char *(p_csl_values[]) = { "slash", "backslash", NULL };
+#endif
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
"auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
@@ -347,22 +351,23 @@ static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
return &dest[len + shift];
}
-/// Compute length of a colon-separated value, doubled and with some suffixes
+/// Compute length of a ENV_SEPCHAR-separated value, doubled and with some
+/// suffixes
///
-/// @param[in] val Colon-separated array value.
+/// @param[in] val ENV_SEPCHAR-separated array value.
/// @param[in] common_suf_len Length of the common suffix which is appended to
/// each item in the array, twice.
/// @param[in] single_suf_len Length of the suffix which is appended to each
/// item in the array once.
///
-/// @return Length of the comma-separated string array that contains each item
-/// in the original array twice with suffixes with given length
+/// @return Length of the ENV_SEPCHAR-separated string array that contains each
+/// item in the original array twice with suffixes with given length
/// (common_suf is present after each new item, single_suf is present
/// after half of the new items) and with commas after each item, commas
/// inside the values are escaped.
-static inline size_t compute_double_colon_len(const char *const val,
- const size_t common_suf_len,
- const size_t single_suf_len)
+static inline size_t compute_double_env_sep_len(const char *const val,
+ const size_t common_suf_len,
+ const size_t single_suf_len)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
if (val == NULL || *val == NUL) {
@@ -373,7 +378,7 @@ static inline size_t compute_double_colon_len(const char *const val,
do {
size_t dir_len;
const char *dir;
- iter = vim_env_iter(':', val, iter, &dir, &dir_len);
+ iter = vim_env_iter(ENV_SEPCHAR, val, iter, &dir, &dir_len);
if (dir != NULL && dir_len > 0) {
ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
+ !after_pathsep(dir, dir + dir_len)) * 2
@@ -385,13 +390,13 @@ static inline size_t compute_double_colon_len(const char *const val,
#define NVIM_SIZE (sizeof("nvim") - 1)
-/// Add directories to a comma-separated array from a colon-separated one
+/// Add directories to a ENV_SEPCHAR-separated array from a colon-separated one
///
/// Commas are escaped in process. To each item PATHSEP "nvim" is appended in
/// addition to suf1 and suf2.
///
/// @param[in,out] dest Destination comma-separated array.
-/// @param[in] val Source colon-separated array.
+/// @param[in] val Source ENV_SEPCHAR-separated array.
/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it
/// directory separator is appended. Suffix must not contain
/// commas.
@@ -404,10 +409,10 @@ static inline size_t compute_double_colon_len(const char *const val,
/// Otherwise in reverse.
///
/// @return (dest + appended_characters_length)
-static inline char *add_colon_dirs(char *dest, const char *const val,
- const char *const suf1, const size_t len1,
- const char *const suf2, const size_t len2,
- const bool forward)
+static inline char *add_env_sep_dirs(char *dest, const char *const val,
+ const char *const suf1, const size_t len1,
+ const char *const suf2, const size_t len2,
+ const bool forward)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
{
if (val == NULL || *val == NUL) {
@@ -417,8 +422,8 @@ static inline char *add_colon_dirs(char *dest, const char *const val,
do {
size_t dir_len;
const char *dir;
- iter = (forward ? vim_env_iter : vim_env_iter_rev)(':', val, iter, &dir,
- &dir_len);
+ iter = (forward ? vim_env_iter : vim_env_iter_rev)(ENV_SEPCHAR, val, iter,
+ &dir, &dir_len);
if (dir != NULL && dir_len > 0) {
dest = strcpy_comma_escaped(dest, dir, dir_len);
if (!after_pathsep(dest - 1, dest)) {
@@ -581,10 +586,11 @@ static void set_runtimepath_default(bool clean_arg)
rtp_size += libdir_len + memcnt(libdir, ',', libdir_len) + 1;
}
}
- rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1,
- AFTER_SIZE + 1);
- rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1,
- AFTER_SIZE + 1);
+ rtp_size += compute_double_env_sep_len(data_dirs,
+ NVIM_SIZE + 1 + SITE_SIZE + 1,
+ AFTER_SIZE + 1);
+ rtp_size += compute_double_env_sep_len(config_dirs, NVIM_SIZE + 1,
+ AFTER_SIZE + 1);
if (rtp_size == 0) {
return;
}
@@ -592,20 +598,20 @@ static void set_runtimepath_default(bool clean_arg)
char *rtp_cur = rtp;
rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
NULL, 0, NULL, 0);
- rtp_cur = add_colon_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true);
+ rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true);
rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
"site", SITE_SIZE, NULL, 0);
- rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0,
- true);
+ rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0,
+ true);
rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone,
NULL, 0, NULL, 0);
rtp_cur = add_dir(rtp_cur, libdir, libdir_len, kXDGNone, NULL, 0, NULL, 0);
- rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE,
- "after", AFTER_SIZE, false);
+ rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE,
+ "after", AFTER_SIZE, false);
rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
"site", SITE_SIZE, "after", AFTER_SIZE);
- rtp_cur = add_colon_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0,
- false);
+ rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0,
+ false);
rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
"after", AFTER_SIZE, NULL, 0);
// Strip trailing comma.
@@ -1355,11 +1361,11 @@ int do_set(
// Disallow changing some options from modelines.
if (opt_flags & OPT_MODELINE) {
if (flags & (P_SECURE | P_NO_ML)) {
- errmsg = (char_u *)_("E520: Not allowed in a modeline");
+ errmsg = (char_u *)N_("E520: Not allowed in a modeline");
goto skip;
}
if ((flags & P_MLE) && !p_mle) {
- errmsg = (char_u *)_(
+ errmsg = (char_u *)N_(
"E992: Not allowed in a modeline when 'modelineexpr' is off");
goto skip;
}
@@ -1376,7 +1382,7 @@ int do_set(
// Disallow changing some options in the sandbox
if (sandbox != 0 && (flags & P_SECURE)) {
- errmsg = (char_u *)_(e_sandbox);
+ errmsg = e_sandbox;
goto skip;
}
@@ -1712,6 +1718,7 @@ int do_set(
#ifdef BACKSLASH_IN_FILENAME
&& !((flags & P_EXPAND)
&& vim_isfilec(arg[1])
+ && !ascii_iswhite(arg[1])
&& (arg[1] != '\\'
|| (s == newval
&& arg[2] != '\\')))
@@ -2282,6 +2289,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_s.b_p_spc);
check_string_option(&buf->b_s.b_p_spf);
check_string_option(&buf->b_s.b_p_spl);
+ check_string_option(&buf->b_s.b_p_spo);
check_string_option(&buf->b_p_sua);
check_string_option(&buf->b_p_cink);
check_string_option(&buf->b_p_cino);
@@ -3087,6 +3095,10 @@ ambw_end:
} else if (varp == &(curwin->w_s->b_p_spc)) {
// When 'spellcapcheck' is set compile the regexp program.
errmsg = compile_cap_prog(curwin->w_s);
+ } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions'
+ if (**varp != NUL && STRCMP("camel", *varp) != 0) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_sps) { // 'spellsuggest'
if (spell_check_sps() != OK) {
errmsg = e_invarg;
@@ -3179,6 +3191,13 @@ ambw_end:
} else {
completeopt_was_set();
}
+#ifdef BACKSLASH_IN_FILENAME
+ } else if (gvarp == &p_csl) { // 'completeslash'
+ if (check_opt_strings(p_csl, p_csl_values, false) != OK
+ || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+#endif
} else if (varp == &curwin->w_p_scl) {
// 'signcolumn'
if (check_opt_strings(*varp, p_scl_values, false) != OK) {
@@ -3429,6 +3448,7 @@ ambw_end:
// recursively, to avoid endless recurrence.
apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
value_changed || syn_recursive == 1, curbuf);
+ curbuf->b_flags |= BF_SYN_SET;
syn_recursive--;
} else if (varp == &(curbuf->b_p_ft)) {
// 'filetype' is set, trigger the FileType autocommand
@@ -5856,6 +5876,9 @@ static char_u *get_varp(vimoption_T *p)
case PV_COM: return (char_u *)&(curbuf->b_p_com);
case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
+# ifdef BACKSLASH_IN_FILENAME
+ case PV_CSL: return (char_u *)&(curbuf->b_p_csl);
+# endif
case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
@@ -5893,6 +5916,7 @@ static char_u *get_varp(vimoption_T *p)
case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc);
case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf);
case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl);
+ case PV_SPO: return (char_u *)&(curwin->w_s->b_p_spo);
case PV_SW: return (char_u *)&(curbuf->b_p_sw);
case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
case PV_TS: return (char_u *)&(curbuf->b_p_ts);
@@ -6142,6 +6166,9 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inf = p_inf;
buf->b_p_swf = cmdmod.noswapfile ? false : p_swf;
buf->b_p_cpt = vim_strsave(p_cpt);
+# ifdef BACKSLASH_IN_FILENAME
+ buf->b_p_csl = vim_strsave(p_csl);
+# endif
buf->b_p_cfu = vim_strsave(p_cfu);
buf->b_p_ofu = vim_strsave(p_ofu);
buf->b_p_tfu = vim_strsave(p_tfu);
@@ -6172,6 +6199,7 @@ void buf_copy_options(buf_T *buf, int flags)
(void)compile_cap_prog(&buf->b_s);
buf->b_s.b_p_spf = vim_strsave(p_spf);
buf->b_s.b_p_spl = vim_strsave(p_spl);
+ buf->b_s.b_p_spo = vim_strsave(p_spo);
buf->b_p_inde = vim_strsave(p_inde);
buf->b_p_indk = vim_strsave(p_indk);
buf->b_p_fp = empty_option;
@@ -6791,7 +6819,8 @@ static void langmap_set(void)
/// Return true if format option 'x' is in effect.
/// Take care of no formatting when 'paste' is set.
-int has_format_option(int x)
+bool has_format_option(int x)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (p_paste) {
return false;
@@ -7258,7 +7287,8 @@ unsigned int get_bkc_value(buf_T *buf)
}
/// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
-int get_fileformat(buf_T *buf)
+int get_fileformat(const buf_T *buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int c = *buf->b_p_ff;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index ecaa941082..4042b79262 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -77,12 +77,13 @@
#define FO_ONE_LETTER '1'
#define FO_WHITE_PAR 'w' // trailing white space continues paragr.
#define FO_AUTO 'a' // automatic formatting
+#define FO_RIGOROUS_TW ']' // respect textwidth rigorously
#define FO_REMOVE_COMS 'j' // remove comment leaders when joining lines
#define FO_PERIOD_ABBR 'p' // don't break a single space after a period
#define DFLT_FO_VI "vt"
#define DFLT_FO_VIM "tcqj"
-#define FO_ALL "tcroq2vlb1mMBn,awjp" // for do_set()
+#define FO_ALL "tcroq2vlb1mMBn,aw]jp" // for do_set()
// characters for the p_cpo option:
#define CPO_ALTREAD 'a' // ":read" sets alternate file name
@@ -372,6 +373,9 @@ EXTERN long p_columns; // 'columns'
EXTERN int p_confirm; // 'confirm'
EXTERN int p_cp; // 'compatible'
EXTERN char_u *p_cot; // 'completeopt'
+# ifdef BACKSLASH_IN_FILENAME
+EXTERN char_u *p_csl; // 'completeslash'
+# endif
EXTERN long p_pb; // 'pumblend'
EXTERN long p_ph; // 'pumheight'
EXTERN long p_pw; // 'pumwidth'
@@ -453,7 +457,6 @@ EXTERN char_u *p_header; // 'printheader'
EXTERN int p_prompt; // 'prompt'
EXTERN char_u *p_guicursor; // 'guicursor'
EXTERN char_u *p_guifont; // 'guifont'
-EXTERN char_u *p_guifontset; // 'guifontset'
EXTERN char_u *p_guifontwide; // 'guifontwide'
EXTERN char_u *p_hf; // 'helpfile'
EXTERN long p_hh; // 'helpheight'
@@ -513,6 +516,7 @@ EXTERN long p_mle; // 'modelineexpr'
EXTERN long p_mls; // 'modelines'
EXTERN char_u *p_mouse; // 'mouse'
EXTERN char_u *p_mousem; // 'mousemodel'
+EXTERN long p_mousef; // 'mousefocus'
EXTERN long p_mouset; // 'mousetime'
EXTERN int p_more; // 'more'
EXTERN char_u *p_opfunc; // 'operatorfunc'
@@ -743,6 +747,7 @@ enum {
, BV_CPT
, BV_DICT
, BV_TSR
+ , BV_CSL
, BV_CFU
, BV_DEF
, BV_INC
@@ -787,6 +792,7 @@ enum {
, BV_SPC
, BV_SPF
, BV_SPL
+ , BV_SPO
, BV_STS
, BV_SUA
, BV_SW
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 60a38dc2e3..65ef7a4527 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -453,6 +453,15 @@ return {
defaults={if_true={vi="menu,preview"}}
},
{
+ full_name='completeslash', abbreviation='csl',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_csl',
+ enable_if='BACKSLASH_IN_FILENAME',
+ defaults={if_true={vi=""}}
+ },
+ {
full_name='confirm', abbreviation='cf',
type='bool', scope={'global'},
vi_def=true,
@@ -1022,15 +1031,6 @@ return {
defaults={if_true={vi=""}}
},
{
- full_name='guifontset', abbreviation='gfs',
- type='string', list='onecomma', scope={'global'},
- deny_duplicates=true,
- vi_def=true,
- varname='p_guifontset',
- redraw={'ui_option'},
- defaults={if_true={vi=""}}
- },
- {
full_name='guifontwide', abbreviation='gfw',
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
@@ -1597,7 +1597,8 @@ return {
full_name='mousefocus', abbreviation='mousef',
type='bool', scope={'global'},
vi_def=true,
- enable_if=false,
+ redraw={'ui_option'},
+ varname='p_mousef',
defaults={if_true={vi=false}}
},
{
@@ -2328,6 +2329,16 @@ return {
defaults={if_true={vi="best"}}
},
{
+ full_name='spelloptions', abbreviation='spo',
+ type='string', list='onecomma', scope={'buffer'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_spo',
+ defaults={if_true={vi="", vim=""}}
+ },
+ {
full_name='splitbelow', abbreviation='sb',
type='bool', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 082ad58223..879266e3d4 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -1176,7 +1176,9 @@ bool os_setenv_append_path(const char *fname)
temp[0] = NUL;
} else {
xstrlcpy(temp, path, newlen);
- xstrlcat(temp, ENV_SEPSTR, newlen);
+ if (ENV_SEPCHAR != path[pathlen - 1]) {
+ xstrlcat(temp, ENV_SEPSTR, newlen);
+ }
}
xstrlcat(temp, os_buf, newlen);
os_setenv("PATH", temp, 1);
diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c
index fe2d7986bf..603191a0ff 100644
--- a/src/nvim/os/lang.c
+++ b/src/nvim/os/lang.c
@@ -43,14 +43,20 @@ void lang_init(void)
}
}
+ char buf[50] = { 0 };
+ bool set_lang;
if (lang_region) {
- os_setenv("LANG", lang_region, true);
+ set_lang = true;
+ xstrlcpy(buf, lang_region, sizeof(buf));
} else {
- char buf[20] = { 0 };
- if (CFStringGetCString(cf_lang_region, buf, 20,
- kCFStringEncodingUTF8)) {
- os_setenv("LANG", buf, true);
+ set_lang = CFStringGetCString(cf_lang_region, buf, 40,
+ kCFStringEncodingUTF8);
+ }
+ if (set_lang) {
+ if (strcasestr(buf, "utf-8") == NULL) {
+ xstrlcat(buf, ".UTF-8", sizeof(buf));
}
+ os_setenv("LANG", buf, true);
}
CFRelease(cf_lang_region);
# ifdef HAVE_LOCALE_H
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index bfe230b521..bc774b8ebc 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -161,8 +161,8 @@ static void deadly_signal(int signum)
WLOG("got signal %d (%s)", signum, signal_name(signum));
- snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\n",
- signal_name(signum));
+ snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n",
+ signal_name(signum));
// Preserve files and exit.
preserve_exit();
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 346e40e02e..4b6533cd0c 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -56,6 +56,8 @@ uint64_t os_now(void)
/// Sleeps for `ms` milliseconds.
///
+/// @see uv_sleep() (libuv v1.34.0)
+///
/// @param ms Number of milliseconds to sleep
/// @param ignoreinput If true, only SIGINT (CTRL-C) can interrupt.
void os_delay(uint64_t ms, bool ignoreinput)
@@ -72,6 +74,8 @@ void os_delay(uint64_t ms, bool ignoreinput)
/// Sleeps for `us` microseconds.
///
+/// @see uv_sleep() (libuv v1.34.0)
+///
/// @param us Number of microseconds to sleep.
/// @param ignoreinput If true, ignore all input (including SIGINT/CTRL-C).
/// If false, waiting is aborted on any input.
@@ -172,10 +176,11 @@ char *os_ctime_r(const time_t *restrict clock, char *restrict result,
struct tm *clock_local_ptr = os_localtime_r(clock, &clock_local);
// MSVC returns NULL for an invalid value of seconds.
if (clock_local_ptr == NULL) {
- snprintf(result, result_len, "%s\n", _("(Invalid)"));
+ xstrlcpy(result, _("(Invalid)"), result_len);
} else {
- strftime(result, result_len, "%a %b %d %H:%M:%S %Y\n", clock_local_ptr);
+ strftime(result, result_len, _("%a %b %d %H:%M:%S %Y"), clock_local_ptr);
}
+ xstrlcat(result, "\n", result_len);
return result;
}
diff --git a/src/nvim/po/check.vim b/src/nvim/po/check.vim
index 650c6155e2..d55d4cfa4d 100644
--- a/src/nvim/po/check.vim
+++ b/src/nvim/po/check.vim
@@ -25,6 +25,7 @@ func! GetMline()
" remove '%', not used for formatting.
let idline = substitute(idline, "'%'", '', 'g')
+ let idline = substitute(idline, "%%", '', 'g')
" remove '%' used for plural forms.
let idline = substitute(idline, '\\nPlural-Forms: .\+;\\n', '', '')
diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po
index 19ea8e897a..f2179f4f1b 100644
--- a/src/nvim/po/uk.po
+++ b/src/nvim/po/uk.po
@@ -14,8 +14,8 @@ msgid ""
msgstr ""
"Project-Id-Version: vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-18 22:42+0200\n"
-"PO-Revision-Date: 2018-12-18 22:42+0200\n"
+"POT-Creation-Date: 2020-08-23 18:45+0300\n"
+"PO-Revision-Date: 2020-08-23 20:19+0300\n"
"Last-Translator: ะะฝะฐั‚ะพะปั–ะน ะกะฐั…ะฝั–ะบ <sakhnik@gmail.com>\n"
"Language-Team: Ukrainian\n"
"Language: uk\n"
@@ -95,6 +95,12 @@ msgid ""
"E89: No write since last change for buffer %<PRId64> (add ! to override)"
msgstr "E89: ะ‘ัƒั„ะตั€ %<PRId64> ะผะฐั” ะทะผั–ะฝะธ (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ะ—ะผั–ะฝะธ ะฝะต ะฑัƒะปะพ ะทะฐะฟะธัะฐะฝะพ (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
+
+msgid "E37: No write since last change"
+msgstr "E37: ะะต ะทะฐะฟะธัะฐะฝะพ ะฟั–ัะปั ะพัั‚ะฐะฝะฝั–ั… ะทะผั–ะฝ"
+
msgid "W14: Warning: List of file names overflow"
msgstr "W14: ะžะฑะตั€ะตะถะฝะพ: ะกะฟะธัะพะบ ะฝะฐะทะฒ ั„ะฐะนะปั–ะฒ ะฟะตั€ะตะฟะพะฒะฝะตะฝะพ"
@@ -123,9 +129,6 @@ msgstr " [ะ—ะผั–ะฝะตะฝะพ]"
msgid "[Not edited]"
msgstr "[ะะต ั€ะตะดะฐะณะพะฒะฐะฝะพ]"
-msgid "[New file]"
-msgstr "[ะะพะฒะธะน ั„ะฐะนะป]"
-
msgid "[Read errors]"
msgstr "[ะŸะพะผะธะปะบะธ ั‡ะธั‚ะฐะฝะฝั]"
@@ -168,23 +171,17 @@ msgstr "ะ—ะฝะธะทัƒ"
msgid "Top"
msgstr "ะ’ะณะพั€ั–"
-msgid "[Scratch]"
-msgstr "[ะ— ะฝัƒะปั]"
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: ะะต ะผะพะถัƒ ะทะฐะฟะธัะฐั‚ะธ, ะฒะบะฐะทะฐะฝะฐ ะพะฟั†ั–ั 'buftype'"
-msgid ""
-"\n"
-"--- Signs ---"
-msgstr ""
-"\n"
-"--- ะŸะพะทะฝะฐั‡ะบะธ ---"
+msgid "[Prompt]"
+msgstr "[ะ—ะฐะฟะธั‚]"
-#, c-format
-msgid "Signs for %s:"
-msgstr "ะŸะพะทะฝะฐั‡ะบะธ ะดะปั %s:"
+msgid "[Scratch]"
+msgstr "[ะ— ะฝัƒะปั]"
-#, c-format
-msgid " line=%<PRId64> id=%d name=%s"
-msgstr " ั€ัะดะพะบ=%<PRId64> id=%d ะฝะฐะทะฒะฐ=%s"
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ะ—ะฐัั‚ะตั€ะตะถะตะฝะฝั: ะ—ะผั–ะฝัŽั”ั‚ัŒัั ั„ะฐะนะป ะฟั€ะธะทะฝะฐั‡ะตะฝะธะน ะปะธัˆะต ะดะปั ั‡ะธั‚ะฐะฝะฝั"
msgid "can only be opened in headless mode"
msgstr "ะผะพะถะฝะฐ ะฒั–ะดะบั€ะธั‚ะธ ั‚ั–ะปัŒะบะธ ะฑะตะท ั–ะฝั‚ะตั€ั„ะตะนััƒ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ"
@@ -198,6 +195,9 @@ msgstr "ะะตะผะพะถะปะธะฒะพ ะฝะฐะดั–ัะปะฐั‚ะธ ะดะฐะฝั– ัƒ ะทะฐะบั€ะธั‚ะธะน ะฟะพั
msgid "Can't send raw data to rpc channel"
msgstr "ะะตะผะพะถะปะธะฒะพ ะฝะฐะดั–ัะปะฐั‚ะธ ะดะฐะฝั– ัƒ ะบะฐะฝะฐะป ะทะฐะฒะดะฐะฝะฝั"
+msgid "E474: Failed to convert list to msgpack string buffer"
+msgstr "E474: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ัะฟะธัะพะบ ัƒ ั‚ะตะบัั‚ะพะฒะธะน ะฑัƒั„ะตั€ msgpack"
+
msgid "E545: Missing colon"
msgstr "E545: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะดะฒะพะบั€ะฐะฟะบัƒ"
@@ -233,9 +233,6 @@ msgstr "E816: ะะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ั€ะตะทัƒะปัŒั‚ะฐั‚ patch"
msgid "E98: Cannot read diff output"
msgstr "E98: ะะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ั€ะตะทัƒะปัŒั‚ะฐั‚ diff"
-msgid "E959: Invalid diff format."
-msgstr "E959: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ั„ะพั€ะผะฐั‚ ะฟะพั€ั–ะฒะฝัะฝะฝั."
-
msgid "E99: Current buffer is not in diff mode"
msgstr "E99: ะฆะตะน ะฑัƒั„ะตั€ ะฝะต ะฒ ั€ะตะถะธะผั– ะฟะพั€ั–ะฒะฝัะฝะฝั"
@@ -264,6 +261,81 @@ msgstr "E787: ะ‘ัƒั„ะตั€ ะฝะตัะฟะพะดั–ะฒะฐะฝะพ ะทะผั–ะฝะธะฒัั"
msgid "E104: Escape not allowed in digraph"
msgstr "E104: ะฃ ะดะธะณั€ะฐั„ะฐั… ะฝะต ะผะพะถะต ะผั–ัั‚ะธั‚ะธัั escape"
+msgid "Custom"
+msgstr "ะ’ะปะฐัะฝะต"
+
+msgid "Latin supplement"
+msgstr "ะ›ะฐั‚ะธะฝะธั†ั ะดะพะฟะพะฒะฝะตะฝะฝั"
+
+msgid "Greek and Coptic"
+msgstr "ะ“ั€ะตั†ัŒะบะฐ ั– ะบะพะฟั‚ััŒะบะฐ"
+
+msgid "Cyrillic"
+msgstr "ะšะธั€ะธะปะธั†ั"
+
+msgid "Hebrew"
+msgstr "ะ†ะฒั€ะธั‚"
+
+msgid "Arabic"
+msgstr "ะั€ะฐะฑััŒะบะฐ"
+
+msgid "Latin extended"
+msgstr "ะ›ะฐั‚ะธะฝะธั†ั ั€ะพะทัˆะธั€ะตะฝะฐ"
+
+msgid "Greek extended"
+msgstr "ะ“ั€ะตั†ัŒะบะฐ ั€ะพะทัˆะธั€ะตะฝะฐ"
+
+msgid "Punctuation"
+msgstr "ะŸัƒะฝะบั‚ัƒะฐั†ั–ั"
+
+msgid "Super- and subscripts"
+msgstr "ะะฐะด- ั– ะฟั–ะดะฟะธัะธ"
+
+msgid "Currency"
+msgstr "ะ’ะฐะปัŽั‚ะฐ"
+
+msgid "Other"
+msgstr "ะ†ะฝัˆะต"
+
+msgid "Roman numbers"
+msgstr "ะ ะธะผััŒะบั– ั†ะธั„ั€ะธ"
+
+msgid "Arrows"
+msgstr "ะกั‚ั€ั–ะปะบะธ"
+
+msgid "Mathematical operators"
+msgstr "ะœะฐั‚ะตะผะฐั‚ะธั‡ะฝั– ะพะฟะตั€ะฐั‚ะพั€ะธ"
+
+msgid "Technical"
+msgstr "ะขะตั…ะฝั–ั‡ะฝะต"
+
+msgid "Box drawing"
+msgstr "ะœะฐะปัŽะฒะฐะฝะฝั ะฟั€ัะผะพะบัƒั‚ะฝะธะบั–ะฒ"
+
+msgid "Block elements"
+msgstr "ะงะฐัั‚ะธะฝะธ ะฑะปะพะบั–ะฒ"
+
+msgid "Geometric shapes"
+msgstr "ะ“ะตะพะผะตั‚ั€ะธั‡ะฝั– ั„ั–ะณัƒั€ะธ"
+
+msgid "Symbols"
+msgstr "ะกะธะผะฒะพะปะธ"
+
+msgid "Dingbats"
+msgstr "ะ”ัƒั€ะฝะธั†ั–"
+
+msgid "CJK symbols and punctuation"
+msgstr "ะกะธะผะฒะพะปะธ ั– ะฟัƒะฝะบั‚ัƒะฐั†ั–ั CJK"
+
+msgid "Hiragana"
+msgstr "ะฅั–ั€ะฐะณะฐะฝะฐ"
+
+msgid "Katakana"
+msgstr "ะšะฐั‚ะฐะบะฐะฝะฐ"
+
+msgid "Bopomofo"
+msgstr "ะ‘ะพะฟะพะผะพั„ะพ"
+
msgid "E544: Keymap file not found"
msgstr "E544: ะะต ะทะฝะฐะนะดะตะฝะพ ั„ะฐะนะป ั€ะพะทะบะปะฐะดะบะธ"
@@ -379,55 +451,18 @@ msgstr "E18: ะะตะพั‡ั–ะบัƒะฒะฐะฝั– ัะธะผะฒะพะปะธ ัƒ :let"
msgid "E111: Missing ']'"
msgstr "E111: ะ‘ั€ะฐะบัƒั” ']'"
-#, c-format
-msgid "E686: Argument of %s must be a List"
-msgstr "E686: ะั€ะณัƒะผะตะฝั‚ ัƒ %s ะผะฐั” ะฑัƒั‚ะธ ัะฟะธัะบะพะผ"
-
-#, c-format
-msgid "E712: Argument of %s must be a List or Dictionary"
-msgstr "E712: ะั€ะณัƒะผะตะฝั‚ ัƒ %s ะผะฐั” ะฑัƒั‚ะธ ัะฟะธัะบะพะผ ั‡ะธ ัะปะพะฒะฝะธะบะพะผ"
-
-msgid "E714: List required"
-msgstr "E714: ะŸะพั‚ั€ั–ะฑะตะฝ ัะฟะธัะพะบ"
-
-msgid "E715: Dictionary required"
-msgstr "E715: ะŸะพั‚ั€ั–ะฑะตะฝ ัะปะพะฒะฝะธะบ"
-
-msgid "E928: String required"
-msgstr "E928: ะŸะพั‚ั€ั–ะฑะตะฝ String"
-
-#, c-format
-msgid "E118: Too many arguments for function: %s"
-msgstr "E118: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั—: %s"
-
-#, c-format
-msgid "E716: Key not present in Dictionary: %s"
-msgstr "E716: ะะตะผะฐั” ั‚ะฐะบะพะณะพ ะบะปัŽั‡ะฐ ัƒ ัะปะพะฒะฝะธะบัƒ: %s"
-
-#, c-format
-msgid "E122: Function %s already exists, add ! to replace it"
-msgstr "E122: ะคัƒะฝะบั†ั–ั %s ัƒะถะต ั–ัะฝัƒั”, ! ั‰ะพะฑ ะทะฐะผั–ะฝะธั‚ะธ"
-
-msgid "E717: Dictionary entry already exists"
-msgstr "E717: ะ—ะฐะฟะธั ัƒ ัะปะพะฒะฝะธะบัƒ ะฒะถะต ั–ัะฝัƒั”"
-
-msgid "E718: Funcref required"
-msgstr "E718: ะขั€ะตะฑะฐ ะฟะพัะธะปะฐะฝะฝั ะฝะฐ ั„ัƒะฝะบั†ั–ัŽ"
-
msgid "E719: Cannot use [:] with a Dictionary"
msgstr "E719: ะะต ะผะพะถะฝะฐ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ [:] ะทั– ัะปะพะฒะฝะธะบะพะผ"
#, c-format
-msgid "E130: Unknown function: %s"
-msgstr "E130: ะะตะฒั–ะดะพะผะฐ ั„ัƒะฝะบั†ั–ั: %s"
-
-#, c-format
msgid "E461: Illegal variable name: %s"
msgstr "E461: ะะตะฟั€ะธะฟัƒัั‚ะธะผะฐ ะฝะฐะทะฒะฐ ะทะผั–ะฝะฝะพั—: %s"
-#, c-format
-msgid "E46: Cannot change read-only variable \"%.*s\""
-msgstr "E46: ะ—ะผั–ะฝะฝะฐ ั‚ั–ะปัŒะบะธ ะดะปั ั‡ะธั‚ะฐะฝะฝั: ยซ%.*sยป"
+msgid "E995: Cannot modify existing variable"
+msgstr "E995: ะะตะผะพะถะปะธะฒะพ ะทะผั–ะฝะธั‚ะธ ะฝะฐัะฒะฝัƒ ะทะผั–ะฝะฝัƒ"
+
+msgid "E957: Invalid window number"
+msgstr "E957: ะะตะบะพั€ะตะบั‚ะฝะธะน ะฝะพะผะตั€ ะฒั–ะบะฝะฐ"
#, c-format
msgid "E734: Wrong variable type for %s="
@@ -439,6 +474,19 @@ msgid ""
msgstr ""
"E5700: ะ’ะธั€ะฐะท ั–ะท 'spellsuggest' ะผะฐั” ะฟะพะฒะตั€ั‚ะฐั‚ะธ ัะฟะธัะพะบ ั–ะท ั€ั–ะฒะฝะพ ะดะฒะพะผะฐ ะตะปะตะผะตะฝั‚ะฐะผะธ"
+msgid "E991: cannot use =<< here"
+msgstr "E991: ะขัƒั‚ ะฝะต ะผะพะถะฝะฐ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ =<<"
+
+msgid "E221: Marker cannot start with lower case letter"
+msgstr "E221: ะŸะพะทะฝะฐั‡ะบะฐ ะฝะต ะผะพะถะต ะฟะพั‡ะธะฝะฐั‚ะธัั ั–ะท ะผะฐะปะพั— ะปั–ั‚ะตั€ะธ"
+
+msgid "E172: Missing marker"
+msgstr "E172: ะ‘ั€ะฐะบัƒั” ะฟะพะทะฝะฐั‡ะบะธ"
+
+#, c-format
+msgid "E990: Missing end marker '%s'"
+msgstr "E990: ะ‘ั€ะฐะบัƒั” ะฟะพะทะฝะฐั‡ะบะธ ะบั–ะฝั†ั ยซ%sยป"
+
msgid "E687: Less targets than List items"
msgstr "E687: ะฆั–ะปะตะน ะผะตะฝัˆะต, ะฝั–ะถ ะตะปะตะผะตะฝั‚ั–ะฒ ัะฟะธัะบัƒ"
@@ -452,6 +500,15 @@ msgstr "ะ”ั€ัƒะณะฐ ; ัƒ ัะฟะธัะบัƒ ะทะผั–ะฝะฝะธั…"
msgid "E738: Can't list variables for %s"
msgstr "E738: ะะต ะผะพะถะฝะฐ ะฟะตั€ะตั€ะฐั…ัƒะฒะฐั‚ะธ ะทะผั–ะฝะฝั– ัƒ %s"
+msgid "E996: Cannot lock an environment variable"
+msgstr "E996: ะะตะผะพะถะปะธะฒะพ ะทะฐะฑะปะพะบัƒะฒะฐั‚ะธ ะทะผั–ะฝะฝัƒ ะพั‚ะพั‡ะตะฝะฝั"
+
+msgid "E996: Cannot lock an option"
+msgstr "E996: ะะตะผะพะถะปะธะฒะพ ะทะฐะฑะปะพะบัƒะฒะฐั‚ะธ ะพะฟั†ั–ัŽ"
+
+msgid "E996: Cannot lock a register"
+msgstr "E996: ะะตะผะพะถะปะธะฒะพ ะทะฐะฑะปะพะบัƒะฒะฐั‚ะธ ั€ะตะณั–ัั‚ั€"
+
#, c-format
msgid "E121: Undefined variable: %.*s"
msgstr "E121: ะะตะฒะธะทะฝะฐั‡ะตะฝะฐ ะทะผั–ะฝะฝะฐ: %.*s"
@@ -468,20 +525,22 @@ msgstr "E713: ะะตะผะพะถะปะธะฒะพ ะฒะถะธั‚ะธ ะฟะพั€ะพะถะฝั–ะน ะบะปัŽั‡ ะฟั–ัะปั
msgid "E709: [:] requires a List value"
msgstr "E709: [:] ะฒะธะผะฐะณะฐั” ัะฟะธัะพะบ"
+msgid "E996: Cannot lock a range"
+msgstr "E996: ะะตะผะพะถะปะธะฒะพ ะทะฐะฑะปะพะบัƒะฒะฐั‚ะธ ะดั–ะฐะฟะฐะทะพะฝ"
+
msgid "E710: List value has more items than target"
msgstr "E710: ะกะฟะธัะพะบ ะผะฐั” ะฑั–ะปัŒัˆะต ะตะปะตะผะตะฝั‚ั–ะฒ, ะฝั–ะถ ั†ั–ะปัŒ"
msgid "E711: List value has not enough items"
msgstr "E711: ะกะฟะธัะพะบ ะผะฐั” ะฝะตะดะพัั‚ะฐั‚ะฝัŒะพ ะตะปะตะผะตะฝั‚ั–ะฒ"
+msgid "E996: Cannot lock a list or dict"
+msgstr "E996: ะะตะผะพะถะปะธะฒะพ ะทะฐะฑะปะพะบัƒะฒะฐั‚ะธ ัะฟะธัะพะบ ั‡ะธ ัะปะพะฒะฝะธะบ"
+
msgid "E690: Missing \"in\" after :for"
msgstr "E690: ะŸั€ะพะฟัƒั‰ะตะฝะพ ยซinยป ะฟั–ัะปั :for"
#, c-format
-msgid "E107: Missing parentheses: %s"
-msgstr "E107: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะดัƒะถะบะธ: %s"
-
-#, c-format
msgid "E108: No such variable: \"%s\""
msgstr "E108: ะ—ะผั–ะฝะฝะพั— ะฝะตะผะฐั”: ยซ%sยป"
@@ -563,68 +622,6 @@ msgstr "E722: ะ‘ั€ะฐะบัƒั” ะบะพะผะธ ัƒ ัะปะพะฒะฝะธะบัƒ: %s"
msgid "E723: Missing end of Dictionary '}': %s"
msgstr "E723: ะะตะผะฐั” ะบั–ะฝั†ั–ะฒะบะธ ัะปะพะฒะฝะธะบะฐ '}': %s"
-#, c-format
-msgid "E125: Illegal argument: %s"
-msgstr "E125: ะะตะดะพะทะฒะพะปะตะฝะธะน ะฐั€ะณัƒะผะตะฝั‚: %s"
-
-#, c-format
-msgid "E853: Duplicate argument name: %s"
-msgstr "E853: ะะฐะทะฒะฐ ะฐั€ะณัƒะผะตะฝั‚ัƒ ะฟะพะฒั‚ะพั€ัŽั”ั‚ัŒัั: %s"
-
-#, c-format
-msgid "E740: Too many arguments for function %s"
-msgstr "E740: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั— %s"
-
-#, c-format
-msgid "E116: Invalid arguments for function %s"
-msgstr "E116: ะะตะฟั€ะฐะฒะธะปัŒะฝั– ะฐั€ะณัƒะผะตะฝั‚ะธ ั„ัƒะฝะบั†ั–ั— %s"
-
-#, c-format
-msgid "E117: Unknown function: %s"
-msgstr "E117: ะะตะฒั–ะดะพะผะฐ ั„ัƒะฝะบั†ั–ั: %s"
-
-#, c-format
-msgid "E933: Function was deleted: %s"
-msgstr "E933: ะคัƒะฝะบั†ั–ัŽ ะฑัƒะปะพ ะฒะธะดะฐะปะตะฝะพ: %s"
-
-#, c-format
-msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: ะ—ะฐะผะฐะปะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั— %s"
-
-#, c-format
-msgid "E120: Using <SID> not in a script context: %s"
-msgstr "E120: <SID> ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะฝะต ัƒ ะบะพะฝั‚ะตะบัั‚ั– ัะบั€ะธะฟั‚ัƒ: %s"
-
-#, c-format
-msgid "E725: Calling dict function without Dictionary: %s"
-msgstr "E725: ะ’ะธะบะปะธะบ dict-ั„ัƒะฝะบั†ั–ั— ะฑะตะท ัะปะพะฒะฝะธะบะฐ: %s"
-
-#, c-format
-msgid "Error converting the call result: %s"
-msgstr "ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ั€ะตะทัƒะปัŒั‚ะฐั‚ ะฒะธะบะปะธะบัƒ: %s"
-
-msgid "add() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ add()"
-
-msgid "E699: Too many arguments"
-msgstr "E699: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ"
-
-#, c-format
-msgid "Invalid channel stream \"%s\""
-msgstr "ะะตะบะพั€ะตะบั‚ะฝะธะน ะฟะพั‚ั–ะบ ะทะฐะฒะดะฐะฝะฝั ยซ%sยป"
-
-msgid "E785: complete() can only be used in Insert mode"
-msgstr "E785: complete() ะผะพะถะฝะฐ ะฒะถะธะฒะฐั‚ะธ ั‚ั–ะปัŒะบะธ ะฒ ั€ะตะถะธะผั– ะฒัั‚ะฐะฒะปัะฝะฝั"
-
-msgid "&Ok"
-msgstr "&O:ะ“ะฐั€ะฐะทะด"
-
-msgid "dictwatcheradd() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ dictwatcheradd()"
-
-msgid "extend() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ extend()"
-
msgid "map() argument"
msgstr "ะฐั€ะณัƒะผะตะฝั‚ map()"
@@ -641,124 +638,13 @@ msgstr "E922: ะพั‡ั–ะบัƒั”ั‚ัŒัั ัะปะพะฒะฝะธะบ"
msgid "E923: Second argument of function() must be a list or a dict"
msgstr "E923: ะ”ั€ัƒะณะธะน ะฐั€ะณัƒะผะตะฝั‚ function() ะผะฐั” ะฑัƒั‚ะธ ัะฟะธัะบะพะผ ั‡ะธ ัะปะพะฒะฝะธะบะพะผ"
-msgid "E5000: Cannot find tab number."
-msgstr "E5000: ะะต ะผะพะถะฝะฐ ะทะฝะฐะนั‚ะธ ะฝะพะผะตั€ ะฒะบะปะฐะดะบะธ."
-
-msgid "E5001: Higher scope cannot be -1 if lower scope is >= 0."
-msgstr "E5001: ะ’ะธั‰ะฐ ะพะฑะปะฐัั‚ัŒ ะฝะต ะผะพะถะต ะฑัƒั‚ะธ -1, ัะบั‰ะพ ะฝะธะถั‡ะฐ ะพะฑะปะฐัั‚ัŒ >= 0."
-
-msgid "E5002: Cannot find window number."
-msgstr "E5002: ะะตะผะพะถะปะธะฒะพ ะทะฝะฐะนั‚ะธ ะฝะพะผะตั€ ะฒั–ะบะฝะฐ."
-
msgid "E5050: {opts} must be the only argument"
msgstr "E5050: {opts} ะผะฐั” ะฑัƒั‚ะธ ั”ะดะธะฝะธะผ ะฐั€ะณัƒะผะตะฝั‚ะพะผ"
-msgid "called inputrestore() more often than inputsave()"
-msgstr "ะ’ะธะบะปะธะบะธ ะดะพ inputrestore() ั‡ะฐัั‚ั–ัˆะต, ะฝั–ะถ ะดะพ inputsave()"
-
-msgid "insert() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ insert()"
-
-msgid "E786: Range not allowed"
-msgstr "E786: ะ†ะฝั‚ะตั€ะฒะฐะป ะฝะต ะดะพะทะฒะพะปะตะฝะพ"
-
-msgid "E474: Failed to convert list to string"
-msgstr "E474: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ัะฟะธัะพะบ ัƒ ั‚ะตะบัั‚"
-
-#, c-format
-msgid "E474: Failed to parse %.*s"
-msgstr "E474: ะะต ะฒะดะฐะปะพัั ั€ะพะทั–ะฑั€ะฐั‚ะธ %.*s"
-
-msgid "E701: Invalid type for len()"
-msgstr "E701: ะะตะบะพั€ะตะบั‚ะฝะธะน ั‚ะธะฟ ะดะปั len()"
-
-#, c-format
-msgid "E798: ID is reserved for \":match\": %<PRId64>"
-msgstr "E798: ID ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะพ ะดะปั \":match\": %<PRId64>"
-
-#, c-format
-msgid "E798: ID is reserved for \"match\": %<PRId64>"
-msgstr "E798: ID ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะพ ะดะปั \"match\": %<PRId64>"
-
-#, c-format
-msgid "msgpackdump() argument, index %i"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ msgpackdump(), ั–ะฝะดะตะบั %i"
-
-msgid "E5070: Character number must not be less than zero"
-msgstr "E5070: ะะพะผะตั€ ัะธะผะฒะพะปะฐ ะผะฐั” ะฑัƒั‚ะธ ะฝะตะฒั–ะดโ€™ั”ะผะฝะธะผ"
-
-#, c-format
-msgid "E5071: Character number must not be greater than INT_MAX (%i)"
-msgstr "E5071: ะะพะผะตั€ ัะธะผะฒะพะปะฐ ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ะฑั–ะปัŒัˆะธะผ, ะฝั–ะถ INT_MAX (%i)"
-
-msgid "E726: Stride is zero"
-msgstr "E726: ะšั€ะพะบ ะฝัƒะปัŒะพะฒะธะน"
-
-msgid "E727: Start past end"
-msgstr "E727: ะŸะพั‡ะฐั‚ะพะบ ะทะฐ ะบั–ะฝั†ะตะผ"
-
-msgid "<empty>"
-msgstr "<ะฝั–ั‡ะพะณะพ>"
-
-msgid "remove() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ remove()"
-
-msgid "E655: Too many symbolic links (cycle?)"
-msgstr "E655: ะ—ะฐะฑะฐะณะฐั‚ะพ ัะธะผะฒะพะปัŒะฝะธั… ะฟะพัะธะปะฐะฝัŒ (ั†ะธะบะป?)"
-
-msgid "reverse() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ reverse()"
-
-#, c-format
-msgid "E5010: List item %d of the second argument is not a string"
-msgstr "E5010: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะดั€ัƒะณะพะณะพ ะฐั€ะณัƒะผะตะฝั‚ัƒ ะฝะต ั‚ะตะบัั‚"
-
-#, c-format
-msgid "E927: Invalid action: '%s'"
-msgstr "E927: ะะตะฟั€ะฐะฒะธะปัŒะฝะฐ ะดั–ั: ยซ%sยป"
-
-#, c-format
-msgid "E474: List item %d is either not a dictionary or an empty one"
-msgstr "E474: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะฐะฑะพ ะฝะต ัะปะพะฒะฝะธะบ ะฐะฑะพ ะฟะพั€ะพะถะฝั–ะน"
-
-#, c-format
-msgid "E474: List item %d is missing one of the required keys"
-msgstr "E474: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะฝะตะผะฐั” ะพะดะฝะพะณะพ ะท ะพะฑะพะฒโ€™ัะทะบะพะฒะธั… ะบะปัŽั‡ั–ะฒ"
-
-#, c-format
-msgid "connection failed: %s"
-msgstr "ะทโ€™ั”ะดะฝะฐะฝะฝั ะฝะต ะฒะดะฐะปะพัั: %s"
-
-msgid "sort() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ sort()"
-
-msgid "uniq() argument"
-msgstr "ะฐั€ะณัƒะผะตะฝั‚ uniq()"
-
-msgid "E702: Sort compare function failed"
-msgstr "E702: ะŸะพะผะธะปะบะฐ ัƒ ั„ัƒะฝะบั†ั–ั— ะฟะพั€ั–ะฒะฝัะฝะฝั"
-
-msgid "E882: Uniq compare function failed"
-msgstr "E882: ะŸะพะผะธะปะบะฐ ัƒ ั„ัƒะฝะบั†ั–ั— ะฟะพั€ั–ะฒะฝัะฝะฝั uniq"
-
-#, c-format
-msgid "E6100: \"%s\" is not a valid stdpath"
-msgstr "E6100: \"%s\" โ€” ะฝะตะบะพั€ะตะบั‚ะฝะธะน stdpath"
-
-msgid "(Invalid)"
-msgstr "(ะะตะผะพะถะปะธะฒะพ)"
-
-#, c-format
-msgid "E935: invalid submatch number: %d"
-msgstr "E935: ะฝะตะฟั€ะฐะฒะธะปัŒะฝะธะน ะฝะพะผะตั€ ะณั€ัƒะฟะธ ัะฟั–ะฒะฟะฐะดั–ะฝะฝั: %d"
-
#, c-format
msgid "Executing command: \"%s\""
msgstr "ะ’ะธะบะพะฝัƒั”ั‚ัŒัั ะบะพะผะฐะฝะดะฐ: ยซ%sยป"
-msgid "Can only call this function in an unmodified buffer"
-msgstr "ะฆัŽ ั„ัƒะฝะบั†ั–ัŽ ะผะพะถะฝะฐ ะฒะธะบะปะธะบะฐั‚ะธ ั‚ั–ะปัŒะบะธ ัƒ ะฝะตะทะผั–ะฝะตะฝะพะผัƒ ะฑัƒั„ะตั€ั–"
-
msgid "E921: Invalid callback argument"
msgstr "E921: ะะตะบะพั€ะตะบั‚ะฝะธะน ะฐั€ะณัƒะผะตะฝั‚ ั„ัƒะฝะบั†ั–ั— ะทะฒะพั€ะพั‚ะฝัŒะพะณะพ ะฒะธะบะปะธะบัƒ"
@@ -767,21 +653,6 @@ msgid "E80: Error while writing: %s"
msgstr "E80: ะŸะพะผะธะปะบะฐ ะฟั–ะด ั‡ะฐั ะทะฐะฟะธััƒ: %s"
#, c-format
-msgid "E5060: Unknown flag: %s"
-msgstr "E5060: ะะตะฒั–ะดะพะผะธะน ะฟั€ะฐะฟะพั€ะตั†ัŒ: %s"
-
-msgid "E482: Can't open file with an empty name"
-msgstr "E482: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป ะท ะฟะพั€ะพะถะฝั–ะผ ั–ะผโ€™ัะผ"
-
-#, c-format
-msgid "E482: Can't open file %s for writing: %s"
-msgstr "E482: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป %s ะดะปั ะทะฐะฟะธััƒ: %s"
-
-#, c-format
-msgid "E80: Error when closing file %s: %s"
-msgstr "E80: ะŸะพะผะธะปะบะฐ ะฟั€ะธ ะทะฐะบั€ะธั‚ั‚ั– ั„ะฐะนะปัƒ %s: %s"
-
-#, c-format
msgid "E963: setting %s to value with wrong type"
msgstr "E963: ะฒัั‚ะฐะฝะพะฒะปะตะฝะฝั %s ะดะพ ะทะฝะฐั‡ะตะฝะฝั ะท ะฝะตะฟั€ะฐะฒะธะปัŒะฝะธะผ ั‚ะธะฟะพะผ"
@@ -799,90 +670,11 @@ msgstr "E704: ะะฐะทะฒะฐ ะทะผั–ะฝะฝะพั— Funcref ะผะฐั” ะฟะพั‡ะธะฝะฐั‚ะธัั ะท ะ
#, c-format
msgid "E705: Variable name conflicts with existing function: %s"
-msgstr "E705: ะะฐะทะฒะฐ ะทะผั–ะฝะฝะพั— ัะฟั–ะฒะฟะฐะดะฐั” ะท ั–ัะฝัƒัŽั‡ะพัŽ ั„ัƒะฝะบั†ั–ั”ัŽ: %s"
+msgstr "E705: ะะฐะทะฒะฐ ะทะผั–ะฝะฝะพั— ัะฟั–ะฒะฟะฐะดะฐั” ะท ะฝะฐัะฒะฝะพัŽ ั„ัƒะฝะบั†ั–ั”ัŽ: %s"
msgid "E698: variable nested too deep for making a copy"
msgstr "E698: ะ—ะผั–ะฝะฝะฐ ะฒะบะปะฐะดะตะฝะฐ ะทะฐะฝะฐะดั‚ะพ ะณะปะธะฑะพะบะพ ั‰ะพะฑ ะทั€ะพะฑะธั‚ะธ ั—ั— ะบะพะฟั–ัŽ"
-#, c-format
-msgid "E123: Undefined function: %s"
-msgstr "E123: ะะตะฒะธะทะฝะฐั‡ะตะฝะฐ ั„ัƒะฝะบั†ั–ั: %s"
-
-#, c-format
-msgid "E124: Missing '(': %s"
-msgstr "E124: ะ‘ั€ะฐะบัƒั” '(': %s"
-
-msgid "E862: Cannot use g: here"
-msgstr "E862: ะขัƒั‚ ะฝะต ะผะพะถะฝะฐ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ g:"
-
-#, c-format
-msgid "E932: Closure function should not be at top level: %s"
-msgstr "E932: ะคัƒะฝะบั†ั–ั ะทะฐะผะธะบะฐะฝะฝั ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ะฝะฐ ะฒะตั€ั…ะฝัŒะพะผัƒ ั€ั–ะฒะฝั–: %s"
-
-msgid "E126: Missing :endfunction"
-msgstr "E126: ะ‘ั€ะฐะบัƒั” :endfunction"
-
-#, c-format
-msgid "W22: Text found after :endfunction: %s"
-msgstr "W22: ะขั€ะฐะฟะธะฒัั ั‚ะตะบัั‚ ะฟั–ัะปั :endfunction: %s"
-
-#, c-format
-msgid "E707: Function name conflicts with variable: %s"
-msgstr "E707: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ัะฟั–ะฒะฟะฐะดะฐั” ะทั– ะทะผั–ะฝะฝะพัŽ: %s"
-
-#, c-format
-msgid "E127: Cannot redefine function %s: It is in use"
-msgstr "E127: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตะฒะธะทะฝะฐั‡ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะฒะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
-
-#, c-format
-msgid "E746: Function name does not match script file name: %s"
-msgstr "E746: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะฝะต ะทะฑั–ะณะฐั”ั‚ัŒัั ะท ะฝะฐะทะฒะพัŽ ั„ะฐะนะปัƒ ัะบั€ะธะฟั‚ัƒ: %s"
-
-msgid "E129: Function name required"
-msgstr "E129: ะะต ะฒะบะฐะทะฐะฝะพ ะฝะฐะทะฒัƒ ั„ัƒะฝะบั†ั–ั—"
-
-#, c-format
-msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะผะฐั” ะฟะพั‡ะธะฝะฐั‚ะธัั ะท ะฒะตะปะธะบะพั— ะปั–ั‚ะตั€ะธ ะฐะฑะพ \"s:\": %s"
-
-#, c-format
-msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E884: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะฝะต ะผะพะถะต ะผั–ัั‚ะธั‚ะธ ะดะฒะพะบั€ะฐะฟะบัƒ: %s"
-
-#, c-format
-msgid "E131: Cannot delete function %s: It is in use"
-msgstr "E131: ะะต ะฒะดะฐะปะพัั ะทะฝะธั‰ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะ’ะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
-
-#, c-format
-msgid "Cannot delete function %s: It is being used internally"
-msgstr "ะะต ะฒะดะฐะปะพัั ะทะฝะธั‰ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะ’ะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
-
-msgid "E132: Function call depth is higher than 'maxfuncdepth'"
-msgstr "E132: ะ“ะปะธะฑะธะฝะฐ ะฒะธะบะปะธะบั–ะฒ ั„ัƒะฝะบั†ั–ั— ะฟะตั€ะตะฒะธั‰ัƒั” 'maxfuncdepth'"
-
-#, c-format
-msgid "calling %s"
-msgstr "ะฒะธะบะปะธะบะฐั”ั‚ัŒัั %s"
-
-#, c-format
-msgid "%s aborted"
-msgstr "%s ะฟั€ะธะฟะธะฝะตะฝะพ"
-
-#, c-format
-msgid "%s returning #%<PRId64>"
-msgstr "%s ะฟะพะฒะตั€ั‚ะฐั” #%<PRId64>"
-
-#, c-format
-msgid "%s returning %s"
-msgstr "%s ะฟะพะฒะตั€ั‚ะฐั” %s"
-
-#, c-format
-msgid "continuing in %s"
-msgstr "ะฟั€ะพะดะพะฒะถะตะฝะฝั ะฒ %s"
-
-msgid "E133: :return not inside a function"
-msgstr "E133: :return ะฟะพะทะฐ ะผะตะถะฐะผะธ ั„ัƒะฝะบั†ั–ั—"
-
msgid ""
"\n"
"\tLast set from "
@@ -1155,6 +947,179 @@ msgid "E684: list index out of range: %<PRId64>"
msgstr "E684: ะ†ะฝะดะตะบั ัะฟะธัะบัƒ ะฟะพะทะฐ ะผะตะถะฐะผะธ: %<PRId64>"
#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: ะั€ะณัƒะผะตะฝั‚ ัƒ %s ะผะฐั” ะฑัƒั‚ะธ ัะฟะธัะบะพะผ"
+
+msgid "E928: String required"
+msgstr "E928: ะŸะพั‚ั€ั–ะฑะตะฝ String"
+
+#, c-format
+msgid "Error converting the call result: %s"
+msgstr "ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ั€ะตะทัƒะปัŒั‚ะฐั‚ ะฒะธะบะปะธะบัƒ: %s"
+
+msgid "add() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ add()"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ะะตะบะพั€ะตะบั‚ะฝะฐ ะฝะฐะทะฒะฐ ะฑัƒั„ะตั€ะฐ: %s"
+
+#, c-format
+msgid "Invalid channel stream \"%s\""
+msgstr "ะะตะบะพั€ะตะบั‚ะฝะธะน ะฟะพั‚ั–ะบ ะทะฐะฒะดะฐะฝะฝั ยซ%sยป"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ะผะพะถะฝะฐ ะฒะถะธะฒะฐั‚ะธ ั‚ั–ะปัŒะบะธ ะฒ ั€ะตะถะธะผั– ะฒัั‚ะฐะฒะปัะฝะฝั"
+
+msgid "&Ok"
+msgstr "&O:ะ“ะฐั€ะฐะทะด"
+
+msgid "Context stack is empty"
+msgstr "ะกั‚ะตะบ ะบะพะฝั‚ะตะบัั‚ัƒ ะฟะพั€ะพะถะฝั–ะน"
+
+msgid "dictwatcheradd() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ dictwatcheradd()"
+
+msgid "E900: maxdepth must be non-negative number"
+msgstr "E900: maxdepth ะผะฐั” ะฑัƒั‚ะธ ะฝะตะฒั–ะดโ€™ั”ะผะฝะธะผ ั‡ะธัะปะพะผ"
+
+msgid "flatten() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ flatten()"
+
+msgid "extend() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ extend()"
+
+msgid "E5000: Cannot find tab number."
+msgstr "E5000: ะะต ะผะพะถะฝะฐ ะทะฝะฐะนั‚ะธ ะฝะพะผะตั€ ะฒะบะปะฐะดะบะธ."
+
+msgid "E5001: Higher scope cannot be -1 if lower scope is >= 0."
+msgstr "E5001: ะ’ะธั‰ะฐ ะพะฑะปะฐัั‚ัŒ ะฝะต ะผะพะถะต ะฑัƒั‚ะธ -1, ัะบั‰ะพ ะฝะธะถั‡ะฐ ะพะฑะปะฐัั‚ัŒ >= 0."
+
+msgid "E5002: Cannot find window number."
+msgstr "E5002: ะะตะผะพะถะปะธะฒะพ ะทะฝะฐะนั‚ะธ ะฝะพะผะตั€ ะฒั–ะบะฝะฐ."
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "ะ’ะธะบะปะธะบะธ ะดะพ inputrestore() ั‡ะฐัั‚ั–ัˆะต, ะฝั–ะถ ะดะพ inputsave()"
+
+msgid "insert() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ะ†ะฝั‚ะตั€ะฒะฐะป ะฝะต ะดะพะทะฒะพะปะตะฝะพ"
+
+msgid "E474: Failed to convert list to string"
+msgstr "E474: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ัะฟะธัะพะบ ัƒ ั‚ะตะบัั‚"
+
+#, c-format
+msgid "E474: Failed to parse %.*s"
+msgstr "E474: ะะต ะฒะดะฐะปะพัั ั€ะพะทั–ะฑั€ะฐั‚ะธ %.*s"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: ะะตะบะพั€ะตะบั‚ะฝะธะน ั‚ะธะฟ ะดะปั len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %<PRId64>"
+msgstr "E798: ID ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะพ ะดะปั \":match\": %<PRId64>"
+
+#, c-format
+msgid "E798: ID is reserved for \"match\": %<PRId64>"
+msgstr "E798: ID ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะพ ะดะปั \"match\": %<PRId64>"
+
+#, c-format
+msgid "msgpackdump() argument, index %i"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ msgpackdump(), ั–ะฝะดะตะบั %i"
+
+msgid "E5070: Character number must not be less than zero"
+msgstr "E5070: ะะพะผะตั€ ัะธะผะฒะพะปะฐ ะผะฐั” ะฑัƒั‚ะธ ะฝะตะฒั–ะดโ€™ั”ะผะฝะธะผ"
+
+#, c-format
+msgid "E5071: Character number must not be greater than INT_MAX (%i)"
+msgstr "E5071: ะะพะผะตั€ ัะธะผะฒะพะปะฐ ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ะฑั–ะปัŒัˆะธะผ, ะฝั–ะถ INT_MAX (%i)"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ะšั€ะพะบ ะฝัƒะปัŒะพะฒะธะน"
+
+msgid "E727: Start past end"
+msgstr "E727: ะŸะพั‡ะฐั‚ะพะบ ะทะฐ ะบั–ะฝั†ะตะผ"
+
+msgid "<empty>"
+msgstr "<ะฝั–ั‡ะพะณะพ>"
+
+msgid "remove() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ะ—ะฐะฑะฐะณะฐั‚ะพ ัะธะผะฒะพะปัŒะฝะธั… ะฟะพัะธะปะฐะฝัŒ (ั†ะธะบะป?)"
+
+msgid "reverse() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ reverse()"
+
+#, c-format
+msgid "E5010: List item %d of the second argument is not a string"
+msgstr "E5010: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะดั€ัƒะณะพะณะพ ะฐั€ะณัƒะผะตะฝั‚ัƒ ะฝะต ั‚ะตะบัั‚"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: ะะตะฟั€ะฐะฒะธะปัŒะฝะฐ ะดั–ั: ยซ%sยป"
+
+#, c-format
+msgid "E474: List item %d is either not a dictionary or an empty one"
+msgstr "E474: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะฐะฑะพ ะฝะต ัะปะพะฒะฝะธะบ ะฐะฑะพ ะฟะพั€ะพะถะฝั–ะน"
+
+#, c-format
+msgid "E474: List item %d is missing one of the required keys"
+msgstr "E474: ะ•ะปะตะผะตะฝั‚ ัะฟะธัะบัƒ %d ะฝะตะผะฐั” ะพะดะฝะพะณะพ ะท ะพะฑะพะฒโ€™ัะทะบะพะฒะธั… ะบะปัŽั‡ั–ะฒ"
+
+#, c-format
+msgid "E962: Invalid action: '%s'"
+msgstr "E962: ะะตะฟั€ะฐะฒะธะปัŒะฝะฐ ะดั–ั: ยซ%sยป"
+
+#, c-format
+msgid "connection failed: %s"
+msgstr "ะทโ€™ั”ะดะฝะฐะฝะฝั ะฝะต ะฒะดะฐะปะพัั: %s"
+
+msgid "sort() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ sort()"
+
+msgid "uniq() argument"
+msgstr "ะฐั€ะณัƒะผะตะฝั‚ uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: ะŸะพะผะธะปะบะฐ ัƒ ั„ัƒะฝะบั†ั–ั— ะฟะพั€ั–ะฒะฝัะฝะฝั"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: ะŸะพะผะธะปะบะฐ ัƒ ั„ัƒะฝะบั†ั–ั— ะฟะพั€ั–ะฒะฝัะฝะฝั uniq"
+
+#, c-format
+msgid "E6100: \"%s\" is not a valid stdpath"
+msgstr "E6100: \"%s\" โ€” ะฝะตะบะพั€ะตะบั‚ะฝะธะน stdpath"
+
+msgid "(Invalid)"
+msgstr "(ะะตะผะพะถะปะธะฒะพ)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ะฝะตะฟั€ะฐะฒะธะปัŒะฝะธะน ะฝะพะผะตั€ ะณั€ัƒะฟะธ ัะฟั–ะฒะฟะฐะดั–ะฝะฝั: %d"
+
+msgid "Can only call this function in an unmodified buffer"
+msgstr "ะฆัŽ ั„ัƒะฝะบั†ั–ัŽ ะผะพะถะฝะฐ ะฒะธะบะปะธะบะฐั‚ะธ ั‚ั–ะปัŒะบะธ ัƒ ะฝะตะทะผั–ะฝะตะฝะพะผัƒ ะฑัƒั„ะตั€ั–"
+
+#, c-format
+msgid "E5060: Unknown flag: %s"
+msgstr "E5060: ะะตะฒั–ะดะพะผะธะน ะฟั€ะฐะฟะพั€ะตั†ัŒ: %s"
+
+msgid "E482: Can't open file with an empty name"
+msgstr "E482: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป ะท ะฟะพั€ะพะถะฝั–ะผ ั–ะผโ€™ัะผ"
+
+#, c-format
+msgid "E482: Can't open file %s for writing: %s"
+msgstr "E482: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป %s ะดะปั ะทะฐะฟะธััƒ: %s"
+
+#, c-format
+msgid "E80: Error when closing file %s: %s"
+msgstr "E80: ะŸะพะผะธะปะบะฐ ะฟั€ะธ ะทะฐะบั€ะธั‚ั‚ั– ั„ะฐะนะปัƒ %s: %s"
+
+#, c-format
msgid "E5142: Failed to open file %s: %s"
msgstr "E5142: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป %s: %s"
@@ -1199,6 +1164,9 @@ msgstr "E745: ะžั‡ั–ะบัƒั”ั‚ัŒัั Number ั‡ะธ String, ั‚ั€ะฐะฟะธะฒัั List"
msgid "E728: Expected a Number or a String, Dictionary found"
msgstr "E728: ะžั‡ั–ะบัƒั”ั‚ัŒัั Number ั‡ะธ String, ั‚ั€ะฐะฟะธะฒัั Dictionary"
+msgid "E5299: Expected a Number or a String, Boolean found"
+msgstr "E5299: ะžั‡ั–ะบัƒั”ั‚ัŒัั Number ั‡ะธ String, ั‚ั€ะฐะฟะธะฒัั Boolean"
+
msgid "E5300: Expected a Number or a String"
msgstr "E5300: ะžั‡ั–ะบัƒั”ั‚ัŒัั Number ั‡ะธ String"
@@ -1235,12 +1203,151 @@ msgstr "E893: List ะฒะถะธั‚ะพ ัะบ Float"
msgid "E894: Using a Dictionary as a Float"
msgstr "E894: Dictionary ะฒะถะธั‚ะพ ัะบ Float"
+msgid "E362: Using a boolean value as a Float"
+msgstr "E362: ะ’ะธะบะพั€ะธัั‚ะฐะฝะพ ะปะพะณั–ั‡ะฝะต ะทะฝะฐั‡ะตะฝะฝั ัะบ Float"
+
msgid "E907: Using a special value as a Float"
msgstr "E907: ะ’ะธะบะพั€ะธัั‚ะฐะฝะพ ัะฟะตั†ั–ะฐะปัŒะฝะต ะทะฝะฐั‡ะตะฝะฝั ัะบ Float"
msgid "E808: Number or Float required"
msgstr "E808: ะขั€ะตะฑะฐ ะฒะบะฐะทะฐั‚ะธ Number ั‡ะธ Float"
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: ะคัƒะฝะบั†ั–ั %s ัƒะถะต ั–ัะฝัƒั”, ! ั‰ะพะฑ ะทะฐะผั–ะฝะธั‚ะธ"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: ะ—ะฐะฟะธั ัƒ ัะปะพะฒะฝะธะบัƒ ะฒะถะต ั–ัะฝัƒั”"
+
+msgid "E718: Funcref required"
+msgstr "E718: ะขั€ะตะฑะฐ ะฟะพัะธะปะฐะฝะฝั ะฝะฐ ั„ัƒะฝะบั†ั–ัŽ"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: ะะตะฒั–ะดะพะผะฐ ั„ัƒะฝะบั†ั–ั: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ะะตะดะพะทะฒะพะปะตะฝะธะน ะฐั€ะณัƒะผะตะฝั‚: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: ะะฐะทะฒะฐ ะฐั€ะณัƒะผะตะฝั‚ัƒ ะฟะพะฒั‚ะพั€ัŽั”ั‚ัŒัั: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั— %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ะะตะฟั€ะฐะฒะธะปัŒะฝั– ะฐั€ะณัƒะผะตะฝั‚ะธ ั„ัƒะฝะบั†ั–ั— %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: ะ“ะปะธะฑะธะฝะฐ ะฒะธะบะปะธะบั–ะฒ ั„ัƒะฝะบั†ั–ั— ะฟะตั€ะตะฒะธั‰ัƒั” 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "ะฒะธะบะปะธะบะฐั”ั‚ัŒัั %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ะฟั€ะธะฟะธะฝะตะฝะพ"
+
+#, c-format
+msgid "%s returning #%<PRId64>"
+msgstr "%s ะฟะพะฒะตั€ั‚ะฐั” #%<PRId64>"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ะฟะพะฒะตั€ั‚ะฐั” %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ะฟั€ะพะดะพะฒะถะตะฝะฝั ะฒ %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: ะะตะฒั–ะดะพะผะฐ ั„ัƒะฝะบั†ั–ั: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: ะคัƒะฝะบั†ั–ัŽ ะฑัƒะปะพ ะฒะธะดะฐะปะตะฝะพ: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ะ—ะฐะผะฐะปะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั— %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะฝะต ัƒ ะบะพะฝั‚ะตะบัั‚ั– ัะบั€ะธะฟั‚ัƒ: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: ะ’ะธะบะปะธะบ dict-ั„ัƒะฝะบั†ั–ั— ะฑะตะท ัะปะพะฒะฝะธะบะฐ: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ะะต ะฒะบะฐะทะฐะฝะพ ะฝะฐะทะฒัƒ ั„ัƒะฝะบั†ั–ั—"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะผะฐั” ะฟะพั‡ะธะฝะฐั‚ะธัั ะท ะฒะตะปะธะบะพั— ะปั–ั‚ะตั€ะธ ะฐะฑะพ \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะฝะต ะผะพะถะต ะผั–ัั‚ะธั‚ะธ ะดะฒะพะบั€ะฐะฟะบัƒ: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ะะตะฒะธะทะฝะฐั‡ะตะฝะฐ ั„ัƒะฝะบั†ั–ั: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ะ‘ั€ะฐะบัƒั” '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ะขัƒั‚ ะฝะต ะผะพะถะฝะฐ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ g:"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: ะคัƒะฝะบั†ั–ั ะทะฐะผะธะบะฐะฝะฝั ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ะฝะฐ ะฒะตั€ั…ะฝัŒะพะผัƒ ั€ั–ะฒะฝั–: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ะ‘ั€ะฐะบัƒั” :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: ะขั€ะฐะฟะธะฒัั ั‚ะตะบัั‚ ะฟั–ัะปั :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ัะฟั–ะฒะฟะฐะดะฐั” ะทั– ะทะผั–ะฝะฝะพัŽ: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตะฒะธะทะฝะฐั‡ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะฒะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: ะะฐะทะฒะฐ ั„ัƒะฝะบั†ั–ั— ะฝะต ะทะฑั–ะณะฐั”ั‚ัŒัั ะท ะฝะฐะทะฒะพัŽ ั„ะฐะนะปัƒ ัะบั€ะธะฟั‚ัƒ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ะะต ะฒะดะฐะปะพัั ะทะฝะธั‰ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะ’ะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
+
+#, c-format
+msgid "Cannot delete function %s: It is being used internally"
+msgstr "ะะต ะฒะดะฐะปะพัั ะทะฝะธั‰ะธั‚ะธ ั„ัƒะฝะบั†ั–ัŽ %s: ะ’ะพะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ะฟะพะทะฐ ะผะตะถะฐะผะธ ั„ัƒะฝะบั†ั–ั—"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะดัƒะถะบะธ: %s"
+
msgid "tcp address must be host:port"
msgstr "ะฐะดั€ะตัะฐ tcp ะผะฐั” ะฑัƒั‚ะธ ะฒัƒะทะพะป:ะฟะพั€ั‚"
@@ -1306,7 +1413,7 @@ msgstr "E140: ะ’ะธะบะพั€ะธัั‚ะฐะนั‚ะต ! ะดะปั ะทะฐะฟะธััƒ ั‡ะฐัั‚ะธะฝะธ ะฑัƒ
#, c-format
msgid "Overwrite existing file \"%s\"?"
-msgstr "ะŸะตั€ะตะฟะธัะฐั‚ะธ ั–ัะฝัƒัŽั‡ะธะน ั„ะฐะนะป ยซ%sยป?"
+msgstr "ะŸะตั€ะตะฟะธัะฐั‚ะธ ะฝะฐัะฒะฝะธะน ั„ะฐะนะป ยซ%sยป?"
#, c-format
msgid "Swap file \"%s\" exists, overwrite anyway?"
@@ -1352,8 +1459,9 @@ msgstr "E143: ะะฒั‚ะพะบะพะผะฐะฝะดะธ ะฝะตัะฟะพะดั–ะฒะฐะฝะพ ะทะฝะธั‰ะธะปะธ ะฝะพะ
msgid "E144: non-numeric argument to :z"
msgstr "E144: ะฝะตั‡ะธัะปะพะฒะธะน ะฐั€ะณัƒะผะตะฝั‚ ะดะปั :z"
-msgid "E145: Shell commands not allowed in restricted mode"
-msgstr "E145: ะฃ ะพะฑะผะตะถะตะฝะพะผัƒ ั€ะตะถะธะผั– ะฝะต ะดะพะทะฒะพะปะตะฝั– ะบะพะผะฐะฝะดะธ ะพะฑะพะปะพะฝะบะธ"
+msgid ""
+"E145: Shell commands and some functionality not allowed in restricted mode"
+msgstr "E145: ะฃ ะพะฑะผะตะถะตะฝะพะผัƒ ั€ะตะถะธะผั– ะฝะต ะดะพะทะฒะพะปะตะฝั– ะบะพะผะฐะฝะดะธ ะพะฑะพะปะพะฝะบะธ ั– ะดะตัะบะฐ ั„ัƒะฝะบั–ะพะฝะฐะปัŒะฝั–ัั‚ัŒ"
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: ะ ะตะณัƒะปัั€ะฝั– ะฒะธั€ะฐะทะธ ะฝะต ะผะพะถะฝะฐ ั€ะพะทะดั–ะปัั‚ะธ ะปั–ั‚ะตั€ะฐะผะธ"
@@ -1439,48 +1547,6 @@ msgstr "E154: ะŸะพะฒั‚ะพั€ะตะฝะฝั ะผั–ั‚ะบะธ ยซ%sยป ัƒ ั„ะฐะนะปั– %s/%s"
msgid "E150: Not a directory: %s"
msgstr "E150: ะะต ั” ะบะฐั‚ะฐะปะพะณะพะผ: %s"
-#, c-format
-msgid "E160: Unknown sign command: %s"
-msgstr "E160: ะะตะฒั–ะดะพะผะฐ ะบะพะผะฐะฝะดะฐ ะฝะฐะดะฟะธััƒ: %s"
-
-msgid "E156: Missing sign name"
-msgstr "E156: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฝะฐะทะฒัƒ ะฝะฐะดะฟะธััƒ"
-
-msgid "E612: Too many signs defined"
-msgstr "E612: ะ’ะธะทะฝะฐั‡ะตะฝะพ ะทะฐะฑะฐะณะฐั‚ะพ ะฝะฐะดะฟะธัั–ะฒ"
-
-#, c-format
-msgid "E239: Invalid sign text: %s"
-msgstr "E239: ะะตะบะพั€ะตะบั‚ะฝะธะน ะฝะฐะดะฟะธั: %s"
-
-#, c-format
-msgid "E155: Unknown sign: %s"
-msgstr "E155: ะะตะฒั–ะดะพะผะธะน ะฝะฐะดะฟะธั: %s"
-
-msgid "E159: Missing sign number"
-msgstr "E159: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฝะพะผะตั€ ะฝะฐะดะฟะธััƒ"
-
-#, c-format
-msgid "E158: Invalid buffer name: %s"
-msgstr "E158: ะะตะบะพั€ะตะบั‚ะฝะฐ ะฝะฐะทะฒะฐ ะฑัƒั„ะตั€ะฐ: %s"
-
-msgid "E934: Cannot jump to a buffer that does not have a name"
-msgstr "E934: ะะต ะผะพะถะฝะฐ ะฟะตั€ะตะนั‚ะธ ะดะพ ะฑัƒั„ะตั€ะฐ ะฑะตะท ะฝะฐะทะฒะธ"
-
-#, c-format
-msgid "E157: Invalid sign ID: %<PRId64>"
-msgstr "E157: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ID ะฝะฐะดะฟะธััƒ: %<PRId64>"
-
-#, c-format
-msgid "E885: Not possible to change sign %s"
-msgstr "E885: ะะตะผะพะถะปะธะฒะพ ะทะผั–ะฝะธั‚ะธ ะทะฝะฐะบ %s"
-
-msgid " (not supported)"
-msgstr " (ะฝะต ะฟั–ะดั‚ั€ะธะผัƒั”ั‚ัŒัั)"
-
-msgid "[Deleted]"
-msgstr "[ะ—ะฝะธั‰ะตะฝะพ]"
-
msgid "No old files"
msgstr "ะ–ะพะดะฝะพะณะพ ัั‚ะฐั€ะพะณะพ ั„ะฐะนะปัƒ"
@@ -1545,6 +1611,9 @@ msgstr "E164: ะฆะต ะฒะถะต ะฝะฐะนะฟะตั€ัˆะธะน ั„ะฐะนะป"
msgid "E165: Cannot go beyond last file"
msgstr "E165: ะฆะต ะฒะถะต ะพัั‚ะฐะฝะฝั–ะน ั„ะฐะนะป"
+msgid "E610: No argument to delete"
+msgstr "E610: ะะตะผะฐั” ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ะทะฝะธั‰ะตะฝะฝั"
+
#, c-format
msgid "E666: compiler not supported: %s"
msgstr "E666: ะšะพะผะฟั–ะปัั‚ะพั€ ะฝะต ะฟั–ะดั‚ั€ะธะผัƒั”ั‚ัŒัั: %s"
@@ -1562,6 +1631,10 @@ msgid "not found in '%s': \"%s\""
msgstr "ะฝะต ะทะฝะฐะนะดะตะฝะพ ะฒ '%s': ยซ%sยป"
#, c-format
+msgid ":source error parsing command %s"
+msgstr ":source ะฟะพะผะธะปะบะฐ ั€ะพะทะฑะพั€ัƒ ะบะพะผะฐะฝะดะธ %s"
+
+#, c-format
msgid "Cannot source a directory: \"%s\""
msgstr "ะะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ะบะฐั‚ะฐะปะพะณ: ยซ%sยป"
@@ -1607,6 +1680,9 @@ msgstr "Lua"
msgid "API client (channel id %<PRIu64>)"
msgstr "ะšะปั–ั”ะฝั‚ API (ะบะฐะฝะฐะป ยซ%<PRIu64>ยป)"
+msgid "anonymous :source"
+msgstr "ะฐะฝะพะฝั–ะผะฝะธะน :source"
+
msgid "W15: Warning: Wrong line separator, ^M may be missing"
msgstr "W15: ะ—ะฐัั‚ะตั€ะตะถะตะฝะฝั: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ั€ะพะทะดั–ะปัŒะฝะธะบ ั€ัะดะบั–ะฒ, ะผะพะถะปะธะฒะพ, ะฑั€ะฐะบัƒั” ^M"
@@ -1652,6 +1728,9 @@ msgstr "E464: ะะตะพะดะฝะพะทะฝะฐั‡ะฝะธะน ะฒะถะธั‚ะพะบ ะบะพะผะฐะฝะดะธ ะบะพั€ะธัั
msgid "E492: Not an editor command"
msgstr "E492: ะฆะต ะฝะต ะบะพะผะฐะฝะดะฐ ั€ะตะดะฐะบั‚ะพั€ะฐ"
+msgid "E981: Command not allowed in restricted mode"
+msgstr "E981: ะšะพะผะฐะฝะดัƒ ะฝะต ะดะพะทะฒะพะปะตะฝะพ ัƒ ะพะฑะผะตะถะตะฝะพะผัƒ ั€ะตะถะธะผั–"
+
msgid "E493: Backwards range given"
msgstr "E493: ะ†ะฝั‚ะตั€ะฒะฐะป ะทะฐะดะฐะฝะพ ะฝะฐะฒะธะฒะพั€ั–ั‚"
@@ -1661,6 +1740,9 @@ msgstr "ะ†ะฝั‚ะตั€ะฒะฐะป ะทะฐะดะฐะฝะพ ะฝะฐะฒะธะฒะพั€ั–ั‚, ั‰ะพะฑ ะฟะพะผั–ะฝัั‚ะ
msgid "E494: Use w or w>>"
msgstr "E494: ะกะฟั€ะพะฑัƒะนั‚ะต w ะฐะฑะพ w>>"
+msgid "E943: Command table needs to be updated, run 'make'"
+msgstr "E943: ะŸะพั‚ั€ั–ะฑะฝะพ ะฟะพะฝะพะฒะธั‚ะธ ั‚ะฐะฑะปะธั†ัŽ ะบะพะผะฐะฝะด, ะทะฐะฟัƒัั‚ั–ั‚ัŒ 'make'"
+
msgid "E319: The command is not available in this version"
msgstr "E319: ะ’ะธะฑะฐั‡ั‚ะต, ั†ั–ั”ั— ะบะพะผะฐะฝะดะธ ะฝะตะผะฐั” ัƒ ั†ั–ะน ะฒะตั€ัั–ั—"
@@ -1678,15 +1760,16 @@ msgstr "E173: ะ—ะฐะปะธัˆะธะปะพัั ะฒั–ะดั€ะตะดะฐะณัƒะฒะฐั‚ะธ ั‰ะต ะพะดะธะฝ ั„ะฐ
msgid "E173: %<PRId64> more files to edit"
msgstr "E173: ะ—ะฐะปะธัˆะธะปะพัั %<PRId64> ะฝะต ั€ะตะดะฐะณะพะฒะฐะฝะธั… ั„ะฐะนะปั–ะฒ"
-msgid "E174: Command already exists: add ! to replace it"
-msgstr "E174: ะšะพะผะฐะฝะดะฐ ะฒะถะต ั–ัะฝัƒั”, ! ั‰ะพะฑ ะทะฐะผั–ะฝะธั‚ะธ ั—ั—"
+#, c-format
+msgid "E174: Command already exists: add ! to replace it: %s"
+msgstr "E174: ะšะพะผะฐะฝะดะฐ ะฒะถะต ั–ัะฝัƒั”, ! ั‰ะพะฑ ะทะฐะผั–ะฝะธั‚ะธ ั—ั—: %s"
msgid ""
"\n"
-" Name Args Address Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" ะะฐะทะฒะฐ ะั€ะณ. ะะดั€ะตัะฐ ะ”ะพะฟะพะฒะฝะตะฝะฝั ะ’ะธะทะฝะฐั‡ะตะฝะฝั"
+" ะะฐะทะฒะฐ ะั€ะณ. ะะดั€ะตัะฐ ะ”ะพะฟะพะฒะฝะตะฝะฝั ะ’ะธะทะฝะฐั‡ะตะฝะฝั"
msgid "No user-defined commands found"
msgstr "ะะต ะทะฝะฐะนะดะตะฝะพ ะบะพะผะฐะฝะด ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ"
@@ -1805,6 +1888,9 @@ msgstr "E498: ะะตะผะฐั” ะฝะฐะทะฒะธ ั„ะฐะนะปัƒ :source ะดะปั ะทะฐะผั–ะฝะธ ยซ<sf
msgid "E842: no line number to use for \"<slnum>\""
msgstr "E842: ะฝะตะผะฐั” ะฝะพะผะตั€ะฐ ั€ัะดะบะฐ, ั‰ะพะฑ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ ะท ยซ<sfile>ยป"
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: ะฝะตะผะฐั” ะฝะพะผะตั€ะฐ ั€ัะดะบะฐ, ั‰ะพะฑ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ ะท ยซ<sflnum>ยป"
+
#, c-format
msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
msgstr "E499: ะะฐะทะฒะฐ ั„ะฐะนะปัƒ ะดะปั '%' ั‡ะธ '#' ะฟะพั€ะพะถะฝั, ะฟั€ะฐั†ัŽั” ะปะธัˆะต ะท ยซ:p:hยป"
@@ -1962,9 +2048,6 @@ msgstr " ั‚ะธะฟ ั„ะฐะนะปัƒ\n"
msgid "'history' option is zero"
msgstr "ะžะฟั†ั–ั 'history' ะฟะพั€ะพะถะฝั"
-msgid "E198: cmd_pchar beyond the command length"
-msgstr "E198: cmd_pchar ะฟะพะทะฐ ะผะตะถะฐะผะธ ะบะพะผะฐะฝะดะธ"
-
msgid "E199: Active window or buffer deleted"
msgstr "E199: ะะบั‚ะธะฒะฝะต ะฒั–ะบะฝะพ ะฐะฑะพ ะฑัƒั„ะตั€ ะฑัƒะปะพ ะทะฝะธั‰ะตะฝะพ"
@@ -2007,9 +2090,6 @@ msgstr "ะบะฐั‚ะฐะปะพะณ"
msgid "is not a file"
msgstr "ะฝะต ั„ะฐะนะป"
-msgid "[New File]"
-msgstr "[ะะพะฒะธะน ั„ะฐะนะป]"
-
msgid "[New DIRECTORY]"
msgstr "[ะะพะฒะธะน ะบะฐั‚ะฐะปะพะณ]"
@@ -2043,6 +2123,9 @@ msgstr "[ัะฟะตั†. ัะธะผะฒะพะปัŒะฝะธะน]"
msgid "[CR missing]"
msgstr "[ะ‘ั€ะฐะบัƒั” CR]"
+msgid "[long lines split]"
+msgstr "[ะดะพะฒะณั– ั€ัะดะบะธ ั€ะพะทะฑะธั‚ะพ]"
+
msgid "[NOT converted]"
msgstr "[ะะ• ะบะพะฝะฒะตั€ั‚ะพะฒะฐะฝะพ]"
@@ -2069,6 +2152,12 @@ msgstr "ะšะพะฝะฒะตั€ั‚ะฐั†ั–ั ะท 'charconvert' ะฝะต ะฒะดะฐะปะฐัั"
msgid "can't read output of 'charconvert'"
msgstr "ะฝะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ะฒะธะฒั–ะด 'charconvert'"
+msgid "[New File]"
+msgstr "[ะะพะฒะธะน ั„ะฐะนะป]"
+
+msgid "[New]"
+msgstr "[ะะพะฒะธะน]"
+
msgid "E676: No matching autocommands for acwrite buffer"
msgstr "E676: ะะตะผะฐั” ะฒั–ะดะฟะพะฒั–ะดะฝะธั… ะฐะฒั‚ะพะบะพะผะฐะฝะด"
@@ -2087,15 +2176,6 @@ msgstr "ะปะธัˆะต ะดะปั ั‡ะธั‚ะฐะฝะฝั (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
msgid "E506: Can't write to backup file (add ! to override)"
msgstr "E506: ะะต ะฒะดะฐะปะพัั ะทะฐะฟะธัะฐั‚ะธ ั€ะตะทะตั€ะฒะฝะธะน ั„ะฐะนะป (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
-#, c-format
-msgid "E507: Close error for backup file (add ! to override): %s"
-msgstr "E507: ะŸะพะผะธะปะบะฐ ะทะฐะบั€ะธั‚ั‚ั ั€ะตะทะตั€ะฒะฝะพะณะพ ั„ะฐะนะปัƒ (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ): %s"
-
-msgid "E508: Can't read file for backup (add ! to override)"
-msgstr ""
-"E508: ะะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ั„ะฐะนะป ั‰ะพะฑ ัั‚ะฒะพั€ะธั‚ะธ ั€ะตะทะตั€ะฒะฝัƒ ะบะพะฟั–ัŽ (! ั‰ะพะฑ ะฝะต "
-"ะทะฒะฐะถะฐั‚ะธ)"
-
msgid "E509: Cannot create backup file (add ! to override)"
msgstr "E509: ะะต ะฒะดะฐะปะพัั ัั‚ะฒะพั€ะธั‚ะธ ั€ะตะทะตั€ะฒะฝัƒ ะบะพะฟั–ัŽ (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
@@ -2116,10 +2196,6 @@ msgid "E212: Can't open file for writing: %s"
msgstr "E212: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป ะดะปั ะทะฐะฟะธััƒ: %s"
#, c-format
-msgid "E667: Fsync failed: %s"
-msgstr "E667: ะะต ะฒะดะฐะปะพัั ะฒะธะบะพะฝะฐั‚ะธ fsync: %s"
-
-#, c-format
msgid "E512: Close failed: %s"
msgstr "E512: ะะต ะฒะดะฐะปะพัั ะทะฐะบั€ะธั‚ะธ: %s"
@@ -2142,9 +2218,6 @@ msgstr " ัƒ ั€ัะดะบัƒ %<PRId64>;"
msgid "[Device]"
msgstr "[ะŸั€ะธัั‚ั€ั–ะน]"
-msgid "[New]"
-msgstr "[ะะพะฒะธะน]"
-
msgid " [a]"
msgstr "[ะด]"
@@ -2461,6 +2534,18 @@ msgid "E475: Invalid argument: %s"
msgstr "E475: ะะตะบะพั€ะตะบั‚ะฝะธะน ะฐั€ะณัƒะผะตะฝั‚: %s"
#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: ะะตะบะพั€ะตะบั‚ะฝะต ะทะฝะฐั‡ะตะฝะฝั ะฐั€ะณัƒะผะตะฝั‚ัƒ %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: ะะตะบะพั€ะตะบั‚ะฝะต ะทะฝะฐั‡ะตะฝะฝั ะฐั€ะณัƒะผะตะฝั‚ัƒ %s: %s"
+
+#, c-format
+msgid "E983: Duplicate argument: %s"
+msgstr "E983: ะั€ะณัƒะผะตะฝั‚ ะฟะพะฒั‚ะพั€ัŽั”ั‚ัŒัั: %s"
+
+#, c-format
msgid "E15: Invalid expression: %s"
msgstr "E15: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ะฒะธั€ะฐะท: %s"
@@ -2512,6 +2597,10 @@ msgid "E364: Library call failed for \"%s()\""
msgstr "E364: ะ‘ั–ะฑะปั–ะพั‚ะตั‡ะฝะธะน ะฒะธะบะปะธะบ ะดะพ ยซ%s()ยป ะฝะต ะฒะดะฐะฒัั"
#, c-format
+msgid "E667: Fsync failed: %s"
+msgstr "E667: ะะต ะฒะดะฐะปะพัั ะฒะธะบะพะฝะฐั‚ะธ fsync: %s"
+
+#, c-format
msgid "E739: Cannot create directory %s: %s"
msgstr "E739: ะะต ะฒะดะฐะปะพัั ัั‚ะฒะพั€ะธั‚ะธ ะบะฐั‚ะฐะปะพะณ %s: %s"
@@ -2589,12 +2678,6 @@ msgstr "E484: ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ั„ะฐะนะป %s: %s"
msgid "E485: Can't read file %s"
msgstr "E485: ะะต ะฒะดะฐะปะพัั ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ั„ะฐะนะป %s"
-msgid "E37: No write since last change (add ! to override)"
-msgstr "E37: ะ—ะผั–ะฝะธ ะฝะต ะฑัƒะปะพ ะทะฐะฟะธัะฐะฝะพ (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
-
-msgid "E37: No write since last change"
-msgstr "E37: ะะต ะทะฐะฟะธัะฐะฝะพ ะฟั–ัะปั ะพัั‚ะฐะฝะฝั–ั… ะทะผั–ะฝ"
-
msgid "E38: Null argument"
msgstr "E38: ะ’ั–ะดััƒั‚ะฝั–ะน ะฐั€ะณัƒะผะตะฝั‚"
@@ -2636,6 +2719,28 @@ msgstr "E44: ะ—ั–ะฟัะพะฒะฐะฝะฐ ะฟั€ะพะณั€ะฐะผะฐ ั€ะตะณัƒะปัั€ะฝะธั… ะฒะธั€ะฐะท
msgid "E45: 'readonly' option is set (add ! to override)"
msgstr "E45: ะ’ัั‚ะฐะฝะพะฒะปะตะฝะพ ะพะฟั†ั–ัŽ 'readonly' (! ั‰ะพะฑ ะฝะต ะทะฒะฐะถะฐั‚ะธ)"
+#, c-format
+msgid "E46: Cannot change read-only variable \"%.*s\""
+msgstr "E46: ะ—ะผั–ะฝะฝะฐ ั‚ั–ะปัŒะบะธ ะดะปั ั‡ะธั‚ะฐะฝะฝั: ยซ%.*sยป"
+
+msgid "E715: Dictionary required"
+msgstr "E715: ะŸะพั‚ั€ั–ะฑะตะฝ ัะปะพะฒะฝะธะบ"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั ั„ัƒะฝะบั†ั–ั—: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: ะะตะผะฐั” ั‚ะฐะบะพะณะพ ะบะปัŽั‡ะฐ ัƒ ัะปะพะฒะฝะธะบัƒ: %s"
+
+msgid "E714: List required"
+msgstr "E714: ะŸะพั‚ั€ั–ะฑะตะฝ ัะฟะธัะพะบ"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: ะั€ะณัƒะผะตะฝั‚ ัƒ %s ะผะฐั” ะฑัƒั‚ะธ ัะฟะธัะบะพะผ ั‡ะธ ัะปะพะฒะฝะธะบะพะผ"
+
msgid "E47: Error while reading errorfile"
msgstr "E47: ะŸะพะผะธะปะบะฐ ั‡ะธั‚ะฐะฝะฝั ั„ะฐะนะปัƒ ะฟะพะผะธะปะพะบ"
@@ -2756,12 +2861,29 @@ msgstr "E5521: ะ—ะฐะผั–ะฝะฐ ะบะปะฐะฒั–ัˆ <Cmd> ะผะฐั” ะทะฐะบั–ะฝั‡ัƒะฒะฐั‚ะธัั
msgid "E5522: <Cmd> mapping must not include %s key"
msgstr "E5522: ะ—ะฐะผั–ะฝะฐ ะบะปะฐะฒั–ัˆ <Cmd> ะฝะต ะผะพะถะต ะผั–ัั‚ะธั‚ะธ ะบะปัŽั‡ %s"
+#, c-format
+msgid "E5555: API call: %s"
+msgstr "E5555: ะฒะธะบะปะธะบ API: %s"
+
+#, c-format
+msgid "E5560: %s must not be called in a lua loop callback"
+msgstr "E5560: %s ะผะฐั” ะฑัƒั‚ะธ ะฒะธะบะปะธะบะฐะฝะต ัƒ ะบะพะฝั‚ะตะบัั‚ั– ั†ะธะบะปัƒ lua"
+
+msgid "E5601: Cannot close window, only floating window would remain"
+msgstr "E5601: ะะต ะฒะดะฐะปะพัั ะทะฐะบั€ะธั‚ะธ ะฒั–ะบะฝะพ, ะทะฐะปะธัˆะธะปะพัั ะฑ ั‚ั–ะปัŒะบะธ ะฟะปะฐะฒัƒั‡ะต ะฒั–ะบะฝะพ"
+
+msgid "E5602: Cannot exchange or rotate float"
+msgstr "E5602: ะะต ะผะพะถะฝะฐ ะพะฑะผั–ะฝัั‚ะธ ั‡ะธ ะฟะพะบั€ัƒั‚ะธั‚ะธ ะฟะปะฐะฒัƒั‡ะต ะฒั–ะบะฝะพ"
+
msgid "search hit TOP, continuing at BOTTOM"
msgstr "ะŸะพัˆัƒะบ ะดั–ะนัˆะพะฒ ะดะพ ะŸะžะงะะขะšะฃ, ะฟั€ะพะดะพะฒะถัƒั”ั‚ัŒัั ะท ะšะ†ะะฆะฏ"
msgid "search hit BOTTOM, continuing at TOP"
msgstr "ะŸะพัˆัƒะบ ะดั–ะนัˆะพะฒ ะดะพ ะšะ†ะะฆะฏ, ะฟั€ะพะดะพะฒะถัƒั”ั‚ัŒัั ะท ะŸะžะงะะขะšะฃ"
+msgid " line "
+msgstr " ั€ัะดะพะบ "
+
msgid "E550: Missing colon"
msgstr "E550: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะดะฒะพะบั€ะฐะฟะบัƒ"
@@ -3032,6 +3154,14 @@ msgid "E5102: Lua failed to grow stack to %i"
msgstr "E5102: Lua ะฝะต ะฒะดะฐะปะพัั ะทะฑั–ะปัŒัˆะธั‚ะธ ัั‚ะตะบ ะดะพ %i"
#, c-format
+msgid "Error executing vim.schedule lua callback: %.*s"
+msgstr "ะŸะพะผะธะปะบะฐ ะฒะธะบะพะฝะฐะฝะฝั ะพะฑั€ะพะฑะฝะธะบะฐ lua vim.schedule: %.*s"
+
+#, c-format
+msgid "E5106: Error while creating shared module: %.*s"
+msgstr "E5106: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ั€ะพะทะดั–ะปัŽะฒะฐะฝะพะณะพ ะผะพะดัƒะปั: %.*s"
+
+#, c-format
msgid "E5106: Error while creating vim module: %.*s"
msgstr "E5106: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ะผะพะดัƒะปั vim: %.*s"
@@ -3043,14 +3173,6 @@ msgid "E5117: Error while updating package paths: %.*s"
msgstr "E5117: ะŸะพะผะธะปะบะฐ ะพะฝะพะฒะปะตะฝะฝั ัˆะปัั…ั–ะฒ ะฟะฐะบัƒะฝะบัƒ: %.*s"
#, c-format
-msgid "E5104: Error while creating lua chunk: %.*s"
-msgstr "E5104: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ัˆะผะฐั‚ะบัƒ lua: %.*s"
-
-#, c-format
-msgid "E5105: Error while calling lua chunk: %.*s"
-msgstr "E5105: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ ัˆะผะฐั‚ะบัƒ lua: %.*s"
-
-#, c-format
msgid "E5114: Error while converting print argument #%i: %.*s"
msgstr "E5114: ะะต ะฒะดะฐะปะพัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ะฐั€ะณัƒะผะตะฝั‚ #%i ะดั€ัƒะบัƒ: %.*s"
@@ -3063,27 +3185,31 @@ msgid "E5116: Error while calling debug string: %.*s"
msgstr "E5116: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ ะฝะฐะปะฐะณะพะดะถะตะฝะฝั: %.*s"
#, c-format
-msgid "E5107: Error while creating lua chunk for luaeval(): %.*s"
-msgstr "E5107: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ัˆะผะฐั‚ะบัƒ lua ะดะปั luaeval(): %.*s"
+msgid "E5107: Error loading lua %.*s"
+msgstr "E5107: ะŸะพะผะธะปะบะฐ ะทะฐะฒะฐะฝั‚ะฐะถะตะฝะฝั lua %.*s"
#, c-format
-msgid "E5108: Error while calling lua chunk for luaeval(): %.*s"
-msgstr "E5108: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ ัˆะผะฐั‚ะบัƒ lua ะดะปั luaeval(): %.*s"
+msgid "E5108: Error executing lua %.*s"
+msgstr "E5108: ะŸะพะผะธะปะบะฐ ะฒะธะบะพะฝะฐะฝะฝั lua %.*s"
+
+#, c-format
+msgid "Error executing lua callback: %.*s"
+msgstr "ะŸะพะผะธะปะบะฐ ะฒะธะบะพะฝะฐะฝะฝั ะพะฑั€ะพะฑะฝะธะบะฐ lua: %.*s"
msgid "cannot save undo information"
msgstr "ะะต ะฒะดะฐะปะพัั ะทะฐะฟะธัะฐั‚ะธ ั–ะฝั„ะพั€ะผะฐั†ั–ัŽ ะฟะพะฒะตั€ะฝะตะฝะฝั"
#, c-format
-msgid "E5109: Error while creating lua chunk: %.*s"
-msgstr "E5109: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ัˆะผะฐั‚ะบัƒ lua: %.*s"
+msgid "E5109: Error loading lua: %.*s"
+msgstr "E5109: ะŸะพะผะธะปะบะฐ ะทะฐะฒะฐะฝั‚ะฐะถะตะฝะฝั lua: %.*s"
#, c-format
-msgid "E5110: Error while creating lua function: %.*s"
-msgstr "E5110: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ั„ัƒะฝะบั†ั–ั— lua: %.*s"
+msgid "E5110: Error executing lua: %.*s"
+msgstr "E5110: ะŸะพะผะธะปะบะฐ ะฒะธะบะพะฝะฐะฝะฝั lua: %.*s"
#, c-format
-msgid "E5111: Error while calling lua function: %.*s"
-msgstr "E5111: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ ั„ัƒะฝะบั†ั–ั— lua: %.*s"
+msgid "E5111: Error calling lua: %.*s"
+msgstr "E5111: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ lua: %.*s"
#, c-format
msgid "E5112: Error while creating lua chunk: %.*s"
@@ -3093,6 +3219,10 @@ msgstr "E5112: ะŸะพะผะธะปะบะฐ ัั‚ะฒะพั€ะตะฝะฝั ัˆะผะฐั‚ะบัƒ lua: %.*s"
msgid "E5113: Error while calling lua chunk: %.*s"
msgstr "E5113: ะŸะพะผะธะปะบะฐ ะฒะธะบะปะธะบัƒ ัˆะผะฐั‚ะบัƒ lua: %.*s"
+#, c-format
+msgid "Error executing vim.log_keystroke lua callback: %.*s"
+msgstr "ะŸะพะผะธะปะบะฐ ะฒะธะบะพะฝะฐะฝะฝั ะพะฑั€ะพะฑะฝะธะบะฐ lua vim.log_keystroke: %.*s"
+
msgid "Argument missing after"
msgstr "ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฐั€ะณัƒะผะตะฝั‚ ะฟั–ัะปั"
@@ -3123,6 +3253,9 @@ msgstr "ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ะดะปั ั‡ะธั‚ะฐะฝะฝั: \"%s\": %s\n
msgid "Cannot open for script output: \""
msgstr "ะะต ะฒะดะฐะปะพัั ะฒั–ะดะบั€ะธั‚ะธ ัะบ ะฒะธั…ั–ะดะฝะธะน ั„ะฐะนะป: \""
+msgid "--embed conflicts with -es/-Es"
+msgstr "--embed ะบะพะฝั„ะปั–ะบั‚ัƒั” ะท -es/-Es"
+
msgid "pre-vimrc command line"
msgstr "ะบะพะผะฐะฝะดะธ ะฟะตั€ะตะด vimrc"
@@ -3567,8 +3700,8 @@ msgid "E315: ml_get: invalid lnum: %<PRId64>"
msgstr "E315: ml_get: ะฝะตะฟั€ะฐะฒะธะปัŒะฝะธะน lnum: %<PRId64>"
#, c-format
-msgid "E316: ml_get: cannot find line %<PRId64>"
-msgstr "E316: ml_get: ะฝะต ะทะฝะฐะนัˆะพะฒ ั€ัะดะพะบ %<PRId64>"
+msgid "E316: ml_get: cannot find line %<PRId64> in buffer %d %s"
+msgstr "E316: ml_get: ะฝะต ะทะฝะฐะนัˆะพะฒ ั€ัะดะพะบ %<PRId64> ัƒ ะฑัƒั„ะตั€ั– %d %s"
msgid "E317: pointer block id wrong 3"
msgstr "E317: ะ’ะบะฐะทั–ะฒะฝะธะบ ะฑะปะพะบัƒ ะฟะพะผะธะปะบะพะฒะธะน 3"
@@ -3666,6 +3799,9 @@ msgstr ""
"ยป,\n"
" ั‰ะพะฑ ะฟะพะทะฑัƒั‚ะธัั ั†ัŒะพะณะพ ะฟะพะฒั–ะดะพะผะปะตะฝะฝั.\n"
+msgid "Found a swap file that is not useful, deleting it"
+msgstr "ะ—ะฝะฐะนะดะตะฝะพ ั„ะฐะนะป ะพะฑะผั–ะฝัƒ, ัะบะธะผ ะฝะต ะผะพะถะฝะฐ ัะบะพั€ะธัั‚ะฐั‚ะธัั, ะทะฝะธั‰ะตะฝะฝั"
+
msgid "Swap file \""
msgstr "ะคะฐะนะป ะพะฑะผั–ะฝัƒ ยซ"
@@ -3750,6 +3886,10 @@ msgstr ""
"\n"
"--- ะœะตะฝัŽ ---"
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: ะ”ะปั ั€ะตะถะธะผัƒ %s ะผะตะฝัŽ ะฝะต ะฒะธะทะฝะฐั‡ะตะฝะพ"
+
msgid "E333: Menu path must lead to a menu item"
msgstr "E333: ะจะปัั… ะฟะพะฒะธะฝะตะฝ ะฒะตัั‚ะธ ะดะพ ะตะปะตะผะตะฝั‚ะฐ ะผะตะฝัŽ"
@@ -3758,10 +3898,6 @@ msgid "E334: Menu not found: %s"
msgstr "E334: ะœะตะฝัŽ ะฝะต ะทะฝะฐะนะดะตะฝะพ: %s"
#, c-format
-msgid "E335: Menu not defined for %s mode"
-msgstr "E335: ะ”ะปั ั€ะตะถะธะผัƒ %s ะผะตะฝัŽ ะฝะต ะฒะธะทะฝะฐั‡ะตะฝะพ"
-
-#, c-format
msgid "Error detected while processing %s:"
msgstr "ะ’ะธัะฒะปะตะฝะพ ะฟะพะผะธะปะบัƒ ะฟั–ะด ั‡ะฐั ะฒะธะบะพะฝะฐะฝะฝั %s:"
@@ -3821,9 +3957,6 @@ msgstr ""
"&D:ะ–ะพะดะฝะพะณะพ\n"
"&C:ะกะบะฐััƒะฒะฐั‚ะธ"
-msgid "W10: Warning: Changing a readonly file"
-msgstr "W10: ะ—ะฐัั‚ะตั€ะตะถะตะฝะฝั: ะ—ะผั–ะฝัŽั”ั‚ัŒัั ั„ะฐะนะป ะฟั€ะธะทะฝะฐั‡ะตะฝะธะน ะปะธัˆะต ะดะปั ั‡ะธั‚ะฐะฝะฝั"
-
msgid "Type number and <Enter> or click with mouse (empty cancels): "
msgstr "ะะฐะฑะตั€ั–ั‚ัŒ ั‡ะธัะปะพ ะน <Enter> ั‡ะธ ะบะปะฐั†ะฝั–ั‚ัŒ ะผะธัˆะบะพัŽ (ะฟะพั€ะพะถะฝั” ัะบะฐัะพะฒัƒั”): "
@@ -3856,9 +3989,6 @@ msgstr "E349: ะะตะผะฐั” ั–ะดะตะฝั‚ะธั„ั–ะบะฐั‚ะพั€ะฐ ะฝะฐะด ะบัƒั€ัะพั€ะพะผ"
msgid "E774: 'operatorfunc' is empty"
msgstr "E774: 'operatorfunc' ะฟะพั€ะพะถะฝั"
-msgid "Warning: terminal cannot highlight"
-msgstr "ะ—ะฐัั‚ะตั€ะตะถะตะฝะฝั: ะขะตั€ะผั–ะฝะฐะป ะฝะต ะฟั–ะดั‚ั€ะธะผัƒั” ะบะพะปัŒะพั€ะธ"
-
msgid "E348: No string under cursor"
msgstr "E348: ะะตะผะฐั” ั€ัะดะบะฐ ะฝะฐ ะบัƒั€ัะพั€ั–"
@@ -3878,6 +4008,10 @@ msgid "Type :qa! and press <Enter> to abandon all changes and exit Nvim"
msgstr ""
"ะ’ะฒะตะดั–ั‚ัŒ :qa! ั– ะฝะฐั‚ะธัะฝั–ัั‚ัŒ <Enter> ั‰ะพะฑ ะฒั–ะดะบะธะฝัƒั‚ะธ ะฒัั– ะทะผั–ะฝะธ ั– ะฒะธะนั‚ะธ Nvim"
+msgid "Type :qa and press <Enter> to exit Nvim"
+msgstr ""
+"ะ’ะฒะตะดั–ั‚ัŒ :qa ั– ะฝะฐั‚ะธัะฝั–ัั‚ัŒ <Enter> ั‰ะพะฑ ะฒะธะนั‚ะธ ะท Nvim"
+
#, c-format
msgid "1 line %sed 1 time"
msgstr "ะžะดะธะฝ ั€ัะดะพะบ %s-ะฝะพ"
@@ -3998,6 +4132,9 @@ msgstr "E518: ะะตะฒั–ะดะพะผะฐ ะพะฟั†ั–ั"
msgid "E520: Not allowed in a modeline"
msgstr "E520: ะะต ะดะพะทะฒะพะปะตะฝะพ ัƒ modeline"
+msgid "E992: Not allowed in a modeline when 'modelineexpr' is off"
+msgstr "E992: ะะต ะดะพะทะฒะพะปะตะฝะพ ัƒ modeline, ะบะพะปะธ ะฒะธะผะบะฝะตะฝะพ 'modelineexpr'"
+
msgid "E846: Key code not set"
msgstr "E846: ะšะพะด ะบะปัŽั‡ะฐ ะฝะต ะฒัั‚ะฐะฝะพะฒะปะตะฝะพ"
@@ -4144,24 +4281,16 @@ msgstr ""
msgid "E5677: Error writing input to shell-command: %s"
msgstr "E5677: ะะต ะฒะดะฐะปะพัั ะทะฐะฟะธัะฐั‚ะธ ะฝะฐ ะฒั…ั–ะด ะบะพะผะฐะฝะดะธ ะพะฑะพะปะพะฝะบะธ: %s"
-msgid ""
-"\n"
-"Could not get security context for "
-msgstr ""
-"\n"
-"ะะต ะฒะดะฐะปะพัั ะพั‚ั€ะธะผะฐั‚ะธ ะบะพะฝั‚ะตะบัั‚ ะฑะตะทะฟะตะบะธ ะดะปั "
-
-msgid ""
-"\n"
-"Could not set security context for "
-msgstr ""
-"\n"
-"ะะต ะฒะดะฐะปะพัั ะฒัั‚ะฐะฝะพะฒะธั‚ะธ ะบะพะฝั‚ะตะบัั‚ ะฑะตะทะฟะตะบะธ ะดะปั "
-
#, c-format
msgid "E447: Can't find file \"%s\" in path"
msgstr "E447: ะคะฐะนะป ยซ%sยป ะฝะต ะทะฝะฐะนะดะตะฝะพ ัƒ ัˆะปัั…ัƒ ะฟะพัˆัƒะบัƒ"
+msgid "E553: No more items"
+msgstr "E553: ะะตะผะฐั” ะฑั–ะปัŒัˆะต ะตะปะตะผะตะฝั‚ั–ะฒ"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: ะฆะตะน ัะฟะธัะพะบ ะผั–ัั†ัŒ ะฑัƒะปะพ ะทะผั–ะฝะตะฝะพ"
+
#, c-format
msgid "E372: Too many %%%c in format string"
msgstr "E372: ะ—ะฐะฑะฐะณะฐั‚ะพ %%%c ัƒ ั€ัะดะบัƒ ั„ะพั€ะผะฐั‚ัƒ"
@@ -4191,18 +4320,12 @@ msgstr "E378: 'errorformat' ะฝะต ะผั–ัั‚ะธั‚ัŒ ะทั€ะฐะทะพะบ"
msgid "E379: Missing or empty directory name"
msgstr "E379: ะŸั€ะพะฟัƒั‰ะตะฝะฐ ั‡ะธ ะฟะพั€ะพะถะฝั ะฝะฐะทะฒะฐ ะบะฐั‚ะฐะปะพะณัƒ"
-msgid "E553: No more items"
-msgstr "E553: ะะตะผะฐั” ะฑั–ะปัŒัˆะต ะตะปะตะผะตะฝั‚ั–ะฒ"
-
msgid "E924: Current window was closed"
msgstr "E924: ะะบั‚ะธะฒะฝะต ะฒั–ะบะฝะพ ะฑัƒะปะพ ะทะฐะบั€ะธั‚ะพ"
msgid "E925: Current quickfix was changed"
msgstr "E925: ะฆะตะน quickfix ะฑัƒะปะพ ะทะผั–ะฝะตะฝะพ"
-msgid "E926: Current location list was changed"
-msgstr "E926: ะฆะตะน ัะฟะธัะพะบ ะผั–ัั†ัŒ ะฑัƒะปะพ ะทะผั–ะฝะตะฝะพ"
-
#, c-format
msgid "(%d of %d)%s%s: "
msgstr "(%d ะท %d)%s%s: "
@@ -4223,9 +4346,6 @@ msgstr "E381: ะ’ะตั€ัˆะธะฝะฐ ัั‚ะตะบัƒ ะฒะธะฟั€ะฐะฒะปะตะฝัŒ"
msgid "No entries"
msgstr "ะั–ั‡ะพะณะพ"
-msgid "E382: Cannot write, 'buftype' option is set"
-msgstr "E382: ะะต ะผะพะถัƒ ะทะฐะฟะธัะฐั‚ะธ, ะฒะบะฐะทะฐะฝะฐ ะพะฟั†ั–ั 'buftype'"
-
msgid "E683: File name missing or invalid pattern"
msgstr "E683: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฝะฐะทะฒัƒ ั„ะฐะนะปัƒ ั‡ะธ ะฝะตะบะพั€ะตะบั‚ะฝะธะน ัˆะฐะฑะปะพะฝ"
@@ -4279,6 +4399,12 @@ msgstr "E69: ะŸั€ะพะฟัƒั‰ะตะฝะพ ] ะฟั–ัะปั %s%%["
msgid "E70: Empty %s%%[]"
msgstr "E70: %s%%[] ะฟะพั€ะพะถะฝั–ะน"
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: ะะต ะผะพะถะฝะฐ ั€ะตะบัƒั€ัะธะฒะฝะพ ะฒะธะบะพั€ะธัั‚ะฐั‚ะธ ัˆะฐะฑะปะพะฝ"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ะะตะบะพั€ะตะบั‚ะฝะต ะทะฒะพั€ะพั‚ะฝั” ะฟะพัะธะปะฐะฝะฝั"
+
msgid "E339: Pattern too long"
msgstr "E339: ะ—ั€ะฐะทะพะบ ะทะฐะฝะฐะดั‚ะพ ะดะพะฒะณะธะน"
@@ -4315,9 +4441,6 @@ msgstr "E63: ะะตะบะพั€ะตะบั‚ะฝะพ ะฒะถะธั‚ะพ \\_"
msgid "E64: %s%c follows nothing"
msgstr "E64: ะŸั–ัะปั %s%c ะฝั–ั‡ะพะณะพ ะฝะตะผะฐั”"
-msgid "E65: Illegal back reference"
-msgstr "E65: ะะตะบะพั€ะตะบั‚ะฝะต ะทะฒะพั€ะพั‚ะฝั” ะฟะพัะธะปะฐะฝะฝั"
-
msgid "E68: Invalid character after \\z"
msgstr "E68: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ัะธะผะฒะพะป ะฟั–ัะปั \\z"
@@ -4658,6 +4781,63 @@ msgstr ""
"ะŸะพะผะธะปะบะฐ ะฟั€ะธ ั‡ะธั‚ะฐะฝะฝั– ั„ะฐะนะปัƒ ShaDa: ัะฟะธัะพะบ ะฑัƒั„ะตั€ั–ะฒ ัƒ ะฟะพะทะธั†ั–ั— %<PRIu64> ะผั–ัั‚ะธั‚ัŒ "
"ะฟะพะปะต, ัะบะต ะฝะต ะผะฐั” ะฝะฐะทะฒัƒ ั„ะฐะนะปัƒ"
+msgid "[Deleted]"
+msgstr "[ะ—ะฝะธั‰ะตะฝะพ]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- ะŸะพะทะฝะฐั‡ะบะธ ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "ะŸะพะทะฝะฐั‡ะบะธ ะดะปั %s:"
+
+#, c-format
+msgid " group=%s"
+msgstr " ะณั€ัƒะฟะฐ=%s"
+
+#, c-format
+msgid " line=%ld id=%d%s name=%s priority=%d"
+msgstr " ั€ัะดะพะบ=%ld id=%d%s ะฝะฐะทะฒะฐ=%s ะฟั€ั–ะพั€ะธั‚ะตั‚=%d"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: ะ’ะธะทะฝะฐั‡ะตะฝะพ ะทะฐะฑะฐะณะฐั‚ะพ ะฝะฐะดะฟะธัั–ะฒ"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ะะตะบะพั€ะตะบั‚ะฝะธะน ะฝะฐะดะฟะธั: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ะะตะฒั–ะดะพะผะธะน ะฝะฐะดะฟะธั: %s"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: ะะตะผะพะถะปะธะฒะพ ะทะผั–ะฝะธั‚ะธ ะทะฝะฐะบ %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฝะพะผะตั€ ะฝะฐะดะฟะธััƒ"
+
+#, c-format
+msgid "E157: Invalid sign ID: %<PRId64>"
+msgstr "E157: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ID ะฝะฐะดะฟะธััƒ: %<PRId64>"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: ะะต ะผะพะถะฝะฐ ะฟะตั€ะตะนั‚ะธ ะดะพ ะฑัƒั„ะตั€ะฐ ะฑะตะท ะฝะฐะทะฒะธ"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: ะะตะฒั–ะดะพะผะฐ ะบะพะผะฐะฝะดะฐ ะฝะฐะดะฟะธััƒ: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ะŸั€ะพะฟัƒั‰ะตะฝะพ ะฝะฐะทะฒัƒ ะฝะฐะดะฟะธััƒ"
+
+msgid " (not supported)"
+msgstr " (ะฝะต ะฟั–ะดั‚ั€ะธะผัƒั”ั‚ัŒัั)"
+
msgid "E759: Format error in spell file"
msgstr "E759: ะŸะพะผะธะปะบะฐ ั„ะพั€ะผะฐั‚ัƒ ัƒ ั„ะฐะนะปั– ะพั€ั„ะพะณั€ะฐั„ั–ั—"
@@ -4709,12 +4889,6 @@ msgstr "ะ—ะฐะนะฒะธะน ั‚ะตะบัั‚ ัƒ %s ัƒ ั€ัะดะบัƒ %d: %s"
msgid "Affix name too long in %s line %d: %s"
msgstr "ะะฐะทะฒะฐ ะฐั„ั–ะบััƒ ะทะฐะฒะตะปะธะบะฐ ัƒ %s ัƒ ั€ัะดะบัƒ %d: %s"
-msgid "E761: Format error in affix file FOL, LOW or UPP"
-msgstr "E761: ะŸะพะผะธะปะบะฐ ั„ะพั€ะผะฐั‚ัƒ ัƒ ั„ะฐะนะปั– ะฐั„ั–ะบัั–ะฒ FOL, LOW ั‡ะธ UPP"
-
-msgid "E762: Character in FOL, LOW or UPP is out of range"
-msgstr "E762: ะกะธะผะฒะพะป ัƒ FOL, LOW ั‡ะธ UPP ะฟะพะทะฐ ะผะตะถะฐะผะธ"
-
msgid "Compressing word tree..."
msgstr "ะกั‚ะธัะบัƒั”ั‚ัŒัั ะดะตั€ะตะฒะพ ัะปั–ะฒ..."
@@ -4855,10 +5029,6 @@ msgstr "ะŸะพะฒั‚ะพั€ะตะฝะฝั ัะธะผะฒะพะปัƒ ัƒ MAP ัƒ %s ัƒ ั€ัะดะบัƒ %d"
msgid "Unrecognized or duplicate item in %s line %d: %s"
msgstr "ะะตั€ะพะทะฟั–ะทะฝะฐะฝะธะน ั‡ะธ ะฟะพะฒั‚ะพั€ะฝะธะน ะตะปะตะผะตะฝั‚ ัƒ %s ัƒ ั€ัะดะบัƒ %d: %s"
-#, c-format
-msgid "Missing FOL/LOW/UPP line in %s"
-msgstr "ะŸั€ะพะฟัƒั‰ะตะฝะพ ั€ัะดะพะบ FOL/LOW/UPP ัƒ %s"
-
msgid "COMPOUNDSYLMAX used without SYLLABLE"
msgstr "ะ’ะถะธั‚ะพ COMPOUNDSYLMAX ะฑะตะท SYLLABLE"
@@ -4960,8 +5130,8 @@ msgid "Ignored %d words with non-ASCII characters"
msgstr "ะŸั€ะพั–ะณะฝะพั€ะพะฒะฐะฝะพ %d ัะปั–ะฒ ั–ะท ะฝะต-ASCII ัะธะผะฒะพะปะฐะผะธ"
#, c-format
-msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
-msgstr "ะกั‚ะธัะฝะตะฝะพ %d ะท %d ะฒัƒะทะปั–ะฒ; ะทะฐะปะธัˆะธะปะพัั %d (%d%%)"
+msgid "Compressed %s of %ld nodes; %ld (%ld%%) remaining"
+msgstr "ะกั‚ะธัะฝะตะฝะพ %s ะท %ld ะฒัƒะทะปั–ะฒ; ะทะฐะปะธัˆะธะปะพัั %ld (%ld%%)"
msgid "Reading back spell file..."
msgstr "ะŸะตั€ะตั‡ะธั‚ัƒั”ั‚ัŒัั ั„ะฐะนะป ะพั€ั„ะพะณั€ะฐั„ั–ั—..."
@@ -5033,25 +5203,34 @@ msgstr "E807: ะžั‡ั–ะบัƒั”ั‚ัŒัั ะฐั€ะณัƒะผะตะฝั‚ Float ะดะปั printf()"
msgid "E767: Too many arguments to printf()"
msgstr "E767: ะ—ะฐะฑะฐะณะฐั‚ะพ ะฐั€ะณัƒะผะตะฝั‚ั–ะฒ ะดะปั printf()"
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ะฐั€ะณัƒะผะตะฝั‚: %s"
+
msgid "No Syntax items defined for this buffer"
msgstr "ะ”ะปั ะฑัƒั„ะตั€ะฐ ะฝะต ะฒะธะทะฝะฐั‡ะตะฝะพ ะตะปะตะผะตะฝั‚ั–ะฒ ัะธะฝั‚ะฐะบัะธััƒ"
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' ะฟะตั€ะตะฒะธั‰ะตะฝะพ, ะฟั–ะดัะฒั–ั‡ัƒะฒะฐะฝะฝั ัะธะฝั‚ะฐะบัะธััƒ ะฒะธะผะบะฝะตะฝะพ"
+
msgid "syntax conceal on"
msgstr "ัะธะฝั‚ะฐะบัะธั‡ะฝะต ะฟั€ะธั…ะพะฒัƒะฒะฐะฝะฝั ัƒะฒั–ะผะบ"
msgid "syntax conceal off"
msgstr "ัะธะฝั‚ะฐะบัะธั‡ะฝะต ะฟั€ะธั…ะพะฒัƒะฒะฐะฝะฝั ะฒะธะผะบ"
-#, c-format
-msgid "E390: Illegal argument: %s"
-msgstr "E390: ะะตะฟั€ะฐะฒะธะปัŒะฝะธะน ะฐั€ะณัƒะผะตะฝั‚: %s"
-
msgid "syntax case ignore"
msgstr "ัะธะฝั‚ะฐะบัะธั ั–ะณะฝะพั€ัƒะฒะฐั‚ะธ ั€ะตะณั–ัั‚ั€"
msgid "syntax case match"
msgstr "ัะธะฝั‚ะฐะบัะธั ะดะพั‚ั€ะธะผัƒะฒะฐั‚ะธัั ั€ะตะณั–ัั‚ั€ัƒ"
+msgid "syntax foldlevel start"
+msgstr "ั€ั–ะฒะตะฝัŒ ะทะณะพั€ั‚ะบะธ ัะธะฝั‚ะฐะบัะธััƒ ะฟะพั‡ะฐั‚ะพะบ"
+
+msgid "syntax foldlevel minimum"
+msgstr "ั€ั–ะฒะตะฝัŒ ะทะณะพั€ั‚ะบะธ ัะธะฝั‚ะฐะบัะธััƒ ะผั–ะฝั–ะผัƒะผ"
+
msgid "syntax spell toplevel"
msgstr "ัะธะฝั‚ะฐะบัะธั ะฟะตั€ะตะฒั–ั€ัั‚ะธ ะฒััŽะดะธ"
@@ -5064,6 +5243,9 @@ msgstr "ัะธะฝั‚ะฐะบัะธั ะฟะพั‡ะฐั‚ะบะพะฒะพ"
msgid "syntax iskeyword "
msgstr "ัะธะฝั‚ะฐะบัะธั iskeyword "
+msgid "syntax iskeyword not set"
+msgstr "ะฝะต ะฒัั‚ะฐะฝะพะฒะปะตะฝะพ ัะธะฝั‚ะฐะบัะธั iskeyword"
+
#, c-format
msgid "E391: No such syntax cluster: %s"
msgstr "E391: ะะตะผะฐั” ั‚ะฐะบะพะณะพ ัะธะฝั‚ะฐะบัะธั‡ะฝะพะณะพ ะบะปะฐัั‚ะตั€ะฐ: %s"
@@ -5124,7 +5306,7 @@ msgid "E844: invalid cchar value"
msgstr "E844: ะะตะบะพั€ะตะบั‚ะฝะต ะทะฝะฐั‡ะตะฝะฝั cchar"
msgid "E393: group[t]here not accepted here"
-msgstr "E393: group[t]hete ั‚ัƒั‚ ะฝะตะฟั€ะธะนะฝัั‚ะฝะธะน"
+msgstr "E393: group[t]here ั‚ัƒั‚ ะฝะตะฟั€ะธะนะฝัั‚ะฝะธะน"
#, c-format
msgid "E394: Didn't find region item for %s"
@@ -5266,6 +5448,12 @@ msgstr "E555: ะšั–ะฝะตั†ัŒ ัั‚ะตะบัƒ ะผั–ั‚ะพะบ"
msgid "E556: at top of tag stack"
msgstr "E556: ะ’ะตั€ัˆะธะฝะฐ ัั‚ะตะบัƒ ะผั–ั‚ะพะบ"
+msgid "E986: cannot modify the tag stack within tagfunc"
+msgstr "E986: ะะต ะผะพะถะฝะฐ ะทะผั–ะฝัŽะฒะฐั‚ะธ ัั‚ะตะบ ะผั–ั‚ะพะบ ัƒ tagfunc"
+
+msgid "E987: invalid return value from tagfunc"
+msgstr "E987: ะะตะบะพั€ะตะบั‚ะฝะต ะฟะพะฒะตั€ะฝะตะฝะต ะทะฝะฐั‡ะตะฝะฝั ะท tagfunc"
+
msgid "E425: Cannot go before first matching tag"
msgstr "E425: ะฆะต ะฒะถะต ะฝะฐะนะฟะตั€ัˆะฐ ะฒั–ะดะฟะพะฒั–ะดะฝะฐ ะผั–ั‚ะบะฐ"
@@ -5273,12 +5461,6 @@ msgstr "E425: ะฆะต ะฒะถะต ะฝะฐะนะฟะตั€ัˆะฐ ะฒั–ะดะฟะพะฒั–ะดะฝะฐ ะผั–ั‚ะบะฐ"
msgid "E426: tag not found: %s"
msgstr "E426: ะœั–ั‚ะบัƒ ะฝะต ะทะฝะฐะนะดะตะฝะพ: %s"
-msgid " # pri kind tag"
-msgstr " # ะฟั€ั– ั‚ะธะฟ ะผั–ั‚ะบะฐ"
-
-msgid "file\n"
-msgstr "ั„ะฐะนะป\n"
-
msgid "E427: There is only one matching tag"
msgstr "E427: ะ›ะธัˆะต ะพะดะฝะฐ ะฒั–ะดะฟะพะฒั–ะดะฝะฐ ะผั–ั‚ะบะฐ"
@@ -5303,6 +5485,12 @@ msgstr " ะ’ะธะบะพั€ะธัั‚ะฐะฝะพ ะผั–ั‚ะบัƒ, ะฝะต ั€ะพะทั€ั–ะทะฝััŽั‡ะธ ะฒะตะปะ
msgid "E429: File \"%s\" does not exist"
msgstr "E429: ะคะฐะนะป ยซ%sยป ะฝะต ั–ัะฝัƒั”"
+msgid " # pri kind tag"
+msgstr " # ะฟั€ั– ั‚ะธะฟ ะผั–ั‚ะบะฐ"
+
+msgid "file\n"
+msgstr "ั„ะฐะนะป\n"
+
msgid ""
"\n"
" # TO tag FROM line in file/text"
@@ -5314,9 +5502,6 @@ msgstr ""
msgid "Searching tags file %s"
msgstr "ะจัƒะบะฐั”ั‚ัŒัั ัƒ ั„ะฐะนะปั– ั‚ะตา‘ั–ะฒ %s"
-msgid "Ignoring long line in tags file"
-msgstr "ะ†ะณะฝะพั€ัƒั”ั‚ัŒัั ะดะพะฒะณะธะน ั€ัะดะพะบ ัƒ ั„ะฐะนะปั– ะท ะฟะพะทะฝะฐั‡ะบะฐะผะธ"
-
#, c-format
msgid "E431: Format error in tags file \"%s\""
msgstr "E431: ะŸะพะผะธะปะบะฐ ั„ะพั€ะผะฐั‚ัƒ ัƒ ั„ะฐะนะปั– ั‚ะตา‘ั–ะฒ ยซ%sยป"
@@ -5453,10 +5638,6 @@ msgstr "ะะตะผะฐั” ะฝั–ั‡ะพะณะพ ัะบะฐัะพะฒัƒะฒะฐั‚ะธ"
msgid "number changes when saved"
msgstr "ะฝะพะผะตั€ ะทะผั–ะฝะธ ั‡ะฐั ะทะฑะตั€ะตะถะตะฝะพ"
-#, c-format
-msgid "%<PRId64> seconds ago"
-msgstr "%<PRId64> ัะตะบัƒะฝะด ั‚ะพะผัƒ"
-
msgid "E790: undojoin is not allowed after undo"
msgstr "E790: ะะต ะผะพะถะฝะฐ ะฒะธะบะพะฝะฐั‚ะธ undojoin ะฟั–ัะปั undo"
@@ -5468,22 +5649,22 @@ msgstr "E440: ะ’ั–ะดััƒั‚ะฝั–ะน ั€ัะดะพะบ ัะบะฐััƒะฒะฐะฝะฝั"
msgid ""
"\n"
-"Compiled "
+"\n"
+"Features: "
msgstr ""
"\n"
-"ะกะบะพะผะฟั–ะปัŽะฒะฐะฒ "
-
-msgid "by "
-msgstr " "
+"\n"
+"ะฅะฐั€ะฐะบั‚ะตั€ะธัั‚ะธะบะธ: "
msgid ""
"\n"
-"\n"
-"Features: "
+"Compiled "
msgstr ""
"\n"
-"\n"
-"ะฅะฐั€ะฐะบั‚ะตั€ะธัั‚ะธะบะธ: "
+"ะกะบะพะผะฟั–ะปัŽะฒะฐะฒ "
+
+msgid "by "
+msgstr " "
msgid " system vimrc file: \""
msgstr " ัะธัั‚ะตะผะฝะธะน vimrc: \""
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index c712762bdf..d2d20852aa 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -226,6 +226,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
pum_above = false;
// Leave two lines of context if possible
+ validate_cheight();
if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) {
context_lines = 3;
} else {
@@ -300,49 +301,49 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
if (pum_width < p_pw) {
pum_width = (int)p_pw;
}
- }
- } else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl)
- || (pum_rl && (cursor_col < Columns - p_pw
- || cursor_col < Columns - max_width))) {
- // align pum edge with "cursor_col"
- if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) {
- pum_col = cursor_col + max_width + pum_scrollbar + 1;
- if (pum_col >= Columns) {
- pum_col = Columns - 1;
- }
- } else if (!pum_rl) {
- if (curwin->w_wincol > Columns - max_width - pum_scrollbar
- && max_width <= p_pw) {
- // use full width to end of the screen
- pum_col = cursor_col - max_width - pum_scrollbar;
- if (pum_col < 0) {
- pum_col = 0;
+ } else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl)
+ || (pum_rl && (cursor_col < Columns - p_pw
+ || cursor_col < Columns - max_width))) {
+ // align pum edge with "cursor_col"
+ if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) {
+ pum_col = cursor_col + max_width + pum_scrollbar + 1;
+ if (pum_col >= Columns) {
+ pum_col = Columns - 1;
+ }
+ } else if (!pum_rl) {
+ if (curwin->w_wincol > Columns - max_width - pum_scrollbar
+ && max_width <= p_pw) {
+ // use full width to end of the screen
+ pum_col = Columns - max_width - pum_scrollbar;
+ if (pum_col < 0) {
+ pum_col = 0;
+ }
}
}
- }
-
- if (pum_rl) {
- pum_width = pum_col - pum_scrollbar + 1;
- } else {
- pum_width = Columns - pum_col - pum_scrollbar;
- }
- if (pum_width < p_pw) {
- pum_width = (int)p_pw;
if (pum_rl) {
- if (pum_width > pum_col) {
- pum_width = pum_col;
- }
+ pum_width = pum_col - pum_scrollbar + 1;
} else {
- if (pum_width >= Columns - pum_col) {
- pum_width = Columns - pum_col - 1;
- }
+ pum_width = Columns - pum_col - pum_scrollbar;
}
- } else if (pum_width > max_width + pum_kind_width + pum_extra_width + 1
- && pum_width > p_pw) {
- pum_width = max_width + pum_kind_width + pum_extra_width + 1;
+
if (pum_width < p_pw) {
pum_width = (int)p_pw;
+ if (pum_rl) {
+ if (pum_width > pum_col) {
+ pum_width = pum_col;
+ }
+ } else {
+ if (pum_width >= Columns - pum_col) {
+ pum_width = Columns - pum_col - 1;
+ }
+ }
+ } else if (pum_width > max_width + pum_kind_width + pum_extra_width + 1
+ && pum_width > p_pw) {
+ pum_width = max_width + pum_kind_width + pum_extra_width + 1;
+ if (pum_width < p_pw) {
+ pum_width = (int)p_pw;
+ }
}
}
} else if (Columns < def_width) {
@@ -918,11 +919,11 @@ void pum_set_event_info(dict_T *dict)
r = (double)pum_row;
c = (double)pum_col;
}
- tv_dict_add_float(dict, S_LEN("height"), h);
- tv_dict_add_float(dict, S_LEN("width"), w);
- tv_dict_add_float(dict, S_LEN("row"), r);
- tv_dict_add_float(dict, S_LEN("col"), c);
- tv_dict_add_nr(dict, S_LEN("size"), pum_size);
- tv_dict_add_bool(dict, S_LEN("scrollbar"),
- pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
+ (void)tv_dict_add_float(dict, S_LEN("height"), h);
+ (void)tv_dict_add_float(dict, S_LEN("width"), w);
+ (void)tv_dict_add_float(dict, S_LEN("row"), r);
+ (void)tv_dict_add_float(dict, S_LEN("col"), c);
+ (void)tv_dict_add_nr(dict, S_LEN("size"), pum_size);
+ (void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
+ pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index ddce1e922d..1cd7879dc0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -239,7 +239,10 @@ static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
static char_u *qf_last_bufname = NULL;
static bufref_T qf_last_bufref = { NULL, 0, 0 };
-static char *e_loc_list_changed = N_("E926: Current location list was changed");
+static char *e_current_quickfix_list_was_changed =
+ N_("E925: Current quickfix list was changed");
+static char *e_current_location_list_was_changed =
+ N_("E926: Current location list was changed");
// Counter to prevent autocmds from freeing up location lists when they are
// still being used.
@@ -808,7 +811,7 @@ retry:
}
break;
}
- if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') {
+ if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 2] == '\n') {
break;
}
}
@@ -901,6 +904,7 @@ static bool qf_list_has_valid_entries(qf_list_T *qfl)
/// Return a pointer to a list in the specified quickfix stack
static qf_list_T * qf_get_list(qf_info_T *qi, int idx)
+ FUNC_ATTR_NONNULL_ALL
{
return &qi->qf_lists[idx];
}
@@ -1088,6 +1092,7 @@ qf_init_ext(
)
FUNC_ATTR_NONNULL_ARG(1)
{
+ qf_list_T *qfl;
qfstate_T state = { 0 };
qffields_T fields = { 0 };
qfline_T *old_last = NULL;
@@ -1111,15 +1116,16 @@ qf_init_ext(
// make place for a new list
qf_new_list(qi, qf_title);
qf_idx = qi->qf_curlist;
+ qfl = qf_get_list(qi, qf_idx);
} else {
// Adding to existing list, use last entry.
adding = true;
- if (!qf_list_empty(qf_get_list(qi, qf_idx) )) {
- old_last = qi->qf_lists[qf_idx].qf_last;
+ qfl = qf_get_list(qi, qf_idx);
+ if (!qf_list_empty(qfl)) {
+ old_last = qfl->qf_last;
}
}
- qf_list_T *qfl = qf_get_list(qi, qf_idx);
// Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
@@ -1230,6 +1236,7 @@ static char_u * qf_cmdtitle(char_u *cmd)
/// Return a pointer to the current list in the specified quickfix stack
static qf_list_T * qf_get_curlist(qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL
{
return qf_get_list(qi, qi->qf_curlist);
}
@@ -1660,8 +1667,8 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
}
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
+ qfprev->qf_viscol = fields->use_viscol;
}
- qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory
@@ -1770,7 +1777,7 @@ static void decr_quickfix_busy(void)
void check_quickfix_busy(void)
{
if (quickfix_busy != 0) {
- EMSGN("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
+ EMSGN("quickfix_busy not zero on exit: %" PRId64, (int64_t)quickfix_busy);
# ifdef ABORT_ON_INTERNAL_ERROR
abort();
# endif
@@ -2348,25 +2355,27 @@ static qfline_T *get_prev_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr,
/// dir == FORWARD or FORWARD_FILE: next valid entry
/// dir == BACKWARD or BACKWARD_FILE: previous valid entry
static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr,
- qfline_T *qf_ptr, int *qf_index, int dir)
+ int dir, int *new_qfidx)
{
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qf_idx = qfl->qf_index;
qfline_T *prev_qf_ptr;
int prev_index;
char_u *err = e_no_more_items;
while (errornr--) {
prev_qf_ptr = qf_ptr;
- prev_index = *qf_index;
+ prev_index = qf_idx;
if (dir == FORWARD || dir == FORWARD_FILE) {
- qf_ptr = get_next_valid_entry(qfl, qf_ptr, qf_index, dir);
+ qf_ptr = get_next_valid_entry(qfl, qf_ptr, &qf_idx, dir);
} else {
- qf_ptr = get_prev_valid_entry(qfl, qf_ptr, qf_index, dir);
+ qf_ptr = get_prev_valid_entry(qfl, qf_ptr, &qf_idx, dir);
}
if (qf_ptr == NULL) {
qf_ptr = prev_qf_ptr;
- *qf_index = prev_index;
+ qf_idx = prev_index;
if (err != NULL) {
EMSG(_(err));
return NULL;
@@ -2377,14 +2386,16 @@ static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr,
err = NULL;
}
+ *new_qfidx = qf_idx;
return qf_ptr;
}
-/// Get n'th (errornr) quickfix entry
-static qfline_T *get_nth_entry(qf_list_T *qfl, int errornr, qfline_T *qf_ptr,
- int *cur_qfidx)
+/// Get n'th (errornr) quickfix entry from the current entry in the quickfix
+/// list 'qfl'. Returns a pointer to the new entry and the index in 'new_qfidx'
+static qfline_T *get_nth_entry(qf_list_T *qfl, int errornr, int *new_qfidx)
{
- int qf_idx = *cur_qfidx;
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qf_idx = qfl->qf_index;;
// New error number is less than the current error number
while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL) {
@@ -2400,10 +2411,31 @@ static qfline_T *get_nth_entry(qf_list_T *qfl, int errornr, qfline_T *qf_ptr,
qf_ptr = qf_ptr->qf_next;
}
- *cur_qfidx = qf_idx;
+ *new_qfidx = qf_idx;
return qf_ptr;
}
+/// Get a entry specied by 'errornr' and 'dir' from the current
+/// quickfix/location list. 'errornr' specifies the index of the entry and 'dir'
+/// specifies the direction (FORWARD/BACKWARD/FORWARD_FILE/BACKWARD_FILE).
+/// Returns a pointer to the entry and the index of the new entry is stored in
+/// 'new_qfidx'.
+static qfline_T * qf_get_entry(qf_list_T *qfl, int errornr,
+ int dir, int *new_qfidx)
+{
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qfidx = qfl->qf_index;
+
+ if (dir != 0) { // next/prev valid entry
+ qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
+ } else if (errornr != 0) { // go to specified number
+ qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
+ }
+
+ *new_qfidx = qfidx;
+ return qf_ptr;
+}
+
// Find a window displaying a Vim help file.
static win_T *qf_find_help_win(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
@@ -2423,12 +2455,13 @@ static void win_set_loclist(win_T *wp, qf_info_T *qi)
qi->qf_refcount++;
}
-/// Find a help window or open one.
-static int jump_to_help_window(qf_info_T *qi, int *opened_window)
+/// Find a help window or open one. If 'newwin' is true, then open a new help
+/// window.
+static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
{
win_T *wp = NULL;
- if (cmdmod.tab != 0) {
+ if (cmdmod.tab != 0 || newwin) {
wp = NULL;
} else {
wp = qf_find_help_win();
@@ -2446,8 +2479,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
flags |= WSP_TOP;
}
- if (IS_LL_STACK(qi)) {
- flags |= WSP_NEWLOC; // don't copy the location list
+ // If the user asks to open a new window, then copy the location list.
+ // Otherwise, don't copy the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
+ flags |= WSP_NEWLOC;
}
if (win_split(0, flags) == FAIL) {
@@ -2460,8 +2495,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
win_setheight((int)p_hh);
}
- if (IS_LL_STACK(qi)) { // not a quickfix list
- // The new window should use the supplied location list
+ // When using location list, the new window should use the supplied
+ // location list. If the user asks to open a new window, then the new
+ // window will get a copy of the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
win_set_loclist(curwin, qi);
}
}
@@ -2622,14 +2659,19 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// Find a suitable window for opening a file (qf_fnum) from the
// quickfix/location list and jump to it. If the file is already opened in a
-// window, jump to it. Otherwise open a new window to display the file. This is
-// called from either a quickfix or a location list window.
-static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
+// window, jump to it. Otherwise open a new window to display the file. If
+// 'newwin' is true, then always open a new window. This is called from either
+// a quickfix or a location list window.
+static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
+ int *opened_window)
{
win_T *usable_win_ptr = NULL;
bool usable_win = false;
- qf_info_T *ll_ref = curwin->w_llist_ref;
+ // If opening a new window, then don't use the location list referred by
+ // the current window. Otherwise two windows will refer to the same
+ // location list.
+ qf_info_T *ll_ref = newwin ? NULL : curwin->w_llist_ref;
if (ll_ref != NULL) {
// Find a non-quickfix window with this location list
usable_win_ptr = qf_find_win_with_loclist(ll_ref);
@@ -2654,7 +2696,7 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
// If there is only one window and it is the quickfix window, create a
// new one above the quickfix window.
- if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) {
+ if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin) {
if (qf_open_new_file_win(ll_ref) != OK) {
return FAIL;
}
@@ -2672,52 +2714,52 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
/// Edit the selected file or help file.
static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
- win_T *oldwin, int *opened_window, int *abort)
+ win_T *oldwin, int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
+ long old_changetick = qfl->qf_changedtick;
+ int old_qf_curlist = qi->qf_curlist;
qfltype_T qfl_type = qfl->qfl_type;
int retval = OK;
+ unsigned save_qfid = qfl->qf_id;
if (qf_ptr->qf_type == 1) {
// Open help file (do_ecmd() will set b_help flag, readfile() will
// set b_p_ro flag).
if (!can_abandon(curbuf, forceit)) {
no_write_message();
- retval = FAIL;
+ return FAIL;
} else {
retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
ECMD_HIDE + ECMD_SET_HELP,
oldwin == curwin ? curwin : NULL);
}
} else {
- unsigned save_qfid = qfl->qf_id;
-
retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
GETF_SETMARK | GETF_SWITCH, forceit);
+ }
+ // If a location list, check whether the associated window is still
+ // present.
+ if (qfl_type == QFLT_LOCATION && !win_valid_any_tab(oldwin)) {
+ EMSG(_("E924: Current window was closed"));
+ *opened_window = false;
+ return NOTDONE;
+ }
- if (qfl_type == QFLT_LOCATION) {
- // Location list. Check whether the associated window is still
- // present and the list is still valid.
- if (!win_valid_any_tab(oldwin)) {
- EMSG(_("E924: Current window was closed"));
- *abort = true;
- *opened_window = false;
- } else if (!qflist_valid(oldwin, save_qfid)) {
- EMSG(_(e_loc_list_changed));
- *abort = true;
- }
- } else if (!is_qf_entry_present(qfl, qf_ptr)) {
- if (qfl_type == QFLT_QUICKFIX) {
- EMSG(_("E925: Current quickfix was changed"));
- } else {
- EMSG(_(e_loc_list_changed));
- }
- *abort = true;
- }
+ if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid)) {
+ EMSG(_(e_current_quickfix_list_was_changed));
+ return NOTDONE;
+ }
- if (*abort) {
- retval = FAIL;
+ if (old_qf_curlist != qi->qf_curlist
+ || old_changetick != qfl->qf_changedtick
+ || !is_qf_entry_present(qfl, qf_ptr)) {
+ if (qfl_type == QFLT_QUICKFIX) {
+ EMSG(_(e_current_quickfix_list_was_changed));
+ } else {
+ EMSG(_(e_current_location_list_was_changed));
}
+ return NOTDONE;
}
return retval;
@@ -2792,22 +2834,133 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
msg_scroll = (int)i;
}
-/// jump to a quickfix line
-/// if dir == FORWARD go "errornr" valid entries forward
-/// if dir == BACKWARD go "errornr" valid entries backward
-/// if dir == FORWARD_FILE go "errornr" valid entries files backward
-/// if dir == BACKWARD_FILE go "errornr" valid entries files backward
-/// else if "errornr" is zero, redisplay the same line
-/// else go to entry "errornr"
+/// Find a usable window for opening a file from the quickfix/location list. If
+/// a window is not found then open a new window. If 'newwin' is true, then open
+/// a new window.
+/// Returns OK if successfully jumped or opened a window. Returns FAIL if not
+/// able to jump/open a window. Returns NOTDONE if a file is not associated
+/// with the entry.
+static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin,
+ int *opened_window)
+{
+ qf_list_T *qfl = qf_get_curlist(qi);
+ long old_changetick = qfl->qf_changedtick;
+ int old_qf_curlist = qi->qf_curlist;
+ qfltype_T qfl_type = qfl->qfl_type;
+
+ // For ":helpgrep" find a help window or open one.
+ if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
+ if (jump_to_help_window(qi, newwin, opened_window) == FAIL) {
+ return FAIL;
+ }
+ }
+ if (old_qf_curlist != qi->qf_curlist
+ || old_changetick != qfl->qf_changedtick
+ || !is_qf_entry_present(qfl, qf_ptr)) {
+ if (qfl_type == QFLT_QUICKFIX) {
+ EMSG(_(e_current_quickfix_list_was_changed));
+ } else {
+ EMSG(_(e_current_location_list_was_changed));
+ }
+ return FAIL;
+ }
+
+ // If currently in the quickfix window, find another window to show the
+ // file in.
+ if (bt_quickfix(curbuf) && !*opened_window) {
+ // If there is no file specified, we don't know where to go.
+ // But do advance, otherwise ":cn" gets stuck.
+ if (qf_ptr->qf_fnum == 0) {
+ return NOTDONE;
+ }
+
+ if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin, opened_window)
+ == FAIL) {
+ return FAIL;
+ }
+ }
+ if (old_qf_curlist != qi->qf_curlist
+ || old_changetick != qfl->qf_changedtick
+ || !is_qf_entry_present(qfl, qf_ptr)) {
+ if (qfl_type == QFLT_QUICKFIX) {
+ EMSG(_(e_current_quickfix_list_was_changed));
+ } else {
+ EMSG(_(e_current_location_list_was_changed));
+ }
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/// Edit a selected file from the quickfix/location list and jump to a
+/// particular line/column, adjust the folds and display a message about the
+/// jump.
+/// Returns OK on success and FAIL on failing to open the file/buffer. Returns
+/// NOTDONE if the quickfix/location list is freed by an autocmd when opening
+/// the file.
+static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
+ int forceit, win_T *oldwin, int *opened_window,
+ int openfold, int print_message)
+{
+ buf_T *old_curbuf;
+ linenr_T old_lnum;
+ int retval = OK;
+
+ // If there is a file name, read the wanted file if needed, and check
+ // autowrite etc.
+ old_curbuf = curbuf;
+ old_lnum = curwin->w_cursor.lnum;
+
+ if (qf_ptr->qf_fnum != 0) {
+ retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin,
+ opened_window);
+ if (retval != OK) {
+ return retval;
+ }
+ }
+
+ // When not switched to another buffer, still need to set pc mark
+ if (curbuf == old_curbuf) {
+ setpcmark();
+ }
+
+ qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
+ qf_ptr->qf_pattern);
+
+ if ((fdo_flags & FDO_QUICKFIX) && openfold) {
+ foldOpenCursor();
+ }
+ if (print_message) {
+ qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
+ }
+
+ return retval;
+}
+
+/// Jump to a quickfix line and try to use an existing window.
void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
{
+ qf_jump_newwin(qi, dir, errornr, forceit, false);
+}
+
+// Jump to a quickfix line.
+// If dir == 0 go to entry "errornr".
+// If dir == FORWARD go "errornr" valid entries forward.
+// If dir == BACKWARD go "errornr" valid entries backward.
+// If dir == FORWARD_FILE go "errornr" valid entries files backward.
+// If dir == BACKWARD_FILE go "errornr" valid entries files backward
+// else if "errornr" is zero, redisplay the same line
+// If 'forceit' is true, then can discard changes to the current buffer.
+// If 'newwin' is true, then open the file in a new window.
+static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
+ bool newwin)
+{
qf_list_T *qfl;
qfline_T *qf_ptr;
qfline_T *old_qf_ptr;
int qf_index;
int old_qf_index;
- buf_T *old_curbuf;
- linenr_T old_lnum;
char_u *old_swb = p_swb;
unsigned old_swb_flags = swb_flags;
int opened_window = false;
@@ -2830,15 +2983,12 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
old_qf_ptr = qf_ptr;
qf_index = qfl->qf_index;
old_qf_index = qf_index;
- if (dir != 0) { // next/prev valid entry
- qf_ptr = get_nth_valid_entry(qfl, errornr, qf_ptr, &qf_index, dir);
- if (qf_ptr == NULL) {
- qf_ptr = old_qf_ptr;
- qf_index = old_qf_index;
- goto theend; // The horror... the horror...
- }
- } else if (errornr != 0) { // go to specified number
- qf_ptr = get_nth_entry(qfl, errornr, qf_ptr, &qf_index);
+
+ qf_ptr = qf_get_entry(qfl, errornr, dir, &qf_index);
+ if (qf_ptr == NULL) {
+ qf_ptr = old_qf_ptr;
+ qf_index = old_qf_index;
+ goto theend;
}
qfl->qf_index = qf_index;
@@ -2848,58 +2998,23 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
print_message = false;
}
- // For ":helpgrep" find a help window or open one.
- if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
- if (jump_to_help_window(qi, &opened_window) == FAIL) {
- goto theend;
- }
+ retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
+ if (retval == FAIL) {
+ goto failed;
}
-
- // If currently in the quickfix window, find another window to show the
- // file in.
- if (bt_quickfix(curbuf) && !opened_window) {
- // If there is no file specified, we don't know where to go.
- // But do advance, otherwise ":cn" gets stuck.
- if (qf_ptr->qf_fnum == 0) {
- goto theend;
- }
- if (qf_jump_to_usable_window(qf_ptr->qf_fnum, &opened_window) == FAIL) {
- goto failed;
- }
+ if (retval == NOTDONE) {
+ goto theend;
}
- // If there is a file name,
- // read the wanted file if needed, and check autowrite etc.
- old_curbuf = curbuf;
- old_lnum = curwin->w_cursor.lnum;
-
- if (qf_ptr->qf_fnum != 0) {
- int abort = false;
- retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin, &opened_window,
- &abort);
- if (abort) {
- qi = NULL;
- qf_ptr = NULL;
- }
+ retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, oldwin,
+ &opened_window, old_KeyTyped, print_message);
+ if (retval == NOTDONE) {
+ // Quickfix/location list is freed by an autocmd
+ qi = NULL;
+ qf_ptr = NULL;
}
- if (retval == OK) {
- // When not switched to another buffer, still need to set pc mark
- if (curbuf == old_curbuf) {
- setpcmark();
- }
-
- if (qf_ptr != NULL) {
- qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
- qf_ptr->qf_pattern);
- }
-
- if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped)
- foldOpenCursor();
- if (print_message) {
- qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
- }
- } else {
+ if (retval != OK) {
if (opened_window) {
win_close(curwin, true); // Close opened window
}
@@ -3185,7 +3300,7 @@ void qf_history(exarg_T *eap)
qf_info_T *qi = qf_cmd_get_stack(eap, false);
int i;
- if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) {
+ if (qf_stack_empty(qi)) {
MSG(_("No entries"));
} else {
for (i = 0; i < qi->qf_listcount; i++) {
@@ -3353,14 +3468,9 @@ void qf_view_result(bool split)
}
if (split) {
- char cmd[32];
-
- snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s",
- (int64_t)curwin->w_cursor.lnum,
- IS_LL_WINDOW(curwin) ? "ll" : "cc");
- if (do_cmdline_cmd(cmd) == OK) {
- do_cmdline_cmd("clearjumps");
- }
+ // Open the selected entry in a new window
+ qf_jump_newwin(qi, 0, (int)curwin->w_cursor.lnum, false, true);
+ do_cmdline_cmd("clearjumps");
return;
}
@@ -3391,7 +3501,7 @@ void ex_cwindow(exarg_T *eap)
// it if we have errors; otherwise, leave it closed.
if (qf_stack_empty(qi)
|| qfl->qf_nonevalid
- || qf_list_empty(qf_get_curlist(qi))) {
+ || qf_list_empty(qfl)) {
if (win != NULL) {
ex_cclose(eap);
}
@@ -3444,10 +3554,23 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
return OK;
}
+// Set options for the buffer in the quickfix or location list window.
+static void qf_set_cwindow_options(void)
+{
+ // switch off 'swapfile'
+ set_option_value("swf", 0L, NULL, OPT_LOCAL);
+ set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
+ set_option_value("bh", 0L, "wipe", OPT_LOCAL);
+ RESET_BINDING(curwin);
+ curwin->w_p_diff = false;
+ set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+}
+
// Open a new quickfix or location list window, load the quickfix buffer and
// set the appropriate options for the window.
// Returns FAIL if the window could not be opened.
-static int qf_open_new_cwindow(const qf_info_T *qi, int height)
+static int qf_open_new_cwindow(qf_info_T *qi, int height)
+ FUNC_ATTR_NONNULL_ALL
{
win_T *oldwin = curwin;
const tabpage_T *const prevtab = curtab;
@@ -3490,14 +3613,13 @@ static int qf_open_new_cwindow(const qf_info_T *qi, int height)
} else {
// Create a new quickfix buffer
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
+ }
- // switch off 'swapfile'
- set_option_value("swf", 0L, NULL, OPT_LOCAL);
- set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
- set_option_value("bh", 0L, "wipe", OPT_LOCAL);
- RESET_BINDING(curwin);
- curwin->w_p_diff = false;
- set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+ // Set the options for the quickfix buffer/window (if not already done)
+ // Do this even if the quickfix buffer was already present, as an autocmd
+ // might have previously deleted (:bdelete) the quickfix buffer.
+ if (curbuf->b_p_bt[0] != 'q') {
+ qf_set_cwindow_options();
}
// Only set the height when still in the same tab page and there is no
@@ -3686,8 +3808,8 @@ static win_T *qf_find_win(const qf_info_T *qi)
// Find a quickfix buffer.
// Searches in windows opened in all the tabs.
-static buf_T *qf_find_buf(const qf_info_T *qi)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+static buf_T *qf_find_buf(qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_TAB_WINDOWS(tp, win) {
if (is_qf_win(win, qi)) {
@@ -3750,7 +3872,7 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
// Add an error line to the quickfix buffer.
static int qf_buf_add_line(buf_T *buf, linenr_T lnum, const qfline_T *qfp,
- char_u *dirname)
+ char_u *dirname, bool first_bufline)
FUNC_ATTR_NONNULL_ALL
{
int len;
@@ -3765,9 +3887,12 @@ static int qf_buf_add_line(buf_T *buf, linenr_T lnum, const qfline_T *qfp,
if (qfp->qf_type == 1) { // :helpgrep
STRLCPY(IObuff, path_tail(errbuf->b_fname), IOSIZE - 1);
} else {
- // shorten the file name if not done already
- if (errbuf->b_sfname == NULL
- || path_is_absolute(errbuf->b_sfname)) {
+ // Shorten the file name if not done already.
+ // For optimization, do this only for the first entry in a
+ // buffer.
+ if (first_bufline
+ && (errbuf->b_sfname == NULL
+ || path_is_absolute(errbuf->b_sfname))) {
if (*dirname == NUL) {
os_dirname(dirname, MAXPATHL);
}
@@ -3845,6 +3970,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last)
// Check if there is anything to display
if (qfl != NULL) {
char_u dirname[MAXPATHL];
+ int prev_bufnr = -1;
*dirname = NUL;
@@ -3857,9 +3983,11 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last)
lnum = buf->b_ml.ml_line_count;
}
while (lnum < qfl->qf_count) {
- if (qf_buf_add_line(buf, lnum, qfp, dirname) == FAIL) {
+ if (qf_buf_add_line(buf, lnum, qfp, dirname,
+ prev_bufnr != qfp->qf_fnum) == FAIL) {
break;
}
+ prev_bufnr = qfp->qf_fnum;
lnum++;
qfp = qfp->qf_next;
if (qfp == NULL) {
@@ -4806,7 +4934,7 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
if (!qflist_valid(wp, qfid)) {
if (wp != NULL) {
// An autocmd has freed the location list
- EMSG(_(e_loc_list_changed));
+ EMSG(_(e_current_location_list_was_changed));
return false;
} else {
// Quickfix list is not found, create a new one.
@@ -4824,20 +4952,21 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
/// Search for a pattern in all the lines in a buffer and add the matching lines
/// to a quickfix list.
-static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
- regmmatch_T *regmatch, long tomatch,
+static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf,
+ regmmatch_T *regmatch, long *tomatch,
int duplicate_name, int flags)
+ FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5)
{
bool found_match = false;
- for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; lnum++) {
+ for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) {
colnr_T col = 0;
while (vim_regexec_multi(regmatch, curwin, buf, lnum, col, NULL,
NULL) > 0) {
// Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the
// buffer will be wiped out below.
- if (qf_add_entry(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -4856,7 +4985,7 @@ static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
break;
}
found_match = true;
- if (--tomatch == 0) {
+ if (--*tomatch == 0) {
break;
}
if ((flags & VGR_GLOBAL) == 0 || regmatch->endpos[0].lnum > 0) {
@@ -4898,6 +5027,20 @@ static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy,
}
}
+// Return true if "buf" had an existing swap file, the current swap file does
+// not end in ".swp".
+static bool existing_swapfile(const buf_T *buf)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
+ const char_u *const fname = buf->b_ml.ml_mfp->mf_fname;
+ const size_t len = STRLEN(fname);
+
+ return fname[len - 1] != 'p' || fname[len - 2] != 'w';
+ }
+ return false;
+}
+
// ":vimgrep {pattern} file(s)"
// ":vimgrepadd {pattern} file(s)"
// ":lvimgrep {pattern} file(s)"
@@ -5030,7 +5173,8 @@ void ex_vimgrep(exarg_T *eap)
} else {
// Try for a match in all lines of the buffer.
// For ":1vimgrep" look for first match only.
- found_match = vgr_match_buflines(qi, fname, buf, &regmatch, tomatch,
+ found_match = vgr_match_buflines(qf_get_curlist(qi),
+ fname, buf, &regmatch, &tomatch,
duplicate_name, flags);
if (using_dummy) {
@@ -5054,7 +5198,9 @@ void ex_vimgrep(exarg_T *eap)
if (!found_match) {
wipe_dummy_buffer(buf, dirname_start);
buf = NULL;
- } else if (buf != first_match_buf || (flags & VGR_NOJUMP)) {
+ } else if (buf != first_match_buf
+ || (flags & VGR_NOJUMP)
+ || existing_swapfile(buf)) {
unload_dummy_buffer(buf, dirname_start);
// Keeping the buffer, remove the dummy flag.
buf->b_flags &= ~BF_DUMMY;
@@ -6020,6 +6166,49 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
return OK;
}
+// Set the current index in the specified quickfix list
+static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
+ const dictitem_T *di)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int newidx;
+
+ // If the specified index is '$', then use the last entry
+ if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0) {
+ newidx = qfl->qf_count;
+ } else {
+ // Otherwise use the specified index
+ bool denote = false;
+ newidx = (int)tv_get_number_chk(&di->di_tv, &denote);
+ if (denote) {
+ return FAIL;
+ }
+ }
+
+ if (newidx < 1) { // sanity check
+ return FAIL;
+ }
+ if (newidx > qfl->qf_count) {
+ newidx = qfl->qf_count;
+ }
+ const int old_qfidx = qfl->qf_index;
+ qfline_T *const qf_ptr = get_nth_entry(qfl, newidx, &newidx);
+ if (qf_ptr == NULL) {
+ return FAIL;
+ }
+ qfl->qf_ptr = qf_ptr;
+ qfl->qf_index = newidx;
+
+ // If the current list is modified and it is displayed in the quickfix
+ // window, then Update it.
+ if (qi->qf_lists[qi->qf_curlist].qf_id == qfl->qf_id) {
+ qf_win_pos_update(qi, old_qfidx);
+ }
+ return OK;
+}
+
/// Set quickfix/location list properties (title, items, context).
/// Also used to add items from parsing a list of lines.
/// Used by the setqflist() and setloclist() Vim script functions.
@@ -6055,6 +6244,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
retval = qf_setprop_context(qfl, di);
}
+ if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
+ retval = qf_setprop_curidx(qi, qfl, di);
+ }
if (retval == OK) {
qf_list_changed(qfl);
@@ -6065,7 +6257,8 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
/// Find the non-location list window with the specified location list stack in
/// the current tabpage.
-static win_T * find_win_with_ll(qf_info_T *qi)
+static win_T *find_win_with_ll(const qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) {
@@ -6124,6 +6317,7 @@ 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.
int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
dict_T *what)
{
@@ -6140,6 +6334,12 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
return OK;
}
+ // A dict argument cannot be specified with a non-empty list argument
+ if (list != NULL && tv_list_len(list) != 0 && what != NULL) {
+ EMSG2(_(e_invarg2), _("cannot have both a list and a \"what\" argument"));
+ return FAIL;
+ }
+
incr_quickfix_busy();
if (what != NULL) {
@@ -6368,7 +6568,7 @@ void ex_cexpr(exarg_T *eap)
// Evaluate the expression. When the result is a string or a list we can
// use it to fill the errorlist.
typval_T tv;
- if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
+ if (eval0(eap->arg, &tv, &eap->nextcmd, true) != FAIL) {
if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
|| tv.v_type == VAR_LIST) {
incr_quickfix_busy();
@@ -6439,7 +6639,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
// Search for a pattern in a help file.
static void hgr_search_file(
- qf_info_T *qi,
+ qf_list_T *qfl,
char_u *fname,
regmatch_T *p_regmatch)
FUNC_ATTR_NONNULL_ARG(1, 3)
@@ -6461,7 +6661,7 @@ static void hgr_search_file(
line[--l] = NUL;
}
- if (qf_add_entry(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -6494,7 +6694,7 @@ static void hgr_search_file(
// Search for a pattern in all the help files in the doc directory under
// the given directory.
static void hgr_search_files_in_dir(
- qf_info_T *qi,
+ qf_list_T *qfl,
char_u *dirname,
regmatch_T *p_regmatch,
const char_u *lang)
@@ -6519,7 +6719,7 @@ static void hgr_search_files_in_dir(
continue;
}
- hgr_search_file(qi, fnames[fi], p_regmatch);
+ hgr_search_file(qfl, fnames[fi], p_regmatch);
}
FreeWild(fcount, fnames);
}
@@ -6529,7 +6729,7 @@ static void hgr_search_files_in_dir(
// and add the matches to a quickfix list.
// 'lang' is the language specifier. If supplied, then only matches in the
// specified language are found.
-static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
+static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch,
const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -6538,7 +6738,7 @@ static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
while (*p != NUL && !got_int) {
copy_option_part(&p, NameBuff, MAXPATHL, ",");
- hgr_search_files_in_dir(qi, NameBuff, p_regmatch, lang);
+ hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang);
}
}
@@ -6580,12 +6780,12 @@ void ex_helpgrep(exarg_T *eap)
if (regmatch.regprog != NULL) {
// Create a new quickfix list.
qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
+ qf_list_T *const qfl = qf_get_curlist(qi);
- hgr_search_in_rtp(qi, &regmatch, lang);
+ hgr_search_in_rtp(qfl, &regmatch, lang);
vim_regfree(regmatch.regprog);
- qf_list_T *qfl = qf_get_curlist(qi);
qfl->qf_nonevalid = false;
qfl->qf_ptr = qfl->qf_start;
qfl->qf_index = 1;
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 9705896e9b..6316129c6a 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -1270,8 +1270,9 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags)
int len;
int flags;
- if (expr == NULL)
- EMSG_RET_NULL(_(e_null));
+ if (expr == NULL) {
+ IEMSG_RET_NULL(_(e_null));
+ }
init_class_tab();
@@ -3483,7 +3484,7 @@ static long bt_regexec_both(char_u *line,
/* Be paranoid... */
if (prog == NULL || line == NULL) {
- EMSG(_(e_null));
+ IEMSG(_(e_null));
goto theend;
}
@@ -4789,7 +4790,7 @@ static bool regmatch(
break;
default:
- EMSG(_(e_re_corr));
+ IEMSG(_(e_re_corr));
#ifdef REGEXP_DEBUG
printf("Illegal op code %d\n", op);
#endif
@@ -5147,7 +5148,7 @@ static bool regmatch(
* We get here only if there's trouble -- normally "case END" is
* the terminating point.
*/
- EMSG(_(e_re_corr));
+ IEMSG(_(e_re_corr));
#ifdef REGEXP_DEBUG
printf("Premature EOL\n");
#endif
@@ -5552,8 +5553,8 @@ do_class:
}
break;
- default: /* Oh dear. Called inappropriately. */
- EMSG(_(e_re_corr));
+ default: // Oh dear. Called inappropriately.
+ IEMSG(_(e_re_corr));
#ifdef REGEXP_DEBUG
printf("Called regrepeat with op code %d\n", OP(p));
#endif
@@ -6707,14 +6708,14 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
argv[0].vval.v_list = &matchList.sl_list;
if (expr->v_type == VAR_FUNC) {
s = expr->vval.v_string;
- call_func(s, (int)STRLEN(s), &rettv, 1, argv,
+ call_func(s, -1, &rettv, 1, argv,
fill_submatch_list, 0L, 0L, &dummy,
true, NULL, NULL);
} else if (expr->v_type == VAR_PARTIAL) {
partial_T *partial = expr->vval.v_partial;
s = partial_name(partial);
- call_func(s, (int)STRLEN(s), &rettv, 1, argv,
+ call_func(s, -1, &rettv, 1, argv,
fill_submatch_list, 0L, 0L, &dummy,
true, partial, NULL);
}
@@ -6911,7 +6912,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
}
} else if (*s == NUL) { // we hit NUL.
if (copy) {
- EMSG(_(e_re_damg));
+ IEMSG(_(e_re_damg));
}
goto exit;
} else {
@@ -7386,6 +7387,7 @@ long vim_regexec_multi(
proftime_T *tm, // timeout limit or NULL
int *timed_out // flag is set when timeout limit reached
)
+ FUNC_ATTR_NONNULL_ARG(1)
{
regexec_T rex_save;
bool rex_in_use_save = rex_in_use;
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 506c4e87db..7cd1ae93d2 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -6519,7 +6519,7 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol,
/* Be paranoid... */
if (prog == NULL || line == NULL) {
- EMSG(_(e_null));
+ IEMSG(_(e_null));
goto theend;
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 69de1de6b2..df0c5ce791 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -119,10 +119,12 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/lua/executor.h"
+#include "nvim/lib/kvec.h"
#define MB_FILLER_CHAR '<' /* character used when a double-width character
* doesn't fit. */
+typedef kvec_withinit_t(DecorationProvider *, 4) Providers;
// temporary buffer for rendering a single screenline, so it can be
// compared with previous contents to calculate smallest delta.
@@ -133,8 +135,6 @@ static sattr_T *linebuf_attr = NULL;
static match_T search_hl; /* used for 'hlsearch' highlight matching */
-static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
-
StlClickDefinition *tab_page_click_defs = NULL;
long tab_page_click_defs_size = 0;
@@ -158,11 +158,43 @@ static bool msg_grid_invalid = false;
static bool resizing = false;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
#define SEARCH_HL_PRIORITY 0
+static char * provider_first_error = NULL;
+
+static bool provider_invoke(NS ns_id, const char *name, LuaRef ref,
+ Array args, bool default_true)
+{
+ Error err = ERROR_INIT;
+
+ textlock++;
+ Object ret = nlua_call_ref(ref, name, args, true, &err);
+ textlock--;
+
+ if (!ERROR_SET(&err)
+ && api_coerce_to_bool(ret, "provider %s retval", default_true, &err)) {
+ return true;
+ }
+
+ if (ERROR_SET(&err)) {
+ const char *ns_name = describe_ns(ns_id);
+ ELOG("error in provider %s:%s: %s", ns_name, name, err.msg);
+ bool verbose_errs = true; // TODO(bfredl):
+ if (verbose_errs && provider_first_error == NULL) {
+ static char errbuf[IOSIZE];
+ snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg);
+ provider_first_error = xstrdup(errbuf);
+ }
+ }
+
+ api_free_object(ret);
+ return false;
+}
+
/*
* Redraw the current window later, with update_screen(type).
* Set must_redraw only if not already set to a higher value.
@@ -446,6 +478,29 @@ int update_screen(int type)
ui_comp_set_screen_valid(true);
+ Providers providers;
+ kvi_init(providers);
+ for (size_t i = 0; i < kv_size(decoration_providers); i++) {
+ DecorationProvider *p = &kv_A(decoration_providers, i);
+ if (!p->active) {
+ continue;
+ }
+
+ bool active;
+ if (p->redraw_start != LUA_NOREF) {
+ FIXED_TEMP_ARRAY(args, 2);
+ args.items[0] = INTEGER_OBJ(display_tick);
+ args.items[1] = INTEGER_OBJ(type);
+ active = provider_invoke(p->ns_id, "start", p->redraw_start, args, true);
+ } else {
+ active = true;
+ }
+
+ if (active) {
+ kvi_push(providers, p);
+ }
+ }
+
if (clear_cmdline) /* going to clear cmdline (done below) */
check_for_delay(FALSE);
@@ -494,30 +549,24 @@ int update_screen(int type)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
update_window_hl(wp, type >= NOT_VALID);
- if (wp->w_buffer->b_mod_set) {
- win_T *wwp;
-
- // Check if we already did this buffer.
- for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) {
- if (wwp->w_buffer == wp->w_buffer) {
- break;
- }
- }
- if (wwp == wp && syntax_present(wp)) {
- syn_stack_apply_changes(wp->w_buffer);
- }
-
- buf_T *buf = wp->w_buffer;
- if (buf->b_luahl && buf->b_luahl_window != LUA_NOREF) {
- Error err = ERROR_INIT;
- FIXED_TEMP_ARRAY(args, 2);
- args.items[0] = BUFFER_OBJ(buf->handle);
- args.items[1] = INTEGER_OBJ(display_tick);
- executor_exec_lua_cb(buf->b_luahl_start, "start", args, false, &err);
- if (ERROR_SET(&err)) {
- ELOG("error in luahl start: %s", err.msg);
- api_clear_error(&err);
+ buf_T *buf = wp->w_buffer;
+ if (buf->b_mod_set) {
+ if (buf->b_mod_tick_syn < display_tick
+ && syntax_present(wp)) {
+ syn_stack_apply_changes(buf);
+ buf->b_mod_tick_syn = display_tick;
+ }
+
+ if (buf->b_mod_tick_deco < display_tick) {
+ for (size_t i = 0; i < kv_size(providers); i++) {
+ DecorationProvider *p = kv_A(providers, i);
+ if (p && p->redraw_buf != LUA_NOREF) {
+ FIXED_TEMP_ARRAY(args, 1);
+ args.items[0] = BUFFER_OBJ(buf->handle);
+ provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true);
+ }
}
+ buf->b_mod_tick_deco = display_tick;
}
}
}
@@ -531,6 +580,8 @@ int update_screen(int type)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ redrawn_win = wp;
+
if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid.chars) {
grid_invalidate(&wp->w_grid);
wp->w_redr_type = NOT_VALID;
@@ -541,13 +592,15 @@ int update_screen(int type)
did_one = TRUE;
start_search_hl();
}
- win_update(wp);
+ win_update(wp, &providers);
}
/* redraw status line after the window to minimize cursor movement */
if (wp->w_redr_status) {
win_redr_status(wp);
}
+
+ redrawn_win = NULL;
}
end_search_hl();
@@ -578,6 +631,21 @@ int update_screen(int type)
maybe_intro_message();
did_intro = TRUE;
+ for (size_t i = 0; i < kv_size(providers); i++) {
+ DecorationProvider *p = kv_A(providers, i);
+ if (!p->active) {
+ continue;
+ }
+
+ if (p->redraw_end != LUA_NOREF) {
+ FIXED_TEMP_ARRAY(args, 1);
+ args.items[0] = INTEGER_OBJ(display_tick);
+ provider_invoke(p->ns_id, "end", p->redraw_end, args, true);
+ }
+ }
+ kvi_destroy(providers);
+
+
// either cmdline is cleared, not drawn or mode is last drawn
cmdline_was_last_drawn = false;
return OK;
@@ -635,14 +703,15 @@ bool win_cursorline_standout(const win_T *wp)
}
static DecorationRedrawState decorations;
-bool decorations_active = false;
-void decorations_add_luahl_attr(int attr_id,
- int start_row, int start_col,
- int end_row, int end_col)
+void decorations_add_ephemeral(int attr_id,
+ int start_row, int start_col,
+ int end_row, int end_col, VirtText *virt_text)
{
kv_push(decorations.active,
- ((HlRange){ start_row, start_col, end_row, end_col, attr_id, NULL }));
+ ((HlRange){ start_row, start_col,
+ end_row, end_col,
+ attr_id, virt_text, virt_text != NULL }));
}
/*
@@ -672,7 +741,7 @@ void decorations_add_luahl_attr(int attr_id,
* mid: from mid_start to mid_end (update inversion or changed text)
* bot: from bot_start to last row (when scrolled up)
*/
-static void win_update(win_T *wp)
+static void win_update(win_T *wp, Providers *providers)
{
buf_T *buf = wp->w_buffer;
int type;
@@ -697,9 +766,10 @@ static void win_update(win_T *wp)
int didline = FALSE; /* if TRUE, we finished the last line */
int i;
long j;
- static int recursive = FALSE; /* being called recursively */
- int old_botline = wp->w_botline;
- long fold_count;
+ static bool recursive = false; // being called recursively
+ const linenr_T old_botline = wp->w_botline;
+ const int old_wrow = wp->w_wrow;
+ const int old_wcol = wp->w_wcol;
// Remember what happened to the previous line.
#define DID_NONE 1 // didn't update a line
#define DID_LINE 2 // updated a normal line
@@ -710,6 +780,7 @@ static void win_update(win_T *wp)
linenr_T mod_bot = 0;
int save_got_int;
+
// If we can compute a change in the automatic sizing of the sign column
// under 'signcolumn=auto:X' and signs currently placed in the buffer, better
// figuring it out here so we can redraw the entire screen for it.
@@ -898,11 +969,12 @@ static void win_update(win_T *wp)
|| type == INVERTED || type == INVERTED_ALL)
&& !wp->w_botfill && !wp->w_old_botfill
) {
- if (mod_top != 0 && wp->w_topline == mod_top) {
- /*
- * w_topline is the first changed line, the scrolling will be done
- * further down.
- */
+ if (mod_top != 0
+ && wp->w_topline == mod_top
+ && (!wp->w_lines[0].wl_valid
+ || wp->w_topline <= wp->w_lines[0].wl_lnum)) {
+ // w_topline is the first changed line and window is not scrolled,
+ // the scrolling from changed lines will be done further down.
} else if (wp->w_lines[0].wl_valid
&& (wp->w_topline < wp->w_lines[0].wl_lnum
|| (wp->w_topline == wp->w_lines[0].wl_lnum
@@ -1226,7 +1298,6 @@ static void win_update(win_T *wp)
// Set the time limit to 'redrawtime'.
proftime_T syntax_tm = profile_setlimit(p_rdt);
syn_set_timeout(&syntax_tm);
- win_foldinfo.fi_level = 0;
/*
* Update all the window rows.
@@ -1236,25 +1307,27 @@ static void win_update(win_T *wp)
srow = 0;
lnum = wp->w_topline; // first line shown in window
- decorations_active = decorations_redraw_reset(buf, &decorations);
+ decorations_redraw_reset(buf, &decorations);
- if (buf->b_luahl && buf->b_luahl_window != LUA_NOREF) {
- Error err = ERROR_INIT;
- FIXED_TEMP_ARRAY(args, 4);
- linenr_T knownmax = ((wp->w_valid & VALID_BOTLINE)
- ? wp->w_botline
- : (wp->w_topline + wp->w_height_inner));
- args.items[0] = WINDOW_OBJ(wp->handle);
- args.items[1] = BUFFER_OBJ(buf->handle);
- // TODO(bfredl): we are not using this, but should be first drawn line?
- args.items[2] = INTEGER_OBJ(wp->w_topline-1);
- args.items[3] = INTEGER_OBJ(knownmax);
- // TODO(bfredl): we could allow this callback to change mod_top, mod_bot.
- // For now the "start" callback is expected to use nvim__buf_redraw_range.
- executor_exec_lua_cb(buf->b_luahl_window, "window", args, false, &err);
- if (ERROR_SET(&err)) {
- ELOG("error in luahl window: %s", err.msg);
- api_clear_error(&err);
+ Providers line_providers;
+ kvi_init(line_providers);
+
+ linenr_T knownmax = ((wp->w_valid & VALID_BOTLINE)
+ ? wp->w_botline
+ : (wp->w_topline + wp->w_height_inner));
+
+ for (size_t k = 0; k < kv_size(*providers); k++) {
+ DecorationProvider *p = kv_A(*providers, k);
+ if (p && p->redraw_win != LUA_NOREF) {
+ FIXED_TEMP_ARRAY(args, 4);
+ args.items[0] = WINDOW_OBJ(wp->handle);
+ args.items[1] = BUFFER_OBJ(buf->handle);
+ // TODO(bfredl): we are not using this, but should be first drawn line?
+ args.items[2] = INTEGER_OBJ(wp->w_topline-1);
+ args.items[3] = INTEGER_OBJ(knownmax);
+ if (provider_invoke(p->ns_id, "win", p->redraw_win, args, true)) {
+ kvi_push(line_providers, p);
+ }
}
}
@@ -1448,24 +1521,19 @@ static void win_update(win_T *wp)
* Otherwise, display normally (can be several display lines when
* 'wrap' is on).
*/
- fold_count = foldedCount(wp, lnum, &win_foldinfo);
- if (fold_count != 0) {
- fold_line(wp, fold_count, &win_foldinfo, lnum, row);
- ++row;
- --fold_count;
- wp->w_lines[idx].wl_folded = TRUE;
- wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
- did_update = DID_FOLD;
- } else if (idx < wp->w_lines_valid
- && wp->w_lines[idx].wl_valid
- && wp->w_lines[idx].wl_lnum == lnum
- && lnum > wp->w_topline
- && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
- && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
- && diff_check_fill(wp, lnum) == 0
- ) {
- /* This line is not going to fit. Don't draw anything here,
- * will draw "@ " lines below. */
+ foldinfo_T foldinfo = fold_info(wp, lnum);
+
+ if (foldinfo.fi_lines == 0
+ && idx < wp->w_lines_valid
+ && wp->w_lines[idx].wl_valid
+ && wp->w_lines[idx].wl_lnum == lnum
+ && lnum > wp->w_topline
+ && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
+ && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
+ && diff_check_fill(wp, lnum) == 0
+ ) {
+ // This line is not going to fit. Don't draw anything here,
+ // will draw "@ " lines below.
row = wp->w_grid.Rows + 1;
} else {
prepare_search_hl(wp, lnum);
@@ -1474,14 +1542,21 @@ static void win_update(win_T *wp)
&& syntax_present(wp))
syntax_end_parsing(syntax_last_parsed + 1);
- /*
- * Display one line.
- */
- row = win_line(wp, lnum, srow, wp->w_grid.Rows, mod_top == 0, false);
+ // Display one line
+ row = win_line(wp, lnum, srow,
+ foldinfo.fi_lines ? srow : wp->w_grid.Rows,
+ mod_top == 0, false, foldinfo, &line_providers);
- wp->w_lines[idx].wl_folded = FALSE;
+ wp->w_lines[idx].wl_folded = foldinfo.fi_lines != 0;
wp->w_lines[idx].wl_lastlnum = lnum;
did_update = DID_LINE;
+
+ if (foldinfo.fi_lines > 0) {
+ did_update = DID_FOLD;
+ foldinfo.fi_lines--;
+ wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines;
+ }
+
syntax_last_parsed = lnum;
}
@@ -1496,20 +1571,18 @@ static void win_update(win_T *wp)
idx++;
break;
}
- if (dollar_vcol == -1)
+ if (dollar_vcol == -1) {
wp->w_lines[idx].wl_size = row - srow;
- ++idx;
- lnum += fold_count + 1;
+ }
+ idx++;
+ lnum += foldinfo.fi_lines + 1;
} else {
if (wp->w_p_rnu) {
// 'relativenumber' set: The text doesn't need to be drawn, but
// the number column nearly always does.
- fold_count = foldedCount(wp, lnum, &win_foldinfo);
- if (fold_count != 0) {
- fold_line(wp, fold_count, &win_foldinfo, lnum, row);
- } else {
- (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true);
- }
+ foldinfo_T info = fold_info(wp, lnum);
+ (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true,
+ info, &line_providers);
}
// This line does not need to be drawn, advance to the next one.
@@ -1605,6 +1678,8 @@ static void win_update(win_T *wp)
HLF_EOB);
}
+ kvi_destroy(line_providers);
+
if (wp->w_redr_type >= REDRAW_TOP) {
draw_vsep_win(wp, 0);
}
@@ -1631,18 +1706,51 @@ static void win_update(win_T *wp)
wp->w_valid |= VALID_BOTLINE;
wp->w_viewport_invalid = true;
if (wp == curwin && wp->w_botline != old_botline && !recursive) {
- recursive = TRUE;
+ const linenr_T old_topline = wp->w_topline;
+ const int new_wcol = wp->w_wcol;
+ recursive = true;
curwin->w_valid &= ~VALID_TOPLINE;
- update_topline(); /* may invalidate w_botline again */
- if (must_redraw != 0) {
- /* Don't update for changes in buffer again. */
+ update_topline(); // may invalidate w_botline again
+
+ if (old_wcol != new_wcol
+ && (wp->w_valid & (VALID_WCOL|VALID_WROW))
+ != (VALID_WCOL|VALID_WROW)) {
+ // A win_line() call applied a fix to screen cursor column to
+ // accomodate concealment of cursor line, but in this call to
+ // update_topline() the cursor's row or column got invalidated.
+ // If they are left invalid, setcursor() will recompute them
+ // but there won't be any further win_line() call to re-fix the
+ // column and the cursor will end up misplaced. So we call
+ // cursor validation now and reapply the fix again (or call
+ // win_line() to do it for us).
+ validate_cursor();
+ if (wp->w_wcol == old_wcol
+ && wp->w_wrow == old_wrow
+ && old_topline == wp->w_topline) {
+ wp->w_wcol = new_wcol;
+ } else {
+ redrawWinline(wp, wp->w_cursor.lnum);
+ }
+ }
+ // New redraw either due to updated topline or due to wcol fix.
+ if (wp->w_redr_type != 0) {
+ // Don't update for changes in buffer again.
i = curbuf->b_mod_set;
curbuf->b_mod_set = false;
- win_update(curwin);
- must_redraw = 0;
+ j = curbuf->b_mod_xlines;
+ curbuf->b_mod_xlines = 0;
+ win_update(curwin, providers);
curbuf->b_mod_set = i;
+ curbuf->b_mod_xlines = j;
+ }
+ // Other windows might have w_redr_type raised in update_topline().
+ must_redraw = 0;
+ FOR_ALL_WINDOWS_IN_TAB(wwp, curtab) {
+ if (wwp->w_redr_type > must_redraw) {
+ must_redraw = wwp->w_redr_type;
+ }
}
- recursive = FALSE;
+ recursive = false;
}
}
@@ -1741,31 +1849,6 @@ static int advance_color_col(int vcol, int **color_cols)
return **color_cols >= 0;
}
-// Returns the next grid column.
-static int text_to_screenline(win_T *wp, char_u *text, int col, int off)
- FUNC_ATTR_NONNULL_ALL
-{
- int idx = wp->w_p_rl ? off : off + col;
- LineState s = LINE_STATE(text);
-
- while (*s.p != NUL) {
- // TODO(bfredl): cargo-culted from the old Vim code:
- // if(col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { break; }
- // This is obvious wrong. If Vim ever fixes this, solve for "cells" again
- // in the correct condition.
- const int maxcells = wp->w_grid.Columns - col - (wp->w_p_rl ? col : 0);
- const int cells = line_putchar(&s, &linebuf_char[idx], maxcells,
- wp->w_p_rl);
- if (cells == -1) {
- break;
- }
- col += cells;
- idx += cells;
- }
-
- return col;
-}
-
// Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
// space is available for window "wp", minus "col".
static int compute_foldcolumn(win_T *wp, int col)
@@ -1830,271 +1913,6 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
return cells;
}
-/*
- * Display one folded line.
- */
-static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row)
-{
- char_u buf[FOLD_TEXT_LEN];
- pos_T *top, *bot;
- linenr_T lnume = lnum + fold_count - 1;
- int len;
- char_u *text;
- int fdc;
- int col;
- int txtcol;
- int off;
-
- /* Build the fold line:
- * 1. Add the cmdwin_type for the command-line window
- * 2. Add the 'foldcolumn'
- * 3. Add the 'number' or 'relativenumber' column
- * 4. Compose the text
- * 5. Add the text
- * 6. set highlighting for the Visual area an other text
- */
- col = 0;
- off = 0;
-
- /*
- * 1. Add the cmdwin_type for the command-line window
- * Ignores 'rightleft', this window is never right-left.
- */
- if (cmdwin_type != 0 && wp == curwin) {
- schar_from_ascii(linebuf_char[off], cmdwin_type);
- linebuf_attr[off] = win_hl_attr(wp, HLF_AT);
- col++;
- }
-
-# define RL_MEMSET(p, v, l) \
- do { \
- if (wp->w_p_rl) { \
- for (int ri = 0; ri < l; ri++) { \
- linebuf_attr[off + (wp->w_grid.Columns - (p) - (l)) + ri] = v; \
- } \
- } else { \
- for (int ri = 0; ri < l; ri++) { \
- linebuf_attr[off + (p) + ri] = v; \
- } \
- } \
- } while (0)
-
- // 2. Add the 'foldcolumn'
- // Reduce the width when there is not enough space.
- fdc = compute_foldcolumn(wp, col);
- if (fdc > 0) {
- fill_foldcolumn(buf, wp, true, lnum);
- const char_u *it = &buf[0];
- for (int i = 0; i < fdc; i++) {
- int mb_c = mb_ptr2char_adv(&it);
- if (wp->w_p_rl) {
- schar_from_char(linebuf_char[off + wp->w_grid.Columns - i - 1 - col],
- mb_c);
- } else {
- schar_from_char(linebuf_char[off + col + i], mb_c);
- }
- }
- RL_MEMSET(col, win_hl_attr(wp, HLF_FC), fdc);
- col += fdc;
- }
-
- /* Set all attributes of the 'number' or 'relativenumber' column and the
- * text */
- RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_grid.Columns - col);
-
- // If signs are being displayed, add spaces.
- if (win_signcol_count(wp) > 0) {
- len = wp->w_grid.Columns - col;
- if (len > 0) {
- int len_max = win_signcol_width(wp) * win_signcol_count(wp);
- if (len > len_max) {
- len = len_max;
- }
- char_u space_buf[18] = " ";
- assert((size_t)len_max <= sizeof(space_buf));
- copy_text_attr(off + col, space_buf, len,
- win_hl_attr(wp, HLF_FL));
- col += len;
- }
- }
-
- /*
- * 3. Add the 'number' or 'relativenumber' column
- */
- if (wp->w_p_nu || wp->w_p_rnu) {
- len = wp->w_grid.Columns - col;
- if (len > 0) {
- int w = number_width(wp);
- long num;
- char *fmt = "%*ld ";
-
- if (len > w + 1)
- len = w + 1;
-
- if (wp->w_p_nu && !wp->w_p_rnu)
- /* 'number' + 'norelativenumber' */
- num = (long)lnum;
- else {
- /* 'relativenumber', don't use negative numbers */
- num = labs((long)get_cursor_rel_lnum(wp, lnum));
- if (num == 0 && wp->w_p_nu && wp->w_p_rnu) {
- /* 'number' + 'relativenumber': cursor line shows absolute
- * line number */
- num = lnum;
- fmt = "%-*ld ";
- }
- }
-
- snprintf((char *)buf, FOLD_TEXT_LEN, fmt, w, num);
- if (wp->w_p_rl) {
- // the line number isn't reversed
- copy_text_attr(off + wp->w_grid.Columns - len - col, buf, len,
- win_hl_attr(wp, HLF_FL));
- } else {
- copy_text_attr(off + col, buf, len, win_hl_attr(wp, HLF_FL));
- }
- col += len;
- }
- }
-
- /*
- * 4. Compose the folded-line string with 'foldtext', if set.
- */
- text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
-
- txtcol = col; /* remember where text starts */
-
- // 5. move the text to linebuf_char[off]. Fill up with "fold".
- // Right-left text is put in columns 0 - number-col, normal text is put
- // in columns number-col - window-width.
- col = text_to_screenline(wp, text, col, off);
-
- /* Fill the rest of the line with the fold filler */
- if (wp->w_p_rl)
- col -= txtcol;
-
- schar_T sc;
- schar_from_char(sc, wp->w_p_fcs_chars.fold);
- while (col < wp->w_grid.Columns
- - (wp->w_p_rl ? txtcol : 0)
- ) {
- schar_copy(linebuf_char[off+col++], sc);
- }
-
- if (text != buf)
- xfree(text);
-
- /*
- * 6. set highlighting for the Visual area an other text.
- * If all folded lines are in the Visual area, highlight the line.
- */
- if (VIsual_active && wp->w_buffer == curwin->w_buffer) {
- if (ltoreq(curwin->w_cursor, VIsual)) {
- /* Visual is after curwin->w_cursor */
- top = &curwin->w_cursor;
- bot = &VIsual;
- } else {
- /* Visual is before curwin->w_cursor */
- top = &VIsual;
- bot = &curwin->w_cursor;
- }
- if (lnum >= top->lnum
- && lnume <= bot->lnum
- && (VIsual_mode != 'v'
- || ((lnum > top->lnum
- || (lnum == top->lnum
- && top->col == 0))
- && (lnume < bot->lnum
- || (lnume == bot->lnum
- && (bot->col - (*p_sel == 'e'))
- >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume,
- FALSE))))))) {
- if (VIsual_mode == Ctrl_V) {
- // Visual block mode: highlight the chars part of the block
- if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_grid.Columns) {
- if (wp->w_old_cursor_lcol != MAXCOL
- && wp->w_old_cursor_lcol + txtcol
- < (colnr_T)wp->w_grid.Columns) {
- len = wp->w_old_cursor_lcol;
- } else {
- len = wp->w_grid.Columns - txtcol;
- }
- RL_MEMSET(wp->w_old_cursor_fcol + txtcol, win_hl_attr(wp, HLF_V),
- len - (int)wp->w_old_cursor_fcol);
- }
- } else {
- // Set all attributes of the text
- RL_MEMSET(txtcol, win_hl_attr(wp, HLF_V), wp->w_grid.Columns - txtcol);
- }
- }
- }
-
- // Show colorcolumn in the fold line, but let cursorcolumn override it.
- if (wp->w_p_cc_cols) {
- int i = 0;
- int j = wp->w_p_cc_cols[i];
- int old_txtcol = txtcol;
-
- while (j > -1) {
- txtcol += j;
- if (wp->w_p_wrap) {
- txtcol -= wp->w_skipcol;
- } else {
- txtcol -= wp->w_leftcol;
- }
- if (txtcol >= 0 && txtcol < wp->w_grid.Columns) {
- linebuf_attr[off + txtcol] =
- hl_combine_attr(linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_MC));
- }
- txtcol = old_txtcol;
- j = wp->w_p_cc_cols[++i];
- }
- }
-
- /* Show 'cursorcolumn' in the fold line. */
- if (wp->w_p_cuc) {
- txtcol += wp->w_virtcol;
- if (wp->w_p_wrap)
- txtcol -= wp->w_skipcol;
- else
- txtcol -= wp->w_leftcol;
- if (txtcol >= 0 && txtcol < wp->w_grid.Columns) {
- linebuf_attr[off + txtcol] = hl_combine_attr(
- linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_CUC));
- }
- }
-
- grid_put_linebuf(&wp->w_grid, row, 0, wp->w_grid.Columns, wp->w_grid.Columns,
- false, wp, wp->w_hl_attr_normal, false);
-
- /*
- * Update w_cline_height and w_cline_folded if the cursor line was
- * updated (saves a call to plines() later).
- */
- if (wp == curwin
- && lnum <= curwin->w_cursor.lnum
- && lnume >= curwin->w_cursor.lnum) {
- curwin->w_cline_row = row;
- curwin->w_cline_height = 1;
- curwin->w_cline_folded = true;
- curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
- conceal_cursor_used = conceal_cursor_line(curwin);
- }
-}
-
-
-/// Copy "buf[len]" to linebuf_char["off"] and set attributes to "attr".
-///
-/// Only works for ASCII text!
-static void copy_text_attr(int off, char_u *buf, int len, int attr)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- schar_from_ascii(linebuf_char[off + i], buf[i]);
- linebuf_attr[off + i] = attr;
- }
-}
/// Fills the foldcolumn at "p" for window "wp".
/// Only to be called when 'foldcolumn' > 0.
@@ -2109,7 +1927,7 @@ static size_t
fill_foldcolumn(
char_u *p,
win_T *wp,
- int closed,
+ foldinfo_T foldinfo,
linenr_T lnum
)
{
@@ -2120,10 +1938,11 @@ fill_foldcolumn(
size_t char_counter = 0;
int symbol = 0;
int len = 0;
+ bool closed = foldinfo.fi_lines > 0;
// Init to all spaces.
memset(p, ' ', MAX_MCO * fdc + 1);
- level = win_foldinfo.fi_level;
+ level = foldinfo.fi_level;
// If the column is too narrow, we start at the lowest level that
// fits and use numbers to indicated the depth.
@@ -2133,8 +1952,8 @@ fill_foldcolumn(
}
for (i = 0; i < MIN(fdc, level); i++) {
- if (win_foldinfo.fi_lnum == lnum
- && first_level + i >= win_foldinfo.fi_low_level) {
+ if (foldinfo.fi_lnum == lnum
+ && first_level + i >= foldinfo.fi_low_level) {
symbol = wp->w_p_fcs_chars.foldopen;
} else if (first_level == 1) {
symbol = wp->w_p_fcs_chars.foldsep;
@@ -2165,22 +1984,23 @@ fill_foldcolumn(
return MAX(char_counter + (fdc-i), (size_t)fdc);
}
-/*
- * Display line "lnum" of window 'wp' on the screen.
- * Start at row "startrow", stop when "endrow" is reached.
- * wp->w_virtcol needs to be valid.
- *
- * Return the number of last row the line occupies.
- */
-static int
-win_line (
- win_T *wp,
- linenr_T lnum,
- int startrow,
- int endrow,
- bool nochange, // not updating for changed text
- bool number_only // only update the number column
-)
+/// Display line "lnum" of window 'wp' on the screen.
+/// wp->w_virtcol needs to be valid.
+///
+/// @param lnum line to display
+/// @param startrow first row relative to window grid
+/// @param endrow last grid row to be redrawn
+/// @param nochange not updating for changed text
+/// @param number_only only update the number column
+/// @param foldinfo fold info for this line
+/// @param[in, out] providers decoration providers active this line
+/// items will be disables if they cause errors
+/// or explicitly return `false`.
+///
+/// @return the number of last row the line occupies.
+static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
+ bool nochange, bool number_only, foldinfo_T foldinfo,
+ Providers *providers)
{
int c = 0; // init for GCC
long vcol = 0; // virtual column (for tabs)
@@ -2284,6 +2104,8 @@ win_line (
bool has_decorations = false; // this buffer has decorations
bool do_virttext = false; // draw virtual text for this line
+ char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
+
/* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */
# define WL_CMDLINE WL_START + 1 /* cmdline window column */
@@ -2322,7 +2144,7 @@ win_line (
row = startrow;
- char *luatext = NULL;
+ char *err_text = NULL;
buf_T *buf = wp->w_buffer;
@@ -2347,35 +2169,33 @@ win_line (
}
}
- if (decorations_active) {
- if (buf->b_luahl && buf->b_luahl_line != LUA_NOREF) {
- Error err = ERROR_INIT;
+ has_decorations = decorations_redraw_line(wp->w_buffer, lnum-1,
+ &decorations);
+
+ for (size_t k = 0; k < kv_size(*providers); k++) {
+ DecorationProvider *p = kv_A(*providers, k);
+ if (p && p->redraw_line != LUA_NOREF) {
FIXED_TEMP_ARRAY(args, 3);
args.items[0] = WINDOW_OBJ(wp->handle);
args.items[1] = BUFFER_OBJ(buf->handle);
args.items[2] = INTEGER_OBJ(lnum-1);
- lua_attr_active = true;
- extra_check = true;
- Object o = executor_exec_lua_cb(buf->b_luahl_line, "line",
- args, true, &err);
- lua_attr_active = false;
- if (o.type == kObjectTypeString) {
- // TODO(bfredl): this is a bit of a hack. A final API should use an
- // "unified" interface where luahl can add both bufhl and virttext
- luatext = o.data.string.data;
- do_virttext = true;
- } else if (ERROR_SET(&err)) {
- ELOG("error in luahl line: %s", err.msg);
- luatext = err.msg;
- do_virttext = true;
+ if (provider_invoke(p->ns_id, "line", p->redraw_line, args, true)) {
+ has_decorations = true;
+ } else {
+ // return 'false' or error: skip rest of this window
+ kv_A(*providers, k) = NULL;
}
}
+ }
- has_decorations = decorations_redraw_line(wp->w_buffer, lnum-1,
- &decorations);
- if (has_decorations) {
- extra_check = true;
- }
+ if (has_decorations) {
+ extra_check = true;
+ }
+
+ if (provider_first_error) {
+ err_text = provider_first_error;
+ provider_first_error = NULL;
+ do_virttext = true;
}
// Check for columns to display for 'colorcolumn'.
@@ -2554,6 +2374,7 @@ win_line (
}
// If this line has a sign with line highlighting set line_attr.
+ // TODO(bfredl, vigoux): this should not take priority over decorations!
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL, 0, 1);
if (v != 0) {
line_attr = sign_get_attr((int)v, SIGN_LINEHL);
@@ -2839,7 +2660,7 @@ win_line (
// already be in use.
xfree(p_extra_free);
p_extra_free = xmalloc(MAX_MCO * fdc + 1);
- n_extra = fill_foldcolumn(p_extra_free, wp, false, lnum);
+ n_extra = fill_foldcolumn(p_extra_free, wp, foldinfo, lnum);
p_extra_free[n_extra] = NUL;
p_extra = p_extra_free;
c_extra = NUL;
@@ -3065,6 +2886,51 @@ win_line (
break;
}
+ if (draw_state == WL_LINE
+ && foldinfo.fi_level != 0
+ && foldinfo.fi_lines > 0
+ && vcol == 0
+ && n_extra == 0
+ && row == startrow) {
+ char_attr = win_hl_attr(wp, HLF_FL);
+
+ linenr_T lnume = lnum + foldinfo.fi_lines - 1;
+ memset(buf_fold, ' ', FOLD_TEXT_LEN);
+ p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold);
+ n_extra = STRLEN(p_extra);
+
+ if (p_extra != buf_fold) {
+ xfree(p_extra_free);
+ p_extra_free = p_extra;
+ }
+ c_extra = NUL;
+ c_final = NUL;
+ p_extra[n_extra] = NUL;
+ }
+
+ if (draw_state == WL_LINE
+ && foldinfo.fi_level != 0
+ && foldinfo.fi_lines > 0
+ && col < grid->Columns
+ && n_extra == 0
+ && row == startrow) {
+ // fill rest of line with 'fold'
+ c_extra = wp->w_p_fcs_chars.fold;
+ c_final = NUL;
+
+ n_extra = wp->w_p_rl ? (col + 1) : (grid->Columns - col);
+ }
+
+ if (draw_state == WL_LINE
+ && foldinfo.fi_level != 0
+ && foldinfo.fi_lines > 0
+ && col >= grid->Columns
+ && n_extra != 0
+ && row == startrow) {
+ // Truncate the folding.
+ n_extra = 0;
+ }
+
if (draw_state == WL_LINE && (area_highlighting || has_spell)) {
// handle Visual or match highlighting in this line
if (vcol == fromcol
@@ -3293,6 +3159,10 @@ win_line (
p_extra++;
}
n_extra--;
+ } else if (foldinfo.fi_lines > 0) {
+ // skip writing the buffer line itself
+ c = NUL;
+ XFREE_CLEAR(p_extra_free);
} else {
int c0;
@@ -3764,7 +3634,7 @@ win_line (
mb_utf8 = false; // don't draw as UTF-8
}
} else if (c != NUL) {
- p_extra = transchar(c);
+ p_extra = transchar_buf(wp->w_buffer, c);
if (n_extra == 0) {
n_extra = byte2cells(c) - 1;
}
@@ -3861,7 +3731,7 @@ win_line (
// not showing the '>', put pointer back to avoid getting stuck
ptr++;
}
- }
+ } // end of printing from buffer content
/* In the cursor line and we may be concealing characters: correct
* the cursor column when we reach its position. */
@@ -3918,7 +3788,7 @@ win_line (
}
// At end of the text line or just after the last character.
- if (c == NUL) {
+ if (c == NUL && eol_hl_off == 0) {
long prevcol = (long)(ptr - line) - 1;
// we're not really at that column when skipping some text
@@ -4028,8 +3898,10 @@ win_line (
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
VirtText virt_text = KV_INITIAL_VALUE;
- if (luatext) {
- kv_push(virt_text, ((VirtTextChunk){ .text = luatext, .hl_id = 0 }));
+ if (err_text) {
+ int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg"));
+ kv_push(virt_text, ((VirtTextChunk){ .text = err_text,
+ .hl_id = hl_err }));
do_virttext = true;
} else if (has_decorations) {
VirtText *vp = decorations_redraw_virt_text(wp->w_buffer, &decorations);
@@ -4171,11 +4043,10 @@ win_line (
if (wp == curwin && lnum == curwin->w_cursor.lnum) {
curwin->w_cline_row = startrow;
curwin->w_cline_height = row - startrow;
- curwin->w_cline_folded = false;
+ curwin->w_cline_folded = foldinfo.fi_lines > 0;
curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
conceal_cursor_used = conceal_cursor_line(curwin);
}
-
break;
}
@@ -4364,6 +4235,7 @@ win_line (
* so far. If there is no more to display it is caught above.
*/
if ((wp->w_p_rl ? (col < 0) : (col >= grid->Columns))
+ && foldinfo.fi_lines == 0
&& (*ptr != NUL
|| filler_todo > 0
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
@@ -4449,7 +4321,7 @@ win_line (
}
xfree(p_extra_free);
- xfree(luatext);
+ xfree(err_text);
return row;
}
@@ -5918,6 +5790,12 @@ next_search_hl (
long nmatched = 0;
int save_called_emsg = called_emsg;
+ // for :{range}s/pat only highlight inside the range
+ if (lnum < search_first_line || lnum > search_last_line) {
+ shl->lnum = 0;
+ return;
+ }
+
if (shl->lnum != 0) {
// Check for three situations:
// 1. If the "lnum" is below a previous match, start a new search.
@@ -6210,7 +6088,7 @@ void win_grid_alloc(win_T *wp)
|| grid->Rows != rows
|| grid->Columns != cols) {
if (want_allocation) {
- grid_alloc(grid, rows, cols, wp->w_grid.valid, wp->w_grid.valid);
+ grid_alloc(grid, rows, cols, wp->w_grid.valid, false);
grid->valid = true;
} else {
// Single grid mode, all rendering will be redirected to default_grid.
diff --git a/src/nvim/search.c b/src/nvim/search.c
index b105d99d7c..9458e6333f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -96,11 +96,8 @@ static int lastc_bytelen = 1; // >1 for multi-byte char
// copy of spats[], for keeping the search patterns while executing autocmds
static struct spat saved_spats[2];
-// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
-// searching
-static struct spat saved_last_search_spat;
-static int saved_last_idx = 0;
-static bool saved_no_hlsearch = false;
+static int saved_spats_last_idx = 0;
+static bool saved_spats_no_hlsearch = false;
static char_u *mr_pattern = NULL; // pattern used by search_regcomp()
static int mr_pattern_alloced = false; // mr_pattern was allocated
@@ -267,8 +264,8 @@ void save_search_patterns(void)
saved_spats[1] = spats[1];
if (spats[1].pat != NULL)
saved_spats[1].pat = vim_strsave(spats[1].pat);
- saved_last_idx = last_idx;
- saved_no_hlsearch = no_hlsearch;
+ saved_spats_last_idx = last_idx;
+ saved_spats_no_hlsearch = no_hlsearch;
}
}
@@ -280,8 +277,8 @@ void restore_search_patterns(void)
set_vv_searchforward();
free_spat(&spats[1]);
spats[1] = saved_spats[1];
- last_idx = saved_last_idx;
- set_no_hlsearch(saved_no_hlsearch);
+ last_idx = saved_spats_last_idx;
+ set_no_hlsearch(saved_spats_no_hlsearch);
}
}
@@ -308,6 +305,13 @@ void free_search_patterns(void)
#endif
+// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
+// searching
+static struct spat saved_last_search_spat;
+static int did_save_last_search_spat = 0;
+static int saved_last_idx = 0;
+static bool saved_no_hlsearch = false;
+
/// Save and restore the search pattern for incremental highlight search
/// feature.
///
@@ -316,6 +320,11 @@ void free_search_patterns(void)
/// cancelling incremental searching even if it's called inside user functions.
void save_last_search_pattern(void)
{
+ if (++did_save_last_search_spat != 1) {
+ // nested call, nothing to do
+ return;
+ }
+
saved_last_search_spat = spats[RE_SEARCH];
if (spats[RE_SEARCH].pat != NULL) {
saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat);
@@ -326,8 +335,19 @@ void save_last_search_pattern(void)
void restore_last_search_pattern(void)
{
+ if (--did_save_last_search_spat > 0) {
+ // nested call, nothing to do
+ return;
+ }
+ if (did_save_last_search_spat != 0) {
+ iemsg("restore_last_search_pattern() called more often than"
+ " save_last_search_pattern()");
+ return;
+ }
+
xfree(spats[RE_SEARCH].pat);
spats[RE_SEARCH] = saved_last_search_spat;
+ saved_last_search_spat.pat = NULL;
set_vv_searchforward();
last_idx = saved_last_idx;
set_no_hlsearch(saved_no_hlsearch);
@@ -474,7 +494,7 @@ void set_last_search_pat(const char_u *s, int idx, int magic, int setlast)
saved_spats[idx].pat = NULL;
else
saved_spats[idx].pat = vim_strsave(spats[idx].pat);
- saved_last_idx = last_idx;
+ saved_spats_last_idx = last_idx;
}
/* If 'hlsearch' set and search pat changed: need redraw. */
if (p_hls && idx == last_idx && !no_hlsearch)
@@ -631,6 +651,10 @@ int searchit(
colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
nmatched = vim_regexec_multi(&regmatch, win, buf,
lnum, col, tm, timed_out);
+ // vim_regexec_multi() may clear "regprog"
+ if (regmatch.regprog == NULL) {
+ break;
+ }
// Abort searching on an error (e.g., out of stack).
if (called_emsg || (timed_out != NULL && *timed_out)) {
break;
@@ -702,6 +726,10 @@ int searchit(
match_ok = false;
break;
}
+ // vim_regexec_multi() may clear "regprog"
+ if (regmatch.regprog == NULL) {
+ break;
+ }
matchpos = regmatch.startpos[0];
endpos = regmatch.endpos[0];
submatch = first_submatch(&regmatch);
@@ -791,10 +819,13 @@ int searchit(
}
break;
}
-
- /* Need to get the line pointer again, a
- * multi-line search may have made it invalid. */
- ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+ // vim_regexec_multi() may clear "regprog"
+ if (regmatch.regprog == NULL) {
+ break;
+ }
+ // Need to get the line pointer again, a
+ // multi-line search may have made it invalid.
+ ptr = ml_get_buf(buf, lnum + matchpos.lnum, false);
}
/*
@@ -871,6 +902,11 @@ int searchit(
}
at_first_line = FALSE;
+ // vim_regexec_multi() may clear "regprog"
+ if (regmatch.regprog == NULL) {
+ break;
+ }
+
// Stop the search if wrapscan isn't set, "stop_lnum" is
// specified, after an interrupt, after a match and after looping
// twice.
@@ -1135,8 +1171,8 @@ int do_search(
pat = p; /* put pat after search command */
}
- if ((options & SEARCH_ECHO) && messaging()
- && !cmd_silent && msg_silent == 0) {
+ if ((options & SEARCH_ECHO) && messaging() && !msg_silent
+ && (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) {
char_u *trunc;
char_u off_buf[40];
size_t off_len = 0;
@@ -1145,7 +1181,8 @@ int do_search(
msg_start();
// Get the offset, so we know how long it is.
- if (spats[0].off.line || spats[0].off.end || spats[0].off.off) {
+ if (!cmd_silent
+ && (spats[0].off.line || spats[0].off.end || spats[0].off.off)) {
p = off_buf; // -V507
*p++ = dirc;
if (spats[0].off.end) {
@@ -1165,19 +1202,19 @@ int do_search(
}
if (*searchstr == NUL) {
- p = spats[last_idx].pat;
+ p = spats[0].pat;
} else {
p = searchstr;
}
- if (!shortmess(SHM_SEARCHCOUNT)) {
+ if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) {
// Reserve enough space for the search pattern + offset +
// search stat. Use all the space available, so that the
// search state is right aligned. If there is not enough space
// msg_strtrunc() will shorten in the middle.
if (ui_has(kUIMessages)) {
len = 0; // adjusted below
- } else if (msg_scrolled != 0) {
+ } else if (msg_scrolled != 0 && !cmd_silent) {
// Use all the columns.
len = (Rows - msg_row) * Columns - 1;
} else {
@@ -1194,11 +1231,13 @@ int do_search(
xfree(msgbuf);
msgbuf = xmalloc(len);
- {
- memset(msgbuf, ' ', len);
- msgbuf[0] = dirc;
- msgbuf[len - 1] = NUL;
+ memset(msgbuf, ' ', len);
+ msgbuf[len - 1] = NUL;
+ // do not fill the msgbuf buffer, if cmd_silent is set, leave it
+ // empty for the search_stat feature.
+ if (!cmd_silent) {
+ msgbuf[0] = dirc;
if (utf_iscomposing(utf_ptr2char(p))) {
// Use a space to draw the composing char on.
msgbuf[1] = ' ';
@@ -1342,12 +1381,15 @@ int do_search(
// Show [1/15] if 'S' is not in 'shortmess'.
if ((options & SEARCH_ECHO)
&& messaging()
- && !(cmd_silent + msg_silent)
+ && !msg_silent
&& c != FAIL
&& !shortmess(SHM_SEARCHCOUNT)
&& msgbuf != NULL) {
search_stat(dirc, &pos, show_top_bot_msg, msgbuf,
- (count != 1 || has_offset));
+ (count != 1
+ || has_offset
+ || (!(fdo_flags & FDO_SEARCH)
+ && hasFolding(curwin->w_cursor.lnum, NULL, NULL))));
}
// The search command can be followed by a ';' to do another search.
@@ -1612,8 +1654,9 @@ static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) {
break;
}
- if (*p == ')' && p[delim_len + 1] == '"'
- && STRNCMP(delim_copy, p + 1, delim_len) == 0) {
+ if (*p == ')'
+ && STRNCMP(delim_copy, p + 1, delim_len) == 0
+ && p[delim_len + 1] == '"') {
found = true;
break;
}
@@ -3393,7 +3436,6 @@ current_tagblock(
pos_T start_pos;
pos_T end_pos;
pos_T old_start, old_end;
- char_u *spat, *epat;
char_u *p;
char_u *cp;
int len;
@@ -3447,9 +3489,9 @@ again:
*/
for (long n = 0; n < count; n++) {
if (do_searchpair(
- (char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
- (char_u *)"",
- (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
+ "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ "",
+ "</[^>]*>", BACKWARD, NULL, 0,
NULL, (linenr_T)0, 0L) <= 0) {
curwin->w_cursor = old_pos;
goto theend;
@@ -3471,12 +3513,15 @@ again:
curwin->w_cursor = old_pos;
goto theend;
}
- spat = xmalloc(len + 31);
- epat = xmalloc(len + 9);
- sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
- sprintf((char *)epat, "</%.*s>\\c", len, p);
-
- const int r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
+ const size_t spat_len = len + 39;
+ char *const spat = xmalloc(spat_len);
+ const size_t epat_len = len + 9;
+ char *const epat = xmalloc(epat_len);
+ snprintf(spat, spat_len,
+ "<%.*s\\>\\%%(\\_s\\_[^>]\\{-}\\_[^/]>\\|\\_s\\?>\\)\\c", len, p);
+ snprintf(epat, epat_len, "</%.*s>\\c", len, p);
+
+ const int r = do_searchpair(spat, "", epat, FORWARD, NULL,
0, NULL, (linenr_T)0, 0L);
xfree(spat);
@@ -4054,7 +4099,7 @@ abort_search:
int
current_search(
long count,
- int forward // true for forward, false for backward
+ bool forward // true for forward, false for backward
)
{
bool old_p_ws = p_ws;
@@ -4069,6 +4114,11 @@ current_search(
pos_T pos; // position after the pattern
int result; // result of various function calls
+ // When searching forward and the cursor is at the start of the Visual
+ // area, skip the first search backward, otherwise it doesn't move.
+ const bool skip_first_backward = forward && VIsual_active
+ && lt(curwin->w_cursor, VIsual);
+
orig_pos = pos = curwin->w_cursor;
if (VIsual_active) {
// Searching further will extend the match.
@@ -4086,13 +4136,20 @@ current_search(
return FAIL; // pattern not found
}
- /*
- * The trick is to first search backwards and then search forward again,
- * so that a match at the current cursor position will be correctly
- * captured.
- */
+ // The trick is to first search backwards and then search forward again,
+ // so that a match at the current cursor position will be correctly
+ // captured. When "forward" is false do it the other way around.
for (int i = 0; i < 2; i++) {
- int dir = forward ? i : !i;
+ int dir;
+ if (forward) {
+ if (i == 0 && skip_first_backward) {
+ continue;
+ }
+ dir = i;
+ } else {
+ dir = !i;
+ }
+
int flags = 0;
if (!dir && !zero_width) {
@@ -4139,11 +4196,17 @@ current_search(
VIsual = start_pos;
}
- // put cursor on last character of match
+ // put the cursor after the match
curwin->w_cursor = end_pos;
if (lt(VIsual, end_pos) && forward) {
- dec_cursor();
- } else if (VIsual_active && lt(curwin->w_cursor, VIsual)) {
+ if (skip_first_backward) {
+ // put the cursor on the start of the match
+ curwin->w_cursor = pos;
+ } else {
+ // put the cursor on last character of match
+ dec_cursor();
+ }
+ } else if (VIsual_active && lt(curwin->w_cursor, VIsual) && forward) {
curwin->w_cursor = pos; // put the cursor on the start of the match
}
VIsual_active = true;
@@ -4216,7 +4279,8 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction)
if (nmatched != 0) {
break;
}
- } while (direction == FORWARD
+ } while (regmatch.regprog != NULL
+ && direction == FORWARD
? regmatch.startpos[0].col < pos.col
: regmatch.startpos[0].col > pos.col);
@@ -4335,7 +4399,9 @@ static void search_stat(int dirc, pos_T *pos,
len = STRLEN(t);
if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
- STRCPY(t + len, " W");
+ memmove(t + 2, t, len);
+ t[0] = 'W';
+ t[1] = ' ';
len += 2;
}
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index aa19d1db1f..2444910bb3 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -4148,7 +4148,7 @@ static inline size_t shada_init_jumps(
}
const char *const fname = (char *) (fm.fmark.fnum == 0
? (fm.fname == NULL ? NULL : fm.fname)
- : buf->b_ffname);
+ : buf ? buf->b_ffname : NULL);
if (fname == NULL) {
continue;
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 95948dac78..1984a357c3 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -362,6 +362,8 @@ size_t spell_check(
size_t wrongcaplen = 0;
int lpi;
bool count_word = docount;
+ bool use_camel_case = *wp->w_s->b_p_spo != NUL;
+ bool camel_case = false;
// A word never starts at a space or a control character. Return quickly
// then, skipping over the character.
@@ -394,9 +396,23 @@ size_t spell_check(
mi.mi_word = ptr;
mi.mi_fend = ptr;
if (spell_iswordp(mi.mi_fend, wp)) {
+ bool this_upper = false; // init for gcc
+
+ if (use_camel_case) {
+ c = PTR2CHAR(mi.mi_fend);
+ this_upper = SPELL_ISUPPER(c);
+ }
+
do {
MB_PTR_ADV(mi.mi_fend);
- } while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
+ if (use_camel_case) {
+ const bool prev_upper = this_upper;
+ c = PTR2CHAR(mi.mi_fend);
+ this_upper = SPELL_ISUPPER(c);
+ camel_case = !prev_upper && this_upper;
+ }
+ } while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp)
+ && !camel_case);
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) {
// Check word starting with capital letter.
@@ -428,6 +444,11 @@ size_t spell_check(
(void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1);
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
+ if (camel_case) {
+ // introduce a fake word end space into the folded word.
+ mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
+ }
+
// The word is bad unless we recognize it.
mi.mi_result = SP_BAD;
mi.mi_result2 = SP_BAD;
@@ -4405,8 +4426,6 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
}
break;
- FALLTHROUGH;
-
case STATE_INS:
// Insert one byte. Repeat this for each possible byte at this
// node.
@@ -5663,6 +5682,9 @@ check_suggestions (
int len;
hlf_T attr;
+ if (gap->ga_len == 0) {
+ return;
+ }
stp = &SUG(*gap, 0);
for (int i = gap->ga_len - 1; i >= 0; --i) {
// Need to append what follows to check for "the the".
@@ -5765,14 +5787,14 @@ cleanup_suggestions (
)
FUNC_ATTR_NONNULL_ALL
{
- suggest_T *stp = &SUG(*gap, 0);
-
if (gap->ga_len > 0) {
// Sort the list.
qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare);
// Truncate the list to the number of suggestions that will be displayed.
if (gap->ga_len > keep) {
+ suggest_T *const stp = &SUG(*gap, 0);
+
for (int i = keep; i < gap->ga_len; i++) {
xfree(stp[i].st_word);
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 6b9348e55d..09d8646c6d 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -628,6 +628,7 @@ spell_load_file (
case SP_OTHERERROR: {
emsgf(_("E5042: Failed to read spell file %s: %s"),
fname, strerror(ferror(fd)));
+ goto endFAIL;
}
case 0: {
break;
@@ -983,15 +984,17 @@ nextone:
static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
{
int cnt = 0;
- int i;
char_u *str;
// read the length bytes, MSB first
- for (i = 0; i < cnt_bytes; ++i)
- cnt = (cnt << 8) + getc(fd);
- if (cnt < 0) {
- *cntp = SP_TRUNCERROR;
- return NULL;
+ for (int i = 0; i < cnt_bytes; i++) {
+ const int c = getc(fd);
+
+ if (c == EOF) {
+ *cntp = SP_TRUNCERROR;
+ return NULL;
+ }
+ cnt = (cnt << 8) + (unsigned)c;
}
*cntp = cnt;
if (cnt == 0)
@@ -3037,9 +3040,9 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
spin->si_msg_count = 999999;
// Read and ignore the first line: word count.
- (void)vim_fgets(line, MAXLINELEN, fd);
- if (!ascii_isdigit(*skipwhite(line)))
+ if (vim_fgets(line, MAXLINELEN, fd) || !ascii_isdigit(*skipwhite(line))) {
EMSG2(_("E760: No word count in %s"), fname);
+ }
// Read all the lines in the file one by one.
// The words are converted to 'encoding' here, before being added to
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 4aa7c21ce4..9a9cc45c6b 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -5588,9 +5588,11 @@ void ex_ownsyntax(exarg_T *eap)
hash_init(&curwin->w_s->b_keywtab_ic);
// TODO: Keep the spell checking as it was. NOLINT(readability/todo)
curwin->w_p_spell = false; // No spell checking
+ // make sure option values are "empty_option" instead of NULL
clear_string_option(&curwin->w_s->b_p_spc);
clear_string_option(&curwin->w_s->b_p_spf);
clear_string_option(&curwin->w_s->b_p_spl);
+ clear_string_option(&curwin->w_s->b_p_spo);
clear_string_option(&curwin->w_s->b_syn_isk);
}
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 57a8eb57b8..7f6b7dcfec 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -1,6 +1,54 @@
source shared.vim
source term_util.vim
+" Command to check for the presence of a feature.
+command -nargs=1 CheckFeature call CheckFeature(<f-args>)
+func CheckFeature(name)
+ if !has(a:name)
+ throw 'Skipped: ' .. a:name .. ' feature missing'
+ endif
+endfunc
+
+" Command to check for the presence of a working option.
+command -nargs=1 CheckOption call CheckOption(<f-args>)
+func CheckOption(name)
+ if !exists('+' .. a:name)
+ throw 'Skipped: ' .. a:name .. ' option not supported'
+ endif
+endfunc
+
+" Command to check for the presence of a function.
+command -nargs=1 CheckFunction call CheckFunction(<f-args>)
+func CheckFunction(name)
+ if !exists('*' .. a:name)
+ throw 'Skipped: ' .. a:name .. ' function missing'
+ endif
+endfunc
+
+" Command to check for the presence of python. Argument should have been
+" obtained with PythonProg()
+func CheckPython(name)
+ if a:name == ''
+ throw 'Skipped: python command not available'
+ endif
+endfunc
+
+" Command to check for running on MS-Windows
+command CheckMSWindows call CheckMSWindows()
+func CheckMSWindows()
+ if !has('win32')
+ throw 'Skipped: only works on MS-Windows'
+ endif
+endfunc
+
+" Command to check for running on Unix
+command CheckUnix call CheckUnix()
+func CheckUnix()
+ if !has('unix')
+ throw 'Skipped: only works on Unix'
+ endif
+endfunc
+
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
@@ -9,3 +57,43 @@ func CheckScreendump()
throw 'Skipped: cannot make screendumps'
endif
endfunc
+
+" Command to check that we can Run Vim in a terminal window
+command CheckRunVimInTerminal call CheckRunVimInTerminal()
+func CheckRunVimInTerminal()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run Vim in a terminal window'
+ endif
+endfunc
+
+" Command to check that we can run the GUI
+command CheckCanRunGui call CheckCanRunGui()
+func CheckCanRunGui()
+ if !has('gui') || ($DISPLAY == "" && !has('gui_running'))
+ throw 'Skipped: cannot start the GUI'
+ endif
+endfunc
+
+" Command to check that not currently using the GUI
+command CheckNotGui call CheckNotGui()
+func CheckNotGui()
+ if has('gui_running')
+ throw 'Skipped: only works in the terminal'
+ endif
+endfunc
+
+" Command to check that the current language is English
+command CheckEnglish call CheckEnglish()
+func CheckEnglish()
+ if v:lang != "C" && v:lang !~ '^[Ee]n'
+ throw 'Skipped: only works in English language environment'
+ endif
+endfunc
+
+" Command to check for NOT running on MS-Windows
+command CheckNotMSWindows call CheckNotMSWindows()
+func CheckNotMSWindows()
+ if has('win32')
+ throw 'Skipped: does not work on MS-Windows'
+ endif
+endfunc
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 2bf61b0719..b02514143c 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -7,6 +7,19 @@
" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
" The output can be found in the "messages" file.
"
+" If the environment variable $TEST_FILTER is set then only test functions
+" matching this pattern are executed. E.g. for sh/bash:
+" export TEST_FILTER=Test_channel
+" For csh:
+" setenv TEST_FILTER Test_channel
+"
+" To ignore failure for tests that are known to fail in a certain environment,
+" set $TEST_MAY_FAIL to a comma separated list of function names. E.g. for
+" sh/bash:
+" export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
+" The failure report will then not be included in the test.log file and
+" "make test" will not fail.
+"
" The test script may contain anything, only functions that start with
" "Test_" are special. These will be invoked and should contain assert
" functions. See test_assert.vim for an example.
@@ -65,10 +78,17 @@ set encoding=utf-8
let s:test_script_fname = expand('%')
au! SwapExists * call HandleSwapExists()
func HandleSwapExists()
- " Only ignore finding a swap file for the test script (the user might be
+ if exists('g:ignoreSwapExists')
+ return
+ endif
+ " Ignore finding a swap file for the test script (the user might be
" editing it and do ":make test_name") and the output file.
+ " Report finding another swap file and chose 'q' to avoid getting stuck.
if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
let v:swapchoice = 'e'
+ else
+ call assert_report('Unexpected swap file: ' .. v:swapname)
+ let v:swapchoice = 'q'
endif
endfunc
@@ -84,6 +104,8 @@ let &runtimepath .= ','.expand($BUILD_DIR).'/runtime/'
" Always use forward slashes.
set shellslash
+let s:t_bold = &t_md
+let s:t_normal = &t_me
if has('win32')
" avoid prompt that is long or contains a line break
let $PROMPT = '$P$G'
@@ -136,13 +158,6 @@ func RunTheTest(test)
endtry
endif
- let message = 'Executed ' . a:test
- if has('reltime')
- let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
- endif
- call add(s:messages, message)
- let s:done += 1
-
if a:test =~ 'Test_nocatch_'
" Function handles errors itself. This avoids skipping commands after the
" error.
@@ -196,13 +211,34 @@ func RunTheTest(test)
endwhile
exe 'cd ' . save_cwd
+
+ let message = 'Executed ' . a:test
+ if has('reltime')
+ let message ..= repeat(' ', 50 - len(message))
+ let time = reltime(func_start)
+ if has('float') && reltimefloat(time) > 0.1
+ let message = s:t_bold .. message
+ endif
+ let message ..= ' in ' .. reltimestr(time) .. ' seconds'
+ if has('float') && reltimefloat(time) > 0.1
+ let message ..= s:t_normal
+ endif
+ endif
+ call add(s:messages, message)
+ let s:done += 1
endfunc
-func AfterTheTest()
+func AfterTheTest(func_name)
if len(v:errors) > 0
- let s:fail += 1
- call add(s:errors, 'Found errors in ' . s:test . ':')
- call extend(s:errors, v:errors)
+ if match(s:may_fail_list, '^' .. a:func_name) >= 0
+ let s:fail_expected += 1
+ call add(s:errors_expected, 'Found errors in ' . s:test . ':')
+ call extend(s:errors_expected, v:errors)
+ else
+ let s:fail += 1
+ call add(s:errors, 'Found errors in ' . s:test . ':')
+ call extend(s:errors, v:errors)
+ endif
let v:errors = []
endif
endfunc
@@ -218,7 +254,7 @@ endfunc
" This function can be called by a test if it wants to abort testing.
func FinishTesting()
- call AfterTheTest()
+ call AfterTheTest('')
" Don't write viminfo on exit.
set viminfo=
@@ -226,7 +262,7 @@ func FinishTesting()
" Clean up files created by setup.vim
call delete('XfakeHOME', 'rf')
- if s:fail == 0
+ if s:fail == 0 && s:fail_expected == 0
" Success, create the .res file so that make knows it's done.
exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
write
@@ -242,12 +278,21 @@ func FinishTesting()
endif
if s:done == 0
- let message = 'NO tests executed'
+ if s:filtered > 0
+ let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
+ else
+ let message = 'NO tests executed'
+ endif
else
+ if s:filtered > 0
+ call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
+ endif
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
endif
- if has('reltime')
+ if s:done > 0 && has('reltime')
+ let message = s:t_bold .. message .. repeat(' ', 40 - len(message))
let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
+ let message ..= s:t_normal
endif
echo message
call add(s:messages, message)
@@ -257,6 +302,12 @@ func FinishTesting()
call add(s:messages, message)
call extend(s:messages, s:errors)
endif
+ if s:fail_expected > 0
+ let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
+ echo message
+ call add(s:messages, message)
+ call extend(s:messages, s:errors_expected)
+ endif
" Add SKIPPED messages
call extend(s:messages, s:skipped)
@@ -276,11 +327,13 @@ endfunc
let g:testname = expand('%')
let s:done = 0
let s:fail = 0
+let s:fail_expected = 0
let s:errors = []
+let s:errors_expected = []
let s:messages = []
let s:skipped = []
if expand('%') =~ 'test_vimscript.vim'
- " this test has intentional s:errors, don't use try/catch.
+ " this test has intentional errors, don't use try/catch.
source %
else
try
@@ -311,11 +364,12 @@ let s:flaky_tests = [
\ 'Test_repeat_three()',
\ 'Test_state()',
\ 'Test_stop_all_in_callback()',
- \ 'Test_term_mouse_double_click_to_create_tab',
+ \ 'Test_term_mouse_double_click_to_create_tab()',
\ 'Test_term_mouse_multiple_clicks_to_visually_select()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()',
+ \ 'Test_termwinscroll()',
\ 'Test_with_partial_callback()',
\ ]
@@ -335,8 +389,17 @@ endif
" If the environment variable $TEST_FILTER is set then filter the function
" names against it.
+let s:filtered = 0
if $TEST_FILTER != ''
+ let s:filtered = len(s:tests)
let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
+ let s:filtered -= len(s:tests)
+endif
+
+let s:may_fail_list = []
+if $TEST_MAY_FAIL != ''
+ " Split the list at commas and add () to make it match s:test.
+ let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
endif
" Execute the tests in alphabetical order.
@@ -388,7 +451,7 @@ for s:test in sort(s:tests)
endwhile
endif
- call AfterTheTest()
+ call AfterTheTest(s:test)
endfor
call FinishTesting()
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index 41ff9b2bd6..4f1ddcd7b9 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -56,6 +56,9 @@ endfunc
" Run "cmd". Returns the job if using a job.
func RunCommand(cmd)
+ " Running an external command can occasionally be slow or fail.
+ let g:test_is_flaky = 1
+
let job = 0
if has('job')
let job = job_start(a:cmd, {"stoponexit": "hup"})
@@ -271,7 +274,7 @@ func GetVimCommand(...)
let cmd = cmd . ' -u ' . name
endif
let cmd .= ' --headless -i NONE'
- let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '')
+ let cmd = substitute(cmd, 'VIMRUNTIME=\S\+', '', '')
" If using valgrind, make sure every run uses a different log file.
if cmd =~ 'valgrind.*--log-file='
@@ -294,6 +297,13 @@ func GetVimCommandClean()
return cmd
endfunc
+" Get the command to run Vim, with --clean, and force to run in terminal so it
+" won't start a new GUI.
+func GetVimCommandCleanTerm()
+ " Add -v to have gvim run in the terminal (if possible)
+ return GetVimCommandClean() .. ' -v '
+endfunc
+
" Run Vim, using the "vimcmd" file and "-u NORC".
" "before" is a list of Vim commands to be executed before loading plugins.
" "after" is a list of Vim commands to be executed after loading plugins.
@@ -330,6 +340,16 @@ func RunVimPiped(before, after, arguments, pipecmd)
return 1
endfunc
-func CanRunGui()
- return has('gui') && ($DISPLAY != "" || has('gui_running'))
+" Get all messages but drop the maintainer entry.
+func GetMessages()
+ redir => result
+ redraw | messages
+ redir END
+ let msg_list = split(result, "\n")
+ " if msg_list->len() > 0 && msg_list[0] =~ 'Messages maintainer:'
+ " return msg_list[1:]
+ " endif
+ return msg_list
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/summarize.vim b/src/nvim/testdir/summarize.vim
index 7f8f758a71..da5856a2e7 100644
--- a/src/nvim/testdir/summarize.vim
+++ b/src/nvim/testdir/summarize.vim
@@ -1,3 +1,4 @@
+set cpo&vim
if 1
" This is executed only with the eval feature
set nocompatible
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 5668f45dea..7647475427 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -13,7 +13,6 @@ source test_ex_undo.vim
source test_ex_z.vim
source test_execute_func.vim
source test_expand_func.vim
-source test_expr.vim
source test_feedkeys.vim
source test_filter_cmd.vim
source test_filter_map.vim
@@ -50,6 +49,7 @@ source test_tagjump.vim
source test_taglist.vim
source test_true_false.vim
source test_unlet.vim
+source test_version.vim
source test_virtualedit.vim
source test_window_cmd.vim
source test_wnext.vim
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 6e7583ade3..92fedf9bfb 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -397,9 +397,15 @@ func Test_argdelete()
last
argdelete %
call assert_equal(['b'], argv())
- call assert_fails('argdelete', 'E471:')
+ call assert_fails('argdelete', 'E610:')
call assert_fails('1,100argdelete', 'E16:')
- %argd
+
+ call Reset_arglist()
+ args a b c d
+ next
+ argdel
+ call Assert_argc(['a', 'c', 'd'])
+ %argdel
endfunc
func Test_argdelete_completion()
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index d116246ef3..04a678eeb8 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1,6 +1,8 @@
" Tests for autocommands
source shared.vim
+source check.vim
+source term_util.vim
func! s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
@@ -1125,7 +1127,7 @@ func Test_change_mark_in_autocmds()
write
au! BufWritePre
- if executable('cat')
+ if has('unix')
write XtestFilter
write >> XtestFilter
@@ -1735,6 +1737,35 @@ func Test_throw_in_BufWritePre()
au! throwing
endfunc
+func Test_autocmd_CmdWinEnter()
+ CheckRunVimInTerminal
+ " There is not cmdwin switch, so
+ " test for cmdline_hist
+ " (both are available with small builds)
+ CheckFeature cmdline_hist
+ let lines =<< trim END
+ let b:dummy_var = 'This is a dummy'
+ autocmd CmdWinEnter * quit
+ let winnr = winnr('$')
+ END
+ let filename='XCmdWinEnter'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 6})
+
+ call term_sendkeys(buf, "q:")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":echo b:dummy_var\<cr>")
+ call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, ":echo &buftype\<cr>")
+ call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, ":echo winnr\<cr>")
+ call WaitForAssert({-> assert_match('^1', term_getline(buf, 6))}, 1000)
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(filename)
+endfunc
+
func Test_FileChangedShell_reload()
if !has('unix')
return
@@ -1866,4 +1897,17 @@ func Test_autocmd_FileReadCmd()
delfunc ReadFileCmd
endfunc
+" Tests for SigUSR1 autocmd event, which is only available on posix systems.
+func Test_autocmd_sigusr1()
+ CheckUnix
+
+ let g:sigusr1_passed = 0
+ au Signal SIGUSR1 let g:sigusr1_passed = 1
+ call system('/bin/kill -s usr1 ' . getpid())
+ call WaitForAssert({-> assert_true(g:sigusr1_passed)})
+
+ au! Signal
+ unlet g:sigusr1_passed
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cjk_linebreak.vim b/src/nvim/testdir/test_cjk_linebreak.vim
new file mode 100644
index 0000000000..dfaa8fa1af
--- /dev/null
+++ b/src/nvim/testdir/test_cjk_linebreak.vim
@@ -0,0 +1,97 @@
+scriptencoding utf-8
+
+func Run_cjk_linebreak_after(rigorous)
+ set textwidth=12
+ for punct in [
+ \ '!', '%', ')', ',', ':', ';', '>', '?', ']', '}', 'โ€™', 'โ€', 'โ€ ', 'โ€ก',
+ \ 'โ€ฆ', 'โ€ฐ', 'โ€ฑ', 'โ€ผ', 'โ‡', 'โˆ', 'โ‰', 'โ„ƒ', 'โ„‰', 'ใ€', 'ใ€‚', 'ใ€‰', 'ใ€‹',
+ \ 'ใ€', 'ใ€', 'ใ€‘', 'ใ€•', 'ใ€—', 'ใ€™', 'ใ€›', '๏ผ', '๏ผ‰', '๏ผŒ', '๏ผŽ', '๏ผš',
+ \ '๏ผ›', '๏ผŸ', '๏ผฝ', '๏ฝ']
+ call setline('.', '่ฟ™ๆ˜ฏไธ€ไธชๆต‹่ฏ•' .. punct.'่ฏ•่ฏ• CJK ่กŒ็ฆๅˆ™่กฅไธใ€‚')
+ normal gqq
+ if a:rigorous
+ call assert_equal('่ฟ™ๆ˜ฏไธ€ไธชๆต‹', getline(1))
+ else
+ call assert_equal('่ฟ™ๆ˜ฏไธ€ไธชๆต‹่ฏ•' .. punct, getline(1))
+ endif
+ %d_
+ endfor
+endfunc
+
+func Test_cjk_linebreak_after()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_after(0)
+endfunc
+
+func Test_cjk_linebreak_after_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_after(1)
+endfunc
+
+func Run_cjk_linebreak_before()
+ set textwidth=12
+ for punct in [
+ \ '(', '<', '[', '`', '{', 'โ€˜', 'โ€œ', 'ใ€ˆ', 'ใ€Š', 'ใ€Œ', 'ใ€Ž', 'ใ€', 'ใ€”',
+ \ 'ใ€–', 'ใ€˜', 'ใ€š', '๏ผˆ', '๏ผป', '๏ฝ›']
+ call setline('.', '่ฟ™ๆ˜ฏไธชๆต‹่ฏ•' .. punct.'่ฏ•่ฏ• CJK ่กŒ็ฆๅˆ™่กฅไธใ€‚')
+ normal gqq
+ call assert_equal('่ฟ™ๆ˜ฏไธชๆต‹่ฏ•', getline(1))
+ %d_
+ endfor
+endfunc
+
+func Test_cjk_linebreak_before()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_before()
+endfunc
+
+func Test_cjk_linebreak_before_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_before()
+endfunc
+
+func Run_cjk_linebreak_nobetween(rigorous)
+ " โ€ฆโ€ฆ must not start a line
+ call setline('.', '่ฟ™ๆ˜ฏไธชๆต‹่ฏ•โ€ฆโ€ฆ่ฏ•่ฏ• CJK ่กŒ็ฆๅˆ™่กฅไธใ€‚')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ if a:rigorous
+ call assert_equal('่ฟ™ๆ˜ฏไธชๆต‹', getline(1))
+ else
+ call assert_equal('่ฟ™ๆ˜ฏไธชๆต‹่ฏ•โ€ฆโ€ฆ', getline(1))
+ endif
+ %d_
+
+ call setline('.', '่ฟ™ๆ˜ฏไธ€ไธชๆต‹่ฏ•โ€ฆโ€ฆ่ฏ•่ฏ• CJK ่กŒ็ฆๅˆ™่กฅไธใ€‚')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ call assert_equal('่ฟ™ๆ˜ฏไธ€ไธชๆต‹', getline(1))
+ %d_
+
+ " but โ€”โ€” can
+ call setline('.', '่ฟ™ๆ˜ฏไธชๆต‹่ฏ•โ€”โ€”่ฏ•่ฏ• CJK ่กŒ็ฆๅˆ™่กฅไธใ€‚')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ call assert_equal('่ฟ™ๆ˜ฏไธชๆต‹่ฏ•', getline(1))
+endfunc
+
+func Test_cjk_linebreak_nobetween()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_nobetween(0)
+endfunc
+
+func Test_cjk_linebreak_nobetween_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_nobetween(1)
+endfunc
+
+func Test_cjk_linebreak_join_punct()
+ for punct in ['โ€”โ€”', 'ใ€—', '๏ผŒ', 'ใ€‚', 'โ€ฆโ€ฆ']
+ call setline(1, 'ๆ–‡ๆœฌๆ–‡ๆœฌ' .. punct)
+ call setline(2, 'English')
+ set formatoptions=croqn2mB1j
+ normal ggJ
+ call assert_equal('ๆ–‡ๆœฌๆ–‡ๆœฌ' .. punct.'English', getline(1))
+ %d_
+ endfor
+endfunc
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index f8d84f1a49..871143699a 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1,5 +1,8 @@
" Tests for editing the command line.
+source check.vim
+source screendump.vim
+
func Test_complete_tab()
call writefile(['testfile'], 'Xtestfile')
call feedkeys(":e Xtestf\t\r", "tx")
@@ -718,6 +721,27 @@ func Test_verbosefile()
call delete('Xlog')
endfunc
+func Test_verbose_option()
+ " See test/functional/ui/cmdline_spec.lua
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
+ call feedkeys("\r", 't') " for the hit-enter prompt
+ set verbose=20
+ [SCRIPT]
+ call writefile(lines, 'XTest_verbose')
+
+ let buf = RunVimInTerminal('-S XTest_verbose', {'rows': 12})
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, ":DoSomething\<CR>")
+ call VerifyScreenDump(buf, 'Test_verbose_option_1', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_verbose')
+endfunc
+
func Test_setcmdpos()
func InsertTextAtPos(text, pos)
call assert_equal(0, setcmdpos(a:pos))
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index 6bb602717f..9101f8cfa0 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -42,12 +42,12 @@ func Test_compiler_without_arg()
let a = split(execute('compiler'))
call assert_match(runtime .. '/compiler/ant.vim$', a[0])
call assert_match(runtime .. '/compiler/bcc.vim$', a[1])
- call assert_match(runtime .. '/compiler/xmlwf.vim$', a[-1])
+ call assert_match(runtime .. '/compiler/xo.vim$', a[-1])
endfunc
func Test_compiler_completion()
call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^"compiler ant bcc .* xmlwf$', @:)
+ call assert_match('^"compiler ant bcc .* xmlwf xo$', @:)
call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"compiler pbx perl php pylint pyunit', @:)
diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim
index eaf200e9bb..fc7ea71f6e 100644
--- a/src/nvim/testdir/test_const.vim
+++ b/src/nvim/testdir/test_const.vim
@@ -36,6 +36,7 @@ func Test_define_var_with_lock()
call assert_fails('let s = "vim"', 'E741:')
call assert_fails('let F = funcref("s:noop")', 'E741:')
call assert_fails('let l = [1, 2, 3]', 'E741:')
+ call assert_fails('call filter(l, "v:val % 2 == 0")', 'E741:')
call assert_fails('let d = {"foo": 10}', 'E741:')
if has('channel')
call assert_fails('let j = test_null_job()', 'E741:')
@@ -247,11 +248,14 @@ func Test_lock_depth_is_1()
const l = [1, 2, 3]
const d = {'foo': 10}
- " Modify list
- call add(l, 4)
+ " Modify list - setting item is OK, adding/removing items not
let l[0] = 42
+ call assert_fails('call add(l, 4)', 'E741:')
+ call assert_fails('unlet l[1]', 'E741:')
- " Modify dict
- let d['bar'] = 'hello'
+ " Modify dict - changing item is OK, adding/removing items not
+ let d['foo'] = 'hello'
let d.foo = 44
+ call assert_fails("let d['bar'] = 'hello'", 'E741:')
+ call assert_fails("unlet d['foo']", 'E741:')
endfunc
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index 811717208e..59d51b855b 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -316,3 +316,128 @@ func Test_Debugger()
call delete('Xtest.vim')
endfunc
+
+" Test for setting a breakpoint on a :endif where the :if condition is false
+" and then quit the script. This should generate an interrupt.
+func Test_breakpt_endif_intr()
+ func F()
+ let g:Xpath ..= 'a'
+ if v:false
+ let g:Xpath ..= 'b'
+ endif
+ invalid_command
+ endfunc
+
+ let g:Xpath = ''
+ breakadd func 4 F
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":call F()\<CR>quit\<CR>", "xt")
+ call F()
+ catch /^Vim:Interrupt$/
+ call assert_match('\.F, line 4', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ delfunc F
+endfunc
+
+" Test for setting a breakpoint on a :else where the :if condition is false
+" and then quit the script. This should generate an interrupt.
+func Test_breakpt_else_intr()
+ func F()
+ let g:Xpath ..= 'a'
+ if v:false
+ let g:Xpath ..= 'b'
+ else
+ invalid_command
+ endif
+ invalid_command
+ endfunc
+
+ let g:Xpath = ''
+ breakadd func 4 F
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":call F()\<CR>quit\<CR>", "xt")
+ call F()
+ catch /^Vim:Interrupt$/
+ call assert_match('\.F, line 4', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ delfunc F
+endfunc
+
+" Test for setting a breakpoint on a :endwhile where the :while condition is
+" false and then quit the script. This should generate an interrupt.
+func Test_breakpt_endwhile_intr()
+ func F()
+ let g:Xpath ..= 'a'
+ while v:false
+ let g:Xpath ..= 'b'
+ endwhile
+ invalid_command
+ endfunc
+
+ let g:Xpath = ''
+ breakadd func 4 F
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":call F()\<CR>quit\<CR>", "xt")
+ call F()
+ catch /^Vim:Interrupt$/
+ call assert_match('\.F, line 4', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ delfunc F
+endfunc
+
+" Test for setting a breakpoint on an :endtry where an exception is pending to
+" be processed and then quit the script. This should generate an interrupt and
+" the thrown exception should be ignored.
+func Test_breakpt_endtry_intr()
+ func F()
+ try
+ let g:Xpath ..= 'a'
+ throw "abc"
+ endtry
+ invalid_command
+ endfunc
+
+ let g:Xpath = ''
+ breakadd func 4 F
+ try
+ let caught_intr = 0
+ let caught_abc = 0
+ debuggreedy
+ call feedkeys(":call F()\<CR>quit\<CR>", "xt")
+ call F()
+ catch /abc/
+ let caught_abc = 1
+ catch /^Vim:Interrupt$/
+ call assert_match('\.F, line 4', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal(0, caught_abc)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ delfunc F
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index a1f1dd3bab..f09a64c329 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -724,10 +724,140 @@ func Test_diff_lastline()
bwipe!
endfunc
+func Test_diff_screen()
+ CheckScreendump
+ CheckFeature menu
+
+ " clean up already existing swap files, just in case
+ call delete('.Xfile1.swp')
+ call delete('.Xfile2.swp')
+
+ " Test 1: Add a line in beginning of file 2
+ call WriteDiffFiles(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ let buf = RunVimInTerminal('-d Xfile1 Xfile2', {})
+ " Set autoread mode, so that Vim won't complain once we re-write the test
+ " files
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ call VerifyBoth(buf, 'Test_diff_01', '')
+
+ " Test 2: Add a line in beginning of file 1
+ call WriteDiffFiles(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_02', '')
+
+ " Test 3: Add a line at the end of file 2
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+ call VerifyBoth(buf, 'Test_diff_03', '')
+
+ " Test 4: Add a line at the end of file 1
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_04', '')
+
+ " Test 5: Add a line in the middle of file 2, remove on at the end of file 1
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_05', '')
+
+ " Test 6: Add a line in the middle of file 1, remove on at the end of file 2
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+ call VerifyBoth(buf, 'Test_diff_06', '')
+
+ " Variants on test 6 with different context settings
+ call term_sendkeys(buf, ":set diffopt+=context:2\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_06.2', {})
+ call term_sendkeys(buf, ":set diffopt-=context:2\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=context:1\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_06.1', {})
+ call term_sendkeys(buf, ":set diffopt-=context:1\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=context:0\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_06.0', {})
+ call term_sendkeys(buf, ":set diffopt-=context:0\<cr>")
+
+ " Test 7 - 9: Test normal/patience/histogram diff algorithm
+ call WriteDiffFiles(buf, ['#include <stdio.h>', '', '// Frobs foo heartily', 'int frobnitz(int foo)', '{',
+ \ ' int i;', ' for(i = 0; i < 10; i++)', ' {', ' printf("Your answer is: ");',
+ \ ' printf("%d\n", foo);', ' }', '}', '', 'int fact(int n)', '{', ' if(n > 1)', ' {',
+ \ ' return fact(n-1) * n;', ' }', ' return 1;', '}', '', 'int main(int argc, char **argv)',
+ \ '{', ' frobnitz(fact(10));', '}'],
+ \ ['#include <stdio.h>', '', 'int fib(int n)', '{', ' if(n > 2)', ' {',
+ \ ' return fib(n-1) + fib(n-2);', ' }', ' return 1;', '}', '', '// Frobs foo heartily',
+ \ 'int frobnitz(int foo)', '{', ' int i;', ' for(i = 0; i < 10; i++)', ' {',
+ \ ' printf("%d\n", foo);', ' }', '}', '',
+ \ 'int main(int argc, char **argv)', '{', ' frobnitz(fib(10));', '}'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_07', {})
+
+ call term_sendkeys(buf, ":set diffopt+=algorithm:patience\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_08', {})
+
+ call term_sendkeys(buf, ":set diffopt+=algorithm:histogram\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_09', {})
+
+ " Test 10-11: normal/indent-heuristic
+ call term_sendkeys(buf, ":set diffopt&vim\<cr>")
+ call WriteDiffFiles(buf, ['', ' def finalize(values)', '', ' values.each do |v|', ' v.finalize', ' end'],
+ \ ['', ' def finalize(values)', '', ' values.each do |v|', ' v.prepare', ' end', '',
+ \ ' values.each do |v|', ' v.finalize', ' end'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_10', {})
+
+ " Leave trailing : at commandline!
+ call term_sendkeys(buf, ":set diffopt+=indent-heuristic\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'one')
+ " shouldn't matter, if indent-algorithm comes before or after the algorithm
+ call term_sendkeys(buf, ":set diffopt&\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=indent-heuristic,algorithm:patience\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'two')
+ call term_sendkeys(buf, ":set diffopt&\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=algorithm:patience,indent-heuristic\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'three')
+
+ " Test 12: diff the same file
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_12', '')
+
+ " Test 13: diff an empty file
+ call WriteDiffFiles(buf, [], [])
+ call VerifyBoth(buf, 'Test_diff_13', '')
+
+ " Test 14: test diffopt+=icase
+ call WriteDiffFiles(buf, ['a', 'b', 'cd'], ['A', 'b', 'cDe'])
+ call VerifyBoth(buf, 'Test_diff_14', " diffopt+=filler diffopt+=icase")
+
+ " Test 15-16: test diffopt+=iwhite
+ call WriteDiffFiles(buf, ['int main()', '{', ' printf("Hello, World!");', ' return 0;', '}'],
+ \ ['int main()', '{', ' if (0)', ' {', ' printf("Hello, World!");', ' return 0;', ' }', '}'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt&vim diffopt+=filler diffopt+=iwhite\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_15', {})
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_16', {})
+
+ " Test 17: test diffopt+=iblank
+ call WriteDiffFiles(buf, ['a', ' ', 'cd', 'ef', 'xxx'], ['a', 'cd', '', 'ef', 'yyy'])
+ call VerifyInternal(buf, 'Test_diff_17', " diffopt+=iblank")
+
+ " Test 18: test diffopt+=iblank,iwhite / iwhiteall / iwhiteeol
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhite")
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhiteall")
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhiteeol")
+
+ " Test 19: test diffopt+=iwhiteeol
+ call WriteDiffFiles(buf, ['a ', 'x', 'cd', 'ef', 'xx xx', 'foo', 'bar'], ['a', 'x', 'c d', ' ef', 'xx xx', 'foo', '', 'bar'])
+ call VerifyInternal(buf, 'Test_diff_19', " diffopt+=iwhiteeol")
+
+ " Test 19: test diffopt+=iwhiteall
+ call VerifyInternal(buf, 'Test_diff_20', " diffopt+=iwhiteall")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunc
+
func Test_diff_with_cursorline()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
+ CheckScreendump
call writefile([
\ 'hi CursorLine ctermbg=red ctermfg=white',
@@ -751,13 +881,45 @@ func Test_diff_with_cursorline()
call delete('Xtest_diff_cursorline')
endfunc
+func Test_diff_with_syntax()
+ CheckScreendump
+
+ let lines =<< trim END
+ void doNothing() {
+ int x = 0;
+ char *s = "hello";
+ return 5;
+ }
+ END
+ call writefile(lines, 'Xprogram1.c')
+ let lines =<< trim END
+ void doSomething() {
+ int x = 0;
+ char *s = "there";
+ return 5;
+ }
+ END
+ call writefile(lines, 'Xprogram2.c')
+
+ let lines =<< trim END
+ edit Xprogram1.c
+ diffsplit Xprogram2.c
+ END
+ call writefile(lines, 'Xtest_diff_syntax')
+ let buf = RunVimInTerminal('-S Xtest_diff_syntax', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_syntax_1', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_syntax')
+ call delete('Xprogram1.c')
+ call delete('Xprogram2.c')
+endfunc
+
func Test_diff_of_diff()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
- if !has("rightleft")
- throw 'Skipped: rightleft not supported'
- endif
+ CheckScreendump
+ CheckFeature rightleft
call writefile([
\ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])',
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 1c2f5a05ff..c702b44b88 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -6,11 +6,12 @@
" endif
source view_util.vim
+source check.vim
+source screendump.vim
+
+func Test_display_foldcolumn()
+ CheckFeature folding
-func! Test_display_foldcolumn()
- if !has("folding")
- return
- endif
new
vnew
vert resize 25
@@ -26,10 +27,10 @@ func! Test_display_foldcolumn()
call cursor(2, 1)
norm! zt
- let lines=ScreenLines([1,2], winwidth(0))
+ let lines = ScreenLines([1,2], winwidth(0))
call assert_equal(expect, lines)
set fdc=2
- let lines=ScreenLines([1,2], winwidth(0))
+ let lines = ScreenLines([1,2], winwidth(0))
let expect = [
\ " e more noise blah blah<",
\ " 82> more stuff here "
@@ -41,9 +42,8 @@ func! Test_display_foldcolumn()
endfunc
func! Test_display_foldtext_mbyte()
- if !has("folding")
- return
- endif
+ CheckFeature folding
+
call NewWindow(10, 40)
call append(0, range(1,20))
exe "set foldmethod=manual foldtext=foldtext() fillchars=fold:\u2500,vert:\u2502 fdc=2"
@@ -70,6 +70,42 @@ func! Test_display_foldtext_mbyte()
bw!
endfunc
+" check that win_ins_lines() and win_del_lines() work when t_cs is empty.
+func Test_scroll_without_region()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, range(1, 20))
+ set t_cs=
+ set laststatus=2
+ END
+ call writefile(lines, 'Xtestscroll')
+ let buf = RunVimInTerminal('-S Xtestscroll', #{rows: 10})
+
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_1', {})
+
+ call term_sendkeys(buf, ":3delete\<cr>")
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_2', {})
+
+ call term_sendkeys(buf, ":4put\<cr>")
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_3', {})
+
+ call term_sendkeys(buf, ":undo\<cr>")
+ call term_sendkeys(buf, ":undo\<cr>")
+ call term_sendkeys(buf, ":set laststatus=0\<cr>")
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_4', {})
+
+ call term_sendkeys(buf, ":3delete\<cr>")
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_5', {})
+
+ call term_sendkeys(buf, ":4put\<cr>")
+ call VerifyScreenDump(buf, 'Test_scroll_no_region_6', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtestscroll')
+endfunc
+
func Test_display_listchars_precedes()
set fillchars+=vert:\|
call NewWindow(10, 10)
@@ -125,3 +161,104 @@ func Test_display_listchars_precedes()
set list& listchars& wrap&
bw!
endfunc
+
+" Check that win_lines() works correctly with the number_only parameter=TRUE
+" should break early to optimize cost of drawing, but needs to make sure
+" that the number column is correctly highlighted.
+func Test_scroll_CursorLineNr_update()
+ CheckScreendump
+
+ let lines =<< trim END
+ hi CursorLineNr ctermfg=73 ctermbg=236
+ set nu rnu cursorline cursorlineopt=number
+ exe ":norm! o\<esc>110ia\<esc>"
+ END
+ let filename = 'Xdrawscreen'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 5, cols: 50})
+ call term_sendkeys(buf, "k")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_winline_rnu', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(filename)
+endfunc
+
+" check a long file name does not result in the hit-enter prompt
+func Test_edit_long_file_name()
+ CheckScreendump
+
+ let longName = 'x'->repeat(min([&columns, 255]))
+ call writefile([], longName)
+ let buf = RunVimInTerminal('-N -u NONE ' .. longName, #{rows: 8})
+
+ call VerifyScreenDump(buf, 'Test_long_file_name_1', {})
+
+ call term_sendkeys(buf, ":q\<cr>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(longName)
+endfunc
+
+func Test_unprintable_fileformats()
+ CheckScreendump
+
+ call writefile(["unix\r", "two"], 'Xunix.txt')
+ call writefile(["mac\r", "two"], 'Xmac.txt')
+ let lines =<< trim END
+ edit Xunix.txt
+ split Xmac.txt
+ edit ++ff=mac
+ END
+ let filename = 'Xunprintable'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 9, cols: 50})
+ call VerifyScreenDump(buf, 'Test_display_unprintable_01', {})
+ call term_sendkeys(buf, "\<C-W>\<C-W>\<C-L>")
+ call VerifyScreenDump(buf, 'Test_display_unprintable_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xunix.txt')
+ call delete('Xmac.txt')
+ call delete(filename)
+endfunc
+
+" Test for scrolling that modifies buffer during visual block
+func Test_visual_block_scroll()
+ " See test/functional/legacy/visual_mode_spec.lua
+ CheckScreendump
+
+ let lines =<< trim END
+ source $VIMRUNTIME/plugin/matchparen.vim
+ set scrolloff=1
+ call setline(1, ['a', 'b', 'c', 'd', 'e', '', '{', '}', '{', 'f', 'g', '}'])
+ call cursor(5, 1)
+ END
+
+ let filename = 'Xvisualblockmodifiedscroll'
+ call writefile(lines, filename)
+
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 7})
+ call term_sendkeys(buf, "V\<C-D>\<C-D>")
+
+ call VerifyScreenDump(buf, 'Test_display_visual_block_scroll', {})
+
+ call StopVimInTerminal(buf)
+ call delete(filename)
+endfunc
+
+func Test_display_scroll_at_topline()
+ " See test/functional/legacy/display_spec.lua
+ CheckScreendump
+
+ let buf = RunVimInTerminal('', #{cols: 20})
+ call term_sendkeys(buf, ":call setline(1, repeat('a', 21))\<CR>")
+ call term_wait(buf)
+ call term_sendkeys(buf, "O\<Esc>")
+ call VerifyScreenDump(buf, 'Test_display_scroll_at_topline', #{rows: 4})
+
+ call StopVimInTerminal(buf)
+endfunc
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 12d5d9790e..15c718b243 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1,9 +1,11 @@
" Test for edit functions
-"
+
if exists("+t_kD")
let &t_kD="[3;*~"
endif
+source check.vim
+
" Needed for testing basic rightleft: Test_edit_rightleft
source view_util.vim
@@ -733,17 +735,16 @@ func! Test_edit_CTRL_O()
endfunc
func! Test_edit_CTRL_R()
- throw 'skipped: Nvim does not support test_override()'
" Insert Register
new
- call test_override("ALL", 1)
+ " call test_override("ALL", 1)
set showcmd
call feedkeys("AFOOBAR eins zwei\<esc>", 'tnix')
call feedkeys("O\<c-r>.", 'tnix')
call feedkeys("O\<c-r>=10*500\<cr>\<esc>", 'tnix')
call feedkeys("O\<c-r>=getreg('=', 1)\<cr>\<esc>", 'tnix')
call assert_equal(["getreg('=', 1)", '5000', "FOOBAR eins zwei", "FOOBAR eins zwei"], getline(1, '$'))
- call test_override("ALL", 0)
+ " call test_override("ALL", 0)
set noshowcmd
bw!
endfunc
@@ -955,7 +956,6 @@ func! Test_edit_DROP()
endfunc
func! Test_edit_CTRL_V()
- throw 'skipped: Nvim does not support test_override()'
if has("ebcdic")
return
endif
@@ -965,7 +965,7 @@ func! Test_edit_CTRL_V()
" force some redraws
set showmode showcmd
"call test_override_char_avail(1)
- call test_override('ALL', 1)
+ " call test_override('ALL', 1)
call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
@@ -978,7 +978,7 @@ func! Test_edit_CTRL_V()
set norl
endif
- call test_override('ALL', 0)
+ " call test_override('ALL', 0)
set noshowmode showcmd
bw!
endfunc
@@ -1441,31 +1441,40 @@ endfunc
func Test_edit_InsertLeave()
new
+ au InsertLeavePre * let g:did_au_pre = 1
au InsertLeave * let g:did_au = 1
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("afoo\<Esc>", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(1, g:did_au)
call assert_equal('foo', getline(1))
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Sbar\<C-C>", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(0, g:did_au)
call assert_equal('bar', getline(1))
inoremap x xx<Esc>
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Saax", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(1, g:did_au)
call assert_equal('aaxx', getline(1))
inoremap x xx<C-C>
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Sbbx", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(0, g:did_au)
call assert_equal('bbxx', getline(1))
bwipe!
- au! InsertLeave
+ au! InsertLeave InsertLeavePre
iunmap x
endfunc
@@ -1514,3 +1523,68 @@ func Test_edit_startinsert()
set backspace&
bwipe!
endfunc
+
+func Test_edit_noesckeys()
+ CheckNotGui
+ new
+
+ " <Left> moves cursor when 'esckeys' is set
+ exe "set t_kl=\<Esc>OD"
+ " set esckeys
+ call feedkeys("axyz\<Esc>ODX", "xt")
+ " call assert_equal("xyXz", getline(1))
+
+ " <Left> exits Insert mode when 'esckeys' is off
+ " set noesckeys
+ call setline(1, '')
+ call feedkeys("axyz\<Esc>ODX", "xt")
+ call assert_equal(["DX", "xyz"], getline(1, 2))
+
+ bwipe!
+ " set esckeys
+endfunc
+
+" Test for editing a directory
+func Test_edit_is_a_directory()
+ CheckEnglish
+ let dirname = getcwd() . "/Xdir"
+ call mkdir(dirname, 'p')
+
+ new
+ redir => msg
+ exe 'edit' dirname
+ redir END
+ call assert_match("is a directory$", split(msg, "\n")[0])
+ bwipe!
+
+ let dirname .= '/'
+
+ new
+ redir => msg
+ exe 'edit' dirname
+ redir END
+ call assert_match("is a directory$", split(msg, "\n")[0])
+ bwipe!
+
+ call delete(dirname, 'rf')
+endfunc
+
+func Test_edit_browse()
+ " in the GUI this opens a file picker, we only test the terminal behavior
+ CheckNotGui
+
+ " ":browse xxx" checks for the FileExplorer augroup and assumes editing "."
+ " works then.
+ augroup FileExplorer
+ au!
+ augroup END
+
+ " When the USE_FNAME_CASE is defined this used to cause a crash.
+ browse enew
+ bwipe!
+
+ browse split
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_environ.vim b/src/nvim/testdir/test_environ.vim
index 21bb09a690..a25d83753c 100644
--- a/src/nvim/testdir/test_environ.vim
+++ b/src/nvim/testdir/test_environ.vim
@@ -1,5 +1,9 @@
+" Test for environment variables.
+
scriptencoding utf-8
+source check.vim
+
func Test_environ()
unlet! $TESTENV
call assert_equal(0, has_key(environ(), 'TESTENV'))
@@ -42,3 +46,24 @@ func Test_external_env()
endif
call assert_equal('', result)
endfunc
+
+func Test_mac_locale()
+ CheckFeature osxdarwin
+
+ " If $LANG is not set then the system locale will be used.
+ " Run Vim after unsetting all the locale environmental vars, and capture the
+ " output of :lang.
+ let lang_results = system("unset LANG; unset LC_MESSAGES; " ..
+ \ shellescape(v:progpath) ..
+ \ " --clean -esX -c 'redir @a' -c 'lang' -c 'put a' -c 'print' -c 'qa!' ")
+
+ " Check that:
+ " 1. The locale is the form of <locale>.UTF-8.
+ " 2. Check that fourth item (LC_NUMERIC) is properly set to "C".
+ " Example match: "en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8"
+ call assert_match('"\([a-zA-Z_]\+\.UTF-8/\)\{3}C\(/[a-zA-Z_]\+\.UTF-8\)\{2}"',
+ \ lang_results,
+ \ "Default locale should have UTF-8 encoding set, and LC_NUMERIC set to 'C'")
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 4b54a0d39f..061364fb73 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -108,3 +108,27 @@ func Test_skip_after_throw()
catch /something/
endtry
endfunc
+
+func Test_curly_assignment()
+ let s:svar = 'svar'
+ let g:gvar = 'gvar'
+ let lname = 'gvar'
+ let gname = 'gvar'
+ let {'s:'.lname} = {'g:'.gname}
+ call assert_equal('gvar', s:gvar)
+ let s:gvar = ''
+ let { 's:'.lname } = { 'g:'.gname }
+ call assert_equal('gvar', s:gvar)
+ let s:gvar = ''
+ let { 's:' . lname } = { 'g:' . gname }
+ call assert_equal('gvar', s:gvar)
+ let s:gvar = ''
+ let { 's:' .. lname } = { 'g:' .. gname }
+ call assert_equal('gvar', s:gvar)
+
+ unlet s:svar
+ unlet s:gvar
+ unlet g:gvar
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim
index fb29c3eb7a..9588d3b89d 100644
--- a/src/nvim/testdir/test_expand_func.vim
+++ b/src/nvim/testdir/test_expand_func.vim
@@ -1,5 +1,7 @@
" Tests for expand()
+source shared.vim
+
let s:sfile = expand('<sfile>')
let s:slnum = str2nr(expand('<slnum>'))
let s:sflnum = str2nr(expand('<sflnum>'))
@@ -16,6 +18,25 @@ func s:expand_sflnum()
return str2nr(expand('<sflnum>'))
endfunc
+" This test depends on the location in the test file, put it first.
+func Test_expand_sflnum()
+ call assert_equal(7, s:sflnum)
+ call assert_equal(24, str2nr(expand('<sflnum>')))
+
+ " Line-continuation
+ call assert_equal(
+ \ 27,
+ \ str2nr(expand('<sflnum>')))
+
+ " Call in script-local function
+ call assert_equal(18, s:expand_sflnum())
+
+ " Call in command
+ command Flnum echo expand('<sflnum>')
+ call assert_equal(36, str2nr(trim(execute('Flnum'))))
+ delcommand Flnum
+endfunc
+
func Test_expand_sfile()
call assert_match('test_expand_func\.vim$', s:sfile)
call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>'))
@@ -30,7 +51,7 @@ func Test_expand_sfile()
endfunc
func Test_expand_slnum()
- call assert_equal(4, s:slnum)
+ call assert_equal(6, s:slnum)
call assert_equal(2, str2nr(expand('<slnum>')))
" Line-continuation
@@ -47,20 +68,14 @@ func Test_expand_slnum()
delcommand Slnum
endfunc
-func Test_expand_sflnum()
- call assert_equal(5, s:sflnum)
- call assert_equal(52, str2nr(expand('<sflnum>')))
-
- " Line-continuation
- call assert_equal(
- \ 55,
- \ str2nr(expand('<sflnum>')))
-
- " Call in script-local function
- call assert_equal(16, s:expand_sflnum())
+func s:sid_test()
+ return 'works'
+endfunc
- " Call in command
- command Flnum echo expand('<sflnum>')
- call assert_equal(64, str2nr(trim(execute('Flnum'))))
- delcommand Flnum
+func Test_expand_SID()
+ let sid = expand('<SID>')
+ execute 'let g:sid_result = ' .. sid .. 'sid_test()'
+ call assert_equal('works', g:sid_result)
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 264d8b000f..b8d6f5aa7d 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -49,6 +49,9 @@ func Test_dict()
let d['a'] = 'aaa'
call assert_equal('none', d[''])
call assert_equal('aaa', d['a'])
+
+ let d[ 'b' ] = 'bbb'
+ call assert_equal('bbb', d[ 'b' ])
endfunc
func Test_strgetchar()
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 2e280417ae..9f79c1b545 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -73,8 +73,9 @@ let s:filename_checks = {
\ 'autoit': ['file.au3'],
\ 'automake': ['GNUmakefile.am'],
\ 'ave': ['file.ave'],
- \ 'awk': ['file.awk'],
+ \ 'awk': ['file.awk', 'file.gawk'],
\ 'b': ['file.mch', 'file.ref', 'file.imp'],
+ \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
\ 'bib': ['file.bib'],
@@ -127,6 +128,7 @@ let s:filename_checks = {
\ 'dart': ['file.dart', 'file.drt'],
\ 'datascript': ['file.ds'],
\ 'dcd': ['file.dcd'],
+ \ 'debchangelog': ['changelog.Debian', 'changelog.dch', 'NEWS.Debian', 'NEWS.dch', '/debian/changelog'],
\ 'debcontrol': ['/debian/control'],
\ 'debsources': ['/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list'],
\ 'def': ['file.def'],
@@ -140,7 +142,7 @@ let s:filename_checks = {
\ 'dnsmasq': ['/etc/dnsmasq.conf'],
\ 'dockerfile': ['Dockerfile', 'file.Dockerfile'],
\ 'dosbatch': ['file.bat', 'file.sys'],
- \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini'],
+ \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5'],
\ 'dot': ['file.dot', 'file.gv'],
\ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe'],
\ 'dsl': ['file.dsl'],
@@ -325,7 +327,7 @@ let s:filename_checks = {
\ 'pamconf': ['/etc/pam.conf'],
\ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment'],
\ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
- \ 'pascal': ['file.pas', 'file.dpr'],
+ \ 'pascal': ['file.pas', 'file.pp', 'file.dpr', 'file.lpr'],
\ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'],
\ 'pccts': ['file.g'],
\ 'pdf': ['file.pdf'],
@@ -454,7 +456,7 @@ let s:filename_checks = {
\ 'texmf': ['texmf.cnf'],
\ 'text': ['file.text', 'README'],
\ 'tf': ['file.tf', '.tfrc', 'tfrc'],
- \ 'tidy': ['.tidyrc', 'tidyrc'],
+ \ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'],
\ 'tilde': ['file.t.html'],
\ 'tli': ['file.tli'],
\ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf'],
@@ -471,6 +473,7 @@ let s:filename_checks = {
\ 'uc': ['file.uc'],
\ 'udevconf': ['/etc/udev/udev.conf'],
\ 'udevperm': ['/etc/udev/permissions.d/file.permissions'],
+ \ 'udevrules': ['/etc/udev/rules.d/file.rules', '/usr/lib/udev/rules.d/file.rules', '/lib/udev/rules.d/file.rules'],
\ 'uil': ['file.uit', 'file.uil'],
\ 'updatedb': ['/etc/updatedb.conf'],
\ 'upstart': ['/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override'],
@@ -525,9 +528,11 @@ let s:filename_checks = {
let s:filename_case_checks = {
\ 'modula2': ['file.DEF', 'file.MOD'],
+ \ 'bzl': ['file.BUILD', 'BUILD'],
\ }
func CheckItems(checks)
+ set noswapfile
for [ft, names] in items(a:checks)
for i in range(0, len(names) - 1)
new
@@ -544,6 +549,7 @@ func CheckItems(checks)
bwipe!
endfor
endfor
+ set swapfile&
endfunc
func Test_filetype_detection()
@@ -596,7 +602,8 @@ let s:script_checks = {
\ 'bc': [['#!/path/bc']],
\ 'sed': [['#!/path/sed']],
\ 'ocaml': [['#!/path/ocaml']],
- \ 'awk': [['#!/path/awk']],
+ \ 'awk': [['#!/path/awk'],
+ \ ['#!/path/gawk']],
\ 'wml': [['#!/path/wml']],
\ 'scheme': [['#!/path/scheme']],
\ 'cfengine': [['#!/path/cfengine']],
diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim
index 1dd3a5b29f..a15567bcf2 100644
--- a/src/nvim/testdir/test_filter_map.vim
+++ b/src/nvim/testdir/test_filter_map.vim
@@ -11,6 +11,7 @@ func Test_filter_map_list_expr_string()
call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], 'v:val * 2'))
call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], 'v:key * 2'))
call assert_equal([9, 9, 9, 9], map([1, 2, 3, 4], 9))
+ call assert_equal([7, 7, 7], map([1, 2, 3], ' 7 '))
endfunc
" dict with expression string
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 51689db9c4..917a5e8eca 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -214,7 +214,7 @@ func Test_strftime()
endif
endfunc
-func Test_resolve()
+func Test_resolve_unix()
if !has('unix')
return
endif
@@ -258,6 +258,8 @@ func Test_resolve()
call assert_equal('Xlink2', resolve('Xlink1'))
call assert_equal('./Xlink2', resolve('./Xlink1'))
call delete('Xlink1')
+
+ call assert_equal('/', resolve('/'))
endfunc
func Test_simplify()
@@ -334,6 +336,10 @@ func Test_strpart()
call assert_equal('lรฉp', strpart('รฉlรฉphant', 2, 4))
call assert_equal('lรฉphant', strpart('รฉlรฉphant', 2))
+
+ call assert_equal('รฉ', strpart('รฉlรฉphant', 0, 1, 1))
+ call assert_equal('รฉp', strpart('รฉlรฉphant', 3, 2, v:true))
+ call assert_equal('oฬ', strpart('coฬmposed', 1, 1, 1))
endfunc
func Test_tolower()
@@ -1079,6 +1085,12 @@ func Test_trim()
call assert_equal("", trim("", ""))
call assert_equal("a", trim("a", ""))
call assert_equal("", trim("", "a"))
+ call assert_equal("vim", trim(" vim ", " ", 0))
+ call assert_equal("vim ", trim(" vim ", " ", 1))
+ call assert_equal(" vim", trim(" vim ", " ", 2))
+ call assert_fails('call trim(" vim ", " ", [])', 'E745:')
+ call assert_fails('call trim(" vim ", " ", -1)', 'E475:')
+ call assert_fails('call trim(" vim ", " ", 3)', 'E475:')
let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
call assert_equal("x", trim(chars . "x" . chars))
@@ -1217,6 +1229,24 @@ func Test_reg_executing_and_recording()
unlet s:reg_stat
endfunc
+func Test_getchar()
+ call feedkeys('a', '')
+ call assert_equal(char2nr('a'), getchar())
+
+ " call test_setmouse(1, 3)
+ " let v:mouse_win = 9
+ " let v:mouse_winid = 9
+ " let v:mouse_lnum = 9
+ " let v:mouse_col = 9
+ " call feedkeys("\<S-LeftMouse>", '')
+ call nvim_input_mouse('left', 'press', 'S', 0, 0, 2)
+ call assert_equal("\<S-LeftMouse>", getchar())
+ call assert_equal(1, v:mouse_win)
+ call assert_equal(win_getid(1), v:mouse_winid)
+ call assert_equal(1, v:mouse_lnum)
+ call assert_equal(3, v:mouse_col)
+endfunc
+
func Test_libcall_libcallnr()
if !has('libcall')
return
@@ -1337,3 +1367,22 @@ func Test_readdir()
call delete('Xdir', 'rf')
endfunc
+
+" Test for the eval() function
+func Test_eval()
+ call assert_fails("call eval('5 a')", 'E488:')
+endfunc
+
+" Test for the nr2char() function
+func Test_nr2char()
+ " set encoding=latin1
+ call assert_equal('@', nr2char(64))
+ set encoding=utf8
+ call assert_equal('a', nr2char(97, 1))
+ call assert_equal('a', nr2char(97, 0))
+
+ call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"'))
+ call assert_equal("\x80\xfc\b\xfd\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index 4a4ffcefa1..ee548037ba 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -1,3 +1,4 @@
+" Test for the gf and gF (goto file) commands
" This is a test if a URL is recognized by "gf", with the cursor before and
" after the "://". Also test ":\\".
@@ -109,7 +110,7 @@ func Test_gf()
endfunc
func Test_gf_visual()
- call writefile([], "Xtest_gf_visual")
+ call writefile(['one', 'two', 'three', 'four'], "Xtest_gf_visual")
new
call setline(1, 'XXXtest_gf_visualXXX')
set hidden
@@ -118,6 +119,30 @@ func Test_gf_visual()
norm! ttvtXgf
call assert_equal('Xtest_gf_visual', bufname('%'))
+ " if multiple lines are selected, then gf should fail
+ call setline(1, ["one", "two"])
+ normal VGgf
+ call assert_equal('Xtest_gf_visual', @%)
+
+ " following line number is used for gF
+ bwipe!
+ new
+ call setline(1, 'XXXtest_gf_visual:3XXX')
+ norm! 0ttvt:gF
+ call assert_equal('Xtest_gf_visual', bufname('%'))
+ call assert_equal(3, getcurpos()[1])
+
+ " line number in visual area is used for file name
+ if has('unix')
+ bwipe!
+ call writefile([], "Xtest_gf_visual:3")
+ new
+ call setline(1, 'XXXtest_gf_visual:3XXX')
+ norm! 0ttvtXgF
+ call assert_equal('Xtest_gf_visual:3', bufname('%'))
+ call delete('Xtest_gf_visual:3')
+ endif
+
bwipe!
call delete('Xtest_gf_visual')
set hidden&
diff --git a/src/nvim/testdir/test_gn.vim b/src/nvim/testdir/test_gn.vim
index d41675be0c..9acec51913 100644
--- a/src/nvim/testdir/test_gn.vim
+++ b/src/nvim/testdir/test_gn.vim
@@ -158,7 +158,32 @@ func Test_gn_command()
set wrapscan&vim
set belloff&vim
-endfu
+endfunc
+
+func Test_gN_repeat()
+ new
+ call setline(1, 'this list is a list with a list of a list.')
+ /list
+ normal $gNgNgNx
+ call assert_equal('list with a list of a list', @")
+ bwipe!
+endfunc
+
+func Test_gN_then_gn()
+ new
+
+ call setline(1, 'this list is a list with a list of a last.')
+ /l.st
+ normal $gNgNgnx
+ call assert_equal('last', @")
+
+ call setline(1, 'this list is a list with a lust of a last.')
+ /l.st
+ normal $gNgNgNgnx
+ call assert_equal('lust of a last', @")
+
+ bwipe!
+endfunc
func Test_gn_multi_line()
new
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 6aa187b17e..00e42733a7 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -596,9 +596,17 @@ endfunc
" This test must come before the Test_cursorline test, as it appears this
" defines the Normal highlighting group anyway.
func Test_1_highlight_Normalgroup_exists()
- " MS-Windows GUI sets the font
- if !has('win32') || !has('gui_running')
- let hlNormal = HighlightArgs('Normal')
+ let hlNormal = HighlightArgs('Normal')
+ if !has('gui_running')
call assert_match('hi Normal\s*clear', hlNormal)
+ elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
+ " expect is DEFAULT_FONT of gui_gtk_x11.c
+ call assert_match('hi Normal\s*font=Monospace 10', hlNormal)
+ elseif has('gui_motif') || has('gui_athena')
+ " expect is DEFAULT_FONT of gui_x11.c
+ call assert_match('hi Normal\s*font=7x13', hlNormal)
+ elseif has('win32')
+ " expect any font
+ call assert_match('hi Normal\s*font=.*', hlNormal)
endif
endfunc
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 1c275d5bd1..57a0a7aaf4 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -1,3 +1,5 @@
+source screendump.vim
+source check.vim
" Test for insert expansion
func Test_ins_complete()
@@ -325,7 +327,10 @@ func Test_compl_in_cmdwin()
set wildmenu wildchar=<Tab>
com! -nargs=1 -complete=command GetInput let input = <q-args>
com! -buffer TestCommand echo 'TestCommand'
+ let w:test_winvar = 'winvar'
+ let b:test_bufvar = 'bufvar'
+ " User-defined commands
let input = ''
call feedkeys("q:iGetInput T\<C-x>\<C-v>\<CR>", 'tx!')
call assert_equal('TestCommand', input)
@@ -334,7 +339,114 @@ func Test_compl_in_cmdwin()
call feedkeys("q::GetInput T\<Tab>\<CR>:q\<CR>", 'tx!')
call assert_equal('T', input)
+ com! -nargs=1 -complete=var GetInput let input = <q-args>
+ " Window-local variables
+ let input = ''
+ call feedkeys("q:iGetInput w:test_\<C-x>\<C-v>\<CR>", 'tx!')
+ call assert_equal('w:test_winvar', input)
+
+ let input = ''
+ call feedkeys("q::GetInput w:test_\<Tab>\<CR>:q\<CR>", 'tx!')
+ call assert_equal('w:test_', input)
+
+ " Buffer-local variables
+ let input = ''
+ call feedkeys("q:iGetInput b:test_\<C-x>\<C-v>\<CR>", 'tx!')
+ call assert_equal('b:test_bufvar', input)
+
+ let input = ''
+ call feedkeys("q::GetInput b:test_\<Tab>\<CR>:q\<CR>", 'tx!')
+ call assert_equal('b:test_', input)
+
delcom TestCommand
delcom GetInput
+ unlet w:test_winvar
+ unlet b:test_bufvar
set wildmenu& wildchar&
endfunc
+
+" Test for insert path completion with completeslash option
+func Test_ins_completeslash()
+ CheckMSWindows
+
+ call mkdir('Xdir')
+
+ let orig_shellslash = &shellslash
+ set cpt&
+
+ new
+
+ set noshellslash
+
+ set completeslash=
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=backslash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=slash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+
+ set shellslash
+
+ set completeslash=
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+
+ set completeslash=backslash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=slash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+ %bw!
+ call delete('Xdir', 'rf')
+
+ set noshellslash
+ set completeslash=slash
+ call assert_true(stridx(globpath(&rtp, 'syntax/*.vim', 1, 1)[0], '\') != -1)
+
+ let &shellslash = orig_shellslash
+ set completeslash=
+endfunc
+
+func Test_issue_7021()
+ CheckMSWindows
+
+ let orig_shellslash = &shellslash
+ set noshellslash
+
+ set completeslash=slash
+ call assert_false(expand('~') =~ '/')
+
+ let &shellslash = orig_shellslash
+ set completeslash=
+endfunc
+
+func Test_pum_with_folds_two_tabs()
+ CheckScreendump
+
+ let lines =<< trim END
+ set fdm=marker
+ call setline(1, ['" x {{{1', '" a some text'])
+ call setline(3, range(&lines)->map({_, val -> '" a' .. val}))
+ norm! zm
+ tab sp
+ call feedkeys('2Gzv', 'xt')
+ call feedkeys("0fa", 'xt')
+ END
+
+ call writefile(lines, 'Xpumscript')
+ let buf = RunVimInTerminal('-S Xpumscript', #{rows: 10})
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "a\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_with_folds_two_tabs', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xpumscript')
+endfunc
diff --git a/src/nvim/testdir/test_interrupt.vim b/src/nvim/testdir/test_interrupt.vim
new file mode 100644
index 0000000000..111752d16a
--- /dev/null
+++ b/src/nvim/testdir/test_interrupt.vim
@@ -0,0 +1,27 @@
+" Test behavior of interrupt()
+
+let s:bufwritepre_called = 0
+let s:bufwritepost_called = 0
+
+func s:bufwritepre()
+ let s:bufwritepre_called = 1
+ call interrupt()
+endfunction
+
+func s:bufwritepost()
+ let s:bufwritepost_called = 1
+endfunction
+
+func Test_interrupt()
+ new Xfile
+ let n = 0
+ try
+ au BufWritePre Xfile call s:bufwritepre()
+ au BufWritePost Xfile call s:bufwritepost()
+ w!
+ catch /^Vim:Interrupt$/
+ endtry
+ call assert_equal(1, s:bufwritepre_called)
+ call assert_equal(0, s:bufwritepost_called)
+ call assert_equal(0, filereadable('Xfile'))
+endfunc
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index bfbb3e5c5b..f026c8a55f 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -181,7 +181,7 @@ function! Test_lambda_scope()
let l:D = s:NewCounter2()
call assert_equal(1, l:C())
- call assert_fails(':call l:D()', 'E15:') " E121: then E15:
+ call assert_fails(':call l:D()', 'E121:')
call assert_equal(2, l:C())
endfunction
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index bea62cb0ad..31a8b48d37 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -280,6 +280,14 @@ func Test_dict_func_remove_in_use()
call assert_equal(expected, d.func(string(remove(d, 'func'))))
endfunc
+func Test_dict_literal_keys()
+ call assert_equal({'one': 1, 'two2': 2, '3three': 3, '44': 4}, #{one: 1, two2: 2, 3three: 3, 44: 4},)
+
+ " why *{} cannot be used
+ let blue = 'blue'
+ call assert_equal('6', trim(execute('echo 2 *{blue: 3}.blue')))
+endfunc
+
" Nasty: deepcopy() dict that refers to itself (fails when noref used)
func Test_dict_deepcopy()
let d = {1:1, 2:2}
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 82562339f6..152afb4b9d 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -391,6 +391,42 @@ func Test_motionforce_omap()
delfunc GetCommand
endfunc
+func Test_error_in_map_expr()
+ if !has('terminal') || (has('win32') && has('gui_running'))
+ throw 'Skipped: cannot run Vim in a terminal window'
+ endif
+
+ let lines =<< trim [CODE]
+ func Func()
+ " fail to create list
+ let x = [
+ endfunc
+ nmap <expr> ! Func()
+ set updatetime=50
+ [CODE]
+ call writefile(lines, 'Xtest.vim')
+
+ let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
+ let job = term_getjob(buf)
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 8))})
+
+ " GC must not run during map-expr processing, which can make Vim crash.
+ call term_sendkeys(buf, '!')
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "\<CR>")
+ call term_wait(buf, 100)
+ call assert_equal('run', job_status(job))
+
+ call term_sendkeys(buf, ":qall!\<CR>")
+ call WaitFor({-> job_status(job) ==# 'dead'})
+ if has('unix')
+ call assert_equal('', job_info(job).termsig)
+ endif
+
+ call delete('Xtest.vim')
+ exe buf .. 'bwipe!'
+endfunc
+
" Test for mapping errors
func Test_map_error()
call assert_fails('unmap', 'E474:')
diff --git a/src/nvim/testdir/test_matchadd_conceal.vim b/src/nvim/testdir/test_matchadd_conceal.vim
index b918525dbc..393e183ddb 100644
--- a/src/nvim/testdir/test_matchadd_conceal.vim
+++ b/src/nvim/testdir/test_matchadd_conceal.vim
@@ -1,9 +1,11 @@
" Test for matchadd() and conceal feature
-if !has('conceal')
- finish
-endif
+
+source check.vim
+CheckFeature conceal
source shared.vim
+source term_util.vim
+source view_util.vim
function! Test_simple_matchadd()
new
@@ -273,3 +275,70 @@ function! Test_matchadd_and_syn_conceal()
call assert_notequal(screenattr(1, 11) , screenattr(1, 12))
call assert_equal(screenattr(1, 11) , screenattr(1, 32))
endfunction
+
+func Test_cursor_column_in_concealed_line_after_window_scroll()
+ CheckRunVimInTerminal
+
+ " Test for issue #5012 fix.
+ " For a concealed line with cursor, there should be no window's cursor
+ " position invalidation during win_update() after scrolling attempt that is
+ " not successful and no real topline change happens. The invalidation would
+ " cause a window's cursor position recalc outside of win_line() where it's
+ " not possible to take conceal into account.
+ let lines =<< trim END
+ 3split
+ let m = matchadd('Conceal', '=')
+ setl conceallevel=2 concealcursor=nc
+ normal gg
+ "==expr==
+ END
+ call writefile(lines, 'Xcolesearch')
+ let buf = RunVimInTerminal('Xcolesearch', {})
+ call term_wait(buf, 100)
+
+ " Jump to something that is beyond the bottom of the window,
+ " so there's a scroll down.
+ call term_sendkeys(buf, ":so %\<CR>")
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "/expr\<CR>")
+ call term_wait(buf, 100)
+
+ " Are the concealed parts of the current line really hidden?
+ let cursor_row = term_scrape(buf, '.')->map({_, e -> e.chars})->join('')
+ call assert_equal('"expr', cursor_row)
+
+ " BugFix check: Is the window's cursor column properly updated for hidden
+ " parts of the current line?
+ call assert_equal(2, term_getcursor(buf)[1])
+
+ call StopVimInTerminal(buf)
+ call delete('Xcolesearch')
+endfunc
+
+func Test_cursor_column_in_concealed_line_after_leftcol_change()
+ CheckRunVimInTerminal
+
+ " Test for issue #5214 fix.
+ let lines =<< trim END
+ 0put = 'ab' .. repeat('-', &columns) .. 'c'
+ call matchadd('Conceal', '-')
+ set nowrap ss=0 cole=3 cocu=n
+ END
+ call writefile(lines, 'Xcurs-columns')
+ let buf = RunVimInTerminal('-S Xcurs-columns', {})
+
+ " Go to the end of the line (3 columns beyond the end of the screen).
+ " Horizontal scroll would center the cursor in the screen line, but conceal
+ " makes it go to screen column 1.
+ call term_sendkeys(buf, "$")
+ call term_wait(buf)
+
+ " Are the concealed parts of the current line really hidden?
+ call WaitForAssert({-> assert_equal('c', term_getline(buf, '.'))})
+
+ " BugFix check: Is the window's cursor column properly updated for conceal?
+ call assert_equal(1, term_getcursor(buf)[1])
+
+ call StopVimInTerminal(buf)
+ call delete('Xcurs-columns')
+endfunc
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 7fbf04311d..ca14494248 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -74,6 +74,7 @@ func Test_echomsg()
call assert_equal("\n12345", execute(':echomsg 12345'))
call assert_equal("\n[]", execute(':echomsg []'))
call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]'))
+ call assert_equal("\n[1, 2, []]", execute(':echomsg [1, 2, v:_null_list]'))
call assert_equal("\n{}", execute(':echomsg {}'))
call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}'))
if has('float')
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 9c9e04be07..3243edbf55 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -9,6 +9,29 @@ endif
source shared.vim
source term_util.vim
+" Test for storing global and local argument list in a session file
+" This one must be done first.
+func Test__mksession_arglocal()
+ enew | only
+ n a b c
+ new
+ arglocal
+ mksession! Xtest_mks.out
+
+ %bwipe!
+ %argdelete
+ argglobal
+ source Xtest_mks.out
+ call assert_equal(2, winnr('$'))
+ call assert_equal(2, arglistid(1))
+ call assert_equal(0, arglistid(2))
+
+ %bwipe!
+ %argdelete
+ argglobal
+ call delete('Xtest_mks.out')
+endfunc
+
func Test_mksession()
tabnew
let wrap_save = &wrap
@@ -155,7 +178,7 @@ endfunc
" Verify that arglist is stored correctly to the session file.
func Test_mksession_arglist()
- argdel *
+ %argdel
next file1 file2 file3 file4
mksession! Xtest_mks.out
source Xtest_mks.out
@@ -307,6 +330,104 @@ func Test_mksession_quote_in_filename()
call delete('Xtest_mks_quoted.out')
endfunc
+" Test for storing global variables in a session file
+func Test_mksession_globals()
+ set sessionoptions+=globals
+
+ " create different global variables
+ let g:Global_string = "Sun is shining"
+ let g:Global_count = 100
+ let g:Global_pi = 3.14
+
+ mksession! Xtest_mks.out
+
+ unlet g:Global_string
+ unlet g:Global_count
+ unlet g:Global_pi
+
+ source Xtest_mks.out
+ call assert_equal("Sun is shining", g:Global_string)
+ call assert_equal(100, g:Global_count)
+ call assert_equal(3.14, g:Global_pi)
+
+ unlet g:Global_string
+ unlet g:Global_count
+ unlet g:Global_pi
+ call delete('Xtest_mks.out')
+ set sessionoptions&
+endfunc
+
+" Test for changing backslash to forward slash in filenames
+func Test_mksession_slash()
+ if exists('+shellslash')
+ throw 'Skipped: cannot use backslash in file name'
+ endif
+ enew
+ %bwipe!
+ e a\\b\\c
+ mksession! Xtest_mks1.out
+ set sessionoptions+=slash
+ mksession! Xtest_mks2.out
+
+ %bwipe!
+ source Xtest_mks1.out
+ call assert_equal('a/b/c', bufname(''))
+ %bwipe!
+ source Xtest_mks2.out
+ call assert_equal('a/b/c', bufname(''))
+
+ %bwipe!
+ call delete('Xtest_mks1.out')
+ call delete('Xtest_mks2.out')
+ set sessionoptions&
+endfunc
+
+" Test for changing directory to the session file directory
+func Test_mksession_sesdir()
+ call mkdir('Xproj')
+ mksession! Xproj/Xtest_mks1.out
+ set sessionoptions-=curdir
+ set sessionoptions+=sesdir
+ mksession! Xproj/Xtest_mks2.out
+
+ source Xproj/Xtest_mks1.out
+ call assert_equal('testdir', fnamemodify(getcwd(), ':t'))
+ source Xproj/Xtest_mks2.out
+ call assert_equal('Xproj', fnamemodify(getcwd(), ':t'))
+ cd ..
+
+ set sessionoptions&
+ call delete('Xproj', 'rf')
+endfunc
+
+" Test for storing the 'lines' and 'columns' settings
+func Test_mksession_resize()
+ mksession! Xtest_mks1.out
+ set sessionoptions+=resize
+ mksession! Xtest_mks2.out
+
+ let lines = readfile('Xtest_mks1.out')
+ let found_resize = v:false
+ for line in lines
+ if line =~ '^set lines='
+ let found_resize = v:true
+ endif
+ endfor
+ call assert_equal(v:false, found_resize)
+ let lines = readfile('Xtest_mks2.out')
+ let found_resize = v:false
+ for line in lines
+ if line =~ '^set lines='
+ let found_resize = v:true
+ endif
+ endfor
+ call assert_equal(v:true, found_resize)
+
+ call delete('Xtest_mks1.out')
+ call delete('Xtest_mks2.out')
+ set sessionoptions&
+endfunc
+
func s:ClearMappings()
mapclear
omapclear
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 04a5c62f66..9e8da74db7 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -576,3 +576,13 @@ func Test_opt_boolean()
set number&
endfunc
+" Test for setting option value containing spaces with isfname+=32
+func Test_isfname_with_options()
+ set isfname+=32
+ setlocal keywordprg=:term\ help.exe
+ call assert_equal(':term help.exe', &keywordprg)
+ set isfname&
+ setlocal keywordprg&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_perl.vim b/src/nvim/testdir/test_perl.vim
new file mode 100644
index 0000000000..872194a804
--- /dev/null
+++ b/src/nvim/testdir/test_perl.vim
@@ -0,0 +1,311 @@
+" Tests for Perl interface
+
+if !has('perl') || has('win32')
+ finish
+endif
+
+" FIXME: RunTest don't see any error when Perl abort...
+perl $SIG{__WARN__} = sub { die "Unexpected warnings from perl: @_" };
+
+func Test_change_buffer()
+ call setline(line('$'), ['1 line 1'])
+ perl VIM::DoCommand("normal /^1\n")
+ perl $curline = VIM::Eval("line('.')")
+ perl $curbuf->Set($curline, "1 changed line 1")
+ call assert_equal('1 changed line 1', getline('$'))
+endfunc
+
+func Test_evaluate_list()
+ call setline(line('$'), ['2 line 2'])
+ perl VIM::DoCommand("normal /^2\n")
+ perl $curline = VIM::Eval("line('.')")
+ let l = ["abc", "def"]
+ perl << EOF
+ $l = VIM::Eval("l");
+ $curbuf->Append($curline, $l);
+EOF
+ normal j
+ .perldo s|\n|/|g
+ " call assert_equal('abc/def/', getline('$'))
+ call assert_equal('def', getline('$'))
+endfunc
+
+funct Test_VIM_Blob()
+ call assert_equal('0z', perleval('VIM::Blob("")'))
+ call assert_equal('0z31326162', perleval('VIM::Blob("12ab")'))
+ call assert_equal('0z00010203', perleval('VIM::Blob("\x00\x01\x02\x03")'))
+ call assert_equal('0z8081FEFF', perleval('VIM::Blob("\x80\x81\xfe\xff")'))
+endfunc
+
+func Test_buffer_Delete()
+ new
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
+ perl $curbuf->Delete(7)
+ perl $curbuf->Delete(2, 5)
+ perl $curbuf->Delete(10)
+ call assert_equal(['a', 'f', 'h'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Append()
+ new
+ perl $curbuf->Append(1, '1')
+ perl $curbuf->Append(2, '2', '3', '4')
+ perl @l = ('5' ..'7')
+ perl $curbuf->Append(0, @l)
+ call assert_equal(['5', '6', '7', '', '1', '2', '3', '4'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Set()
+ new
+ call setline(1, ['1', '2', '3', '4', '5'])
+ perl $curbuf->Set(2, 'a', 'b', 'c')
+ perl $curbuf->Set(4, 'A', 'B', 'C')
+ call assert_equal(['1', 'a', 'b', 'A', 'B'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Get()
+ new
+ call setline(1, ['1', '2', '3', '4'])
+ call assert_equal('2:3', perleval('join(":", $curbuf->Get(2, 3))'))
+ bwipe!
+endfunc
+
+func Test_buffer_Count()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ call assert_equal(3, perleval('$curbuf->Count()'))
+ bwipe!
+endfunc
+
+func Test_buffer_Name()
+ new
+ call assert_equal('', perleval('$curbuf->Name()'))
+ bwipe!
+ new Xfoo
+ call assert_equal('Xfoo', perleval('$curbuf->Name()'))
+ bwipe!
+endfunc
+
+func Test_buffer_Number()
+ call assert_equal(bufnr('%'), perleval('$curbuf->Number()'))
+endfunc
+
+func Test_window_Cursor()
+ new
+ call setline(1, ['line1', 'line2'])
+ perl $curwin->Cursor(2, 3)
+ call assert_equal('2:3', perleval('join(":", $curwin->Cursor())'))
+ " Col is numbered from 0 in Perl, and from 1 in Vim script.
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ bwipe!
+endfunc
+
+func Test_window_SetHeight()
+ new
+ perl $curwin->SetHeight(2)
+ call assert_equal(2, winheight(0))
+ bwipe!
+endfunc
+
+func Test_VIM_Windows()
+ new
+ " VIM::Windows() without argument in scalar and list context.
+ perl $winnr = VIM::Windows()
+ perl @winlist = VIM::Windows()
+ perl $curbuf->Append(0, $winnr, scalar(@winlist))
+ call assert_equal(['2', '2', ''], getline(1, '$'))
+
+ " VIM::Windows() with window number argument.
+ perl (VIM::Windows(VIM::Eval('winnr()')))[0]->Buffer()->Set(1, 'bar')
+ call assert_equal('bar', getline(1))
+ bwipe!
+endfunc
+
+func Test_VIM_Buffers()
+ new Xbar
+ " VIM::Buffers() without argument in scalar and list context.
+ perl $nbuf = VIM::Buffers()
+ perl @buflist = VIM::Buffers()
+
+ " VIM::Buffers() with argument.
+ perl $curbuf = (VIM::Buffers('Xbar'))[0]
+ perl $curbuf->Append(0, $nbuf, scalar(@buflist))
+ call assert_equal(['2', '2', ''], getline(1, '$'))
+ bwipe!
+endfunc
+
+func <SID>catch_peval(expr)
+ try
+ call perleval(a:expr)
+ catch
+ return v:exception
+ endtry
+ call assert_report('no exception for `perleval("'.a:expr.'")`')
+ return ''
+endfunc
+
+func Test_perleval()
+ call assert_false(perleval('undef'))
+
+ " scalar
+ call assert_equal(0, perleval('0'))
+ call assert_equal(2, perleval('2'))
+ call assert_equal(-2, perleval('-2'))
+ if has('float')
+ call assert_equal(2.5, perleval('2.5'))
+ else
+ call assert_equal(2, perleval('2.5'))
+ end
+
+ " sandbox call assert_equal(2, perleval('2'))
+
+ call assert_equal('abc', perleval('"abc"'))
+ " call assert_equal("abc\ndef", perleval('"abc\0def"'))
+
+ " ref
+ call assert_equal([], perleval('[]'))
+ call assert_equal(['word', 42, [42],{}], perleval('["word", 42, [42], {}]'))
+
+ call assert_equal({}, perleval('{}'))
+ call assert_equal({'foo': 'bar'}, perleval('{foo => "bar"}'))
+
+ perl our %h; our @a;
+ let a = perleval('[\(%h, %h, @a, @a)]')
+ " call assert_true((a[0] is a[1]))
+ call assert_equal(a[0], a[1])
+ " call assert_true((a[2] is a[3]))
+ call assert_equal(a[2], a[3])
+ perl undef %h; undef @a;
+
+ " call assert_true(<SID>catch_peval('{"" , 0}') =~ 'Malformed key Dictionary')
+ " call assert_true(<SID>catch_peval('{"\0" , 0}') =~ 'Malformed key Dictionary')
+ " call assert_true(<SID>catch_peval('{"foo\0bar" , 0}') =~ 'Malformed key Dictionary')
+
+ call assert_equal('*VIM', perleval('"*VIM"'))
+ " call assert_true(perleval('\\0') =~ 'SCALAR(0x\x\+)')
+endfunc
+
+func Test_perldo()
+ sp __TEST__
+ exe 'read ' g:testname
+ perldo s/perl/vieux_chameau/g
+ 1
+ call assert_false(search('\Cperl'))
+ bw!
+
+ " Check deleting lines does not trigger ml_get error.
+ new
+ call setline(1, ['one', 'two', 'three'])
+ perldo VIM::DoCommand("%d_")
+ bwipe!
+
+ " Check switching to another buffer does not trigger ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ perldo VIM::DoCommand("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ bwipe!
+ bwipe!
+endfunc
+
+func Test_VIM_package()
+ perl VIM::DoCommand('let l:var = "foo"')
+ call assert_equal(l:var, 'foo')
+
+ set noet
+ perl VIM::SetOption('et')
+ call assert_true(&et)
+endfunc
+
+func Test_stdio()
+ throw 'skipped: TODO: '
+ redir =>l:out
+ perl <<EOF
+ VIM::Msg("&VIM::Msg");
+ print "STDOUT";
+ print STDERR "STDERR";
+EOF
+ redir END
+ call assert_equal(['&VIM::Msg', 'STDOUT', 'STDERR'], split(l:out, "\n"))
+endfunc
+
+" Run first to get a clean namespace
+func Test_000_SvREFCNT()
+ throw 'skipped: TODO: '
+ for i in range(8)
+ exec 'new X'.i
+ endfor
+ new t
+ perl <<--perl
+#line 5 "Test_000_SvREFCNT()"
+ my ($b, $w);
+
+ my $num = 0;
+ for ( 0 .. 100 ) {
+ if ( ++$num >= 8 ) { $num = 0 }
+ VIM::DoCommand("buffer X$num");
+ $b = $curbuf;
+ }
+
+ VIM::DoCommand("buffer t");
+
+ $b = $curbuf for 0 .. 100;
+ $w = $curwin for 0 .. 100;
+ () = VIM::Buffers for 0 .. 100;
+ () = VIM::Windows for 0 .. 100;
+
+ VIM::DoCommand('bw! t');
+ if (exists &Internals::SvREFCNT) {
+ my $cb = Internals::SvREFCNT($$b);
+ my $cw = Internals::SvREFCNT($$w);
+ VIM::Eval("assert_equal(2, $cb, 'T1')");
+ VIM::Eval("assert_equal(2, $cw, 'T2')");
+ my $strongref;
+ foreach ( VIM::Buffers, VIM::Windows ) {
+ VIM::DoCommand("%bw!");
+ my $c = Internals::SvREFCNT($_);
+ VIM::Eval("assert_equal(2, $c, 'T3')");
+ $c = Internals::SvREFCNT($$_);
+ next if $c == 2 && !$strongref++;
+ VIM::Eval("assert_equal(1, $c, 'T4')");
+ }
+ $cb = Internals::SvREFCNT($$curbuf);
+ $cw = Internals::SvREFCNT($$curwin);
+ VIM::Eval("assert_equal(3, $cb, 'T5')");
+ VIM::Eval("assert_equal(3, $cw, 'T6')");
+ }
+ VIM::Eval("assert_false($$b)");
+ VIM::Eval("assert_false($$w)");
+--perl
+ %bw!
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ perldo $curwin->Cursor(1, 5)
+ call assert_equal([1, 6], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 6], [line('.'), col('.')])
+endfunc
+
+" Test for various heredoc syntax
+func Test_perl_heredoc()
+ perl << END
+VIM::DoCommand('let s = "A"')
+END
+ perl <<
+VIM::DoCommand('let s ..= "B"')
+.
+ call assert_equal('AB', s)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index bb0ed6e00c..fb464d95ea 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -2,6 +2,7 @@
source shared.vim
source screendump.vim
+source check.vim
let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
let g:setting = ''
@@ -755,6 +756,52 @@ func Test_popup_and_previewwindow_dump()
call delete('Xscript')
endfunc
+func Test_balloon_split()
+ CheckFunction balloon_split
+
+ call assert_equal([
+ \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
+ \ ], balloon_split(
+ \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
+ call assert_equal([
+ \ 'one two three four one two three four one two thre',
+ \ 'e four',
+ \ ], balloon_split(
+ \ 'one two three four one two three four one two three four'))
+
+ eval 'struct = {one = 1, two = 2, three = 3}'
+ \ ->balloon_split()
+ \ ->assert_equal([
+ \ 'struct = {',
+ \ ' one = 1,',
+ \ ' two = 2,',
+ \ ' three = 3}',
+ \ ])
+
+ call assert_equal([
+ \ 'struct = {',
+ \ ' one = 1,',
+ \ ' nested = {',
+ \ ' n1 = "yes",',
+ \ ' n2 = "no"}',
+ \ ' two = 2}',
+ \ ], balloon_split(
+ \ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
+ call assert_equal([
+ \ 'struct = 0x234 {',
+ \ ' long = 2343 "\\"some long string that will be wr',
+ \ 'apped in two\\"",',
+ \ ' next = 123}',
+ \ ], balloon_split(
+ \ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
+ call assert_equal([
+ \ 'Some comment',
+ \ '',
+ \ 'typedef this that;',
+ \ ], balloon_split(
+ \ "Some comment\n\ntypedef this that;"))
+endfunc
+
func Test_popup_position()
if !CanRunVimInTerminal()
return
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index 884ada7e88..15745d5619 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -22,12 +22,21 @@ endfunc
func Test_put_char_block2()
new
- let a = [ getreg('a'), getregtype('a') ]
call setreg('a', ' one ', 'v')
call setline(1, ['Line 1', '', 'Line 3', ''])
" visually select the first 3 lines and put register a over it
exe "norm! ggl\<c-v>2j2l\"ap"
- call assert_equal(['L one 1', '', 'L one 3', ''], getline(1,4))
+ call assert_equal(['L one 1', '', 'L one 3', ''], getline(1, 4))
+ " clean up
+ bw!
+endfunc
+
+func Test_put_lines()
+ new
+ let a = [ getreg('a'), getregtype('a') ]
+ call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
+ exe 'norm! gg"add"AddG""p'
+ call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1, '$'))
" clean up
bw!
call setreg('a', a[0], a[1])
@@ -42,21 +51,10 @@ func Test_put_expr()
exec "4norm! \"=\<cr>P"
norm! j0.
norm! j0.
- call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1,'$'))
+ call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1, '$'))
bw!
endfunc
-func Test_put_lines()
- new
- let a = [ getreg('a'), getregtype('a') ]
- call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
- exe 'norm! gg"add"AddG""p'
- call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1,'$'))
- " clean up
- bw!
- call setreg('a', a[0], a[1])
-endfunc
-
func Test_put_fails_when_nomodifiable()
new
setlocal nomodifiable
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 926103b69f..cf0af07528 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1,8 +1,7 @@
" Test for the quickfix commands.
-if !has('quickfix')
- finish
-endif
+source check.vim
+CheckFeature quickfix
set encoding=utf-8
@@ -95,7 +94,7 @@ func XlistTests(cchar)
" Populate the list and then try
Xgetexpr ['non-error 1', 'Xtestfile1:1:3:Line1',
\ 'non-error 2', 'Xtestfile2:2:2:Line2',
- \ 'non-error 3', 'Xtestfile3:3:1:Line3']
+ \ 'non-error| 3', 'Xtestfile3:3:1:Line3']
" List only valid entries
let l = split(execute('Xlist', ''), "\n")
@@ -107,7 +106,7 @@ func XlistTests(cchar)
let l = split(execute('Xlist!', ''), "\n")
call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2',
- \ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l)
+ \ ' 5: non-error| 3', ' 6 Xtestfile3:3 col 1: Line3'], l)
" List a range of errors
let l = split(execute('Xlist 3,6', ''), "\n")
@@ -507,7 +506,7 @@ func Xtest_browse(cchar)
Xexpr ""
call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
call assert_equal(0, g:Xgetlist({'size' : 0}).size)
- Xaddexpr ['foo', 'bar', 'baz', 'quux', 'shmoo']
+ Xaddexpr ['foo', 'bar', 'baz', 'quux', 'sh|moo']
call assert_equal(5, g:Xgetlist({'size' : 0}).size)
Xlast
call assert_equal(5, g:Xgetlist({'idx' : 0}).idx)
@@ -1284,6 +1283,30 @@ func Test_quickfix_was_changed_by_autocmd()
call XquickfixChangedByAutocmd('l')
endfunc
+func Test_setloclist_in_autocommand()
+ call writefile(['test1', 'test2'], 'Xfile')
+ edit Xfile
+ let s:bufnr = bufnr()
+ call setloclist(1,
+ \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'},
+ \ {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}])
+
+ augroup Test_LocList
+ au!
+ autocmd BufEnter * call setloclist(1,
+ \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'},
+ \ {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}], 'r')
+ augroup END
+
+ lopen
+ call assert_fails('exe "normal j\<CR>"', 'E926:')
+
+ augroup Test_LocList
+ au!
+ augroup END
+ call delete('Xfile')
+endfunc
+
func Test_caddbuffer_to_empty()
helpgr quickfix
call setqflist([], 'r')
@@ -1597,6 +1620,24 @@ func Test_long_lines()
call s:long_lines_tests('l')
endfunc
+func Test_cgetfile_on_long_lines()
+ " Problematic values if the line is longer than 4096 bytes. Then 1024 bytes
+ " are read at a time.
+ for len in [4078, 4079, 4080, 5102, 5103, 5104, 6126, 6127, 6128, 7150, 7151, 7152]
+ let lines = [
+ \ '/tmp/file1:1:1:aaa',
+ \ '/tmp/file2:1:1:%s',
+ \ '/tmp/file3:1:1:bbb',
+ \ '/tmp/file4:1:1:ccc',
+ \ ]
+ let lines[1] = substitute(lines[1], '%s', repeat('x', len), '')
+ call writefile(lines, 'Xcqetfile.txt')
+ cgetfile Xcqetfile.txt
+ call assert_equal(4, getqflist(#{size: v:true}).size, 'with length ' .. len)
+ endfor
+ call delete('Xcqetfile.txt')
+endfunc
+
func s:create_test_file(filename)
let l = []
for i in range(1, 20)
@@ -1874,6 +1915,13 @@ func HistoryTest(cchar)
call g:Xsetlist([], 'f')
let l = split(execute(a:cchar . 'hist'), "\n")
call assert_equal('No entries', l[0])
+
+ " An empty list should still show the stack history
+ call g:Xsetlist([])
+ let res = split(execute(a:cchar . 'hist'), "\n")
+ call assert_equal('> error list 1 of 1; 0 ' . common, res[0])
+
+ call g:Xsetlist([], 'f')
endfunc
func Test_history()
@@ -2124,6 +2172,9 @@ func Xproperty_tests(cchar)
call assert_equal(['Colors'], newl2.context)
call assert_equal('Line10', newl2.items[0].text)
call g:Xsetlist([], 'f')
+
+ " Cannot specify both a non-empty list argument and a dict argument
+ call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:')
endfunc
func Test_qf_property()
@@ -2131,6 +2182,56 @@ func Test_qf_property()
call Xproperty_tests('l')
endfunc
+" Test for setting the current index in the location/quickfix list
+func Xtest_setqfidx(cchar)
+ call s:setup_commands(a:cchar)
+
+ Xgetexpr "F1:10:1:Line1\nF2:20:2:Line2\nF3:30:3:Line3"
+ Xgetexpr "F4:10:1:Line1\nF5:20:2:Line2\nF6:30:3:Line3"
+ Xgetexpr "F7:10:1:Line1\nF8:20:2:Line2\nF9:30:3:Line3"
+
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 3})
+ Xolder 2
+ Xopen
+ call assert_equal(3, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ " Update the current index with the quickfix window open
+ wincmd w
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 3})
+ Xopen
+ call assert_equal(3, line('.'))
+ Xclose
+
+ " Set the current index to the last entry
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : '$'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " A large value should set the index to the last index
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 1})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 999})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " Invalid index values
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : -1})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 0})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 'xx'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call assert_fails("call g:Xsetlist([], 'a', {'nr':1, 'idx':[]})", 'E745:')
+
+ call g:Xsetlist([], 'f')
+ new | only
+endfunc
+
+func Test_setqfidx()
+ call Xtest_setqfidx('c')
+ call Xtest_setqfidx('l')
+endfunc
+
" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
func QfAutoCmdHandler(loc, cmd)
call add(g:acmds, a:loc . a:cmd)
@@ -2450,6 +2551,57 @@ func Test_vimgrep()
call XvimgrepTests('l')
endfunc
+" Test for incsearch highlighting of the :vimgrep pattern
+" This test used to cause "E315: ml_get: invalid lnum" errors.
+func Test_vimgrep_incsearch()
+ throw 'skipped: Nvim does not support test_override()'
+ enew
+ set incsearch
+ call test_override("char_avail", 1)
+
+ call feedkeys(":2vimgrep assert test_quickfix.vim test_cdo.vim\<CR>", "ntx")
+ let l = getqflist()
+ call assert_equal(2, len(l))
+
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+" Test vimgrep without swap file
+func Test_vimgrep_without_swap_file()
+ let lines =<< trim [SCRIPT]
+ vimgrep grep test_c*
+ call writefile(['done'], 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -n -S Xscript Xscript')
+ call assert_equal(['done'], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+func Test_vimgrep_existing_swapfile()
+ call writefile(['match apple with apple'], 'Xapple')
+ call writefile(['swapfile'], '.Xapple.swp')
+ let g:foundSwap = 0
+ let g:ignoreSwapExists = 1
+ augroup grep
+ au SwapExists * let foundSwap = 1 | let v:swapchoice = 'e'
+ augroup END
+ vimgrep apple Xapple
+ call assert_equal(1, g:foundSwap)
+ call assert_match('.Xapple.swo', swapname(''))
+
+ call delete('Xapple')
+ call delete('Xapple.swp')
+ augroup grep
+ au! SwapExists
+ augroup END
+ unlet g:ignoreSwapExists
+endfunc
+
func XfreeTests(cchar)
call s:setup_commands(a:cchar)
@@ -3342,6 +3494,17 @@ func Test_lvimgrep_crash()
augroup QF_Test
au!
augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setloclist(0, [], 'r')
+ augroup END
+ call assert_fails('lvimgrep Test_lvimgrep_crash *', 'E926:')
+ augroup QF_Test
+ au!
+ augroup END
+
enew | only
endfunc
@@ -3432,6 +3595,37 @@ func Test_lhelpgrep_autocmd()
call assert_equal('help', &filetype)
call assert_equal(1, getloclist(0, {'nr' : '$'}).nr)
au! QuickFixCmdPost
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setqflist([], 'f')
+ augroup END
+ call assert_fails('helpgrep quickfix', 'E925:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setqflist([], 'r')
+ augroup END
+ call assert_fails('helpgrep quickfix', 'E925:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setloclist(0, [], 'r')
+ augroup END
+ call assert_fails('lhelpgrep quickfix', 'E926:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
new | only
endfunc
@@ -3457,6 +3651,18 @@ func Test_shorten_fname()
" Displaying the quickfix list should simplify the file path
silent! clist
call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
+ " Add a few entries for the same file with different paths and check whether
+ " the buffer name is shortened
+ %bwipe
+ call setqflist([], 'f')
+ call setqflist([{'filename' : 'test_quickfix.vim', 'lnum' : 10},
+ \ {'filename' : '../testdir/test_quickfix.vim', 'lnum' : 20},
+ \ {'filename' : fname, 'lnum' : 30}], ' ')
+ copen
+ call assert_equal(['test_quickfix.vim|10| ',
+ \ 'test_quickfix.vim|20| ',
+ \ 'test_quickfix.vim|30| '], getline(1, '$'))
+ cclose
endfunc
" Quickfix title tests
@@ -3757,6 +3963,52 @@ func Test_curswant()
cclose | helpclose
endfunc
+" Test for opening a file from the quickfix window using CTRL-W <Enter>
+" doesn't leave an empty buffer around.
+func Test_splitview()
+ call s:create_test_file('Xtestfile1')
+ call s:create_test_file('Xtestfile2')
+ new | only
+ let last_bufnr = bufnr('Test_sv_1', 1)
+ let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
+ cgetexpr l
+ copen
+ let numbufs = len(getbufinfo())
+ exe "normal \<C-W>\<CR>"
+ copen
+ exe "normal j\<C-W>\<CR>"
+ " Make sure new empty buffers are not created
+ call assert_equal(numbufs, len(getbufinfo()))
+ " Creating a new buffer should use the next available buffer number
+ call assert_equal(last_bufnr + 4, bufnr("Test_sv_2", 1))
+ bwipe Test_sv_1
+ bwipe Test_sv_2
+ new | only
+
+ " When split opening files from location list window, make sure that two
+ " windows doesn't refer to the same location list
+ lgetexpr l
+ let locid = getloclist(0, {'id' : 0}).id
+ lopen
+ exe "normal \<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ " When split opening files from a helpgrep location list window, a new help
+ " window should be opend with a copy of the location list.
+ lhelpgrep window
+ let locid = getloclist(0, {'id' : 0}).id
+ lwindow
+ exe "normal j\<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
" Test for parsing entries using visual screen column
func Test_viscol()
enew
@@ -3808,11 +4060,102 @@ func Test_viscol()
cnext
call assert_equal([16, 25], [col('.'), virtcol('.')])
+ " Use screen column number with a multi-line error message
+ enew
+ call writefile(["ร  test"], 'Xfile1')
+ set efm=%E===\ %f\ ===,%C%l:%v,%Z%m
+ cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
+ call assert_equal('Xfile1', @%)
+ call assert_equal([0, 1, 4, 0], getpos('.'))
+
+ " Repeat previous test with byte offset %c: ensure that fix to issue #7145
+ " does not break this
+ set efm=%E===\ %f\ ===,%C%l:%c,%Z%m
+ cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
+ call assert_equal('Xfile1', @%)
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
enew | only
set efm&
call delete('Xfile1')
endfunc
+" Test for the quickfix window buffer
+func Xqfbuf_test(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Quickfix buffer should be reused across closing and opening a quickfix
+ " window
+ Xexpr "F1:10:Line10"
+ Xopen
+ let qfbnum = bufnr('')
+ Xclose
+ " Even after the quickfix window is closed, the buffer should be loaded
+ call assert_true(bufloaded(qfbnum))
+ Xopen
+ " Buffer should be reused when opening the window again
+ call assert_equal(qfbnum, bufnr(''))
+ Xclose
+
+ if a:cchar == 'l'
+ %bwipe
+ " For a location list, when both the file window and the location list
+ " window for the list are closed, then the buffer should be freed.
+ new | only
+ lexpr "F1:10:Line10"
+ let wid = win_getid()
+ lopen
+ let qfbnum = bufnr('')
+ call assert_match(qfbnum . ' %a- "\[Location List]"', execute('ls'))
+ close
+ " When the location list window is closed, the buffer name should not
+ " change to 'Quickfix List'
+ call assert_match(qfbnum . ' h- "\[Location List]"', execute('ls'))
+ call assert_true(bufloaded(qfbnum))
+
+ " After deleting a location list buffer using ":bdelete", opening the
+ " location list window should mark the buffer as a location list buffer.
+ exe "bdelete " . qfbnum
+ lopen
+ call assert_equal("quickfix", &buftype)
+ call assert_equal(1, getwininfo(win_getid(winnr()))[0].loclist)
+ call assert_equal(wid, getloclist(0, {'filewinid' : 0}).filewinid)
+ call assert_false(&swapfile)
+ lclose
+
+ " When the location list is cleared for the window, the buffer should be
+ " removed
+ call setloclist(0, [], 'f')
+ call assert_false(bufexists(qfbnum))
+
+ " When the location list is freed with the location list window open, the
+ " location list buffer should not be lost. It should be reused when the
+ " location list is again populated.
+ lexpr "F1:10:Line10"
+ lopen
+ let wid = win_getid()
+ let qfbnum = bufnr('')
+ wincmd p
+ call setloclist(0, [], 'f')
+ lexpr "F1:10:Line10"
+ lopen
+ call assert_equal(wid, win_getid())
+ call assert_equal(qfbnum, bufnr(''))
+ lclose
+
+ " When the window with the location list is closed, the buffer should be
+ " removed
+ new | only
+ call assert_false(bufexists(qfbnum))
+ endif
+endfunc
+
+func Test_qfbuf()
+ throw 'skipped: enable after porting patch 8.1.0877'
+ call Xqfbuf_test('c')
+ call Xqfbuf_test('l')
+endfunc
+
" Test to make sure that an empty quickfix buffer is not reused for loading
" a normal buffer.
func Test_empty_qfbuf()
@@ -4021,4 +4364,46 @@ func Test_qfcmd_abort()
augroup END
endfunc
+" Test for using a file in one of the parent directories.
+func Test_search_in_dirstack()
+ call mkdir('Xtestdir/a/b/c', 'p')
+ let save_cwd = getcwd()
+ call writefile(["X1_L1", "X1_L2"], 'Xtestdir/Xfile1')
+ call writefile(["X2_L1", "X2_L2"], 'Xtestdir/a/Xfile2')
+ call writefile(["X3_L1", "X3_L2"], 'Xtestdir/a/b/Xfile3')
+ call writefile(["X4_L1", "X4_L2"], 'Xtestdir/a/b/c/Xfile4')
+
+ let lines = "Entering dir Xtestdir\n" .
+ \ "Entering dir a\n" .
+ \ "Entering dir b\n" .
+ \ "Xfile2:2:X2_L2\n" .
+ \ "Leaving dir a\n" .
+ \ "Xfile1:2:X1_L2\n" .
+ \ "Xfile3:1:X3_L1\n" .
+ \ "Entering dir c\n" .
+ \ "Xfile4:2:X4_L2\n" .
+ \ "Leaving dir c\n"
+ set efm=%DEntering\ dir\ %f,%XLeaving\ dir\ %f,%f:%l:%m
+ cexpr lines .. "Leaving dir Xtestdir|\n" | let next = 1
+ call assert_equal(11, getqflist({'size' : 0}).size)
+ call assert_equal(4, getqflist({'idx' : 0}).idx)
+ call assert_equal('X2_L2', getline('.'))
+ call assert_equal(1, next)
+ cnext
+ call assert_equal(6, getqflist({'idx' : 0}).idx)
+ call assert_equal('X1_L2', getline('.'))
+ cnext
+ call assert_equal(7, getqflist({'idx' : 0}).idx)
+ call assert_equal(1, line('$'))
+ call assert_equal('', getline(1))
+ cnext
+ call assert_equal(9, getqflist({'idx' : 0}).idx)
+ call assert_equal(1, line('$'))
+ call assert_equal('', getline(1))
+
+ set efm&
+ exe 'cd ' . save_cwd
+ call delete('Xtestdir', 'rf')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_ruby.vim b/src/nvim/testdir/test_ruby.vim
index 64199570a9..07ad8561c3 100644
--- a/src/nvim/testdir/test_ruby.vim
+++ b/src/nvim/testdir/test_ruby.vim
@@ -11,37 +11,6 @@ func Test_ruby_change_buffer()
call assert_equal('1 changed line 1', getline('$'))
endfunc
-func Test_ruby_evaluate_list()
- throw 'skipped: TODO: '
- call setline(line('$'), ['2 line 2'])
- ruby Vim.command("normal /^2\n")
- let l = ["abc", "def"]
- ruby << EOF
- curline = $curbuf.line_number
- l = Vim.evaluate("l");
- $curbuf.append(curline, l.join("\n"))
-EOF
- normal j
- .rubydo $_ = $_.gsub(/\n/, '/')
- call assert_equal('abc/def', getline('$'))
-endfunc
-
-func Test_ruby_evaluate_dict()
- let d = {'a': 'foo', 'b': 123}
- redir => l:out
- ruby d = Vim.evaluate("d"); print d
- redir END
- call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
-endfunc
-
-func Test_ruby_evaluate_special_var()
- let l = [v:true, v:false, v:null]
- redir => l:out
- ruby d = Vim.evaluate("l"); print d
- redir END
- call assert_equal(['[true, false, nil]'], split(l:out, "\n"))
-endfunc
-
func Test_rubydo()
throw 'skipped: TODO: '
" Check deleting lines does not trigger ml_get error.
@@ -56,8 +25,7 @@ func Test_rubydo()
call setline(1, ['one', 'two', 'three'])
rubydo Vim.command("new")
call assert_equal(wincount + 1, winnr('$'))
- bwipe!
- bwipe!
+ %bwipe!
endfunc
func Test_rubyfile()
@@ -75,8 +43,350 @@ func Test_set_cursor()
normal gg
rubydo $curwin.cursor = [1, 5]
call assert_equal([1, 6], [line('.'), col('.')])
+ call assert_equal([1, 5], rubyeval('$curwin.cursor'))
" Check that movement after setting cursor position keeps current column.
normal j
call assert_equal([2, 6], [line('.'), col('.')])
+ call assert_equal([2, 5], rubyeval('$curwin.cursor'))
+
+ " call assert_fails('ruby $curwin.cursor = [1]',
+ " \ 'ArgumentError: array length must be 2')
+ bwipe!
+endfunc
+
+" Test buffer.count and buffer.length (number of lines in buffer)
+func Test_buffer_count()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call assert_equal(3, rubyeval('$curbuf.count'))
+ call assert_equal(3, rubyeval('$curbuf.length'))
+ bwipe!
+endfunc
+
+" Test buffer.name (buffer name)
+func Test_buffer_name()
+ new Xfoo
+ call assert_equal(expand('%:p'), rubyeval('$curbuf.name'))
+ bwipe
+ call assert_equal('', rubyeval('$curbuf.name'))
+endfunc
+
+" Test buffer.number (number of the buffer).
+func Test_buffer_number()
+ new
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
+ new
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
+
+ %bwipe
+endfunc
+
+" Test buffer.delete({n}) (delete line {n})
+func Test_buffer_delete()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ ruby $curbuf.delete(2)
+ call assert_equal(['one', 'three'], getline(1, '$'))
+
+ " call assert_fails('ruby $curbuf.delete(0)', 'IndexError: line number 0 out of range')
+ " call assert_fails('ruby $curbuf.delete(3)', 'IndexError: line number 3 out of range')
+ call assert_fails('ruby $curbuf.delete(3)', 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+" Test buffer.append({str}, str) (append line {str} after line {n})
+func Test_buffer_append()
+ new
+ ruby $curbuf.append(0, 'one')
+ ruby $curbuf.append(1, 'three')
+ ruby $curbuf.append(1, 'two')
+ ruby $curbuf.append(4, 'four')
+
+ call assert_equal(['one', 'two', 'three', '', 'four'], getline(1, '$'))
+
+ " call assert_fails('ruby $curbuf.append(-1, "x")',
+ " \ 'IndexError: line number -1 out of range')
+ call assert_fails('ruby $curbuf.append(-1, "x")',
+ \ 'ArgumentError: Index out of bounds')
+ call assert_fails('ruby $curbuf.append(6, "x")',
+ \ 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+" Test buffer.line (get or set the current line)
+func Test_buffer_line()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal('two', rubyeval('$curbuf.line'))
+
+ ruby $curbuf.line = 'TWO'
+ call assert_equal(['one', 'TWO', 'three'], getline(1, '$'))
+
+ bwipe!
+endfunc
+
+" Test buffer.line_number (get current line number)
+func Test_buffer_line_number()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal(2, rubyeval('$curbuf.line_number'))
+
+ bwipe!
+endfunc
+
+func Test_buffer_get()
+ new
+ call setline(1, ['one', 'two'])
+ call assert_equal('one', rubyeval('$curbuf[1]'))
+ call assert_equal('two', rubyeval('$curbuf[2]'))
+
+ " call assert_fails('ruby $curbuf[0]',
+ " \ 'IndexError: line number 0 out of range')
+ call assert_fails('ruby $curbuf[3]',
+ \ 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+func Test_buffer_set()
+ new
+ call setline(1, ['one', 'two'])
+ ruby $curbuf[2] = 'TWO'
+ ruby $curbuf[1] = 'ONE'
+
+ " call assert_fails('ruby $curbuf[0] = "ZERO"',
+ " \ 'IndexError: line number 0 out of range')
+ " call assert_fails('ruby $curbuf[3] = "THREE"',
+ " \ 'IndexError: line number 3 out of range')
+ call assert_fails('ruby $curbuf[3] = "THREE"',
+ \ 'RuntimeError: Index out of bounds')
+ bwipe!
+endfunc
+
+" Test window.width (get or set window height).
+func Test_window_height()
+ new
+
+ " Test setting window height
+ ruby $curwin.height = 2
+ call assert_equal(2, winheight(0))
+
+ " Test getting window height
+ call assert_equal(2, rubyeval('$curwin.height'))
+
+ bwipe
+endfunc
+
+" Test window.width (get or set window width).
+func Test_window_width()
+ vnew
+
+ " Test setting window width
+ ruby $curwin.width = 2
+ call assert_equal(2, winwidth(0))
+
+ " Test getting window width
+ call assert_equal(2, rubyeval('$curwin.width'))
+
+ bwipe
+endfunc
+
+" Test window.buffer (get buffer object of a window object).
+func Test_window_buffer()
+ new Xfoo1
+ new Xfoo2
+ ruby $b2 = $curwin.buffer
+ ruby $w2 = $curwin
+ wincmd j
+ ruby $b1 = $curwin.buffer
+ ruby $w1 = $curwin
+
+ " call assert_equal(rubyeval('$b1'), rubyeval('$w1.buffer'))
+ " call assert_equal(rubyeval('$b2'), rubyeval('$w2.buffer'))
+ call assert_equal(bufnr('Xfoo1'), rubyeval('$w1.buffer.number'))
+ call assert_equal(bufnr('Xfoo2'), rubyeval('$w2.buffer.number'))
+
+ ruby $b1, $w1, $b2, $w2 = nil
+ %bwipe
+endfunc
+
+" Test Vim::Window.current (get current window object)
+func Test_Vim_window_current()
+ let cw = rubyeval('$curwin.to_s')
+ " call assert_equal(cw, rubyeval('Vim::Window.current'))
+ call assert_match('^#<Neovim::Window:0x\x\+>$', cw)
+endfunc
+
+" Test Vim::Window.count (number of windows)
+func Test_Vim_window_count()
+ new Xfoo1
+ new Xfoo2
+ split
+ call assert_equal(4, rubyeval('Vim::Window.count'))
+ %bwipe
+ call assert_equal(1, rubyeval('Vim::Window.count'))
+endfunc
+
+" Test Vim::Window[n] (get window object of window n)
+func Test_Vim_window_get()
+ new Xfoo1
+ new Xfoo2
+ call assert_match('Xfoo2$', rubyeval('Vim::Window[0].buffer.name'))
+ wincmd j
+ call assert_match('Xfoo1$', rubyeval('Vim::Window[1].buffer.name'))
+ wincmd j
+ call assert_equal('', rubyeval('Vim::Window[2].buffer.name'))
+ %bwipe
+endfunc
+
+" Test Vim::Buffer.current (return the buffer object of current buffer)
+func Test_Vim_buffer_current()
+ let cb = rubyeval('$curbuf.to_s')
+ " call assert_equal(cb, rubyeval('Vim::Buffer.current'))
+ call assert_match('^#<Neovim::Buffer:0x\x\+>$', cb)
+endfunc
+
+" Test Vim::Buffer:.count (return the number of buffers)
+func Test_Vim_buffer_count()
+ new Xfoo1
+ new Xfoo2
+ call assert_equal(3, rubyeval('Vim::Buffer.count'))
+ %bwipe
+ call assert_equal(1, rubyeval('Vim::Buffer.count'))
+endfunc
+
+" Test Vim::buffer[n] (return the buffer object of buffer number n)
+func Test_Vim_buffer_get()
+ new Xfoo1
+ new Xfoo2
+
+ " Index of Vim::Buffer[n] goes from 0 to the number of buffers.
+ call assert_equal('', rubyeval('Vim::Buffer[0].name'))
+ call assert_match('Xfoo1$', rubyeval('Vim::Buffer[1].name'))
+ call assert_match('Xfoo2$', rubyeval('Vim::Buffer[2].name'))
+ call assert_fails('ruby print Vim::Buffer[3].name',
+ \ "NoMethodError: undefined method `name' for nil:NilClass")
+ %bwipe
+endfunc
+
+" Test Vim::command({cmd}) (execute a Ex command))
+" Test Vim::command({cmd})
+func Test_Vim_command()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ ruby Vim::command('2,3d')
+ call assert_equal(['one', 'four'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test Vim::set_option (set a vim option)
+func Test_Vim_set_option()
+ call assert_equal(0, &number)
+ ruby Vim::set_option('number')
+ call assert_equal(1, &number)
+ ruby Vim::set_option('nonumber')
+ call assert_equal(0, &number)
+endfunc
+
+func Test_Vim_evaluate()
+ call assert_equal(123, rubyeval('Vim::evaluate("123")'))
+ " Vim::evaluate("123").class gives Integer or Fixnum depending
+ " on versions of Ruby.
+ call assert_match('^Integer\|Fixnum$', rubyeval('Vim::evaluate("123").class'))
+
+ call assert_equal(1.23, rubyeval('Vim::evaluate("1.23")'))
+ call assert_equal('Float', rubyeval('Vim::evaluate("1.23").class'))
+
+ call assert_equal('foo', rubyeval('Vim::evaluate("\"foo\"")'))
+ call assert_equal('String', rubyeval('Vim::evaluate("\"foo\"").class'))
+
+ call assert_equal([1, 2], rubyeval('Vim::evaluate("[1, 2]")'))
+ call assert_equal('Array', rubyeval('Vim::evaluate("[1, 2]").class'))
+
+ call assert_equal({'1': 2}, rubyeval('Vim::evaluate("{1:2}")'))
+ call assert_equal('Hash', rubyeval('Vim::evaluate("{1:2}").class'))
+
+ call assert_equal(v:null, rubyeval('Vim::evaluate("v:null")'))
+ call assert_equal('NilClass', rubyeval('Vim::evaluate("v:null").class'))
+
+ " call assert_equal(v:null, rubyeval('Vim::evaluate("v:none")'))
+ " call assert_equal('NilClass', rubyeval('Vim::evaluate("v:none").class'))
+
+ call assert_equal(v:true, rubyeval('Vim::evaluate("v:true")'))
+ call assert_equal('TrueClass', rubyeval('Vim::evaluate("v:true").class'))
+ call assert_equal(v:false, rubyeval('Vim::evaluate("v:false")'))
+ call assert_equal('FalseClass',rubyeval('Vim::evaluate("v:false").class'))
+endfunc
+
+func Test_Vim_evaluate_list()
+ call setline(line('$'), ['2 line 2'])
+ ruby Vim.command("normal /^2\n")
+ let l = ["abc", "def"]
+ ruby << EOF
+ curline = $curbuf.line_number
+ l = Vim.evaluate("l");
+ $curbuf.append(curline, l.join("|"))
+EOF
+ normal j
+ .rubydo $_ = $_.gsub(/\|/, '/')
+ call assert_equal('abc/def', getline('$'))
+endfunc
+
+func Test_Vim_evaluate_dict()
+ let d = {'a': 'foo', 'b': 123}
+ redir => l:out
+ ruby d = Vim.evaluate("d"); print d
+ redir END
+ call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
+endfunc
+
+" Test Vim::message({msg}) (display message {msg})
+func Test_Vim_message()
+ throw 'skipped: TODO: '
+ ruby Vim::message('A message')
+ let messages = split(execute('message'), "\n")
+ call assert_equal('A message', messages[-1])
+endfunc
+
+func Test_print()
+ func RubyPrint(expr)
+ return trim(execute('ruby print ' . a:expr))
+ endfunc
+
+ call assert_equal('123', RubyPrint('123'))
+ call assert_equal('1.23', RubyPrint('1.23'))
+ call assert_equal('Hello World!', RubyPrint('"Hello World!"'))
+ call assert_equal('[1, 2]', RubyPrint('[1, 2]'))
+ call assert_equal('{"k1"=>"v1", "k2"=>"v2"}', RubyPrint('({"k1" => "v1", "k2" => "v2"})'))
+ call assert_equal('true', RubyPrint('true'))
+ call assert_equal('false', RubyPrint('false'))
+ call assert_equal('', RubyPrint('nil'))
+ call assert_match('Vim', RubyPrint('Vim'))
+ call assert_match('Module', RubyPrint('Vim.class'))
+
+ delfunc RubyPrint
+endfunc
+
+func Test_p()
+ ruby p 'Just a test'
+ let messages = split(execute('message'), "\n")
+ call assert_equal('"Just a test"', messages[-1])
+
+ " Check return values of p method
+
+ call assert_equal(123, rubyeval('p(123)'))
+ call assert_equal([1, 2, 3], rubyeval('p(1, 2, 3)'))
+
+ " Avoid the "message maintainer" line.
+ let $LANG = ''
+ messages clear
+ call assert_equal(v:true, rubyeval('p() == nil'))
+
+ let messages = split(execute('message'), "\n")
+ call assert_equal(0, len(messages))
endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 8036dea29f..5db23c22a8 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -244,6 +244,10 @@ func Test_search_cmdline2()
" go to previous match (on line 2)
call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
+ 1
+ " go to previous match (on line 2)
+ call feedkeys("/the\<C-G>\<C-R>\<C-W>\<cr>", 'tx')
+ call assert_equal('theother', @/)
" Test 2: keep the view,
" after deleting a character from the search cmd
@@ -255,7 +259,7 @@ func Test_search_cmdline2()
call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
" remove all history entries
- for i in range(10)
+ for i in range(11)
call histdel('/')
endfor
@@ -346,25 +350,104 @@ func Test_searchc()
bw!
endfunc
-func Test_search_cmdline3()
+func Cmdline3_prep()
throw 'skipped: Nvim does not support test_override()'
- if !exists('+incsearch')
- return
- endif
" need to disable char_avail,
" so that expansion of commandline works
call test_override("char_avail", 1)
new
call setline(1, [' 1', ' 2 the~e', ' 3 the theother'])
set incsearch
+endfunc
+
+func Incsearch_cleanup()
+ throw 'skipped: Nvim does not support test_override()'
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline3()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
1
" first match
call feedkeys("/the\<c-l>\<cr>", 'tx')
call assert_equal(' 2 the~e', getline('.'))
- " clean up
- set noincsearch
- call test_override("char_avail", 0)
- bw!
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3s()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxx', getline('.'))
+ undo
+ call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
+ "
+ call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxx', getline('.'))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3g()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline(2))
+ undo
+ call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline(2))
+ undo
+ call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+ undo
+ call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3v()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+ undo
+ call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+
+ call Incsearch_cleanup()
endfunc
func Test_search_cmdline4()
@@ -410,19 +493,58 @@ func Test_search_cmdline5()
" Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
" regardless char_avail.
new
- call setline(1, [' 1 the first', ' 2 the second', ' 3 the third'])
+ call setline(1, [' 1 the first', ' 2 the second', ' 3 the third', ''])
set incsearch
1
call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
call assert_equal(' 3 the third', getline('.'))
$
call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
- call assert_equal(' 2 the second', getline('.'))
+ call assert_equal(' 1 the first', getline('.'))
" clean up
set noincsearch
bw!
endfunc
+func Test_search_cmdline7()
+ throw 'skipped: Nvim does not support test_override()'
+ " Test that an pressing <c-g> in an empty command line
+ " does not move the cursor
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ let @/ = 'b'
+ call setline(1, [' bbvimb', ''])
+ set incsearch
+ " first match
+ norm! gg0
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,2,0], getpos('.'))
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<cr>", 'tx')
+ call assert_equal([0,1,3,0], getpos('.'))
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<c-t>\<cr>", 'tx')
+ call assert_equal([0,1,7,0], getpos('.'))
+
+ " using an offset uses the last search pattern
+ call cursor(1, 1)
+ call setline(1, ['1 bbvimb', ' 2 bbvimb'])
+ let @/ = 'b'
+ call feedkeys("//e\<c-g>\<cr>", 'tx')
+ call assert_equal('1 bbvimb', getline('.'))
+ call assert_equal(4, col('.'))
+
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
" Tests for regexp with various magic settings
func Test_search_regexp()
enew!
@@ -504,6 +626,7 @@ func Test_incsearch_substitute_dump()
\ 'for n in range(1, 10)',
\ ' call setline(n, "foo " . n)',
\ 'endfor',
+ \ 'call setline(11, "bar 11")',
\ '3',
\ ], 'Xis_subst_script')
let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
@@ -512,6 +635,7 @@ func Test_incsearch_substitute_dump()
sleep 100m
" Need to send one key at a time to force a redraw.
+ " Select three lines at the cursor with typed pattern.
call term_sendkeys(buf, ':.,.+2s/')
sleep 100m
call term_sendkeys(buf, 'f')
@@ -520,12 +644,219 @@ func Test_incsearch_substitute_dump()
sleep 100m
call term_sendkeys(buf, 'o')
call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Select three lines at the cursor using previous pattern.
+ call term_sendkeys(buf, "/foo\<CR>")
+ sleep 100m
+ call term_sendkeys(buf, ':.,.+2s//')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
+
+ " Deleting last slash should remove the match.
+ call term_sendkeys(buf, "\<BS>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Reverse range is accepted
+ call term_sendkeys(buf, ':5,2s/foo')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " White space after the command is skipped
+ call term_sendkeys(buf, ':2,3sub /fo')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Command modifiers are skipped
+ call term_sendkeys(buf, ':above below browse botr confirm keepmar keepalt keeppat keepjum filter xxx hide lockm leftabove noau noswap rightbel sandbox silent silent! $tab top unsil vert verbose 4,5s/fo.')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Cursorline highlighting at match
+ call term_sendkeys(buf, ":set cursorline\<CR>")
+ call term_sendkeys(buf, 'G9G')
+ call term_sendkeys(buf, ':9,11s/bar')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
+ call term_sendkeys(buf, "\<Esc>")
+ " Cursorline highlighting at cursor when no match
+ call term_sendkeys(buf, ':9,10s/bar')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
call term_sendkeys(buf, "\<Esc>")
+
+ " Only \v handled as empty pattern, does not move cursor
+ call term_sendkeys(buf, '3G4G')
+ call term_sendkeys(buf, ":nohlsearch\<CR>")
+ call term_sendkeys(buf, ':6,7s/\v')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ":set nocursorline\<CR>")
+
+ " All matches are highlighted for 'hlsearch' after the incsearch canceled
+ call term_sendkeys(buf, "1G*")
+ call term_sendkeys(buf, ":2,5s/foo")
+ sleep 100m
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_10', {})
+
+ call term_sendkeys(buf, ":split\<CR>")
+ call term_sendkeys(buf, ":let @/ = 'xyz'\<CR>")
+ call term_sendkeys(buf, ":%s/.")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_11', {})
+ call term_sendkeys(buf, "\<BS>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
+ call term_sendkeys(buf, ":%bwipe!\<CR>")
+ call term_sendkeys(buf, ":only!\<CR>")
+
+ " get :'<,'>s command in history
+ call term_sendkeys(buf, ":set cmdheight=2\<CR>")
+ call term_sendkeys(buf, "aasdfasdf\<Esc>")
+ call term_sendkeys(buf, "V:s/a/b/g\<CR>")
+ " Using '<,'> does not give E20
+ call term_sendkeys(buf, ":new\<CR>")
+ call term_sendkeys(buf, "aasdfasdf\<Esc>")
+ call term_sendkeys(buf, ":\<Up>\<Up>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_14', {})
+ call term_sendkeys(buf, "<Esc>")
+
call StopVimInTerminal(buf)
call delete('Xis_subst_script')
endfunc
+" Similar to Test_incsearch_substitute_dump() for :sort
+func Test_incsearch_sort_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot make screendumps'
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
+ \ ], 'Xis_sort_script')
+ let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ call term_sendkeys(buf, ':sort ni u /on')
+ call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':sort! /on')
+ call VerifyScreenDump(buf, 'Test_incsearch_sort_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_sort_script')
+endfunc
+
+" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry
+func Test_incsearch_vimgrep_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot make screendumps'
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
+ \ ], 'Xis_vimgrep_script')
+ let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ call term_sendkeys(buf, ':vimgrep on')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':vimg /on/ *.txt')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':vimgrepadd "\<on')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':lv "tha')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_vimgrep_script')
+endfunc
+
+func Test_keep_last_search_pattern()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, ['foo', 'foo', 'foo'])
+ set incsearch
+ call test_override("char_avail", 1)
+ let @/ = 'bar'
+ call feedkeys(":/foo/s//\<Esc>", 'ntx')
+ call assert_equal('bar', @/)
+
+ " no error message if pattern not found
+ call feedkeys(":/xyz/s//\<Esc>", 'ntx')
+ call assert_equal('bar', @/)
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func Test_word_under_cursor_after_match()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, 'foo bar')
+ set incsearch
+ call test_override("char_avail", 1)
+ try
+ call feedkeys("/foo\<C-R>\<C-W>\<CR>", 'ntx')
+ catch /E486:/
+ endtry
+ call assert_equal('foobar', @/)
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func Test_subst_word_under_cursor()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, ['int SomeLongName;', 'for (xxx = 1; xxx < len; ++xxx)'])
+ set incsearch
+ call test_override("char_avail", 1)
+ call feedkeys("/LongName\<CR>", 'ntx')
+ call feedkeys(":%s/xxx/\<C-R>\<C-W>/g\<CR>", 'ntx')
+ call assert_equal('for (SomeLongName = 1; SomeLongName < len; ++SomeLongName)', getline(2))
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
func Test_incsearch_with_change()
if !has('timers') || !exists('+incsearch') || !CanRunVimInTerminal()
throw 'Skipped: cannot make screendumps and/or timers feature and/or incsearch option missing'
@@ -550,6 +881,21 @@ func Test_incsearch_with_change()
call delete('Xis_change_script')
endfunc
+func Test_incsearch_cmdline_modifier()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call test_override("char_avail", 1)
+ new
+ call setline(1, ['foo'])
+ set incsearch
+ " Test that error E14 does not occur in parsing command modifier.
+ call feedkeys("V:tab", 'tx')
+
+ call Incsearch_cleanup()
+endfunc
+
func Test_incsearch_scrolling()
if !CanRunVimInTerminal()
return
@@ -580,6 +926,76 @@ func Test_incsearch_scrolling()
call delete('Xscript')
endfunc
+func Test_incsearch_search_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'for n in range(1, 8)',
+ \ ' call setline(n, "foo " . n)',
+ \ 'endfor',
+ \ '3',
+ \ ], 'Xis_search_script')
+ let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ call term_sendkeys(buf, '/fo')
+ call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+ sleep 100m
+
+ call term_sendkeys(buf, '/\v')
+ call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_search_script')
+endfunc
+
+func Test_incsearch_substitute()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ call test_override("char_avail", 1)
+ new
+ set incsearch
+ for n in range(1, 10)
+ call setline(n, 'foo ' . n)
+ endfor
+ 4
+ call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
+ call assert_equal('foo 3', getline(3))
+ call assert_equal('xxx 4', getline(4))
+ call assert_equal('xxx 5', getline(5))
+ call assert_equal('xxx 6', getline(6))
+ call assert_equal('foo 7', getline(7))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_incsearch_substitute_long_line()
+ throw 'skipped: Nvim does not support test_override()'
+ new
+ call test_override("char_avail", 1)
+ set incsearch
+
+ call repeat('x', 100000)->setline(1)
+ call feedkeys(':s/\%c', 'xt')
+ redraw
+ call feedkeys("\<Esc>", 'xt')
+
+ call Incsearch_cleanup()
+ bwipe!
+endfunc
+
func Test_search_undefined_behaviour()
if !has("terminal")
return
@@ -616,6 +1032,40 @@ func Test_search_sentence()
/
endfunc
+" Test that there is no crash when there is a last search pattern but no last
+" substitute pattern.
+func Test_no_last_substitute_pat()
+ " Use viminfo to set the last search pattern to a string and make the last
+ " substitute pattern the most recent used and make it empty (NULL).
+ call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo')
+ rviminfo! Xviminfo
+ call assert_fails('normal n', 'E35:')
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_search_Ctrl_L_combining()
+ " Make sure, that Ctrl-L works correctly with combining characters.
+ " It uses an artificial example of an 'a' with 4 combining chars:
+ " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
+ " ' ฬ€' U+0300 Dec:768 COMBINING GRAVE ACCENT &#x300; /\%u300\Z "\u0300"
+ " ' ฬ' U+0301 Dec:769 COMBINING ACUTE ACCENT &#x301; /\%u301\Z "\u0301"
+ " ' ฬ‡' U+0307 Dec:775 COMBINING DOT ABOVE &#x307; /\%u307\Z "\u0307"
+ " ' ฬฃ' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
+ " Those should also appear on the commandline
+ if !has('multi_byte') || !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ let bufcontent = ['', 'Miaฬ€ฬฬ‡ฬฃm']
+ call append('$', bufcontent)
+ call feedkeys("/Mi\<c-l>\<c-l>\<cr>", 'tx')
+ call assert_equal(5, line('.'))
+ call assert_equal(bufcontent[1], @/)
+ call Incsearch_cleanup()
+endfunc
+
func Test_large_hex_chars1()
" This used to cause a crash, the character becomes an NFA state.
try
@@ -653,6 +1103,24 @@ func Test_one_error_msg()
call assert_fails('call search(" \\((\\v[[=P=]]){185}+ ")', 'E871:')
endfunc
+func Test_incsearch_add_char_under_cursor()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ set incsearch
+ new
+ call setline(1, ['find match', 'anything'])
+ 1
+ call test_override('char_avail', 1)
+ call feedkeys("fc/m\<C-L>\<C-L>\<C-L>\<C-L>\<C-L>\<CR>", 'tx')
+ call assert_equal('match', @/)
+ call test_override('char_avail', 0)
+
+ set incsearch&
+ bwipe!
+endfunc
+
" Test for the search() function with match at the cursor position
func Test_search_match_at_curpos()
new
diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim
index cf36f3214a..11c6489ca2 100644
--- a/src/nvim/testdir/test_search_stat.vim
+++ b/src/nvim/testdir/test_search_stat.vim
@@ -1,11 +1,9 @@
" Tests for search_stats, when "S" is not in 'shortmess'
-"
-" This test is fragile, it might not work interactively, but it works when run
-" as test!
-source shared.vim
+source screendump.vim
+source check.vim
-func! Test_search_stat()
+func Test_search_stat()
new
set shortmess-=S
" Append 50 lines with text to search for, "foobar" appears 20 times
@@ -45,7 +43,7 @@ func! Test_search_stat()
call assert_match(pat .. stat, g:a)
call cursor(line('$'), 1)
let g:a = execute(':unsilent :norm! n')
- let stat = '\[1/>99\] W'
+ let stat = 'W \[1/>99\]'
call assert_match(pat .. stat, g:a)
" Many matches
@@ -55,7 +53,7 @@ func! Test_search_stat()
call assert_match(pat .. stat, g:a)
call cursor(1, 1)
let g:a = execute(':unsilent :norm! N')
- let stat = '\[>99/>99\] W'
+ let stat = 'W \[>99/>99\]'
call assert_match(pat .. stat, g:a)
" right-left
@@ -87,7 +85,7 @@ func! Test_search_stat()
call cursor('$',1)
let pat = 'raboof/\s\+'
let g:a = execute(':unsilent :norm! n')
- let stat = '\[20/1\]'
+ let stat = 'W \[20/1\]'
call assert_match(pat .. stat, g:a)
call assert_match('search hit BOTTOM, continuing at TOP', g:a)
set norl
@@ -98,10 +96,10 @@ func! Test_search_stat()
let @/ = 'foobar'
let pat = '?foobar\s\+'
let g:a = execute(':unsilent :norm! N')
- let stat = '\[20/20\]'
+ let stat = 'W \[20/20\]'
call assert_match(pat .. stat, g:a)
call assert_match('search hit TOP, continuing at BOTTOM', g:a)
- call assert_match('\[20/20\] W', Screenline(&lines))
+ call assert_match('W \[20/20\]', Screenline(&lines))
" normal, no match
call cursor(1,1)
@@ -160,7 +158,115 @@ func! Test_search_stat()
let stat = '\[1/2\]'
call assert_notmatch(pat .. stat, g:a)
- " close the window
+ " normal, n comes from a silent mapping
+ " First test a normal mapping, then a silent mapping
+ call cursor(1,1)
+ nnoremap n n
+ let @/ = 'find this'
+ let pat = '/find this\s\+'
+ let g:a = execute(':unsilent :norm n')
+ let g:b = split(g:a, "\n")[-1]
+ let stat = '\[1/2\]'
+ call assert_match(pat .. stat, g:b)
+ nnoremap <silent> n n
+ call cursor(1,1)
+ let g:a = execute(':unsilent :norm n')
+ let g:b = split(g:a, "\n")[-1]
+ let stat = '\[1/2\]'
+ call assert_notmatch(pat .. stat, g:b)
+ call assert_match(stat, g:b)
+ " Test that the message is not truncated
+ " it would insert '...' into the output.
+ call assert_match('^\s\+' .. stat, g:b)
+ unmap n
+
+ " Clean up
set shortmess+=S
+ " close the window
bwipe!
endfunc
+
+func Test_search_stat_foldopen()
+ CheckScreendump
+
+ let lines =<< trim END
+ set shortmess-=S
+ setl foldenable foldmethod=indent foldopen-=search
+ call append(0, ['if', "\tfoo", "\tfoo", 'endif'])
+ let @/ = 'foo'
+ call cursor(1,1)
+ norm n
+ END
+ call writefile(lines, 'Xsearchstat1')
+
+ let buf = RunVimInTerminal('-S Xsearchstat1', #{rows: 10})
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_3', {})
+
+ call term_sendkeys(buf, "n")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_3', {})
+
+ call term_sendkeys(buf, "n")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_3', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xsearchstat1')
+endfunc
+
+func! Test_search_stat_screendump()
+ CheckScreendump
+
+ let lines =<< trim END
+ set shortmess-=S
+ " Append 50 lines with text to search for, "foobar" appears 20 times
+ call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 20))
+ call setline(2, 'find this')
+ call setline(70, 'find this')
+ nnoremap n n
+ let @/ = 'find this'
+ call cursor(1,1)
+ norm n
+ END
+ call writefile(lines, 'Xsearchstat')
+ let buf = RunVimInTerminal('-S Xsearchstat', #{rows: 10})
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_1', {})
+
+ call term_sendkeys(buf, ":nnoremap <silent> n n\<cr>")
+ call term_sendkeys(buf, "gg0n")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xsearchstat')
+endfunc
+
+func Test_searchcount_in_statusline()
+ CheckScreendump
+
+ let lines =<< trim END
+ set shortmess-=S
+ call append(0, 'this is something')
+ function TestSearchCount() abort
+ let search_count = searchcount()
+ if !empty(search_count)
+ return '[' . search_count.current . '/' . search_count.total . ']'
+ else
+ return ''
+ endif
+ endfunction
+ set hlsearch
+ set laststatus=2 statusline+=%{TestSearchCount()}
+ END
+ call writefile(lines, 'Xsearchstatusline')
+ let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10})
+ call TermWait(buf)
+ call term_sendkeys(buf, "/something")
+ call VerifyScreenDump(buf, 'Test_searchstat_4', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xsearchstatusline')
+endfunc
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 414c7278eb..ab8a998bb8 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -79,6 +79,11 @@ func Test_spellbadword()
call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence'))
+ call assert_equal(['TheCamelWord', 'bad'], spellbadword('TheCamelWord asdf'))
+ set spelloptions=camel
+ call assert_equal(['asdf', 'bad'], spellbadword('TheCamelWord asdf'))
+ set spelloptions=
+
set spelllang=en
call assert_equal(['', ''], spellbadword('centre'))
call assert_equal(['', ''], spellbadword('center'))
@@ -113,6 +118,43 @@ foobar/?
set spell&
endfunc
+func Test_spelllang_inv_region()
+ set spell spelllang=en_xx
+ let messages = GetMessages()
+ call assert_equal('Warning: region xx not supported', messages[-1])
+ set spell& spelllang&
+endfunc
+
+func Test_compl_with_CTRL_X_CTRL_K_using_spell()
+ " When spell checking is enabled and 'dictionary' is empty,
+ " CTRL-X CTRL-K in insert mode completes using the spelling dictionary.
+ new
+ set spell spelllang=en dictionary=
+
+ set ignorecase
+ call feedkeys("Senglis\<c-x>\<c-k>\<esc>", 'tnx')
+ call assert_equal(['English'], getline(1, '$'))
+ call feedkeys("SEnglis\<c-x>\<c-k>\<esc>", 'tnx')
+ call assert_equal(['English'], getline(1, '$'))
+
+ set noignorecase
+ call feedkeys("Senglis\<c-x>\<c-k>\<esc>", 'tnx')
+ call assert_equal(['englis'], getline(1, '$'))
+ call feedkeys("SEnglis\<c-x>\<c-k>\<esc>", 'tnx')
+ call assert_equal(['English'], getline(1, '$'))
+
+ set spelllang=en_us
+ call feedkeys("Stheat\<c-x>\<c-k>\<esc>", 'tnx')
+ call assert_equal(['theater'], getline(1, '$'))
+ set spelllang=en_gb
+ call feedkeys("Stheat\<c-x>\<c-k>\<esc>", 'tnx')
+ " FIXME: commented out, expected theatre bug got theater. See issue #7025.
+ " call assert_equal(['theatre'], getline(1, '$'))
+
+ bwipe!
+ set spell& spelllang& dictionary& ignorecase&
+endfunc
+
func Test_spellreall()
new
set spell
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 9abaca5957..12bec745a8 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -369,12 +369,11 @@ func Test_invalid_args()
endfor
if has('clientserver')
- " FIXME: need to add --servername to this list
- " but it causes vim-8.1.1282 to crash!
for opt in ['--remote', '--remote-send', '--remote-silent', '--remote-expr',
\ '--remote-tab', '--remote-tab-wait',
\ '--remote-tab-wait-silent', '--remote-tab-silent',
\ '--remote-wait', '--remote-wait-silent',
+ \ '--servername',
\ ]
let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
call assert_equal(1, v:shell_error)
@@ -384,14 +383,21 @@ func Test_invalid_args()
endfor
endif
- " FIXME: commented out as this causes vim-8.1.1282 to crash!
- "if has('clipboard')
- " let out = split(system(GetVimCommand() .. ' --display'), "\n")
- " call assert_equal(1, v:shell_error)
- " call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
- " call assert_equal('Argument missing after: "--display"', out[1])
- " call assert_equal('More info with: "vim -h"', out[2])
- "endif
+ if has('gui_gtk')
+ let out = split(system(GetVimCommand() .. ' --display'), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ call assert_equal('Argument missing after: "--display"', out[1])
+ call assert_equal('More info with: "vim -h"', out[2])
+ endif
+
+ if has('xterm_clipboard')
+ let out = split(system(GetVimCommand() .. ' -display'), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ call assert_equal('Argument missing after: "-display"', out[1])
+ call assert_equal('More info with: "vim -h"', out[2])
+ endif
let out = split(system(GetVimCommand() .. ' -ix'), "\n")
call assert_equal(1, v:shell_error)
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index 8c81ec3431..7efd181d04 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -412,3 +412,22 @@ func Test_statusline_removed_group()
call StopVimInTerminal(buf)
call delete('XTest_statusline')
endfunc
+
+func Test_statusline_after_split_vsplit()
+ only
+
+ " Make the status line of each window show the window number.
+ set ls=2 stl=%{winnr()}
+
+ split | redraw
+ vsplit | redraw
+
+ " The status line of the third window should read '3' here.
+ call assert_equal('3', nr2char(screenchar(&lines - 1, 1)))
+
+ only
+ set ls& stl&
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index e072e9ed7f..f27920d20f 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -1,5 +1,7 @@
" Tests for the swap feature
+source check.vim
+
func s:swapname()
return trim(execute('swapname'))
endfunc
@@ -305,3 +307,61 @@ func Test_swap_recover_ext()
augroup END
augroup! test_swap_recover_ext
endfunc
+
+" Test for selecting 'q' in the attention prompt
+func Test_swap_prompt_splitwin()
+ CheckRunVimInTerminal
+
+ call writefile(['foo bar'], 'Xfile1')
+ edit Xfile1
+ preserve " should help to make sure the swap file exists
+
+ let buf = RunVimInTerminal('', {'rows': 20})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":set noruler\n")
+ call term_sendkeys(buf, ":split Xfile1\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))})
+ call term_sendkeys(buf, "q")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":\<CR>")
+ call WaitForAssert({-> assert_match('^:$', term_getline(buf, 20))})
+ call term_sendkeys(buf, ":echomsg winnr('$')\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
+ call StopVimInTerminal(buf)
+ %bwipe!
+ call delete('Xfile1')
+endfunc
+
+func Test_swap_symlink()
+ if !has("unix")
+ return
+ endif
+
+ call writefile(['text'], 'Xtestfile')
+ silent !ln -s -f Xtestfile Xtestlink
+
+ set dir=.
+
+ " Test that swap file uses the name of the file when editing through a
+ " symbolic link (so that editing the file twice is detected)
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ call mkdir('Xswapdir')
+ exe 'set dir=' . getcwd() . '/Xswapdir//'
+
+ " Check that this also works when 'directory' ends with '//'
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ set dir&
+ call delete('Xtestfile')
+ call delete('Xtestlink')
+ call delete('Xswapdir', 'rf')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 85ee42420e..2617aa3945 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -369,7 +369,11 @@ func Test_ownsyntax()
call setline(1, '#define FOO')
syntax on
set filetype=c
+
ownsyntax perl
+ " this should not crash
+ set
+
call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name'))
call assert_equal('c', b:current_syntax)
call assert_equal('perl', w:current_syntax)
@@ -471,6 +475,40 @@ func Test_bg_detection()
hi Normal ctermbg=NONE
endfunc
+func Test_syntax_hangs()
+ if !has('reltime') || !has('float') || !has('syntax')
+ return
+ endif
+
+ " This pattern takes a long time to match, it should timeout.
+ new
+ call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
+ let start = reltime()
+ set nolazyredraw redrawtime=101
+ syn match Error /\%#=1a*.*X\@<=b*/
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ " second time syntax HL is disabled
+ let start = reltime()
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed < 0.1)
+
+ " after CTRL-L the timeout flag is reset
+ let start = reltime()
+ exe "normal \<C-L>"
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ set redrawtime&
+ bwipe!
+endfunc
+
func Test_synstack_synIDtrans()
new
setfiletype c
@@ -546,38 +584,42 @@ func Test_syn_wrong_z_one()
bwipe!
endfunc
-func Test_syntax_hangs()
- if !has('reltime') || !has('float') || !has('syntax')
- return
- endif
-
- " This pattern takes a long time to match, it should timeout.
- new
- call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
- let start = reltime()
- set nolazyredraw redrawtime=101
- syn match Error /\%#=1a*.*X\@<=b*/
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
-
- " second time syntax HL is disabled
- let start = reltime()
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed < 0.1)
+func Test_syntax_after_bufdo()
+ call writefile(['/* aaa comment */'], 'Xaaa.c')
+ call writefile(['/* bbb comment */'], 'Xbbb.c')
+ call writefile(['/* ccc comment */'], 'Xccc.c')
+ call writefile(['/* ddd comment */'], 'Xddd.c')
+
+ let bnr = bufnr('%')
+ new Xaaa.c
+ badd Xbbb.c
+ badd Xccc.c
+ badd Xddd.c
+ exe "bwipe " . bnr
+ let l = []
+ bufdo call add(l, bufnr('%'))
+ call assert_equal(4, len(l))
- " after CTRL-L the timeout flag is reset
- let start = reltime()
- exe "normal \<C-L>"
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
+ syntax on
- set redrawtime&
- bwipe!
+ " This used to only enable syntax HL in the last buffer.
+ bufdo tab split
+ tabrewind
+ for tab in range(1, 4)
+ norm fm
+ call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ tabnext
+ endfor
+
+ bwipe! Xaaa.c
+ bwipe! Xbbb.c
+ bwipe! Xccc.c
+ bwipe! Xddd.c
+ syntax off
+ call delete('Xaaa.c')
+ call delete('Xbbb.c')
+ call delete('Xccc.c')
+ call delete('Xddd.c')
endfunc
func Test_syntax_foldlevel()
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 6abe5b7c89..7057cdefb2 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -1,5 +1,8 @@
" Tests for tagjump (tags and special searches)
+source check.vim
+source screendump.vim
+
" SEGV occurs in older versions. (At least 7.4.1748 or older)
func Test_ptag_with_notagstack()
set notagstack
@@ -551,6 +554,37 @@ func Test_tag_line_toolong()
let &verbose = old_vbs
endfunc
+" Check that using :tselect does not run into the hit-enter prompt.
+" Requires a terminal to trigger that prompt.
+func Test_tselect()
+ CheckScreendump
+
+ call writefile([
+ \ 'main Xtest.h /^void test();$/;" f',
+ \ 'main Xtest.c /^int main()$/;" f',
+ \ 'main Xtest.x /^void test()$/;" f',
+ \ ], 'Xtags')
+ cal writefile([
+ \ 'int main()',
+ \ 'void test()',
+ \ ], 'Xtest.c')
+
+ let lines =<< trim [SCRIPT]
+ set tags=Xtags
+ [SCRIPT]
+ call writefile(lines, 'XTest_tselect')
+ let buf = RunVimInTerminal('-S XTest_tselect', {'rows': 10, 'cols': 50})
+
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, ":tselect main\<CR>2\<CR>")
+ call VerifyScreenDump(buf, 'Test_tselect_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xtags')
+ call delete('Xtest.c')
+ call delete('XTest_tselect')
+endfunc
+
func Test_tagline()
call writefile([
\ 'provision Xtest.py /^ def provision(self, **kwargs):$/;" m line:1 language:Python class:Foo',
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 75673adf0a..2223be952c 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -1,4 +1,7 @@
" Tests for the various 'formatoptions' settings
+
+source check.vim
+
func Test_text_format()
enew!
@@ -490,6 +493,23 @@ func Test_format_list_auto()
set fo& ai& bs&
endfunc
+func Test_crash_github_issue_5095()
+ CheckFeature autocmd
+
+ " This used to segfault, see https://github.com/vim/vim/issues/5095
+ augroup testing
+ au BufNew x center
+ augroup END
+
+ next! x
+
+ bw
+ augroup testing
+ au!
+ augroup END
+ augroup! testing
+endfunc
+
" Test for formatting multi-byte text with 'fo=t'
func Test_tw_2_fo_t()
new
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index 7863317eb0..f70cc1f70a 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -152,6 +152,36 @@ func Test_string_html_objects()
normal! dit
call assert_equal('-<b></b>', getline('.'))
+ " copy the tag block from leading indentation before the start tag
+ let t = " <b>\ntext\n</b>"
+ $put =t
+ normal! 2kvaty
+ call assert_equal("<b>\ntext\n</b>", @")
+
+ " copy the tag block from the end tag
+ let t = "<title>\nwelcome\n</title>"
+ $put =t
+ normal! $vaty
+ call assert_equal("<title>\nwelcome\n</title>", @")
+
+ " copy the outer tag block from a tag without an end tag
+ let t = "<html>\n<title>welcome\n</html>"
+ $put =t
+ normal! k$vaty
+ call assert_equal("<html>\n<title>welcome\n</html>", @")
+
+ " nested tag that has < in a different line from >
+ let t = "<div><div\n></div></div>"
+ $put =t
+ normal! k0vaty
+ call assert_equal("<div><div\n></div></div>", @")
+
+ " nested tag with attribute that has < in a different line from >
+ let t = "<div><div\nattr=\"attr\"\n></div></div>"
+ $put =t
+ normal! 2k0vaty
+ call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @")
+
set quoteescape&
enew!
endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index cffd80ff4f..13971a918d 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -233,16 +233,17 @@ func Test_timer_catch_error()
endfunc
func FeedAndPeek(timer)
- call test_feedinput('a')
+ " call test_feedinput('a')
+ call nvim_input('a')
call getchar(1)
endfunc
func Interrupt(timer)
- call test_feedinput("\<C-C>")
+ " call test_feedinput("\<C-C>")
+ call nvim_input("\<C-C>")
endfunc
func Test_peek_and_get_char()
- throw 'skipped: Nvim does not support test_feedinput()'
if !has('unix') && !has('gui_running')
return
endif
@@ -339,6 +340,41 @@ func Test_nocatch_garbage_collect()
delfunc FeedChar
endfunc
+func Test_error_in_timer_callback()
+ if !has('terminal') || (has('win32') && has('gui_running'))
+ throw 'Skipped: cannot run Vim in a terminal window'
+ endif
+
+ let lines =<< trim [CODE]
+ func Func(timer)
+ " fail to create list
+ let x = [
+ endfunc
+ set updatetime=50
+ call timer_start(1, 'Func')
+ [CODE]
+ call writefile(lines, 'Xtest.vim')
+
+ let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
+ let job = term_getjob(buf)
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 8))})
+
+ " GC must not run during timer callback, which can make Vim crash.
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "\<CR>")
+ call term_wait(buf, 100)
+ call assert_equal('run', job_status(job))
+
+ call term_sendkeys(buf, ":qall!\<CR>")
+ call WaitFor({-> job_status(job) ==# 'dead'})
+ if has('unix')
+ call assert_equal('', job_info(job).termsig)
+ endif
+
+ call delete('Xtest.vim')
+ exe buf .. 'bwipe!'
+endfunc
+
func Test_timer_invalid_callback()
call assert_fails('call timer_start(0, "0")', 'E921')
endfunc
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index adcdcb1cd9..3b66071d6d 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -364,6 +364,25 @@ func Test_wundo_errors()
bwipe!
endfunc
+" Check that reading a truncted undo file doesn't hang.
+func Test_undofile_truncated()
+ throw 'skipped: TODO: '
+ new
+ call setline(1, 'hello')
+ set ul=100
+ wundo Xundofile
+ let contents = readfile('Xundofile', 'B')
+
+ " try several sizes
+ for size in range(20, 500, 33)
+ call writefile(contents[0:size], 'Xundofile')
+ call assert_fails('rundo Xundofile', 'E825:')
+ endfor
+
+ bwipe!
+ call delete('Xundofile')
+endfunc
+
func Test_rundo_errors()
call assert_fails('rundo XfileDoesNotExist', 'E822:')
@@ -373,6 +392,26 @@ func Test_rundo_errors()
call delete('Xundofile')
endfunc
+func Test_undofile_next()
+ set undofile
+ new Xfoo.txt
+ execute "norm ix\<c-g>uy\<c-g>uz\<Esc>"
+ write
+ bwipe
+
+ next Xfoo.txt
+ call assert_equal('xyz', getline(1))
+ silent undo
+ call assert_equal('xy', getline(1))
+ silent undo
+ call assert_equal('x', getline(1))
+ bwipe!
+
+ call delete('Xfoo.txt')
+ call delete('.Xfoo.txt.un~')
+ set undofile&
+endfunc
+
" Test for undo working properly when executing commands from a register.
" Also test this in an empty buffer.
func Test_cmd_in_reg_undo()
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index 2c7cb7bab7..0a89066a2b 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -184,6 +184,34 @@ func Test_Ambiguous()
call assert_fails("\x4ei\041", 'E492: Not an editor command: Ni!')
endfunc
+func Test_redefine_on_reload()
+ call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists')
+ call assert_equal(0, exists(':ExistingCommand'))
+ source Xcommandexists
+ call assert_equal(2, exists(':ExistingCommand'))
+ " Redefining a command when reloading a script is OK.
+ source Xcommandexists
+ call assert_equal(2, exists(':ExistingCommand'))
+
+ " But redefining in another script is not OK.
+ call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists2')
+ call assert_fails('source Xcommandexists2', 'E174:')
+ call delete('Xcommandexists2')
+
+ " And defining twice in one script is not OK.
+ delcommand ExistingCommand
+ call assert_equal(0, exists(':ExistingCommand'))
+ call writefile([
+ \ 'command ExistingCommand echo "yes"',
+ \ 'command ExistingCommand echo "no"',
+ \ ], 'Xcommandexists')
+ call assert_fails('source Xcommandexists', 'E174:')
+ call assert_equal(2, exists(':ExistingCommand'))
+
+ call delete('Xcommandexists')
+ delcommand ExistingCommand
+endfunc
+
func Test_CmdUndefined()
call assert_fails('Doit', 'E492:')
au CmdUndefined Doit :command Doit let g:didit = 'yes'
@@ -248,7 +276,7 @@ func Test_CmdCompletion()
call assert_equal('"com -nargs=* + 0 1 ?', @:)
call feedkeys(":com -addr=\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"com -addr=arguments buffers lines loaded_buffers quickfix tabs windows', @:)
+ call assert_equal('"com -addr=arguments buffers lines loaded_buffers other quickfix tabs windows', @:)
call feedkeys(":com -complete=co\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -complete=color command compiler', @:)
@@ -312,3 +340,202 @@ func Test_use_execute_in_completion()
call assert_equal('"DoExec hi', @:)
delcommand DoExec
endfunc
+
+func Test_addr_all()
+ throw 'skipped: requires patch v8.1.0341 to pass'
+ command! -addr=lines DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(line('$'), g:a2)
+
+ command! -addr=arguments DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ args one two three
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(3, g:a2)
+
+ command! -addr=buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if buflisted(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ call assert_equal(bufnr('$'), g:a2)
+
+ command! -addr=loaded_buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if bufloaded(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ for up in range(bufnr('$'), 1, -1)
+ if bufloaded(up)
+ break
+ endif
+ endfor
+ call assert_equal(up, g:a2)
+
+ command! -addr=windows DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ new
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(winnr('$'), g:a2)
+ bwipe
+
+ command! -addr=tabs DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ tabnew
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(len(gettabinfo()), g:a2)
+ bwipe
+
+ command! -addr=other DoSomething echo 'nothing'
+ DoSomething
+ call assert_fails('%DoSomething')
+
+ delcommand DoSomething
+endfunc
+
+func Test_command_list()
+ command! DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :",
+ \ execute('command DoCmd'))
+
+ " Test with various -range= and -count= argument values.
+ command! -range DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . :",
+ \ execute('command DoCmd'))
+ command! -range=% DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 % :",
+ \ execute('command! DoCmd'))
+ command! -range=2 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 2 :",
+ \ execute('command DoCmd'))
+ command! -count=2 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 2c :",
+ \ execute('command DoCmd'))
+
+ " Test with various -addr= argument values.
+ command! -addr=lines DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . :",
+ \ execute('command DoCmd'))
+ command! -addr=arguments DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . arg :",
+ \ execute('command DoCmd'))
+ command! -addr=buffers DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . buf :",
+ \ execute('command DoCmd'))
+ command! -addr=loaded_buffers DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . load :",
+ \ execute('command DoCmd'))
+ command! -addr=windows DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . win :",
+ \ execute('command DoCmd'))
+ command! -addr=tabs DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . tab :",
+ \ execute('command DoCmd'))
+ command! -addr=other DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . ? :",
+ \ execute('command DoCmd'))
+
+ " Test with various -complete= argument values (non-exhaustive list)
+ command! -complete=arglist DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 arglist :",
+ \ execute('command DoCmd'))
+ command! -complete=augroup DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 augroup :",
+ \ execute('command DoCmd'))
+ command! -complete=custom,CustomComplete DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 custom :",
+ \ execute('command DoCmd'))
+ command! -complete=customlist,CustomComplete DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 customlist :",
+ \ execute('command DoCmd'))
+
+ " Test with various -narg= argument values.
+ command! -nargs=0 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -nargs=1 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 1 :",
+ \ execute('command DoCmd'))
+ command! -nargs=* DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd * :",
+ \ execute('command DoCmd'))
+ command! -nargs=? DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd ? :",
+ \ execute('command DoCmd'))
+ command! -nargs=+ DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd + :",
+ \ execute('command DoCmd'))
+
+ " Test with other arguments.
+ command! -bang DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n! DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -bar DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n| DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -register DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n\" DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -buffer DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\nb DoCmd 0 :"
+ \ .. "\n\" DoCmd 0 :",
+ \ execute('command DoCmd'))
+ comclear
+
+ " Test with many args.
+ command! -bang -bar -register -buffer -nargs=+ -complete=environment -addr=windows -count=3 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n!\"b|DoCmd + 3c win environment :",
+ \ execute('command DoCmd'))
+ comclear
+
+ " Test with special characters in command definition.
+ command! DoCmd :<cr><tab><c-d>
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :<CR><Tab><C-D>",
+ \ execute('command DoCmd'))
+
+ " Test output in verbose mode.
+ command! DoCmd :
+ call assert_match("^\n"
+ \ .. " Name Args Address Complete Definition\n"
+ \ .. " DoCmd 0 :\n"
+ \ .. "\tLast set from .*/test_usercommands.vim line \\d\\+$",
+ \ execute('verbose command DoCmd'))
+
+ comclear
+ call assert_equal("\nNo user-defined commands found", execute(':command Xxx'))
+ call assert_equal("\nNo user-defined commands found", execute('command'))
+endfunc
diff --git a/src/nvim/testdir/test_version.vim b/src/nvim/testdir/test_version.vim
new file mode 100644
index 0000000000..46cf34979f
--- /dev/null
+++ b/src/nvim/testdir/test_version.vim
@@ -0,0 +1,12 @@
+" Test :version Ex command
+
+func Test_version()
+ " version should always return the same string.
+ let v1 = execute('version')
+ let v2 = execute('version')
+ call assert_equal(v1, v2)
+
+ call assert_match("^\n\nNVIM v[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+.*", v1)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index d2f13ff072..cb81997d39 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1409,6 +1409,17 @@ func Test_compound_assignment_operators()
let @/ = ''
endfunc
+func Test_funccall_garbage_collect()
+ func Func(x, ...)
+ call add(a:x, a:000)
+ endfunc
+ call Func([], [])
+ " Must not crash cause by invalid freeing
+ call test_garbagecollect_now()
+ call assert_true(v:true)
+ delfunc Func
+endfunc
+
func Test_function_defined_line()
if has('gui_running')
" Can't catch the output of gvim.
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 7fc8cdd7f4..734f264672 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -432,3 +432,14 @@ func Test_Visual_Block()
close!
endfunc
+
+func Test_visual_put_in_block()
+ new
+ call setline(1, ['xxxx', 'yโˆžyy', 'zzzz'])
+ normal 1G2yl
+ exe "normal 1G2l\<C-V>jjlp"
+ call assert_equal(['xxxx', 'yโˆžxx', 'zzxx'], getline(1, 3))
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index aaa291f87d..500e3ff088 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -841,4 +841,50 @@ func Test_winnr()
only | tabonly
endfunc
+func Test_window_resize()
+ " Vertical :resize (absolute, relative, min and max size).
+ vsplit
+ vert resize 8
+ call assert_equal(8, winwidth(0))
+ vert resize +2
+ call assert_equal(10, winwidth(0))
+ vert resize -2
+ call assert_equal(8, winwidth(0))
+ vert resize
+ call assert_equal(&columns - 2, winwidth(0))
+ vert resize 0
+ call assert_equal(1, winwidth(0))
+ vert resize 99999
+ call assert_equal(&columns - 2, winwidth(0))
+
+ %bwipe!
+
+ " Horizontal :resize (with absolute, relative size, min and max size).
+ split
+ resize 8
+ call assert_equal(8, winheight(0))
+ resize +2
+ call assert_equal(10, winheight(0))
+ resize -2
+ call assert_equal(8, winheight(0))
+ resize
+ call assert_equal(&lines - 4, winheight(0))
+ resize 0
+ call assert_equal(1, winheight(0))
+ resize 99999
+ call assert_equal(&lines - 4, winheight(0))
+
+ " :resize with explicit window number.
+ let other_winnr = winnr('j')
+ exe other_winnr .. 'resize 10'
+ call assert_equal(10, winheight(other_winnr))
+ call assert_equal(&lines - 10 - 3, winheight(0))
+ exe other_winnr .. 'resize +1'
+ exe other_winnr .. 'resize +1'
+ call assert_equal(12, winheight(other_winnr))
+ call assert_equal(&lines - 10 - 3 -2, winheight(0))
+
+ %bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bfd9435c49..62d7dc8b18 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -52,15 +52,10 @@
#define OUTBUF_SIZE 0xffff
#define TOO_MANY_EVENTS 1000000
-#define STARTS_WITH(str, prefix) \
- (strlen(str) >= (sizeof(prefix) - 1) && 0 == memcmp((str), (prefix), \
- sizeof(prefix) - 1))
-#define SCREEN_WRAP(is_screen, seq) ((is_screen) \
- ? DCS_STR seq STERM_STR : seq)
-#define SCREEN_TMUX_WRAP(is_screen, is_tmux, seq) \
- ((is_screen) \
- ? DCS_STR seq STERM_STR : (is_tmux) \
- ? DCS_STR "tmux;\x1b" seq STERM_STR : seq)
+#define STARTS_WITH(str, prefix) (strlen(str) >= (sizeof(prefix) - 1) \
+ && 0 == memcmp((str), (prefix), sizeof(prefix) - 1))
+#define TMUX_WRAP(is_tmux, seq) ((is_tmux) \
+ ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
#define LINUXSET0C "\x1b[?0c"
#define LINUXSET1C "\x1b[?1c"
@@ -113,6 +108,7 @@ typedef struct {
bool cork, overflow;
bool cursor_color_changed;
bool is_starting;
+ FILE *screenshot;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
kvec_t(HlAttrs) attrs;
@@ -172,6 +168,7 @@ UI *tui_start(void)
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon;
+ ui->screenshot = tui_screenshot;
ui->option_set= tui_option_set;
ui->raw_line = tui_raw_line;
@@ -319,7 +316,13 @@ static void terminfo_start(UI *ui)
#ifdef WIN32
uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
#else
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ int retry_count = 10;
+ // A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
+ // few times. #12322
+ while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR
+ && retry_count > 0) {
+ retry_count--;
+ }
#endif
} else {
uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
@@ -417,6 +420,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
data->bridge = bridge;
data->loop = &tui_loop;
data->is_starting = true;
+ data->screenshot = NULL;
kv_init(data->invalid_regions);
signal_watcher_init(data->loop, &data->winch_handle, ui);
signal_watcher_init(data->loop, &data->cont_handle, data);
@@ -1085,6 +1089,7 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
} else if (c.id == 0) {
// No cursor color for this mode; reset to default.
+ data->want_invisible = false;
unibi_out_ext(ui, data->unibi_ext.reset_cursor_color);
}
@@ -1103,6 +1108,15 @@ static void tui_set_mode(UI *ui, ModeShape mode)
static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
{
TUIData *data = ui->data;
+#ifdef UNIX
+ // If stdin is not a TTY, the LHS of pipe may change the state of the TTY
+ // after calling uv_tty_set_mode. So, set the mode of the TTY again here.
+ // #13073
+ if (data->is_starting && data->input.in_fd == STDERR_FILENO) {
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ }
+#endif
tui_set_mode(ui, (ModeShape)mode_idx);
data->is_starting = false; // mode entered, no longer starting
data->showing_mode = (ModeShape)mode_idx;
@@ -1322,6 +1336,31 @@ static void tui_set_icon(UI *ui, String icon)
{
}
+static void tui_screenshot(UI *ui, String path)
+{
+ TUIData *data = ui->data;
+ UGrid *grid = &data->grid;
+ flush_buf(ui);
+ grid->row = 0;
+ grid->col = 0;
+
+ FILE *f = fopen(path.data, "w");
+ data->screenshot = f;
+ fprintf(f, "%d,%d\n", grid->height, grid->width);
+ unibi_out(ui, unibi_clear_screen);
+ for (int i = 0; i < grid->height; i++) {
+ cursor_goto(ui, i, 0);
+ for (int j = 0; j < grid->width; j++) {
+ print_cell(ui, &grid->cells[i][j]);
+ }
+ }
+ flush_buf(ui);
+ data->screenshot = NULL;
+
+ fclose(f);
+}
+
+
static void tui_option_set(UI *ui, String name, Object value)
{
TUIData *data = ui->data;
@@ -1591,10 +1630,6 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool mate_pretending_xterm = xterm && colorterm
&& strstr(colorterm, "mate-terminal");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
- bool true_screen = screen && !os_getenv("TMUX");
- bool screen_host_linuxvt =
- terminfo_is_term_family(true_screen && term[6] == '.'
- ? term + 7 : NULL, "linux");
bool cygwin = terminfo_is_term_family(term, "cygwin");
char *fix_normal = (char *)unibi_get_str(ut, unibi_cursor_normal);
@@ -1737,10 +1772,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
#define XTERM_SETAB_16 \
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m"
- data->unibi_ext.get_bg =
- (int)unibi_add_ext_str(ut, "ext.get_bg",
- SCREEN_TMUX_WRAP(true_screen,
- tmux, "\x1b]11;?\x07"));
+ data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
+ "\x1b]11;?\x07");
// Terminals with 256-colour SGR support despite what terminfo says.
if (unibi_get_num(ut, unibi_max_colors) < 256) {
@@ -1775,32 +1808,6 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
}
- // GNU Screen does not have Ss/Se. When terminfo has Ss/Se, it is wrapped with
- // DCS because it is inherited from the host terminal.
- if (true_screen) {
- size_t len;
- size_t dcs_st_len = strlen(DCS_STR) + strlen(STERM_STR);
- if (-1 != data->unibi_ext.set_cursor_style) {
- const char *orig_ss =
- unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style);
- len = STRLEN(orig_ss) + dcs_st_len + 1;
- char *ss = xmalloc(len);
- snprintf(ss, len, "%s%s%s", DCS_STR, orig_ss, STERM_STR);
- unibi_set_ext_str(data->ut, (size_t)data->unibi_ext.set_cursor_style, ss);
- xfree(ss);
- }
- if (-1 != data->unibi_ext.reset_cursor_style) {
- const char *orig_se =
- unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style);
- len = strlen(orig_se) + dcs_st_len + 1;
- char *se = xmalloc(len);
- snprintf(se, len, "%s%s%s", DCS_STR, orig_se, STERM_STR);
- unibi_set_ext_str(data->ut,
- (size_t)data->unibi_ext.reset_cursor_style, se);
- xfree(se);
- }
- }
-
// Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So
// adding them to terminal types, that have such control sequences but lack
// the correct terminfo entries, is a fixup, not an augmentation.
@@ -1816,12 +1823,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| (konsolev >= 180770) // #9364
|| tmux // per tmux manual page
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
- || (true_screen
- && (!screen_host_linuxvt
- || (screen_host_linuxvt
- && (xterm_version || (vte_version > 0) || colorterm))))
- // Since GNU Screen does not support DECSCUSR, DECSCUSR is wrapped
- // in DCS and output to the host terminal.
+ || screen
|| st // #7641
|| rxvt // per command.C
// per analysis of VT100Terminal.m
@@ -1834,72 +1836,58 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| (linuxvt
&& (xterm_version || (vte_version > 0) || colorterm)))) {
data->unibi_ext.set_cursor_style =
- (int)unibi_add_ext_str(ut, "Ss",
- SCREEN_WRAP(true_screen, "\x1b[%p1%d q"));
+ (int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- SCREEN_WRAP(true_screen, "\x1b[ q"));
- } else if (linuxvt || screen_host_linuxvt) {
+ "\x1b[ q");
+ } else if (linuxvt) {
// Linux uses an idiosyncratic escape code to set the cursor shape and
// does not support DECSCUSR.
// See http://linuxgazette.net/137/anonymous.html for more info
- //
- // Since gnu Screen does not have Ss/Se, if the host terminal is a linux
- // console that does not support xterm extensions, it will wraps the
- // linux-specific sequence in DCS and outputs it.
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(
- ut, "Ss",
- SCREEN_WRAP(true_screen,
- "\x1b[?"
- "%?"
- // The parameter passed to Ss is the DECSCUSR parameter,
- // so the
- // terminal capability has to translate into the Linux
- // idiosyncratic parameter.
- //
- // linuxvt only supports block and underline. It is also
- // only possible to have a steady block (no steady
- // underline)
- "%p1%{2}%<" "%t%{8}" // blink block
- "%e%p1%{2}%=" "%t%{112}" // steady block
- "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half
- // block)
- "%e%p1%{4}%=" "%t%{4}" // steady underline
- "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
- "%e%p1%{6}%=" "%t%{2}" // steady bar
- "%e%{0}" // anything else
- "%;" "%dc"));
+ data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
+ "\x1b[?"
+ "%?"
+ // The parameter passed to Ss is the DECSCUSR parameter, so the
+ // terminal capability has to translate into the Linux idiosyncratic
+ // parameter.
+ //
+ // linuxvt only supports block and underline. It is also only
+ // possible to have a steady block (no steady underline)
+ "%p1%{2}%<" "%t%{8}" // blink block
+ "%e%p1%{2}%=" "%t%{112}" // steady block
+ "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
+ "%e%p1%{4}%=" "%t%{4}" // steady underline
+ "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
+ "%e%p1%{6}%=" "%t%{2}" // steady bar
+ "%e%{0}" // anything else
+ "%;" "%dc");
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- SCREEN_WRAP(true_screen, "\x1b[?c"));
+ "\x1b[?c");
} else if (konsolev > 0 && konsolev < 180770) {
// Konsole before version 18.07.70: set up a nonce profile. This has
// side-effects on temporary font resizing. #6798
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(
- ut, "Ss",
- SCREEN_TMUX_WRAP(true_screen, tmux,
- "\x1b]50;CursorShape=%?"
- "%p1%{3}%<" "%t%{0}" // block
- "%e%p1%{5}%<" "%t%{2}" // underline
- "%e%{1}" // everything else is bar
- "%;%d;BlinkingCursorEnabled=%?"
- "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude
- // zero as special,
- "%e%p1%{1}%&" // in all other c2ses we can treat bit
- // #0 as a flag.
- "%;%d\x07"));
+ data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
+ TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?"
+ "%p1%{3}%<" "%t%{0}" // block
+ "%e%p1%{5}%<" "%t%{2}" // underline
+ "%e%{1}" // everything else is bar
+ "%;%d;BlinkingCursorEnabled=%?"
+ "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
+ "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
+ "%;%d\x07"));
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- SCREEN_TMUX_WRAP(true_screen, tmux, "\x1b]50;\x07"));
+ "\x1b]50;\x07");
}
}
}
@@ -1931,10 +1919,6 @@ static void augment_terminfo(TUIData *data, const char *term,
const char *xterm_version = os_getenv("XTERM_VERSION");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
- bool true_screen = screen && !os_getenv("TMUX");
- bool screen_host_rxvt =
- terminfo_is_term_family(true_screen
- && term[6] == '.' ? term + 7 : NULL, "rxvt");
// Only define this capability for terminal types that we know understand it.
if (dtterm // originated this extension
@@ -2001,7 +1985,7 @@ static void augment_terminfo(TUIData *data, const char *term,
// all panes, which is not particularly desirable. A better approach
// would use a tmux control sequence and an extra if(screen) test.
data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
- ut, NULL, SCREEN_TMUX_WRAP(true_screen, tmux, "\033]Pl%p1%06x\033\\"));
+ ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
} else if ((xterm || rxvt || tmux || alacritty)
&& (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
@@ -2021,27 +2005,21 @@ static void augment_terminfo(TUIData *data, const char *term,
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
- /// If the DECSET is not supported by GNU Screen, it is wrapped with DCS and
- /// sent to the host terminal.
data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(
ut, "ext.enable_lr_margin", "\x1b[?69h");
data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(
ut, "ext.disable_lr_margin", "\x1b[?69l");
data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.enable_bpaste", SCREEN_WRAP(true_screen, "\x1b[?2004h"));
+ ut, "ext.enable_bpaste", "\x1b[?2004h");
data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.disable_bpaste", SCREEN_WRAP(true_screen, "\x1b[?2004l"));
+ ut, "ext.disable_bpaste", "\x1b[?2004l");
// For urxvt send BOTH xterm and old urxvt sequences. #8695
data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(
ut, "ext.enable_focus",
- (rxvt || screen_host_rxvt)
- ? SCREEN_WRAP(true_screen, "\x1b[?1004h\x1b]777;focus;on\x7")
- : SCREEN_WRAP(true_screen, "\x1b[?1004h"));
+ rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(
ut, "ext.disable_focus",
- (rxvt || screen_host_rxvt)
- ? SCREEN_WRAP(true_screen, "\x1b[?1004l\x1b]777;focus;off\x7")
- : SCREEN_WRAP(true_screen, "\x1b[?1004l"));
+ rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(
ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h");
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(
@@ -2120,9 +2098,15 @@ static void flush_buf(UI *ui)
}
}
- uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
- bufs, (unsigned)(bufp - bufs), NULL);
- uv_run(&data->write_loop, UV_RUN_DEFAULT);
+ if (data->screenshot) {
+ for (size_t i = 0; i < (size_t)(bufp - bufs); i++) {
+ fwrite(bufs[i].base, bufs[i].len, 1, data->screenshot);
+ }
+ } else {
+ uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
+ bufs, (unsigned)(bufp - bufs), NULL);
+ uv_run(&data->write_loop, UV_RUN_DEFAULT);
+ }
data->bufpos = 0;
data->overflow = false;
}
diff --git a/src/nvim/types.h b/src/nvim/types.h
index 87560a43da..a3d87f35ca 100644
--- a/src/nvim/types.h
+++ b/src/nvim/types.h
@@ -16,11 +16,13 @@ typedef uint32_t u8char_T;
// Opaque handle used by API clients to refer to various objects in vim
typedef int handle_T;
-// Opaque handle to a lua value. Must be free with `executor_free_luaref` when
+// Opaque handle to a lua value. Must be free with `api_free_luaref` when
// not needed anymore! LUA_NOREF represents missing reference, i e to indicate
// absent callback etc.
typedef int LuaRef;
+typedef uint64_t NS;
+
typedef struct expand expand_T;
typedef enum {
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 9a1988739c..25f45b8fe6 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -61,6 +61,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title;
rv->bridge.set_icon = ui_bridge_set_icon;
+ rv->bridge.screenshot = ui_bridge_screenshot;
rv->bridge.option_set = ui_bridge_option_set;
rv->bridge.raw_line = ui_bridge_raw_line;
rv->bridge.inspect = ui_bridge_inspect;
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 97018f6c02..6c5a6cdb46 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -878,7 +878,12 @@ static u_header_T *unserialize_uhp(bufinfo_T *bi,
for (;; ) {
int len = undo_read_byte(bi);
- if (len == 0 || len == EOF) {
+ if (len == EOF) {
+ corruption_error("truncated", file_name);
+ u_free_uhp(uhp);
+ return NULL;
+ }
+ if (len == 0) {
break;
}
int what = undo_read_byte(bi);
@@ -3029,8 +3034,6 @@ u_header_T *u_force_get_undo_header(buf_T *buf)
curbuf = buf;
// Args are tricky: this means replace empty range by empty range..
u_savecommon(0, 1, 1, true);
- curbuf = save_curbuf;
-
uhp = buf->b_u_curhead;
if (!uhp) {
uhp = buf->b_u_newhead;
@@ -3038,6 +3041,7 @@ u_header_T *u_force_get_undo_header(buf_T *buf)
abort();
}
}
+ curbuf = save_curbuf;
}
return uhp;
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 190f13e74b..32cb0091a3 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -144,7 +144,7 @@ static const int included_patches[] = {
1777,
1776,
1775,
- // 1774,
+ 1774,
1773,
1772,
1771,
@@ -171,9 +171,9 @@ static const int included_patches[] = {
1750,
1749,
1748,
- // 1747,
+ 1747,
1746,
- // 1745,
+ 1745,
// 1744,
// 1743,
1742,
@@ -206,7 +206,7 @@ static const int included_patches[] = {
1715,
1714,
1713,
- // 1712,
+ 1712,
1711,
1710,
1709,
@@ -327,9 +327,9 @@ static const int included_patches[] = {
1594,
1593,
// 1592,
- // 1591,
+ 1591,
1590,
- // 1589,
+ 1589,
// 1588,
1587,
1586,
@@ -374,7 +374,7 @@ static const int included_patches[] = {
1547,
1546,
1545,
- // 1544,
+ 1544,
1543,
1542,
1541,
@@ -387,7 +387,7 @@ static const int included_patches[] = {
1534,
1533,
1532,
- // 1531,
+ 1531,
1530,
1529,
1528,
@@ -464,7 +464,7 @@ static const int included_patches[] = {
1457,
1456,
// 1455,
- // 1454,
+ 1454,
1453,
1452,
1451,
@@ -2119,13 +2119,13 @@ void list_in_columns(char_u **items, int size, int current)
void list_lua_version(void)
{
- typval_T luaver_tv;
- typval_T arg = { .v_type = VAR_UNKNOWN }; // No args.
- char *luaver_expr = "((jit and jit.version) and jit.version or _VERSION)";
- executor_eval_lua(cstr_as_string(luaver_expr), &arg, &luaver_tv);
- assert(luaver_tv.v_type == VAR_STRING);
- MSG(luaver_tv.vval.v_string);
- xfree(luaver_tv.vval.v_string);
+ char *code = "return ((jit and jit.version) and jit.version or _VERSION)";
+ Error err = ERROR_INIT;
+ Object ret = nlua_exec(cstr_as_string(code), (Array)ARRAY_DICT_INIT, &err);
+ assert(!ERROR_SET(&err));
+ assert(ret.type == kObjectTypeString);
+ MSG(ret.data.string.data);
+ api_free_object(ret);
}
void list_version(void)
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index b77b80a5f3..44b6ab5f5a 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -1431,7 +1431,7 @@ static inline void east_set_error(const ParserState *const pstate,
const ParserLine pline = pstate->reader.lines.items[start.line];
ret_ast_err->msg = msg;
ret_ast_err->arg_len = (int)(pline.size - start.col);
- ret_ast_err->arg = pline.data + start.col;
+ ret_ast_err->arg = pline.data ? pline.data + start.col : NULL;
}
/// Set error from the given token and given message
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 0fff93d984..4931221e7a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1490,13 +1490,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & (WSP_TOP | WSP_BOT))
(void)win_comp_pos();
- /*
- * Both windows need redrawing
- */
+ // Both windows need redrawing. Update all status lines, in case they
+ // show something related to the window count or position.
redraw_win_later(wp, NOT_VALID);
- wp->w_redr_status = TRUE;
redraw_win_later(oldwin, NOT_VALID);
- oldwin->w_redr_status = TRUE;
+ status_redraw_all();
if (need_status) {
msg_row = Rows - 1;
@@ -2580,9 +2578,10 @@ int win_close(win_T *win, bool free_buf)
return OK;
}
- /* Free independent synblock before the buffer is freed. */
- if (win->w_buffer != NULL)
+ // Free independent synblock before the buffer is freed.
+ if (win->w_buffer != NULL) {
reset_synblock(win);
+ }
/*
* Close the link to the buffer.
@@ -6019,6 +6018,12 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
char_u *ptr;
if (get_visual_text(NULL, &ptr, &len) == FAIL)
return NULL;
+ // Only recognize ":123" here
+ if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) {
+ char_u *p = ptr + len + 1;
+
+ *file_lnum = getdigits_long(&p, false, 0);
+ }
return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
}
return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
@@ -6986,7 +6991,7 @@ void win_findbuf(typval_T *argvars, list_T *list)
int bufnr = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp->w_buffer->b_fnum == bufnr) {
+ if (!wp->w_closing && wp->w_buffer->b_fnum == bufnr) {
tv_list_append_number(list, wp->handle);
}
}
diff --git a/src/tree_sitter/alloc.h b/src/tree_sitter/alloc.h
index d3c6b5eca8..32c90f23c8 100644
--- a/src/tree_sitter/alloc.h
+++ b/src/tree_sitter/alloc.h
@@ -58,7 +58,7 @@ static inline bool ts_toggle_allocation_recording(bool value) {
static inline void *ts_malloc(size_t size) {
void *result = malloc(size);
if (size > 0 && !result) {
- fprintf(stderr, "tree-sitter failed to allocate %lu bytes", size);
+ fprintf(stderr, "tree-sitter failed to allocate %zu bytes", size);
exit(1);
}
return result;
@@ -67,7 +67,7 @@ static inline void *ts_malloc(size_t size) {
static inline void *ts_calloc(size_t count, size_t size) {
void *result = calloc(count, size);
if (count > 0 && !result) {
- fprintf(stderr, "tree-sitter failed to allocate %lu bytes", count * size);
+ fprintf(stderr, "tree-sitter failed to allocate %zu bytes", count * size);
exit(1);
}
return result;
@@ -76,7 +76,7 @@ static inline void *ts_calloc(size_t count, size_t size) {
static inline void *ts_realloc(void *buffer, size_t size) {
void *result = realloc(buffer, size);
if (size > 0 && !result) {
- fprintf(stderr, "tree-sitter failed to reallocate %lu bytes", size);
+ fprintf(stderr, "tree-sitter failed to reallocate %zu bytes", size);
exit(1);
}
return result;
diff --git a/src/tree_sitter/lexer.c b/src/tree_sitter/lexer.c
index 3f8a4c0ae8..a3c29544d3 100644
--- a/src/tree_sitter/lexer.c
+++ b/src/tree_sitter/lexer.c
@@ -73,7 +73,6 @@ static void ts_lexer__get_chunk(Lexer *self) {
// code that spans the current position.
static void ts_lexer__get_lookahead(Lexer *self) {
uint32_t position_in_chunk = self->current_position.bytes - self->chunk_start;
- const uint8_t *chunk = (const uint8_t *)self->chunk + position_in_chunk;
uint32_t size = self->chunk_size - position_in_chunk;
if (size == 0) {
@@ -82,6 +81,7 @@ static void ts_lexer__get_lookahead(Lexer *self) {
return;
}
+ const uint8_t *chunk = (const uint8_t *)self->chunk + position_in_chunk;
UnicodeDecodeFunction decode = self->input.encoding == TSInputEncodingUTF8
? ts_decode_utf8
: ts_decode_utf16;
diff --git a/src/tree_sitter/parser.c b/src/tree_sitter/parser.c
index dd222cd3c4..79cad797a0 100644
--- a/src/tree_sitter/parser.c
+++ b/src/tree_sitter/parser.c
@@ -292,6 +292,7 @@ static bool ts_parser__better_version_exists(
return true;
case ErrorComparisonPreferRight:
if (ts_stack_can_merge(self->stack, i, version)) return true;
+ break;
default:
break;
}
@@ -355,10 +356,14 @@ static Subtree ts_parser__lex(
StackVersion version,
TSStateId parse_state
) {
+ TSLexMode lex_mode = self->language->lex_modes[parse_state];
+ if (lex_mode.lex_state == (uint16_t)-1) {
+ LOG("no_lookahead_after_non_terminal_extra");
+ return NULL_SUBTREE;
+ }
+
Length start_position = ts_stack_position(self->stack, version);
Subtree external_token = ts_stack_last_external_token(self->stack, version);
- TSLexMode lex_mode = self->language->lex_modes[parse_state];
- if (lex_mode.lex_state == (uint16_t)-1) return NULL_SUBTREE;
const bool *valid_external_tokens = ts_language_enabled_external_tokens(
self->language,
lex_mode.external_lex_state
@@ -761,20 +766,26 @@ static StackVersion ts_parser__reduce(
int dynamic_precedence,
uint16_t production_id,
bool is_fragile,
- bool is_extra
+ bool end_of_non_terminal_extra
) {
uint32_t initial_version_count = ts_stack_version_count(self->stack);
- uint32_t removed_version_count = 0;
- StackSliceArray pop = ts_stack_pop_count(self->stack, version, count);
+ // Pop the given number of nodes from the given version of the parse stack.
+ // If stack versions have previously merged, then there may be more than one
+ // path back through the stack. For each path, create a new parent node to
+ // contain the popped children, and push it onto the stack in place of the
+ // children.
+ StackSliceArray pop = ts_stack_pop_count(self->stack, version, count);
+ uint32_t removed_version_count = 0;
for (uint32_t i = 0; i < pop.size; i++) {
StackSlice slice = pop.contents[i];
StackVersion slice_version = slice.version - removed_version_count;
- // Error recovery can sometimes cause lots of stack versions to merge,
- // such that a single pop operation can produce a lots of slices.
- // Avoid creating too many stack versions in that situation.
- if (i > 0 && slice_version > MAX_VERSION_COUNT + MAX_VERSION_COUNT_OVERFLOW) {
+ // This is where new versions are added to the parse stack. The versions
+ // will all be sorted and truncated at the end of the outer parsing loop.
+ // Allow the maximum version count to be temporarily exceeded, but only
+ // by a limited threshold.
+ if (slice_version > MAX_VERSION_COUNT + MAX_VERSION_COUNT_OVERFLOW) {
ts_stack_remove_version(self->stack, slice_version);
ts_subtree_array_delete(&self->tree_pool, &slice.subtrees);
removed_version_count++;
@@ -826,7 +837,9 @@ static StackVersion ts_parser__reduce(
TSStateId state = ts_stack_state(self->stack, slice_version);
TSStateId next_state = ts_language_next_state(self->language, state, symbol);
- if (is_extra) parent.ptr->extra = true;
+ if (end_of_non_terminal_extra && next_state == state) {
+ parent.ptr->extra = true;
+ }
if (is_fragile || pop.size > 1 || initial_version_count > 1) {
parent.ptr->fragile_left = true;
parent.ptr->fragile_right = true;
@@ -963,6 +976,7 @@ static bool ts_parser__do_all_potential_reductions(
.dynamic_precedence = action.params.reduce.dynamic_precedence,
.production_id = action.params.reduce.production_id,
});
+ break;
default:
break;
}
@@ -1339,23 +1353,26 @@ static bool ts_parser__advance(
);
}
- // Otherwise, re-run the lexer.
- if (!lookahead.ptr) {
- lookahead = ts_parser__lex(self, version, state);
- if (lookahead.ptr) {
- ts_parser__set_cached_token(self, position, last_external_token, lookahead);
- ts_language_table_entry(self->language, state, ts_subtree_symbol(lookahead), &table_entry);
- }
+ bool needs_lex = !lookahead.ptr;
+ for (;;) {
+ // Otherwise, re-run the lexer.
+ if (needs_lex) {
+ needs_lex = false;
+ lookahead = ts_parser__lex(self, version, state);
+
+ if (lookahead.ptr) {
+ ts_parser__set_cached_token(self, position, last_external_token, lookahead);
+ ts_language_table_entry(self->language, state, ts_subtree_symbol(lookahead), &table_entry);
+ }
- // When parsing a non-terminal extra, a null lookahead indicates the
- // end of the rule. The reduction is stored in the EOF table entry.
- // After the reduction, the lexer needs to be run again.
- else {
- ts_language_table_entry(self->language, state, ts_builtin_sym_end, &table_entry);
+ // When parsing a non-terminal extra, a null lookahead indicates the
+ // end of the rule. The reduction is stored in the EOF table entry.
+ // After the reduction, the lexer needs to be run again.
+ else {
+ ts_language_table_entry(self->language, state, ts_builtin_sym_end, &table_entry);
+ }
}
- }
- for (;;) {
// If a cancellation flag or a timeout was provided, then check every
// time a fixed number of parse actions has been processed.
if (++self->operation_count == OP_COUNT_PER_TIMEOUT_CHECK) {
@@ -1407,12 +1424,12 @@ static bool ts_parser__advance(
case TSParseActionTypeReduce: {
bool is_fragile = table_entry.action_count > 1;
- bool is_extra = lookahead.ptr == NULL;
+ bool end_of_non_terminal_extra = lookahead.ptr == NULL;
LOG("reduce sym:%s, child_count:%u", SYM_NAME(action.params.reduce.symbol), action.params.reduce.child_count);
StackVersion reduction_version = ts_parser__reduce(
self, version, action.params.reduce.symbol, action.params.reduce.child_count,
action.params.reduce.dynamic_precedence, action.params.reduce.production_id,
- is_fragile, is_extra
+ is_fragile, end_of_non_terminal_extra
);
if (reduction_version != STACK_VERSION_NONE) {
last_reduction_version = reduction_version;
@@ -1452,8 +1469,10 @@ static bool ts_parser__advance(
// (and completing the non-terminal extra rule) run the lexer again based
// on the current parse state.
if (!lookahead.ptr) {
- lookahead = ts_parser__lex(self, version, state);
+ needs_lex = true;
+ continue;
}
+
ts_language_table_entry(
self->language,
state,
@@ -1463,6 +1482,11 @@ static bool ts_parser__advance(
continue;
}
+ if (!lookahead.ptr) {
+ ts_stack_pause(self->stack, version, ts_builtin_sym_end);
+ return true;
+ }
+
// If there were no parse actions for the current lookahead token, then
// it is not valid in this state. If the current lookahead token is a
// keyword, then switch to treating it as the normal word token if that
@@ -1500,6 +1524,9 @@ static bool ts_parser__advance(
// push each of its children. Then try again to process the current
// lookahead.
if (ts_parser__breakdown_top_of_stack(self, version)) {
+ state = ts_stack_state(self->stack, version);
+ ts_subtree_release(&self->tree_pool, lookahead);
+ needs_lex = true;
continue;
}
diff --git a/src/tree_sitter/query.c b/src/tree_sitter/query.c
index 59902dee3b..b887b74ff6 100644
--- a/src/tree_sitter/query.c
+++ b/src/tree_sitter/query.c
@@ -11,7 +11,6 @@
// #define LOG(...) fprintf(stderr, __VA_ARGS__)
#define LOG(...)
-#define MAX_STATE_COUNT 256
#define MAX_CAPTURE_LIST_COUNT 32
#define MAX_STEP_CAPTURE_COUNT 3
@@ -49,7 +48,6 @@ typedef struct {
uint16_t alternative_index;
uint16_t depth;
bool contains_captures: 1;
- bool is_pattern_start: 1;
bool is_immediate: 1;
bool is_last_child: 1;
bool is_pass_through: 1;
@@ -119,9 +117,10 @@ typedef struct {
uint16_t step_index;
uint16_t pattern_index;
uint16_t capture_list_id;
- uint16_t consumed_capture_count: 14;
+ uint16_t consumed_capture_count: 12;
bool seeking_immediate_match: 1;
bool has_in_progress_alternatives: 1;
+ bool dead: 1;
} QueryState;
typedef Array(TSQueryCapture) CaptureList;
@@ -172,6 +171,7 @@ struct TSQueryCursor {
TSPoint start_point;
TSPoint end_point;
bool ascending;
+ bool halted;
};
static const TSQueryError PARENT_DONE = -1;
@@ -448,7 +448,6 @@ static QueryStep query_step__new(
.alternative_index = NONE,
.contains_captures = false,
.is_last_child = false,
- .is_pattern_start = false,
.is_pass_through = false,
.is_dead_end = false,
.is_immediate = is_immediate,
@@ -546,6 +545,23 @@ static inline void ts_query__pattern_map_insert(
) {
uint32_t index;
ts_query__pattern_map_search(self, symbol, &index);
+
+ // Ensure that the entries are sorted not only by symbol, but also
+ // by pattern_index. This way, states for earlier patterns will be
+ // initiated first, which allows the ordering of the states array
+ // to be maintained more efficiently.
+ while (index < self->pattern_map.size) {
+ PatternEntry *entry = &self->pattern_map.contents[index];
+ if (
+ self->steps.contents[entry->step_index].symbol == symbol &&
+ entry->pattern_index < pattern_index
+ ) {
+ index++;
+ } else {
+ break;
+ }
+ }
+
array_insert(&self->pattern_map, index, ((PatternEntry) {
.step_index = start_step_index,
.pattern_index = pattern_index,
@@ -715,7 +731,7 @@ static TSQueryError ts_query__parse_pattern(
uint32_t *capture_count,
bool is_immediate
) {
- uint32_t starting_step_index = self->steps.size;
+ const uint32_t starting_step_index = self->steps.size;
if (stream->next == 0) return TSQueryErrorSyntax;
@@ -804,8 +820,8 @@ static TSQueryError ts_query__parse_pattern(
}
}
- // A pound character indicates the start of a predicate.
- else if (stream->next == '#') {
+ // A dot/pound character indicates the start of a predicate.
+ else if (stream->next == '.' || stream->next == '#') {
stream_advance(stream);
return ts_query__parse_predicate(self, stream);
}
@@ -951,7 +967,6 @@ static TSQueryError ts_query__parse_pattern(
stream_skip_whitespace(stream);
// Parse the pattern
- uint32_t step_index = self->steps.size;
TSQueryError e = ts_query__parse_pattern(
self,
stream,
@@ -972,7 +987,22 @@ static TSQueryError ts_query__parse_pattern(
stream->input = field_name;
return TSQueryErrorField;
}
- self->steps.contents[step_index].field = field_id;
+
+ uint32_t step_index = starting_step_index;
+ QueryStep *step = &self->steps.contents[step_index];
+ for (;;) {
+ step->field = field_id;
+ if (
+ step->alternative_index != NONE &&
+ step->alternative_index > step_index &&
+ step->alternative_index < self->steps.size
+ ) {
+ step_index = step->alternative_index;
+ step = &self->steps.contents[step_index];
+ } else {
+ break;
+ }
+ }
}
else {
@@ -1041,15 +1071,16 @@ static TSQueryError ts_query__parse_pattern(
length
);
+ uint32_t step_index = starting_step_index;
for (;;) {
query_step__add_capture(step, capture_id);
if (
step->alternative_index != NONE &&
- step->alternative_index > starting_step_index &&
+ step->alternative_index > step_index &&
step->alternative_index < self->steps.size
) {
- starting_step_index = step->alternative_index;
- step = &self->steps.contents[starting_step_index];
+ step_index = step->alternative_index;
+ step = &self->steps.contents[step_index];
} else {
break;
}
@@ -1152,7 +1183,6 @@ TSQuery *ts_query_new(
// Maintain a map that can look up patterns for a given root symbol.
for (;;) {
QueryStep *step = &self->steps.contents[start_step_index];
- step->is_pattern_start = true;
ts_query__pattern_map_insert(self, step->symbol, start_step_index, pattern_index);
if (step->symbol == WILDCARD_SYMBOL) {
self->wildcard_root_pattern_count++;
@@ -1162,6 +1192,7 @@ TSQuery *ts_query_new(
// then add multiple entries to the pattern map.
if (step->alternative_index != NONE) {
start_step_index = step->alternative_index;
+ step->alternative_index = NONE;
} else {
break;
}
@@ -1221,6 +1252,9 @@ const TSQueryPredicateStep *ts_query_predicates_for_pattern(
) {
Slice slice = self->predicates_by_pattern.contents[pattern_index];
*step_count = slice.length;
+ if (self->predicate_steps.contents == NULL) {
+ return NULL;
+ }
return &self->predicate_steps.contents[slice.offset];
}
@@ -1271,6 +1305,7 @@ TSQueryCursor *ts_query_cursor_new(void) {
TSQueryCursor *self = ts_malloc(sizeof(TSQueryCursor));
*self = (TSQueryCursor) {
.ascending = false,
+ .halted = false,
.states = array_new(),
.finished_states = array_new(),
.capture_list_pool = capture_list_pool_new(),
@@ -1279,8 +1314,8 @@ TSQueryCursor *ts_query_cursor_new(void) {
.start_point = {0, 0},
.end_point = POINT_MAX,
};
- array_reserve(&self->states, MAX_STATE_COUNT);
- array_reserve(&self->finished_states, MAX_CAPTURE_LIST_COUNT);
+ array_reserve(&self->states, 8);
+ array_reserve(&self->finished_states, 8);
return self;
}
@@ -1304,6 +1339,7 @@ void ts_query_cursor_exec(
self->next_state_id = 0;
self->depth = 0;
self->ascending = false;
+ self->halted = false;
self->query = query;
}
@@ -1347,6 +1383,7 @@ static bool ts_query_cursor__first_in_progress_capture(
*pattern_index = UINT32_MAX;
for (unsigned i = 0; i < self->states.size; i++) {
const QueryState *state = &self->states.contents[i];
+ if (state->dead) continue;
const CaptureList *captures = capture_list_pool_get(
&self->capture_list_pool,
state->capture_list_id
@@ -1441,65 +1478,138 @@ void ts_query_cursor__compare_captures(
}
}
-static bool ts_query_cursor__add_state(
+static void ts_query_cursor__add_state(
TSQueryCursor *self,
const PatternEntry *pattern
) {
- if (self->states.size >= MAX_STATE_COUNT) {
- LOG(" too many states");
- return false;
+ QueryStep *step = &self->query->steps.contents[pattern->step_index];
+ uint32_t start_depth = self->depth - step->depth;
+
+ // Keep the states array in ascending order of start_depth and pattern_index,
+ // so that it can be processed more efficiently elsewhere. Usually, there is
+ // no work to do here because of two facts:
+ // * States with lower start_depth are naturally added first due to the
+ // order in which nodes are visited.
+ // * Earlier patterns are naturally added first because of the ordering of the
+ // pattern_map data structure that's used to initiate matches.
+ //
+ // This loop is only needed in cases where two conditions hold:
+ // * A pattern consists of more than one sibling node, so that its states
+ // remain in progress after exiting the node that started the match.
+ // * The first node in the pattern matches against multiple nodes at the
+ // same depth.
+ //
+ // An example of this is the pattern '((comment)* (function))'. If multiple
+ // `comment` nodes appear in a row, then we may initiate a new state for this
+ // pattern while another state for the same pattern is already in progress.
+ // If there are multiple patterns like this in a query, then this loop will
+ // need to execute in order to keep the states ordered by pattern_index.
+ uint32_t index = self->states.size;
+ while (index > 0) {
+ QueryState *prev_state = &self->states.contents[index - 1];
+ if (prev_state->start_depth < start_depth) break;
+ if (prev_state->start_depth == start_depth) {
+ if (prev_state->pattern_index < pattern->pattern_index) break;
+ if (prev_state->pattern_index == pattern->pattern_index) {
+ // Avoid unnecessarily inserting an unnecessary duplicate state,
+ // which would be immediately pruned by the longest-match criteria.
+ if (prev_state->step_index == pattern->step_index) return;
+ }
+ }
+ index--;
}
+
LOG(
" start state. pattern:%u, step:%u\n",
pattern->pattern_index,
pattern->step_index
);
- QueryStep *step = &self->query->steps.contents[pattern->step_index];
- array_push(&self->states, ((QueryState) {
+ array_insert(&self->states, index, ((QueryState) {
.capture_list_id = NONE,
.step_index = pattern->step_index,
.pattern_index = pattern->pattern_index,
- .start_depth = self->depth - step->depth,
+ .start_depth = start_depth,
.consumed_capture_count = 0,
- .seeking_immediate_match = false,
+ .seeking_immediate_match = true,
+ .has_in_progress_alternatives = false,
+ .dead = false,
}));
- return true;
}
-// Duplicate the given state and insert the newly-created state immediately after
-// the given state in the `states` array.
-static QueryState *ts_query__cursor_copy_state(
+// Acquire a capture list for this state. If there are no capture lists left in the
+// pool, this will steal the capture list from another existing state, and mark that
+// other state as 'dead'.
+static CaptureList *ts_query_cursor__prepare_to_capture(
TSQueryCursor *self,
- const QueryState *state
+ QueryState *state,
+ unsigned state_index_to_preserve
) {
- if (self->states.size >= MAX_STATE_COUNT) {
- LOG(" too many states");
- return NULL;
+ if (state->capture_list_id == NONE) {
+ state->capture_list_id = capture_list_pool_acquire(&self->capture_list_pool);
+
+ // If there are no capture lists left in the pool, then terminate whichever
+ // state has captured the earliest node in the document, and steal its
+ // capture list.
+ if (state->capture_list_id == NONE) {
+ uint32_t state_index, byte_offset, pattern_index;
+ if (
+ ts_query_cursor__first_in_progress_capture(
+ self,
+ &state_index,
+ &byte_offset,
+ &pattern_index
+ ) &&
+ state_index != state_index_to_preserve
+ ) {
+ LOG(
+ " abandon state. index:%u, pattern:%u, offset:%u.\n",
+ state_index, pattern_index, byte_offset
+ );
+ QueryState *other_state = &self->states.contents[state_index];
+ state->capture_list_id = other_state->capture_list_id;
+ other_state->capture_list_id = NONE;
+ other_state->dead = true;
+ CaptureList *list = capture_list_pool_get_mut(
+ &self->capture_list_pool,
+ state->capture_list_id
+ );
+ array_clear(list);
+ return list;
+ } else {
+ LOG(" ran out of capture lists");
+ return NULL;
+ }
+ }
}
+ return capture_list_pool_get_mut(&self->capture_list_pool, state->capture_list_id);
+}
- // If the state has captures, copy its capture list.
+// Duplicate the given state and insert the newly-created state immediately after
+// the given state in the `states` array. Ensures that the given state reference is
+// still valid, even if the states array is reallocated.
+static QueryState *ts_query_cursor__copy_state(
+ TSQueryCursor *self,
+ QueryState **state_ref
+) {
+ const QueryState *state = *state_ref;
+ uint32_t state_index = state - self->states.contents;
QueryState copy = *state;
- copy.capture_list_id = state->capture_list_id;
+ copy.capture_list_id = NONE;
+
+ // If the state has captures, copy its capture list.
if (state->capture_list_id != NONE) {
- copy.capture_list_id = capture_list_pool_acquire(&self->capture_list_pool);
- if (copy.capture_list_id == NONE) {
- LOG(" too many capture lists");
- return NULL;
- }
+ CaptureList *new_captures = ts_query_cursor__prepare_to_capture(self, &copy, state_index);
+ if (!new_captures) return NULL;
const CaptureList *old_captures = capture_list_pool_get(
&self->capture_list_pool,
state->capture_list_id
);
- CaptureList *new_captures = capture_list_pool_get_mut(
- &self->capture_list_pool,
- copy.capture_list_id
- );
array_push_all(new_captures, old_captures);
}
- uint32_t index = (state - self->states.contents) + 1;
- array_insert(&self->states, index, copy);
- return &self->states.contents[index];
+ array_insert(&self->states, state_index + 1, copy);
+ *state_ref = &self->states.contents[state_index];
+ return &self->states.contents[state_index + 1];
}
// Walk the tree, processing patterns until at least one pattern finishes,
@@ -1507,18 +1617,30 @@ static QueryState *ts_query__cursor_copy_state(
// `finished_states` array. Multiple patterns can finish on the same node. If
// there are no more matches, return `false`.
static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
- do {
+ bool did_match = false;
+ for (;;) {
+ if (self->halted) {
+ while (self->states.size > 0) {
+ QueryState state = array_pop(&self->states);
+ capture_list_pool_release(
+ &self->capture_list_pool,
+ state.capture_list_id
+ );
+ }
+ }
+
+ if (did_match || self->halted) return did_match;
+
if (self->ascending) {
LOG("leave node. type:%s\n", ts_node_type(ts_tree_cursor_current_node(&self->cursor)));
// Leave this node by stepping to its next sibling or to its parent.
- bool did_move = true;
if (ts_tree_cursor_goto_next_sibling(&self->cursor)) {
self->ascending = false;
} else if (ts_tree_cursor_goto_parent(&self->cursor)) {
self->depth--;
} else {
- did_move = false;
+ self->halted = true;
}
// After leaving a node, remove any states that cannot make further progress.
@@ -1530,10 +1652,11 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// If a state completed its pattern inside of this node, but was deferred from finishing
// in order to search for longer matches, mark it as finished.
if (step->depth == PATTERN_DONE_MARKER) {
- if (state->start_depth > self->depth || !did_move) {
+ if (state->start_depth > self->depth || self->halted) {
LOG(" finish pattern %u\n", state->pattern_index);
state->id = self->next_state_id++;
array_push(&self->finished_states, *state);
+ did_match = true;
deleted_count++;
continue;
}
@@ -1560,10 +1683,6 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
}
}
self->states.size -= deleted_count;
-
- if (!did_move) {
- return self->finished_states.size > 0;
- }
} else {
// If this node is before the selected range, then avoid descending into it.
TSNode node = ts_tree_cursor_current_node(&self->cursor);
@@ -1581,7 +1700,10 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
if (
self->end_byte <= ts_node_start_byte(node) ||
point_lte(self->end_point, ts_node_start_point(node))
- ) return false;
+ ) {
+ self->halted = true;
+ continue;
+ }
// Get the properties of the current node.
TSSymbol symbol = ts_node_symbol(node);
@@ -1613,7 +1735,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// If this node matches the first step of the pattern, then add a new
// state at the start of this pattern.
if (step->field && field_id != step->field) continue;
- if (!ts_query_cursor__add_state(self, pattern)) break;
+ ts_query_cursor__add_state(self, pattern);
}
// Add new states for any patterns whose root node matches this node.
@@ -1625,7 +1747,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// If this node matches the first step of the pattern, then add a new
// state at the start of this pattern.
if (step->field && field_id != step->field) continue;
- if (!ts_query_cursor__add_state(self, pattern)) break;
+ ts_query_cursor__add_state(self, pattern);
// Advance to the next pattern whose root node matches this node.
i++;
@@ -1693,12 +1815,8 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// parent, then this query state cannot simply be updated in place. It must be
// split into two states: one that matches this node, and one which skips over
// this node, to preserve the possibility of matching later siblings.
- if (
- later_sibling_can_match &&
- !step->is_pattern_start &&
- step->contains_captures
- ) {
- if (ts_query__cursor_copy_state(self, state)) {
+ if (later_sibling_can_match && step->contains_captures) {
+ if (ts_query_cursor__copy_state(self, &state)) {
LOG(
" split state for capture. pattern:%u, step:%u\n",
state->pattern_index,
@@ -1709,45 +1827,14 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
}
// If the current node is captured in this pattern, add it to the capture list.
- // For the first capture in a pattern, lazily acquire a capture list.
if (step->capture_ids[0] != NONE) {
- if (state->capture_list_id == NONE) {
- state->capture_list_id = capture_list_pool_acquire(&self->capture_list_pool);
-
- // If there are no capture lists left in the pool, then terminate whichever
- // state has captured the earliest node in the document, and steal its
- // capture list.
- if (state->capture_list_id == NONE) {
- uint32_t state_index, byte_offset, pattern_index;
- if (ts_query_cursor__first_in_progress_capture(
- self,
- &state_index,
- &byte_offset,
- &pattern_index
- )) {
- LOG(
- " abandon state. index:%u, pattern:%u, offset:%u.\n",
- state_index, pattern_index, byte_offset
- );
- state->capture_list_id = self->states.contents[state_index].capture_list_id;
- array_erase(&self->states, state_index);
- if (state_index < i) {
- i--;
- state--;
- }
- } else {
- LOG(" too many finished states.\n");
- array_erase(&self->states, i);
- i--;
- continue;
- }
- }
+ CaptureList *capture_list = ts_query_cursor__prepare_to_capture(self, state, UINT32_MAX);
+ if (!capture_list) {
+ array_erase(&self->states, i);
+ i--;
+ continue;
}
- CaptureList *capture_list = capture_list_pool_get_mut(
- &self->capture_list_pool,
- state->capture_list_id
- );
for (unsigned j = 0; j < MAX_STEP_CAPTURE_COUNT; j++) {
uint16_t capture_id = step->capture_ids[j];
if (step->capture_ids[j] == NONE) break;
@@ -1770,10 +1857,9 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
state->step_index
);
- // If this state's next step has an 'alternative' step (the step is either optional,
- // or is the end of a repetition), then copy the state in order to pursue both
- // alternatives. The alternative step itself may have an alternative, so this is
- // an interative process.
+ // If this state's next step has an alternative step, then copy the state in order
+ // to pursue both alternatives. The alternative step itself may have an alternative,
+ // so this is an interative process.
unsigned end_index = i + 1;
for (unsigned j = i; j < end_index; j++) {
QueryState *state = &self->states.contents[j];
@@ -1785,25 +1871,27 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
continue;
}
- QueryState *copy = ts_query__cursor_copy_state(self, state);
if (next_step->is_pass_through) {
state->step_index++;
j--;
}
+
+ QueryState *copy = ts_query_cursor__copy_state(self, &state);
if (copy) {
- copy_count++;
+ LOG(
+ " split state for branch. pattern:%u, from_step:%u, to_step:%u, immediate:%d, capture_count: %u\n",
+ copy->pattern_index,
+ copy->step_index,
+ next_step->alternative_index,
+ next_step->alternative_is_immediate,
+ capture_list_pool_get(&self->capture_list_pool, copy->capture_list_id)->size
+ );
end_index++;
+ copy_count++;
copy->step_index = next_step->alternative_index;
if (next_step->alternative_is_immediate) {
copy->seeking_immediate_match = true;
}
- LOG(
- " split state for branch. pattern:%u, step:%u, step:%u, immediate:%d\n",
- copy->pattern_index,
- state->step_index,
- copy->step_index,
- copy->seeking_immediate_match
- );
}
}
}
@@ -1811,59 +1899,77 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
for (unsigned i = 0; i < self->states.size; i++) {
QueryState *state = &self->states.contents[i];
- bool did_remove = false;
+ if (state->dead) {
+ array_erase(&self->states, i);
+ i--;
+ continue;
+ }
// Enfore the longest-match criteria. When a query pattern contains optional or
- // repeated nodes, this is necesssary to avoid multiple redundant states, where
+ // repeated nodes, this is necessary to avoid multiple redundant states, where
// one state has a strict subset of another state's captures.
+ bool did_remove = false;
for (unsigned j = i + 1; j < self->states.size; j++) {
QueryState *other_state = &self->states.contents[j];
+
+ // Query states are kept in ascending order of start_depth and pattern_index.
+ // Since the longest-match criteria is only used for deduping matches of the same
+ // pattern and root node, we only need to perform pairwise comparisons within a
+ // small slice of the states array.
if (
- state->pattern_index == other_state->pattern_index &&
- state->start_depth == other_state->start_depth
- ) {
- bool left_contains_right, right_contains_left;
- ts_query_cursor__compare_captures(
- self,
- state,
- other_state,
- &left_contains_right,
- &right_contains_left
- );
- if (left_contains_right) {
- if (state->step_index == other_state->step_index) {
- LOG(
- " drop shorter state. pattern: %u, step_index: %u\n",
- state->pattern_index,
- state->step_index
- );
- capture_list_pool_release(&self->capture_list_pool, other_state->capture_list_id);
- array_erase(&self->states, j);
- j--;
- continue;
- }
- other_state->has_in_progress_alternatives = true;
+ other_state->start_depth != state->start_depth ||
+ other_state->pattern_index != state->pattern_index
+ ) break;
+
+ bool left_contains_right, right_contains_left;
+ ts_query_cursor__compare_captures(
+ self,
+ state,
+ other_state,
+ &left_contains_right,
+ &right_contains_left
+ );
+ if (left_contains_right) {
+ if (state->step_index == other_state->step_index) {
+ LOG(
+ " drop shorter state. pattern: %u, step_index: %u\n",
+ state->pattern_index,
+ state->step_index
+ );
+ capture_list_pool_release(&self->capture_list_pool, other_state->capture_list_id);
+ array_erase(&self->states, j);
+ j--;
+ continue;
}
- if (right_contains_left) {
- if (state->step_index == other_state->step_index) {
- LOG(
- " drop shorter state. pattern: %u, step_index: %u\n",
- state->pattern_index,
- state->step_index
- );
- capture_list_pool_release(&self->capture_list_pool, state->capture_list_id);
- array_erase(&self->states, i);
- did_remove = true;
- break;
- }
- state->has_in_progress_alternatives = true;
+ other_state->has_in_progress_alternatives = true;
+ }
+ if (right_contains_left) {
+ if (state->step_index == other_state->step_index) {
+ LOG(
+ " drop shorter state. pattern: %u, step_index: %u\n",
+ state->pattern_index,
+ state->step_index
+ );
+ capture_list_pool_release(&self->capture_list_pool, state->capture_list_id);
+ array_erase(&self->states, i);
+ i--;
+ did_remove = true;
+ break;
}
+ state->has_in_progress_alternatives = true;
}
}
// If there the state is at the end of its pattern, remove it from the list
// of in-progress states and add it to the list of finished states.
if (!did_remove) {
+ LOG(
+ " keep state. pattern: %u, start_depth: %u, step_index: %u, capture_count: %u\n",
+ state->pattern_index,
+ state->start_depth,
+ state->step_index,
+ capture_list_pool_get(&self->capture_list_pool, state->capture_list_id)->size
+ );
QueryStep *next_step = &self->query->steps.contents[state->step_index];
if (next_step->depth == PATTERN_DONE_MARKER) {
if (state->has_in_progress_alternatives) {
@@ -1873,6 +1979,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
state->id = self->next_state_id++;
array_push(&self->finished_states, *state);
array_erase(&self->states, state - self->states.contents);
+ did_match = true;
i--;
}
}
@@ -1886,9 +1993,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
self->ascending = true;
}
}
- } while (self->finished_states.size == 0);
-
- return true;
+ }
}
bool ts_query_cursor_next_match(
@@ -2028,7 +2133,10 @@ bool ts_query_cursor_next_capture(
// If there are no finished matches that are ready to be returned, then
// continue finding more matches.
- if (!ts_query_cursor__advance(self)) return false;
+ if (
+ !ts_query_cursor__advance(self) &&
+ self->finished_states.size == 0
+ ) return false;
}
}
diff --git a/src/tree_sitter/stack.c b/src/tree_sitter/stack.c
index 6ceee2577f..6a8d897c37 100644
--- a/src/tree_sitter/stack.c
+++ b/src/tree_sitter/stack.c
@@ -571,7 +571,12 @@ void ts_stack_record_summary(Stack *self, StackVersion version, unsigned max_dep
};
array_init(session.summary);
stack__iter(self, version, summarize_stack_callback, &session, -1);
- self->heads.contents[version].summary = session.summary;
+ StackHead *head = &self->heads.contents[version];
+ if (head->summary) {
+ array_delete(head->summary);
+ ts_free(head->summary);
+ }
+ head->summary = session.summary;
}
StackSummary *ts_stack_get_summary(Stack *self, StackVersion version) {
@@ -743,6 +748,10 @@ bool ts_stack_print_dot_graph(Stack *self, const TSLanguage *language, FILE *f)
ts_stack_error_cost(self, i)
);
+ if (head->summary) {
+ fprintf(f, "\nsummary_size: %u", head->summary->size);
+ }
+
if (head->last_external_token.ptr) {
const ExternalScannerState *state = &head->last_external_token.ptr->external_scanner_state;
const char *data = ts_external_scanner_state_data(state);
diff --git a/src/tree_sitter/treesitter_commit_hash.txt b/src/tree_sitter/treesitter_commit_hash.txt
index bd7fcfbe76..322cdd24a6 100644
--- a/src/tree_sitter/treesitter_commit_hash.txt
+++ b/src/tree_sitter/treesitter_commit_hash.txt
@@ -1 +1 @@
-81d533d2d1b580fdb507accabc91ceddffb5b6f0
+87df53a99b51bce0d1e901cd6838f24e1c7a4073
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index da7515f012..8ed642b43e 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -534,6 +534,26 @@ describe('api/buf', function()
end)
end)
+ describe('nvim_buf_delete', function()
+ it('allows for just deleting', function()
+ nvim('command', 'new')
+ local b = nvim('get_current_buf')
+ ok(buffer('is_valid', b))
+ nvim('buf_delete', b, {})
+ ok(not buffer('is_loaded', b))
+ ok(not buffer('is_valid', b))
+ end)
+
+ it('allows for just unloading', function()
+ nvim('command', 'new')
+ local b = nvim('get_current_buf')
+ ok(buffer('is_valid', b))
+ nvim('buf_delete', b, { unload = true })
+ ok(not buffer('is_loaded', b))
+ ok(buffer('is_valid', b))
+ end)
+ end)
+
describe('nvim_buf_get_mark', function()
it('works', function()
curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'})
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 9ea35e50a2..ab913ba4a4 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -17,22 +17,14 @@ local function expect(contents)
return eq(contents, helpers.curbuf_contents())
end
-local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end
- local rv = curbufmeths.get_extmark_by_id(ns, mark)
- eq({er, ec}, rv)
- feed("u")
- rv = curbufmeths.get_extmark_by_id(ns, mark)
- eq({sr, sc}, rv)
- feed("<c-r>")
- rv = curbufmeths.get_extmark_by_id(ns, mark)
- eq({er, ec}, rv)
-end
-
local function set_extmark(ns_id, id, line, col, opts)
if opts == nil then
opts = {}
end
- return curbufmeths.set_extmark(ns_id, id, line, col, opts)
+ if id ~= nil and id ~= 0 then
+ opts.id = id
+ end
+ return curbufmeths.set_extmark(ns_id, line, col, opts)
end
local function get_extmarks(ns_id, start, end_, opts)
@@ -42,6 +34,24 @@ local function get_extmarks(ns_id, start, end_, opts)
return curbufmeths.get_extmarks(ns_id, start, end_, opts)
end
+local function get_extmark_by_id(ns_id, id, opts)
+ if opts == nil then
+ opts = {}
+ end
+ return curbufmeths.get_extmark_by_id(ns_id, id, opts)
+end
+
+local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end
+ local rv = get_extmark_by_id(ns, mark)
+ eq({er, ec}, rv)
+ feed("u")
+ rv = get_extmark_by_id(ns, mark)
+ eq({sr, sc}, rv)
+ feed("<c-r>")
+ rv = get_extmark_by_id(ns, mark)
+ eq({er, ec}, rv)
+end
+
local function batch_set(ns_id, positions)
local ids = {}
for _, pos in ipairs(positions) do
@@ -90,10 +100,19 @@ describe('API/extmarks', function()
ns2 = request('nvim_create_namespace', "my-fancy-plugin2")
end)
+ it("can end extranges past final newline using end_col = 0", function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 0,
+ end_line = 1
+ })
+ eq("end_col value outside range",
+ pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_line = 1 }))
+ end)
+
it('adds, updates and deletes marks', function()
local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2])
eq(marks[1], rv)
- rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ rv = get_extmark_by_id(ns, marks[1])
eq({positions[1][1], positions[1][2]}, rv)
-- Test adding a second mark on same row works
rv = set_extmark(ns, marks[2], positions[2][1], positions[2][2])
@@ -102,14 +121,14 @@ describe('API/extmarks', function()
-- Test an update, (same pos)
rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2])
eq(marks[1], rv)
- rv = curbufmeths.get_extmark_by_id(ns, marks[2])
+ rv = get_extmark_by_id(ns, marks[2])
eq({positions[2][1], positions[2][2]}, rv)
-- Test an update, (new pos)
row = positions[1][1]
col = positions[1][2] + 1
rv = set_extmark(ns, marks[1], row, col)
eq(marks[1], rv)
- rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ rv = get_extmark_by_id(ns, marks[1])
eq({row, col}, rv)
-- remove the test marks
@@ -432,7 +451,7 @@ describe('API/extmarks', function()
~ |
|
]])
- local rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ local rv = get_extmark_by_id(ns, marks[1])
eq({0, 6}, rv)
check_undo_redo(ns, marks[1], 0, 3, 0, 6)
end)
@@ -906,9 +925,9 @@ describe('API/extmarks', function()
-- Set the mark before the cursor, should stay there
set_extmark(ns, marks[2], 0, 10)
feed("i<cr><esc>")
- local rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ local rv = get_extmark_by_id(ns, marks[1])
eq({1, 3}, rv)
- rv = curbufmeths.get_extmark_by_id(ns, marks[2])
+ rv = get_extmark_by_id(ns, marks[2])
eq({0, 10}, rv)
check_undo_redo(ns, marks[1], 0, 12, 1, 3)
end)
@@ -921,12 +940,12 @@ describe('API/extmarks', function()
feed("0iint <esc>A {<cr><esc>0i1M1<esc>")
set_extmark(ns, marks[1], 1, 1)
feed("0i<c-f><esc>")
- local rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ local rv = get_extmark_by_id(ns, marks[1])
eq({1, 3}, rv)
check_undo_redo(ns, marks[1], 1, 1, 1, 3)
-- now check when cursor at eol
feed("uA<c-f><esc>")
- rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ rv = get_extmark_by_id(ns, marks[1])
eq({1, 3}, rv)
end)
@@ -937,12 +956,12 @@ describe('API/extmarks', function()
feed("0i<tab><esc>")
set_extmark(ns, marks[1], 0, 3)
feed("bi<c-d><esc>")
- local rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ local rv = get_extmark_by_id(ns, marks[1])
eq({0, 1}, rv)
check_undo_redo(ns, marks[1], 0, 3, 0, 1)
-- check when cursor at eol
feed("uA<c-d><esc>")
- rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ rv = get_extmark_by_id(ns, marks[1])
eq({0, 1}, rv)
end)
@@ -1072,7 +1091,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[5], 2, 0, 3, 0)
feed('u')
feed([[:1,2s:3:\rxx<cr>]])
- eq({1, 3}, curbufmeths.get_extmark_by_id(ns, marks[3]))
+ eq({1, 3}, get_extmark_by_id(ns, marks[3]))
end)
it('substitions over multiple lines with replace in substition', function()
@@ -1311,16 +1330,16 @@ describe('API/extmarks', function()
eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2]))
eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1]))
eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2]))
- eq("Invalid ns_id", pcall_err(curbufmeths.get_extmark_by_id, ns_invalid, marks[1]))
+ eq("Invalid ns_id", pcall_err(get_extmark_by_id, ns_invalid, marks[1]))
end)
it('when col = line-length, set the mark on eol', function()
set_extmark(ns, marks[1], 0, -1)
- local rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ local rv = get_extmark_by_id(ns, marks[1])
eq({0, init_text:len()}, rv)
-- Test another
set_extmark(ns, marks[1], 0, -1)
- rv = curbufmeths.get_extmark_by_id(ns, marks[1])
+ rv = get_extmark_by_id(ns, marks[1])
eq({0, init_text:len()}, rv)
end)
@@ -1333,7 +1352,7 @@ describe('API/extmarks', function()
local invalid_col = init_text:len() + 1
local invalid_lnum = 3
eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col))
- eq({}, curbufmeths.get_extmark_by_id(ns, marks[1]))
+ eq({}, get_extmark_by_id(ns, marks[1]))
end)
it('bug from check_col in extmark_set', function()
@@ -1357,14 +1376,14 @@ describe('API/extmarks', function()
it('can set a mark to other buffer', function()
local buf = request('nvim_create_buf', 0, 1)
request('nvim_buf_set_lines', buf, 0, -1, 1, {"", ""})
- local id = bufmeths.set_extmark(buf, ns, 0, 1, 0, {})
+ local id = bufmeths.set_extmark(buf, ns, 1, 0, {})
eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {}))
end)
it('does not crash with append/delete/undo seqence', function()
meths.exec([[
let ns = nvim_create_namespace('myplugin')
- call nvim_buf_set_extmark(0, ns, 0, 0, 0, {})
+ call nvim_buf_set_extmark(0, ns, 0, 0, {})
call append(0, '')
%delete
undo]],false)
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index a9d4c72d31..daf20c006c 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -7,6 +7,7 @@ local meths = helpers.meths
local funcs = helpers.funcs
local pcall_err = helpers.pcall_err
local ok = helpers.ok
+local assert_alive = helpers.assert_alive
describe('API: highlight',function()
local expected_rgb = {
@@ -145,4 +146,15 @@ describe('API: highlight',function()
eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")},
meths.get_hl_by_name("Shrubbery", true))
end)
+
+ it("nvim_buf_add_highlight to other buffer doesn't crash if undo is disabled #12873", function()
+ command('vsplit file')
+ local err, _ = pcall(meths.buf_set_option, 1, 'undofile', false)
+ eq(true, err)
+ err, _ = pcall(meths.buf_set_option, 1, 'undolevels', -1)
+ eq(true, err)
+ err, _ = pcall(meths.buf_add_highlight, 1, -1, 'Question', 0, 0, -1)
+ eq(true, err)
+ assert_alive()
+ end)
end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 72e810e3e4..0b52d06df9 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -449,19 +449,19 @@ describe('API', function()
end)
it('reports errors', function()
- eq([[Error loading lua: [string "<nvim>"]:1: '=' expected near '+']],
+ eq([[Error loading lua: [string "<nvim>"]:0: '=' expected near '+']],
pcall_err(meths.exec_lua, 'a+*b', {}))
- eq([[Error loading lua: [string "<nvim>"]:1: unexpected symbol near '1']],
+ eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol near '1']],
pcall_err(meths.exec_lua, '1+2', {}))
- eq([[Error loading lua: [string "<nvim>"]:1: unexpected symbol]],
+ eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol]],
pcall_err(meths.exec_lua, 'aa=bb\0', {}))
- eq([[Error executing lua: [string "<nvim>"]:1: attempt to call global 'bork' (a nil value)]],
+ eq([[Error executing lua: [string "<nvim>"]:0: attempt to call global 'bork' (a nil value)]],
pcall_err(meths.exec_lua, 'bork()', {}))
- eq('Error executing lua: [string "<nvim>"]:1: did\nthe\nfail',
+ eq('Error executing lua: [string "<nvim>"]:0: did\nthe\nfail',
pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {}))
end)
@@ -605,7 +605,7 @@ describe('API', function()
end)
it('vim.paste() failure', function()
nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {})
- eq([[Error executing lua: [string "<nvim>"]:1: fake fail]],
+ eq([[Error executing lua: [string "<nvim>"]:0: fake fail]],
pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1))
end)
end)
@@ -1252,7 +1252,7 @@ describe('API', function()
{0:~ }|
{1:very fail} |
]])
- helpers.wait()
+ helpers.poke_eventloop()
-- shows up to &cmdheight lines
nvim_async('err_write', 'more fail\ntoo fail\n')
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 8c7c3208c0..7471f50dbd 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -3,7 +3,7 @@ local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs
local request = helpers.request
@@ -82,7 +82,7 @@ describe('API/win', function()
insert("epilogue")
local win = curwin()
feed('gg')
- wait() -- let nvim process the 'gg' command
+ poke_eventloop() -- let nvim process the 'gg' command
-- cursor position is at beginning
eq({1, 0}, window('get_cursor', win))
@@ -128,7 +128,7 @@ describe('API/win', function()
insert("second line")
feed('gg')
- wait() -- let nvim process the 'gg' command
+ poke_eventloop() -- let nvim process the 'gg' command
-- cursor position is at beginning
local win = curwin()
@@ -139,7 +139,7 @@ describe('API/win', function()
-- move down a line
feed('j')
- wait() -- let nvim process the 'j' command
+ poke_eventloop() -- let nvim process the 'j' command
-- cursor is still in column 5
eq({2, 5}, window('get_cursor', win))
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 80c65e4544..230b7f8e01 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -8,7 +8,7 @@ local run = helpers.run
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
local redir_exec = helpers.redir_exec
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('v:exiting', function()
local cid
@@ -52,7 +52,7 @@ describe(':cquit', function()
local function test_cq(cmdline, exit_code, redir_msg)
if redir_msg then
eq('\n' .. redir_msg, redir_exec(cmdline))
- wait()
+ poke_eventloop()
eq(2, eval("1+1")) -- Still alive?
else
funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline})
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 57e6f4fd63..6d1182478a 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -11,7 +11,7 @@ local os_kill = helpers.os_kill
local retry = helpers.retry
local meths = helpers.meths
local NIL = helpers.NIL
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local get_pathsep = helpers.get_pathsep
local pathroot = helpers.pathroot
@@ -93,6 +93,7 @@ describe('jobs', function()
{'notification', 'stdout', {0, {'hello world %VAR%', ''}}}
})
else
+ nvim('command', "set shell=/bin/sh")
nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
expect_msg_seq({
{'notification', 'stdout', {0, {'hello world', ''}}}
@@ -427,7 +428,7 @@ describe('jobs', function()
\ }
let job = jobstart(['cat', '-'], g:callbacks)
]])
- wait()
+ poke_eventloop()
source([[
function! g:JobHandler(job_id, data, event)
endfunction
diff --git a/test/functional/eval/interrupt_spec.lua b/test/functional/eval/interrupt_spec.lua
index 7f4ca95317..05b1f4ff57 100644
--- a/test/functional/eval/interrupt_spec.lua
+++ b/test/functional/eval/interrupt_spec.lua
@@ -4,7 +4,7 @@ local command = helpers.command
local meths = helpers.meths
local clear = helpers.clear
local sleep = helpers.sleep
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local feed = helpers.feed
local eq = helpers.eq
@@ -39,7 +39,7 @@ describe('List support code', function()
feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
sleep(min_dur / 16 * 1000)
feed('<C-c>')
- wait()
+ poke_eventloop()
command('let t_dur = reltimestr(reltime(t_rt))')
local t_dur = tonumber(meths.get_var('t_dur'))
if t_dur >= dur / 8 then
@@ -50,7 +50,7 @@ describe('List support code', function()
feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
sleep(min_dur / 16 * 1000)
feed('<C-c>')
- wait()
+ poke_eventloop()
command('let t_dur = reltimestr(reltime(t_rt))')
local t_dur = tonumber(meths.get_var('t_dur'))
print(('t_dur: %g'):format(t_dur))
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 802c3f68c6..003ab64dd4 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
-local feed, wait = helpers.feed, helpers.wait
+local feed, poke_eventloop = helpers.feed, helpers.poke_eventloop
local ok = helpers.ok
local eval = helpers.eval
@@ -90,7 +90,7 @@ describe(':browse oldfiles', function()
feed_command('edit testfile2')
filename2 = buf.get_name()
feed_command('wshada')
- wait()
+ poke_eventloop()
_clear()
-- Ensure nvim is out of "Press ENTER..." prompt.
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index dca7f35923..a30eb748d0 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -125,6 +125,26 @@ function tests.basic_check_capabilities()
}
end
+function tests.capabilities_for_client_supports_method()
+ skeleton {
+ on_init = function(params)
+ local expected_capabilities = protocol.make_client_capabilities()
+ assert_eq(params.capabilities, expected_capabilities)
+ return {
+ capabilities = {
+ textDocumentSync = protocol.TextDocumentSyncKind.Full;
+ completionProvider = true;
+ hoverProvider = true;
+ definitionProvider = false;
+ referencesProvider = false;
+ }
+ }
+ end;
+ body = function()
+ end;
+ }
+end
+
function tests.basic_finish()
skeleton {
on_init = function(params)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index e8435cd3b7..0bd378d832 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -22,6 +22,7 @@ local ok = global_helpers.ok
local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
local write_file = global_helpers.write_file
+local fail = global_helpers.fail
local module = {
NIL = mpack.NIL,
@@ -553,9 +554,9 @@ function module.curbuf(method, ...)
return module.buffer(method, 0, ...)
end
-function module.wait()
- -- Execute 'nvim_eval' (a deferred function) to block
- -- until all pending input is processed.
+function module.poke_eventloop()
+ -- Execute 'nvim_eval' (a deferred function) to
+ -- force at least one main_loop iteration
session:request('nvim_eval', '1')
end
@@ -565,7 +566,7 @@ end
--@see buf_lines()
function module.curbuf_contents()
- module.wait() -- Before inspecting the buffer, process all input.
+ module.poke_eventloop() -- Before inspecting the buffer, do whatever.
return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
end
@@ -592,6 +593,24 @@ function module.expect_any(contents)
return ok(nil ~= string.find(module.curbuf_contents(), contents, 1, true))
end
+function module.expect_events(expected, received, kind)
+ local inspect = require'vim.inspect'
+ if not pcall(eq, expected, received) then
+ local msg = 'unexpected '..kind..' received.\n\n'
+
+ msg = msg .. 'received events:\n'
+ for _, e in ipairs(received) do
+ msg = msg .. ' ' .. inspect(e) .. ';\n'
+ end
+ msg = msg .. '\nexpected events:\n'
+ for _, e in ipairs(expected) do
+ msg = msg .. ' ' .. inspect(e) .. ';\n'
+ end
+ fail(msg)
+ end
+ return received
+end
+
-- Checks that the Nvim session did not terminate.
function module.assert_alive()
assert(2 == module.eval('1+1'), 'crash? request failed')
@@ -769,14 +788,14 @@ end
function module.missing_provider(provider)
if provider == 'ruby' or provider == 'node' or provider == 'perl' then
- local prog = module.funcs['provider#' .. provider .. '#Detect']()
- return prog == '' and (provider .. ' not detected') or false
+ local e = module.funcs['provider#'..provider..'#Detect']()[2]
+ return e ~= '' and e or false
elseif provider == 'python' or provider == 'python3' then
local py_major_version = (provider == 'python3' and 3 or 2)
- local errors = module.funcs['provider#pythonx#Detect'](py_major_version)[2]
- return errors ~= '' and errors or false
+ local e = module.funcs['provider#pythonx#Detect'](py_major_version)[2]
+ return e ~= '' and e or false
else
- assert(false, 'Unknown provider: ' .. provider)
+ assert(false, 'Unknown provider: '..provider)
end
end
diff --git a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
index 8b92c877a6..8e977aa73e 100644
--- a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
+++ b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('test5', function()
setup(clear)
@@ -34,7 +34,7 @@ describe('test5', function()
command('bwipe')
feed('G?this is a<cr>')
feed('othis is some more text<esc>')
- wait()
+ poke_eventloop()
-- Append some text to this file.
@@ -45,7 +45,7 @@ describe('test5', function()
command('bwipe!')
-- Append an extra line to the output register.
feed('ithis is another test line<esc>:yank A<cr>')
- wait()
+ poke_eventloop()
-- Output results
command('%d')
diff --git a/test/functional/legacy/006_argument_list_spec.lua b/test/functional/legacy/006_argument_list_spec.lua
index 9f75a91fa8..d269bf8ec9 100644
--- a/test/functional/legacy/006_argument_list_spec.lua
+++ b/test/functional/legacy/006_argument_list_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, dedent, eq = helpers.command, helpers.dedent, helpers.eq
local curbuf_contents = helpers.curbuf_contents
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('argument list', function()
setup(clear)
@@ -17,7 +17,7 @@ describe('argument list', function()
this is a test
this is a test
end of test file Xxx]])
- wait()
+ poke_eventloop()
command('au BufReadPost Xxx2 next Xxx2 Xxx1')
command('/^start of')
@@ -30,7 +30,7 @@ describe('argument list', function()
-- Write test file Xxx3
feed('$r3:.,/end of/w! Xxx3<cr>')
- wait()
+ poke_eventloop()
-- Redefine arglist; go to Xxx1
command('next! Xxx1 Xxx2 Xxx3')
@@ -43,7 +43,7 @@ describe('argument list', function()
-- Append contents of last window (Xxx1)
feed('')
- wait()
+ poke_eventloop()
command('%yank A')
-- should now be in Xxx2
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index cec4f93737..48dd24db9e 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -8,7 +8,7 @@ local lfs = require('lfs')
local eq = helpers.eq
local neq = helpers.neq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local funcs = helpers.funcs
local meths = helpers.meths
local clear = helpers.clear
@@ -64,7 +64,7 @@ describe("'directory' option", function()
eq(nil, lfs.attributes('.Xtest1.swp'))
command('edit! Xtest1')
- wait()
+ poke_eventloop()
eq('Xtest1', funcs.buffer_name('%'))
-- Verify that the swapfile exists. In the legacy test this was done by
-- reading the output from :!ls.
@@ -72,7 +72,7 @@ describe("'directory' option", function()
meths.set_option('directory', './Xtest2,.')
command('edit Xtest1')
- wait()
+ poke_eventloop()
-- swapfile should no longer exist in CWD.
eq(nil, lfs.attributes('.Xtest1.swp'))
@@ -82,7 +82,7 @@ describe("'directory' option", function()
meths.set_option('directory', 'Xtest.je')
command('edit Xtest2/Xtest3')
eq(true, curbufmeths.get_option('swapfile'))
- wait()
+ poke_eventloop()
eq({ "Xtest3" }, ls_dir_sorted("Xtest2"))
eq({ "Xtest3.swp" }, ls_dir_sorted("Xtest.je"))
diff --git a/test/functional/legacy/023_edit_arguments_spec.lua b/test/functional/legacy/023_edit_arguments_spec.lua
index e705397a2b..f59d192c1e 100644
--- a/test/functional/legacy/023_edit_arguments_spec.lua
+++ b/test/functional/legacy/023_edit_arguments_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, insert = helpers.clear, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe(':edit', function()
setup(clear)
@@ -13,7 +13,7 @@ describe(':edit', function()
The result should be in Xfile1: "fooPIPEbar", in Xfile2: "fooSLASHbar"
foo|bar
foo/bar]])
- wait()
+ poke_eventloop()
-- Prepare some test files
command('$-1w! Xfile1')
diff --git a/test/functional/legacy/030_fileformats_spec.lua b/test/functional/legacy/030_fileformats_spec.lua
index 2fd51602d8..15dbd05cf5 100644
--- a/test/functional/legacy/030_fileformats_spec.lua
+++ b/test/functional/legacy/030_fileformats_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local feed, clear, command = helpers.feed, helpers.clear, helpers.command
local eq, write_file = helpers.eq, helpers.write_file
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('fileformats option', function()
setup(function()
@@ -107,7 +107,7 @@ describe('fileformats option', function()
command('bwipe XXDosMac')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt54')
command('bwipeout! XXEol')
command('set fileformats=dos,mac')
@@ -116,7 +116,7 @@ describe('fileformats option', function()
command('bwipe XXUxDs')
command('e! XXUxMac')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt62')
command('bwipeout! XXUxMac')
command('e! XXUxDsMc')
@@ -124,7 +124,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXMacEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt64')
command('bwipeout! XXMacEol')
@@ -135,7 +135,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt72')
command('bwipeout! XXEol')
command('set fileformats=mac,dos,unix')
@@ -144,7 +144,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt82')
command('bwipeout! XXEol')
-- Try with 'binary' set.
@@ -165,7 +165,7 @@ describe('fileformats option', function()
-- char was.
command('set fileformat=unix nobin')
feed('ggdGaEND<esc>')
- wait()
+ poke_eventloop()
command('w >>XXtt01')
command('w >>XXtt02')
command('w >>XXtt11')
@@ -204,52 +204,52 @@ describe('fileformats option', function()
command('$r XXtt01')
command('$r XXtt02')
feed('Go1<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt11')
command('$r XXtt12')
command('$r XXtt13')
feed('Go2<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt21')
command('$r XXtt22')
command('$r XXtt23')
feed('Go3<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt31')
command('$r XXtt32')
command('$r XXtt33')
feed('Go4<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt41')
command('$r XXtt42')
command('$r XXtt43')
feed('Go5<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt51')
command('$r XXtt52')
command('$r XXtt53')
command('$r XXtt54')
feed('Go6<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt61')
command('$r XXtt62')
command('$r XXtt63')
command('$r XXtt64')
feed('Go7<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt71')
command('$r XXtt72')
feed('Go8<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt81')
command('$r XXtt82')
feed('Go9<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt91')
command('$r XXtt92')
command('$r XXtt93')
feed('Go10<esc>')
- wait()
+ poke_eventloop()
command('$r XXUnix')
command('set nobinary ff&')
diff --git a/test/functional/legacy/033_lisp_indent_spec.lua b/test/functional/legacy/033_lisp_indent_spec.lua
index 5132333a5c..b27de6c16d 100644
--- a/test/functional/legacy/033_lisp_indent_spec.lua
+++ b/test/functional/legacy/033_lisp_indent_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('lisp indent', function()
setup(clear)
@@ -39,7 +39,7 @@ describe('lisp indent', function()
command('set lisp')
command('/^(defun')
feed('=G:/^(defun/,$yank A<cr>')
- wait()
+ poke_eventloop()
-- Put @a and clean empty line
command('%d')
diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua
index 38e8145d1c..6f66efcb67 100644
--- a/test/functional/legacy/036_regexp_character_classes_spec.lua
+++ b/test/functional/legacy/036_regexp_character_classes_spec.lua
@@ -15,7 +15,7 @@ end
local function diff(text, nodedent)
local fname = helpers.tmpname()
command('w! '..fname)
- helpers.wait()
+ helpers.poke_eventloop()
local data = io.open(fname):read('*all')
if nodedent then
helpers.eq(text, data)
diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua
index 1e5239ceac..7d7856fd37 100644
--- a/test/functional/legacy/045_folding_spec.lua
+++ b/test/functional/legacy/045_folding_spec.lua
@@ -59,7 +59,7 @@ describe('folding', function()
feed('kYpj')
feed_command('call append("$", foldlevel("."))')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
dd {{{ |
ee {{{ }}} |
@@ -88,7 +88,7 @@ describe('folding', function()
feed_command('call append("$", foldlevel(2))')
feed('zR')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
aa |
bb |
diff --git a/test/functional/legacy/051_highlight_spec.lua b/test/functional/legacy/051_highlight_spec.lua
index 0c9c9621ee..d3f2897493 100644
--- a/test/functional/legacy/051_highlight_spec.lua
+++ b/test/functional/legacy/051_highlight_spec.lua
@@ -5,7 +5,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, feed = helpers.clear, helpers.feed
local expect = helpers.expect
local eq = helpers.eq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local exc_exec = helpers.exc_exec
local feed_command = helpers.feed_command
@@ -34,7 +34,7 @@ describe(':highlight', function()
-- More --^ |
]])
feed('q')
- wait() -- wait until we're back to normal
+ poke_eventloop() -- wait until we're back to normal
feed_command('hi Search')
feed_command('hi Normal')
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
index bdc2c9779c..328d6f6fa0 100644
--- a/test/functional/legacy/057_sort_spec.lua
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -2,8 +2,8 @@
local helpers = require('test.functional.helpers')(after_each)
-local insert, command, clear, expect, eq, wait = helpers.insert,
- helpers.command, helpers.clear, helpers.expect, helpers.eq, helpers.wait
+local insert, command, clear, expect, eq, poke_eventloop = helpers.insert,
+ helpers.command, helpers.clear, helpers.expect, helpers.eq, helpers.poke_eventloop
local exc_exec = helpers.exc_exec
describe(':sort', function()
@@ -27,7 +27,7 @@ describe(':sort', function()
it('alphabetical', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort')
expect([[
@@ -67,7 +67,7 @@ describe(':sort', function()
b321
b321b
]])
- wait()
+ poke_eventloop()
command('sort n')
expect([[
abc
@@ -92,7 +92,7 @@ describe(':sort', function()
it('hexadecimal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort x')
expect([[
@@ -114,7 +114,7 @@ describe(':sort', function()
it('alphabetical, unique', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort u')
expect([[
@@ -135,7 +135,7 @@ describe(':sort', function()
it('alphabetical, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort!')
expect([[
c321d
@@ -157,7 +157,7 @@ describe(':sort', function()
it('numerical, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! n')
expect([[
b322b
@@ -179,7 +179,7 @@ describe(':sort', function()
it('unique, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! u')
expect([[
c321d
@@ -200,7 +200,7 @@ describe(':sort', function()
it('octal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort o')
expect([[
abc
@@ -222,7 +222,7 @@ describe(':sort', function()
it('reverse, hexadecimal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! x')
expect([[
c321d
@@ -244,7 +244,7 @@ describe(':sort', function()
it('alphabetical, skip first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./')
expect([[
a
@@ -266,7 +266,7 @@ describe(':sort', function()
it('alphabetical, skip first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../')
expect([[
ab
@@ -288,7 +288,7 @@ describe(':sort', function()
it('alphabetical, unique, skip first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../u')
expect([[
ab
@@ -309,7 +309,7 @@ describe(':sort', function()
it('numerical, skip first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./n')
expect([[
abc
@@ -331,7 +331,7 @@ describe(':sort', function()
it('alphabetical, sort on first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./r')
expect([[
@@ -353,7 +353,7 @@ describe(':sort', function()
it('alphabetical, sort on first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../r')
expect([[
a
@@ -375,7 +375,7 @@ describe(':sort', function()
it('numerical, sort on first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./rn')
expect([[
abc
@@ -397,7 +397,7 @@ describe(':sort', function()
it('alphabetical, skip past first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/]])
expect([[
abc
@@ -419,7 +419,7 @@ describe(':sort', function()
it('alphabetical, sort on first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/r]])
expect([[
abc
@@ -441,7 +441,7 @@ describe(':sort', function()
it('numerical, skip past first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/n]])
expect([[
abc
@@ -463,7 +463,7 @@ describe(':sort', function()
it('numerical, sort on first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/rn]])
expect([[
abc
@@ -485,7 +485,7 @@ describe(':sort', function()
it('alphabetical, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/]])
expect([[
abc
@@ -507,7 +507,7 @@ describe(':sort', function()
it('numerical, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/n]])
expect([[
abc
@@ -529,7 +529,7 @@ describe(':sort', function()
it('hexadecimal, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/x]])
expect([[
abc
@@ -551,7 +551,7 @@ describe(':sort', function()
it('alpha, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/r]])
expect([[
abc
@@ -573,7 +573,7 @@ describe(':sort', function()
it('numeric, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/rn]])
expect([[
abc
@@ -595,7 +595,7 @@ describe(':sort', function()
it('hexadecimal, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/rx]])
expect([[
abc
@@ -638,7 +638,7 @@ describe(':sort', function()
0b100010
0b100100
0b100010]])
- wait()
+ poke_eventloop()
command([[sort b]])
expect([[
0b000000
@@ -673,7 +673,7 @@ describe(':sort', function()
0b101010
0b000000
b0b111000]])
- wait()
+ poke_eventloop()
command([[sort b]])
expect([[
0b000000
@@ -700,7 +700,7 @@ describe(':sort', function()
1.15e-6
-1.1e3
-1.01e3]])
- wait()
+ poke_eventloop()
command([[sort f]])
expect([[
-1.1e3
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 f7f074c61a..445d742c1f 100644
--- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua
+++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua
@@ -2,9 +2,9 @@
local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
-local clear, command, eq, neq, eval, wait =
+local clear, command, eq, neq, eval, poke_eventloop =
helpers.clear, helpers.command, helpers.eq, helpers.neq, helpers.eval,
- helpers.wait
+ helpers.poke_eventloop
describe('storing global variables in ShaDa files', function()
local tempname = 'Xtest-functional-legacy-074'
@@ -36,7 +36,7 @@ describe('storing global variables in ShaDa files', function()
eq(test_list, eval('MY_GLOBAL_LIST'))
command('wsh! ' .. tempname)
- wait()
+ poke_eventloop()
-- Assert that the shada file exists.
neq(nil, lfs.attributes(tempname))
diff --git a/test/functional/legacy/075_maparg_spec.lua b/test/functional/legacy/075_maparg_spec.lua
index ee2b041b51..ad6c190104 100644
--- a/test/functional/legacy/075_maparg_spec.lua
+++ b/test/functional/legacy/075_maparg_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed = helpers.clear, helpers.feed
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('maparg()', function()
setup(clear)
@@ -25,7 +25,7 @@ describe('maparg()', function()
command('map abc y<S-char-114>y')
command([[call append('$', maparg('abc'))]])
feed('Go<esc>:<cr>')
- wait()
+ poke_eventloop()
-- Outside of the range, minimum
command('inoremap <Char-0x1040> a')
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 239f60341a..841eeef0af 100644
--- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua
+++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local clear = helpers.clear
local insert = helpers.insert
local command = helpers.command
@@ -16,7 +16,7 @@ describe('107', function()
screen:attach()
insert('start:')
- wait()
+ poke_eventloop()
command('new')
command('call setline(1, range(1,256))')
command('let r=[]')
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index 241a19d940..67c5750033 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -42,9 +42,7 @@ describe('argument list commands', function()
end)
it('test that argadd() works', function()
- -- Fails with โ€œE474: Invalid argumentโ€. Not sure whether it is how it is
- -- supposed to behave.
- -- command('%argdelete')
+ command('%argdelete')
command('argadd a b c')
eq(0, eval('argidx()'))
@@ -176,9 +174,14 @@ describe('argument list commands', function()
command('last')
command('argdelete %')
eq({'b'}, eval('argv()'))
- assert_fails('argdelete', 'E471:')
+ assert_fails('argdelete', 'E610:')
assert_fails('1,100argdelete', 'E16:')
- command('%argd')
+ reset_arglist()
+ command('args a b c d')
+ command('next')
+ command('argdel')
+ eq({'a', 'c', 'd'}, eval('argv()'))
+ command('%argdel')
end)
it('test for the :next, :prev, :first, :last, :rewind commands', function()
diff --git a/test/functional/legacy/autoformat_join_spec.lua b/test/functional/legacy/autoformat_join_spec.lua
index 84d661c190..22b1c258fe 100644
--- a/test/functional/legacy/autoformat_join_spec.lua
+++ b/test/functional/legacy/autoformat_join_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('autoformat join', function()
setup(clear)
@@ -21,7 +21,7 @@ Results:]])
feed('gg')
feed('0gqj<cr>')
- wait()
+ poke_eventloop()
command([[let a=string(getpos("'[")).'/'.string(getpos("']"))]])
command("g/^This line/;'}-join")
diff --git a/test/functional/legacy/close_count_spec.lua b/test/functional/legacy/close_count_spec.lua
index 9b932e2ef0..60ae155fbf 100644
--- a/test/functional/legacy/close_count_spec.lua
+++ b/test/functional/legacy/close_count_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
@@ -110,23 +110,23 @@ describe('close_count', function()
command('for i in range(5)|new|endfor')
command('4wincmd w')
feed('<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({25, 24, 23, 21, 1}, eval('buffers'))
feed('1<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 23, 21, 1}, eval('buffers'))
feed('9<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 23, 21}, eval('buffers'))
command('1wincmd w')
feed('2<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 21}, eval('buffers'))
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
new file mode 100644
index 0000000000..3fbbe96947
--- /dev/null
+++ b/test/functional/legacy/display_spec.lua
@@ -0,0 +1,31 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local poke_eventloop = helpers.poke_eventloop
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+
+describe('display', function()
+ local screen
+
+ it('scroll when modified at topline', function()
+ clear()
+ screen = Screen.new(20, 4)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true},
+ })
+
+ feed_command([[call setline(1, repeat('a', 21))]])
+ poke_eventloop()
+ feed('O')
+ screen:expect([[
+ ^ |
+ aaaaaaaaaaaaaaaaaaaa|
+ a |
+ {1:-- INSERT --} |
+ ]])
+ end)
+end)
+
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index 4198ea8bfe..ee9bd29fc4 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, command, expect = helpers.clear, helpers.command, helpers.expect
local eq, eval, write_file = helpers.eq, helpers.eval, helpers.write_file
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local exc_exec = helpers.exc_exec
local dedent = helpers.dedent
@@ -71,7 +71,7 @@ describe('eval', function()
command([[call SetReg('I', 'abcI')]])
feed('Go{{{1 Appending single lines with setreg()<esc>')
- wait()
+ poke_eventloop()
command([[call SetReg('A', 'abcAc', 'c')]])
command([[call SetReg('A', 'abcAl', 'l')]])
command([[call SetReg('A', 'abcAc2','c')]])
@@ -700,13 +700,13 @@ describe('eval', function()
start:]])
command('/^012345678')
feed('6l')
- wait()
+ poke_eventloop()
command('let sp = getcurpos()')
feed('0')
- wait()
+ poke_eventloop()
command("call setpos('.', sp)")
feed('jyl')
- wait()
+ poke_eventloop()
command('$put')
expect([[
012345678
diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua
index 56a5652184..92a757ca85 100644
--- a/test/functional/legacy/mapping_spec.lua
+++ b/test/functional/legacy/mapping_spec.lua
@@ -2,7 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local feed_command, expect, wait = helpers.feed_command, helpers.expect, helpers.wait
+local feed_command, expect, poke_eventloop = helpers.feed_command, helpers.expect, helpers.poke_eventloop
describe('mapping', function()
before_each(clear)
@@ -29,9 +29,9 @@ describe('mapping', function()
feed_command('cunmap <c-c>')
feed('GA<cr>')
feed('TEST2: CTRL-C |')
- wait()
+ poke_eventloop()
feed('<c-c>A|<cr><esc>')
- wait()
+ poke_eventloop()
feed_command('unmap <c-c>')
feed_command('unmap! <c-c>')
@@ -46,7 +46,7 @@ describe('mapping', function()
feed('GV')
-- XXX: For some reason the mapping is only triggered
-- when <C-c> is in a separate feed command.
- wait()
+ poke_eventloop()
feed('<c-c>')
feed_command('vunmap <c-c>')
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 251e6a5ea4..fb0bacc2d2 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -7,7 +7,7 @@ local iswin = helpers.iswin
local retry = helpers.retry
local ok = helpers.ok
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local uname = helpers.uname
local load_adjust = helpers.load_adjust
@@ -102,7 +102,7 @@ describe('memory usage', function()
call s:f(0)
endfor
]])
- wait()
+ poke_eventloop()
local after = monitor_memory_usage(pid)
-- Estimate the limit of max usage as 2x initial usage.
-- The lower limit can fluctuate a bit, use 97%.
@@ -147,11 +147,11 @@ describe('memory usage', function()
call s:f()
endfor
]])
- wait()
+ poke_eventloop()
local after = monitor_memory_usage(pid)
for _ = 1, 3 do
feed_command('so '..fname)
- wait()
+ poke_eventloop()
end
local last = monitor_memory_usage(pid)
-- The usage may be a bit less than the last value, use 80%.
diff --git a/test/functional/legacy/search_mbyte_spec.lua b/test/functional/legacy/search_mbyte_spec.lua
index a365f79cdf..ef7e41aa30 100644
--- a/test/functional/legacy/search_mbyte_spec.lua
+++ b/test/functional/legacy/search_mbyte_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local clear = helpers.clear
local insert = helpers.insert
local expect = helpers.expect
@@ -15,7 +15,7 @@ describe('search_mbyte', function()
Test bce:
๏ผก]=])
- wait()
+ poke_eventloop()
command('/^Test bce:/+1')
command([[$put =search('๏ผก', 'bce', line('.'))]])
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index a207b176d3..4ed08881de 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -6,7 +6,7 @@ local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('search cmdline', function()
local screen
@@ -21,6 +21,7 @@ describe('search cmdline', function()
err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
more = { bold = true, foreground = Screen.colors.SeaGreen4 },
tilde = { bold = true, foreground = Screen.colors.Blue1 },
+ hl = { background = Screen.colors.Yellow },
})
end)
@@ -482,9 +483,9 @@ describe('search cmdline', function()
-- "interactive". This mimics Vim's test_override("char_avail").
-- (See legacy test: test_search.vim)
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -495,11 +496,11 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 ^the first |
@@ -510,13 +511,13 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -527,9 +528,9 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 ^the first |
@@ -540,11 +541,11 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -555,13 +556,13 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -570,4 +571,72 @@ describe('search cmdline', function()
?the |
]])
end)
+
+ it('incsearch works with :sort', function()
+ -- oldtest: Test_incsearch_sort_dump().
+ screen:try_resize(20, 4)
+ command('set incsearch hlsearch scrolloff=0')
+ funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
+
+ feed(':sort ni u /on')
+ screen:expect([[
+ another {inc:on}e 2 |
+ that {hl:on}e 3 |
+ the {hl:on}e 1 |
+ :sort ni u /on^ |
+ ]])
+ feed('<esc>')
+ end)
+
+ it('incsearch works with :vimgrep family', function()
+ -- oldtest: Test_incsearch_vimgrep_dump().
+ screen:try_resize(30, 4)
+ command('set incsearch hlsearch scrolloff=0')
+ funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
+
+ feed(':vimgrep on')
+ screen:expect([[
+ another {inc:on}e 2 |
+ that {hl:on}e 3 |
+ the {hl:on}e 1 |
+ :vimgrep on^ |
+ ]])
+ feed('<esc>')
+
+ feed(':vimg /on/ *.txt')
+ screen:expect([[
+ another {inc:on}e 2 |
+ that {hl:on}e 3 |
+ the {hl:on}e 1 |
+ :vimg /on/ *.txt^ |
+ ]])
+ feed('<esc>')
+
+ feed(':vimgrepadd "\\<LT>on')
+ screen:expect([[
+ another {inc:on}e 2 |
+ that {hl:on}e 3 |
+ the {hl:on}e 1 |
+ :vimgrepadd "\<on^ |
+ ]])
+ feed('<esc>')
+
+ feed(':lv "tha')
+ screen:expect([[
+ another one 2 |
+ {inc:tha}t one 3 |
+ the one 1 |
+ :lv "tha^ |
+ ]])
+ feed('<esc>')
+
+ feed(':lvimgrepa "the" **/*.txt')
+ screen:expect([[
+ ano{inc:the}r one 2 |
+ that one 3 |
+ {hl:the} one 1 |
+ :lvimgrepa "the" **/*.txt^ |
+ ]])
+ feed('<esc>')
+ end)
end)
diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua
index 5b93f25b24..8b5fc02d11 100644
--- a/test/functional/legacy/utf8_spec.lua
+++ b/test/functional/legacy/utf8_spec.lua
@@ -5,7 +5,7 @@ local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
local eq, eval = helpers.eq, helpers.eval
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('utf8', function()
before_each(clear)
@@ -18,7 +18,7 @@ describe('utf8', function()
-- Visual block Insert adjusts for multi-byte char
feed('gg0l<C-V>jjIx<Esc>')
- wait()
+ poke_eventloop()
command('let r = getline(1, "$")')
command('bwipeout!')
diff --git a/test/functional/legacy/visual_mode_spec.lua b/test/functional/legacy/visual_mode_spec.lua
new file mode 100644
index 0000000000..c8e83ed649
--- /dev/null
+++ b/test/functional/legacy/visual_mode_spec.lua
@@ -0,0 +1,42 @@
+-- Test visual line mode selection redraw after scrolling
+
+local helpers = require('test.functional.helpers')(after_each)
+
+local Screen = require('test.functional.ui.screen')
+local call = helpers.call
+local clear = helpers.clear
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local funcs = helpers.funcs
+local meths = helpers.meths
+local eq = helpers.eq
+
+describe('visual line mode', function()
+ local screen
+
+ it('redraws properly after scrolling with matchparen loaded and scrolloff=1', function()
+ clear{args={'-u', 'NORC'}}
+ screen = Screen.new(30, 7)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true},
+ [2] = {background = Screen.colors.LightGrey},
+ })
+
+ eq(1, meths.get_var('loaded_matchparen'))
+ feed_command('set scrolloff=1')
+ funcs.setline(1, {'a', 'b', 'c', 'd', 'e', '', '{', '}', '{', 'f', 'g', '}'})
+ call('cursor', 5, 1)
+
+ feed('V<c-d><c-d>')
+ screen:expect([[
+ {2:{} |
+ {2:}} |
+ {2:{} |
+ {2:f} |
+ ^g |
+ } |
+ {1:-- VISUAL LINE --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua
index 0c8bd2cdcc..826743b0ca 100644
--- a/test/functional/legacy/wordcount_spec.lua
+++ b/test/functional/legacy/wordcount_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, command = helpers.clear, helpers.command
local eq, eval = helpers.eq, helpers.eval
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('wordcount', function()
before_each(clear)
@@ -14,7 +14,7 @@ describe('wordcount', function()
insert([=[
RESULT test:]=])
- wait()
+ poke_eventloop()
command('new')
source([=[
@@ -127,7 +127,7 @@ describe('wordcount', function()
-- -- Start visual mode quickly and select complete buffer.
command('0')
feed('V2jy<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
@@ -144,7 +144,7 @@ describe('wordcount', function()
-- Start visual mode quickly and select complete buffer.
command('0')
feed('v$y<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
@@ -161,7 +161,7 @@ describe('wordcount', function()
-- Start visual mode quickly and select complete buffer.
command('2')
feed('0v$y<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 77f8189bb9..7e4de7c39a 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -3,10 +3,14 @@ local helpers = require('test.functional.helpers')(after_each)
local command = helpers.command
local meths = helpers.meths
+local funcs = helpers.funcs
local clear = helpers.clear
local eq = helpers.eq
+local fail = helpers.fail
local exec_lua = helpers.exec_lua
local feed = helpers.feed
+local deepcopy = helpers.deepcopy
+local expect_events = helpers.expect_events
local origlines = {"original line 1",
"original line 2",
@@ -16,32 +20,37 @@ local origlines = {"original line 1",
"original line 6",
" indented line"}
-describe('lua: buffer event callbacks', function()
- before_each(function()
- clear()
- exec_lua([[
- local events = {}
+local function attach_buffer(evname)
+ exec_lua([[
+ local evname = ...
+ local events = {}
- function test_register(bufnr, id, changedtick, utf_sizes)
- local function callback(...)
- table.insert(events, {id, ...})
- if test_unreg == id then
- return true
- end
+ function test_register(bufnr, id, changedtick, utf_sizes)
+ local function callback(...)
+ table.insert(events, {id, ...})
+ if test_unreg == id then
+ return true
end
- local opts = {on_lines=callback, on_detach=callback, utf_sizes=utf_sizes}
- if changedtick then
- opts.on_changedtick = callback
- end
- vim.api.nvim_buf_attach(bufnr, false, opts)
end
-
- function get_events()
- local ret_events = events
- events = {}
- return ret_events
+ local opts = {[evname]=callback, on_detach=callback, utf_sizes=utf_sizes}
+ if changedtick then
+ opts.on_changedtick = callback
end
- ]])
+ vim.api.nvim_buf_attach(bufnr, false, opts)
+ end
+
+ function get_events()
+ local ret_events = events
+ events = {}
+ return ret_events
+ end
+ ]], evname)
+end
+
+describe('lua buffer event callbacks: on_lines', function()
+ before_each(function()
+ clear()
+ attach_buffer('on_lines')
end)
@@ -62,7 +71,7 @@ describe('lua: buffer event callbacks', function()
local function check_events(expected)
local events = exec_lua("return get_events(...)" )
if utf_sizes then
- -- this test case uses ASCII only, so sizes sshould be the same.
+ -- this test case uses ASCII only, so sizes should be the same.
-- Unicode is tested below.
for _, event in ipairs(expected) do
event[9] = event[8]
@@ -216,4 +225,282 @@ describe('lua: buffer event callbacks', function()
eq(1, meths.get_var('listener_cursor_line'))
end)
+ it('does not SEGFAULT when calling win_findbuf in on_detach', function()
+
+ exec_lua[[
+ local buf = vim.api.nvim_create_buf(false, false)
+
+ vim.cmd"split"
+ vim.api.nvim_win_set_buf(0, buf)
+
+ vim.api.nvim_buf_attach(buf, false, {
+ on_detach = function(_, buf)
+ vim.fn.win_findbuf(buf)
+ end
+ })
+ ]]
+
+ command("q!")
+ helpers.assert_alive()
+ end)
+
+ it('#12718 lnume', function()
+ meths.buf_set_lines(0, 0, -1, true, {'1', '2', '3'})
+ exec_lua([[
+ vim.api.nvim_buf_attach(0, false, {
+ on_lines = function(...)
+ vim.api.nvim_set_var('linesev', { ... })
+ end,
+ })
+ ]])
+ feed('1G0')
+ feed('y<C-v>2j')
+ feed('G0')
+ feed('p')
+ -- Is the last arg old_byte_size correct? Doesn't matter for this PR
+ eq(meths.get_var('linesev'), { "lines", 1, 4, 2, 3, 5, 4 })
+
+ feed('2G0')
+ feed('p')
+ eq(meths.get_var('linesev'), { "lines", 1, 5, 1, 4, 4, 8 })
+
+ feed('1G0')
+ feed('P')
+ eq(meths.get_var('linesev'), { "lines", 1, 6, 0, 3, 3, 9 })
+
+ end)
+end)
+
+describe('lua: nvim_buf_attach on_bytes', function()
+ before_each(function()
+ clear()
+ attach_buffer('on_bytes')
+ end)
+
+ -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
+ -- assert the wrong thing), but masks errors with unflushed lines (as
+ -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
+ -- test both ways.
+ local function setup_eventcheck(verify, start_txt)
+ meths.buf_set_lines(0, 0, -1, true, start_txt)
+ local shadow = deepcopy(start_txt)
+ local shadowbytes = table.concat(shadow, '\n') .. '\n'
+ -- TODO: while we are brewing the real strong coffe,
+ -- verify should check buf_get_offset after every check_events
+ if verify then
+ meths.buf_get_offset(0, meths.buf_line_count(0))
+ end
+ exec_lua("return test_register(...)", 0, "test1",false, nil)
+ meths.buf_get_changedtick(0)
+
+ local verify_name = "test1"
+ local function check_events(expected)
+ local events = exec_lua("return get_events(...)" )
+ expect_events(expected, events, "byte updates")
+
+ if not verify then
+ return
+ end
+
+ for _, event in ipairs(events) do
+ for _, elem in ipairs(event) do
+ if type(elem) == "number" and elem < 0 then
+ fail(string.format("Received event has negative values"))
+ end
+ end
+
+ if event[1] == verify_name and event[2] == "bytes" then
+ local _, _, _, _, _, _, start_byte, _, _, old_byte, _, _, new_byte = unpack(event)
+ local before = string.sub(shadowbytes, 1, start_byte)
+ -- no text in the tests will contain 0xff bytes (invalid UTF-8)
+ -- so we can use it as marker for unknown bytes
+ local unknown = string.rep('\255', new_byte)
+ local after = string.sub(shadowbytes, start_byte + old_byte + 1)
+ shadowbytes = before .. unknown .. after
+ end
+ end
+
+ local text = meths.buf_get_lines(0, 0, -1, true)
+ local bytes = table.concat(text, '\n') .. '\n'
+
+ eq(string.len(bytes), string.len(shadowbytes), '\non_bytes: total bytecount of buffer is wrong')
+ for i = 1, string.len(shadowbytes) do
+ local shadowbyte = string.sub(shadowbytes, i, i)
+ if shadowbyte ~= '\255' then
+ eq(string.sub(bytes, i, i), shadowbyte, i)
+ end
+ end
+ end
+
+ return check_events
+ end
+
+ -- Yes, we can do both
+ local function do_both(verify)
+ it('single and multiple join', function()
+ local check_events = setup_eventcheck(verify, origlines)
+ feed 'ggJ'
+ check_events {
+ {'test1', 'bytes', 1, 3, 0, 15, 15, 1, 0, 1, 0, 1, 1};
+ }
+
+ feed '3J'
+ check_events {
+ {'test1', 'bytes', 1, 5, 0, 31, 31, 1, 0, 1, 0, 1, 1};
+ {'test1', 'bytes', 1, 5, 0, 47, 47, 1, 0, 1, 0, 1, 1};
+ }
+ end)
+
+ it('opening lines', function()
+ local check_events = setup_eventcheck(verify, origlines)
+ -- meths.buf_set_option(0, 'autoindent', true)
+ feed 'Go'
+ check_events {
+ { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 };
+ }
+ feed '<cr>'
+ check_events {
+ { "test1", "bytes", 1, 5, 7, 0, 114, 0, 0, 0, 1, 0, 1 };
+ }
+ end)
+
+ it('opening lines with autoindent', function()
+ local check_events = setup_eventcheck(verify, origlines)
+ meths.buf_set_option(0, 'autoindent', true)
+ feed 'Go'
+ check_events {
+ { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 5 };
+ }
+ feed '<cr>'
+ check_events {
+ { "test1", "bytes", 1, 4, 8, 0, 115, 0, 4, 4, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 7, 4, 118, 0, 0, 0, 1, 4, 5 };
+ }
+ end)
+
+ it('setline(num, line)', function()
+ local check_events = setup_eventcheck(verify, origlines)
+ funcs.setline(2, "babla")
+ check_events {
+ { "test1", "bytes", 1, 3, 1, 0, 16, 0, 15, 15, 0, 5, 5 };
+ }
+
+ funcs.setline(2, {"foo", "bar"})
+ check_events {
+ { "test1", "bytes", 1, 4, 1, 0, 16, 0, 5, 5, 0, 3, 3 };
+ { "test1", "bytes", 1, 5, 2, 0, 20, 0, 15, 15, 0, 3, 3 };
+ }
+
+ local buf_len = meths.buf_line_count(0)
+ funcs.setline(buf_len + 1, "baz")
+ check_events {
+ { "test1", "bytes", 1, 6, 7, 0, 90, 0, 0, 0, 1, 0, 4 };
+ }
+ end)
+
+ it('continuing comments with fo=or', function()
+ local check_events = setup_eventcheck(verify, {'// Comment'})
+ meths.buf_set_option(0, 'formatoptions', 'ro')
+ meths.buf_set_option(0, 'filetype', 'c')
+ feed 'A<CR>'
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 };
+ }
+
+ feed '<ESC>'
+ check_events {
+ { "test1", "bytes", 1, 4, 1, 2, 13, 0, 1, 1, 0, 0, 0 };
+ }
+
+ feed 'ggo' -- goto first line to continue testing
+ check_events {
+ { "test1", "bytes", 1, 6, 1, 0, 11, 0, 0, 0, 1, 0, 4 };
+ }
+
+ feed '<CR>'
+ check_events {
+ { "test1", "bytes", 1, 6, 2, 2, 16, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 7, 1, 3, 14, 0, 0, 0, 1, 3, 4 };
+ }
+ end)
+
+ it('editing empty buffers', function()
+ local check_events = setup_eventcheck(verify, {})
+
+ feed 'ia'
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ }
+ end)
+
+ it("changing lines", function()
+ local check_events = setup_eventcheck(verify, origlines)
+
+ feed "cc"
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 0, 15, 15, 0, 0, 0 };
+ }
+
+ feed "<ESC>"
+ check_events {}
+
+ feed "c3j"
+ check_events {
+ { "test1", "bytes", 1, 4, 1, 0, 1, 3, 0, 48, 0, 0, 0 };
+ }
+ end)
+
+ it("visual charwise paste", function()
+ local check_events = setup_eventcheck(verify, {'1234567890'})
+ funcs.setreg('a', '___')
+
+ feed '1G1|vll'
+ check_events {}
+
+ feed '"ap'
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3 };
+ }
+ end)
+
+ it('blockwise paste', function()
+ local check_events = setup_eventcheck(verify, {'1', '2', '3'})
+ feed('1G0')
+ feed('y<C-v>2j')
+ feed('G0')
+ feed('p')
+ check_events {
+ { "test1", "bytes", 1, 3, 2, 1, 5, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 3, 3, 0, 7, 0, 0, 0, 0, 3, 3 };
+ { "test1", "bytes", 1, 3, 4, 0, 10, 0, 0, 0, 0, 3, 3 };
+ }
+
+ feed('2G0')
+ feed('p')
+ check_events {
+ { "test1", "bytes", 1, 4, 1, 1, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 4, 2, 1, 6, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 4, 3, 1, 10, 0, 0, 0, 0, 1, 1 };
+ }
+
+ feed('1G0')
+ feed('P')
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 1, 0, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 2, 0, 7, 0, 0, 0, 0, 1, 1 };
+ }
+
+ end)
+ end
+
+ describe('(with verify) handles', function()
+ do_both(true)
+ end)
+
+ describe('(without verify) handles', function()
+ do_both(false)
+ end)
end)
+
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index cbc3aee557..f2a1b7dede 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -43,7 +43,7 @@ describe(':lua command', function()
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
end)
it('throws catchable errors', function()
- eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near ')']],
+ eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']],
pcall_err(command, 'lua ()'))
eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]],
exc_exec('lua error("TEST")'))
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 75966393b1..2ec48777fd 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -477,14 +477,14 @@ describe('v:lua', function()
eq(NIL, eval('v:lua.mymod.noisy("eval")'))
eq("hey eval", meths.get_current_line())
- eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
+ eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
pcall_err(eval, 'v:lua.mymod.crashy()'))
end)
it('works in :call', function()
command(":call v:lua.mymod.noisy('command')")
eq("hey command", meths.get_current_line())
- eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
+ eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
pcall_err(command, 'call v:lua.mymod.crashy()'))
end)
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
index aa3d55b06d..3526b64395 100644
--- a/test/functional/lua/treesitter_spec.lua
+++ b/test/functional/lua/treesitter_spec.lua
@@ -15,17 +15,16 @@ before_each(clear)
describe('treesitter API', function()
-- error tests not requiring a parser library
it('handles missing language', function()
- eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language",
- pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')"))
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')"))
-- actual message depends on platform
matches("Error executing lua: Failed to load parser: uv_dlopen: .+",
pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')"))
- eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language",
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
end)
-
end)
describe('treesitter API with C parser', function()
@@ -127,6 +126,58 @@ void ui_refresh(void)
}
}]]
+ it('allows to iterate over nodes children', function()
+ if not check_parser() then return end
+
+ insert(test_text);
+
+ local res = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ func_node = parser:parse():root():child(0)
+
+ res = {}
+ for node, field in func_node:iter_children() do
+ table.insert(res, {node:type(), field})
+ end
+ return res
+ ]])
+
+ eq({
+ {"primitive_type", "type"},
+ {"function_declarator", "declarator"},
+ {"compound_statement", "body"}
+ }, res)
+ end)
+
+ it('allows to get a child by field', function()
+ if not check_parser() then return end
+
+ insert(test_text);
+
+ local res = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ func_node = parser:parse():root():child(0)
+
+ local res = {}
+ for _, node in ipairs(func_node:field("type")) do
+ table.insert(res, {node:type(), node:range()})
+ end
+ return res
+ ]])
+
+ eq({{ "primitive_type", 0, 0, 0, 4 }}, res)
+
+ local res_fail = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ return #func_node:field("foo") == 0
+ ]])
+
+ assert(res_fail)
+ end)
+
local query = [[
((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN"))
"for" @keyword
@@ -134,6 +185,16 @@ void ui_refresh(void)
(field_expression argument: (identifier) @fieldarg)
]]
+ it("supports runtime queries", function()
+ if not check_parser() then return end
+
+ local ret = exec_lua [[
+ return require"vim.treesitter.query".get_query("c", "highlights").captures[1]
+ ]]
+
+ eq('variable', ret)
+ end)
+
it('support query and iter by capture', function()
if not check_parser() then return end
@@ -198,6 +259,82 @@ void ui_refresh(void)
}, res)
end)
+ it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function()
+ if not check_parser() then return end
+
+ insert('char* astring = "Hello World!";')
+
+ local res = exec_lua([[
+ cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))')
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()
+ res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do
+ -- can't transmit node over RPC. just check the name and range
+ local mrepr = {}
+ for cid,node in pairs(match) do
+ table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()})
+ end
+ table.insert(res, {pattern, mrepr})
+ end
+ return res
+ ]])
+
+ eq({
+ { 1, { { "quote", '"', 0, 16, 0, 17 } } },
+ { 2, { { "quote", '"', 0, 16, 0, 17 } } },
+ { 1, { { "quote", '"', 0, 29, 0, 30 } } },
+ { 2, { { "quote", '"', 0, 29, 0, 30 } } },
+ }, res)
+ end)
+
+ it('allows to add predicates', function()
+ insert([[
+ int main(void) {
+ return 0;
+ }
+ ]])
+
+ local custom_query = "((identifier) @main (#is-main? @main))"
+
+ local res = exec_lua([[
+ local query = require"vim.treesitter.query"
+
+ local function is_main(match, pattern, bufnr, predicate)
+ local node = match[ predicate[2] ]
+
+ return query.get_node_text(node, bufnr)
+ end
+
+ local parser = vim.treesitter.get_parser(0, "c")
+
+ query.add_predicate("is-main?", is_main)
+
+ local query = query.parse_query("c", ...)
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
+ table.insert(nodes, {node:range()})
+ end
+
+ return nodes
+ ]], custom_query)
+
+ eq({{0, 4, 0, 8}}, res)
+
+ local res_list = exec_lua[[
+ local query = require'vim.treesitter.query'
+
+ local list = query.list_predicates()
+
+ table.sort(list)
+
+ return list
+ ]]
+
+ eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
+ end)
+
it('supports highlighting', function()
if not check_parser() then return end
@@ -243,10 +380,10 @@ static int nlua_schedule(lua_State *const lstate)
(primitive_type) @type
(sized_type_specifier) @type
-; defaults to very magic syntax, for best compatibility
-((identifier) @Identifier (#match? @Identifier "^l(u)a_"))
-; still support \M etc prefixes
-((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$"))
+; Use lua regexes
+((identifier) @Identifier (#contains? @Identifier "lua_"))
+((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$"))
+((identifier) @Normal (#vim-match? @Constant "^lstate$"))
((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right))
@@ -292,13 +429,14 @@ static int nlua_schedule(lua_State *const lstate)
]]}
exec_lua([[
- local TSHighlighter = vim.treesitter.TSHighlighter
+ local parser = vim.treesitter.get_parser(0, "c")
+ local highlighter = vim.treesitter.highlighter
local query = ...
- test_hl = TSHighlighter.new(query, 0, "c")
+ test_hl = highlighter.new(parser, query)
]], hl_query)
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
|| {6:lstate} != {6:lstate}) { |
@@ -306,9 +444,9 @@ static int nlua_schedule(lua_State *const lstate)
{4:return} {11:lua_error}(lstate); |
} |
|
- {7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
|
- multiqueue_put(main_loop.events, nlua_schedule_event, |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
^} |
@@ -317,10 +455,33 @@ static int nlua_schedule(lua_State *const lstate)
|
]]}
+ feed("5Goc<esc>dd")
+
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
feed('7Go*/<esc>')
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
|| {6:lstate} != {6:lstate}) { |
@@ -329,9 +490,9 @@ static int nlua_schedule(lua_State *const lstate)
{8:*^/} |
} |
|
- {7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
|
- multiqueue_put(main_loop.events, nlua_schedule_event, |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
} |
@@ -342,7 +503,7 @@ static int nlua_schedule(lua_State *const lstate)
feed('3Go/*<esc>')
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{2:/^*} |
{2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
@@ -352,9 +513,9 @@ static int nlua_schedule(lua_State *const lstate)
{2:*/} |
} |
|
- {7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
|
- multiqueue_put(main_loop.events, nlua_schedule_event, |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
{8:}} |
@@ -365,7 +526,7 @@ static int nlua_schedule(lua_State *const lstate)
feed("~")
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queu^E} |
- {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{2:/*} |
{2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
@@ -375,9 +536,9 @@ static int nlua_schedule(lua_State *const lstate)
{2:*/} |
} |
|
- {7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
|
- multiqueue_put(main_loop.events, nlua_schedule_event, |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
{8:}} |
@@ -388,7 +549,7 @@ static int nlua_schedule(lua_State *const lstate)
feed("re")
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queu^e} |
- {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{2:/*} |
{2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
@@ -398,9 +559,9 @@ static int nlua_schedule(lua_State *const lstate)
{2:*/} |
} |
|
- {7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
|
- multiqueue_put(main_loop.events, nlua_schedule_event, |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
{8:}} |
@@ -408,6 +569,72 @@ static int nlua_schedule(lua_State *const lstate)
]]}
end)
+ it("supports highlighting with custom parser", function()
+ if not check_parser() then return end
+
+ local screen = Screen.new(65, 18)
+ screen:attach()
+ screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} })
+
+ insert(test_text)
+
+ screen:expect{ grid= [[
+ int width = INT_MAX, height = INT_MAX; |
+ bool ext_widgets[kUIExtCount]; |
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool inclusive = ui_override(); |
+ for (size_t i = 0; i < ui_count; i++) { |
+ UI *ui = uis[i]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+ query = vim.treesitter.parse_query("c", "(declaration) @decl")
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
+ table.insert(nodes, node)
+ end
+
+ parser:set_included_ranges(nodes)
+
+ local hl = vim.treesitter.highlighter.new(parser, "(identifier) @type")
+ ]])
+
+ screen:expect{ grid = [[
+ int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
+ bool {1:ext_widgets}[{1:kUIExtCount}]; |
+ for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {1:inclusive} = {1:ui_override}(); |
+ for (size_t {1:i} = 0; i < ui_count; i++) { |
+ UI *{1:ui} = {1:uis}[{1:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+ end)
+
it('inspects language', function()
if not check_parser() then return end
@@ -453,23 +680,29 @@ static int nlua_schedule(lua_State *const lstate)
insert(test_text)
- local res = exec_lua([[
+ local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
return { parser:parse():root():range() }
- ]])
+ ]]
eq({0, 0, 19, 0}, res)
-- The following sets the included ranges for the current parser
-- As stated here, this only includes the function (thus the whole buffer, without the last line)
- local res2 = exec_lua([[
+ local res2 = exec_lua [[
local root = parser:parse():root()
parser:set_included_ranges({root:child(0)})
parser.valid = false
return { parser:parse():root():range() }
- ]])
+ ]]
eq({0, 0, 18, 1}, res2)
+
+ local range = exec_lua [[
+ return parser:included_ranges()
+ ]]
+
+ eq(range, { { 0, 0, 18, 1 } })
end)
it("allows to set complex ranges", function()
if not check_parser() then return end
@@ -477,7 +710,7 @@ static int nlua_schedule(lua_State *const lstate)
insert(test_text)
- local res = exec_lua([[
+ local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
query = vim.treesitter.parse_query("c", "(declaration) @decl")
@@ -495,7 +728,7 @@ static int nlua_schedule(lua_State *const lstate)
table.insert(res, { root:named_child(i):range() })
end
return res
- ]])
+ ]]
eq({
{ 2, 2, 2, 40 },
@@ -509,4 +742,35 @@ static int nlua_schedule(lua_State *const lstate)
{ 10, 5, 10, 20 },
{ 14, 9, 14, 27 } }, res)
end)
+
+ it("allows to create string parsers", function()
+ local ret = exec_lua [[
+ local parser = vim.treesitter.get_string_parser("int foo = 42;", "c")
+ return { parser:parse():root():range() }
+ ]]
+
+ eq({ 0, 0, 0, 13 }, ret)
+ end)
+
+ it("allows to run queries with string parsers", function()
+ local txt = [[
+ int foo = 42;
+ int bar = 13;
+ ]]
+
+ local ret = exec_lua([[
+ local str = ...
+ local parser = vim.treesitter.get_string_parser(str, "c")
+
+ local nodes = {}
+ local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))')
+
+ for _, node in query:iter_captures(parser:parse():root(), str, 0, 2) do
+ table.insert(nodes, { node:range() })
+ end
+
+ return nodes]], txt)
+
+ eq({ {0, 10, 0, 13} }, ret)
+ end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 9b2697b3c2..1cbf6b21e3 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -4,13 +4,14 @@ local Screen = require('test.functional.ui.screen')
local funcs = helpers.funcs
local meths = helpers.meths
+local dedent = helpers.dedent
local command = helpers.command
local clear = helpers.clear
local eq = helpers.eq
local ok = helpers.ok
local eval = helpers.eval
local feed = helpers.feed
-local pcall_err = helpers.pcall_err
+local pcall_err_withfile = helpers.pcall_err_withfile
local exec_lua = helpers.exec_lua
local matches = helpers.matches
local source = helpers.source
@@ -128,8 +129,8 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.startswith("123", "2")'))
eq(false, funcs.luaeval('vim.startswith("123", "1234")'))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith("123", nil)')))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith(nil, "123")')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.startswith("123", nil)')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.startswith(nil, "123")')))
end)
it('vim.endswith', function()
@@ -142,8 +143,8 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.endswith("123", "2")'))
eq(false, funcs.luaeval('vim.endswith("123", "1234")'))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith("123", nil)')))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith(nil, "123")')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.endswith("123", nil)')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.endswith(nil, "123")')))
end)
it("vim.str_utfindex/str_byteindex", function()
@@ -182,10 +183,10 @@ describe('lua stdlib', function()
eq({"yy","xx"}, exec_lua("return test_table"))
-- Validates args.
- eq('Error executing lua: vim.schedule: expected function',
- pcall_err(exec_lua, "vim.schedule('stringly')"))
- eq('Error executing lua: vim.schedule: expected function',
- pcall_err(exec_lua, "vim.schedule()"))
+ eq('.../helpers.lua:0: Error executing lua: vim.schedule: expected function',
+ pcall_err_withfile(exec_lua, "vim.schedule('stringly')"))
+ eq('.../helpers.lua:0: Error executing lua: vim.schedule: expected function',
+ pcall_err_withfile(exec_lua, "vim.schedule()"))
exec_lua([[
vim.schedule(function()
@@ -257,17 +258,29 @@ describe('lua stdlib', function()
}
for _, t in ipairs(loops) do
- matches(".*Infinite loop detected", pcall_err(split, t[1], t[2]))
+ matches(".*Infinite loop detected", pcall_err_withfile(split, t[1], t[2]))
end
-- Validates args.
eq(true, pcall(split, 'string', 'string'))
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(split, 1, 'string'))
- eq('Error executing lua: .../shared.lua: sep: expected string, got number',
- pcall_err(split, 'string', 1))
- eq('Error executing lua: .../shared.lua: plain: expected boolean, got number',
- pcall_err(split, 'string', 'string', 1))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 1, 'string'))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: sep: expected string, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 'string', 1))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: plain: expected boolean, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 'string', 'string', 1))
end)
it('vim.trim', function()
@@ -287,8 +300,11 @@ describe('lua stdlib', function()
end
-- Validates args.
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(trim, 2))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(trim, 2))
end)
it('vim.inspect', function()
@@ -353,8 +369,8 @@ describe('lua stdlib', function()
return t1.f() ~= t2.f()
]]))
- eq('Error executing lua: .../shared.lua: Cannot deepcopy object of type thread',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: Cannot deepcopy object of type thread',
+ pcall_err_withfile(exec_lua, [[
local thread = coroutine.create(function () return 0 end)
local t = {thr = thread}
vim.deepcopy(t)
@@ -366,8 +382,11 @@ describe('lua stdlib', function()
eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
-- Validates args.
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(exec_lua, [[return vim.pesc(2)]]))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(exec_lua, [[return vim.pesc(2)]]))
end)
it('vim.tbl_keys', function()
@@ -491,20 +510,20 @@ describe('lua stdlib', function()
return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1
]]))
- eq('Error executing lua: .../shared.lua: invalid "behavior": nil',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: invalid "behavior": nil',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend()
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend("keep")
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend("keep", {})
]])
)
@@ -579,20 +598,20 @@ describe('lua stdlib', function()
return vim.tbl_islist(c) and count == 0
]]))
- eq('Error executing lua: .../shared.lua: invalid "behavior": nil',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: invalid "behavior": nil',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend()
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend("keep")
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend("keep", {})
]])
)
@@ -624,8 +643,11 @@ describe('lua stdlib', function()
it('vim.list_extend', function()
eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]])
- eq('Error executing lua: .../shared.lua: src: expected table, got nil',
- pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: src: expected table, got nil
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]])
eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]])
eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]])
@@ -648,8 +670,8 @@ describe('lua stdlib', function()
assert(vim.deep_equal(a, { A = 1; [1] = 'A'; }))
vim.tbl_add_reverse_lookup(a)
]]
- matches('Error executing lua: .../shared.lua: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"',
- pcall_err(exec_lua, code))
+ matches('.../helpers.lua:0: Error executing lua: shared.lua:0: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"',
+ pcall_err_withfile(exec_lua, code))
end)
it('vim.call, vim.fn', function()
@@ -820,34 +842,77 @@ 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' }}")
- eq("Error executing lua: .../shared.lua: 1: expected table, got number",
- pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
- eq("Error executing lua: .../shared.lua: invalid type name: x",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
- eq("Error executing lua: .../shared.lua: invalid type name: 1",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
- eq("Error executing lua: .../shared.lua: invalid type name: nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: opt[1]: expected table, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ 1, 'x' }"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: x
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: 1
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1 }}"))
-- Validated parameters are required by default.
- eq("Error executing lua: .../shared.lua: arg1: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
-- Explicitly required.
- eq("Error executing lua: .../shared.lua: arg1: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
-
- eq("Error executing lua: .../shared.lua: arg1: expected table, got number",
- pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got number",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3",
- pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
- eq("Error executing lua: .../shared.lua: arg1: expected ?, got 3",
- pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
+
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected table, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={1, 't'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected even number, got 3
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+
+ -- Pass an additional message back.
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3. Info: TEST_MSG
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1, 'TEST_MSG' end}}"))
end)
it('vim.is_callable', function()
@@ -992,10 +1057,10 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$",
- pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
- matches("^Error executing lua: .*: Expected lua string$",
- pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Invalid option name: 'nosuchopt'$",
+ pcall_err_withfile(exec_lua, 'return vim.bo.nosuchopt'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Expected lua string$",
+ pcall_err_withfile(exec_lua, 'return vim.bo[0][0].autoread'))
end)
it('vim.wo', function()
@@ -1011,10 +1076,10 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("^Error executing lua: .*: Invalid option name: 'notanopt'$",
- pcall_err(exec_lua, 'return vim.wo.notanopt'))
- matches("^Error executing lua: .*: Expected lua string$",
- pcall_err(exec_lua, 'return vim.wo[0][0].list'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Invalid option name: 'notanopt'$",
+ pcall_err_withfile(exec_lua, 'return vim.wo.notanopt'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Expected lua string$",
+ pcall_err_withfile(exec_lua, 'return vim.wo[0][0].list'))
eq(2, funcs.luaeval "vim.wo[1000].cole")
exec_lua [[
vim.wo[1000].cole = 0
@@ -1068,6 +1133,104 @@ describe('lua stdlib', function()
eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
end)
+ describe('vim.execute_on_keystroke', function()
+ it('should keep track of keystrokes', function()
+ helpers.insert([[hello world ]])
+
+ exec_lua [[
+ KeysPressed = {}
+
+ vim.register_keystroke_callback(function(buf)
+ if buf:byte() == 27 then
+ buf = "<ESC>"
+ end
+
+ table.insert(KeysPressed, buf)
+ end)
+ ]]
+
+ helpers.insert([[next ๐Ÿคฆ lines รฅ ]])
+
+ -- It has escape in the keys pressed
+ eq('inext ๐Ÿคฆ lines รฅ <ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
+ end)
+
+ it('should allow removing trackers.', function()
+ helpers.insert([[hello world]])
+
+ exec_lua [[
+ KeysPressed = {}
+
+ return vim.register_keystroke_callback(function(buf)
+ if buf:byte() == 27 then
+ buf = "<ESC>"
+ end
+
+ table.insert(KeysPressed, buf)
+ end, vim.api.nvim_create_namespace("logger"))
+ ]]
+
+ helpers.insert([[next lines]])
+
+ exec_lua("vim.register_keystroke_callback(nil, vim.api.nvim_create_namespace('logger'))")
+
+ helpers.insert([[more lines]])
+
+ -- It has escape in the keys pressed
+ eq('inext lines<ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
+ end)
+
+ it('should not call functions that error again.', function()
+ helpers.insert([[hello world]])
+
+ exec_lua [[
+ KeysPressed = {}
+
+ return vim.register_keystroke_callback(function(buf)
+ if buf:byte() == 27 then
+ buf = "<ESC>"
+ end
+
+ table.insert(KeysPressed, buf)
+
+ if buf == 'l' then
+ error("Dumb Error")
+ end
+ end)
+ ]]
+
+ helpers.insert([[next lines]])
+ helpers.insert([[more lines]])
+
+ -- Only the first letter gets added. After that we remove the callback
+ eq('inext l', exec_lua [[ return table.concat(KeysPressed, '') ]])
+ end)
+
+ it('should process mapped keys, not unmapped keys', function()
+ exec_lua [[
+ KeysPressed = {}
+
+ vim.cmd("inoremap hello world")
+
+ vim.register_keystroke_callback(function(buf)
+ if buf:byte() == 27 then
+ buf = "<ESC>"
+ end
+
+ table.insert(KeysPressed, buf)
+ end)
+ ]]
+
+ helpers.insert("hello")
+
+ local next_status = exec_lua [[
+ return table.concat(KeysPressed, '')
+ ]]
+
+ eq("iworld<ESC>", next_status)
+ end)
+ end)
+
describe('vim.wait', function()
before_each(function()
exec_lua[[
@@ -1116,6 +1279,23 @@ describe('lua stdlib', function()
]])
end)
+ it('should not process non-fast events when commanded', function()
+ eq({wait_result = false}, exec_lua[[
+ start_time = get_time()
+
+ vim.g.timer_result = false
+ timer = vim.loop.new_timer()
+ timer:start(100, 0, vim.schedule_wrap(function()
+ vim.g.timer_result = true
+ end))
+
+ wait_result = vim.wait(300, function() return vim.g.timer_result end, nil, true)
+
+ return {
+ wait_result = wait_result,
+ }
+ ]])
+ end)
it('should work with vim.defer_fn', function()
eq({time = true, wait_result = true}, exec_lua[[
start_time = get_time()
@@ -1130,22 +1310,38 @@ describe('lua stdlib', function()
]])
end)
- it('should require functions to be passed', function()
+ it('should not crash when callback errors', function()
local pcall_result = exec_lua [[
- return {pcall(function() vim.wait(1000, 13) end)}
+ return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)}
]]
eq(pcall_result[1], false)
- matches('condition must be a function', pcall_result[2])
+ matches('As Expected', pcall_result[2])
end)
- it('should not crash when callback errors', function()
+ it('if callback is passed, it must be a function', function()
local pcall_result = exec_lua [[
- return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)}
+ return {pcall(function() vim.wait(1000, 13) end)}
]]
eq(pcall_result[1], false)
- matches('As Expected', pcall_result[2])
+ matches('if passed, condition must be a function', pcall_result[2])
+ end)
+
+ it('should allow waiting with no callback, explicit', function()
+ eq(true, exec_lua [[
+ local start_time = vim.loop.hrtime()
+ vim.wait(50, nil)
+ return vim.loop.hrtime() - start_time > 25000
+ ]])
+ end)
+
+ it('should allow waiting with no callback, implicit', function()
+ eq(true, exec_lua [[
+ local start_time = vim.loop.hrtime()
+ vim.wait(50)
+ return vim.loop.hrtime() - start_time > 25000
+ ]])
end)
it('should call callbacks exactly once if they return true immediately', function()
@@ -1232,4 +1428,29 @@ describe('lua stdlib', function()
eq(false, pcall_result)
end)
end)
+
+ describe('vim.api.nvim_buf_call', function()
+ it('can access buf options', function()
+ local buf1 = meths.get_current_buf()
+ local buf2 = exec_lua [[
+ buf2 = vim.api.nvim_create_buf(false, true)
+ return buf2
+ ]]
+
+ eq(false, meths.buf_get_option(buf1, 'autoindent'))
+ eq(false, meths.buf_get_option(buf2, 'autoindent'))
+
+ local val = exec_lua [[
+ return vim.api.nvim_buf_call(buf2, function()
+ vim.cmd "set autoindent"
+ return vim.api.nvim_get_current_buf()
+ end)
+ ]]
+
+ eq(false, meths.buf_get_option(buf1, 'autoindent'))
+ eq(true, meths.buf_get_option(buf2, 'autoindent'))
+ eq(buf1, meths.get_current_buf())
+ eq(buf2, val)
+ end)
+ end)
end)
diff --git a/test/functional/normal/meta_key_spec.lua b/test/functional/normal/meta_key_spec.lua
new file mode 100644
index 0000000000..9f9fad67d2
--- /dev/null
+++ b/test/functional/normal/meta_key_spec.lua
@@ -0,0 +1,22 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
+local expect = helpers.expect
+
+describe('meta-keys-in-normal-mode', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('ALT/META', function()
+ -- Unmapped ALT-chords behave as Esc+c
+ insert('hello')
+ feed('0<A-x><M-x>')
+ expect('llo')
+ -- Mapped ALT-chord behaves as mapped.
+ command('nnoremap <M-l> Ameta-l<Esc>')
+ command('nnoremap <A-j> Aalt-j<Esc>')
+ feed('<A-j><M-l>')
+ expect('lloalt-jmeta-l')
+ end)
+end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 11ce26410d..92d077ed14 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -290,9 +290,6 @@ describe('XDG-based defaults', function()
end)
end)
- -- TODO(jkeyes): tests below fail on win32 because of path separator.
- if helpers.pending_win32(pending) then return end
-
local function vimruntime_and_libdir()
local vimruntime = eval('$VIMRUNTIME')
-- libdir is hard to calculate reliably across various ci platforms
@@ -301,71 +298,78 @@ describe('XDG-based defaults', function()
return vimruntime, libdir
end
+ local env_sep = iswin() and ';' or ':'
+ local data_dir = iswin() and 'nvim-data' or 'nvim'
+ local root_path = iswin() and 'C:' or ''
+
describe('with too long XDG variables', function()
before_each(function()
clear({env={
- XDG_CONFIG_HOME=('/x'):rep(4096),
- XDG_CONFIG_DIRS=(('/a'):rep(2048)
- .. ':' .. ('/b'):rep(2048)
- .. (':/c'):rep(512)),
- XDG_DATA_HOME=('/X'):rep(4096),
- XDG_DATA_DIRS=(('/A'):rep(2048)
- .. ':' .. ('/B'):rep(2048)
- .. (':/C'):rep(512)),
+ XDG_CONFIG_HOME=(root_path .. ('/x'):rep(4096)),
+ XDG_CONFIG_DIRS=(root_path .. ('/a'):rep(2048)
+ .. env_sep.. root_path .. ('/b'):rep(2048)
+ .. (env_sep .. root_path .. '/c'):rep(512)),
+ XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)),
+ XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048)
+ .. env_sep .. root_path .. ('/B'):rep(2048)
+ .. (env_sep .. root_path .. '/C'):rep(512)),
}})
end)
it('are correctly set', function()
local vimruntime, libdir = vimruntime_and_libdir()
- eq((('/x'):rep(4096) .. '/nvim'
- .. ',' .. ('/a'):rep(2048) .. '/nvim'
- .. ',' .. ('/b'):rep(2048) .. '/nvim'
- .. (',' .. '/c/nvim'):rep(512)
- .. ',' .. ('/X'):rep(4096) .. '/nvim/site'
- .. ',' .. ('/A'):rep(2048) .. '/nvim/site'
- .. ',' .. ('/B'):rep(2048) .. '/nvim/site'
- .. (',' .. '/C/nvim/site'):rep(512)
+ eq(((root_path .. ('/x'):rep(4096) .. '/nvim'
+ .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim'
+ .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim'
+ .. (',' .. root_path .. '/c/nvim'):rep(512)
+ .. ',' .. root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/site'
+ .. ',' .. root_path .. ('/A'):rep(2048) .. '/nvim/site'
+ .. ',' .. root_path .. ('/B'):rep(2048) .. '/nvim/site'
+ .. (',' .. root_path .. '/C/nvim/site'):rep(512)
.. ',' .. vimruntime
.. ',' .. libdir
- .. (',' .. '/C/nvim/site/after'):rep(512)
- .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after'
- .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after'
- .. ',' .. ('/X'):rep(4096) .. '/nvim/site/after'
- .. (',' .. '/c/nvim/after'):rep(512)
- .. ',' .. ('/b'):rep(2048) .. '/nvim/after'
- .. ',' .. ('/a'):rep(2048) .. '/nvim/after'
- .. ',' .. ('/x'):rep(4096) .. '/nvim/after'
- ), meths.get_option('runtimepath'))
+ .. (',' .. root_path .. '/C/nvim/site/after'):rep(512)
+ .. ',' .. root_path .. ('/B'):rep(2048) .. '/nvim/site/after'
+ .. ',' .. root_path .. ('/A'):rep(2048) .. '/nvim/site/after'
+ .. ',' .. root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/site/after'
+ .. (',' .. root_path .. '/c/nvim/after'):rep(512)
+ .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim/after'
+ .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
+ .. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
+ ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
meths.command('set runtimepath&')
meths.command('set backupdir&')
meths.command('set directory&')
meths.command('set undodir&')
meths.command('set viewdir&')
- eq((('/x'):rep(4096) .. '/nvim'
- .. ',' .. ('/a'):rep(2048) .. '/nvim'
- .. ',' .. ('/b'):rep(2048) .. '/nvim'
- .. (',' .. '/c/nvim'):rep(512)
- .. ',' .. ('/X'):rep(4096) .. '/nvim/site'
- .. ',' .. ('/A'):rep(2048) .. '/nvim/site'
- .. ',' .. ('/B'):rep(2048) .. '/nvim/site'
- .. (',' .. '/C/nvim/site'):rep(512)
+ eq(((root_path .. ('/x'):rep(4096) .. '/nvim'
+ .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim'
+ .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim'
+ .. (',' .. root_path .. '/c/nvim'):rep(512)
+ .. ',' .. root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/site'
+ .. ',' .. root_path .. ('/A'):rep(2048) .. '/nvim/site'
+ .. ',' .. root_path .. ('/B'):rep(2048) .. '/nvim/site'
+ .. (',' .. root_path .. '/C/nvim/site'):rep(512)
.. ',' .. vimruntime
.. ',' .. libdir
- .. (',' .. '/C/nvim/site/after'):rep(512)
- .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after'
- .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after'
- .. ',' .. ('/X'):rep(4096) .. '/nvim/site/after'
- .. (',' .. '/c/nvim/after'):rep(512)
- .. ',' .. ('/b'):rep(2048) .. '/nvim/after'
- .. ',' .. ('/a'):rep(2048) .. '/nvim/after'
- .. ',' .. ('/x'):rep(4096) .. '/nvim/after'
- ), meths.get_option('runtimepath'))
- eq('.,' .. ('/X'):rep(4096) .. '/nvim/backup',
- meths.get_option('backupdir'))
- eq(('/X'):rep(4096) .. '/nvim/swap//', meths.get_option('directory'))
- eq(('/X'):rep(4096) .. '/nvim/undo', meths.get_option('undodir'))
- eq(('/X'):rep(4096) .. '/nvim/view', meths.get_option('viewdir'))
+ .. (',' .. root_path .. '/C/nvim/site/after'):rep(512)
+ .. ',' .. root_path .. ('/B'):rep(2048) .. '/nvim/site/after'
+ .. ',' .. root_path .. ('/A'):rep(2048) .. '/nvim/site/after'
+ .. ',' .. root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/site/after'
+ .. (',' .. root_path .. '/c/nvim/after'):rep(512)
+ .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim/after'
+ .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
+ .. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
+ ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+ eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup',
+ (meths.get_option('backupdir'):gsub('\\', '/')))
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//',
+ (meths.get_option('directory')):gsub('\\', '/'))
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo',
+ (meths.get_option('undodir')):gsub('\\', '/'))
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view',
+ (meths.get_option('viewdir')):gsub('\\', '/'))
end)
end)
@@ -381,53 +385,61 @@ describe('XDG-based defaults', function()
it('are not expanded', function()
local vimruntime, libdir = vimruntime_and_libdir()
- eq(('$XDG_DATA_HOME/nvim'
+ eq((('$XDG_DATA_HOME/nvim'
.. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/nvim/site'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site'
.. ',$XDG_CONFIG_DIRS/nvim/site'
.. ',' .. vimruntime
.. ',' .. libdir
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
- ), meths.get_option('runtimepath'))
+ ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
meths.command('set runtimepath&')
meths.command('set backupdir&')
meths.command('set directory&')
meths.command('set undodir&')
meths.command('set viewdir&')
- eq(('$XDG_DATA_HOME/nvim'
+ eq((('$XDG_DATA_HOME/nvim'
.. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/nvim/site'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site'
.. ',$XDG_CONFIG_DIRS/nvim/site'
.. ',' .. vimruntime
.. ',' .. libdir
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
- ), meths.get_option('runtimepath'))
- eq('.,$XDG_CONFIG_HOME/nvim/backup', meths.get_option('backupdir'))
- eq('$XDG_CONFIG_HOME/nvim/swap//', meths.get_option('directory'))
- eq('$XDG_CONFIG_HOME/nvim/undo', meths.get_option('undodir'))
- eq('$XDG_CONFIG_HOME/nvim/view', meths.get_option('viewdir'))
+ ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+ eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
+ meths.get_option('backupdir'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
+ meths.get_option('directory'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
+ meths.get_option('undodir'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
+ meths.get_option('viewdir'):gsub('\\', '/'))
meths.command('set all&')
eq(('$XDG_DATA_HOME/nvim'
.. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/nvim/site'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site'
.. ',$XDG_CONFIG_DIRS/nvim/site'
.. ',' .. vimruntime
.. ',' .. libdir
.. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
- ), meths.get_option('runtimepath'))
- eq('.,$XDG_CONFIG_HOME/nvim/backup', meths.get_option('backupdir'))
- eq('$XDG_CONFIG_HOME/nvim/swap//', meths.get_option('directory'))
- eq('$XDG_CONFIG_HOME/nvim/undo', meths.get_option('undodir'))
- eq('$XDG_CONFIG_HOME/nvim/view', meths.get_option('viewdir'))
+ ):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
+ eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
+ meths.get_option('backupdir'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
+ meths.get_option('directory'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
+ meths.get_option('undodir'):gsub('\\', '/'))
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
+ meths.get_option('viewdir'):gsub('\\', '/'))
end)
end)
@@ -435,53 +447,58 @@ describe('XDG-based defaults', function()
before_each(function()
clear({env={
XDG_CONFIG_HOME=', , ,',
- XDG_CONFIG_DIRS=',-,-,:-,-,-',
+ XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
XDG_DATA_HOME=',=,=,',
- XDG_DATA_DIRS=',โ‰ก,โ‰ก,:โ‰ก,โ‰ก,โ‰ก',
+ XDG_DATA_DIRS=',โ‰ก,โ‰ก,' .. env_sep .. 'โ‰ก,โ‰ก,โ‰ก',
}})
end)
it('are escaped properly', function()
local vimruntime, libdir = vimruntime_and_libdir()
- eq(('\\, \\, \\,/nvim'
- .. ',\\,-\\,-\\,/nvim'
- .. ',-\\,-\\,-/nvim'
- .. ',\\,=\\,=\\,/nvim/site'
- .. ',\\,โ‰ก\\,โ‰ก\\,/nvim/site'
- .. ',โ‰ก\\,โ‰ก\\,โ‰ก/nvim/site'
+ local path_sep = iswin() and '\\' or '/'
+ eq(('\\, \\, \\,' .. path_sep .. 'nvim'
+ .. ',\\,-\\,-\\,' .. path_sep .. 'nvim'
+ .. ',-\\,-\\,-' .. path_sep .. 'nvim'
+ .. ',\\,=\\,=\\,' .. path_sep .. data_dir .. path_sep .. 'site'
+ .. ',\\,โ‰ก\\,โ‰ก\\,' .. path_sep .. 'nvim' .. path_sep .. 'site'
+ .. ',โ‰ก\\,โ‰ก\\,โ‰ก' .. path_sep .. 'nvim' .. path_sep .. 'site'
.. ',' .. vimruntime
.. ',' .. libdir
- .. ',โ‰ก\\,โ‰ก\\,โ‰ก/nvim/site/after'
- .. ',\\,โ‰ก\\,โ‰ก\\,/nvim/site/after'
- .. ',\\,=\\,=\\,/nvim/site/after'
- .. ',-\\,-\\,-/nvim/after'
- .. ',\\,-\\,-\\,/nvim/after'
- .. ',\\, \\, \\,/nvim/after'
+ .. ',โ‰ก\\,โ‰ก\\,โ‰ก' .. path_sep .. 'nvim' .. path_sep .. 'site' .. path_sep .. 'after'
+ .. ',\\,โ‰ก\\,โ‰ก\\,' .. path_sep .. 'nvim' .. path_sep .. 'site' .. path_sep .. 'after'
+ .. ',\\,=\\,=\\,' .. path_sep.. data_dir .. path_sep .. 'site' .. path_sep .. 'after'
+ .. ',-\\,-\\,-' .. path_sep .. 'nvim' .. path_sep .. 'after'
+ .. ',\\,-\\,-\\,' .. path_sep .. 'nvim' .. path_sep .. 'after'
+ .. ',\\, \\, \\,' .. path_sep .. 'nvim' .. path_sep .. 'after'
), meths.get_option('runtimepath'))
meths.command('set runtimepath&')
meths.command('set backupdir&')
meths.command('set directory&')
meths.command('set undodir&')
meths.command('set viewdir&')
- eq(('\\, \\, \\,/nvim'
- .. ',\\,-\\,-\\,/nvim'
- .. ',-\\,-\\,-/nvim'
- .. ',\\,=\\,=\\,/nvim/site'
- .. ',\\,โ‰ก\\,โ‰ก\\,/nvim/site'
- .. ',โ‰ก\\,โ‰ก\\,โ‰ก/nvim/site'
+ eq(('\\, \\, \\,' .. path_sep .. 'nvim'
+ .. ',\\,-\\,-\\,' .. path_sep ..'nvim'
+ .. ',-\\,-\\,-' .. path_sep ..'nvim'
+ .. ',\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'site'
+ .. ',\\,โ‰ก\\,โ‰ก\\,' .. path_sep ..'nvim' .. path_sep ..'site'
+ .. ',โ‰ก\\,โ‰ก\\,โ‰ก' .. path_sep ..'nvim' .. path_sep ..'site'
.. ',' .. vimruntime
.. ',' .. libdir
- .. ',โ‰ก\\,โ‰ก\\,โ‰ก/nvim/site/after'
- .. ',\\,โ‰ก\\,โ‰ก\\,/nvim/site/after'
- .. ',\\,=\\,=\\,/nvim/site/after'
- .. ',-\\,-\\,-/nvim/after'
- .. ',\\,-\\,-\\,/nvim/after'
- .. ',\\, \\, \\,/nvim/after'
+ .. ',โ‰ก\\,โ‰ก\\,โ‰ก' .. path_sep ..'nvim' .. path_sep ..'site' .. path_sep ..'after'
+ .. ',\\,โ‰ก\\,โ‰ก\\,' .. path_sep ..'nvim' .. path_sep ..'site' .. path_sep ..'after'
+ .. ',\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'site' .. path_sep ..'after'
+ .. ',-\\,-\\,-' .. path_sep ..'nvim' .. path_sep ..'after'
+ .. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
+ .. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
), meths.get_option('runtimepath'))
- eq('.,\\,=\\,=\\,/nvim/backup', meths.get_option('backupdir'))
- eq('\\,=\\,=\\,/nvim/swap//', meths.get_option('directory'))
- eq('\\,=\\,=\\,/nvim/undo', meths.get_option('undodir'))
- eq('\\,=\\,=\\,/nvim/view', meths.get_option('viewdir'))
+ eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup',
+ meths.get_option('backupdir'))
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
+ meths.get_option('directory'))
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo',
+ meths.get_option('undodir'))
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view',
+ meths.get_option('viewdir'))
end)
end)
end)
@@ -491,6 +508,7 @@ describe('stdpath()', function()
-- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions
-- due to XDG_CONFIG_HOME and XDG_DATA_HOME being the same.
local datadir = iswin() and 'nvim-data' or 'nvim'
+ local env_sep = iswin() and ';' or ':'
it('acceptance', function()
clear() -- Do not explicitly set any env vars.
@@ -634,13 +652,13 @@ describe('stdpath()', function()
local function set_paths_via_system(var_name, paths)
local env = base_env()
- env[var_name] = table.concat(paths, ':')
+ env[var_name] = table.concat(paths, env_sep)
clear({env=env})
end
local function set_paths_at_runtime(var_name, paths)
clear({env=base_env()})
- meths.set_var('env_val', table.concat(paths, ':'))
+ meths.set_var('env_val', table.concat(paths, env_sep))
command(('let $%s=g:env_val'):format(var_name))
end
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 1002011999..73f3fe5d0c 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -270,6 +270,76 @@ describe('LSP', function()
test_name = "basic_check_capabilities";
on_init = function(client)
client.stop()
+ local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_callback = function(...)
+ eq(table.remove(expected_callbacks), {...}, "expected callback")
+ end;
+ }
+ end)
+
+ it('client.supports_methods() should validate capabilities', function()
+ local expected_callbacks = {
+ {NIL, "shutdown", {}, 1};
+ }
+ test_rpc_server {
+ test_name = "capabilities_for_client_supports_method";
+ on_init = function(client)
+ client.stop()
+ local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ eq(true, client.resolved_capabilities().completion)
+ eq(true, client.resolved_capabilities().hover)
+ eq(false, client.resolved_capabilities().goto_definition)
+ eq(false, client.resolved_capabilities().rename)
+
+ -- known methods for resolved capabilities
+ eq(true, client.supports_method("textDocument/hover"))
+ eq(false, client.supports_method("textDocument/definition"))
+
+ -- unknown methods are assumed to be supported.
+ eq(true, client.supports_method("unknown-method"))
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_callback = function(...)
+ eq(table.remove(expected_callbacks), {...}, "expected callback")
+ end;
+ }
+ end)
+
+ it('should call unsupported_method when trying to call an unsupported method', function()
+ local expected_callbacks = {
+ {NIL, "shutdown", {}, 1};
+ }
+ test_rpc_server {
+ test_name = "capabilities_for_client_supports_method";
+ on_setup = function()
+ exec_lua([=[
+ vim.lsp.callbacks['textDocument/hover'] = function(err, method)
+ vim.lsp._last_lsp_callback = { err = err; method = method }
+ end
+ vim.lsp._unsupported_method = function(method)
+ vim.lsp._last_unsupported_method = method
+ return 'fake-error'
+ end
+ vim.lsp.buf.hover()
+ ]=])
+ end;
+ on_init = function(client)
+ client.stop()
+ local method = exec_lua("return vim.lsp._last_unsupported_method")
+ eq("textDocument/hover", method)
+ local lsp_cb_call = exec_lua("return vim.lsp._last_lsp_callback")
+ eq("fake-error", lsp_cb_call.err)
+ eq("textDocument/hover", lsp_cb_call.method)
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
@@ -747,8 +817,16 @@ describe('LSP', function()
end)
it('should invalid cmd argument', function()
- eq('Error executing lua: .../shared.lua: cmd: expected list, got nvim', pcall_err(_cmd_parts, "nvim"))
- eq('Error executing lua: .../shared.lua: cmd argument: expected string, got number', pcall_err(_cmd_parts, {"nvim", 1}))
+ eq(dedent([[
+ Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim
+ stack traceback:
+ .../lsp.lua:0: in function .../lsp.lua:0>]]),
+ pcall_err(_cmd_parts, 'nvim'))
+ eq(dedent([[
+ Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number
+ stack traceback:
+ .../lsp.lua:0: in function .../lsp.lua:0>]]),
+ pcall_err(_cmd_parts, {'nvim', 1}))
end)
end)
end)
@@ -971,34 +1049,34 @@ describe('LSP', function()
local prefix = 'foo'
local completion_list = {
-- resolves into label
- { label='foobar' },
- { label='foobar', textEdit={} },
+ { label='foobar', sortText="a" },
+ { label='foobar', sortText="b", textEdit={} },
-- resolves into insertText
- { label='foocar', insertText='foobar' },
- { label='foocar', insertText='foobar', textEdit={} },
+ { label='foocar', sortText="c", insertText='foobar' },
+ { label='foocar', sortText="d", insertText='foobar', textEdit={} },
-- resolves into textEdit.newText
- { label='foocar', insertText='foodar', textEdit={newText='foobar'} },
- { label='foocar', textEdit={newText='foobar'} },
+ { label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} },
+ { label='foocar', sortText="f", textEdit={newText='foobar'} },
-- real-world snippet text
- { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} },
- { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} },
+ { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} },
+ { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} },
-- nested snippet tokens
- { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} },
+ { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} },
-- plain text
- { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
+ { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
}
local completion_list_items = {items=completion_list}
local expected = {
- { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar' } } } } },
- { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar' } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar', sortText="a" } } } } },
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', sortText="b", textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="c", insertText='foobar' } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="d", insertText='foobar', textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="f", textEdit={newText='foobar'} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
}
eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index da9dd09129..1431054494 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -153,6 +153,16 @@ describe('clipboard', function()
eq('', eval('provider#clipboard#Error()'))
end)
+ it('g:clipboard using lists', function()
+ source([[let g:clipboard = {
+ \ 'name': 'custom',
+ \ 'copy': { '+': ['any', 'command'], '*': ['some', 'other'] },
+ \ 'paste': { '+': ['any', 'command'], '*': ['some', 'other'] },
+ \}]])
+ eq('custom', eval('provider#clipboard#Executable()'))
+ eq('', eval('provider#clipboard#Error()'))
+ end)
+
it('g:clipboard using VimL functions', function()
-- Implements a fake clipboard provider. cache_enabled is meaningless here.
source([[let g:clipboard = {
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index 7b446e4ab3..125674660b 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -5,6 +5,10 @@ local command = helpers.command
local write_file = helpers.write_file
local eval = helpers.eval
local retry = helpers.retry
+local curbufmeths = helpers.curbufmeths
+local insert = helpers.insert
+local expect = helpers.expect
+local feed = helpers.feed
do
clear()
@@ -19,7 +23,51 @@ before_each(function()
clear()
end)
-describe('perl host', function()
+describe('legacy perl provider', function()
+ if helpers.pending_win32(pending) then return end
+
+ it('feature test', function()
+ eq(1, eval('has("perl")'))
+ end)
+
+ it(':perl command', function()
+ command('perl $vim->vars->{set_by_perl} = [100, 0];')
+ eq({100, 0}, eval('g:set_by_perl'))
+ end)
+
+ it(':perlfile command', function()
+ local fname = 'perlfile.pl'
+ write_file(fname, '$vim->command("let set_by_perlfile = 123")')
+ command('perlfile perlfile.pl')
+ eq(123, eval('g:set_by_perlfile'))
+ os.remove(fname)
+ end)
+
+ it(':perldo command', function()
+ -- :perldo 1; doesn't change $_,
+ -- the buffer should not be changed
+ command('normal :perldo 1;')
+ eq(false, curbufmeths.get_option('modified'))
+ -- insert some text
+ insert('abc\ndef\nghi')
+ expect([[
+ abc
+ def
+ ghi]])
+ -- go to top and select and replace the first two lines
+ feed('ggvj:perldo $_ = reverse ($_)."$linenr"<CR>')
+ expect([[
+ cba1
+ fed2
+ ghi]])
+ end)
+
+ it('perleval()', function()
+ eq({1, 2, {['key'] = 'val'}}, eval([[perleval('[1, 2, {"key" => "val"}]')]]))
+ end)
+end)
+
+describe('perl provider', function()
if helpers.pending_win32(pending) then return end
teardown(function ()
os.remove('Xtest-perl-hello.pl')
diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua
index bb7d23ede6..2729d8dfa2 100644
--- a/test/functional/provider/ruby_spec.lua
+++ b/test/functional/provider/ruby_spec.lua
@@ -5,6 +5,7 @@ local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
local eval = helpers.eval
+local exc_exec = helpers.exc_exec
local expect = helpers.expect
local feed = helpers.feed
local feed_command = helpers.feed_command
@@ -109,3 +110,24 @@ describe('ruby provider', function()
eq(2, eval('1+1')) -- Still alive?
end)
end)
+
+describe('rubyeval()', function()
+ it('evaluates ruby objects', function()
+ eq({1, 2, {['key'] = 'val'}}, funcs.rubyeval('[1, 2, {key: "val"}]'))
+ end)
+
+ it('returns nil for empty strings', function()
+ eq(helpers.NIL, funcs.rubyeval(''))
+ end)
+
+ it('errors out when given non-string', function()
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(10)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:_null_dict)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:_null_list)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(0.0)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(function("tr"))'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:true)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:false)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:null)'))
+ end)
+end)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 6372cd935e..8e171d31aa 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source
local eq, neq = helpers.eq, helpers.neq
local write_file = helpers.write_file
@@ -13,7 +13,7 @@ describe(':terminal buffer', function()
before_each(function()
clear()
feed_command('set modifiable swapfile undolevels=20')
- wait()
+ poke_eventloop()
screen = thelpers.screen_setup()
end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index ef12438ecc..8d70ebf679 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -70,7 +70,7 @@ describe(':terminal cursor', function()
:set number |
]])
feed('i')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 46 |
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 138befd978..4b512605e1 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim
+local clear, poke_eventloop, nvim = helpers.clear, helpers.poke_eventloop, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
local feed = helpers.feed
local feed_command, eval = helpers.feed_command, helpers.eval
@@ -29,7 +29,7 @@ describe(':terminal', function()
-- Invoke a command that emits frequent terminal activity.
feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 9999 !terminal_output!<cr>]])
feed([[<C-\><C-N>]])
- wait()
+ poke_eventloop()
-- Wait for some terminal activity.
retry(nil, 4000, function()
ok(funcs.line('$') > 6)
@@ -60,7 +60,7 @@ describe(':terminal', function()
feed_command([[terminal while true; do echo foo; sleep .1; done]])
end
feed([[<C-\><C-N>M]]) -- move cursor away from last line
- wait()
+ poke_eventloop()
eq(3, eval("line('$')")) -- window height
eq(2, eval("line('.')")) -- cursor is in the middle
feed_command('vsplit')
@@ -76,11 +76,11 @@ describe(':terminal', function()
-- Create a new line (in the shell). For a normal buffer this
-- increments the jumplist; for a terminal-buffer it should not. #3723
feed('i')
- wait()
+ poke_eventloop()
feed('<CR><CR><CR><CR>')
- wait()
+ poke_eventloop()
feed([[<C-\><C-N>]])
- wait()
+ poke_eventloop()
-- Wait for >=1 lines to be created.
retry(nil, 4000, function()
ok(funcs.line('$') > lines_before)
@@ -210,7 +210,7 @@ describe(':terminal (with fake shell)', function()
it('ignores writes if the backing stream closes', function()
terminal_with_fake_shell()
feed('iiXXXXXXX')
- wait()
+ poke_eventloop()
-- Race: Though the shell exited (and streams were closed by SIGCHLD
-- handler), :terminal cleanup is pending on the main-loop.
-- This write should be ignored (not crash, #5445).
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 1df8df6f6e..77fdba7fc4 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -6,7 +6,7 @@ local feed, nvim_dir, feed_command = helpers.feed, helpers.nvim_dir, helpers.fee
local iswin = helpers.iswin
local eval = helpers.eval
local command = helpers.command
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local retry = helpers.retry
local curbufmeths = helpers.curbufmeths
local nvim = helpers.nvim
@@ -347,7 +347,7 @@ describe(':terminal prints more lines than the screen height and exits', functio
local screen = Screen.new(30, 7)
screen:attach({rgb=false})
feed_command('call termopen(["'..nvim_dir..'/tty-test", "10"]) | startinsert')
- wait()
+ poke_eventloop()
screen:expect([[
line6 |
line7 |
@@ -423,7 +423,7 @@ describe("'scrollback' option", function()
retry(nil, nil, function() expect_lines(33, 2) end)
curbufmeths.set_option('scrollback', 10)
- wait()
+ poke_eventloop()
retry(nil, nil, function() expect_lines(16) end)
curbufmeths.set_option('scrollback', 10000)
retry(nil, nil, function() expect_lines(16) end)
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index f1c828d17e..9f278fd157 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed_data = thelpers.feed_data
local feed, clear = helpers.feed, helpers.clear
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local command = helpers.command
local retry = helpers.retry
@@ -127,7 +127,7 @@ describe(':terminal window', function()
it('wont show any folds', function()
feed([[<C-\><C-N>ggvGzf]])
- wait()
+ poke_eventloop()
screen:expect([[
^tty ready |
line1 |
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 3cb592c714..d7269d2c29 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -690,7 +690,7 @@ describe('Buffer highlighting', function()
end)
it('can be retrieved', function()
- local get_virtual_text = curbufmeths.get_virtual_text
+ local get_extmarks = curbufmeths.get_extmarks
local line_count = curbufmeths.line_count
local s1 = {{'Kรถttbullar', 'Comment'}, {'Krรคuterbutter'}}
@@ -699,12 +699,14 @@ describe('Buffer highlighting', function()
-- TODO: only a virtual text from the same ns curretly overrides
-- an existing virtual text. We might add a prioritation system.
set_virtual_text(id1, 0, s1, {})
- eq(s1, get_virtual_text(0))
+ eq({{1, 0, 0, {virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
- set_virtual_text(-1, line_count(), s2, {})
- eq(s2, get_virtual_text(line_count()))
+ -- TODO: is this really valid? shouldn't the max be line_count()-1?
+ local lastline = line_count()
+ set_virtual_text(id1, line_count(), s2, {})
+ eq({{3, lastline, 0, {virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
- eq({}, get_virtual_text(line_count() + 9000))
+ eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {}))
end)
it('is not highlighted by visual selection', function()
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 21c01b3458..01f0d8a4d7 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
+local feed_command = helpers.feed_command
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -842,3 +843,34 @@ describe('cmdline redraw', function()
]], unchanged=true}
end)
end)
+
+describe('cmdline', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('prints every executed Ex command if verbose >= 16', function()
+ local screen = Screen.new(50, 12)
+ screen:attach()
+ source([[
+ command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
+ call feedkeys("\r", 't') " for the hit-enter prompt
+ set verbose=20
+ ]])
+ feed_command('DoSomething')
+ screen:expect([[
+ |
+ ~ |
+ |
+ Executing: DoSomething |
+ Executing: echo 'hello' |set ts=4 |let v = '123' ||
+ echo v |
+ hello |
+ Executing: set ts=4 |let v = '123' |echo v |
+ Executing: let v = '123' |echo v |
+ Executing: echo v |
+ 123 |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 6c913124ac..e1a72ced05 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -286,6 +286,21 @@ describe('ui/cursor', function()
eq(173, named.normal.blinkon)
eq(42, named.showmatch.cell_percentage)
end)
+
+ -- If there is no setting for guicursor, it becomes the default setting.
+ meths.set_option('guicursor', 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor')
+ screen:expect(function()
+ for _,m in ipairs(screen._mode_info) do
+ if m.name ~= 'normal' then
+ eq('block', m.cursor_shape or 'block')
+ eq(0, m.blinkon or 0)
+ eq(0, m.blinkoff or 0)
+ eq(0, m.blinkwait or 0)
+ eq(0, m.hl_id or 0)
+ eq(0, m.id_lm or 0)
+ end
+ end
+ end)
end)
it("empty 'guicursor' sets cursor_shape=block in all modes", function()
@@ -297,6 +312,8 @@ describe('ui/cursor', function()
if m['cursor_shape'] ~= nil then
eq('block', m.cursor_shape)
eq(0, m.blinkon)
+ eq(0, m.hl_id)
+ eq(0, m.id_lm)
end
end
end)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
new file mode 100644
index 0000000000..304c5aecb1
--- /dev/null
+++ b/test/functional/ui/decorations_spec.lua
@@ -0,0 +1,118 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear = helpers.clear
+local feed = helpers.feed
+local insert = helpers.insert
+local exec_lua = helpers.exec_lua
+local expect_events = helpers.expect_events
+
+describe('decorations provider', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ })
+ end)
+
+ local mudholland = [[
+ // just to see if there was an accident
+ // on Mulholland Drive
+ try_start();
+ bufref_T save_buf;
+ switch_buffer(&save_buf, buf);
+ posp = getmark(mark, false);
+ restore_buffer(&save_buf); ]]
+
+ local function setup_provider(code)
+ exec_lua ([[
+ local a = vim.api
+ test1 = a.nvim_create_namespace "test1"
+ ]] .. (code or [[
+ beamtrace = {}
+ function on_do(kind, ...)
+ table.insert(beamtrace, {kind, ...})
+ end
+ ]]) .. [[
+ a.nvim_set_decoration_provider(
+ test1, {
+ on_start = on_do; on_buf = on_do;
+ on_win = on_do; on_line = on_do;
+ on_end = on_do;
+ })
+ ]])
+ end
+
+ local function check_trace(expected)
+ local actual = exec_lua [[ local b = beamtrace beamtrace = {} return b ]]
+ expect_events(expected, actual, "beam trace")
+ end
+
+ it('leaves a trace', function()
+ insert(mudholland)
+
+ setup_provider()
+
+ screen:expect{grid=[[
+ // just to see if there was an accident |
+ // on Mulholland Drive |
+ try_start(); |
+ bufref_T save_buf; |
+ switch_buffer(&save_buf, buf); |
+ posp = getmark(mark, false); |
+ restore_buffer(&save_buf);^ |
+ |
+ ]]}
+ check_trace {
+ { "start", 4, 40 };
+ { "win", 1000, 1, 0, 8 };
+ { "line", 1000, 1, 0 };
+ { "line", 1000, 1, 1 };
+ { "line", 1000, 1, 2 };
+ { "line", 1000, 1, 3 };
+ { "line", 1000, 1, 4 };
+ { "line", 1000, 1, 5 };
+ { "line", 1000, 1, 6 };
+ { "end", 4 };
+ }
+
+ feed "iรผ<esc>"
+ screen:expect{grid=[[
+ // just to see if there was an accident |
+ // on Mulholland Drive |
+ try_start(); |
+ bufref_T save_buf; |
+ switch_buffer(&save_buf, buf); |
+ posp = getmark(mark, false); |
+ restore_buffer(&save_buf);^รผ |
+ |
+ ]]}
+ check_trace {
+ { "start", 5, 10 };
+ { "buf", 1 };
+ { "win", 1000, 1, 0, 8 };
+ { "line", 1000, 1, 6 };
+ { "end", 5 };
+ }
+ end)
+
+ it('single provider', function()
+ insert(mudholland)
+ setup_provider [[
+ local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
+ function do_it(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ a.nvim_buf_set_extmark(buf, test_ns, line, line,
+ { end_line = line, end_col = line+1,
+ hl_group = hl,
+ ephemeral = true
+ })
+ end
+ end
+ ]]
+ end)
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 11fe861de8..eec8eb93d4 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -59,7 +59,7 @@ describe('floatwin', function()
end)
it('closed immediately by autocmd #11383', function()
- eq('Error executing lua: [string "<nvim>"]:4: Window was closed immediately',
+ eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
pcall_err(exec_lua, [[
local a = vim.api
local function crashes(contents)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 6ec45064da..9877f30206 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -6,6 +6,8 @@ local feed_command = helpers.feed_command
local insert = helpers.insert
local funcs = helpers.funcs
local meths = helpers.meths
+local source = helpers.source
+local assert_alive = helpers.assert_alive
describe("folded lines", function()
local screen
@@ -21,6 +23,8 @@ describe("folded lines", function()
[5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
[6] = {background = Screen.colors.Yellow},
[7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [8] = {foreground = Screen.colors.Brown },
+ [9] = {bold = true, foreground = Screen.colors.Brown}
})
end)
@@ -29,7 +33,7 @@ describe("folded lines", function()
feed("i<cr><esc>")
feed("vkzf")
screen:expect([[
- {5: ^+-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยท}|
+ {7: }{5:^+-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยท}|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -49,8 +53,8 @@ describe("folded lines", function()
funcs.setline(4, 'line 2')
feed("j")
screen:expect([[
- {7:+ }{5: 1 +-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
- {7:+ }{5: 0 ^+-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
+ {7:+ }{8: 1 }{5:+-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
+ {7:+ }{9: 0 }{5:^+-- 2 lines: ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -130,8 +134,8 @@ describe("folded lines", function()
]])
feed('vkzf')
- screen:expect([[
- {5:^+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ๏บŽ๏ป ๏ป‹ูŽ๏บฎูŽ๏บ’ู๏ปณูŽู‘๏บ“ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
+ screen:expect{grid=[[
+ {5:^+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ุงู„ุนูŽุฑูŽุจููŠูŽู‘ุฉยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท}|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -139,7 +143,7 @@ describe("folded lines", function()
{1:~ }|
{1:~ }|
|
- ]])
+ ]]}
feed_command("set noarabicshape")
screen:expect([[
@@ -155,7 +159,7 @@ describe("folded lines", function()
feed_command("set number foldcolumn=2")
screen:expect([[
- {7:+ }{5: 1 ^+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ุงู„ุนูŽุฑูŽุจููŠูŽู‘ุฉยทยทยทยทยทยทยทยทยทยทยท}|
+ {7:+ }{8: 1 }{5:^+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ุงู„ุนูŽุฑูŽุจููŠูŽู‘ุฉยทยทยทยทยทยทยทยทยทยทยท}|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -168,7 +172,7 @@ describe("folded lines", function()
-- Note: too much of the folded line gets cut off.This is a vim bug.
feed_command("set rightleft")
screen:expect([[
- {5:+-- 2 lines: รฅ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท^ยท 1 }{7: +}|
+ {5:ยทยทยทยทยทยทยทยทยทยทยทุฉูŠูŽู‘ุจูุฑูŽุนูŽู„ุง xฬŽอ‚อ€ฬ‚อ›อ› ่ฏญ รฅ :senil 2 --^+}{8: 1 }{7: +}|
{1: ~}|
{1: ~}|
{1: ~}|
@@ -180,7 +184,7 @@ describe("folded lines", function()
feed_command("set nonumber foldcolumn=0")
screen:expect([[
- {5:+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ุงู„ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท^ยท}|
+ {5:ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทุฉูŠูŽู‘ุจูุฑูŽุนูŽู„ุง xฬŽอ‚อ€ฬ‚อ›อ› ่ฏญ รฅ :senil 2 --^+}|
{1: ~}|
{1: ~}|
{1: ~}|
@@ -192,7 +196,7 @@ describe("folded lines", function()
feed_command("set arabicshape")
screen:expect([[
- {5:+-- 2 lines: รฅ ่ฏญ xฬŽอ‚อ€ฬ‚อ›อ› ๏บ๏ปŸยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท^ยท}|
+ {5:ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทุฉูŠูŽู‘ุจูุฑูŽุนูŽู„ุง xฬŽอ‚อ€ฬ‚อ›อ› ่ฏญ รฅ :senil 2 --^+}|
{1: ~}|
{1: ~}|
{1: ~}|
@@ -355,4 +359,26 @@ describe("folded lines", function()
|
]]}
end)
+
+ it('does not crash when foldtext is longer than columns #12988', function()
+ source([[
+ function! MyFoldText() abort
+ return repeat('-', &columns + 100)
+ endfunction
+ ]])
+ command('set foldtext=MyFoldText()')
+ feed("i<cr><esc>")
+ feed("vkzf")
+ screen:expect{grid=[[
+ {5:^---------------------------------------------}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ assert_alive()
+ end)
end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index afb0c9cfa6..712c1f377a 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -14,7 +14,7 @@ local neq = helpers.neq
local ok = helpers.ok
local retry = helpers.retry
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local nvim = helpers.nvim
local sleep = helpers.sleep
local nvim_dir = helpers.nvim_dir
@@ -114,7 +114,7 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by a script", function()
source('%s/tw/MO/g')
- wait()
+ poke_eventloop()
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
expect(default_text:gsub("tw", "MO"))
@@ -123,10 +123,10 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by feedkeys()", function()
-- in a script...
source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
- wait()
+ poke_eventloop()
-- or interactively...
feed([[:call feedkeys(":%s/tw/MO/g\<CR>")<CR>]])
- wait()
+ poke_eventloop()
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
expect(default_text:gsub("tw", "MO"))
@@ -162,7 +162,7 @@ describe(":substitute, 'inccommand' preserves", function()
insert(default_text)
feed_command("set inccommand=" .. case)
- local delims = { '/', '#', ';', '%', ',', '@', '!', ''}
+ local delims = { '/', '#', ';', '%', ',', '@', '!' }
for _,delim in pairs(delims) do
feed_command("%s"..delim.."lines"..delim.."LINES"..delim.."g")
expect([[
@@ -194,7 +194,7 @@ describe(":substitute, 'inccommand' preserves", function()
-- Start typing an incomplete :substitute command.
feed([[:%s/e/YYYY/g]])
- wait()
+ poke_eventloop()
-- Cancel the :substitute.
feed([[<C-\><C-N>]])
@@ -230,7 +230,7 @@ describe(":substitute, 'inccommand' preserves", function()
-- Start typing an incomplete :substitute command.
feed([[:%s/e/YYYY/g]])
- wait()
+ poke_eventloop()
-- Cancel the :substitute.
feed([[<C-\><C-N>]])
@@ -251,7 +251,7 @@ describe(":substitute, 'inccommand' preserves", function()
some text 1
some text 2]])
feed(":%s/e/XXX/")
- wait()
+ poke_eventloop()
eq(expected_tick, eval("b:changedtick"))
end)
@@ -1128,15 +1128,15 @@ describe(":substitute, inccommand=split", function()
feed(":%s/tw/Xo/g")
-- Delete and re-type the g a few times.
feed("<BS>")
- wait()
+ poke_eventloop()
feed("g")
- wait()
+ poke_eventloop()
feed("<BS>")
- wait()
+ poke_eventloop()
feed("g")
- wait()
+ poke_eventloop()
feed("<CR>")
- wait()
+ poke_eventloop()
feed(":vs tmp<enter>")
eq(3, helpers.call('bufnr', '$'))
end)
@@ -1171,7 +1171,7 @@ describe(":substitute, inccommand=split", function()
feed_command("silent edit! test/functional/fixtures/bigfile_oneline.txt")
-- Start :substitute with a slow pattern.
feed([[:%s/B.*N/x]])
- wait()
+ poke_eventloop()
-- Assert that 'inccommand' is DISABLED in cmdline mode.
eq("", eval("&inccommand"))
@@ -1360,7 +1360,7 @@ describe("inccommand=nosplit", function()
feed("<Esc>")
command("set icm=nosplit")
feed(":%s/tw/OKOK")
- wait()
+ poke_eventloop()
screen:expect([[
Inc substitution on |
{12:OKOK}o lines |
@@ -2592,7 +2592,7 @@ describe(":substitute", function()
feed("<C-c>")
feed('gg')
- wait()
+ poke_eventloop()
feed([[:%s/\(some\)\@<lt>!thing/one/]])
screen:expect([[
something |
@@ -2613,7 +2613,7 @@ describe(":substitute", function()
]])
feed([[<C-c>]])
- wait()
+ poke_eventloop()
feed([[:%s/some\(thing\)\@=/every/]])
screen:expect([[
{12:every}thing |
@@ -2634,7 +2634,7 @@ describe(":substitute", function()
]])
feed([[<C-c>]])
- wait()
+ poke_eventloop()
feed([[:%s/some\(thing\)\@!/every/]])
screen:expect([[
something |
@@ -2718,7 +2718,7 @@ it(':substitute with inccommand during :terminal activity', function()
feed('gg')
feed(':%s/foo/ZZZ')
sleep(20) -- Allow some terminal activity.
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect_unchanged()
end)
end)
@@ -2750,6 +2750,26 @@ it(':substitute with inccommand, timer-induced :redraw #9777', function()
]])
end)
+it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
+ local screen = Screen.new(10,5)
+ clear()
+ command('set undolevels=-1')
+ common_setup(screen, 'split', 'test')
+ feed(':%s/test')
+ sleep(100)
+ feed('/')
+ sleep(100)
+ feed('f')
+ screen:expect([[
+ {12:f} |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/test/f^ |
+ ]])
+ assert_alive()
+end)
+
it('long :%s/ with inccommand does not collapse cmdline', function()
local screen = Screen.new(10,5)
clear()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index efc02db159..5df4a1d533 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -323,7 +323,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
]], messages={
- {content = {{"/line [1/2] W"}}, kind = "search_count"}
+ {content = {{"/line W [1/2]"}}, kind = "search_count"}
}}
feed('n')
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index d857b57a31..a741136111 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -546,7 +546,7 @@ describe('ui/mouse/input', function()
:tabprevious |
]])
feed('<LeftMouse><10,0><LeftRelease>') -- go to second tab
- helpers.wait()
+ helpers.poke_eventloop()
feed('<LeftMouse><0,1>')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index e4d1187dea..6601c2d68e 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -4,7 +4,7 @@ local clear = helpers.clear
local feed, command, insert = helpers.feed, helpers.command, helpers.insert
local eq = helpers.eq
local meths = helpers.meths
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('ext_multigrid', function()
@@ -1846,8 +1846,8 @@ describe('ext_multigrid', function()
meths.input_mouse('left', 'press', '', 1,6, 20)
-- TODO(bfredl): "batching" input_mouse is formally not supported yet.
-- Normally it should work fine in async context when nvim is not blocked,
- -- but add a wait be sure.
- wait()
+ -- but add a poke_eventloop be sure.
+ poke_eventloop()
meths.input_mouse('left', 'drag', '', 1, 4, 20)
screen:expect{grid=[[
## grid 1
@@ -1921,7 +1921,7 @@ describe('ext_multigrid', function()
]]}
meths.input_mouse('left', 'press', '', 1,8, 26)
- wait()
+ poke_eventloop()
meths.input_mouse('left', 'drag', '', 1, 6, 30)
screen:expect{grid=[[
## grid 1
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 9646c3fdad..2f113f6ac6 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -14,10 +14,10 @@ describe('UI receives option updates', function()
arabicshape=true,
emoji=true,
guifont='',
- guifontset='',
guifontwide='',
linespace=0,
pumblend=0,
+ mousefocus=false,
showtabline=1,
termguicolors=false,
ttimeout=true,
@@ -110,6 +110,12 @@ describe('UI receives option updates', function()
eq(expected, screen.options)
end)
+ command("set mousefocus")
+ expected.mousefocus = true
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+
command("set nottimeout")
expected.ttimeout = false
screen:expect(function()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index c1c5d1ce2e..3f984ff943 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1213,10 +1213,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -1261,10 +1261,10 @@ describe('builtin popupmenu', function()
feed('<c-p>')
screen:expect([[
some long prefix before the text|
- {n:^word }{1: }|
- {n:choice }{1: }|
- {s:text }{1: }|
- {n:thing }{1: }|
+ {1:^~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{s: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -1341,10 +1341,10 @@ describe('builtin popupmenu', function()
screen:expect([[
some long prefix |
before the text^ |
- {1:~ }{n: word }|
- {1:~ }{n: choice }|
- {1:~ }{s: text }|
- {1:~ }{n: thing }|
+ {1:~ }{n: word }{1: }|
+ {1:~ }{n: choice }{1: }|
+ {1:~ }{s: text }{1: }|
+ {1:~ }{n: thing }{1: }|
{1:~ }|
{2:-- INSERT --} |
]])
@@ -1358,10 +1358,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -2168,8 +2168,8 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{c: }{1: }|
- {n:choice }{s: }{1: }|
+ {1:~ }{n: word }{c: }|
+ {1:~ }{n: choice}{s: }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -2187,10 +2187,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{2:-- INSERT --} |
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 635ce7392b..222275eb4d 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -158,7 +158,7 @@ describe('search highlighting', function()
bar foo baz
]])
feed('/foo')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect_unchanged()
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 9d4cb325d9..01fc50289d 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -6,7 +6,7 @@ local feed_command, source, expect = helpers.feed_command, helpers.source, helpe
local curbufmeths = helpers.curbufmeths
local command = helpers.command
local meths = helpers.meths
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('completion', function()
local screen
@@ -737,8 +737,8 @@ describe('completion', function()
-- Does not indent when "ind" is typed.
feed("in<C-X><C-N>")
-- Completion list is generated incorrectly if we send everything at once
- -- via nvim_input(). So wait() before sending <BS>. #8480
- wait()
+ -- via nvim_input(). So poke_eventloop() before sending <BS>. #8480
+ poke_eventloop()
feed("<BS>d")
screen:expect([[
@@ -778,7 +778,7 @@ describe('completion', function()
]])
-- Works for unindenting too.
feed("ounin<C-X><C-N>")
- helpers.wait()
+ helpers.poke_eventloop()
feed("<BS>d")
screen:expect([[
inc uninc indent unindent |
@@ -1000,65 +1000,65 @@ describe('completion', function()
command('let g:foo = []')
feed('o')
- wait()
+ poke_eventloop()
feed('<esc>')
eq({'I'}, eval('g:foo'))
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
eq({'I', 'I'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
eq({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua
index c5390cbd12..9acc61e398 100644
--- a/test/functional/viml/errorlist_spec.lua
+++ b/test/functional/viml/errorlist_spec.lua
@@ -27,7 +27,7 @@ describe('setqflist()', function()
setqflist({''}, 'r', 'foo')
command('copen')
eq('foo', get_cur_win_var('quickfix_title'))
- setqflist({''}, 'r', {['title'] = 'qf_title'})
+ setqflist({}, 'r', {['title'] = 'qf_title'})
eq('qf_title', get_cur_win_var('quickfix_title'))
end)
diff --git a/test/functional/visual/meta_key_spec.lua b/test/functional/visual/meta_key_spec.lua
new file mode 100644
index 0000000000..11f7203da0
--- /dev/null
+++ b/test/functional/visual/meta_key_spec.lua
@@ -0,0 +1,22 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
+local expect = helpers.expect
+
+describe('meta-keys-in-visual-mode', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('ALT/META', function()
+ -- Unmapped ALT-chords behave as Esc+c
+ insert('peaches')
+ feed('viw<A-x>viw<M-x>')
+ expect('peach')
+ -- Mapped ALT-chord behaves as mapped.
+ command('vnoremap <M-l> Ameta-l<Esc>')
+ command('vnoremap <A-j> Aalt-j<Esc>')
+ feed('viw<A-j>viw<M-l>')
+ expect('peachalt-jmeta-l')
+ end)
+end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 40b93d9935..68f0c92244 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -82,6 +82,17 @@ end
function module.ok(res, msg, logfile)
return dumplog(logfile, assert.is_true, res, msg)
end
+
+-- TODO(bfredl): this should "failure" not "error" (issue with dumplog() )
+local function epicfail(state, arguments, _)
+ state.failure_message = arguments[1]
+ return false
+end
+assert:register("assertion", "epicfail", epicfail)
+function module.fail(msg, logfile)
+ return dumplog(logfile, assert.epicfail, msg)
+end
+
function module.matches(pat, actual)
if nil ~= string.match(actual, pat) then
return true
@@ -105,8 +116,12 @@ function module.assert_log(pat, logfile)
pat, nrlines, logfile, logtail))
end
--- Invokes `fn` and returns the error string (may truncate full paths), or
--- raises an error if `fn` succeeds.
+-- Invokes `fn` and returns the error string (with truncated paths), or raises
+-- an error if `fn` succeeds.
+--
+-- Replaces line/column numbers with zero:
+-- shared.lua:0: in function 'gsplit'
+-- shared.lua:0: in function <shared.lua:0>'
--
-- Usage:
-- -- Match exact string.
@@ -114,29 +129,36 @@ end
-- -- Match Lua pattern.
-- matches('e[or]+$', pcall_err(function(a, b) error('some error') end, 'arg1', 'arg2'))
--
-function module.pcall_err(fn, ...)
+function module.pcall_err_withfile(fn, ...)
assert(type(fn) == 'function')
local status, rv = pcall(fn, ...)
if status == true then
error('expected failure, but got success')
end
- -- From this:
- -- /home/foo/neovim/runtime/lua/vim/shared.lua:186: Expected string, got number
- -- to this:
- -- Expected string, got number
- local errmsg = tostring(rv):gsub('^[^:]+:%d+: ', '')
- -- From this:
- -- Error executing lua: /very/long/foo.lua:186: Expected string, got number
- -- to this:
- -- Error executing lua: .../foo.lua:186: Expected string, got number
- errmsg = errmsg:gsub([[lua: [a-zA-Z]?:?[^:]-[/\]([^:/\]+):%d+: ]], 'lua: .../%1: ')
- -- Compiled modules will not have a path and will just be a name like
- -- shared.lua:186, so strip the number.
- errmsg = errmsg:gsub([[lua: ([^:/\ ]+):%d+: ]], 'lua: .../%1: ')
- -- ^ Windows drive-letter (C:)
+ -- From:
+ -- C:/long/path/foo.lua:186: Expected string, got number
+ -- to:
+ -- .../foo.lua:0: Expected string, got number
+ local errmsg = tostring(rv):gsub('[^%s]-[/\\]([^%s:/\\]+):%d+', '.../%1:0')
+ -- Scrub numbers in paths/stacktraces:
+ -- shared.lua:0: in function 'gsplit'
+ -- shared.lua:0: in function <shared.lua:0>'
+ errmsg = errmsg:gsub('([^%s]):%d+', '%1:0')
+ -- Scrub tab chars:
+ errmsg = errmsg:gsub('\t', ' ')
+ -- In Lua 5.1, we sometimes get a "(tail call): ?" on the last line.
+ -- We remove this so that the tests are not lua dependent.
+ errmsg = errmsg:gsub('%s*%(tail call%): %?', '')
+
return errmsg
end
+function module.pcall_err(fn, ...)
+ local errmsg = module.pcall_err_withfile(fn, ...)
+
+ return errmsg:gsub('.../helpers.lua:0: ', '')
+end
+
-- initial_path: directory to recurse into
-- re: include pattern (string)
-- exc_re: exclude pattern(s) (string or table)
@@ -200,14 +222,25 @@ function module.check_logs()
end
end
fd:close()
- os.remove(file)
if #lines > 0 then
+ local status, f
local out = io.stdout
+ if os.getenv('SYMBOLIZER') then
+ status, f = pcall(module.popen_r, os.getenv('SYMBOLIZER'), '-l', file)
+ end
out:write(start_msg .. '\n')
- out:write('= ' .. table.concat(lines, '\n= ') .. '\n')
+ if status then
+ for line in f:lines() do
+ out:write('= '..line..'\n')
+ end
+ f:close()
+ else
+ out:write('= ' .. table.concat(lines, '\n= ') .. '\n')
+ end
out:write(select(1, start_msg:gsub('.', '=')) .. '\n')
table.insert(runtime_errors, file)
end
+ os.remove(file)
end
end
end
@@ -323,7 +356,7 @@ function module.check_cores(app, force)
exc_re = { os.getenv('NVIM_TEST_CORE_EXC_RE'), local_tmpdir }
db_cmd = os.getenv('NVIM_TEST_CORE_DB_CMD') or gdb_db_cmd
random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP')
- elseif os.getenv('TRAVIS_OS_NAME') == 'osx' then
+ elseif 'darwin' == module.uname() then
initial_path = '/cores'
re = nil
exc_re = { local_tmpdir }
diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c
index 95853a6834..f9bc3fabc4 100644
--- a/test/symbolic/klee/nvim/charset.c
+++ b/test/symbolic/klee/nvim/charset.c
@@ -69,7 +69,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
&& !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1];
- // Detect hexadecimal: 0x or 0X follwed by hex digit
+ // Detect hexadecimal: 0x or 0X followed by hex digit
if ((what & STR2NR_HEX)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x')
@@ -77,7 +77,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr += 2;
goto vim_str2nr_hex;
}
- // Detect binary: 0b or 0B follwed by 0 or 1
+ // Detect binary: 0b or 0B followed by 0 or 1
if ((what & STR2NR_BIN)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b')
diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua
index ad05b134e0..e7cb5e5d5e 100644
--- a/test/unit/os/env_spec.lua
+++ b/test/unit/os/env_spec.lua
@@ -78,15 +78,22 @@ describe('env.c', function()
end)
describe('os_setenv_append_path', function()
- itp('appends /foo/bar to $PATH', function()
+ itp('appends :/foo/bar to $PATH', function()
local original_path = os.getenv('PATH')
- eq(true, cimp.os_setenv_append_path(to_cstr('/foo/bar/baz')))
+ eq(true, cimp.os_setenv_append_path(to_cstr('/foo/bar/baz.exe')))
eq(original_path..':/foo/bar', os.getenv('PATH'))
end)
+ itp('avoids redundant separator when appending to $PATH #7377', function()
+ os_setenv('PATH', '/a/b/c:', true)
+ eq(true, cimp.os_setenv_append_path(to_cstr('/foo/bar/baz.exe')))
+ -- Must not have duplicate separators. #7377
+ eq('/a/b/c:/foo/bar', os.getenv('PATH'))
+ end)
+
itp('returns false if `fname` is not absolute', function()
local original_path = os.getenv('PATH')
- eq(false, cimp.os_setenv_append_path(to_cstr('foo/bar/baz')))
+ eq(false, cimp.os_setenv_append_path(to_cstr('foo/bar/baz.exe')))
eq(original_path, os.getenv('PATH'))
end)
end)
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 477e25a882..493d7aacdd 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -161,8 +161,8 @@ set(UNIBILIUM_SHA256 29815283c654277ef77a3adcc8840db79ddbb20a0f0b0c8f648bd8cd49a
set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.22.tar.gz)
set(LIBTERMKEY_SHA256 6945bd3c4aaa83da83d80a045c5563da4edd7d0374c62c0d35aec09eb3014600)
-set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/65dbda3ed214f036ee799d18b2e693a833a0e591.tar.gz)
-set(LIBVTERM_SHA256 95d3c7e86336fbd40dfd7a0aa0a795320bb71bc957ea995ea0e549c96d20db3a)
+set(LIBVTERM_URL http://www.leonerd.org.uk/code/libvterm/libvterm-0.1.4.tar.gz)
+set(LIBVTERM_SHA256 bc70349e95559c667672fc8c55b9527d9db9ada0fb80a3beda533418d782d3dd)
set(LUV_VERSION 1.30.1-1)
set(LUV_URL https://github.com/luvit/luv/archive/${LUV_VERSION}.tar.gz)
diff --git a/unicode/CaseFolding.txt b/unicode/CaseFolding.txt
index 7eeb915abf..033788b253 100644
--- a/unicode/CaseFolding.txt
+++ b/unicode/CaseFolding.txt
@@ -1,5 +1,5 @@
-# CaseFolding-12.1.0.txt
-# Date: 2019-03-10, 10:53:00 GMT
+# CaseFolding-13.0.0.txt
+# Date: 2019-09-08, 23:30:59 GMT
# ยฉ 2019 Unicodeยฎ, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
@@ -1234,6 +1234,9 @@ A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W
A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK
A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK
A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK
+A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY
+A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY
+A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H
AB70; C; 13A0; # CHEROKEE SMALL LETTER A
AB71; C; 13A1; # CHEROKEE SMALL LETTER E
AB72; C; 13A2; # CHEROKEE SMALL LETTER I
diff --git a/unicode/EastAsianWidth.txt b/unicode/EastAsianWidth.txt
index 94d55d6654..b43aec9273 100644
--- a/unicode/EastAsianWidth.txt
+++ b/unicode/EastAsianWidth.txt
@@ -1,6 +1,6 @@
-# EastAsianWidth-12.1.0.txt
-# Date: 2019-03-31, 22:01:58 GMT [KW, LI]
-# ยฉ 2019 Unicodeยฎ, Inc.
+# EastAsianWidth-13.0.0.txt
+# Date: 2029-01-21, 18:14:00 GMT [KW, LI]
+# ยฉ 2020 Unicodeยฎ, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -9,7 +9,7 @@
#
# East_Asian_Width Property
#
-# This file is an informative contributory data file in the
+# This file is a normative contributory data file in the
# Unicode Character Database.
#
# The format is two fields separated by a semicolon.
@@ -332,7 +332,7 @@
085E;N # Po MANDAIC PUNCTUATION
0860..086A;N # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
08A0..08B4;N # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
-08B6..08BD;N # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+08B6..08C7;N # Lo [18] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE
08D3..08E1;N # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA
08E2;N # Cf ARABIC DISPUTED END OF AYAH
08E3..08FF;N # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA
@@ -450,7 +450,7 @@
0B47..0B48;N # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
0B4B..0B4C;N # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
0B4D;N # Mn ORIYA SIGN VIRAMA
-0B56;N # Mn ORIYA AI LENGTH MARK
+0B55..0B56;N # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
0B57;N # Mc ORIYA AU LENGTH MARK
0B5C..0B5D;N # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
0B5F..0B61;N # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
@@ -529,7 +529,7 @@
0CF1..0CF2;N # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
0D00..0D01;N # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
0D02..0D03;N # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
-0D05..0D0C;N # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D04..0D0C;N # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
0D0E..0D10;N # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
0D12..0D3A;N # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
0D3B..0D3C;N # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
@@ -550,6 +550,7 @@
0D70..0D78;N # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS
0D79;N # So MALAYALAM DATE MARK
0D7A..0D7F;N # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D81;N # Mn SINHALA SIGN CANDRABINDU
0D82..0D83;N # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
0D85..0D96;N # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
0D9A..0DB1;N # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
@@ -795,6 +796,7 @@
1AA8..1AAD;N # Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG
1AB0..1ABD;N # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
1ABE;N # Me COMBINING PARENTHESES OVERLAY
+1ABF..1AC0;N # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW
1B00..1B03;N # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
1B04;N # Mc BALINESE SIGN BISAH
1B05..1B33;N # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
@@ -1335,7 +1337,7 @@
2B56..2B59;A # So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE
2B5A..2B73;N # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
2B76..2B95;N # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
-2B98..2BFF;N # So [104] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..HELLSCHREIBER PAUSE SYMBOL
+2B97..2BFF;N # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL
2C00..2C2E;N # Lu [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
2C30..2C5E;N # Ll [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
2C60..2C7B;N # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
@@ -1404,6 +1406,8 @@
2E41;N # Po REVERSED COMMA
2E42;N # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
2E43..2E4F;N # Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER
+2E50..2E51;N # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR
+2E52;N # Po TIRONIAN SIGN CAPITAL ET
2E80..2E99;W # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
2E9B..2EF3;W # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
2F00..2FD5;W # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
@@ -1464,7 +1468,7 @@
3190..3191;W # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
3192..3195;W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
3196..319F;W # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
-31A0..31BA;W # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31A0..31BF;W # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH
31C0..31E3;W # So [36] CJK STROKE T..CJK STROKE Q
31F0..31FF;W # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
3200..321E;W # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
@@ -1479,11 +1483,10 @@
32B1..32BF;W # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
32C0..32FF;W # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA
3300..33FF;W # So [256] SQUARE APAATO..SQUARE GAL
-3400..4DB5;W # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
-4DB6..4DBF;W # Cn [10] <reserved-4DB6>..<reserved-4DBF>
+3400..4DBF;W # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF
4DC0..4DFF;N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
-4E00..9FEF;W # Lo [20976] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEF
-9FF0..9FFF;W # Cn [16] <reserved-9FF0>..<reserved-9FFF>
+4E00..9FFC;W # Lo [20989] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFC
+9FFD..9FFF;W # Cn [3] <reserved-9FFD>..<reserved-9FFF>
A000..A014;W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
A015;W # Lm YI SYLLABLE WU
A016..A48C;W # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
@@ -1523,7 +1526,8 @@ A789..A78A;N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUAL
A78B..A78E;N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
A78F;N # Lo LATIN LETTER SINOLOGICAL DOT
A790..A7BF;N # L& [48] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER GLOTTAL U
-A7C2..A7C6;N # L& [5] LATIN CAPITAL LETTER ANGLICANA W..LATIN CAPITAL LETTER Z WITH PALATAL HOOK
+A7C2..A7CA;N # L& [9] LATIN CAPITAL LETTER ANGLICANA W..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY
+A7F5..A7F6;N # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
A7F7;N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
A7F8..A7F9;N # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
A7FA;N # Ll LATIN LETTER SMALL CAPITAL TURNED M
@@ -1539,6 +1543,7 @@ A823..A824;N # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN
A825..A826;N # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
A827;N # Mc SYLOTI NAGRI VOWEL SIGN OO
A828..A82B;N # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+A82C;N # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
A830..A835;N # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS
A836..A837;N # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
A838;N # Sc NORTH INDIC RUPEE MARK
@@ -1639,7 +1644,9 @@ AB28..AB2E;N # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
AB30..AB5A;N # Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
AB5B;N # Sk MODIFIER BREVE WITH INVERTED BREVE
AB5C..AB5F;N # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
-AB60..AB67;N # Ll [8] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK
+AB60..AB68;N # Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE
+AB69;N # Lm MODIFIER LETTER SMALL TURNED W
+AB6A..AB6B;N # Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK
AB70..ABBF;N # Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
ABC0..ABE2;N # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
ABE3..ABE4;N # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
@@ -1800,7 +1807,7 @@ FFFD;A # So REPLACEMENT CHARACTER
10179..10189;N # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
1018A..1018B;N # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
1018C..1018E;N # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN
-10190..1019B;N # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
+10190..1019C;N # So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL
101A0;N # So GREEK SYMBOL TAU RHO
101D0..101FC;N # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
101FD;N # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
@@ -1902,6 +1909,10 @@ FFFD;A # So REPLACEMENT CHARACTER
10D24..10D27;N # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
10D30..10D39;N # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
10E60..10E7E;N # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
+10E80..10EA9;N # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+10EAB..10EAC;N # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+10EAD;N # Pd YEZIDI HYPHENATION MARK
+10EB0..10EB1;N # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
10F00..10F1C;N # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
10F1D..10F26;N # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF
10F27;N # Lo OLD SOGDIAN LIGATURE AYIN-DALETH
@@ -1909,6 +1920,8 @@ FFFD;A # So REPLACEMENT CHARACTER
10F46..10F50;N # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
10F51..10F54;N # No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED
10F55..10F59;N # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
+10FB0..10FC4;N # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW
+10FC5..10FCB;N # No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED
10FE0..10FF6;N # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH
11000;N # Mc BRAHMI SIGN CANDRABINDU
11001;N # Mn BRAHMI SIGN ANUSVARA
@@ -1941,6 +1954,7 @@ FFFD;A # So REPLACEMENT CHARACTER
11140..11143;N # Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK
11144;N # Lo CHAKMA LETTER LHAA
11145..11146;N # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+11147;N # Lo CHAKMA LETTER VAA
11150..11172;N # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
11173;N # Mn MAHAJANI SIGN NUKTA
11174..11175;N # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK
@@ -1955,6 +1969,8 @@ FFFD;A # So REPLACEMENT CHARACTER
111C5..111C8;N # Po [4] SHARADA DANDA..SHARADA SEPARATOR
111C9..111CC;N # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
111CD;N # Po SHARADA SUTRA MARK
+111CE;N # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+111CF;N # Mn SHARADA SIGN INVERTED CANDRABINDU
111D0..111D9;N # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
111DA;N # Lo SHARADA EKAM
111DB;N # Po SHARADA SIGN SIDDHAM
@@ -2013,10 +2029,10 @@ FFFD;A # So REPLACEMENT CHARACTER
11447..1144A;N # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
1144B..1144F;N # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN
11450..11459;N # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
-1145B;N # Po NEWA PLACEHOLDER MARK
+1145A..1145B;N # Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK
1145D;N # Po NEWA INSERTION SIGN
1145E;N # Mn NEWA SANDHI MARK
-1145F;N # Lo NEWA LETTER VEDIC ANUSVARA
+1145F..11461;N # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA
11480..114AF;N # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
114B0..114B2;N # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
114B3..114B8;N # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
@@ -2081,6 +2097,23 @@ FFFD;A # So REPLACEMENT CHARACTER
118E0..118E9;N # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
118EA..118F2;N # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
118FF;N # Lo WARANG CITI OM
+11900..11906;N # Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E
+11909;N # Lo DIVES AKURU LETTER O
+1190C..11913;N # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA
+11915..11916;N # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA
+11918..1192F;N # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA
+11930..11935;N # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E
+11937..11938;N # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+1193B..1193C;N # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+1193D;N # Mc DIVES AKURU SIGN HALANTA
+1193E;N # Mn DIVES AKURU VIRAMA
+1193F;N # Lo DIVES AKURU PREFIXED NASAL SIGN
+11940;N # Mc DIVES AKURU MEDIAL YA
+11941;N # Lo DIVES AKURU INITIAL RA
+11942;N # Mc DIVES AKURU MEDIAL RA
+11943;N # Mn DIVES AKURU SIGN NUKTA
+11944..11946;N # Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK
+11950..11959;N # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE
119A0..119A7;N # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR
119AA..119D0;N # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA
119D1..119D3;N # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
@@ -2158,6 +2191,7 @@ FFFD;A # So REPLACEMENT CHARACTER
11EF3..11EF4;N # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
11EF5..11EF6;N # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
11EF7..11EF8;N # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
+11FB0;N # Lo LISU LETTER YHA
11FC0..11FD4;N # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH
11FD5..11FDC;N # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI
11FDD..11FE0;N # Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN
@@ -2200,8 +2234,12 @@ FFFD;A # So REPLACEMENT CHARACTER
16FE0..16FE1;W # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
16FE2;W # Po OLD CHINESE HOOK MARK
16FE3;W # Lm OLD CHINESE ITERATION MARK
+16FE4;W # Mn KHITAN SMALL SCRIPT FILLER
+16FF0..16FF1;W # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
17000..187F7;W # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7
-18800..18AF2;W # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+18800..18AFF;W # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768
+18B00..18CD5;W # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5
+18D00..18D08;W # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08
1B000..1B0FF;W # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2
1B100..1B11E;W # Lo [31] HENTAIGANA LETTER RE-3..HENTAIGANA LETTER N-MU-MO-2
1B150..1B152;W # Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO
@@ -2364,15 +2402,17 @@ FFFD;A # So REPLACEMENT CHARACTER
1F0D1..1F0F5;N # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
1F100..1F10A;A # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA
1F10B..1F10C;N # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
+1F10D..1F10F;N # So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
1F110..1F12D;A # So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD
1F12E..1F12F;N # So [2] CIRCLED WZ..COPYLEFT SYMBOL
1F130..1F169;A # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
-1F16A..1F16C;N # So [3] RAISED MC SIGN..RAISED MR SIGN
+1F16A..1F16F;N # So [6] RAISED MC SIGN..CIRCLED HUMAN FIGURE
1F170..1F18D;A # So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA
1F18E;W # So NEGATIVE SQUARED AB
1F18F..1F190;A # So [2] NEGATIVE SQUARED WC..SQUARE DJ
1F191..1F19A;W # So [10] SQUARED CL..SQUARED VS
1F19B..1F1AC;A # So [18] SQUARED THREE D..SQUARED VOD
+1F1AD;N # So MASK WORK SYMBOL
1F1E6..1F1FF;N # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
1F200..1F202;W # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA
1F210..1F23B;W # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D
@@ -2424,11 +2464,11 @@ FFFD;A # So REPLACEMENT CHARACTER
1F6CD..1F6CF;N # So [3] SHOPPING BAGS..BED
1F6D0..1F6D2;W # So [3] PLACE OF WORSHIP..SHOPPING TROLLEY
1F6D3..1F6D4;N # So [2] STUPA..PAGODA
-1F6D5;W # So HINDU TEMPLE
+1F6D5..1F6D7;W # So [3] HINDU TEMPLE..ELEVATOR
1F6E0..1F6EA;N # So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE
1F6EB..1F6EC;W # So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING
1F6F0..1F6F3;N # So [4] SATELLITE..PASSENGER SHIP
-1F6F4..1F6FA;W # So [7] SCOOTER..AUTO RICKSHAW
+1F6F4..1F6FC;W # So [9] SCOOTER..ROLLER SKATE
1F700..1F773;N # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE
1F780..1F7D8;N # So [89] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NEGATIVE CIRCLED SQUARE
1F7E0..1F7EB;W # So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE
@@ -2437,21 +2477,29 @@ FFFD;A # So REPLACEMENT CHARACTER
1F850..1F859;N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
1F860..1F887;N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
1F890..1F8AD;N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
+1F8B0..1F8B1;N # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST
1F900..1F90B;N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT
-1F90D..1F971;W # So [101] WHITE HEART..YAWNING FACE
-1F973..1F976;W # So [4] FACE WITH PARTY HORN AND PARTY HAT..FREEZING FACE
-1F97A..1F9A2;W # So [41] FACE WITH PLEADING EYES..SWAN
-1F9A5..1F9AA;W # So [6] SLOTH..OYSTER
-1F9AE..1F9CA;W # So [29] GUIDE DOG..ICE CUBE
+1F90C..1F93A;W # So [47] PINCHED FINGERS..FENCER
+1F93B;N # So MODERN PENTATHLON
+1F93C..1F945;W # So [10] WRESTLERS..GOAL NET
+1F946;N # So RIFLE
+1F947..1F978;W # So [50] FIRST PLACE MEDAL..DISGUISED FACE
+1F97A..1F9CB;W # So [82] FACE WITH PLEADING EYES..BUBBLE TEA
1F9CD..1F9FF;W # So [51] STANDING PERSON..NAZAR AMULET
1FA00..1FA53;N # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
1FA60..1FA6D;N # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
-1FA70..1FA73;W # So [4] BALLET SHOES..SHORTS
+1FA70..1FA74;W # So [5] BALLET SHOES..THONG SANDAL
1FA78..1FA7A;W # So [3] DROP OF BLOOD..STETHOSCOPE
-1FA80..1FA82;W # So [3] YO-YO..PARACHUTE
-1FA90..1FA95;W # So [6] RINGED PLANET..BANJO
-20000..2A6D6;W # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
-2A6D7..2A6FF;W # Cn [41] <reserved-2A6D7>..<reserved-2A6FF>
+1FA80..1FA86;W # So [7] YO-YO..NESTING DOLLS
+1FA90..1FAA8;W # So [25] RINGED PLANET..ROCK
+1FAB0..1FAB6;W # So [7] FLY..FEATHER
+1FAC0..1FAC2;W # So [3] ANATOMICAL HEART..PEOPLE HUGGING
+1FAD0..1FAD6;W # So [7] BLUEBERRIES..TEAPOT
+1FB00..1FB92;N # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK
+1FB94..1FBCA;N # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON
+1FBF0..1FBF9;N # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
+20000..2A6DD;W # Lo [42718] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DD
+2A6DE..2A6FF;W # Cn [34] <reserved-2A6DE>..<reserved-2A6FF>
2A700..2B734;W # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
2B735..2B73F;W # Cn [11] <reserved-2B735>..<reserved-2B73F>
2B740..2B81D;W # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
@@ -2463,7 +2511,8 @@ FFFD;A # So REPLACEMENT CHARACTER
2F800..2FA1D;W # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
2FA1E..2FA1F;W # Cn [2] <reserved-2FA1E>..<reserved-2FA1F>
2FA20..2FFFD;W # Cn [1502] <reserved-2FA20>..<reserved-2FFFD>
-30000..3FFFD;W # Cn [65534] <reserved-30000>..<reserved-3FFFD>
+30000..3134A;W # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A
+3134B..3FFFD;W # Cn [60595] <reserved-3134B>..<reserved-3FFFD>
E0001;N # Cf LANGUAGE TAG
E0020..E007F;N # Cf [96] TAG SPACE..CANCEL TAG
E0100..E01EF;A # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
diff --git a/unicode/UnicodeData.txt b/unicode/UnicodeData.txt
index e65aec52f7..e22f967bba 100644
--- a/unicode/UnicodeData.txt
+++ b/unicode/UnicodeData.txt
@@ -2118,6 +2118,16 @@
08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;;
08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;;
08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;;
+08BE;ARABIC LETTER PEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+08BF;ARABIC LETTER TEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+08C0;ARABIC LETTER TTEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+08C1;ARABIC LETTER TCHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+08C2;ARABIC LETTER KEHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+08C3;ARABIC LETTER GHAIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08C4;ARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08C5;ARABIC LETTER JEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08C6;ARABIC LETTER JEEM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+08C7;ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;;
08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;;
08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;;
08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;;
@@ -2621,6 +2631,7 @@
0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;
0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;
0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0B55;ORIYA SIGN OVERLINE;Mn;0;NSM;;;;;N;;;;;
0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;
@@ -2911,6 +2922,7 @@
0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0D04;MALAYALAM LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;
0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;
0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;
0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;
@@ -3024,6 +3036,7 @@
0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;;
0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;;
0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;;
+0D81;SINHALA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;
0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;
0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;
@@ -6044,6 +6057,8 @@
1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;;
1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;;
1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;;
+1ABF;COMBINING LATIN SMALL LETTER W BELOW;Mn;220;NSM;;;;;N;;;;;
+1AC0;COMBINING LATIN SMALL LETTER TURNED W BELOW;Mn;220;NSM;;;;;N;;;;;
1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;;
1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;;
1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;;
@@ -10133,6 +10148,7 @@
2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;;
2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;;
2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;;
2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
@@ -10776,6 +10792,9 @@
2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;;
2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;;
2E4F;CORNISH VERSE DIVIDER;Po;0;ON;;;;;N;;;;;
+2E50;CROSS PATTY WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;;
+2E51;CROSS PATTY WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;;
+2E52;TIRONIAN SIGN CAPITAL ET;Po;0;ON;;;;;N;;;;;
2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
@@ -11550,6 +11569,11 @@
31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;;
31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;;
31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;;
+31BB;BOPOMOFO FINAL LETTER G;Lo;0;L;;;;;N;;;;;
+31BC;BOPOMOFO LETTER GW;Lo;0;L;;;;;N;;;;;
+31BD;BOPOMOFO LETTER KW;Lo;0;L;;;;;N;;;;;
+31BE;BOPOMOFO LETTER OE;Lo;0;L;;;;;N;;;;;
+31BF;BOPOMOFO LETTER AH;Lo;0;L;;;;;N;;;;;
31C0;CJK STROKE T;So;0;ON;;;;;N;;;;;
31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;;
31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;;
@@ -12114,7 +12138,7 @@
33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;
33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;;
3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
-4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+4DBF;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;;
4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;;
4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;;
@@ -12180,7 +12204,7 @@
4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
-9FEF;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+9FFC;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
@@ -14130,6 +14154,12 @@ A7C3;LATIN SMALL LETTER ANGLICANA W;Ll;0;L;;;;;N;;;A7C2;;A7C2
A7C4;LATIN CAPITAL LETTER C WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;A794;
A7C5;LATIN CAPITAL LETTER S WITH HOOK;Lu;0;L;;;;;N;;;;0282;
A7C6;LATIN CAPITAL LETTER Z WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;1D8E;
+A7C7;LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7C8;
+A7C8;LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C7;;A7C7
+A7C9;LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7CA;
+A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9
+A7F5;LATIN CAPITAL LETTER REVERSED HALF H;Lu;0;L;;;;;N;;;;A7F6;
+A7F6;LATIN SMALL LETTER REVERSED HALF H;Ll;0;L;;;;;N;;;A7F5;;A7F5
A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;;
A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;;
A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;;
@@ -14183,6 +14213,7 @@ A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;;
A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;;
A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;;
A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;;
+A82C;SYLOTI NAGRI SIGN ALTERNATE HASANTA;Mn;9;NSM;;;;;N;;;;;
A830;NORTH INDIC FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;
A831;NORTH INDIC FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;
A832;NORTH INDIC FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;
@@ -14897,6 +14928,10 @@ AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;;
AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;;
AB66;LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
AB67;LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+AB68;LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+AB69;MODIFIER LETTER SMALL TURNED W;Lm;0;L;<super> 028D;;;;N;;;;;
+AB6A;MODIFIER LETTER LEFT TACK;Sk;0;ON;;;;;N;;;;;
+AB6B;MODIFIER LETTER RIGHT TACK;Sk;0;ON;;;;;N;;;;;
AB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0
AB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1
AB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2
@@ -17086,6 +17121,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;;
1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;;
1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;;
+1019C;ASCIA SYMBOL;So;0;ON;;;;;N;;;;;
101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;;
101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;;
101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;;
@@ -19057,6 +19093,53 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;;
10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;;
10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;;
+10E80;YEZIDI LETTER ELIF;Lo;0;R;;;;;N;;;;;
+10E81;YEZIDI LETTER BE;Lo;0;R;;;;;N;;;;;
+10E82;YEZIDI LETTER PE;Lo;0;R;;;;;N;;;;;
+10E83;YEZIDI LETTER PHE;Lo;0;R;;;;;N;;;;;
+10E84;YEZIDI LETTER THE;Lo;0;R;;;;;N;;;;;
+10E85;YEZIDI LETTER SE;Lo;0;R;;;;;N;;;;;
+10E86;YEZIDI LETTER CIM;Lo;0;R;;;;;N;;;;;
+10E87;YEZIDI LETTER CHIM;Lo;0;R;;;;;N;;;;;
+10E88;YEZIDI LETTER CHHIM;Lo;0;R;;;;;N;;;;;
+10E89;YEZIDI LETTER HHA;Lo;0;R;;;;;N;;;;;
+10E8A;YEZIDI LETTER XA;Lo;0;R;;;;;N;;;;;
+10E8B;YEZIDI LETTER DAL;Lo;0;R;;;;;N;;;;;
+10E8C;YEZIDI LETTER ZAL;Lo;0;R;;;;;N;;;;;
+10E8D;YEZIDI LETTER RA;Lo;0;R;;;;;N;;;;;
+10E8E;YEZIDI LETTER RHA;Lo;0;R;;;;;N;;;;;
+10E8F;YEZIDI LETTER ZA;Lo;0;R;;;;;N;;;;;
+10E90;YEZIDI LETTER JA;Lo;0;R;;;;;N;;;;;
+10E91;YEZIDI LETTER SIN;Lo;0;R;;;;;N;;;;;
+10E92;YEZIDI LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10E93;YEZIDI LETTER SAD;Lo;0;R;;;;;N;;;;;
+10E94;YEZIDI LETTER DAD;Lo;0;R;;;;;N;;;;;
+10E95;YEZIDI LETTER TA;Lo;0;R;;;;;N;;;;;
+10E96;YEZIDI LETTER ZE;Lo;0;R;;;;;N;;;;;
+10E97;YEZIDI LETTER EYN;Lo;0;R;;;;;N;;;;;
+10E98;YEZIDI LETTER XHEYN;Lo;0;R;;;;;N;;;;;
+10E99;YEZIDI LETTER FA;Lo;0;R;;;;;N;;;;;
+10E9A;YEZIDI LETTER VA;Lo;0;R;;;;;N;;;;;
+10E9B;YEZIDI LETTER VA ALTERNATE FORM;Lo;0;R;;;;;N;;;;;
+10E9C;YEZIDI LETTER QAF;Lo;0;R;;;;;N;;;;;
+10E9D;YEZIDI LETTER KAF;Lo;0;R;;;;;N;;;;;
+10E9E;YEZIDI LETTER KHAF;Lo;0;R;;;;;N;;;;;
+10E9F;YEZIDI LETTER GAF;Lo;0;R;;;;;N;;;;;
+10EA0;YEZIDI LETTER LAM;Lo;0;R;;;;;N;;;;;
+10EA1;YEZIDI LETTER MIM;Lo;0;R;;;;;N;;;;;
+10EA2;YEZIDI LETTER NUN;Lo;0;R;;;;;N;;;;;
+10EA3;YEZIDI LETTER UM;Lo;0;R;;;;;N;;;;;
+10EA4;YEZIDI LETTER WAW;Lo;0;R;;;;;N;;;;;
+10EA5;YEZIDI LETTER OW;Lo;0;R;;;;;N;;;;;
+10EA6;YEZIDI LETTER EW;Lo;0;R;;;;;N;;;;;
+10EA7;YEZIDI LETTER HAY;Lo;0;R;;;;;N;;;;;
+10EA8;YEZIDI LETTER YOT;Lo;0;R;;;;;N;;;;;
+10EA9;YEZIDI LETTER ET;Lo;0;R;;;;;N;;;;;
+10EAB;YEZIDI COMBINING HAMZA MARK;Mn;230;NSM;;;;;N;;;;;
+10EAC;YEZIDI COMBINING MADDA MARK;Mn;230;NSM;;;;;N;;;;;
+10EAD;YEZIDI HYPHENATION MARK;Pd;0;R;;;;;N;;;;;
+10EB0;YEZIDI LETTER LAM WITH DOT ABOVE;Lo;0;R;;;;;N;;;;;
+10EB1;YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE;Lo;0;R;;;;;N;;;;;
10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;
10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
@@ -19139,6 +19222,34 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;;
10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
+10FB0;CHORASMIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10FB1;CHORASMIAN LETTER SMALL ALEPH;Lo;0;R;;;;;N;;;;;
+10FB2;CHORASMIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10FB3;CHORASMIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10FB4;CHORASMIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10FB5;CHORASMIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10FB6;CHORASMIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10FB7;CHORASMIAN LETTER CURLED WAW;Lo;0;R;;;;;N;;;;;
+10FB8;CHORASMIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10FB9;CHORASMIAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10FBA;CHORASMIAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10FBB;CHORASMIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10FBC;CHORASMIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10FBD;CHORASMIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10FBE;CHORASMIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10FBF;CHORASMIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10FC0;CHORASMIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10FC1;CHORASMIAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10FC2;CHORASMIAN LETTER RESH;Lo;0;R;;;;;N;;;;;
+10FC3;CHORASMIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10FC4;CHORASMIAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10FC5;CHORASMIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10FC6;CHORASMIAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+10FC7;CHORASMIAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+10FC8;CHORASMIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10FC9;CHORASMIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10FCA;CHORASMIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10FCB;CHORASMIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
10FE0;ELYMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;;
10FE1;ELYMAIC LETTER BETH;Lo;0;R;;;;;N;;;;;
10FE2;ELYMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;;
@@ -19443,6 +19554,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;;
11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;
+11147;CHAKMA LETTER VAA;Lo;0;L;;;;;N;;;;;
11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;;
11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;;
11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;;
@@ -19560,6 +19672,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;;
111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;;
111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;;
+111CE;SHARADA VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;;
+111CF;SHARADA SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
@@ -19941,10 +20055,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1145A;NEWA DOUBLE COMMA;Po;0;L;;;;;N;;;;;
1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;;
1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;;
1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;;
1145F;NEWA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;
+11460;NEWA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
+11461;NEWA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;;
11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;;
11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;;
@@ -20480,6 +20597,78 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;;
118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;;
+11900;DIVES AKURU LETTER A;Lo;0;L;;;;;N;;;;;
+11901;DIVES AKURU LETTER AA;Lo;0;L;;;;;N;;;;;
+11902;DIVES AKURU LETTER I;Lo;0;L;;;;;N;;;;;
+11903;DIVES AKURU LETTER II;Lo;0;L;;;;;N;;;;;
+11904;DIVES AKURU LETTER U;Lo;0;L;;;;;N;;;;;
+11905;DIVES AKURU LETTER UU;Lo;0;L;;;;;N;;;;;
+11906;DIVES AKURU LETTER E;Lo;0;L;;;;;N;;;;;
+11909;DIVES AKURU LETTER O;Lo;0;L;;;;;N;;;;;
+1190C;DIVES AKURU LETTER KA;Lo;0;L;;;;;N;;;;;
+1190D;DIVES AKURU LETTER KHA;Lo;0;L;;;;;N;;;;;
+1190E;DIVES AKURU LETTER GA;Lo;0;L;;;;;N;;;;;
+1190F;DIVES AKURU LETTER GHA;Lo;0;L;;;;;N;;;;;
+11910;DIVES AKURU LETTER NGA;Lo;0;L;;;;;N;;;;;
+11911;DIVES AKURU LETTER CA;Lo;0;L;;;;;N;;;;;
+11912;DIVES AKURU LETTER CHA;Lo;0;L;;;;;N;;;;;
+11913;DIVES AKURU LETTER JA;Lo;0;L;;;;;N;;;;;
+11915;DIVES AKURU LETTER NYA;Lo;0;L;;;;;N;;;;;
+11916;DIVES AKURU LETTER TTA;Lo;0;L;;;;;N;;;;;
+11918;DIVES AKURU LETTER DDA;Lo;0;L;;;;;N;;;;;
+11919;DIVES AKURU LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1191A;DIVES AKURU LETTER NNA;Lo;0;L;;;;;N;;;;;
+1191B;DIVES AKURU LETTER TA;Lo;0;L;;;;;N;;;;;
+1191C;DIVES AKURU LETTER THA;Lo;0;L;;;;;N;;;;;
+1191D;DIVES AKURU LETTER DA;Lo;0;L;;;;;N;;;;;
+1191E;DIVES AKURU LETTER DHA;Lo;0;L;;;;;N;;;;;
+1191F;DIVES AKURU LETTER NA;Lo;0;L;;;;;N;;;;;
+11920;DIVES AKURU LETTER PA;Lo;0;L;;;;;N;;;;;
+11921;DIVES AKURU LETTER PHA;Lo;0;L;;;;;N;;;;;
+11922;DIVES AKURU LETTER BA;Lo;0;L;;;;;N;;;;;
+11923;DIVES AKURU LETTER BHA;Lo;0;L;;;;;N;;;;;
+11924;DIVES AKURU LETTER MA;Lo;0;L;;;;;N;;;;;
+11925;DIVES AKURU LETTER YA;Lo;0;L;;;;;N;;;;;
+11926;DIVES AKURU LETTER YYA;Lo;0;L;;;;;N;;;;;
+11927;DIVES AKURU LETTER RA;Lo;0;L;;;;;N;;;;;
+11928;DIVES AKURU LETTER LA;Lo;0;L;;;;;N;;;;;
+11929;DIVES AKURU LETTER VA;Lo;0;L;;;;;N;;;;;
+1192A;DIVES AKURU LETTER SHA;Lo;0;L;;;;;N;;;;;
+1192B;DIVES AKURU LETTER SSA;Lo;0;L;;;;;N;;;;;
+1192C;DIVES AKURU LETTER SA;Lo;0;L;;;;;N;;;;;
+1192D;DIVES AKURU LETTER HA;Lo;0;L;;;;;N;;;;;
+1192E;DIVES AKURU LETTER LLA;Lo;0;L;;;;;N;;;;;
+1192F;DIVES AKURU LETTER ZA;Lo;0;L;;;;;N;;;;;
+11930;DIVES AKURU VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11931;DIVES AKURU VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11932;DIVES AKURU VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+11933;DIVES AKURU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+11934;DIVES AKURU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+11935;DIVES AKURU VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+11937;DIVES AKURU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+11938;DIVES AKURU VOWEL SIGN O;Mc;0;L;11935 11930;;;;N;;;;;
+1193B;DIVES AKURU SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1193C;DIVES AKURU SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+1193D;DIVES AKURU SIGN HALANTA;Mc;9;L;;;;;N;;;;;
+1193E;DIVES AKURU VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1193F;DIVES AKURU PREFIXED NASAL SIGN;Lo;0;L;;;;;N;;;;;
+11940;DIVES AKURU MEDIAL YA;Mc;0;L;;;;;N;;;;;
+11941;DIVES AKURU INITIAL RA;Lo;0;L;;;;;N;;;;;
+11942;DIVES AKURU MEDIAL RA;Mc;0;L;;;;;N;;;;;
+11943;DIVES AKURU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+11944;DIVES AKURU DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+11945;DIVES AKURU GAP FILLER;Po;0;L;;;;;N;;;;;
+11946;DIVES AKURU END OF TEXT MARK;Po;0;L;;;;;N;;;;;
+11950;DIVES AKURU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11951;DIVES AKURU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11952;DIVES AKURU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11953;DIVES AKURU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11954;DIVES AKURU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11955;DIVES AKURU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11956;DIVES AKURU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11957;DIVES AKURU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11958;DIVES AKURU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11959;DIVES AKURU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
119A0;NANDINAGARI LETTER A;Lo;0;L;;;;;N;;;;;
119A1;NANDINAGARI LETTER AA;Lo;0;L;;;;;N;;;;;
119A2;NANDINAGARI LETTER I;Lo;0;L;;;;;N;;;;;
@@ -21085,6 +21274,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;;
11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;;
+11FB0;LISU LETTER YHA;Lo;0;L;;;;;N;;;;;
11FC0;TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH;No;0;L;;;;1/320;N;;;;;
11FC1;TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;;
11FC2;TAMIL FRACTION ONE EIGHTIETH;No;0;L;;;;1/80;N;;;;;
@@ -25052,6 +25242,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;;
16FE2;OLD CHINESE HOOK MARK;Po;0;ON;;;;;N;;;;;
16FE3;OLD CHINESE ITERATION MARK;Lm;0;L;;;;;N;;;;;
+16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;;
+16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;;
+16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;;
17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;;
187F7;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;
@@ -25809,6 +26002,491 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;;
18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;;
18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;;
+18AF3;TANGUT COMPONENT-756;Lo;0;L;;;;;N;;;;;
+18AF4;TANGUT COMPONENT-757;Lo;0;L;;;;;N;;;;;
+18AF5;TANGUT COMPONENT-758;Lo;0;L;;;;;N;;;;;
+18AF6;TANGUT COMPONENT-759;Lo;0;L;;;;;N;;;;;
+18AF7;TANGUT COMPONENT-760;Lo;0;L;;;;;N;;;;;
+18AF8;TANGUT COMPONENT-761;Lo;0;L;;;;;N;;;;;
+18AF9;TANGUT COMPONENT-762;Lo;0;L;;;;;N;;;;;
+18AFA;TANGUT COMPONENT-763;Lo;0;L;;;;;N;;;;;
+18AFB;TANGUT COMPONENT-764;Lo;0;L;;;;;N;;;;;
+18AFC;TANGUT COMPONENT-765;Lo;0;L;;;;;N;;;;;
+18AFD;TANGUT COMPONENT-766;Lo;0;L;;;;;N;;;;;
+18AFE;TANGUT COMPONENT-767;Lo;0;L;;;;;N;;;;;
+18AFF;TANGUT COMPONENT-768;Lo;0;L;;;;;N;;;;;
+18B00;KHITAN SMALL SCRIPT CHARACTER-18B00;Lo;0;L;;;;;N;;;;;
+18B01;KHITAN SMALL SCRIPT CHARACTER-18B01;Lo;0;L;;;;;N;;;;;
+18B02;KHITAN SMALL SCRIPT CHARACTER-18B02;Lo;0;L;;;;;N;;;;;
+18B03;KHITAN SMALL SCRIPT CHARACTER-18B03;Lo;0;L;;;;;N;;;;;
+18B04;KHITAN SMALL SCRIPT CHARACTER-18B04;Lo;0;L;;;;;N;;;;;
+18B05;KHITAN SMALL SCRIPT CHARACTER-18B05;Lo;0;L;;;;;N;;;;;
+18B06;KHITAN SMALL SCRIPT CHARACTER-18B06;Lo;0;L;;;;;N;;;;;
+18B07;KHITAN SMALL SCRIPT CHARACTER-18B07;Lo;0;L;;;;;N;;;;;
+18B08;KHITAN SMALL SCRIPT CHARACTER-18B08;Lo;0;L;;;;;N;;;;;
+18B09;KHITAN SMALL SCRIPT CHARACTER-18B09;Lo;0;L;;;;;N;;;;;
+18B0A;KHITAN SMALL SCRIPT CHARACTER-18B0A;Lo;0;L;;;;;N;;;;;
+18B0B;KHITAN SMALL SCRIPT CHARACTER-18B0B;Lo;0;L;;;;;N;;;;;
+18B0C;KHITAN SMALL SCRIPT CHARACTER-18B0C;Lo;0;L;;;;;N;;;;;
+18B0D;KHITAN SMALL SCRIPT CHARACTER-18B0D;Lo;0;L;;;;;N;;;;;
+18B0E;KHITAN SMALL SCRIPT CHARACTER-18B0E;Lo;0;L;;;;;N;;;;;
+18B0F;KHITAN SMALL SCRIPT CHARACTER-18B0F;Lo;0;L;;;;;N;;;;;
+18B10;KHITAN SMALL SCRIPT CHARACTER-18B10;Lo;0;L;;;;;N;;;;;
+18B11;KHITAN SMALL SCRIPT CHARACTER-18B11;Lo;0;L;;;;;N;;;;;
+18B12;KHITAN SMALL SCRIPT CHARACTER-18B12;Lo;0;L;;;;;N;;;;;
+18B13;KHITAN SMALL SCRIPT CHARACTER-18B13;Lo;0;L;;;;;N;;;;;
+18B14;KHITAN SMALL SCRIPT CHARACTER-18B14;Lo;0;L;;;;;N;;;;;
+18B15;KHITAN SMALL SCRIPT CHARACTER-18B15;Lo;0;L;;;;;N;;;;;
+18B16;KHITAN SMALL SCRIPT CHARACTER-18B16;Lo;0;L;;;;;N;;;;;
+18B17;KHITAN SMALL SCRIPT CHARACTER-18B17;Lo;0;L;;;;;N;;;;;
+18B18;KHITAN SMALL SCRIPT CHARACTER-18B18;Lo;0;L;;;;;N;;;;;
+18B19;KHITAN SMALL SCRIPT CHARACTER-18B19;Lo;0;L;;;;;N;;;;;
+18B1A;KHITAN SMALL SCRIPT CHARACTER-18B1A;Lo;0;L;;;;;N;;;;;
+18B1B;KHITAN SMALL SCRIPT CHARACTER-18B1B;Lo;0;L;;;;;N;;;;;
+18B1C;KHITAN SMALL SCRIPT CHARACTER-18B1C;Lo;0;L;;;;;N;;;;;
+18B1D;KHITAN SMALL SCRIPT CHARACTER-18B1D;Lo;0;L;;;;;N;;;;;
+18B1E;KHITAN SMALL SCRIPT CHARACTER-18B1E;Lo;0;L;;;;;N;;;;;
+18B1F;KHITAN SMALL SCRIPT CHARACTER-18B1F;Lo;0;L;;;;;N;;;;;
+18B20;KHITAN SMALL SCRIPT CHARACTER-18B20;Lo;0;L;;;;;N;;;;;
+18B21;KHITAN SMALL SCRIPT CHARACTER-18B21;Lo;0;L;;;;;N;;;;;
+18B22;KHITAN SMALL SCRIPT CHARACTER-18B22;Lo;0;L;;;;;N;;;;;
+18B23;KHITAN SMALL SCRIPT CHARACTER-18B23;Lo;0;L;;;;;N;;;;;
+18B24;KHITAN SMALL SCRIPT CHARACTER-18B24;Lo;0;L;;;;;N;;;;;
+18B25;KHITAN SMALL SCRIPT CHARACTER-18B25;Lo;0;L;;;;;N;;;;;
+18B26;KHITAN SMALL SCRIPT CHARACTER-18B26;Lo;0;L;;;;;N;;;;;
+18B27;KHITAN SMALL SCRIPT CHARACTER-18B27;Lo;0;L;;;;;N;;;;;
+18B28;KHITAN SMALL SCRIPT CHARACTER-18B28;Lo;0;L;;;;;N;;;;;
+18B29;KHITAN SMALL SCRIPT CHARACTER-18B29;Lo;0;L;;;;;N;;;;;
+18B2A;KHITAN SMALL SCRIPT CHARACTER-18B2A;Lo;0;L;;;;;N;;;;;
+18B2B;KHITAN SMALL SCRIPT CHARACTER-18B2B;Lo;0;L;;;;;N;;;;;
+18B2C;KHITAN SMALL SCRIPT CHARACTER-18B2C;Lo;0;L;;;;;N;;;;;
+18B2D;KHITAN SMALL SCRIPT CHARACTER-18B2D;Lo;0;L;;;;;N;;;;;
+18B2E;KHITAN SMALL SCRIPT CHARACTER-18B2E;Lo;0;L;;;;;N;;;;;
+18B2F;KHITAN SMALL SCRIPT CHARACTER-18B2F;Lo;0;L;;;;;N;;;;;
+18B30;KHITAN SMALL SCRIPT CHARACTER-18B30;Lo;0;L;;;;;N;;;;;
+18B31;KHITAN SMALL SCRIPT CHARACTER-18B31;Lo;0;L;;;;;N;;;;;
+18B32;KHITAN SMALL SCRIPT CHARACTER-18B32;Lo;0;L;;;;;N;;;;;
+18B33;KHITAN SMALL SCRIPT CHARACTER-18B33;Lo;0;L;;;;;N;;;;;
+18B34;KHITAN SMALL SCRIPT CHARACTER-18B34;Lo;0;L;;;;;N;;;;;
+18B35;KHITAN SMALL SCRIPT CHARACTER-18B35;Lo;0;L;;;;;N;;;;;
+18B36;KHITAN SMALL SCRIPT CHARACTER-18B36;Lo;0;L;;;;;N;;;;;
+18B37;KHITAN SMALL SCRIPT CHARACTER-18B37;Lo;0;L;;;;;N;;;;;
+18B38;KHITAN SMALL SCRIPT CHARACTER-18B38;Lo;0;L;;;;;N;;;;;
+18B39;KHITAN SMALL SCRIPT CHARACTER-18B39;Lo;0;L;;;;;N;;;;;
+18B3A;KHITAN SMALL SCRIPT CHARACTER-18B3A;Lo;0;L;;;;;N;;;;;
+18B3B;KHITAN SMALL SCRIPT CHARACTER-18B3B;Lo;0;L;;;;;N;;;;;
+18B3C;KHITAN SMALL SCRIPT CHARACTER-18B3C;Lo;0;L;;;;;N;;;;;
+18B3D;KHITAN SMALL SCRIPT CHARACTER-18B3D;Lo;0;L;;;;;N;;;;;
+18B3E;KHITAN SMALL SCRIPT CHARACTER-18B3E;Lo;0;L;;;;;N;;;;;
+18B3F;KHITAN SMALL SCRIPT CHARACTER-18B3F;Lo;0;L;;;;;N;;;;;
+18B40;KHITAN SMALL SCRIPT CHARACTER-18B40;Lo;0;L;;;;;N;;;;;
+18B41;KHITAN SMALL SCRIPT CHARACTER-18B41;Lo;0;L;;;;;N;;;;;
+18B42;KHITAN SMALL SCRIPT CHARACTER-18B42;Lo;0;L;;;;;N;;;;;
+18B43;KHITAN SMALL SCRIPT CHARACTER-18B43;Lo;0;L;;;;;N;;;;;
+18B44;KHITAN SMALL SCRIPT CHARACTER-18B44;Lo;0;L;;;;;N;;;;;
+18B45;KHITAN SMALL SCRIPT CHARACTER-18B45;Lo;0;L;;;;;N;;;;;
+18B46;KHITAN SMALL SCRIPT CHARACTER-18B46;Lo;0;L;;;;;N;;;;;
+18B47;KHITAN SMALL SCRIPT CHARACTER-18B47;Lo;0;L;;;;;N;;;;;
+18B48;KHITAN SMALL SCRIPT CHARACTER-18B48;Lo;0;L;;;;;N;;;;;
+18B49;KHITAN SMALL SCRIPT CHARACTER-18B49;Lo;0;L;;;;;N;;;;;
+18B4A;KHITAN SMALL SCRIPT CHARACTER-18B4A;Lo;0;L;;;;;N;;;;;
+18B4B;KHITAN SMALL SCRIPT CHARACTER-18B4B;Lo;0;L;;;;;N;;;;;
+18B4C;KHITAN SMALL SCRIPT CHARACTER-18B4C;Lo;0;L;;;;;N;;;;;
+18B4D;KHITAN SMALL SCRIPT CHARACTER-18B4D;Lo;0;L;;;;;N;;;;;
+18B4E;KHITAN SMALL SCRIPT CHARACTER-18B4E;Lo;0;L;;;;;N;;;;;
+18B4F;KHITAN SMALL SCRIPT CHARACTER-18B4F;Lo;0;L;;;;;N;;;;;
+18B50;KHITAN SMALL SCRIPT CHARACTER-18B50;Lo;0;L;;;;;N;;;;;
+18B51;KHITAN SMALL SCRIPT CHARACTER-18B51;Lo;0;L;;;;;N;;;;;
+18B52;KHITAN SMALL SCRIPT CHARACTER-18B52;Lo;0;L;;;;;N;;;;;
+18B53;KHITAN SMALL SCRIPT CHARACTER-18B53;Lo;0;L;;;;;N;;;;;
+18B54;KHITAN SMALL SCRIPT CHARACTER-18B54;Lo;0;L;;;;;N;;;;;
+18B55;KHITAN SMALL SCRIPT CHARACTER-18B55;Lo;0;L;;;;;N;;;;;
+18B56;KHITAN SMALL SCRIPT CHARACTER-18B56;Lo;0;L;;;;;N;;;;;
+18B57;KHITAN SMALL SCRIPT CHARACTER-18B57;Lo;0;L;;;;;N;;;;;
+18B58;KHITAN SMALL SCRIPT CHARACTER-18B58;Lo;0;L;;;;;N;;;;;
+18B59;KHITAN SMALL SCRIPT CHARACTER-18B59;Lo;0;L;;;;;N;;;;;
+18B5A;KHITAN SMALL SCRIPT CHARACTER-18B5A;Lo;0;L;;;;;N;;;;;
+18B5B;KHITAN SMALL SCRIPT CHARACTER-18B5B;Lo;0;L;;;;;N;;;;;
+18B5C;KHITAN SMALL SCRIPT CHARACTER-18B5C;Lo;0;L;;;;;N;;;;;
+18B5D;KHITAN SMALL SCRIPT CHARACTER-18B5D;Lo;0;L;;;;;N;;;;;
+18B5E;KHITAN SMALL SCRIPT CHARACTER-18B5E;Lo;0;L;;;;;N;;;;;
+18B5F;KHITAN SMALL SCRIPT CHARACTER-18B5F;Lo;0;L;;;;;N;;;;;
+18B60;KHITAN SMALL SCRIPT CHARACTER-18B60;Lo;0;L;;;;;N;;;;;
+18B61;KHITAN SMALL SCRIPT CHARACTER-18B61;Lo;0;L;;;;;N;;;;;
+18B62;KHITAN SMALL SCRIPT CHARACTER-18B62;Lo;0;L;;;;;N;;;;;
+18B63;KHITAN SMALL SCRIPT CHARACTER-18B63;Lo;0;L;;;;;N;;;;;
+18B64;KHITAN SMALL SCRIPT CHARACTER-18B64;Lo;0;L;;;;;N;;;;;
+18B65;KHITAN SMALL SCRIPT CHARACTER-18B65;Lo;0;L;;;;;N;;;;;
+18B66;KHITAN SMALL SCRIPT CHARACTER-18B66;Lo;0;L;;;;;N;;;;;
+18B67;KHITAN SMALL SCRIPT CHARACTER-18B67;Lo;0;L;;;;;N;;;;;
+18B68;KHITAN SMALL SCRIPT CHARACTER-18B68;Lo;0;L;;;;;N;;;;;
+18B69;KHITAN SMALL SCRIPT CHARACTER-18B69;Lo;0;L;;;;;N;;;;;
+18B6A;KHITAN SMALL SCRIPT CHARACTER-18B6A;Lo;0;L;;;;;N;;;;;
+18B6B;KHITAN SMALL SCRIPT CHARACTER-18B6B;Lo;0;L;;;;;N;;;;;
+18B6C;KHITAN SMALL SCRIPT CHARACTER-18B6C;Lo;0;L;;;;;N;;;;;
+18B6D;KHITAN SMALL SCRIPT CHARACTER-18B6D;Lo;0;L;;;;;N;;;;;
+18B6E;KHITAN SMALL SCRIPT CHARACTER-18B6E;Lo;0;L;;;;;N;;;;;
+18B6F;KHITAN SMALL SCRIPT CHARACTER-18B6F;Lo;0;L;;;;;N;;;;;
+18B70;KHITAN SMALL SCRIPT CHARACTER-18B70;Lo;0;L;;;;;N;;;;;
+18B71;KHITAN SMALL SCRIPT CHARACTER-18B71;Lo;0;L;;;;;N;;;;;
+18B72;KHITAN SMALL SCRIPT CHARACTER-18B72;Lo;0;L;;;;;N;;;;;
+18B73;KHITAN SMALL SCRIPT CHARACTER-18B73;Lo;0;L;;;;;N;;;;;
+18B74;KHITAN SMALL SCRIPT CHARACTER-18B74;Lo;0;L;;;;;N;;;;;
+18B75;KHITAN SMALL SCRIPT CHARACTER-18B75;Lo;0;L;;;;;N;;;;;
+18B76;KHITAN SMALL SCRIPT CHARACTER-18B76;Lo;0;L;;;;;N;;;;;
+18B77;KHITAN SMALL SCRIPT CHARACTER-18B77;Lo;0;L;;;;;N;;;;;
+18B78;KHITAN SMALL SCRIPT CHARACTER-18B78;Lo;0;L;;;;;N;;;;;
+18B79;KHITAN SMALL SCRIPT CHARACTER-18B79;Lo;0;L;;;;;N;;;;;
+18B7A;KHITAN SMALL SCRIPT CHARACTER-18B7A;Lo;0;L;;;;;N;;;;;
+18B7B;KHITAN SMALL SCRIPT CHARACTER-18B7B;Lo;0;L;;;;;N;;;;;
+18B7C;KHITAN SMALL SCRIPT CHARACTER-18B7C;Lo;0;L;;;;;N;;;;;
+18B7D;KHITAN SMALL SCRIPT CHARACTER-18B7D;Lo;0;L;;;;;N;;;;;
+18B7E;KHITAN SMALL SCRIPT CHARACTER-18B7E;Lo;0;L;;;;;N;;;;;
+18B7F;KHITAN SMALL SCRIPT CHARACTER-18B7F;Lo;0;L;;;;;N;;;;;
+18B80;KHITAN SMALL SCRIPT CHARACTER-18B80;Lo;0;L;;;;;N;;;;;
+18B81;KHITAN SMALL SCRIPT CHARACTER-18B81;Lo;0;L;;;;;N;;;;;
+18B82;KHITAN SMALL SCRIPT CHARACTER-18B82;Lo;0;L;;;;;N;;;;;
+18B83;KHITAN SMALL SCRIPT CHARACTER-18B83;Lo;0;L;;;;;N;;;;;
+18B84;KHITAN SMALL SCRIPT CHARACTER-18B84;Lo;0;L;;;;;N;;;;;
+18B85;KHITAN SMALL SCRIPT CHARACTER-18B85;Lo;0;L;;;;;N;;;;;
+18B86;KHITAN SMALL SCRIPT CHARACTER-18B86;Lo;0;L;;;;;N;;;;;
+18B87;KHITAN SMALL SCRIPT CHARACTER-18B87;Lo;0;L;;;;;N;;;;;
+18B88;KHITAN SMALL SCRIPT CHARACTER-18B88;Lo;0;L;;;;;N;;;;;
+18B89;KHITAN SMALL SCRIPT CHARACTER-18B89;Lo;0;L;;;;;N;;;;;
+18B8A;KHITAN SMALL SCRIPT CHARACTER-18B8A;Lo;0;L;;;;;N;;;;;
+18B8B;KHITAN SMALL SCRIPT CHARACTER-18B8B;Lo;0;L;;;;;N;;;;;
+18B8C;KHITAN SMALL SCRIPT CHARACTER-18B8C;Lo;0;L;;;;;N;;;;;
+18B8D;KHITAN SMALL SCRIPT CHARACTER-18B8D;Lo;0;L;;;;;N;;;;;
+18B8E;KHITAN SMALL SCRIPT CHARACTER-18B8E;Lo;0;L;;;;;N;;;;;
+18B8F;KHITAN SMALL SCRIPT CHARACTER-18B8F;Lo;0;L;;;;;N;;;;;
+18B90;KHITAN SMALL SCRIPT CHARACTER-18B90;Lo;0;L;;;;;N;;;;;
+18B91;KHITAN SMALL SCRIPT CHARACTER-18B91;Lo;0;L;;;;;N;;;;;
+18B92;KHITAN SMALL SCRIPT CHARACTER-18B92;Lo;0;L;;;;;N;;;;;
+18B93;KHITAN SMALL SCRIPT CHARACTER-18B93;Lo;0;L;;;;;N;;;;;
+18B94;KHITAN SMALL SCRIPT CHARACTER-18B94;Lo;0;L;;;;;N;;;;;
+18B95;KHITAN SMALL SCRIPT CHARACTER-18B95;Lo;0;L;;;;;N;;;;;
+18B96;KHITAN SMALL SCRIPT CHARACTER-18B96;Lo;0;L;;;;;N;;;;;
+18B97;KHITAN SMALL SCRIPT CHARACTER-18B97;Lo;0;L;;;;;N;;;;;
+18B98;KHITAN SMALL SCRIPT CHARACTER-18B98;Lo;0;L;;;;;N;;;;;
+18B99;KHITAN SMALL SCRIPT CHARACTER-18B99;Lo;0;L;;;;;N;;;;;
+18B9A;KHITAN SMALL SCRIPT CHARACTER-18B9A;Lo;0;L;;;;;N;;;;;
+18B9B;KHITAN SMALL SCRIPT CHARACTER-18B9B;Lo;0;L;;;;;N;;;;;
+18B9C;KHITAN SMALL SCRIPT CHARACTER-18B9C;Lo;0;L;;;;;N;;;;;
+18B9D;KHITAN SMALL SCRIPT CHARACTER-18B9D;Lo;0;L;;;;;N;;;;;
+18B9E;KHITAN SMALL SCRIPT CHARACTER-18B9E;Lo;0;L;;;;;N;;;;;
+18B9F;KHITAN SMALL SCRIPT CHARACTER-18B9F;Lo;0;L;;;;;N;;;;;
+18BA0;KHITAN SMALL SCRIPT CHARACTER-18BA0;Lo;0;L;;;;;N;;;;;
+18BA1;KHITAN SMALL SCRIPT CHARACTER-18BA1;Lo;0;L;;;;;N;;;;;
+18BA2;KHITAN SMALL SCRIPT CHARACTER-18BA2;Lo;0;L;;;;;N;;;;;
+18BA3;KHITAN SMALL SCRIPT CHARACTER-18BA3;Lo;0;L;;;;;N;;;;;
+18BA4;KHITAN SMALL SCRIPT CHARACTER-18BA4;Lo;0;L;;;;;N;;;;;
+18BA5;KHITAN SMALL SCRIPT CHARACTER-18BA5;Lo;0;L;;;;;N;;;;;
+18BA6;KHITAN SMALL SCRIPT CHARACTER-18BA6;Lo;0;L;;;;;N;;;;;
+18BA7;KHITAN SMALL SCRIPT CHARACTER-18BA7;Lo;0;L;;;;;N;;;;;
+18BA8;KHITAN SMALL SCRIPT CHARACTER-18BA8;Lo;0;L;;;;;N;;;;;
+18BA9;KHITAN SMALL SCRIPT CHARACTER-18BA9;Lo;0;L;;;;;N;;;;;
+18BAA;KHITAN SMALL SCRIPT CHARACTER-18BAA;Lo;0;L;;;;;N;;;;;
+18BAB;KHITAN SMALL SCRIPT CHARACTER-18BAB;Lo;0;L;;;;;N;;;;;
+18BAC;KHITAN SMALL SCRIPT CHARACTER-18BAC;Lo;0;L;;;;;N;;;;;
+18BAD;KHITAN SMALL SCRIPT CHARACTER-18BAD;Lo;0;L;;;;;N;;;;;
+18BAE;KHITAN SMALL SCRIPT CHARACTER-18BAE;Lo;0;L;;;;;N;;;;;
+18BAF;KHITAN SMALL SCRIPT CHARACTER-18BAF;Lo;0;L;;;;;N;;;;;
+18BB0;KHITAN SMALL SCRIPT CHARACTER-18BB0;Lo;0;L;;;;;N;;;;;
+18BB1;KHITAN SMALL SCRIPT CHARACTER-18BB1;Lo;0;L;;;;;N;;;;;
+18BB2;KHITAN SMALL SCRIPT CHARACTER-18BB2;Lo;0;L;;;;;N;;;;;
+18BB3;KHITAN SMALL SCRIPT CHARACTER-18BB3;Lo;0;L;;;;;N;;;;;
+18BB4;KHITAN SMALL SCRIPT CHARACTER-18BB4;Lo;0;L;;;;;N;;;;;
+18BB5;KHITAN SMALL SCRIPT CHARACTER-18BB5;Lo;0;L;;;;;N;;;;;
+18BB6;KHITAN SMALL SCRIPT CHARACTER-18BB6;Lo;0;L;;;;;N;;;;;
+18BB7;KHITAN SMALL SCRIPT CHARACTER-18BB7;Lo;0;L;;;;;N;;;;;
+18BB8;KHITAN SMALL SCRIPT CHARACTER-18BB8;Lo;0;L;;;;;N;;;;;
+18BB9;KHITAN SMALL SCRIPT CHARACTER-18BB9;Lo;0;L;;;;;N;;;;;
+18BBA;KHITAN SMALL SCRIPT CHARACTER-18BBA;Lo;0;L;;;;;N;;;;;
+18BBB;KHITAN SMALL SCRIPT CHARACTER-18BBB;Lo;0;L;;;;;N;;;;;
+18BBC;KHITAN SMALL SCRIPT CHARACTER-18BBC;Lo;0;L;;;;;N;;;;;
+18BBD;KHITAN SMALL SCRIPT CHARACTER-18BBD;Lo;0;L;;;;;N;;;;;
+18BBE;KHITAN SMALL SCRIPT CHARACTER-18BBE;Lo;0;L;;;;;N;;;;;
+18BBF;KHITAN SMALL SCRIPT CHARACTER-18BBF;Lo;0;L;;;;;N;;;;;
+18BC0;KHITAN SMALL SCRIPT CHARACTER-18BC0;Lo;0;L;;;;;N;;;;;
+18BC1;KHITAN SMALL SCRIPT CHARACTER-18BC1;Lo;0;L;;;;;N;;;;;
+18BC2;KHITAN SMALL SCRIPT CHARACTER-18BC2;Lo;0;L;;;;;N;;;;;
+18BC3;KHITAN SMALL SCRIPT CHARACTER-18BC3;Lo;0;L;;;;;N;;;;;
+18BC4;KHITAN SMALL SCRIPT CHARACTER-18BC4;Lo;0;L;;;;;N;;;;;
+18BC5;KHITAN SMALL SCRIPT CHARACTER-18BC5;Lo;0;L;;;;;N;;;;;
+18BC6;KHITAN SMALL SCRIPT CHARACTER-18BC6;Lo;0;L;;;;;N;;;;;
+18BC7;KHITAN SMALL SCRIPT CHARACTER-18BC7;Lo;0;L;;;;;N;;;;;
+18BC8;KHITAN SMALL SCRIPT CHARACTER-18BC8;Lo;0;L;;;;;N;;;;;
+18BC9;KHITAN SMALL SCRIPT CHARACTER-18BC9;Lo;0;L;;;;;N;;;;;
+18BCA;KHITAN SMALL SCRIPT CHARACTER-18BCA;Lo;0;L;;;;;N;;;;;
+18BCB;KHITAN SMALL SCRIPT CHARACTER-18BCB;Lo;0;L;;;;;N;;;;;
+18BCC;KHITAN SMALL SCRIPT CHARACTER-18BCC;Lo;0;L;;;;;N;;;;;
+18BCD;KHITAN SMALL SCRIPT CHARACTER-18BCD;Lo;0;L;;;;;N;;;;;
+18BCE;KHITAN SMALL SCRIPT CHARACTER-18BCE;Lo;0;L;;;;;N;;;;;
+18BCF;KHITAN SMALL SCRIPT CHARACTER-18BCF;Lo;0;L;;;;;N;;;;;
+18BD0;KHITAN SMALL SCRIPT CHARACTER-18BD0;Lo;0;L;;;;;N;;;;;
+18BD1;KHITAN SMALL SCRIPT CHARACTER-18BD1;Lo;0;L;;;;;N;;;;;
+18BD2;KHITAN SMALL SCRIPT CHARACTER-18BD2;Lo;0;L;;;;;N;;;;;
+18BD3;KHITAN SMALL SCRIPT CHARACTER-18BD3;Lo;0;L;;;;;N;;;;;
+18BD4;KHITAN SMALL SCRIPT CHARACTER-18BD4;Lo;0;L;;;;;N;;;;;
+18BD5;KHITAN SMALL SCRIPT CHARACTER-18BD5;Lo;0;L;;;;;N;;;;;
+18BD6;KHITAN SMALL SCRIPT CHARACTER-18BD6;Lo;0;L;;;;;N;;;;;
+18BD7;KHITAN SMALL SCRIPT CHARACTER-18BD7;Lo;0;L;;;;;N;;;;;
+18BD8;KHITAN SMALL SCRIPT CHARACTER-18BD8;Lo;0;L;;;;;N;;;;;
+18BD9;KHITAN SMALL SCRIPT CHARACTER-18BD9;Lo;0;L;;;;;N;;;;;
+18BDA;KHITAN SMALL SCRIPT CHARACTER-18BDA;Lo;0;L;;;;;N;;;;;
+18BDB;KHITAN SMALL SCRIPT CHARACTER-18BDB;Lo;0;L;;;;;N;;;;;
+18BDC;KHITAN SMALL SCRIPT CHARACTER-18BDC;Lo;0;L;;;;;N;;;;;
+18BDD;KHITAN SMALL SCRIPT CHARACTER-18BDD;Lo;0;L;;;;;N;;;;;
+18BDE;KHITAN SMALL SCRIPT CHARACTER-18BDE;Lo;0;L;;;;;N;;;;;
+18BDF;KHITAN SMALL SCRIPT CHARACTER-18BDF;Lo;0;L;;;;;N;;;;;
+18BE0;KHITAN SMALL SCRIPT CHARACTER-18BE0;Lo;0;L;;;;;N;;;;;
+18BE1;KHITAN SMALL SCRIPT CHARACTER-18BE1;Lo;0;L;;;;;N;;;;;
+18BE2;KHITAN SMALL SCRIPT CHARACTER-18BE2;Lo;0;L;;;;;N;;;;;
+18BE3;KHITAN SMALL SCRIPT CHARACTER-18BE3;Lo;0;L;;;;;N;;;;;
+18BE4;KHITAN SMALL SCRIPT CHARACTER-18BE4;Lo;0;L;;;;;N;;;;;
+18BE5;KHITAN SMALL SCRIPT CHARACTER-18BE5;Lo;0;L;;;;;N;;;;;
+18BE6;KHITAN SMALL SCRIPT CHARACTER-18BE6;Lo;0;L;;;;;N;;;;;
+18BE7;KHITAN SMALL SCRIPT CHARACTER-18BE7;Lo;0;L;;;;;N;;;;;
+18BE8;KHITAN SMALL SCRIPT CHARACTER-18BE8;Lo;0;L;;;;;N;;;;;
+18BE9;KHITAN SMALL SCRIPT CHARACTER-18BE9;Lo;0;L;;;;;N;;;;;
+18BEA;KHITAN SMALL SCRIPT CHARACTER-18BEA;Lo;0;L;;;;;N;;;;;
+18BEB;KHITAN SMALL SCRIPT CHARACTER-18BEB;Lo;0;L;;;;;N;;;;;
+18BEC;KHITAN SMALL SCRIPT CHARACTER-18BEC;Lo;0;L;;;;;N;;;;;
+18BED;KHITAN SMALL SCRIPT CHARACTER-18BED;Lo;0;L;;;;;N;;;;;
+18BEE;KHITAN SMALL SCRIPT CHARACTER-18BEE;Lo;0;L;;;;;N;;;;;
+18BEF;KHITAN SMALL SCRIPT CHARACTER-18BEF;Lo;0;L;;;;;N;;;;;
+18BF0;KHITAN SMALL SCRIPT CHARACTER-18BF0;Lo;0;L;;;;;N;;;;;
+18BF1;KHITAN SMALL SCRIPT CHARACTER-18BF1;Lo;0;L;;;;;N;;;;;
+18BF2;KHITAN SMALL SCRIPT CHARACTER-18BF2;Lo;0;L;;;;;N;;;;;
+18BF3;KHITAN SMALL SCRIPT CHARACTER-18BF3;Lo;0;L;;;;;N;;;;;
+18BF4;KHITAN SMALL SCRIPT CHARACTER-18BF4;Lo;0;L;;;;;N;;;;;
+18BF5;KHITAN SMALL SCRIPT CHARACTER-18BF5;Lo;0;L;;;;;N;;;;;
+18BF6;KHITAN SMALL SCRIPT CHARACTER-18BF6;Lo;0;L;;;;;N;;;;;
+18BF7;KHITAN SMALL SCRIPT CHARACTER-18BF7;Lo;0;L;;;;;N;;;;;
+18BF8;KHITAN SMALL SCRIPT CHARACTER-18BF8;Lo;0;L;;;;;N;;;;;
+18BF9;KHITAN SMALL SCRIPT CHARACTER-18BF9;Lo;0;L;;;;;N;;;;;
+18BFA;KHITAN SMALL SCRIPT CHARACTER-18BFA;Lo;0;L;;;;;N;;;;;
+18BFB;KHITAN SMALL SCRIPT CHARACTER-18BFB;Lo;0;L;;;;;N;;;;;
+18BFC;KHITAN SMALL SCRIPT CHARACTER-18BFC;Lo;0;L;;;;;N;;;;;
+18BFD;KHITAN SMALL SCRIPT CHARACTER-18BFD;Lo;0;L;;;;;N;;;;;
+18BFE;KHITAN SMALL SCRIPT CHARACTER-18BFE;Lo;0;L;;;;;N;;;;;
+18BFF;KHITAN SMALL SCRIPT CHARACTER-18BFF;Lo;0;L;;;;;N;;;;;
+18C00;KHITAN SMALL SCRIPT CHARACTER-18C00;Lo;0;L;;;;;N;;;;;
+18C01;KHITAN SMALL SCRIPT CHARACTER-18C01;Lo;0;L;;;;;N;;;;;
+18C02;KHITAN SMALL SCRIPT CHARACTER-18C02;Lo;0;L;;;;;N;;;;;
+18C03;KHITAN SMALL SCRIPT CHARACTER-18C03;Lo;0;L;;;;;N;;;;;
+18C04;KHITAN SMALL SCRIPT CHARACTER-18C04;Lo;0;L;;;;;N;;;;;
+18C05;KHITAN SMALL SCRIPT CHARACTER-18C05;Lo;0;L;;;;;N;;;;;
+18C06;KHITAN SMALL SCRIPT CHARACTER-18C06;Lo;0;L;;;;;N;;;;;
+18C07;KHITAN SMALL SCRIPT CHARACTER-18C07;Lo;0;L;;;;;N;;;;;
+18C08;KHITAN SMALL SCRIPT CHARACTER-18C08;Lo;0;L;;;;;N;;;;;
+18C09;KHITAN SMALL SCRIPT CHARACTER-18C09;Lo;0;L;;;;;N;;;;;
+18C0A;KHITAN SMALL SCRIPT CHARACTER-18C0A;Lo;0;L;;;;;N;;;;;
+18C0B;KHITAN SMALL SCRIPT CHARACTER-18C0B;Lo;0;L;;;;;N;;;;;
+18C0C;KHITAN SMALL SCRIPT CHARACTER-18C0C;Lo;0;L;;;;;N;;;;;
+18C0D;KHITAN SMALL SCRIPT CHARACTER-18C0D;Lo;0;L;;;;;N;;;;;
+18C0E;KHITAN SMALL SCRIPT CHARACTER-18C0E;Lo;0;L;;;;;N;;;;;
+18C0F;KHITAN SMALL SCRIPT CHARACTER-18C0F;Lo;0;L;;;;;N;;;;;
+18C10;KHITAN SMALL SCRIPT CHARACTER-18C10;Lo;0;L;;;;;N;;;;;
+18C11;KHITAN SMALL SCRIPT CHARACTER-18C11;Lo;0;L;;;;;N;;;;;
+18C12;KHITAN SMALL SCRIPT CHARACTER-18C12;Lo;0;L;;;;;N;;;;;
+18C13;KHITAN SMALL SCRIPT CHARACTER-18C13;Lo;0;L;;;;;N;;;;;
+18C14;KHITAN SMALL SCRIPT CHARACTER-18C14;Lo;0;L;;;;;N;;;;;
+18C15;KHITAN SMALL SCRIPT CHARACTER-18C15;Lo;0;L;;;;;N;;;;;
+18C16;KHITAN SMALL SCRIPT CHARACTER-18C16;Lo;0;L;;;;;N;;;;;
+18C17;KHITAN SMALL SCRIPT CHARACTER-18C17;Lo;0;L;;;;;N;;;;;
+18C18;KHITAN SMALL SCRIPT CHARACTER-18C18;Lo;0;L;;;;;N;;;;;
+18C19;KHITAN SMALL SCRIPT CHARACTER-18C19;Lo;0;L;;;;;N;;;;;
+18C1A;KHITAN SMALL SCRIPT CHARACTER-18C1A;Lo;0;L;;;;;N;;;;;
+18C1B;KHITAN SMALL SCRIPT CHARACTER-18C1B;Lo;0;L;;;;;N;;;;;
+18C1C;KHITAN SMALL SCRIPT CHARACTER-18C1C;Lo;0;L;;;;;N;;;;;
+18C1D;KHITAN SMALL SCRIPT CHARACTER-18C1D;Lo;0;L;;;;;N;;;;;
+18C1E;KHITAN SMALL SCRIPT CHARACTER-18C1E;Lo;0;L;;;;;N;;;;;
+18C1F;KHITAN SMALL SCRIPT CHARACTER-18C1F;Lo;0;L;;;;;N;;;;;
+18C20;KHITAN SMALL SCRIPT CHARACTER-18C20;Lo;0;L;;;;;N;;;;;
+18C21;KHITAN SMALL SCRIPT CHARACTER-18C21;Lo;0;L;;;;;N;;;;;
+18C22;KHITAN SMALL SCRIPT CHARACTER-18C22;Lo;0;L;;;;;N;;;;;
+18C23;KHITAN SMALL SCRIPT CHARACTER-18C23;Lo;0;L;;;;;N;;;;;
+18C24;KHITAN SMALL SCRIPT CHARACTER-18C24;Lo;0;L;;;;;N;;;;;
+18C25;KHITAN SMALL SCRIPT CHARACTER-18C25;Lo;0;L;;;;;N;;;;;
+18C26;KHITAN SMALL SCRIPT CHARACTER-18C26;Lo;0;L;;;;;N;;;;;
+18C27;KHITAN SMALL SCRIPT CHARACTER-18C27;Lo;0;L;;;;;N;;;;;
+18C28;KHITAN SMALL SCRIPT CHARACTER-18C28;Lo;0;L;;;;;N;;;;;
+18C29;KHITAN SMALL SCRIPT CHARACTER-18C29;Lo;0;L;;;;;N;;;;;
+18C2A;KHITAN SMALL SCRIPT CHARACTER-18C2A;Lo;0;L;;;;;N;;;;;
+18C2B;KHITAN SMALL SCRIPT CHARACTER-18C2B;Lo;0;L;;;;;N;;;;;
+18C2C;KHITAN SMALL SCRIPT CHARACTER-18C2C;Lo;0;L;;;;;N;;;;;
+18C2D;KHITAN SMALL SCRIPT CHARACTER-18C2D;Lo;0;L;;;;;N;;;;;
+18C2E;KHITAN SMALL SCRIPT CHARACTER-18C2E;Lo;0;L;;;;;N;;;;;
+18C2F;KHITAN SMALL SCRIPT CHARACTER-18C2F;Lo;0;L;;;;;N;;;;;
+18C30;KHITAN SMALL SCRIPT CHARACTER-18C30;Lo;0;L;;;;;N;;;;;
+18C31;KHITAN SMALL SCRIPT CHARACTER-18C31;Lo;0;L;;;;;N;;;;;
+18C32;KHITAN SMALL SCRIPT CHARACTER-18C32;Lo;0;L;;;;;N;;;;;
+18C33;KHITAN SMALL SCRIPT CHARACTER-18C33;Lo;0;L;;;;;N;;;;;
+18C34;KHITAN SMALL SCRIPT CHARACTER-18C34;Lo;0;L;;;;;N;;;;;
+18C35;KHITAN SMALL SCRIPT CHARACTER-18C35;Lo;0;L;;;;;N;;;;;
+18C36;KHITAN SMALL SCRIPT CHARACTER-18C36;Lo;0;L;;;;;N;;;;;
+18C37;KHITAN SMALL SCRIPT CHARACTER-18C37;Lo;0;L;;;;;N;;;;;
+18C38;KHITAN SMALL SCRIPT CHARACTER-18C38;Lo;0;L;;;;;N;;;;;
+18C39;KHITAN SMALL SCRIPT CHARACTER-18C39;Lo;0;L;;;;;N;;;;;
+18C3A;KHITAN SMALL SCRIPT CHARACTER-18C3A;Lo;0;L;;;;;N;;;;;
+18C3B;KHITAN SMALL SCRIPT CHARACTER-18C3B;Lo;0;L;;;;;N;;;;;
+18C3C;KHITAN SMALL SCRIPT CHARACTER-18C3C;Lo;0;L;;;;;N;;;;;
+18C3D;KHITAN SMALL SCRIPT CHARACTER-18C3D;Lo;0;L;;;;;N;;;;;
+18C3E;KHITAN SMALL SCRIPT CHARACTER-18C3E;Lo;0;L;;;;;N;;;;;
+18C3F;KHITAN SMALL SCRIPT CHARACTER-18C3F;Lo;0;L;;;;;N;;;;;
+18C40;KHITAN SMALL SCRIPT CHARACTER-18C40;Lo;0;L;;;;;N;;;;;
+18C41;KHITAN SMALL SCRIPT CHARACTER-18C41;Lo;0;L;;;;;N;;;;;
+18C42;KHITAN SMALL SCRIPT CHARACTER-18C42;Lo;0;L;;;;;N;;;;;
+18C43;KHITAN SMALL SCRIPT CHARACTER-18C43;Lo;0;L;;;;;N;;;;;
+18C44;KHITAN SMALL SCRIPT CHARACTER-18C44;Lo;0;L;;;;;N;;;;;
+18C45;KHITAN SMALL SCRIPT CHARACTER-18C45;Lo;0;L;;;;;N;;;;;
+18C46;KHITAN SMALL SCRIPT CHARACTER-18C46;Lo;0;L;;;;;N;;;;;
+18C47;KHITAN SMALL SCRIPT CHARACTER-18C47;Lo;0;L;;;;;N;;;;;
+18C48;KHITAN SMALL SCRIPT CHARACTER-18C48;Lo;0;L;;;;;N;;;;;
+18C49;KHITAN SMALL SCRIPT CHARACTER-18C49;Lo;0;L;;;;;N;;;;;
+18C4A;KHITAN SMALL SCRIPT CHARACTER-18C4A;Lo;0;L;;;;;N;;;;;
+18C4B;KHITAN SMALL SCRIPT CHARACTER-18C4B;Lo;0;L;;;;;N;;;;;
+18C4C;KHITAN SMALL SCRIPT CHARACTER-18C4C;Lo;0;L;;;;;N;;;;;
+18C4D;KHITAN SMALL SCRIPT CHARACTER-18C4D;Lo;0;L;;;;;N;;;;;
+18C4E;KHITAN SMALL SCRIPT CHARACTER-18C4E;Lo;0;L;;;;;N;;;;;
+18C4F;KHITAN SMALL SCRIPT CHARACTER-18C4F;Lo;0;L;;;;;N;;;;;
+18C50;KHITAN SMALL SCRIPT CHARACTER-18C50;Lo;0;L;;;;;N;;;;;
+18C51;KHITAN SMALL SCRIPT CHARACTER-18C51;Lo;0;L;;;;;N;;;;;
+18C52;KHITAN SMALL SCRIPT CHARACTER-18C52;Lo;0;L;;;;;N;;;;;
+18C53;KHITAN SMALL SCRIPT CHARACTER-18C53;Lo;0;L;;;;;N;;;;;
+18C54;KHITAN SMALL SCRIPT CHARACTER-18C54;Lo;0;L;;;;;N;;;;;
+18C55;KHITAN SMALL SCRIPT CHARACTER-18C55;Lo;0;L;;;;;N;;;;;
+18C56;KHITAN SMALL SCRIPT CHARACTER-18C56;Lo;0;L;;;;;N;;;;;
+18C57;KHITAN SMALL SCRIPT CHARACTER-18C57;Lo;0;L;;;;;N;;;;;
+18C58;KHITAN SMALL SCRIPT CHARACTER-18C58;Lo;0;L;;;;;N;;;;;
+18C59;KHITAN SMALL SCRIPT CHARACTER-18C59;Lo;0;L;;;;;N;;;;;
+18C5A;KHITAN SMALL SCRIPT CHARACTER-18C5A;Lo;0;L;;;;;N;;;;;
+18C5B;KHITAN SMALL SCRIPT CHARACTER-18C5B;Lo;0;L;;;;;N;;;;;
+18C5C;KHITAN SMALL SCRIPT CHARACTER-18C5C;Lo;0;L;;;;;N;;;;;
+18C5D;KHITAN SMALL SCRIPT CHARACTER-18C5D;Lo;0;L;;;;;N;;;;;
+18C5E;KHITAN SMALL SCRIPT CHARACTER-18C5E;Lo;0;L;;;;;N;;;;;
+18C5F;KHITAN SMALL SCRIPT CHARACTER-18C5F;Lo;0;L;;;;;N;;;;;
+18C60;KHITAN SMALL SCRIPT CHARACTER-18C60;Lo;0;L;;;;;N;;;;;
+18C61;KHITAN SMALL SCRIPT CHARACTER-18C61;Lo;0;L;;;;;N;;;;;
+18C62;KHITAN SMALL SCRIPT CHARACTER-18C62;Lo;0;L;;;;;N;;;;;
+18C63;KHITAN SMALL SCRIPT CHARACTER-18C63;Lo;0;L;;;;;N;;;;;
+18C64;KHITAN SMALL SCRIPT CHARACTER-18C64;Lo;0;L;;;;;N;;;;;
+18C65;KHITAN SMALL SCRIPT CHARACTER-18C65;Lo;0;L;;;;;N;;;;;
+18C66;KHITAN SMALL SCRIPT CHARACTER-18C66;Lo;0;L;;;;;N;;;;;
+18C67;KHITAN SMALL SCRIPT CHARACTER-18C67;Lo;0;L;;;;;N;;;;;
+18C68;KHITAN SMALL SCRIPT CHARACTER-18C68;Lo;0;L;;;;;N;;;;;
+18C69;KHITAN SMALL SCRIPT CHARACTER-18C69;Lo;0;L;;;;;N;;;;;
+18C6A;KHITAN SMALL SCRIPT CHARACTER-18C6A;Lo;0;L;;;;;N;;;;;
+18C6B;KHITAN SMALL SCRIPT CHARACTER-18C6B;Lo;0;L;;;;;N;;;;;
+18C6C;KHITAN SMALL SCRIPT CHARACTER-18C6C;Lo;0;L;;;;;N;;;;;
+18C6D;KHITAN SMALL SCRIPT CHARACTER-18C6D;Lo;0;L;;;;;N;;;;;
+18C6E;KHITAN SMALL SCRIPT CHARACTER-18C6E;Lo;0;L;;;;;N;;;;;
+18C6F;KHITAN SMALL SCRIPT CHARACTER-18C6F;Lo;0;L;;;;;N;;;;;
+18C70;KHITAN SMALL SCRIPT CHARACTER-18C70;Lo;0;L;;;;;N;;;;;
+18C71;KHITAN SMALL SCRIPT CHARACTER-18C71;Lo;0;L;;;;;N;;;;;
+18C72;KHITAN SMALL SCRIPT CHARACTER-18C72;Lo;0;L;;;;;N;;;;;
+18C73;KHITAN SMALL SCRIPT CHARACTER-18C73;Lo;0;L;;;;;N;;;;;
+18C74;KHITAN SMALL SCRIPT CHARACTER-18C74;Lo;0;L;;;;;N;;;;;
+18C75;KHITAN SMALL SCRIPT CHARACTER-18C75;Lo;0;L;;;;;N;;;;;
+18C76;KHITAN SMALL SCRIPT CHARACTER-18C76;Lo;0;L;;;;;N;;;;;
+18C77;KHITAN SMALL SCRIPT CHARACTER-18C77;Lo;0;L;;;;;N;;;;;
+18C78;KHITAN SMALL SCRIPT CHARACTER-18C78;Lo;0;L;;;;;N;;;;;
+18C79;KHITAN SMALL SCRIPT CHARACTER-18C79;Lo;0;L;;;;;N;;;;;
+18C7A;KHITAN SMALL SCRIPT CHARACTER-18C7A;Lo;0;L;;;;;N;;;;;
+18C7B;KHITAN SMALL SCRIPT CHARACTER-18C7B;Lo;0;L;;;;;N;;;;;
+18C7C;KHITAN SMALL SCRIPT CHARACTER-18C7C;Lo;0;L;;;;;N;;;;;
+18C7D;KHITAN SMALL SCRIPT CHARACTER-18C7D;Lo;0;L;;;;;N;;;;;
+18C7E;KHITAN SMALL SCRIPT CHARACTER-18C7E;Lo;0;L;;;;;N;;;;;
+18C7F;KHITAN SMALL SCRIPT CHARACTER-18C7F;Lo;0;L;;;;;N;;;;;
+18C80;KHITAN SMALL SCRIPT CHARACTER-18C80;Lo;0;L;;;;;N;;;;;
+18C81;KHITAN SMALL SCRIPT CHARACTER-18C81;Lo;0;L;;;;;N;;;;;
+18C82;KHITAN SMALL SCRIPT CHARACTER-18C82;Lo;0;L;;;;;N;;;;;
+18C83;KHITAN SMALL SCRIPT CHARACTER-18C83;Lo;0;L;;;;;N;;;;;
+18C84;KHITAN SMALL SCRIPT CHARACTER-18C84;Lo;0;L;;;;;N;;;;;
+18C85;KHITAN SMALL SCRIPT CHARACTER-18C85;Lo;0;L;;;;;N;;;;;
+18C86;KHITAN SMALL SCRIPT CHARACTER-18C86;Lo;0;L;;;;;N;;;;;
+18C87;KHITAN SMALL SCRIPT CHARACTER-18C87;Lo;0;L;;;;;N;;;;;
+18C88;KHITAN SMALL SCRIPT CHARACTER-18C88;Lo;0;L;;;;;N;;;;;
+18C89;KHITAN SMALL SCRIPT CHARACTER-18C89;Lo;0;L;;;;;N;;;;;
+18C8A;KHITAN SMALL SCRIPT CHARACTER-18C8A;Lo;0;L;;;;;N;;;;;
+18C8B;KHITAN SMALL SCRIPT CHARACTER-18C8B;Lo;0;L;;;;;N;;;;;
+18C8C;KHITAN SMALL SCRIPT CHARACTER-18C8C;Lo;0;L;;;;;N;;;;;
+18C8D;KHITAN SMALL SCRIPT CHARACTER-18C8D;Lo;0;L;;;;;N;;;;;
+18C8E;KHITAN SMALL SCRIPT CHARACTER-18C8E;Lo;0;L;;;;;N;;;;;
+18C8F;KHITAN SMALL SCRIPT CHARACTER-18C8F;Lo;0;L;;;;;N;;;;;
+18C90;KHITAN SMALL SCRIPT CHARACTER-18C90;Lo;0;L;;;;;N;;;;;
+18C91;KHITAN SMALL SCRIPT CHARACTER-18C91;Lo;0;L;;;;;N;;;;;
+18C92;KHITAN SMALL SCRIPT CHARACTER-18C92;Lo;0;L;;;;;N;;;;;
+18C93;KHITAN SMALL SCRIPT CHARACTER-18C93;Lo;0;L;;;;;N;;;;;
+18C94;KHITAN SMALL SCRIPT CHARACTER-18C94;Lo;0;L;;;;;N;;;;;
+18C95;KHITAN SMALL SCRIPT CHARACTER-18C95;Lo;0;L;;;;;N;;;;;
+18C96;KHITAN SMALL SCRIPT CHARACTER-18C96;Lo;0;L;;;;;N;;;;;
+18C97;KHITAN SMALL SCRIPT CHARACTER-18C97;Lo;0;L;;;;;N;;;;;
+18C98;KHITAN SMALL SCRIPT CHARACTER-18C98;Lo;0;L;;;;;N;;;;;
+18C99;KHITAN SMALL SCRIPT CHARACTER-18C99;Lo;0;L;;;;;N;;;;;
+18C9A;KHITAN SMALL SCRIPT CHARACTER-18C9A;Lo;0;L;;;;;N;;;;;
+18C9B;KHITAN SMALL SCRIPT CHARACTER-18C9B;Lo;0;L;;;;;N;;;;;
+18C9C;KHITAN SMALL SCRIPT CHARACTER-18C9C;Lo;0;L;;;;;N;;;;;
+18C9D;KHITAN SMALL SCRIPT CHARACTER-18C9D;Lo;0;L;;;;;N;;;;;
+18C9E;KHITAN SMALL SCRIPT CHARACTER-18C9E;Lo;0;L;;;;;N;;;;;
+18C9F;KHITAN SMALL SCRIPT CHARACTER-18C9F;Lo;0;L;;;;;N;;;;;
+18CA0;KHITAN SMALL SCRIPT CHARACTER-18CA0;Lo;0;L;;;;;N;;;;;
+18CA1;KHITAN SMALL SCRIPT CHARACTER-18CA1;Lo;0;L;;;;;N;;;;;
+18CA2;KHITAN SMALL SCRIPT CHARACTER-18CA2;Lo;0;L;;;;;N;;;;;
+18CA3;KHITAN SMALL SCRIPT CHARACTER-18CA3;Lo;0;L;;;;;N;;;;;
+18CA4;KHITAN SMALL SCRIPT CHARACTER-18CA4;Lo;0;L;;;;;N;;;;;
+18CA5;KHITAN SMALL SCRIPT CHARACTER-18CA5;Lo;0;L;;;;;N;;;;;
+18CA6;KHITAN SMALL SCRIPT CHARACTER-18CA6;Lo;0;L;;;;;N;;;;;
+18CA7;KHITAN SMALL SCRIPT CHARACTER-18CA7;Lo;0;L;;;;;N;;;;;
+18CA8;KHITAN SMALL SCRIPT CHARACTER-18CA8;Lo;0;L;;;;;N;;;;;
+18CA9;KHITAN SMALL SCRIPT CHARACTER-18CA9;Lo;0;L;;;;;N;;;;;
+18CAA;KHITAN SMALL SCRIPT CHARACTER-18CAA;Lo;0;L;;;;;N;;;;;
+18CAB;KHITAN SMALL SCRIPT CHARACTER-18CAB;Lo;0;L;;;;;N;;;;;
+18CAC;KHITAN SMALL SCRIPT CHARACTER-18CAC;Lo;0;L;;;;;N;;;;;
+18CAD;KHITAN SMALL SCRIPT CHARACTER-18CAD;Lo;0;L;;;;;N;;;;;
+18CAE;KHITAN SMALL SCRIPT CHARACTER-18CAE;Lo;0;L;;;;;N;;;;;
+18CAF;KHITAN SMALL SCRIPT CHARACTER-18CAF;Lo;0;L;;;;;N;;;;;
+18CB0;KHITAN SMALL SCRIPT CHARACTER-18CB0;Lo;0;L;;;;;N;;;;;
+18CB1;KHITAN SMALL SCRIPT CHARACTER-18CB1;Lo;0;L;;;;;N;;;;;
+18CB2;KHITAN SMALL SCRIPT CHARACTER-18CB2;Lo;0;L;;;;;N;;;;;
+18CB3;KHITAN SMALL SCRIPT CHARACTER-18CB3;Lo;0;L;;;;;N;;;;;
+18CB4;KHITAN SMALL SCRIPT CHARACTER-18CB4;Lo;0;L;;;;;N;;;;;
+18CB5;KHITAN SMALL SCRIPT CHARACTER-18CB5;Lo;0;L;;;;;N;;;;;
+18CB6;KHITAN SMALL SCRIPT CHARACTER-18CB6;Lo;0;L;;;;;N;;;;;
+18CB7;KHITAN SMALL SCRIPT CHARACTER-18CB7;Lo;0;L;;;;;N;;;;;
+18CB8;KHITAN SMALL SCRIPT CHARACTER-18CB8;Lo;0;L;;;;;N;;;;;
+18CB9;KHITAN SMALL SCRIPT CHARACTER-18CB9;Lo;0;L;;;;;N;;;;;
+18CBA;KHITAN SMALL SCRIPT CHARACTER-18CBA;Lo;0;L;;;;;N;;;;;
+18CBB;KHITAN SMALL SCRIPT CHARACTER-18CBB;Lo;0;L;;;;;N;;;;;
+18CBC;KHITAN SMALL SCRIPT CHARACTER-18CBC;Lo;0;L;;;;;N;;;;;
+18CBD;KHITAN SMALL SCRIPT CHARACTER-18CBD;Lo;0;L;;;;;N;;;;;
+18CBE;KHITAN SMALL SCRIPT CHARACTER-18CBE;Lo;0;L;;;;;N;;;;;
+18CBF;KHITAN SMALL SCRIPT CHARACTER-18CBF;Lo;0;L;;;;;N;;;;;
+18CC0;KHITAN SMALL SCRIPT CHARACTER-18CC0;Lo;0;L;;;;;N;;;;;
+18CC1;KHITAN SMALL SCRIPT CHARACTER-18CC1;Lo;0;L;;;;;N;;;;;
+18CC2;KHITAN SMALL SCRIPT CHARACTER-18CC2;Lo;0;L;;;;;N;;;;;
+18CC3;KHITAN SMALL SCRIPT CHARACTER-18CC3;Lo;0;L;;;;;N;;;;;
+18CC4;KHITAN SMALL SCRIPT CHARACTER-18CC4;Lo;0;L;;;;;N;;;;;
+18CC5;KHITAN SMALL SCRIPT CHARACTER-18CC5;Lo;0;L;;;;;N;;;;;
+18CC6;KHITAN SMALL SCRIPT CHARACTER-18CC6;Lo;0;L;;;;;N;;;;;
+18CC7;KHITAN SMALL SCRIPT CHARACTER-18CC7;Lo;0;L;;;;;N;;;;;
+18CC8;KHITAN SMALL SCRIPT CHARACTER-18CC8;Lo;0;L;;;;;N;;;;;
+18CC9;KHITAN SMALL SCRIPT CHARACTER-18CC9;Lo;0;L;;;;;N;;;;;
+18CCA;KHITAN SMALL SCRIPT CHARACTER-18CCA;Lo;0;L;;;;;N;;;;;
+18CCB;KHITAN SMALL SCRIPT CHARACTER-18CCB;Lo;0;L;;;;;N;;;;;
+18CCC;KHITAN SMALL SCRIPT CHARACTER-18CCC;Lo;0;L;;;;;N;;;;;
+18CCD;KHITAN SMALL SCRIPT CHARACTER-18CCD;Lo;0;L;;;;;N;;;;;
+18CCE;KHITAN SMALL SCRIPT CHARACTER-18CCE;Lo;0;L;;;;;N;;;;;
+18CCF;KHITAN SMALL SCRIPT CHARACTER-18CCF;Lo;0;L;;;;;N;;;;;
+18CD0;KHITAN SMALL SCRIPT CHARACTER-18CD0;Lo;0;L;;;;;N;;;;;
+18CD1;KHITAN SMALL SCRIPT CHARACTER-18CD1;Lo;0;L;;;;;N;;;;;
+18CD2;KHITAN SMALL SCRIPT CHARACTER-18CD2;Lo;0;L;;;;;N;;;;;
+18CD3;KHITAN SMALL SCRIPT CHARACTER-18CD3;Lo;0;L;;;;;N;;;;;
+18CD4;KHITAN SMALL SCRIPT CHARACTER-18CD4;Lo;0;L;;;;;N;;;;;
+18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;;
+18D00;<Tangut Ideograph Supplement, First>;Lo;0;L;;;;;N;;;;;
+18D08;<Tangut Ideograph Supplement, Last>;Lo;0;L;;;;;N;;;;;
1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;;
1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;;
1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;;
@@ -29973,6 +30651,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F10A;DIGIT NINE COMMA;No;0;EN;<compat> 0039 002C;;9;9;N;;;;;
1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;
1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;
+1F10D;CIRCLED ZERO WITH SLASH;So;0;ON;;;;;N;;;;;
+1F10E;CIRCLED ANTICLOCKWISE ARROW;So;0;ON;;;;;N;;;;;
+1F10F;CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;;
1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L;<compat> 0028 0041 0029;;;;N;;;;;
1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L;<compat> 0028 0042 0029;;;;N;;;;;
1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L;<compat> 0028 0043 0029;;;;N;;;;;
@@ -30066,6 +30747,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F16A;RAISED MC SIGN;So;0;ON;<super> 004D 0043;;;;N;;;;;
1F16B;RAISED MD SIGN;So;0;ON;<super> 004D 0044;;;;N;;;;;
1F16C;RAISED MR SIGN;So;0;ON;<super> 004D 0052;;;;N;;;;;
+1F16D;CIRCLED CC;So;0;ON;;;;;N;;;;;
+1F16E;CIRCLED C WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;;
+1F16F;CIRCLED HUMAN FIGURE;So;0;ON;;;;;N;;;;;
1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;;
1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;;
1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;;
@@ -30127,6 +30811,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;;
1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;;
1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;;
+1F1AD;MASK WORK SYMBOL;So;0;ON;;;;;N;;;;;
1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;;
1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;;
1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;;
@@ -31199,6 +31884,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6D3;STUPA;So;0;ON;;;;;N;;;;;
1F6D4;PAGODA;So;0;ON;;;;;N;;;;;
1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;;
+1F6D6;HUT;So;0;ON;;;;;N;;;;;
+1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;;
1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;;
1F6E1;SHIELD;So;0;ON;;;;;N;;;;;
1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;;
@@ -31223,6 +31910,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;;
1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;;
1F6FA;AUTO RICKSHAW;So;0;ON;;;;;N;;;;;
+1F6FB;PICKUP TRUCK;So;0;ON;;;;;N;;;;;
+1F6FC;ROLLER SKATE;So;0;ON;;;;;N;;;;;
1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;;
1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;;
1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;;
@@ -31588,6 +32277,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;
1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;
+1F8B0;ARROW POINTING UPWARDS THEN NORTH WEST;So;0;ON;;;;;N;;;;;
+1F8B1;ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST;So;0;ON;;;;;N;;;;;
1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;
1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;;
@@ -31600,6 +32291,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;;
1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;;
1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;;
+1F90C;PINCHED FINGERS;So;0;ON;;;;;N;;;;;
1F90D;WHITE HEART;So;0;ON;;;;;N;;;;;
1F90E;BROWN HEART;So;0;ON;;;;;N;;;;;
1F90F;PINCHING HAND;So;0;ON;;;;;N;;;;;
@@ -31701,10 +32393,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F96F;BAGEL;So;0;ON;;;;;N;;;;;
1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;;
1F971;YAWNING FACE;So;0;ON;;;;;N;;;;;
+1F972;SMILING FACE WITH TEAR;So;0;ON;;;;;N;;;;;
1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;;
1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;;
1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;;
1F976;FREEZING FACE;So;0;ON;;;;;N;;;;;
+1F977;NINJA;So;0;ON;;;;;N;;;;;
+1F978;DISGUISED FACE;So;0;ON;;;;;N;;;;;
1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;;
1F97B;SARI;So;0;ON;;;;;N;;;;;
1F97C;LAB COAT;So;0;ON;;;;;N;;;;;
@@ -31746,12 +32441,17 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F9A0;MICROBE;So;0;ON;;;;;N;;;;;
1F9A1;BADGER;So;0;ON;;;;;N;;;;;
1F9A2;SWAN;So;0;ON;;;;;N;;;;;
+1F9A3;MAMMOTH;So;0;ON;;;;;N;;;;;
+1F9A4;DODO;So;0;ON;;;;;N;;;;;
1F9A5;SLOTH;So;0;ON;;;;;N;;;;;
1F9A6;OTTER;So;0;ON;;;;;N;;;;;
1F9A7;ORANGUTAN;So;0;ON;;;;;N;;;;;
1F9A8;SKUNK;So;0;ON;;;;;N;;;;;
1F9A9;FLAMINGO;So;0;ON;;;;;N;;;;;
1F9AA;OYSTER;So;0;ON;;;;;N;;;;;
+1F9AB;BEAVER;So;0;ON;;;;;N;;;;;
+1F9AC;BISON;So;0;ON;;;;;N;;;;;
+1F9AD;SEAL;So;0;ON;;;;;N;;;;;
1F9AE;GUIDE DOG;So;0;ON;;;;;N;;;;;
1F9AF;PROBING CANE;So;0;ON;;;;;N;;;;;
1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;;
@@ -31781,6 +32481,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F9C8;BUTTER;So;0;ON;;;;;N;;;;;
1F9C9;MATE DRINK;So;0;ON;;;;;N;;;;;
1F9CA;ICE CUBE;So;0;ON;;;;;N;;;;;
+1F9CB;BUBBLE TEA;So;0;ON;;;;;N;;;;;
1F9CD;STANDING PERSON;So;0;ON;;;;;N;;;;;
1F9CE;KNEELING PERSON;So;0;ON;;;;;N;;;;;
1F9CF;DEAF PERSON;So;0;ON;;;;;N;;;;;
@@ -31934,20 +32635,273 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FA71;ONE-PIECE SWIMSUIT;So;0;ON;;;;;N;;;;;
1FA72;BRIEFS;So;0;ON;;;;;N;;;;;
1FA73;SHORTS;So;0;ON;;;;;N;;;;;
+1FA74;THONG SANDAL;So;0;ON;;;;;N;;;;;
1FA78;DROP OF BLOOD;So;0;ON;;;;;N;;;;;
1FA79;ADHESIVE BANDAGE;So;0;ON;;;;;N;;;;;
1FA7A;STETHOSCOPE;So;0;ON;;;;;N;;;;;
1FA80;YO-YO;So;0;ON;;;;;N;;;;;
1FA81;KITE;So;0;ON;;;;;N;;;;;
1FA82;PARACHUTE;So;0;ON;;;;;N;;;;;
+1FA83;BOOMERANG;So;0;ON;;;;;N;;;;;
+1FA84;MAGIC WAND;So;0;ON;;;;;N;;;;;
+1FA85;PINATA;So;0;ON;;;;;N;;;;;
+1FA86;NESTING DOLLS;So;0;ON;;;;;N;;;;;
1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;;
1FA91;CHAIR;So;0;ON;;;;;N;;;;;
1FA92;RAZOR;So;0;ON;;;;;N;;;;;
1FA93;AXE;So;0;ON;;;;;N;;;;;
1FA94;DIYA LAMP;So;0;ON;;;;;N;;;;;
1FA95;BANJO;So;0;ON;;;;;N;;;;;
+1FA96;MILITARY HELMET;So;0;ON;;;;;N;;;;;
+1FA97;ACCORDION;So;0;ON;;;;;N;;;;;
+1FA98;LONG DRUM;So;0;ON;;;;;N;;;;;
+1FA99;COIN;So;0;ON;;;;;N;;;;;
+1FA9A;CARPENTRY SAW;So;0;ON;;;;;N;;;;;
+1FA9B;SCREWDRIVER;So;0;ON;;;;;N;;;;;
+1FA9C;LADDER;So;0;ON;;;;;N;;;;;
+1FA9D;HOOK;So;0;ON;;;;;N;;;;;
+1FA9E;MIRROR;So;0;ON;;;;;N;;;;;
+1FA9F;WINDOW;So;0;ON;;;;;N;;;;;
+1FAA0;PLUNGER;So;0;ON;;;;;N;;;;;
+1FAA1;SEWING NEEDLE;So;0;ON;;;;;N;;;;;
+1FAA2;KNOT;So;0;ON;;;;;N;;;;;
+1FAA3;BUCKET;So;0;ON;;;;;N;;;;;
+1FAA4;MOUSE TRAP;So;0;ON;;;;;N;;;;;
+1FAA5;TOOTHBRUSH;So;0;ON;;;;;N;;;;;
+1FAA6;HEADSTONE;So;0;ON;;;;;N;;;;;
+1FAA7;PLACARD;So;0;ON;;;;;N;;;;;
+1FAA8;ROCK;So;0;ON;;;;;N;;;;;
+1FAB0;FLY;So;0;ON;;;;;N;;;;;
+1FAB1;WORM;So;0;ON;;;;;N;;;;;
+1FAB2;BEETLE;So;0;ON;;;;;N;;;;;
+1FAB3;COCKROACH;So;0;ON;;;;;N;;;;;
+1FAB4;POTTED PLANT;So;0;ON;;;;;N;;;;;
+1FAB5;WOOD;So;0;ON;;;;;N;;;;;
+1FAB6;FEATHER;So;0;ON;;;;;N;;;;;
+1FAC0;ANATOMICAL HEART;So;0;ON;;;;;N;;;;;
+1FAC1;LUNGS;So;0;ON;;;;;N;;;;;
+1FAC2;PEOPLE HUGGING;So;0;ON;;;;;N;;;;;
+1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;;
+1FAD1;BELL PEPPER;So;0;ON;;;;;N;;;;;
+1FAD2;OLIVE;So;0;ON;;;;;N;;;;;
+1FAD3;FLATBREAD;So;0;ON;;;;;N;;;;;
+1FAD4;TAMALE;So;0;ON;;;;;N;;;;;
+1FAD5;FONDUE;So;0;ON;;;;;N;;;;;
+1FAD6;TEAPOT;So;0;ON;;;;;N;;;;;
+1FB00;BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;;
+1FB01;BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;;
+1FB02;BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;;
+1FB03;BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;;
+1FB04;BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;;
+1FB05;BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;;
+1FB06;BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;;
+1FB07;BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;;
+1FB08;BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;;
+1FB09;BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;;
+1FB0A;BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;;
+1FB0B;BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;;
+1FB0C;BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;;
+1FB0D;BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;;
+1FB0E;BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;;
+1FB0F;BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;;
+1FB10;BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;;
+1FB11;BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;;
+1FB12;BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;;
+1FB13;BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;;
+1FB14;BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;;
+1FB15;BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;;
+1FB16;BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;;
+1FB17;BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;;
+1FB18;BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;;
+1FB19;BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;;
+1FB1A;BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;;
+1FB1B;BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;;
+1FB1C;BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;;
+1FB1D;BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;;
+1FB1E;BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;;
+1FB1F;BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;;
+1FB20;BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;;
+1FB21;BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;;
+1FB22;BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;;
+1FB23;BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;;
+1FB24;BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;;
+1FB25;BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;;
+1FB26;BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;;
+1FB27;BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;;
+1FB28;BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;;
+1FB29;BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;;
+1FB2A;BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;;
+1FB2B;BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;;
+1FB2C;BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;;
+1FB2D;BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;;
+1FB2E;BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;;
+1FB2F;BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;;
+1FB30;BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;;
+1FB31;BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;;
+1FB32;BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;;
+1FB33;BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;;
+1FB34;BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;;
+1FB35;BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;;
+1FB36;BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;;
+1FB37;BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;;
+1FB38;BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;;
+1FB39;BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;;
+1FB3A;BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;;
+1FB3B;BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;;
+1FB3C;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB3D;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB3E;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB3F;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB40;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB41;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB42;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB43;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB44;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB45;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB46;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB47;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB48;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB49;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB4A;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB4B;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB4C;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB4D;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB4E;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB4F;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB50;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB51;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB52;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB53;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB54;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB55;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB56;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FB57;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB58;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB59;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB5A;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB5B;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;
+1FB5C;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB5D;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB5E;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB5F;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB60;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB61;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;
+1FB62;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB63;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB64;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB65;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB66;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;
+1FB67;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FB68;UPPER AND RIGHT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB69;LEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB6A;UPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB6B;LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB6C;LEFT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB6D;UPPER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB6E;RIGHT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB6F;LOWER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB70;VERTICAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;;
+1FB71;VERTICAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;;
+1FB72;VERTICAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;;
+1FB73;VERTICAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;;
+1FB74;VERTICAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;;
+1FB75;VERTICAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;;
+1FB76;HORIZONTAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;;
+1FB77;HORIZONTAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;;
+1FB78;HORIZONTAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;;
+1FB79;HORIZONTAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;;
+1FB7A;HORIZONTAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;;
+1FB7B;HORIZONTAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;;
+1FB7C;LEFT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FB7D;LEFT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FB7E;RIGHT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FB7F;RIGHT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FB80;UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FB81;HORIZONTAL ONE EIGHTH BLOCK-1358;So;0;ON;;;;;N;;;;;
+1FB82;UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB83;UPPER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB84;UPPER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB85;UPPER THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB86;UPPER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB87;RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+1FB88;RIGHT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB89;RIGHT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB8A;RIGHT THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;
+1FB8B;RIGHT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+1FB8C;LEFT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB8D;RIGHT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB8E;UPPER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB8F;LOWER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB90;INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB91;UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB92;UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;
+1FB94;LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;
+1FB95;CHECKER BOARD FILL;So;0;ON;;;;;N;;;;;
+1FB96;INVERSE CHECKER BOARD FILL;So;0;ON;;;;;N;;;;;
+1FB97;HEAVY HORIZONTAL FILL;So;0;ON;;;;;N;;;;;
+1FB98;UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;
+1FB99;UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;
+1FB9A;UPPER AND LOWER TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;;
+1FB9B;LEFT AND RIGHT TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;;
+1FB9C;UPPER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB9D;UPPER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB9E;LOWER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FB9F;LOWER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+1FBA0;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;;
+1FBA1;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FBA2;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBA3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBA4;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBA5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBA6;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FBA7;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FBA8;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBA9;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBAA;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;;
+1FBAB;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;
+1FBAC;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBAD;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBAE;BOX DRAWINGS LIGHT DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;;
+1FBAF;BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE;So;0;ON;;;;;N;;;;;
+1FBB0;ARROWHEAD-SHAPED POINTER;So;0;ON;;;;;N;;;;;
+1FBB1;INVERSE CHECK MARK;So;0;ON;;;;;N;;;;;
+1FBB2;LEFT HALF RUNNING MAN;So;0;ON;;;;;N;;;;;
+1FBB3;RIGHT HALF RUNNING MAN;So;0;ON;;;;;N;;;;;
+1FBB4;INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;;;;;
+1FBB5;LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FBB6;RIGHTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FBB7;DOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FBB8;UPWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+1FBB9;LEFT HALF FOLDER;So;0;ON;;;;;N;;;;;
+1FBBA;RIGHT HALF FOLDER;So;0;ON;;;;;N;;;;;
+1FBBB;VOIDED GREEK CROSS;So;0;ON;;;;;N;;;;;
+1FBBC;RIGHT OPEN SQUARED DOT;So;0;ON;;;;;N;;;;;
+1FBBD;NEGATIVE DIAGONAL CROSS;So;0;ON;;;;;N;;;;;
+1FBBE;NEGATIVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;
+1FBBF;NEGATIVE DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;;
+1FBC0;WHITE HEAVY SALTIRE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+1FBC1;LEFT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1FBC2;MIDDLE THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1FBC3;RIGHT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1FBC4;NEGATIVE SQUARED QUESTION MARK;So;0;ON;;;;;N;;;;;
+1FBC5;STICK FIGURE;So;0;ON;;;;;N;;;;;
+1FBC6;STICK FIGURE WITH ARMS RAISED;So;0;ON;;;;;N;;;;;
+1FBC7;STICK FIGURE LEANING LEFT;So;0;ON;;;;;N;;;;;
+1FBC8;STICK FIGURE LEANING RIGHT;So;0;ON;;;;;N;;;;;
+1FBC9;STICK FIGURE WITH DRESS;So;0;ON;;;;;N;;;;;
+1FBCA;WHITE UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;;
+1FBF0;SEGMENTED DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1FBF1;SEGMENTED DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1FBF2;SEGMENTED DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1FBF3;SEGMENTED DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1FBF4;SEGMENTED DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1FBF5;SEGMENTED DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1FBF6;SEGMENTED DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
-2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+2A6DD;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
2B734;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;
2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;
@@ -32498,6 +33452,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;
2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;
2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;
+30000;<CJK Ideograph Extension G, First>;Lo;0;L;;;;;N;;;;;
+3134A;<CJK Ideograph Extension G, Last>;Lo;0;L;;;;;N;;;;;
E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
diff --git a/unicode/emoji-data.txt b/unicode/emoji-data.txt
index 2fb5c3ff68..5d7dc1b156 100644
--- a/unicode/emoji-data.txt
+++ b/unicode/emoji-data.txt
@@ -1,11 +1,11 @@
# emoji-data.txt
-# Date: 2019-01-15, 12:10:05 GMT
-# ยฉ 2019 Unicodeยฎ, Inc.
+# Date: 2020-01-28, 20:52:38 GMT
+# ยฉ 2020 Unicodeยฎ, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
# Emoji Data for UTS #51
-# Version: 12.0
+# Version: 13.0
#
# For documentation and usage, see http://www.unicode.org/reports/tr51
#
@@ -22,414 +22,667 @@
# All omitted code points have Emoji=No
# @missing: 0000..10FFFF ; Emoji ; No
-0023 ; Emoji # 1.1 [1] (#๏ธ) number sign
-002A ; Emoji # 1.1 [1] (*๏ธ) asterisk
-0030..0039 ; Emoji # 1.1 [10] (0๏ธ..9๏ธ) digit zero..digit nine
-00A9 ; Emoji # 1.1 [1] (ยฉ๏ธ) copyright
-00AE ; Emoji # 1.1 [1] (ยฎ๏ธ) registered
-203C ; Emoji # 1.1 [1] (โ€ผ๏ธ) double exclamation mark
-2049 ; Emoji # 3.0 [1] (โ‰๏ธ) exclamation question mark
-2122 ; Emoji # 1.1 [1] (โ„ข๏ธ) trade mark
-2139 ; Emoji # 3.0 [1] (โ„น๏ธ) information
-2194..2199 ; Emoji # 1.1 [6] (โ†”๏ธ..โ†™๏ธ) left-right arrow..down-left arrow
-21A9..21AA ; Emoji # 1.1 [2] (โ†ฉ๏ธ..โ†ช๏ธ) right arrow curving left..left arrow curving right
-231A..231B ; Emoji # 1.1 [2] (โŒš..โŒ›) watch..hourglass done
-2328 ; Emoji # 1.1 [1] (โŒจ๏ธ) keyboard
-23CF ; Emoji # 4.0 [1] (โ๏ธ) eject button
-23E9..23F3 ; Emoji # 6.0 [11] (โฉ..โณ) fast-forward button..hourglass not done
-23F8..23FA ; Emoji # 7.0 [3] (โธ๏ธ..โบ๏ธ) pause button..record button
-24C2 ; Emoji # 1.1 [1] (โ“‚๏ธ) circled M
-25AA..25AB ; Emoji # 1.1 [2] (โ–ช๏ธ..โ–ซ๏ธ) black small square..white small square
-25B6 ; Emoji # 1.1 [1] (โ–ถ๏ธ) play button
-25C0 ; Emoji # 1.1 [1] (โ—€๏ธ) reverse button
-25FB..25FE ; Emoji # 3.2 [4] (โ—ป๏ธ..โ—พ) white medium square..black medium-small square
-2600..2604 ; Emoji # 1.1 [5] (โ˜€๏ธ..โ˜„๏ธ) sun..comet
-260E ; Emoji # 1.1 [1] (โ˜Ž๏ธ) telephone
-2611 ; Emoji # 1.1 [1] (โ˜‘๏ธ) check box with check
-2614..2615 ; Emoji # 4.0 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
-2618 ; Emoji # 4.1 [1] (โ˜˜๏ธ) shamrock
-261D ; Emoji # 1.1 [1] (โ˜๏ธ) index pointing up
-2620 ; Emoji # 1.1 [1] (โ˜ ๏ธ) skull and crossbones
-2622..2623 ; Emoji # 1.1 [2] (โ˜ข๏ธ..โ˜ฃ๏ธ) radioactive..biohazard
-2626 ; Emoji # 1.1 [1] (โ˜ฆ๏ธ) orthodox cross
-262A ; Emoji # 1.1 [1] (โ˜ช๏ธ) star and crescent
-262E..262F ; Emoji # 1.1 [2] (โ˜ฎ๏ธ..โ˜ฏ๏ธ) peace symbol..yin yang
-2638..263A ; Emoji # 1.1 [3] (โ˜ธ๏ธ..โ˜บ๏ธ) wheel of dharma..smiling face
-2640 ; Emoji # 1.1 [1] (โ™€๏ธ) female sign
-2642 ; Emoji # 1.1 [1] (โ™‚๏ธ) male sign
-2648..2653 ; Emoji # 1.1 [12] (โ™ˆ..โ™“) Aries..Pisces
-265F..2660 ; Emoji # 1.1 [2] (โ™Ÿ๏ธ..โ™ ๏ธ) chess pawn..spade suit
-2663 ; Emoji # 1.1 [1] (โ™ฃ๏ธ) club suit
-2665..2666 ; Emoji # 1.1 [2] (โ™ฅ๏ธ..โ™ฆ๏ธ) heart suit..diamond suit
-2668 ; Emoji # 1.1 [1] (โ™จ๏ธ) hot springs
-267B ; Emoji # 3.2 [1] (โ™ป๏ธ) recycling symbol
-267E..267F ; Emoji # 4.1 [2] (โ™พ๏ธ..โ™ฟ) infinity..wheelchair symbol
-2692..2697 ; Emoji # 4.1 [6] (โš’๏ธ..โš—๏ธ) hammer and pick..alembic
-2699 ; Emoji # 4.1 [1] (โš™๏ธ) gear
-269B..269C ; Emoji # 4.1 [2] (โš›๏ธ..โšœ๏ธ) atom symbol..fleur-de-lis
-26A0..26A1 ; Emoji # 4.0 [2] (โš ๏ธ..โšก) warning..high voltage
-26AA..26AB ; Emoji # 4.1 [2] (โšช..โšซ) white circle..black circle
-26B0..26B1 ; Emoji # 4.1 [2] (โšฐ๏ธ..โšฑ๏ธ) coffin..funeral urn
-26BD..26BE ; Emoji # 5.2 [2] (โšฝ..โšพ) soccer ball..baseball
-26C4..26C5 ; Emoji # 5.2 [2] (โ›„..โ›…) snowman without snow..sun behind cloud
-26C8 ; Emoji # 5.2 [1] (โ›ˆ๏ธ) cloud with lightning and rain
-26CE ; Emoji # 6.0 [1] (โ›Ž) Ophiuchus
-26CF ; Emoji # 5.2 [1] (โ›๏ธ) pick
-26D1 ; Emoji # 5.2 [1] (โ›‘๏ธ) rescue workerโ€™s helmet
-26D3..26D4 ; Emoji # 5.2 [2] (โ›“๏ธ..โ›”) chains..no entry
-26E9..26EA ; Emoji # 5.2 [2] (โ›ฉ๏ธ..โ›ช) shinto shrine..church
-26F0..26F5 ; Emoji # 5.2 [6] (โ›ฐ๏ธ..โ›ต) mountain..sailboat
-26F7..26FA ; Emoji # 5.2 [4] (โ›ท๏ธ..โ›บ) skier..tent
-26FD ; Emoji # 5.2 [1] (โ›ฝ) fuel pump
-2702 ; Emoji # 1.1 [1] (โœ‚๏ธ) scissors
-2705 ; Emoji # 6.0 [1] (โœ…) check mark button
-2708..2709 ; Emoji # 1.1 [2] (โœˆ๏ธ..โœ‰๏ธ) airplane..envelope
-270A..270B ; Emoji # 6.0 [2] (โœŠ..โœ‹) raised fist..raised hand
-270C..270D ; Emoji # 1.1 [2] (โœŒ๏ธ..โœ๏ธ) victory hand..writing hand
-270F ; Emoji # 1.1 [1] (โœ๏ธ) pencil
-2712 ; Emoji # 1.1 [1] (โœ’๏ธ) black nib
-2714 ; Emoji # 1.1 [1] (โœ”๏ธ) check mark
-2716 ; Emoji # 1.1 [1] (โœ–๏ธ) multiplication sign
-271D ; Emoji # 1.1 [1] (โœ๏ธ) latin cross
-2721 ; Emoji # 1.1 [1] (โœก๏ธ) star of David
-2728 ; Emoji # 6.0 [1] (โœจ) sparkles
-2733..2734 ; Emoji # 1.1 [2] (โœณ๏ธ..โœด๏ธ) eight-spoked asterisk..eight-pointed star
-2744 ; Emoji # 1.1 [1] (โ„๏ธ) snowflake
-2747 ; Emoji # 1.1 [1] (โ‡๏ธ) sparkle
-274C ; Emoji # 6.0 [1] (โŒ) cross mark
-274E ; Emoji # 6.0 [1] (โŽ) cross mark button
-2753..2755 ; Emoji # 6.0 [3] (โ“..โ•) question mark..white exclamation mark
-2757 ; Emoji # 5.2 [1] (โ—) exclamation mark
-2763..2764 ; Emoji # 1.1 [2] (โฃ๏ธ..โค๏ธ) heart exclamation..red heart
-2795..2797 ; Emoji # 6.0 [3] (โž•..โž—) plus sign..division sign
-27A1 ; Emoji # 1.1 [1] (โžก๏ธ) right arrow
-27B0 ; Emoji # 6.0 [1] (โžฐ) curly loop
-27BF ; Emoji # 6.0 [1] (โžฟ) double curly loop
-2934..2935 ; Emoji # 3.2 [2] (โคด๏ธ..โคต๏ธ) right arrow curving up..right arrow curving down
-2B05..2B07 ; Emoji # 4.0 [3] (โฌ…๏ธ..โฌ‡๏ธ) left arrow..down arrow
-2B1B..2B1C ; Emoji # 5.1 [2] (โฌ›..โฌœ) black large square..white large square
-2B50 ; Emoji # 5.1 [1] (โญ) star
-2B55 ; Emoji # 5.2 [1] (โญ•) hollow red circle
-3030 ; Emoji # 1.1 [1] (ใ€ฐ๏ธ) wavy dash
-303D ; Emoji # 3.2 [1] (ใ€ฝ๏ธ) part alternation mark
-3297 ; Emoji # 1.1 [1] (ใŠ—๏ธ) Japanese โ€œcongratulationsโ€ button
-3299 ; Emoji # 1.1 [1] (ใŠ™๏ธ) Japanese โ€œsecretโ€ button
-1F004 ; Emoji # 5.1 [1] (๐Ÿ€„) mahjong red dragon
-1F0CF ; Emoji # 6.0 [1] (๐Ÿƒ) joker
-1F170..1F171 ; Emoji # 6.0 [2] (๐Ÿ…ฐ๏ธ..๐Ÿ…ฑ๏ธ) A button (blood type)..B button (blood type)
-1F17E ; Emoji # 6.0 [1] (๐Ÿ…พ๏ธ) O button (blood type)
-1F17F ; Emoji # 5.2 [1] (๐Ÿ…ฟ๏ธ) P button
-1F18E ; Emoji # 6.0 [1] (๐Ÿ†Ž) AB button (blood type)
-1F191..1F19A ; Emoji # 6.0 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
-1F1E6..1F1FF ; Emoji # 6.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
-1F201..1F202 ; Emoji # 6.0 [2] (๐Ÿˆ..๐Ÿˆ‚๏ธ) Japanese โ€œhereโ€ button..Japanese โ€œservice chargeโ€ button
-1F21A ; Emoji # 5.2 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
-1F22F ; Emoji # 5.2 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
-1F232..1F23A ; Emoji # 6.0 [9] (๐Ÿˆฒ..๐Ÿˆบ) Japanese โ€œprohibitedโ€ button..Japanese โ€œopen for businessโ€ button
-1F250..1F251 ; Emoji # 6.0 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
-1F300..1F320 ; Emoji # 6.0 [33] (๐ŸŒ€..๐ŸŒ ) cyclone..shooting star
-1F321 ; Emoji # 7.0 [1] (๐ŸŒก๏ธ) thermometer
-1F324..1F32C ; Emoji # 7.0 [9] (๐ŸŒค๏ธ..๐ŸŒฌ๏ธ) sun behind small cloud..wind face
-1F32D..1F32F ; Emoji # 8.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
-1F330..1F335 ; Emoji # 6.0 [6] (๐ŸŒฐ..๐ŸŒต) chestnut..cactus
-1F336 ; Emoji # 7.0 [1] (๐ŸŒถ๏ธ) hot pepper
-1F337..1F37C ; Emoji # 6.0 [70] (๐ŸŒท..๐Ÿผ) tulip..baby bottle
-1F37D ; Emoji # 7.0 [1] (๐Ÿฝ๏ธ) fork and knife with plate
-1F37E..1F37F ; Emoji # 8.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
-1F380..1F393 ; Emoji # 6.0 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
-1F396..1F397 ; Emoji # 7.0 [2] (๐ŸŽ–๏ธ..๐ŸŽ—๏ธ) military medal..reminder ribbon
-1F399..1F39B ; Emoji # 7.0 [3] (๐ŸŽ™๏ธ..๐ŸŽ›๏ธ) studio microphone..control knobs
-1F39E..1F39F ; Emoji # 7.0 [2] (๐ŸŽž๏ธ..๐ŸŽŸ๏ธ) film frames..admission tickets
-1F3A0..1F3C4 ; Emoji # 6.0 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
-1F3C5 ; Emoji # 7.0 [1] (๐Ÿ…) sports medal
-1F3C6..1F3CA ; Emoji # 6.0 [5] (๐Ÿ†..๐ŸŠ) trophy..person swimming
-1F3CB..1F3CE ; Emoji # 7.0 [4] (๐Ÿ‹๏ธ..๐ŸŽ๏ธ) person lifting weights..racing car
-1F3CF..1F3D3 ; Emoji # 8.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
-1F3D4..1F3DF ; Emoji # 7.0 [12] (๐Ÿ”๏ธ..๐ŸŸ๏ธ) snow-capped mountain..stadium
-1F3E0..1F3F0 ; Emoji # 6.0 [17] (๐Ÿ ..๐Ÿฐ) house..castle
-1F3F3..1F3F5 ; Emoji # 7.0 [3] (๐Ÿณ๏ธ..๐Ÿต๏ธ) white flag..rosette
-1F3F7 ; Emoji # 7.0 [1] (๐Ÿท๏ธ) label
-1F3F8..1F3FF ; Emoji # 8.0 [8] (๐Ÿธ..๐Ÿฟ) badminton..dark skin tone
-1F400..1F43E ; Emoji # 6.0 [63] (๐Ÿ€..๐Ÿพ) rat..paw prints
-1F43F ; Emoji # 7.0 [1] (๐Ÿฟ๏ธ) chipmunk
-1F440 ; Emoji # 6.0 [1] (๐Ÿ‘€) eyes
-1F441 ; Emoji # 7.0 [1] (๐Ÿ‘๏ธ) eye
-1F442..1F4F7 ; Emoji # 6.0[182] (๐Ÿ‘‚..๐Ÿ“ท) ear..camera
-1F4F8 ; Emoji # 7.0 [1] (๐Ÿ“ธ) camera with flash
-1F4F9..1F4FC ; Emoji # 6.0 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
-1F4FD ; Emoji # 7.0 [1] (๐Ÿ“ฝ๏ธ) film projector
-1F4FF ; Emoji # 8.0 [1] (๐Ÿ“ฟ) prayer beads
-1F500..1F53D ; Emoji # 6.0 [62] (๐Ÿ”€..๐Ÿ”ฝ) shuffle tracks button..downwards button
-1F549..1F54A ; Emoji # 7.0 [2] (๐Ÿ•‰๏ธ..๐Ÿ•Š๏ธ) om..dove
-1F54B..1F54E ; Emoji # 8.0 [4] (๐Ÿ•‹..๐Ÿ•Ž) kaaba..menorah
-1F550..1F567 ; Emoji # 6.0 [24] (๐Ÿ•..๐Ÿ•ง) one oโ€™clock..twelve-thirty
-1F56F..1F570 ; Emoji # 7.0 [2] (๐Ÿ•ฏ๏ธ..๐Ÿ•ฐ๏ธ) candle..mantelpiece clock
-1F573..1F579 ; Emoji # 7.0 [7] (๐Ÿ•ณ๏ธ..๐Ÿ•น๏ธ) hole..joystick
-1F57A ; Emoji # 9.0 [1] (๐Ÿ•บ) man dancing
-1F587 ; Emoji # 7.0 [1] (๐Ÿ–‡๏ธ) linked paperclips
-1F58A..1F58D ; Emoji # 7.0 [4] (๐Ÿ–Š๏ธ..๐Ÿ–๏ธ) pen..crayon
-1F590 ; Emoji # 7.0 [1] (๐Ÿ–๏ธ) hand with fingers splayed
-1F595..1F596 ; Emoji # 7.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
-1F5A4 ; Emoji # 9.0 [1] (๐Ÿ–ค) black heart
-1F5A5 ; Emoji # 7.0 [1] (๐Ÿ–ฅ๏ธ) desktop computer
-1F5A8 ; Emoji # 7.0 [1] (๐Ÿ–จ๏ธ) printer
-1F5B1..1F5B2 ; Emoji # 7.0 [2] (๐Ÿ–ฑ๏ธ..๐Ÿ–ฒ๏ธ) computer mouse..trackball
-1F5BC ; Emoji # 7.0 [1] (๐Ÿ–ผ๏ธ) framed picture
-1F5C2..1F5C4 ; Emoji # 7.0 [3] (๐Ÿ—‚๏ธ..๐Ÿ—„๏ธ) card index dividers..file cabinet
-1F5D1..1F5D3 ; Emoji # 7.0 [3] (๐Ÿ—‘๏ธ..๐Ÿ—“๏ธ) wastebasket..spiral calendar
-1F5DC..1F5DE ; Emoji # 7.0 [3] (๐Ÿ—œ๏ธ..๐Ÿ—ž๏ธ) clamp..rolled-up newspaper
-1F5E1 ; Emoji # 7.0 [1] (๐Ÿ—ก๏ธ) dagger
-1F5E3 ; Emoji # 7.0 [1] (๐Ÿ—ฃ๏ธ) speaking head
-1F5E8 ; Emoji # 7.0 [1] (๐Ÿ—จ๏ธ) left speech bubble
-1F5EF ; Emoji # 7.0 [1] (๐Ÿ—ฏ๏ธ) right anger bubble
-1F5F3 ; Emoji # 7.0 [1] (๐Ÿ—ณ๏ธ) ballot box with ballot
-1F5FA ; Emoji # 7.0 [1] (๐Ÿ—บ๏ธ) world map
-1F5FB..1F5FF ; Emoji # 6.0 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
-1F600 ; Emoji # 6.1 [1] (๐Ÿ˜€) grinning face
-1F601..1F610 ; Emoji # 6.0 [16] (๐Ÿ˜..๐Ÿ˜) beaming face with smiling eyes..neutral face
-1F611 ; Emoji # 6.1 [1] (๐Ÿ˜‘) expressionless face
-1F612..1F614 ; Emoji # 6.0 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
-1F615 ; Emoji # 6.1 [1] (๐Ÿ˜•) confused face
-1F616 ; Emoji # 6.0 [1] (๐Ÿ˜–) confounded face
-1F617 ; Emoji # 6.1 [1] (๐Ÿ˜—) kissing face
-1F618 ; Emoji # 6.0 [1] (๐Ÿ˜˜) face blowing a kiss
-1F619 ; Emoji # 6.1 [1] (๐Ÿ˜™) kissing face with smiling eyes
-1F61A ; Emoji # 6.0 [1] (๐Ÿ˜š) kissing face with closed eyes
-1F61B ; Emoji # 6.1 [1] (๐Ÿ˜›) face with tongue
-1F61C..1F61E ; Emoji # 6.0 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
-1F61F ; Emoji # 6.1 [1] (๐Ÿ˜Ÿ) worried face
-1F620..1F625 ; Emoji # 6.0 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
-1F626..1F627 ; Emoji # 6.1 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
-1F628..1F62B ; Emoji # 6.0 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
-1F62C ; Emoji # 6.1 [1] (๐Ÿ˜ฌ) grimacing face
-1F62D ; Emoji # 6.0 [1] (๐Ÿ˜ญ) loudly crying face
-1F62E..1F62F ; Emoji # 6.1 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
-1F630..1F633 ; Emoji # 6.0 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
-1F634 ; Emoji # 6.1 [1] (๐Ÿ˜ด) sleeping face
-1F635..1F640 ; Emoji # 6.0 [12] (๐Ÿ˜ต..๐Ÿ™€) dizzy face..weary cat
-1F641..1F642 ; Emoji # 7.0 [2] (๐Ÿ™..๐Ÿ™‚) slightly frowning face..slightly smiling face
-1F643..1F644 ; Emoji # 8.0 [2] (๐Ÿ™ƒ..๐Ÿ™„) upside-down face..face with rolling eyes
-1F645..1F64F ; Emoji # 6.0 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
-1F680..1F6C5 ; Emoji # 6.0 [70] (๐Ÿš€..๐Ÿ›…) rocket..left luggage
-1F6CB..1F6CF ; Emoji # 7.0 [5] (๐Ÿ›‹๏ธ..๐Ÿ›๏ธ) couch and lamp..bed
-1F6D0 ; Emoji # 8.0 [1] (๐Ÿ›) place of worship
-1F6D1..1F6D2 ; Emoji # 9.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
-1F6D5 ; Emoji # 12.0 [1] (๐Ÿ›•) hindu temple
-1F6E0..1F6E5 ; Emoji # 7.0 [6] (๐Ÿ› ๏ธ..๐Ÿ›ฅ๏ธ) hammer and wrench..motor boat
-1F6E9 ; Emoji # 7.0 [1] (๐Ÿ›ฉ๏ธ) small airplane
-1F6EB..1F6EC ; Emoji # 7.0 [2] (๐Ÿ›ซ..๐Ÿ›ฌ) airplane departure..airplane arrival
-1F6F0 ; Emoji # 7.0 [1] (๐Ÿ›ฐ๏ธ) satellite
-1F6F3 ; Emoji # 7.0 [1] (๐Ÿ›ณ๏ธ) passenger ship
-1F6F4..1F6F6 ; Emoji # 9.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
-1F6F7..1F6F8 ; Emoji # 10.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
-1F6F9 ; Emoji # 11.0 [1] (๐Ÿ›น) skateboard
-1F6FA ; Emoji # 12.0 [1] (๐Ÿ›บ) auto rickshaw
-1F7E0..1F7EB ; Emoji # 12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
-1F90D..1F90F ; Emoji # 12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
-1F910..1F918 ; Emoji # 8.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
-1F919..1F91E ; Emoji # 9.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
-1F91F ; Emoji # 10.0 [1] (๐ŸคŸ) love-you gesture
-1F920..1F927 ; Emoji # 9.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
-1F928..1F92F ; Emoji # 10.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
-1F930 ; Emoji # 9.0 [1] (๐Ÿคฐ) pregnant woman
-1F931..1F932 ; Emoji # 10.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
-1F933..1F93A ; Emoji # 9.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
-1F93C..1F93E ; Emoji # 9.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
-1F93F ; Emoji # 12.0 [1] (๐Ÿคฟ) diving mask
-1F940..1F945 ; Emoji # 9.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
-1F947..1F94B ; Emoji # 9.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
-1F94C ; Emoji # 10.0 [1] (๐ŸฅŒ) curling stone
-1F94D..1F94F ; Emoji # 11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
-1F950..1F95E ; Emoji # 9.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
-1F95F..1F96B ; Emoji # 10.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
-1F96C..1F970 ; Emoji # 11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
-1F971 ; Emoji # 12.0 [1] (๐Ÿฅฑ) yawning face
-1F973..1F976 ; Emoji # 11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
-1F97A ; Emoji # 11.0 [1] (๐Ÿฅบ) pleading face
-1F97B ; Emoji # 12.0 [1] (๐Ÿฅป) sari
-1F97C..1F97F ; Emoji # 11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
-1F980..1F984 ; Emoji # 8.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
-1F985..1F991 ; Emoji # 9.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
-1F992..1F997 ; Emoji # 10.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
-1F998..1F9A2 ; Emoji # 11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
-1F9A5..1F9AA ; Emoji # 12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
-1F9AE..1F9AF ; Emoji # 12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..probing cane
-1F9B0..1F9B9 ; Emoji # 11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
-1F9BA..1F9BF ; Emoji # 12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
-1F9C0 ; Emoji # 8.0 [1] (๐Ÿง€) cheese wedge
-1F9C1..1F9C2 ; Emoji # 11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
-1F9C3..1F9CA ; Emoji # 12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice cube
-1F9CD..1F9CF ; Emoji # 12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
-1F9D0..1F9E6 ; Emoji # 10.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
-1F9E7..1F9FF ; Emoji # 11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
-1FA70..1FA73 ; Emoji # 12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
-1FA78..1FA7A ; Emoji # 12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
-1FA80..1FA82 ; Emoji # 12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
-1FA90..1FA95 ; Emoji # 12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
+0023 ; Emoji # E0.0 [1] (#๏ธ) number sign
+002A ; Emoji # E0.0 [1] (*๏ธ) asterisk
+0030..0039 ; Emoji # E0.0 [10] (0๏ธ..9๏ธ) digit zero..digit nine
+00A9 ; Emoji # E0.6 [1] (ยฉ๏ธ) copyright
+00AE ; Emoji # E0.6 [1] (ยฎ๏ธ) registered
+203C ; Emoji # E0.6 [1] (โ€ผ๏ธ) double exclamation mark
+2049 ; Emoji # E0.6 [1] (โ‰๏ธ) exclamation question mark
+2122 ; Emoji # E0.6 [1] (โ„ข๏ธ) trade mark
+2139 ; Emoji # E0.6 [1] (โ„น๏ธ) information
+2194..2199 ; Emoji # E0.6 [6] (โ†”๏ธ..โ†™๏ธ) left-right arrow..down-left arrow
+21A9..21AA ; Emoji # E0.6 [2] (โ†ฉ๏ธ..โ†ช๏ธ) right arrow curving left..left arrow curving right
+231A..231B ; Emoji # E0.6 [2] (โŒš..โŒ›) watch..hourglass done
+2328 ; Emoji # E1.0 [1] (โŒจ๏ธ) keyboard
+23CF ; Emoji # E1.0 [1] (โ๏ธ) eject button
+23E9..23EC ; Emoji # E0.6 [4] (โฉ..โฌ) fast-forward button..fast down button
+23ED..23EE ; Emoji # E0.7 [2] (โญ๏ธ..โฎ๏ธ) next track button..last track button
+23EF ; Emoji # E1.0 [1] (โฏ๏ธ) play or pause button
+23F0 ; Emoji # E0.6 [1] (โฐ) alarm clock
+23F1..23F2 ; Emoji # E1.0 [2] (โฑ๏ธ..โฒ๏ธ) stopwatch..timer clock
+23F3 ; Emoji # E0.6 [1] (โณ) hourglass not done
+23F8..23FA ; Emoji # E0.7 [3] (โธ๏ธ..โบ๏ธ) pause button..record button
+24C2 ; Emoji # E0.6 [1] (โ“‚๏ธ) circled M
+25AA..25AB ; Emoji # E0.6 [2] (โ–ช๏ธ..โ–ซ๏ธ) black small square..white small square
+25B6 ; Emoji # E0.6 [1] (โ–ถ๏ธ) play button
+25C0 ; Emoji # E0.6 [1] (โ—€๏ธ) reverse button
+25FB..25FE ; Emoji # E0.6 [4] (โ—ป๏ธ..โ—พ) white medium square..black medium-small square
+2600..2601 ; Emoji # E0.6 [2] (โ˜€๏ธ..โ˜๏ธ) sun..cloud
+2602..2603 ; Emoji # E0.7 [2] (โ˜‚๏ธ..โ˜ƒ๏ธ) umbrella..snowman
+2604 ; Emoji # E1.0 [1] (โ˜„๏ธ) comet
+260E ; Emoji # E0.6 [1] (โ˜Ž๏ธ) telephone
+2611 ; Emoji # E0.6 [1] (โ˜‘๏ธ) check box with check
+2614..2615 ; Emoji # E0.6 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
+2618 ; Emoji # E1.0 [1] (โ˜˜๏ธ) shamrock
+261D ; Emoji # E0.6 [1] (โ˜๏ธ) index pointing up
+2620 ; Emoji # E1.0 [1] (โ˜ ๏ธ) skull and crossbones
+2622..2623 ; Emoji # E1.0 [2] (โ˜ข๏ธ..โ˜ฃ๏ธ) radioactive..biohazard
+2626 ; Emoji # E1.0 [1] (โ˜ฆ๏ธ) orthodox cross
+262A ; Emoji # E0.7 [1] (โ˜ช๏ธ) star and crescent
+262E ; Emoji # E1.0 [1] (โ˜ฎ๏ธ) peace symbol
+262F ; Emoji # E0.7 [1] (โ˜ฏ๏ธ) yin yang
+2638..2639 ; Emoji # E0.7 [2] (โ˜ธ๏ธ..โ˜น๏ธ) wheel of dharma..frowning face
+263A ; Emoji # E0.6 [1] (โ˜บ๏ธ) smiling face
+2640 ; Emoji # E4.0 [1] (โ™€๏ธ) female sign
+2642 ; Emoji # E4.0 [1] (โ™‚๏ธ) male sign
+2648..2653 ; Emoji # E0.6 [12] (โ™ˆ..โ™“) Aries..Pisces
+265F ; Emoji # E11.0 [1] (โ™Ÿ๏ธ) chess pawn
+2660 ; Emoji # E0.6 [1] (โ™ ๏ธ) spade suit
+2663 ; Emoji # E0.6 [1] (โ™ฃ๏ธ) club suit
+2665..2666 ; Emoji # E0.6 [2] (โ™ฅ๏ธ..โ™ฆ๏ธ) heart suit..diamond suit
+2668 ; Emoji # E0.6 [1] (โ™จ๏ธ) hot springs
+267B ; Emoji # E0.6 [1] (โ™ป๏ธ) recycling symbol
+267E ; Emoji # E11.0 [1] (โ™พ๏ธ) infinity
+267F ; Emoji # E0.6 [1] (โ™ฟ) wheelchair symbol
+2692 ; Emoji # E1.0 [1] (โš’๏ธ) hammer and pick
+2693 ; Emoji # E0.6 [1] (โš“) anchor
+2694 ; Emoji # E1.0 [1] (โš”๏ธ) crossed swords
+2695 ; Emoji # E4.0 [1] (โš•๏ธ) medical symbol
+2696..2697 ; Emoji # E1.0 [2] (โš–๏ธ..โš—๏ธ) balance scale..alembic
+2699 ; Emoji # E1.0 [1] (โš™๏ธ) gear
+269B..269C ; Emoji # E1.0 [2] (โš›๏ธ..โšœ๏ธ) atom symbol..fleur-de-lis
+26A0..26A1 ; Emoji # E0.6 [2] (โš ๏ธ..โšก) warning..high voltage
+26A7 ; Emoji # E13.0 [1] (โšง๏ธ) transgender symbol
+26AA..26AB ; Emoji # E0.6 [2] (โšช..โšซ) white circle..black circle
+26B0..26B1 ; Emoji # E1.0 [2] (โšฐ๏ธ..โšฑ๏ธ) coffin..funeral urn
+26BD..26BE ; Emoji # E0.6 [2] (โšฝ..โšพ) soccer ball..baseball
+26C4..26C5 ; Emoji # E0.6 [2] (โ›„..โ›…) snowman without snow..sun behind cloud
+26C8 ; Emoji # E0.7 [1] (โ›ˆ๏ธ) cloud with lightning and rain
+26CE ; Emoji # E0.6 [1] (โ›Ž) Ophiuchus
+26CF ; Emoji # E0.7 [1] (โ›๏ธ) pick
+26D1 ; Emoji # E0.7 [1] (โ›‘๏ธ) rescue workerโ€™s helmet
+26D3 ; Emoji # E0.7 [1] (โ›“๏ธ) chains
+26D4 ; Emoji # E0.6 [1] (โ›”) no entry
+26E9 ; Emoji # E0.7 [1] (โ›ฉ๏ธ) shinto shrine
+26EA ; Emoji # E0.6 [1] (โ›ช) church
+26F0..26F1 ; Emoji # E0.7 [2] (โ›ฐ๏ธ..โ›ฑ๏ธ) mountain..umbrella on ground
+26F2..26F3 ; Emoji # E0.6 [2] (โ›ฒ..โ›ณ) fountain..flag in hole
+26F4 ; Emoji # E0.7 [1] (โ›ด๏ธ) ferry
+26F5 ; Emoji # E0.6 [1] (โ›ต) sailboat
+26F7..26F9 ; Emoji # E0.7 [3] (โ›ท๏ธ..โ›น๏ธ) skier..person bouncing ball
+26FA ; Emoji # E0.6 [1] (โ›บ) tent
+26FD ; Emoji # E0.6 [1] (โ›ฝ) fuel pump
+2702 ; Emoji # E0.6 [1] (โœ‚๏ธ) scissors
+2705 ; Emoji # E0.6 [1] (โœ…) check mark button
+2708..270C ; Emoji # E0.6 [5] (โœˆ๏ธ..โœŒ๏ธ) airplane..victory hand
+270D ; Emoji # E0.7 [1] (โœ๏ธ) writing hand
+270F ; Emoji # E0.6 [1] (โœ๏ธ) pencil
+2712 ; Emoji # E0.6 [1] (โœ’๏ธ) black nib
+2714 ; Emoji # E0.6 [1] (โœ”๏ธ) check mark
+2716 ; Emoji # E0.6 [1] (โœ–๏ธ) multiply
+271D ; Emoji # E0.7 [1] (โœ๏ธ) latin cross
+2721 ; Emoji # E0.7 [1] (โœก๏ธ) star of David
+2728 ; Emoji # E0.6 [1] (โœจ) sparkles
+2733..2734 ; Emoji # E0.6 [2] (โœณ๏ธ..โœด๏ธ) eight-spoked asterisk..eight-pointed star
+2744 ; Emoji # E0.6 [1] (โ„๏ธ) snowflake
+2747 ; Emoji # E0.6 [1] (โ‡๏ธ) sparkle
+274C ; Emoji # E0.6 [1] (โŒ) cross mark
+274E ; Emoji # E0.6 [1] (โŽ) cross mark button
+2753..2755 ; Emoji # E0.6 [3] (โ“..โ•) question mark..white exclamation mark
+2757 ; Emoji # E0.6 [1] (โ—) exclamation mark
+2763 ; Emoji # E1.0 [1] (โฃ๏ธ) heart exclamation
+2764 ; Emoji # E0.6 [1] (โค๏ธ) red heart
+2795..2797 ; Emoji # E0.6 [3] (โž•..โž—) plus..divide
+27A1 ; Emoji # E0.6 [1] (โžก๏ธ) right arrow
+27B0 ; Emoji # E0.6 [1] (โžฐ) curly loop
+27BF ; Emoji # E1.0 [1] (โžฟ) double curly loop
+2934..2935 ; Emoji # E0.6 [2] (โคด๏ธ..โคต๏ธ) right arrow curving up..right arrow curving down
+2B05..2B07 ; Emoji # E0.6 [3] (โฌ…๏ธ..โฌ‡๏ธ) left arrow..down arrow
+2B1B..2B1C ; Emoji # E0.6 [2] (โฌ›..โฌœ) black large square..white large square
+2B50 ; Emoji # E0.6 [1] (โญ) star
+2B55 ; Emoji # E0.6 [1] (โญ•) hollow red circle
+3030 ; Emoji # E0.6 [1] (ใ€ฐ๏ธ) wavy dash
+303D ; Emoji # E0.6 [1] (ใ€ฝ๏ธ) part alternation mark
+3297 ; Emoji # E0.6 [1] (ใŠ—๏ธ) Japanese โ€œcongratulationsโ€ button
+3299 ; Emoji # E0.6 [1] (ใŠ™๏ธ) Japanese โ€œsecretโ€ button
+1F004 ; Emoji # E0.6 [1] (๐Ÿ€„) mahjong red dragon
+1F0CF ; Emoji # E0.6 [1] (๐Ÿƒ) joker
+1F170..1F171 ; Emoji # E0.6 [2] (๐Ÿ…ฐ๏ธ..๐Ÿ…ฑ๏ธ) A button (blood type)..B button (blood type)
+1F17E..1F17F ; Emoji # E0.6 [2] (๐Ÿ…พ๏ธ..๐Ÿ…ฟ๏ธ) O button (blood type)..P button
+1F18E ; Emoji # E0.6 [1] (๐Ÿ†Ž) AB button (blood type)
+1F191..1F19A ; Emoji # E0.6 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
+1F1E6..1F1FF ; Emoji # E0.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
+1F201..1F202 ; Emoji # E0.6 [2] (๐Ÿˆ..๐Ÿˆ‚๏ธ) Japanese โ€œhereโ€ button..Japanese โ€œservice chargeโ€ button
+1F21A ; Emoji # E0.6 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
+1F22F ; Emoji # E0.6 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
+1F232..1F23A ; Emoji # E0.6 [9] (๐Ÿˆฒ..๐Ÿˆบ) Japanese โ€œprohibitedโ€ button..Japanese โ€œopen for businessโ€ button
+1F250..1F251 ; Emoji # E0.6 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
+1F300..1F30C ; Emoji # E0.6 [13] (๐ŸŒ€..๐ŸŒŒ) cyclone..milky way
+1F30D..1F30E ; Emoji # E0.7 [2] (๐ŸŒ..๐ŸŒŽ) globe showing Europe-Africa..globe showing Americas
+1F30F ; Emoji # E0.6 [1] (๐ŸŒ) globe showing Asia-Australia
+1F310 ; Emoji # E1.0 [1] (๐ŸŒ) globe with meridians
+1F311 ; Emoji # E0.6 [1] (๐ŸŒ‘) new moon
+1F312 ; Emoji # E1.0 [1] (๐ŸŒ’) waxing crescent moon
+1F313..1F315 ; Emoji # E0.6 [3] (๐ŸŒ“..๐ŸŒ•) first quarter moon..full moon
+1F316..1F318 ; Emoji # E1.0 [3] (๐ŸŒ–..๐ŸŒ˜) waning gibbous moon..waning crescent moon
+1F319 ; Emoji # E0.6 [1] (๐ŸŒ™) crescent moon
+1F31A ; Emoji # E1.0 [1] (๐ŸŒš) new moon face
+1F31B ; Emoji # E0.6 [1] (๐ŸŒ›) first quarter moon face
+1F31C ; Emoji # E0.7 [1] (๐ŸŒœ) last quarter moon face
+1F31D..1F31E ; Emoji # E1.0 [2] (๐ŸŒ..๐ŸŒž) full moon face..sun with face
+1F31F..1F320 ; Emoji # E0.6 [2] (๐ŸŒŸ..๐ŸŒ ) glowing star..shooting star
+1F321 ; Emoji # E0.7 [1] (๐ŸŒก๏ธ) thermometer
+1F324..1F32C ; Emoji # E0.7 [9] (๐ŸŒค๏ธ..๐ŸŒฌ๏ธ) sun behind small cloud..wind face
+1F32D..1F32F ; Emoji # E1.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
+1F330..1F331 ; Emoji # E0.6 [2] (๐ŸŒฐ..๐ŸŒฑ) chestnut..seedling
+1F332..1F333 ; Emoji # E1.0 [2] (๐ŸŒฒ..๐ŸŒณ) evergreen tree..deciduous tree
+1F334..1F335 ; Emoji # E0.6 [2] (๐ŸŒด..๐ŸŒต) palm tree..cactus
+1F336 ; Emoji # E0.7 [1] (๐ŸŒถ๏ธ) hot pepper
+1F337..1F34A ; Emoji # E0.6 [20] (๐ŸŒท..๐ŸŠ) tulip..tangerine
+1F34B ; Emoji # E1.0 [1] (๐Ÿ‹) lemon
+1F34C..1F34F ; Emoji # E0.6 [4] (๐ŸŒ..๐Ÿ) banana..green apple
+1F350 ; Emoji # E1.0 [1] (๐Ÿ) pear
+1F351..1F37B ; Emoji # E0.6 [43] (๐Ÿ‘..๐Ÿป) peach..clinking beer mugs
+1F37C ; Emoji # E1.0 [1] (๐Ÿผ) baby bottle
+1F37D ; Emoji # E0.7 [1] (๐Ÿฝ๏ธ) fork and knife with plate
+1F37E..1F37F ; Emoji # E1.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji # E0.6 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
+1F396..1F397 ; Emoji # E0.7 [2] (๐ŸŽ–๏ธ..๐ŸŽ—๏ธ) military medal..reminder ribbon
+1F399..1F39B ; Emoji # E0.7 [3] (๐ŸŽ™๏ธ..๐ŸŽ›๏ธ) studio microphone..control knobs
+1F39E..1F39F ; Emoji # E0.7 [2] (๐ŸŽž๏ธ..๐ŸŽŸ๏ธ) film frames..admission tickets
+1F3A0..1F3C4 ; Emoji # E0.6 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
+1F3C5 ; Emoji # E1.0 [1] (๐Ÿ…) sports medal
+1F3C6 ; Emoji # E0.6 [1] (๐Ÿ†) trophy
+1F3C7 ; Emoji # E1.0 [1] (๐Ÿ‡) horse racing
+1F3C8 ; Emoji # E0.6 [1] (๐Ÿˆ) american football
+1F3C9 ; Emoji # E1.0 [1] (๐Ÿ‰) rugby football
+1F3CA ; Emoji # E0.6 [1] (๐ŸŠ) person swimming
+1F3CB..1F3CE ; Emoji # E0.7 [4] (๐Ÿ‹๏ธ..๐ŸŽ๏ธ) person lifting weights..racing car
+1F3CF..1F3D3 ; Emoji # E1.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
+1F3D4..1F3DF ; Emoji # E0.7 [12] (๐Ÿ”๏ธ..๐ŸŸ๏ธ) snow-capped mountain..stadium
+1F3E0..1F3E3 ; Emoji # E0.6 [4] (๐Ÿ ..๐Ÿฃ) house..Japanese post office
+1F3E4 ; Emoji # E1.0 [1] (๐Ÿค) post office
+1F3E5..1F3F0 ; Emoji # E0.6 [12] (๐Ÿฅ..๐Ÿฐ) hospital..castle
+1F3F3 ; Emoji # E0.7 [1] (๐Ÿณ๏ธ) white flag
+1F3F4 ; Emoji # E1.0 [1] (๐Ÿด) black flag
+1F3F5 ; Emoji # E0.7 [1] (๐Ÿต๏ธ) rosette
+1F3F7 ; Emoji # E0.7 [1] (๐Ÿท๏ธ) label
+1F3F8..1F407 ; Emoji # E1.0 [16] (๐Ÿธ..๐Ÿ‡) badminton..rabbit
+1F408 ; Emoji # E0.7 [1] (๐Ÿˆ) cat
+1F409..1F40B ; Emoji # E1.0 [3] (๐Ÿ‰..๐Ÿ‹) dragon..whale
+1F40C..1F40E ; Emoji # E0.6 [3] (๐ŸŒ..๐ŸŽ) snail..horse
+1F40F..1F410 ; Emoji # E1.0 [2] (๐Ÿ..๐Ÿ) ram..goat
+1F411..1F412 ; Emoji # E0.6 [2] (๐Ÿ‘..๐Ÿ’) ewe..monkey
+1F413 ; Emoji # E1.0 [1] (๐Ÿ“) rooster
+1F414 ; Emoji # E0.6 [1] (๐Ÿ”) chicken
+1F415 ; Emoji # E0.7 [1] (๐Ÿ•) dog
+1F416 ; Emoji # E1.0 [1] (๐Ÿ–) pig
+1F417..1F429 ; Emoji # E0.6 [19] (๐Ÿ—..๐Ÿฉ) boar..poodle
+1F42A ; Emoji # E1.0 [1] (๐Ÿช) camel
+1F42B..1F43E ; Emoji # E0.6 [20] (๐Ÿซ..๐Ÿพ) two-hump camel..paw prints
+1F43F ; Emoji # E0.7 [1] (๐Ÿฟ๏ธ) chipmunk
+1F440 ; Emoji # E0.6 [1] (๐Ÿ‘€) eyes
+1F441 ; Emoji # E0.7 [1] (๐Ÿ‘๏ธ) eye
+1F442..1F464 ; Emoji # E0.6 [35] (๐Ÿ‘‚..๐Ÿ‘ค) ear..bust in silhouette
+1F465 ; Emoji # E1.0 [1] (๐Ÿ‘ฅ) busts in silhouette
+1F466..1F46B ; Emoji # E0.6 [6] (๐Ÿ‘ฆ..๐Ÿ‘ซ) boy..woman and man holding hands
+1F46C..1F46D ; Emoji # E1.0 [2] (๐Ÿ‘ฌ..๐Ÿ‘ญ) men holding hands..women holding hands
+1F46E..1F4AC ; Emoji # E0.6 [63] (๐Ÿ‘ฎ..๐Ÿ’ฌ) police officer..speech balloon
+1F4AD ; Emoji # E1.0 [1] (๐Ÿ’ญ) thought balloon
+1F4AE..1F4B5 ; Emoji # E0.6 [8] (๐Ÿ’ฎ..๐Ÿ’ต) white flower..dollar banknote
+1F4B6..1F4B7 ; Emoji # E1.0 [2] (๐Ÿ’ถ..๐Ÿ’ท) euro banknote..pound banknote
+1F4B8..1F4EB ; Emoji # E0.6 [52] (๐Ÿ’ธ..๐Ÿ“ซ) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Emoji # E0.7 [2] (๐Ÿ“ฌ..๐Ÿ“ญ) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Emoji # E0.6 [1] (๐Ÿ“ฎ) postbox
+1F4EF ; Emoji # E1.0 [1] (๐Ÿ“ฏ) postal horn
+1F4F0..1F4F4 ; Emoji # E0.6 [5] (๐Ÿ“ฐ..๐Ÿ“ด) newspaper..mobile phone off
+1F4F5 ; Emoji # E1.0 [1] (๐Ÿ“ต) no mobile phones
+1F4F6..1F4F7 ; Emoji # E0.6 [2] (๐Ÿ“ถ..๐Ÿ“ท) antenna bars..camera
+1F4F8 ; Emoji # E1.0 [1] (๐Ÿ“ธ) camera with flash
+1F4F9..1F4FC ; Emoji # E0.6 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
+1F4FD ; Emoji # E0.7 [1] (๐Ÿ“ฝ๏ธ) film projector
+1F4FF..1F502 ; Emoji # E1.0 [4] (๐Ÿ“ฟ..๐Ÿ”‚) prayer beads..repeat single button
+1F503 ; Emoji # E0.6 [1] (๐Ÿ”ƒ) clockwise vertical arrows
+1F504..1F507 ; Emoji # E1.0 [4] (๐Ÿ”„..๐Ÿ”‡) counterclockwise arrows button..muted speaker
+1F508 ; Emoji # E0.7 [1] (๐Ÿ”ˆ) speaker low volume
+1F509 ; Emoji # E1.0 [1] (๐Ÿ”‰) speaker medium volume
+1F50A..1F514 ; Emoji # E0.6 [11] (๐Ÿ”Š..๐Ÿ””) speaker high volume..bell
+1F515 ; Emoji # E1.0 [1] (๐Ÿ”•) bell with slash
+1F516..1F52B ; Emoji # E0.6 [22] (๐Ÿ”–..๐Ÿ”ซ) bookmark..pistol
+1F52C..1F52D ; Emoji # E1.0 [2] (๐Ÿ”ฌ..๐Ÿ”ญ) microscope..telescope
+1F52E..1F53D ; Emoji # E0.6 [16] (๐Ÿ”ฎ..๐Ÿ”ฝ) crystal ball..downwards button
+1F549..1F54A ; Emoji # E0.7 [2] (๐Ÿ•‰๏ธ..๐Ÿ•Š๏ธ) om..dove
+1F54B..1F54E ; Emoji # E1.0 [4] (๐Ÿ•‹..๐Ÿ•Ž) kaaba..menorah
+1F550..1F55B ; Emoji # E0.6 [12] (๐Ÿ•..๐Ÿ•›) one oโ€™clock..twelve oโ€™clock
+1F55C..1F567 ; Emoji # E0.7 [12] (๐Ÿ•œ..๐Ÿ•ง) one-thirty..twelve-thirty
+1F56F..1F570 ; Emoji # E0.7 [2] (๐Ÿ•ฏ๏ธ..๐Ÿ•ฐ๏ธ) candle..mantelpiece clock
+1F573..1F579 ; Emoji # E0.7 [7] (๐Ÿ•ณ๏ธ..๐Ÿ•น๏ธ) hole..joystick
+1F57A ; Emoji # E3.0 [1] (๐Ÿ•บ) man dancing
+1F587 ; Emoji # E0.7 [1] (๐Ÿ–‡๏ธ) linked paperclips
+1F58A..1F58D ; Emoji # E0.7 [4] (๐Ÿ–Š๏ธ..๐Ÿ–๏ธ) pen..crayon
+1F590 ; Emoji # E0.7 [1] (๐Ÿ–๏ธ) hand with fingers splayed
+1F595..1F596 ; Emoji # E1.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
+1F5A4 ; Emoji # E3.0 [1] (๐Ÿ–ค) black heart
+1F5A5 ; Emoji # E0.7 [1] (๐Ÿ–ฅ๏ธ) desktop computer
+1F5A8 ; Emoji # E0.7 [1] (๐Ÿ–จ๏ธ) printer
+1F5B1..1F5B2 ; Emoji # E0.7 [2] (๐Ÿ–ฑ๏ธ..๐Ÿ–ฒ๏ธ) computer mouse..trackball
+1F5BC ; Emoji # E0.7 [1] (๐Ÿ–ผ๏ธ) framed picture
+1F5C2..1F5C4 ; Emoji # E0.7 [3] (๐Ÿ—‚๏ธ..๐Ÿ—„๏ธ) card index dividers..file cabinet
+1F5D1..1F5D3 ; Emoji # E0.7 [3] (๐Ÿ—‘๏ธ..๐Ÿ—“๏ธ) wastebasket..spiral calendar
+1F5DC..1F5DE ; Emoji # E0.7 [3] (๐Ÿ—œ๏ธ..๐Ÿ—ž๏ธ) clamp..rolled-up newspaper
+1F5E1 ; Emoji # E0.7 [1] (๐Ÿ—ก๏ธ) dagger
+1F5E3 ; Emoji # E0.7 [1] (๐Ÿ—ฃ๏ธ) speaking head
+1F5E8 ; Emoji # E2.0 [1] (๐Ÿ—จ๏ธ) left speech bubble
+1F5EF ; Emoji # E0.7 [1] (๐Ÿ—ฏ๏ธ) right anger bubble
+1F5F3 ; Emoji # E0.7 [1] (๐Ÿ—ณ๏ธ) ballot box with ballot
+1F5FA ; Emoji # E0.7 [1] (๐Ÿ—บ๏ธ) world map
+1F5FB..1F5FF ; Emoji # E0.6 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
+1F600 ; Emoji # E1.0 [1] (๐Ÿ˜€) grinning face
+1F601..1F606 ; Emoji # E0.6 [6] (๐Ÿ˜..๐Ÿ˜†) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Emoji # E1.0 [2] (๐Ÿ˜‡..๐Ÿ˜ˆ) smiling face with halo..smiling face with horns
+1F609..1F60D ; Emoji # E0.6 [5] (๐Ÿ˜‰..๐Ÿ˜) winking face..smiling face with heart-eyes
+1F60E ; Emoji # E1.0 [1] (๐Ÿ˜Ž) smiling face with sunglasses
+1F60F ; Emoji # E0.6 [1] (๐Ÿ˜) smirking face
+1F610 ; Emoji # E0.7 [1] (๐Ÿ˜) neutral face
+1F611 ; Emoji # E1.0 [1] (๐Ÿ˜‘) expressionless face
+1F612..1F614 ; Emoji # E0.6 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
+1F615 ; Emoji # E1.0 [1] (๐Ÿ˜•) confused face
+1F616 ; Emoji # E0.6 [1] (๐Ÿ˜–) confounded face
+1F617 ; Emoji # E1.0 [1] (๐Ÿ˜—) kissing face
+1F618 ; Emoji # E0.6 [1] (๐Ÿ˜˜) face blowing a kiss
+1F619 ; Emoji # E1.0 [1] (๐Ÿ˜™) kissing face with smiling eyes
+1F61A ; Emoji # E0.6 [1] (๐Ÿ˜š) kissing face with closed eyes
+1F61B ; Emoji # E1.0 [1] (๐Ÿ˜›) face with tongue
+1F61C..1F61E ; Emoji # E0.6 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
+1F61F ; Emoji # E1.0 [1] (๐Ÿ˜Ÿ) worried face
+1F620..1F625 ; Emoji # E0.6 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
+1F626..1F627 ; Emoji # E1.0 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji # E0.6 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
+1F62C ; Emoji # E1.0 [1] (๐Ÿ˜ฌ) grimacing face
+1F62D ; Emoji # E0.6 [1] (๐Ÿ˜ญ) loudly crying face
+1F62E..1F62F ; Emoji # E1.0 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
+1F630..1F633 ; Emoji # E0.6 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
+1F634 ; Emoji # E1.0 [1] (๐Ÿ˜ด) sleeping face
+1F635 ; Emoji # E0.6 [1] (๐Ÿ˜ต) dizzy face
+1F636 ; Emoji # E1.0 [1] (๐Ÿ˜ถ) face without mouth
+1F637..1F640 ; Emoji # E0.6 [10] (๐Ÿ˜ท..๐Ÿ™€) face with medical mask..weary cat
+1F641..1F644 ; Emoji # E1.0 [4] (๐Ÿ™..๐Ÿ™„) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Emoji # E0.6 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
+1F680 ; Emoji # E0.6 [1] (๐Ÿš€) rocket
+1F681..1F682 ; Emoji # E1.0 [2] (๐Ÿš..๐Ÿš‚) helicopter..locomotive
+1F683..1F685 ; Emoji # E0.6 [3] (๐Ÿšƒ..๐Ÿš…) railway car..bullet train
+1F686 ; Emoji # E1.0 [1] (๐Ÿš†) train
+1F687 ; Emoji # E0.6 [1] (๐Ÿš‡) metro
+1F688 ; Emoji # E1.0 [1] (๐Ÿšˆ) light rail
+1F689 ; Emoji # E0.6 [1] (๐Ÿš‰) station
+1F68A..1F68B ; Emoji # E1.0 [2] (๐ŸšŠ..๐Ÿš‹) tram..tram car
+1F68C ; Emoji # E0.6 [1] (๐ŸšŒ) bus
+1F68D ; Emoji # E0.7 [1] (๐Ÿš) oncoming bus
+1F68E ; Emoji # E1.0 [1] (๐ŸšŽ) trolleybus
+1F68F ; Emoji # E0.6 [1] (๐Ÿš) bus stop
+1F690 ; Emoji # E1.0 [1] (๐Ÿš) minibus
+1F691..1F693 ; Emoji # E0.6 [3] (๐Ÿš‘..๐Ÿš“) ambulance..police car
+1F694 ; Emoji # E0.7 [1] (๐Ÿš”) oncoming police car
+1F695 ; Emoji # E0.6 [1] (๐Ÿš•) taxi
+1F696 ; Emoji # E1.0 [1] (๐Ÿš–) oncoming taxi
+1F697 ; Emoji # E0.6 [1] (๐Ÿš—) automobile
+1F698 ; Emoji # E0.7 [1] (๐Ÿš˜) oncoming automobile
+1F699..1F69A ; Emoji # E0.6 [2] (๐Ÿš™..๐Ÿšš) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Emoji # E1.0 [7] (๐Ÿš›..๐Ÿšก) articulated lorry..aerial tramway
+1F6A2 ; Emoji # E0.6 [1] (๐Ÿšข) ship
+1F6A3 ; Emoji # E1.0 [1] (๐Ÿšฃ) person rowing boat
+1F6A4..1F6A5 ; Emoji # E0.6 [2] (๐Ÿšค..๐Ÿšฅ) speedboat..horizontal traffic light
+1F6A6 ; Emoji # E1.0 [1] (๐Ÿšฆ) vertical traffic light
+1F6A7..1F6AD ; Emoji # E0.6 [7] (๐Ÿšง..๐Ÿšญ) construction..no smoking
+1F6AE..1F6B1 ; Emoji # E1.0 [4] (๐Ÿšฎ..๐Ÿšฑ) litter in bin sign..non-potable water
+1F6B2 ; Emoji # E0.6 [1] (๐Ÿšฒ) bicycle
+1F6B3..1F6B5 ; Emoji # E1.0 [3] (๐Ÿšณ..๐Ÿšต) no bicycles..person mountain biking
+1F6B6 ; Emoji # E0.6 [1] (๐Ÿšถ) person walking
+1F6B7..1F6B8 ; Emoji # E1.0 [2] (๐Ÿšท..๐Ÿšธ) no pedestrians..children crossing
+1F6B9..1F6BE ; Emoji # E0.6 [6] (๐Ÿšน..๐Ÿšพ) menโ€™s room..water closet
+1F6BF ; Emoji # E1.0 [1] (๐Ÿšฟ) shower
+1F6C0 ; Emoji # E0.6 [1] (๐Ÿ›€) person taking bath
+1F6C1..1F6C5 ; Emoji # E1.0 [5] (๐Ÿ›..๐Ÿ›…) bathtub..left luggage
+1F6CB ; Emoji # E0.7 [1] (๐Ÿ›‹๏ธ) couch and lamp
+1F6CC ; Emoji # E1.0 [1] (๐Ÿ›Œ) person in bed
+1F6CD..1F6CF ; Emoji # E0.7 [3] (๐Ÿ›๏ธ..๐Ÿ›๏ธ) shopping bags..bed
+1F6D0 ; Emoji # E1.0 [1] (๐Ÿ›) place of worship
+1F6D1..1F6D2 ; Emoji # E3.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
+1F6D5 ; Emoji # E12.0 [1] (๐Ÿ›•) hindu temple
+1F6D6..1F6D7 ; Emoji # E13.0 [2] (๐Ÿ›–..๐Ÿ›—) hut..elevator
+1F6E0..1F6E5 ; Emoji # E0.7 [6] (๐Ÿ› ๏ธ..๐Ÿ›ฅ๏ธ) hammer and wrench..motor boat
+1F6E9 ; Emoji # E0.7 [1] (๐Ÿ›ฉ๏ธ) small airplane
+1F6EB..1F6EC ; Emoji # E1.0 [2] (๐Ÿ›ซ..๐Ÿ›ฌ) airplane departure..airplane arrival
+1F6F0 ; Emoji # E0.7 [1] (๐Ÿ›ฐ๏ธ) satellite
+1F6F3 ; Emoji # E0.7 [1] (๐Ÿ›ณ๏ธ) passenger ship
+1F6F4..1F6F6 ; Emoji # E3.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji # E5.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
+1F6F9 ; Emoji # E11.0 [1] (๐Ÿ›น) skateboard
+1F6FA ; Emoji # E12.0 [1] (๐Ÿ›บ) auto rickshaw
+1F6FB..1F6FC ; Emoji # E13.0 [2] (๐Ÿ›ป..๐Ÿ›ผ) pickup truck..roller skate
+1F7E0..1F7EB ; Emoji # E12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
+1F90C ; Emoji # E13.0 [1] (๐ŸคŒ) pinched fingers
+1F90D..1F90F ; Emoji # E12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
+1F910..1F918 ; Emoji # E1.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji # E3.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
+1F91F ; Emoji # E5.0 [1] (๐ŸคŸ) love-you gesture
+1F920..1F927 ; Emoji # E3.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji # E5.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
+1F930 ; Emoji # E3.0 [1] (๐Ÿคฐ) pregnant woman
+1F931..1F932 ; Emoji # E5.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
+1F933..1F93A ; Emoji # E3.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
+1F93C..1F93E ; Emoji # E3.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
+1F93F ; Emoji # E12.0 [1] (๐Ÿคฟ) diving mask
+1F940..1F945 ; Emoji # E3.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
+1F947..1F94B ; Emoji # E3.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
+1F94C ; Emoji # E5.0 [1] (๐ŸฅŒ) curling stone
+1F94D..1F94F ; Emoji # E11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
+1F950..1F95E ; Emoji # E3.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
+1F95F..1F96B ; Emoji # E5.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
+1F96C..1F970 ; Emoji # E11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
+1F971 ; Emoji # E12.0 [1] (๐Ÿฅฑ) yawning face
+1F972 ; Emoji # E13.0 [1] (๐Ÿฅฒ) smiling face with tear
+1F973..1F976 ; Emoji # E11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
+1F977..1F978 ; Emoji # E13.0 [2] (๐Ÿฅท..๐Ÿฅธ) ninja..disguised face
+1F97A ; Emoji # E11.0 [1] (๐Ÿฅบ) pleading face
+1F97B ; Emoji # E12.0 [1] (๐Ÿฅป) sari
+1F97C..1F97F ; Emoji # E11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
+1F980..1F984 ; Emoji # E1.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
+1F985..1F991 ; Emoji # E3.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
+1F992..1F997 ; Emoji # E5.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
+1F998..1F9A2 ; Emoji # E11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
+1F9A3..1F9A4 ; Emoji # E13.0 [2] (๐Ÿฆฃ..๐Ÿฆค) mammoth..dodo
+1F9A5..1F9AA ; Emoji # E12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
+1F9AB..1F9AD ; Emoji # E13.0 [3] (๐Ÿฆซ..๐Ÿฆญ) beaver..seal
+1F9AE..1F9AF ; Emoji # E12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..white cane
+1F9B0..1F9B9 ; Emoji # E11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
+1F9BA..1F9BF ; Emoji # E12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
+1F9C0 ; Emoji # E1.0 [1] (๐Ÿง€) cheese wedge
+1F9C1..1F9C2 ; Emoji # E11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
+1F9C3..1F9CA ; Emoji # E12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice
+1F9CB ; Emoji # E13.0 [1] (๐Ÿง‹) bubble tea
+1F9CD..1F9CF ; Emoji # E12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
+1F9D0..1F9E6 ; Emoji # E5.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
+1F9E7..1F9FF ; Emoji # E11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
+1FA70..1FA73 ; Emoji # E12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
+1FA74 ; Emoji # E13.0 [1] (๐Ÿฉด) thong sandal
+1FA78..1FA7A ; Emoji # E12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
+1FA80..1FA82 ; Emoji # E12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
+1FA83..1FA86 ; Emoji # E13.0 [4] (๐Ÿชƒ..๐Ÿช†) boomerang..nesting dolls
+1FA90..1FA95 ; Emoji # E12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
+1FA96..1FAA8 ; Emoji # E13.0 [19] (๐Ÿช–..๐Ÿชจ) military helmet..rock
+1FAB0..1FAB6 ; Emoji # E13.0 [7] (๐Ÿชฐ..๐Ÿชถ) fly..feather
+1FAC0..1FAC2 ; Emoji # E13.0 [3] (๐Ÿซ€..๐Ÿซ‚) anatomical heart..people hugging
+1FAD0..1FAD6 ; Emoji # E13.0 [7] (๐Ÿซ..๐Ÿซ–) blueberries..teapot
-# Total elements: 1311
+# Total elements: 1367
# ================================================
# All omitted code points have Emoji_Presentation=No
# @missing: 0000..10FFFF ; Emoji_Presentation ; No
-231A..231B ; Emoji_Presentation # 1.1 [2] (โŒš..โŒ›) watch..hourglass done
-23E9..23EC ; Emoji_Presentation # 6.0 [4] (โฉ..โฌ) fast-forward button..fast down button
-23F0 ; Emoji_Presentation # 6.0 [1] (โฐ) alarm clock
-23F3 ; Emoji_Presentation # 6.0 [1] (โณ) hourglass not done
-25FD..25FE ; Emoji_Presentation # 3.2 [2] (โ—ฝ..โ—พ) white medium-small square..black medium-small square
-2614..2615 ; Emoji_Presentation # 4.0 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
-2648..2653 ; Emoji_Presentation # 1.1 [12] (โ™ˆ..โ™“) Aries..Pisces
-267F ; Emoji_Presentation # 4.1 [1] (โ™ฟ) wheelchair symbol
-2693 ; Emoji_Presentation # 4.1 [1] (โš“) anchor
-26A1 ; Emoji_Presentation # 4.0 [1] (โšก) high voltage
-26AA..26AB ; Emoji_Presentation # 4.1 [2] (โšช..โšซ) white circle..black circle
-26BD..26BE ; Emoji_Presentation # 5.2 [2] (โšฝ..โšพ) soccer ball..baseball
-26C4..26C5 ; Emoji_Presentation # 5.2 [2] (โ›„..โ›…) snowman without snow..sun behind cloud
-26CE ; Emoji_Presentation # 6.0 [1] (โ›Ž) Ophiuchus
-26D4 ; Emoji_Presentation # 5.2 [1] (โ›”) no entry
-26EA ; Emoji_Presentation # 5.2 [1] (โ›ช) church
-26F2..26F3 ; Emoji_Presentation # 5.2 [2] (โ›ฒ..โ›ณ) fountain..flag in hole
-26F5 ; Emoji_Presentation # 5.2 [1] (โ›ต) sailboat
-26FA ; Emoji_Presentation # 5.2 [1] (โ›บ) tent
-26FD ; Emoji_Presentation # 5.2 [1] (โ›ฝ) fuel pump
-2705 ; Emoji_Presentation # 6.0 [1] (โœ…) check mark button
-270A..270B ; Emoji_Presentation # 6.0 [2] (โœŠ..โœ‹) raised fist..raised hand
-2728 ; Emoji_Presentation # 6.0 [1] (โœจ) sparkles
-274C ; Emoji_Presentation # 6.0 [1] (โŒ) cross mark
-274E ; Emoji_Presentation # 6.0 [1] (โŽ) cross mark button
-2753..2755 ; Emoji_Presentation # 6.0 [3] (โ“..โ•) question mark..white exclamation mark
-2757 ; Emoji_Presentation # 5.2 [1] (โ—) exclamation mark
-2795..2797 ; Emoji_Presentation # 6.0 [3] (โž•..โž—) plus sign..division sign
-27B0 ; Emoji_Presentation # 6.0 [1] (โžฐ) curly loop
-27BF ; Emoji_Presentation # 6.0 [1] (โžฟ) double curly loop
-2B1B..2B1C ; Emoji_Presentation # 5.1 [2] (โฌ›..โฌœ) black large square..white large square
-2B50 ; Emoji_Presentation # 5.1 [1] (โญ) star
-2B55 ; Emoji_Presentation # 5.2 [1] (โญ•) hollow red circle
-1F004 ; Emoji_Presentation # 5.1 [1] (๐Ÿ€„) mahjong red dragon
-1F0CF ; Emoji_Presentation # 6.0 [1] (๐Ÿƒ) joker
-1F18E ; Emoji_Presentation # 6.0 [1] (๐Ÿ†Ž) AB button (blood type)
-1F191..1F19A ; Emoji_Presentation # 6.0 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
-1F1E6..1F1FF ; Emoji_Presentation # 6.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
-1F201 ; Emoji_Presentation # 6.0 [1] (๐Ÿˆ) Japanese โ€œhereโ€ button
-1F21A ; Emoji_Presentation # 5.2 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
-1F22F ; Emoji_Presentation # 5.2 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
-1F232..1F236 ; Emoji_Presentation # 6.0 [5] (๐Ÿˆฒ..๐Ÿˆถ) Japanese โ€œprohibitedโ€ button..Japanese โ€œnot free of chargeโ€ button
-1F238..1F23A ; Emoji_Presentation # 6.0 [3] (๐Ÿˆธ..๐Ÿˆบ) Japanese โ€œapplicationโ€ button..Japanese โ€œopen for businessโ€ button
-1F250..1F251 ; Emoji_Presentation # 6.0 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
-1F300..1F320 ; Emoji_Presentation # 6.0 [33] (๐ŸŒ€..๐ŸŒ ) cyclone..shooting star
-1F32D..1F32F ; Emoji_Presentation # 8.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
-1F330..1F335 ; Emoji_Presentation # 6.0 [6] (๐ŸŒฐ..๐ŸŒต) chestnut..cactus
-1F337..1F37C ; Emoji_Presentation # 6.0 [70] (๐ŸŒท..๐Ÿผ) tulip..baby bottle
-1F37E..1F37F ; Emoji_Presentation # 8.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
-1F380..1F393 ; Emoji_Presentation # 6.0 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
-1F3A0..1F3C4 ; Emoji_Presentation # 6.0 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
-1F3C5 ; Emoji_Presentation # 7.0 [1] (๐Ÿ…) sports medal
-1F3C6..1F3CA ; Emoji_Presentation # 6.0 [5] (๐Ÿ†..๐ŸŠ) trophy..person swimming
-1F3CF..1F3D3 ; Emoji_Presentation # 8.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
-1F3E0..1F3F0 ; Emoji_Presentation # 6.0 [17] (๐Ÿ ..๐Ÿฐ) house..castle
-1F3F4 ; Emoji_Presentation # 7.0 [1] (๐Ÿด) black flag
-1F3F8..1F3FF ; Emoji_Presentation # 8.0 [8] (๐Ÿธ..๐Ÿฟ) badminton..dark skin tone
-1F400..1F43E ; Emoji_Presentation # 6.0 [63] (๐Ÿ€..๐Ÿพ) rat..paw prints
-1F440 ; Emoji_Presentation # 6.0 [1] (๐Ÿ‘€) eyes
-1F442..1F4F7 ; Emoji_Presentation # 6.0[182] (๐Ÿ‘‚..๐Ÿ“ท) ear..camera
-1F4F8 ; Emoji_Presentation # 7.0 [1] (๐Ÿ“ธ) camera with flash
-1F4F9..1F4FC ; Emoji_Presentation # 6.0 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
-1F4FF ; Emoji_Presentation # 8.0 [1] (๐Ÿ“ฟ) prayer beads
-1F500..1F53D ; Emoji_Presentation # 6.0 [62] (๐Ÿ”€..๐Ÿ”ฝ) shuffle tracks button..downwards button
-1F54B..1F54E ; Emoji_Presentation # 8.0 [4] (๐Ÿ•‹..๐Ÿ•Ž) kaaba..menorah
-1F550..1F567 ; Emoji_Presentation # 6.0 [24] (๐Ÿ•..๐Ÿ•ง) one oโ€™clock..twelve-thirty
-1F57A ; Emoji_Presentation # 9.0 [1] (๐Ÿ•บ) man dancing
-1F595..1F596 ; Emoji_Presentation # 7.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
-1F5A4 ; Emoji_Presentation # 9.0 [1] (๐Ÿ–ค) black heart
-1F5FB..1F5FF ; Emoji_Presentation # 6.0 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
-1F600 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜€) grinning face
-1F601..1F610 ; Emoji_Presentation # 6.0 [16] (๐Ÿ˜..๐Ÿ˜) beaming face with smiling eyes..neutral face
-1F611 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜‘) expressionless face
-1F612..1F614 ; Emoji_Presentation # 6.0 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
-1F615 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜•) confused face
-1F616 ; Emoji_Presentation # 6.0 [1] (๐Ÿ˜–) confounded face
-1F617 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜—) kissing face
-1F618 ; Emoji_Presentation # 6.0 [1] (๐Ÿ˜˜) face blowing a kiss
-1F619 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜™) kissing face with smiling eyes
-1F61A ; Emoji_Presentation # 6.0 [1] (๐Ÿ˜š) kissing face with closed eyes
-1F61B ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜›) face with tongue
-1F61C..1F61E ; Emoji_Presentation # 6.0 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
-1F61F ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜Ÿ) worried face
-1F620..1F625 ; Emoji_Presentation # 6.0 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
-1F626..1F627 ; Emoji_Presentation # 6.1 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
-1F628..1F62B ; Emoji_Presentation # 6.0 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
-1F62C ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜ฌ) grimacing face
-1F62D ; Emoji_Presentation # 6.0 [1] (๐Ÿ˜ญ) loudly crying face
-1F62E..1F62F ; Emoji_Presentation # 6.1 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
-1F630..1F633 ; Emoji_Presentation # 6.0 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
-1F634 ; Emoji_Presentation # 6.1 [1] (๐Ÿ˜ด) sleeping face
-1F635..1F640 ; Emoji_Presentation # 6.0 [12] (๐Ÿ˜ต..๐Ÿ™€) dizzy face..weary cat
-1F641..1F642 ; Emoji_Presentation # 7.0 [2] (๐Ÿ™..๐Ÿ™‚) slightly frowning face..slightly smiling face
-1F643..1F644 ; Emoji_Presentation # 8.0 [2] (๐Ÿ™ƒ..๐Ÿ™„) upside-down face..face with rolling eyes
-1F645..1F64F ; Emoji_Presentation # 6.0 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
-1F680..1F6C5 ; Emoji_Presentation # 6.0 [70] (๐Ÿš€..๐Ÿ›…) rocket..left luggage
-1F6CC ; Emoji_Presentation # 7.0 [1] (๐Ÿ›Œ) person in bed
-1F6D0 ; Emoji_Presentation # 8.0 [1] (๐Ÿ›) place of worship
-1F6D1..1F6D2 ; Emoji_Presentation # 9.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
-1F6D5 ; Emoji_Presentation # 12.0 [1] (๐Ÿ›•) hindu temple
-1F6EB..1F6EC ; Emoji_Presentation # 7.0 [2] (๐Ÿ›ซ..๐Ÿ›ฌ) airplane departure..airplane arrival
-1F6F4..1F6F6 ; Emoji_Presentation # 9.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
-1F6F7..1F6F8 ; Emoji_Presentation # 10.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
-1F6F9 ; Emoji_Presentation # 11.0 [1] (๐Ÿ›น) skateboard
-1F6FA ; Emoji_Presentation # 12.0 [1] (๐Ÿ›บ) auto rickshaw
-1F7E0..1F7EB ; Emoji_Presentation # 12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
-1F90D..1F90F ; Emoji_Presentation # 12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
-1F910..1F918 ; Emoji_Presentation # 8.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
-1F919..1F91E ; Emoji_Presentation # 9.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
-1F91F ; Emoji_Presentation # 10.0 [1] (๐ŸคŸ) love-you gesture
-1F920..1F927 ; Emoji_Presentation # 9.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
-1F928..1F92F ; Emoji_Presentation # 10.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
-1F930 ; Emoji_Presentation # 9.0 [1] (๐Ÿคฐ) pregnant woman
-1F931..1F932 ; Emoji_Presentation # 10.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
-1F933..1F93A ; Emoji_Presentation # 9.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
-1F93C..1F93E ; Emoji_Presentation # 9.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
-1F93F ; Emoji_Presentation # 12.0 [1] (๐Ÿคฟ) diving mask
-1F940..1F945 ; Emoji_Presentation # 9.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
-1F947..1F94B ; Emoji_Presentation # 9.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
-1F94C ; Emoji_Presentation # 10.0 [1] (๐ŸฅŒ) curling stone
-1F94D..1F94F ; Emoji_Presentation # 11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
-1F950..1F95E ; Emoji_Presentation # 9.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
-1F95F..1F96B ; Emoji_Presentation # 10.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
-1F96C..1F970 ; Emoji_Presentation # 11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
-1F971 ; Emoji_Presentation # 12.0 [1] (๐Ÿฅฑ) yawning face
-1F973..1F976 ; Emoji_Presentation # 11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
-1F97A ; Emoji_Presentation # 11.0 [1] (๐Ÿฅบ) pleading face
-1F97B ; Emoji_Presentation # 12.0 [1] (๐Ÿฅป) sari
-1F97C..1F97F ; Emoji_Presentation # 11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
-1F980..1F984 ; Emoji_Presentation # 8.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
-1F985..1F991 ; Emoji_Presentation # 9.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
-1F992..1F997 ; Emoji_Presentation # 10.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
-1F998..1F9A2 ; Emoji_Presentation # 11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
-1F9A5..1F9AA ; Emoji_Presentation # 12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
-1F9AE..1F9AF ; Emoji_Presentation # 12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..probing cane
-1F9B0..1F9B9 ; Emoji_Presentation # 11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
-1F9BA..1F9BF ; Emoji_Presentation # 12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
-1F9C0 ; Emoji_Presentation # 8.0 [1] (๐Ÿง€) cheese wedge
-1F9C1..1F9C2 ; Emoji_Presentation # 11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
-1F9C3..1F9CA ; Emoji_Presentation # 12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice cube
-1F9CD..1F9CF ; Emoji_Presentation # 12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
-1F9D0..1F9E6 ; Emoji_Presentation # 10.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
-1F9E7..1F9FF ; Emoji_Presentation # 11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
-1FA70..1FA73 ; Emoji_Presentation # 12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
-1FA78..1FA7A ; Emoji_Presentation # 12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
-1FA80..1FA82 ; Emoji_Presentation # 12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
-1FA90..1FA95 ; Emoji_Presentation # 12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
+231A..231B ; Emoji_Presentation # E0.6 [2] (โŒš..โŒ›) watch..hourglass done
+23E9..23EC ; Emoji_Presentation # E0.6 [4] (โฉ..โฌ) fast-forward button..fast down button
+23F0 ; Emoji_Presentation # E0.6 [1] (โฐ) alarm clock
+23F3 ; Emoji_Presentation # E0.6 [1] (โณ) hourglass not done
+25FD..25FE ; Emoji_Presentation # E0.6 [2] (โ—ฝ..โ—พ) white medium-small square..black medium-small square
+2614..2615 ; Emoji_Presentation # E0.6 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
+2648..2653 ; Emoji_Presentation # E0.6 [12] (โ™ˆ..โ™“) Aries..Pisces
+267F ; Emoji_Presentation # E0.6 [1] (โ™ฟ) wheelchair symbol
+2693 ; Emoji_Presentation # E0.6 [1] (โš“) anchor
+26A1 ; Emoji_Presentation # E0.6 [1] (โšก) high voltage
+26AA..26AB ; Emoji_Presentation # E0.6 [2] (โšช..โšซ) white circle..black circle
+26BD..26BE ; Emoji_Presentation # E0.6 [2] (โšฝ..โšพ) soccer ball..baseball
+26C4..26C5 ; Emoji_Presentation # E0.6 [2] (โ›„..โ›…) snowman without snow..sun behind cloud
+26CE ; Emoji_Presentation # E0.6 [1] (โ›Ž) Ophiuchus
+26D4 ; Emoji_Presentation # E0.6 [1] (โ›”) no entry
+26EA ; Emoji_Presentation # E0.6 [1] (โ›ช) church
+26F2..26F3 ; Emoji_Presentation # E0.6 [2] (โ›ฒ..โ›ณ) fountain..flag in hole
+26F5 ; Emoji_Presentation # E0.6 [1] (โ›ต) sailboat
+26FA ; Emoji_Presentation # E0.6 [1] (โ›บ) tent
+26FD ; Emoji_Presentation # E0.6 [1] (โ›ฝ) fuel pump
+2705 ; Emoji_Presentation # E0.6 [1] (โœ…) check mark button
+270A..270B ; Emoji_Presentation # E0.6 [2] (โœŠ..โœ‹) raised fist..raised hand
+2728 ; Emoji_Presentation # E0.6 [1] (โœจ) sparkles
+274C ; Emoji_Presentation # E0.6 [1] (โŒ) cross mark
+274E ; Emoji_Presentation # E0.6 [1] (โŽ) cross mark button
+2753..2755 ; Emoji_Presentation # E0.6 [3] (โ“..โ•) question mark..white exclamation mark
+2757 ; Emoji_Presentation # E0.6 [1] (โ—) exclamation mark
+2795..2797 ; Emoji_Presentation # E0.6 [3] (โž•..โž—) plus..divide
+27B0 ; Emoji_Presentation # E0.6 [1] (โžฐ) curly loop
+27BF ; Emoji_Presentation # E1.0 [1] (โžฟ) double curly loop
+2B1B..2B1C ; Emoji_Presentation # E0.6 [2] (โฌ›..โฌœ) black large square..white large square
+2B50 ; Emoji_Presentation # E0.6 [1] (โญ) star
+2B55 ; Emoji_Presentation # E0.6 [1] (โญ•) hollow red circle
+1F004 ; Emoji_Presentation # E0.6 [1] (๐Ÿ€„) mahjong red dragon
+1F0CF ; Emoji_Presentation # E0.6 [1] (๐Ÿƒ) joker
+1F18E ; Emoji_Presentation # E0.6 [1] (๐Ÿ†Ž) AB button (blood type)
+1F191..1F19A ; Emoji_Presentation # E0.6 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
+1F1E6..1F1FF ; Emoji_Presentation # E0.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
+1F201 ; Emoji_Presentation # E0.6 [1] (๐Ÿˆ) Japanese โ€œhereโ€ button
+1F21A ; Emoji_Presentation # E0.6 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
+1F22F ; Emoji_Presentation # E0.6 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
+1F232..1F236 ; Emoji_Presentation # E0.6 [5] (๐Ÿˆฒ..๐Ÿˆถ) Japanese โ€œprohibitedโ€ button..Japanese โ€œnot free of chargeโ€ button
+1F238..1F23A ; Emoji_Presentation # E0.6 [3] (๐Ÿˆธ..๐Ÿˆบ) Japanese โ€œapplicationโ€ button..Japanese โ€œopen for businessโ€ button
+1F250..1F251 ; Emoji_Presentation # E0.6 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
+1F300..1F30C ; Emoji_Presentation # E0.6 [13] (๐ŸŒ€..๐ŸŒŒ) cyclone..milky way
+1F30D..1F30E ; Emoji_Presentation # E0.7 [2] (๐ŸŒ..๐ŸŒŽ) globe showing Europe-Africa..globe showing Americas
+1F30F ; Emoji_Presentation # E0.6 [1] (๐ŸŒ) globe showing Asia-Australia
+1F310 ; Emoji_Presentation # E1.0 [1] (๐ŸŒ) globe with meridians
+1F311 ; Emoji_Presentation # E0.6 [1] (๐ŸŒ‘) new moon
+1F312 ; Emoji_Presentation # E1.0 [1] (๐ŸŒ’) waxing crescent moon
+1F313..1F315 ; Emoji_Presentation # E0.6 [3] (๐ŸŒ“..๐ŸŒ•) first quarter moon..full moon
+1F316..1F318 ; Emoji_Presentation # E1.0 [3] (๐ŸŒ–..๐ŸŒ˜) waning gibbous moon..waning crescent moon
+1F319 ; Emoji_Presentation # E0.6 [1] (๐ŸŒ™) crescent moon
+1F31A ; Emoji_Presentation # E1.0 [1] (๐ŸŒš) new moon face
+1F31B ; Emoji_Presentation # E0.6 [1] (๐ŸŒ›) first quarter moon face
+1F31C ; Emoji_Presentation # E0.7 [1] (๐ŸŒœ) last quarter moon face
+1F31D..1F31E ; Emoji_Presentation # E1.0 [2] (๐ŸŒ..๐ŸŒž) full moon face..sun with face
+1F31F..1F320 ; Emoji_Presentation # E0.6 [2] (๐ŸŒŸ..๐ŸŒ ) glowing star..shooting star
+1F32D..1F32F ; Emoji_Presentation # E1.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
+1F330..1F331 ; Emoji_Presentation # E0.6 [2] (๐ŸŒฐ..๐ŸŒฑ) chestnut..seedling
+1F332..1F333 ; Emoji_Presentation # E1.0 [2] (๐ŸŒฒ..๐ŸŒณ) evergreen tree..deciduous tree
+1F334..1F335 ; Emoji_Presentation # E0.6 [2] (๐ŸŒด..๐ŸŒต) palm tree..cactus
+1F337..1F34A ; Emoji_Presentation # E0.6 [20] (๐ŸŒท..๐ŸŠ) tulip..tangerine
+1F34B ; Emoji_Presentation # E1.0 [1] (๐Ÿ‹) lemon
+1F34C..1F34F ; Emoji_Presentation # E0.6 [4] (๐ŸŒ..๐Ÿ) banana..green apple
+1F350 ; Emoji_Presentation # E1.0 [1] (๐Ÿ) pear
+1F351..1F37B ; Emoji_Presentation # E0.6 [43] (๐Ÿ‘..๐Ÿป) peach..clinking beer mugs
+1F37C ; Emoji_Presentation # E1.0 [1] (๐Ÿผ) baby bottle
+1F37E..1F37F ; Emoji_Presentation # E1.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji_Presentation # E0.6 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
+1F3A0..1F3C4 ; Emoji_Presentation # E0.6 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
+1F3C5 ; Emoji_Presentation # E1.0 [1] (๐Ÿ…) sports medal
+1F3C6 ; Emoji_Presentation # E0.6 [1] (๐Ÿ†) trophy
+1F3C7 ; Emoji_Presentation # E1.0 [1] (๐Ÿ‡) horse racing
+1F3C8 ; Emoji_Presentation # E0.6 [1] (๐Ÿˆ) american football
+1F3C9 ; Emoji_Presentation # E1.0 [1] (๐Ÿ‰) rugby football
+1F3CA ; Emoji_Presentation # E0.6 [1] (๐ŸŠ) person swimming
+1F3CF..1F3D3 ; Emoji_Presentation # E1.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
+1F3E0..1F3E3 ; Emoji_Presentation # E0.6 [4] (๐Ÿ ..๐Ÿฃ) house..Japanese post office
+1F3E4 ; Emoji_Presentation # E1.0 [1] (๐Ÿค) post office
+1F3E5..1F3F0 ; Emoji_Presentation # E0.6 [12] (๐Ÿฅ..๐Ÿฐ) hospital..castle
+1F3F4 ; Emoji_Presentation # E1.0 [1] (๐Ÿด) black flag
+1F3F8..1F407 ; Emoji_Presentation # E1.0 [16] (๐Ÿธ..๐Ÿ‡) badminton..rabbit
+1F408 ; Emoji_Presentation # E0.7 [1] (๐Ÿˆ) cat
+1F409..1F40B ; Emoji_Presentation # E1.0 [3] (๐Ÿ‰..๐Ÿ‹) dragon..whale
+1F40C..1F40E ; Emoji_Presentation # E0.6 [3] (๐ŸŒ..๐ŸŽ) snail..horse
+1F40F..1F410 ; Emoji_Presentation # E1.0 [2] (๐Ÿ..๐Ÿ) ram..goat
+1F411..1F412 ; Emoji_Presentation # E0.6 [2] (๐Ÿ‘..๐Ÿ’) ewe..monkey
+1F413 ; Emoji_Presentation # E1.0 [1] (๐Ÿ“) rooster
+1F414 ; Emoji_Presentation # E0.6 [1] (๐Ÿ”) chicken
+1F415 ; Emoji_Presentation # E0.7 [1] (๐Ÿ•) dog
+1F416 ; Emoji_Presentation # E1.0 [1] (๐Ÿ–) pig
+1F417..1F429 ; Emoji_Presentation # E0.6 [19] (๐Ÿ—..๐Ÿฉ) boar..poodle
+1F42A ; Emoji_Presentation # E1.0 [1] (๐Ÿช) camel
+1F42B..1F43E ; Emoji_Presentation # E0.6 [20] (๐Ÿซ..๐Ÿพ) two-hump camel..paw prints
+1F440 ; Emoji_Presentation # E0.6 [1] (๐Ÿ‘€) eyes
+1F442..1F464 ; Emoji_Presentation # E0.6 [35] (๐Ÿ‘‚..๐Ÿ‘ค) ear..bust in silhouette
+1F465 ; Emoji_Presentation # E1.0 [1] (๐Ÿ‘ฅ) busts in silhouette
+1F466..1F46B ; Emoji_Presentation # E0.6 [6] (๐Ÿ‘ฆ..๐Ÿ‘ซ) boy..woman and man holding hands
+1F46C..1F46D ; Emoji_Presentation # E1.0 [2] (๐Ÿ‘ฌ..๐Ÿ‘ญ) men holding hands..women holding hands
+1F46E..1F4AC ; Emoji_Presentation # E0.6 [63] (๐Ÿ‘ฎ..๐Ÿ’ฌ) police officer..speech balloon
+1F4AD ; Emoji_Presentation # E1.0 [1] (๐Ÿ’ญ) thought balloon
+1F4AE..1F4B5 ; Emoji_Presentation # E0.6 [8] (๐Ÿ’ฎ..๐Ÿ’ต) white flower..dollar banknote
+1F4B6..1F4B7 ; Emoji_Presentation # E1.0 [2] (๐Ÿ’ถ..๐Ÿ’ท) euro banknote..pound banknote
+1F4B8..1F4EB ; Emoji_Presentation # E0.6 [52] (๐Ÿ’ธ..๐Ÿ“ซ) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Emoji_Presentation # E0.7 [2] (๐Ÿ“ฌ..๐Ÿ“ญ) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Emoji_Presentation # E0.6 [1] (๐Ÿ“ฎ) postbox
+1F4EF ; Emoji_Presentation # E1.0 [1] (๐Ÿ“ฏ) postal horn
+1F4F0..1F4F4 ; Emoji_Presentation # E0.6 [5] (๐Ÿ“ฐ..๐Ÿ“ด) newspaper..mobile phone off
+1F4F5 ; Emoji_Presentation # E1.0 [1] (๐Ÿ“ต) no mobile phones
+1F4F6..1F4F7 ; Emoji_Presentation # E0.6 [2] (๐Ÿ“ถ..๐Ÿ“ท) antenna bars..camera
+1F4F8 ; Emoji_Presentation # E1.0 [1] (๐Ÿ“ธ) camera with flash
+1F4F9..1F4FC ; Emoji_Presentation # E0.6 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
+1F4FF..1F502 ; Emoji_Presentation # E1.0 [4] (๐Ÿ“ฟ..๐Ÿ”‚) prayer beads..repeat single button
+1F503 ; Emoji_Presentation # E0.6 [1] (๐Ÿ”ƒ) clockwise vertical arrows
+1F504..1F507 ; Emoji_Presentation # E1.0 [4] (๐Ÿ”„..๐Ÿ”‡) counterclockwise arrows button..muted speaker
+1F508 ; Emoji_Presentation # E0.7 [1] (๐Ÿ”ˆ) speaker low volume
+1F509 ; Emoji_Presentation # E1.0 [1] (๐Ÿ”‰) speaker medium volume
+1F50A..1F514 ; Emoji_Presentation # E0.6 [11] (๐Ÿ”Š..๐Ÿ””) speaker high volume..bell
+1F515 ; Emoji_Presentation # E1.0 [1] (๐Ÿ”•) bell with slash
+1F516..1F52B ; Emoji_Presentation # E0.6 [22] (๐Ÿ”–..๐Ÿ”ซ) bookmark..pistol
+1F52C..1F52D ; Emoji_Presentation # E1.0 [2] (๐Ÿ”ฌ..๐Ÿ”ญ) microscope..telescope
+1F52E..1F53D ; Emoji_Presentation # E0.6 [16] (๐Ÿ”ฎ..๐Ÿ”ฝ) crystal ball..downwards button
+1F54B..1F54E ; Emoji_Presentation # E1.0 [4] (๐Ÿ•‹..๐Ÿ•Ž) kaaba..menorah
+1F550..1F55B ; Emoji_Presentation # E0.6 [12] (๐Ÿ•..๐Ÿ•›) one oโ€™clock..twelve oโ€™clock
+1F55C..1F567 ; Emoji_Presentation # E0.7 [12] (๐Ÿ•œ..๐Ÿ•ง) one-thirty..twelve-thirty
+1F57A ; Emoji_Presentation # E3.0 [1] (๐Ÿ•บ) man dancing
+1F595..1F596 ; Emoji_Presentation # E1.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
+1F5A4 ; Emoji_Presentation # E3.0 [1] (๐Ÿ–ค) black heart
+1F5FB..1F5FF ; Emoji_Presentation # E0.6 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
+1F600 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜€) grinning face
+1F601..1F606 ; Emoji_Presentation # E0.6 [6] (๐Ÿ˜..๐Ÿ˜†) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Emoji_Presentation # E1.0 [2] (๐Ÿ˜‡..๐Ÿ˜ˆ) smiling face with halo..smiling face with horns
+1F609..1F60D ; Emoji_Presentation # E0.6 [5] (๐Ÿ˜‰..๐Ÿ˜) winking face..smiling face with heart-eyes
+1F60E ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜Ž) smiling face with sunglasses
+1F60F ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜) smirking face
+1F610 ; Emoji_Presentation # E0.7 [1] (๐Ÿ˜) neutral face
+1F611 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜‘) expressionless face
+1F612..1F614 ; Emoji_Presentation # E0.6 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
+1F615 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜•) confused face
+1F616 ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜–) confounded face
+1F617 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜—) kissing face
+1F618 ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜˜) face blowing a kiss
+1F619 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜™) kissing face with smiling eyes
+1F61A ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜š) kissing face with closed eyes
+1F61B ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜›) face with tongue
+1F61C..1F61E ; Emoji_Presentation # E0.6 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
+1F61F ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜Ÿ) worried face
+1F620..1F625 ; Emoji_Presentation # E0.6 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
+1F626..1F627 ; Emoji_Presentation # E1.0 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji_Presentation # E0.6 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
+1F62C ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜ฌ) grimacing face
+1F62D ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜ญ) loudly crying face
+1F62E..1F62F ; Emoji_Presentation # E1.0 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
+1F630..1F633 ; Emoji_Presentation # E0.6 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
+1F634 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜ด) sleeping face
+1F635 ; Emoji_Presentation # E0.6 [1] (๐Ÿ˜ต) dizzy face
+1F636 ; Emoji_Presentation # E1.0 [1] (๐Ÿ˜ถ) face without mouth
+1F637..1F640 ; Emoji_Presentation # E0.6 [10] (๐Ÿ˜ท..๐Ÿ™€) face with medical mask..weary cat
+1F641..1F644 ; Emoji_Presentation # E1.0 [4] (๐Ÿ™..๐Ÿ™„) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Emoji_Presentation # E0.6 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
+1F680 ; Emoji_Presentation # E0.6 [1] (๐Ÿš€) rocket
+1F681..1F682 ; Emoji_Presentation # E1.0 [2] (๐Ÿš..๐Ÿš‚) helicopter..locomotive
+1F683..1F685 ; Emoji_Presentation # E0.6 [3] (๐Ÿšƒ..๐Ÿš…) railway car..bullet train
+1F686 ; Emoji_Presentation # E1.0 [1] (๐Ÿš†) train
+1F687 ; Emoji_Presentation # E0.6 [1] (๐Ÿš‡) metro
+1F688 ; Emoji_Presentation # E1.0 [1] (๐Ÿšˆ) light rail
+1F689 ; Emoji_Presentation # E0.6 [1] (๐Ÿš‰) station
+1F68A..1F68B ; Emoji_Presentation # E1.0 [2] (๐ŸšŠ..๐Ÿš‹) tram..tram car
+1F68C ; Emoji_Presentation # E0.6 [1] (๐ŸšŒ) bus
+1F68D ; Emoji_Presentation # E0.7 [1] (๐Ÿš) oncoming bus
+1F68E ; Emoji_Presentation # E1.0 [1] (๐ŸšŽ) trolleybus
+1F68F ; Emoji_Presentation # E0.6 [1] (๐Ÿš) bus stop
+1F690 ; Emoji_Presentation # E1.0 [1] (๐Ÿš) minibus
+1F691..1F693 ; Emoji_Presentation # E0.6 [3] (๐Ÿš‘..๐Ÿš“) ambulance..police car
+1F694 ; Emoji_Presentation # E0.7 [1] (๐Ÿš”) oncoming police car
+1F695 ; Emoji_Presentation # E0.6 [1] (๐Ÿš•) taxi
+1F696 ; Emoji_Presentation # E1.0 [1] (๐Ÿš–) oncoming taxi
+1F697 ; Emoji_Presentation # E0.6 [1] (๐Ÿš—) automobile
+1F698 ; Emoji_Presentation # E0.7 [1] (๐Ÿš˜) oncoming automobile
+1F699..1F69A ; Emoji_Presentation # E0.6 [2] (๐Ÿš™..๐Ÿšš) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Emoji_Presentation # E1.0 [7] (๐Ÿš›..๐Ÿšก) articulated lorry..aerial tramway
+1F6A2 ; Emoji_Presentation # E0.6 [1] (๐Ÿšข) ship
+1F6A3 ; Emoji_Presentation # E1.0 [1] (๐Ÿšฃ) person rowing boat
+1F6A4..1F6A5 ; Emoji_Presentation # E0.6 [2] (๐Ÿšค..๐Ÿšฅ) speedboat..horizontal traffic light
+1F6A6 ; Emoji_Presentation # E1.0 [1] (๐Ÿšฆ) vertical traffic light
+1F6A7..1F6AD ; Emoji_Presentation # E0.6 [7] (๐Ÿšง..๐Ÿšญ) construction..no smoking
+1F6AE..1F6B1 ; Emoji_Presentation # E1.0 [4] (๐Ÿšฎ..๐Ÿšฑ) litter in bin sign..non-potable water
+1F6B2 ; Emoji_Presentation # E0.6 [1] (๐Ÿšฒ) bicycle
+1F6B3..1F6B5 ; Emoji_Presentation # E1.0 [3] (๐Ÿšณ..๐Ÿšต) no bicycles..person mountain biking
+1F6B6 ; Emoji_Presentation # E0.6 [1] (๐Ÿšถ) person walking
+1F6B7..1F6B8 ; Emoji_Presentation # E1.0 [2] (๐Ÿšท..๐Ÿšธ) no pedestrians..children crossing
+1F6B9..1F6BE ; Emoji_Presentation # E0.6 [6] (๐Ÿšน..๐Ÿšพ) menโ€™s room..water closet
+1F6BF ; Emoji_Presentation # E1.0 [1] (๐Ÿšฟ) shower
+1F6C0 ; Emoji_Presentation # E0.6 [1] (๐Ÿ›€) person taking bath
+1F6C1..1F6C5 ; Emoji_Presentation # E1.0 [5] (๐Ÿ›..๐Ÿ›…) bathtub..left luggage
+1F6CC ; Emoji_Presentation # E1.0 [1] (๐Ÿ›Œ) person in bed
+1F6D0 ; Emoji_Presentation # E1.0 [1] (๐Ÿ›) place of worship
+1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
+1F6D5 ; Emoji_Presentation # E12.0 [1] (๐Ÿ›•) hindu temple
+1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (๐Ÿ›–..๐Ÿ›—) hut..elevator
+1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (๐Ÿ›ซ..๐Ÿ›ฌ) airplane departure..airplane arrival
+1F6F4..1F6F6 ; Emoji_Presentation # E3.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji_Presentation # E5.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
+1F6F9 ; Emoji_Presentation # E11.0 [1] (๐Ÿ›น) skateboard
+1F6FA ; Emoji_Presentation # E12.0 [1] (๐Ÿ›บ) auto rickshaw
+1F6FB..1F6FC ; Emoji_Presentation # E13.0 [2] (๐Ÿ›ป..๐Ÿ›ผ) pickup truck..roller skate
+1F7E0..1F7EB ; Emoji_Presentation # E12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
+1F90C ; Emoji_Presentation # E13.0 [1] (๐ŸคŒ) pinched fingers
+1F90D..1F90F ; Emoji_Presentation # E12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
+1F910..1F918 ; Emoji_Presentation # E1.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji_Presentation # E3.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
+1F91F ; Emoji_Presentation # E5.0 [1] (๐ŸคŸ) love-you gesture
+1F920..1F927 ; Emoji_Presentation # E3.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji_Presentation # E5.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
+1F930 ; Emoji_Presentation # E3.0 [1] (๐Ÿคฐ) pregnant woman
+1F931..1F932 ; Emoji_Presentation # E5.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
+1F933..1F93A ; Emoji_Presentation # E3.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
+1F93C..1F93E ; Emoji_Presentation # E3.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
+1F93F ; Emoji_Presentation # E12.0 [1] (๐Ÿคฟ) diving mask
+1F940..1F945 ; Emoji_Presentation # E3.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
+1F947..1F94B ; Emoji_Presentation # E3.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
+1F94C ; Emoji_Presentation # E5.0 [1] (๐ŸฅŒ) curling stone
+1F94D..1F94F ; Emoji_Presentation # E11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
+1F950..1F95E ; Emoji_Presentation # E3.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
+1F95F..1F96B ; Emoji_Presentation # E5.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
+1F96C..1F970 ; Emoji_Presentation # E11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
+1F971 ; Emoji_Presentation # E12.0 [1] (๐Ÿฅฑ) yawning face
+1F972 ; Emoji_Presentation # E13.0 [1] (๐Ÿฅฒ) smiling face with tear
+1F973..1F976 ; Emoji_Presentation # E11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
+1F977..1F978 ; Emoji_Presentation # E13.0 [2] (๐Ÿฅท..๐Ÿฅธ) ninja..disguised face
+1F97A ; Emoji_Presentation # E11.0 [1] (๐Ÿฅบ) pleading face
+1F97B ; Emoji_Presentation # E12.0 [1] (๐Ÿฅป) sari
+1F97C..1F97F ; Emoji_Presentation # E11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
+1F980..1F984 ; Emoji_Presentation # E1.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
+1F985..1F991 ; Emoji_Presentation # E3.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
+1F992..1F997 ; Emoji_Presentation # E5.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
+1F998..1F9A2 ; Emoji_Presentation # E11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
+1F9A3..1F9A4 ; Emoji_Presentation # E13.0 [2] (๐Ÿฆฃ..๐Ÿฆค) mammoth..dodo
+1F9A5..1F9AA ; Emoji_Presentation # E12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
+1F9AB..1F9AD ; Emoji_Presentation # E13.0 [3] (๐Ÿฆซ..๐Ÿฆญ) beaver..seal
+1F9AE..1F9AF ; Emoji_Presentation # E12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..white cane
+1F9B0..1F9B9 ; Emoji_Presentation # E11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
+1F9BA..1F9BF ; Emoji_Presentation # E12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
+1F9C0 ; Emoji_Presentation # E1.0 [1] (๐Ÿง€) cheese wedge
+1F9C1..1F9C2 ; Emoji_Presentation # E11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
+1F9C3..1F9CA ; Emoji_Presentation # E12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice
+1F9CB ; Emoji_Presentation # E13.0 [1] (๐Ÿง‹) bubble tea
+1F9CD..1F9CF ; Emoji_Presentation # E12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
+1F9D0..1F9E6 ; Emoji_Presentation # E5.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
+1F9E7..1F9FF ; Emoji_Presentation # E11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
+1FA70..1FA73 ; Emoji_Presentation # E12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
+1FA74 ; Emoji_Presentation # E13.0 [1] (๐Ÿฉด) thong sandal
+1FA78..1FA7A ; Emoji_Presentation # E12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
+1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
+1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (๐Ÿชƒ..๐Ÿช†) boomerang..nesting dolls
+1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
+1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (๐Ÿช–..๐Ÿชจ) military helmet..rock
+1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (๐Ÿชฐ..๐Ÿชถ) fly..feather
+1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (๐Ÿซ€..๐Ÿซ‚) anatomical heart..people hugging
+1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (๐Ÿซ..๐Ÿซ–) blueberries..teapot
-# Total elements: 1093
+# Total elements: 1148
# ================================================
# All omitted code points have Emoji_Modifier=No
# @missing: 0000..10FFFF ; Emoji_Modifier ; No
-1F3FB..1F3FF ; Emoji_Modifier # 8.0 [5] (๐Ÿป..๐Ÿฟ) light skin tone..dark skin tone
+1F3FB..1F3FF ; Emoji_Modifier # E1.0 [5] (๐Ÿป..๐Ÿฟ) light skin tone..dark skin tone
# Total elements: 5
@@ -438,66 +691,71 @@
# All omitted code points have Emoji_Modifier_Base=No
# @missing: 0000..10FFFF ; Emoji_Modifier_Base ; No
-261D ; Emoji_Modifier_Base # 1.1 [1] (โ˜๏ธ) index pointing up
-26F9 ; Emoji_Modifier_Base # 5.2 [1] (โ›น๏ธ) person bouncing ball
-270A..270B ; Emoji_Modifier_Base # 6.0 [2] (โœŠ..โœ‹) raised fist..raised hand
-270C..270D ; Emoji_Modifier_Base # 1.1 [2] (โœŒ๏ธ..โœ๏ธ) victory hand..writing hand
-1F385 ; Emoji_Modifier_Base # 6.0 [1] (๐ŸŽ…) Santa Claus
-1F3C2..1F3C4 ; Emoji_Modifier_Base # 6.0 [3] (๐Ÿ‚..๐Ÿ„) snowboarder..person surfing
-1F3C7 ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ‡) horse racing
-1F3CA ; Emoji_Modifier_Base # 6.0 [1] (๐ŸŠ) person swimming
-1F3CB..1F3CC ; Emoji_Modifier_Base # 7.0 [2] (๐Ÿ‹๏ธ..๐ŸŒ๏ธ) person lifting weights..person golfing
-1F442..1F443 ; Emoji_Modifier_Base # 6.0 [2] (๐Ÿ‘‚..๐Ÿ‘ƒ) ear..nose
-1F446..1F450 ; Emoji_Modifier_Base # 6.0 [11] (๐Ÿ‘†..๐Ÿ‘) backhand index pointing up..open hands
-1F466..1F478 ; Emoji_Modifier_Base # 6.0 [19] (๐Ÿ‘ฆ..๐Ÿ‘ธ) boy..princess
-1F47C ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ‘ผ) baby angel
-1F481..1F483 ; Emoji_Modifier_Base # 6.0 [3] (๐Ÿ’..๐Ÿ’ƒ) person tipping hand..woman dancing
-1F485..1F487 ; Emoji_Modifier_Base # 6.0 [3] (๐Ÿ’…..๐Ÿ’‡) nail polish..person getting haircut
-1F48F ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ’) kiss
-1F491 ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ’‘) couple with heart
-1F4AA ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ’ช) flexed biceps
-1F574..1F575 ; Emoji_Modifier_Base # 7.0 [2] (๐Ÿ•ด๏ธ..๐Ÿ•ต๏ธ) man in suit levitating..detective
-1F57A ; Emoji_Modifier_Base # 9.0 [1] (๐Ÿ•บ) man dancing
-1F590 ; Emoji_Modifier_Base # 7.0 [1] (๐Ÿ–๏ธ) hand with fingers splayed
-1F595..1F596 ; Emoji_Modifier_Base # 7.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
-1F645..1F647 ; Emoji_Modifier_Base # 6.0 [3] (๐Ÿ™…..๐Ÿ™‡) person gesturing NO..person bowing
-1F64B..1F64F ; Emoji_Modifier_Base # 6.0 [5] (๐Ÿ™‹..๐Ÿ™) person raising hand..folded hands
-1F6A3 ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿšฃ) person rowing boat
-1F6B4..1F6B6 ; Emoji_Modifier_Base # 6.0 [3] (๐Ÿšด..๐Ÿšถ) person biking..person walking
-1F6C0 ; Emoji_Modifier_Base # 6.0 [1] (๐Ÿ›€) person taking bath
-1F6CC ; Emoji_Modifier_Base # 7.0 [1] (๐Ÿ›Œ) person in bed
-1F90F ; Emoji_Modifier_Base # 12.0 [1] (๐Ÿค) pinching hand
-1F918 ; Emoji_Modifier_Base # 8.0 [1] (๐Ÿค˜) sign of the horns
-1F919..1F91E ; Emoji_Modifier_Base # 9.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
-1F91F ; Emoji_Modifier_Base # 10.0 [1] (๐ŸคŸ) love-you gesture
-1F926 ; Emoji_Modifier_Base # 9.0 [1] (๐Ÿคฆ) person facepalming
-1F930 ; Emoji_Modifier_Base # 9.0 [1] (๐Ÿคฐ) pregnant woman
-1F931..1F932 ; Emoji_Modifier_Base # 10.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
-1F933..1F939 ; Emoji_Modifier_Base # 9.0 [7] (๐Ÿคณ..๐Ÿคน) selfie..person juggling
-1F93C..1F93E ; Emoji_Modifier_Base # 9.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
-1F9B5..1F9B6 ; Emoji_Modifier_Base # 11.0 [2] (๐Ÿฆต..๐Ÿฆถ) leg..foot
-1F9B8..1F9B9 ; Emoji_Modifier_Base # 11.0 [2] (๐Ÿฆธ..๐Ÿฆน) superhero..supervillain
-1F9BB ; Emoji_Modifier_Base # 12.0 [1] (๐Ÿฆป) ear with hearing aid
-1F9CD..1F9CF ; Emoji_Modifier_Base # 12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
-1F9D1..1F9DD ; Emoji_Modifier_Base # 10.0 [13] (๐Ÿง‘..๐Ÿง) person..elf
+261D ; Emoji_Modifier_Base # E0.6 [1] (โ˜๏ธ) index pointing up
+26F9 ; Emoji_Modifier_Base # E0.7 [1] (โ›น๏ธ) person bouncing ball
+270A..270C ; Emoji_Modifier_Base # E0.6 [3] (โœŠ..โœŒ๏ธ) raised fist..victory hand
+270D ; Emoji_Modifier_Base # E0.7 [1] (โœ๏ธ) writing hand
+1F385 ; Emoji_Modifier_Base # E0.6 [1] (๐ŸŽ…) Santa Claus
+1F3C2..1F3C4 ; Emoji_Modifier_Base # E0.6 [3] (๐Ÿ‚..๐Ÿ„) snowboarder..person surfing
+1F3C7 ; Emoji_Modifier_Base # E1.0 [1] (๐Ÿ‡) horse racing
+1F3CA ; Emoji_Modifier_Base # E0.6 [1] (๐ŸŠ) person swimming
+1F3CB..1F3CC ; Emoji_Modifier_Base # E0.7 [2] (๐Ÿ‹๏ธ..๐ŸŒ๏ธ) person lifting weights..person golfing
+1F442..1F443 ; Emoji_Modifier_Base # E0.6 [2] (๐Ÿ‘‚..๐Ÿ‘ƒ) ear..nose
+1F446..1F450 ; Emoji_Modifier_Base # E0.6 [11] (๐Ÿ‘†..๐Ÿ‘) backhand index pointing up..open hands
+1F466..1F46B ; Emoji_Modifier_Base # E0.6 [6] (๐Ÿ‘ฆ..๐Ÿ‘ซ) boy..woman and man holding hands
+1F46C..1F46D ; Emoji_Modifier_Base # E1.0 [2] (๐Ÿ‘ฌ..๐Ÿ‘ญ) men holding hands..women holding hands
+1F46E..1F478 ; Emoji_Modifier_Base # E0.6 [11] (๐Ÿ‘ฎ..๐Ÿ‘ธ) police officer..princess
+1F47C ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿ‘ผ) baby angel
+1F481..1F483 ; Emoji_Modifier_Base # E0.6 [3] (๐Ÿ’..๐Ÿ’ƒ) person tipping hand..woman dancing
+1F485..1F487 ; Emoji_Modifier_Base # E0.6 [3] (๐Ÿ’…..๐Ÿ’‡) nail polish..person getting haircut
+1F48F ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿ’) kiss
+1F491 ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿ’‘) couple with heart
+1F4AA ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿ’ช) flexed biceps
+1F574..1F575 ; Emoji_Modifier_Base # E0.7 [2] (๐Ÿ•ด๏ธ..๐Ÿ•ต๏ธ) person in suit levitating..detective
+1F57A ; Emoji_Modifier_Base # E3.0 [1] (๐Ÿ•บ) man dancing
+1F590 ; Emoji_Modifier_Base # E0.7 [1] (๐Ÿ–๏ธ) hand with fingers splayed
+1F595..1F596 ; Emoji_Modifier_Base # E1.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
+1F645..1F647 ; Emoji_Modifier_Base # E0.6 [3] (๐Ÿ™…..๐Ÿ™‡) person gesturing NO..person bowing
+1F64B..1F64F ; Emoji_Modifier_Base # E0.6 [5] (๐Ÿ™‹..๐Ÿ™) person raising hand..folded hands
+1F6A3 ; Emoji_Modifier_Base # E1.0 [1] (๐Ÿšฃ) person rowing boat
+1F6B4..1F6B5 ; Emoji_Modifier_Base # E1.0 [2] (๐Ÿšด..๐Ÿšต) person biking..person mountain biking
+1F6B6 ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿšถ) person walking
+1F6C0 ; Emoji_Modifier_Base # E0.6 [1] (๐Ÿ›€) person taking bath
+1F6CC ; Emoji_Modifier_Base # E1.0 [1] (๐Ÿ›Œ) person in bed
+1F90C ; Emoji_Modifier_Base # E13.0 [1] (๐ŸคŒ) pinched fingers
+1F90F ; Emoji_Modifier_Base # E12.0 [1] (๐Ÿค) pinching hand
+1F918 ; Emoji_Modifier_Base # E1.0 [1] (๐Ÿค˜) sign of the horns
+1F919..1F91E ; Emoji_Modifier_Base # E3.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
+1F91F ; Emoji_Modifier_Base # E5.0 [1] (๐ŸคŸ) love-you gesture
+1F926 ; Emoji_Modifier_Base # E3.0 [1] (๐Ÿคฆ) person facepalming
+1F930 ; Emoji_Modifier_Base # E3.0 [1] (๐Ÿคฐ) pregnant woman
+1F931..1F932 ; Emoji_Modifier_Base # E5.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
+1F933..1F939 ; Emoji_Modifier_Base # E3.0 [7] (๐Ÿคณ..๐Ÿคน) selfie..person juggling
+1F93C..1F93E ; Emoji_Modifier_Base # E3.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
+1F977 ; Emoji_Modifier_Base # E13.0 [1] (๐Ÿฅท) ninja
+1F9B5..1F9B6 ; Emoji_Modifier_Base # E11.0 [2] (๐Ÿฆต..๐Ÿฆถ) leg..foot
+1F9B8..1F9B9 ; Emoji_Modifier_Base # E11.0 [2] (๐Ÿฆธ..๐Ÿฆน) superhero..supervillain
+1F9BB ; Emoji_Modifier_Base # E12.0 [1] (๐Ÿฆป) ear with hearing aid
+1F9CD..1F9CF ; Emoji_Modifier_Base # E12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
+1F9D1..1F9DD ; Emoji_Modifier_Base # E5.0 [13] (๐Ÿง‘..๐Ÿง) person..elf
-# Total elements: 120
+# Total elements: 122
# ================================================
# All omitted code points have Emoji_Component=No
# @missing: 0000..10FFFF ; Emoji_Component ; No
-0023 ; Emoji_Component # 1.1 [1] (#๏ธ) number sign
-002A ; Emoji_Component # 1.1 [1] (*๏ธ) asterisk
-0030..0039 ; Emoji_Component # 1.1 [10] (0๏ธ..9๏ธ) digit zero..digit nine
-200D ; Emoji_Component # 1.1 [1] (โ€) zero width joiner
-20E3 ; Emoji_Component # 3.0 [1] (โƒฃ) combining enclosing keycap
-FE0F ; Emoji_Component # 3.2 [1] () VARIATION SELECTOR-16
-1F1E6..1F1FF ; Emoji_Component # 6.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
-1F3FB..1F3FF ; Emoji_Component # 8.0 [5] (๐Ÿป..๐Ÿฟ) light skin tone..dark skin tone
-1F9B0..1F9B3 ; Emoji_Component # 11.0 [4] (๐Ÿฆฐ..๐Ÿฆณ) red hair..white hair
-E0020..E007F ; Emoji_Component # 3.1 [96] (๓ € ..๓ ฟ) tag space..cancel tag
+0023 ; Emoji_Component # E0.0 [1] (#๏ธ) number sign
+002A ; Emoji_Component # E0.0 [1] (*๏ธ) asterisk
+0030..0039 ; Emoji_Component # E0.0 [10] (0๏ธ..9๏ธ) digit zero..digit nine
+200D ; Emoji_Component # E0.0 [1] (โ€) zero width joiner
+20E3 ; Emoji_Component # E0.0 [1] (โƒฃ) combining enclosing keycap
+FE0F ; Emoji_Component # E0.0 [1] () VARIATION SELECTOR-16
+1F1E6..1F1FF ; Emoji_Component # E0.0 [26] (๐Ÿ‡ฆ..๐Ÿ‡ฟ) regional indicator symbol letter a..regional indicator symbol letter z
+1F3FB..1F3FF ; Emoji_Component # E1.0 [5] (๐Ÿป..๐Ÿฟ) light skin tone..dark skin tone
+1F9B0..1F9B3 ; Emoji_Component # E11.0 [4] (๐Ÿฆฐ..๐Ÿฆณ) red hair..white hair
+E0020..E007F ; Emoji_Component # E0.0 [96] (๓ € ..๓ ฟ) tag space..cancel tag
# Total elements: 146
@@ -506,264 +764,498 @@ E0020..E007F ; Emoji_Component # 3.1 [96] (๓ € ..๓ ฟ) tag space..ca
# All omitted code points have Extended_Pictographic=No
# @missing: 0000..10FFFF ; Extended_Pictographic ; No
-00A9 ; Extended_Pictographic# 1.1 [1] (ยฉ๏ธ) copyright
-00AE ; Extended_Pictographic# 1.1 [1] (ยฎ๏ธ) registered
-203C ; Extended_Pictographic# 1.1 [1] (โ€ผ๏ธ) double exclamation mark
-2049 ; Extended_Pictographic# 3.0 [1] (โ‰๏ธ) exclamation question mark
-2122 ; Extended_Pictographic# 1.1 [1] (โ„ข๏ธ) trade mark
-2139 ; Extended_Pictographic# 3.0 [1] (โ„น๏ธ) information
-2194..2199 ; Extended_Pictographic# 1.1 [6] (โ†”๏ธ..โ†™๏ธ) left-right arrow..down-left arrow
-21A9..21AA ; Extended_Pictographic# 1.1 [2] (โ†ฉ๏ธ..โ†ช๏ธ) right arrow curving left..left arrow curving right
-231A..231B ; Extended_Pictographic# 1.1 [2] (โŒš..โŒ›) watch..hourglass done
-2328 ; Extended_Pictographic# 1.1 [1] (โŒจ๏ธ) keyboard
-2388 ; Extended_Pictographic# 3.0 [1] (โŽˆ) HELM SYMBOL
-23CF ; Extended_Pictographic# 4.0 [1] (โ๏ธ) eject button
-23E9..23F3 ; Extended_Pictographic# 6.0 [11] (โฉ..โณ) fast-forward button..hourglass not done
-23F8..23FA ; Extended_Pictographic# 7.0 [3] (โธ๏ธ..โบ๏ธ) pause button..record button
-24C2 ; Extended_Pictographic# 1.1 [1] (โ“‚๏ธ) circled M
-25AA..25AB ; Extended_Pictographic# 1.1 [2] (โ–ช๏ธ..โ–ซ๏ธ) black small square..white small square
-25B6 ; Extended_Pictographic# 1.1 [1] (โ–ถ๏ธ) play button
-25C0 ; Extended_Pictographic# 1.1 [1] (โ—€๏ธ) reverse button
-25FB..25FE ; Extended_Pictographic# 3.2 [4] (โ—ป๏ธ..โ—พ) white medium square..black medium-small square
-2600..2605 ; Extended_Pictographic# 1.1 [6] (โ˜€๏ธ..โ˜…) sun..BLACK STAR
-2607..2612 ; Extended_Pictographic# 1.1 [12] (โ˜‡..โ˜’) LIGHTNING..BALLOT BOX WITH X
-2614..2615 ; Extended_Pictographic# 4.0 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
-2616..2617 ; Extended_Pictographic# 3.2 [2] (โ˜–..โ˜—) WHITE SHOGI PIECE..BLACK SHOGI PIECE
-2618 ; Extended_Pictographic# 4.1 [1] (โ˜˜๏ธ) shamrock
-2619 ; Extended_Pictographic# 3.0 [1] (โ˜™) REVERSED ROTATED FLORAL HEART BULLET
-261A..266F ; Extended_Pictographic# 1.1 [86] (โ˜š..โ™ฏ) BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN
-2670..2671 ; Extended_Pictographic# 3.0 [2] (โ™ฐ..โ™ฑ) WEST SYRIAC CROSS..EAST SYRIAC CROSS
-2672..267D ; Extended_Pictographic# 3.2 [12] (โ™ฒ..โ™ฝ) UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
-267E..267F ; Extended_Pictographic# 4.1 [2] (โ™พ๏ธ..โ™ฟ) infinity..wheelchair symbol
-2680..2685 ; Extended_Pictographic# 3.2 [6] (โš€..โš…) DIE FACE-1..DIE FACE-6
-2690..2691 ; Extended_Pictographic# 4.0 [2] (โš..โš‘) WHITE FLAG..BLACK FLAG
-2692..269C ; Extended_Pictographic# 4.1 [11] (โš’๏ธ..โšœ๏ธ) hammer and pick..fleur-de-lis
-269D ; Extended_Pictographic# 5.1 [1] (โš) OUTLINED WHITE STAR
-269E..269F ; Extended_Pictographic# 5.2 [2] (โšž..โšŸ) THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
-26A0..26A1 ; Extended_Pictographic# 4.0 [2] (โš ๏ธ..โšก) warning..high voltage
-26A2..26B1 ; Extended_Pictographic# 4.1 [16] (โšข..โšฑ๏ธ) DOUBLED FEMALE SIGN..funeral urn
-26B2 ; Extended_Pictographic# 5.0 [1] (โšฒ) NEUTER
-26B3..26BC ; Extended_Pictographic# 5.1 [10] (โšณ..โšผ) CERES..SESQUIQUADRATE
-26BD..26BF ; Extended_Pictographic# 5.2 [3] (โšฝ..โšฟ) soccer ball..SQUARED KEY
-26C0..26C3 ; Extended_Pictographic# 5.1 [4] (โ›€..โ›ƒ) WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
-26C4..26CD ; Extended_Pictographic# 5.2 [10] (โ›„..โ›) snowman without snow..DISABLED CAR
-26CE ; Extended_Pictographic# 6.0 [1] (โ›Ž) Ophiuchus
-26CF..26E1 ; Extended_Pictographic# 5.2 [19] (โ›๏ธ..โ›ก) pick..RESTRICTED LEFT ENTRY-2
-26E2 ; Extended_Pictographic# 6.0 [1] (โ›ข) ASTRONOMICAL SYMBOL FOR URANUS
-26E3 ; Extended_Pictographic# 5.2 [1] (โ›ฃ) HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
-26E4..26E7 ; Extended_Pictographic# 6.0 [4] (โ›ค..โ›ง) PENTAGRAM..INVERTED PENTAGRAM
-26E8..26FF ; Extended_Pictographic# 5.2 [24] (โ›จ..โ›ฟ) BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
-2700 ; Extended_Pictographic# 7.0 [1] (โœ€) BLACK SAFETY SCISSORS
-2701..2704 ; Extended_Pictographic# 1.1 [4] (โœ..โœ„) UPPER BLADE SCISSORS..WHITE SCISSORS
-2705 ; Extended_Pictographic# 6.0 [1] (โœ…) check mark button
-2708..2709 ; Extended_Pictographic# 1.1 [2] (โœˆ๏ธ..โœ‰๏ธ) airplane..envelope
-270A..270B ; Extended_Pictographic# 6.0 [2] (โœŠ..โœ‹) raised fist..raised hand
-270C..2712 ; Extended_Pictographic# 1.1 [7] (โœŒ๏ธ..โœ’๏ธ) victory hand..black nib
-2714 ; Extended_Pictographic# 1.1 [1] (โœ”๏ธ) check mark
-2716 ; Extended_Pictographic# 1.1 [1] (โœ–๏ธ) multiplication sign
-271D ; Extended_Pictographic# 1.1 [1] (โœ๏ธ) latin cross
-2721 ; Extended_Pictographic# 1.1 [1] (โœก๏ธ) star of David
-2728 ; Extended_Pictographic# 6.0 [1] (โœจ) sparkles
-2733..2734 ; Extended_Pictographic# 1.1 [2] (โœณ๏ธ..โœด๏ธ) eight-spoked asterisk..eight-pointed star
-2744 ; Extended_Pictographic# 1.1 [1] (โ„๏ธ) snowflake
-2747 ; Extended_Pictographic# 1.1 [1] (โ‡๏ธ) sparkle
-274C ; Extended_Pictographic# 6.0 [1] (โŒ) cross mark
-274E ; Extended_Pictographic# 6.0 [1] (โŽ) cross mark button
-2753..2755 ; Extended_Pictographic# 6.0 [3] (โ“..โ•) question mark..white exclamation mark
-2757 ; Extended_Pictographic# 5.2 [1] (โ—) exclamation mark
-2763..2767 ; Extended_Pictographic# 1.1 [5] (โฃ๏ธ..โง) heart exclamation..ROTATED FLORAL HEART BULLET
-2795..2797 ; Extended_Pictographic# 6.0 [3] (โž•..โž—) plus sign..division sign
-27A1 ; Extended_Pictographic# 1.1 [1] (โžก๏ธ) right arrow
-27B0 ; Extended_Pictographic# 6.0 [1] (โžฐ) curly loop
-27BF ; Extended_Pictographic# 6.0 [1] (โžฟ) double curly loop
-2934..2935 ; Extended_Pictographic# 3.2 [2] (โคด๏ธ..โคต๏ธ) right arrow curving up..right arrow curving down
-2B05..2B07 ; Extended_Pictographic# 4.0 [3] (โฌ…๏ธ..โฌ‡๏ธ) left arrow..down arrow
-2B1B..2B1C ; Extended_Pictographic# 5.1 [2] (โฌ›..โฌœ) black large square..white large square
-2B50 ; Extended_Pictographic# 5.1 [1] (โญ) star
-2B55 ; Extended_Pictographic# 5.2 [1] (โญ•) hollow red circle
-3030 ; Extended_Pictographic# 1.1 [1] (ใ€ฐ๏ธ) wavy dash
-303D ; Extended_Pictographic# 3.2 [1] (ใ€ฝ๏ธ) part alternation mark
-3297 ; Extended_Pictographic# 1.1 [1] (ใŠ—๏ธ) Japanese โ€œcongratulationsโ€ button
-3299 ; Extended_Pictographic# 1.1 [1] (ใŠ™๏ธ) Japanese โ€œsecretโ€ button
-1F000..1F02B ; Extended_Pictographic# 5.1 [44] (๐Ÿ€€..๐Ÿ€ซ) MAHJONG TILE EAST WIND..MAHJONG TILE BACK
-1F02C..1F02F ; Extended_Pictographic# NA [4] (๐Ÿ€ฌ..๐Ÿ€ฏ) <reserved-1F02C>..<reserved-1F02F>
-1F030..1F093 ; Extended_Pictographic# 5.1[100] (๐Ÿ€ฐ..๐Ÿ‚“) DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
-1F094..1F09F ; Extended_Pictographic# NA [12] (๐Ÿ‚”..๐Ÿ‚Ÿ) <reserved-1F094>..<reserved-1F09F>
-1F0A0..1F0AE ; Extended_Pictographic# 6.0 [15] (๐Ÿ‚ ..๐Ÿ‚ฎ) PLAYING CARD BACK..PLAYING CARD KING OF SPADES
-1F0AF..1F0B0 ; Extended_Pictographic# NA [2] (๐Ÿ‚ฏ..๐Ÿ‚ฐ) <reserved-1F0AF>..<reserved-1F0B0>
-1F0B1..1F0BE ; Extended_Pictographic# 6.0 [14] (๐Ÿ‚ฑ..๐Ÿ‚พ) PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS
-1F0BF ; Extended_Pictographic# 7.0 [1] (๐Ÿ‚ฟ) PLAYING CARD RED JOKER
-1F0C0 ; Extended_Pictographic# NA [1] (๐Ÿƒ€) <reserved-1F0C0>
-1F0C1..1F0CF ; Extended_Pictographic# 6.0 [15] (๐Ÿƒ..๐Ÿƒ) PLAYING CARD ACE OF DIAMONDS..joker
-1F0D0 ; Extended_Pictographic# NA [1] (๐Ÿƒ) <reserved-1F0D0>
-1F0D1..1F0DF ; Extended_Pictographic# 6.0 [15] (๐Ÿƒ‘..๐ŸƒŸ) PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER
-1F0E0..1F0F5 ; Extended_Pictographic# 7.0 [22] (๐Ÿƒ ..๐Ÿƒต) PLAYING CARD FOOL..PLAYING CARD TRUMP-21
-1F0F6..1F0FF ; Extended_Pictographic# NA [10] (๐Ÿƒถ..๐Ÿƒฟ) <reserved-1F0F6>..<reserved-1F0FF>
-1F10D..1F10F ; Extended_Pictographic# NA [3] (๐Ÿ„..๐Ÿ„) <reserved-1F10D>..<reserved-1F10F>
-1F12F ; Extended_Pictographic# 11.0 [1] (๐Ÿ„ฏ) COPYLEFT SYMBOL
-1F16C ; Extended_Pictographic# 12.0 [1] (๐Ÿ…ฌ) RAISED MR SIGN
-1F16D..1F16F ; Extended_Pictographic# NA [3] (๐Ÿ…ญ..๐Ÿ…ฏ) <reserved-1F16D>..<reserved-1F16F>
-1F170..1F171 ; Extended_Pictographic# 6.0 [2] (๐Ÿ…ฐ๏ธ..๐Ÿ…ฑ๏ธ) A button (blood type)..B button (blood type)
-1F17E ; Extended_Pictographic# 6.0 [1] (๐Ÿ…พ๏ธ) O button (blood type)
-1F17F ; Extended_Pictographic# 5.2 [1] (๐Ÿ…ฟ๏ธ) P button
-1F18E ; Extended_Pictographic# 6.0 [1] (๐Ÿ†Ž) AB button (blood type)
-1F191..1F19A ; Extended_Pictographic# 6.0 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
-1F1AD..1F1E5 ; Extended_Pictographic# NA [57] (๐Ÿ†ญ..๐Ÿ‡ฅ) <reserved-1F1AD>..<reserved-1F1E5>
-1F201..1F202 ; Extended_Pictographic# 6.0 [2] (๐Ÿˆ..๐Ÿˆ‚๏ธ) Japanese โ€œhereโ€ button..Japanese โ€œservice chargeโ€ button
-1F203..1F20F ; Extended_Pictographic# NA [13] (๐Ÿˆƒ..๐Ÿˆ) <reserved-1F203>..<reserved-1F20F>
-1F21A ; Extended_Pictographic# 5.2 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
-1F22F ; Extended_Pictographic# 5.2 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
-1F232..1F23A ; Extended_Pictographic# 6.0 [9] (๐Ÿˆฒ..๐Ÿˆบ) Japanese โ€œprohibitedโ€ button..Japanese โ€œopen for businessโ€ button
-1F23C..1F23F ; Extended_Pictographic# NA [4] (๐Ÿˆผ..๐Ÿˆฟ) <reserved-1F23C>..<reserved-1F23F>
-1F249..1F24F ; Extended_Pictographic# NA [7] (๐Ÿ‰‰..๐Ÿ‰) <reserved-1F249>..<reserved-1F24F>
-1F250..1F251 ; Extended_Pictographic# 6.0 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
-1F252..1F25F ; Extended_Pictographic# NA [14] (๐Ÿ‰’..๐Ÿ‰Ÿ) <reserved-1F252>..<reserved-1F25F>
-1F260..1F265 ; Extended_Pictographic# 10.0 [6] (๐Ÿ‰ ..๐Ÿ‰ฅ) ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
-1F266..1F2FF ; Extended_Pictographic# NA[154] (๐Ÿ‰ฆ..๐Ÿ‹ฟ) <reserved-1F266>..<reserved-1F2FF>
-1F300..1F320 ; Extended_Pictographic# 6.0 [33] (๐ŸŒ€..๐ŸŒ ) cyclone..shooting star
-1F321..1F32C ; Extended_Pictographic# 7.0 [12] (๐ŸŒก๏ธ..๐ŸŒฌ๏ธ) thermometer..wind face
-1F32D..1F32F ; Extended_Pictographic# 8.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
-1F330..1F335 ; Extended_Pictographic# 6.0 [6] (๐ŸŒฐ..๐ŸŒต) chestnut..cactus
-1F336 ; Extended_Pictographic# 7.0 [1] (๐ŸŒถ๏ธ) hot pepper
-1F337..1F37C ; Extended_Pictographic# 6.0 [70] (๐ŸŒท..๐Ÿผ) tulip..baby bottle
-1F37D ; Extended_Pictographic# 7.0 [1] (๐Ÿฝ๏ธ) fork and knife with plate
-1F37E..1F37F ; Extended_Pictographic# 8.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
-1F380..1F393 ; Extended_Pictographic# 6.0 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
-1F394..1F39F ; Extended_Pictographic# 7.0 [12] (๐ŸŽ”..๐ŸŽŸ๏ธ) HEART WITH TIP ON THE LEFT..admission tickets
-1F3A0..1F3C4 ; Extended_Pictographic# 6.0 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
-1F3C5 ; Extended_Pictographic# 7.0 [1] (๐Ÿ…) sports medal
-1F3C6..1F3CA ; Extended_Pictographic# 6.0 [5] (๐Ÿ†..๐ŸŠ) trophy..person swimming
-1F3CB..1F3CE ; Extended_Pictographic# 7.0 [4] (๐Ÿ‹๏ธ..๐ŸŽ๏ธ) person lifting weights..racing car
-1F3CF..1F3D3 ; Extended_Pictographic# 8.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
-1F3D4..1F3DF ; Extended_Pictographic# 7.0 [12] (๐Ÿ”๏ธ..๐ŸŸ๏ธ) snow-capped mountain..stadium
-1F3E0..1F3F0 ; Extended_Pictographic# 6.0 [17] (๐Ÿ ..๐Ÿฐ) house..castle
-1F3F1..1F3F7 ; Extended_Pictographic# 7.0 [7] (๐Ÿฑ..๐Ÿท๏ธ) WHITE PENNANT..label
-1F3F8..1F3FA ; Extended_Pictographic# 8.0 [3] (๐Ÿธ..๐Ÿบ) badminton..amphora
-1F400..1F43E ; Extended_Pictographic# 6.0 [63] (๐Ÿ€..๐Ÿพ) rat..paw prints
-1F43F ; Extended_Pictographic# 7.0 [1] (๐Ÿฟ๏ธ) chipmunk
-1F440 ; Extended_Pictographic# 6.0 [1] (๐Ÿ‘€) eyes
-1F441 ; Extended_Pictographic# 7.0 [1] (๐Ÿ‘๏ธ) eye
-1F442..1F4F7 ; Extended_Pictographic# 6.0[182] (๐Ÿ‘‚..๐Ÿ“ท) ear..camera
-1F4F8 ; Extended_Pictographic# 7.0 [1] (๐Ÿ“ธ) camera with flash
-1F4F9..1F4FC ; Extended_Pictographic# 6.0 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
-1F4FD..1F4FE ; Extended_Pictographic# 7.0 [2] (๐Ÿ“ฝ๏ธ..๐Ÿ“พ) film projector..PORTABLE STEREO
-1F4FF ; Extended_Pictographic# 8.0 [1] (๐Ÿ“ฟ) prayer beads
-1F500..1F53D ; Extended_Pictographic# 6.0 [62] (๐Ÿ”€..๐Ÿ”ฝ) shuffle tracks button..downwards button
-1F546..1F54A ; Extended_Pictographic# 7.0 [5] (๐Ÿ•†..๐Ÿ•Š๏ธ) WHITE LATIN CROSS..dove
-1F54B..1F54F ; Extended_Pictographic# 8.0 [5] (๐Ÿ•‹..๐Ÿ•) kaaba..BOWL OF HYGIEIA
-1F550..1F567 ; Extended_Pictographic# 6.0 [24] (๐Ÿ•..๐Ÿ•ง) one oโ€™clock..twelve-thirty
-1F568..1F579 ; Extended_Pictographic# 7.0 [18] (๐Ÿ•จ..๐Ÿ•น๏ธ) RIGHT SPEAKER..joystick
-1F57A ; Extended_Pictographic# 9.0 [1] (๐Ÿ•บ) man dancing
-1F57B..1F5A3 ; Extended_Pictographic# 7.0 [41] (๐Ÿ•ป..๐Ÿ–ฃ) LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX
-1F5A4 ; Extended_Pictographic# 9.0 [1] (๐Ÿ–ค) black heart
-1F5A5..1F5FA ; Extended_Pictographic# 7.0 [86] (๐Ÿ–ฅ๏ธ..๐Ÿ—บ๏ธ) desktop computer..world map
-1F5FB..1F5FF ; Extended_Pictographic# 6.0 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
-1F600 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜€) grinning face
-1F601..1F610 ; Extended_Pictographic# 6.0 [16] (๐Ÿ˜..๐Ÿ˜) beaming face with smiling eyes..neutral face
-1F611 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜‘) expressionless face
-1F612..1F614 ; Extended_Pictographic# 6.0 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
-1F615 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜•) confused face
-1F616 ; Extended_Pictographic# 6.0 [1] (๐Ÿ˜–) confounded face
-1F617 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜—) kissing face
-1F618 ; Extended_Pictographic# 6.0 [1] (๐Ÿ˜˜) face blowing a kiss
-1F619 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜™) kissing face with smiling eyes
-1F61A ; Extended_Pictographic# 6.0 [1] (๐Ÿ˜š) kissing face with closed eyes
-1F61B ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜›) face with tongue
-1F61C..1F61E ; Extended_Pictographic# 6.0 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
-1F61F ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜Ÿ) worried face
-1F620..1F625 ; Extended_Pictographic# 6.0 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
-1F626..1F627 ; Extended_Pictographic# 6.1 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
-1F628..1F62B ; Extended_Pictographic# 6.0 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
-1F62C ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜ฌ) grimacing face
-1F62D ; Extended_Pictographic# 6.0 [1] (๐Ÿ˜ญ) loudly crying face
-1F62E..1F62F ; Extended_Pictographic# 6.1 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
-1F630..1F633 ; Extended_Pictographic# 6.0 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
-1F634 ; Extended_Pictographic# 6.1 [1] (๐Ÿ˜ด) sleeping face
-1F635..1F640 ; Extended_Pictographic# 6.0 [12] (๐Ÿ˜ต..๐Ÿ™€) dizzy face..weary cat
-1F641..1F642 ; Extended_Pictographic# 7.0 [2] (๐Ÿ™..๐Ÿ™‚) slightly frowning face..slightly smiling face
-1F643..1F644 ; Extended_Pictographic# 8.0 [2] (๐Ÿ™ƒ..๐Ÿ™„) upside-down face..face with rolling eyes
-1F645..1F64F ; Extended_Pictographic# 6.0 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
-1F680..1F6C5 ; Extended_Pictographic# 6.0 [70] (๐Ÿš€..๐Ÿ›…) rocket..left luggage
-1F6C6..1F6CF ; Extended_Pictographic# 7.0 [10] (๐Ÿ›†..๐Ÿ›๏ธ) TRIANGLE WITH ROUNDED CORNERS..bed
-1F6D0 ; Extended_Pictographic# 8.0 [1] (๐Ÿ›) place of worship
-1F6D1..1F6D2 ; Extended_Pictographic# 9.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
-1F6D3..1F6D4 ; Extended_Pictographic# 10.0 [2] (๐Ÿ›“..๐Ÿ›”) STUPA..PAGODA
-1F6D5 ; Extended_Pictographic# 12.0 [1] (๐Ÿ›•) hindu temple
-1F6D6..1F6DF ; Extended_Pictographic# NA [10] (๐Ÿ›–..๐Ÿ›Ÿ) <reserved-1F6D6>..<reserved-1F6DF>
-1F6E0..1F6EC ; Extended_Pictographic# 7.0 [13] (๐Ÿ› ๏ธ..๐Ÿ›ฌ) hammer and wrench..airplane arrival
-1F6ED..1F6EF ; Extended_Pictographic# NA [3] (๐Ÿ›ญ..๐Ÿ›ฏ) <reserved-1F6ED>..<reserved-1F6EF>
-1F6F0..1F6F3 ; Extended_Pictographic# 7.0 [4] (๐Ÿ›ฐ๏ธ..๐Ÿ›ณ๏ธ) satellite..passenger ship
-1F6F4..1F6F6 ; Extended_Pictographic# 9.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
-1F6F7..1F6F8 ; Extended_Pictographic# 10.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
-1F6F9 ; Extended_Pictographic# 11.0 [1] (๐Ÿ›น) skateboard
-1F6FA ; Extended_Pictographic# 12.0 [1] (๐Ÿ›บ) auto rickshaw
-1F6FB..1F6FF ; Extended_Pictographic# NA [5] (๐Ÿ›ป..๐Ÿ›ฟ) <reserved-1F6FB>..<reserved-1F6FF>
-1F774..1F77F ; Extended_Pictographic# NA [12] (๐Ÿด..๐Ÿฟ) <reserved-1F774>..<reserved-1F77F>
-1F7D5..1F7D8 ; Extended_Pictographic# 11.0 [4] (๐ŸŸ•..๐ŸŸ˜) CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE
-1F7D9..1F7DF ; Extended_Pictographic# NA [7] (๐ŸŸ™..๐ŸŸŸ) <reserved-1F7D9>..<reserved-1F7DF>
-1F7E0..1F7EB ; Extended_Pictographic# 12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
-1F7EC..1F7FF ; Extended_Pictographic# NA [20] (๐ŸŸฌ..๐ŸŸฟ) <reserved-1F7EC>..<reserved-1F7FF>
-1F80C..1F80F ; Extended_Pictographic# NA [4] (๐Ÿ Œ..๐Ÿ ) <reserved-1F80C>..<reserved-1F80F>
-1F848..1F84F ; Extended_Pictographic# NA [8] (๐Ÿกˆ..๐Ÿก) <reserved-1F848>..<reserved-1F84F>
-1F85A..1F85F ; Extended_Pictographic# NA [6] (๐Ÿกš..๐ŸกŸ) <reserved-1F85A>..<reserved-1F85F>
-1F888..1F88F ; Extended_Pictographic# NA [8] (๐Ÿขˆ..๐Ÿข) <reserved-1F888>..<reserved-1F88F>
-1F8AE..1F8FF ; Extended_Pictographic# NA [82] (๐Ÿขฎ..๐Ÿฃฟ) <reserved-1F8AE>..<reserved-1F8FF>
-1F90C ; Extended_Pictographic# NA [1] (๐ŸคŒ) <reserved-1F90C>
-1F90D..1F90F ; Extended_Pictographic# 12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
-1F910..1F918 ; Extended_Pictographic# 8.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
-1F919..1F91E ; Extended_Pictographic# 9.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
-1F91F ; Extended_Pictographic# 10.0 [1] (๐ŸคŸ) love-you gesture
-1F920..1F927 ; Extended_Pictographic# 9.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
-1F928..1F92F ; Extended_Pictographic# 10.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
-1F930 ; Extended_Pictographic# 9.0 [1] (๐Ÿคฐ) pregnant woman
-1F931..1F932 ; Extended_Pictographic# 10.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
-1F933..1F93A ; Extended_Pictographic# 9.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
-1F93C..1F93E ; Extended_Pictographic# 9.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
-1F93F ; Extended_Pictographic# 12.0 [1] (๐Ÿคฟ) diving mask
-1F940..1F945 ; Extended_Pictographic# 9.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
-1F947..1F94B ; Extended_Pictographic# 9.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
-1F94C ; Extended_Pictographic# 10.0 [1] (๐ŸฅŒ) curling stone
-1F94D..1F94F ; Extended_Pictographic# 11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
-1F950..1F95E ; Extended_Pictographic# 9.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
-1F95F..1F96B ; Extended_Pictographic# 10.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
-1F96C..1F970 ; Extended_Pictographic# 11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
-1F971 ; Extended_Pictographic# 12.0 [1] (๐Ÿฅฑ) yawning face
-1F972 ; Extended_Pictographic# NA [1] (๐Ÿฅฒ) <reserved-1F972>
-1F973..1F976 ; Extended_Pictographic# 11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
-1F977..1F979 ; Extended_Pictographic# NA [3] (๐Ÿฅท..๐Ÿฅน) <reserved-1F977>..<reserved-1F979>
-1F97A ; Extended_Pictographic# 11.0 [1] (๐Ÿฅบ) pleading face
-1F97B ; Extended_Pictographic# 12.0 [1] (๐Ÿฅป) sari
-1F97C..1F97F ; Extended_Pictographic# 11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
-1F980..1F984 ; Extended_Pictographic# 8.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
-1F985..1F991 ; Extended_Pictographic# 9.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
-1F992..1F997 ; Extended_Pictographic# 10.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
-1F998..1F9A2 ; Extended_Pictographic# 11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
-1F9A3..1F9A4 ; Extended_Pictographic# NA [2] (๐Ÿฆฃ..๐Ÿฆค) <reserved-1F9A3>..<reserved-1F9A4>
-1F9A5..1F9AA ; Extended_Pictographic# 12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
-1F9AB..1F9AD ; Extended_Pictographic# NA [3] (๐Ÿฆซ..๐Ÿฆญ) <reserved-1F9AB>..<reserved-1F9AD>
-1F9AE..1F9AF ; Extended_Pictographic# 12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..probing cane
-1F9B0..1F9B9 ; Extended_Pictographic# 11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
-1F9BA..1F9BF ; Extended_Pictographic# 12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
-1F9C0 ; Extended_Pictographic# 8.0 [1] (๐Ÿง€) cheese wedge
-1F9C1..1F9C2 ; Extended_Pictographic# 11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
-1F9C3..1F9CA ; Extended_Pictographic# 12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice cube
-1F9CB..1F9CC ; Extended_Pictographic# NA [2] (๐Ÿง‹..๐ŸงŒ) <reserved-1F9CB>..<reserved-1F9CC>
-1F9CD..1F9CF ; Extended_Pictographic# 12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
-1F9D0..1F9E6 ; Extended_Pictographic# 10.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
-1F9E7..1F9FF ; Extended_Pictographic# 11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
-1FA00..1FA53 ; Extended_Pictographic# 12.0 [84] (๐Ÿจ€..๐Ÿฉ“) NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
-1FA54..1FA5F ; Extended_Pictographic# NA [12] (๐Ÿฉ”..๐ŸฉŸ) <reserved-1FA54>..<reserved-1FA5F>
-1FA60..1FA6D ; Extended_Pictographic# 11.0 [14] (๐Ÿฉ ..๐Ÿฉญ) XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
-1FA6E..1FA6F ; Extended_Pictographic# NA [2] (๐Ÿฉฎ..๐Ÿฉฏ) <reserved-1FA6E>..<reserved-1FA6F>
-1FA70..1FA73 ; Extended_Pictographic# 12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
-1FA74..1FA77 ; Extended_Pictographic# NA [4] (๐Ÿฉด..๐Ÿฉท) <reserved-1FA74>..<reserved-1FA77>
-1FA78..1FA7A ; Extended_Pictographic# 12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
-1FA7B..1FA7F ; Extended_Pictographic# NA [5] (๐Ÿฉป..๐Ÿฉฟ) <reserved-1FA7B>..<reserved-1FA7F>
-1FA80..1FA82 ; Extended_Pictographic# 12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
-1FA83..1FA8F ; Extended_Pictographic# NA [13] (๐Ÿชƒ..๐Ÿช) <reserved-1FA83>..<reserved-1FA8F>
-1FA90..1FA95 ; Extended_Pictographic# 12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
-1FA96..1FFFD ; Extended_Pictographic# NA[1384] (๐Ÿช–..๐Ÿฟฝ) <reserved-1FA96>..<reserved-1FFFD>
+00A9 ; Extended_Pictographic# E0.6 [1] (ยฉ๏ธ) copyright
+00AE ; Extended_Pictographic# E0.6 [1] (ยฎ๏ธ) registered
+203C ; Extended_Pictographic# E0.6 [1] (โ€ผ๏ธ) double exclamation mark
+2049 ; Extended_Pictographic# E0.6 [1] (โ‰๏ธ) exclamation question mark
+2122 ; Extended_Pictographic# E0.6 [1] (โ„ข๏ธ) trade mark
+2139 ; Extended_Pictographic# E0.6 [1] (โ„น๏ธ) information
+2194..2199 ; Extended_Pictographic# E0.6 [6] (โ†”๏ธ..โ†™๏ธ) left-right arrow..down-left arrow
+21A9..21AA ; Extended_Pictographic# E0.6 [2] (โ†ฉ๏ธ..โ†ช๏ธ) right arrow curving left..left arrow curving right
+231A..231B ; Extended_Pictographic# E0.6 [2] (โŒš..โŒ›) watch..hourglass done
+2328 ; Extended_Pictographic# E1.0 [1] (โŒจ๏ธ) keyboard
+2388 ; Extended_Pictographic# E0.0 [1] (โŽˆ) HELM SYMBOL
+23CF ; Extended_Pictographic# E1.0 [1] (โ๏ธ) eject button
+23E9..23EC ; Extended_Pictographic# E0.6 [4] (โฉ..โฌ) fast-forward button..fast down button
+23ED..23EE ; Extended_Pictographic# E0.7 [2] (โญ๏ธ..โฎ๏ธ) next track button..last track button
+23EF ; Extended_Pictographic# E1.0 [1] (โฏ๏ธ) play or pause button
+23F0 ; Extended_Pictographic# E0.6 [1] (โฐ) alarm clock
+23F1..23F2 ; Extended_Pictographic# E1.0 [2] (โฑ๏ธ..โฒ๏ธ) stopwatch..timer clock
+23F3 ; Extended_Pictographic# E0.6 [1] (โณ) hourglass not done
+23F8..23FA ; Extended_Pictographic# E0.7 [3] (โธ๏ธ..โบ๏ธ) pause button..record button
+24C2 ; Extended_Pictographic# E0.6 [1] (โ“‚๏ธ) circled M
+25AA..25AB ; Extended_Pictographic# E0.6 [2] (โ–ช๏ธ..โ–ซ๏ธ) black small square..white small square
+25B6 ; Extended_Pictographic# E0.6 [1] (โ–ถ๏ธ) play button
+25C0 ; Extended_Pictographic# E0.6 [1] (โ—€๏ธ) reverse button
+25FB..25FE ; Extended_Pictographic# E0.6 [4] (โ—ป๏ธ..โ—พ) white medium square..black medium-small square
+2600..2601 ; Extended_Pictographic# E0.6 [2] (โ˜€๏ธ..โ˜๏ธ) sun..cloud
+2602..2603 ; Extended_Pictographic# E0.7 [2] (โ˜‚๏ธ..โ˜ƒ๏ธ) umbrella..snowman
+2604 ; Extended_Pictographic# E1.0 [1] (โ˜„๏ธ) comet
+2605 ; Extended_Pictographic# E0.0 [1] (โ˜…) BLACK STAR
+2607..260D ; Extended_Pictographic# E0.0 [7] (โ˜‡..โ˜) LIGHTNING..OPPOSITION
+260E ; Extended_Pictographic# E0.6 [1] (โ˜Ž๏ธ) telephone
+260F..2610 ; Extended_Pictographic# E0.0 [2] (โ˜..โ˜) WHITE TELEPHONE..BALLOT BOX
+2611 ; Extended_Pictographic# E0.6 [1] (โ˜‘๏ธ) check box with check
+2612 ; Extended_Pictographic# E0.0 [1] (โ˜’) BALLOT BOX WITH X
+2614..2615 ; Extended_Pictographic# E0.6 [2] (โ˜”..โ˜•) umbrella with rain drops..hot beverage
+2616..2617 ; Extended_Pictographic# E0.0 [2] (โ˜–..โ˜—) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+2618 ; Extended_Pictographic# E1.0 [1] (โ˜˜๏ธ) shamrock
+2619..261C ; Extended_Pictographic# E0.0 [4] (โ˜™..โ˜œ) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX
+261D ; Extended_Pictographic# E0.6 [1] (โ˜๏ธ) index pointing up
+261E..261F ; Extended_Pictographic# E0.0 [2] (โ˜ž..โ˜Ÿ) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
+2620 ; Extended_Pictographic# E1.0 [1] (โ˜ ๏ธ) skull and crossbones
+2621 ; Extended_Pictographic# E0.0 [1] (โ˜ก) CAUTION SIGN
+2622..2623 ; Extended_Pictographic# E1.0 [2] (โ˜ข๏ธ..โ˜ฃ๏ธ) radioactive..biohazard
+2624..2625 ; Extended_Pictographic# E0.0 [2] (โ˜ค..โ˜ฅ) CADUCEUS..ANKH
+2626 ; Extended_Pictographic# E1.0 [1] (โ˜ฆ๏ธ) orthodox cross
+2627..2629 ; Extended_Pictographic# E0.0 [3] (โ˜ง..โ˜ฉ) CHI RHO..CROSS OF JERUSALEM
+262A ; Extended_Pictographic# E0.7 [1] (โ˜ช๏ธ) star and crescent
+262B..262D ; Extended_Pictographic# E0.0 [3] (โ˜ซ..โ˜ญ) FARSI SYMBOL..HAMMER AND SICKLE
+262E ; Extended_Pictographic# E1.0 [1] (โ˜ฎ๏ธ) peace symbol
+262F ; Extended_Pictographic# E0.7 [1] (โ˜ฏ๏ธ) yin yang
+2630..2637 ; Extended_Pictographic# E0.0 [8] (โ˜ฐ..โ˜ท) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH
+2638..2639 ; Extended_Pictographic# E0.7 [2] (โ˜ธ๏ธ..โ˜น๏ธ) wheel of dharma..frowning face
+263A ; Extended_Pictographic# E0.6 [1] (โ˜บ๏ธ) smiling face
+263B..263F ; Extended_Pictographic# E0.0 [5] (โ˜ป..โ˜ฟ) BLACK SMILING FACE..MERCURY
+2640 ; Extended_Pictographic# E4.0 [1] (โ™€๏ธ) female sign
+2641 ; Extended_Pictographic# E0.0 [1] (โ™) EARTH
+2642 ; Extended_Pictographic# E4.0 [1] (โ™‚๏ธ) male sign
+2643..2647 ; Extended_Pictographic# E0.0 [5] (โ™ƒ..โ™‡) JUPITER..PLUTO
+2648..2653 ; Extended_Pictographic# E0.6 [12] (โ™ˆ..โ™“) Aries..Pisces
+2654..265E ; Extended_Pictographic# E0.0 [11] (โ™”..โ™ž) WHITE CHESS KING..BLACK CHESS KNIGHT
+265F ; Extended_Pictographic# E11.0 [1] (โ™Ÿ๏ธ) chess pawn
+2660 ; Extended_Pictographic# E0.6 [1] (โ™ ๏ธ) spade suit
+2661..2662 ; Extended_Pictographic# E0.0 [2] (โ™ก..โ™ข) WHITE HEART SUIT..WHITE DIAMOND SUIT
+2663 ; Extended_Pictographic# E0.6 [1] (โ™ฃ๏ธ) club suit
+2664 ; Extended_Pictographic# E0.0 [1] (โ™ค) WHITE SPADE SUIT
+2665..2666 ; Extended_Pictographic# E0.6 [2] (โ™ฅ๏ธ..โ™ฆ๏ธ) heart suit..diamond suit
+2667 ; Extended_Pictographic# E0.0 [1] (โ™ง) WHITE CLUB SUIT
+2668 ; Extended_Pictographic# E0.6 [1] (โ™จ๏ธ) hot springs
+2669..267A ; Extended_Pictographic# E0.0 [18] (โ™ฉ..โ™บ) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS
+267B ; Extended_Pictographic# E0.6 [1] (โ™ป๏ธ) recycling symbol
+267C..267D ; Extended_Pictographic# E0.0 [2] (โ™ผ..โ™ฝ) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+267E ; Extended_Pictographic# E11.0 [1] (โ™พ๏ธ) infinity
+267F ; Extended_Pictographic# E0.6 [1] (โ™ฟ) wheelchair symbol
+2680..2685 ; Extended_Pictographic# E0.0 [6] (โš€..โš…) DIE FACE-1..DIE FACE-6
+2690..2691 ; Extended_Pictographic# E0.0 [2] (โš..โš‘) WHITE FLAG..BLACK FLAG
+2692 ; Extended_Pictographic# E1.0 [1] (โš’๏ธ) hammer and pick
+2693 ; Extended_Pictographic# E0.6 [1] (โš“) anchor
+2694 ; Extended_Pictographic# E1.0 [1] (โš”๏ธ) crossed swords
+2695 ; Extended_Pictographic# E4.0 [1] (โš•๏ธ) medical symbol
+2696..2697 ; Extended_Pictographic# E1.0 [2] (โš–๏ธ..โš—๏ธ) balance scale..alembic
+2698 ; Extended_Pictographic# E0.0 [1] (โš˜) FLOWER
+2699 ; Extended_Pictographic# E1.0 [1] (โš™๏ธ) gear
+269A ; Extended_Pictographic# E0.0 [1] (โšš) STAFF OF HERMES
+269B..269C ; Extended_Pictographic# E1.0 [2] (โš›๏ธ..โšœ๏ธ) atom symbol..fleur-de-lis
+269D..269F ; Extended_Pictographic# E0.0 [3] (โš..โšŸ) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT
+26A0..26A1 ; Extended_Pictographic# E0.6 [2] (โš ๏ธ..โšก) warning..high voltage
+26A2..26A6 ; Extended_Pictographic# E0.0 [5] (โšข..โšฆ) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN
+26A7 ; Extended_Pictographic# E13.0 [1] (โšง๏ธ) transgender symbol
+26A8..26A9 ; Extended_Pictographic# E0.0 [2] (โšจ..โšฉ) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+26AA..26AB ; Extended_Pictographic# E0.6 [2] (โšช..โšซ) white circle..black circle
+26AC..26AF ; Extended_Pictographic# E0.0 [4] (โšฌ..โšฏ) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL
+26B0..26B1 ; Extended_Pictographic# E1.0 [2] (โšฐ๏ธ..โšฑ๏ธ) coffin..funeral urn
+26B2..26BC ; Extended_Pictographic# E0.0 [11] (โšฒ..โšผ) NEUTER..SESQUIQUADRATE
+26BD..26BE ; Extended_Pictographic# E0.6 [2] (โšฝ..โšพ) soccer ball..baseball
+26BF..26C3 ; Extended_Pictographic# E0.0 [5] (โšฟ..โ›ƒ) SQUARED KEY..BLACK DRAUGHTS KING
+26C4..26C5 ; Extended_Pictographic# E0.6 [2] (โ›„..โ›…) snowman without snow..sun behind cloud
+26C6..26C7 ; Extended_Pictographic# E0.0 [2] (โ›†..โ›‡) RAIN..BLACK SNOWMAN
+26C8 ; Extended_Pictographic# E0.7 [1] (โ›ˆ๏ธ) cloud with lightning and rain
+26C9..26CD ; Extended_Pictographic# E0.0 [5] (โ›‰..โ›) TURNED WHITE SHOGI PIECE..DISABLED CAR
+26CE ; Extended_Pictographic# E0.6 [1] (โ›Ž) Ophiuchus
+26CF ; Extended_Pictographic# E0.7 [1] (โ›๏ธ) pick
+26D0 ; Extended_Pictographic# E0.0 [1] (โ›) CAR SLIDING
+26D1 ; Extended_Pictographic# E0.7 [1] (โ›‘๏ธ) rescue workerโ€™s helmet
+26D2 ; Extended_Pictographic# E0.0 [1] (โ›’) CIRCLED CROSSING LANES
+26D3 ; Extended_Pictographic# E0.7 [1] (โ›“๏ธ) chains
+26D4 ; Extended_Pictographic# E0.6 [1] (โ›”) no entry
+26D5..26E8 ; Extended_Pictographic# E0.0 [20] (โ›•..โ›จ) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD
+26E9 ; Extended_Pictographic# E0.7 [1] (โ›ฉ๏ธ) shinto shrine
+26EA ; Extended_Pictographic# E0.6 [1] (โ›ช) church
+26EB..26EF ; Extended_Pictographic# E0.0 [5] (โ›ซ..โ›ฏ) CASTLE..MAP SYMBOL FOR LIGHTHOUSE
+26F0..26F1 ; Extended_Pictographic# E0.7 [2] (โ›ฐ๏ธ..โ›ฑ๏ธ) mountain..umbrella on ground
+26F2..26F3 ; Extended_Pictographic# E0.6 [2] (โ›ฒ..โ›ณ) fountain..flag in hole
+26F4 ; Extended_Pictographic# E0.7 [1] (โ›ด๏ธ) ferry
+26F5 ; Extended_Pictographic# E0.6 [1] (โ›ต) sailboat
+26F6 ; Extended_Pictographic# E0.0 [1] (โ›ถ) SQUARE FOUR CORNERS
+26F7..26F9 ; Extended_Pictographic# E0.7 [3] (โ›ท๏ธ..โ›น๏ธ) skier..person bouncing ball
+26FA ; Extended_Pictographic# E0.6 [1] (โ›บ) tent
+26FB..26FC ; Extended_Pictographic# E0.0 [2] (โ›ป..โ›ผ) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+26FD ; Extended_Pictographic# E0.6 [1] (โ›ฝ) fuel pump
+26FE..2701 ; Extended_Pictographic# E0.0 [4] (โ›พ..โœ) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS
+2702 ; Extended_Pictographic# E0.6 [1] (โœ‚๏ธ) scissors
+2703..2704 ; Extended_Pictographic# E0.0 [2] (โœƒ..โœ„) LOWER BLADE SCISSORS..WHITE SCISSORS
+2705 ; Extended_Pictographic# E0.6 [1] (โœ…) check mark button
+2708..270C ; Extended_Pictographic# E0.6 [5] (โœˆ๏ธ..โœŒ๏ธ) airplane..victory hand
+270D ; Extended_Pictographic# E0.7 [1] (โœ๏ธ) writing hand
+270E ; Extended_Pictographic# E0.0 [1] (โœŽ) LOWER RIGHT PENCIL
+270F ; Extended_Pictographic# E0.6 [1] (โœ๏ธ) pencil
+2710..2711 ; Extended_Pictographic# E0.0 [2] (โœ..โœ‘) UPPER RIGHT PENCIL..WHITE NIB
+2712 ; Extended_Pictographic# E0.6 [1] (โœ’๏ธ) black nib
+2714 ; Extended_Pictographic# E0.6 [1] (โœ”๏ธ) check mark
+2716 ; Extended_Pictographic# E0.6 [1] (โœ–๏ธ) multiply
+271D ; Extended_Pictographic# E0.7 [1] (โœ๏ธ) latin cross
+2721 ; Extended_Pictographic# E0.7 [1] (โœก๏ธ) star of David
+2728 ; Extended_Pictographic# E0.6 [1] (โœจ) sparkles
+2733..2734 ; Extended_Pictographic# E0.6 [2] (โœณ๏ธ..โœด๏ธ) eight-spoked asterisk..eight-pointed star
+2744 ; Extended_Pictographic# E0.6 [1] (โ„๏ธ) snowflake
+2747 ; Extended_Pictographic# E0.6 [1] (โ‡๏ธ) sparkle
+274C ; Extended_Pictographic# E0.6 [1] (โŒ) cross mark
+274E ; Extended_Pictographic# E0.6 [1] (โŽ) cross mark button
+2753..2755 ; Extended_Pictographic# E0.6 [3] (โ“..โ•) question mark..white exclamation mark
+2757 ; Extended_Pictographic# E0.6 [1] (โ—) exclamation mark
+2763 ; Extended_Pictographic# E1.0 [1] (โฃ๏ธ) heart exclamation
+2764 ; Extended_Pictographic# E0.6 [1] (โค๏ธ) red heart
+2765..2767 ; Extended_Pictographic# E0.0 [3] (โฅ..โง) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
+2795..2797 ; Extended_Pictographic# E0.6 [3] (โž•..โž—) plus..divide
+27A1 ; Extended_Pictographic# E0.6 [1] (โžก๏ธ) right arrow
+27B0 ; Extended_Pictographic# E0.6 [1] (โžฐ) curly loop
+27BF ; Extended_Pictographic# E1.0 [1] (โžฟ) double curly loop
+2934..2935 ; Extended_Pictographic# E0.6 [2] (โคด๏ธ..โคต๏ธ) right arrow curving up..right arrow curving down
+2B05..2B07 ; Extended_Pictographic# E0.6 [3] (โฌ…๏ธ..โฌ‡๏ธ) left arrow..down arrow
+2B1B..2B1C ; Extended_Pictographic# E0.6 [2] (โฌ›..โฌœ) black large square..white large square
+2B50 ; Extended_Pictographic# E0.6 [1] (โญ) star
+2B55 ; Extended_Pictographic# E0.6 [1] (โญ•) hollow red circle
+3030 ; Extended_Pictographic# E0.6 [1] (ใ€ฐ๏ธ) wavy dash
+303D ; Extended_Pictographic# E0.6 [1] (ใ€ฝ๏ธ) part alternation mark
+3297 ; Extended_Pictographic# E0.6 [1] (ใŠ—๏ธ) Japanese โ€œcongratulationsโ€ button
+3299 ; Extended_Pictographic# E0.6 [1] (ใŠ™๏ธ) Japanese โ€œsecretโ€ button
+1F000..1F003 ; Extended_Pictographic# E0.0 [4] (๐Ÿ€€..๐Ÿ€ƒ) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+1F004 ; Extended_Pictographic# E0.6 [1] (๐Ÿ€„) mahjong red dragon
+1F005..1F0CE ; Extended_Pictographic# E0.0 [202] (๐Ÿ€…..๐ŸƒŽ) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS
+1F0CF ; Extended_Pictographic# E0.6 [1] (๐Ÿƒ) joker
+1F0D0..1F0FF ; Extended_Pictographic# E0.0 [48] (๐Ÿƒ..๐Ÿƒฟ) <reserved-1F0D0>..<reserved-1F0FF>
+1F10D..1F10F ; Extended_Pictographic# E0.0 [3] (๐Ÿ„..๐Ÿ„) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+1F12F ; Extended_Pictographic# E0.0 [1] (๐Ÿ„ฏ) COPYLEFT SYMBOL
+1F16C..1F16F ; Extended_Pictographic# E0.0 [4] (๐Ÿ…ฌ..๐Ÿ…ฏ) RAISED MR SIGN..CIRCLED HUMAN FIGURE
+1F170..1F171 ; Extended_Pictographic# E0.6 [2] (๐Ÿ…ฐ๏ธ..๐Ÿ…ฑ๏ธ) A button (blood type)..B button (blood type)
+1F17E..1F17F ; Extended_Pictographic# E0.6 [2] (๐Ÿ…พ๏ธ..๐Ÿ…ฟ๏ธ) O button (blood type)..P button
+1F18E ; Extended_Pictographic# E0.6 [1] (๐Ÿ†Ž) AB button (blood type)
+1F191..1F19A ; Extended_Pictographic# E0.6 [10] (๐Ÿ†‘..๐Ÿ†š) CL button..VS button
+1F1AD..1F1E5 ; Extended_Pictographic# E0.0 [57] (๐Ÿ†ญ..๐Ÿ‡ฅ) MASK WORK SYMBOL..<reserved-1F1E5>
+1F201..1F202 ; Extended_Pictographic# E0.6 [2] (๐Ÿˆ..๐Ÿˆ‚๏ธ) Japanese โ€œhereโ€ button..Japanese โ€œservice chargeโ€ button
+1F203..1F20F ; Extended_Pictographic# E0.0 [13] (๐Ÿˆƒ..๐Ÿˆ) <reserved-1F203>..<reserved-1F20F>
+1F21A ; Extended_Pictographic# E0.6 [1] (๐Ÿˆš) Japanese โ€œfree of chargeโ€ button
+1F22F ; Extended_Pictographic# E0.6 [1] (๐Ÿˆฏ) Japanese โ€œreservedโ€ button
+1F232..1F23A ; Extended_Pictographic# E0.6 [9] (๐Ÿˆฒ..๐Ÿˆบ) Japanese โ€œprohibitedโ€ button..Japanese โ€œopen for businessโ€ button
+1F23C..1F23F ; Extended_Pictographic# E0.0 [4] (๐Ÿˆผ..๐Ÿˆฟ) <reserved-1F23C>..<reserved-1F23F>
+1F249..1F24F ; Extended_Pictographic# E0.0 [7] (๐Ÿ‰‰..๐Ÿ‰) <reserved-1F249>..<reserved-1F24F>
+1F250..1F251 ; Extended_Pictographic# E0.6 [2] (๐Ÿ‰..๐Ÿ‰‘) Japanese โ€œbargainโ€ button..Japanese โ€œacceptableโ€ button
+1F252..1F2FF ; Extended_Pictographic# E0.0 [174] (๐Ÿ‰’..๐Ÿ‹ฟ) <reserved-1F252>..<reserved-1F2FF>
+1F300..1F30C ; Extended_Pictographic# E0.6 [13] (๐ŸŒ€..๐ŸŒŒ) cyclone..milky way
+1F30D..1F30E ; Extended_Pictographic# E0.7 [2] (๐ŸŒ..๐ŸŒŽ) globe showing Europe-Africa..globe showing Americas
+1F30F ; Extended_Pictographic# E0.6 [1] (๐ŸŒ) globe showing Asia-Australia
+1F310 ; Extended_Pictographic# E1.0 [1] (๐ŸŒ) globe with meridians
+1F311 ; Extended_Pictographic# E0.6 [1] (๐ŸŒ‘) new moon
+1F312 ; Extended_Pictographic# E1.0 [1] (๐ŸŒ’) waxing crescent moon
+1F313..1F315 ; Extended_Pictographic# E0.6 [3] (๐ŸŒ“..๐ŸŒ•) first quarter moon..full moon
+1F316..1F318 ; Extended_Pictographic# E1.0 [3] (๐ŸŒ–..๐ŸŒ˜) waning gibbous moon..waning crescent moon
+1F319 ; Extended_Pictographic# E0.6 [1] (๐ŸŒ™) crescent moon
+1F31A ; Extended_Pictographic# E1.0 [1] (๐ŸŒš) new moon face
+1F31B ; Extended_Pictographic# E0.6 [1] (๐ŸŒ›) first quarter moon face
+1F31C ; Extended_Pictographic# E0.7 [1] (๐ŸŒœ) last quarter moon face
+1F31D..1F31E ; Extended_Pictographic# E1.0 [2] (๐ŸŒ..๐ŸŒž) full moon face..sun with face
+1F31F..1F320 ; Extended_Pictographic# E0.6 [2] (๐ŸŒŸ..๐ŸŒ ) glowing star..shooting star
+1F321 ; Extended_Pictographic# E0.7 [1] (๐ŸŒก๏ธ) thermometer
+1F322..1F323 ; Extended_Pictographic# E0.0 [2] (๐ŸŒข..๐ŸŒฃ) BLACK DROPLET..WHITE SUN
+1F324..1F32C ; Extended_Pictographic# E0.7 [9] (๐ŸŒค๏ธ..๐ŸŒฌ๏ธ) sun behind small cloud..wind face
+1F32D..1F32F ; Extended_Pictographic# E1.0 [3] (๐ŸŒญ..๐ŸŒฏ) hot dog..burrito
+1F330..1F331 ; Extended_Pictographic# E0.6 [2] (๐ŸŒฐ..๐ŸŒฑ) chestnut..seedling
+1F332..1F333 ; Extended_Pictographic# E1.0 [2] (๐ŸŒฒ..๐ŸŒณ) evergreen tree..deciduous tree
+1F334..1F335 ; Extended_Pictographic# E0.6 [2] (๐ŸŒด..๐ŸŒต) palm tree..cactus
+1F336 ; Extended_Pictographic# E0.7 [1] (๐ŸŒถ๏ธ) hot pepper
+1F337..1F34A ; Extended_Pictographic# E0.6 [20] (๐ŸŒท..๐ŸŠ) tulip..tangerine
+1F34B ; Extended_Pictographic# E1.0 [1] (๐Ÿ‹) lemon
+1F34C..1F34F ; Extended_Pictographic# E0.6 [4] (๐ŸŒ..๐Ÿ) banana..green apple
+1F350 ; Extended_Pictographic# E1.0 [1] (๐Ÿ) pear
+1F351..1F37B ; Extended_Pictographic# E0.6 [43] (๐Ÿ‘..๐Ÿป) peach..clinking beer mugs
+1F37C ; Extended_Pictographic# E1.0 [1] (๐Ÿผ) baby bottle
+1F37D ; Extended_Pictographic# E0.7 [1] (๐Ÿฝ๏ธ) fork and knife with plate
+1F37E..1F37F ; Extended_Pictographic# E1.0 [2] (๐Ÿพ..๐Ÿฟ) bottle with popping cork..popcorn
+1F380..1F393 ; Extended_Pictographic# E0.6 [20] (๐ŸŽ€..๐ŸŽ“) ribbon..graduation cap
+1F394..1F395 ; Extended_Pictographic# E0.0 [2] (๐ŸŽ”..๐ŸŽ•) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS
+1F396..1F397 ; Extended_Pictographic# E0.7 [2] (๐ŸŽ–๏ธ..๐ŸŽ—๏ธ) military medal..reminder ribbon
+1F398 ; Extended_Pictographic# E0.0 [1] (๐ŸŽ˜) MUSICAL KEYBOARD WITH JACKS
+1F399..1F39B ; Extended_Pictographic# E0.7 [3] (๐ŸŽ™๏ธ..๐ŸŽ›๏ธ) studio microphone..control knobs
+1F39C..1F39D ; Extended_Pictographic# E0.0 [2] (๐ŸŽœ..๐ŸŽ) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
+1F39E..1F39F ; Extended_Pictographic# E0.7 [2] (๐ŸŽž๏ธ..๐ŸŽŸ๏ธ) film frames..admission tickets
+1F3A0..1F3C4 ; Extended_Pictographic# E0.6 [37] (๐ŸŽ ..๐Ÿ„) carousel horse..person surfing
+1F3C5 ; Extended_Pictographic# E1.0 [1] (๐Ÿ…) sports medal
+1F3C6 ; Extended_Pictographic# E0.6 [1] (๐Ÿ†) trophy
+1F3C7 ; Extended_Pictographic# E1.0 [1] (๐Ÿ‡) horse racing
+1F3C8 ; Extended_Pictographic# E0.6 [1] (๐Ÿˆ) american football
+1F3C9 ; Extended_Pictographic# E1.0 [1] (๐Ÿ‰) rugby football
+1F3CA ; Extended_Pictographic# E0.6 [1] (๐ŸŠ) person swimming
+1F3CB..1F3CE ; Extended_Pictographic# E0.7 [4] (๐Ÿ‹๏ธ..๐ŸŽ๏ธ) person lifting weights..racing car
+1F3CF..1F3D3 ; Extended_Pictographic# E1.0 [5] (๐Ÿ..๐Ÿ“) cricket game..ping pong
+1F3D4..1F3DF ; Extended_Pictographic# E0.7 [12] (๐Ÿ”๏ธ..๐ŸŸ๏ธ) snow-capped mountain..stadium
+1F3E0..1F3E3 ; Extended_Pictographic# E0.6 [4] (๐Ÿ ..๐Ÿฃ) house..Japanese post office
+1F3E4 ; Extended_Pictographic# E1.0 [1] (๐Ÿค) post office
+1F3E5..1F3F0 ; Extended_Pictographic# E0.6 [12] (๐Ÿฅ..๐Ÿฐ) hospital..castle
+1F3F1..1F3F2 ; Extended_Pictographic# E0.0 [2] (๐Ÿฑ..๐Ÿฒ) WHITE PENNANT..BLACK PENNANT
+1F3F3 ; Extended_Pictographic# E0.7 [1] (๐Ÿณ๏ธ) white flag
+1F3F4 ; Extended_Pictographic# E1.0 [1] (๐Ÿด) black flag
+1F3F5 ; Extended_Pictographic# E0.7 [1] (๐Ÿต๏ธ) rosette
+1F3F6 ; Extended_Pictographic# E0.0 [1] (๐Ÿถ) BLACK ROSETTE
+1F3F7 ; Extended_Pictographic# E0.7 [1] (๐Ÿท๏ธ) label
+1F3F8..1F3FA ; Extended_Pictographic# E1.0 [3] (๐Ÿธ..๐Ÿบ) badminton..amphora
+1F400..1F407 ; Extended_Pictographic# E1.0 [8] (๐Ÿ€..๐Ÿ‡) rat..rabbit
+1F408 ; Extended_Pictographic# E0.7 [1] (๐Ÿˆ) cat
+1F409..1F40B ; Extended_Pictographic# E1.0 [3] (๐Ÿ‰..๐Ÿ‹) dragon..whale
+1F40C..1F40E ; Extended_Pictographic# E0.6 [3] (๐ŸŒ..๐ŸŽ) snail..horse
+1F40F..1F410 ; Extended_Pictographic# E1.0 [2] (๐Ÿ..๐Ÿ) ram..goat
+1F411..1F412 ; Extended_Pictographic# E0.6 [2] (๐Ÿ‘..๐Ÿ’) ewe..monkey
+1F413 ; Extended_Pictographic# E1.0 [1] (๐Ÿ“) rooster
+1F414 ; Extended_Pictographic# E0.6 [1] (๐Ÿ”) chicken
+1F415 ; Extended_Pictographic# E0.7 [1] (๐Ÿ•) dog
+1F416 ; Extended_Pictographic# E1.0 [1] (๐Ÿ–) pig
+1F417..1F429 ; Extended_Pictographic# E0.6 [19] (๐Ÿ—..๐Ÿฉ) boar..poodle
+1F42A ; Extended_Pictographic# E1.0 [1] (๐Ÿช) camel
+1F42B..1F43E ; Extended_Pictographic# E0.6 [20] (๐Ÿซ..๐Ÿพ) two-hump camel..paw prints
+1F43F ; Extended_Pictographic# E0.7 [1] (๐Ÿฟ๏ธ) chipmunk
+1F440 ; Extended_Pictographic# E0.6 [1] (๐Ÿ‘€) eyes
+1F441 ; Extended_Pictographic# E0.7 [1] (๐Ÿ‘๏ธ) eye
+1F442..1F464 ; Extended_Pictographic# E0.6 [35] (๐Ÿ‘‚..๐Ÿ‘ค) ear..bust in silhouette
+1F465 ; Extended_Pictographic# E1.0 [1] (๐Ÿ‘ฅ) busts in silhouette
+1F466..1F46B ; Extended_Pictographic# E0.6 [6] (๐Ÿ‘ฆ..๐Ÿ‘ซ) boy..woman and man holding hands
+1F46C..1F46D ; Extended_Pictographic# E1.0 [2] (๐Ÿ‘ฌ..๐Ÿ‘ญ) men holding hands..women holding hands
+1F46E..1F4AC ; Extended_Pictographic# E0.6 [63] (๐Ÿ‘ฎ..๐Ÿ’ฌ) police officer..speech balloon
+1F4AD ; Extended_Pictographic# E1.0 [1] (๐Ÿ’ญ) thought balloon
+1F4AE..1F4B5 ; Extended_Pictographic# E0.6 [8] (๐Ÿ’ฎ..๐Ÿ’ต) white flower..dollar banknote
+1F4B6..1F4B7 ; Extended_Pictographic# E1.0 [2] (๐Ÿ’ถ..๐Ÿ’ท) euro banknote..pound banknote
+1F4B8..1F4EB ; Extended_Pictographic# E0.6 [52] (๐Ÿ’ธ..๐Ÿ“ซ) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Extended_Pictographic# E0.7 [2] (๐Ÿ“ฌ..๐Ÿ“ญ) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Extended_Pictographic# E0.6 [1] (๐Ÿ“ฎ) postbox
+1F4EF ; Extended_Pictographic# E1.0 [1] (๐Ÿ“ฏ) postal horn
+1F4F0..1F4F4 ; Extended_Pictographic# E0.6 [5] (๐Ÿ“ฐ..๐Ÿ“ด) newspaper..mobile phone off
+1F4F5 ; Extended_Pictographic# E1.0 [1] (๐Ÿ“ต) no mobile phones
+1F4F6..1F4F7 ; Extended_Pictographic# E0.6 [2] (๐Ÿ“ถ..๐Ÿ“ท) antenna bars..camera
+1F4F8 ; Extended_Pictographic# E1.0 [1] (๐Ÿ“ธ) camera with flash
+1F4F9..1F4FC ; Extended_Pictographic# E0.6 [4] (๐Ÿ“น..๐Ÿ“ผ) video camera..videocassette
+1F4FD ; Extended_Pictographic# E0.7 [1] (๐Ÿ“ฝ๏ธ) film projector
+1F4FE ; Extended_Pictographic# E0.0 [1] (๐Ÿ“พ) PORTABLE STEREO
+1F4FF..1F502 ; Extended_Pictographic# E1.0 [4] (๐Ÿ“ฟ..๐Ÿ”‚) prayer beads..repeat single button
+1F503 ; Extended_Pictographic# E0.6 [1] (๐Ÿ”ƒ) clockwise vertical arrows
+1F504..1F507 ; Extended_Pictographic# E1.0 [4] (๐Ÿ”„..๐Ÿ”‡) counterclockwise arrows button..muted speaker
+1F508 ; Extended_Pictographic# E0.7 [1] (๐Ÿ”ˆ) speaker low volume
+1F509 ; Extended_Pictographic# E1.0 [1] (๐Ÿ”‰) speaker medium volume
+1F50A..1F514 ; Extended_Pictographic# E0.6 [11] (๐Ÿ”Š..๐Ÿ””) speaker high volume..bell
+1F515 ; Extended_Pictographic# E1.0 [1] (๐Ÿ”•) bell with slash
+1F516..1F52B ; Extended_Pictographic# E0.6 [22] (๐Ÿ”–..๐Ÿ”ซ) bookmark..pistol
+1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (๐Ÿ”ฌ..๐Ÿ”ญ) microscope..telescope
+1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (๐Ÿ”ฎ..๐Ÿ”ฝ) crystal ball..downwards button
+1F546..1F548 ; Extended_Pictographic# E0.0 [3] (๐Ÿ•†..๐Ÿ•ˆ) WHITE LATIN CROSS..CELTIC CROSS
+1F549..1F54A ; Extended_Pictographic# E0.7 [2] (๐Ÿ•‰๏ธ..๐Ÿ•Š๏ธ) om..dove
+1F54B..1F54E ; Extended_Pictographic# E1.0 [4] (๐Ÿ•‹..๐Ÿ•Ž) kaaba..menorah
+1F54F ; Extended_Pictographic# E0.0 [1] (๐Ÿ•) BOWL OF HYGIEIA
+1F550..1F55B ; Extended_Pictographic# E0.6 [12] (๐Ÿ•..๐Ÿ•›) one oโ€™clock..twelve oโ€™clock
+1F55C..1F567 ; Extended_Pictographic# E0.7 [12] (๐Ÿ•œ..๐Ÿ•ง) one-thirty..twelve-thirty
+1F568..1F56E ; Extended_Pictographic# E0.0 [7] (๐Ÿ•จ..๐Ÿ•ฎ) RIGHT SPEAKER..BOOK
+1F56F..1F570 ; Extended_Pictographic# E0.7 [2] (๐Ÿ•ฏ๏ธ..๐Ÿ•ฐ๏ธ) candle..mantelpiece clock
+1F571..1F572 ; Extended_Pictographic# E0.0 [2] (๐Ÿ•ฑ..๐Ÿ•ฒ) BLACK SKULL AND CROSSBONES..NO PIRACY
+1F573..1F579 ; Extended_Pictographic# E0.7 [7] (๐Ÿ•ณ๏ธ..๐Ÿ•น๏ธ) hole..joystick
+1F57A ; Extended_Pictographic# E3.0 [1] (๐Ÿ•บ) man dancing
+1F57B..1F586 ; Extended_Pictographic# E0.0 [12] (๐Ÿ•ป..๐Ÿ–†) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE
+1F587 ; Extended_Pictographic# E0.7 [1] (๐Ÿ–‡๏ธ) linked paperclips
+1F588..1F589 ; Extended_Pictographic# E0.0 [2] (๐Ÿ–ˆ..๐Ÿ–‰) BLACK PUSHPIN..LOWER LEFT PENCIL
+1F58A..1F58D ; Extended_Pictographic# E0.7 [4] (๐Ÿ–Š๏ธ..๐Ÿ–๏ธ) pen..crayon
+1F58E..1F58F ; Extended_Pictographic# E0.0 [2] (๐Ÿ–Ž..๐Ÿ–) LEFT WRITING HAND..TURNED OK HAND SIGN
+1F590 ; Extended_Pictographic# E0.7 [1] (๐Ÿ–๏ธ) hand with fingers splayed
+1F591..1F594 ; Extended_Pictographic# E0.0 [4] (๐Ÿ–‘..๐Ÿ–”) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
+1F595..1F596 ; Extended_Pictographic# E1.0 [2] (๐Ÿ–•..๐Ÿ––) middle finger..vulcan salute
+1F597..1F5A3 ; Extended_Pictographic# E0.0 [13] (๐Ÿ–—..๐Ÿ–ฃ) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+1F5A4 ; Extended_Pictographic# E3.0 [1] (๐Ÿ–ค) black heart
+1F5A5 ; Extended_Pictographic# E0.7 [1] (๐Ÿ–ฅ๏ธ) desktop computer
+1F5A6..1F5A7 ; Extended_Pictographic# E0.0 [2] (๐Ÿ–ฆ..๐Ÿ–ง) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS
+1F5A8 ; Extended_Pictographic# E0.7 [1] (๐Ÿ–จ๏ธ) printer
+1F5A9..1F5B0 ; Extended_Pictographic# E0.0 [8] (๐Ÿ–ฉ..๐Ÿ–ฐ) POCKET CALCULATOR..TWO BUTTON MOUSE
+1F5B1..1F5B2 ; Extended_Pictographic# E0.7 [2] (๐Ÿ–ฑ๏ธ..๐Ÿ–ฒ๏ธ) computer mouse..trackball
+1F5B3..1F5BB ; Extended_Pictographic# E0.0 [9] (๐Ÿ–ณ..๐Ÿ–ป) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE
+1F5BC ; Extended_Pictographic# E0.7 [1] (๐Ÿ–ผ๏ธ) framed picture
+1F5BD..1F5C1 ; Extended_Pictographic# E0.0 [5] (๐Ÿ–ฝ..๐Ÿ—) FRAME WITH TILES..OPEN FOLDER
+1F5C2..1F5C4 ; Extended_Pictographic# E0.7 [3] (๐Ÿ—‚๏ธ..๐Ÿ—„๏ธ) card index dividers..file cabinet
+1F5C5..1F5D0 ; Extended_Pictographic# E0.0 [12] (๐Ÿ—…..๐Ÿ—) EMPTY NOTE..PAGES
+1F5D1..1F5D3 ; Extended_Pictographic# E0.7 [3] (๐Ÿ—‘๏ธ..๐Ÿ—“๏ธ) wastebasket..spiral calendar
+1F5D4..1F5DB ; Extended_Pictographic# E0.0 [8] (๐Ÿ—”..๐Ÿ—›) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
+1F5DC..1F5DE ; Extended_Pictographic# E0.7 [3] (๐Ÿ—œ๏ธ..๐Ÿ—ž๏ธ) clamp..rolled-up newspaper
+1F5DF..1F5E0 ; Extended_Pictographic# E0.0 [2] (๐Ÿ—Ÿ..๐Ÿ— ) PAGE WITH CIRCLED TEXT..STOCK CHART
+1F5E1 ; Extended_Pictographic# E0.7 [1] (๐Ÿ—ก๏ธ) dagger
+1F5E2 ; Extended_Pictographic# E0.0 [1] (๐Ÿ—ข) LIPS
+1F5E3 ; Extended_Pictographic# E0.7 [1] (๐Ÿ—ฃ๏ธ) speaking head
+1F5E4..1F5E7 ; Extended_Pictographic# E0.0 [4] (๐Ÿ—ค..๐Ÿ—ง) THREE RAYS ABOVE..THREE RAYS RIGHT
+1F5E8 ; Extended_Pictographic# E2.0 [1] (๐Ÿ—จ๏ธ) left speech bubble
+1F5E9..1F5EE ; Extended_Pictographic# E0.0 [6] (๐Ÿ—ฉ..๐Ÿ—ฎ) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE
+1F5EF ; Extended_Pictographic# E0.7 [1] (๐Ÿ—ฏ๏ธ) right anger bubble
+1F5F0..1F5F2 ; Extended_Pictographic# E0.0 [3] (๐Ÿ—ฐ..๐Ÿ—ฒ) MOOD BUBBLE..LIGHTNING MOOD
+1F5F3 ; Extended_Pictographic# E0.7 [1] (๐Ÿ—ณ๏ธ) ballot box with ballot
+1F5F4..1F5F9 ; Extended_Pictographic# E0.0 [6] (๐Ÿ—ด..๐Ÿ—น) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
+1F5FA ; Extended_Pictographic# E0.7 [1] (๐Ÿ—บ๏ธ) world map
+1F5FB..1F5FF ; Extended_Pictographic# E0.6 [5] (๐Ÿ—ป..๐Ÿ—ฟ) mount fuji..moai
+1F600 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜€) grinning face
+1F601..1F606 ; Extended_Pictographic# E0.6 [6] (๐Ÿ˜..๐Ÿ˜†) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Extended_Pictographic# E1.0 [2] (๐Ÿ˜‡..๐Ÿ˜ˆ) smiling face with halo..smiling face with horns
+1F609..1F60D ; Extended_Pictographic# E0.6 [5] (๐Ÿ˜‰..๐Ÿ˜) winking face..smiling face with heart-eyes
+1F60E ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜Ž) smiling face with sunglasses
+1F60F ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜) smirking face
+1F610 ; Extended_Pictographic# E0.7 [1] (๐Ÿ˜) neutral face
+1F611 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜‘) expressionless face
+1F612..1F614 ; Extended_Pictographic# E0.6 [3] (๐Ÿ˜’..๐Ÿ˜”) unamused face..pensive face
+1F615 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜•) confused face
+1F616 ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜–) confounded face
+1F617 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜—) kissing face
+1F618 ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜˜) face blowing a kiss
+1F619 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜™) kissing face with smiling eyes
+1F61A ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜š) kissing face with closed eyes
+1F61B ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜›) face with tongue
+1F61C..1F61E ; Extended_Pictographic# E0.6 [3] (๐Ÿ˜œ..๐Ÿ˜ž) winking face with tongue..disappointed face
+1F61F ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜Ÿ) worried face
+1F620..1F625 ; Extended_Pictographic# E0.6 [6] (๐Ÿ˜ ..๐Ÿ˜ฅ) angry face..sad but relieved face
+1F626..1F627 ; Extended_Pictographic# E1.0 [2] (๐Ÿ˜ฆ..๐Ÿ˜ง) frowning face with open mouth..anguished face
+1F628..1F62B ; Extended_Pictographic# E0.6 [4] (๐Ÿ˜จ..๐Ÿ˜ซ) fearful face..tired face
+1F62C ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜ฌ) grimacing face
+1F62D ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜ญ) loudly crying face
+1F62E..1F62F ; Extended_Pictographic# E1.0 [2] (๐Ÿ˜ฎ..๐Ÿ˜ฏ) face with open mouth..hushed face
+1F630..1F633 ; Extended_Pictographic# E0.6 [4] (๐Ÿ˜ฐ..๐Ÿ˜ณ) anxious face with sweat..flushed face
+1F634 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜ด) sleeping face
+1F635 ; Extended_Pictographic# E0.6 [1] (๐Ÿ˜ต) dizzy face
+1F636 ; Extended_Pictographic# E1.0 [1] (๐Ÿ˜ถ) face without mouth
+1F637..1F640 ; Extended_Pictographic# E0.6 [10] (๐Ÿ˜ท..๐Ÿ™€) face with medical mask..weary cat
+1F641..1F644 ; Extended_Pictographic# E1.0 [4] (๐Ÿ™..๐Ÿ™„) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Extended_Pictographic# E0.6 [11] (๐Ÿ™…..๐Ÿ™) person gesturing NO..folded hands
+1F680 ; Extended_Pictographic# E0.6 [1] (๐Ÿš€) rocket
+1F681..1F682 ; Extended_Pictographic# E1.0 [2] (๐Ÿš..๐Ÿš‚) helicopter..locomotive
+1F683..1F685 ; Extended_Pictographic# E0.6 [3] (๐Ÿšƒ..๐Ÿš…) railway car..bullet train
+1F686 ; Extended_Pictographic# E1.0 [1] (๐Ÿš†) train
+1F687 ; Extended_Pictographic# E0.6 [1] (๐Ÿš‡) metro
+1F688 ; Extended_Pictographic# E1.0 [1] (๐Ÿšˆ) light rail
+1F689 ; Extended_Pictographic# E0.6 [1] (๐Ÿš‰) station
+1F68A..1F68B ; Extended_Pictographic# E1.0 [2] (๐ŸšŠ..๐Ÿš‹) tram..tram car
+1F68C ; Extended_Pictographic# E0.6 [1] (๐ŸšŒ) bus
+1F68D ; Extended_Pictographic# E0.7 [1] (๐Ÿš) oncoming bus
+1F68E ; Extended_Pictographic# E1.0 [1] (๐ŸšŽ) trolleybus
+1F68F ; Extended_Pictographic# E0.6 [1] (๐Ÿš) bus stop
+1F690 ; Extended_Pictographic# E1.0 [1] (๐Ÿš) minibus
+1F691..1F693 ; Extended_Pictographic# E0.6 [3] (๐Ÿš‘..๐Ÿš“) ambulance..police car
+1F694 ; Extended_Pictographic# E0.7 [1] (๐Ÿš”) oncoming police car
+1F695 ; Extended_Pictographic# E0.6 [1] (๐Ÿš•) taxi
+1F696 ; Extended_Pictographic# E1.0 [1] (๐Ÿš–) oncoming taxi
+1F697 ; Extended_Pictographic# E0.6 [1] (๐Ÿš—) automobile
+1F698 ; Extended_Pictographic# E0.7 [1] (๐Ÿš˜) oncoming automobile
+1F699..1F69A ; Extended_Pictographic# E0.6 [2] (๐Ÿš™..๐Ÿšš) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Extended_Pictographic# E1.0 [7] (๐Ÿš›..๐Ÿšก) articulated lorry..aerial tramway
+1F6A2 ; Extended_Pictographic# E0.6 [1] (๐Ÿšข) ship
+1F6A3 ; Extended_Pictographic# E1.0 [1] (๐Ÿšฃ) person rowing boat
+1F6A4..1F6A5 ; Extended_Pictographic# E0.6 [2] (๐Ÿšค..๐Ÿšฅ) speedboat..horizontal traffic light
+1F6A6 ; Extended_Pictographic# E1.0 [1] (๐Ÿšฆ) vertical traffic light
+1F6A7..1F6AD ; Extended_Pictographic# E0.6 [7] (๐Ÿšง..๐Ÿšญ) construction..no smoking
+1F6AE..1F6B1 ; Extended_Pictographic# E1.0 [4] (๐Ÿšฎ..๐Ÿšฑ) litter in bin sign..non-potable water
+1F6B2 ; Extended_Pictographic# E0.6 [1] (๐Ÿšฒ) bicycle
+1F6B3..1F6B5 ; Extended_Pictographic# E1.0 [3] (๐Ÿšณ..๐Ÿšต) no bicycles..person mountain biking
+1F6B6 ; Extended_Pictographic# E0.6 [1] (๐Ÿšถ) person walking
+1F6B7..1F6B8 ; Extended_Pictographic# E1.0 [2] (๐Ÿšท..๐Ÿšธ) no pedestrians..children crossing
+1F6B9..1F6BE ; Extended_Pictographic# E0.6 [6] (๐Ÿšน..๐Ÿšพ) menโ€™s room..water closet
+1F6BF ; Extended_Pictographic# E1.0 [1] (๐Ÿšฟ) shower
+1F6C0 ; Extended_Pictographic# E0.6 [1] (๐Ÿ›€) person taking bath
+1F6C1..1F6C5 ; Extended_Pictographic# E1.0 [5] (๐Ÿ›..๐Ÿ›…) bathtub..left luggage
+1F6C6..1F6CA ; Extended_Pictographic# E0.0 [5] (๐Ÿ›†..๐Ÿ›Š) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL
+1F6CB ; Extended_Pictographic# E0.7 [1] (๐Ÿ›‹๏ธ) couch and lamp
+1F6CC ; Extended_Pictographic# E1.0 [1] (๐Ÿ›Œ) person in bed
+1F6CD..1F6CF ; Extended_Pictographic# E0.7 [3] (๐Ÿ›๏ธ..๐Ÿ›๏ธ) shopping bags..bed
+1F6D0 ; Extended_Pictographic# E1.0 [1] (๐Ÿ›) place of worship
+1F6D1..1F6D2 ; Extended_Pictographic# E3.0 [2] (๐Ÿ›‘..๐Ÿ›’) stop sign..shopping cart
+1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (๐Ÿ›“..๐Ÿ›”) STUPA..PAGODA
+1F6D5 ; Extended_Pictographic# E12.0 [1] (๐Ÿ›•) hindu temple
+1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (๐Ÿ›–..๐Ÿ›—) hut..elevator
+1F6D8..1F6DF ; Extended_Pictographic# E0.0 [8] (๐Ÿ›˜..๐Ÿ›Ÿ) <reserved-1F6D8>..<reserved-1F6DF>
+1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (๐Ÿ› ๏ธ..๐Ÿ›ฅ๏ธ) hammer and wrench..motor boat
+1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (๐Ÿ›ฆ..๐Ÿ›จ) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE
+1F6E9 ; Extended_Pictographic# E0.7 [1] (๐Ÿ›ฉ๏ธ) small airplane
+1F6EA ; Extended_Pictographic# E0.0 [1] (๐Ÿ›ช) NORTHEAST-POINTING AIRPLANE
+1F6EB..1F6EC ; Extended_Pictographic# E1.0 [2] (๐Ÿ›ซ..๐Ÿ›ฌ) airplane departure..airplane arrival
+1F6ED..1F6EF ; Extended_Pictographic# E0.0 [3] (๐Ÿ›ญ..๐Ÿ›ฏ) <reserved-1F6ED>..<reserved-1F6EF>
+1F6F0 ; Extended_Pictographic# E0.7 [1] (๐Ÿ›ฐ๏ธ) satellite
+1F6F1..1F6F2 ; Extended_Pictographic# E0.0 [2] (๐Ÿ›ฑ..๐Ÿ›ฒ) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE
+1F6F3 ; Extended_Pictographic# E0.7 [1] (๐Ÿ›ณ๏ธ) passenger ship
+1F6F4..1F6F6 ; Extended_Pictographic# E3.0 [3] (๐Ÿ›ด..๐Ÿ›ถ) kick scooter..canoe
+1F6F7..1F6F8 ; Extended_Pictographic# E5.0 [2] (๐Ÿ›ท..๐Ÿ›ธ) sled..flying saucer
+1F6F9 ; Extended_Pictographic# E11.0 [1] (๐Ÿ›น) skateboard
+1F6FA ; Extended_Pictographic# E12.0 [1] (๐Ÿ›บ) auto rickshaw
+1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (๐Ÿ›ป..๐Ÿ›ผ) pickup truck..roller skate
+1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (๐Ÿ›ฝ..๐Ÿ›ฟ) <reserved-1F6FD>..<reserved-1F6FF>
+1F774..1F77F ; Extended_Pictographic# E0.0 [12] (๐Ÿด..๐Ÿฟ) <reserved-1F774>..<reserved-1F77F>
+1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (๐ŸŸ•..๐ŸŸŸ) CIRCLED TRIANGLE..<reserved-1F7DF>
+1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (๐ŸŸ ..๐ŸŸซ) orange circle..brown square
+1F7EC..1F7FF ; Extended_Pictographic# E0.0 [20] (๐ŸŸฌ..๐ŸŸฟ) <reserved-1F7EC>..<reserved-1F7FF>
+1F80C..1F80F ; Extended_Pictographic# E0.0 [4] (๐Ÿ Œ..๐Ÿ ) <reserved-1F80C>..<reserved-1F80F>
+1F848..1F84F ; Extended_Pictographic# E0.0 [8] (๐Ÿกˆ..๐Ÿก) <reserved-1F848>..<reserved-1F84F>
+1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (๐Ÿกš..๐ŸกŸ) <reserved-1F85A>..<reserved-1F85F>
+1F888..1F88F ; Extended_Pictographic# E0.0 [8] (๐Ÿขˆ..๐Ÿข) <reserved-1F888>..<reserved-1F88F>
+1F8AE..1F8FF ; Extended_Pictographic# E0.0 [82] (๐Ÿขฎ..๐Ÿฃฟ) <reserved-1F8AE>..<reserved-1F8FF>
+1F90C ; Extended_Pictographic# E13.0 [1] (๐ŸคŒ) pinched fingers
+1F90D..1F90F ; Extended_Pictographic# E12.0 [3] (๐Ÿค..๐Ÿค) white heart..pinching hand
+1F910..1F918 ; Extended_Pictographic# E1.0 [9] (๐Ÿค..๐Ÿค˜) zipper-mouth face..sign of the horns
+1F919..1F91E ; Extended_Pictographic# E3.0 [6] (๐Ÿค™..๐Ÿคž) call me hand..crossed fingers
+1F91F ; Extended_Pictographic# E5.0 [1] (๐ŸคŸ) love-you gesture
+1F920..1F927 ; Extended_Pictographic# E3.0 [8] (๐Ÿค ..๐Ÿคง) cowboy hat face..sneezing face
+1F928..1F92F ; Extended_Pictographic# E5.0 [8] (๐Ÿคจ..๐Ÿคฏ) face with raised eyebrow..exploding head
+1F930 ; Extended_Pictographic# E3.0 [1] (๐Ÿคฐ) pregnant woman
+1F931..1F932 ; Extended_Pictographic# E5.0 [2] (๐Ÿคฑ..๐Ÿคฒ) breast-feeding..palms up together
+1F933..1F93A ; Extended_Pictographic# E3.0 [8] (๐Ÿคณ..๐Ÿคบ) selfie..person fencing
+1F93C..1F93E ; Extended_Pictographic# E3.0 [3] (๐Ÿคผ..๐Ÿคพ) people wrestling..person playing handball
+1F93F ; Extended_Pictographic# E12.0 [1] (๐Ÿคฟ) diving mask
+1F940..1F945 ; Extended_Pictographic# E3.0 [6] (๐Ÿฅ€..๐Ÿฅ…) wilted flower..goal net
+1F947..1F94B ; Extended_Pictographic# E3.0 [5] (๐Ÿฅ‡..๐Ÿฅ‹) 1st place medal..martial arts uniform
+1F94C ; Extended_Pictographic# E5.0 [1] (๐ŸฅŒ) curling stone
+1F94D..1F94F ; Extended_Pictographic# E11.0 [3] (๐Ÿฅ..๐Ÿฅ) lacrosse..flying disc
+1F950..1F95E ; Extended_Pictographic# E3.0 [15] (๐Ÿฅ..๐Ÿฅž) croissant..pancakes
+1F95F..1F96B ; Extended_Pictographic# E5.0 [13] (๐ŸฅŸ..๐Ÿฅซ) dumpling..canned food
+1F96C..1F970 ; Extended_Pictographic# E11.0 [5] (๐Ÿฅฌ..๐Ÿฅฐ) leafy green..smiling face with hearts
+1F971 ; Extended_Pictographic# E12.0 [1] (๐Ÿฅฑ) yawning face
+1F972 ; Extended_Pictographic# E13.0 [1] (๐Ÿฅฒ) smiling face with tear
+1F973..1F976 ; Extended_Pictographic# E11.0 [4] (๐Ÿฅณ..๐Ÿฅถ) partying face..cold face
+1F977..1F978 ; Extended_Pictographic# E13.0 [2] (๐Ÿฅท..๐Ÿฅธ) ninja..disguised face
+1F979 ; Extended_Pictographic# E0.0 [1] (๐Ÿฅน) <reserved-1F979>
+1F97A ; Extended_Pictographic# E11.0 [1] (๐Ÿฅบ) pleading face
+1F97B ; Extended_Pictographic# E12.0 [1] (๐Ÿฅป) sari
+1F97C..1F97F ; Extended_Pictographic# E11.0 [4] (๐Ÿฅผ..๐Ÿฅฟ) lab coat..flat shoe
+1F980..1F984 ; Extended_Pictographic# E1.0 [5] (๐Ÿฆ€..๐Ÿฆ„) crab..unicorn
+1F985..1F991 ; Extended_Pictographic# E3.0 [13] (๐Ÿฆ…..๐Ÿฆ‘) eagle..squid
+1F992..1F997 ; Extended_Pictographic# E5.0 [6] (๐Ÿฆ’..๐Ÿฆ—) giraffe..cricket
+1F998..1F9A2 ; Extended_Pictographic# E11.0 [11] (๐Ÿฆ˜..๐Ÿฆข) kangaroo..swan
+1F9A3..1F9A4 ; Extended_Pictographic# E13.0 [2] (๐Ÿฆฃ..๐Ÿฆค) mammoth..dodo
+1F9A5..1F9AA ; Extended_Pictographic# E12.0 [6] (๐Ÿฆฅ..๐Ÿฆช) sloth..oyster
+1F9AB..1F9AD ; Extended_Pictographic# E13.0 [3] (๐Ÿฆซ..๐Ÿฆญ) beaver..seal
+1F9AE..1F9AF ; Extended_Pictographic# E12.0 [2] (๐Ÿฆฎ..๐Ÿฆฏ) guide dog..white cane
+1F9B0..1F9B9 ; Extended_Pictographic# E11.0 [10] (๐Ÿฆฐ..๐Ÿฆน) red hair..supervillain
+1F9BA..1F9BF ; Extended_Pictographic# E12.0 [6] (๐Ÿฆบ..๐Ÿฆฟ) safety vest..mechanical leg
+1F9C0 ; Extended_Pictographic# E1.0 [1] (๐Ÿง€) cheese wedge
+1F9C1..1F9C2 ; Extended_Pictographic# E11.0 [2] (๐Ÿง..๐Ÿง‚) cupcake..salt
+1F9C3..1F9CA ; Extended_Pictographic# E12.0 [8] (๐Ÿงƒ..๐ŸงŠ) beverage box..ice
+1F9CB ; Extended_Pictographic# E13.0 [1] (๐Ÿง‹) bubble tea
+1F9CC ; Extended_Pictographic# E0.0 [1] (๐ŸงŒ) <reserved-1F9CC>
+1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (๐Ÿง..๐Ÿง) person standing..deaf person
+1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (๐Ÿง..๐Ÿงฆ) face with monocle..socks
+1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (๐Ÿงง..๐Ÿงฟ) red envelope..nazar amulet
+1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (๐Ÿจ€..๐Ÿฉฏ) NEUTRAL CHESS KING..<reserved-1FA6F>
+1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (๐Ÿฉฐ..๐Ÿฉณ) ballet shoes..shorts
+1FA74 ; Extended_Pictographic# E13.0 [1] (๐Ÿฉด) thong sandal
+1FA75..1FA77 ; Extended_Pictographic# E0.0 [3] (๐Ÿฉต..๐Ÿฉท) <reserved-1FA75>..<reserved-1FA77>
+1FA78..1FA7A ; Extended_Pictographic# E12.0 [3] (๐Ÿฉธ..๐Ÿฉบ) drop of blood..stethoscope
+1FA7B..1FA7F ; Extended_Pictographic# E0.0 [5] (๐Ÿฉป..๐Ÿฉฟ) <reserved-1FA7B>..<reserved-1FA7F>
+1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (๐Ÿช€..๐Ÿช‚) yo-yo..parachute
+1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (๐Ÿชƒ..๐Ÿช†) boomerang..nesting dolls
+1FA87..1FA8F ; Extended_Pictographic# E0.0 [9] (๐Ÿช‡..๐Ÿช) <reserved-1FA87>..<reserved-1FA8F>
+1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (๐Ÿช..๐Ÿช•) ringed planet..banjo
+1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (๐Ÿช–..๐Ÿชจ) military helmet..rock
+1FAA9..1FAAF ; Extended_Pictographic# E0.0 [7] (๐Ÿชฉ..๐Ÿชฏ) <reserved-1FAA9>..<reserved-1FAAF>
+1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (๐Ÿชฐ..๐Ÿชถ) fly..feather
+1FAB7..1FABF ; Extended_Pictographic# E0.0 [9] (๐Ÿชท..๐Ÿชฟ) <reserved-1FAB7>..<reserved-1FABF>
+1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (๐Ÿซ€..๐Ÿซ‚) anatomical heart..people hugging
+1FAC3..1FACF ; Extended_Pictographic# E0.0 [13] (๐Ÿซƒ..๐Ÿซ) <reserved-1FAC3>..<reserved-1FACF>
+1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (๐Ÿซ..๐Ÿซ–) blueberries..teapot
+1FAD7..1FAFF ; Extended_Pictographic# E0.0 [41] (๐Ÿซ—..๐Ÿซฟ) <reserved-1FAD7>..<reserved-1FAFF>
+1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (๐Ÿฐ€..๐Ÿฟฝ) <reserved-1FC00>..<reserved-1FFFD>
-# Total elements: 3793
+# Total elements: 3537
#EOF