aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml21
-rw-r--r--CMakeLists.txt5
-rw-r--r--cmake.deps/deps.txt4
-rw-r--r--cmake/Deps.cmake2
-rw-r--r--runtime/autoload/netrw.vim8
-rw-r--r--runtime/autoload/provider/clipboard.vim2
-rw-r--r--runtime/autoload/spotbugs.vim250
-rw-r--r--runtime/autoload/typst.vim5
-rw-r--r--runtime/compiler/eslint.vim7
-rw-r--r--runtime/compiler/javac.vim8
-rw-r--r--runtime/compiler/maven.vim2
-rw-r--r--runtime/compiler/pytest.vim103
-rw-r--r--runtime/compiler/spotbugs.vim189
-rw-r--r--runtime/compiler/typst.vim5
-rw-r--r--runtime/doc/api.txt19
-rw-r--r--runtime/doc/autocmd.txt4
-rw-r--r--runtime/doc/builtin.txt27
-rw-r--r--runtime/doc/cmdline.txt4
-rw-r--r--runtime/doc/credits.txt (renamed from runtime/doc/backers.txt)111
-rw-r--r--runtime/doc/deprecated.txt1
-rw-r--r--runtime/doc/dev_arch.txt10
-rw-r--r--runtime/doc/develop.txt8
-rw-r--r--runtime/doc/diagnostic.txt27
-rw-r--r--runtime/doc/filetype.txt6
-rw-r--r--runtime/doc/gui.txt465
-rw-r--r--runtime/doc/help.txt1
-rw-r--r--runtime/doc/index.txt2
-rw-r--r--runtime/doc/intro.txt963
-rw-r--r--runtime/doc/lsp.txt102
-rw-r--r--runtime/doc/lua.txt20
-rw-r--r--runtime/doc/map.txt2
-rw-r--r--runtime/doc/message.txt3
-rw-r--r--runtime/doc/news.txt13
-rw-r--r--runtime/doc/nvim.txt36
-rw-r--r--runtime/doc/options.txt37
-rw-r--r--runtime/doc/provider.txt2
-rw-r--r--runtime/doc/quickfix.txt119
-rw-r--r--runtime/doc/sign.txt2
-rw-r--r--runtime/doc/terminal.txt4
-rw-r--r--runtime/doc/treesitter.txt27
-rw-r--r--runtime/doc/ui.txt2
-rw-r--r--runtime/doc/various.txt6
-rw-r--r--runtime/doc/vietnamese.txt73
-rw-r--r--runtime/doc/vim_diff.txt8
-rw-r--r--runtime/doc/vvars.txt2
-rw-r--r--runtime/filetype.lua4
-rw-r--r--runtime/ftplugin/java.vim138
-rw-r--r--runtime/ftplugin/proto.vim18
-rw-r--r--runtime/ftplugin/ptx.vim16
-rw-r--r--runtime/ftplugin/python.vim11
-rw-r--r--runtime/ftplugin/typst.vim13
-rw-r--r--runtime/indent/typst.vim5
-rw-r--r--runtime/lua/vim/_defaults.lua8
-rw-r--r--runtime/lua/vim/_inspector.lua20
-rw-r--r--runtime/lua/vim/_meta/api.lua20
-rw-r--r--runtime/lua/vim/_meta/json.lua5
-rw-r--r--runtime/lua/vim/_meta/options.lua43
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua13
-rw-r--r--runtime/lua/vim/_meta/vvars.lua22
-rw-r--r--runtime/lua/vim/_meta/vvars_extra.lua77
-rw-r--r--runtime/lua/vim/_system.lua126
-rw-r--r--runtime/lua/vim/diagnostic.lua56
-rw-r--r--runtime/lua/vim/filetype.lua5
-rw-r--r--runtime/lua/vim/loader.lua6
-rw-r--r--runtime/lua/vim/lsp.lua364
-rw-r--r--runtime/lua/vim/lsp/_folding_range.lua373
-rw-r--r--runtime/lua/vim/lsp/buf.lua4
-rw-r--r--runtime/lua/vim/lsp/client.lua142
-rw-r--r--runtime/lua/vim/lsp/codelens.lua8
-rw-r--r--runtime/lua/vim/lsp/completion.lua2
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua4
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua21
-rw-r--r--runtime/lua/vim/lsp/protocol.lua7
-rw-r--r--runtime/lua/vim/lsp/rpc.lua2
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua19
-rw-r--r--runtime/lua/vim/lsp/util.lua16
-rw-r--r--runtime/lua/vim/shared.lua57
-rw-r--r--runtime/lua/vim/treesitter.lua22
-rw-r--r--runtime/lua/vim/treesitter/_fold.lua53
-rw-r--r--runtime/lua/vim/treesitter/query.lua53
-rw-r--r--runtime/optwin.vim6
-rw-r--r--runtime/syntax/po.vim56
-rw-r--r--runtime/syntax/ptx.vim52
-rw-r--r--runtime/syntax/typst.vim5
-rwxr-xr-xscripts/gen_eval_files.lua25
-rw-r--r--scripts/gen_help_html.lua7
-rwxr-xr-xscripts/gen_vimdoc.lua1
-rw-r--r--src/cjson/lua_cjson.c121
-rw-r--r--src/nvim/CMakeLists.txt3
-rw-r--r--src/nvim/api/autocmd.c6
-rw-r--r--src/nvim/api/deprecated.c6
-rw-r--r--src/nvim/api/vim.c14
-rw-r--r--src/nvim/autocmd.c6
-rw-r--r--src/nvim/autocmd_defs.h1
-rw-r--r--src/nvim/decoration_provider.c3
-rw-r--r--src/nvim/digraph.c10
-rw-r--r--src/nvim/drawscreen.c58
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.lua8
-rw-r--r--src/nvim/ex_docmd.c16
-rw-r--r--src/nvim/ex_getln.c5
-rw-r--r--src/nvim/extmark.c26
-rw-r--r--src/nvim/generators/c_grammar.lua313
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua16
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua2
-rw-r--r--src/nvim/generators/gen_declarations.lua468
-rw-r--r--src/nvim/generators/gen_options.lua6
-rw-r--r--src/nvim/highlight.c3
-rw-r--r--src/nvim/indent_c.c81
-rw-r--r--src/nvim/insexpand.c183
-rw-r--r--src/nvim/lua/stdlib.c1
-rw-r--r--src/nvim/marktree.c3
-rw-r--r--src/nvim/math.c6
-rw-r--r--src/nvim/message.c228
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/ops.c142
-rw-r--r--src/nvim/option.c25
-rw-r--r--src/nvim/option_vars.h2
-rw-r--r--src/nvim/options.lua58
-rw-r--r--src/nvim/optionstr.c18
-rw-r--r--src/nvim/po/vi.po6618
-rw-r--r--src/nvim/runtime.c84
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/vvars.lua12
-rw-r--r--src/nvim/window.c28
-rw-r--r--src/vterm/vterm.c506
-rw-r--r--src/vterm/vterm.h34
-rw-r--r--test/functional/api/autocmd_spec.lua50
-rw-r--r--test/functional/api/extmark_spec.lua2
-rw-r--r--test/functional/api/highlight_spec.lua9
-rw-r--r--test/functional/api/version_spec.lua18
-rw-r--r--test/functional/core/main_spec.lua4
-rw-r--r--test/functional/editor/completion_spec.lua43
-rw-r--r--test/functional/editor/defaults_spec.lua68
-rw-r--r--test/functional/legacy/messages_spec.lua39
-rw-r--r--test/functional/lua/filetype_spec.lua2
-rw-r--r--test/functional/lua/fs_spec.lua12
-rw-r--r--test/functional/lua/json_spec.lua39
-rw-r--r--test/functional/lua/system_spec.lua46
-rw-r--r--test/functional/lua/with_spec.lua17
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua4
-rw-r--r--test/functional/plugin/lsp/folding_range_spec.lua647
-rw-r--r--test/functional/plugin/lsp/handler_spec.lua42
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua2
-rw-r--r--test/functional/plugin/lsp_spec.lua4
-rw-r--r--test/functional/terminal/cursor_spec.lua2
-rw-r--r--test/functional/treesitter/highlight_spec.lua816
-rw-r--r--test/functional/treesitter/parser_spec.lua132
-rw-r--r--test/functional/treesitter/testutil.lua25
-rw-r--r--test/functional/ui/cursor_spec.lua34
-rw-r--r--test/functional/ui/screen.lua25
-rw-r--r--test/functional/ui/screen_basic_spec.lua53
-rw-r--r--test/functional/ui/sign_spec.lua73
-rw-r--r--test/functional/ui/title_spec.lua57
-rw-r--r--test/old/testdir/gen_opt_test.vim9
-rw-r--r--test/old/testdir/runtest.vim4
-rw-r--r--test/old/testdir/setup.vim1
-rw-r--r--test/old/testdir/test_autocmd.vim4
-rw-r--r--test/old/testdir/test_cmdline.vim26
-rw-r--r--test/old/testdir/test_compiler.vim198
-rw-r--r--test/old/testdir/test_digraph.vim7
-rw-r--r--test/old/testdir/test_filetype.vim5
-rw-r--r--test/old/testdir/test_highlight.vim4
-rw-r--r--test/old/testdir/test_indent.vim27
-rw-r--r--test/old/testdir/test_ins_complete.vim87
-rw-r--r--test/old/testdir/test_messages.vim47
-rw-r--r--test/old/testdir/test_options.vim52
-rw-r--r--test/old/testdir/test_popup.vim25
-rw-r--r--test/old/testdir/test_shift.vim807
-rw-r--r--test/old/testdir/test_window_cmd.vim21
-rw-r--r--test/unit/fixtures/vterm_test.c504
-rw-r--r--test/unit/fixtures/vterm_test.h37
-rw-r--r--test/unit/vterm_spec.lua6
174 files changed, 9933 insertions, 7958 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0885efddd5..c7802d2210 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -106,7 +106,7 @@ jobs:
[
{ runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
{ runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON },
- { runner: ubuntu-24.04, os: ubuntu, cc: gcc },
+ { runner: ubuntu-24.04, os: ubuntu, flavor: release, cc: gcc, flags: -D CMAKE_BUILD_TYPE=Release },
{ runner: macos-13, os: macos, flavor: intel, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: macos-15, os: macos, flavor: arm, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
{ runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON },
@@ -145,6 +145,10 @@ jobs:
sudo cpanm -n Neovim::Ext || cat "$HOME/.cpanm/build.log"
perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION'
+ - name: Remove .git directory
+ if: ${{ matrix.build.os == 'ubuntu' }}
+ run: cmake -E rm -rf -- .git
+
- name: Build third-party deps
run: |
cmake -S cmake.deps --preset ci -D CMAKE_BUILD_TYPE=Debug ${{ matrix.build.deps_flags }}
@@ -155,9 +159,15 @@ jobs:
cmake --preset ci -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX ${{ matrix.build.flags }}
cmake --build build
- - name: ${{ matrix.test }}
+ - if: ${{ matrix.test == 'oldtest' }}
+ name: ${{ matrix.test }}
+ timeout-minutes: 20
+ run: make -C test/old/testdir NVIM_PRG=$(realpath build)/bin/nvim
+
+ - if: ${{ matrix.test != 'oldtest' }}
+ name: ${{ matrix.test }}
timeout-minutes: 20
- run: make ${{ matrix.test }}
+ run: cmake --build build --target ${{ matrix.test }}
- name: Install
run: |
@@ -194,7 +204,7 @@ jobs:
uses: ./.github/workflows/test_windows.yml
# This job tests the following things:
- # - Check if Release, MinSizeRel and RelWithDebInfo compiles correctly.
+ # - Check if MinSizeRel and RelWithDebInfo compiles correctly.
# - Test the above build types with the GCC compiler specifically.
# Empirically the difference in warning levels between GCC and other
# compilers is particularly big.
@@ -218,9 +228,6 @@ jobs:
- name: Configure
run: cmake --preset ci -G "Ninja Multi-Config"
- - name: Release
- run: cmake --build build --config Release
-
- name: RelWithDebInfo
run: cmake --build build --config RelWithDebInfo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9723de9176..ae5704cfe4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -187,6 +187,7 @@ if(NOT PREFER_LUA)
find_program(LUA_PRG NAMES luajit)
endif()
find_program(LUA_PRG NAMES lua5.1 lua5.2 lua)
+mark_as_advanced(LUA_PRG)
if(NOT LUA_PRG)
message(FATAL_ERROR "Failed to find a Lua 5.1-compatible interpreter")
endif()
@@ -200,6 +201,7 @@ message(STATUS "Using Lua interpreter: ${LUA_PRG}")
if(NOT LUA_GEN_PRG)
set(LUA_GEN_PRG "${LUA_PRG}" CACHE FILEPATH "Path to the lua used for code generation.")
endif()
+mark_as_advanced(LUA_GEN_PRG)
message(STATUS "Using Lua interpreter for code generation: ${LUA_GEN_PRG}")
option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
@@ -219,6 +221,7 @@ if(COMPILE_LUA AND NOT WIN32)
endif()
endif()
endif()
+mark_as_advanced(LUAC_PRG)
if(LUAC_PRG)
message(STATUS "Using Lua compiler: ${LUAC_PRG}")
endif()
@@ -229,7 +232,9 @@ if(CI_LINT)
set(LINT_REQUIRED "REQUIRED")
endif()
find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED})
+mark_as_advanced(SHELLCHECK_PRG)
find_program(STYLUA_PRG stylua ${LINT_REQUIRED})
+mark_as_advanced(STYLUA_PRG)
set(STYLUA_DIRS runtime scripts src test contrib)
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index c42790ed5d..f7827fc47a 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -1,8 +1,8 @@
LIBUV_URL https://github.com/libuv/libuv/archive/v1.49.2.tar.gz
LIBUV_SHA256 388ffcf3370d4cf7c4b3a3205504eea06c4be5f9e80d2ab32d19f8235accc1cf
-LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/fe71d0fb54ceadfb5b5f3b6baf29e486d97f6059.tar.gz
-LUAJIT_SHA256 92325f209b21aaf0a67b099bc73cf9bbac5789a9749bdc3898d4a990abb4f36e
+LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/19878ec05c239ccaf5f3d17af27670a963e25b8b.tar.gz
+LUAJIT_SHA256 e91acbe181cf6ffa3ef15870b8e620131002240ba24c5c779fd0131db021517f
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
diff --git a/cmake/Deps.cmake b/cmake/Deps.cmake
index 519826654f..5902ca6970 100644
--- a/cmake/Deps.cmake
+++ b/cmake/Deps.cmake
@@ -19,6 +19,7 @@ if(APPLE)
endif()
find_program(CACHE_PRG NAMES ccache sccache)
+mark_as_advanced(CACHE_PRG)
if(CACHE_PRG)
set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env CCACHE_SLOPPINESS=pch_defines,time_macros ${CACHE_PRG})
list(APPEND DEPS_CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER})
@@ -27,6 +28,7 @@ endif()
# MAKE_PRG
if(UNIX)
find_program(MAKE_PRG NAMES gmake make)
+ mark_as_advanced(MAKE_PRG)
if(NOT MAKE_PRG)
message(FATAL_ERROR "GNU Make is required to build the dependencies.")
else()
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 6a26a7d0b1..cbe0b29620 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -38,6 +38,8 @@
" 2024 Nov 14 by Vim Project: small fixes to netrw#BrowseX (#16056)
" 2024 Nov 23 by Vim Project: update decompress defaults (#16104)
" 2024 Nov 23 by Vim Project: fix powershell escaping issues (#16094)
+" 2024 Dec 04 by Vim Project: do not detach for gvim (#16168)
+" 2024 Dec 08 by Vim Project: check the first arg of netrw_browsex_viewer for being executable (#16185)
" }}}
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
@@ -5040,7 +5042,7 @@ if has('unix')
endfun
else
fun! netrw#Launch(args)
- exe ':silent ! nohup' a:args s:redir() '&' | redraw!
+ exe ':silent ! nohup' a:args s:redir() (has('gui_running') ? '' : '&') | redraw!
endfun
endif
elseif has('win32')
@@ -5070,7 +5072,9 @@ elseif executable('open')
endif
fun! s:viewer()
- if exists('g:netrw_browsex_viewer') && executable(g:netrw_browsex_viewer)
+ " g:netrw_browsex_viewer could be a string of program + its arguments,
+ " test if first argument is executable
+ if exists('g:netrw_browsex_viewer') && executable(split(g:netrw_browsex_viewer)[0])
" extract any viewing options. Assumes that they're set apart by spaces.
" call Decho("extract any viewing options from g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
if g:netrw_browsex_viewer =~ '\s'
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 58d3d4550f..848fa401f1 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -158,7 +158,7 @@ function! provider#clipboard#Executable() abort
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'termux-clipboard'
- elseif !empty($TMUX) && executable('tmux')
+ elseif executable('tmux') && (!empty($TMUX) || 0 == jobwait([jobstart(['tmux', 'list-buffers'])], 2000)[0])
let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V']))
if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0])
let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
diff --git a/runtime/autoload/spotbugs.vim b/runtime/autoload/spotbugs.vim
new file mode 100644
index 0000000000..9161395794
--- /dev/null
+++ b/runtime/autoload/spotbugs.vim
@@ -0,0 +1,250 @@
+" Default pre- and post-compiler actions for SpotBugs
+" Maintainers: @konfekt and @zzzyxwvut
+" Last Change: 2024 Nov 27
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+if v:version > 900
+
+ function! spotbugs#DeleteClassFiles() abort
+ if !exists('b:spotbugs_class_files')
+ return
+ endif
+
+ for pathname in b:spotbugs_class_files
+ let classname = pathname =~# "^'.\\+\\.class'$"
+ \ ? eval(pathname)
+ \ : pathname
+
+ if classname =~# '\.class$' && filereadable(classname)
+ " Since v9.0.0795.
+ let octad = readblob(classname, 0, 8)
+
+ " Test the magic number and the major version number (45 for v1.0).
+ " Since v9.0.2027.
+ if len(octad) == 8 && octad[0 : 3] == 0zcafe.babe &&
+ \ or((octad[6] << 8), octad[7]) >= 45
+ echomsg printf('Deleting %s: %d', classname, delete(classname))
+ endif
+ endif
+ endfor
+
+ let b:spotbugs_class_files = []
+ endfunction
+
+else
+
+ function! s:DeleteClassFilesWithNewLineCodes(classname) abort
+ " The distribution of "0a"s in class file versions 2560 and 2570:
+ "
+ " 0zca.fe.ba.be.00.00.0a.00 0zca.fe.ba.be.00.00.0a.0a
+ " 0zca.fe.ba.be.00.0a.0a.00 0zca.fe.ba.be.00.0a.0a.0a
+ " 0zca.fe.ba.be.0a.00.0a.00 0zca.fe.ba.be.0a.00.0a.0a
+ " 0zca.fe.ba.be.0a.0a.0a.00 0zca.fe.ba.be.0a.0a.0a.0a
+ let numbers = [0, 0, 0, 0, 0, 0, 0, 0]
+ let offset = 0
+ let lines = readfile(a:classname, 'b', 4)
+
+ " Track NL byte counts to handle files of less than 8 bytes.
+ let nl_cnt = len(lines)
+ " Track non-NL byte counts for "0zca.fe.ba.be.0a.0a.0a.0a".
+ let non_nl_cnt = 0
+
+ for line in lines
+ for idx in range(strlen(line))
+ " Remap NLs to Nuls.
+ let numbers[offset] = (line[idx] == "\n") ? 0 : char2nr(line[idx]) % 256
+ let non_nl_cnt += 1
+ let offset += 1
+
+ if offset > 7
+ break
+ endif
+ endfor
+
+ let nl_cnt -= 1
+
+ if offset > 7 || (nl_cnt < 1 && non_nl_cnt > 4)
+ break
+ endif
+
+ " Reclaim NLs.
+ let numbers[offset] = 10
+ let offset += 1
+
+ if offset > 7
+ break
+ endif
+ endfor
+
+ " Test the magic number and the major version number (45 for v1.0).
+ if offset > 7 && numbers[0] == 0xca && numbers[1] == 0xfe &&
+ \ numbers[2] == 0xba && numbers[3] == 0xbe &&
+ \ (numbers[6] * 256 + numbers[7]) >= 45
+ echomsg printf('Deleting %s: %d', a:classname, delete(a:classname))
+ endif
+ endfunction
+
+ function! spotbugs#DeleteClassFiles() abort
+ if !exists('b:spotbugs_class_files')
+ return
+ endif
+
+ let encoding = &encoding
+
+ try
+ set encoding=latin1
+
+ for pathname in b:spotbugs_class_files
+ let classname = pathname =~# "^'.\\+\\.class'$"
+ \ ? eval(pathname)
+ \ : pathname
+
+ if classname =~# '\.class$' && filereadable(classname)
+ let line = get(readfile(classname, 'b', 1), 0, '')
+ let length = strlen(line)
+
+ " Test the magic number and the major version number (45 for v1.0).
+ if length > 3 && line[0 : 3] == "\xca\xfe\xba\xbe"
+ if length > 7 && ((line[6] == "\n" ? 0 : char2nr(line[6]) % 256) * 256 +
+ \ (line[7] == "\n" ? 0 : char2nr(line[7]) % 256)) >= 45
+ echomsg printf('Deleting %s: %d', classname, delete(classname))
+ else
+ call s:DeleteClassFilesWithNewLineCodes(classname)
+ endif
+ endif
+ endif
+ endfor
+ finally
+ let &encoding = encoding
+ endtry
+
+ let b:spotbugs_class_files = []
+ endfunction
+
+endif
+
+function! spotbugs#DefaultPostCompilerAction() abort
+ " Since v7.4.191.
+ make %:S
+endfunction
+
+" Look for "spotbugs#compiler" in "ftplugin/java.vim".
+let s:compiler = exists('spotbugs#compiler') ? spotbugs#compiler : ''
+let s:readable = filereadable($VIMRUNTIME . '/compiler/' . s:compiler . '.vim')
+
+if s:readable && s:compiler ==# 'maven' && executable('mvn')
+
+ function! spotbugs#DefaultPreCompilerAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler maven
+ make compile
+ endfunction
+
+ function! spotbugs#DefaultPreCompilerTestAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler maven
+ make test-compile
+ endfunction
+
+ function! spotbugs#DefaultProperties() abort
+ return {
+ \ 'PreCompilerAction':
+ \ function('spotbugs#DefaultPreCompilerAction'),
+ \ 'PreCompilerTestAction':
+ \ function('spotbugs#DefaultPreCompilerTestAction'),
+ \ 'PostCompilerAction':
+ \ function('spotbugs#DefaultPostCompilerAction'),
+ \ 'sourceDirPath': 'src/main/java',
+ \ 'classDirPath': 'target/classes',
+ \ 'testSourceDirPath': 'src/test/java',
+ \ 'testClassDirPath': 'target/test-classes',
+ \ }
+ endfunction
+
+ unlet s:readable s:compiler
+elseif s:readable && s:compiler ==# 'ant' && executable('ant')
+
+ function! spotbugs#DefaultPreCompilerAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler ant
+ make compile
+ endfunction
+
+ function! spotbugs#DefaultPreCompilerTestAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler ant
+ make compile-test
+ endfunction
+
+ function! spotbugs#DefaultProperties() abort
+ return {
+ \ 'PreCompilerAction':
+ \ function('spotbugs#DefaultPreCompilerAction'),
+ \ 'PreCompilerTestAction':
+ \ function('spotbugs#DefaultPreCompilerTestAction'),
+ \ 'PostCompilerAction':
+ \ function('spotbugs#DefaultPostCompilerAction'),
+ \ 'sourceDirPath': 'src',
+ \ 'classDirPath': 'build/classes',
+ \ 'testSourceDirPath': 'test',
+ \ 'testClassDirPath': 'build/test/classes',
+ \ }
+ endfunction
+
+ unlet s:readable s:compiler
+elseif s:readable && s:compiler ==# 'javac' && executable('javac')
+
+ function! spotbugs#DefaultPreCompilerAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler javac
+
+ if get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')) =~ '\s@\S'
+ " Read options and filenames from @options [@sources ...].
+ make
+ else
+ " Let Javac figure out what files to compile.
+ execute 'make ' . join(map(filter(copy(v:argv),
+ \ "v:val =~# '\\.java\\=$'"),
+ \ 'shellescape(v:val)'), ' ')
+ endif
+ endfunction
+
+ function! spotbugs#DefaultPreCompilerTestAction() abort
+ call spotbugs#DefaultPreCompilerAction()
+ endfunction
+
+ function! spotbugs#DefaultProperties() abort
+ return {
+ \ 'PreCompilerAction':
+ \ function('spotbugs#DefaultPreCompilerAction'),
+ \ 'PreCompilerTestAction':
+ \ function('spotbugs#DefaultPreCompilerTestAction'),
+ \ 'PostCompilerAction':
+ \ function('spotbugs#DefaultPostCompilerAction'),
+ \ }
+ endfunction
+
+ unlet s:readable s:compiler
+else
+
+ function! spotbugs#DefaultPreCompilerAction() abort
+ echomsg printf('Not supported: "%s"', s:compiler)
+ endfunction
+
+ function! spotbugs#DefaultPreCompilerTestAction() abort
+ call spotbugs#DefaultPreCompilerAction()
+ endfunction
+
+ function! spotbugs#DefaultProperties() abort
+ return {}
+ endfunction
+
+ unlet s:readable
+endif
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim: set foldmethod=syntax shiftwidth=2 expandtab:
diff --git a/runtime/autoload/typst.vim b/runtime/autoload/typst.vim
index 6d097dd922..362da3f45e 100644
--- a/runtime/autoload/typst.vim
+++ b/runtime/autoload/typst.vim
@@ -1,6 +1,7 @@
" Language: Typst
-" Maintainer: Gregory Anders
-" Last Change: 2024 Nov 02
+" Previous Maintainer: Gregory Anders
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Dec 09
" Based on: https://github.com/kaarmu/typst.vim
function! typst#indentexpr() abort
diff --git a/runtime/compiler/eslint.vim b/runtime/compiler/eslint.vim
index db7a665991..0414817900 100644
--- a/runtime/compiler/eslint.vim
+++ b/runtime/compiler/eslint.vim
@@ -1,13 +1,12 @@
" Vim compiler file
" Compiler: ESLint for JavaScript
" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
-" Last Change: 2020 August 20
-" 2024 Apr 03 by The Vim Project (removed :CompilerSet definition)
+" Last Change: 2024 Nov 30
if exists("current_compiler")
finish
endif
let current_compiler = "eslint"
-CompilerSet makeprg=npx\ eslint\ --format\ compact
-CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %m,%-G%.%#
+CompilerSet makeprg=npx\ eslint\ --format\ stylish
+CompilerSet errorformat=%-P%f,\%\\s%#%l:%c\ %#\ %trror\ \ %m,\%\\s%#%l:%c\ %#\ %tarning\ \ %m,\%-Q,\%-G%.%#,
diff --git a/runtime/compiler/javac.vim b/runtime/compiler/javac.vim
index 9bd4cdf270..53cd772ed8 100644
--- a/runtime/compiler/javac.vim
+++ b/runtime/compiler/javac.vim
@@ -1,7 +1,7 @@
" Vim compiler file
" Compiler: Java Development Kit Compiler
" Maintainer: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2024 Jun 14
+" Last Change: 2024 Nov 19 (enable local javac_makeprg_params)
if exists("current_compiler")
finish
@@ -11,11 +11,7 @@ let current_compiler = "javac"
let s:cpo_save = &cpo
set cpo&vim
-if exists("g:javac_makeprg_params")
- execute $'CompilerSet makeprg=javac\ {escape(g:javac_makeprg_params, ' \|"')}'
-else
- CompilerSet makeprg=javac
-endif
+execute $'CompilerSet makeprg=javac\ {escape(get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')), ' \|"')}'
CompilerSet errorformat=%E%f:%l:\ error:\ %m,
\%W%f:%l:\ warning:\ %m,
diff --git a/runtime/compiler/maven.vim b/runtime/compiler/maven.vim
index ef8d8a6fb2..72e74e301d 100644
--- a/runtime/compiler/maven.vim
+++ b/runtime/compiler/maven.vim
@@ -14,7 +14,7 @@ if exists("current_compiler")
endif
let current_compiler = "maven"
-CompilerSet makeprg=mvn\ --batch-mode
+execute $'CompilerSet makeprg=mvn\ --batch-mode\ {escape(get(b:, 'maven_makeprg_params', get(g:, 'maven_makeprg_params', '')), ' \|"')}'
" Error message for POM
CompilerSet errorformat=[FATAL]\ Non-parseable\ POM\ %f:\ %m%\\s%\\+@%.%#line\ %l\\,\ column\ %c%.%#,
diff --git a/runtime/compiler/pytest.vim b/runtime/compiler/pytest.vim
new file mode 100644
index 0000000000..7fc189932c
--- /dev/null
+++ b/runtime/compiler/pytest.vim
@@ -0,0 +1,103 @@
+" Vim compiler file
+" Compiler: Pytest (Python testing framework)
+" Maintainer: @Konfekt and @mgedmin
+" Last Change: 2024 Nov 28
+
+if exists("current_compiler") | finish | endif
+let current_compiler = "pytest"
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" CompilerSet makeprg=pytest
+if has('unix')
+ execute $'CompilerSet makeprg=/usr/bin/env\ PYTHONWARNINGS=ignore\ pytest\ {escape(get(b:, 'pytest_makeprg_params', get(g:, 'pytest_makeprg_params', '--tb=short --quiet')), ' \|"')}'
+elseif has('win32')
+ execute $'CompilerSet makeprg=set\ PYTHONWARNINGS=ignore\ &&\ pytest\ {escape(get(b:, 'pytest_makeprg_params', get(g:, 'pytest_makeprg_params', '--tb=short --quiet')), ' \|"')}'
+else
+ CompilerSet makeprg=pytest\ --tb=short\ --quiet
+ execute $'CompilerSet makeprg=pytest\ {escape(get(b:, 'pytest_makeprg_params', get(g:, 'pytest_makeprg_params', '--tb=short --quiet')), ' \|"')}'
+endif
+
+" Pytest syntax errors {{{2
+
+" Reset error format so that sourcing .vimrc again and again doesn't grow it
+" without bounds
+setlocal errorformat&
+
+" For the record, the default errorformat is this:
+"
+" %*[^"]"%f"%*\D%l: %m
+" "%f"%*\D%l: %m
+" %-G%f:%l: (Each undeclared identifier is reported only once
+" %-G%f:%l: for each function it appears in.)
+" %-GIn file included from %f:%l:%c:
+" %-GIn file included from %f:%l:%c\,
+" %-GIn file included from %f:%l:%c
+" %-GIn file included from %f:%l
+" %-G%*[ ]from %f:%l:%c
+" %-G%*[ ]from %f:%l:
+" %-G%*[ ]from %f:%l\,
+" %-G%*[ ]from %f:%l
+" %f:%l:%c:%m
+" %f(%l):%m
+" %f:%l:%m
+" "%f"\, line %l%*\D%c%*[^ ] %m
+" %D%*\a[%*\d]: Entering directory %*[`']%f'
+" %X%*\a[%*\d]: Leaving directory %*[`']%f'
+" %D%*\a: Entering directory %*[`']%f'
+" %X%*\a: Leaving directory %*[`']%f'
+" %DMaking %*\a in %f
+" %f|%l| %m
+"
+" and sometimes it misfires, so let's fix it up a bit
+" (TBH I don't even know what compiler produces filename(lineno) so why even
+" have it?)
+setlocal errorformat-=%f(%l):%m
+
+" Sometimes Vim gets confused about ISO-8601 timestamps and thinks they're
+" filenames; this is a big hammer that ignores anything filename-like on lines
+" that start with at least two spaces, possibly preceded by a number and
+" optional punctuation
+setlocal errorformat^=%+G%\\d%#%.%\\=\ \ %.%#
+
+" Similar, but when the entire line starts with a date
+setlocal errorformat^=%+G\\d\\d\\d\\d-\\d\\d-\\d\\d\ \\d\\d:\\d\\d%.%#
+
+" make: *** [Makefile:14: target] Error 1
+setlocal errorformat^=%+Gmake:\ ***\ %.%#
+
+" FAILED tests.py::test_with_params[YYYY-MM-DD:HH:MM:SS] - Exception: bla bla
+setlocal errorformat^=%+GFAILED\ %.%#
+
+" AssertionError: assert ...YYYY-MM-DD:HH:MM:SS...
+setlocal errorformat^=%+GAssertionError:\ %.%#
+
+" --- /path/to/file:before YYYY-MM-DD HH:MM:SS.ssssss
+setlocal errorformat^=---%f:%m
+
+" +++ /path/to/file:before YYYY-MM-DD HH:MM:SS.ssssss
+setlocal errorformat^=+++%f:%m
+
+" Sometimes pytest prepends an 'E' marker at the beginning of a traceback line
+setlocal errorformat+=E\ %#File\ \"%f\"\\,\ line\ %l%.%#
+
+" Python tracebacks (unittest + doctest output) {{{2
+
+" This collapses the entire traceback into just the last file+lineno,
+" which is convenient when you want to jump to the line that failed (and not
+" the top-level entry point), but it makes it impossible to see the full
+" traceback, which sucks.
+""setlocal errorformat+=
+"" \File\ \"%f\"\\,\ line\ %l%.%#,
+"" \%C\ %.%#,
+"" \%-A\ \ File\ \"unittest%.py\"\\,\ line\ %.%#,
+"" \%-A\ \ File\ \"%f\"\\,\ line\ 0%.%#,
+"" \%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,
+"" \%Z%[%^\ ]%\\@=%m
+setlocal errorformat+=File\ \"%f\"\\,\ line\ %l\\,%#%m
+
+exe 'CompilerSet errorformat='..escape(&l:errorformat, ' \|"')
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/compiler/spotbugs.vim b/runtime/compiler/spotbugs.vim
new file mode 100644
index 0000000000..72a5084976
--- /dev/null
+++ b/runtime/compiler/spotbugs.vim
@@ -0,0 +1,189 @@
+" Vim compiler file
+" Compiler: Spotbugs (Java static checker; needs javac compiled classes)
+" Maintainer: @konfekt and @zzzyxwvut
+" Last Change: 2024 Nov 27
+
+if exists('g:current_compiler') || bufname() !~# '\.java\=$' || wordcount().chars < 9
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Unfortunately Spotbugs does not output absolute paths, so you need to
+" pass the directory of the files being checked as `-sourcepath` parameter.
+" The regex, auxpath and glob try to include all dependent classes of the
+" current buffer. See https://github.com/spotbugs/spotbugs/issues/856
+
+" FIXME: When "search()" is used with the "e" flag, it makes no _further_
+" progress after claiming an EOL match (i.e. "\_" or "\n", but not "$").
+" XXX: Omit anonymous class declarations
+let s:keywords = '\C\<\%(\.\@1<!class\|@\=interface\|enum\|record\|package\)\%(\s\|$\)'
+let s:type_names = '\C\<\%(\.\@1<!class\|@\=interface\|enum\|record\)\s*\(\K\k*\)\>'
+" Capture ";" for counting a class file directory (see s:package_dir_heads below)
+let s:package_names = '\C\<package\s*\(\K\%(\k*\.\=\)\+;\)'
+let s:package = ''
+
+if has('syntax') && exists('g:syntax_on') && exists('b:current_syntax') &&
+ \ b:current_syntax == 'java' && hlexists('javaClassDecl')
+
+ function! s:GetDeclaredTypeNames() abort
+ if bufname() =~# '\<\%(module\|package\)-info\.java\=$'
+ return [expand('%:t:r')]
+ endif
+ defer execute('silent! normal! g``')
+ call cursor(1, 1)
+ let type_names = []
+ let lnum = search(s:keywords, 'eW')
+ while lnum > 0
+ let name_attr = synIDattr(synID(lnum, (col('.') - 1), 0), 'name')
+ if name_attr ==# 'javaClassDecl'
+ let tokens = matchlist(getline(lnum)..getline(lnum + 1), s:type_names)
+ if !empty(tokens) | call add(type_names, tokens[1]) | endif
+ elseif name_attr ==# 'javaExternal'
+ let tokens = matchlist(getline(lnum)..getline(lnum + 1), s:package_names)
+ if !empty(tokens) | let s:package = tokens[1] | endif
+ endif
+ let lnum = search(s:keywords, 'eW')
+ endwhile
+ return type_names
+ endfunction
+
+else
+ function! s:GetDeclaredTypeNames() abort
+ if bufname() =~# '\<\%(module\|package\)-info\.java\=$'
+ return [expand('%:t:r')]
+ endif
+ " Undo the unsetting of &hls, see below
+ if &hls
+ defer execute('set hls')
+ endif
+ " Possibly restore the current values for registers '"' and "y", see below
+ defer call('setreg', ['"', getreg('"'), getregtype('"')])
+ defer call('setreg', ['y', getreg('y'), getregtype('y')])
+ defer execute('silent bwipeout')
+ " Copy buffer contents for modification
+ silent %y y
+ new
+ " Apply ":help scratch-buffer" effects and match "$" in Java (generated)
+ " type names (see s:type_names)
+ setlocal iskeyword+=$ buftype=nofile bufhidden=hide noswapfile nohls
+ 0put y
+ " Discard text blocks and strings
+ silent keeppatterns %s/\\\@<!"""\_.\{-}\\\@<!"""\|\\"//ge
+ silent keeppatterns %s/".*"//ge
+ " Discard comments
+ silent keeppatterns %s/\/\/.\+$//ge
+ silent keeppatterns %s/\/\*\_.\{-}\*\///ge
+ call cursor(1, 1)
+ let type_names = []
+ let lnum = search(s:keywords, 'eW')
+ while lnum > 0
+ let line = getline(lnum)
+ if line =~# '\<package\>'
+ let tokens = matchlist(line..getline(lnum + 1), s:package_names)
+ if !empty(tokens) | let s:package = tokens[1] | endif
+ else
+ let tokens = matchlist(line..getline(lnum + 1), s:type_names)
+ if !empty(tokens) | call add(type_names, tokens[1]) | endif
+ endif
+ let lnum = search(s:keywords, 'eW')
+ endwhile
+ return type_names
+ endfunction
+endif
+
+if has('win32')
+
+ function! s:GlobClassFiles(src_type_name) abort
+ return glob(a:src_type_name..'$*.class', 1, 1)
+ endfunction
+
+else
+ function! s:GlobClassFiles(src_type_name) abort
+ return glob(a:src_type_name..'\$*.class', 1, 1)
+ endfunction
+endif
+
+if exists('g:spotbugs_properties') &&
+ \ (has_key(g:spotbugs_properties, 'sourceDirPath') &&
+ \ has_key(g:spotbugs_properties, 'classDirPath')) ||
+ \ (has_key(g:spotbugs_properties, 'testSourceDirPath') &&
+ \ has_key(g:spotbugs_properties, 'testClassDirPath'))
+
+function! s:FindClassFiles(src_type_name) abort
+ let class_files = []
+ " Match pairwise the components of source and class pathnames
+ for [src_dir, bin_dir] in filter([
+ \ [get(g:spotbugs_properties, 'sourceDirPath', ''),
+ \ get(g:spotbugs_properties, 'classDirPath', '')],
+ \ [get(g:spotbugs_properties, 'testSourceDirPath', ''),
+ \ get(g:spotbugs_properties, 'testClassDirPath', '')]],
+ \ '!(empty(v:val[0]) || empty(v:val[1]))')
+ " Since only the rightmost "src" is sought, while there can be any number of
+ " such filenames, no "fnamemodify(a:src_type_name, ':p:s?src?bin?')" is used
+ let tail_idx = strridx(a:src_type_name, src_dir)
+ " No such directory or no such inner type (i.e. without "$")
+ if tail_idx < 0 | continue | endif
+ " Substitute "bin_dir" for the rightmost "src_dir"
+ let candidate_type_name = strpart(a:src_type_name, 0, tail_idx)..
+ \ bin_dir..
+ \ strpart(a:src_type_name, (tail_idx + strlen(src_dir)))
+ for candidate in insert(s:GlobClassFiles(candidate_type_name),
+ \ candidate_type_name..'.class')
+ if filereadable(candidate) | call add(class_files, shellescape(candidate)) | endif
+ endfor
+ if !empty(class_files) | break | endif
+ endfor
+ return class_files
+endfunction
+
+else
+function! s:FindClassFiles(src_type_name) abort
+ let class_files = []
+ for candidate in insert(s:GlobClassFiles(a:src_type_name),
+ \ a:src_type_name..'.class')
+ if filereadable(candidate) | call add(class_files, shellescape(candidate)) | endif
+ endfor
+ return class_files
+endfunction
+endif
+
+function! s:CollectClassFiles() abort
+ " Get a platform-independent pathname prefix, cf. "expand('%:p:h')..'/'"
+ let pathname = expand('%:p')
+ let tail_idx = strridx(pathname, expand('%:t'))
+ let src_pathname = strpart(pathname, 0, tail_idx)
+ let all_class_files = []
+ " Get all type names in the current buffer and let the filename globbing
+ " discover inner type names from arbitrary type names
+ for type_name in s:GetDeclaredTypeNames()
+ call extend(all_class_files, s:FindClassFiles(src_pathname..type_name))
+ endfor
+ return all_class_files
+endfunction
+
+" Expose class files for removal etc.
+let b:spotbugs_class_files = s:CollectClassFiles()
+let s:package_dir_heads = repeat(':h', (1 + strlen(substitute(s:package, '[^.;]', '', 'g'))))
+let g:current_compiler = 'spotbugs'
+" CompilerSet makeprg=spotbugs
+let &l:makeprg = 'spotbugs'..(has('win32') ? '.bat' : '')..' '..
+ \ get(b:, 'spotbugs_makeprg_params', get(g:, 'spotbugs_makeprg_params', '-workHard -experimental'))..
+ \ ' -textui -emacs -auxclasspath %:p'..s:package_dir_heads..':S -sourcepath %:p'..s:package_dir_heads..':S '..
+ \ join(b:spotbugs_class_files, ' ')
+" Emacs expects doubled line numbers
+setlocal errorformat=%f:%l:%*[0-9]\ %m,%f:-%*[0-9]:-%*[0-9]\ %m
+
+" " This compiler is meant to be used for a single buffer only
+" exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
+" exe 'CompilerSet errorformat='..escape(&l:errorformat, ' \|"')
+
+delfunction s:CollectClassFiles
+delfunction s:FindClassFiles
+delfunction s:GlobClassFiles
+delfunction s:GetDeclaredTypeNames
+let &cpo = s:cpo_save
+unlet s:package_dir_heads s:package s:package_names s:type_names s:keywords s:cpo_save
+
+" vim: set foldmethod=syntax shiftwidth=2 expandtab:
diff --git a/runtime/compiler/typst.vim b/runtime/compiler/typst.vim
index 33e55818e9..13699f4675 100644
--- a/runtime/compiler/typst.vim
+++ b/runtime/compiler/typst.vim
@@ -1,7 +1,8 @@
" Vim compiler file
" Language: Typst
-" Maintainer: Gregory Anders
-" Last Change: 2024-07-14
+" Previous Maintainer: Gregory Anders
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Dec 09
" Based on: https://github.com/kaarmu/typst.vim
if exists('current_compiler')
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index c5dabeb551..cb3b2a3f77 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1114,7 +1114,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
Open a terminal instance in a buffer
By default (and currently the only option) the terminal will not be
- connected to an external process. Instead, input send on the channel will
+ connected to an external process. Instead, input sent on the channel will
be echoed directly by the terminal. This is useful to display ANSI
terminal sequences returned as part of a rpc message, or similar.
@@ -1125,6 +1125,17 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
|nvim_chan_send()| can be called immediately to process sequences in a
virtual terminal having the intended size.
+ Example: this `TermHl` command can be used to display and highlight raw
+ ANSI termcodes, so you can use Nvim as a "scrollback pager" (for terminals
+ like kitty): *terminal-scrollback-pager* >lua
+ vim.api.nvim_create_user_command('TermHl', function()
+ local b = vim.api.nvim_create_buf(false, true)
+ local chan = vim.api.nvim_open_term(b, {})
+ vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
+ vim.api.nvim_win_set_buf(0, b)
+ end, { desc = 'Highlights ANSI termcodes in curbuf' })
+<
+
Attributes: ~
not allowed when |textlock| is active
@@ -3483,9 +3494,9 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()*
• event: (string) name of the triggered event
|autocmd-events|
• group: (number|nil) autocommand group id, if any
- • match: (string) expanded value of <amatch>
- • buf: (number) expanded value of <abuf>
- • file: (string) expanded value of <afile>
+ • file: (string) <afile> (not expanded to a full path)
+ • match: (string) <amatch> (expanded to a full path)
+ • buf: (number) <abuf>
• data: (any) arbitrary data passed from
|nvim_exec_autocmds()| *event-data*
• command (string) optional: Vim command to execute on event.
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 998ef5e9f3..c094281154 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -463,6 +463,10 @@ CompleteDone After Insert mode completion is done. Either
|v:completed_item| gives the completed item.
Sets these |v:event| keys:
+ complete_word The word that was
+ selected, empty if
+ abandoned complete.
+ complete_type |complete_info_mode|
reason Reason for completion being
done. Can be one of:
- "accept": completion was
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 585db21a0b..f2942b959b 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -2997,7 +2997,7 @@ getbufline({buf}, {lnum} [, {end}]) *getbufline()*
Parameters: ~
• {buf} (`integer|string`)
• {lnum} (`integer`)
- • {end_} (`integer?`)
+ • {end} (`integer?`)
Return: ~
(`any`)
@@ -3635,7 +3635,7 @@ getline({lnum} [, {end}]) *getline()*
Parameters: ~
• {lnum} (`integer|string`)
- • {end_} (`nil|false?`)
+ • {end} (`nil|false?`)
Return: ~
(`string`)
@@ -5443,7 +5443,7 @@ jobwait({jobs} [, {timeout}]) *jobwait()*
• {timeout} (`integer?`)
Return: ~
- (`any`)
+ (`integer[]`)
join({list} [, {sep}]) *join()*
Join the items in {list} together into one String.
@@ -6292,7 +6292,7 @@ matchbufline({buf}, {pat}, {lnum}, {end}, [, {dict}]) *matchbufline()*
• {buf} (`string|integer`)
• {pat} (`string`)
• {lnum} (`string|integer`)
- • {end_} (`string|integer`)
+ • {end} (`string|integer`)
• {dict} (`table?`)
Return: ~
@@ -7786,7 +7786,7 @@ reltime({start}, {end})
Parameters: ~
• {start} (`any?`)
- • {end_} (`any?`)
+ • {end} (`any?`)
Return: ~
(`any`)
@@ -7847,7 +7847,7 @@ remove({list}, {idx}, {end})
Parameters: ~
• {list} (`any[]`)
• {idx} (`integer`)
- • {end_} (`integer?`)
+ • {end} (`integer?`)
Return: ~
(`any`)
@@ -7869,7 +7869,7 @@ remove({blob}, {idx}, {end})
Parameters: ~
• {blob} (`any`)
• {idx} (`integer`)
- • {end_} (`integer?`)
+ • {end} (`integer?`)
Return: ~
(`any`)
@@ -7986,7 +7986,7 @@ rpcnotify({channel}, {event} [, {args}...]) *rpcnotify()*
Parameters: ~
• {channel} (`integer`)
• {event} (`string`)
- • {args} (`any?`)
+ • {...} (`any`)
Return: ~
(`any`)
@@ -8001,7 +8001,7 @@ rpcrequest({channel}, {method} [, {args}...]) *rpcrequest()*
Parameters: ~
• {channel} (`integer`)
• {method} (`string`)
- • {args} (`any?`)
+ • {...} (`any`)
Return: ~
(`any`)
@@ -8500,7 +8500,7 @@ searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeo
Parameters: ~
• {start} (`string`)
• {middle} (`string`)
- • {end_} (`string`)
+ • {end} (`string`)
• {flags} (`string?`)
• {skip} (`string|function?`)
• {stopline} (`integer?`)
@@ -8524,7 +8524,7 @@ searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {ti
Parameters: ~
• {start} (`string`)
• {middle} (`string`)
- • {end_} (`string`)
+ • {end} (`string`)
• {flags} (`string?`)
• {skip} (`string|function?`)
• {stopline} (`integer?`)
@@ -9840,7 +9840,7 @@ slice({expr}, {start} [, {end}]) *slice()*
Parameters: ~
• {expr} (`any`)
• {start} (`integer`)
- • {end_} (`integer?`)
+ • {end} (`integer?`)
Return: ~
(`any`)
@@ -10234,6 +10234,7 @@ str2list({string} [, {utf8}]) *str2list()*
and exists only for backwards-compatibility.
With UTF-8 composing characters are handled properly: >vim
echo str2list("á") " returns [97, 769]
+<
Parameters: ~
• {string} (`string`)
@@ -11991,7 +11992,7 @@ winlayout([{tabnr}]) *winlayout()*
• {tabnr} (`integer?`)
Return: ~
- (`any`)
+ (`any[]`)
winline() *winline()*
The result is a Number, which is the screen line of the cursor
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 7967e2ce1a..f6a3e95b35 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -41,15 +41,19 @@ thus you cannot edit beyond that.
The command-lines that you enter are remembered in a history table. You can
recall them with the up and down cursor keys. There are actually five
history tables:
+
- one for ':' commands
- one for search strings
- one for expressions
- one for input lines, typed for the |input()| function.
- one for debug mode commands
+
These are completely separate. Each history can only be accessed when
entering the same type of line.
Use the 'history' option to set the number of lines that are remembered.
+
Notes:
+
- When you enter a command-line that is exactly the same as an older one, the
old one is removed (to avoid repeated commands moving older commands out of
the history).
diff --git a/runtime/doc/backers.txt b/runtime/doc/credits.txt
index d0cbd94978..5fe79dfef8 100644
--- a/runtime/doc/backers.txt
+++ b/runtime/doc/credits.txt
@@ -1,11 +1,118 @@
-*backers.txt* Nvim
+*credits.txt* Nvim
NVIM REFERENCE MANUAL
==============================================================================
-Fundraiser Backers
+Credits *credits*
+
+Most of Vim was written by Bram Moolenaar <Bram@vim.org> |Bram-Moolenaar|.
+
+Parts of the documentation come from several Vi manuals, written by:
+ W.N. Joy
+ Alan P.W. Hewett
+ Mark Horton
+
+The Vim editor is based on Stevie and includes (ideas from) other software,
+worked on by the people mentioned here. Other people helped by sending me
+patches, suggestions and giving feedback about what is good and bad in Vim.
+
+Vim would never have become what it is now, without the help of these people!
+
+ Ron Aaron Win32 GUI changes
+ Mohsin Ahmed encryption
+ Zoltan Arpadffy work on VMS port
+ Tony Andrews Stevie
+ Gert van Antwerpen changes for DJGPP on MS-DOS
+ Berkeley DB(3) ideas for swap file implementation
+ Keith Bostic Nvi
+ Walter Briscoe Makefile updates, various patches
+ Ralf Brown SPAWNO library for MS-DOS
+ Robert Colon many useful remarks
+ Marcin Dalecki GTK+ GUI port, toolbar icons, gettext()
+ Kayhan Demirel sent me news in Uganda
+ Chris & John Downey xvi (ideas for multi-windows version)
+ Henk Elbers first VMS port
+ Daniel Elstner GTK+ 2 port
+ Eric Fischer Mac port, 'cindent', and other improvements
+ Benji Fisher Answering lots of user questions
+ Bill Foster Athena GUI port (later removed)
+ Google Let Bram work on Vim one day a week
+ Loic Grenie xvim (ideas for multi windows version)
+ Sven Guckes Vim promoter and previous WWW page maintainer
+ Darren Hiebert Exuberant ctags
+ Jason Hildebrand GTK+ 2 port
+ Bruce Hunsaker improvements for VMS port
+ Andy Kahn Cscope support, GTK+ GUI port
+ Oezguer Kesim Maintainer of Vim Mailing Lists
+ Axel Kielhorn work on the Macintosh port
+ Steve Kirkendall Elvis
+ Roger Knobbe original port to Windows NT
+ Sergey Laskavy Vim's help from Moscow
+ Felix von Leitner Previous maintainer of Vim Mailing Lists
+ David Leonard Port of Python extensions to Unix
+ Avner Lottem Edit in right-to-left windows
+ Flemming Madsen X11 client-server, various features and patches
+ Tony Mechelynck answers many user questions
+ Paul Moore Python interface extensions, many patches
+ Katsuhito Nagano Work on multibyte versions
+ Sung-Hyun Nam Work on multibyte versions
+ Vince Negri Win32 GUI and generic console enhancements
+ Steve Oualline Author of the first Vim book |frombook|
+ Dominique Pelle Valgrind reports and many fixes
+ A.Politz Many bug reports and some fixes
+ George V. Reilly Win32 port, Win32 GUI start-off
+ Stephen Riehm bug collector
+ Stefan Roemer various patches and help to users
+ Ralf Schandl IBM OS/390 port
+ Olaf Seibert DICE and BeBox version, regexp improvements
+ Mortaza Shiran Farsi patches
+ Peter da Silva termlib
+ Paul Slootman OS/2 port
+ Henry Spencer regular expressions
+ Dany St-Amant Macintosh port
+ Tim Thompson Stevie
+ G. R. (Fred) Walter Stevie
+ Sven Verdoolaege Perl interface
+ Robert Webb Command-line completion, GUI versions, and
+ lots of patches
+ Ingo Wilken Tcl interface
+ Mike Williams PostScript printing
+ Juergen Weigert Lattice version, AUX improvements, Unix and
+ MS-DOS ports, autoconf
+ Stefan 'Sec' Zehl Maintainer of vim.org
+ Yasuhiro Matsumoto many MS-Windows improvements
+ Ken Takata fixes and features
+ Kazunobu Kuriyama GTK 3
+ Christian Brabandt many fixes, features, user support, etc.
+ Yegappan Lakshmanan many quickfix features
+
+I wish to thank all the people that sent me bug reports and suggestions. The
+list is too long to mention them all here. Vim would not be the same without
+the ideas from all these people: They keep Vim alive!
+*love* *peace* *friendship* *gross-national-happiness*
+
+
+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". 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)". Source code is freely available.
+ *Elvis*
+Elvis Another Vi clone, made by Steve Kirkendall. Very compact but isn't
+ as flexible as Vim. Source code is freely available.
+
+Vim Nvim is based on Vim. https://www.vim.org/
+
+
+==============================================================================
+Neovim fundraiser backers *backers.txt*
Thank you to everyone who backed the original Neovim Fundraiser.
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index c6ca5e5ce9..ab9c0b2ce8 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -64,6 +64,7 @@ LSP
• `client.is_stopped()` Use |Client:is_stopped()| instead.
• `client.supports_method()` Use |Client:supports_method()| instead.
• `client.on_attach()` Use |Client:on_attach()| instead.
+• `vim.lsp.start_client()` Use |vim.lsp.start()| instead.
------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10*
diff --git a/runtime/doc/dev_arch.txt b/runtime/doc/dev_arch.txt
index 1cb3b9ad67..2be6221117 100644
--- a/runtime/doc/dev_arch.txt
+++ b/runtime/doc/dev_arch.txt
@@ -46,11 +46,11 @@ Remember to bump NVIM_API_LEVEL if it wasn't already during this development
cycle.
Other references:
-* |msgpack-rpc|
-* |ui|
-* https://github.com/neovim/neovim/pull/3246
-* https://github.com/neovim/neovim/pull/18375
-* https://github.com/neovim/neovim/pull/21605
+- |msgpack-rpc|
+- |ui|
+- https://github.com/neovim/neovim/pull/3246
+- https://github.com/neovim/neovim/pull/18375
+- https://github.com/neovim/neovim/pull/21605
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index a61c569a67..da64475465 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -300,7 +300,7 @@ vim.paste in runtime/lua/vim/_editor.lua like this: >
--- @returns false if client should cancel the paste.
-LUA STDLIB DESIGN GUIDELINES *dev-lua*
+STDLIB DESIGN GUIDELINES *dev-lua*
See also |dev-naming|.
@@ -337,7 +337,7 @@ preference):
way. Advantage is that propagation happens for free and it's harder to
accidentally swallow errors. (E.g. using
`uv_handle/pipe:write()` without checking return values is common.)
-4. `on_error` parameter
+4. `on_error` callback
- For async and "visitors" traversing a graph, where many errors may be
collected while work continues.
5. `vim.notify` (sometimes with optional `opts.silent` (async, visitors ^))
@@ -434,7 +434,9 @@ Use existing common {verb} names (actions) if possible:
- eval: Evaluates an expression
- exec: Executes code, may return a result
- fmt: Formats
- - get: Gets things (often by a query)
+ - get: Gets things. Two variants (overloads):
+ 1. `get<T>(id: int): T` returns one item.
+ 2. `get<T>(filter: dict): T[]` returns a list.
- inspect: Presents a high-level, often interactive, view
- is_enabled: Checks if functionality is enabled.
- open: Opens something (a buffer, window, …)
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 9ccc3102b6..eaa3681caa 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -163,6 +163,33 @@ show a sign for the highest severity diagnostic on a given line: >lua
}
<
+ *diagnostic-loclist-example*
+Whenever the |location-list| is opened, the following `show` handler will show
+the most recent diagnostics: >lua
+
+ vim.diagnostic.handlers.loclist = {
+ show = function(_, _, _, opts)
+ -- Generally don't want it to open on every update
+ opts.loclist.open = opts.loclist.open or false
+ local winid = vim.api.nvim_get_current_win()
+ vim.diagnostic.setloclist(opts.loclist)
+ vim.api.nvim_set_current_win(winid)
+ end
+ }
+<
+
+The handler accepts the same options as |vim.diagnostic.setloclist()| and can be
+configured using |vim.diagnostic.config()|: >lua
+
+ -- Open the location list on every diagnostic change (warnings/errors only).
+ vim.diagnostic.config({
+ loclist = {
+ open = true,
+ severity = { min = vim.diagnostic.severity.WARN },
+ }
+ })
+<
+
==============================================================================
HIGHLIGHTS *diagnostic-highlights*
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index 19c018bc11..cc520484b3 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -597,7 +597,7 @@ To disable this behavior, set the following variable in your vimrc: >
let g:gdscript_recommended_style = 0
-GIT COMMIT *ft-gitcommit-plugin*
+GIT COMMIT *ft-gitcommit-plugin*
One command, :DiffGitCached, is provided to show a diff of the current commit
in the preview window. It is equivalent to calling "git diff --cached" plus
@@ -778,7 +778,7 @@ An alternative to using `MANPAGER` in shell can be redefined `man`, for example:
nvim "+hide Man $1"
}
-MARKDOWN *ft-markdown-plugin*
+MARKDOWN *ft-markdown-plugin*
To enable folding use this: >
let g:markdown_folding = 1
@@ -870,7 +870,7 @@ To enable this behavior, set the following variable in your vimrc: >
let g:rst_style = 1
-RNOWEB *ft-rnoweb-plugin*
+RNOWEB *ft-rnoweb-plugin*
The 'formatexpr' option is set dynamically with different values for R code
and for LaTeX code. If you prefer that 'formatexpr' is not set, add to your
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 21f1ba8241..380fa71537 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -1,10 +1,10 @@
*gui.txt* Nvim
- VIM REFERENCE MANUAL by Bram Moolenaar
+ VIM REFERENCE MANUAL by Bram Moolenaar
-Nvim Graphical User Interface *gui* *GUI*
+Nvim Graphical User Interface *gui* *GUI*
Any client that supports the Nvim |ui-protocol| can be used as a UI for Nvim.
And multiple UIs can connect to the same Nvim instance! The terms "UI" and
@@ -20,8 +20,9 @@ features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|.
Nvim provides a default, builtin UI (the |TUI|), but there are many other
(third-party) GUIs that you can use instead:
-- Firenvim (Nvim in your web browser!) https://github.com/glacambre/firenvim
+ *vscode*
- vscode-neovim (Nvim in VSCode!) https://github.com/vscode-neovim/vscode-neovim
+- Firenvim (Nvim in your web browser!) https://github.com/glacambre/firenvim
- Neovide https://neovide.dev/
- Goneovim https://github.com/akiyosi/goneovim
- Nvy https://github.com/RMichelsen/Nvy
@@ -32,71 +33,71 @@ Nvim provides a default, builtin UI (the |TUI|), but there are many other
Type |gO| to see the table of contents.
==============================================================================
-Starting the GUI *gui-config* *gui-start*
+Starting the GUI *gui-config* *gui-start*
- *ginit.vim* *gui-init* *gvimrc* *$MYGVIMRC*
+ *ginit.vim* *gui-init* *gvimrc* *$MYGVIMRC*
For GUI-specific configuration Nvim provides the |UIEnter| event. This
happens after other |initialization|s, or whenever a UI attaches (multiple UIs
can connect to any Nvim instance).
Example: this sets "g:gui" to the value of the UI's "rgb" field: >
- :autocmd UIEnter * let g:gui = filter(nvim_list_uis(),{k,v-> v.chan==v:event.chan})[0].rgb
+ :autocmd UIEnter * let g:gui = filter(nvim_list_uis(),{k,v-> v.chan==v:event.chan})[0].rgb
<
- *:winp* *:winpos* *E188*
+ *:winp* *:winpos* *E188*
:winp[os]
- Display current position of the top left corner of the GUI vim
- window in pixels. Does not work in all versions.
- Also see |getwinpos()|, |getwinposx()| and |getwinposy()|.
-
-:winp[os] {X} {Y} *E466*
- Put the GUI vim window at the given {X} and {Y} coordinates.
- The coordinates should specify the position in pixels of the
- top left corner of the window.
- When the GUI window has not been opened yet, the values are
- remembered until the window is opened. The position is
- adjusted to make the window fit on the screen (if possible).
-
- *:wi* *:win* *:winsize* *E465*
+ Display current position of the top left corner of the GUI vim
+ window in pixels. Does not work in all versions.
+ Also see |getwinpos()|, |getwinposx()| and |getwinposy()|.
+
+:winp[os] {X} {Y} *E466*
+ Put the GUI vim window at the given {X} and {Y} coordinates.
+ The coordinates should specify the position in pixels of the
+ top left corner of the window.
+ When the GUI window has not been opened yet, the values are
+ remembered until the window is opened. The position is
+ adjusted to make the window fit on the screen (if possible).
+
+ *:wi* *:win* *:winsize* *E465*
:win[size] {width} {height}
- Set the window height to {width} by {height} characters.
- Obsolete, use ":set lines=11 columns=22".
+ Set the window height to {width} by {height} characters.
+ Obsolete, use ":set lines=11 columns=22".
==============================================================================
-Scrollbars *gui-scrollbars*
+Scrollbars *gui-scrollbars*
There are vertical scrollbars and a horizontal scrollbar. You may
configure which ones appear with the 'guioptions' option.
The interface looks like this (with `:set guioptions=mlrb`):
>
- +------------------------------+ `
- | File Edit Help | <- Menu bar (m) `
- +-+--------------------------+-+ `
- |^| |^| `
- |#| Text area. |#| `
- | | | | `
- |v|__________________________|v| `
- Normal status line -> |-+ File.c 5,2 +-| `
+ +------------------------------+ `
+ | File Edit Help | <- Menu bar (m) `
+ +-+--------------------------+-+ `
+ |^| |^| `
+ |#| Text area. |#| `
+ | | | | `
+ |v|__________________________|v| `
+ Normal status line -> |-+ File.c 5,2 +-| `
between Vim windows |^|""""""""""""""""""""""""""|^| `
- | | | | `
- | | Another file buffer. | | `
- | | | | `
- |#| |#| `
- Left scrollbar (l) -> |#| |#| <- Right `
- |#| |#| scrollbar (r) `
- | | | | `
- |v| |v| `
- +-+--------------------------+-+ `
- | |< #### >| | <- Bottom `
- +-+--------------------------+-+ scrollbar (b) `
+ | | | | `
+ | | Another file buffer. | | `
+ | | | | `
+ |#| |#| `
+ Left scrollbar (l) -> |#| |#| <- Right `
+ |#| |#| scrollbar (r) `
+ | | | | `
+ |v| |v| `
+ +-+--------------------------+-+ `
+ | |< #### >| | <- Bottom `
+ +-+--------------------------+-+ scrollbar (b) `
<
Any of the scrollbar or menu components may be turned off by not putting the
appropriate letter in the 'guioptions' string. The bottom scrollbar is
only useful when 'nowrap' is set.
-VERTICAL SCROLLBARS *gui-vert-scroll*
+VERTICAL SCROLLBARS *gui-vert-scroll*
Each Vim window has a scrollbar next to it which may be scrolled up and down
to move through the text in that buffer. The size of the scrollbar-thumb
@@ -115,7 +116,7 @@ is on the left half, the right scrollbar column will contain scrollbars for
the rightmost windows. The same happens on the other side.
-HORIZONTAL SCROLLBARS *gui-horiz-scroll*
+HORIZONTAL SCROLLBARS *gui-horiz-scroll*
The horizontal scrollbar (at the bottom of the Vim GUI) may be used to
scroll text sideways when the 'wrap' option is turned off. The
@@ -131,7 +132,7 @@ include the 'h' flag in 'guioptions'. Then the scrolling is limited by the
text of the current cursor line.
==============================================================================
-Drag and drop *drag-n-drop*
+Drag and drop *drag-n-drop*
You can drag and drop one or more files into the Vim window, where they will
be opened as if a |:drop| command was used.
@@ -150,12 +151,12 @@ names with any Ex command. Special characters (space, tab, double quote and
"|"; backslash on non-MS-Windows systems) will be escaped.
==============================================================================
-Menus *menus*
+Menus *menus*
For an introduction see |usr_42.txt| in the user manual.
-Using Menus *using-menus*
+Using Menus *using-menus*
Basically, menus can be used just like mappings. You can define your own
menus, as many as you like.
@@ -165,45 +166,45 @@ what the key sequence was.
For creating menus in a different language, see |:menutrans|.
- *menu.vim*
+ *menu.vim*
The default menus are read from the file "$VIMRUNTIME/menu.vim". See
|$VIMRUNTIME| for where the path comes from. You can set up your own menus.
Starting off with the default set is a good idea. You can add more items, or,
if you don't like the defaults at all, start with removing all menus
|:unmenu-all|. You can also avoid the default menus being loaded by adding
this line to your vimrc file (NOT your gvimrc file!): >
- :let did_install_default_menus = 1
+ :let did_install_default_menus = 1
If you also want to avoid the Syntax menu: >
- :let did_install_syntax_menu = 1
+ :let did_install_syntax_menu = 1
The first item in the Syntax menu can be used to show all available filetypes
in the menu (which can take a bit of time to load). If you want to have all
filetypes already present at startup, add: >
- :let do_syntax_sel_menu = 1
+ :let do_syntax_sel_menu = 1
Note that the menu.vim is sourced when `:syntax on` or `:filetype on` is
executed or after your .vimrc file is sourced. This means that the 'encoding'
option and the language of messages (`:language messages`) must be set before
that (if you want to change them).
- *console-menus*
+ *console-menus*
Although this documentation is in the GUI section, you can actually use menus
in console mode too. You will have to load |menu.vim| explicitly then, it is
not done by default. You can use the |:emenu| command and command-line
completion with 'wildmenu' to access the menu entries almost like a real menu
system. To do this, put these commands in your vimrc file: >
- :source $VIMRUNTIME/menu.vim
- :set wildmenu
- :set cpo-=<
- :set wcm=<C-Z>
- :map <F4> :emenu <C-Z>
+ :source $VIMRUNTIME/menu.vim
+ :set wildmenu
+ :set cpo-=<
+ :set wcm=<C-Z>
+ :map <F4> :emenu <C-Z>
Pressing <F4> will start the menu. You can now use the cursor keys to select
a menu entry. Hit <Enter> to execute it. Hit <Esc> if you want to cancel.
-Creating New Menus *creating-menus*
+Creating New Menus *creating-menus*
- *:me* *:menu* *:noreme* *:noremenu*
- *E330* *E327* *E331* *E336* *E333*
- *E328* *E329* *E337* *E792*
+ *:me* *:menu* *:noreme* *:noremenu*
+ *E330* *E327* *E331* *E336* *E333*
+ *E328* *E329* *E337* *E792*
To create a new menu item, use the ":menu" commands. They are mostly like
the ":map" set of commands (see |map-modes|), but the first argument is a menu
item name, given as a path of menus and submenus with a '.' between them,
@@ -224,15 +225,16 @@ tooltips for menus. See |terminal-input|.
Special characters in a menu name:
- *menu-shortcut*
- & The next character is the shortcut key. Make sure each
- shortcut key is only used once in a (sub)menu. If you want to
- insert a literal "&" in the menu name use "&&".
- *menu-text*
- <Tab> Separates the menu name from right-aligned text. This can be
- used to show the equivalent typed command. The text "<Tab>"
- can be used here for convenience. If you are using a real
- tab, don't forget to put a backslash before it!
+ *menu-shortcut*
+- & The next character is the shortcut key. Make sure each shortcut key is
+ only used once in a (sub)menu. If you want to insert a literal "&" in the
+ menu name use "&&".
+ *menu-text*
+- <Tab> Separates the menu name from right-aligned text. This can be used to
+ show the equivalent typed command. The text "<Tab>" can be used here for
+ convenience. If you are using a real tab, don't forget to put a backslash
+ before it!
+
Example: >
:amenu &File.&Open<Tab>:e :browse e<CR>
@@ -242,99 +244,99 @@ With the shortcut "F" (while keeping the <Alt> key pressed), and then "O",
this menu can be used. The second part is shown as "Open :e". The ":e"
is right aligned, and the "O" is underlined, to indicate it is the shortcut.
- *:am* *:amenu* *:an* *:anoremenu*
+ *:am* *:amenu* *:an* *:anoremenu*
The ":amenu" command can be used to define menu entries for all modes at once,
except for Terminal mode. To make the command work correctly, a character is
-automatically inserted for some modes:
- mode inserted appended ~
- Normal nothing nothing
- Visual <C-C> <C-\><C-G>
- Insert <C-\><C-O>
- Cmdline <C-C> <C-\><C-G>
- Op-pending <C-C> <C-\><C-G>
-
+automatically inserted for some modes: >
+ mode inserted appended
+ Normal nothing nothing
+ Visual <C-C> <C-\><C-G>
+ Insert <C-\><C-O>
+ Cmdline <C-C> <C-\><C-G>
+ Op-pending <C-C> <C-\><C-G>
+<
Example: >
- :amenu File.Next :next^M
+ :amenu File.Next :next^M
is equal to: >
- :nmenu File.Next :next^M
- :vmenu File.Next ^C:next^M^\^G
- :imenu File.Next ^\^O:next^M
- :cmenu File.Next ^C:next^M^\^G
- :omenu File.Next ^C:next^M^\^G
+ :nmenu File.Next :next^M
+ :vmenu File.Next ^C:next^M^\^G
+ :imenu File.Next ^\^O:next^M
+ :cmenu File.Next ^C:next^M^\^G
+ :omenu File.Next ^C:next^M^\^G
Careful: In Insert mode this only works for a SINGLE Normal mode command,
because of the CTRL-O. If you have two or more commands, you will need to use
the ":imenu" command. For inserting text in any mode, you can use the
expression register: >
- :amenu Insert.foobar "='foobar'<CR>P
+ :amenu Insert.foobar "='foobar'<CR>P
The special text <Cmd> begins a "command menu", it executes the command
directly without changing modes. Where you might use ":...<CR>" you can
instead use "<Cmd>...<CR>". See |<Cmd>| for more info. Example: >
- anoremenu File.Next <Cmd>next<CR>
+ anoremenu File.Next <Cmd>next<CR>
Note that <Esc> in Cmdline mode executes the command, like in a mapping. This
is Vi compatible. Use CTRL-C to quit Cmdline mode.
- *:nme* *:nmenu* *:nnoreme* *:nnoremenu* *:nunme* *:nunmenu*
+ *:nme* *:nmenu* *:nnoreme* *:nnoremenu* *:nunme* *:nunmenu*
Menu commands starting with "n" work in Normal mode. |mapmode-n|
- *:ome* *:omenu* *:onoreme* *:onoremenu* *:ounme* *:ounmenu*
+ *:ome* *:omenu* *:onoreme* *:onoremenu* *:ounme* *:ounmenu*
Menu commands starting with "o" work in Operator-pending mode. |mapmode-o|
- *:vme* *:vmenu* *:vnoreme* *:vnoremenu* *:vunme* *:vunmenu*
+ *:vme* *:vmenu* *:vnoreme* *:vnoremenu* *:vunme* *:vunmenu*
Menu commands starting with "v" work in Visual mode. |mapmode-v|
- *:xme* *:xmenu* *:xnoreme* *:xnoremenu* *:xunme* *:xunmenu*
+ *:xme* *:xmenu* *:xnoreme* *:xnoremenu* *:xunme* *:xunmenu*
Menu commands starting with "x" work in Visual and Select mode. |mapmode-x|
- *:sme* *:smenu* *:snoreme* *:snoremenu* *:sunme* *:sunmenu*
+ *:sme* *:smenu* *:snoreme* *:snoremenu* *:sunme* *:sunmenu*
Menu commands starting with "s" work in Select mode. |mapmode-s|
- *:ime* *:imenu* *:inoreme* *:inoremenu* *:iunme* *:iunmenu*
+ *:ime* *:imenu* *:inoreme* *:inoremenu* *:iunme* *:iunmenu*
Menu commands starting with "i" work in Insert mode. |mapmode-i|
- *:cme* *:cmenu* *:cnoreme* *:cnoremenu* *:cunme* *:cunmenu*
+ *:cme* *:cmenu* *:cnoreme* *:cnoremenu* *:cunme* *:cunmenu*
Menu commands starting with "c" work in Cmdline mode. |mapmode-c|
- *:tlm* *:tlmenu* *:tln* *:tlnoremenu* *:tlu* *:tlunmenu*
+ *:tlm* *:tlmenu* *:tln* *:tlnoremenu* *:tlu* *:tlunmenu*
Menu commands starting with "tl" work in Terminal mode. |mapmode-t|
- *:menu-<silent>* *:menu-silent*
+ *:menu-<silent>* *:menu-silent*
To define a menu which will not be echoed on the command line, add
"<silent>" as the first argument. Example: >
- :menu <silent> Settings.Ignore\ case :set ic<CR>
+ :menu <silent> Settings.Ignore\ case :set ic<CR>
The ":set ic" will not be echoed when using this menu. Messages from the
executed command are still given though. To shut them up too, add a ":silent"
in the executed command: >
- :menu <silent> Search.Header :exe ":silent normal /Header\r"<CR>
+ :menu <silent> Search.Header :exe ":silent normal /Header\r"<CR>
"<silent>" may also appear just after "<script>".
- *:menu-<script>* *:menu-script*
+ *:menu-<script>* *:menu-script*
The "to" part of the menu will be inspected for mappings. If you don't want
this, use the ":noremenu" command (or the similar one for a specific mode).
If you do want to use script-local mappings, add "<script>" as the very first
argument to the ":menu" command or just after "<silent>".
- *menu-priority*
+ *menu-priority*
You can give a priority to a menu. Menus with a higher priority go more to
the right. The priority is given as a number before the ":menu" command.
Example: >
- :80menu Buffer.next :bn<CR>
-
-The default menus have these priorities:
- File 10
- Edit 20
- Tools 40
- Syntax 50
- Buffers 60
- Window 70
- Help 9999
-
+ :80menu Buffer.next :bn<CR>
+
+The default menus have these priorities: >
+ File 10
+ Edit 20
+ Tools 40
+ Syntax 50
+ Buffers 60
+ Window 70
+ Help 9999
+<
When no or zero priority is given, 500 is used.
The priority for the PopUp menu is not used.
@@ -342,18 +344,18 @@ You can use a priority higher than 9999, to make it go after the Help menu,
but that is non-standard and is discouraged. The highest possible priority is
about 32000. The lowest is 1.
- *sub-menu-priority*
+ *sub-menu-priority*
The same mechanism can be used to position a sub-menu. The priority is then
given as a dot-separated list of priorities, before the menu name: >
- :menu 80.500 Buffer.next :bn<CR>
+ :menu 80.500 Buffer.next :bn<CR>
Giving the sub-menu priority is only needed when the item is not to be put
in a normal position. For example, to put a sub-menu before the other items: >
- :menu 80.100 Buffer.first :brew<CR>
+ :menu 80.100 Buffer.first :brew<CR>
Or to put a sub-menu after the other items, and further items with default
priority will be put before it: >
- :menu 80.900 Buffer.last :blast<CR>
+ :menu 80.900 Buffer.last :blast<CR>
When a number is missing, the default value 500 will be used: >
- :menu .900 myMenu.test :echo "text"<CR>
+ :menu .900 myMenu.test :echo "text"<CR>
The menu priority is only used when creating a new menu. When it already
existed, e.g., in another mode, the priority will not change. Thus, the
priority only needs to be given the first time a menu is used.
@@ -363,49 +365,49 @@ menus can be different. This is different from menu-bar menus, which have
the same order for all modes.
NOTE: sub-menu priorities currently don't work for all versions of the GUI.
- *menu-separator* *E332*
+ *menu-separator* *E332*
Menu items can be separated by a special item that inserts some space between
items. Depending on the system this is displayed as a line or a dotted line.
These items must start with a '-' and end in a '-'. The part in between is
used to give it a unique name. Priorities can be used as with normal items.
Example: >
- :menu Example.item1 :do something
- :menu Example.-Sep- :
- :menu Example.item2 :do something different
+ :menu Example.item1 :do something
+ :menu Example.-Sep- :
+ :menu Example.item2 :do something different
Note that the separator also requires a rhs. It doesn't matter what it is,
because the item will never be selected. Use a single colon to keep it
simple.
- *gui-toolbar*
+ *gui-toolbar*
The default toolbar is setup in menu.vim. The display of the toolbar is
controlled by the 'guioptions' letter 'T'. You can thus have menu & toolbar
together, or either on its own, or neither. The appearance is controlled by
the 'toolbar' option. You can choose between an image, text or both.
- *toolbar-icon*
+ *toolbar-icon*
The toolbar is defined as a special menu called ToolBar, which only has one
level. Vim interprets the items in this menu as follows:
-1) If an "icon=" argument was specified, the file with this name is used.
+- 1 If an "icon=" argument was specified, the file with this name is used.
The file can either be specified with the full path or with the base name.
In the last case it is searched for in the "bitmaps" directory in
'runtimepath', like in point 3. Examples: >
- :amenu icon=/usr/local/pixmaps/foo_icon.xpm ToolBar.Foo :echo "Foo"<CR>
- :amenu icon=FooIcon ToolBar.Foo :echo "Foo"<CR>
+ :amenu icon=/usr/local/pixmaps/foo_icon.xpm ToolBar.Foo :echo "Foo"<CR>
+ :amenu icon=FooIcon ToolBar.Foo :echo "Foo"<CR>
< Note that in the first case the extension is included, while in the second
case it is omitted.
If the file cannot be opened the next points are tried.
A space in the file name must be escaped with a backslash.
A menu priority must come _after_ the icon argument: >
- :amenu icon=foo 1.42 ToolBar.Foo :echo "42!"<CR>
-2) An item called 'BuiltIn##', where ## is a number, is taken as number ## of
+ :amenu icon=foo 1.42 ToolBar.Foo :echo "42!"<CR>
+- 2 An item called 'BuiltIn##', where ## is a number, is taken as number ## of
the built-in bitmaps available in Vim. Currently there are 31 numbered
from 0 to 30 which cover most common editing operations |builtin-tools|. >
- :amenu ToolBar.BuiltIn22 :call SearchNext("back")<CR>
-3) An item with another name is first searched for in the directory
+ :amenu ToolBar.BuiltIn22 :call SearchNext("back")<CR>
+- 3 An item with another name is first searched for in the directory
"bitmaps" in 'runtimepath'. If found, the bitmap file is used as the
toolbar button image. Note that the exact filename is OS-specific: For
example, under Win32 the command >
- :amenu ToolBar.Hello :echo "hello"<CR>
+ :amenu ToolBar.Hello :echo "hello"<CR>
< would find the file 'hello.bmp'. Under X11 it is 'Hello.xpm'.
For MS-Windows and the bitmap is scaled to fit the button. For
MS-Windows a size of 18 by 18 pixels works best.
@@ -413,55 +415,56 @@ level. Vim interprets the items in this menu as follows:
The light grey pixels will be changed to the Window frame color and the
dark grey pixels to the window shadow color. More colors might also work,
depending on your system.
-4) If the bitmap is still not found, Vim checks for a match against its list
+- 4 If the bitmap is still not found, Vim checks for a match against its list
of built-in names. Each built-in button image has a name.
So the command >
- :amenu ToolBar.Open :e
+ :amenu ToolBar.Open :e
< will show the built-in "open a file" button image if no open.bmp exists.
All the built-in names can be seen used in menu.vim.
-5) If all else fails, a blank, but functioning, button is displayed.
-
- *builtin-tools*
-nr Name Normal action ~
-00 New open new window
-01 Open browse for file to open in current window
-02 Save write buffer to file
-03 Undo undo last change
-04 Redo redo last undone change
-05 Cut delete selected text to clipboard
-06 Copy copy selected text to clipboard
-07 Paste paste text from clipboard
-08 Print print current buffer
-09 Help open a buffer on Vim's builtin help
-10 Find start a search command
-11 SaveAll write all modified buffers to file
-12 SaveSesn write session file for current situation
-13 NewSesn write new session file
-14 LoadSesn load session file
-15 RunScript browse for file to run as a Vim script
-16 Replace prompt for substitute command
-17 WinClose close current window
-18 WinMax make current window use many lines
-19 WinMin make current window use few lines
-20 WinSplit split current window
-21 Shell start a shell
-22 FindPrev search again, backward
-23 FindNext search again, forward
-24 FindHelp prompt for word to search help for
-25 Make run make and jump to first error
-26 TagJump jump to tag under the cursor
-27 RunCtags build tags for files in current directory
-28 WinVSplit split current window vertically
-29 WinMaxWidth make current window use many columns
-30 WinMinWidth make current window use few columns
-
- *hidden-menus* *win32-hidden-menus*
+- 5 If all else fails, a blank, but functioning, button is displayed.
+
+ *builtin-tools*
+>
+ nr Name Normal action
+ 00 New open new window
+ 01 Open browse for file to open in current window
+ 02 Save write buffer to file
+ 03 Undo undo last change
+ 04 Redo redo last undone change
+ 05 Cut delete selected text to clipboard
+ 06 Copy copy selected text to clipboard
+ 07 Paste paste text from clipboard
+ 08 Print print current buffer
+ 09 Help open a buffer on Vim's builtin help
+ 10 Find start a search command
+ 11 SaveAll write all modified buffers to file
+ 12 SaveSesn write session file for current situation
+ 13 NewSesn write new session file
+ 14 LoadSesn load session file
+ 15 RunScript browse for file to run as a Vim script
+ 16 Replace prompt for substitute command
+ 17 WinClose close current window
+ 18 WinMax make current window use many lines
+ 19 WinMin make current window use few lines
+ 20 WinSplit split current window
+ 21 Shell start a shell
+ 22 FindPrev search again, backward
+ 23 FindNext search again, forward
+ 24 FindHelp prompt for word to search help for
+ 25 Make run make and jump to first error
+ 26 TagJump jump to tag under the cursor
+ 27 RunCtags build tags for files in current directory
+ 28 WinVSplit split current window vertically
+ 29 WinMaxWidth make current window use many columns
+ 30 WinMinWidth make current window use few columns
+<
+ *hidden-menus* *win32-hidden-menus*
In the Win32 GUI, starting a menu name with ']' excludes that menu from the
main menu bar. You must then use the |:popup| command to display it.
When splitting the window the window toolbar is not copied to the new window.
- *popup-menu*
+ *popup-menu*
You can define the special menu "PopUp". This is the menu that is displayed
when the right mouse button is pressed, if 'mousemodel' is set to popup or
popup_setpos.
@@ -483,7 +486,7 @@ The default "PopUp" menu is: >vim
anoremenu PopUp.How-to\ disable\ mouse <Cmd>help disable-mouse<CR>
<
-Showing What Menus Are Mapped To *showing-menus*
+Showing What Menus Are Mapped To *showing-menus*
To see what an existing menu is mapped to, use just one argument after the
menu commands (just like you would with the ":map" commands). If the menu
@@ -502,25 +505,25 @@ Note that hitting <Tab> while entering a menu name after a menu command may
be used to complete the name of the menu item.
-Executing Menus *execute-menus*
+Executing Menus *execute-menus*
- *:em* *:emenu* *E334* *E335*
-:[range]em[enu] {menu} Execute {menu} from the command line.
- The default is to execute the Normal mode
- menu. If a range is specified, it executes
- the Visual mode menu.
- If used from <c-o>, it executes the
- insert-mode menu Eg: >
- :emenu File.Exit
+ *:em* *:emenu* *E334* *E335*
+:[range]em[enu] {menu} Execute {menu} from the command line.
+ The default is to execute the Normal mode
+ menu. If a range is specified, it executes
+ the Visual mode menu.
+ If used from <c-o>, it executes the
+ insert-mode menu Eg: >
+ :emenu File.Exit
-:[range]em[enu] {mode} {menu} Like above, but execute the menu for {mode}:
- 'n': |:nmenu| Normal mode
- 'v': |:vmenu| Visual mode
- 's': |:smenu| Select mode
- 'o': |:omenu| Operator-pending mode
- 't': |:tlmenu| Terminal mode
- 'i': |:imenu| Insert mode
- 'c': |:cmenu| Cmdline mode
+:[range]em[enu] {mode} {menu} Like above, but execute the menu for {mode}:
+ - 'n': |:nmenu| Normal mode
+ - 'v': |:vmenu| Visual mode
+ - 's': |:smenu| Select mode
+ - 'o': |:omenu| Operator-pending mode
+ - 't': |:tlmenu| Terminal mode
+ - 'i': |:imenu| Insert mode
+ - 'c': |:cmenu| Cmdline mode
You can use :emenu to access useful menu items you may have got used to from
@@ -531,10 +534,10 @@ When using a range, if the lines match with '<,'>, then the menu is executed
using the last visual selection.
-Deleting Menus *delete-menus*
+Deleting Menus *delete-menus*
- *:unme* *:unmenu*
- *:aun* *:aunmenu*
+ *:unme* *:unmenu*
+ *:aun* *:aunmenu*
To delete a menu item or a whole submenu, use the unmenu commands, which are
analogous to the unmap commands. Eg: >
:unmenu! Edit.Paste
@@ -545,26 +548,26 @@ Command-line modes.
Note that hitting <Tab> while entering a menu name after an umenu command
may be used to complete the name of the menu item for the appropriate mode.
-To remove all menus use: *:unmenu-all* >
- :unmenu * " remove all menus in Normal and visual mode
- :unmenu! * " remove all menus in Insert and Command-line mode
- :aunmenu * " remove all menus in all modes, except for Terminal
- " mode
- :tlunmenu * " remove all menus in Terminal mode
+To remove all menus use: *:unmenu-all* >
+ :unmenu * " remove all menus in Normal and visual mode
+ :unmenu! * " remove all menus in Insert and Command-line mode
+ :aunmenu * " remove all menus in all modes, except for Terminal
+ " mode
+ :tlunmenu * " remove all menus in Terminal mode
If you want to get rid of the menu bar: >
- :set guioptions-=m
+ :set guioptions-=m
-Disabling Menus *disable-menus*
+Disabling Menus *disable-menus*
- *:menu-disable* *:menu-enable*
+ *:menu-disable* *:menu-enable*
If you do not want to remove a menu, but disable it for a moment, this can be
done by adding the "enable" or "disable" keyword to a ":menu" command.
Examples: >
- :menu disable &File.&Open\.\.\.
- :amenu enable *
- :amenu disable &Tools.*
+ :menu disable &File.&Open\.\.\.
+ :amenu enable *
+ :amenu disable &Tools.*
The command applies to the modes as used with all menu commands. Note that
characters like "&" need to be included for translated names to be found.
@@ -572,36 +575,36 @@ When the argument is "*", all menus are affected. Otherwise the given menu
name and all existing submenus below it are affected.
-Examples for Menus *menu-examples*
+Examples for Menus *menu-examples*
Here is an example on how to add menu items with menus! You can add a menu
item for the keyword under the cursor. The register "z" is used. >
- :nmenu Words.Add\ Var wb"zye:menu! Words.<C-R>z <C-R>z<CR>
- :nmenu Words.Remove\ Var wb"zye:unmenu! Words.<C-R>z<CR>
- :vmenu Words.Add\ Var "zy:menu! Words.<C-R>z <C-R>z <CR>
- :vmenu Words.Remove\ Var "zy:unmenu! Words.<C-R>z<CR>
- :imenu Words.Add\ Var <Esc>wb"zye:menu! Words.<C-R>z <C-R>z<CR>a
- :imenu Words.Remove\ Var <Esc>wb"zye:unmenu! Words.<C-R>z<CR>a
+ :nmenu Words.Add\ Var wb"zye:menu! Words.<C-R>z <C-R>z<CR>
+ :nmenu Words.Remove\ Var wb"zye:unmenu! Words.<C-R>z<CR>
+ :vmenu Words.Add\ Var "zy:menu! Words.<C-R>z <C-R>z <CR>
+ :vmenu Words.Remove\ Var "zy:unmenu! Words.<C-R>z<CR>
+ :imenu Words.Add\ Var <Esc>wb"zye:menu! Words.<C-R>z <C-R>z<CR>a
+ :imenu Words.Remove\ Var <Esc>wb"zye:unmenu! Words.<C-R>z<CR>a
(the rhs is in <> notation, you can copy/paste this text to try out the
mappings, or put these lines in your gvimrc; "<C-R>" is CTRL-R, "<CR>" is
the <CR> key. |<>|)
- *tooltips* *menu-tips*
+ *tooltips* *menu-tips*
Tooltips & Menu tips
See section |42.4| in the user manual.
- *:tmenu*
-:tm[enu] {menupath} {rhs} Define a tip for a menu or tool. (only in
- X11 and Win32 GUI)
+ *:tmenu*
+:tm[enu] {menupath} {rhs} Define a tip for a menu or tool. (only in
+ X11 and Win32 GUI)
-:tm[enu] [menupath] List menu tips. (only in X11 and Win32 GUI)
+:tm[enu] [menupath] List menu tips. (only in X11 and Win32 GUI)
- *:tunmenu*
-:tu[nmenu] {menupath} Remove a tip for a menu or tool.
- (only in X11 and Win32 GUI)
+ *:tunmenu*
+:tu[nmenu] {menupath} Remove a tip for a menu or tool.
+ (only in X11 and Win32 GUI)
Note: To create menus for terminal mode, use |:tlmenu| instead.
@@ -615,11 +618,11 @@ highlight group to change its colors.
A "tip" can be defined for each menu item. For example, when defining a menu
item like this: >
- :amenu MyMenu.Hello :echo "Hello"<CR>
+ :amenu MyMenu.Hello :echo "Hello"<CR>
The tip is defined like this: >
- :tmenu MyMenu.Hello Displays a greeting.
+ :tmenu MyMenu.Hello Displays a greeting.
And delete it with: >
- :tunmenu MyMenu.Hello
+ :tunmenu MyMenu.Hello
Tooltips are currently only supported for the X11 and Win32 GUI. However, they
should appear for the other gui platforms in the not too distant future.
@@ -638,24 +641,24 @@ a menu item - you don't need to do a :tunmenu as well.
You can cause a menu to popup at the cursor. This behaves similarly to the
PopUp menus except that any menu tree can be popped up.
- *:popup* *:popu*
-:popu[p] {name} Popup the menu {name}. The menu named must
- have at least one subentry, but need not
- appear on the menu-bar (see |hidden-menus|).
+ *:popup* *:popu*
+:popu[p] {name} Popup the menu {name}. The menu named must
+ have at least one subentry, but need not
+ appear on the menu-bar (see |hidden-menus|).
-:popu[p]! {name} Like above, but use the position of the mouse
- pointer instead of the cursor.
+:popu[p]! {name} Like above, but use the position of the mouse
+ pointer instead of the cursor.
Example: >
- :popup File
+ :popup File
will make the "File" menu (if there is one) appear at the text cursor (mouse
pointer if ! was used). >
- :amenu ]Toolbar.Make :make<CR>
- :popup ]Toolbar
+ :amenu ]Toolbar.Make :make<CR>
+ :popup ]Toolbar
This creates a popup menu that doesn't exist on the main menu-bar.
Note that a menu that starts with ']' will not be displayed.
- vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
+ vim:tw=78:sw=4:ts=8:et:ft=help:norl:
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index fd8bfd644f..914dc64c0a 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -150,6 +150,7 @@ LANGUAGE SUPPORT
|arabic.txt| Arabic language support and editing
|hebrew.txt| Hebrew language support and editing
|russian.txt| Russian language support and editing
+|vietnamese.txt| Vietnamese language support and editing
------------------------------------------------------------------------------
INTEROP
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 9ee75ea950..d81d59c56f 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -1569,6 +1569,8 @@ tag command action ~
|:sign| :sig[n] manipulate signs
|:silent| :sil[ent] run a command silently
|:sleep| :sl[eep] do nothing for a few seconds
+|:sleep!| :sl[eep]! do nothing for a few seconds, without the
+ cursor visible
|:slast| :sla[st] split window and go to last file in the
argument list
|:smagic| :sm[agic] :substitute with 'magic'
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index d099c29bdb..ac019a4f25 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -1,15 +1,15 @@
*intro.txt* Nvim
- NVIM REFERENCE MANUAL
+ NVIM REFERENCE MANUAL
-Nvim *ref* *reference*
+Nvim *ref* *reference*
Type |gO| to see the table of contents.
==============================================================================
-Introduction *intro*
+Introduction *intro*
Vim is a text editor which includes most commands from the Unix program "Vi"
and many new ones.
@@ -21,52 +21,67 @@ It can be accessed from within Vim with the <Help> or <F1> key and with the
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*
+ *pronounce*
Vim is pronounced as one word, like Jim. So Nvim is "En-Vim", two syllables.
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:
-
- "Practical Vim" by Drew Neil
- "Modern Vim" by Drew Neil
- https://vimcasts.org/publications/
-
-"Practical Vim" is acclaimed for its focus on quickly learning common editing
-tasks with Vim. "Modern Vim" explores new features in Nvim and Vim 8.
-
- "Vim - Vi Improved" by Steve Oualline
-
-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
- https://www.vim.org/iccf/click5.html
-
-==============================================================================
-Nvim on the interwebs *internet*
-
- *www* *distribution* *download*
-
- Nvim home page: https://neovim.io/
- Downloads: https://github.com/neovim/neovim/releases
- Vim FAQ: https://vimhelp.org/vim_faq.txt.html
-
-
- *bugs* *bug-report*
-Report bugs and request features here:
-https://github.com/neovim/neovim/issues
-
+introduction; instead for beginners, there is a hands-on |tutor|, |lua-guide|,
+and |user-manual|.
+
+------------------------------------------------------------------------------
+Resources *resources*
+
+ *internet* *www* *distribution*
+- Nvim home page: https://neovim.io/
+- Vim FAQ: https://vimhelp.org/vim_faq.txt.html
+
+ *book*
+There are many resources to learn Vi, Vim, and Nvim. We recommend:
+
+- "Practical Vim" by Drew Neil. Acclaimed for its focus on quickly learning
+ common editing tasks with Vim.
+- "Modern Vim" by Drew Neil. Explores new features in Nvim and Vim 8.
+- https://vimcasts.org/publications/
+- "Vim - Vi Improved" by Steve Oualline. This was the first book dedicated to
+ Vim. Parts of it were included in the Vim user manual. |frombook| ISBN:
+ 0735710015
+- For more information try one of these:
+ - https://iccf-holland.org/click5.html
+ - https://www.vim.org/iccf/click5.html
+
+ *bugs* *bug-report* *feature-request*
+Report bugs and request features here: https://github.com/neovim/neovim/issues
Be brief, yet complete. Always give a reproducible example and try to find
-out which settings or other things trigger the bug.
+out which settings or other things trigger the bug. If Nvim crashed, try to
+get a backtrace (see |dev-tools-backtrace|).
-If Nvim crashes, try to get a backtrace. See |debug.txt|.
+==============================================================================
+Installing Nvim *install*
+
+ *download* *upgrade* *ubuntu*
+To install or upgrade Nvim, you can...
+- Download a pre-built archive:
+ https://github.com/neovim/neovim/releases
+- Use your system package manager:
+ https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-package
+- Build from source:
+ https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-source
+
+ *uninstall*
+To uninstall Nvim:
+- If you downloaded a pre-built archive or built Nvim from source (e.g. `make
+ install`), just delete its files, typically located in: >
+ /usr/local/bin/nvim
+ /usr/local/share/nvim
+<
+- If you installed via package manager, read your package manager's
+ documentation. Common examples:
+ - APT (Debian, Ubuntu, …): `apt-get remove neovim`
+ - Homebrew (macOS): `brew install neovim`
+ - Scoop (Windows): `scoop install neovim`
==============================================================================
-Sponsor Vim/Nvim development *sponsor* *register*
+Sponsor Vim/Nvim development *sponsor* *register*
Fixing bugs and adding new features takes a lot of time and effort. To show
your appreciation for the work and motivate developers to continue working on
@@ -78,121 +93,15 @@ motivation to keep working on Vim!
For the most recent information about sponsoring look on the Vim web site:
- https://www.vim.org/sponsor/
+ https://www.vim.org/sponsor/
Nvim development is funded separately from Vim:
- https://neovim.io/#sponsor
-
-==============================================================================
-Credits *credits*
-
-Most of Vim was written by Bram Moolenaar <Bram@vim.org> |Bram-Moolenaar|.
-
-Parts of the documentation come from several Vi manuals, written by:
- W.N. Joy
- Alan P.W. Hewett
- Mark Horton
-
-The Vim editor is based on Stevie and includes (ideas from) other software,
-worked on by the people mentioned here. Other people helped by sending me
-patches, suggestions and giving feedback about what is good and bad in Vim.
-
-Vim would never have become what it is now, without the help of these people!
-
- Ron Aaron Win32 GUI changes
- Mohsin Ahmed encryption
- Zoltan Arpadffy work on VMS port
- Tony Andrews Stevie
- Gert van Antwerpen changes for DJGPP on MS-DOS
- Berkeley DB(3) ideas for swap file implementation
- Keith Bostic Nvi
- Walter Briscoe Makefile updates, various patches
- Ralf Brown SPAWNO library for MS-DOS
- Robert Colon many useful remarks
- Marcin Dalecki GTK+ GUI port, toolbar icons, gettext()
- Kayhan Demirel sent me news in Uganda
- Chris & John Downey xvi (ideas for multi-windows version)
- Henk Elbers first VMS port
- Daniel Elstner GTK+ 2 port
- Eric Fischer Mac port, 'cindent', and other improvements
- Benji Fisher Answering lots of user questions
- Bill Foster Athena GUI port (later removed)
- Google Let Bram work on Vim one day a week
- Loic Grenie xvim (ideas for multi windows version)
- Sven Guckes Vim promoter and previous WWW page maintainer
- Darren Hiebert Exuberant ctags
- Jason Hildebrand GTK+ 2 port
- Bruce Hunsaker improvements for VMS port
- Andy Kahn Cscope support, GTK+ GUI port
- Oezguer Kesim Maintainer of Vim Mailing Lists
- Axel Kielhorn work on the Macintosh port
- Steve Kirkendall Elvis
- Roger Knobbe original port to Windows NT
- Sergey Laskavy Vim's help from Moscow
- Felix von Leitner Previous maintainer of Vim Mailing Lists
- David Leonard Port of Python extensions to Unix
- Avner Lottem Edit in right-to-left windows
- Flemming Madsen X11 client-server, various features and patches
- Tony Mechelynck answers many user questions
- Paul Moore Python interface extensions, many patches
- Katsuhito Nagano Work on multibyte versions
- Sung-Hyun Nam Work on multibyte versions
- Vince Negri Win32 GUI and generic console enhancements
- Steve Oualline Author of the first Vim book |frombook|
- Dominique Pelle Valgrind reports and many fixes
- A.Politz Many bug reports and some fixes
- George V. Reilly Win32 port, Win32 GUI start-off
- Stephen Riehm bug collector
- Stefan Roemer various patches and help to users
- Ralf Schandl IBM OS/390 port
- Olaf Seibert DICE and BeBox version, regexp improvements
- Mortaza Shiran Farsi patches
- Peter da Silva termlib
- Paul Slootman OS/2 port
- Henry Spencer regular expressions
- Dany St-Amant Macintosh port
- Tim Thompson Stevie
- G. R. (Fred) Walter Stevie
- Sven Verdoolaege Perl interface
- Robert Webb Command-line completion, GUI versions, and
- lots of patches
- Ingo Wilken Tcl interface
- Mike Williams PostScript printing
- Juergen Weigert Lattice version, AUX improvements, Unix and
- MS-DOS ports, autoconf
- Stefan 'Sec' Zehl Maintainer of vim.org
- Yasuhiro Matsumoto many MS-Windows improvements
- Ken Takata fixes and features
- Kazunobu Kuriyama GTK 3
- Christian Brabandt many fixes, features, user support, etc.
- Yegappan Lakshmanan many quickfix features
-
-I wish to thank all the people that sent me bug reports and suggestions. The
-list is too long to mention them all here. Vim would not be the same without
-the ideas from all these people: They keep Vim alive!
-*love* *peace* *friendship* *gross-national-happiness*
-
-
-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". 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)". Source code is freely available.
- *Elvis*
-Elvis Another Vi clone, made by Steve Kirkendall. Very compact but isn't
- as flexible as Vim. Source code is freely available.
-
-Vim Nvim is based on Vim. https://www.vim.org/
+ https://neovim.io/#sponsor
==============================================================================
-Bram Moolenaar *Bram* *Moolenaar* *Bram-Moolenaar* *brammool*
+Bram Moolenaar *Bram* *Moolenaar* *Bram-Moolenaar* *brammool*
Nvim is a fork of the Vim ("Vi IMproved") text editor, which was originally
developed by Bram Moolenaar. Searching his name within the source code of
@@ -201,11 +110,11 @@ On August 3, 2023, he passed away at the age of 62. If Vim or Nvim have been
of use to you in your life, please read |Uganda| and consider honoring his
memory however you may see fit.
-Obituary Articles: https://github.com/vim/vim/discussions/12742
-Say Farewell: https://github.com/vim/vim/discussions/12737
+- Obituary Articles: https://github.com/vim/vim/discussions/12742
+- Say Farewell: https://github.com/vim/vim/discussions/12737
==============================================================================
-Notation *notation*
+Notation *notation*
When syntax highlighting is used to read this, text that is not typed
literally is often highlighted with the Special group. These are items in [],
@@ -215,177 +124,177 @@ Note that Vim uses all possible characters in commands. Sometimes the [], {}
and <> are part of what you type, the context should make this clear.
-[] Characters in square brackets are optional.
-
- *count* *[count]*
-[count] An optional number that may precede the command to multiply
- or iterate the command. If no number is given, a count of one
- is used, unless otherwise noted. Note that in this manual the
- [count] is not mentioned in the description of the command,
- but only in the explanation. This was done to make the
- commands easier to look up. If the 'showcmd' option is on,
- the (partially) entered count is shown at the bottom of the
- window. You can use <Del> to erase the last digit (|N<Del>|).
-
- *[quotex]*
-["x] An optional register designation where text can be stored.
- See |registers|. The x is a single character between 'a' and
- 'z' or 'A' and 'Z' or '"', and in some cases (with the put
- command) between '0' and '9', '%', '#', or others. The
- uppercase and lowercase letter designate the same register,
- but the lowercase letter is used to overwrite the previous
- register contents, while the uppercase letter is used to
- append to the previous register contents. Without the ""x" or
- with """" the stored text is put into the unnamed register.
-
- *{}*
-{} Curly braces denote parts of the command which must appear,
- but which can take a number of different values. The
- differences between Vim and Vi are also given in curly braces
- (this will be clear from the context).
-
- *{char1-char2}*
-{char1-char2} A single character from the range char1 to char2. For
- example: {a-z} is a lowercase letter. Multiple ranges may be
- concatenated. For example, {a-zA-Z0-9} is any alphanumeric
- character.
-
- *{motion}* *movement*
-{motion} A command that moves the cursor. These are explained in
- |motion.txt|. Examples:
- w to start of next word
- b to begin of current word
- 4j four lines down
- /The<CR> to next occurrence of "The"
- This is used after an |operator| command to move over the text
- that is to be operated upon.
- - If the motion includes a count and the operator also has a
- count, the two counts are multiplied. For example: "2d3w"
- deletes six words.
- - The motion can be backwards, e.g. "db" to delete to the
- start of the word.
- - The motion can also be a mouse click. The mouse is not
- supported in every terminal though.
- - The ":omap" command can be used to map characters while an
- operator is pending.
- - Ex commands can be used to move the cursor. This can be
- used to call a function that does some complicated motion.
- The motion is always charwise exclusive, no matter
- what ":" command is used. This means it's impossible to
- include the last character of a line without the line break
- (unless 'virtualedit' is set).
- If the Ex command changes the text before where the operator
- starts or jumps to another buffer the result is
- unpredictable. It is possible to change the text further
- down. Jumping to another buffer is possible if the current
- buffer is not unloaded.
-
- *{Visual}*
-{Visual} A selected text area. It is started with the "v", "V", or
- CTRL-V command, then any cursor movement command can be used
- to change the end of the selected text.
- This is used before an |operator| command to highlight the
- text that is to be operated upon.
- See |Visual-mode|.
-
- *<character>*
-<character> A special character from the table below, optionally with
- modifiers, or a single ASCII character with modifiers.
-
- *'character'*
-'c' A single ASCII character.
-
- *CTRL-{char}*
-CTRL-{char} {char} typed as a control character; that is, typing {char}
- while holding the CTRL key down. The case of {char} is
- ignored; thus CTRL-A and CTRL-a are equivalent. But in
- some terminals and environments, using the SHIFT key will
- produce a distinct code (e.g. CTRL-SHIFT-a); in these
- environments using the SHIFT key will not trigger commands
- such as CTRL-A.
-
- *'option'*
-'option' An option, or parameter, that can be set to a value, is
- enclosed in single quotes. See |options|.
-
- *quotecommandquote*
-"command" A reference to a command that you can type is enclosed in
- double quotes.
-`command` New style command, this distinguishes it from other quoted
- text and strings.
-
- *key-notation* *key-codes* *keycodes*
+- [] Characters in square brackets are optional.
+
+ *count* *[count]*
+- [count] An optional number that may precede the command to multiply
+ or iterate the command. If no number is given, a count of one
+ is used, unless otherwise noted. Note that in this manual the
+ [count] is not mentioned in the description of the command,
+ but only in the explanation. This was done to make the
+ commands easier to look up. If the 'showcmd' option is on,
+ the (partially) entered count is shown at the bottom of the
+ window. You can use <Del> to erase the last digit (|N<Del>|).
+
+ *[quotex]*
+- ["x] An optional register designation where text can be stored.
+ See |registers|. The x is a single character between 'a' and
+ 'z' or 'A' and 'Z' or '"', and in some cases (with the put
+ command) between '0' and '9', '%', '#', or others. The
+ uppercase and lowercase letter designate the same register,
+ but the lowercase letter is used to overwrite the previous
+ register contents, while the uppercase letter is used to
+ append to the previous register contents. Without the ""x" or
+ with """" the stored text is put into the unnamed register.
+
+ *{}*
+- {} Curly braces denote parts of the command which must appear,
+ but which can take a number of different values. The
+ differences between Vim and Vi are also given in curly braces
+ (this will be clear from the context).
+
+ *{char1-char2}*
+- {char1-char2} A single character from the range char1 to char2. For
+ example: {a-z} is a lowercase letter. Multiple ranges may be
+ concatenated. For example, {a-zA-Z0-9} is any alphanumeric
+ character.
+
+ *{motion}* *movement*
+- {motion} A command that moves the cursor. These are explained in
+ |motion.txt|.
+ - Examples:
+ - `w` to start of next word
+ - `b` to begin of current word
+ - `4j` four lines down
+ - `/The<CR>` to next occurrence of "The"
+ - This is used after an |operator| command to move over the
+ text that is to be operated upon.
+ - If the motion includes a count and the operator also has
+ a count, the two counts are multiplied. For example:
+ "2d3w" deletes six words.
+ - The motion can be backwards, e.g. "db" to delete to the
+ start of the word.
+ - The motion can also be a mouse click. The mouse is not
+ supported in every terminal though.
+ - The ":omap" command can be used to map characters while an
+ operator is pending.
+ - Ex commands can be used to move the cursor. This can be
+ used to call a function that does some complicated motion.
+ The motion is always charwise exclusive, no matter what
+ ":" command is used. This means it's impossible to
+ include the last character of a line without the line
+ break (unless 'virtualedit' is set). If the Ex command
+ changes the text before where the operator starts or jumps
+ to another buffer the result is unpredictable. It is
+ possible to change the text further down. Jumping to
+ another buffer is possible if the current buffer is not
+ unloaded.
+
+ *{Visual}*
+- {Visual} A selected text area. It is started with the "v", "V", or
+ CTRL-V command, then any cursor movement command can be used
+ to change the end of the selected text.
+ This is used before an |operator| command to highlight the
+ text that is to be operated upon.
+ See |Visual-mode|.
+
+ *<character>*
+- <character> A special character from the table below, optionally with
+ modifiers, or a single ASCII character with modifiers.
+
+ *'character'*
+- 'c' A single ASCII character.
+
+ *CTRL-{char}*
+- CTRL-{char} {char} typed as a control character; that is, typing {char}
+ while holding the CTRL key down. The case of {char} is
+ ignored; thus CTRL-A and CTRL-a are equivalent. But in
+ some terminals and environments, using the SHIFT key will
+ produce a distinct code (e.g. CTRL-SHIFT-a); in these
+ environments using the SHIFT key will not trigger commands
+ such as CTRL-A.
+
+ *'option'*
+- 'option' An option, or parameter, that can be set to a value, is
+ enclosed in single quotes. See |options|.
+
+ *quotecommandquote*
+- "command" A reference to a command that you can type is enclosed in
+ double quotes.
+- `command` New style command, this distinguishes it from other quoted
+ text and strings.
+
+ *key-notation* *key-codes* *keycodes*
These names for keys are used in the documentation. They can also be used
with the ":map" command.
-notation meaning equivalent decimal value(s) ~
------------------------------------------------------------------------ ~
-<Nul> zero CTRL-@ 0 (stored as 10) *<Nul>*
-<BS> backspace CTRL-H 8 *backspace*
-<Tab> tab CTRL-I 9 *tab* *Tab*
- *linefeed*
-<NL> linefeed CTRL-J 10 (used for <Nul>)
-<CR> carriage return CTRL-M 13 *carriage-return*
-<Return> same as <CR> *<Return>*
-<Enter> same as <CR> *<Enter>*
-<Esc> escape CTRL-[ 27 *escape* *<Esc>*
-<Space> space 32 *space*
-<lt> less-than < 60 *<lt>*
-<Bslash> backslash \ 92 *backslash* *<Bslash>*
-<Bar> vertical bar | 124 *<Bar>*
-<Del> delete 127
-<CSI> command sequence intro ALT-Esc 155 *<CSI>*
-
-<EOL> end-of-line (can be <CR>, <NL> or <CR><NL>,
- depends on system and 'fileformat') *<EOL>*
-<Ignore> cancel wait-for-character *<Ignore>*
-<NOP> no-op: do nothing (useful in mappings) *<Nop>*
-
-<Up> cursor-up *cursor-up* *cursor_up*
-<Down> cursor-down *cursor-down* *cursor_down*
-<Left> cursor-left *cursor-left* *cursor_left*
-<Right> cursor-right *cursor-right* *cursor_right*
-<S-Up> shift-cursor-up
-<S-Down> shift-cursor-down
-<S-Left> shift-cursor-left
-<S-Right> shift-cursor-right
-<C-Left> control-cursor-left
-<C-Right> control-cursor-right
-<F1> - <F12> function keys 1 to 12 *function_key* *function-key*
-<S-F1> - <S-F12> shift-function keys 1 to 12 *<S-F1>*
-<Help> help key
-<Undo> undo key
-<Insert> insert key
-<Home> home *home*
-<End> end *end*
-<PageUp> page-up *page_up* *page-up*
-<PageDown> page-down *page_down* *page-down*
-<kUp> keypad cursor-up *keypad-cursor-up*
-<kDown> keypad cursor-down *keypad-cursor-down*
-<kLeft> keypad cursor-left *keypad-cursor-left*
-<kRight> keypad cursor-right *keypad-cursor-right*
-<kHome> keypad home (upper left) *keypad-home*
-<kEnd> keypad end (lower left) *keypad-end*
-<kOrigin> keypad origin (middle) *keypad-origin*
-<kPageUp> keypad page-up (upper right) *keypad-page-up*
-<kPageDown> keypad page-down (lower right) *keypad-page-down*
-<kDel> keypad delete *keypad-delete*
-<kPlus> keypad + *keypad-plus*
-<kMinus> keypad - *keypad-minus*
-<kMultiply> keypad * *keypad-multiply*
-<kDivide> keypad / *keypad-divide*
-<kPoint> keypad . *keypad-point*
-<kComma> keypad , *keypad-comma*
-<kEqual> keypad = *keypad-equal*
-<kEnter> keypad Enter *keypad-enter*
-<k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*
-<S-…> shift-key *shift* *<S-*
-<C-…> control-key *control* *ctrl* *<C-*
-<M-…> alt-key or meta-key *META* *ALT* *<M-*
-<A-…> same as <M-…> *<A-*
-<T-…> meta-key when it's not alt *<T-*
-<D-…> command-key or "super" key *<D-*
------------------------------------------------------------------------ ~
+notation meaning equivalent decimal value(s) ~
+<Nul> zero CTRL-@ 0 (stored as 10) *<Nul>*
+<BS> backspace CTRL-H 8 *backspace*
+<Tab> tab CTRL-I 9 *tab* *Tab*
+ *linefeed*
+<NL> linefeed CTRL-J 10 (used for <Nul>)
+<CR> carriage return CTRL-M 13 *carriage-return*
+<Return> same as <CR> *<Return>*
+<Enter> same as <CR> *<Enter>*
+<Esc> escape CTRL-[ 27 *escape* *<Esc>*
+<Space> space 32 *space*
+<lt> less-than < 60 *<lt>*
+<Bslash> backslash \ 92 *backslash* *<Bslash>*
+<Bar> vertical bar | 124 *<Bar>*
+<Del> delete 127
+<CSI> command sequence intro ALT-Esc 155 *<CSI>*
+
+<EOL> end-of-line (can be <CR>, <NL> or <CR><NL>,
+ depends on system and 'fileformat') *<EOL>*
+<Ignore> cancel wait-for-character *<Ignore>*
+<NOP> no-op: do nothing (useful in mappings) *<Nop>*
+
+<Up> cursor-up *cursor-up* *cursor_up*
+<Down> cursor-down *cursor-down* *cursor_down*
+<Left> cursor-left *cursor-left* *cursor_left*
+<Right> cursor-right *cursor-right* *cursor_right*
+<S-Up> shift-cursor-up
+<S-Down> shift-cursor-down
+<S-Left> shift-cursor-left
+<S-Right> shift-cursor-right
+<C-Left> control-cursor-left
+<C-Right> control-cursor-right
+<F1> - <F12> function keys 1 to 12 *function_key* *function-key*
+<S-F1> - <S-F12> shift-function keys 1 to 12 *<S-F1>*
+<Help> help key
+<Undo> undo key
+<Insert> insert key
+<Home> home *home*
+<End> end *end*
+<PageUp> page-up *page_up* *page-up*
+<PageDown> page-down *page_down* *page-down*
+<kUp> keypad cursor-up *keypad-cursor-up*
+<kDown> keypad cursor-down *keypad-cursor-down*
+<kLeft> keypad cursor-left *keypad-cursor-left*
+<kRight> keypad cursor-right *keypad-cursor-right*
+<kHome> keypad home (upper left) *keypad-home*
+<kEnd> keypad end (lower left) *keypad-end*
+<kOrigin> keypad origin (middle) *keypad-origin*
+<kPageUp> keypad page-up (upper right) *keypad-page-up*
+<kPageDown> keypad page-down (lower right) *keypad-page-down*
+<kDel> keypad delete *keypad-delete*
+<kPlus> keypad + *keypad-plus*
+<kMinus> keypad - *keypad-minus*
+<kMultiply> keypad * *keypad-multiply*
+<kDivide> keypad / *keypad-divide*
+<kPoint> keypad . *keypad-point*
+<kComma> keypad , *keypad-comma*
+<kEqual> keypad = *keypad-equal*
+<kEnter> keypad Enter *keypad-enter*
+<k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*
+<S-…> shift-key *shift* *<S-*
+<C-…> control-key *control* *ctrl* *<C-*
+<M-…> alt-key or meta-key *META* *ALT* *<M-*
+<A-…> same as <M-…> *<A-*
+<T-…> meta-key when it's not alt *<T-*
+<D-…> command-key or "super" key *<D-*
+
Note:
@@ -400,125 +309,125 @@ Note:
- It is possible to notate combined modifiers (e.g. <M-C-T> for CTRL-ALT-T),
but your terminal must encode the input for that to work. |tui-input|
- *<>*
+ *<>*
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. 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
- <C-LeftMouse> Control- left mouse click
- <S-F11> Shifted function key 11
- <M-a> Meta- a ('a' with bit 8 set)
- <M-A> Meta- A ('A' with bit 8 set)
+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
+ - <C-LeftMouse> Control- left mouse click
+ - <S-F11> Shifted function key 11
+ - <M-a> Meta- a ('a' with bit 8 set)
+ - <M-A> Meta- A ('A' with bit 8 set)
The <> notation uses <lt> to escape the special meaning of key names. Using a
backslash also works, but only when 'cpoptions' does not include the 'B' flag.
Examples for mapping CTRL-H to the six characters "<Home>": >vim
- :imap <C-H> \<Home>
- :imap <C-H> <lt>Home>
+ :imap <C-H> \<Home>
+ :imap <C-H> <lt>Home>
The first one only works when the 'B' flag is not in 'cpoptions'. The second
one always works.
To get a literal "<lt>" in a mapping: >vim
- :map <C-L> <lt>lt>
+ :map <C-L> <lt>lt>
The notation can be used in a double quoted strings, using "\<" at the start,
e.g. "\<C-Space>". This results in a special key code. To convert this back
to readable text use `keytrans()`.
==============================================================================
-Modes, introduction *vim-modes-intro* *vim-modes*
+Modes, introduction *vim-modes-intro* *vim-modes*
Vim has seven BASIC modes:
- *Normal* *Normal-mode* *command-mode*
-Normal mode In Normal mode you can enter all the normal editor
- commands. If you start the editor you are in this
- mode. This is also known as command mode.
-
-Visual mode This is like Normal mode, but the movement commands
- extend a highlighted area. When a non-movement
- command is used, it is executed for the highlighted
- area. See |Visual-mode|.
- If the 'showmode' option is on "-- VISUAL --" is shown
- at the bottom of the window.
-
-Select mode This looks most like the MS-Windows selection mode.
- Typing a printable character deletes the selection
- and starts Insert mode. See |Select-mode|.
- If the 'showmode' option is on "-- SELECT --" is shown
- at the bottom of the window.
-
-Insert mode In Insert mode the text you type is inserted into the
- buffer. See |Insert-mode|.
- If the 'showmode' option is on "-- INSERT --" is shown
- at the bottom of the window.
-
-Command-line mode In Command-line mode (also called Cmdline mode) you
-Cmdline mode can enter one line of text at the bottom of the
- window. This is for the Ex commands, ":", the pattern
- search commands, "?" and "/", and the filter command,
- "!". |Cmdline-mode|
-
-Ex mode Like Command-line mode, but after entering a command
- you remain in Ex mode. Very limited editing of the
- command line. |Ex-mode|
-
- *Terminal-mode*
-Terminal mode In Terminal mode all input (except CTRL-\) is sent to
- the process running in the current |terminal| buffer.
- If CTRL-\ is pressed, the next key is sent unless it
- is CTRL-N (|CTRL-\_CTRL-N|) or CTRL-O (|t_CTRL-\_CTRL-O|).
- If the 'showmode' option is on "-- TERMINAL --" is shown
- at the bottom of the window.
+ *Normal* *Normal-mode* *command-mode*
+- Normal mode: In Normal mode you can enter all the normal editor
+ commands. If you start the editor you are in this
+ mode. This is also known as command mode.
+
+- Visual mode: This is like Normal mode, but the movement commands
+ extend a highlighted area. When a non-movement
+ command is used, it is executed for the highlighted
+ area. See |Visual-mode|.
+ If the 'showmode' option is on "-- VISUAL --" is shown
+ at the bottom of the window.
+
+- Select mode: This looks most like the MS-Windows selection mode.
+ Typing a printable character deletes the selection
+ and starts Insert mode. See |Select-mode|.
+ If the 'showmode' option is on "-- SELECT --" is shown
+ at the bottom of the window.
+
+- Insert mode: In Insert mode the text you type is inserted into the
+ buffer. See |Insert-mode|.
+ If the 'showmode' option is on "-- INSERT --" is shown
+ at the bottom of the window.
+
+- Cmdline mode: In Command-line mode (also called Cmdline mode) you
+ can enter one line of text at the bottom of the
+ window. This is for the Ex commands, ":", the pattern
+ search commands, "?" and "/", and the filter command,
+ "!". |Cmdline-mode|
+
+- Ex mode: Like Command-line mode, but after entering a command
+ you remain in Ex mode. Very limited editing of the
+ command line. |Ex-mode|
+
+ *Terminal-mode*
+- Terminal mode: In Terminal mode all input (except CTRL-\) is sent to
+ the process running in the current |terminal| buffer.
+ If CTRL-\ is pressed, the next key is sent unless it
+ is CTRL-N (|CTRL-\_CTRL-N|) or CTRL-O (|t_CTRL-\_CTRL-O|).
+ If the 'showmode' option is on "-- TERMINAL --" is shown
+ at the bottom of the window.
There are six ADDITIONAL modes. These are variants of the BASIC modes:
- *Operator-pending* *Operator-pending-mode*
-Operator-pending mode This is like Normal mode, but after an operator
- command has started, and Vim is waiting for a {motion}
- to specify the text that the operator will work on.
-
-Replace mode Replace mode is a special case of Insert mode. You
- can do the same things as in Insert mode, but for
- each character you enter, one character of the existing
- text is deleted. See |Replace-mode|.
- If the 'showmode' option is on "-- REPLACE --" is
- shown at the bottom of the window.
-
-Virtual Replace mode Virtual Replace mode is similar to Replace mode, but
- instead of file characters you are replacing screen
- real estate. See |Virtual-Replace-mode|.
- If the 'showmode' option is on "-- VREPLACE --" is
- shown at the bottom of the window.
-
-Insert Normal mode Entered when CTRL-O is typed in Insert mode (see
- |i_CTRL-O|). This is like Normal mode, but after
- executing one command Vim returns to Insert mode.
- If the 'showmode' option is on "-- (insert) --" is
- shown at the bottom of the window.
-
-Insert Visual mode Entered when starting a Visual selection from Insert
- mode, e.g., by using CTRL-O and then "v", "V" or
- CTRL-V. When the Visual selection ends, Vim returns
- to Insert mode.
- If the 'showmode' option is on "-- (insert) VISUAL --"
- is shown at the bottom of the window.
-
-Insert Select mode Entered when starting Select mode from Insert mode.
- E.g., by dragging the mouse or <S-Right>.
- When the Select mode ends, Vim returns to Insert mode.
- If the 'showmode' option is on "-- (insert) SELECT --"
- is shown at the bottom of the window.
+ *Operator-pending* *Operator-pending-mode*
+- Operator-pending mode: This is like Normal mode, but after an operator
+ command has started, and Vim is waiting for a {motion}
+ to specify the text that the operator will work on.
+
+- Replace mode: Replace mode is a special case of Insert mode. You
+ can do the same things as in Insert mode, but for
+ each character you enter, one character of the existing
+ text is deleted. See |Replace-mode|.
+ If the 'showmode' option is on "-- REPLACE --" is
+ shown at the bottom of the window.
+
+- Virtual Replace mode: Virtual Replace mode is similar to Replace mode, but
+ instead of file characters you are replacing screen
+ real estate. See |Virtual-Replace-mode|.
+ If the 'showmode' option is on "-- VREPLACE --" is
+ shown at the bottom of the window.
+
+- Insert Normal mode: Entered when CTRL-O is typed in Insert mode (see
+ |i_CTRL-O|). This is like Normal mode, but after
+ executing one command Vim returns to Insert mode.
+ If the 'showmode' option is on "-- (insert) --" is
+ shown at the bottom of the window.
+
+- Insert Visual mode: Entered when starting a Visual selection from Insert
+ mode, e.g., by using CTRL-O and then "v", "V" or
+ CTRL-V. When the Visual selection ends, Vim returns
+ to Insert mode.
+ If the 'showmode' option is on "-- (insert) VISUAL --"
+ is shown at the bottom of the window.
+
+- Insert Select mode: Entered when starting Select mode from Insert mode.
+ E.g., by dragging the mouse or <S-Right>.
+ When the Select mode ends, Vim returns to Insert mode.
+ If the 'showmode' option is on "-- (insert) SELECT --"
+ is shown at the bottom of the window.
==============================================================================
-Switching from mode to mode *mode-switching*
+Switching from mode to mode *mode-switching*
If for any reason you do not know which mode you are in, you can always get
back to Normal mode by typing <Esc> twice. This doesn't work for Ex mode
@@ -528,25 +437,27 @@ hear the bell after you type <Esc>. However, when pressing <Esc> after using
CTRL-O in Insert mode you get a beep but you are still in Insert mode, type
<Esc> again.
- *i_esc*
- FROM mode TO mode ~
- Normal Visual Select Insert Replace Cmd-line Ex >
- Normal v V ^V *4 *1 R gR : / ? ! Q
- Visual *2 ^G c C -- : --
- Select *5 ^O ^G *6 -- -- --
- Insert <Esc> -- -- <Insert> -- --
- Replace <Esc> -- -- <Insert> -- --
- Command-line *3 -- -- :start -- --
- Ex :vi -- -- -- -- --
-
--- not possible
+ *i_esc*
+ >
+ FROM mode TO mode
+ Normal Visual Select Insert Replace Cmd-line Ex >
+ Normal v V ^V *4 *1 R gR : / ? ! Q
+ Visual *2 ^G c C -- : --
+ Select *5 ^O ^G *6 -- -- --
+ Insert <Esc> -- -- <Insert> -- --
+ Replace <Esc> -- -- <Insert> -- --
+ Command-line *3 -- -- :start -- --
+ Ex :vi -- -- -- -- --
+
+ -- not possible
+<
-* 1 Go from Normal mode to Insert mode by giving the command "i", "I", "a",
+- 1 Go from Normal mode to Insert mode by giving the command "i", "I", "a",
"A", "o", "O", "c", "C", "s" or S".
-* 2 Go from Visual mode to Normal mode by giving a non-movement command, which
+- 2 Go from Visual mode to Normal mode by giving a non-movement command, which
causes the command to be executed, or by hitting <Esc> "v", "V" or "CTRL-V"
(see |v_v|), which just stops Visual mode without side effects.
-* 3 Go from Command-line mode to Normal mode by:
+- 3 Go from Command-line mode to Normal mode by:
- Hitting <CR> or <NL>, which causes the entered command to be executed.
- Deleting the complete line (e.g., with CTRL-U) and giving a final <BS>.
- Hitting CTRL-C or <Esc>, which quits the command-line without executing
@@ -554,37 +465,37 @@ CTRL-O in Insert mode you get a beep but you are still in Insert mode, type
In the last case <Esc> may be the character defined with the 'wildchar'
option, in which case it will start command-line completion. You can
ignore that and type <Esc> again.
-* 4 Go from Normal to Select mode by:
+- 4 Go from Normal to Select mode by:
- use the mouse to select text while 'selectmode' contains "mouse"
- use a non-printable command to move the cursor while keeping the Shift
key pressed, and the 'selectmode' option contains "key"
- use "v", "V" or "CTRL-V" while 'selectmode' contains "cmd"
- use "gh", "gH" or "g CTRL-H" |g_CTRL-H|
-* 5 Go from Select mode to Normal mode by using a non-printable command to move
+- 5 Go from Select mode to Normal mode by using a non-printable command to move
the cursor, without keeping the Shift key pressed.
-* 6 Go from Select mode to Insert mode by typing a printable character. The
+- 6 Go from Select mode to Insert mode by typing a printable character. The
selection is deleted and the character is inserted.
- *CTRL-\_CTRL-N* *i_CTRL-\_CTRL-N* *c_CTRL-\_CTRL-N*
- *v_CTRL-\_CTRL-N* *t_CTRL-\_CTRL-N*
+ *CTRL-\_CTRL-N* *i_CTRL-\_CTRL-N* *c_CTRL-\_CTRL-N*
+ *v_CTRL-\_CTRL-N* *t_CTRL-\_CTRL-N*
Additionally the command CTRL-\ CTRL-N or <C-\><C-N> can be used to go to
Normal mode from any other mode. This can be used to make sure Vim is in
Normal mode, without causing a beep like <Esc> would. However, this does not
work in Ex mode. When used after a command that takes an argument, such as
|f| or |m|, the timeout set with 'ttimeoutlen' applies.
- *CTRL-\_CTRL-G* *i_CTRL-\_CTRL-G* *c_CTRL-\_CTRL-G* *v_CTRL-\_CTRL-G*
+ *CTRL-\_CTRL-G* *i_CTRL-\_CTRL-G* *c_CTRL-\_CTRL-G* *v_CTRL-\_CTRL-G*
CTRL-\ CTRL-G works the same as |CTRL-\_CTRL-N| for backward compatibility.
- *gQ* *mode-Ex* *Ex-mode* *Ex* *EX* *E501*
-gQ Switch to Ex mode. This is like typing ":" commands
- one after another, except:
- - You don't have to keep pressing ":".
- - The screen doesn't get updated after each command.
- Use the `:vi` command (|:visual|) to exit this mode.
+ *gQ* *mode-Ex* *Ex-mode* *Ex* *EX* *E501*
+gQ Switch to Ex mode. This is like typing ":" commands
+ one after another, except:
+ - You don't have to keep pressing ":".
+ - The screen doesn't get updated after each command.
+ Use the `:vi` command (|:visual|) to exit this mode.
==============================================================================
-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
@@ -601,24 +512,24 @@ Lines longer than the window width will wrap, unless the 'wrap' option is off
If the window has room after the last line of the buffer, Vim will show '~' in
the first column of the last lines in the window, like this:
>
- +-----------------------+
- |some line |
- |last line |
- |~ |
- |~ |
- +-----------------------+
+ +-----------------------+
+ |some line |
+ |last line |
+ |~ |
+ |~ |
+ +-----------------------+
<
Thus the '~' lines indicate that the end of the buffer was reached.
If the last line in a window doesn't fit, Vim will indicate this with a '@' in
the first column of the last lines in the window, like this:
>
- +-----------------------+
- |first line |
- |second line |
- |@ |
- |@ |
- +-----------------------+
+ +-----------------------+
+ |first line |
+ |second line |
+ |@ |
+ |@ |
+ +-----------------------+
<
Thus the '@' lines indicate that there is a line that doesn't fit in the
window.
@@ -628,12 +539,12 @@ When the "lastline" flag is present in the 'display' option, you will not see
completely, only the part that fits is shown, and the last three characters of
the last line are replaced with "@@@", like this:
>
- +-----------------------+
- |first line |
- |second line |
- |a very long line that d|
- |oesn't fit in the wi@@@|
- +-----------------------+
+ +-----------------------+
+ |first line |
+ |second line |
+ |a very long line that d|
+ |oesn't fit in the wi@@@|
+ +-----------------------+
<
If there is a single line that is too long to fit in the window, this is a
special situation. Vim will show only part of the line, around where the
@@ -646,7 +557,7 @@ from real characters in the buffer.
The 'showbreak' option contains the string to put in front of wrapped lines.
- *wrap-off*
+ *wrap-off*
If the 'wrap' option is off, long lines will not wrap. Only the part that
fits on the screen is shown. If the cursor is moved to a part of the line
that is not shown, the screen is scrolled horizontally. The advantage of
@@ -665,8 +576,8 @@ position on the screen. The cursor can only be positioned on the first one.
If you set the 'number' option, all lines will be preceded with their
number. Tip: If you don't like wrapping lines to mix with the line numbers,
-set the 'showbreak' option to eight spaces:
- ":set showbreak=\ \ \ \ \ \ \ \ "
+set the 'showbreak' option to eight spaces: >
+ ":set showbreak=\ \ \ \ \ \ \ \ "
If you set the 'list' option, <Tab> characters will not be shown as several
spaces, but as "^I". A '$' will be placed at the end of the line, so you can
@@ -677,19 +588,19 @@ display of the buffer contents is updated as soon as you go back to Command
mode.
The last line of the window is used for status and other messages. The
-status messages will only be used if an option is on:
+status messages will only be used if an option is on: >
-status message option default Unix default ~
-current mode 'showmode' on on
-command characters 'showcmd' on off
-cursor position 'ruler' off off
+ status message option default Unix default
+ current mode 'showmode' on on
+ command characters 'showcmd' on off
+ cursor position 'ruler' off off
The current mode is "-- INSERT --" or "-- REPLACE --", see |'showmode'|. The
command characters are those that you typed but were not used yet.
If you have a slow terminal you can switch off the status messages to speed
up editing: >
- :set nosc noru nosm
+ :set nosc noru nosm
If there is an error, an error message will be shown for at least one second
(in reverse video).
@@ -704,70 +615,70 @@ small not a single line will fit in it. Make it at least 40 characters wide
to be able to read most messages on the last line.
==============================================================================
-Definitions *definitions* *jargon*
+Definitions *definitions* *jargon*
- buffer Contains lines of text, usually from a file.
- screen The whole area that Nvim uses to display things.
- window A view on a buffer. There can be multiple windows for
- one buffer.
- frame Windows are kept in a tree of frames. Each frame
- contains a column, row, or window ("leaf" frame).
+- buffer: Contains lines of text, usually from a file.
+- screen: The whole area that Nvim uses to display things.
+- window: A view on a buffer. There can be multiple windows for one buffer.
+- frame: Windows are kept in a tree of frames. Each frame contains a column,
+ row, or window ("leaf" frame).
A screen contains one or more windows, separated by status lines and with the
command line at the bottom.
>
- +-------------------------------+
- screen | window 1 | window 2 |
- | | |
- | | |
- |= status line =|= status line =|
- | window 3 |
- | |
- | |
- |==== status line ==============|
- |command line |
- +-------------------------------+
+ +-------------------------------+
+ screen | window 1 | window 2 |
+ | | |
+ | | |
+ |= status line =|= status line =|
+ | window 3 |
+ | |
+ | |
+ |==== status line ==============|
+ |command line |
+ +-------------------------------+
<
The command line is also used for messages. It scrolls up the screen when
there is not enough room in the command line.
A difference is made between four types of lines:
- buffer lines The lines in the buffer. This is the same as the
- lines as they are read from/written to a file. They
- can be thousands of characters long.
- logical lines The buffer lines with folding applied. Buffer lines
- in a closed fold are changed to a single logical line:
- "+-- 99 lines folded". They can be thousands of
- characters long.
- window lines The lines displayed in a window: A range of logical
- lines with wrapping, line breaks, etc. applied. They
- can only be as long as the width of the window allows,
- longer lines are wrapped or truncated.
- screen lines The lines of the screen that Nvim uses. Consists of
- the window lines of all windows, with status lines
- and the command line added. They can only be as long
- as the width of the screen allows. When the command
- line gets longer it wraps and lines are scrolled to
- make room.
-
-buffer lines logical lines window lines screen lines ~
-
-1. one 1. one 1. +-- folded 1. +-- folded
-2. two 2. +-- folded 2. five 2. five
-3. three 3. five 3. six 3. six
-4. four 4. six 4. seven 4. seven
-5. five 5. seven 5. === status line ===
-6. six 6. aaa
-7. seven 7. bbb
- 8. ccc ccc c
-1. aaa 1. aaa 1. aaa 9. cc
-2. bbb 2. bbb 2. bbb 10. ddd
-3. ccc ccc ccc 3. ccc ccc ccc 3. ccc ccc c 11. ~
-4. ddd 4. ddd 4. cc 12. === status line ===
- 5. ddd 13. (command line)
- 6. ~
+- buffer lines: The lines in the buffer. This is the same as the
+ lines as they are read from/written to a file. They
+ can be thousands of characters long.
+- logical lines: The buffer lines with folding applied. Buffer lines
+ in a closed fold are changed to a single logical line:
+ "+-- 99 lines folded". They can be thousands of
+ characters long.
+- window lines: The lines displayed in a window: A range of logical
+ lines with wrapping, line breaks, etc. applied. They
+ can only be as long as the width of the window allows,
+ longer lines are wrapped or truncated.
+- screen lines: The lines of the screen that Nvim uses. Consists of
+ the window lines of all windows, with status lines
+ and the command line added. They can only be as long
+ as the width of the screen allows. When the command
+ line gets longer it wraps and lines are scrolled to
+ make room.
+>
+ buffer lines logical lines window lines screen lines
+ -----------------------------------------------------------------------
+ 1. one 1. one 1. +-- folded 1. +-- folded
+ 2. two 2. +-- folded 2. five 2. five
+ 3. three 3. five 3. six 3. six
+ 4. four 4. six 4. seven 4. seven
+ 5. five 5. seven 5. === status line ===
+ 6. six 6. aaa
+ 7. seven 7. bbb
+ 8. ccc ccc c
+ 1. aaa 1. aaa 1. aaa 9. cc
+ 2. bbb 2. bbb 2. bbb 10. ddd
+ 3. ccc ccc ccc 3. ccc ccc ccc 3. ccc ccc c 11. ~
+ 4. ddd 4. ddd 4. cc 12. === status line ===
+ 5. ddd 13. (command line)
+ 6. ~
+<
API client ~
All external UIs and remote plugins (as opposed to regular Vim plugins) are
@@ -775,8 +686,8 @@ All external UIs and remote plugins (as opposed to regular Vim plugins) are
to abstract or wrap the RPC API for the convenience of other applications
(just like a REST client or SDK such as boto3 for AWS: you can speak AWS REST
using an HTTP client like curl, but boto3 wraps that in a convenient python
-interface). For example, the Nvim lua-client is an API client:
- https://github.com/neovim/lua-client
+interface). For example, the Nvim node-client is an API client:
+ https://github.com/neovim/node-client
Host ~
@@ -791,4 +702,4 @@ process and communicates with Nvim via the |api|.
==============================================================================
- vim:tw=78:ts=8:noet:ft=help:norl:
+ vim:tw=78:ts=8:et:sw=4:ft=help:norl:
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 1693ff5e4f..d9e536b79b 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -204,6 +204,7 @@ won't run if your server doesn't support them.
- `'textDocument/diagnostic'`
- `'textDocument/documentHighlight'`
- `'textDocument/documentSymbol'`
+- `'textDocument/foldingRange'`
- `'textDocument/formatting'`
- `'textDocument/hover'`
- `'textDocument/implementation'`
@@ -697,6 +698,48 @@ commands *vim.lsp.commands*
The second argument is the `ctx` of |lsp-handler|
+foldclose({kind}, {winid}) *vim.lsp.foldclose()*
+ Close all {kind} of folds in the the window with {winid}.
+
+ To automatically fold imports when opening a file, you can use an autocmd: >lua
+ vim.api.nvim_create_autocmd('LspNotify', {
+ callback = function(args)
+ if args.data.method == 'textDocument/didOpen' then
+ vim.lsp.foldclose('imports', vim.fn.bufwinid(args.buf))
+ end
+ end,
+ })
+<
+
+ Parameters: ~
+ • {kind} (`lsp.FoldingRangeKind`) Kind to close, one of "comment",
+ "imports" or "region".
+ • {winid} (`integer?`) Defaults to the current window.
+
+foldexpr({lnum}) *vim.lsp.foldexpr()*
+ Provides an interface between the built-in client and a `foldexpr`
+ function.
+
+ To use, check for the "textDocument/foldingRange" capability in an
+ |LspAttach| autocommand. Example: >lua
+ vim.api.nvim_create_autocommand('LspAttach', {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ if client:supports_method('textDocument/foldingRange') then
+ vim.wo.foldmethod = 'expr'
+ vim.wo.foldexpr = 'v:lua.vim.lsp.foldexpr()'
+ end
+ end,
+ })
+<
+
+ Parameters: ~
+ • {lnum} (`integer`) line number
+
+foldtext() *vim.lsp.foldtext()*
+ Provides a `foldtext` function that shows the `collapsedText` retrieved,
+ defaults to the first folded line if `collapsedText` is not provided.
+
formatexpr({opts}) *vim.lsp.formatexpr()*
Provides an interface between the built-in client and a `formatexpr`
function.
@@ -798,12 +841,11 @@ start({config}, {opts}) *vim.lsp.start()*
})
<
- See |vim.lsp.start_client()| for all available options. The most important
+ See |vim.lsp.ClientConfig| for all available options. The most important
are:
• `name` arbitrary name for the LSP client. Should be unique per language
server.
- • `cmd` command string[] or function, described at
- |vim.lsp.start_client()|.
+ • `cmd` command string[] or function.
• `root_dir` path to the project root. By default this is used to decide
if an existing client should be re-used. The example above uses
|vim.fs.root()| to detect the root by traversing the file system upwards
@@ -825,33 +867,25 @@ start({config}, {opts}) *vim.lsp.start()*
Parameters: ~
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|vim.lsp.ClientConfig|.
- • {opts} (`table?`) Optional keyword arguments
+ • {opts} (`table?`) Optional keyword arguments.
• {reuse_client}?
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be re-used.
Used on all running clients. The default implementation
- re-uses a client if name and root_dir matches.
+ re-uses a client if it has the same name and if the given
+ workspace folders (or root_dir) are all included in the
+ client's workspace folders.
• {bufnr}? (`integer`) Buffer handle to attach to if
starting or re-using a client (0 for current).
+ • {attach}? (`boolean`) Whether to attach the client to a
+ buffer (default true). If set to `false`, `reuse_client`
+ and `bufnr` will be ignored.
• {silent}? (`boolean`) Suppress error reporting if the LSP
server fails to start (default false).
Return: ~
(`integer?`) client_id
-start_client({config}) *vim.lsp.start_client()*
- Starts and initializes a client with the given configuration.
-
- Parameters: ~
- • {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
- |vim.lsp.ClientConfig|.
-
- Return (multiple): ~
- (`integer?`) 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.
- (`string?`) Error message, if any
-
status() *vim.lsp.status()*
Consumes the latest progress messages from all clients and formats them as
a string. Empty if there are no clients or if no new messages
@@ -912,7 +946,7 @@ Lua module: vim.lsp.client *lsp-client*
• {handlers} (`table<string,lsp.Handler>`) The handlers
used by the client as described in
|lsp-handler|.
- • {requests} (`table<integer,{ type: string, bufnr: integer, method: string}>`)
+ • {requests} (`table<integer,{ type: string, bufnr: integer, method: string}?>`)
The current pending requests in flight to the
server. Entries are key-value pairs with the
key being the request id while the value is a
@@ -925,8 +959,7 @@ Lua module: vim.lsp.client *lsp-client*
server.
• {config} (`vim.lsp.ClientConfig`) copy of the table
that was passed by the user to
- |vim.lsp.start_client()|. See
- |vim.lsp.ClientConfig|.
+ |vim.lsp.start()|. See |vim.lsp.ClientConfig|.
• {server_capabilities} (`lsp.ServerCapabilities?`) Response from the
server sent on `initialize` describing the
server's capabilities.
@@ -949,9 +982,9 @@ Lua module: vim.lsp.client *lsp-client*
lenses, ...) triggers the command. Client
commands take precedence over the global
command registry.
- • {settings} (`table`) Map with language server specific
- settings. These are returned to the language
- server if requested via
+ • {settings} (`lsp.LSPObject`) Map with language server
+ specific settings. These are returned to the
+ language server if requested via
`workspace/configuration`. Keys are
case-sensitive.
• {flags} (`table`) A table with flags for the client.
@@ -1044,20 +1077,21 @@ Lua module: vim.lsp.client *lsp-client*
an array.
• {handlers}? (`table<string,function>`) Map of language
server method names to |lsp-handler|
- • {settings}? (`table`) Map with language server specific
- settings. See the {settings} in
+ • {settings}? (`lsp.LSPObject`) Map with language server
+ specific settings. See the {settings} in
|vim.lsp.Client|.
• {commands}? (`table<string,fun(command: lsp.Command, ctx: table)>`)
Table that maps string of clientside commands to
user-defined functions. Commands passed to
- start_client take precedence over the global
+ `start()` take precedence over the global
command registry. Each key must be a unique
command name, and the value is a function which
is called if any LSP action (code action, code
lenses, ...) triggers the command.
- • {init_options}? (`table`) Values to pass in the initialization
- request as `initializationOptions`. See
- `initialize` in the LSP spec.
+ • {init_options}? (`lsp.LSPObject`) Values to pass in the
+ initialization request as
+ `initializationOptions`. See `initialize` in the
+ LSP spec.
• {name}? (`string`, default: client-id) Name in log
messages.
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
@@ -1079,9 +1113,9 @@ Lua module: vim.lsp.client *lsp-client*
Callback 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
- |vim.lsp.start_client()|. You can use this to
- modify parameters before they are sent.
+ config that was passed to |vim.lsp.start()|. You
+ can use this to modify parameters before they
+ are sent.
• {on_init}? (`elem_or_list<fun(client: vim.lsp.Client, initialize_result: lsp.InitializeResult)>`)
Callback invoked after LSP "initialize", where
`result` is a table of `capabilities` and
@@ -2253,7 +2287,7 @@ connect({host_or_path}, {port}) *vim.lsp.rpc.connect()*
• a host and port via TCP
Return a function that can be passed to the `cmd` field for
- |vim.lsp.start_client()| or |vim.lsp.start()|.
+ |vim.lsp.start()|.
Parameters: ~
• {host_or_path} (`string`) host to connect to or path to a pipe/domain
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index c3dddaf888..dad3d92238 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -17,9 +17,9 @@ get an idea of what lurks beneath: >vim
:lua vim.print(package.loaded)
Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the
-"editor stdlib" (|builtin-functions| and |Ex-commands|) and the |API|, all of
-which can be used from Lua code (|lua-vimscript| |vim.api|). Together these
-"namespaces" form the Nvim programming interface.
+"editor stdlib" (|vimscript-functions| + |Ex-commands|) and the |API|, all of
+which can be used from Lua code (|lua-vimscript| |vim.api|). These three
+namespaces form the Nvim programming interface.
Lua plugins and user config are automatically discovered and loaded, just like
Vimscript. See |lua-guide| for practical guidance.
@@ -811,11 +811,14 @@ vim.json.decode({str}, {opts}) *vim.json.decode()*
Return: ~
(`any`)
-vim.json.encode({obj}) *vim.json.encode()*
+vim.json.encode({obj}, {opts}) *vim.json.encode()*
Encodes (or "packs") Lua object {obj} as JSON in a Lua string.
Parameters: ~
- • {obj} (`any`)
+ • {obj} (`any`)
+ • {opts} (`table<string,any>?`) Options table with keys:
+ • escape_slash: (boolean) (default false) When true, escapes
+ `/` character in JSON strings
Return: ~
(`string`)
@@ -1911,6 +1914,11 @@ vim.show_pos({bufnr}, {row}, {col}, {filter}) *vim.show_pos()*
Can also be shown with `:Inspect`. *:Inspect*
+ Example: To bind this function to the vim-scriptease inspired `zS` in
+ Normal mode: >lua
+ vim.keymap.set('n', 'zS', vim.show_pos)
+<
+
Attributes: ~
Since: 0.9.0
@@ -2469,7 +2477,7 @@ vim.validate({name}, {value}, {validator}, {optional}, {message})
Parameters: ~
• {name} (`string`) Argument name
- • {value} (`string`) Argument value
+ • {value} (`any`) Argument value
• {validator} (`vim.validate.Validator`)
• (`string|string[]`): Any value that can be returned
from |lua-type()| in addition to `'callable'`:
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 11048aee30..34cf309576 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -12,7 +12,7 @@ manual.
Type |gO| to see the table of contents.
==============================================================================
-1. Key mapping *key-mapping* *mapping* *macro*
+1. Key mapping *keybind* *key-mapping* *mapping* *macro*
Key mapping is used to change the meaning of typed keys. The most common use
is to define a sequence of commands for a function key. Example: >
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index ac151811c2..d6f5aeb354 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -27,7 +27,7 @@ depends on the 'shortmess' option.
Clear messages, keeping only the {count} most
recent ones.
-The number of remembered messages is fixed at 200.
+The number of remembered messages is determined by the 'messagesopt' option.
*g<*
The "g<" command can be used to see the last page of previous command output.
@@ -789,6 +789,7 @@ If you accidentally hit <Enter> or <Space> and you want to see the displayed
text then use |g<|. This only works when 'more' is set.
To reduce the number of hit-enter prompts:
+- Set 'messagesopt'.
- Set 'cmdheight' to 2 or higher.
- Add flags to 'shortmess'.
- Reset 'showcmd' and/or 'ruler'.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 6808fd9292..ef055161df 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -25,6 +25,7 @@ EXPERIMENTS
OPTIONS
• 'jumpoptions' flag "unload" has been renamed to "clean".
+• The `msghistory` option has been removed in favor of 'messagesopt'.
==============================================================================
BREAKING CHANGES *news-breaking*
@@ -58,6 +59,9 @@ DEFAULTS
• |]d-default| and |[d-default| accept a count.
• |[D-default| and |]D-default| jump to the first and last diagnostic in the
current buffer, respectively.
+• 'number', 'relativenumber', 'signcolumn', and 'foldcolumn' are disabled in
+ |terminal| buffers. See |terminal-config| for an example of changing these defaults.
+• |vim.json.encode()| no longer escapes the forward slash symbol by default
DIAGNOSTICS
@@ -167,6 +171,7 @@ The following new features were added.
API
• |nvim__ns_set()| can set properties for a namespace
+• |vim.json.encode()| has an option to enable forward slash escaping
DEFAULTS
@@ -230,6 +235,8 @@ LSP
• |vim.lsp.buf.hover()| now highlights hover ranges using the
|hl-LspReferenceTarget| highlight group.
• Functions in |vim.lsp.Client| can now be called as methods.
+• Implemented LSP folding: |vim.lsp.foldexpr()|
+ https://microsoft.github.io/language-server-protocol/specification/#textDocument_foldingRange
LUA
@@ -242,7 +249,7 @@ LUA
OPTIONS
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
-• 'msghistory' controls maximum number of messages to remember.
+• 'messagesopt' configures |:messages| and |hit-enter| prompt.
• 'tabclose' controls which tab page to focus when closing a tab page.
PERFORMANCE
@@ -277,6 +284,8 @@ TREESITTER
• |LanguageTree:node_for_range()| gets anonymous and named nodes for a range
• |vim.treesitter.get_node()| now takes an option `include_anonymous`, default
false, which allows it to return anonymous nodes as well as named nodes.
+• |treesitter-directive-trim!| can trim all whitespace (not just empty lines)
+ from both sides of a node.
TUI
@@ -302,6 +311,8 @@ UI
|hl-PmenuSel| and |hl-PmenuMatch| both inherit from |hl-Pmenu|, and
|hl-PmenuMatchSel| inherits highlights from both |hl-PmenuSel| and
|hl-PmenuMatch|.
+• |vim.diagnostic.setqflist()| updates existing diagnostics quickfix list if one
+ exists.
• |ui-messages| content chunks now also contain the highlight group ID.
diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt
index 86e344c654..8593511dbc 100644
--- a/runtime/doc/nvim.txt
+++ b/runtime/doc/nvim.txt
@@ -6,21 +6,23 @@
Nvim *nvim* *neovim* *nvim-intro*
-Nvim is based on Vim by Bram Moolenaar.
+Nvim is based on Vim by Bram Moolenaar. Nvim is emphatically a fork of Vim,
+not a clone: compatibility with Vim (especially editor and Vimscript features,
+except |Vim9script|) is maintained where possible. See |vim-differences| for
+the complete reference.
-If you already use Vim see |nvim-from-vim| for a quickstart.
-If you are new to Vim, try the 30-minute tutorial: >vim
+If you already use Vim, see |nvim-from-vim| for a quickstart. If you just
+installed Nvim and have never used it before, watch this 10-minute
+video: https://youtu.be/TQn2hJeHQbM .
- :Tutor<Enter>
-
-Nvim is emphatically a fork of Vim, not a clone: compatibility with Vim
-(especially editor and Vimscript features) is maintained where possible. See
-|vim-differences| for the complete reference of differences from Vim.
+To learn how to use Vim in 30 minutes, try the tutorial: >vim
+ :Tutor<Enter>
+<
Type |gO| to see the table of contents.
==============================================================================
-Transitioning from Vim *nvim-from-vim*
+Transitioning from Vim *nvim-from-vim*
1. To start the transition, create your |init.vim| (user config) file: >vim
@@ -71,4 +73,20 @@ the same Nvim configuration on all of your machines, by creating
source ~/.config/nvim/init.vim
==============================================================================
+What next? *nvim-quickstart*
+
+If you are just trying out Nvim for a few minutes, and want to see the
+extremes of what it can do, try one of these popular "extension packs" or
+"distributions" (Note: Nvim is not affiliated with these projects, and does
+not support them):
+
+- *kickstart* https://github.com/nvim-lua/kickstart.nvim
+- *lazyvim* https://www.lazyvim.org/
+- *nvchad* https://nvchad.com/
+
+However, in general, we recommend (eventually) taking time to learn Nvim from
+its stock configuration, and incrementally setting options and adding plugins
+to your |config| as you find an explicit need to do so.
+
+==============================================================================
vim:tw=78:ts=8:et:ft=help:norl:
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index c5f21c64a2..5763d16cad 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1559,9 +1559,9 @@ A jump table for the options with a short description can be found at |Q_op|.
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
- noselect Do not select a match in the menu, force the user to
- select one from the menu. Only works in combination with
- "menu" or "menuone".
+ noselect Same as "noinsert", except that no menu item is
+ pre-selected. If both "noinsert" and "noselect" are present,
+ "noselect" has precedence.
fuzzy Enable |fuzzy-matching| for completion candidates. This
allows for more flexible and intuitive matching, where
@@ -3197,7 +3197,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
- each of these histories (see |cmdline-editing| and 'msghistory' for
+ each of these histories (see |cmdline-editing| and 'messagesopt' for
the number of messages to remember).
The maximum value is 10000.
@@ -4045,6 +4045,28 @@ A jump table for the options with a short description can be found at |Q_op|.
generated from a list of items, e.g., the Buffers menu. Changing this
option has no direct effect, the menu must be refreshed first.
+ *'messagesopt'* *'mopt'*
+'messagesopt' 'mopt' string (default "hit-enter,history:500")
+ global
+ Option settings for outputting messages. It can consist of the
+ following items. Items must be separated by a comma.
+
+ hit-enter Use a |hit-enter| prompt when the message is longer than
+ 'cmdheight' size.
+
+ wait:{n} Instead of using a |hit-enter| prompt, simply wait for
+ {n} milliseconds so that the user has a chance to read
+ the message. The maximum value of {n} is 10000. Use
+ 0 to disable the wait (but then the user may miss an
+ important message).
+ This item is ignored when "hit-enter" is present, but
+ required when "hit-enter" is not present.
+
+ history:{n} Determines how many entries are remembered in the
+ |:messages| history. The maximum value is 10000.
+ Setting it to zero clears the message history.
+ This item must always be present.
+
*'mkspellmem'* *'msm'*
'mkspellmem' 'msm' string (default "460000,2000,500")
global
@@ -4290,13 +4312,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Defines the maximum time in msec between two mouse clicks for the
second click to be recognized as a multi click.
- *'msghistory'* *'mhi'*
-'msghistory' 'mhi' number (default 500)
- global
- Determines how many entries are remembered in the |:messages| history.
- The maximum value is 10000.
- Setting it to zero clears the message history.
-
*'nrformats'* *'nf'*
'nrformats' 'nf' string (default "bin,hex")
local to buffer
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index f1b0daee76..c54a4df3d8 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -193,7 +193,7 @@ registers. Nvim looks for these clipboard tools, in order of priority:
- xclip (if $DISPLAY is set)
- lemonade (for SSH) https://github.com/pocke/lemonade
- doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/
- - win32yank (Windows)
+ - *win32yank* (Windows)
- putclip, getclip (Windows) https://cygwin.com/packages/summary/cygutils.html
- clip, powershell (Windows) https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/clip
- termux (via termux-clipboard-set, termux-clipboard-set)
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index b3399b2766..a291c0277d 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1317,9 +1317,117 @@ g:compiler_gcc_ignore_unmatched_lines
JAVAC *compiler-javac*
Commonly used compiler options can be added to 'makeprg' by setting the
-g:javac_makeprg_params variable. For example: >
+b/g:javac_makeprg_params variable. For example: >
+
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
-<
+
+MAVEN *compiler-maven*
+
+Commonly used compiler options can be added to 'makeprg' by setting the
+b/g:maven_makeprg_params variable. For example: >
+
+ let g:maven_makeprg_params = "-DskipTests -U -X"
+
+SPOTBUGS *compiler-spotbugs*
+
+SpotBugs is a static analysis tool that can be used to find bugs in Java.
+It scans the Java bytecode of all classes in the currently open buffer.
+(Therefore, `:compiler! spotbugs` is not supported.)
+
+Commonly used compiler options can be added to 'makeprg' by setting the
+"b:" or "g:spotbugs_makeprg_params" variable. For example: >
+
+ let b:spotbugs_makeprg_params = "-longBugCodes -effort:max -low"
+
+The global default is "-workHard -experimental".
+
+By default, the class files are searched in the directory where the source
+files are placed. However, typical Java projects use distinct directories
+for source files and class files. To make both known to SpotBugs, assign
+their paths (distinct and relative to their common root directory) to the
+following properties (using the example of a common Maven project): >
+
+ let g:spotbugs_properties = {
+ \ 'sourceDirPath': 'src/main/java',
+ \ 'classDirPath': 'target/classes',
+ \ 'testSourceDirPath': 'src/test/java',
+ \ 'testClassDirPath': 'target/test-classes',
+ \ }
+
+Note that values for the path keys describe only for SpotBugs where to look
+for files; refer to the documentation for particular compiler plugins for more
+information.
+
+The default pre- and post-compiler actions are provided for Ant, Maven, and
+Javac compiler plugins and can be selected by assigning the name of a compiler
+plugin to the "compiler" key: >
+
+ let g:spotbugs_properties = {
+ \ 'compiler': 'maven',
+ \ }
+
+This single setting is essentially equivalent to all the settings below, with
+the exception made for the "PreCompilerAction" and "PreCompilerTestAction"
+values: their listed |Funcref|s will obtain no-op implementations whereas the
+implicit Funcrefs of the "compiler" key will obtain the requested defaults if
+available. >
+
+ let g:spotbugs_properties = {
+ \ 'PreCompilerAction':
+ \ function('spotbugs#DefaultPreCompilerAction'),
+ \ 'PreCompilerTestAction':
+ \ function('spotbugs#DefaultPreCompilerTestAction'),
+ \ 'PostCompilerAction':
+ \ function('spotbugs#DefaultPostCompilerAction'),
+ \ 'sourceDirPath': 'src/main/java',
+ \ 'classDirPath': 'target/classes',
+ \ 'testSourceDirPath': 'src/test/java',
+ \ 'testClassDirPath': 'target/test-classes',
+ \ }
+
+With default actions, the compiler of choice will attempt to rebuild the class
+files for the buffer (and possibly for the whole project) as soon as a Java
+syntax file is loaded; then, `spotbugs` will attempt to analyze the quality of
+the compilation unit of the buffer.
+
+When default actions are not suited to a desired workflow, consider writing
+arbitrary functions yourself and matching their |Funcref|s to the supported
+keys: "PreCompilerAction", "PreCompilerTestAction", and "PostCompilerAction".
+
+The next example re-implements the default pre-compiler actions for a Maven
+project and requests other default Maven settings with the "compiler" entry: >
+
+ function! MavenPreCompilerAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler maven
+ make compile
+ endfunction
+
+ function! MavenPreCompilerTestAction() abort
+ call spotbugs#DeleteClassFiles()
+ compiler maven
+ make test-compile
+ endfunction
+
+ let g:spotbugs_properties = {
+ \ 'compiler': 'maven',
+ \ 'PreCompilerAction':
+ \ function('MavenPreCompilerAction'),
+ \ 'PreCompilerTestAction':
+ \ function('MavenPreCompilerTestAction'),
+ \ }
+
+Note that all entered custom settings will take precedence over the matching
+default settings in "g:spotbugs_properties".
+
+The "g:spotbugs_properties" variable is consulted by the Java filetype plugin
+(|ft-java-plugin|) to arrange for the described automation, and, therefore, it
+must be defined before |FileType| events can take place for the buffers loaded
+with Java source files. It could, for example, be set in a project-local
+|vimrc| loaded by [0].
+
+[0] https://github.com/MarcWeber/vim-addon-local-vimrc/
+
GNU MAKE *compiler-make*
Since the default make program is "make", the compiler plugin for make,
@@ -1409,6 +1517,13 @@ Useful values for the 'makeprg' options therefore are:
setlocal makeprg=./alltests.py " Run a testsuite
setlocal makeprg=python\ %:S " Run a single testcase
+PYTEST COMPILER *compiler-pytest*
+Commonly used compiler options can be added to 'makeprg' by setting the
+b/g:pytest_makeprg_params variable. For example: >
+
+ let b:pytest_makeprg_params = "--verbose --no-summary --disable-warnings"
+
+The global default is "--tb=short --quiet"; Python warnings are suppressed.
TEX COMPILER *compiler-tex*
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index 9d74f1f376..9895b606fd 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -10,7 +10,7 @@ Sign Support Features *sign-support*
Type |gO| to see the table of contents.
==============================================================================
-1. Introduction *sign-intro* *signs*
+1. Introduction *sign-intro* *signs* *gutter*
When a debugger or other IDE tool is driving an editor it needs to be able
to give specific highlights which quickly tell the user useful information
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index ed9659d6e7..5a1421f430 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -108,6 +108,10 @@ global configuration.
- 'list' is disabled
- 'wrap' is disabled
+- 'number' is disabled
+- 'relativenumber' is disabled
+- 'signcolumn' is set to "no"
+- 'foldcolumn' is set to "0"
You can change the defaults with a TermOpen autocommand: >vim
au TermOpen * setlocal list
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 5fc6429f7a..877d90a3b7 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -245,15 +245,32 @@ The following directives are built in:
(#gsub! @_node ".*%.(.*)" "%1")
<
`trim!` *treesitter-directive-trim!*
- Trim blank lines from the end of the node. This will set a new
- `metadata[capture_id].range`.
+ Trims whitespace from the node. Sets a new
+ `metadata[capture_id].range`. Takes a capture ID and, optionally, four
+ integers to customize trimming behavior (`1` meaning trim, `0` meaning
+ don't trim). When only given a capture ID, trims blank lines (lines
+ that contain only whitespace, or are empty) from the end of the node
+ (for backwards compatibility). Can trim all whitespace from both sides
+ of the node if parameters are given.
+ Examples: >query
+ ; only trim blank lines from the end of the node
+ ; (equivalent to (#trim! @fold 0 0 1 0))
+ (#trim! @fold)
+
+ ; trim blank lines from both sides of the node
+ (#trim! @fold 1 0 1 0)
+
+ ; trim all whitespace around the node
+ (#trim! @fold 1 1 1 1)
+<
Parameters: ~
{capture_id}
+ {trim_start_linewise}
+ {trim_start_charwise}
+ {trim_end_linewise} (default `1` if only given {capture_id})
+ {trim_end_charwise}
- Example: >query
- (#trim! @fold)
-<
Further directives can be added via |vim.treesitter.query.add_directive()|.
Use |vim.treesitter.query.list_directives()| to list all available directives.
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 55eba484bc..77eddfd8e1 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -788,7 +788,7 @@ must handle.
kind
Name indicating the message kind:
- "" (empty) Unknown (consider a feature-request: |bugs|)
+ "" (empty) Unknown (consider a |feature-request|)
"confirm" |confirm()| or |:confirm| dialog
"confirm_sub" |:substitute| confirm dialog |:s_c|
"emsg" Error (|errors|, internal error, |:throw|, …)
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index d967e7c75b..6074931565 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -534,7 +534,8 @@ gO Show a filetype-specific, navigable "outline" of the
current buffer. For example, in a |help| buffer this
shows the table of contents.
- Currently works in |help| and |:Man| buffers.
+ Works in |help| and |:Man| buffers, or any buffer with
+ an active |LSP| client (|lsp-defaults|).
[N]gs *gs* *:sl* *:sleep*
:[N]sl[eep] [N][m] Do nothing for [N] seconds, or [N] milliseconds if [m]
@@ -551,8 +552,7 @@ gO Show a filetype-specific, navigable "outline" of the
Queued messages are processed during the sleep.
*:sl!* *:sleep!*
-:[N]sl[eep]! [N][m] Same as above. Unlike Vim, it does not hide the
- cursor. |vim-differences|
+:[N]sl[eep]! [N][m] Same as above, but hide the cursor.
==============================================================================
2. Using Vim like less or more *less*
diff --git a/runtime/doc/vietnamese.txt b/runtime/doc/vietnamese.txt
new file mode 100644
index 0000000000..ed3fe9bc68
--- /dev/null
+++ b/runtime/doc/vietnamese.txt
@@ -0,0 +1,73 @@
+*vietnamese.txt* Nvim
+
+
+ VIM REFERENCE MANUAL by Phạm Bình An
+
+ Type |gO| to see the table of contents.
+
+===============================================================================
+1. Introduction
+ *vietnamese-intro*
+Vim supports Vietnamese language in the following ways:
+
+- Built-in |vietnamese-keymap|, which allows you to type Vietnamese characters
+ in |Insert-mode| and |search-commands| using US keyboard layout.
+- Localization in Vietnamese. See |vietnamese-l10n|
+
+===============================================================================
+2. Vietnamese keymaps
+ *vietnamese-keymap*
+To switch between languages you can use your system native keyboard switcher,
+or use one of the Vietnamese keymaps included in the Vim distribution, like
+below >
+ :set keymap=vietnamese-telex_utf-8
+<
+See |'keymap'| for more information.
+
+In the latter case, you can type Vietnamese even if you do not have a
+Vietnamese input method engine (IME) or you want Vim to be independent from a
+system-wide keyboard settings (when |'imdisable'| is set). You can also |:map|
+a key to switch between keyboards.
+
+Vim comes with the following Vietnamese keymaps:
+- *vietnamese-telex_utf-8* Telex input method, |UTF-8| encoding.
+- *vietnamese-viqr_utf-8* VIQR input method, |UTF-8| encoding.
+- *vietnamese-vni_utf-8* VNI input method, |UTF-8| encoding.
+
+ *vietnamese-ime_diff*
+Since these keymaps were designed to be minimalistic, they do not support all
+features of the corresponding input methods. The differences are described
+below:
+
+- You can only type each character individually, entering the base letter first
+ and then the diacritics later. For example, to type the word `nến` using
+ |vietnamese-vni_utf-8|, you must type `ne61n`, not `nen61` or `ne6n1`
+- For characters with more than 1 diacritic, you need to type vowel mark before
+ tone mark. For example, to type `ồ` using |vietnamese-telex_utf-8|, you need
+ to type `oof`, not `ofo`.
+- With |vietnamese-telex_utf-8|, you need to type all uppercase letters to
+ produce uppercase characters with diacritics. For example, `Ừ` must be typed
+ as `UWF`.
+- With |vietnamese-telex_utf-8|, the escape character `\` from VNI is added,
+ hence the confusing `ooo` input to type `oo` is removed, which could lead to
+ ambiguities. For example, to type the word `Đoòng`, you would type
+ `DDo\ofng`.
+- Simple Telex (both v1 and v2), including the `w[]{}` style, is not
+ supported.
+- Removing diacritics using `z` in Telex or `0` in VNI and VIQR is not supported.
+
+===============================================================================
+3. Localization
+ *vietnamese-l10n*
+Vim |messages| are also available in Vietnamese. If you wish to see messages
+in Vietnamese, you can run the command |:language| with an argument being the
+name of the Vietnamese locale. For example, >
+ :language vi_VN
+< or >
+ :language vi_VN.utf-8
+<
+Note that the name of the Vietnamese locale may vary depending on your system.
+See |mbyte-first| for details.
+
+===============================================================================
+vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index adc866af6b..bfef5d5d4a 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -39,7 +39,6 @@ Defaults *nvim-defaults*
- 'autoindent' is enabled
- 'autoread' is enabled (works in all UIs, including terminal)
- 'background' defaults to "dark" (unless set automatically by the terminal/UI)
-- 'backspace' defaults to "indent,eol,start"
- 'backupdir' defaults to .,~/.local/state/nvim/backup// (|xdg|), auto-created
- 'belloff' defaults to "all"
- 'comments' includes "fb:•"
@@ -187,6 +186,10 @@ nvim_terminal:
- 'textwidth' set to 0
- 'nowrap'
- 'nolist'
+ - 'nonumber'
+ - 'norelativenumber'
+ - 'signcolumn' set to "no"
+ - 'foldcolumn' set to "0"
- 'winhighlight' uses |hl-StatusLineTerm| and |hl-StatusLineTermNC| in
place of |hl-StatusLine| and |hl-StatusLineNC|
@@ -667,7 +670,6 @@ Commands:
- :promptrepl
- :scriptversion (always version 1)
- :shell
-- :sleep! (does not hide the cursor; same as :sleep)
- :smile
- :tearoff
- :cstag
@@ -687,7 +689,7 @@ Cscope:
https://github.com/dhananjaylatkar/cscope_maps.nvim
Eval:
-- Vim9script
+- *Vim9script* (the Vim 9+ flavor of Vimscript) is not supported.
- *cscope_connection()*
- *err_teapot()*
- *js_encode()*
diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt
index 0c349c4e57..32f3b96269 100644
--- a/runtime/doc/vvars.txt
+++ b/runtime/doc/vvars.txt
@@ -189,6 +189,8 @@ v:event
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
*v:exception* *exception-variable*
v:exception
diff --git a/runtime/filetype.lua b/runtime/filetype.lua
index 797033da06..730991a00c 100644
--- a/runtime/filetype.lua
+++ b/runtime/filetype.lua
@@ -13,8 +13,8 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, {
end
local ft, on_detect = vim.filetype.match({
-- The unexpanded file name is needed here. #27914
- -- Neither args.file nor args.match are guaranteed to be unexpanded.
- filename = vim.fn.bufname(args.buf),
+ -- However, bufname() can't be used, as it doesn't work with :doautocmd. #31306
+ filename = args.file,
buf = args.buf,
})
if not ft then
diff --git a/runtime/ftplugin/java.vim b/runtime/ftplugin/java.vim
index 55b358374f..6e12fe2fe5 100644
--- a/runtime/ftplugin/java.vim
+++ b/runtime/ftplugin/java.vim
@@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Dan Sharp
" Repository: https://github.com/zzzyxwvut/java-vim.git
-" Last Change: 2024 Sep 26
+" Last Change: 2024 Nov 24
" 2024 Jan 14 by Vim Project (browsefilter)
" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
@@ -90,10 +90,127 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
endif
endif
+" The support for pre- and post-compiler actions for SpotBugs.
+if exists("g:spotbugs_properties") && has_key(g:spotbugs_properties, 'compiler')
+ try
+ let spotbugs#compiler = g:spotbugs_properties.compiler
+ let g:spotbugs_properties = extend(
+ \ spotbugs#DefaultProperties(),
+ \ g:spotbugs_properties,
+ \ 'force')
+ catch
+ echomsg v:errmsg
+ finally
+ call remove(g:spotbugs_properties, 'compiler')
+ endtry
+endif
+
+if exists("g:spotbugs_properties") &&
+ \ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim')
+ let s:request = 0
+
+ if has_key(g:spotbugs_properties, 'PreCompilerAction')
+ let s:dispatcher = 'call g:spotbugs_properties.PreCompilerAction() | '
+ let s:request += 1
+ endif
+
+ if has_key(g:spotbugs_properties, 'PreCompilerTestAction')
+ let s:dispatcher = 'call g:spotbugs_properties.PreCompilerTestAction() | '
+ let s:request += 2
+ endif
+
+ if has_key(g:spotbugs_properties, 'PostCompilerAction')
+ let s:request += 4
+ endif
+
+ if (s:request == 3 || s:request == 7) &&
+ \ has_key(g:spotbugs_properties, 'sourceDirPath') &&
+ \ has_key(g:spotbugs_properties, 'testSourceDirPath')
+ function! s:DispatchAction(path_action_pairs) abort
+ let name = expand('%:p')
+
+ for [path, Action] in a:path_action_pairs
+ if name =~# (path . '.\{-}\.java\=$')
+ call Action()
+ break
+ endif
+ endfor
+ endfunction
+
+ let s:dispatcher = printf('call s:DispatchAction(%s) | ',
+ \ string([[g:spotbugs_properties.sourceDirPath,
+ \ g:spotbugs_properties.PreCompilerAction],
+ \ [g:spotbugs_properties.testSourceDirPath,
+ \ g:spotbugs_properties.PreCompilerTestAction]]))
+ endif
+
+ if s:request
+ if exists("b:spotbugs_syntax_once")
+ let s:actions = [{'event': 'BufWritePost'}]
+ else
+ " XXX: Handle multiple FileType events when vimrc contains more
+ " than one filetype setting for the language, e.g.:
+ " :filetype plugin indent on
+ " :autocmd BufRead,BufNewFile *.java setlocal filetype=java ...
+ " XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin !
+ let b:spotbugs_syntax_once = 1
+ let s:actions = [{
+ \ 'event': 'Syntax',
+ \ 'once': 1,
+ \ }, {
+ \ 'event': 'BufWritePost',
+ \ }]
+ endif
+
+ for s:idx in range(len(s:actions))
+ if s:request == 7 || s:request == 6 || s:request == 5
+ let s:actions[s:idx].cmd = s:dispatcher . 'compiler spotbugs | ' .
+ \ 'call g:spotbugs_properties.PostCompilerAction()'
+ elseif s:request == 4
+ let s:actions[s:idx].cmd = 'compiler spotbugs | ' .
+ \ 'call g:spotbugs_properties.PostCompilerAction()'
+ elseif s:request == 3 || s:request == 2 || s:request == 1
+ let s:actions[s:idx].cmd = s:dispatcher . 'compiler spotbugs'
+ else
+ let s:actions[s:idx].cmd = ''
+ endif
+ endfor
+
+ if !exists("#java_spotbugs")
+ augroup java_spotbugs
+ augroup END
+ endif
+
+ " The events are defined in s:actions.
+ silent! autocmd! java_spotbugs BufWritePost <buffer>
+ silent! autocmd! java_spotbugs Syntax <buffer>
+
+ for s:action in s:actions
+ execute printf('autocmd java_spotbugs %s <buffer> %s',
+ \ s:action.event,
+ \ s:action.cmd . (has_key(s:action, 'once')
+ \ ? printf(' | autocmd! java_spotbugs %s <buffer>',
+ \ s:action.event)
+ \ : ''))
+ endfor
+
+ unlet! s:action s:actions s:idx s:dispatcher
+ endif
+
+ unlet s:request
+endif
+
+function! JavaFileTypeCleanUp() abort
+ setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr<
+ unlet! b:browsefilter
+
+ " The concatenated removals may be misparsed as a BufWritePost autocmd.
+ silent! autocmd! java_spotbugs BufWritePost <buffer>
+ silent! autocmd! java_spotbugs Syntax <buffer>
+endfunction
+
" Undo the stuff we changed.
-let b:undo_ftplugin = "setlocal suffixes< suffixesadd<" .
- \ " formatoptions< comments< commentstring< path< includeexpr<" .
- \ " | unlet! b:browsefilter"
+let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp'
" See ":help vim9-mix".
if !has("vim9script")
@@ -114,6 +231,19 @@ if exists("s:zip_func_upgradable")
setlocal suffixesadd<
endif
+if exists("*s:DispatchAction")
+ def! s:DispatchAction(path_action_pairs: list<list<any>>)
+ const name: string = expand('%:p')
+
+ for [path: string, Action: func: any] in path_action_pairs
+ if name =~# (path .. '.\{-}\.java\=$')
+ Action()
+ break
+ endif
+ endfor
+ enddef
+endif
+
" Restore the saved compatibility options.
let &cpo = s:save_cpo
unlet s:save_cpo
diff --git a/runtime/ftplugin/proto.vim b/runtime/ftplugin/proto.vim
new file mode 100644
index 0000000000..585f4461d3
--- /dev/null
+++ b/runtime/ftplugin/proto.vim
@@ -0,0 +1,18 @@
+" Vim filetype plugin
+" Language: Protobuf
+" Maintainer: David Pedersen <limero@me.com>
+" Last Change: 2024 Dec 09
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal formatoptions-=t formatoptions+=croql
+
+setlocal comments=s1:/*,mb:*,ex:*/,://
+setlocal commentstring=//\ %s
+
+let b:undo_ftplugin = "setlocal formatoptions< comments< commentstring<"
+
+" vim: sw=2 sts=2 et
diff --git a/runtime/ftplugin/ptx.vim b/runtime/ftplugin/ptx.vim
new file mode 100644
index 0000000000..12b127c8fc
--- /dev/null
+++ b/runtime/ftplugin/ptx.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: Nvidia PTX (Parellel Thread Execution)
+" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com>
+" Last Change: 2024-12-05
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+let b:did_ftplugin = 1
+
+" Comments in PTX follow C/C++ syntax
+" See: https://docs.nvidia.com/cuda/parallel-thread-execution/#syntax
+setlocal commentstring=//\ %s
+
+let b:undo_ftplugin = 'setl commentstring<'
diff --git a/runtime/ftplugin/python.vim b/runtime/ftplugin/python.vim
index c000296726..6f20468896 100644
--- a/runtime/ftplugin/python.vim
+++ b/runtime/ftplugin/python.vim
@@ -3,8 +3,9 @@
" Maintainer: Tom Picton <tom@tompicton.com>
" Previous Maintainer: James Sully <sullyj3@gmail.com>
" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: 2024/05/13
-" https://github.com/tpict/vim-ftplugin-python
+" Repository: https://github.com/tpict/vim-ftplugin-python
+" Last Change: 2024/05/13
+" 2024 Nov 30 use pytest compiler (#16130)
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
@@ -134,6 +135,11 @@ elseif executable('python')
setlocal keywordprg=python\ -m\ pydoc
endif
+if expand('%:t') =~# '\v^test_.*\.py$|_test\.py$' && executable('pytest')
+ compiler pytest
+ let &l:makeprg .= ' %:S'
+endif
+
" Script for filetype switching to undo the local stuff we may have changed
let b:undo_ftplugin = 'setlocal cinkeys<'
\ . '|setlocal comments<'
@@ -148,6 +154,7 @@ let b:undo_ftplugin = 'setlocal cinkeys<'
\ . '|setlocal softtabstop<'
\ . '|setlocal suffixesadd<'
\ . '|setlocal tabstop<'
+ \ . '|setlocal makeprg<'
\ . '|silent! nunmap <buffer> [M'
\ . '|silent! nunmap <buffer> [['
\ . '|silent! nunmap <buffer> []'
diff --git a/runtime/ftplugin/typst.vim b/runtime/ftplugin/typst.vim
index 3841e427f3..08929bbdbe 100644
--- a/runtime/ftplugin/typst.vim
+++ b/runtime/ftplugin/typst.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: Typst
-" Maintainer: Gregory Anders
-" Last Change: 2024 Oct 21
+" Previous Maintainer: Gregory Anders
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Dec 09
" Based on: https://github.com/kaarmu/typst.vim
if exists('b:did_ftplugin')
@@ -11,10 +12,14 @@ let b:did_ftplugin = 1
setlocal commentstring=//\ %s
setlocal comments=s1:/*,mb:*,ex:*/,://
-setlocal formatoptions+=croq
+setlocal formatoptions+=croqn
+" Numbered Lists
+setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
+" Unordered (-), Ordered (+) and definition (/) Lists
+setlocal formatlistpat+=\\\|^\\s*[-+/\]\\s\\+
setlocal suffixesadd=.typ
-let b:undo_ftplugin = 'setl cms< com< fo< sua<'
+let b:undo_ftplugin = 'setl cms< com< fo< flp< sua<'
if get(g:, 'typst_conceal', 0)
setlocal conceallevel=2
diff --git a/runtime/indent/typst.vim b/runtime/indent/typst.vim
index 6aaa04a53a..c990b968c8 100644
--- a/runtime/indent/typst.vim
+++ b/runtime/indent/typst.vim
@@ -1,7 +1,8 @@
" Vim indent file
" Language: Typst
-" Maintainer: Gregory Anders <greg@gpanders.com>
-" Last Change: 2024-07-14
+" Previous Maintainer: Gregory Anders
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Dec 09
" Based on: https://github.com/kaarmu/typst.vim
if exists('b:did_indent')
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 6583cf48b3..0b8a54e957 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -49,10 +49,10 @@ do
vim.keymap.set('x', '*', function()
return _visual_search('/')
- end, { desc = ':help v_star-default', expr = true, silent = true })
+ end, { desc = ':help v_star-default', expr = true, replace_keycodes = false })
vim.keymap.set('x', '#', function()
return _visual_search('?')
- end, { desc = ':help v_#-default', expr = true, silent = true })
+ end, { desc = ':help v_#-default', expr = true, replace_keycodes = false })
end
--- Map Y to y$. This mimics the behavior of D and C. See |Y-default|
@@ -492,6 +492,10 @@ do
vim.bo.textwidth = 0
vim.wo[0][0].wrap = false
vim.wo[0][0].list = false
+ vim.wo[0][0].number = false
+ vim.wo[0][0].relativenumber = false
+ vim.wo[0][0].signcolumn = 'no'
+ vim.wo[0][0].foldcolumn = '0'
-- This is gross. Proper list options support when?
local winhl = vim.o.winhighlight
diff --git a/runtime/lua/vim/_inspector.lua b/runtime/lua/vim/_inspector.lua
index fccf4b8dbe..15b0733671 100644
--- a/runtime/lua/vim/_inspector.lua
+++ b/runtime/lua/vim/_inspector.lua
@@ -53,7 +53,7 @@ function vim.inspect_pos(bufnr, row, col, filter)
local cursor = vim.api.nvim_win_get_cursor(win)
row, col = cursor[1] - 1, cursor[2]
end
- bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
+ bufnr = vim._resolve_bufnr(bufnr)
local results = {
treesitter = {}, --- @type table[]
@@ -146,6 +146,13 @@ end
---
---Can also be shown with `:Inspect`. [:Inspect]()
---
+---Example: To bind this function to the vim-scriptease
+---inspired `zS` in Normal mode:
+---
+---```lua
+---vim.keymap.set('n', 'zS', vim.show_pos)
+---```
+---
---@since 11
---@param bufnr? integer defaults to the current buffer
---@param row? integer row to inspect, 0-based. Defaults to the row of the current cursor
@@ -171,7 +178,7 @@ function vim.show_pos(bufnr, row, col, filter)
if data.hl_group ~= data.hl_group_link then
append('links to ', 'MoreMsg')
append(data.hl_group_link, data.hl_group_link)
- append(' ')
+ append(' ')
end
if comment then
append(comment, 'Comment')
@@ -184,7 +191,14 @@ function vim.show_pos(bufnr, row, col, filter)
append('Treesitter', 'Title')
nl()
for _, capture in ipairs(items.treesitter) do
- item(capture, capture.lang)
+ item(
+ capture,
+ string.format(
+ 'priority: %d language: %s',
+ capture.metadata.priority or vim.hl.priorities.treesitter,
+ capture.lang
+ )
+ )
end
nl()
end
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index acd12b353d..b2385197bd 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -963,9 +963,9 @@ function vim.api.nvim_create_augroup(name, opts) end
--- - id: (number) autocommand id
--- - event: (string) name of the triggered event `autocmd-events`
--- - group: (number|nil) autocommand group id, if any
---- - match: (string) expanded value of [<amatch>]
---- - buf: (number) expanded value of [<abuf>]
---- - file: (string) expanded value of [<afile>]
+--- - file: (string) [<afile>] (not expanded to a full path)
+--- - match: (string) [<amatch>] (expanded to a full path)
+--- - buf: (number) [<abuf>]
--- - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]()
--- - command (string) optional: Vim command to execute on event. Cannot be used with
--- {callback}
@@ -1654,7 +1654,7 @@ function vim.api.nvim_notify(msg, log_level, opts) end
--- Open a terminal instance in a buffer
---
--- By default (and currently the only option) the terminal will not be
---- connected to an external process. Instead, input send on the channel
+--- connected to an external process. Instead, input sent on the channel
--- will be echoed directly by the terminal. This is useful to display
--- ANSI terminal sequences returned as part of a rpc message, or similar.
---
@@ -1665,6 +1665,18 @@ function vim.api.nvim_notify(msg, log_level, opts) end
--- Then `nvim_chan_send()` can be called immediately to process sequences
--- in a virtual terminal having the intended size.
---
+--- Example: this `TermHl` command can be used to display and highlight raw ANSI termcodes, so you
+--- can use Nvim as a "scrollback pager" (for terminals like kitty): [terminal-scrollback-pager]()
+---
+--- ```lua
+--- vim.api.nvim_create_user_command('TermHl', function()
+--- local b = vim.api.nvim_create_buf(false, true)
+--- local chan = vim.api.nvim_open_term(b, {})
+--- vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
+--- vim.api.nvim_win_set_buf(0, b)
+--- end, { desc = 'Highlights ANSI termcodes in curbuf' })
+--- ```
+---
--- @param buffer integer the buffer to use (expected to be empty)
--- @param opts vim.api.keyset.open_term Optional parameters.
--- - on_input: Lua callback for input sent, i e keypresses in terminal
diff --git a/runtime/lua/vim/_meta/json.lua b/runtime/lua/vim/_meta/json.lua
index 07d89aafc8..1a7e87db9c 100644
--- a/runtime/lua/vim/_meta/json.lua
+++ b/runtime/lua/vim/_meta/json.lua
@@ -35,5 +35,8 @@ function vim.json.decode(str, opts) end
--- Encodes (or "packs") Lua object {obj} as JSON in a Lua string.
---@param obj any
+---@param opts? table<string,any> Options table with keys:
+--- - escape_slash: (boolean) (default false) When true, escapes `/`
+--- character in JSON strings
---@return string
-function vim.json.encode(obj) end
+function vim.json.encode(obj, opts) end
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 247b464a70..7a8c3a6c29 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -1086,9 +1086,9 @@ vim.go.cia = vim.go.completeitemalign
--- a match from the menu. Only works in combination with
--- "menu" or "menuone". No effect if "longest" is present.
---
---- noselect Do not select a match in the menu, force the user to
---- select one from the menu. Only works in combination with
---- "menu" or "menuone".
+--- noselect Same as "noinsert", except that no menu item is
+--- pre-selected. If both "noinsert" and "noselect" are present,
+--- "noselect" has precedence.
---
--- fuzzy Enable `fuzzy-matching` for completion candidates. This
--- allows for more flexible and intuitive matching, where
@@ -3016,7 +3016,7 @@ vim.go.hid = vim.go.hidden
--- A history of ":" commands, and a history of previous search patterns
--- is remembered. This option decides how many entries may be stored in
---- each of these histories (see `cmdline-editing` and 'msghistory' for
+--- each of these histories (see `cmdline-editing` and 'messagesopt' for
--- the number of messages to remember).
--- The maximum value is 10000.
---
@@ -4084,6 +4084,31 @@ vim.o.mis = vim.o.menuitems
vim.go.menuitems = vim.o.menuitems
vim.go.mis = vim.go.menuitems
+--- Option settings for outputting messages. It can consist of the
+--- following items. Items must be separated by a comma.
+---
+--- hit-enter Use a `hit-enter` prompt when the message is longer than
+--- 'cmdheight' size.
+---
+--- wait:{n} Instead of using a `hit-enter` prompt, simply wait for
+--- {n} milliseconds so that the user has a chance to read
+--- the message. The maximum value of {n} is 10000. Use
+--- 0 to disable the wait (but then the user may miss an
+--- important message).
+--- This item is ignored when "hit-enter" is present, but
+--- required when "hit-enter" is not present.
+---
+--- history:{n} Determines how many entries are remembered in the
+--- `:messages` history. The maximum value is 10000.
+--- Setting it to zero clears the message history.
+--- This item must always be present.
+---
+--- @type string
+vim.o.messagesopt = "hit-enter,history:500"
+vim.o.mopt = vim.o.messagesopt
+vim.go.messagesopt = vim.o.messagesopt
+vim.go.mopt = vim.go.messagesopt
+
--- Parameters for `:mkspell`. This tunes when to start compressing the
--- word tree. Compression can be slow when there are many words, but
--- it's needed to avoid running out of memory. The amount of memory used
@@ -4379,16 +4404,6 @@ vim.o.mouset = vim.o.mousetime
vim.go.mousetime = vim.o.mousetime
vim.go.mouset = vim.go.mousetime
---- Determines how many entries are remembered in the `:messages` history.
---- The maximum value is 10000.
---- Setting it to zero clears the message history.
----
---- @type integer
-vim.o.msghistory = 500
-vim.o.mhi = vim.o.msghistory
-vim.go.msghistory = vim.o.msghistory
-vim.go.mhi = vim.go.msghistory
-
--- This defines what bases Vim will consider for numbers when using the
--- CTRL-A and CTRL-X commands for adding to and subtracting from a number
--- respectively; see `CTRL-A` for more info on these commands.
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index f9b5d93a4b..e207f641de 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -4928,7 +4928,7 @@ function vim.fn.jobstop(id) end
---
--- @param jobs integer[]
--- @param timeout? integer
---- @return any
+--- @return integer[]
function vim.fn.jobwait(jobs, timeout) end
--- Join the items in {list} together into one String.
@@ -7244,9 +7244,9 @@ function vim.fn.round(expr) end
---
--- @param channel integer
--- @param event string
---- @param args? any
+--- @param ... any
--- @return any
-function vim.fn.rpcnotify(channel, event, args) end
+function vim.fn.rpcnotify(channel, event, ...) end
--- Sends a request to {channel} to invoke {method} via
--- |RPC| and blocks until a response is received.
@@ -7256,9 +7256,9 @@ function vim.fn.rpcnotify(channel, event, args) end
---
--- @param channel integer
--- @param method string
---- @param args? any
+--- @param ... any
--- @return any
-function vim.fn.rpcrequest(channel, method, args) end
+function vim.fn.rpcrequest(channel, method, ...) end
--- @deprecated
--- Deprecated. Replace >vim
@@ -9328,6 +9328,7 @@ function vim.fn.str2float(string, quoted) end
--- and exists only for backwards-compatibility.
--- With UTF-8 composing characters are handled properly: >vim
--- echo str2list("á") " returns [97, 769]
+--- <
---
--- @param string string
--- @param utf8? boolean
@@ -10870,7 +10871,7 @@ function vim.fn.winheight(nr) end
--- <
---
--- @param tabnr? integer
---- @return any
+--- @return any[]
function vim.fn.winlayout(tabnr) end
--- The result is a Number, which is the screen line of the cursor
diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua
index 8784fdbac9..445da4e02f 100644
--- a/runtime/lua/vim/_meta/vvars.lua
+++ b/runtime/lua/vim/_meta/vvars.lua
@@ -15,7 +15,7 @@ vim.v.argv = ...
--- Argument for evaluating 'formatexpr' and used for the typed
--- character when using <expr> in an abbreviation `:map-<expr>`.
--- It is also used by the `InsertCharPre` and `InsertEnter` events.
---- @type any
+--- @type string
vim.v.char = ...
--- The name of the character encoding of a file to be converted.
@@ -60,7 +60,7 @@ vim.v.collate = ...
--- mode.
--- Note: Plugins can modify the value to emulate the builtin
--- `CompleteDone` event behavior.
---- @type any
+--- @type vim.v.completed_item
vim.v.completed_item = ...
--- The count given for the last Normal mode command. Can be used
@@ -90,7 +90,7 @@ vim.v.count1 = ...
--- This variable can not be set directly, use the `:language`
--- command.
--- See `multi-lang`.
---- @type any
+--- @type string
vim.v.ctype = ...
--- Normally zero. When a deadly signal is caught it's set to
@@ -197,7 +197,9 @@ vim.v.errors = ...
--- changing window (or tab) on `DirChanged`.
--- status Job status or exit code, -1 means "unknown". `TermClose`
--- reason Reason for completion being done. `CompleteDone`
---- @type any
+--- complete_word The word that was selected, empty if abandoned complete.
+--- complete_type See `complete_info_mode`
+--- @type vim.v.event
vim.v.event = ...
--- The value of the exception most recently caught and not
@@ -223,7 +225,7 @@ vim.v.exception = ...
--- ```vim
--- :au VimLeave * echo "Exit value is " .. v:exiting
--- ```
---- @type any
+--- @type integer?
vim.v.exiting = ...
--- Special value used to put "false" in JSON and msgpack. See
@@ -419,7 +421,7 @@ vim.v.mouse_winid = ...
--- and `msgpackdump()`. All types inside dictionary are fixed
--- (not editable) empty lists. To check whether some list is one
--- of msgpack types, use `is` operator.
---- @type any
+--- @type table
vim.v.msgpack_types = ...
--- Special value used to put "null" in JSON and NIL in msgpack.
@@ -563,7 +565,7 @@ vim.v.relnum = ...
--- typed command.
--- This can be used to find out why your script causes the
--- hit-enter prompt.
---- @type any
+--- @type string
vim.v.scrollstart = ...
--- Search direction: 1 after a forward search, 0 after a
@@ -705,13 +707,13 @@ vim.v.termrequest = ...
vim.v.termresponse = ...
--- Must be set before using `test_garbagecollect_now()`.
---- @type any
+--- @type integer
vim.v.testing = ...
--- Full filename of the last loaded or saved session file.
--- Empty when no session file has been saved. See `:mksession`.
--- Modifiable (can be set).
---- @type any
+--- @type string
vim.v.this_session = ...
--- The point where the exception most recently caught and not
@@ -728,7 +730,7 @@ vim.v.this_session = ...
--- ```
---
--- Output: "Exception from test.vim, line 2"
---- @type any
+--- @type string
vim.v.throwpoint = ...
--- Special value used to put "true" in JSON and msgpack. See
diff --git a/runtime/lua/vim/_meta/vvars_extra.lua b/runtime/lua/vim/_meta/vvars_extra.lua
new file mode 100644
index 0000000000..7ef3021e89
--- /dev/null
+++ b/runtime/lua/vim/_meta/vvars_extra.lua
@@ -0,0 +1,77 @@
+--- @meta _
+error('Cannot require a meta file')
+
+--- Extra types for vim.v dictionary fields
+
+--- @class vim.v.completed_item
+--- @field word? string the text that will be inserted, mandatory
+--- abbreviation of "word"; when not empty it is used in the menu instead of "word"
+--- @field abbr? string
+--- extra text for the popup menu, displayed after "word" or "abbr"
+--- @field menu? string
+--- more information about the item, can be displayed in a preview window
+--- @field info? string
+--- @field kind? string single letter indicating the type of completion
+--- when non-zero case is to be ignored when comparing items to be equal; when
+--- omitted zero is used, thus items that only differ in case are added
+--- @field icase? integer
+--- when non-zero, always treat this item to be equal when comparing. Which
+--- means, "equal=1" disables filtering of this item.
+--- @field equal? integer
+--- when non-zero this match will be added even when an item with the same word
+--- is already present.
+--- @field dup? integer
+--- when non-zero this match will be added even when it is an empty string
+--- @field empty? integer
+--- custom data which is associated with the item and available
+--- in |v:completed_item|; it can be any type; defaults to an empty string
+--- @field user_data? any
+--- an additional highlight group whose attributes are combined
+--- with |hl-PmenuSel| and |hl-Pmenu| or |hl-PmenuMatchSel| and |hl-PmenuMatch|
+--- highlight attributes in the popup menu to apply cterm and gui properties
+--- (with higher priority) like strikethrough to the completion items abbreviation
+--- @field abbr_hlgroup? string
+--- an additional highlight group specifically for setting the highlight
+--- attributes of the completion kind. When this field is present, it will
+--- override the |hl-PmenuKind| highlight group, allowing for the customization
+--- of ctermfg and guifg properties for the completion kind
+--- @field kind_hlgroup? string
+
+--- @class vim.v.event
+--- Whether the event triggered during an aborting condition (e.g. |c_Esc| or
+--- |c_CTRL-C| for |CmdlineLeave|).
+--- @field abort? boolean
+--- @field chan? integer See |channel-id|
+--- @field info? table Dict of arbitrary event data.
+--- @field cmdlevel? integer Level of cmdline.
+--- @field cmdtype? string Type of cmdline, |cmdline-char|.
+--- @field cwd? string Current working directory.
+--- @field inclusive? boolean Motion is |inclusive|, else exclusive.
+--- @field scope? string Event-specific scope name.
+--- Current |operator|. Also set for Ex commands (unlike |v:operator|). For
+--- example if |TextYankPost| is triggered by the |:yank| Ex command then
+--- `v:event.operator` is "y".
+--- @field operator? string
+--- Text stored in the register as a |readfile()|-style list of lines.
+--- @field regcontents? string
+--- Requested register (e.g "x" for "xyy) or the empty string for an unnamed operation.
+--- @field regname? string
+--- @field regtype? string Type of register as returned by |getregtype()|.
+--- @field visual? boolean Selection is visual (as opposed to, e.g., via motion).
+--- @field completed_item? vim.v.completed_item
+--- Current selected complete item on |CompleteChanged|, Is `{}` when no
+--- complete item selected.
+--- @field height? integer
+--- @field width? integer Height of popup menu on |CompleteChanged|
+--- @field row? integer Width of popup menu on |CompleteChanged|
+--- Col count of popup menu on |CompleteChanged|, relative to screen.
+--- @field col? integer
+--- @field size? integer Total number of completion items on |CompleteChanged|.
+--- Is |v:true| if popup menu have scrollbar, or |v:false| if not.
+--- @field scrollbar? boolean
+--- Is |v:true| if the event fired while changing window (or tab) on |DirChanged|.
+--- @field changed_window? boolean
+--- @field status? boolean Job status or exit code, -1 means "unknown". |TermClose|
+--- @field reason? string Reason for completion being done. |CompleteDone|
+--- The word that was selected, empty if abandoned complete. @field complete_word? string
+--- @field complete_type? string See |complete_info_mode|
diff --git a/runtime/lua/vim/_system.lua b/runtime/lua/vim/_system.lua
index ce5dbffeaa..c0a0570e13 100644
--- a/runtime/lua/vim/_system.lua
+++ b/runtime/lua/vim/_system.lua
@@ -47,15 +47,6 @@ local function close_handle(handle)
end
end
----@param state vim.SystemState
-local function close_handles(state)
- close_handle(state.handle)
- close_handle(state.stdin)
- close_handle(state.stdout)
- close_handle(state.stderr)
- close_handle(state.timer)
-end
-
--- @class vim.SystemObj
--- @field cmd string[]
--- @field pid integer
@@ -132,9 +123,7 @@ function SystemObj:write(data)
-- (https://github.com/neovim/neovim/pull/17620#discussion_r820775616)
stdin:write('', function()
stdin:shutdown(function()
- if stdin then
- stdin:close()
- end
+ close_handle(stdin)
end)
end)
end
@@ -146,25 +135,52 @@ function SystemObj:is_closing()
return handle == nil or handle:is_closing() or false
end
----@param output fun(err:string?, data: string?)|false
----@return uv.uv_stream_t?
----@return fun(err:string?, data: string?)? Handler
-local function setup_output(output)
- if output == nil then
- return assert(uv.new_pipe(false)), nil
+--- @param output? uv.read_start.callback|false
+--- @param text? boolean
+--- @return uv.uv_stream_t? pipe
+--- @return uv.read_start.callback? handler
+--- @return string[]? data
+local function setup_output(output, text)
+ if output == false then
+ return
end
+ local bucket --- @type string[]?
+ local handler --- @type uv.read_start.callback
+
if type(output) == 'function' then
- return assert(uv.new_pipe(false)), output
+ handler = output
+ else
+ bucket = {}
+ handler = function(err, data)
+ if err then
+ error(err)
+ end
+ if text and data then
+ bucket[#bucket + 1] = data:gsub('\r\n', '\n')
+ else
+ bucket[#bucket + 1] = data
+ end
+ end
end
- assert(output == false)
- return nil, nil
+ local pipe = assert(uv.new_pipe(false))
+
+ --- @type uv.read_start.callback
+ local function handler_with_close(err, data)
+ handler(err, data)
+ if data == nil then
+ pipe:read_stop()
+ pipe:close()
+ end
+ end
+
+ return pipe, handler_with_close, bucket
end
----@param input string|string[]|true|nil
----@return uv.uv_stream_t?
----@return string|string[]?
+--- @param input? string|string[]|boolean
+--- @return uv.uv_stream_t?
+--- @return string|string[]?
local function setup_input(input)
if not input then
return
@@ -208,28 +224,6 @@ local function setup_env(env, clear_env)
return renv
end
---- @param stream uv.uv_stream_t
---- @param text? boolean
---- @param bucket string[]
---- @return fun(err: string?, data: string?)
-local function default_handler(stream, text, bucket)
- return function(err, data)
- if err then
- error(err)
- end
- if data ~= nil then
- if text then
- bucket[#bucket + 1] = data:gsub('\r\n', '\n')
- else
- bucket[#bucket + 1] = data
- end
- else
- stream:read_stop()
- stream:close()
- end
- end
-end
-
local is_win = vim.fn.has('win32') == 1
local M = {}
@@ -255,9 +249,9 @@ local function spawn(cmd, opts, on_exit, on_error)
return handle, pid_or_err --[[@as integer]]
end
----@param timeout integer
----@param cb fun()
----@return uv.uv_timer_t
+--- @param timeout integer
+--- @param cb fun()
+--- @return uv.uv_timer_t
local function timer_oneshot(timeout, cb)
local timer = assert(uv.new_timer())
timer:start(timeout, 0, function()
@@ -273,7 +267,12 @@ end
--- @param signal integer
--- @param on_exit fun(result: vim.SystemCompleted)?
local function _on_exit(state, code, signal, on_exit)
- close_handles(state)
+ close_handle(state.handle)
+ close_handle(state.stdin)
+ close_handle(state.timer)
+
+ -- #30846: Do not close stdout/stderr here, as they may still have data to
+ -- read. They will be closed in uv.read_start on EOF.
local check = assert(uv.new_check())
check:start(function()
@@ -311,6 +310,15 @@ local function _on_exit(state, code, signal, on_exit)
end)
end
+--- @param state vim.SystemState
+local function _on_error(state)
+ close_handle(state.handle)
+ close_handle(state.stdin)
+ close_handle(state.stdout)
+ close_handle(state.stderr)
+ close_handle(state.timer)
+end
+
--- Run a system command
---
--- @param cmd string[]
@@ -324,8 +332,8 @@ function M.run(cmd, opts, on_exit)
opts = opts or {}
- local stdout, stdout_handler = setup_output(opts.stdout)
- local stderr, stderr_handler = setup_output(opts.stderr)
+ local stdout, stdout_handler, stdout_data = setup_output(opts.stdout, opts.text)
+ local stderr, stderr_handler, stderr_data = setup_output(opts.stderr, opts.text)
local stdin, towrite = setup_input(opts.stdin)
--- @type vim.SystemState
@@ -335,7 +343,9 @@ function M.run(cmd, opts, on_exit)
timeout = opts.timeout,
stdin = stdin,
stdout = stdout,
+ stdout_data = stdout_data,
stderr = stderr,
+ stderr_data = stderr_data,
}
--- @diagnostic disable-next-line:missing-fields
@@ -350,17 +360,15 @@ function M.run(cmd, opts, on_exit)
}, function(code, signal)
_on_exit(state, code, signal, on_exit)
end, function()
- close_handles(state)
+ _on_error(state)
end)
- if stdout then
- state.stdout_data = {}
- stdout:read_start(stdout_handler or default_handler(stdout, opts.text, state.stdout_data))
+ if stdout and stdout_handler then
+ stdout:read_start(stdout_handler)
end
- if stderr then
- state.stderr_data = {}
- stderr:read_start(stderr_handler or default_handler(stderr, opts.text, state.stderr_data))
+ if stderr and stderr_handler then
+ stderr:read_start(stderr_handler)
end
local obj = new_systemobj(state)
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 2de996feeb..340bca4f6b 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -2,6 +2,8 @@ local api, if_nil = vim.api, vim.F.if_nil
local M = {}
+local _qf_id = nil
+
--- [diagnostic-structure]()
---
--- Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
@@ -571,13 +573,6 @@ local underline_highlight_map = make_highlight_map('Underline')
local floating_highlight_map = make_highlight_map('Floating')
local sign_highlight_map = make_highlight_map('Sign')
-local function get_bufnr(bufnr)
- if not bufnr or bufnr == 0 then
- return api.nvim_get_current_buf()
- end
- return bufnr
-end
-
--- @param diagnostics vim.Diagnostic[]
--- @return table<integer,vim.Diagnostic[]>
local function diagnostic_lines(diagnostics)
@@ -640,7 +635,7 @@ end
--- @param namespace integer
--- @param bufnr? integer
local function save_extmarks(namespace, bufnr)
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
if not diagnostic_attached_buffers[bufnr] then
api.nvim_buf_attach(bufnr, false, {
on_lines = function(_, _, _, _, _, last)
@@ -812,7 +807,7 @@ local function get_diagnostics(bufnr, opts, clamp)
end
end
elseif namespace == nil then
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
for iter_namespace in pairs(diagnostic_cache[bufnr]) do
add_all_diags(bufnr, diagnostic_cache[bufnr][iter_namespace])
end
@@ -823,7 +818,7 @@ local function get_diagnostics(bufnr, opts, clamp)
end
end
else
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
for _, iter_namespace in ipairs(namespace) do
add_all_diags(bufnr, diagnostic_cache[bufnr][iter_namespace] or {})
end
@@ -848,9 +843,26 @@ local function set_list(loclist, opts)
local diagnostics = get_diagnostics(bufnr, opts --[[@as vim.diagnostic.GetOpts]], false)
local items = M.toqflist(diagnostics)
if loclist then
- vim.fn.setloclist(winnr, {}, ' ', { title = title, items = items })
+ vim.fn.setloclist(winnr, {}, 'u', { title = title, items = items })
else
- vim.fn.setqflist({}, ' ', { title = title, items = items })
+ -- Check if the diagnostics quickfix list no longer exists.
+ if _qf_id and vim.fn.getqflist({ id = _qf_id }).id == 0 then
+ _qf_id = nil
+ end
+
+ -- If we already have a diagnostics quickfix, update it rather than creating a new one.
+ -- This avoids polluting the finite set of quickfix lists, and preserves the currently selected
+ -- entry.
+ vim.fn.setqflist({}, _qf_id and 'u' or ' ', {
+ title = title,
+ items = items,
+ id = _qf_id,
+ })
+
+ -- Get the id of the newly created quickfix list.
+ if _qf_id == nil then
+ _qf_id = vim.fn.getqflist({ id = 0 }).id
+ end
end
if open then
api.nvim_command(loclist and 'lwindow' or 'botright cwindow')
@@ -1081,7 +1093,7 @@ function M.set(namespace, bufnr, diagnostics, opts)
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
vim.validate('opts', opts, 'table', true)
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
if vim.tbl_isempty(diagnostics) then
diagnostic_cache[bufnr][namespace] = nil
@@ -1361,7 +1373,7 @@ M.handlers.signs = {
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
vim.validate('opts', opts, 'table', true)
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
opts = opts or {}
if not api.nvim_buf_is_loaded(bufnr) then
@@ -1467,7 +1479,7 @@ M.handlers.underline = {
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
vim.validate('opts', opts, 'table', true)
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
opts = opts or {}
if not vim.api.nvim_buf_is_loaded(bufnr) then
@@ -1531,7 +1543,7 @@ M.handlers.virtual_text = {
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
vim.validate('opts', opts, 'table', true)
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
opts = opts or {}
if not vim.api.nvim_buf_is_loaded(bufnr) then
@@ -1656,7 +1668,7 @@ function M.hide(namespace, bufnr)
vim.validate('namespace', namespace, 'number', true)
vim.validate('bufnr', bufnr, 'number', true)
- local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
+ local buffers = bufnr and { vim._resolve_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
for _, iter_bufnr in ipairs(buffers) do
local namespaces = namespace and { namespace } or vim.tbl_keys(diagnostic_cache[iter_bufnr])
for _, iter_namespace in ipairs(namespaces) do
@@ -1683,7 +1695,7 @@ function M.is_enabled(filter)
return vim.tbl_isempty(diagnostic_disabled) and not diagnostic_disabled[1]
end
- local bufnr = get_bufnr(filter.bufnr)
+ local bufnr = vim._resolve_bufnr(filter.bufnr)
if type(diagnostic_disabled[bufnr]) == 'table' then
return not diagnostic_disabled[bufnr][filter.ns_id]
end
@@ -1724,7 +1736,7 @@ function M.show(namespace, bufnr, diagnostics, opts)
end
else
-- namespace is nil
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
for iter_namespace in pairs(diagnostic_cache[bufnr]) do
M.show(iter_namespace, bufnr, nil, opts)
end
@@ -1791,7 +1803,7 @@ function M.open_float(opts, ...)
end
opts = opts or {}
- bufnr = get_bufnr(bufnr or opts.bufnr)
+ bufnr = vim._resolve_bufnr(bufnr or opts.bufnr)
do
-- Resolve options with user settings from vim.diagnostic.config
@@ -1994,7 +2006,7 @@ function M.reset(namespace, bufnr)
vim.validate('namespace', namespace, 'number', true)
vim.validate('bufnr', bufnr, 'number', true)
- local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
+ local buffers = bufnr and { vim._resolve_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache)
for _, iter_bufnr in ipairs(buffers) do
local namespaces = namespace and { namespace } or vim.tbl_keys(diagnostic_cache[iter_bufnr])
for _, iter_namespace in ipairs(namespaces) do
@@ -2132,7 +2144,7 @@ function M.enable(enable, filter)
ns.disabled = not enable
end
else
- bufnr = get_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
if not ns_id then
diagnostic_disabled[bufnr] = (not enable) and true or nil
else
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index aa566973b6..b983e7d1c6 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -958,11 +958,14 @@ local extension = {
ps1xml = 'ps1xml',
psf = 'psf',
psl = 'psl',
+ ptx = 'ptx',
pug = 'pug',
purs = 'purescript',
arr = 'pyret',
pxd = 'pyrex',
+ pxi = 'pyrex',
pyx = 'pyrex',
+ ['pyx+'] = 'pyrex',
pyw = 'python',
py = 'python',
pyi = 'python',
@@ -1871,6 +1874,8 @@ local filename = {
['.clang-tidy'] = 'yaml',
['yarn.lock'] = 'yaml',
matplotlibrc = 'yaml',
+ ['.condarc'] = 'yaml',
+ condarc = 'yaml',
zathurarc = 'zathurarc',
['/etc/zprofile'] = 'zsh',
['.zlogin'] = 'zsh',
diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua
index 71d0188128..c7158673fe 100644
--- a/runtime/lua/vim/loader.lua
+++ b/runtime/lua/vim/loader.lua
@@ -446,6 +446,12 @@ function M.enable(enable)
end
end
+--- @deprecated
+function M.disable()
+ vim.deprecate('vim.loader.disable', 'vim.loader.enable(false)', '0.12')
+ vim.loader.enable(false)
+end
+
--- Tracks the time spent in a function
--- @generic F: function
--- @param f F
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 6d29c9e4df..ebdc050405 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -3,6 +3,7 @@ local validate = vim.validate
local lsp = vim._defer_require('vim.lsp', {
_changetracking = ..., --- @module 'vim.lsp._changetracking'
+ _folding_range = ..., --- @module 'vim.lsp._folding_range'
_snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar'
_tagfunc = ..., --- @module 'vim.lsp._tagfunc'
_watchfiles = ..., --- @module 'vim.lsp._watchfiles'
@@ -57,6 +58,7 @@ lsp._request_name_to_capability = {
[ms.textDocument_documentHighlight] = { 'documentHighlightProvider' },
[ms.textDocument_documentLink] = { 'documentLinkProvider' },
[ms.textDocument_documentSymbol] = { 'documentSymbolProvider' },
+ [ms.textDocument_foldingRange] = { 'foldingRangeProvider' },
[ms.textDocument_formatting] = { 'documentFormattingProvider' },
[ms.textDocument_hover] = { 'hoverProvider' },
[ms.textDocument_implementation] = { 'implementationProvider' },
@@ -87,18 +89,6 @@ lsp._request_name_to_capability = {
-- TODO improve handling of scratch buffers with LSP attached.
---- Returns the buffer number for the given {bufnr}.
----
----@param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer
----@return integer bufnr
-local function resolve_bufnr(bufnr)
- validate('bufnr', bufnr, 'number', true)
- if bufnr == nil or bufnr == 0 then
- return api.nvim_get_current_buf()
- end
- return bufnr
-end
-
---@private
--- Called by the client when trying to call a method that's not
--- supported in any of the servers registered for the current buffer.
@@ -112,6 +102,22 @@ function lsp._unsupported_method(method)
return msg
end
+---@private
+---@param workspace_folders string|lsp.WorkspaceFolder[]?
+---@return lsp.WorkspaceFolder[]?
+function lsp._get_workspace_folders(workspace_folders)
+ if type(workspace_folders) == 'table' then
+ return workspace_folders
+ elseif type(workspace_folders) == 'string' then
+ return {
+ {
+ uri = vim.uri_from_fname(workspace_folders),
+ name = workspace_folders,
+ },
+ }
+ end
+end
+
local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' }
local format_line_ending = {
@@ -194,32 +200,138 @@ local function reuse_client_default(client, config)
return false
end
- if config.root_dir then
- local root = vim.uri_from_fname(config.root_dir)
- for _, dir in ipairs(client.workspace_folders or {}) do
- -- note: do not need to check client.root_dir since that should be client.workspace_folders[1]
- if root == dir.uri then
- return true
+ local config_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir)
+ or {}
+ local config_folders_included = 0
+
+ if not next(config_folders) then
+ return false
+ end
+
+ for _, config_folder in ipairs(config_folders) do
+ for _, client_folder in ipairs(client.workspace_folders) do
+ if config_folder.uri == client_folder.uri then
+ config_folders_included = config_folders_included + 1
+ break
end
end
end
- -- TODO(lewis6991): also check config.workspace_folders
+ return config_folders_included == #config_folders
+end
- return false
+--- Reset defaults set by `set_defaults`.
+--- Must only be called if the last client attached to a buffer exits.
+local function reset_defaults(bufnr)
+ if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
+ vim.bo[bufnr].tagfunc = nil
+ end
+ if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
+ vim.bo[bufnr].omnifunc = nil
+ end
+ if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
+ vim.bo[bufnr].formatexpr = nil
+ end
+ vim._with({ buf = bufnr }, function()
+ local keymap = vim.fn.maparg('K', 'n', false, true)
+ if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
+ vim.keymap.del('n', 'K', { buffer = bufnr })
+ end
+ end)
+end
+
+--- @param code integer
+--- @param signal integer
+--- @param client_id integer
+local function on_client_exit(code, signal, client_id)
+ local client = all_clients[client_id]
+
+ vim.schedule(function()
+ for bufnr in pairs(client.attached_buffers) do
+ if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
+ api.nvim_exec_autocmds('LspDetach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = client_id },
+ })
+ end
+
+ client.attached_buffers[bufnr] = nil
+
+ if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
+ reset_defaults(bufnr)
+ end
+ end
+
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ vim.diagnostic.reset(namespace)
+ end)
+
+ local name = client.name or 'unknown'
+
+ -- Schedule the deletion of the client object so that it exists in the execution of LspDetach
+ -- autocommands
+ vim.schedule(function()
+ all_clients[client_id] = nil
+
+ -- Client can be absent if executable starts, but initialize fails
+ -- init/attach won't have happened
+ if client then
+ changetracking.reset(client)
+ end
+ if code ~= 0 or (signal ~= 0 and signal ~= 15) then
+ local msg = string.format(
+ 'Client %s quit with exit code %s and signal %s. Check log for errors: %s',
+ name,
+ code,
+ signal,
+ lsp.get_log_path()
+ )
+ vim.notify(msg, vim.log.levels.WARN)
+ end
+ end)
+end
+
+--- Creates and initializes a client with the given configuration.
+--- @param config vim.lsp.ClientConfig Configuration for the server.
+--- @return integer? 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.
+--- @return string? # Error message, if any
+local function create_and_initialize_client(config)
+ local ok, res = pcall(require('vim.lsp.client').create, config)
+ if not ok then
+ return nil, res --[[@as string]]
+ end
+
+ local client = assert(res)
+
+ --- @diagnostic disable-next-line: invisible
+ table.insert(client._on_exit_cbs, on_client_exit)
+
+ all_clients[client.id] = client
+
+ client:initialize()
+
+ return client.id, nil
end
--- @class vim.lsp.start.Opts
--- @inlinedoc
---
--- Predicate used to decide if a client should be re-used. Used on all
---- running clients. The default implementation re-uses a client if name and
---- root_dir matches.
+--- running clients. The default implementation re-uses a client if it has the
+--- same name and if the given workspace folders (or root_dir) are all included
+--- in the client's workspace folders.
--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- Buffer handle to attach to if starting or re-using a client (0 for current).
--- @field bufnr? integer
---
+--- Whether to attach the client to a buffer (default true).
+--- If set to `false`, `reuse_client` and `bufnr` will be ignored.
+--- @field attach? boolean
+---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
@@ -237,10 +349,10 @@ end
--- })
--- ```
---
---- See |vim.lsp.start_client()| for all available options. The most important are:
+--- See |vim.lsp.ClientConfig| for all available options. The most important are:
---
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
---- - `cmd` command string[] or function, described at |vim.lsp.start_client()|.
+--- - `cmd` command string[] or function.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
--- should be re-used. The example above uses |vim.fs.root()| to detect the root by traversing
--- the file system upwards starting from the current directory until either a `pyproject.toml`
@@ -260,15 +372,19 @@ end
--- `ftplugin/<filetype_name>.lua` (See |ftplugin-name|)
---
--- @param config vim.lsp.ClientConfig Configuration for the server.
---- @param opts vim.lsp.start.Opts? Optional keyword arguments
+--- @param opts vim.lsp.start.Opts? Optional keyword arguments.
--- @return integer? client_id
function lsp.start(config, opts)
opts = opts or {}
local reuse_client = opts.reuse_client or reuse_client_default
- local bufnr = resolve_bufnr(opts.bufnr)
+ local bufnr = vim._resolve_bufnr(opts.bufnr)
for _, client in pairs(all_clients) do
if reuse_client(client, config) then
+ if opts.attach == false then
+ return client.id
+ end
+
if lsp.buf_attach_client(bufnr, client.id) then
return client.id
else
@@ -277,7 +393,7 @@ function lsp.start(config, opts)
end
end
- local client_id, err = lsp.start_client(config)
+ local client_id, err = create_and_initialize_client(config)
if err then
if not opts.silent then
vim.notify(err, vim.log.levels.WARN)
@@ -285,6 +401,10 @@ function lsp.start(config, opts)
return nil
end
+ if opts.attach == false then
+ return client_id
+ end
+
if client_id and lsp.buf_attach_client(bufnr, client_id) then
return client_id
end
@@ -381,78 +501,7 @@ function lsp._set_defaults(client, bufnr)
end
end
---- Reset defaults set by `set_defaults`.
---- Must only be called if the last client attached to a buffer exits.
-local function reset_defaults(bufnr)
- if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
- vim.bo[bufnr].tagfunc = nil
- end
- if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
- vim.bo[bufnr].omnifunc = nil
- end
- if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
- vim.bo[bufnr].formatexpr = nil
- end
- vim._with({ buf = bufnr }, function()
- local keymap = vim.fn.maparg('K', 'n', false, true)
- if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
- vim.keymap.del('n', 'K', { buffer = bufnr })
- end
- end)
-end
-
---- @param code integer
---- @param signal integer
---- @param client_id integer
-local function on_client_exit(code, signal, client_id)
- local client = all_clients[client_id]
-
- vim.schedule(function()
- for bufnr in pairs(client.attached_buffers) do
- if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
- api.nvim_exec_autocmds('LspDetach', {
- buffer = bufnr,
- modeline = false,
- data = { client_id = client_id },
- })
- end
-
- client.attached_buffers[bufnr] = nil
-
- if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
- reset_defaults(bufnr)
- end
- end
-
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
- vim.diagnostic.reset(namespace)
- end)
-
- local name = client.name or 'unknown'
-
- -- Schedule the deletion of the client object so that it exists in the execution of LspDetach
- -- autocommands
- vim.schedule(function()
- all_clients[client_id] = nil
-
- -- Client can be absent if executable starts, but initialize fails
- -- init/attach won't have happened
- if client then
- changetracking.reset(client)
- end
- if code ~= 0 or (signal ~= 0 and signal ~= 15) then
- local msg = string.format(
- 'Client %s quit with exit code %s and signal %s. Check log for errors: %s',
- name,
- code,
- signal,
- lsp.get_log_path()
- )
- vim.notify(msg, vim.log.levels.WARN)
- end
- end)
-end
-
+--- @deprecated
--- Starts and initializes a client with the given configuration.
--- @param config vim.lsp.ClientConfig Configuration for the server.
--- @return integer? client_id |vim.lsp.get_client_by_id()| Note: client may not be
@@ -460,27 +509,14 @@ end
--- the client has been initialized.
--- @return string? # Error message, if any
function lsp.start_client(config)
- local ok, res = pcall(require('vim.lsp.client').create, config)
- if not ok then
- return nil, res --[[@as string]]
- end
-
- local client = assert(res)
-
- --- @diagnostic disable-next-line: invisible
- table.insert(client._on_exit_cbs, on_client_exit)
-
- all_clients[client.id] = client
-
- client:initialize()
-
- return client.id, nil
+ vim.deprecate('vim.lsp.start_client()', 'vim.lsp.start()', '0.13')
+ return create_and_initialize_client(config)
end
---Buffer lifecycle handler for textDocument/didSave
--- @param bufnr integer
local function text_document_did_save_handler(bufnr)
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
local uri = vim.uri_from_bufnr(bufnr)
local text = once(lsp._buf_get_full_text)
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@@ -641,7 +677,7 @@ end
function lsp.buf_attach_client(bufnr, client_id)
validate('bufnr', bufnr, 'number', true)
validate('client_id', client_id, 'number')
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
return false
@@ -678,7 +714,7 @@ end
function lsp.buf_detach_client(bufnr, client_id)
validate('bufnr', bufnr, 'number', true)
validate('client_id', client_id, 'number')
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
local client = all_clients[client_id]
if not client or not client.attached_buffers[bufnr] then
@@ -784,7 +820,7 @@ function lsp.get_clients(filter)
local clients = {} --- @type vim.lsp.Client[]
- local bufnr = filter.bufnr and resolve_bufnr(filter.bufnr)
+ local bufnr = filter.bufnr and vim._resolve_bufnr(filter.bufnr)
for _, client in pairs(all_clients) do
if
@@ -880,7 +916,7 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
validate('handler', handler, 'function', true)
validate('on_unsupported', on_unsupported, 'function', true)
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
local method_supported = false
local clients = lsp.get_clients({ bufnr = bufnr })
local client_request_ids = {} --- @type table<integer,integer>
@@ -1094,6 +1130,54 @@ function lsp.tagfunc(pattern, flags)
return vim.lsp._tagfunc(pattern, flags)
end
+--- Provides an interface between the built-in client and a `foldexpr` function.
+---
+--- To use, check for the "textDocument/foldingRange" capability in an
+--- |LspAttach| autocommand. Example:
+---
+--- ```lua
+--- vim.api.nvim_create_autocommand('LspAttach', {
+--- callback = function(args)
+--- local client = vim.lsp.get_client_by_id(args.data.client_id)
+--- if client:supports_method('textDocument/foldingRange') then
+--- vim.wo.foldmethod = 'expr'
+--- vim.wo.foldexpr = 'v:lua.vim.lsp.foldexpr()'
+--- end
+--- end,
+--- })
+--- ```
+---
+---@param lnum integer line number
+function lsp.foldexpr(lnum)
+ return vim.lsp._folding_range.foldexpr(lnum)
+end
+
+--- Close all {kind} of folds in the the window with {winid}.
+---
+--- To automatically fold imports when opening a file, you can use an autocmd:
+---
+--- ```lua
+--- vim.api.nvim_create_autocmd('LspNotify', {
+--- callback = function(args)
+--- if args.data.method == 'textDocument/didOpen' then
+--- vim.lsp.foldclose('imports', vim.fn.bufwinid(args.buf))
+--- end
+--- end,
+--- })
+--- ```
+---
+---@param kind lsp.FoldingRangeKind Kind to close, one of "comment", "imports" or "region".
+---@param winid? integer Defaults to the current window.
+function lsp.foldclose(kind, winid)
+ return vim.lsp._folding_range.foldclose(kind, winid)
+end
+
+--- Provides a `foldtext` function that shows the `collapsedText` retrieved,
+--- defaults to the first folded line if `collapsedText` is not provided.
+function lsp.foldtext()
+ return vim.lsp._folding_range.foldtext()
+end
+
---Checks whether a client is stopped.
---
---@param client_id (integer)
@@ -1112,7 +1196,7 @@ end
function lsp.buf_get_clients(bufnr)
vim.deprecate('vim.lsp.buf_get_clients()', 'vim.lsp.get_clients()', '0.12')
local result = {} --- @type table<integer,vim.lsp.Client>
- for _, client in ipairs(lsp.get_clients({ bufnr = resolve_bufnr(bufnr) })) do
+ for _, client in ipairs(lsp.get_clients({ bufnr = vim._resolve_bufnr(bufnr) })) do
result[client.id] = client
end
return result
@@ -1166,7 +1250,7 @@ function lsp.for_each_buffer_client(bufnr, fn)
'lsp.get_clients({ bufnr = bufnr }) with regular loop',
'0.12'
)
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
fn(client, client.id, bufnr)
@@ -1183,44 +1267,6 @@ function lsp.with(handler, override_config)
end
end
---- Helper function to use when implementing a handler.
---- This will check that all of the keys in the user configuration
---- are valid keys and make sense to include for this handler.
----
---- Will error on invalid keys (i.e. keys that do not exist in the options)
---- @param name string
---- @param options table<string,any>
---- @param user_config table<string,any>
-function lsp._with_extend(name, options, user_config)
- user_config = user_config or {}
-
- local resulting_config = {} --- @type table<string,any>
- for k, v in pairs(user_config) do
- if options[k] == nil then
- error(
- debug.traceback(
- string.format(
- 'Invalid option for `%s`: %s. Valid options are:\n%s',
- name,
- k,
- vim.inspect(vim.tbl_keys(options))
- )
- )
- )
- end
-
- resulting_config[k] = v
- end
-
- for k, v in pairs(options) do
- if resulting_config[k] == nil then
- resulting_config[k] = v
- end
- end
-
- return resulting_config
-end
-
--- Registry for client side commands.
--- This is an extension point for plugins to handle custom commands which are
--- not part of the core language server protocol specification.
diff --git a/runtime/lua/vim/lsp/_folding_range.lua b/runtime/lua/vim/lsp/_folding_range.lua
new file mode 100644
index 0000000000..2f1767aaf5
--- /dev/null
+++ b/runtime/lua/vim/lsp/_folding_range.lua
@@ -0,0 +1,373 @@
+local util = require('vim.lsp.util')
+local log = require('vim.lsp.log')
+local ms = require('vim.lsp.protocol').Methods
+local api = vim.api
+
+local M = {}
+
+---@class (private) vim.lsp.folding_range.BufState
+---
+---@field version? integer
+---
+--- Never use this directly, `renew()` the cached foldinfo
+--- then use on demand via `row_*` fields.
+---
+--- Index In the form of client_id -> ranges
+---@field client_ranges table<integer, lsp.FoldingRange[]?>
+---
+--- Index in the form of row -> [foldlevel, mark]
+---@field row_level table<integer, [integer, ">" | "<"?]?>
+---
+--- Index in the form of start_row -> kinds
+---@field row_kinds table<integer, table<lsp.FoldingRangeKind, true?>?>>
+---
+--- Index in the form of start_row -> collapsed_text
+---@field row_text table<integer, string?>
+
+---@type table<integer, vim.lsp.folding_range.BufState?>
+local bufstates = {}
+
+--- Renew the cached foldinfo in the buffer.
+---@param bufnr integer
+local function renew(bufnr)
+ local bufstate = assert(bufstates[bufnr])
+
+ ---@type table<integer, [integer, ">" | "<"?]?>
+ local row_level = {}
+ ---@type table<integer, table<lsp.FoldingRangeKind, true?>?>>
+ local row_kinds = {}
+ ---@type table<integer, string?>
+ local row_text = {}
+
+ for _, ranges in pairs(bufstate.client_ranges) do
+ for _, range in ipairs(ranges) do
+ local start_row = range.startLine
+ local end_row = range.endLine
+ -- Adding folds within a single line is not supported by Nvim.
+ if start_row ~= end_row then
+ row_text[start_row] = range.collapsedText
+
+ local kind = range.kind
+ if kind then
+ local kinds = row_kinds[start_row] or {}
+ kinds[kind] = true
+ row_kinds[start_row] = kinds
+ end
+
+ for row = start_row, end_row do
+ local level = row_level[row] or { 0 }
+ level[1] = level[1] + 1
+ row_level[row] = level
+ end
+ row_level[start_row][2] = '>'
+ row_level[end_row][2] = '<'
+ end
+ end
+ end
+
+ bufstate.row_level = row_level
+ bufstate.row_kinds = row_kinds
+ bufstate.row_text = row_text
+end
+
+--- Renew the cached foldinfo then force `foldexpr()` to be re-evaluated,
+--- without opening folds.
+---@param bufnr integer
+local function foldupdate(bufnr)
+ renew(bufnr)
+ for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
+ local wininfo = vim.fn.getwininfo(winid)[1]
+ if wininfo and wininfo.tabnr == vim.fn.tabpagenr() then
+ if vim.wo[winid].foldmethod == 'expr' then
+ vim._foldupdate(winid, 0, api.nvim_buf_line_count(bufnr))
+ end
+ end
+ end
+end
+
+--- Whether `foldupdate()` is scheduled for the buffer with `bufnr`.
+---
+--- Index in the form of bufnr -> true?
+---@type table<integer, true?>
+local scheduled_foldupdate = {}
+
+--- Schedule `foldupdate()` after leaving insert mode.
+---@param bufnr integer
+local function schedule_foldupdate(bufnr)
+ if not scheduled_foldupdate[bufnr] then
+ scheduled_foldupdate[bufnr] = true
+ api.nvim_create_autocmd('InsertLeave', {
+ buffer = bufnr,
+ once = true,
+ callback = function()
+ foldupdate(bufnr)
+ scheduled_foldupdate[bufnr] = nil
+ end,
+ })
+ end
+end
+
+---@param results table<integer,{err: lsp.ResponseError?, result: lsp.FoldingRange[]?}>
+---@type lsp.MultiHandler
+local function multi_handler(results, ctx)
+ local bufnr = assert(ctx.bufnr)
+ -- Handling responses from outdated buffer only causes performance overhead.
+ if util.buf_versions[bufnr] ~= ctx.version then
+ return
+ end
+
+ local bufstate = assert(bufstates[bufnr])
+ for client_id, result in pairs(results) do
+ if result.err then
+ log.error(result.err)
+ else
+ bufstate.client_ranges[client_id] = result.result
+ end
+ end
+ bufstate.version = ctx.version
+
+ if api.nvim_get_mode().mode:match('^i') then
+ -- `foldUpdate()` is guarded in insert mode.
+ schedule_foldupdate(bufnr)
+ else
+ foldupdate(bufnr)
+ end
+end
+
+---@param result lsp.FoldingRange[]?
+---@type lsp.Handler
+local function handler(err, result, ctx)
+ multi_handler({ [ctx.client_id] = { err = err, result = result } }, ctx)
+end
+
+--- Request `textDocument/foldingRange` from the server.
+--- `foldupdate()` is scheduled once after the request is completed.
+---@param bufnr integer
+---@param client? vim.lsp.Client The client whose server supports `foldingRange`.
+local function request(bufnr, client)
+ ---@type lsp.FoldingRangeParams
+ local params = { textDocument = util.make_text_document_params(bufnr) }
+
+ if client then
+ client:request(ms.textDocument_foldingRange, params, handler, bufnr)
+ return
+ end
+
+ if not next(vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_foldingRange })) then
+ return
+ end
+
+ vim.lsp.buf_request_all(bufnr, ms.textDocument_foldingRange, params, multi_handler)
+end
+
+-- NOTE:
+-- `bufstate` and event hooks are interdependent:
+-- * `bufstate` needs event hooks for correctness.
+-- * event hooks require the previous `bufstate` for updates.
+-- Since they are manually created and destroyed,
+-- we ensure their lifecycles are always synchronized.
+--
+-- TODO(ofseed):
+-- 1. Implement clearing `bufstate` and event hooks
+-- when no clients in the buffer support the corresponding method.
+-- 2. Then generalize this state management to other LSP modules.
+local augroup_setup = api.nvim_create_augroup('vim_lsp_folding_range/setup', {})
+
+--- Initialize `bufstate` and event hooks, then request folding ranges.
+--- Manage their lifecycle within this function.
+---@param bufnr integer
+---@return vim.lsp.folding_range.BufState?
+local function setup(bufnr)
+ if not api.nvim_buf_is_loaded(bufnr) then
+ return
+ end
+
+ -- Register the new `bufstate`.
+ bufstates[bufnr] = {
+ client_ranges = {},
+ row_level = {},
+ row_kinds = {},
+ row_text = {},
+ }
+
+ -- Event hooks from `buf_attach` can't be removed externally.
+ -- Hooks and `bufstate` share the same lifecycle;
+ -- they should self-destroy if `bufstate == nil`.
+ api.nvim_buf_attach(bufnr, false, {
+ -- `on_detach` also runs on buffer reload (`:e`).
+ -- Ensure `bufstate` and hooks are cleared to avoid duplication or leftover states.
+ on_detach = function()
+ bufstates[bufnr] = nil
+ api.nvim_clear_autocmds({ buffer = bufnr, group = augroup_setup })
+ end,
+ -- Reset `bufstate` and request folding ranges.
+ on_reload = function()
+ bufstates[bufnr] = {
+ client_ranges = {},
+ row_level = {},
+ row_kinds = {},
+ row_text = {},
+ }
+ request(bufnr)
+ end,
+ --- Sync changed rows with their previous foldlevels before applying new ones.
+ on_bytes = function(_, _, _, start_row, _, _, old_row, _, _, new_row, _, _)
+ if bufstates[bufnr] == nil then
+ return true
+ end
+ local row_level = bufstates[bufnr].row_level
+ if next(row_level) == nil then
+ return
+ end
+ local row = new_row - old_row
+ if row > 0 then
+ vim._list_insert(row_level, start_row, start_row + math.abs(row) - 1, { -1 })
+ -- If the previous row ends a fold,
+ -- Nvim treats the first row after consecutive `-1`s as a new fold start,
+ -- which is not the desired behavior.
+ local prev_level = row_level[start_row - 1]
+ if prev_level and prev_level[2] == '<' then
+ row_level[start_row] = { prev_level[1] - 1 }
+ end
+ elseif row < 0 then
+ vim._list_remove(row_level, start_row, start_row + math.abs(row) - 1)
+ end
+ end,
+ })
+ api.nvim_create_autocmd('LspDetach', {
+ group = augroup_setup,
+ buffer = bufnr,
+ callback = function(args)
+ if not api.nvim_buf_is_loaded(bufnr) then
+ return
+ end
+
+ ---@type integer
+ local client_id = args.data.client_id
+ bufstates[bufnr].client_ranges[client_id] = nil
+
+ ---@type vim.lsp.Client[]
+ local clients = vim
+ .iter(vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_foldingRange }))
+ ---@param client vim.lsp.Client
+ :filter(function(client)
+ return client.id ~= client_id
+ end)
+ :totable()
+ if #clients == 0 then
+ bufstates[bufnr] = {
+ client_ranges = {},
+ row_level = {},
+ row_kinds = {},
+ row_text = {},
+ }
+ end
+
+ foldupdate(bufnr)
+ end,
+ })
+ api.nvim_create_autocmd('LspAttach', {
+ group = augroup_setup,
+ buffer = bufnr,
+ callback = function(args)
+ local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ if client:supports_method(vim.lsp.protocol.Methods.textDocument_foldingRange, bufnr) then
+ request(bufnr, client)
+ end
+ end,
+ })
+ api.nvim_create_autocmd('LspNotify', {
+ group = augroup_setup,
+ buffer = bufnr,
+ callback = function(args)
+ local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ if
+ client:supports_method(ms.textDocument_foldingRange, bufnr)
+ and (
+ args.data.method == ms.textDocument_didChange
+ or args.data.method == ms.textDocument_didOpen
+ )
+ then
+ request(bufnr, client)
+ end
+ end,
+ })
+
+ request(bufnr)
+
+ return bufstates[bufnr]
+end
+
+---@param kind lsp.FoldingRangeKind
+---@param winid integer
+local function foldclose(kind, winid)
+ vim._with({ win = winid }, function()
+ local bufnr = api.nvim_win_get_buf(winid)
+ local row_kinds = bufstates[bufnr].row_kinds
+ -- Reverse traverse to ensure that the smallest ranges are closed first.
+ for row = api.nvim_buf_line_count(bufnr) - 1, 0, -1 do
+ local kinds = row_kinds[row]
+ if kinds and kinds[kind] then
+ vim.cmd(row + 1 .. 'foldclose')
+ end
+ end
+ end)
+end
+
+---@param kind lsp.FoldingRangeKind
+---@param winid? integer
+function M.foldclose(kind, winid)
+ vim.validate('kind', kind, 'string')
+ vim.validate('winid', winid, 'number', true)
+
+ winid = winid or api.nvim_get_current_win()
+ local bufnr = api.nvim_win_get_buf(winid)
+ local bufstate = bufstates[bufnr]
+ if not bufstate then
+ return
+ end
+
+ if bufstate.version == util.buf_versions[bufnr] then
+ foldclose(kind, winid)
+ return
+ end
+ -- Schedule `foldclose()` if the buffer is not up-to-date.
+
+ if not next(vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_foldingRange })) then
+ return
+ end
+ ---@type lsp.FoldingRangeParams
+ local params = { textDocument = util.make_text_document_params(bufnr) }
+ vim.lsp.buf_request_all(bufnr, ms.textDocument_foldingRange, params, function(...)
+ multi_handler(...)
+ foldclose(kind, winid)
+ end)
+end
+
+---@return string
+function M.foldtext()
+ local bufnr = api.nvim_get_current_buf()
+ local lnum = vim.v.foldstart
+ local row = lnum - 1
+ local bufstate = bufstates[bufnr]
+ if bufstate and bufstate.row_text[row] then
+ return bufstate.row_text[row]
+ end
+ return vim.fn.getline(lnum)
+end
+
+---@param lnum? integer
+---@return string level
+function M.foldexpr(lnum)
+ local bufnr = api.nvim_get_current_buf()
+ local bufstate = bufstates[bufnr] or setup(bufnr)
+ if not bufstate then
+ return '0'
+ end
+
+ local row = (lnum or vim.v.lnum) - 1
+ local level = bufstate.row_level[row]
+ return level and (level[2] or '') .. (level[1] or '0') or '0'
+end
+
+return M
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 10479807a2..1926a0228d 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -519,7 +519,7 @@ end
--- @param opts? vim.lsp.buf.format.Opts
function M.format(opts)
opts = opts or {}
- local bufnr = opts.bufnr or api.nvim_get_current_buf()
+ local bufnr = vim._resolve_bufnr(opts.bufnr)
local mode = api.nvim_get_mode().mode
local range = opts.range
-- Try to use visual selection if no range is given
@@ -617,7 +617,7 @@ end
---@param opts? vim.lsp.buf.rename.Opts Additional options:
function M.rename(new_name, opts)
opts = opts or {}
- local bufnr = opts.bufnr or api.nvim_get_current_buf()
+ local bufnr = vim._resolve_bufnr(opts.bufnr)
local clients = lsp.get_clients({
bufnr = bufnr,
name = opts.name,
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index a14b6ccda6..5eefe4600e 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -75,17 +75,17 @@ local validate = vim.validate
---
--- Map with language server specific settings.
--- See the {settings} in |vim.lsp.Client|.
---- @field settings? table
+--- @field settings? lsp.LSPObject
---
--- Table that maps string of clientside commands to user-defined functions.
---- Commands passed to start_client take precedence over the global command registry. Each key
+--- Commands passed to `start()` take precedence over the global command registry. Each key
--- must be a unique command name, and the value is a function which is called if any LSP action
--- (code action, code lenses, ...) triggers the command.
--- @field commands? table<string,fun(command: lsp.Command, ctx: table)>
---
--- Values to pass in the initialization request as `initializationOptions`. See `initialize` in
--- the LSP spec.
---- @field init_options? table
+--- @field init_options? lsp.LSPObject
---
--- Name in log messages.
--- (default: client-id)
@@ -104,7 +104,7 @@ local validate = vim.validate
--- @field on_error? fun(code: integer, err: string)
---
--- Callback 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 |vim.lsp.start_client()|.
+--- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
--- You can use this to modify parameters before they are sent.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
@@ -164,10 +164,10 @@ local validate = vim.validate
--- for an active request, or "cancel" for a cancel request. It will be
--- "complete" ephemerally while executing |LspRequest| autocmds when replies
--- are received from the server.
---- @field requests table<integer,{ type: string, bufnr: integer, method: string}>
+--- @field requests table<integer,{ type: string, bufnr: integer, method: string}?>
---
--- copy of the table that was passed by the user
---- to |vim.lsp.start_client()|.
+--- to |vim.lsp.start()|.
--- @field config vim.lsp.ClientConfig
---
--- Response from the server sent on `initialize` describing the server's
@@ -189,9 +189,6 @@ local validate = vim.validate
---
--- @field attached_buffers table<integer,true>
---
---- Buffers that should be attached to upon initialize()
---- @field package _buffers_to_attach table<integer,true>
----
--- @field private _log_prefix string
---
--- Track this so that we can escalate automatically if we've already tried a
@@ -210,7 +207,7 @@ local validate = vim.validate
--- Map with language server specific settings. These are returned to the
--- language server if requested via `workspace/configuration`. Keys are
--- case-sensitive.
---- @field settings table
+--- @field settings lsp.LSPObject
---
--- A table with flags for the client. The current (experimental) flags are:
--- @field flags vim.lsp.Client.Flags
@@ -265,9 +262,6 @@ local valid_encodings = {
['utf8'] = 'utf-8',
['utf16'] = 'utf-16',
['utf32'] = 'utf-32',
- UTF8 = 'utf-8',
- UTF16 = 'utf-16',
- UTF32 = 'utf-32',
}
--- Normalizes {encoding} to valid LSP encoding names.
@@ -276,7 +270,7 @@ local valid_encodings = {
local function validate_encoding(encoding)
validate('encoding', encoding, 'string', true)
if not encoding then
- return valid_encodings.UTF16
+ return valid_encodings.utf16
end
return valid_encodings[encoding:lower()]
or error(
@@ -307,7 +301,7 @@ local function default_get_language_id(_bufnr, filetype)
return filetype
end
---- Validates a client configuration as given to |vim.lsp.start_client()|.
+--- Validates a client configuration as given to |vim.lsp.start()|.
--- @param config vim.lsp.ClientConfig
local function validate_config(config)
validate('config', config, 'table')
@@ -365,21 +359,6 @@ local function get_name(id, config)
return tostring(id)
end
---- @param workspace_folders string|lsp.WorkspaceFolder[]?
---- @return lsp.WorkspaceFolder[]?
-local function get_workspace_folders(workspace_folders)
- if type(workspace_folders) == 'table' then
- return workspace_folders
- elseif type(workspace_folders) == 'string' then
- return {
- {
- uri = vim.uri_from_fname(workspace_folders),
- name = workspace_folders,
- },
- }
- end
-end
-
--- @generic T
--- @param x elem_or_list<T>?
--- @return T[]
@@ -417,7 +396,7 @@ function Client.create(config)
flags = config.flags or {},
get_language_id = config.get_language_id or default_get_language_id,
capabilities = config.capabilities or lsp.protocol.make_client_capabilities(),
- workspace_folders = get_workspace_folders(config.workspace_folders or config.root_dir),
+ workspace_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir),
root_dir = config.root_dir,
_before_init_cb = config.before_init,
_on_init_cbs = ensure_list(config.on_init),
@@ -619,16 +598,55 @@ function Client:_resolve_handler(method)
return self.handlers[method] or lsp.handlers[method]
end
---- Returns the buffer number for the given {bufnr}.
----
---- @param bufnr integer? Buffer number to resolve. Defaults to current buffer
---- @return integer bufnr
-local function resolve_bufnr(bufnr)
- validate('bufnr', bufnr, 'number', true)
- if bufnr == nil or bufnr == 0 then
- return api.nvim_get_current_buf()
+--- @private
+--- @param id integer
+--- @param req_type 'pending'|'complete'|'cancel'|
+--- @param bufnr? integer (only required for req_type='pending')
+--- @param method? string (only required for req_type='pending')
+function Client:_process_request(id, req_type, bufnr, method)
+ local pending = req_type == 'pending'
+
+ validate('id', id, 'number')
+ if pending then
+ validate('bufnr', bufnr, 'number')
+ validate('method', method, 'string')
+ end
+
+ local cur_request = self.requests[id]
+
+ if pending and cur_request then
+ log.error(
+ self._log_prefix,
+ ('Cannot create request with id %d as one already exists'):format(id)
+ )
+ return
+ elseif not pending and not cur_request then
+ log.error(
+ self._log_prefix,
+ ('Cannot find request with id %d whilst attempting to %s'):format(id, req_type)
+ )
+ return
+ end
+
+ if cur_request then
+ bufnr = cur_request.bufnr
+ method = cur_request.method
end
- return bufnr
+
+ assert(bufnr and method)
+
+ local request = { type = req_type, bufnr = bufnr, method = method }
+
+ -- Clear 'complete' requests
+ -- Note 'pending' and 'cancelled' requests are cleared when the server sends a response
+ -- which is processed via the notify_reply_callback argument to rpc.request.
+ self.requests[id] = req_type ~= 'complete' and request or nil
+
+ api.nvim_exec_autocmds('LspRequest', {
+ buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil,
+ modeline = false,
+ data = { client_id = self.id, request_id = id, request = request },
+ })
end
--- Sends a request to the server.
@@ -655,37 +673,24 @@ function Client:request(method, params, handler, bufnr)
end
-- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state
changetracking.flush(self, bufnr)
- bufnr = resolve_bufnr(bufnr)
+ bufnr = vim._resolve_bufnr(bufnr)
local version = lsp.util.buf_versions[bufnr]
log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
local success, request_id = self.rpc.request(method, params, function(err, result)
- local context = {
+ handler(err, result, {
method = method,
client_id = self.id,
bufnr = bufnr,
params = params,
version = version,
- }
- handler(err, result, context)
- end, function(request_id)
- local request = self.requests[request_id]
- request.type = 'complete'
- api.nvim_exec_autocmds('LspRequest', {
- buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil,
- modeline = false,
- data = { client_id = self.id, request_id = request_id, request = request },
})
- self.requests[request_id] = nil
+ end, function(request_id)
+ -- Called when the server sends a response to the request (including cancelled acknowledgment).
+ self:_process_request(request_id, 'complete')
end)
if success and request_id then
- local request = { type = 'pending', bufnr = bufnr, method = method }
- self.requests[request_id] = request
- api.nvim_exec_autocmds('LspRequest', {
- buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil,
- modeline = false,
- data = { client_id = self.id, request_id = request_id, request = request },
- })
+ self:_process_request(request_id, 'pending', bufnr, method)
end
return success, request_id
@@ -783,16 +788,7 @@ end
--- @return boolean status indicating if the notification was successful.
--- @see |Client:notify()|
function Client:cancel_request(id)
- validate('id', id, 'number')
- local request = self.requests[id]
- if request and request.type == 'pending' then
- request.type = 'cancel'
- api.nvim_exec_autocmds('LspRequest', {
- buffer = api.nvim_buf_is_valid(request.bufnr) and request.bufnr or nil,
- modeline = false,
- data = { client_id = self.id, request_id = id, request = request },
- })
- end
+ self:_process_request(id, 'cancel')
return self.rpc.notify(ms.dollar_cancelRequest, { id = id })
end
@@ -906,7 +902,7 @@ end
--- @param bufnr? integer
--- @return lsp.Registration?
function Client:_get_registration(method, bufnr)
- bufnr = bufnr or vim.api.nvim_get_current_buf()
+ bufnr = vim._resolve_bufnr(bufnr)
for _, reg in ipairs(self.registrations[method] or {}) do
if not reg.registerOptions or not reg.registerOptions.documentSelector then
return reg
@@ -943,7 +939,7 @@ end
--- @param handler? lsp.Handler only called if a server command
function Client:exec_cmd(command, context, handler)
context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]]
- context.bufnr = context.bufnr or api.nvim_get_current_buf()
+ context.bufnr = vim._resolve_bufnr(context.bufnr)
context.client_id = self.id
local cmdname = command.command
local fn = self.commands[cmdname] or lsp.commands[cmdname]
@@ -1174,7 +1170,7 @@ function Client:_add_workspace_folder(dir)
end
end
- local wf = assert(get_workspace_folders(dir))
+ local wf = assert(lsp._get_workspace_folders(dir))
self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = wf, removed = {} },
@@ -1189,7 +1185,7 @@ end
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
- local wf = assert(get_workspace_folders(dir))
+ local wf = assert(lsp._get_workspace_folders(dir))
self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = {}, removed = wf },
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index a11f84d6c6..3ccd165d0b 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -104,16 +104,12 @@ function M.run()
end
end
-local function resolve_bufnr(bufnr)
- return bufnr == 0 and api.nvim_get_current_buf() or bufnr
-end
-
--- Clear the lenses
---
---@param client_id integer|nil filter by client_id. All clients if nil
---@param bufnr integer|nil filter by buffer. All buffers if nil, 0 for current buffer
function M.clear(client_id, bufnr)
- bufnr = bufnr and resolve_bufnr(bufnr)
+ bufnr = bufnr and vim._resolve_bufnr(bufnr)
local buffers = bufnr and { bufnr }
or vim.tbl_filter(api.nvim_buf_is_loaded, api.nvim_list_bufs())
for _, iter_bufnr in pairs(buffers) do
@@ -296,7 +292,7 @@ end
--- @param opts? vim.lsp.codelens.refresh.Opts Optional fields
function M.refresh(opts)
opts = opts or {}
- local bufnr = opts.bufnr and resolve_bufnr(opts.bufnr)
+ local bufnr = opts.bufnr and vim._resolve_bufnr(opts.bufnr)
local buffers = bufnr and { bufnr }
or vim.tbl_filter(api.nvim_buf_is_loaded, api.nvim_list_bufs())
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index 1e950f625e..dbf0a62eeb 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -716,7 +716,7 @@ end
--- @param bufnr integer Buffer handle, or 0 for the current buffer
--- @param opts? vim.lsp.completion.BufferOpts
function M.enable(enable, client_id, bufnr, opts)
- bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr
+ bufnr = vim._resolve_bufnr(bufnr)
if enable then
enable_completions(client_id, bufnr, opts or {})
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 3f135d84f3..9a879d9f38 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -356,9 +356,7 @@ end
---@param bufnr (integer) Buffer handle, or 0 for current
---@private
function M._enable(bufnr)
- if bufnr == nil or bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
if not bufstates[bufnr] then
bufstates[bufnr] = { enabled = true }
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index f1a58de621..50cf9f5f29 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -149,8 +149,8 @@ function M.get(filter)
vim.list_extend(hints, M.get(vim.tbl_extend('keep', { bufnr = buf }, filter)))
end, vim.api.nvim_list_bufs())
return hints
- elseif bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
+ else
+ bufnr = vim._resolve_bufnr(bufnr)
end
local bufstate = bufstates[bufnr]
@@ -203,9 +203,7 @@ end
--- Clear inlay hints
---@param bufnr (integer) Buffer handle, or 0 for current
local function clear(bufnr)
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local bufstate = bufstates[bufnr]
local client_lens = (bufstate or {}).client_hints or {}
local client_ids = vim.tbl_keys(client_lens) --- @type integer[]
@@ -221,9 +219,7 @@ end
--- Disable inlay hints for a buffer
---@param bufnr (integer) Buffer handle, or 0 for current
local function _disable(bufnr)
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
clear(bufnr)
bufstates[bufnr] = nil
bufstates[bufnr].enabled = false
@@ -242,9 +238,7 @@ end
--- Enable inlay hints for a buffer
---@param bufnr (integer) Buffer handle, or 0 for current
local function _enable(bufnr)
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
bufstates[bufnr] = nil
bufstates[bufnr].enabled = true
_refresh(bufnr)
@@ -371,13 +365,10 @@ function M.is_enabled(filter)
filter = filter or {}
local bufnr = filter.bufnr
- vim.validate('bufnr', bufnr, 'number', true)
if bufnr == nil then
return globalstate.enabled
- elseif bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
end
- return bufstates[bufnr].enabled
+ return bufstates[vim._resolve_bufnr(bufnr)].enabled
end
--- Optional filters |kwargs|, or `nil` for all.
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 3d29dad90a..cfd47d8f7c 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -440,6 +440,13 @@ function protocol.make_client_capabilities()
properties = { 'command' },
},
},
+ foldingRange = {
+ dynamicRegistration = false,
+ lineFoldingOnly = true,
+ foldingRange = {
+ collapsedText = true,
+ },
+ },
formatting = {
dynamicRegistration = true,
},
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 6c8564845f..2327a37ab1 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -617,7 +617,7 @@ end
--- - a host and port via TCP
---
--- Return a function that can be passed to the `cmd` field for
---- |vim.lsp.start_client()| or |vim.lsp.start()|.
+--- |vim.lsp.start()|.
---
---@param host_or_path string host to connect to or path to a pipe/domain socket
---@param port integer? TCP port to connect to. If absent the first argument must be a pipe
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index 01421fea29..7cc3f95aed 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -600,9 +600,7 @@ function M.start(bufnr, client_id, opts)
vim.validate('bufnr', bufnr, 'number')
vim.validate('client_id', client_id, 'number')
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
opts = opts or {}
assert(
@@ -655,9 +653,7 @@ function M.stop(bufnr, client_id)
vim.validate('bufnr', bufnr, 'number')
vim.validate('client_id', client_id, 'number')
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local highlighter = STHighlighter.active[bufnr]
if not highlighter then
@@ -691,9 +687,7 @@ end
--- - modifiers (table) token modifiers as a set. E.g., { static = true, readonly = true }
--- - client_id (integer)
function M.get_at_pos(bufnr, row, col)
- if bufnr == nil or bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local highlighter = STHighlighter.active[bufnr]
if not highlighter then
@@ -739,8 +733,7 @@ function M.force_refresh(bufnr)
vim.validate('bufnr', bufnr, 'number', true)
local buffers = bufnr == nil and vim.tbl_keys(STHighlighter.active)
- or bufnr == 0 and { api.nvim_get_current_buf() }
- or { bufnr }
+ or { vim._resolve_bufnr(bufnr) }
for _, buffer in ipairs(buffers) do
local highlighter = STHighlighter.active[buffer]
@@ -770,9 +763,7 @@ end
---@param hl_group (string) Highlight group name
---@param opts? vim.lsp.semantic_tokens.highlight_token.Opts Optional parameters:
function M.highlight_token(token, bufnr, client_id, hl_group, opts)
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local highlighter = STHighlighter.active[bufnr]
if not highlighter then
return
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index ced8aa5745..6bee5bc31f 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -192,9 +192,7 @@ local function get_lines(bufnr, rows)
rows = type(rows) == 'table' and rows or { rows }
-- This is needed for bufload and bufloaded
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local function buf_lines()
local lines = {} --- @type table<integer,string>
@@ -1976,7 +1974,7 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, position_encoding)
validate('start_pos', start_pos, 'table', true)
validate('end_pos', end_pos, 'table', true)
validate('position_encoding', position_encoding, 'string', true)
- bufnr = bufnr or api.nvim_get_current_buf()
+ bufnr = vim._resolve_bufnr(bufnr)
if position_encoding == nil then
vim.notify_once(
'position_encoding param is required in vim.lsp.util.make_given_range_params. Defaulting to position encoding of the first client.',
@@ -2143,10 +2141,7 @@ end
---@param opts? vim.lsp.util._refresh.Opts Options table
function M._refresh(method, opts)
opts = opts or {}
- local bufnr = opts.bufnr
- if bufnr == nil or bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ local bufnr = vim._resolve_bufnr(opts.bufnr)
local clients = vim.lsp.get_clients({ bufnr = bufnr, method = method, id = opts.client_id })
@@ -2162,6 +2157,11 @@ function M._refresh(method, opts)
local first = vim.fn.line('w0', window)
local last = vim.fn.line('w$', window)
for _, client in ipairs(clients) do
+ for rid, req in pairs(client.requests) do
+ if req.method == method and req.type == 'pending' and req.bufnr == bufnr then
+ client:cancel_request(rid)
+ end
+ end
client:request(method, {
textDocument = textDocument,
range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 4f2373b182..0fe8e99350 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -737,6 +737,51 @@ function vim.list_slice(list, start, finish)
return new_list
end
+--- Efficiently insert items into the middle of a list.
+---
+--- Calling table.insert() in a loop will re-index the tail of the table on
+--- every iteration, instead this function will re-index the table exactly
+--- once.
+---
+--- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
+---
+---@param t any[]
+---@param first integer
+---@param last integer
+---@param v any
+function vim._list_insert(t, first, last, v)
+ local n = #t
+
+ -- Shift table forward
+ for i = n - first, 0, -1 do
+ t[last + 1 + i] = t[first + i]
+ end
+
+ -- Fill in new values
+ for i = first, last do
+ t[i] = v
+ end
+end
+
+--- Efficiently remove items from middle of a list.
+---
+--- Calling table.remove() in a loop will re-index the tail of the table on
+--- every iteration, instead this function will re-index the table exactly
+--- once.
+---
+--- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
+---
+---@param t any[]
+---@param first integer
+---@param last integer
+function vim._list_remove(t, first, last)
+ local n = #t
+ for i = 0, n - first do
+ t[first + i] = t[last + 1 + i]
+ t[last + 1 + i] = nil
+ end
+end
+
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
---
---@see |lua-patterns|
@@ -968,7 +1013,7 @@ do
--- best performance.
---
--- @param name string Argument name
- --- @param value string Argument value
+ --- @param value any Argument value
--- @param validator vim.validate.Validator
--- - (`string|string[]`): Any value that can be returned from |lua-type()| in addition to
--- `'callable'`: `'boolean'`, `'callable'`, `'function'`, `'nil'`, `'number'`, `'string'`, `'table'`,
@@ -1354,4 +1399,14 @@ function vim._with(context, f)
return vim._with_c(context, callback)
end
+--- @param bufnr? integer
+--- @return integer
+function vim._resolve_bufnr(bufnr)
+ if bufnr == nil or bufnr == 0 then
+ return vim.api.nvim_get_current_buf()
+ end
+ vim.validate('bufnr', bufnr, 'number')
+ return bufnr
+end
+
return vim
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index dca89f413c..5f4e796413 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -32,9 +32,7 @@ M.minimum_language_version = vim._ts_get_minimum_language_version()
---
---@return vim.treesitter.LanguageTree object to use for parsing
function M._create_parser(bufnr, lang, opts)
- if bufnr == 0 then
- bufnr = vim.api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
vim.fn.bufload(bufnr)
@@ -90,9 +88,7 @@ function M.get_parser(bufnr, lang, opts)
opts = opts or {}
local should_error = opts.error == nil or opts.error
- if bufnr == nil or bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
if not valid_lang(lang) then
lang = M.language.get_lang(vim.bo[bufnr].filetype)
@@ -258,9 +254,7 @@ end
---
---@return {capture: string, lang: string, metadata: vim.treesitter.query.TSMetadata}[]
function M.get_captures_at_pos(bufnr, row, col)
- if bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ bufnr = vim._resolve_bufnr(bufnr)
local buf_highlighter = M.highlighter.active[bufnr]
if not buf_highlighter then
@@ -361,11 +355,7 @@ end
function M.get_node(opts)
opts = opts or {}
- local bufnr = opts.bufnr
-
- if not bufnr or bufnr == 0 then
- bufnr = api.nvim_get_current_buf()
- end
+ local bufnr = vim._resolve_bufnr(opts.bufnr)
local row, col --- @type integer, integer
if opts.pos then
@@ -417,7 +407,7 @@ end
---@param bufnr (integer|nil) Buffer to be highlighted (default: current buffer)
---@param lang (string|nil) Language of the parser (default: from buffer filetype)
function M.start(bufnr, lang)
- bufnr = bufnr or api.nvim_get_current_buf()
+ bufnr = vim._resolve_bufnr(bufnr)
local parser = assert(M.get_parser(bufnr, lang, { error = false }))
M.highlighter.new(parser)
end
@@ -426,7 +416,7 @@ end
---
---@param bufnr (integer|nil) Buffer to stop highlighting (default: current buffer)
function M.stop(bufnr)
- bufnr = (bufnr and bufnr ~= 0) and bufnr or api.nvim_get_current_buf()
+ bufnr = vim._resolve_bufnr(bufnr)
if M.highlighter.active[bufnr] then
M.highlighter.active[bufnr]:destroy()
diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index 7237d2e7d4..0cb5b497c7 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -30,65 +30,20 @@ function FoldInfo.new()
}, FoldInfo)
end
---- Efficiently remove items from middle of a list a list.
----
---- Calling table.remove() in a loop will re-index the tail of the table on
---- every iteration, instead this function will re-index the table exactly
---- once.
----
---- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
----
----@param t any[]
----@param first integer
----@param last integer
-local function list_remove(t, first, last)
- local n = #t
- for i = 0, n - first do
- t[first + i] = t[last + 1 + i]
- t[last + 1 + i] = nil
- end
-end
-
---@package
---@param srow integer
---@param erow integer 0-indexed, exclusive
function FoldInfo:remove_range(srow, erow)
- list_remove(self.levels, srow + 1, erow)
- list_remove(self.levels0, srow + 1, erow)
-end
-
---- Efficiently insert items into the middle of a list.
----
---- Calling table.insert() in a loop will re-index the tail of the table on
---- every iteration, instead this function will re-index the table exactly
---- once.
----
---- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
----
----@param t any[]
----@param first integer
----@param last integer
----@param v any
-local function list_insert(t, first, last, v)
- local n = #t
-
- -- Shift table forward
- for i = n - first, 0, -1 do
- t[last + 1 + i] = t[first + i]
- end
-
- -- Fill in new values
- for i = first, last do
- t[i] = v
- end
+ vim._list_remove(self.levels, srow + 1, erow)
+ vim._list_remove(self.levels0, srow + 1, erow)
end
---@package
---@param srow integer
---@param erow integer 0-indexed, exclusive
function FoldInfo:add_range(srow, erow)
- list_insert(self.levels, srow + 1, erow, -1)
- list_insert(self.levels0, srow + 1, erow, -1)
+ vim._list_insert(self.levels, srow + 1, erow, -1)
+ vim._list_insert(self.levels0, srow + 1, erow, -1)
end
---@param range Range2
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 1677e8d364..dbe3d54c2f 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -572,13 +572,17 @@ local directive_handlers = {
metadata[id].text = text:gsub(pattern, replacement)
end,
- -- Trim blank lines from end of the node
- -- Example: (#trim! @fold)
- -- TODO(clason): generalize to arbitrary whitespace removal
+ -- Trim whitespace from both sides of the node
+ -- Example: (#trim! @fold 1 1 1 1)
['trim!'] = function(match, _, bufnr, pred, metadata)
local capture_id = pred[2]
assert(type(capture_id) == 'number')
+ local trim_start_lines = pred[3] == '1'
+ local trim_start_cols = pred[4] == '1'
+ local trim_end_lines = pred[5] == '1' or not pred[3] -- default true for backwards compatibility
+ local trim_end_cols = pred[6] == '1'
+
local nodes = match[capture_id]
if not nodes or #nodes == 0 then
return
@@ -588,20 +592,45 @@ local directive_handlers = {
local start_row, start_col, end_row, end_col = node:range()
- -- Don't trim if region ends in middle of a line
- if end_col ~= 0 then
- return
+ local node_text = vim.split(vim.treesitter.get_node_text(node, bufnr), '\n')
+ if end_col == 0 then
+ -- get_node_text() will ignore the last line if the node ends at column 0
+ node_text[#node_text + 1] = ''
end
- while end_row >= start_row do
- -- As we only care when end_col == 0, always inspect one line above end_row.
- local end_line = api.nvim_buf_get_lines(bufnr, end_row - 1, end_row, true)[1]
+ local end_idx = #node_text
+ local start_idx = 1
- if end_line ~= '' then
- break
+ if trim_end_lines then
+ while end_idx > 0 and node_text[end_idx]:find('^%s*$') do
+ end_idx = end_idx - 1
+ end_row = end_row - 1
+ -- set the end position to the last column of the next line, or 0 if we just trimmed the
+ -- last line
+ end_col = end_idx > 0 and #node_text[end_idx] or 0
end
+ end
+ if trim_end_cols then
+ if end_idx == 0 then
+ end_row = start_row
+ end_col = start_col
+ else
+ local whitespace_start = node_text[end_idx]:find('(%s*)$')
+ end_col = (whitespace_start - 1) + (end_idx == 1 and start_col or 0)
+ end
+ end
- end_row = end_row - 1
+ if trim_start_lines then
+ while start_idx <= end_idx and node_text[start_idx]:find('^%s*$') do
+ start_idx = start_idx + 1
+ start_row = start_row + 1
+ start_col = 0
+ end
+ end
+ if trim_start_cols and node_text[start_idx] then
+ local _, whitespace_end = node_text[start_idx]:find('^(%s*)')
+ whitespace_end = whitespace_end or 0
+ start_col = (start_idx == 1 and start_col or 0) + whitespace_end
end
-- If this produces an invalid range, we just skip it.
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 48a4bd2816..6866d46d51 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2024 Jul 12
+" Last Change: 2024 Dec 07
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" If there already is an option window, jump to that one.
@@ -626,8 +626,8 @@ call <SID>AddOption("terse", gettext("add 's' flag in 'shortmess' (don't show se
call <SID>BinOptionG("terse", &terse)
call <SID>AddOption("shortmess", gettext("list of flags to make messages shorter"))
call <SID>OptionG("shm", &shm)
-call <SID>AddOption("msghistory", gettext("how many messages are remembered"))
-call append("$", " \tset mhi=" . &mhi)
+call <SID>AddOption("messagesopt", gettext("options for outputting messages"))
+call <SID>OptionG("mopt", &mopt)
call <SID>AddOption("showcmd", gettext("show (partial) command keys in location given by 'showcmdloc'"))
let &sc = s:old_sc
call <SID>BinOptionG("sc", &sc)
diff --git a/runtime/syntax/po.vim b/runtime/syntax/po.vim
index 08d6baec27..6da27f639d 100644
--- a/runtime/syntax/po.vim
+++ b/runtime/syntax/po.vim
@@ -1,10 +1,11 @@
" Vim syntax file
" Language: po (gettext)
" Maintainer: Dwayne Bailey <dwayne@translate.org.za>
-" Last Change: 2015 Jun 07
+" Last Change: 2024 Nov 28
" Contributors: Dwayne Bailey (Most advanced syntax highlighting)
" Leonardo Fontenelle (Spell checking)
" Nam SungHyun <namsh@kldp.org> (Original maintainer)
+" Eisuke Kawashima (add format-flags: #16132)
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -32,9 +33,9 @@ syn region poMsgCTxt matchgroup=poStatementMsgCTxt start=+^msgctxt "+rs=e-1
syn region poMsgID matchgroup=poStatementMsgid start=+^msgid "+rs=e-1 matchgroup=poStringID end=+^msgstr\(\|\[[\]0\[]\]\) "+me=s-1 contains=poStringID,poStatementMsgidplural,poStatementMsgid
syn region poMsgSTR matchgroup=poStatementMsgstr start=+^msgstr\(\|\[[\]0\[]\]\) "+rs=e-1 matchgroup=poStringSTR end=+\n\n+me=s-1 contains=poStringSTR,poStatementMsgstr
syn region poStringCTxt start=+"+ skip=+\\\\\|\\"+ end=+"+
-syn region poStringID start=+"+ skip=+\\\\\|\\"+ end=+"+ contained
+syn region poStringID start=+"+ skip=+\\\\\|\\"+ end=+"+ contained
\ contains=poSpecial,poFormat,poCommentKDE,poPluralKDE,poKDEdesktopFile,poHtml,poAcceleratorId,poHtmlNot,poVariable
-syn region poStringSTR start=+"+ skip=+\\\\\|\\"+ end=+"+ contained
+syn region poStringSTR start=+"+ skip=+\\\\\|\\"+ end=+"+ contained
\ contains=@Spell,poSpecial,poFormat,poHeaderItem,poCommentKDEError,poHeaderUndefined,poPluralKDEError,poMsguniqError,poKDEdesktopFile,poHtml,poAcceleratorStr,poHtmlNot,poVariable
" Header and Copyright
@@ -45,13 +46,43 @@ syn match poCopyrightUnset "SOME DESCRIPTIVE TITLE\|FIRST AUTHOR <EMAIL@ADDR
" Translation comment block including: translator comment, automatic comments, flags and locations
syn match poComment "^#.*$"
syn keyword poFlagFuzzy fuzzy contained
+
+syn match poFlagFormat /\<\%(no-\)\?awk-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?boost-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?c++-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?c-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?csharp-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?elisp-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?gcc-internal-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?gfc-internal-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?java-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?java-printf-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?javascript-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?kde-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?librep-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?lisp-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?lua-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?objc-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?object-pascal-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?perl-brace-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?perl-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?php-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?python-brace-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?python-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?qt-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?qt-plural-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?ruby-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?scheme-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?sh-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?smalltalk-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?tcl-format\>/ contained
+syn match poFlagFormat /\<\%(no-\)\?ycp-format\>/ contained
+
syn match poCommentTranslator "^# .*$" contains=poCopyrightUnset
-syn match poCommentAutomatic "^#\..*$"
+syn match poCommentAutomatic "^#\..*$"
syn match poCommentSources "^#:.*$"
-syn match poCommentFlags "^#,.*$" contains=poFlagFuzzy
-syn match poDiffOld '\(^#| "[^{]*+}\|{+[^}]*+}\|{+[^}]*\|"$\)' contained
-syn match poDiffNew '\(^#| "[^{]*-}\|{-[^}]*-}\|{-[^}]*\|"$\)' contained
-syn match poCommentDiff "^#|.*$" contains=poDiffOld,poDiffNew
+syn match poCommentFlags "^#,.*$" contains=poFlagFuzzy,poFlagFormat
+syn match poCommentPrevious "^#|.*$"
" Translations (also includes header fields as they appear in a translation msgstr)
syn region poCommentKDE start=+"_: +ms=s+1 end="\\n" end="\"\n^msgstr"me=s-1 contained
@@ -66,13 +97,13 @@ syn match poFormat "%%" contained
syn region poMsguniqError matchgroup=poMsguniqErrorMarkers start="#-#-#-#-#" end='#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)\\n' contained
" Obsolete messages
-syn match poObsolete "^#\~.*$"
+syn match poObsolete "^#\~.*$"
" KDE Name= handling
syn match poKDEdesktopFile "\"\(Name\|Comment\|GenericName\|Description\|Keywords\|About\)="ms=s+1,me=e-1
" Accelerator keys - this messes up if the preceding or following char is a multibyte unicode char
-syn match poAcceleratorId contained "[^&_~][&_~]\(\a\|\d\)[^:]"ms=s+1,me=e-1
+syn match poAcceleratorId contained "[^&_~][&_~]\(\a\|\d\)[^:]"ms=s+1,me=e-1
syn match poAcceleratorStr contained "[^&_~][&_~]\(\a\|\d\)[^:]"ms=s+1,me=e-1 contains=@Spell
" Variables simple
@@ -86,11 +117,10 @@ hi def link poComment Comment
hi def link poCommentAutomatic Comment
hi def link poCommentTranslator Comment
hi def link poCommentFlags Special
-hi def link poCommentDiff Comment
+hi def link poCommentPrevious Comment
hi def link poCopyrightUnset Todo
hi def link poFlagFuzzy Todo
-hi def link poDiffOld Todo
-hi def link poDiffNew Special
+hi def link poFlagFormat Todo
hi def link poObsolete Comment
hi def link poStatementMsgid Statement
diff --git a/runtime/syntax/ptx.vim b/runtime/syntax/ptx.vim
new file mode 100644
index 0000000000..98de4ff6d3
--- /dev/null
+++ b/runtime/syntax/ptx.vim
@@ -0,0 +1,52 @@
+" Vim syntax file
+" Language: Nvidia PTX (Parallel Thread Execution)
+" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com>
+" Latest Revision: 2024-12-05
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+syntax iskeyword .,_,a-z,48-57
+
+" https://docs.nvidia.com/cuda/parallel-thread-execution/#directives
+syntax keyword ptxFunction .entry .func
+syntax keyword ptxDirective .branchtargets .file .loc .secion .maxnctapersm .maxnreg .minnctapersm .noreturn .pragma .reqntid .target .version .weak
+syntax keyword ptxOperator .address_size .alias .align .callprototype .calltargets
+syntax keyword ptxStorageClass .common .const .extern .global .local .param .reg .sreg .shared .tex .visible
+syntax keyword ptxType .explicitcluster .maxclusterrank .reqnctapercluster
+
+" https://docs.nvidia.com/cuda/parallel-thread-execution/#fundamental-types
+" signed integer
+syntax keyword ptxType .s8 .s16 .s32 .s64
+" unsigned integer
+syntax keyword ptxType .u8 .u16 .u32 .u64
+" floating-point
+syntax keyword ptxType .f16 .f16x2 .f32 .f64
+" bits (untyped)
+syntax keyword ptxType .b8 .b16 .b32 .b64 .b128
+" predicate
+syntax keyword ptxType .pred
+
+" https://docs.nvidia.com/cuda/parallel-thread-execution/#instruction-statements
+syntax keyword ptxStatement ret
+
+syntax region ptxCommentL start="//" skip="\\$" end="$" keepend
+syntax region ptxComment matchgroup=ptxCommentStart start="/\*" end="\*/" extend
+
+hi def link ptxFunction Function
+hi def link ptxDirective Keyword
+hi def link ptxOperator Operator
+hi def link ptxStorageClass StorageClass
+hi def link ptxType Type
+hi def link ptxStatement Statement
+
+hi def link ptxCommentL ptxComment
+hi def link ptxCommentStart ptxComment
+hi def link ptxComment Comment
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/typst.vim b/runtime/syntax/typst.vim
index dae1424780..b1f05ec853 100644
--- a/runtime/syntax/typst.vim
+++ b/runtime/syntax/typst.vim
@@ -1,7 +1,8 @@
" Vim syntax file
" Language: Typst
-" Maintainer: Gregory Anders <greg@gpanders.com>
-" Last Change: 2024 Nov 02
+" Previous Maintainer: Gregory Anders
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 Dec 09
" Based on: https://github.com/kaarmu/typst.vim
if exists('b:current_syntax')
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index 498bf6b26f..de9df5054f 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -134,6 +134,15 @@ local API_TYPES = {
void = '',
}
+--- @param s string
+--- @return string
+local function luaescape(s)
+ if LUA_KEYWORDS[s] then
+ return s .. '_'
+ end
+ return s
+end
+
--- @param x string
--- @param sep? string
--- @return string[]
@@ -208,7 +217,7 @@ local function render_fun_sig(f, params)
--- @param v [string,string]
--- @return string
function(v)
- return v[1]
+ return luaescape(v[1])
end,
params
),
@@ -224,7 +233,6 @@ local function render_fun_sig(f, params)
end
--- Uniquify names
---- Fix any names that are lua keywords
--- @param params [string,string,string][]
--- @return [string,string,string][]
local function process_params(params)
@@ -232,9 +240,6 @@ local function process_params(params)
local sfx = 1
for _, p in ipairs(params) do
- if LUA_KEYWORDS[p[1]] then
- p[1] = p[1] .. '_'
- end
if seen[p[1]] then
p[1] = p[1] .. sfx
sfx = sfx + 1
@@ -389,10 +394,10 @@ local function render_api_meta(_f, fun, write)
local param_names = {} --- @type string[]
local params = process_params(fun.params)
for _, p in ipairs(params) do
- param_names[#param_names + 1] = p[1]
- local pdesc = p[3]
+ local pname, ptype, pdesc = luaescape(p[1]), p[2], p[3]
+ param_names[#param_names + 1] = pname
if pdesc then
- local s = '--- @param ' .. p[1] .. ' ' .. p[2] .. ' '
+ local s = '--- @param ' .. pname .. ' ' .. ptype .. ' '
local pdesc_a = split(vim.trim(norm_text(pdesc)))
write(s .. pdesc_a[1])
for i = 2, #pdesc_a do
@@ -402,7 +407,7 @@ local function render_api_meta(_f, fun, write)
write('--- ' .. pdesc_a[i])
end
else
- write('--- @param ' .. p[1] .. ' ' .. p[2])
+ write('--- @param ' .. pname .. ' ' .. ptype)
end
end
@@ -494,7 +499,7 @@ local function render_eval_meta(f, fun, write)
local req_args = type(fun.args) == 'table' and fun.args[1] or fun.args or 0
for i, param in ipairs(params) do
- local pname, ptype = param[1], param[2]
+ local pname, ptype = luaescape(param[1]), param[2]
local optional = (pname ~= '...' and i > req_args) and '?' or ''
write(fmt('--- @param %s%s %s', pname, optional, ptype))
end
diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua
index b8f80e94be..53a65fd65f 100644
--- a/scripts/gen_help_html.lua
+++ b/scripts/gen_help_html.lua
@@ -48,7 +48,7 @@ local spell_dict = {
--- specify the list of keywords to ignore (i.e. allow), or true to disable spell check completely.
--- @type table<string, true|string[]>
local spell_ignore_files = {
- ['backers.txt'] = true,
+ ['credits.txt'] = { 'Neovim' },
['news.txt'] = { 'tree-sitter' }, -- in news, may refer to the upstream "tree-sitter" library
['news-0.10.txt'] = { 'tree-sitter' },
}
@@ -70,6 +70,8 @@ local new_layout = {
['dev_vimpatch.txt'] = true,
['editorconfig.txt'] = true,
['faq.txt'] = true,
+ ['gui.txt'] = true,
+ ['intro.txt'] = true,
['lua.txt'] = true,
['luaref.txt'] = true,
['news.txt'] = true,
@@ -84,6 +86,7 @@ local new_layout = {
-- Map of new:old pages, to redirect renamed pages.
local redirects = {
+ ['credits'] = 'backers',
['tui'] = 'term',
['terminal'] = 'nvim_terminal_emulator',
}
@@ -116,7 +119,7 @@ local exclude_invalid_urls = {
-- Deprecated, brain-damaged files that I don't care about.
local ignore_errors = {
['pi_netrw.txt'] = true,
- ['backers.txt'] = true,
+ ['credits.txt'] = true,
}
local function tofile(fname, text)
diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua
index 1125021bdc..3f870c561f 100755
--- a/scripts/gen_vimdoc.lua
+++ b/scripts/gen_vimdoc.lua
@@ -274,6 +274,7 @@ local config = {
'diagnostic.lua',
'codelens.lua',
'completion.lua',
+ 'folding_range.lua',
'inlay_hint.lua',
'tagfunc.lua',
'semantic_tokens.lua',
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c
index 254355e5a2..e4bd0bcf6b 100644
--- a/src/cjson/lua_cjson.c
+++ b/src/cjson/lua_cjson.c
@@ -173,6 +173,16 @@ typedef struct {
} json_config_t;
typedef struct {
+ const char **char2escape[256];
+} json_encode_options_t;
+
+typedef struct {
+ json_config_t *cfg;
+ json_encode_options_t *options;
+ strbuf_t *json;
+} json_encode_t;
+
+typedef struct {
/* convert null in json objects to lua nil instead of vim.NIL */
bool luanil_object;
/* convert null in json arrays to lua nil instead of vim.NIL */
@@ -209,7 +219,7 @@ static const char *char2escape[256] = {
"\\u0018", "\\u0019", "\\u001a", "\\u001b",
"\\u001c", "\\u001d", "\\u001e", "\\u001f",
NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -555,11 +565,11 @@ static void json_create_config(lua_State *l)
/* ===== ENCODING ===== */
-static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,
+static void json_encode_exception(lua_State *l, json_encode_t *ctx, int lindex,
const char *reason)
{
- if (!cfg->encode_keep_buffer)
- strbuf_free(json);
+ if (!ctx->cfg->encode_keep_buffer)
+ strbuf_free(ctx->json);
luaL_error(l, "Cannot serialise %s: %s",
lua_typename(l, lua_type(l, lindex)), reason);
}
@@ -570,12 +580,13 @@ static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *js
* - String (Lua stack index)
*
* Returns nothing. Doesn't remove string from Lua stack */
-static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
+static void json_append_string(lua_State *l, json_encode_t *ctx, int lindex)
{
const char *escstr;
unsigned i;
const char *str;
size_t len;
+ strbuf_t *json = ctx->json;
str = lua_tolstring(l, lindex, &len);
@@ -587,7 +598,7 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
strbuf_append_char_unsafe(json, '\"');
for (i = 0; i < len; i++) {
- escstr = char2escape[(unsigned char)str[i]];
+ escstr = (*ctx->options->char2escape)[(unsigned char)str[i]];
if (escstr)
strbuf_append_string(json, escstr);
else
@@ -600,11 +611,12 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
* -1 object (not a pure array)
* >=0 elements in array
*/
-static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)
+static int lua_array_length(lua_State *l, json_encode_t *ctx)
{
double k;
int max;
int items;
+ json_config_t *cfg = ctx->cfg;
max = 0;
items = 0;
@@ -635,7 +647,7 @@ static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)
max > items * cfg->encode_sparse_ratio &&
max > cfg->encode_sparse_safe) {
if (!cfg->encode_sparse_convert)
- json_encode_exception(l, cfg, json, -1, "excessively sparse array");
+ json_encode_exception(l, ctx, -1, "excessively sparse array");
return -1;
}
@@ -666,17 +678,18 @@ static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
current_depth);
}
-static void json_append_data(lua_State *l, json_config_t *cfg,
- int current_depth, strbuf_t *json);
+static void json_append_data(lua_State *l, json_encode_t *cfg,
+ int current_depth);
/* json_append_array args:
* - lua_State
* - JSON strbuf
* - Size of passwd Lua array (top of stack) */
-static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth,
- strbuf_t *json, int array_length)
+static void json_append_array(lua_State *l, json_encode_t *ctx, int current_depth,
+ int array_length)
{
int comma, i;
+ strbuf_t *json = ctx->json;
strbuf_append_char(json, '[');
@@ -688,23 +701,25 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
comma = 1;
lua_rawgeti(l, -1, i);
- json_append_data(l, cfg, current_depth, json);
+ json_append_data(l, ctx, current_depth);
lua_pop(l, 1);
}
strbuf_append_char(json, ']');
}
-static void json_append_number(lua_State *l, json_config_t *cfg,
- strbuf_t *json, int lindex)
+static void json_append_number(lua_State *l, json_encode_t *ctx,
+ int lindex)
{
double num = lua_tonumber(l, lindex);
int len;
+ json_config_t *cfg = ctx->cfg;
+ strbuf_t *json = ctx->json;
if (cfg->encode_invalid_numbers == 0) {
/* Prevent encoding invalid numbers */
if (isinf(num) || isnan(num))
- json_encode_exception(l, cfg, json, lindex,
+ json_encode_exception(l, ctx, lindex,
"must not be NaN or Infinity");
} else if (cfg->encode_invalid_numbers == 1) {
/* Encode NaN/Infinity separately to ensure Javascript compatible
@@ -733,10 +748,11 @@ static void json_append_number(lua_State *l, json_config_t *cfg,
strbuf_extend_length(json, len);
}
-static void json_append_object(lua_State *l, json_config_t *cfg,
- int current_depth, strbuf_t *json)
+static void json_append_object(lua_State *l, json_encode_t *ctx,
+ int current_depth)
{
int comma, keytype;
+ strbuf_t *json = ctx->json;
/* Object */
strbuf_append_char(json, '{');
@@ -754,19 +770,19 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
keytype = lua_type(l, -2);
if (keytype == LUA_TNUMBER) {
strbuf_append_char(json, '"');
- json_append_number(l, cfg, json, -2);
+ json_append_number(l, ctx, -2);
strbuf_append_mem(json, "\":", 2);
} else if (keytype == LUA_TSTRING) {
- json_append_string(l, json, -2);
+ json_append_string(l, ctx, -2);
strbuf_append_char(json, ':');
} else {
- json_encode_exception(l, cfg, json, -2,
+ json_encode_exception(l, ctx, -2,
"table key must be a number or string");
/* never returns */
}
/* table, key, value */
- json_append_data(l, cfg, current_depth, json);
+ json_append_data(l, ctx, current_depth);
lua_pop(l, 1);
/* table, key */
}
@@ -775,20 +791,22 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
}
/* Serialise Lua data into JSON string. */
-static void json_append_data(lua_State *l, json_config_t *cfg,
- int current_depth, strbuf_t *json)
+static void json_append_data(lua_State *l, json_encode_t *ctx,
+ int current_depth)
{
int len;
int as_array = 0;
int as_empty_dict = 0;
int has_metatable;
+ json_config_t *cfg = ctx->cfg;
+ strbuf_t *json = ctx->json;
switch (lua_type(l, -1)) {
case LUA_TSTRING:
- json_append_string(l, json, -1);
+ json_append_string(l, ctx, -1);
break;
case LUA_TNUMBER:
- json_append_number(l, cfg, json, -1);
+ json_append_number(l, ctx, -1);
break;
case LUA_TBOOLEAN:
if (lua_toboolean(l, -1))
@@ -818,12 +836,12 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
if (as_array) {
len = lua_objlen(l, -1);
- json_append_array(l, cfg, current_depth, json, len);
+ json_append_array(l, ctx, current_depth, len);
} else {
- len = lua_array_length(l, cfg, json);
+ len = lua_array_length(l, ctx);
if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object && !as_empty_dict)) {
- json_append_array(l, cfg, current_depth, json, len);
+ json_append_array(l, ctx, current_depth, len);
} else {
if (has_metatable) {
lua_getmetatable(l, -1);
@@ -833,11 +851,11 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
as_array = lua_rawequal(l, -1, -2);
lua_pop(l, 2); /* pop pointer + metatable */
if (as_array) {
- json_append_array(l, cfg, current_depth, json, 0);
+ json_append_array(l, ctx, current_depth, 0);
break;
}
}
- json_append_object(l, cfg, current_depth, json);
+ json_append_object(l, ctx, current_depth);
}
}
break;
@@ -846,7 +864,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
break;
case LUA_TLIGHTUSERDATA:
if (lua_touserdata(l, -1) == &json_array) {
- json_append_array(l, cfg, current_depth, json, 0);
+ json_append_array(l, ctx, current_depth, 0);
}
break;
case LUA_TUSERDATA:
@@ -862,7 +880,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
default:
/* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,
* and LUA_TLIGHTUSERDATA) cannot be serialised */
- json_encode_exception(l, cfg, json, -1, "type not supported");
+ json_encode_exception(l, ctx, -1, "type not supported");
/* never returns */
}
}
@@ -870,12 +888,44 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
static int json_encode(lua_State *l)
{
json_config_t *cfg = json_fetch_config(l);
+ json_encode_options_t options = { .char2escape = { char2escape } };
+ json_encode_t ctx = { .options = &options, .cfg = cfg };
strbuf_t local_encode_buf;
strbuf_t *encode_buf;
char *json;
int len;
+ const char *customChar2escape[256];
- luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+ switch (lua_gettop(l)) {
+ case 1:
+ break;
+ case 2:
+ luaL_checktype(l, 2, LUA_TTABLE);
+ lua_getfield(l, 2, "escape_slash");
+
+ /* We only handle the escape_slash option for now */
+ if (lua_isnil(l, -1)) {
+ lua_pop(l, 2);
+ break;
+ }
+
+ luaL_checktype(l, -1, LUA_TBOOLEAN);
+
+ int escape_slash = lua_toboolean(l, -1);
+
+ if (escape_slash) {
+ /* This can be optimised by adding a new hard-coded escape table for this case,
+ * but this path will rarely if ever be used, so let's just memcpy.*/
+ memcpy(customChar2escape, char2escape, sizeof(char2escape));
+ customChar2escape['/'] = "\\/";
+ *ctx.options->char2escape = customChar2escape;
+ }
+
+ lua_pop(l, 2);
+ break;
+ default:
+ return luaL_error (l, "expected 1 or 2 arguments");
+ }
if (!cfg->encode_keep_buffer) {
/* Use private buffer */
@@ -887,7 +937,8 @@ static int json_encode(lua_State *l)
strbuf_reset(encode_buf);
}
- json_append_data(l, cfg, 0, encode_buf);
+ ctx.json = encode_buf;
+ json_append_data(l, &ctx, 0);
json = strbuf_string(encode_buf, &len);
lua_pushlstring(l, json, len);
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index e2b1036d95..cce8ab5b25 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -556,7 +556,7 @@ foreach(sfile ${NVIM_SOURCES}
set(PREPROC_OUTPUT -w -E -o ${gf_i})
endif()
- set(depends "${HEADER_GENERATOR}" "${sfile}" "${LUA_GEN_DEPS}")
+ set(depends "${HEADER_GENERATOR}" "${sfile}" "${LUA_GEN_DEPS}" "${GENERATOR_C_GRAMMAR}")
if("${f}" STREQUAL "version.c")
# Ensure auto/versiondef_git.h exists after "make clean".
list(APPEND depends update_version_stamp "${NVIM_VERSION_GIT_H}" "${NVIM_VERSION_DEF_H}")
@@ -826,6 +826,7 @@ target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv)
#-------------------------------------------------------------------------------
find_program(CLANG_TIDY_PRG clang-tidy)
+mark_as_advanced(CLANG_TIDY_PRG)
set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h)
if(WIN32)
list(APPEND EXCLUDE_CLANG_TIDY
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index db87500d08..45e2de69e0 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -386,9 +386,9 @@ cleanup:
/// - id: (number) autocommand id
/// - event: (string) name of the triggered event |autocmd-events|
/// - group: (number|nil) autocommand group id, if any
-/// - match: (string) expanded value of [<amatch>]
-/// - buf: (number) expanded value of [<abuf>]
-/// - file: (string) expanded value of [<afile>]
+/// - file: (string) [<afile>] (not expanded to a full path)
+/// - match: (string) [<amatch>] (expanded to a full path)
+/// - buf: (number) [<abuf>]
/// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]()
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 493856905f..51ed6eaa41 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -798,7 +798,8 @@ theend:
/// @param channel_id Channel id (passed automatically by the dispatcher)
/// @param event Event type string
void nvim_subscribe(uint64_t channel_id, String event)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+// XXX: c_grammar.lua is order-sensitive.
+ FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(13) FUNC_API_REMOTE_ONLY
{
// Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions".
}
@@ -808,7 +809,8 @@ void nvim_subscribe(uint64_t channel_id, String event)
/// @param channel_id Channel id (passed automatically by the dispatcher)
/// @param event Event type string
void nvim_unsubscribe(uint64_t channel_id, String event)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+// XXX: c_grammar.lua is order-sensitive.
+ FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(13) FUNC_API_REMOTE_ONLY
{
// Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions".
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index ab52612f9f..1262af5e40 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1040,7 +1040,7 @@ fail:
/// Open a terminal instance in a buffer
///
/// By default (and currently the only option) the terminal will not be
-/// connected to an external process. Instead, input send on the channel
+/// connected to an external process. Instead, input sent on the channel
/// will be echoed directly by the terminal. This is useful to display
/// ANSI terminal sequences returned as part of a rpc message, or similar.
///
@@ -1051,6 +1051,18 @@ fail:
/// Then |nvim_chan_send()| can be called immediately to process sequences
/// in a virtual terminal having the intended size.
///
+/// Example: this `TermHl` command can be used to display and highlight raw ANSI termcodes, so you
+/// can use Nvim as a "scrollback pager" (for terminals like kitty): [terminal-scrollback-pager]()
+///
+/// ```lua
+/// vim.api.nvim_create_user_command('TermHl', function()
+/// local b = vim.api.nvim_create_buf(false, true)
+/// local chan = vim.api.nvim_open_term(b, {})
+/// vim.api.nvim_chan_send(chan, table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n'))
+/// vim.api.nvim_win_set_buf(0, b)
+/// end, { desc = 'Highlights ANSI termcodes in curbuf' })
+/// ```
+///
/// @param buffer the buffer to use (expected to be empty)
/// @param opts Optional parameters.
/// - on_input: Lua callback for input sent, i e keypresses in terminal
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index c08ef7a4c1..118a50e15d 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1666,7 +1666,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
} else {
autocmd_fname = fname_io;
}
+ char *afile_orig = NULL; ///< Unexpanded <afile>
if (autocmd_fname != NULL) {
+ afile_orig = xstrdup(autocmd_fname);
// Allocate MAXPATHL for when eval_vars() resolves the fullpath.
autocmd_fname = xstrnsave(autocmd_fname, MAXPATHL);
}
@@ -1798,6 +1800,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
// save vector size, to avoid an endless loop when more patterns
// are added when executing autocommands
.ausize = kv_size(autocmds[(int)event]),
+ .afile_orig = afile_orig,
.fname = fname,
.sfname = sfname,
.tail = tail,
@@ -1865,6 +1868,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
autocmd_nested = save_autocmd_nested;
xfree(SOURCING_NAME);
estack_pop();
+ xfree(afile_orig);
xfree(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
@@ -2029,8 +2033,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc)
MAXSIZE_TEMP_DICT(data, 7);
PUT_C(data, "id", INTEGER_OBJ(ac->id));
PUT_C(data, "event", CSTR_AS_OBJ(event_nr2name(apc->event)));
+ PUT_C(data, "file", CSTR_AS_OBJ(apc->afile_orig));
PUT_C(data, "match", CSTR_AS_OBJ(autocmd_match));
- PUT_C(data, "file", CSTR_AS_OBJ(autocmd_fname));
PUT_C(data, "buf", INTEGER_OBJ(autocmd_bufnr));
if (apc->data) {
diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h
index 490782b209..cba947e85f 100644
--- a/src/nvim/autocmd_defs.h
+++ b/src/nvim/autocmd_defs.h
@@ -52,6 +52,7 @@ struct AutoPatCmd_S {
AutoPat *lastpat; ///< Last matched AutoPat
size_t auidx; ///< Current autocmd index to execute
size_t ausize; ///< Saved AutoCmd vector size
+ char *afile_orig; ///< Unexpanded <afile>
char *fname; ///< Fname to match with
char *sfname; ///< Sfname to match with
char *tail; ///< Tail of fname
diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c
index a473fc1dc9..e5d2658720 100644
--- a/src/nvim/decoration_provider.c
+++ b/src/nvim/decoration_provider.c
@@ -55,14 +55,13 @@ static bool decor_provider_invoke(int provider_idx, const char *name, LuaRef ref
// We get the provider here via an index in case the above call to nlua_call_ref causes
// decor_providers to be reallocated.
DecorProvider *provider = &kv_A(decor_providers, provider_idx);
-
if (!ERROR_SET(&err)
&& api_object_to_bool(ret, "provider %s retval", default_true, &err)) {
provider->error_count = 0;
return true;
}
- if (ERROR_SET(&err)) {
+ if (ERROR_SET(&err) && provider->error_count < DP_MAX_ERROR) {
decor_provider_error(provider, name, err.msg);
provider->error_count++;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index ea0d1ba708..4d40455507 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1954,16 +1954,16 @@ void f_digraph_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "digraph_getlist()" function
void f_digraph_getlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ if (tv_check_for_opt_bool_arg(argvars, 0) == FAIL) {
+ return;
+ }
+
bool flag_list_all;
if (argvars[0].v_type == VAR_UNKNOWN) {
flag_list_all = false;
} else {
- bool error = false;
- varnumber_T flag = tv_get_number_chk(&argvars[0], &error);
- if (error) {
- return;
- }
+ varnumber_T flag = tv_get_bool(&argvars[0]);
flag_list_all = flag != 0;
}
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index e645d1bbea..0961aabf21 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -290,9 +290,23 @@ void screen_resize(int width, int height)
Rows = height;
Columns = width;
check_screensize();
- int max_p_ch = Rows - min_rows() + 1;
- if (!ui_has(kUIMessages) && p_ch > 0 && p_ch > max_p_ch) {
- p_ch = max_p_ch ? max_p_ch : 1;
+ if (!ui_has(kUIMessages)) {
+ // clamp 'cmdheight'
+ int max_p_ch = Rows - min_rows(curtab) + 1;
+ if (p_ch > 0 && p_ch > max_p_ch) {
+ p_ch = MAX(max_p_ch, 1);
+ curtab->tp_ch_used = p_ch;
+ }
+ // clamp 'cmdheight' for other tab pages
+ FOR_ALL_TABS(tp) {
+ if (tp == curtab) {
+ continue; // already set above
+ }
+ int max_tp_ch = Rows - min_rows(tp) + 1;
+ if (tp->tp_ch_used > 0 && tp->tp_ch_used > max_tp_ch) {
+ tp->tp_ch_used = MAX(max_tp_ch, 1);
+ }
+ }
}
height = Rows;
width = Columns;
@@ -396,7 +410,7 @@ void check_screensize(void)
{
// Limit Rows and Columns to avoid an overflow in Rows * Columns.
// need room for one window and command line
- Rows = MIN(MAX(Rows, min_rows()), 1000);
+ Rows = MIN(MAX(Rows, min_rows_for_all_tabpages()), 1000);
Columns = MIN(MAX(Columns, MIN_COLUMNS), 10000);
}
@@ -665,6 +679,10 @@ int update_screen(void)
updating_screen = false;
+ if (need_maketitle) {
+ maketitle();
+ }
+
// Clear or redraw the command line. Done last, because scrolling may
// mess up the command line.
if (clear_cmdline || redraw_cmdline || redraw_mode) {
@@ -842,6 +860,19 @@ void setcursor_mayforce(win_T *wp, bool force)
}
}
+/// Mark the title and icon for redraw if either of them uses statusline format.
+///
+/// @return whether either title or icon uses statusline format.
+bool redraw_custom_title_later(void)
+{
+ if ((p_icon && (stl_syntax & STL_IN_ICON))
+ || (p_title && (stl_syntax & STL_IN_TITLE))) {
+ need_maketitle = true;
+ return true;
+ }
+ return false;
+}
+
/// Show current cursor info in ruler and various other places
///
/// @param always if false, only show ruler if position has changed.
@@ -875,10 +906,7 @@ void show_cursor_info_later(bool force)
curwin->w_redr_status = true;
}
- if ((p_icon && (stl_syntax & STL_IN_ICON))
- || (p_title && (stl_syntax & STL_IN_TITLE))) {
- need_maketitle = true;
- }
+ redraw_custom_title_later();
}
curwin->w_stl_cursor = curwin->w_cursor;
@@ -1502,10 +1530,12 @@ static void win_update(win_T *wp)
decor_providers_invoke_win(wp);
- if (win_redraw_signcols(wp)) {
- wp->w_lines_valid = 0;
- wp->w_redr_type = UPD_NOT_VALID;
- changed_line_abv_curs_win(wp);
+ FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
+ if (win->w_buffer == wp->w_buffer && win_redraw_signcols(win)) {
+ win->w_lines_valid = 0;
+ changed_line_abv_curs_win(win);
+ redraw_later(win, UPD_NOT_VALID);
+ }
}
init_search_hl(wp, &screen_search_hl);
@@ -2757,6 +2787,10 @@ void redraw_statuslines(void)
if (redraw_tabline) {
draw_tabline();
}
+
+ if (need_maketitle) {
+ maketitle();
+ }
}
/// Redraw all status lines at the bottom of frame "frp".
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 248f419807..f5e11a188f 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -604,7 +604,7 @@ static int insert_execute(VimState *state, int key)
|| (ins_compl_enter_selects()
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
&& stop_arrow() == OK) {
- ins_compl_delete();
+ ins_compl_delete(false);
ins_compl_insert(false);
}
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index cd3ccf543e..08c9cd3991 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -6049,6 +6049,7 @@ M.funcs = {
]=],
name = 'jobwait',
params = { { 'jobs', 'integer[]' }, { 'timeout', 'integer' } },
+ returns = 'integer[]',
signature = 'jobwait({jobs} [, {timeout}])',
},
join = {
@@ -8776,7 +8777,7 @@ M.funcs = {
<
]=],
name = 'rpcnotify',
- params = { { 'channel', 'integer' }, { 'event', 'string' }, { 'args', 'any' } },
+ params = { { 'channel', 'integer' }, { 'event', 'string' }, { '...', 'any' } },
signature = 'rpcnotify({channel}, {event} [, {args}...])',
},
rpcrequest = {
@@ -8789,7 +8790,7 @@ M.funcs = {
<
]=],
name = 'rpcrequest',
- params = { { 'channel', 'integer' }, { 'method', 'string' }, { 'args', 'any' } },
+ params = { { 'channel', 'integer' }, { 'method', 'string' }, { '...', 'any' } },
signature = 'rpcrequest({channel}, {method} [, {args}...])',
},
rpcstart = {
@@ -11155,7 +11156,7 @@ M.funcs = {
and exists only for backwards-compatibility.
With UTF-8 composing characters are handled properly: >vim
echo str2list("á") " returns [97, 769]
-
+ <
]=],
name = 'str2list',
params = { { 'string', 'string' }, { 'utf8', 'boolean' } },
@@ -13091,6 +13092,7 @@ M.funcs = {
]=],
name = 'winlayout',
params = { { 'tabnr', 'integer' } },
+ returns = 'any[]',
signature = 'winlayout([{tabnr}])',
},
winline = {
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 9968f32de1..b32a8b867f 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -6101,12 +6101,20 @@ static void ex_sleep(exarg_T *eap)
default:
semsg(_(e_invarg2), eap->arg); return;
}
- do_sleep(len);
+
+ // Hide the cursor if invoked with !
+ do_sleep(len, eap->forceit);
}
/// Sleep for "msec" milliseconds, but return early on CTRL-C.
-void do_sleep(int64_t msec)
+///
+/// @param hide_cursor hide the cursor if true
+void do_sleep(int64_t msec, bool hide_cursor)
{
+ if (hide_cursor) {
+ ui_busy_start();
+ }
+
ui_flush(); // flush before waiting
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, msec, got_int);
@@ -6115,6 +6123,10 @@ void do_sleep(int64_t msec)
if (got_int) {
vpeekc();
}
+
+ if (hide_cursor) {
+ ui_busy_stop();
+ }
}
/// ":winsize" command (obsolete).
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 2d9d4417dd..85fbdbd20a 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -847,6 +847,10 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
found_one = true;
}
+ if (redraw_custom_title_later()) {
+ found_one = true;
+ }
+
if (found_one) {
redraw_statuslines();
}
@@ -959,6 +963,7 @@ theend:
msg_ext_clear_later();
}
if (!cmd_silent) {
+ redraw_custom_title_later();
status_redraw_all(); // redraw to show mode change
}
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index c20c7dea23..6119d838f9 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -367,12 +367,23 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
marktree_itr_get(buf->b_marktree, (int32_t)l_row, l_col, itr);
while (true) {
MTKey mark = marktree_itr_current(itr);
- if (mark.pos.row < 0
- || mark.pos.row > u_row
- || (mark.pos.row == u_row && mark.pos.col > u_col)) {
+ if (mark.pos.row < 0 || mark.pos.row > u_row) {
break;
}
+ bool copy = true;
+ // No need to copy left gravity marks at the beginning of the range,
+ // and right gravity marks at the end of the range, unless invalidated.
+ if (mark.pos.row == l_row && mark.pos.col - !mt_right(mark) < l_col) {
+ copy = false;
+ } else if (mark.pos.row == u_row) {
+ if (mark.pos.col > u_col + 1) {
+ break;
+ } else if (mark.pos.col + mt_right(mark) > u_col) {
+ copy = false;
+ }
+ }
+
bool invalidated = false;
// Invalidate/delete mark
if (!only_copy && !mt_invalid(mark) && mt_invalidate(mark) && !mt_end(mark)) {
@@ -388,6 +399,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
extmark_del(buf, itr, mark, true);
continue;
} else {
+ copy = true;
invalidated = true;
mt_itr_rawkey(itr).flags |= MT_FLAG_INVALID;
marktree_revise_meta(buf->b_marktree, itr, mark);
@@ -397,7 +409,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
}
// Push mark to undo header
- if (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark))) {
+ if (copy && (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark)))) {
ExtmarkSavePos pos = {
.mark = mt_lookup_key(mark),
.invalidated = invalidated,
@@ -541,10 +553,8 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
if (old_row > 0 || old_col > 0) {
// Copy and invalidate 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!)
+ // TODO(bfredl): Be smart about marks that already have been
+ // saved (important for merge!)
int end_row = start_row + old_row;
int end_col = (old_row ? 0 : start_col) + old_col;
u_header_T *uhp = u_force_get_undo_header(buf);
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index a0a9c86789..890c260843 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -1,10 +1,37 @@
-local lpeg = vim.lpeg
-
-- lpeg grammar for building api metadata from a set of header files. It
-- ignores comments and preprocessor commands and parses a very small subset
-- of C prototypes with a limited set of types
+
+--- @class nvim.c_grammar.Proto
+--- @field [1] 'proto'
+--- @field pos integer
+--- @field endpos integer
+--- @field fast boolean
+--- @field name string
+--- @field return_type string
+--- @field parameters [string, string][]
+--- @field static true?
+--- @field inline true?
+
+--- @class nvim.c_grammar.Preproc
+--- @field [1] 'preproc'
+--- @field content string
+
+--- @class nvim.c_grammar.Empty
+--- @field [1] 'empty'
+
+--- @alias nvim.c_grammar.result
+--- | nvim.c_grammar.Proto
+--- | nvim.c_grammar.Preproc
+--- | nvim.c_grammar.Empty
+
+--- @class nvim.c_grammar
+--- @field match fun(self, input: string): nvim.c_grammar.result[]
+
+local lpeg = vim.lpeg
+
local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
-local C, Ct, Cc, Cg = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg
+local C, Ct, Cc, Cg, Cp = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cp
--- @param pat vim.lpeg.Pattern
local function rep(pat)
@@ -21,125 +48,253 @@ local function opt(pat)
return pat ^ -1
end
-local any = P(1) -- (consume one character)
+local any = P(1)
local letter = R('az', 'AZ') + S('_$')
local num = R('09')
local alpha = letter + num
local nl = P('\r\n') + P('\n')
-local not_nl = any - nl
local space = S(' \t')
+local str = P('"') * rep((P('\\') * any) + (1 - P('"'))) * P('"')
+local char = P("'") * (any - P("'")) * P("'")
local ws = space + nl
-local fill = rep(ws)
-local c_comment = P('//') * rep(not_nl)
-local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(not_nl), 'comment')))
-local c_preproc = P('#') * rep(not_nl)
-local dllexport = P('DLLEXPORT') * rep1(ws)
+local wb = #-alpha -- word boundary
+local id = letter * rep(alpha)
+
+local comment_inline = P('/*') * rep(1 - P('*/')) * P('*/')
+local comment = P('//') * rep(1 - nl) * nl
+local preproc = Ct(Cc('preproc') * P('#') * Cg(rep(1 - nl) * nl, 'content'))
+
+local fill = rep(ws + comment_inline + comment + preproc)
+
+--- @param s string
+--- @return vim.lpeg.Pattern
+local function word(s)
+ return fill * P(s) * wb * fill
+end
--- @param x vim.lpeg.Pattern
local function comma1(x)
return x * rep(fill * P(',') * fill * x)
end
--- Define the grammar
-
-local basic_id = letter * rep(alpha)
-
-local str = P('"') * rep(any - P('"')) * P('"')
+--- @param v string
+local function Pf(v)
+ return fill * P(v) * fill
+end
--- @param x vim.lpeg.Pattern
local function paren(x)
return P('(') * fill * x * fill * P(')')
end
+local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(1 - nl), 'comment')))
+
+local braces = P({
+ 'S',
+ A = comment_inline + comment + preproc + str + char + (any - S('{}')),
+ S = P('{') * rep(V('A')) * rep(V('S') + V('A')) * P('}'),
+})
+
-- stylua: ignore start
local typed_container = P({
'S',
- ID = V('S') + basic_id,
S = (
(P('Union') * paren(comma1(V('ID'))))
- + (P('ArrayOf') * paren(basic_id * opt(P(',') * fill * rep1(num))))
- + (P('DictOf') * paren(basic_id))
+ + (P('ArrayOf') * paren(id * opt(P(',') * fill * rep1(num))))
+ + (P('DictOf') * paren(id))
+ (P('LuaRefOf') * paren(
- paren(comma1((V('ID') + str) * rep1(ws) * opt(P('*')) * basic_id))
+ paren(comma1((V('ID') + str) * rep1(ws) * opt(P('*')) * id))
* opt(P(',') * fill * opt(P('*')) * V('ID'))
))
- + (P('Dict') * paren(basic_id))),
+ + (P('Dict') * paren(id))),
+ ID = V('S') + id,
})
-- stylua: ignore end
-local c_id = typed_container + basic_id
-local c_void = P('void')
+local ptr_mod = word('restrict') + word('__restrict') + word('const')
+local opt_ptr = rep(Pf('*') * opt(ptr_mod))
+
+--- @param name string
+--- @param var string
+--- @return vim.lpeg.Pattern
+local function attr(name, var)
+ return Cg((P(name) * Cc(true)), var)
+end
+
+--- @param name string
+--- @param var string
+--- @return vim.lpeg.Pattern
+local function attr_num(name, var)
+ return Cg((P(name) * paren(C(rep1(num)))), var)
+end
+
+local fattr = (
+ attr_num('FUNC_API_SINCE', 'since')
+ + attr_num('FUNC_API_DEPRECATED_SINCE', 'deprecated_since')
+ + attr('FUNC_API_FAST', 'fast')
+ + attr('FUNC_API_RET_ALLOC', 'ret_alloc')
+ + attr('FUNC_API_NOEXPORT', 'noexport')
+ + attr('FUNC_API_REMOTE_ONLY', 'remote_only')
+ + attr('FUNC_API_LUA_ONLY', 'lua_only')
+ + attr('FUNC_API_TEXTLOCK_ALLOW_CMDWIN', 'textlock_allow_cmdwin')
+ + attr('FUNC_API_TEXTLOCK', 'textlock')
+ + attr('FUNC_API_REMOTE_IMPL', 'remote_impl')
+ + attr('FUNC_API_COMPOSITOR_IMPL', 'compositor_impl')
+ + attr('FUNC_API_CLIENT_IMPL', 'client_impl')
+ + attr('FUNC_API_CLIENT_IGNORE', 'client_ignore')
+ + (P('FUNC_') * rep(alpha) * opt(fill * paren(rep(1 - P(')') * any))))
+)
+
+local void = P('void') * wb
-local c_param_type = (
- ((P('Error') * fill * P('*') * fill) * Cc('error'))
- + ((P('Arena') * fill * P('*') * fill) * Cc('arena'))
- + ((P('lua_State') * fill * P('*') * fill) * Cc('lstate'))
- + C(opt(P('const ')) * c_id * rep1(ws) * rep1(P('*')))
- + (C(c_id) * rep1(ws))
+local api_param_type = (
+ (word('Error') * opt_ptr * Cc('error'))
+ + (word('Arena') * opt_ptr * Cc('arena'))
+ + (word('lua_State') * opt_ptr * Cc('lstate'))
)
-local c_type = (C(c_void) * (ws ^ 1)) + c_param_type
-local c_param = Ct(c_param_type * C(c_id))
-local c_param_list = c_param * (fill * (P(',') * fill * c_param) ^ 0)
-local c_params = Ct(c_void + c_param_list)
+local ctype = C(
+ opt(word('const'))
+ * (
+ typed_container
+ -- 'unsigned' is a type modifier, and a type itself
+ + (word('unsigned char') + word('unsigned'))
+ + (word('struct') * fill * id)
+ + id
+ )
+ * opt(word('const'))
+ * opt_ptr
+)
-local impl_line = (any - P('}')) * opt(rep(not_nl)) * nl
+local return_type = (C(void) * fill) + ctype
-local ignore_line = rep1(not_nl) * nl
+-- stylua: ignore start
+local params = Ct(
+ (void * #P(')'))
+ + comma1(Ct(
+ (api_param_type + ctype)
+ * fill
+ * C(id)
+ * rep(Pf('[') * rep(alpha) * Pf(']'))
+ * rep(fill * fattr)
+ ))
+ * opt(Pf(',') * P('...'))
+)
+-- stylua: ignore end
+local ignore_line = rep1(1 - nl) * nl
local empty_line = Ct(Cc('empty') * nl * nl)
-local c_proto = Ct(
- Cc('proto')
- * opt(dllexport)
- * opt(Cg(P('static') * fill * Cc(true), 'static'))
- * Cg(c_type, 'return_type')
- * Cg(c_id, 'name')
- * fill
- * (P('(') * fill * Cg(c_params, 'parameters') * fill * P(')'))
- * Cg(Cc(false), 'fast')
- * (fill * Cg((P('FUNC_API_SINCE(') * C(rep1(num))) * P(')'), 'since') ^ -1)
- * (fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(rep1(num))) * P(')'), 'deprecated_since') ^ -1)
- * (fill * Cg((P('FUNC_API_FAST') * Cc(true)), 'fast') ^ -1)
- * (fill * Cg((P('FUNC_API_RET_ALLOC') * Cc(true)), 'ret_alloc') ^ -1)
- * (fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1)
- * (fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1)
- * (fill * Cg((P('FUNC_API_LUA_ONLY') * Cc(true)), 'lua_only') ^ -1)
- * (fill * (Cg(P('FUNC_API_TEXTLOCK_ALLOW_CMDWIN') * Cc(true), 'textlock_allow_cmdwin') + Cg(
- P('FUNC_API_TEXTLOCK') * Cc(true),
- 'textlock'
- )) ^ -1)
- * (fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1)
- * (fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1)
- * (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1)
- * (fill * Cg((P('FUNC_API_CLIENT_IGNORE') * Cc(true)), 'client_ignore') ^ -1)
- * fill
- * (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}')))
+local proto_name = opt_ptr * fill * id
+
+-- __inline is used in MSVC
+local decl_mod = (
+ Cg(word('static') * Cc(true), 'static')
+ + Cg((word('inline') + word('__inline')) * Cc(true), 'inline')
)
-local dict_key = P('DictKey(') * Cg(rep1(any - P(')')), 'dict_key') * P(')')
-local keyset_field =
- Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * (dict_key ^ -1) * fill * P(';') * fill)
-local c_keyset = Ct(
- P('typedef')
- * ws
- * P('struct')
+local proto = Ct(
+ Cg(Cp(), 'pos')
+ * Cc('proto')
+ * -#P('typedef')
+ * #alpha
+ * opt(P('DLLEXPORT') * rep1(ws))
+ * rep(decl_mod)
+ * Cg(return_type, 'return_type')
* fill
- * P('{')
+ * Cg(proto_name, 'name')
* fill
- * Cg(Ct(keyset_field ^ 1), 'fields')
- * P('}')
- * fill
- * P('Dict')
+ * paren(Cg(params, 'parameters'))
+ * Cg(Cc(false), 'fast')
+ * rep(fill * fattr)
+ * Cg(Cp(), 'endpos')
+ * (fill * (S(';') + braces))
+)
+
+local keyset_field = Ct(
+ Cg(ctype, 'type')
* fill
- * P('(')
- * Cg(c_id, 'keyset_name')
+ * Cg(id, 'name')
* fill
- * P(')')
- * P(';')
+ * opt(P('DictKey') * paren(Cg(rep1(1 - P(')')), 'dict_key')))
+ * Pf(';')
)
-local grammar = Ct(
- rep1(empty_line + c_proto + cdoc_comment + c_comment + c_preproc + ws + c_keyset + ignore_line)
+local keyset = Ct(
+ P('typedef')
+ * word('struct')
+ * Pf('{')
+ * Cg(Ct(rep1(keyset_field)), 'fields')
+ * Pf('}')
+ * P('Dict')
+ * paren(Cg(id, 'keyset_name'))
+ * Pf(';')
)
-return { grammar = grammar, typed_container = typed_container }
+
+local grammar =
+ Ct(rep1(empty_line + proto + cdoc_comment + comment + preproc + ws + keyset + ignore_line))
+
+if arg[1] == '--test' then
+ for i, t in ipairs({
+ 'void multiqueue_put_event(MultiQueue *self, Event event) {} ',
+ 'void *xmalloc(size_t size) {} ',
+ {
+ 'struct tm *os_localtime_r(const time_t *restrict clock,',
+ ' struct tm *restrict result) FUNC_ATTR_NONNULL_ALL {}',
+ },
+ {
+ '_Bool',
+ '# 163 "src/nvim/event/multiqueue.c"',
+ ' multiqueue_empty(MultiQueue *self)',
+ '{}',
+ },
+ 'const char *find_option_end(const char *arg, OptIndex *opt_idxp) {}',
+ 'bool semsg(const char *const fmt, ...) {}',
+ 'int32_t utf_ptr2CharInfo_impl(uint8_t const *p, uintptr_t const len) {}',
+ 'void ex_argdedupe(exarg_T *eap FUNC_ATTR_UNUSED) {}',
+ 'static TermKeySym register_c0(TermKey *tk, TermKeySym sym, unsigned char ctrl, const char *name) {}',
+ 'unsigned get_bkc_flags(buf_T *buf) {}',
+ 'char *xstpcpy(char *restrict dst, const char *restrict src) {}',
+ 'bool try_leave(const TryState *const tstate, Error *const err) {}',
+ 'void api_set_error(ErrorType errType) {}',
+ {
+ 'void nvim_subscribe(uint64_t channel_id, String event)',
+ 'FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(13) FUNC_API_REMOTE_ONLY',
+ '{}',
+ },
+
+ -- Do not consume leading preproc statements
+ {
+ '#line 1 "D:/a/neovim/neovim/src\\nvim/mark.h"',
+ 'static __inline int mark_global_index(const char name)',
+ ' FUNC_ATTR_CONST',
+ '{}',
+ },
+ {
+ '',
+ '#line 1 "D:/a/neovim/neovim/src\\nvim/mark.h"',
+ 'static __inline int mark_global_index(const char name)',
+ '{}',
+ },
+ {
+ 'size_t xstrlcpy(char *__restrict dst, const char *__restrict src, size_t dsize)',
+ ' FUNC_ATTR_NONNULL_ALL',
+ ' {}',
+ },
+ }) do
+ if type(t) == 'table' then
+ t = table.concat(t, '\n') .. '\n'
+ end
+ t = t:gsub(' +', ' ')
+ local r = grammar:match(t)
+ if not r then
+ print('Test ' .. i .. ' failed')
+ print(' |' .. table.concat(vim.split(t, '\n'), '\n |'))
+ end
+ end
+end
+
+return {
+ grammar = grammar --[[@as nvim.c_grammar]],
+ typed_container = typed_container,
+}
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 402382acd2..c987037324 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -1,3 +1,10 @@
+-- Example (manual) invocation:
+--
+-- make
+-- cp build/nvim_version.lua src/nvim/
+-- cd src/nvim
+-- nvim -l generators/gen_api_dispatch.lua "../../build/src/nvim/auto/api/private/dispatch_wrappers.generated.h" "../../build/src/nvim/auto/api/private/api_metadata.generated.h" "../../build/funcs_metadata.mpack" "../../build/src/nvim/auto/lua_api_c_bindings.generated.h" "../../build/src/nvim/auto/keysets_defs.generated.h" "../../build/ui_metadata.mpack" "../../build/cmake.config/auto/versiondef_git.h" "./api/autocmd.h" "./api/buffer.h" "./api/command.h" "./api/deprecated.h" "./api/extmark.h" "./api/keysets_defs.h" "./api/options.h" "./api/tabpage.h" "./api/ui.h" "./api/vim.h" "./api/vimscript.h" "./api/win_config.h" "./api/window.h" "../../build/include/api/autocmd.h.generated.h" "../../build/include/api/buffer.h.generated.h" "../../build/include/api/command.h.generated.h" "../../build/include/api/deprecated.h.generated.h" "../../build/include/api/extmark.h.generated.h" "../../build/include/api/options.h.generated.h" "../../build/include/api/tabpage.h.generated.h" "../../build/include/api/ui.h.generated.h" "../../build/include/api/vim.h.generated.h" "../../build/include/api/vimscript.h.generated.h" "../../build/include/api/win_config.h.generated.h" "../../build/include/api/window.h.generated.h"
+
local mpack = vim.mpack
local hashy = require 'generators.hashy'
@@ -8,7 +15,7 @@ assert(#arg >= pre_args)
local dispatch_outputf = arg[1]
-- output h file with packed metadata (api_metadata.generated.h)
local api_metadata_outputf = arg[2]
--- output metadata mpack file, for use by other build scripts (api_metadata.mpack)
+-- output metadata mpack file, for use by other build scripts (funcs_metadata.mpack)
local mpack_outputf = arg[3]
local lua_c_bindings_outputf = arg[4] -- lua_api_c_bindings.generated.c
local keysets_outputf = arg[5] -- keysets_defs.generated.h
@@ -235,7 +242,7 @@ for x in string.gmatch(ui_options_text, '"([a-z][a-z_]+)"') do
table.insert(ui_options, x)
end
-local version = require 'nvim_version'
+local version = require 'nvim_version' -- `build/nvim_version.lua` file.
local git_version = io.open(git_version_inputf):read '*a'
local version_build = string.match(git_version, '#define NVIM_VERSION_BUILD "([^"]+)"') or vim.NIL
@@ -266,10 +273,7 @@ fixdict(1 + #version)
for _, item in ipairs(version) do
-- NB: all items are mandatory. But any error will be less confusing
-- with placeholder vim.NIL (than invalid mpack data)
- local val = item[2]
- if val == nil then
- val = vim.NIL
- end
+ local val = item[2] == nil and vim.NIL or item[2]
put(item[1], val)
end
put('build', version_build)
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 30a83330eb..a3bb76cb91 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -98,7 +98,7 @@ local function call_ui_event_method(output, ev)
end
events = vim.tbl_filter(function(ev)
- return ev[1] ~= 'empty'
+ return ev[1] ~= 'empty' and ev[1] ~= 'preproc'
end, events)
for i = 1, #events do
diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua
index 2ec0e9ab68..6e1ea92572 100644
--- a/src/nvim/generators/gen_declarations.lua
+++ b/src/nvim/generators/gen_declarations.lua
@@ -1,136 +1,105 @@
-local fname = arg[1]
-local static_fname = arg[2]
-local non_static_fname = arg[3]
-local preproc_fname = arg[4]
-local static_basename = arg[5]
-
-local lpeg = vim.lpeg
-
-local fold = function(func, ...)
- local result = nil
- for _, v in ipairs({ ... }) do
- if result == nil then
- result = v
- else
- result = func(result, v)
+local grammar = require('generators.c_grammar').grammar
+
+--- @param fname string
+--- @return string?
+local function read_file(fname)
+ local f = io.open(fname, 'r')
+ if not f then
+ return
+ end
+ local contents = f:read('*a')
+ f:close()
+ return contents
+end
+
+--- @param fname string
+--- @param contents string[]
+local function write_file(fname, contents)
+ local contents_s = table.concat(contents, '\n') .. '\n'
+ local fcontents = read_file(fname)
+ if fcontents == contents_s then
+ return
+ end
+ local f = assert(io.open(fname, 'w'))
+ f:write(contents_s)
+ f:close()
+end
+
+--- @param fname string
+--- @param non_static_fname string
+--- @return string? non_static
+local function add_iwyu_non_static(fname, non_static_fname)
+ if fname:find('.*/src/nvim/.*%.c$') then
+ -- Add an IWYU pragma comment if the corresponding .h file exists.
+ local header_fname = fname:sub(1, -3) .. '.h'
+ local header_f = io.open(header_fname, 'r')
+ if header_f then
+ header_f:close()
+ return (header_fname:gsub('.*/src/nvim/', 'nvim/'))
end
+ elseif non_static_fname:find('/include/api/private/dispatch_wrappers%.h%.generated%.h$') then
+ return 'nvim/api/private/dispatch.h'
+ elseif non_static_fname:find('/include/ui_events_call%.h%.generated%.h$') then
+ return 'nvim/ui.h'
+ elseif non_static_fname:find('/include/ui_events_client%.h%.generated%.h$') then
+ return 'nvim/ui_client.h'
+ elseif non_static_fname:find('/include/ui_events_remote%.h%.generated%.h$') then
+ return 'nvim/api/ui.h'
end
- return result
end
-local folder = function(func)
- return function(...)
- return fold(func, ...)
+--- @param d string
+local function process_decl(d)
+ -- Comments are really handled by preprocessor, so the following is not
+ -- needed
+ d = d:gsub('/%*.-%*/', '')
+ d = d:gsub('//.-\n', '\n')
+ d = d:gsub('# .-\n', '')
+ d = d:gsub('\n', ' ')
+ d = d:gsub('%s+', ' ')
+ d = d:gsub(' ?%( ?', '(')
+ d = d:gsub(' ?, ?', ', ')
+ d = d:gsub(' ?(%*+) ?', ' %1')
+ d = d:gsub(' ?(FUNC_ATTR_)', ' %1')
+ d = d:gsub(' $', '')
+ d = d:gsub('^ ', '')
+ return d .. ';'
+end
+
+--- @param fname string
+--- @param text string
+--- @return string[] static
+--- @return string[] non_static
+--- @return boolean any_static
+local function gen_declarations(fname, text)
+ local non_static = {} --- @type string[]
+ local static = {} --- @type string[]
+
+ local neededfile = fname:match('[^/]+$')
+ local curfile = nil
+ local any_static = false
+ for _, node in ipairs(grammar:match(text)) do
+ if node[1] == 'preproc' then
+ curfile = node.content:match('^%a* %d+ "[^"]-/?([^"/]+)"') or curfile
+ elseif node[1] == 'proto' and curfile == neededfile then
+ local node_text = text:sub(node.pos, node.endpos - 1)
+ local declaration = process_decl(node_text)
+
+ if node.static then
+ if not any_static and declaration:find('FUNC_ATTR_') then
+ any_static = true
+ end
+ static[#static + 1] = declaration
+ else
+ non_static[#non_static + 1] = 'DLLEXPORT ' .. declaration
+ end
+ end
end
-end
-local lit = lpeg.P
-local set = function(...)
- return lpeg.S(fold(function(a, b)
- return a .. b
- end, ...))
-end
-local any_character = lpeg.P(1)
-local rng = function(s, e)
- return lpeg.R(s .. e)
-end
-local concat = folder(function(a, b)
- return a * b
-end)
-local branch = folder(function(a, b)
- return a + b
-end)
-local one_or_more = function(v)
- return v ^ 1
-end
-local two_or_more = function(v)
- return v ^ 2
-end
-local any_amount = function(v)
- return v ^ 0
-end
-local one_or_no = function(v)
- return v ^ -1
-end
-local look_behind = lpeg.B
-local look_ahead = function(v)
- return #v
-end
-local neg_look_ahead = function(v)
- return -v
-end
-local neg_look_behind = function(v)
- return -look_behind(v)
+ return static, non_static, any_static
end
-local w = branch(rng('a', 'z'), rng('A', 'Z'), lit('_'))
-local aw = branch(w, rng('0', '9'))
-local s = set(' ', '\n', '\t')
-local raw_word = concat(w, any_amount(aw))
-local right_word = concat(raw_word, neg_look_ahead(aw))
-local word = branch(
- concat(
- branch(lit('ArrayOf('), lit('DictOf('), lit('Dict(')), -- typed container macro
- one_or_more(any_character - lit(')')),
- lit(')')
- ),
- concat(neg_look_behind(aw), right_word)
-)
-local inline_comment =
- concat(lit('/*'), any_amount(concat(neg_look_ahead(lit('*/')), any_character)), lit('*/'))
-local spaces = any_amount(branch(
- s,
- -- Comments are really handled by preprocessor, so the following is not needed
- inline_comment,
- concat(lit('//'), any_amount(concat(neg_look_ahead(lit('\n')), any_character)), lit('\n')),
- -- Linemarker inserted by preprocessor
- concat(lit('# '), any_amount(concat(neg_look_ahead(lit('\n')), any_character)), lit('\n'))
-))
-local typ_part = concat(word, any_amount(concat(spaces, lit('*'))), spaces)
-
-local typ_id = two_or_more(typ_part)
-local arg = typ_id -- argument name is swallowed by typ
-local pattern = concat(
- any_amount(branch(set(' ', '\t'), inline_comment)),
- typ_id, -- return type with function name
- spaces,
- lit('('),
- spaces,
- one_or_no(branch( -- function arguments
- concat(
- arg, -- first argument, does not require comma
- any_amount(concat( -- following arguments, start with a comma
- spaces,
- lit(','),
- spaces,
- arg,
- any_amount(concat(lit('['), spaces, any_amount(aw), spaces, lit(']')))
- )),
- one_or_no(concat(spaces, lit(','), spaces, lit('...')))
- ),
- lit('void') -- also accepts just void
- )),
- spaces,
- lit(')'),
- any_amount(concat( -- optional attributes
- spaces,
- lit('FUNC_'),
- any_amount(aw),
- one_or_no(concat( -- attribute argument
- spaces,
- lit('('),
- any_amount(concat(neg_look_ahead(lit(')')), any_character)),
- lit(')')
- ))
- )),
- look_ahead(concat( -- definition must be followed by "{"
- spaces,
- lit('{')
- ))
-)
-
-if fname == '--help' then
- print([[
+local usage = [[
Usage:
gen_declarations.lua definitions.c static.h non-static.h definitions.i
@@ -141,204 +110,77 @@ non-static.h. File `definitions.i' should contain an already preprocessed
version of definitions.c and it is the only one which is actually parsed,
definitions.c is needed only to determine functions from which file out of all
functions found in definitions.i are needed and to generate an IWYU comment.
-
-Additionally uses the following environment variables:
-
- NVIM_GEN_DECLARATIONS_LINE_NUMBERS:
- If set to 1 then all generated declarations receive a comment with file
- name and line number after the declaration. This may be useful for
- debugging gen_declarations script, but not much beyond that with
- configured development environment (i.e. with with clang/etc).
-
- WARNING: setting this to 1 will cause extensive rebuilds: declarations
- generator script will not regenerate non-static.h file if its
- contents did not change, but including line numbers will make
- contents actually change.
-
- With contents changed timestamp of the file is regenerated even
- when no real changes were made (e.g. a few lines were added to
- a function which is not at the bottom of the file).
-
- With changed timestamp build system will assume that header
- changed, triggering rebuilds of all C files which depend on the
- "changed" header.
-]])
- os.exit()
-end
-
-local preproc_f = io.open(preproc_fname)
-local text = preproc_f:read('*all')
-preproc_f:close()
-
-local non_static = [[
-#define DEFINE_FUNC_ATTRIBUTES
-#include "nvim/func_attr.h"
-#undef DEFINE_FUNC_ATTRIBUTES
-#ifndef DLLEXPORT
-# ifdef MSWIN
-# define DLLEXPORT __declspec(dllexport)
-# else
-# define DLLEXPORT
-# endif
-#endif
-]]
-
-local static = [[
-#define DEFINE_FUNC_ATTRIBUTES
-#include "nvim/func_attr.h"
-#undef DEFINE_FUNC_ATTRIBUTES
]]
-local non_static_footer = [[
-#include "nvim/func_attr.h"
-]]
+local function main()
+ local fname = arg[1]
+ local static_fname = arg[2]
+ local non_static_fname = arg[3]
+ local preproc_fname = arg[4]
+ local static_basename = arg[5]
-local static_footer = [[
-#define DEFINE_EMPTY_ATTRIBUTES
-#include "nvim/func_attr.h" // IWYU pragma: export
-]]
-
-if fname:find('.*/src/nvim/.*%.c$') then
- -- Add an IWYU pragma comment if the corresponding .h file exists.
- local header_fname = fname:sub(1, -3) .. '.h'
- local header_f = io.open(header_fname, 'r')
- if header_f ~= nil then
- header_f:close()
- non_static = ([[
-// IWYU pragma: private, include "%s"
-]]):format(header_fname:gsub('.*/src/nvim/', 'nvim/')) .. non_static
+ if fname == '--help' or #arg < 5 then
+ print(usage)
+ os.exit()
end
-elseif fname:find('.*/src/nvim/.*%.h$') then
- static = ([[
-// IWYU pragma: private, include "%s"
-]]):format(fname:gsub('.*/src/nvim/', 'nvim/')) .. static
-elseif non_static_fname:find('/include/api/private/dispatch_wrappers%.h%.generated%.h$') then
- non_static = [[
-// IWYU pragma: private, include "nvim/api/private/dispatch.h"
-]] .. non_static
-elseif non_static_fname:find('/include/ui_events_call%.h%.generated%.h$') then
- non_static = [[
-// IWYU pragma: private, include "nvim/ui.h"
-]] .. non_static
-elseif non_static_fname:find('/include/ui_events_client%.h%.generated%.h$') then
- non_static = [[
-// IWYU pragma: private, include "nvim/ui_client.h"
-]] .. non_static
-elseif non_static_fname:find('/include/ui_events_remote%.h%.generated%.h$') then
- non_static = [[
-// IWYU pragma: private, include "nvim/api/ui.h"
-]] .. non_static
-end
-local filepattern = '^#%a* (%d+) "([^"]-)/?([^"/]+)"'
+ local text = assert(read_file(preproc_fname))
-local init = 1
-local curfile = nil
-local neededfile = fname:match('[^/]+$')
-local declline = 0
-local declendpos = 0
-local curdir = nil
-local is_needed_file = false
-local init_is_nl = true
-local any_static = false
-while init ~= nil do
- if init_is_nl and text:sub(init, init) == '#' then
- local line, dir, file = text:match(filepattern, init)
- if file ~= nil then
- curfile = file
- is_needed_file = (curfile == neededfile)
- declline = tonumber(line) - 1
- curdir = dir:gsub('.*/src/nvim/', '')
- else
- declline = declline - 1
- end
- elseif init < declendpos then -- luacheck: ignore 542
- -- Skipping over declaration
- elseif is_needed_file then
- s = init
- local e = pattern:match(text, init)
- if e ~= nil then
- local declaration = text:sub(s, e - 1)
- -- Comments are really handled by preprocessor, so the following is not
- -- needed
- declaration = declaration:gsub('/%*.-%*/', '')
- declaration = declaration:gsub('//.-\n', '\n')
-
- declaration = declaration:gsub('# .-\n', '')
+ local static_decls, non_static_decls, any_static = gen_declarations(fname, text)
- declaration = declaration:gsub('\n', ' ')
- declaration = declaration:gsub('%s+', ' ')
- declaration = declaration:gsub(' ?%( ?', '(')
- -- declaration = declaration:gsub(' ?%) ?', ')')
- declaration = declaration:gsub(' ?, ?', ', ')
- declaration = declaration:gsub(' ?(%*+) ?', ' %1')
- declaration = declaration:gsub(' ?(FUNC_ATTR_)', ' %1')
- declaration = declaration:gsub(' $', '')
- declaration = declaration:gsub('^ ', '')
- declaration = declaration .. ';'
-
- if os.getenv('NVIM_GEN_DECLARATIONS_LINE_NUMBERS') == '1' then
- declaration = declaration .. (' // %s/%s:%u'):format(curdir, curfile, declline)
- end
- declaration = declaration .. '\n'
- if declaration:sub(1, 6) == 'static' then
- if declaration:find('FUNC_ATTR_') then
- any_static = true
- end
- static = static .. declaration
- else
- declaration = 'DLLEXPORT ' .. declaration
- non_static = non_static .. declaration
- end
- declendpos = e
- end
- end
- init = text:find('[\n;}]', init)
- if init == nil then
- break
- end
- init_is_nl = text:sub(init, init) == '\n'
- init = init + 1
- if init_is_nl and is_needed_file then
- declline = declline + 1
+ local static = {} --- @type string[]
+ if fname:find('.*/src/nvim/.*%.h$') then
+ static[#static + 1] = ('// IWYU pragma: private, include "%s"'):format(
+ fname:gsub('.*/src/nvim/', 'nvim/')
+ )
end
-end
-
-non_static = non_static .. non_static_footer
-static = static .. static_footer
-
-local F
-F = io.open(static_fname, 'w')
-F:write(static)
-F:close()
-
-if any_static then
- F = io.open(fname, 'r')
- local orig_text = F:read('*a')
- local pat = '\n#%s?include%s+"' .. static_basename .. '"\n'
- local pat_comment = '\n#%s?include%s+"' .. static_basename .. '"%s*//'
- if not string.find(orig_text, pat) and not string.find(orig_text, pat_comment) then
- error('fail: missing include for ' .. static_basename .. ' in ' .. fname)
+ vim.list_extend(static, {
+ '#define DEFINE_FUNC_ATTRIBUTES',
+ '#include "nvim/func_attr.h"',
+ '#undef DEFINE_FUNC_ATTRIBUTES',
+ })
+ vim.list_extend(static, static_decls)
+ vim.list_extend(static, {
+ '#define DEFINE_EMPTY_ATTRIBUTES',
+ '#include "nvim/func_attr.h" // IWYU pragma: export',
+ '',
+ })
+
+ write_file(static_fname, static)
+
+ if any_static then
+ local orig_text = assert(read_file(fname))
+ local pat = '\n#%s?include%s+"' .. static_basename .. '"\n'
+ local pat_comment = '\n#%s?include%s+"' .. static_basename .. '"%s*//'
+ if not orig_text:find(pat) and not orig_text:find(pat_comment) then
+ error(('fail: missing include for %s in %s'):format(static_basename, fname))
+ end
end
- F:close()
-end
-if non_static_fname == 'SKIP' then
- return -- only want static declarations
-end
-
--- Before generating the non-static headers, check if the current file (if
--- exists) is different from the new one. If they are the same, we won't touch
--- the current version to avoid triggering an unnecessary rebuilds of modules
--- that depend on this one
-F = io.open(non_static_fname, 'r')
-if F ~= nil then
- if F:read('*a') == non_static then
- os.exit(0)
+ if non_static_fname ~= 'SKIP' then
+ local non_static = {} --- @type string[]
+ local iwyu_non_static = add_iwyu_non_static(fname, non_static_fname)
+ if iwyu_non_static then
+ non_static[#non_static + 1] = ('// IWYU pragma: private, include "%s"'):format(
+ iwyu_non_static
+ )
+ end
+ vim.list_extend(non_static, {
+ '#define DEFINE_FUNC_ATTRIBUTES',
+ '#include "nvim/func_attr.h"',
+ '#undef DEFINE_FUNC_ATTRIBUTES',
+ '#ifndef DLLEXPORT',
+ '# ifdef MSWIN',
+ '# define DLLEXPORT __declspec(dllexport)',
+ '# else',
+ '# define DLLEXPORT',
+ '# endif',
+ '#endif',
+ })
+ vim.list_extend(non_static, non_static_decls)
+ non_static[#non_static + 1] = '#include "nvim/func_attr.h"'
+ write_file(non_static_fname, non_static)
end
- F:close()
end
-F = io.open(non_static_fname, 'w')
-F:write(non_static)
-F:close()
+return main()
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 779b31e7a0..c79683dc00 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -47,7 +47,9 @@ end
--- @param s string
--- @return string
local lowercase_to_titlecase = function(s)
- return s:sub(1, 1):upper() .. s:sub(2)
+ return table.concat(vim.tbl_map(function(word) --- @param word string
+ return word:sub(1, 1):upper() .. word:sub(2)
+ end, vim.split(s, '[-_]')))
end
-- Generate options enum file
@@ -177,7 +179,7 @@ for _, option in ipairs(options_meta) do
vars_w(
(' kOpt%sFlag%s = 0x%02x,'):format(
opt_name,
- lowercase_to_titlecase(flag_name),
+ lowercase_to_titlecase(flag_name:gsub(':$', '')),
enum_values[flag_name]
)
)
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index b063a7708d..1a4b211f9c 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -1100,6 +1100,9 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(cterm, cterm_mask, italic, , HL_ITALIC);
CHECK_FLAG(cterm, cterm_mask, underline, , HL_UNDERLINE);
CHECK_FLAG(cterm, cterm_mask, undercurl, , HL_UNDERCURL);
+ CHECK_FLAG(cterm, cterm_mask, underdouble, , HL_UNDERDOUBLE);
+ CHECK_FLAG(cterm, cterm_mask, underdotted, , HL_UNDERDOTTED);
+ CHECK_FLAG(cterm, cterm_mask, underdashed, , HL_UNDERDASHED);
CHECK_FLAG(cterm, cterm_mask, standout, , HL_STANDOUT);
CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH);
CHECK_FLAG(cterm, cterm_mask, altfont, , HL_ALTFONT);
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 98b0d6003a..c9b7a1ba3f 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -14,6 +14,7 @@
#include "nvim/indent_c.h"
#include "nvim/macros_defs.h"
#include "nvim/mark_defs.h"
+#include "nvim/math.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/option.h"
@@ -1689,7 +1690,7 @@ void parse_cino(buf_T *buf)
p++;
}
char *digits_start = p; // remember where the digits start
- int n = getdigits_int(&p, true, 0);
+ int64_t n = getdigits_int(&p, true, 0);
divider = 0;
if (*p == '.') { // ".5s" means a fraction.
fraction = atoi(++p);
@@ -1708,7 +1709,7 @@ void parse_cino(buf_T *buf)
} else {
n *= sw;
if (divider) {
- n += (sw * fraction + divider / 2) / divider;
+ n += ((int64_t)sw * fraction + divider / 2) / divider;
}
}
p++;
@@ -1717,119 +1718,121 @@ void parse_cino(buf_T *buf)
n = -n;
}
+ n = trim_to_int(n);
+
// When adding an entry here, also update the default 'cinoptions' in
// doc/indent.txt, and add explanation for it!
switch (*l) {
case '>':
- buf->b_ind_level = n;
+ buf->b_ind_level = (int)n;
break;
case 'e':
- buf->b_ind_open_imag = n;
+ buf->b_ind_open_imag = (int)n;
break;
case 'n':
- buf->b_ind_no_brace = n;
+ buf->b_ind_no_brace = (int)n;
break;
case 'f':
- buf->b_ind_first_open = n;
+ buf->b_ind_first_open = (int)n;
break;
case '{':
- buf->b_ind_open_extra = n;
+ buf->b_ind_open_extra = (int)n;
break;
case '}':
- buf->b_ind_close_extra = n;
+ buf->b_ind_close_extra = (int)n;
break;
case '^':
- buf->b_ind_open_left_imag = n;
+ buf->b_ind_open_left_imag = (int)n;
break;
case 'L':
- buf->b_ind_jump_label = n;
+ buf->b_ind_jump_label = (int)n;
break;
case ':':
- buf->b_ind_case = n;
+ buf->b_ind_case = (int)n;
break;
case '=':
- buf->b_ind_case_code = n;
+ buf->b_ind_case_code = (int)n;
break;
case 'b':
- buf->b_ind_case_break = n;
+ buf->b_ind_case_break = (int)n;
break;
case 'p':
- buf->b_ind_param = n;
+ buf->b_ind_param = (int)n;
break;
case 't':
- buf->b_ind_func_type = n;
+ buf->b_ind_func_type = (int)n;
break;
case '/':
- buf->b_ind_comment = n;
+ buf->b_ind_comment = (int)n;
break;
case 'c':
- buf->b_ind_in_comment = n;
+ buf->b_ind_in_comment = (int)n;
break;
case 'C':
- buf->b_ind_in_comment2 = n;
+ buf->b_ind_in_comment2 = (int)n;
break;
case 'i':
- buf->b_ind_cpp_baseclass = n;
+ buf->b_ind_cpp_baseclass = (int)n;
break;
case '+':
- buf->b_ind_continuation = n;
+ buf->b_ind_continuation = (int)n;
break;
case '(':
- buf->b_ind_unclosed = n;
+ buf->b_ind_unclosed = (int)n;
break;
case 'u':
- buf->b_ind_unclosed2 = n;
+ buf->b_ind_unclosed2 = (int)n;
break;
case 'U':
- buf->b_ind_unclosed_noignore = n;
+ buf->b_ind_unclosed_noignore = (int)n;
break;
case 'W':
- buf->b_ind_unclosed_wrapped = n;
+ buf->b_ind_unclosed_wrapped = (int)n;
break;
case 'w':
- buf->b_ind_unclosed_whiteok = n;
+ buf->b_ind_unclosed_whiteok = (int)n;
break;
case 'm':
- buf->b_ind_matching_paren = n;
+ buf->b_ind_matching_paren = (int)n;
break;
case 'M':
- buf->b_ind_paren_prev = n;
+ buf->b_ind_paren_prev = (int)n;
break;
case ')':
- buf->b_ind_maxparen = n;
+ buf->b_ind_maxparen = (int)n;
break;
case '*':
- buf->b_ind_maxcomment = n;
+ buf->b_ind_maxcomment = (int)n;
break;
case 'g':
- buf->b_ind_scopedecl = n;
+ buf->b_ind_scopedecl = (int)n;
break;
case 'h':
- buf->b_ind_scopedecl_code = n;
+ buf->b_ind_scopedecl_code = (int)n;
break;
case 'j':
- buf->b_ind_java = n;
+ buf->b_ind_java = (int)n;
break;
case 'J':
- buf->b_ind_js = n;
+ buf->b_ind_js = (int)n;
break;
case 'l':
- buf->b_ind_keep_case_label = n;
+ buf->b_ind_keep_case_label = (int)n;
break;
case '#':
- buf->b_ind_hash_comment = n;
+ buf->b_ind_hash_comment = (int)n;
break;
case 'N':
- buf->b_ind_cpp_namespace = n;
+ buf->b_ind_cpp_namespace = (int)n;
break;
case 'k':
- buf->b_ind_if_for_while = n;
+ buf->b_ind_if_for_while = (int)n;
break;
case 'E':
- buf->b_ind_cpp_extern_c = n;
+ buf->b_ind_cpp_extern_c = (int)n;
break;
case 'P':
- buf->b_ind_pragma = n;
+ buf->b_ind_pragma = (int)n;
break;
}
if (*p == ',') {
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index d3517667fb..b18c4ead41 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -156,6 +156,7 @@ typedef struct compl_S compl_T;
struct compl_S {
compl_T *cp_next;
compl_T *cp_prev;
+ compl_T *cp_match_next; ///< matched next compl_T
char *cp_str; ///< matched text
char *(cp_text[CPT_COUNT]); ///< text for the menu
typval_T cp_user_data;
@@ -560,11 +561,19 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_match;
}
-static void do_autocmd_completedone(int c)
+static void do_autocmd_completedone(int c, int mode, char *word)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
+ mode = mode & ~CTRL_X_WANT_IDENT;
+ char *mode_str = NULL;
+ if (ctrl_x_mode_names[mode]) {
+ mode_str = ctrl_x_mode_names[mode];
+ }
+ tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : "");
+ tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : "");
+
tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event);
@@ -758,7 +767,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir
flags |= CP_ICASE;
}
- int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, -1, -1);
+ int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, NULL);
xfree(tofree);
return res;
}
@@ -789,6 +798,7 @@ static inline void free_cptext(char *const *const cptext)
/// @param[in] cdir match direction. If 0, use "compl_direction".
/// @param[in] flags_arg match flags (cp_flags)
/// @param[in] adup accept this match even if it is already present.
+/// @param[in] user_hl list of extra highlight attributes for abbr kind.
///
/// If "cdir" is FORWARD, then the match is added after the current match.
/// Otherwise, it is added before the current match.
@@ -798,7 +808,7 @@ static inline void free_cptext(char *const *const cptext)
/// returned in case of error.
static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext,
const bool cptext_allocated, typval_T *user_data, const Direction cdir,
- int flags_arg, const bool adup, int user_abbr_hlattr, int user_kind_hlattr)
+ int flags_arg, const bool adup, const int *user_hl)
FUNC_ATTR_NONNULL_ARG(1)
{
compl_T *match;
@@ -864,8 +874,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match->cp_fname = NULL;
}
match->cp_flags = flags;
- match->cp_user_abbr_hlattr = user_abbr_hlattr;
- match->cp_user_kind_hlattr = user_kind_hlattr;
+ match->cp_user_abbr_hlattr = user_hl ? user_hl[0] : -1;
+ match->cp_user_kind_hlattr = user_hl ? user_hl[1] : -1;
if (cptext != NULL) {
int i;
@@ -941,14 +951,14 @@ static void ins_compl_longest_match(compl_T *match)
compl_leader = xstrdup(match->cp_str);
bool had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
+ ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
- ins_compl_delete();
+ ins_compl_delete(false);
}
compl_used_match = false;
@@ -975,14 +985,14 @@ static void ins_compl_longest_match(compl_T *match)
// Leader was shortened, need to change the inserted text.
*p = NUL;
bool had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
+ ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
- ins_compl_delete();
+ ins_compl_delete(false);
}
}
@@ -999,7 +1009,7 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase)
for (int i = 0; i < num_matches && add_r != FAIL; i++) {
if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
CP_FAST | (icase ? CP_ICASE : 0),
- false, -1, -1)) == OK) {
+ false, NULL)) == OK) {
// If dir was BACKWARD then honor it just once.
dir = FORWARD;
}
@@ -1173,29 +1183,7 @@ static int ins_compl_build_pum(void)
unsigned cur_cot_flags = get_cot_flags();
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0;
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
-
- do {
- // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
- // set the cp_score for later comparisons.
- if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
- comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader);
- }
-
- if (!match_at_original_text(comp)
- && (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
- || (compl_fuzzy_match && comp->cp_score > 0))) {
- compl_match_arraysize++;
- }
- comp = comp->cp_next;
- } while (comp != NULL && !is_first_match(comp));
-
- if (compl_match_arraysize == 0) {
- return -1;
- }
-
- assert(compl_match_arraysize >= 0);
- compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
+ compl_T *match_head = NULL, *match_tail = NULL;
// If the current match is the original text don't find the first
// match after it, don't highlight anything.
@@ -1205,16 +1193,29 @@ static int ins_compl_build_pum(void)
compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next;
}
- compl_T *shown_compl = NULL;
bool did_find_shown_match = false;
- int cur = -1;
+ compl_T *shown_compl = NULL;
int i = 0;
- comp = compl_first_match;
+ int cur = -1;
+
do {
+ // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
+ // set the cp_score for later comparisons.
+ if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader);
+ }
+
if (!match_at_original_text(comp)
&& (compl_leader == NULL
|| ins_compl_equal(comp, compl_leader, (size_t)lead_len)
|| (compl_fuzzy_match && comp->cp_score > 0))) {
+ compl_match_arraysize++;
+ if (match_head == NULL) {
+ match_head = comp;
+ } else {
+ match_tail->cp_match_next = comp;
+ }
+ match_tail = comp;
if (!shown_match_ok && !compl_fuzzy_match) {
if (comp == compl_shown_match || did_find_shown_match) {
// This item is the shown match or this is the
@@ -1241,51 +1242,21 @@ static int ins_compl_build_pum(void)
compl_shown_match = comp;
}
}
-
if (!shown_match_ok && comp == compl_shown_match && !compl_no_select) {
cur = i;
shown_match_ok = true;
}
-
- // If there is no "no select" condition and the max fuzzy
- // score is positive, or there is no completion leader or the
- // leader length is zero, mark the shown match as valid and
- // reset the current index.
- if (!compl_no_select
- && (max_fuzzy_score > 0
- || (compl_leader == NULL || lead_len == 0))) {
- if (match_at_original_text(compl_shown_match)) {
- compl_shown_match = shown_compl;
- }
- }
- }
-
- if (comp->cp_text[CPT_ABBR] != NULL) {
- compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR];
- } else {
- compl_match_array[i].pum_text = comp->cp_str;
- }
- compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
- compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
- compl_match_array[i].pum_score = comp->cp_score;
- compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr;
- compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr;
- if (comp->cp_text[CPT_MENU] != NULL) {
- compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
- } else {
- compl_match_array[i++].pum_extra = comp->cp_fname;
}
+ i++;
}
if (comp == compl_shown_match && !compl_fuzzy_match) {
did_find_shown_match = true;
-
// When the original text is the shown match don't set
// compl_shown_match.
if (match_at_original_text(comp)) {
shown_match_ok = true;
}
-
if (!shown_match_ok && shown_compl != NULL) {
// The shown match isn't displayed, set it to the
// previously displayed match.
@@ -1296,6 +1267,36 @@ static int ins_compl_build_pum(void)
comp = comp->cp_next;
} while (comp != NULL && !is_first_match(comp));
+ if (compl_match_arraysize == 0) {
+ return -1;
+ }
+
+ assert(compl_match_arraysize >= 0);
+ compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
+
+ i = 0;
+ comp = match_head;
+ while (comp != NULL) {
+ if (comp->cp_text[CPT_ABBR] != NULL) {
+ compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR];
+ } else {
+ compl_match_array[i].pum_text = comp->cp_str;
+ }
+ compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
+ compl_match_array[i].pum_score = comp->cp_score;
+ compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr;
+ compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr;
+ if (comp->cp_text[CPT_MENU] != NULL) {
+ compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
+ } else {
+ compl_match_array[i++].pum_extra = comp->cp_fname;
+ }
+ compl_T *match_next = comp->cp_match_next;
+ comp->cp_match_next = NULL;
+ comp = match_next;
+ }
+
if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
for (i = 0; i < compl_match_arraysize; i++) {
compl_match_array[i].pum_idx = i;
@@ -1810,7 +1811,7 @@ static bool ins_compl_need_restart(void)
static void ins_compl_new_leader(void)
{
ins_compl_del_pum();
- ins_compl_delete();
+ ins_compl_delete(true);
ins_bytes(compl_leader + get_compl_len());
compl_used_match = false;
@@ -2121,19 +2122,21 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
}
+ char *word = NULL;
// If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) {
+ word = xstrdup(compl_shown_match->cp_str);
retval = true;
}
// CTRL-E means completion is Ended, go back to the typed text.
// but only do this, if the Popup is still visible
if (c == Ctrl_E) {
- ins_compl_delete();
+ ins_compl_delete(false);
char *p = NULL;
if (compl_leader != NULL) {
p = compl_leader;
@@ -2184,7 +2187,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, prev_mode, word);
+ xfree(word);
return retval;
}
@@ -2273,7 +2277,7 @@ bool ins_compl_prep(int c)
} else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
// Trigger the CompleteDone event to give scripts a chance to act
// upon the (possibly failed) completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, ctrl_x_mode, NULL);
}
may_trigger_modechanged();
@@ -2573,9 +2577,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
int flags = fast ? CP_FAST : 0;
char *(cptext[CPT_COUNT]);
char *user_abbr_hlname = NULL;
- int user_abbr_hlattr = -1;
char *user_kind_hlname = NULL;
- int user_kind_hlattr = -1;
+ int user_hl[2] = { -1, -1 };
typval_T user_data;
user_data.v_type = VAR_UNKNOWN;
@@ -2587,10 +2590,10 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
user_abbr_hlname = tv_dict_get_string(tv->vval.v_dict, "abbr_hlgroup", false);
- user_abbr_hlattr = get_user_highlight_attr(user_abbr_hlname);
+ user_hl[0] = get_user_highlight_attr(user_abbr_hlname);
user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false);
- user_kind_hlattr = get_user_highlight_attr(user_kind_hlname);
+ user_hl[1] = get_user_highlight_attr(user_kind_hlname);
tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
@@ -2613,8 +2616,7 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
return FAIL;
}
int status = ins_compl_add((char *)word, -1, NULL, cptext, true,
- &user_data, dir, flags, dup,
- user_abbr_hlattr, user_kind_hlattr);
+ &user_data, dir, flags, dup, user_hl);
if (status != OK) {
tv_clear(&user_data);
}
@@ -2707,7 +2709,7 @@ static void set_completion(colnr_T startcol, list_T *list)
flags |= CP_ICASE;
}
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags | CP_FAST, false, -1, -1) != OK) {
+ flags | CP_FAST, false, NULL) != OK) {
return;
}
@@ -3452,7 +3454,7 @@ static void get_next_bufname_token(void)
char *tail = path_tail(b->b_sfname);
if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) {
ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0,
- p_ic ? CP_ICASE : 0, false, -1, -1);
+ p_ic ? CP_ICASE : 0, false, NULL);
}
}
}
@@ -3607,11 +3609,24 @@ static void ins_compl_update_shown_match(void)
}
/// Delete the old text being completed.
-void ins_compl_delete(void)
+void ins_compl_delete(bool new_leader)
{
+ // Avoid deleting text that will be reinserted when changing leader. This
+ // allows marks present on the original text to shrink/grow appropriately.
+ int orig_col = 0;
+ if (new_leader) {
+ char *orig = compl_orig_text;
+ char *leader = ins_compl_leader();
+ while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) {
+ leader += utf_ptr2len(leader);
+ orig += utf_ptr2len(orig);
+ }
+ orig_col = (int)(orig - compl_orig_text);
+ }
+
// In insert mode: Delete the typed part.
// In replace mode: Put the old characters back, if any.
- int col = compl_col + (compl_status_adding() ? compl_length : 0);
+ int col = compl_col + (compl_status_adding() ? compl_length : orig_col);
if ((int)curwin->w_cursor.col > col) {
if (stop_arrow() == FAIL) {
return;
@@ -3855,7 +3870,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
if (allow_get_expansion && insert_match
&& (!compl_get_longest || compl_used_match)) {
// Delete old text to be replaced
- ins_compl_delete();
+ ins_compl_delete(false);
}
// When finding the longest common text we stick at the original text,
@@ -3908,7 +3923,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
// Delete old text to be replaced, since we're still searching and
// don't want to match ourselves!
- ins_compl_delete();
+ ins_compl_delete(false);
}
// Enter will select a match when the match wasn't inserted and the popup
@@ -4490,7 +4505,7 @@ static int ins_compl_start(void)
flags |= CP_ICASE;
}
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags, false, -1, -1) != OK) {
+ flags, false, NULL) != OK) {
XFREE_CLEAR(compl_pattern);
compl_patternlen = 0;
XFREE_CLEAR(compl_orig_text);
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index e719d99640..5ebff3a809 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -619,6 +619,7 @@ static int nlua_with(lua_State *L)
int rets = 0;
cmdmod_T save_cmdmod = cmdmod;
+ CLEAR_FIELD(cmdmod);
cmdmod.cmod_flags = flags;
apply_cmdmod(&cmdmod);
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 555fef5bbd..5ccd4fd45d 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -2330,7 +2330,6 @@ void marktree_check(MarkTree *b)
#endif
}
-#ifndef NDEBUG
size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right,
const uint32_t *meta_node_ref)
{
@@ -2485,8 +2484,6 @@ bool mt_recurse_nodes_compare(MTNode *x, PMap(ptr_t) *checked)
return true;
}
-#endif
-
// TODO(bfredl): kv_print
#define GA_PUT(x) ga_concat(ga, (char *)(x))
#define GA_PRINT(fmt, ...) snprintf(buf, sizeof(buf), fmt, __VA_ARGS__); \
diff --git a/src/nvim/math.c b/src/nvim/math.c
index 4ca212413b..0b5886d36c 100644
--- a/src/nvim/math.c
+++ b/src/nvim/math.c
@@ -106,3 +106,9 @@ int vim_append_digit_int(int *value, int digit)
*value = x * 10 + digit;
return OK;
}
+
+/// Return something that fits into an int.
+int trim_to_int(int64_t x)
+{
+ return x > INT_MAX ? INT_MAX : x < INT_MIN ? INT_MIN : (int)x;
+}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 0b1156a6bd..edb332a786 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -26,6 +26,7 @@
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/ex_cmds_defs.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/fileio.h"
#include "nvim/garray.h"
@@ -94,6 +95,16 @@ static char *confirm_msg_tail; // tail of confirm_msg
MessageHistoryEntry *first_msg_hist = NULL;
MessageHistoryEntry *last_msg_hist = NULL;
static int msg_hist_len = 0;
+static int msg_hist_max = 500; // The default max value is 500
+
+// args in 'messagesopt' option
+#define MESSAGES_OPT_HIT_ENTER "hit-enter"
+#define MESSAGES_OPT_WAIT "wait:"
+#define MESSAGES_OPT_HISTORY "history:"
+
+// The default is "hit-enter,history:500"
+static int msg_flags = kOptMoptFlagHitEnter | kOptMoptFlagHistory;
+static int msg_wait = 0;
static FILE *verbose_fd = NULL;
static bool verbose_did_open = false;
@@ -1038,14 +1049,76 @@ int delete_first_msg(void)
return OK;
}
-void check_msg_hist(void)
+static void check_msg_hist(void)
{
// Don't let the message history get too big
- while (msg_hist_len > 0 && msg_hist_len > p_mhi) {
+ while (msg_hist_len > 0 && msg_hist_len > msg_hist_max) {
(void)delete_first_msg();
}
}
+int messagesopt_changed(void)
+{
+ int messages_flags_new = 0;
+ int messages_wait_new = 0;
+ int messages_history_new = 0;
+
+ char *p = p_mopt;
+ while (*p != NUL) {
+ if (strnequal(p, S_LEN(MESSAGES_OPT_HIT_ENTER))) {
+ p += STRLEN_LITERAL(MESSAGES_OPT_HIT_ENTER);
+ messages_flags_new |= kOptMoptFlagHitEnter;
+ } else if (strnequal(p, S_LEN(MESSAGES_OPT_WAIT))
+ && ascii_isdigit(p[STRLEN_LITERAL(MESSAGES_OPT_WAIT)])) {
+ p += STRLEN_LITERAL(MESSAGES_OPT_WAIT);
+ messages_wait_new = getdigits_int(&p, false, INT_MAX);
+ messages_flags_new |= kOptMoptFlagWait;
+ } else if (strnequal(p, S_LEN(MESSAGES_OPT_HISTORY))
+ && ascii_isdigit(p[STRLEN_LITERAL(MESSAGES_OPT_HISTORY)])) {
+ p += STRLEN_LITERAL(MESSAGES_OPT_HISTORY);
+ messages_history_new = getdigits_int(&p, false, INT_MAX);
+ messages_flags_new |= kOptMoptFlagHistory;
+ }
+
+ if (*p != ',' && *p != NUL) {
+ return FAIL;
+ }
+ if (*p == ',') {
+ p++;
+ }
+ }
+
+ // Either "wait" or "hit-enter" is required
+ if (!(messages_flags_new & (kOptMoptFlagHitEnter | kOptMoptFlagWait))) {
+ return FAIL;
+ }
+
+ // "history" must be set
+ if (!(messages_flags_new & kOptMoptFlagHistory)) {
+ return FAIL;
+ }
+
+ assert(messages_history_new >= 0);
+ // "history" must be <= 10000
+ if (messages_history_new > 10000) {
+ return FAIL;
+ }
+
+ assert(messages_wait_new >= 0);
+ // "wait" must be <= 10000
+ if (messages_wait_new > 10000) {
+ return FAIL;
+ }
+
+ msg_flags = messages_flags_new;
+ msg_wait = messages_wait_new;
+
+ msg_hist_max = messages_history_new;
+ check_msg_hist();
+
+ return OK;
+}
+
/// :messages command implementation
void ex_messages(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
@@ -1209,83 +1282,88 @@ void wait_return(int redraw)
cmdline_row = Rows - 1;
}
- hit_return_msg(true);
-
- do {
- // Remember "got_int", if it is set vgetc() probably returns a
- // CTRL-C, but we need to loop then.
- had_got_int = got_int;
-
- // Don't do mappings here, we put the character back in the
- // typeahead buffer.
- no_mapping++;
- allow_keys++;
-
- // Temporarily disable Recording. If Recording is active, the
- // character will be recorded later, since it will be added to the
- // typebuf after the loop
- const int save_reg_recording = reg_recording;
- save_scriptout = scriptout;
- reg_recording = 0;
- scriptout = NULL;
- c = safe_vgetc();
- if (had_got_int && !global_busy) {
- got_int = false;
- }
- no_mapping--;
- allow_keys--;
- reg_recording = save_reg_recording;
- scriptout = save_scriptout;
-
- // Allow scrolling back in the messages.
- // Also accept scroll-down commands when messages fill the screen,
- // to avoid that typing one 'j' too many makes the messages
- // disappear.
- if (p_more) {
- if (c == 'b' || c == 'k' || c == 'u' || c == 'g'
- || c == K_UP || c == K_PAGEUP) {
- if (msg_scrolled > Rows) {
- // scroll back to show older messages
- do_more_prompt(c);
- } else {
- msg_didout = false;
- c = K_IGNORE;
- msg_col = 0;
- }
- if (quit_more) {
- c = CAR; // just pretend CR was hit
- quit_more = false;
- got_int = false;
- } else if (c != K_IGNORE) {
+ if (msg_flags & kOptMoptFlagHitEnter) {
+ hit_return_msg(true);
+
+ do {
+ // Remember "got_int", if it is set vgetc() probably returns a
+ // CTRL-C, but we need to loop then.
+ had_got_int = got_int;
+
+ // Don't do mappings here, we put the character back in the
+ // typeahead buffer.
+ no_mapping++;
+ allow_keys++;
+
+ // Temporarily disable Recording. If Recording is active, the
+ // character will be recorded later, since it will be added to the
+ // typebuf after the loop
+ const int save_reg_recording = reg_recording;
+ save_scriptout = scriptout;
+ reg_recording = 0;
+ scriptout = NULL;
+ c = safe_vgetc();
+ if (had_got_int && !global_busy) {
+ got_int = false;
+ }
+ no_mapping--;
+ allow_keys--;
+ reg_recording = save_reg_recording;
+ scriptout = save_scriptout;
+
+ // Allow scrolling back in the messages.
+ // Also accept scroll-down commands when messages fill the screen,
+ // to avoid that typing one 'j' too many makes the messages
+ // disappear.
+ if (p_more) {
+ if (c == 'b' || c == 'k' || c == 'u' || c == 'g'
+ || c == K_UP || c == K_PAGEUP) {
+ if (msg_scrolled > Rows) {
+ // scroll back to show older messages
+ do_more_prompt(c);
+ } else {
+ msg_didout = false;
+ c = K_IGNORE;
+ msg_col = 0;
+ }
+ if (quit_more) {
+ c = CAR; // just pretend CR was hit
+ quit_more = false;
+ got_int = false;
+ } else if (c != K_IGNORE) {
+ c = K_IGNORE;
+ hit_return_msg(false);
+ }
+ } else if (msg_scrolled > Rows - 2
+ && (c == 'j' || c == 'd' || c == 'f'
+ || c == K_DOWN || c == K_PAGEDOWN)) {
c = K_IGNORE;
- hit_return_msg(false);
}
- } else if (msg_scrolled > Rows - 2
- && (c == 'j' || c == 'd' || c == 'f'
- || c == K_DOWN || c == K_PAGEDOWN)) {
- c = K_IGNORE;
}
+ } while ((had_got_int && c == Ctrl_C)
+ || c == K_IGNORE
+ || c == K_LEFTDRAG || c == K_LEFTRELEASE
+ || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
+ || c == K_RIGHTDRAG || c == K_RIGHTRELEASE
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT
+ || c == K_MOUSEDOWN || c == K_MOUSEUP
+ || c == K_MOUSEMOVE);
+ os_breakcheck();
+
+ // Avoid that the mouse-up event causes visual mode to start.
+ if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
+ || c == K_X1MOUSE || c == K_X2MOUSE) {
+ jump_to_mouse(MOUSE_SETPOS, NULL, 0);
+ } else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) {
+ // Put the character back in the typeahead buffer. Don't use the
+ // stuff buffer, because lmaps wouldn't work.
+ ins_char_typebuf(vgetc_char, vgetc_mod_mask, true);
+ do_redraw = true; // need a redraw even though there is typeahead
}
- } while ((had_got_int && c == Ctrl_C)
- || c == K_IGNORE
- || c == K_LEFTDRAG || c == K_LEFTRELEASE
- || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
- || c == K_RIGHTDRAG || c == K_RIGHTRELEASE
- || c == K_MOUSELEFT || c == K_MOUSERIGHT
- || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSEMOVE);
- os_breakcheck();
-
- // Avoid that the mouse-up event causes visual mode to start.
- if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
- || c == K_X1MOUSE || c == K_X2MOUSE) {
- jump_to_mouse(MOUSE_SETPOS, NULL, 0);
- } else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) {
- // Put the character back in the typeahead buffer. Don't use the
- // stuff buffer, because lmaps wouldn't work.
- ins_char_typebuf(vgetc_char, vgetc_mod_mask, true);
- do_redraw = true; // need a redraw even though there is
- // typeahead
+ } else {
+ c = CAR;
+ // Wait to allow the user to verify the output.
+ do_sleep(msg_wait, true);
}
}
redir_off = false;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index ba84380529..4d2abf1c8c 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -812,7 +812,7 @@ static void normal_get_additional_char(NormalState *s)
// There is a busy wait here when typing "f<C-\>" and then
// something different from CTRL-N. Can't be avoided.
while ((s->c = vpeekc()) <= 0 && towait > 0) {
- do_sleep(towait > 50 ? 50 : towait);
+ do_sleep(towait > 50 ? 50 : towait, false);
towait -= 50;
}
if (s->c > 0) {
@@ -1372,10 +1372,6 @@ static void normal_redraw(NormalState *s)
}
}
- if (need_maketitle) {
- maketitle();
- }
-
curbuf->b_last_used = time(NULL);
// Display message after redraw. If an external message is still visible,
@@ -5561,7 +5557,7 @@ static void nv_g_cmd(cmdarg_T *cap)
// "gs": Goto sleep.
case 's':
- do_sleep(cap->count1 * 1000);
+ do_sleep(cap->count1 * 1000, false);
break;
// "ga": Display the ascii value of the character under the
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 63c78936ba..71a005bd24 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -48,6 +48,7 @@
#include "nvim/macros_defs.h"
#include "nvim/mark.h"
#include "nvim/mark_defs.h"
+#include "nvim/math.h"
#include "nvim/mbyte.h"
#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
@@ -273,21 +274,53 @@ void op_shift(oparg_T *oap, bool curs_top, int amount)
changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0, true);
}
-/// Shift the current line one shiftwidth left (if left != 0) or right
-/// leaves cursor on first blank in the line.
-///
-/// @param call_changed_bytes call changed_bytes()
-void shift_line(bool left, bool round, int amount, int call_changed_bytes)
+/// Return the tabstop width at the index of the variable tabstop array. If an
+/// index greater than the length of the array is given, the last tabstop width
+/// in the array is returned.
+static int get_vts(const int *vts_array, int index)
+{
+ int ts;
+
+ if (index < 1) {
+ ts = 0;
+ } else if (index <= vts_array[0]) {
+ ts = vts_array[index];
+ } else {
+ ts = vts_array[vts_array[0]];
+ }
+
+ return ts;
+}
+
+/// Return the sum of all the tabstops through the index-th.
+static int get_vts_sum(const int *vts_array, int index)
{
- int sw_val = get_sw_value_indent(curbuf, left);
- if (sw_val == 0) {
- sw_val = 1; // shouldn't happen, just in case
+ int sum = 0;
+ int i;
+
+ // Perform the summation for indeces within the actual array.
+ for (i = 1; i <= index && i <= vts_array[0]; i++) {
+ sum += vts_array[i];
}
- int count = get_indent(); // get current indent
+
+ // Add topstops whose indeces exceed the actual array.
+ if (i <= index) {
+ sum += vts_array[vts_array[0]] * (index - vts_array[0]);
+ }
+
+ return sum;
+}
+
+/// @param left true if shift is to the left
+/// @param count true if new indent is to be to a tabstop
+/// @param amount number of shifts
+static int64_t get_new_sw_indent(bool left, bool round, int64_t amount, int64_t sw_val)
+{
+ int64_t count = get_indent(); // get current indent
if (round) { // round off indent
- int i = count / sw_val; // number of 'shiftwidth' rounded down
- int j = count % sw_val; // extra spaces
+ int64_t i = trim_to_int(count / sw_val); // number of 'shiftwidth' rounded down
+ int64_t j = trim_to_int(count % sw_val); // extra spaces
if (j && left) { // first remove extra spaces
amount--;
}
@@ -305,11 +338,94 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes)
}
}
+ return count;
+}
+
+/// @param left true if shift is to the left
+/// @param count true if new indent is to be to a tabstop
+/// @param amount number of shifts
+static int64_t get_new_vts_indent(bool left, bool round, int amount, int *vts_array)
+{
+ int64_t indent = get_indent();
+ int vtsi = 0;
+ int vts_indent = 0;
+ int ts = 0; // Silence uninitialized variable warning.
+
+ // Find the tabstop at or to the left of the current indent.
+ while (vts_indent <= indent) {
+ vtsi++;
+ ts = get_vts(vts_array, vtsi);
+ vts_indent += ts;
+ }
+ vts_indent -= ts;
+ vtsi--;
+
+ // Extra indent spaces to the right of the tabstop
+ int64_t offset = indent - vts_indent;
+
+ if (round) {
+ if (left) {
+ if (offset == 0) {
+ indent = get_vts_sum(vts_array, vtsi - amount);
+ } else {
+ indent = get_vts_sum(vts_array, vtsi - (amount - 1));
+ }
+ } else {
+ indent = get_vts_sum(vts_array, vtsi + amount);
+ }
+ } else {
+ if (left) {
+ if (amount > vtsi) {
+ indent = 0;
+ } else {
+ indent = get_vts_sum(vts_array, vtsi - amount) + offset;
+ }
+ } else {
+ indent = get_vts_sum(vts_array, vtsi + amount) + offset;
+ }
+ }
+
+ return indent;
+}
+
+/// Shift the current line 'amount' shiftwidth(s) left (if 'left' is true) or
+/// right.
+///
+/// The rules for choosing a shiftwidth are: If 'shiftwidth' is non-zero, use
+/// 'shiftwidth'; else if 'vartabstop' is not empty, use 'vartabstop'; else use
+/// 'tabstop'. The Vim documentation says nothing about 'softtabstop' or
+/// 'varsofttabstop' affecting the shiftwidth, and neither affects the
+/// shiftwidth in current versions of Vim, so they are not considered here.
+///
+/// @param left true if shift is to the left
+/// @param count true if new indent is to be to a tabstop
+/// @param amount number of shifts
+/// @param call_changed_bytes call changed_bytes()
+void shift_line(bool left, bool round, int amount, int call_changed_bytes)
+{
+ int64_t count;
+ int64_t sw_val = curbuf->b_p_sw;
+ int64_t ts_val = curbuf->b_p_ts;
+ int *vts_array = curbuf->b_p_vts_array;
+
+ if (sw_val != 0) {
+ // 'shiftwidth' is not zero; use it as the shift size.
+ count = get_new_sw_indent(left, round, amount, sw_val);
+ } else if ((vts_array == NULL) || (vts_array[0] == 0)) {
+ // 'shiftwidth' is zero and 'vartabstop' is empty; use 'tabstop' as the
+ // shift size.
+ count = get_new_sw_indent(left, round, amount, ts_val);
+ } else {
+ // 'shiftwidth' is zero and 'vartabstop' is defined; use 'vartabstop'
+ // to determine the new indent.
+ count = get_new_vts_indent(left, round, amount, vts_array);
+ }
+
// Set new indent
if (State & VREPLACE_FLAG) {
- change_indent(INDENT_SET, count, false, call_changed_bytes);
+ change_indent(INDENT_SET, trim_to_int(count), false, call_changed_bytes);
} else {
- set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
+ set_indent(trim_to_int(count), call_changed_bytes ? SIN_CHANGED : 0);
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 27b80c0ac8..e261f06b42 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1977,8 +1977,8 @@ static const char *did_set_cmdheight(optset_T *args)
{
OptInt old_value = args->os_oldval.number;
- if (p_ch > Rows - min_rows() + 1) {
- p_ch = Rows - min_rows() + 1;
+ if (p_ch > Rows - min_rows(curtab) + 1) {
+ p_ch = Rows - min_rows(curtab) + 1;
}
// if p_ch changed value, change the command line height
@@ -2199,13 +2199,6 @@ static const char *did_set_modified(optset_T *args)
return NULL;
}
-/// Process the updated 'msghistory' option value.
-static const char *did_set_msghistory(optset_T *args FUNC_ATTR_UNUSED)
-{
- check_msg_hist();
- return NULL;
-}
-
/// Process the updated 'number' or 'relativenumber' option value.
static const char *did_set_number_relativenumber(optset_T *args)
{
@@ -2764,10 +2757,11 @@ static const char *check_num_option_bounds(OptIndex opt_idx, OptInt *newval, cha
switch (opt_idx) {
case kOptLines:
- if (*newval < min_rows() && full_screen) {
- vim_snprintf(errbuf, errbuflen, _("E593: Need at least %d lines"), min_rows());
+ if (*newval < min_rows_for_all_tabpages() && full_screen) {
+ vim_snprintf(errbuf, errbuflen, _("E593: Need at least %d lines"),
+ min_rows_for_all_tabpages());
errmsg = errbuf;
- *newval = min_rows();
+ *newval = min_rows_for_all_tabpages();
}
// True max size is defined by check_screensize().
*newval = MIN(*newval, INT_MAX);
@@ -2885,13 +2879,6 @@ static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *e
return e_invarg;
}
break;
- case kOptMsghistory:
- if (value < 0) {
- return e_positive;
- } else if (value > 10000) {
- return e_invarg;
- }
- break;
case kOptPyxversion:
if (value == 0) {
*newval = 3;
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
index 3bb2035e7c..97455380cc 100644
--- a/src/nvim/option_vars.h
+++ b/src/nvim/option_vars.h
@@ -448,6 +448,7 @@ EXTERN OptInt p_mfd; ///< 'maxfuncdepth'
EXTERN OptInt p_mmd; ///< 'maxmapdepth'
EXTERN OptInt p_mmp; ///< 'maxmempattern'
EXTERN OptInt p_mis; ///< 'menuitems'
+EXTERN char *p_mopt; ///< 'messagesopt'
EXTERN char *p_msm; ///< 'mkspellmem'
EXTERN int p_ml; ///< 'modeline'
EXTERN int p_mle; ///< 'modelineexpr'
@@ -464,7 +465,6 @@ EXTERN OptInt p_mousescroll_vert INIT( = MOUSESCROLL_VERT_DFLT);
EXTERN OptInt p_mousescroll_hor INIT( = MOUSESCROLL_HOR_DFLT);
EXTERN OptInt p_mouset; ///< 'mousetime'
EXTERN int p_more; ///< 'more'
-EXTERN OptInt p_mhi; ///< 'msghistory'
EXTERN char *p_nf; ///< 'nrformats'
EXTERN char *p_opfunc; ///< 'operatorfunc'
EXTERN char *p_para; ///< 'paragraphs'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 84c90e44a7..afce4a918b 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1530,9 +1530,9 @@ return {
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
- noselect Do not select a match in the menu, force the user to
- select one from the menu. Only works in combination with
- "menu" or "menuone".
+ noselect Same as "noinsert", except that no menu item is
+ pre-selected. If both "noinsert" and "noselect" are present,
+ "noselect" has precedence.
fuzzy Enable |fuzzy-matching| for completion candidates. This
allows for more flexible and intuitive matching, where
@@ -4094,7 +4094,7 @@ return {
desc = [=[
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
- each of these histories (see |cmdline-editing| and 'msghistory' for
+ each of these histories (see |cmdline-editing| and 'messagesopt' for
the number of messages to remember).
The maximum value is 10000.
]=],
@@ -5449,6 +5449,41 @@ return {
varname = 'p_mis',
},
{
+ abbreviation = 'mopt',
+ cb = 'did_set_messagesopt',
+ defaults = { if_true = 'hit-enter,history:500' },
+ values = { 'hit-enter', 'wait:', 'history:' },
+ flags = true,
+ deny_duplicates = true,
+ desc = [=[
+ Option settings for outputting messages. It can consist of the
+ following items. Items must be separated by a comma.
+
+ hit-enter Use a |hit-enter| prompt when the message is longer than
+ 'cmdheight' size.
+
+ wait:{n} Instead of using a |hit-enter| prompt, simply wait for
+ {n} milliseconds so that the user has a chance to read
+ the message. The maximum value of {n} is 10000. Use
+ 0 to disable the wait (but then the user may miss an
+ important message).
+ This item is ignored when "hit-enter" is present, but
+ required when "hit-enter" is not present.
+
+ history:{n} Determines how many entries are remembered in the
+ |:messages| history. The maximum value is 10000.
+ Setting it to zero clears the message history.
+ This item must always be present.
+ ]=],
+ expand_cb = 'expand_set_messagesopt',
+ full_name = 'messagesopt',
+ list = 'onecommacolon',
+ scope = { 'global' },
+ short_desc = N_('options for outputting messages'),
+ type = 'string',
+ varname = 'p_mopt',
+ },
+ {
abbreviation = 'msm',
cb = 'did_set_mkspellmem',
defaults = { if_true = '460000,2000,500' },
@@ -5893,21 +5928,6 @@ return {
varname = 'p_mouset',
},
{
- abbreviation = 'mhi',
- cb = 'did_set_msghistory',
- defaults = { if_true = 500 },
- desc = [=[
- Determines how many entries are remembered in the |:messages| history.
- The maximum value is 10000.
- Setting it to zero clears the message history.
- ]=],
- full_name = 'msghistory',
- scope = { 'global' },
- short_desc = N_('how many messages are remembered'),
- type = 'number',
- varname = 'p_mhi',
- },
- {
abbreviation = 'nf',
cb = 'did_set_nrformats',
defaults = { if_true = 'bin,hex' },
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 918443db9f..75b6585553 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -1682,6 +1682,24 @@ const char *did_set_matchpairs(optset_T *args)
return NULL;
}
+/// Process the updated 'messagesopt' option value.
+const char *did_set_messagesopt(optset_T *args FUNC_ATTR_UNUSED)
+{
+ if (messagesopt_changed() == FAIL) {
+ return e_invarg;
+ }
+ return NULL;
+}
+
+int expand_set_messagesopt(optexpand_T *args, int *numMatches, char ***matches)
+{
+ return expand_set_opt_string(args,
+ opt_mopt_values,
+ ARRAY_SIZE(opt_mopt_values) - 1,
+ numMatches,
+ matches);
+}
+
/// The 'mkspellmem' option is changed.
const char *did_set_mkspellmem(optset_T *args FUNC_ATTR_UNUSED)
{
diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po
index 3e88ac446c..bcc1e0af8e 100644
--- a/src/nvim/po/vi.po
+++ b/src/nvim/po/vi.po
@@ -4,219 +4,147 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: Vim 6.3 \n"
+"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2005-02-30 21:37+0400\n"
-"Last-Translator: Phan Vinh Thinh <teppi@vnlinux.org>\n"
+"POT-Creation-Date: 2024-12-03 22:06+0100\n"
+"PO-Revision-Date: 2024-12-03 22:07+0100\n"
+"Last-Translator: Phạm Bình An <111893501+brianhuster@users.noreply.github.com>\n"
"Language-Team: Phan Vinh Thinh <teppi@vnlinux.org>\n"
-"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../api/private/helpers.c:201
-#, fuzzy
-msgid "Unable to get option value"
-msgstr "E258: Không thể trả lời cho máy con"
-
-#: ../api/private/helpers.c:204
-msgid "internal error: unknown option type"
-msgstr ""
-
-#: ../buffer.c:92
-msgid "[Location List]"
-msgstr ""
-
-#: ../buffer.c:93
-msgid "[Quickfix List]"
-msgstr ""
-
-#: ../buffer.c:94
-msgid "E855: Autocommands caused command to abort"
-msgstr ""
-
-#: ../buffer.c:135
msgid "E82: Cannot allocate any buffer, exiting..."
msgstr "E82: Không thể phân chia bộ nhớ thậm chí cho một bộ đệm, thoát..."
-#: ../buffer.c:138
msgid "E83: Cannot allocate buffer, using other one..."
msgstr "E83: Không thể phân chia bộ nhớ cho bộ đệm, sử dụng bộ đệm khác..."
-#: ../buffer.c:763
msgid "E515: No buffers were unloaded"
msgstr "E515: Không có bộ đệm nào được bỏ nạp từ bộ nhớ"
-#: ../buffer.c:765
msgid "E516: No buffers were deleted"
msgstr "E516: Không có bộ đệm nào bị xóa"
-#: ../buffer.c:767
msgid "E517: No buffers were wiped out"
msgstr "E517: Không có bộ đệm nào được làm sạch"
-#: ../buffer.c:772
msgid "1 buffer unloaded"
msgstr "1 bộ đệm được bỏ nạp từ bộ nhớ"
-#: ../buffer.c:774
#, c-format
msgid "%d buffers unloaded"
msgstr "%d bộ đệm được bỏ nạp từ bộ nhớ"
-#: ../buffer.c:777
msgid "1 buffer deleted"
msgstr "1 bộ đệm bị xóa"
-#: ../buffer.c:779
#, c-format
msgid "%d buffers deleted"
msgstr "%d bộ đệm được bỏ nạp"
-#: ../buffer.c:782
msgid "1 buffer wiped out"
msgstr "1 bộ đệm được làm sạch"
-#: ../buffer.c:784
#, c-format
msgid "%d buffers wiped out"
msgstr "%d bộ đệm được làm sạch"
-#: ../buffer.c:806
-msgid "E90: Cannot unload last buffer"
-msgstr "E90: Không thể bỏ nạp từ bộ nhớ bộ đệm cuối cùng"
-
-#: ../buffer.c:874
msgid "E84: No modified buffer found"
msgstr "E84: Không tìm thấy bộ đệm có thay đổi"
-#. back where we started, didn't find anything.
-#: ../buffer.c:903
msgid "E85: There is no listed buffer"
msgstr "E85: Không có bộ đệm được liệt kê"
-#: ../buffer.c:913
#, c-format
-msgid "E86: Buffer %<PRId64> does not exist"
-msgstr "E86: Bộ đệm %<PRId64> không tồn tại"
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bộ đệm %ld không tồn tại"
-#: ../buffer.c:915
msgid "E87: Cannot go beyond last buffer"
msgstr "E87: Đây là bộ đệm cuối cùng"
-#: ../buffer.c:917
msgid "E88: Cannot go before first buffer"
msgstr "E88: Đây là bộ đệm đầu tiên"
-#: ../buffer.c:945
#, c-format
-msgid ""
-"E89: No write since last change for buffer %<PRId64> (add ! to override)"
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
msgstr ""
-"E89: Thay đổi trong bộ đệm %<PRId64> chưa được ghi lại (thêm ! để thoát ra "
-"bằng mọi giá)"
+"E89: Thay đổi trong bộ đệm %ld chưa được ghi lại (thêm ! để thoát ra bằng "
+"mọi giá)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Không thể bỏ nạp từ bộ nhớ bộ đệm cuối cùng"
-#. wrap around (may cause duplicates)
-#: ../buffer.c:1423
msgid "W14: Warning: List of file names overflow"
msgstr "W14: Cảnh báo: Danh sách tên tập tin quá đầy"
-#: ../buffer.c:1555 ../quickfix.c:3361
#, c-format
-msgid "E92: Buffer %<PRId64> not found"
-msgstr "E92: Bộ đệm %<PRId64> không được tìm thấy"
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Bộ đệm %ld không được tìm thấy"
-#: ../buffer.c:1798
#, c-format
msgid "E93: More than one match for %s"
msgstr "E93: Tìm thấy vài tương ứng với %s"
-#: ../buffer.c:1800
#, c-format
msgid "E94: No matching buffer for %s"
msgstr "E94: Không có bộ đệm tương ứng với %s"
-#: ../buffer.c:2161
#, c-format
-msgid "line %<PRId64>"
-msgstr "dòng %<PRId64>"
+msgid "line %ld"
+msgstr "dòng %ld"
-#: ../buffer.c:2233
msgid "E95: Buffer with this name already exists"
msgstr "E95: Đã có bộ đệm với tên như vậy"
-#: ../buffer.c:2498
msgid " [Modified]"
msgstr " [Đã thay đổi]"
-#: ../buffer.c:2501
msgid "[Not edited]"
msgstr "[Chưa soạn thảo]"
-#: ../buffer.c:2504
msgid "[New file]"
msgstr "[Tập tin mới]"
-#: ../buffer.c:2505
msgid "[Read errors]"
msgstr "[Lỗi đọc]"
-#: ../buffer.c:2506 ../buffer.c:3217 ../fileio.c:1807 ../screen.c:4895
-msgid "[RO]"
-msgstr "[Chỉ đọc]"
-
-#: ../buffer.c:2507 ../fileio.c:1807
msgid "[readonly]"
msgstr "[chỉ đọc]"
-#: ../buffer.c:2524
#, c-format
msgid "1 line --%d%%--"
msgstr "1 dòng --%d%%--"
-#: ../buffer.c:2526
#, c-format
-msgid "%<PRId64> lines --%d%%--"
-msgstr "%<PRId64> dòng --%d%%--"
+msgid "%ld lines --%d%%--"
+msgstr "%ld dòng --%d%%--"
-#: ../buffer.c:2530
#, c-format
-msgid "line %<PRId64> of %<PRId64> --%d%%-- col "
-msgstr "dòng %<PRId64> của %<PRId64> --%d%%-- cột "
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "dòng %ld của %ld --%d%%-- cột "
-#: ../buffer.c:2632 ../buffer.c:4292 ../memline.c:1554
-#, fuzzy
-msgid "[No Name]"
+msgid "[No file]"
msgstr "[Không có tập tin]"
-#. must be a help buffer
-#: ../buffer.c:2667
msgid "help"
msgstr "trợ giúp"
-#: ../buffer.c:3225 ../screen.c:4883
-#, fuzzy
-msgid "[Help]"
+msgid "[help]"
msgstr "[trợ giúp]"
-#: ../buffer.c:3254 ../screen.c:4887
msgid "[Preview]"
msgstr "[Xem trước]"
-#: ../buffer.c:3528
msgid "All"
msgstr "Tất cả"
-#: ../buffer.c:3528
msgid "Bot"
msgstr "Cuối"
-#: ../buffer.c:3531
msgid "Top"
msgstr "Đầu"
-#: ../buffer.c:4244
msgid ""
"\n"
"# Buffer list:\n"
@@ -224,11 +152,12 @@ msgstr ""
"\n"
"# Danh sách bộ đệm:\n"
-#: ../buffer.c:4289
-msgid "[Scratch]"
-msgstr ""
+msgid "[Error List]"
+msgstr "[Danh sách lỗi]"
+
+msgid "[No File]"
+msgstr "[Không có tập tin]"
-#: ../buffer.c:4529
msgid ""
"\n"
"--- Signs ---"
@@ -236,806 +165,300 @@ msgstr ""
"\n"
"--- Ký hiệu ---"
-#: ../buffer.c:4538
#, c-format
msgid "Signs for %s:"
msgstr "Ký hiệu cho %s:"
-#: ../buffer.c:4543
#, c-format
-msgid " line=%<PRId64> id=%d name=%s"
-msgstr " dòng=%<PRId64> id=%d tên=%s"
-
-#: ../cursor_shape.c:68
-msgid "E545: Missing colon"
-msgstr "E545: Thiếu dấu hai chấm"
-
-#: ../cursor_shape.c:70 ../cursor_shape.c:94
-msgid "E546: Illegal mode"
-msgstr "E546: Chế độ không cho phép"
-
-#: ../cursor_shape.c:134
-msgid "E548: digit expected"
-msgstr "E548: yêu cầu một số"
+msgid " line=%ld id=%d name=%s"
+msgstr " dòng=%ld id=%d tên=%s"
-#: ../cursor_shape.c:138
-msgid "E549: Illegal percentage"
-msgstr "E549: Tỷ lệ phần trăm không cho phép"
-
-#: ../diff.c:146
#, c-format
-msgid "E96: Can not diff more than %<PRId64> buffers"
-msgstr ""
-"E96: Chỉ có thể theo dõi sự khác nhau trong nhiều nhất %<PRId64> bộ đệm"
-
-#: ../diff.c:753
-#, fuzzy
-msgid "E810: Cannot read or write temp files"
-msgstr "E557: Không thể mở tập tin termcap"
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Chỉ có thể theo dõi sự khác nhau trong nhiều nhất %ld bộ đệm"
-#: ../diff.c:755
msgid "E97: Cannot create diffs"
msgstr "E97: Không thể tạo tập tin khác biệt (diff)"
-#: ../diff.c:966
-#, fuzzy
-msgid "E816: Cannot read patch output"
-msgstr "E98: Không thể đọc dữ liệu ra của lệnh diff"
+msgid "Patch file"
+msgstr "Tập tin vá lỗi (patch)"
-#: ../diff.c:1220
msgid "E98: Cannot read diff output"
msgstr "E98: Không thể đọc dữ liệu ra của lệnh diff"
-#: ../diff.c:2081
msgid "E99: Current buffer is not in diff mode"
msgstr "E99: Bộ đệm hiện thời không nằm trong chế độ khác biệt (diff)"
-#: ../diff.c:2100
-#, fuzzy
-msgid "E793: No other buffer in diff mode is modifiable"
-msgstr "E100: Không còn bộ đệm trong chế độ khác biệt (diff) nào nữa"
-
-#: ../diff.c:2102
msgid "E100: No other buffer in diff mode"
msgstr "E100: Không còn bộ đệm trong chế độ khác biệt (diff) nào nữa"
-#: ../diff.c:2112
msgid "E101: More than two buffers in diff mode, don't know which one to use"
-msgstr ""
-"E101: Có nhiều hơn hai bộ đệm trong chế độ khác biệt (diff), không biết chọn"
+msgstr "E101: Có nhiều hơn hai bộ đệm trong chế độ khác biệt (diff), không biết nên chọn cái nào"
-#: ../diff.c:2141
#, c-format
msgid "E102: Can't find buffer \"%s\""
msgstr "E102: Không tìm thấy bộ đệm \"%s\""
-#: ../diff.c:2152
#, c-format
msgid "E103: Buffer \"%s\" is not in diff mode"
msgstr "E103: Bộ đệm \"%s\" không nằm trong chế độ khác biệt (diff)"
-#: ../diff.c:2193
-msgid "E787: Buffer changed unexpectedly"
-msgstr ""
-
-#: ../digraph.c:1598
msgid "E104: Escape not allowed in digraph"
msgstr "E104: Không cho phép dùng ký tự thoát Escape trong chữ ghép"
-#: ../digraph.c:1760
msgid "E544: Keymap file not found"
msgstr "E544: Không tìm thấy tập tin sơ đồ bàn phím"
-#: ../digraph.c:1785
msgid "E105: Using :loadkeymap not in a sourced file"
msgstr "E105: Câu lệnh :loadkeymap được sử dụng ngoài tập tin script"
-#: ../digraph.c:1821
-msgid "E791: Empty keymap entry"
-msgstr ""
-
-#: ../edit.c:82
msgid " Keyword completion (^N^P)"
msgstr " Tự động kết thúc cho từ khóa (^N^P)"
-#. ctrl_x_mode == 0, ^P/^N compl.
-#: ../edit.c:83
-#, fuzzy
-msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgid " ^X mode (^E^Y^L^]^F^I^K^D^V^N^P)"
msgstr " Chế độ ^X (^E^Y^L^]^F^I^K^D^V^N^P)"
-#: ../edit.c:85
+msgid " Keyword Local completion (^N^P)"
+msgstr " Tự động kết thúc nội bộ cho từ khóa (^N^P)"
+
msgid " Whole line completion (^L^N^P)"
msgstr " Tự động kết thúc cho cả dòng (^L^N^P)"
-#: ../edit.c:86
msgid " File name completion (^F^N^P)"
msgstr " Tự động kết thúc tên tập tin (^F^N^P)"
-#: ../edit.c:87
msgid " Tag completion (^]^N^P)"
msgstr " Tự động kết thúc thẻ đánh dấu (^]^N^P)"
-#: ../edit.c:88
msgid " Path pattern completion (^N^P)"
msgstr " Tự động kết thúc mẫu đường dẫn (^N^P)"
-#: ../edit.c:89
msgid " Definition completion (^D^N^P)"
msgstr " Tự động kết thúc định nghĩa (^D^N^P)"
-#: ../edit.c:91
msgid " Dictionary completion (^K^N^P)"
msgstr " Tự động kết thúc theo từ điển (^K^N^P)"
-#: ../edit.c:92
msgid " Thesaurus completion (^T^N^P)"
msgstr " Tự động kết thúc từ đồng âm (^T^N^P)"
-#: ../edit.c:93
msgid " Command-line completion (^V^N^P)"
msgstr " Tự động kết thúc dòng lệnh (^V^N^P)"
-#: ../edit.c:94
-#, fuzzy
-msgid " User defined completion (^U^N^P)"
-msgstr " Tự động kết thúc cho cả dòng (^L^N^P)"
-
-#: ../edit.c:95
-#, fuzzy
-msgid " Omni completion (^O^N^P)"
-msgstr " Tự động kết thúc thẻ đánh dấu (^]^N^P)"
-
-#: ../edit.c:96
-#, fuzzy
-msgid " Spelling suggestion (^S^N^P)"
-msgstr " Tự động kết thúc cho cả dòng (^L^N^P)"
-
-#: ../edit.c:97
-msgid " Keyword Local completion (^N^P)"
-msgstr " Tự động kết thúc nội bộ cho từ khóa (^N^P)"
-
-#: ../edit.c:100
msgid "Hit end of paragraph"
msgstr "Kết thúc của đoạn văn"
-#: ../edit.c:101
-msgid "E839: Completion function changed window"
-msgstr ""
-
-#: ../edit.c:102
-msgid "E840: Completion function deleted text"
-msgstr ""
+msgid "'thesaurus' option is empty"
+msgstr "Không đưa ra giá trị của tùy chọn 'thesaurus'"
-#: ../edit.c:1847
msgid "'dictionary' option is empty"
msgstr "Không đưa ra giá trị của tùy chọn 'dictionary'"
-#: ../edit.c:1848
-msgid "'thesaurus' option is empty"
-msgstr "Không đưa ra giá trị của tùy chọn 'thesaurus'"
-
-#: ../edit.c:2655
#, c-format
msgid "Scanning dictionary: %s"
msgstr "Quét từ điển: %s"
-#: ../edit.c:3079
msgid " (insert) Scroll (^E/^Y)"
msgstr " (chèn) Cuộn (^E/^Y)"
-#: ../edit.c:3081
msgid " (replace) Scroll (^E/^Y)"
msgstr " (thay thế) Cuộn (^E/^Y)"
-#: ../edit.c:3587
#, c-format
msgid "Scanning: %s"
msgstr "Quét: %s"
-#: ../edit.c:3614
msgid "Scanning tags."
msgstr "Tìm kiếm trong số thẻ đánh dấu."
-#: ../edit.c:4519
msgid " Adding"
msgstr " Thêm"
-#. showmode might reset the internal line pointers, so it must
-#. * be called before line = ml_get(), or when this address is no
-#. * longer needed. -- Acevedo.
-#.
-#: ../edit.c:4562
msgid "-- Searching..."
msgstr "-- Tìm kiếm..."
-#: ../edit.c:4618
msgid "Back at original"
msgstr "Từ ban đầu"
-#: ../edit.c:4621
msgid "Word from other line"
msgstr "Từ của dòng khác"
-#: ../edit.c:4624
msgid "The only match"
msgstr "Tương ứng duy nhất"
-#: ../edit.c:4680
#, c-format
msgid "match %d of %d"
msgstr "Tương ứng %d của %d"
-#: ../edit.c:4684
#, c-format
msgid "match %d"
msgstr "Tương ứng %d"
-#: ../eval.c:137
-#, fuzzy
-msgid "E18: Unexpected characters in :let"
-msgstr "E18: Ở trước '=' có các ký tự không mong đợi"
-
-#: ../eval.c:138
-#, fuzzy, c-format
-msgid "E684: list index out of range: %<PRId64>"
-msgstr "E322: số thứ tự dòng vượt quá giới hạn : %<PRId64>"
-
-#: ../eval.c:139
#, c-format
-msgid "E121: Undefined variable: %s"
-msgstr "E121: Biến không xác định: %s"
-
-#: ../eval.c:140
-msgid "E111: Missing ']'"
-msgstr "E111: Thiếu ']'"
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: Biến không biết: \"%s\""
-#: ../eval.c:141
-#, fuzzy, c-format
-msgid "E686: Argument of %s must be a List"
-msgstr "E487: Tham số phải là một số dương"
-
-#: ../eval.c:143
-#, fuzzy, c-format
-msgid "E712: Argument of %s must be a List or Dictionary"
-msgstr "E487: Tham số phải là một số dương"
-
-#: ../eval.c:144
-#, fuzzy
-msgid "E713: Cannot use empty key for Dictionary"
-msgstr "E214: Không tìm thấy tập tin tạm thời (temp) để ghi nhớ"
-
-#: ../eval.c:145
-#, fuzzy
-msgid "E714: List required"
-msgstr "E471: Cần chỉ ra tham số"
-
-#: ../eval.c:146
-#, fuzzy
-msgid "E715: Dictionary required"
-msgstr "E129: Cần tên hàm số"
-
-#: ../eval.c:147
-#, c-format
-msgid "E118: Too many arguments for function: %s"
-msgstr "E118: Quá nhiều tham số cho hàm: %s"
-
-#: ../eval.c:148
-#, c-format
-msgid "E716: Key not present in Dictionary: %s"
-msgstr ""
-
-#: ../eval.c:150
-#, c-format
-msgid "E122: Function %s already exists, add ! to replace it"
-msgstr "E122: Hàm số %s đã có, hãy thêm ! để thay thế nó."
-
-#: ../eval.c:151
-#, fuzzy
-msgid "E717: Dictionary entry already exists"
-msgstr "E95: Đã có bộ đệm với tên như vậy"
-
-#: ../eval.c:152
-#, fuzzy
-msgid "E718: Funcref required"
-msgstr "E129: Cần tên hàm số"
-
-#: ../eval.c:153
-#, fuzzy
-msgid "E719: Cannot use [:] with a Dictionary"
-msgstr "E360: Không chạy được shell với tùy chọn -f"
-
-#: ../eval.c:154
-#, c-format
-msgid "E734: Wrong variable type for %s="
-msgstr ""
-
-#: ../eval.c:155
-#, fuzzy, c-format
-msgid "E130: Unknown function: %s"
-msgstr "E117: Hàm số không biết: %s"
-
-#: ../eval.c:156
-#, c-format
-msgid "E461: Illegal variable name: %s"
-msgstr "E461: Tên biến không cho phép: %s"
-
-#: ../eval.c:157
-msgid "E806: using Float as a String"
-msgstr ""
-
-#: ../eval.c:1830
-msgid "E687: Less targets than List items"
-msgstr ""
-
-#: ../eval.c:1834
-msgid "E688: More targets than List items"
-msgstr ""
-
-#: ../eval.c:1906
-msgid "Double ; in list of variables"
-msgstr ""
-
-#: ../eval.c:2078
-#, fuzzy, c-format
-msgid "E738: Can't list variables for %s"
-msgstr "E138: Không thể ghi tập tin viminfo %s!"
-
-#: ../eval.c:2391
-msgid "E689: Can only index a List or Dictionary"
-msgstr ""
-
-#: ../eval.c:2396
-msgid "E708: [:] must come last"
-msgstr ""
-
-#: ../eval.c:2439
-msgid "E709: [:] requires a List value"
-msgstr ""
-
-#: ../eval.c:2674
-msgid "E710: List value has more items than target"
-msgstr ""
-
-#: ../eval.c:2678
-msgid "E711: List value has not enough items"
-msgstr ""
-
-#: ../eval.c:2867
-#, fuzzy
-msgid "E690: Missing \"in\" after :for"
-msgstr "E69: Thiếu ] sau %s%%["
-
-#: ../eval.c:3063
#, c-format
msgid "E107: Missing parentheses: %s"
msgstr "E107: Thiếu dấu ngoặc: %s"
-#: ../eval.c:3263
#, c-format
msgid "E108: No such variable: \"%s\""
msgstr "E108: Không có biến như vậy: \"%s\""
-#: ../eval.c:3333
-msgid "E743: variable nested too deep for (un)lock"
-msgstr ""
-
-#: ../eval.c:3630
msgid "E109: Missing ':' after '?'"
msgstr "E109: Thiếu ':' sau '?'"
-#: ../eval.c:3893
-msgid "E691: Can only compare List with List"
-msgstr ""
-
-#: ../eval.c:3895
-#, fuzzy
-msgid "E692: Invalid operation for Lists"
-msgstr "E449: Nhận được một biểu thức không cho phép"
-
-#: ../eval.c:3915
-msgid "E735: Can only compare Dictionary with Dictionary"
-msgstr ""
-
-#: ../eval.c:3917
-#, fuzzy
-msgid "E736: Invalid operation for Dictionary"
-msgstr "E116: Tham số cho hàm %s đưa ra không đúng"
-
-#: ../eval.c:3932
-msgid "E693: Can only compare Funcref with Funcref"
-msgstr ""
-
-#: ../eval.c:3934
-#, fuzzy
-msgid "E694: Invalid operation for Funcrefs"
-msgstr "E116: Tham số cho hàm %s đưa ra không đúng"
-
-#: ../eval.c:4277
-#, fuzzy
-msgid "E804: Cannot use '%' with Float"
-msgstr "E360: Không chạy được shell với tùy chọn -f"
-
-#: ../eval.c:4478
msgid "E110: Missing ')'"
msgstr "E110: Thiếu ')'"
-#: ../eval.c:4609
-#, fuzzy
-msgid "E695: Cannot index a Funcref"
-msgstr "E90: Không thể bỏ nạp từ bộ nhớ bộ đệm cuối cùng"
+msgid "E111: Missing ']'"
+msgstr "E111: Thiếu ']'"
-#: ../eval.c:4839
#, c-format
msgid "E112: Option name missing: %s"
msgstr "E112: Không đưa ra tên tùy chọn: %s"
-#: ../eval.c:4855
#, c-format
msgid "E113: Unknown option: %s"
msgstr "E113: Tùy chọn không biết: %s"
-#: ../eval.c:4904
#, c-format
msgid "E114: Missing quote: %s"
msgstr "E114: Thiếu ngoặc kép: %s"
-#: ../eval.c:5020
#, c-format
msgid "E115: Missing quote: %s"
msgstr "E115: Thiếu ngoặc kép: %s"
-#: ../eval.c:5084
-#, fuzzy, c-format
-msgid "E696: Missing comma in List: %s"
-msgstr "E405: Thiếu dấu bằng: %s"
-
-#: ../eval.c:5091
-#, fuzzy, c-format
-msgid "E697: Missing end of List ']': %s"
-msgstr "E398: Thiếu '=': %s"
-
-#: ../eval.c:6475
-#, fuzzy, c-format
-msgid "E720: Missing colon in Dictionary: %s"
-msgstr "E405: Thiếu dấu bằng: %s"
-
-#: ../eval.c:6499
-#, c-format
-msgid "E721: Duplicate key in Dictionary: \"%s\""
-msgstr ""
-
-#: ../eval.c:6517
-#, fuzzy, c-format
-msgid "E722: Missing comma in Dictionary: %s"
-msgstr "E527: Thiếu dấu phẩy"
-
-#: ../eval.c:6524
-#, fuzzy, c-format
-msgid "E723: Missing end of Dictionary '}': %s"
-msgstr "E126: Thiếu lệnh :endfunction"
-
-#: ../eval.c:6555
-#, fuzzy
-msgid "E724: variable nested too deep for displaying"
-msgstr "E22: Các script lồng vào nhau quá sâu"
-
-#: ../eval.c:7188
-#, fuzzy, c-format
-msgid "E740: Too many arguments for function %s"
-msgstr "E118: Quá nhiều tham số cho hàm: %s"
-
-#: ../eval.c:7190
#, c-format
msgid "E116: Invalid arguments for function %s"
msgstr "E116: Tham số cho hàm %s đưa ra không đúng"
-#: ../eval.c:7377
#, c-format
msgid "E117: Unknown function: %s"
msgstr "E117: Hàm số không biết: %s"
-#: ../eval.c:7383
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Quá nhiều tham số cho hàm: %s"
+
#, c-format
msgid "E119: Not enough arguments for function: %s"
msgstr "E119: Không đủ tham số cho hàm: %s"
-#: ../eval.c:7387
#, c-format
msgid "E120: Using <SID> not in a script context: %s"
msgstr "E120: Sử dụng <SID> ngoài script: %s"
-#: ../eval.c:7391
-#, c-format
-msgid "E725: Calling dict function without Dictionary: %s"
-msgstr ""
-
-#: ../eval.c:7453
-#, fuzzy
-msgid "E808: Number or Float required"
-msgstr "E521: Sau dấu = cần đưa ra một số"
-
-#: ../eval.c:7503
-#, fuzzy
-msgid "add() argument"
-msgstr "Tham số không được phép cho"
-
-#: ../eval.c:7907
-#, fuzzy
-msgid "E699: Too many arguments"
-msgstr "Có quá nhiều tham số soạn thảo"
-
-#: ../eval.c:8073
-#, fuzzy
-msgid "E785: complete() can only be used in Insert mode"
-msgstr "E328: Trình đơn chỉ có trong chế độ khác"
-
-#: ../eval.c:8156
msgid "&Ok"
msgstr "&Ok"
-#: ../eval.c:8676
-#, fuzzy, c-format
-msgid "E737: Key already exists: %s"
-msgstr "E227: đã có ánh xạ cho %s"
-
-#: ../eval.c:8692
-msgid "extend() argument"
-msgstr ""
-
-#: ../eval.c:8915
-#, fuzzy
-msgid "map() argument"
-msgstr " vim [các tham số] "
-
-#: ../eval.c:8916
-msgid "filter() argument"
-msgstr ""
-
-#: ../eval.c:9229
#, c-format
msgid "+-%s%3ld lines: "
msgstr "+-%s%3ld dòng: "
-#: ../eval.c:9291
-#, fuzzy, c-format
-msgid "E700: Unknown function: %s"
-msgstr "E117: Hàm số không biết: %s"
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Hủy bỏ"
-#: ../eval.c:10729
msgid "called inputrestore() more often than inputsave()"
msgstr "Hàm số inputrestore() được gọi nhiều hơn hàm inputsave()"
-#: ../eval.c:10771
-#, fuzzy
-msgid "insert() argument"
-msgstr "Có quá nhiều tham số soạn thảo"
-
-#: ../eval.c:10841
-#, fuzzy
-msgid "E786: Range not allowed"
-msgstr "E481: Không cho phép sử dụng phạm vi"
-
-#: ../eval.c:11140
-#, fuzzy
-msgid "E701: Invalid type for len()"
-msgstr "E596: Phông chữ không đúng"
-
-#: ../eval.c:11980
-msgid "E726: Stride is zero"
-msgstr ""
-
-#: ../eval.c:11982
-msgid "E727: Start past end"
-msgstr ""
-
-#: ../eval.c:12024 ../eval.c:15297
-msgid "<empty>"
-msgstr ""
-
-#: ../eval.c:12282
-msgid "remove() argument"
-msgstr ""
-
-#: ../eval.c:12466
msgid "E655: Too many symbolic links (cycle?)"
msgstr "E655: Quá nhiều liên kết tượng trưng (vòng lặp?)"
-#: ../eval.c:12593
-msgid "reverse() argument"
-msgstr ""
+msgid "E240: No connection to Vim server"
+msgstr "E240: Không có kết nối với máy chủ Vim"
-#: ../eval.c:13721
-msgid "sort() argument"
-msgstr ""
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Máy chủ không trả lời"
-#: ../eval.c:13721
-#, fuzzy
-msgid "uniq() argument"
-msgstr "Tham số không được phép cho"
-
-#: ../eval.c:13776
-#, fuzzy
-msgid "E702: Sort compare function failed"
-msgstr "E237: Chọn máy in không thành công"
+msgid "E258: Unable to send to client"
+msgstr "E258: Không thể trả lời cho máy con"
-#: ../eval.c:13806
-msgid "E882: Uniq compare function failed"
-msgstr ""
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Không thể gửi tin nhắn tới %s"
-#: ../eval.c:14085
msgid "(Invalid)"
msgstr "(Không đúng)"
-#: ../eval.c:14590
-#, fuzzy
-msgid "E677: Error writing temp file"
-msgstr "E208: Lỗi ghi nhớ vào \"%s\""
-
-#: ../eval.c:16159
-msgid "E805: Using a Float as a Number"
-msgstr ""
-
-#: ../eval.c:16162
-msgid "E703: Using a Funcref as a Number"
-msgstr ""
-
-#: ../eval.c:16170
-msgid "E745: Using a List as a Number"
-msgstr ""
-
-#: ../eval.c:16173
-msgid "E728: Using a Dictionary as a Number"
-msgstr ""
-
-#: ../eval.c:16259
-msgid "E729: using Funcref as a String"
-msgstr ""
-
-#: ../eval.c:16262
-#, fuzzy
-msgid "E730: using List as a String"
-msgstr "E374: Thiếu ] trong chuỗi định dạng"
-
-#: ../eval.c:16265
-msgid "E731: using Dictionary as a String"
-msgstr ""
-
-#: ../eval.c:16619
-#, fuzzy, c-format
-msgid "E706: Variable type mismatch for: %s"
-msgstr "E93: Tìm thấy vài tương ứng với %s"
-
-#: ../eval.c:16705
-#, fuzzy, c-format
-msgid "E795: Cannot delete variable %s"
-msgstr "E46: Không thay đổi được biến chỉ đọc \"%s\""
-
-#: ../eval.c:16724
-#, fuzzy, c-format
-msgid "E704: Funcref variable name must start with a capital: %s"
-msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
-
-#: ../eval.c:16732
#, c-format
-msgid "E705: Variable name conflicts with existing function: %s"
-msgstr ""
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Biến không xác định: %s"
-#: ../eval.c:16763
#, c-format
-msgid "E741: Value is locked: %s"
-msgstr ""
-
-#: ../eval.c:16764 ../eval.c:16769 ../message.c:1839
-msgid "Unknown"
-msgstr "Không rõ"
-
-#: ../eval.c:16768
-#, fuzzy, c-format
-msgid "E742: Cannot change value of %s"
-msgstr "E284: Không đặt được giá trị nội dung nhập vào (IC)"
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Tên biến không cho phép: %s"
-#: ../eval.c:16838
-msgid "E698: variable nested too deep for making a copy"
-msgstr ""
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Hàm số %s đã có, hãy thêm ! để thay thế nó."
-#: ../eval.c:17249
#, c-format
msgid "E123: Undefined function: %s"
msgstr "E123: Hàm số không xác định: %s"
-#: ../eval.c:17260
#, c-format
msgid "E124: Missing '(': %s"
msgstr "E124: Thiếu '(': %s"
-#: ../eval.c:17293
-#, fuzzy
-msgid "E862: Cannot use g: here"
-msgstr "E284: Không đặt được giá trị nội dung nhập vào (IC)"
-
-#: ../eval.c:17312
#, c-format
msgid "E125: Illegal argument: %s"
msgstr "E125: Tham số không cho phép: %s"
-#: ../eval.c:17323
-#, fuzzy, c-format
-msgid "E853: Duplicate argument name: %s"
-msgstr "E154: Thẻ ghi lặp lại \"%s\" trong tập tin %s"
-
-#: ../eval.c:17416
msgid "E126: Missing :endfunction"
msgstr "E126: Thiếu lệnh :endfunction"
-#: ../eval.c:17537
-#, fuzzy, c-format
-msgid "E707: Function name conflicts with variable: %s"
-msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
-
-#: ../eval.c:17549
#, c-format
msgid "E127: Cannot redefine function %s: It is in use"
msgstr "E127: Không thể định nghĩa lại hàm số %s: hàm đang được sử dụng"
-#: ../eval.c:17604
-#, fuzzy, c-format
-msgid "E746: Function name does not match script file name: %s"
-msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
-
-#: ../eval.c:17716
msgid "E129: Function name required"
msgstr "E129: Cần tên hàm số"
-#: ../eval.c:17824
-#, fuzzy, c-format
-msgid "E128: Function name must start with a capital or \"s:\": %s"
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
-#: ../eval.c:17833
-#, fuzzy, c-format
-msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: Hàm số %s chưa xác định"
-#: ../eval.c:18336
#, c-format
msgid "E131: Cannot delete function %s: It is in use"
msgstr "E131: Không thể xóa hàm số %s: Hàm đang được sử dụng"
-#: ../eval.c:18441
msgid "E132: Function call depth is higher than 'maxfuncdepth'"
msgstr "E132: Độ sâu của lời gọi hàm số lớn hơn giá trị 'maxfuncdepth'"
-#: ../eval.c:18568
#, c-format
msgid "calling %s"
msgstr "lời gọi %s"
-#: ../eval.c:18651
#, c-format
msgid "%s aborted"
msgstr "%s dừng"
-#: ../eval.c:18653
#, c-format
-msgid "%s returning #%<PRId64>"
-msgstr "%s trả lại #%<PRId64>"
+msgid "%s returning #%ld"
+msgstr "%s trả lại #%ld"
-#: ../eval.c:18670
-#, fuzzy, c-format
-msgid "%s returning %s"
+#, c-format
+msgid "%s returning \"%s\""
msgstr "%s trả lại \"%s\""
-#: ../eval.c:18691 ../ex_cmds2.c:2695
#, c-format
msgid "continuing in %s"
msgstr "tiếp tục trong %s"
-#: ../eval.c:18795
msgid "E133: :return not inside a function"
msgstr "E133: lệnh :return ở ngoài một hàm"
-#: ../eval.c:19159
msgid ""
"\n"
"# global variables:\n"
@@ -1043,114 +466,260 @@ msgstr ""
"\n"
"# biến toàn cầu:\n"
-#: ../eval.c:19254
-msgid ""
-"\n"
-"\tLast set from "
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Bật chế độ sửa lỗi (Debug). Gõ \"cont\" để tiếp tục."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "dòng %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "câu lệnh: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Điểm dừng trên \"%s%s\" dòng %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Không tìm thấy điểm dừng: %s"
+
+msgid "No breakpoints defined"
+msgstr "Điểm dừng không được xác định"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s dòng %ld"
+
+msgid "Save As"
+msgstr "Ghi nhớ như"
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "Ghi nhớ thay đổi vào \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "Chưa đặt tên"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Thay đổi chưa được ghi nhớ trong bộ đệm \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
msgstr ""
-"\n"
-"\tLần cuối cùng tùy chọn thay đổi vào "
+"Cảnh báo: Chuyển tới bộ đệm khác không theo ý muốn (hãy kiểm tra câu lệnh tự "
+"động)"
-#: ../eval.c:19272
-#, fuzzy
-msgid "No old files"
-msgstr "Không có tập tin được tính đến"
+msgid "E163: There is only one file to edit"
+msgstr "E163: Chỉ có một tập tin để soạn thảo"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Đây là tập tin đầu tiên"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Đây là tập tin cuối cùng"
+
+# TODO: Capitalise first word of message?
+msgid "E666: Compiler not supported: %s"
+msgstr "E666: trình biên dịch không được hỗ trợ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Tìm kiếm \"%s\" trong \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Tìm kiếm \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "không tìm thấy trong 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Thực hiện script của Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Không thể thực hiện một thư mục: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "không thực hiện được \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "dòng %ld: không thực hiện được \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "thực hiện \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "dòng %ld: thực hiện \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "thực hiện xong %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Cảnh báo: Ký tự phân cách dòng không đúng. Rất có thể thiếu ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Lệnh :scriptencoding sử dụng ngoài tập tin script"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Lệnh :finish sử dụng ngoài tập tin script"
+
+#, c-format
+msgid "Page %d"
+msgstr "Trang %d"
+
+msgid "No text to be printed"
+msgstr "Không có gì để in"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "In trang %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Sao chép %d của %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Đã in: %s"
+
+msgid "Printing aborted"
+msgstr "In bị dừng"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Lỗi ghi nhớ vào tập tin PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Không thể mở tập tin \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Không thể đọc tập tin tài nguyên PostScript \"%s\""
+
+# TODO: Capitalise first word of message?
+msgid "E618: File \"%s\" is not a PostScript resource file"
+msgstr "E618: \"%s\" không phải là tập tin tài nguyên PostScript"
+
+# TODO: Capitalise first word of message?
+msgid "E619: File \"%s\" is not a supported PostScript resource file"
+msgstr "E619: \"%s\" không phải là tập tin tài nguyên PostScript được hỗ trợ"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: tập tin tài nguyên \"%s\" có phiên bản không đúng"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Không thể mở tập tin PostScript"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Không thể mở tập tin \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Không tìm thấy tập tin tài nguyên PostScript \"prolog.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Không tìm thấy tập tin tài nguyên PostScript \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert from multi-byte to \"%s\" encoding"
+msgstr "E620: Không thể chuyển từ các ký tự nhiều byte thành bảng mã \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Gửi tới máy in..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: In tập tin PostScript không thành công"
+
+msgid "Print job sent."
+msgstr "Đã gửi công việc in."
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Ngôn ngữ %shiện thời: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Không thể thay đổi ngôn ngữ thành \"%s\""
-#: ../ex_cmds.c:122
#, c-format
msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
-#: ../ex_cmds.c:145
#, c-format
msgid "> %d, Hex %04x, Octal %o"
msgstr "> %d, Hex %04x, Octal %o"
-#: ../ex_cmds.c:146
#, c-format
msgid "> %d, Hex %08x, Octal %o"
msgstr "> %d, Hex %08x, Octal %o"
-#: ../ex_cmds.c:684
msgid "E134: Move lines into themselves"
msgstr "E134: Di chuyển các dòng lên chính chúng"
-#: ../ex_cmds.c:747
msgid "1 line moved"
msgstr "Đã di chuyển 1 dòng"
-#: ../ex_cmds.c:749
#, c-format
-msgid "%<PRId64> lines moved"
-msgstr "Đã di chuyển %<PRId64> dòng"
+msgid "%ld lines moved"
+msgstr "Đã di chuyển %ld dòng"
-#: ../ex_cmds.c:1175
#, c-format
-msgid "%<PRId64> lines filtered"
-msgstr "Đã lọc %<PRId64> dòng"
+msgid "%ld lines filtered"
+msgstr "Đã lọc %ld dòng"
-#: ../ex_cmds.c:1194
msgid "E135: *Filter* Autocommands must not change current buffer"
msgstr "E135: Các lệnh tự động *Filter* không được thay đổi bộ đệm hiện thời"
-#: ../ex_cmds.c:1244
msgid "[No write since last change]\n"
msgstr "[Thay đổi chưa được ghi nhớ]\n"
-#: ../ex_cmds.c:1424
#, c-format
msgid "%sviminfo: %s in line: "
msgstr "%sviminfo: %s trên dòng: "
-#: ../ex_cmds.c:1431
msgid "E136: viminfo: Too many errors, skipping rest of file"
msgstr "E136: viminfo: Quá nhiều lỗi, phần còn lại của tập tin sẽ được bỏ qua"
-#: ../ex_cmds.c:1458
#, c-format
msgid "Reading viminfo file \"%s\"%s%s%s"
msgstr "Đọc tập tin viminfo \"%s\"%s%s%s"
-#: ../ex_cmds.c:1460
msgid " info"
msgstr " thông tin"
-#: ../ex_cmds.c:1461
msgid " marks"
msgstr " dấu hiệu"
-#: ../ex_cmds.c:1462
-#, fuzzy
-msgid " oldfiles"
-msgstr "Không có tập tin được tính đến"
-
-#: ../ex_cmds.c:1463
msgid " FAILED"
msgstr " KHÔNG THÀNH CÔNG"
-#. avoid a wait_return for this message, it's annoying
-#: ../ex_cmds.c:1541
#, c-format
msgid "E137: Viminfo file is not writable: %s"
msgstr "E137: Thiếu quyền ghi lên tập tin viminfo: %s"
-#: ../ex_cmds.c:1626
#, c-format
msgid "E138: Can't write viminfo file %s!"
msgstr "E138: Không thể ghi tập tin viminfo %s!"
-#: ../ex_cmds.c:1635
#, c-format
msgid "Writing viminfo file \"%s\""
msgstr "Ghi tập tin viminfo \"%s\""
-#. Write the info:
-#: ../ex_cmds.c:1720
#, c-format
msgid "# This viminfo file was generated by Vim %s.\n"
msgstr "# Tập tin viminfo này được tự động tạo bởi Vim %s.\n"
-#: ../ex_cmds.c:1722
msgid ""
"# You may edit it if you're careful!\n"
"\n"
@@ -1158,137 +727,88 @@ msgstr ""
"# Bạn có thể sửa tập tin này, nhưng hãy thận trọng!\n"
"\n"
-#: ../ex_cmds.c:1723
msgid "# Value of 'encoding' when this file was written\n"
msgstr "# Giá trị của tùy chọn 'encoding' vào thời điểm ghi tập tin\n"
-#: ../ex_cmds.c:1800
msgid "Illegal starting char"
msgstr "Ký tự đầu tiên không cho phép"
-#: ../ex_cmds.c:2162
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Tập tin được nạp trong bộ đệm khác"
+
msgid "Write partial file?"
msgstr "Ghi nhớ một phần tập tin?"
-#: ../ex_cmds.c:2166
msgid "E140: Use ! to write partial buffer"
msgstr "E140: Sử dụng ! để ghi nhớ một phần bộ đệm"
-#: ../ex_cmds.c:2281
-#, fuzzy, c-format
-msgid "Overwrite existing file \"%s\"?"
-msgstr "Ghi đè lên tập tin đã có \"%.*s\"?"
-
-#: ../ex_cmds.c:2317
#, c-format
-msgid "Swap file \"%s\" exists, overwrite anyway?"
-msgstr ""
-
-#: ../ex_cmds.c:2326
-#, fuzzy, c-format
-msgid "E768: Swap file exists: %s (:silent! overrides)"
-msgstr "E13: Tập tin đã tồn tại (thêm ! để ghi chèn)"
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "Ghi đè lên tập tin đã có \"%.*s\"?"
-#: ../ex_cmds.c:2381
#, c-format
-msgid "E141: No file name for buffer %<PRId64>"
-msgstr "E141: Không có tên tập tin cho bộ đệm %<PRId64>"
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Không có tên tập tin cho bộ đệm %ld"
-#: ../ex_cmds.c:2412
msgid "E142: File not written: Writing is disabled by 'write' option"
msgstr "E142: Tập tin chưa được ghi nhớ: Ghi nhớ bị tắt bởi tùy chọn 'write'"
-#: ../ex_cmds.c:2434
-#, fuzzy, c-format
+#, c-format
msgid ""
-"'readonly' option is set for \"%s\".\n"
+"'readonly' option is set for \"%.*s\".\n"
"Do you wish to write anyway?"
msgstr ""
"Tùy chọn 'readonly' được đặt cho \"%.*s\".\n"
"Ghi nhớ bằng mọi giá?"
-#: ../ex_cmds.c:2439
-#, c-format
-msgid ""
-"File permissions of \"%s\" are read-only.\n"
-"It may still be possible to write it.\n"
-"Do you wish to try?"
-msgstr ""
-
-#: ../ex_cmds.c:2451
-#, fuzzy, c-format
-msgid "E505: \"%s\" is read-only (add ! to override)"
-msgstr "là tập tin chỉ đọc (thêm ! để ghi nhớ bằng mọi giá)"
+msgid "Edit File"
+msgstr "Soạn thảo tập tin"
-#: ../ex_cmds.c:3120
#, c-format
msgid "E143: Autocommands unexpectedly deleted new buffer %s"
msgstr "E143: Các lệnh tự động xóa bộ đệm mới ngoài ý muốn %s"
-#: ../ex_cmds.c:3313
-msgid "E144: non-numeric argument to :z"
+# TODO: Capitalise first word of message?
+msgid "E144: Non-numeric argument to :z"
msgstr "E144: Tham số của lệnh :z phải là số"
-#: ../ex_cmds.c:3498
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Không cho phép sử dụng lệnh shell trong rvim."
+
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Không thể phân cách biểu thức chính quy bằng chữ cái"
-#: ../ex_cmds.c:3964
#, c-format
msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
msgstr "thay thế bằng %s? (y/n/a/q/l/^E/^Y)"
-#: ../ex_cmds.c:4379
msgid "(Interrupted) "
msgstr "(bị dừng)"
-#: ../ex_cmds.c:4384
-#, fuzzy
-msgid "1 match"
-msgstr "; tương ứng "
-
-#: ../ex_cmds.c:4384
msgid "1 substitution"
msgstr "1 thay thế"
-#: ../ex_cmds.c:4387
-#, fuzzy, c-format
-msgid "%<PRId64> matches"
-msgstr "%<PRId64> thay đổi"
-
-#: ../ex_cmds.c:4388
#, c-format
-msgid "%<PRId64> substitutions"
-msgstr "%<PRId64> thay thế"
+msgid "%ld substitutions"
+msgstr "%ld thay thế"
-#: ../ex_cmds.c:4392
msgid " on 1 line"
msgstr " trên 1 dòng"
-#: ../ex_cmds.c:4395
#, c-format
-msgid " on %<PRId64> lines"
-msgstr " trên %<PRId64> dòng"
+msgid " on %ld lines"
+msgstr " trên %ld dòng"
-#: ../ex_cmds.c:4438
msgid "E147: Cannot do :global recursive"
msgstr "E147: Không thực hiện được lệnh :global đệ qui"
-#: ../ex_cmds.c:4467
msgid "E148: Regular expression missing from global"
msgstr "E148: Thiếu biểu thức chính quy trong lệnh :global"
-#: ../ex_cmds.c:4508
#, c-format
msgid "Pattern found in every line: %s"
msgstr "Tìm thấy tương ứng trên mọi dòng: %s"
-#: ../ex_cmds.c:4510
-#, fuzzy, c-format
-msgid "Pattern not found: %s"
-msgstr "Không tìm thấy mẫu (pattern)"
-
-#: ../ex_cmds.c:4587
msgid ""
"\n"
"# Last Substitute String:\n"
@@ -1298,342 +818,138 @@ msgstr ""
"# Chuỗi thay thế cuối cùng:\n"
"$"
-#: ../ex_cmds.c:4679
msgid "E478: Don't panic!"
msgstr "E478: Hãy bình tĩnh, đừng hoảng hốt!"
-#: ../ex_cmds.c:4717
#, c-format
msgid "E661: Sorry, no '%s' help for %s"
msgstr "E661: Rất tiếc, không có trợ giúp '%s' cho %s"
-#: ../ex_cmds.c:4719
#, c-format
msgid "E149: Sorry, no help for %s"
msgstr "E149: Rất tiếc không có trợ giúp cho %s"
-#: ../ex_cmds.c:4751
#, c-format
msgid "Sorry, help file \"%s\" not found"
msgstr "Xin lỗi, không tìm thấy tập tin trợ giúp \"%s\""
-#: ../ex_cmds.c:5323
#, c-format
msgid "E150: Not a directory: %s"
msgstr "E150: %s không phải là một thư mục"
-#: ../ex_cmds.c:5446
#, c-format
msgid "E152: Cannot open %s for writing"
msgstr "E152: Không thể mở %s để ghi"
-#: ../ex_cmds.c:5471
#, c-format
msgid "E153: Unable to open %s for reading"
msgstr "E153: Không thể mở %s để đọc"
-#: ../ex_cmds.c:5500
#, c-format
msgid "E670: Mix of help file encodings within a language: %s"
msgstr ""
"E670: Tập tin trợ giúp sử dụng nhiều bảng mã khác nhau cho một ngôn ngữ: %s"
-#: ../ex_cmds.c:5565
-#, fuzzy, c-format
-msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
msgstr "E154: Thẻ ghi lặp lại \"%s\" trong tập tin %s"
-#: ../ex_cmds.c:5687
#, c-format
msgid "E160: Unknown sign command: %s"
msgstr "E160: Câu lệnh ký hiệu không biết: %s"
-#: ../ex_cmds.c:5704
msgid "E156: Missing sign name"
msgstr "E156: Thiếu tên ký hiệu"
-#: ../ex_cmds.c:5746
msgid "E612: Too many signs defined"
msgstr "E612: Định nghĩa quá nhiều ký hiệu"
-#: ../ex_cmds.c:5813
#, c-format
msgid "E239: Invalid sign text: %s"
msgstr "E239: Văn bản ký hiệu không thích hợp: %s"
-#: ../ex_cmds.c:5844 ../ex_cmds.c:6035
#, c-format
msgid "E155: Unknown sign: %s"
msgstr "E155: Ký hiệu không biết: %s"
-#: ../ex_cmds.c:5877
msgid "E159: Missing sign number"
msgstr "E159: Thiếu số của ký hiệu"
-#: ../ex_cmds.c:5971
#, c-format
msgid "E158: Invalid buffer name: %s"
msgstr "E158: Tên bộ đệm không đúng: %s"
-#: ../ex_cmds.c:6008
#, c-format
-msgid "E157: Invalid sign ID: %<PRId64>"
-msgstr "E157: ID của ký hiệu không đúng: %<PRId64>"
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ID của ký hiệu không đúng: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (KHÔNG TÌM THẤY)"
-#: ../ex_cmds.c:6066
msgid " (not supported)"
msgstr " (không được hỗ trợ)"
-#: ../ex_cmds.c:6169
msgid "[Deleted]"
msgstr "[bị xóa]"
-#: ../ex_cmds2.c:139
-msgid "Entering Debug mode. Type \"cont\" to continue."
-msgstr "Bật chế độ sửa lỗi (Debug). Gõ \"cont\" để tiếp tục."
-
-#: ../ex_cmds2.c:143 ../ex_docmd.c:759
-#, c-format
-msgid "line %<PRId64>: %s"
-msgstr "dòng %<PRId64>: %s"
-
-#: ../ex_cmds2.c:145
-#, c-format
-msgid "cmd: %s"
-msgstr "câu lệnh: %s"
-
-#: ../ex_cmds2.c:322
-#, c-format
-msgid "Breakpoint in \"%s%s\" line %<PRId64>"
-msgstr "Điểm dừng trên \"%s%s\" dòng %<PRId64>"
-
-#: ../ex_cmds2.c:581
-#, c-format
-msgid "E161: Breakpoint not found: %s"
-msgstr "E161: Không tìm thấy điểm dừng: %s"
-
-#: ../ex_cmds2.c:611
-msgid "No breakpoints defined"
-msgstr "Điểm dừng không được xác định"
-
-#: ../ex_cmds2.c:617
-#, c-format
-msgid "%3d %s %s line %<PRId64>"
-msgstr "%3d %s %s dòng %<PRId64>"
-
-#: ../ex_cmds2.c:942
-msgid "E750: First use \":profile start {fname}\""
-msgstr ""
-
-#: ../ex_cmds2.c:1269
-#, fuzzy, c-format
-msgid "Save changes to \"%s\"?"
-msgstr "Ghi nhớ thay đổi vào \"%.*s\"?"
-
-#: ../ex_cmds2.c:1271 ../ex_docmd.c:8851
-msgid "Untitled"
-msgstr "Chưa đặt tên"
-
-#: ../ex_cmds2.c:1421
-#, c-format
-msgid "E162: No write since last change for buffer \"%s\""
-msgstr "E162: Thay đổi chưa được ghi nhớ trong bộ đệm \"%s\""
-
-#: ../ex_cmds2.c:1480
-msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
-msgstr ""
-"Cảnh báo: Chuyển tới bộ đệm khác không theo ý muốn (hãy kiểm tra câu lệnh tự "
-"động)"
-
-#: ../ex_cmds2.c:1826
-msgid "E163: There is only one file to edit"
-msgstr "E163: Chỉ có một tập tin để soạn thảo"
-
-#: ../ex_cmds2.c:1828
-msgid "E164: Cannot go before first file"
-msgstr "E164: Đây là tập tin đầu tiên"
-
-#: ../ex_cmds2.c:1830
-msgid "E165: Cannot go beyond last file"
-msgstr "E165: Đây là tập tin cuối cùng"
-
-#: ../ex_cmds2.c:2175
-#, c-format
-msgid "E666: compiler not supported: %s"
-msgstr "E666: trình biên dịch không được hỗ trợ: %s"
-
-#: ../ex_cmds2.c:2257
-#, c-format
-msgid "Searching for \"%s\" in \"%s\""
-msgstr "Tìm kiếm \"%s\" trong \"%s\""
-
-#: ../ex_cmds2.c:2284
-#, c-format
-msgid "Searching for \"%s\""
-msgstr "Tìm kiếm \"%s\""
-
-#: ../ex_cmds2.c:2307
-#, c-format
-msgid "not found in 'runtimepath': \"%s\""
-msgstr "không tìm thấy trong 'runtimepath': \"%s\""
-
-#: ../ex_cmds2.c:2472
-#, c-format
-msgid "Cannot source a directory: \"%s\""
-msgstr "Không thể thực hiện một thư mục: \"%s\""
-
-#: ../ex_cmds2.c:2518
-#, c-format
-msgid "could not source \"%s\""
-msgstr "không thực hiện được \"%s\""
-
-#: ../ex_cmds2.c:2520
-#, c-format
-msgid "line %<PRId64>: could not source \"%s\""
-msgstr "dòng %<PRId64>: không thực hiện được \"%s\""
-
-#: ../ex_cmds2.c:2535
-#, c-format
-msgid "sourcing \"%s\""
-msgstr "thực hiện \"%s\""
-
-#: ../ex_cmds2.c:2537
-#, c-format
-msgid "line %<PRId64>: sourcing \"%s\""
-msgstr "dòng %<PRId64>: thực hiện \"%s\""
-
-#: ../ex_cmds2.c:2693
-#, c-format
-msgid "finished sourcing %s"
-msgstr "thực hiện xong %s"
-
-#: ../ex_cmds2.c:2765
-#, fuzzy
-msgid "modeline"
-msgstr "Thêm 1 dòng"
-
-#: ../ex_cmds2.c:2767
-#, fuzzy
-msgid "--cmd argument"
-msgstr " vim [các tham số] "
-
-#: ../ex_cmds2.c:2769
-#, fuzzy
-msgid "-c argument"
-msgstr " vim [các tham số] "
-
-#: ../ex_cmds2.c:2771
-msgid "environment variable"
-msgstr ""
-
-#: ../ex_cmds2.c:2773
-#, fuzzy
-msgid "error handler"
-msgstr "Lỗi và sự gián đoạn"
-
-#: ../ex_cmds2.c:3020
-msgid "W15: Warning: Wrong line separator, ^M may be missing"
-msgstr "W15: Cảnh báo: Ký tự phân cách dòng không đúng. Rất có thể thiếu ^M"
-
-#: ../ex_cmds2.c:3139
-msgid "E167: :scriptencoding used outside of a sourced file"
-msgstr "E167: Lệnh :scriptencoding sử dụng ngoài tập tin script"
-
-#: ../ex_cmds2.c:3166
-msgid "E168: :finish used outside of a sourced file"
-msgstr "E168: Lệnh :finish sử dụng ngoài tập tin script"
-
-#: ../ex_cmds2.c:3389
-#, c-format
-msgid "Current %slanguage: \"%s\""
-msgstr "Ngôn ngữ %shiện thời: \"%s\""
-
-#: ../ex_cmds2.c:3404
-#, c-format
-msgid "E197: Cannot set language to \"%s\""
-msgstr "E197: Không thể thay đổi ngôn ngữ thành \"%s\""
-
-#. don't redisplay the window
-#. don't wait for return
-#: ../ex_docmd.c:387
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
msgstr ""
"Chuyển vào chế độ Ex. Để chuyển về chế độ Thông thường hãy gõ \"visual\""
-#: ../ex_docmd.c:428
msgid "E501: At end-of-file"
msgstr "E501: Ở cuối tập tin"
-#: ../ex_docmd.c:513
msgid "E169: Command too recursive"
msgstr "E169: Câu lệnh quá đệ quy"
-#: ../ex_docmd.c:1006
#, c-format
msgid "E605: Exception not caught: %s"
msgstr "E605: Trường hợp đặc biệt không được xử lý: %s"
-#: ../ex_docmd.c:1085
msgid "End of sourced file"
msgstr "Kết thúc tập tin script"
-#: ../ex_docmd.c:1086
msgid "End of function"
msgstr "Kết thúc của hàm số"
-#: ../ex_docmd.c:1628
msgid "E464: Ambiguous use of user-defined command"
msgstr "E464: Sự sử dụng không rõ ràng câu lệnh do người dùng định nghĩa"
-#: ../ex_docmd.c:1638
msgid "E492: Not an editor command"
msgstr "E492: Không phải là câu lệnh của trình soạn thảo"
-#: ../ex_docmd.c:1729
msgid "E493: Backwards range given"
msgstr "E493: Đưa ra phạm vi ngược lại"
-#: ../ex_docmd.c:1733
msgid "Backwards range given, OK to swap"
msgstr "Đưa ra phạm vi ngược lại, thay đổi vị trí hai giới hạn"
-#. append
-#. typed wrong
-#: ../ex_docmd.c:1787
msgid "E494: Use w or w>>"
msgstr "E494: Hãy sử dụng w hoặc w>>"
-#: ../ex_docmd.c:3454
-msgid "E319: The command is not available in this version"
+msgid "E319: Sorry, the command is not available in this version"
msgstr "E319: Xin lỗi, câu lệnh này không có trong phiên bản này"
-#: ../ex_docmd.c:3752
msgid "E172: Only one file name allowed"
msgstr "E172: Chỉ cho phép sử dụng một tên tập tin"
-#: ../ex_docmd.c:4238
msgid "1 more file to edit. Quit anyway?"
msgstr "Còn 1 tập tin nữa cần soạn thảo. Thoát?"
-#: ../ex_docmd.c:4242
#, c-format
msgid "%d more files to edit. Quit anyway?"
msgstr "Còn %d tập tin nữa chưa soạn thảo. Thoát?"
-#: ../ex_docmd.c:4248
msgid "E173: 1 more file to edit"
msgstr "E173: 1 tập tin nữa chờ soạn thảo."
-#: ../ex_docmd.c:4250
#, c-format
-msgid "E173: %<PRId64> more files to edit"
-msgstr "E173: %<PRId64> tập tin nữa chưa soạn thảo."
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld tập tin nữa chưa soạn thảo."
-#: ../ex_docmd.c:4320
msgid "E174: Command already exists: add ! to replace it"
msgstr "E174: Đã có câu lệnh: Thêm ! để thay thế"
-#: ../ex_docmd.c:4432
msgid ""
"\n"
" Name Args Range Complete Definition"
@@ -1641,352 +957,252 @@ msgstr ""
"\n"
" Tên\t\tTham_số Phạm_vi Phần_phụ Định_nghĩa"
-#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
msgstr "Không tìm thấy câu lệnh do người dùng định nghĩa"
-#: ../ex_docmd.c:4538
msgid "E175: No attribute specified"
msgstr "E175: Không có tham số được chỉ ra"
-#: ../ex_docmd.c:4583
msgid "E176: Invalid number of arguments"
msgstr "E176: Số lượng tham số không đúng"
-#: ../ex_docmd.c:4594
msgid "E177: Count cannot be specified twice"
msgstr "E177: Số đếm không thể được chỉ ra hai lần"
-#: ../ex_docmd.c:4603
msgid "E178: Invalid default value for count"
msgstr "E178: Giá trị của số đếm theo mặc định không đúng"
-#: ../ex_docmd.c:4625
-#, fuzzy
-msgid "E179: argument required for -complete"
+# TODO: Capitalise first word of message?
+msgid "E179: Argument required for complete"
msgstr "E179: yêu cầu đưa ra tham số để kết thúc"
-#: ../ex_docmd.c:4635
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Giá trị phần phụ không đúng: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Tham số tự động kết thúc chỉ cho phép sử dụng với phần phụ đặc biệt"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Phần phục đặc biệt yêu cầu một tham số của hàm"
+
#, c-format
msgid "E181: Invalid attribute: %s"
msgstr "E181: Thuộc tính không đúng: %s"
-#: ../ex_docmd.c:4678
msgid "E182: Invalid command name"
msgstr "E182: Tên câu lệnh không đúng"
-#: ../ex_docmd.c:4691
msgid "E183: User defined commands must start with an uppercase letter"
msgstr "E183: Câu lệnh người dùng định nghĩa phải bắt đầu với một ký tự hoa"
-#: ../ex_docmd.c:4696
-#, fuzzy
-msgid "E841: Reserved name, cannot be used for user defined command"
-msgstr "E464: Sự sử dụng không rõ ràng câu lệnh do người dùng định nghĩa"
-
-#: ../ex_docmd.c:4751
#, c-format
msgid "E184: No such user-defined command: %s"
msgstr "E184: Không có câu lệnh người dùng định nghĩa như vậy: %s"
-#: ../ex_docmd.c:5219
#, c-format
-msgid "E180: Invalid complete value: %s"
-msgstr "E180: Giá trị phần phụ không đúng: %s"
-
-#: ../ex_docmd.c:5225
-msgid "E468: Completion argument only allowed for custom completion"
-msgstr ""
-"E468: Tham số tự động kết thúc chỉ cho phép sử dụng với phần phụ đặc biệt"
-
-#: ../ex_docmd.c:5231
-msgid "E467: Custom completion requires a function argument"
-msgstr "E467: Phần phục đặc biệt yêu cầu một tham số của hàm"
-
-#: ../ex_docmd.c:5257
-#, fuzzy, c-format
-msgid "E185: Cannot find color scheme '%s'"
+msgid "E185: Cannot find color scheme %s"
msgstr "E185: Không tin thấy sơ đồ màu sắc %s"
-#: ../ex_docmd.c:5263
msgid "Greetings, Vim user!"
msgstr "Xin chào người dùng Vim!"
-#: ../ex_docmd.c:5431
-#, fuzzy
-msgid "E784: Cannot close last tab page"
-msgstr "E444: Không được đóng cửa sổ cuối cùng"
-
-#: ../ex_docmd.c:5462
-#, fuzzy
-msgid "Already only one tab page"
-msgstr "Chỉ có một cửa sổ"
-
-#: ../ex_docmd.c:6004
-#, fuzzy, c-format
-msgid "Tab page %d"
-msgstr "Trang %d"
+msgid "Edit File in new window"
+msgstr "Soạn thảo tập tin trong cửa sổ mới"
-#: ../ex_docmd.c:6295
msgid "No swap file"
msgstr "Không có tập tin swap"
-#: ../ex_docmd.c:6478
-#, fuzzy
-msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
-msgstr ""
-"E509: Không tạo được tập tin lưu trữ (thêm ! để bỏ qua việc kiểm tra lại)"
+msgid "Append File"
+msgstr "Thêm tập tin"
-#: ../ex_docmd.c:6485
msgid "E186: No previous directory"
msgstr "E186: Không có thư mục trước"
-#: ../ex_docmd.c:6530
msgid "E187: Unknown"
msgstr "E187: Không rõ"
-#: ../ex_docmd.c:6610
msgid "E465: :winsize requires two number arguments"
msgstr "E465: câu lệnh :winsize yêu cầu hai tham số bằng số"
-#: ../ex_docmd.c:6655
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vị trí cửa sổ: X %d, Y %d"
+
msgid "E188: Obtaining window position not implemented for this platform"
msgstr "E188: Trên hệ thống này việc xác định vị trí cửa sổ không làm việc"
-#: ../ex_docmd.c:6662
msgid "E466: :winpos requires two number arguments"
msgstr "E466: câu lệnh :winpos yêu câu hai tham số bằng số"
-#: ../ex_docmd.c:7241
-#, fuzzy, c-format
-msgid "E739: Cannot create directory: %s"
-msgstr "Không thể thực hiện một thư mục: \"%s\""
+msgid "Save Redirection"
+msgstr "Chuyển hướng ghi nhớ"
+
+msgid "Save View"
+msgstr "Ghi nhớ vẻ ngoài"
+
+msgid "Save Session"
+msgstr "Ghi nhớ buổi làm việc"
+
+msgid "Save Setup"
+msgstr "Ghi nhớ cấu hình"
-#: ../ex_docmd.c:7268
#, c-format
msgid "E189: \"%s\" exists (add ! to override)"
msgstr "E189: \"%s\" đã có (thêm !, để ghi đè)"
-#: ../ex_docmd.c:7273
#, c-format
msgid "E190: Cannot open \"%s\" for writing"
msgstr "E190: Không mở được \"%s\" để ghi nhớ"
-#. set mark
-#: ../ex_docmd.c:7294
msgid "E191: Argument must be a letter or forward/backward quote"
msgstr "E191: Tham số phải là một chữ cái hoặc dấu ngoặc thẳng/ngược"
-#: ../ex_docmd.c:7333
msgid "E192: Recursive use of :normal too deep"
msgstr "E192: Sử dụng đệ quy lệnh :normal quá sâu"
-#: ../ex_docmd.c:7807
msgid "E194: No alternate file name to substitute for '#'"
msgstr "E194: Không có tên tập tin tương đương để thay thế '#'"
-#: ../ex_docmd.c:7841
-msgid "E495: no autocommand file name to substitute for \"<afile>\""
+# TODO: Capitalise first word of message?
+msgid "E495: No autocommand file name to substitute for \"<afile>\""
msgstr "E495: Không có tên tập tin câu lệnh tự động để thay thế \"<afile>\""
-#: ../ex_docmd.c:7850
-msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+# TODO: Capitalise first word of message?
+msgid "E496: No autocommand buffer number to substitute for \"<abuf>\""
msgstr ""
"E496: Không có số thứ tự bộ đệm câu lệnh tự động để thay thế \"<abuf>\""
-#: ../ex_docmd.c:7861
-msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+# TODO: Capitalise first word of message?
+msgid "E497: No autocommand match name to substitute for \"<amatch>\""
msgstr "E497: Không có tên tương ứng câu lệnh tự động để thay thế \"<amatch>\""
-#: ../ex_docmd.c:7870
-msgid "E498: no :source file name to substitute for \"<sfile>\""
-msgstr "E498: không có tên tập tin :source để thay thế \"<sfile>\""
-
-#: ../ex_docmd.c:7876
-#, fuzzy
-msgid "E842: no line number to use for \"<slnum>\""
+# TODO: Capitalise first word of message?
+msgid "E498: No :source file name to substitute for \"<sfile>\""
msgstr "E498: không có tên tập tin :source để thay thế \"<sfile>\""
-#: ../ex_docmd.c:7903
-#, fuzzy, c-format
+#, no-c-format
msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
msgstr "E499: Tên tập tin rỗng cho '%' hoặc '#', chỉ làm việc với \":p:h\""
-#: ../ex_docmd.c:7905
msgid "E500: Evaluates to an empty string"
msgstr "E500: Kết quả của biểu thức là một chuỗi rỗng"
-#: ../ex_docmd.c:8838
msgid "E195: Cannot open viminfo file for reading"
msgstr "E195: Không thể mở tập tin viminfo để đọc"
-#: ../ex_eval.c:464
+msgid "E196: No digraphs in this version"
+msgstr "E196: Trong phiên bản này chữ ghép không được hỗ trợ"
+
msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
msgstr ""
"E608: Không thể thực hiện lệnh :throw cho những ngoại lệ với tiền tố 'Vim'"
-#. always scroll up, don't overwrite
-#: ../ex_eval.c:496
#, c-format
msgid "Exception thrown: %s"
msgstr "Trường hợp ngoại lệ: %s"
-#: ../ex_eval.c:545
#, c-format
msgid "Exception finished: %s"
msgstr "Kết thúc việc xử lý trường hợp ngoại lệ: %s"
-#: ../ex_eval.c:546
#, c-format
msgid "Exception discarded: %s"
msgstr "Trường hợp ngoại lệ bị bỏ qua: %s"
-#: ../ex_eval.c:588 ../ex_eval.c:634
#, c-format
-msgid "%s, line %<PRId64>"
-msgstr "%s, dòng %<PRId64>"
+msgid "%s, line %ld"
+msgstr "%s, dòng %ld"
-#. always scroll up, don't overwrite
-#: ../ex_eval.c:608
#, c-format
msgid "Exception caught: %s"
msgstr "Xử lý trường hợp ngoại lệ: %s"
-#: ../ex_eval.c:676
#, c-format
msgid "%s made pending"
msgstr "%s thực hiện việc chờ đợi"
-#: ../ex_eval.c:679
#, c-format
msgid "%s resumed"
msgstr "%s được phục hồi lại"
-#: ../ex_eval.c:683
#, c-format
msgid "%s discarded"
msgstr "%s bị bỏ qua"
-#: ../ex_eval.c:708
msgid "Exception"
msgstr "Trường hợp ngoại lệ"
-#: ../ex_eval.c:713
msgid "Error and interrupt"
msgstr "Lỗi và sự gián đoạn"
-#: ../ex_eval.c:715
msgid "Error"
msgstr "Lỗi"
-#. if (pending & CSTP_INTERRUPT)
-#: ../ex_eval.c:717
msgid "Interrupt"
msgstr "Sự gián đoạn"
-#: ../ex_eval.c:795
+# TODO: Capitalise first word of message?
msgid "E579: :if nesting too deep"
msgstr "E579: :if xếp lồng vào nhau quá sâu"
-#: ../ex_eval.c:830
msgid "E580: :endif without :if"
msgstr "E580: :endif không có :if"
-#: ../ex_eval.c:873
msgid "E581: :else without :if"
msgstr "E581: :else không có :if"
-#: ../ex_eval.c:876
msgid "E582: :elseif without :if"
msgstr "E582: :elseif không có :if"
-#: ../ex_eval.c:880
-msgid "E583: multiple :else"
+# TODO: Capitalise first word of message?
+msgid "E583: Multiple :else"
msgstr "E583: phát hiện vài :else"
-#: ../ex_eval.c:883
msgid "E584: :elseif after :else"
msgstr "E584: :elseif sau :else"
-#: ../ex_eval.c:941
-#, fuzzy
-msgid "E585: :while/:for nesting too deep"
+msgid "E585: :while nesting too deep"
msgstr "E585: :while xếp lồng vào nhau quá sâu"
-#: ../ex_eval.c:1028
-#, fuzzy
-msgid "E586: :continue without :while or :for"
+msgid "E586: :continue without :while"
msgstr "E586: :continue không có :while"
-#: ../ex_eval.c:1061
-#, fuzzy
-msgid "E587: :break without :while or :for"
+msgid "E587: :break without :while"
msgstr "E587: :break không có :while"
-#: ../ex_eval.c:1102
-#, fuzzy
-msgid "E732: Using :endfor with :while"
-msgstr "E170: Thiếu câu lệnh :endwhile"
-
-#: ../ex_eval.c:1104
-#, fuzzy
-msgid "E733: Using :endwhile with :for"
-msgstr "E170: Thiếu câu lệnh :endwhile"
-
-#: ../ex_eval.c:1247
msgid "E601: :try nesting too deep"
msgstr "E601: :try xếp lồng vào nhau quá sâu"
-#: ../ex_eval.c:1317
msgid "E603: :catch without :try"
msgstr "E603: :catch không có :try"
-#. Give up for a ":catch" after ":finally" and ignore it.
-#. * Just parse.
-#: ../ex_eval.c:1332
msgid "E604: :catch after :finally"
msgstr "E604: :catch đứng sau :finally"
-#: ../ex_eval.c:1451
msgid "E606: :finally without :try"
msgstr "E606: :finally không có :try"
-#. Give up for a multiple ":finally" and ignore it.
-#: ../ex_eval.c:1467
-msgid "E607: multiple :finally"
+# TODO: Capitalise first word of message?
+msgid "E607: Multiple :finally"
msgstr "E607: phát hiện vài :finally"
-#: ../ex_eval.c:1571
msgid "E602: :endtry without :try"
msgstr "E602: :endtry không có :try"
-#: ../ex_eval.c:2026
msgid "E193: :endfunction not inside a function"
msgstr "E193: lệnh :endfunction chỉ được sử dụng trong một hàm số"
-#: ../ex_getln.c:1643
-#, fuzzy
-msgid "E788: Not allowed to edit another buffer now"
-msgstr "E48: Không cho phép trong hộp cát (sandbox)"
-
-#: ../ex_getln.c:1656
-#, fuzzy
-msgid "E811: Not allowed to change buffer information now"
-msgstr "E94: Không có bộ đệm tương ứng với %s"
-
-#: ../ex_getln.c:3178
msgid "tagname"
msgstr "tên thẻ ghi"
-#: ../ex_getln.c:3181
msgid " kind file\n"
msgstr " loại tập tin\n"
-#: ../ex_getln.c:4799
msgid "'history' option is zero"
msgstr "giá trị của tùy chọn 'history' bằng không"
-#: ../ex_getln.c:5046
#, c-format
msgid ""
"\n"
@@ -1995,312 +1211,201 @@ msgstr ""
"\n"
"# %s, Lịch sử (bắt đầu từ mới nhất tới cũ nhất):\n"
-#: ../ex_getln.c:5047
msgid "Command Line"
msgstr "Dòng lệnh"
-#: ../ex_getln.c:5048
msgid "Search String"
msgstr "Chuỗi tìm kiếm"
-#: ../ex_getln.c:5049
msgid "Expression"
msgstr "Biểu thức"
-#: ../ex_getln.c:5050
msgid "Input Line"
msgstr "Dòng nhập"
-#: ../ex_getln.c:5117
msgid "E198: cmd_pchar beyond the command length"
msgstr "E198: cmd_pchar lớn hơn chiều dài câu lệnh"
-#: ../ex_getln.c:5279
msgid "E199: Active window or buffer deleted"
msgstr "E199: Cửa sổ hoặc bộ đệm hoạt động bị xóa"
-#: ../file_search.c:203
-msgid "E854: path too long for completion"
-msgstr ""
-
-#: ../file_search.c:446
-#, c-format
-msgid ""
-"E343: Invalid path: '**[number]' must be at the end of the path or be "
-"followed by '%s'."
-msgstr ""
-"E343: Đường dẫn đưa ra không đúng: '**[số]' phải ở cuối đường dẫn hoặc theo "
-"sau bởi '%s'"
-
-#: ../file_search.c:1505
-#, c-format
-msgid "E344: Can't find directory \"%s\" in cdpath"
-msgstr "E344: Không tìm thấy thư mục \"%s\" để chuyển thư mục"
-
-#: ../file_search.c:1508
-#, c-format
-msgid "E345: Can't find file \"%s\" in path"
-msgstr "E345: Không tìm thấy tập tin \"%s\" trong đường dẫn"
-
-#: ../file_search.c:1512
-#, c-format
-msgid "E346: No more directory \"%s\" found in cdpath"
-msgstr "E346: Trong đường dẫn thay đổi thư mục không còn có thư mục \"%s\" nữa"
-
-#: ../file_search.c:1515
-#, c-format
-msgid "E347: No more file \"%s\" found in path"
-msgstr "E347: Trong đường dẫn path không còn có tập tin \"%s\" nữa"
-
-#: ../fileio.c:137
-#, fuzzy
-msgid "E812: Autocommands changed buffer or buffer name"
-msgstr "E135: Các lệnh tự động *Filter* không được thay đổi bộ đệm hiện thời"
-
-#: ../fileio.c:368
msgid "Illegal file name"
msgstr "Tên tập tin không cho phép"
-#: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578
msgid "is a directory"
msgstr "là một thư mục"
-#: ../fileio.c:397
msgid "is not a file"
msgstr "không phải là một tập tin"
-#: ../fileio.c:508 ../fileio.c:3522
msgid "[New File]"
msgstr "[Tập tin mới]"
-#: ../fileio.c:511
-msgid "[New DIRECTORY]"
-msgstr ""
-
-#: ../fileio.c:529 ../fileio.c:532
-msgid "[File too big]"
-msgstr ""
-
-#: ../fileio.c:534
msgid "[Permission Denied]"
msgstr "[Truy cập bị từ chối]"
-#: ../fileio.c:653
msgid "E200: *ReadPre autocommands made the file unreadable"
msgstr ""
"E200: Câu lệnh tự động *ReadPre làm cho tập tin trở thành không thể đọc"
-#: ../fileio.c:655
msgid "E201: *ReadPre autocommands must not change current buffer"
msgstr "E201: Câu lệnh tự động *ReadPre không được thay đổi bộ đệm hoạt động"
-#: ../fileio.c:672
-msgid "Nvim: Reading from stdin...\n"
+msgid "Vim: Reading from stdin...\n"
msgstr "Vim: Đọc từ đầu vào tiêu chuẩn stdin...\n"
-#. Re-opening the original file failed!
-#: ../fileio.c:909
+msgid "Reading from stdin..."
+msgstr "Đọc từ đầu vào tiêu chuẩn stdin..."
+
msgid "E202: Conversion made file unreadable!"
msgstr "E202: Sự biến đổi làm cho tập tin trở thành không thể đọc!"
-#. fifo or socket
-#: ../fileio.c:1782
msgid "[fifo/socket]"
msgstr "[fifo/socket]"
-#. fifo
-#: ../fileio.c:1788
msgid "[fifo]"
msgstr "[fifo]"
-#. or socket
-#: ../fileio.c:1794
msgid "[socket]"
msgstr "[socket]"
-#. or character special
-#: ../fileio.c:1801
-#, fuzzy
-msgid "[character special]"
-msgstr "1 ký tự"
+msgid "[RO]"
+msgstr "[Chỉ đọc]"
-#: ../fileio.c:1815
msgid "[CR missing]"
msgstr "[thiếu ký tự CR]"
-#: ../fileio.c:1819
+msgid "[NL found]"
+msgstr "[tìm thấy ký tự NL]"
+
msgid "[long lines split]"
msgstr "[dòng dài được chia nhỏ]"
-#: ../fileio.c:1823 ../fileio.c:3512
msgid "[NOT converted]"
msgstr "[KHÔNG được chuyển đổi]"
-#: ../fileio.c:1826 ../fileio.c:3515
msgid "[converted]"
msgstr "[đã chuyển bảng mã]"
-#: ../fileio.c:1831
-#, fuzzy, c-format
-msgid "[CONVERSION ERROR in line %<PRId64>]"
-msgstr "[BYTE KHÔNG CHO PHÉP trên dòng %<PRId64>]"
+msgid "[crypted]"
+msgstr "[đã mã hóa]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[LỖI CHUYỂN BẢNG MÃ]"
-#: ../fileio.c:1835
#, c-format
-msgid "[ILLEGAL BYTE in line %<PRId64>]"
-msgstr "[BYTE KHÔNG CHO PHÉP trên dòng %<PRId64>]"
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BYTE KHÔNG CHO PHÉP trên dòng %ld]"
-#: ../fileio.c:1838
msgid "[READ ERRORS]"
msgstr "[LỖI ĐỌC]"
-#: ../fileio.c:2104
msgid "Can't find temp file for conversion"
msgstr "Không tìm thấy tập tin tạm thời (temp) để chuyển bảng mã"
-#: ../fileio.c:2110
msgid "Conversion with 'charconvert' failed"
msgstr "Chuyển đổi nhờ 'charconvert' không được thực hiện"
-#: ../fileio.c:2113
msgid "can't read output of 'charconvert'"
msgstr "không đọc được đầu ra của 'charconvert'"
-#: ../fileio.c:2437
-#, fuzzy
-msgid "E676: No matching autocommands for acwrite buffer"
-msgstr "Không có câu lệnh tự động tương ứng"
-
-#: ../fileio.c:2466
msgid "E203: Autocommands deleted or unloaded buffer to be written"
msgstr "E203: Câu lệnh tự động đã xóa hoặc bỏ nạp bộ đệm cần ghi nhớ"
-#: ../fileio.c:2486
msgid "E204: Autocommand changed number of lines in unexpected way"
msgstr "E204: Câu lệnh tự động đã thay đổ số dòng theo cách không mong muốn"
-#: ../fileio.c:2548 ../fileio.c:2565
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans không cho phép ghi nhớ bộ đệm chưa có thay đổi nào"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Ghi nhớ một phần bộ đệm NetBeans không được cho phép"
+
msgid "is not a file or writable device"
msgstr "không phải là một tập tin thay một thiết bị có thể ghi nhớ"
-#: ../fileio.c:2601
msgid "is read-only (add ! to override)"
msgstr "là tập tin chỉ đọc (thêm ! để ghi nhớ bằng mọi giá)"
-#: ../fileio.c:2886
msgid "E506: Can't write to backup file (add ! to override)"
msgstr ""
"E506: Không thể ghi nhớ vào tập tin lưu trữ (thêm ! để ghi nhớ bằng mọi giá"
-#: ../fileio.c:2898
msgid "E507: Close error for backup file (add ! to override)"
msgstr "E507: Lỗi đóng tập tin lưu trữ (thêm ! để bỏ qua việc kiểm tra lại)"
-#: ../fileio.c:2901
msgid "E508: Can't read file for backup (add ! to override)"
msgstr ""
"E508: Không đọc được tập tin lưu trữ (thêm ! để bỏ qua việc kiểm tra lại)"
-#: ../fileio.c:2923
msgid "E509: Cannot create backup file (add ! to override)"
msgstr ""
"E509: Không tạo được tập tin lưu trữ (thêm ! để bỏ qua việc kiểm tra lại)"
-#: ../fileio.c:3008
msgid "E510: Can't make backup file (add ! to override)"
msgstr ""
"E510: Không tạo được tập tin lưu trữ (thêm ! để bỏ qua việc kiểm tra lại)"
-#. Can't write without a tempfile!
-#: ../fileio.c:3121
msgid "E214: Can't find temp file for writing"
msgstr "E214: Không tìm thấy tập tin tạm thời (temp) để ghi nhớ"
-#: ../fileio.c:3134
msgid "E213: Cannot convert (add ! to write without conversion)"
msgstr ""
"E213: Không thể chuyển đổi bảng mã (thêm ! để ghi nhớ mà không chuyển đổi)"
-#: ../fileio.c:3169
msgid "E166: Can't open linked file for writing"
msgstr "E166: Không thể mở tập tin liên kết để ghi nhớ"
-#: ../fileio.c:3173
msgid "E212: Can't open file for writing"
msgstr "E212: Không thể mở tập tin để ghi nhớ"
-#: ../fileio.c:3363
msgid "E667: Fsync failed"
msgstr "E667: Không thực hiện thành công hàm số fsync()"
-#: ../fileio.c:3398
msgid "E512: Close failed"
msgstr "E512: Thao tác đóng không thành công"
-#: ../fileio.c:3436
-#, fuzzy
-msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+# TODO: Capitalise first word of message?
+msgid "E513: Write error, conversion failed"
msgstr "E513: Lỗi ghi nhớ, biến đổi không thành công"
-#: ../fileio.c:3441
-#, c-format
-msgid ""
-"E513: write error, conversion failed in line %<PRId64> (make 'fenc' empty to "
-"override)"
-msgstr ""
-
-#: ../fileio.c:3448
-msgid "E514: write error (file system full?)"
+# TODO: Capitalise first word of message?
+msgid "E514: Write error (file system full?)"
msgstr "E514: lỗi ghi nhớ (không còn chỗ trống?)"
-#: ../fileio.c:3506
msgid " CONVERSION ERROR"
msgstr " LỖI BIẾN ĐỔI"
-#: ../fileio.c:3509
-#, fuzzy, c-format
-msgid " in line %<PRId64>;"
-msgstr "dòng %<PRId64>"
-
-#: ../fileio.c:3519
msgid "[Device]"
msgstr "[Thiết bị]"
-#: ../fileio.c:3522
msgid "[New]"
msgstr "[Mới]"
-#: ../fileio.c:3535
msgid " [a]"
msgstr " [a]"
-#: ../fileio.c:3535
msgid " appended"
msgstr " đã thêm"
-#: ../fileio.c:3537
msgid " [w]"
msgstr " [w]"
-#: ../fileio.c:3537
msgid " written"
msgstr " đã ghi"
-#: ../fileio.c:3579
msgid "E205: Patchmode: can't save original file"
msgstr "E205: Chế độ vá lỗi (patch): không thể ghi nhớ tập tin gốc"
-#: ../fileio.c:3602
-msgid "E206: patchmode: can't touch empty original file"
+# TODO: Capitalise first word of message?
+msgid "E206: Patchmode: can't touch empty original file"
msgstr ""
"E206: Chế độ vá lỗi (patch): không thể thay đổi tham số của tập tin gốc "
"trống rỗng"
-#: ../fileio.c:3616
msgid "E207: Can't delete backup file"
msgstr "E207: Không thể xóa tập tin lưu trữ (backup)"
-#: ../fileio.c:3672
msgid ""
"\n"
"WARNING: Original file may be lost or damaged\n"
@@ -2308,97 +1413,73 @@ msgstr ""
"\n"
"CẢNH BÁO: Tập tin gốc có thể bị mất hoặc bị hỏng\n"
-#: ../fileio.c:3675
msgid "don't quit the editor until the file is successfully written!"
msgstr ""
"đừng thoát khởi trình soạn thảo, khi tập tin còn chưa được ghi nhớ thành cồng"
-#: ../fileio.c:3795
msgid "[dos]"
msgstr "[dos]"
-#: ../fileio.c:3795
msgid "[dos format]"
msgstr "[định dạng dos]"
-#: ../fileio.c:3801
msgid "[mac]"
msgstr "[mac]"
-#: ../fileio.c:3801
msgid "[mac format]"
msgstr "[định dạng mac]"
-#: ../fileio.c:3807
msgid "[unix]"
msgstr "[unix]"
-#: ../fileio.c:3807
msgid "[unix format]"
msgstr "[định dạng unix]"
-#: ../fileio.c:3831
msgid "1 line, "
msgstr "1 dòng, "
-#: ../fileio.c:3833
#, c-format
-msgid "%<PRId64> lines, "
-msgstr "%<PRId64> dòng, "
+msgid "%ld lines, "
+msgstr "%ld dòng, "
-#: ../fileio.c:3836
msgid "1 character"
msgstr "1 ký tự"
-#: ../fileio.c:3838
#, c-format
-msgid "%<PRId64> characters"
-msgstr "%<PRId64> ký tự"
+msgid "%ld characters"
+msgstr "%ld ký tự"
-#: ../fileio.c:3849
msgid "[noeol]"
msgstr "[noeol]"
-#: ../fileio.c:3849
msgid "[Incomplete last line]"
msgstr "[Dòng cuối cùng không đầy đủ]"
-#. don't overwrite messages here
-#. must give this prompt
-#. don't use emsg() here, don't want to flush the buffers
-#: ../fileio.c:3865
msgid "WARNING: The file has been changed since reading it!!!"
msgstr "CẢNH BÁO: Tập tin đã thay đổi so với thời điểm đọc!!!"
-#: ../fileio.c:3867
msgid "Do you really want to write to it"
msgstr "Bạn có chắc muốn ghi nhớ vào tập tin này"
-#: ../fileio.c:4648
#, c-format
msgid "E208: Error writing to \"%s\""
msgstr "E208: Lỗi ghi nhớ vào \"%s\""
-#: ../fileio.c:4655
#, c-format
msgid "E209: Error closing \"%s\""
msgstr "E209: Lỗi đóng \"%s\""
-#: ../fileio.c:4657
#, c-format
msgid "E210: Error reading \"%s\""
msgstr "E210: Lỗi đọc \"%s\""
-#: ../fileio.c:4883
msgid "E246: FileChangedShell autocommand deleted buffer"
msgstr "E246: Bộ đệm bị xóa khi thực hiện câu lệnh tự động FileChangedShell"
-#: ../fileio.c:4894
-#, fuzzy, c-format
-msgid "E211: File \"%s\" no longer available"
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
msgstr "E211: Cảnh báo: Tập tin \"%s\" không còn truy cập được nữa"
-#: ../fileio.c:4906
#, c-format
msgid ""
"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
@@ -2407,44 +1488,28 @@ msgstr ""
"W12: Cảnh báo: Tập tin \"%s\" và bộ đệm Vim đã thay đổi không phụ thuộc vào "
"nhau"
-#: ../fileio.c:4907
-#, fuzzy
-msgid "See \":help W12\" for more info."
-msgstr "Hãy xem thông tin chi tiết trong \":help W11\"."
-
-#: ../fileio.c:4910
#, c-format
msgid "W11: Warning: File \"%s\" has changed since editing started"
msgstr ""
"W11: Cảnh báo: Tập tin \"%s\" đã thay đổi sau khi việc soạn thảo bắt đầu"
-#: ../fileio.c:4911
-msgid "See \":help W11\" for more info."
-msgstr "Hãy xem thông tin chi tiết trong \":help W11\"."
-
-#: ../fileio.c:4914
#, c-format
msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
msgstr ""
"W16: Cảnh báo: chế độ truy cập tới tập tin \"%s\" đã thay đổi sau khi bắt "
"đầu soạn thảo"
-#: ../fileio.c:4915
-#, fuzzy
-msgid "See \":help W16\" for more info."
-msgstr "Hãy xem thông tin chi tiết trong \":help W11\"."
-
-#: ../fileio.c:4927
#, c-format
msgid "W13: Warning: File \"%s\" has been created after editing started"
msgstr ""
"W13: Cảnh báo: tập tin \"%s\" được tạo ra sau khi việc soạn thảo bắt đầu"
-#: ../fileio.c:4947
+msgid "See \":help W11\" for more info."
+msgstr "Hãy xem thông tin chi tiết trong \":help W11\"."
+
msgid "Warning"
msgstr "Cảnh báo"
-#: ../fileio.c:4948
msgid ""
"&OK\n"
"&Load File"
@@ -2452,48 +1517,33 @@ msgstr ""
"&OK\n"
"&Nạp tập tin"
-#: ../fileio.c:5065
#, c-format
msgid "E462: Could not prepare for reloading \"%s\""
msgstr "E462: Không thể chuẩn bị để nạp lại \"%s\""
-#: ../fileio.c:5078
#, c-format
msgid "E321: Could not reload \"%s\""
msgstr "E321: Không thể nạp lại \"%s\""
-#: ../fileio.c:5601
msgid "--Deleted--"
msgstr "--Bị xóa--"
-#: ../fileio.c:5732
-#, c-format
-msgid "auto-removing autocommand: %s <buffer=%d>"
-msgstr ""
-
-#. the group doesn't exist
-#: ../fileio.c:5772
#, c-format
msgid "E367: No such group: \"%s\""
msgstr "E367: Nhóm \"%s\" không tồn tại"
-#: ../fileio.c:5897
#, c-format
msgid "E215: Illegal character after *: %s"
msgstr "E215: Ký tự không cho phép sau *: %s"
-#: ../fileio.c:5905
#, c-format
msgid "E216: No such event: %s"
msgstr "E216: Sự kiện không có thật: %s"
-#: ../fileio.c:5907
#, c-format
msgid "E216: No such group or event: %s"
msgstr "E216: Nhóm hoặc sự kiện không có thật: %s"
-#. Highlight title
-#: ../fileio.c:6090
msgid ""
"\n"
"--- Autocommands ---"
@@ -2501,681 +1551,400 @@ msgstr ""
"\n"
"--- Câu lệnh tự động ---"
-#: ../fileio.c:6293
-#, fuzzy, c-format
-msgid "E680: <buffer=%d>: invalid buffer number "
-msgstr "số của bộ đệm không đúng"
-
-#: ../fileio.c:6370
msgid "E217: Can't execute autocommands for ALL events"
msgstr "E217: Không thể thực hiện câu lệnh tự động cho MỌI sự kiện"
-#: ../fileio.c:6393
msgid "No matching autocommands"
msgstr "Không có câu lệnh tự động tương ứng"
-#: ../fileio.c:6831
-msgid "E218: autocommand nesting too deep"
+# TODO: Capitalise first word of message?
+msgid "E218: Autocommand nesting too deep"
msgstr "E218: câu lệnh tự động xếp lồng vào nhau quá xâu"
-#: ../fileio.c:7143
#, c-format
msgid "%s Autocommands for \"%s\""
msgstr "%s câu lệnh tự động cho \"%s\""
-#: ../fileio.c:7149
#, c-format
msgid "Executing %s"
msgstr "Thực hiện %s"
-#: ../fileio.c:7211
#, c-format
msgid "autocommand %s"
msgstr "câu lệnh tự động %s"
-#: ../fileio.c:7795
msgid "E219: Missing {."
msgstr "E219: Thiếu {."
-#: ../fileio.c:7797
msgid "E220: Missing }."
msgstr "E220: Thiếu }."
-#: ../fold.c:93
msgid "E490: No fold found"
msgstr "E490: Không tìm thấy nếp gấp"
-#: ../fold.c:544
msgid "E350: Cannot create fold with current 'foldmethod'"
msgstr ""
"E350: Không thể tạo nếp gấp với giá trị hiện thời của tùy chọn 'foldmethod'"
-#: ../fold.c:546
msgid "E351: Cannot delete fold with current 'foldmethod'"
msgstr ""
"E351: Không thể xóa nếp gấp với giá trị hiện thời của tùy chọn 'foldmethod'"
-#: ../fold.c:1784
-#, c-format
-msgid "+--%3ld lines folded "
-msgstr "+--%3ld dòng được gấp"
-
-#. buffer has already been read
-#: ../getchar.c:273
msgid "E222: Add to read buffer"
msgstr "E222: Thêm vào bộ đệm đang đọc"
-#: ../getchar.c:2040
-msgid "E223: recursive mapping"
+# TODO: Capitalise first word of message?
+msgid "E223: Recursive mapping"
msgstr "E223: ánh xạ đệ quy"
-#: ../getchar.c:2849
-#, c-format
-msgid "E224: global abbreviation already exists for %s"
+# TODO: Capitalise first word of message?
+msgid "E224: Global abbreviation already exists for %s"
msgstr "E224: đã có sự viết tắt toàn cầu cho %s"
-#: ../getchar.c:2852
-#, c-format
-msgid "E225: global mapping already exists for %s"
+# TODO: Capitalise first word of message?
+msgid "E225: Global mapping already exists for %s"
msgstr "E225: đã có ánh xạ toàn cầu cho %s"
-#: ../getchar.c:2952
-#, c-format
-msgid "E226: abbreviation already exists for %s"
+# TODO: Capitalise first word of message?
+msgid "E226: Abbreviation already exists for %s"
msgstr "E226: đã có sự viết tắt cho %s"
-#: ../getchar.c:2955
-#, c-format
-msgid "E227: mapping already exists for %s"
+# TODO: Capitalise first word of message?
+msgid "E227: Mapping already exists for %s"
msgstr "E227: đã có ánh xạ cho %s"
-#: ../getchar.c:3008
msgid "No abbreviation found"
msgstr "Không tìm thấy viết tắt"
-#: ../getchar.c:3010
msgid "No mapping found"
msgstr "Không tìm thấy ánh xạ"
-#: ../getchar.c:3974
msgid "E228: makemap: Illegal mode"
msgstr "E228: makemap: Chế độ không cho phép"
-#. key value of 'cedit' option
-#. type of cmdline window or 0
-#. result of cmdline window or 0
-#: ../globals.h:924
-msgid "--No lines in buffer--"
-msgstr "-- Không có dòng nào trong bộ đệm --"
-
-#.
-#. * The error messages that can be shared are included here.
-#. * Excluded are errors that are only used once and debugging messages.
-#.
-#: ../globals.h:996
-msgid "E470: Command aborted"
-msgstr "E470: Câu lệnh bị dừng"
-
-#: ../globals.h:997
-msgid "E471: Argument required"
-msgstr "E471: Cần chỉ ra tham số"
-
-#: ../globals.h:998
-msgid "E10: \\ should be followed by /, ? or &"
-msgstr "E10: Sau \\ phải là các ký tự /, ? hoặc &"
-
-#: ../globals.h:1000
-msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
-msgstr "E11: Lỗi trong cửa sổ dòng lệnh; <CR> thực hiện, CTRL-C thoát"
-
-#: ../globals.h:1002
-msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
-msgstr ""
-"E12: Câu lệnh không cho phép từ exrc/vimrc trong thư mục hiện thời hoặc "
-"trong tìm kiếm thẻ ghi"
+msgid "<cannot open> "
+msgstr "<không thể mở> "
-#: ../globals.h:1003
-msgid "E171: Missing :endif"
-msgstr "E171: Thiếu câu lệnh :endif"
-
-#: ../globals.h:1004
-msgid "E600: Missing :endtry"
-msgstr "E600: Thiếu câu lệnh :endtry"
-
-#: ../globals.h:1005
-msgid "E170: Missing :endwhile"
-msgstr "E170: Thiếu câu lệnh :endwhile"
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: không tìm thấy phông chữ %s"
-#: ../globals.h:1006
-#, fuzzy
-msgid "E170: Missing :endfor"
-msgstr "E171: Thiếu câu lệnh :endif"
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: không trở lại được thư mục hiện thời"
-#: ../globals.h:1007
-msgid "E588: :endwhile without :while"
-msgstr "E588: Câu lệnh :endwhile không có lệnh :while (1 cặp)"
+msgid "Pathname:"
+msgstr "Đường dẫn tới tập tin:"
-#: ../globals.h:1008
-#, fuzzy
-msgid "E588: :endfor without :for"
-msgstr "E580: :endif không có :if"
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: không tìm thấy thư mục hiện thời"
-#: ../globals.h:1009
-msgid "E13: File exists (add ! to override)"
-msgstr "E13: Tập tin đã tồn tại (thêm ! để ghi chèn)"
+msgid "OK"
+msgstr "Đồng ý"
-#: ../globals.h:1010
-msgid "E472: Command failed"
-msgstr "E472: Không thực hiện thành công câu lệnh"
+msgid "Cancel"
+msgstr "Hủy bỏ"
-#: ../globals.h:1011
-msgid "E473: Internal error"
-msgstr "E473: Lỗi nội bộ"
+msgid "Vim dialog"
+msgstr "Hộp thoại Vim"
-#: ../globals.h:1012
-msgid "Interrupted"
-msgstr "Bị gián đoạn"
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Thanh cuộn: Không thể xác định hình học của thanh cuộn."
-#: ../globals.h:1013
-msgid "E14: Invalid address"
-msgstr "E14: Địa chỉ không cho phép"
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Không tạo được BalloonEval với cả thông báo và lời gọi ngược lại"
-#: ../globals.h:1014
-msgid "E474: Invalid argument"
-msgstr "E474: Tham số không cho phép"
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Không chạy được giao diện đồ họa GUI"
-#: ../globals.h:1015
#, c-format
-msgid "E475: Invalid argument: %s"
-msgstr "E475: Tham số không cho phép: %s"
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Không đọc được từ \"%s\""
-#: ../globals.h:1016
-#, c-format
-msgid "E15: Invalid expression: %s"
-msgstr "E15: Biểu thức không cho phép: %s"
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Không chạy được giao diện đồ họa GUI, đưa ra phông chữ không đúng"
-#: ../globals.h:1017
-msgid "E16: Invalid range"
-msgstr "E16: Vùng không cho phép"
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' có giá trị không đúng"
-#: ../globals.h:1018
-msgid "E476: Invalid command"
-msgstr "E476: Câu lệnh không cho phép"
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Giá trị của 'imactivatekey' không đúng"
-#: ../globals.h:1019
#, c-format
-msgid "E17: \"%s\" is a directory"
-msgstr "E17: \"%s\" là mộ thư mục"
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Không chỉ định được màu %s"
-#: ../globals.h:1020
-#, fuzzy
-msgid "E900: Invalid job id"
-msgstr "E49: Kích thước thanh cuộn không cho phép"
+msgid "Vim dialog..."
+msgstr "Hộp thoại Vim..."
-#: ../globals.h:1021
-msgid "E901: Job table is full"
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
msgstr ""
+"&Có\n"
+"&Không\n"
+"&Dừng"
-#: ../globals.h:1024
-#, c-format
-msgid "E364: Library call failed for \"%s()\""
-msgstr "E364: Gọi hàm số \"%s()\" của thư viện không thành công"
+msgid "Input _Methods"
+msgstr "Phương pháp _nhập liệu"
-#: ../globals.h:1026
-msgid "E19: Mark has invalid line number"
-msgstr "E19: Dấu hiệu chỉ đến một số thứ tự dòng không đúng"
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Tìm kiếm và thay thế..."
-#: ../globals.h:1027
-msgid "E20: Mark not set"
-msgstr "E20: Dấu hiệu không được xác định"
+msgid "VIM - Search..."
+msgstr "VIM - Tìm kiếm..."
-#: ../globals.h:1029
-msgid "E21: Cannot make changes, 'modifiable' is off"
-msgstr "E21: Không thể thay đổi, vì tùy chọn 'modifiable' bị tắt"
+msgid "Find what:"
+msgstr "Tìm kiếm gì:"
-#: ../globals.h:1030
-msgid "E22: Scripts nested too deep"
-msgstr "E22: Các script lồng vào nhau quá sâu"
+msgid "Replace with:"
+msgstr "Thay thế bởi:"
-#: ../globals.h:1031
-msgid "E23: No alternate file"
-msgstr "E23: Không có tập tin xen kẽ"
+msgid "Match whole word only"
+msgstr "Chỉ tìm tương ứng hoàn toàn với từ"
-#: ../globals.h:1032
-msgid "E24: No such abbreviation"
-msgstr "E24: Không có chữ viết tắt như vậy"
+msgid "Match case"
+msgstr "Có tính kiểu chữ"
-#: ../globals.h:1033
-msgid "E477: No ! allowed"
-msgstr "E477: Không cho phép !"
+msgid "Direction"
+msgstr "Hướng"
-#: ../globals.h:1035
-msgid "E25: Nvim does not have a built-in GUI"
-msgstr "E25: Không sử dụng được giao diện đồ họa vì không chọn khi biên dịch"
+msgid "Up"
+msgstr "Lên"
-#: ../globals.h:1036
-#, c-format
-msgid "E28: No such highlight group name: %s"
-msgstr "E28: Nhóm chiếu sáng cú pháp %s không tồn tại"
+msgid "Down"
+msgstr "Xuống"
-#: ../globals.h:1037
-msgid "E29: No inserted text yet"
-msgstr "E29: Tạm thời chưa có văn bản được chèn"
+msgid "Find Next"
+msgstr "Tìm tiếp"
-#: ../globals.h:1038
-msgid "E30: No previous command line"
-msgstr "E30: Không có dòng lệnh trước"
+msgid "Replace"
+msgstr "Thay thế"
-#: ../globals.h:1039
-msgid "E31: No such mapping"
-msgstr "E31: Không có ánh xạ (mapping) như vậy"
+msgid "Replace All"
+msgstr "Thay thế tất cả"
-#: ../globals.h:1040
-msgid "E479: No match"
-msgstr "E479: Không có tương ứng"
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Nhận được yêu cầu \"chết\" (dừng) từ trình quản lý màn hình\n"
-#: ../globals.h:1041
-#, c-format
-msgid "E480: No match: %s"
-msgstr "E480: Không có tương ứng: %s"
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Cửa sổ chính đã bị đóng đột ngột\n"
-#: ../globals.h:1042
-msgid "E32: No file name"
-msgstr "E32: Không có tên tập tin"
+msgid "Font Selection"
+msgstr "Chọn phông chữ"
-#: ../globals.h:1044
-msgid "E33: No previous substitute regular expression"
-msgstr "E33: Không có biểu thức chính quy trước để thay thế"
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Sử dụng CUT_BUFFER0 thay cho lựa chọn trống rỗng"
-#: ../globals.h:1045
-msgid "E34: No previous command"
-msgstr "E34: Không có câu lệnh trước"
+msgid "Filter"
+msgstr "Đầu lọc"
-#: ../globals.h:1046
-msgid "E35: No previous regular expression"
-msgstr "E35: Không có biểu thức chính quy trước"
+msgid "Directories"
+msgstr "Thư mục"
-#: ../globals.h:1047
-msgid "E481: No range allowed"
-msgstr "E481: Không cho phép sử dụng phạm vi"
+msgid "Help"
+msgstr "Trợ giúp"
-#: ../globals.h:1048
-msgid "E36: Not enough room"
-msgstr "E36: Không đủ chỗ trống"
+msgid "Files"
+msgstr "Tập tin"
-#: ../globals.h:1049
-#, c-format
-msgid "E482: Can't create file %s"
-msgstr "E482: Không tạo được tập tin %s"
+msgid "Selection"
+msgstr "Lựa chọn"
-#: ../globals.h:1050
-msgid "E483: Can't get temp file name"
-msgstr "E483: Không nhận được tên tập tin tạm thời (temp)"
+msgid "Undo"
+msgstr "Hủy thao tác"
-#: ../globals.h:1051
#, c-format
-msgid "E484: Can't open file %s"
-msgstr "E484: Không mở được tập tin %s"
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Không tìm được tiêu đề cửa sổ \"%s\""
-#: ../globals.h:1052
#, c-format
-msgid "E485: Can't read file %s"
-msgstr "E485: Không đọc được tập tin %s"
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Tham số không được hỗ trợ: \"-%s\"; Hãy sử dụng phiên bản OLE."
-#: ../globals.h:1054
-msgid "E37: No write since last change (add ! to override)"
-msgstr "E37: Thay đổi chưa được ghi nhớ (thêm ! để bỏ qua ghi nhớ)"
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Không mở được cửa sổ bên trong ứng dụng MDI"
-#: ../globals.h:1055
-#, fuzzy
-msgid "E37: No write since last change"
-msgstr "[Thay đổi chưa được ghi nhớ]\n"
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Tìm kiếm chuỗi (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
-#: ../globals.h:1056
-msgid "E38: Null argument"
-msgstr "E38: Tham sô bằng 0"
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Tìm kiếm và Thay thế (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
-#: ../globals.h:1057
-msgid "E39: Number expected"
-msgstr "E39: Yêu cầu một số"
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Không chỉ định được bản ghi trong bảng màu, một vài màu có thể "
+"hiển thị không chính xác"
-#: ../globals.h:1058
#, c-format
-msgid "E40: Can't open errorfile %s"
-msgstr "E40: Không mở được tập tin lỗi %s"
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Trong bộ phông chữ %s thiếu phông cho các bảng mã sau:"
-#: ../globals.h:1059
-msgid "E41: Out of memory!"
-msgstr "E41: Không đủ bộ nhớ!"
-
-#: ../globals.h:1060
-msgid "Pattern not found"
-msgstr "Không tìm thấy mẫu (pattern)"
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Bộ phông chữ: %s"
-#: ../globals.h:1061
#, c-format
-msgid "E486: Pattern not found: %s"
-msgstr "E486: Không tìm thấy mẫu (pattern): %s"
+msgid "Font '%s' is not fixed-width"
+msgstr "Phông chữ '%s' không phải là phông có độ rộng cố định (fixed-width)"
-#: ../globals.h:1062
-msgid "E487: Argument must be positive"
-msgstr "E487: Tham số phải là một số dương"
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Bộ phông chữ: %s\n"
-#: ../globals.h:1064
-msgid "E459: Cannot go back to previous directory"
-msgstr "E459: Không quay lại được thư mục trước đó"
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
-#: ../globals.h:1066
-msgid "E42: No Errors"
-msgstr "E42: Không có lỗi"
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
-#: ../globals.h:1067
-msgid "E776: No location list"
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
msgstr ""
+"Chiều rộng phông chữ font%ld phải lớn hơn hai lần so với chiều rộng font0\n"
-#: ../globals.h:1068
-msgid "E43: Damaged match string"
-msgstr "E43: Chuỗi tương ứng bị hỏng"
-
-#: ../globals.h:1069
-msgid "E44: Corrupted regexp program"
-msgstr "E44: Chương trình xử lý biểu thức chính quy bị hỏng"
-
-#: ../globals.h:1071
-msgid "E45: 'readonly' option is set (add ! to override)"
-msgstr "E45: Tùy chọn 'readonly' được bật (Hãy thêm ! để lờ đi)"
-
-#: ../globals.h:1073
-#, fuzzy, c-format
-msgid "E46: Cannot change read-only variable \"%s\""
-msgstr "E46: Không thay đổi được biến chỉ đọc \"%s\""
-
-#: ../globals.h:1075
-#, fuzzy, c-format
-msgid "E794: Cannot set variable in the sandbox: \"%s\""
-msgstr "E46: Không thay đổi được biến chỉ đọc \"%s\""
-
-#: ../globals.h:1076
-msgid "E47: Error while reading errorfile"
-msgstr "E47: Lỗi khi đọc tập tin lỗi"
-
-#: ../globals.h:1078
-msgid "E48: Not allowed in sandbox"
-msgstr "E48: Không cho phép trong hộp cát (sandbox)"
-
-#: ../globals.h:1080
-msgid "E523: Not allowed here"
-msgstr "E523: Không cho phép ở đây"
-
-#: ../globals.h:1082
-msgid "E359: Screen mode setting not supported"
-msgstr "E359: Chế độ màn hình không được hỗ trợ"
-
-#: ../globals.h:1083
-msgid "E49: Invalid scroll size"
-msgstr "E49: Kích thước thanh cuộn không cho phép"
-
-#: ../globals.h:1084
-msgid "E91: 'shell' option is empty"
-msgstr "E91: Tùy chọn 'shell' là một chuỗi rỗng"
-
-#: ../globals.h:1085
-msgid "E255: Couldn't read in sign data!"
-msgstr "E255: Không đọc được dữ liệu về ký tự!"
-
-#: ../globals.h:1086
-msgid "E72: Close error on swap file"
-msgstr "E72: Lỗi đóng tập tin trao đổi (swap)"
-
-#: ../globals.h:1087
-msgid "E73: tag stack empty"
-msgstr "E73: đống thẻ ghi rỗng"
-
-#: ../globals.h:1088
-msgid "E74: Command too complex"
-msgstr "E74: Câu lệnh quá phức tạp"
-
-#: ../globals.h:1089
-msgid "E75: Name too long"
-msgstr "E75: Tên quá dài"
-
-#: ../globals.h:1090
-msgid "E76: Too many ["
-msgstr "E76: Quá nhiều ký tự ["
-
-#: ../globals.h:1091
-msgid "E77: Too many file names"
-msgstr "E77: Quá nhiều tên tập tin"
-
-#: ../globals.h:1092
-msgid "E488: Trailing characters"
-msgstr "E488: Ký tự thừa ở đuôi"
-
-#: ../globals.h:1093
-msgid "E78: Unknown mark"
-msgstr "E78: Dấu hiệu không biết"
-
-#: ../globals.h:1094
-msgid "E79: Cannot expand wildcards"
-msgstr "E79: Không thực hiện được phép thế theo wildcard"
-
-#: ../globals.h:1096
-msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
-msgstr "E591: giá trị của 'winheight' không thể nhỏ hơn 'winminheight'"
-
-#: ../globals.h:1098
-msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
-msgstr "E592: giá trị của 'winwidth' không thể nhỏ hơn 'winminwidth'"
-
-#: ../globals.h:1099
-msgid "E80: Error while writing"
-msgstr "E80: Lỗi khi ghi nhớ"
-
-#: ../globals.h:1100
-msgid "Zero count"
-msgstr "Giá trị của bộ đếm bằng 0"
-
-#: ../globals.h:1101
-msgid "E81: Using <SID> not in a script context"
-msgstr "E81: Sử dụng <SID> ngoài phạm vi script"
-
-#: ../globals.h:1102
-#, fuzzy, c-format
-msgid "E685: Internal error: %s"
-msgstr "E473: Lỗi nội bộ"
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Chiều rộng font0: %ld\n"
-#: ../globals.h:1104
-msgid "E363: pattern uses more memory than 'maxmempattern'"
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
msgstr ""
+"Chiều rộng font1: %ld\n"
+"\n"
-#: ../globals.h:1105
-#, fuzzy
-msgid "E749: empty buffer"
-msgstr "E279: Đây không phải là bộ đệm SNiFF+"
-
-#: ../globals.h:1108
-#, fuzzy
-msgid "E682: Invalid search pattern or delimiter"
-msgstr "E383: Chuỗi tìm kiếm không đúng: %s"
-
-#: ../globals.h:1109
-msgid "E139: File is loaded in another buffer"
-msgstr "E139: Tập tin được nạp trong bộ đệm khác"
-
-#: ../globals.h:1110
-#, fuzzy, c-format
-msgid "E764: Option '%s' is not set"
-msgstr "E236: Phông chữ \"%s\" không có độ rộng cố định (fixed-width)"
-
-#: ../globals.h:1111
-#, fuzzy
-msgid "E850: Invalid register name"
-msgstr "E354: Tên sổ đăng ký không cho phép: '%s'"
-
-#: ../globals.h:1114
-msgid "search hit TOP, continuing at BOTTOM"
-msgstr "tìm kiếm sẽ được tiếp tục từ CUỐI tài liệu"
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: LỖI máy tự động Hangual (tiếng Hàn)"
-#: ../globals.h:1115
-msgid "search hit BOTTOM, continuing at TOP"
-msgstr "tìm kiếm sẽ được tiếp tục từ ĐẦU tài liệu"
-
-#: ../if_cscope.c:85
msgid "Add a new database"
msgstr "Thêm một cơ sở dữ liệu mới"
-#: ../if_cscope.c:87
msgid "Query for a pattern"
msgstr "Yêu cầu theo một mẫu"
-#: ../if_cscope.c:89
msgid "Show this message"
msgstr "Hiển thị thông báo này"
-#: ../if_cscope.c:91
msgid "Kill a connection"
msgstr "Hủy kết nối"
-#: ../if_cscope.c:93
msgid "Reinit all connections"
msgstr "Khởi đầu lại tất cả các kết nối"
-#: ../if_cscope.c:95
msgid "Show connections"
msgstr "Hiển thị kết nối"
-#: ../if_cscope.c:101
#, c-format
msgid "E560: Usage: cs[cope] %s"
msgstr "E560: Sử dụng: cs[cope] %s"
-#: ../if_cscope.c:225
msgid "This cscope command does not support splitting the window.\n"
msgstr "Câu lệnh cscope này không hỗ trợ việc chia (split) cửa sổ.\n"
-#: ../if_cscope.c:266
msgid "E562: Usage: cstag <ident>"
msgstr "E562: Sử dụng: cstag <tên>"
-#: ../if_cscope.c:313
-msgid "E257: cstag: tag not found"
+# TODO: Capitalise first word of message?
+msgid "E257: cstag: Tag not found"
msgstr "E257: cstag: không tìm thấy thẻ ghi"
-#: ../if_cscope.c:461
#, c-format
msgid "E563: stat(%s) error: %d"
msgstr "E563: lỗi stat(%s): %d"
-#: ../if_cscope.c:551
+msgid "E563: stat error"
+msgstr "E563: lỗi stat"
+
#, c-format
msgid "E564: %s is not a directory or a valid cscope database"
msgstr ""
"E564: %s không phải là một thư mục hoặc một cơ sở dữ liệu cscope thích hợp"
-#: ../if_cscope.c:566
#, c-format
msgid "Added cscope database %s"
msgstr "Đã thêm cơ sở dữ liệu cscope %s"
-#: ../if_cscope.c:616
-#, c-format
-msgid "E262: error reading cscope connection %<PRId64>"
-msgstr "E262: lỗi lấy thông tin từ kết nối cscope %<PRId64>"
+# TODO: Capitalise first word of message?
+msgid "E262: Error reading cscope connection %ld"
+msgstr "E262: lỗi lấy thông tin từ kết nối cscope %ld"
-#: ../if_cscope.c:711
-msgid "E561: unknown cscope search type"
+# TODO: Capitalise first word of message?
+msgid "E561: Unknown cscope search type"
msgstr "E561: không rõ loại tìm kiếm cscope"
-#: ../if_cscope.c:752 ../if_cscope.c:789
msgid "E566: Could not create cscope pipes"
msgstr "E566: Không tạo được đường ống (pipe) cho cscope"
-#: ../if_cscope.c:767
msgid "E622: Could not fork for cscope"
msgstr "E622: Không thực hiện được fork() cho cscope"
-#: ../if_cscope.c:849
-#, fuzzy
-msgid "cs_create_connection setpgid failed"
-msgstr "thực hiện cs_create_connection không thành công"
-
-#: ../if_cscope.c:853 ../if_cscope.c:889
msgid "cs_create_connection exec failed"
msgstr "thực hiện cs_create_connection không thành công"
-#: ../if_cscope.c:863 ../if_cscope.c:902
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Chạy tiến trình cscope không thành công"
+
msgid "cs_create_connection: fdopen for to_fp failed"
msgstr "cs_create_connection: thực hiện fdopen cho to_fp không thành công"
-#: ../if_cscope.c:865 ../if_cscope.c:906
msgid "cs_create_connection: fdopen for fr_fp failed"
msgstr "cs_create_connection: thực hiện fdopen cho fr_fp không thành công"
-#: ../if_cscope.c:890
-msgid "E623: Could not spawn cscope process"
-msgstr "E623: Chạy tiến trình cscope không thành công"
-
-#: ../if_cscope.c:932
-msgid "E567: no cscope connections"
+# TODO: Capitalise first word of message?
+msgid "E567: No cscope connections"
msgstr "E567: không có kết nối với cscope"
-#: ../if_cscope.c:1009
-#, c-format
-msgid "E469: invalid cscopequickfix flag %c for %c"
-msgstr "E469: cờ cscopequickfix %c cho %c không chính xác"
-
-#: ../if_cscope.c:1058
-#, c-format
-msgid "E259: no matches found for cscope query %s of %s"
+# TODO: Capitalise first word of message?
+msgid "E259: No matches found for cscope query %s of %s"
msgstr "E259: không tìm thấy tương ứng với yêu cầu cscope %s cho %s"
-#: ../if_cscope.c:1142
+# TODO: Capitalise first word of message?
+msgid "E469: Invalid cscopequickfix flag %c for %c"
+msgstr "E469: cờ cscopequickfix %c cho %c không chính xác"
+
msgid "cscope commands:\n"
msgstr "các lệnh cscope:\n"
-#: ../if_cscope.c:1150
-#, fuzzy, c-format
-msgid "%-5s: %s%*s (Usage: %s)"
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
msgstr "%-5s: %-30s (Sử dụng: %s)"
-#: ../if_cscope.c:1155
-msgid ""
-"\n"
-" c: Find functions calling this function\n"
-" d: Find functions called by this function\n"
-" e: Find this egrep pattern\n"
-" f: Find this file\n"
-" g: Find this definition\n"
-" i: Find files #including this file\n"
-" s: Find this C symbol\n"
-" t: Find this text string\n"
-msgstr ""
+# TODO: Capitalise first word of message?
+msgid "E625: Cannot open cscope database: %s"
+msgstr "E625: không mở được cơ sở dữ liệu cscope: %s"
-#: ../if_cscope.c:1226
-msgid "E568: duplicate cscope database not added"
+# TODO: Capitalise first word of message?
+msgid "E626: Cannot get cscope database information"
+msgstr "E626: không lấy được thông tin về cơ sở dữ liệu cscope"
+
+# TODO: Capitalise first word of message?
+msgid "E568: Duplicate cscope database not added"
msgstr "E568: cơ sở dữ liệu này của cscope đã được gắn vào từ trước"
-#: ../if_cscope.c:1335
-#, c-format
-msgid "E261: cscope connection %s not found"
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: đã đạt tới số kết nối lớn nhất cho phép với cscope"
+
+# TODO: Capitalise first word of message?
+msgid "E261: Cscope connection %s not found"
msgstr "E261: kết nối với cscope %s không được tìm thấy"
-#: ../if_cscope.c:1364
#, c-format
msgid "cscope connection %s closed"
msgstr "kết nối %s với cscope đã bị đóng"
-#. should not reach here
-#: ../if_cscope.c:1486
-msgid "E570: fatal error in cs_manage_matches"
+# TODO: Capitalise first word of message?
+msgid "E570: Fatal error in cs_manage_matches"
msgstr "E570: lỗi nặng trong cs_manage_matches"
-#: ../if_cscope.c:1693
#, c-format
msgid "Cscope tag: %s"
msgstr "Thẻ ghi cscope: %s"
-#: ../if_cscope.c:1711
msgid ""
"\n"
" # line"
@@ -3183,90 +1952,305 @@ msgstr ""
"\n"
" # dòng"
-#: ../if_cscope.c:1713
msgid "filename / context / line\n"
msgstr "tên tập tin / nội dung / dòng\n"
-#: ../if_cscope.c:1809
#, c-format
msgid "E609: Cscope error: %s"
msgstr "E609: Lỗi cscope: %s"
-#: ../if_cscope.c:2053
msgid "All cscope databases reset"
msgstr "Khởi động lại tất cả cơ sở dữ liệu cscope"
-#: ../if_cscope.c:2123
msgid "no cscope connections\n"
msgstr "không có kết nối với cscope\n"
-#: ../if_cscope.c:2126
msgid " # pid database name prepend path\n"
msgstr " # pid tên cơ sở dữ liệu đường dẫn ban đầu\n"
-#: ../main.c:144
-#, fuzzy
-msgid "Unknown option argument"
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Rất tiếc câu lệnh này không làm việc, vì thư viện Python chưa được nạp."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Không thể gọi Python một cách đệ quy"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Không xóa được thuộc tính OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "giá trị softspace phải là một số nguyên"
+
+msgid "invalid attribute"
+msgstr "thuộc tính không đúng"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() yêu cầu một danh sách các chuỗi"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Lỗi khi bắt đầu sử dụng vật thể I/O"
+
+msgid "invalid expression"
+msgstr "biểu thức không đúng"
+
+msgid "expressions disabled at compile time"
+msgstr "biểu thức bị tắt khi biên dịch"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "cố chỉ đến bộ đệm đã bị xóa"
+
+msgid "line number out of range"
+msgstr "số thứ tự của dòng vượt quá giới hạn"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<vật thể của bộ đệm (bị xóa) tại %8lX>"
+
+msgid "invalid mark name"
+msgstr "tên dấu hiệu không đúng"
+
+msgid "no such buffer"
+msgstr "không có bộ đệm như vậy"
+
+msgid "attempt to refer to deleted window"
+msgstr "cố chỉ đến cửa sổ đã bị đóng"
+
+msgid "readonly attribute"
+msgstr "thuộc tính chỉ đọc"
+
+msgid "cursor position outside buffer"
+msgstr "vị trí con trỏ nằm ngoài bộ đệm"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<vật thể của cửa sổ (bị xóa) tại %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<vật thể của cửa sổ (không rõ) tại %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<cửa sổ %d>"
+
+msgid "no such window"
+msgstr "không có cửa sổ như vậy"
+
+msgid "cannot save undo information"
+msgstr "không ghi được thông tin về việc hủy thao tác"
+
+msgid "cannot delete line"
+msgstr "không xóa được dòng"
+
+msgid "cannot replace line"
+msgstr "không thay thế được dòng"
+
+msgid "cannot insert line"
+msgstr "không chèn được dòng"
+
+msgid "string cannot contain newlines"
+msgstr "chuỗi không thể chứa ký tự dòng mới"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Rất tiếc câu lệnh này không làm việc, vì thư viện Ruby chưa đượcnạp."
+
+# TODO: Capitalise first word of message?
+msgid "E273: Unknown longjmp status %d"
+msgstr "E273: không rõ trạng thái của longjmp %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Bật tắt giữa thi hành/định nghĩa"
+
+msgid "Show base class of"
+msgstr "Hiển thị hạng cơ bản của"
+
+msgid "Show overridden member function"
+msgstr "Hiển thị hàm số bị nạp đè lên"
+
+msgid "Retrieve from file"
+msgstr "Nhận từ tập tin"
+
+msgid "Retrieve from project"
+msgstr "Nhận từ dự án"
+
+msgid "Retrieve from all projects"
+msgstr "Nhận từ tất cả các dự án"
+
+msgid "Retrieve"
+msgstr "Nhận"
+
+msgid "Show source of"
+msgstr "Hiển thị mã nguồn"
+
+msgid "Find symbol"
+msgstr "Tìm ký hiệu"
+
+msgid "Browse class"
+msgstr "Duyệt hạng"
+
+msgid "Show class in hierarchy"
+msgstr "Hiển thị hạng trong hệ thống cấp bậc"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Hiển thị hạng trong hệ thống cấp bậc giới hạn"
+
+msgid "Xref refers to"
+msgstr "Xref chỉ đến"
+
+msgid "Xref referred by"
+msgstr "Liên kết đến xref từ"
+
+msgid "Xref has a"
+msgstr "Xref có một"
+
+msgid "Xref used by"
+msgstr "Xref được sử dụng bởi"
+
+msgid "Show docu of"
+msgstr "Hiển thị docu của"
+
+msgid "Generate docu for"
+msgstr "Tạo docu cho"
+
+msgid "not "
+msgstr "không "
+
+msgid "connected"
+msgstr "được kết nối"
+
+
+msgid "invalid buffer number"
+msgstr "số của bộ đệm không đúng"
+
+msgid "not implemented yet"
+msgstr "tạm thời chưa được thực thi"
+
+msgid "unknown option"
+msgstr "tùy chọn không rõ"
+
+msgid "cannot set line(s)"
+msgstr "không thể đặt (các) dòng"
+
+msgid "mark not set"
+msgstr "dấu hiệu chưa được đặt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "hàng %d cột %d"
+
+msgid "cannot insert/append line"
+msgstr "không thể chèn hoặc thêm dòng"
+
+msgid "unknown flag: "
+msgstr "cờ không biết: "
+
+msgid "unknown vimOption"
+msgstr "không rõ tùy chọn vimOption"
+
+msgid "keyboard interrupt"
+msgstr "sự gián đoạn của bàn phím"
+
+msgid "Vim error"
+msgstr "lỗi của vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "không tạo được câu lệnh của bộ đệm hay của cửa sổ: vật thể đang bị xóa"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "không đăng ký được câu lệnh gọi ngược: bộ đệm hoặc cửa sổ đang bị xóa"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: LỖI NẶNG CỦA TCL: bị hỏng danh sách liên kết!? Hãy thông báo việc "
+"nàyđến danh sách thư (mailing list) vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"không đăng ký được câu lệnh gọi ngược: không tìm thấy liên kết đến bộ đệm "
+"hoặc cửa sổ"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Rất tiếc là câu lệnh này không làm việc, vì thư viện Tcl chưa được nạp"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: LỖI TCL: mã thoát ra không phải là một số nguyên!? Hãy thông báo điều "
+"này đến danh sách thư (mailing list) vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "không nhận được dòng"
+
+msgid "Unable to register a command server name"
+msgstr "Không đăng ký được một tên cho máy chủ câu lệnh"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Gửi câu lệnh vào chương trình khác không thành công"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Sử dụng id máy chủ không đúng: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Thuộc tính đăng ký của Vim được định dạng không đúng. Xóa!"
+
+msgid "Unknown option"
msgstr "Tùy chọn không biết"
-#: ../main.c:146
msgid "Too many edit arguments"
msgstr "Có quá nhiều tham số soạn thảo"
-#: ../main.c:148
msgid "Argument missing after"
msgstr "Thiếu tham số sau"
-#: ../main.c:150
-#, fuzzy
-msgid "Garbage after option argument"
+msgid "Garbage after option"
msgstr "Rác sau tùy chọn"
-#: ../main.c:152
msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
msgstr ""
"Quá nhiều tham số \"+câu lệnh\", \"-c câu lệnh\" hoặc \"--cmd câu lệnh\""
-#: ../main.c:154
msgid "Invalid argument for"
msgstr "Tham số không được phép cho"
-#: ../main.c:294
-#, c-format
-msgid "%d files to edit\n"
-msgstr "%d tập tin để soạn thảo\n"
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Vim không được biên dịch với tính năng hỗ trợ xem khác biệt (diff)."
-#: ../main.c:1342
msgid "Attempt to open script file again: \""
msgstr "Thử mở tập tin script một lần nữa: \""
-#: ../main.c:1350
msgid "Cannot open for reading: \""
msgstr "Không mở để đọc được: \""
-#: ../main.c:1393
msgid "Cannot open for script output: \""
msgstr "Không mở cho đầu ra script được: \""
-#: ../main.c:1622
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d tập tin để soạn thảo\n"
+
msgid "Vim: Warning: Output is not to a terminal\n"
msgstr "Vim: Cảnh báo: Đầu ra không hướng tới một terminal\n"
-#: ../main.c:1624
msgid "Vim: Warning: Input is not from a terminal\n"
msgstr "Vim: Cảnh báo: Đầu vào không phải đến từ một terminal\n"
-#. just in case..
-#: ../main.c:1891
msgid "pre-vimrc command line"
msgstr "dòng lệnh chạy trước khi thực hiện vimrc"
-#: ../main.c:1964
#, c-format
msgid "E282: Cannot read from \"%s\""
msgstr "E282: Không đọc được từ \"%s\""
-#: ../main.c:2149
msgid ""
"\n"
"More info with: \"vim -h\"\n"
@@ -3274,23 +2258,18 @@ msgstr ""
"\n"
"Xem thông tin chi tiết với: \"vim -h\"\n"
-#: ../main.c:2178
msgid "[file ..] edit specified file(s)"
msgstr "[tập tin ..] soạn thảo (các) tập tin chỉ ra"
-#: ../main.c:2179
msgid "- read text from stdin"
msgstr "- đọc văn bản từ đầu vào stdin"
-#: ../main.c:2180
msgid "-t tag edit file where tag is defined"
msgstr "-t thẻ ghi soạn thảo tập tin từ chỗ thẻ ghi chỉ ra"
-#: ../main.c:2181
msgid "-q [errorfile] edit file with first error"
msgstr "-q [tập tin lỗi] soạn thảo tập tin với lỗi đầu tiên"
-#: ../main.c:2187
msgid ""
"\n"
"\n"
@@ -3300,11 +2279,9 @@ msgstr ""
"\n"
"Sử dụng:"
-#: ../main.c:2189
msgid " vim [arguments] "
msgstr " vim [các tham số] "
-#: ../main.c:2193
msgid ""
"\n"
" or:"
@@ -3312,7 +2289,6 @@ msgstr ""
"\n"
" hoặc:"
-#: ../main.c:2196
msgid ""
"\n"
"\n"
@@ -3322,187 +2298,322 @@ msgstr ""
"\n"
"Tham số:\n"
-#: ../main.c:2197
msgid "--\t\t\tOnly file names after this"
msgstr "--\t\t\tSau tham số chỉ đưa ra tên tập tin"
-#: ../main.c:2199
msgid "--literal\t\tDon't expand wildcards"
msgstr "--literal\t\tKhông thực hiện việc mở rộng wildcard"
-#: ../main.c:2201
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tĐăng ký gvim này cho OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tBỏ đăng ký gvim này cho OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tSử dụng giao diện đồ họa GUI (giống \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f hoặc --nofork\tTrong chương trình hoạt động: Không thực hiện fork khi "
+"chạy GUI"
+
msgid "-v\t\t\tVi mode (like \"vi\")"
msgstr "-v\t\t\tChế độ Vi (giống \"vi\")"
-#: ../main.c:2202
msgid "-e\t\t\tEx mode (like \"ex\")"
msgstr "-e\t\t\tChế độ Ex (giống \"ex\")"
-#: ../main.c:2203
-msgid "-E\t\t\tImproved Ex mode"
-msgstr ""
-
-#: ../main.c:2204
msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
msgstr "-s\t\t\tChế độ ít đưa thông báo (gói) (chỉ dành cho \"ex\")"
-#: ../main.c:2205
msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
msgstr "-d\t\t\tChế độ khác biệt, diff (giống \"vimdiff\")"
-#: ../main.c:2206
msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
msgstr "-y\t\t\tChế độ đơn giản (giống \"evim\", không có chế độ)"
-#: ../main.c:2207
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tChế độ chỉ đọc (giống \"view\")"
-#: ../main.c:2209
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tChế độ hạn chế (giống \"rvim\")"
+
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tKhông có khả năng ghi nhớ thay đổi (ghi nhớ tập tin)"
-#: ../main.c:2210
msgid "-M\t\t\tModifications in text not allowed"
msgstr "-M\t\t\tKhông có khả năng thay đổi văn bản"
-#: ../main.c:2211
msgid "-b\t\t\tBinary mode"
msgstr "-b\t\t\tChế độ nhị phân (binary)"
-#: ../main.c:2212
msgid "-l\t\t\tLisp mode"
msgstr "-l\t\t\tChế độ Lisp"
-#: ../main.c:2213
msgid "-C\t\t\tCompatible with Vi: 'compatible'"
msgstr "-C\t\t\tChế độ tương thích với Vi: 'compatible'"
-#: ../main.c:2214
msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
msgstr "-N\t\t\tChế độ không tương thích hoàn toàn với Vi: 'nocompatible'"
-#: ../main.c:2215
-msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
-msgstr ""
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tMức độ chi tiết của thông báo"
-#: ../main.c:2216
msgid "-D\t\t\tDebugging mode"
msgstr "-D\t\t\tChế độ sửa lỗi (debug)"
-#: ../main.c:2217
msgid "-n\t\t\tNo swap file, use memory only"
msgstr "-n\t\t\tKhông sử dụng tập tin swap, chỉ sử dụng bộ nhớ"
-#: ../main.c:2218
msgid "-r\t\t\tList swap files and exit"
msgstr "-r\t\t\tLiệt kê các tập tin swap rồi thoát"
-#: ../main.c:2219
msgid "-r (with file name)\tRecover crashed session"
msgstr "-r (với tên tập tin)\tPhục hồi lần soạn thảo gặp sự cố"
-#: ../main.c:2220
msgid "-L\t\t\tSame as -r"
msgstr "-L\t\t\tGiống với -r"
-#: ../main.c:2221
-msgid "-A\t\t\tstart in Arabic mode"
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tKhông sử dụng newcli để mở cửa sổ"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <thiết bị>\t\tSử dụng <thiết bị> cho I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
msgstr "-A\t\t\tKhởi động vào chế độ Ả Rập"
-#: ../main.c:2222
msgid "-H\t\t\tStart in Hebrew mode"
msgstr "-H\t\t\tKhởi động vào chế độ Do thái"
-#: ../main.c:2223
msgid "-F\t\t\tStart in Farsi mode"
msgstr "-F\t\t\tKhởi động vào chế độ Farsi"
-#: ../main.c:2224
msgid "-T <terminal>\tSet terminal type to <terminal>"
msgstr "-T <terminal>\tĐặt loại terminal thành <terminal>"
-#: ../main.c:2225
msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
msgstr "-u <vimrc>\t\tSử dụng <vimrc> thay thế cho mọi .vimrc"
-#: ../main.c:2226
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tSử dụng <gvimrc> thay thế cho mọi .gvimrc"
+
msgid "--noplugin\t\tDon't load plugin scripts"
msgstr "--noplugin\t\tKhông nạp bất kỳ script môđun nào"
-#: ../main.c:2227
-#, fuzzy
-msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
-msgstr "-o[N]\t\tMở N cửa sổ (theo mặc định: mỗi cửa sổ cho một tập tin)"
-
-#: ../main.c:2228
msgid "-o[N]\t\tOpen N windows (default: one for each file)"
msgstr "-o[N]\t\tMở N cửa sổ (theo mặc định: mỗi cửa sổ cho một tập tin)"
-#: ../main.c:2229
msgid "-O[N]\t\tLike -o but split vertically"
msgstr "-O[N]\t\tGiống với -o nhưng phân chia theo đường thẳng đứng"
-#: ../main.c:2230
msgid "+\t\t\tStart at end of file"
msgstr "+\t\t\tBắt đầu soạn thảo từ cuối tập tin"
-#: ../main.c:2231
msgid "+<lnum>\t\tStart at line <lnum>"
msgstr "+<lnum>\t\tBắt đầu soạn thảo từ dòng thứ <lnum> (số thứ tự của dòng)"
-#: ../main.c:2232
msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
msgstr "--cmd <câu lệnh>\tThực hiện <câu lệnh> trước khi nạp tập tin vimrc"
-#: ../main.c:2233
msgid "-c <command>\t\tExecute <command> after loading the first file"
msgstr "-c <câu lệnh>\t\tThực hiện <câu lệnh> sau khi nạp tập tin đầu tiên"
-#: ../main.c:2235
msgid "-S <session>\t\tSource file <session> after loading the first file"
msgstr "-S <session>\t\tThực hiện <session> sau khi nạp tập tin đầu tiên"
-#: ../main.c:2236
msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
msgstr ""
"-s <scriptin>\tĐọc các lệnh của chế độ Thông thường từ tập tin <scriptin>"
-#: ../main.c:2237
msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
msgstr "-w <scriptout>\tThêm tất cả các lệnh đã gõ vào tập tin <scriptout>"
-#: ../main.c:2238
msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
msgstr "-W <scriptout>\tGhi nhớ tất cả các lệnh đã gõ vào tập tin <scriptout>"
-#: ../main.c:2240
-msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tSoạn thảo tập tin đã mã hóa"
+
+msgid "-display <display>\tConnect Vim to this particular X-server"
+msgstr "-display <màn hình>\tKết nối Vim tới máy chủ X đã chỉ ra"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tKhông thực hiện việc kết nối tới máy chủ X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <tập tin>\tSoạn thảo <tập tin> trên máy chủ Vim nếu có thể"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có máy chủ"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <tập tin> Cũng như --remote, nhưng chờ sự kết thúc"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có máy "
+"chủ"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <phím>\tGửi <phím> lên máy chủ Vim và thoát"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
msgstr ""
+"--remote-expr <biểu thức>\tTính <biểu thức> trên máy chủ Vim và in ra kết quả"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tHiển thị danh sách máy chủ Vim và thoát"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <tên>\tGửi lên (hoặc trở thành) máy chủ Vim với <tên>"
-#: ../main.c:2242
msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
msgstr "-i <viminfo>\t\tSử dụng tập tin <viminfo> thay cho .viminfo"
-#: ../main.c:2243
msgid "-h or --help\tPrint Help (this message) and exit"
msgstr "-h hoặc --help\tHiển thị Trợ giúp (thông tin này) và thoát"
-#: ../main.c:2244
msgid "--version\t\tPrint version information and exit"
msgstr "--version\t\tĐưa ra thông tin về phiên bản Vim và thoát"
-#: ../mark.c:676
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản Athena):\n"
+
+msgid "-display <display>\tRun Vim on <display>"
+msgstr "-display <màn hình>\tChạy Vim trong <màn hình> đã chỉ ra"
+
+msgid "-iconic\t\tStart Vim iconified"
+msgstr "-iconic\t\tChạy Vim ở dạng thu nhỏ"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <tên>\t\tSử dụng tài nguyên giống như khi vim có <tên>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Chưa được thực thi)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <màu>\tSử dụng <màu> chỉ ra cho nền (cũng như: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <màu>\tSử dụng <màu> cho văn bản thông thường (cũng như: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr ""
+"-font <phông>\t\tSử dụng <phông> chữ cho văn bản thông thường (cũng như: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <phông>\tSử dụng <phông> chữ cho văn bản in đậm"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <phông>\tSử dụng <phông> chữ cho văn bản in nghiêng"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <kích thước>\tSử dụng <kích thước> ban đầu (cũng như: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <rộng>\tSử dụng đường viền có chiều <rộng> (cũng như: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <rộng> Sử dụng thanh cuộn với chiều <rộng> (cũng như: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <cao>\tSử dụng thanh trình đơn với chiều <cao> (cũng như: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tSử dụng chế độ video đảo ngược (cũng như: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tKhông sử dụng chế độ video đảo ngược (cũng như: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <tài nguyên>\tĐặt <tài nguyên> chỉ ra"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản RISC OS):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <số>\tChiều rộng ban đầu của cửa sổ tính theo số cột"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <số>\tChiều cao ban đầu của cửa sổ tính theo số dòng"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản GTK+):\n"
+
+msgid "-display <display>\tRun Vim on <display> (also: --display)"
+msgstr ""
+"-display <màn hình>\tChạy Vim trên <màn hình> chỉ ra (cũng như: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <vai trò>\tĐặt <vai trò> duy nhất để nhận diện cửa sổ chính"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tMở Vim bên trong thành phần GTK khác"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <tiêu đề của mẹ>\tMở Vim bên trong ứng dụng mẹ"
+
+msgid "No display"
+msgstr "Không có màn hình"
+
+msgid ": Send failed.\n"
+msgstr ": Gửi không thành công.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Gửi không thành công. Thử thực hiện nội bộ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "đã soạn thảo %d từ %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Không có màn hình: gửi biểu thức không thành công.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Gửi biểu thức không thành công.\n"
+
msgid "No marks set"
msgstr "Không có dấu hiệu nào được đặt."
-#: ../mark.c:678
#, c-format
msgid "E283: No marks matching \"%s\""
msgstr "E283: Không có dấu hiệu tương ứng với \"%s\""
-#. Highlight title
-#: ../mark.c:687
msgid ""
"\n"
"mark line col file/text"
@@ -3510,8 +2621,6 @@ msgstr ""
"\n"
"nhãn dòng cột tập tin/văn bản"
-#. Highlight title
-#: ../mark.c:789
msgid ""
"\n"
" jump line col file/text"
@@ -3519,8 +2628,6 @@ msgstr ""
"\n"
" bước_nhảy dòng cột tập tin/văn bản"
-#. Highlight title
-#: ../mark.c:831
msgid ""
"\n"
"change line col text"
@@ -3528,7 +2635,6 @@ msgstr ""
"\n"
"thay_đổi dòng cột văn_bản"
-#: ../mark.c:1238
msgid ""
"\n"
"# File marks:\n"
@@ -3536,8 +2642,6 @@ msgstr ""
"\n"
"# Nhãn của tập tin:\n"
-#. Write the jumplist with -'
-#: ../mark.c:1271
msgid ""
"\n"
"# Jumplist (newest first):\n"
@@ -3545,7 +2649,6 @@ msgstr ""
"\n"
"# Danh sách bước nhảy (mới hơn đứng trước):\n"
-#: ../mark.c:1352
msgid ""
"\n"
"# History of marks within files (newest to oldest):\n"
@@ -3553,88 +2656,94 @@ msgstr ""
"\n"
"# Lịch sử các nhãn trong tập tin (từ mới nhất đến cũ nhất):\n"
-#: ../mark.c:1431
msgid "Missing '>'"
msgstr "Thiếu '>'"
-#: ../memfile.c:426
-msgid "E293: block was not locked"
+msgid "E543: Not a valid codepage"
+msgstr "E543: Bảng mã không cho phép"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Không đặt được giá trị nội dung nhập vào (IC)"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Không tạo được nội dung nhập vào"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Việc thử mở phương pháp nhập không thành công"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Cảnh báo: không đặt được sự gọi ngược hủy diệt thành phương pháp nhập"
+
+# TODO: Capitalise first word of message?
+msgid "E288: Input method doesn't support any style"
+msgstr "E288: phương pháp nhập không hỗ trợ bất kỳ phong cách (style) nào"
+
+# TODO: Capitalise first word of message?
+msgid "E289: Input method doesn't support my preedit type"
+msgstr "E289: phương pháp nhập không hỗ trợ loại soạn thảo trước của Vim"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: GTK+ cũ hơn 1.2.3. Vùng chỉ trạng thái không làm việc"
+
+# TODO: Capitalise first word of message?
+msgid "E293: Block was not locked"
msgstr "E293: khối chưa bị khóa"
-#: ../memfile.c:799
msgid "E294: Seek error in swap file read"
msgstr "E294: Lỗi tìm kiếm khi đọc tập tin trao đổi (swap)"
-#: ../memfile.c:803
msgid "E295: Read error in swap file"
msgstr "E295: Lỗi đọc tập tin trao đổi (swap)"
-#: ../memfile.c:849
msgid "E296: Seek error in swap file write"
msgstr "E296: Lỗi tìm kiếm khi ghi nhớ tập tin trao đổi (swap)"
-#: ../memfile.c:865
msgid "E297: Write error in swap file"
msgstr "E297: Lỗi ghi nhớ tập tin trao đổi (swap)"
-#: ../memfile.c:1036
msgid "E300: Swap file already exists (symlink attack?)"
msgstr ""
"E300: Tập tin trao đổi (swap) đã tồn tại (sử dụng liên kết mềm tấn công?)"
-#: ../memline.c:318
msgid "E298: Didn't get block nr 0?"
msgstr "E298: Chưa lấy khối số 0?"
-#: ../memline.c:361
msgid "E298: Didn't get block nr 1?"
msgstr "E298: Chưa lấy khối số 12?"
-#: ../memline.c:377
msgid "E298: Didn't get block nr 2?"
msgstr "E298: Chưa lấy khối số 2?"
-#. could not (re)open the swap file, what can we do????
-#: ../memline.c:465
msgid "E301: Oops, lost the swap file!!!"
msgstr "E301: Ối, mất tập tin trao đổi (swap)!!!"
-#: ../memline.c:477
msgid "E302: Could not rename swap file"
msgstr "E302: Không đổi được tên tập tin trao đổi (swap)"
-#: ../memline.c:554
#, c-format
msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
msgstr ""
"E303: Không mở được tập tin trao đổi (swap) cho \"%s\", nên không thể phục "
"hồi"
-#: ../memline.c:666
-#, fuzzy
-msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgid "E304: ml_timestamp: Didn't get block 0??"
msgstr "E304: ml_timestamp: Chưa lấy khối số 0??"
-#. no swap files found
-#: ../memline.c:830
#, c-format
msgid "E305: No swap file found for %s"
msgstr "E305: Không tìm thấy tập tin trao đổi (swap) cho %s"
-#: ../memline.c:839
msgid "Enter number of swap file to use (0 to quit): "
msgstr "Hãy nhập số của tập tin trao đổi (swap) muốn sử dụng (0 để thoát): "
-#: ../memline.c:879
#, c-format
msgid "E306: Cannot open %s"
msgstr "E306: Không mở được %s"
-#: ../memline.c:897
msgid "Unable to read block 0 from "
msgstr "Không thể đọc khối số 0 từ "
-#: ../memline.c:900
msgid ""
"\n"
"Maybe no changes were made or Vim did not update the swap file."
@@ -3642,28 +2751,22 @@ msgstr ""
"\n"
"Chưa có thay đổi nào hoặc Vim không thể cập nhật tập tin trao đổi (swap)"
-#: ../memline.c:909
msgid " cannot be used with this version of Vim.\n"
msgstr " không thể sử dụng trong phiên bản Vim này.\n"
-#: ../memline.c:911
msgid "Use Vim version 3.0.\n"
msgstr "Hãy sử dụng Vim phiên bản 3.0.\n"
-#: ../memline.c:916
#, c-format
msgid "E307: %s does not look like a Vim swap file"
msgstr "E307: %s không phải là tập tin trao đổi (swap) của Vim"
-#: ../memline.c:922
msgid " cannot be used on this computer.\n"
msgstr " không thể sử dụng trên máy tính này.\n"
-#: ../memline.c:924
msgid "The file was created on "
msgstr "Tập tin đã được tạo trên "
-#: ../memline.c:928
msgid ""
",\n"
"or the file has been damaged."
@@ -3671,85 +2774,63 @@ msgstr ""
",\n"
"hoặc tập tin đã bị hỏng."
-#: ../memline.c:945
-msgid " has been damaged (page size is smaller than minimum value).\n"
-msgstr ""
-
-#: ../memline.c:974
#, c-format
msgid "Using swap file \"%s\""
msgstr "Đang sử dụng tập tin trao đổi (swap) \"%s\""
-#: ../memline.c:980
#, c-format
msgid "Original file \"%s\""
msgstr "Tập tin gốc \"%s\""
-#: ../memline.c:995
msgid "E308: Warning: Original file may have been changed"
msgstr "E308: Cảnh báo: Tập tin gốc có thể đã bị thay đổi"
-#: ../memline.c:1061
#, c-format
msgid "E309: Unable to read block 1 from %s"
msgstr "E309: Không đọc được khối số 1 từ %s"
-#: ../memline.c:1065
msgid "???MANY LINES MISSING"
msgstr "???THIẾU NHIỀU DÒNG"
-#: ../memline.c:1076
msgid "???LINE COUNT WRONG"
msgstr "???GIÁ TRỊ CỦA SỐ ĐẾM DÒNG BỊ SAI"
-#: ../memline.c:1082
msgid "???EMPTY BLOCK"
msgstr "???KHỐI RỖNG"
-#: ../memline.c:1103
msgid "???LINES MISSING"
msgstr "???THIẾU DÒNG"
-#: ../memline.c:1128
#, c-format
msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
msgstr "E310: Khối 1 ID sai (%s không phải là tập tin .swp?)"
-#: ../memline.c:1133
msgid "???BLOCK MISSING"
msgstr "???THIẾU KHỐI"
-#: ../memline.c:1147
msgid "??? from here until ???END lines may be messed up"
msgstr "??? từ đây tới ???CUỐI, các dòng có thể đã bị hỏng"
-#: ../memline.c:1164
msgid "??? from here until ???END lines may have been inserted/deleted"
msgstr "??? từ đây tới ???CUỐI, các dòng có thể đã bị chèn hoặc xóa"
-#: ../memline.c:1181
msgid "???END"
msgstr "???CUỐI"
-#: ../memline.c:1238
msgid "E311: Recovery Interrupted"
msgstr "E311: Việc phục hồi bị gián đoạn"
-#: ../memline.c:1243
msgid ""
"E312: Errors detected while recovering; look for lines starting with ???"
msgstr ""
"E312: Phát hiện ra lỗi trong khi phục hồi; hãy xem những dòng bắt đầu với ???"
-#: ../memline.c:1245
msgid "See \":help E312\" for more information."
msgstr "Hãy xem thông tin bổ sung trong trợ giúp \":help E312\""
-#: ../memline.c:1249
msgid "Recovery completed. You should check if everything is OK."
msgstr "Việc phục hồi đã hoàn thành. Nên kiểm tra xem mọi thứ có ổn không."
-#: ../memline.c:1251
msgid ""
"\n"
"(You might want to write out this file under another name\n"
@@ -3757,71 +2838,49 @@ msgstr ""
"\n"
"(Có thể ghi nhớ tập tin với tên khác và so sánh với tập\n"
-#: ../memline.c:1252
-#, fuzzy
-msgid "and run diff with the original file to check for changes)"
+msgid "and run diff with the original file to check for changes)\n"
msgstr "gốc bằng chương trình diff).\n"
-#: ../memline.c:1254
-msgid "Recovery completed. Buffer contents equals file contents."
-msgstr ""
-
-#: ../memline.c:1255
-#, fuzzy
msgid ""
-"\n"
-"You may want to delete the .swp file now.\n"
+"Delete the .swp file afterwards.\n"
"\n"
msgstr ""
"Sau đó hãy xóa tập tin .swp.\n"
"\n"
-#. use msg() to start the scrolling properly
-#: ../memline.c:1327
msgid "Swap files found:"
msgstr "Tìm thấy tập tin trao đổi (swap):"
-#: ../memline.c:1446
msgid " In current directory:\n"
msgstr " Trong thư mục hiện thời:\n"
-#: ../memline.c:1448
msgid " Using specified name:\n"
msgstr " Với tên chỉ ra:\n"
-#: ../memline.c:1450
msgid " In directory "
msgstr " Trong thư mục "
-#: ../memline.c:1465
msgid " -- none --\n"
msgstr " -- không --\n"
-#: ../memline.c:1527
msgid " owned by: "
msgstr " người sở hữu: "
-#: ../memline.c:1529
msgid " dated: "
msgstr " ngày: "
-#: ../memline.c:1532 ../memline.c:3231
msgid " dated: "
msgstr " ngày: "
-#: ../memline.c:1548
msgid " [from Vim version 3.0]"
msgstr " [từ Vim phiên bản 3.0]"
-#: ../memline.c:1550
msgid " [does not look like a Vim swap file]"
msgstr " [không phải là tập tin trao đổi (swap) của Vim]"
-#: ../memline.c:1552
msgid " file name: "
msgstr " tên tập tin: "
-#: ../memline.c:1558
msgid ""
"\n"
" modified: "
@@ -3829,15 +2888,12 @@ msgstr ""
"\n"
" thay đổi: "
-#: ../memline.c:1559
msgid "YES"
msgstr "CÓ"
-#: ../memline.c:1559
msgid "no"
msgstr "không"
-#: ../memline.c:1562
msgid ""
"\n"
" user name: "
@@ -3845,11 +2901,9 @@ msgstr ""
"\n"
" tên người dùng: "
-#: ../memline.c:1568
msgid " host name: "
msgstr " tên máy: "
-#: ../memline.c:1570
msgid ""
"\n"
" host name: "
@@ -3857,7 +2911,6 @@ msgstr ""
"\n"
" tên máy: "
-#: ../memline.c:1575
msgid ""
"\n"
" process ID: "
@@ -3865,11 +2918,16 @@ msgstr ""
"\n"
" ID tiến trình: "
-#: ../memline.c:1579
msgid " (still running)"
msgstr " (vẫn đang chạy)"
-#: ../memline.c:1586
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [không sử dụng được với phiên bản này của Vim]"
+
msgid ""
"\n"
" [not usable on this computer]"
@@ -3877,97 +2935,75 @@ msgstr ""
"\n"
" [không sử dụng được trên máy tính này]"
-#: ../memline.c:1590
msgid " [cannot be read]"
msgstr " [không đọc được]"
-#: ../memline.c:1593
msgid " [cannot be opened]"
msgstr " [không mở được]"
-#: ../memline.c:1698
msgid "E313: Cannot preserve, there is no swap file"
msgstr "E313: Không cập nhật được tập tin trao đổi (swap) vì không tìm thấy nó"
-#: ../memline.c:1747
msgid "File preserved"
msgstr "Đã cập nhật tập tin trao đổi (swap)"
-#: ../memline.c:1749
msgid "E314: Preserve failed"
msgstr "E314: Cập nhật không thành công"
-#: ../memline.c:1819
-#, c-format
-msgid "E315: ml_get: invalid lnum: %<PRId64>"
-msgstr "E315: ml_get: giá trị lnum không đúng: %<PRId64>"
+# TODO: Capitalise first word of message?
+msgid "E315: ml_get: Invalid lnum: %ld"
+msgstr "E315: ml_get: giá trị lnum không đúng: %ld"
-#: ../memline.c:1851
-#, c-format
-msgid "E316: ml_get: cannot find line %<PRId64>"
-msgstr "E316: ml_get: không tìm được dòng %<PRId64>"
+# TODO: Capitalise first word of message?
+msgid "E316: ml_get: Cannot find line %ld"
+msgstr "E316: ml_get: không tìm được dòng %ld"
-#: ../memline.c:2236
-msgid "E317: pointer block id wrong 3"
+# TODO: Capitalise first word of message?
+msgid "E317: Pointer block id wrong 3"
msgstr "E317: Giá trị của pointer khối số 3 không đúng"
-#: ../memline.c:2311
msgid "stack_idx should be 0"
msgstr "giá trị stack_idx phải bằng 0"
-#: ../memline.c:2369
msgid "E318: Updated too many blocks?"
msgstr "E318: Đã cập nhật quá nhiều khối?"
-#: ../memline.c:2511
-msgid "E317: pointer block id wrong 4"
+# TODO: Capitalise first word of message?
+msgid "E317: Pointer block id wrong 4"
msgstr "E317: Giá trị của pointer khối số 4 không đúng"
-#: ../memline.c:2536
msgid "deleted block 1?"
msgstr "đã xóa khối số 1?"
-#: ../memline.c:2707
#, c-format
-msgid "E320: Cannot find line %<PRId64>"
-msgstr "E320: Không tìm được dòng %<PRId64>"
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Không tìm được dòng %ld"
-#: ../memline.c:2916
-msgid "E317: pointer block id wrong"
+# TODO: Capitalise first word of message?
+msgid "E317: Pointer block id wrong"
msgstr "E317: giá trị của pointer khối không đúng"
-#: ../memline.c:2930
msgid "pe_line_count is zero"
msgstr "giá trị pe_line_count bằng không"
-#: ../memline.c:2955
-#, c-format
-msgid "E322: line number out of range: %<PRId64> past the end"
-msgstr "E322: số thứ tự dòng vượt quá giới hạn : %<PRId64>"
+# TODO: Capitalise first word of message?
+msgid "E322: Line number out of range: %ld past the end"
+msgstr "E322: số thứ tự dòng vượt quá giới hạn : %ld"
-#: ../memline.c:2959
-#, c-format
-msgid "E323: line count wrong in block %<PRId64>"
-msgstr "E323: giá trị đếm dòng không đúng trong khối %<PRId64>"
+# TODO: Capitalise first word of message?
+msgid "E323: Line count wrong in block %ld"
+msgstr "E323: giá trị đếm dòng không đúng trong khối %ld"
-#: ../memline.c:2999
msgid "Stack size increases"
msgstr "Kích thước của đống tăng lên"
-#: ../memline.c:3038
-msgid "E317: pointer block id wrong 2"
+# TODO: Capitalise first word of message?
+msgid "E317: Pointer block id wrong 2"
msgstr "E317: Giá trị của cái chỉ (pointer) khối số 2 không đúng"
-#: ../memline.c:3070
-#, c-format
-msgid "E773: Symlink loop for \"%s\""
-msgstr ""
-
-#: ../memline.c:3221
msgid "E325: ATTENTION"
msgstr "E325: CHÚ Ý"
-#: ../memline.c:3222
msgid ""
"\n"
"Found a swap file by the name \""
@@ -3975,45 +3011,37 @@ msgstr ""
"\n"
"Tìm thấy một tập tin trao đổi (swap) với tên \""
-#: ../memline.c:3226
msgid "While opening file \""
msgstr "Khi mở tập tin: \""
-#: ../memline.c:3239
msgid " NEWER than swap file!\n"
msgstr " MỚI hơn so với tập tin trao đổi (swap)\n"
-#: ../memline.c:3244
-#, fuzzy
msgid ""
"\n"
-"(1) Another program may be editing the same file. If this is the case,\n"
-" be careful not to end up with two different instances of the same\n"
-" file when making changes."
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
msgstr ""
"\n"
"(1) Rất có thể một chương trình khác đang soạn thảo tập tin.\n"
" Nếu như vậy, hãy cẩn thận khi thay đổi, làm sao để không thu\n"
" được hai phương án khác nhau của cùng một tập tin.\n"
-#: ../memline.c:3245
-#, fuzzy
-msgid " Quit, or continue with caution.\n"
+msgid " Quit, or continue with caution.\n"
msgstr " Thoát hoặc tiếp tục với sự cẩn thận.\n"
-#: ../memline.c:3246
-#, fuzzy
-msgid "(2) An edit session for this file crashed.\n"
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
msgstr ""
"\n"
"(2) Lần soạn thảo trước của tập tin này gặp sự cố.\n"
-#: ../memline.c:3247
-msgid " If this is the case, use \":recover\" or \"nvim -r "
+msgid " If this is the case, use \":recover\" or \"vim -r "
msgstr ""
-" Trong trường hợp này, hãy sử dụng câu lệnh \":recover\" hoặc \"nvim -r "
+" Trong trường hợp này, hãy sử dụng câu lệnh \":recover\" hoặc \"vim -r "
-#: ../memline.c:3249
msgid ""
"\"\n"
" to recover the changes (see \":help recovery\").\n"
@@ -4021,12 +3049,10 @@ msgstr ""
"\"\n"
" để phục hồi những thay đổi (hãy xem \":help recovery\").\n"
-#: ../memline.c:3250
msgid " If you did this already, delete the swap file \""
msgstr ""
" Nếu đã thực hiện thao tác này rồi, thì hãy xóa tập tin trao đổi (swap) \""
-#: ../memline.c:3252
msgid ""
"\"\n"
" to avoid this message.\n"
@@ -4034,23 +3060,18 @@ msgstr ""
"\"\n"
" để tránh sự xuất hiện của thông báo này trong tương lai.\n"
-#: ../memline.c:3450 ../memline.c:3452
msgid "Swap file \""
msgstr "Tập tin trao đổi (swap) \""
-#: ../memline.c:3451 ../memline.c:3455
msgid "\" already exists!"
msgstr "\" đã có rồi!"
-#: ../memline.c:3457
msgid "VIM - ATTENTION"
msgstr "VIM - CHÚ Ý"
-#: ../memline.c:3459
msgid "Swap file already exists!"
msgstr "Tập tin trao đổi (swap) đã rồi!"
-#: ../memline.c:3464
msgid ""
"&Open Read-Only\n"
"&Edit anyway\n"
@@ -4064,75 +3085,44 @@ msgstr ""
"&Q Thoát\n"
"&A Gián đoạn"
-#: ../memline.c:3467
-#, fuzzy
msgid ""
"&Open Read-Only\n"
"&Edit anyway\n"
"&Recover\n"
-"&Delete it\n"
"&Quit\n"
-"&Abort"
+"&Abort\n"
+"&Delete it"
msgstr ""
"&O Mở chỉ để đọc\n"
"&E Vẫn soạn thảo\n"
"&R Phục hồi\n"
"&Q Thoát\n"
-"&A Gián đoạn"
+"&A Gián đoạn&D Xóa nó"
-#.
-#. * Change the ".swp" extension to find another file that can be used.
-#. * First decrement the last char: ".swo", ".swn", etc.
-#. * If that still isn't enough decrement the last but one char: ".svz"
-#. * Can happen when editing many "No Name" buffers.
-#.
-#. ".s?a"
-#. ".saa": tried enough, give up
-#: ../memline.c:3528
msgid "E326: Too many swap files found"
msgstr "E326: Tìm thấy quá nhiều tập tin trao đổi (swap)"
-#: ../memory.c:227
-#, c-format
-msgid "E342: Out of memory! (allocating %<PRIu64> bytes)"
-msgstr "E342: Không đủ bộ nhớ! (phân chia %<PRIu64> byte)"
-
-#: ../menu.c:62
msgid "E327: Part of menu-item path is not sub-menu"
msgstr ""
"E327: Một phần của đường dẫn tới phần tử của trình đơn không phải là trình "
"đơn con"
-#: ../menu.c:63
msgid "E328: Menu only exists in another mode"
msgstr "E328: Trình đơn chỉ có trong chế độ khác"
-#: ../menu.c:64
-#, fuzzy, c-format
-msgid "E329: No menu \"%s\""
+msgid "E329: No menu of that name"
msgstr "E329: Không có trình đơn với tên như vậy"
-#. Only a mnemonic or accelerator is not valid.
-#: ../menu.c:329
-msgid "E792: Empty menu name"
-msgstr ""
-
-#: ../menu.c:340
msgid "E330: Menu path must not lead to a sub-menu"
msgstr "E330: Đường dẫn tới trình đơn không được đưa tới trình đơn con"
-#: ../menu.c:365
msgid "E331: Must not add menu items directly to menu bar"
msgstr ""
"E331: Các phần tử của trình đơn không thể thêm trực tiếp vào thanh trình đơn"
-#: ../menu.c:370
msgid "E332: Separator cannot be part of a menu path"
msgstr "E332: Cái phân chia không thể là một phần của đường dẫn tới trình đơn"
-#. Now we have found the matching menu, and we list the mappings
-#. Highlight title
-#: ../menu.c:762
msgid ""
"\n"
"--- Menus ---"
@@ -4140,70 +3130,62 @@ msgstr ""
"\n"
"--- Trình đơn ---"
-#: ../menu.c:1313
+msgid "Tear off this menu"
+msgstr "Chia cắt trình đơn này"
+
msgid "E333: Menu path must lead to a menu item"
msgstr "E333: Đường dẫn tới trình đơn phải đưa tới một phần tử cuả trình đơn"
-#: ../menu.c:1330
#, c-format
msgid "E334: Menu not found: %s"
msgstr "E334: Không tìm thấy trình đơn: %s"
-#: ../menu.c:1396
#, c-format
msgid "E335: Menu not defined for %s mode"
msgstr "E335: Trình đơn không được định nghĩa cho chế độ %s"
-#: ../menu.c:1426
msgid "E336: Menu path must lead to a sub-menu"
msgstr "E336: Đường dẫn tới trình đơn phải đưa tới một trình đơn con"
-#: ../menu.c:1447
msgid "E337: Menu not found - check menu names"
msgstr "E337: Không tìm thấy trình đơn - hãy kiểm tra tên trình đơn"
-#: ../message.c:423
#, c-format
msgid "Error detected while processing %s:"
msgstr "Phát hiện lỗi khi xử lý %s:"
-#: ../message.c:445
#, c-format
msgid "line %4ld:"
msgstr "dòng %4ld:"
-#: ../message.c:617
-#, c-format
-msgid "E354: Invalid register name: '%s'"
-msgstr "E354: Tên sổ đăng ký không cho phép: '%s'"
+msgid "[string too long]"
+msgstr "[chuỗi quá dài]"
+
+msgid "Messages maintainer: The Vim Project"
+msgstr ""
+"Bản dịch các thông báo sang tiếng Việt: Phan Vĩnh Thịnh <teppi@vnlinux.org>"
-#: ../message.c:986
msgid "Interrupt: "
msgstr "Gián đoạn: "
-#: ../message.c:988
-#, fuzzy
-msgid "Press ENTER or type command to continue"
-msgstr "Nhấn phím ENTER hoặc nhập câu lệnh để tiếp tục"
+msgid "Hit ENTER to continue"
+msgstr "Nhấn phím ENTER để tiếp tục"
-#: ../message.c:1843
-#, fuzzy, c-format
-msgid "%s line %<PRId64>"
-msgstr "%s, dòng %<PRId64>"
+msgid "Hit ENTER or type command to continue"
+msgstr "Nhấn phím ENTER hoặc nhập câu lệnh để tiếp tục"
-#: ../message.c:2392
msgid "-- More --"
msgstr "-- Còn nữa --"
-#: ../message.c:2398
-msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
-msgstr ""
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: dòng, SPACE/b: trang, d/u: nửa trang, q: thoát)"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: dòng, SPACE: trang, d: nửa trang, q: thoát)"
-#: ../message.c:3021 ../message.c:3031
msgid "Question"
msgstr "Câu hỏi"
-#: ../message.c:3023
msgid ""
"&Yes\n"
"&No"
@@ -4211,17 +3193,6 @@ msgstr ""
"&Có\n"
"&Không"
-#: ../message.c:3033
-msgid ""
-"&Yes\n"
-"&No\n"
-"&Cancel"
-msgstr ""
-"&Có\n"
-"&Không\n"
-"&Dừng"
-
-#: ../message.c:3045
msgid ""
"&Yes\n"
"&No\n"
@@ -4234,181 +3205,233 @@ msgstr ""
"&Vứt bỏ tất cả\n"
"&Dừng lại"
-#: ../message.c:3058
-#, fuzzy
-msgid "E766: Insufficient arguments for printf()"
-msgstr "E116: Tham số cho hàm %s đưa ra không đúng"
+msgid "Save File dialog"
+msgstr "Ghi nhớ tập tin"
-#: ../message.c:3119
-msgid "E807: Expected Float argument for printf()"
-msgstr ""
+msgid "Open File dialog"
+msgstr "Mở tập tin"
-#: ../message.c:3873
-#, fuzzy
-msgid "E767: Too many arguments to printf()"
-msgstr "E118: Quá nhiều tham số cho hàm: %s"
+msgid "E338: Sorry, no file browser in console mode"
+msgstr ""
+"E338: Xin lỗi nhưng không có trình duyệt tập tin trong chế độ kênh giao tác "
+"(console)"
-#: ../misc1.c:2256
msgid "W10: Warning: Changing a readonly file"
msgstr "W10: Cảnh báo: Thay đổi một tập tin chỉ có quyền đọc"
-#: ../misc1.c:2537
-msgid "Type number and <Enter> or click with mouse (empty cancels): "
-msgstr ""
-
-#: ../misc1.c:2539
-msgid "Type number and <Enter> (empty cancels): "
-msgstr ""
-
-#: ../misc1.c:2585
msgid "1 more line"
msgstr "Thêm 1 dòng"
-#: ../misc1.c:2588
msgid "1 line less"
msgstr "Bớt 1 dòng"
-#: ../misc1.c:2593
#, c-format
-msgid "%<PRId64> more lines"
-msgstr "Thêm %<PRId64> dòng"
+msgid "%ld more lines"
+msgstr "Thêm %ld dòng"
-#: ../misc1.c:2596
#, c-format
-msgid "%<PRId64> fewer lines"
-msgstr "Bớt %<PRId64> dòng"
+msgid "%ld fewer lines"
+msgstr "Bớt %ld dòng"
-#: ../misc1.c:2599
msgid " (Interrupted)"
msgstr " (Bị gián đoạn)"
-#: ../misc1.c:2635
-msgid "Beep!"
+msgid "Vim: preserving files...\n"
+msgstr "Vim: ghi nhớ các tập tin...\n"
+
+msgid "Vim: Finished.\n"
+msgstr "Vim: Đã xong.\n"
+
+msgid "ERROR: "
+msgstr "LỖI: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
msgstr ""
+"\n"
+"[byte] tổng phân phối-còn trống %lu-%lu, sử dụng %lu, píc sử dụng %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[gọi] tổng re/malloc() %lu, tổng free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Dòng đang trở thành quá dài"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Lỗi nội bộ: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Không đủ bộ nhớ! (phân chia %lu byte)"
-#: ../misc2.c:738
#, c-format
msgid "Calling shell to execute: \"%s\""
msgstr "Gọi shell để thực hiện: \"%s\""
-#: ../normal.c:183
-msgid "E349: No identifier under cursor"
-msgstr "E349: Không có tên ở vị trí con trỏ"
+msgid "E545: Missing colon"
+msgstr "E545: Thiếu dấu hai chấm"
-#: ../normal.c:1866
-#, fuzzy
-msgid "E774: 'operatorfunc' is empty"
-msgstr "E91: Tùy chọn 'shell' là một chuỗi rỗng"
+msgid "E546: Illegal mode"
+msgstr "E546: Chế độ không cho phép"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Dạng trỏ chuột không cho phép"
+
+# TODO: Capitalise first word of message?
+msgid "E548: Digit expected"
+msgstr "E548: yêu cầu một số"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Tỷ lệ phần trăm không cho phép"
+
+msgid "Enter encryption key: "
+msgstr "Nhập mật khẩu để mã hóa: "
+
+msgid "Enter same key again: "
+msgstr " Nhập lại mật khẩu:"
+
+msgid "Keys don't match!"
+msgstr "Hai mật khẩu không trùng nhau!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Đường dẫn đưa ra không đúng: '**[số]' phải ở cuối đường dẫn hoặc theo "
+"sau bởi '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Không tìm thấy thư mục \"%s\" để chuyển thư mục"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Không tìm thấy tập tin \"%s\" trong đường dẫn"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Trong đường dẫn thay đổi thư mục không còn có thư mục \"%s\" nữa"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Trong đường dẫn path không còn có tập tin \"%s\" nữa"
+
+msgid "E550: Missing colon"
+msgstr "E550: Thiếu dấu hai chấm"
+
+msgid "E551: Illegal component"
+msgstr "E551: Thành phần không cho phép"
+
+# TODO: Capitalise first word of message?
+msgid "E552: Digit expected"
+msgstr "E552: Cần chỉ ra một số"
+
+msgid "Cannot connect to Netbeans #2"
+msgstr "Không kết nối được với Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Không kết nối được với NetBeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Chế độ truy cập thông tin về liên kết với NetBeans không đúng: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "đọc từ socket NetBeans"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Bị mất liên kết với NetBeans cho bộ đệm %ld"
-#: ../normal.c:2637
msgid "Warning: terminal cannot highlight"
msgstr "Cảnh báo: terminal không thực hiện được sự chiếu sáng"
-#: ../normal.c:2807
msgid "E348: No string under cursor"
msgstr "E348: Không có chuỗi ở vị trí con trỏ"
-#: ../normal.c:3937
+msgid "E349: No identifier under cursor"
+msgstr "E349: Không có tên ở vị trí con trỏ"
+
msgid "E352: Cannot erase folds with current 'foldmethod'"
msgstr ""
"E352: Không thể tẩy xóa nếp gấp với giá trị hiện thời của tùy chọn "
"'foldmethod'"
-#: ../normal.c:5897
-msgid "E664: changelist is empty"
+# TODO: Capitalise first word of message?
+msgid "E664: Changelist is empty"
msgstr "E664: danh sách những thay đổi trống rỗng"
-#: ../normal.c:5899
msgid "E662: At start of changelist"
msgstr "E662: Ở đầu danh sách những thay đổi"
-#: ../normal.c:5901
msgid "E663: At end of changelist"
msgstr "E663: Ở cuối danh sách những thay đổi"
-#: ../normal.c:7053
-msgid "Type :quit<Enter> to exit Nvim"
+msgid "Type :quit<Enter> to exit Vim"
msgstr "Gõ :quit<Enter> để thoát khỏi Vim"
-#: ../ops.c:248
#, c-format
msgid "1 line %sed 1 time"
msgstr "Trên 1 dòng %s 1 lần"
-#: ../ops.c:250
#, c-format
msgid "1 line %sed %d times"
msgstr "Trên 1 dòng %s %d lần"
-#: ../ops.c:253
#, c-format
-msgid "%<PRId64> lines %sed 1 time"
-msgstr "Trên %<PRId64> dòng %s 1 lần"
+msgid "%ld lines %sed 1 time"
+msgstr "Trên %ld dòng %s 1 lần"
-#: ../ops.c:256
#, c-format
-msgid "%<PRId64> lines %sed %d times"
-msgstr "Trên %<PRId64> dòng %s %d lần"
+msgid "%ld lines %sed %d times"
+msgstr "Trên %ld dòng %s %d lần"
-#: ../ops.c:592
#, c-format
-msgid "%<PRId64> lines to indent... "
-msgstr "Thụt đầu %<PRId64> dòng..."
+msgid "%ld lines to indent... "
+msgstr "Thụt đầu %ld dòng..."
-#: ../ops.c:634
msgid "1 line indented "
msgstr "Đã thụt đầu 1 dòng"
-#: ../ops.c:636
#, c-format
-msgid "%<PRId64> lines indented "
-msgstr "%<PRId64> dòng đã thụt đầu"
-
-#: ../ops.c:938
-#, fuzzy
-msgid "E748: No previously used register"
-msgstr "E186: Không có thư mục trước"
+msgid "%ld lines indented "
+msgstr "%ld dòng đã thụt đầu"
-#. must display the prompt
-#: ../ops.c:1433
msgid "cannot yank; delete anyway"
msgstr "sao chép không thành công; đã xóa"
-#: ../ops.c:1929
msgid "1 line changed"
msgstr "1 dòng đã thay đổi"
-#: ../ops.c:1931
#, c-format
-msgid "%<PRId64> lines changed"
-msgstr "%<PRId64> đã thay đổi"
+msgid "%ld lines changed"
+msgstr "%ld đã thay đổi"
-#: ../ops.c:2521
-#, fuzzy
-msgid "block of 1 line yanked"
-msgstr "đã sao chép 1 dòng"
+#, c-format
+msgid "freeing %ld lines"
+msgstr "đã làm sạch %ld dòng"
-#: ../ops.c:2523
msgid "1 line yanked"
msgstr "đã sao chép 1 dòng"
-#: ../ops.c:2525
-#, fuzzy, c-format
-msgid "block of %<PRId64> lines yanked"
-msgstr "đã sao chép %<PRId64> dòng"
-
-#: ../ops.c:2528
#, c-format
-msgid "%<PRId64> lines yanked"
-msgstr "đã sao chép %<PRId64> dòng"
+msgid "%ld lines yanked"
+msgstr "đã sao chép %ld dòng"
-#: ../ops.c:2710
#, c-format
msgid "E353: Nothing in register %s"
msgstr "E353: Trong sổ đăng ký %s không có gì hết"
-#. Highlight title
-#: ../ops.c:3185
msgid ""
"\n"
"--- Registers ---"
@@ -4416,11 +3439,9 @@ msgstr ""
"\n"
"--- Sổ đăng ký ---"
-#: ../ops.c:4455
msgid "Illegal register name"
msgstr "Tên sổ đăng ký không cho phép"
-#: ../ops.c:4533
msgid ""
"\n"
"# Registers:\n"
@@ -4428,194 +3449,154 @@ msgstr ""
"\n"
"# Sổ đăng ký:\n"
-#: ../ops.c:4575
#, c-format
msgid "E574: Unknown register type %d"
msgstr "E574: Loại sổ đăng ký không biết %d"
-#: ../ops.c:5089
#, c-format
-msgid "%<PRId64> Cols; "
-msgstr "%<PRId64> Cột; "
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Tên sổ đăng ký không cho phép: '%s'"
-#: ../ops.c:5097
#, c-format
-msgid ""
-"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
-"%<PRId64> of %<PRId64> Bytes"
-msgstr ""
-"Chọn %s%<PRId64> của %<PRId64> Dòng; %<PRId64> của %<PRId64> Từ; %<PRId64> "
-"của %<PRId64> Byte"
-
-#: ../ops.c:5105
-#, fuzzy, c-format
-msgid ""
-"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
-"%<PRId64> of %<PRId64> Chars; %<PRId64> of %<PRId64> Bytes"
-msgstr ""
-"Chọn %s%<PRId64> của %<PRId64> Dòng; %<PRId64> của %<PRId64> Từ; %<PRId64> "
-"của %<PRId64> Byte"
+msgid "%ld Cols; "
+msgstr "%ld Cột; "
-#: ../ops.c:5123
#, c-format
-msgid ""
-"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Byte "
-"%<PRId64> of %<PRId64>"
-msgstr ""
-"Cột %s của %s; Dòng %<PRId64> của %<PRId64>; Từ %<PRId64> của %<PRId64>; "
-"Byte %<PRId64> của %<PRId64>"
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Chọn %s%ld của %ld Dòng; %ld của %ld Từ; %ld của %ld Byte"
-#: ../ops.c:5133
-#, fuzzy, c-format
-msgid ""
-"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Char "
-"%<PRId64> of %<PRId64>; Byte %<PRId64> of %<PRId64>"
-msgstr ""
-"Cột %s của %s; Dòng %<PRId64> của %<PRId64>; Từ %<PRId64> của %<PRId64>; "
-"Byte %<PRId64> của %<PRId64>"
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Cột %s của %s; Dòng %ld của %ld; Từ %ld của %ld; Byte %ld của %ld"
-#: ../ops.c:5146
#, c-format
-msgid "(+%<PRId64> for BOM)"
-msgstr "(+%<PRId64> cho BOM)"
+msgid "(+%ld for BOM)"
+msgstr "(+%ld cho BOM)"
-#: ../option.c:1238
msgid "%<%f%h%m%=Page %N"
msgstr "%<%f%h%m%=Trang %N"
-#: ../option.c:1574
msgid "Thanks for flying Vim"
msgstr "Xin cảm ơn đã sử dụng Vim"
-#. found a mismatch: skip
-#: ../option.c:2698
msgid "E518: Unknown option"
msgstr "E518: Tùy chọn không biết"
-#: ../option.c:2709
msgid "E519: Option not supported"
msgstr "E519: Tùy chọn không được hỗ trợ"
-#: ../option.c:2740
msgid "E520: Not allowed in a modeline"
msgstr "E520: Không cho phép trên dòng chế độ (modeline)"
-#: ../option.c:2815
-msgid "E846: Key code not set"
+msgid ""
+"\n"
+"\tLast set from "
msgstr ""
+"\n"
+"\tLần cuối cùng tùy chọn thay đổi vào "
-#: ../option.c:2924
msgid "E521: Number required after ="
msgstr "E521: Sau dấu = cần đưa ra một số"
-#: ../option.c:3226 ../option.c:3864
msgid "E522: Not found in termcap"
msgstr "E522: Không tìm thấy trong termcap"
-#: ../option.c:3335
#, c-format
msgid "E539: Illegal character <%s>"
msgstr "E539: Ký tự không cho phép <%s>"
-#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: Giá trị của tùy chọn 'term' không thể là một chuỗi trống rỗng"
-#: ../option.c:3885
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Không thể thay đổi terminal trong giao diện đồ họa GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Hãy sử dụng \":gui\" để chạy giao diện đồ họa GUI"
+
msgid "E589: 'backupext' and 'patchmode' are equal"
msgstr "E589: giá trị của tùy chọn 'backupext' và 'patchmode' bằng nhau"
-#: ../option.c:3964
-msgid "E834: Conflicts with value of 'listchars'"
-msgstr ""
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Không thể thay đổi trong giao diện đồ họa GTK+ 2"
-#: ../option.c:3966
-msgid "E835: Conflicts with value of 'fillchars'"
-msgstr ""
-
-#: ../option.c:4163
msgid "E524: Missing colon"
msgstr "E524: Thiếu dấu hai chấm"
-#: ../option.c:4165
msgid "E525: Zero length string"
msgstr "E525: Chuỗi có độ dài bằng không"
-#: ../option.c:4220
#, c-format
msgid "E526: Missing number after <%s>"
msgstr "E526: Thiếu một số sau <%s>"
-#: ../option.c:4232
msgid "E527: Missing comma"
msgstr "E527: Thiếu dấu phẩy"
-#: ../option.c:4239
msgid "E528: Must specify a ' value"
msgstr "E528: Cần đưa ra một giá trị cho '"
-#: ../option.c:4271
msgid "E595: contains unprintable or wide character"
msgstr "E595: chứa ký tự không in ra hoặc ký tự với chiều rộng gấp đôi"
-#: ../option.c:4469
+msgid "E596: Invalid font(s)"
+msgstr "E596: Phông chữ không đúng"
+
+# TODO: Capitalise first word of message?
+msgid "E597: Can't select fontset"
+msgstr "E597: không chọn được bộ phông chữ"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Bộ phông chữ không đúng"
+
+# TODO: Capitalise first word of message?
+msgid "E533: Can't select wide font"
+msgstr "E533: không chọn được phông chữ với các ký tự có chiều rộng gấp đôi"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Phông chữ, với ký tự có chiều rộng gấp đôi, không đúng"
+
#, c-format
msgid "E535: Illegal character after <%c>"
msgstr "E535: Ký tự sau <%c> không chính xác"
-#: ../option.c:4534
-msgid "E536: comma required"
+# TODO: Capitalise first word of message?
+msgid "E536: Comma required"
msgstr "E536: cầu có dấu phẩy"
-#: ../option.c:4543
#, c-format
msgid "E537: 'commentstring' must be empty or contain %s"
msgstr "E537: Giá trị của tùy chọn 'commentstring' phải rỗng hoặc chứa %s"
-#: ../option.c:4928
+msgid "E538: No mouse support"
+msgstr "E538: Chuột không được hỗ trợ"
+
msgid "E540: Unclosed expression sequence"
msgstr "E540: Dãy các biểu thức không đóng"
-#: ../option.c:4932
-msgid "E541: too many items"
-msgstr "E541: quá nhiều phần tử"
-#: ../option.c:4934
-msgid "E542: unbalanced groups"
+# TODO: Capitalise first word of message?
+msgid "E542: Unbalanced groups"
msgstr "E542: các nhóm không cân bằng"
-#: ../option.c:5148
msgid "E590: A preview window already exists"
msgstr "E590: Cửa sổ xem trước đã có"
-#: ../option.c:5311
msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
msgstr "W17: Tiếng Ả Rập yêu cầu sử dụng UTF-8, hãy nhập ':set encoding=utf-8'"
-#: ../option.c:5623
#, c-format
msgid "E593: Need at least %d lines"
msgstr "E593: Cần ít nhất %d dòng"
-#: ../option.c:5631
#, c-format
msgid "E594: Need at least %d columns"
msgstr "E594: Cần ít nhất %d cột"
-#: ../option.c:6011
#, c-format
msgid "E355: Unknown option: %s"
msgstr "E355: Tùy chọn không biết: %s"
-#. There's another character after zeros or the string
-#. * is empty. In both cases, we are trying to set a
-#. * num option using a string.
-#: ../option.c:6037
-#, fuzzy, c-format
-msgid "E521: Number required: &%s = '%s'"
-msgstr "E521: Sau dấu = cần đưa ra một số"
-
-#: ../option.c:6149
msgid ""
"\n"
"--- Terminal codes ---"
@@ -4623,7 +3604,6 @@ msgstr ""
"\n"
"--- Mã terminal ---"
-#: ../option.c:6151
msgid ""
"\n"
"--- Global option values ---"
@@ -4631,7 +3611,6 @@ msgstr ""
"\n"
"--- Giá trị tùy chọn toàn cầu ---"
-#: ../option.c:6153
msgid ""
"\n"
"--- Local option values ---"
@@ -4639,7 +3618,6 @@ msgstr ""
"\n"
"--- Giá trị tùy chọn nội bộ ---"
-#: ../option.c:6155
msgid ""
"\n"
"--- Options ---"
@@ -4647,21 +3625,127 @@ msgstr ""
"\n"
"--- Tùy chọn ---"
-#: ../option.c:6816
msgid "E356: get_varp ERROR"
msgstr "E356: LỖI get_varp"
-#: ../option.c:7696
#, c-format
msgid "E357: 'langmap': Matching character missing for %s"
msgstr "E357: 'langmap': Thiếu ký tự tương ứng cho %s"
-#: ../option.c:7715
#, c-format
msgid "E358: 'langmap': Extra characters after semicolon: %s"
msgstr "E358: 'langmap': Thừa ký tự sau dấu chấm phẩy: %s"
-#: ../os/shell.c:194
+msgid "cannot open "
+msgstr "không mở được "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Không mở được cửa sổ!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Cần Amigados phiên bản 2.04 hoặc mới hơn\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Cần %s phiên bản %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Không mở được NIL:\n"
+
+msgid "Cannot create "
+msgstr "Không tạo được "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Thoát Vim với mã %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "không thay đổi được chế độ kênh giao tác (console)?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: không phải là kênh giao tác (console)??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Không chạy được shell với tùy chọn -f"
+
+msgid "Cannot execute "
+msgstr "Không chạy được "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " thoát\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "Giá trị ANCHOR_BUF_SIZE quá nhỏ."
+
+msgid "I/O ERROR"
+msgstr "LỖI I/O (NHẬP/XUẤT)"
+
+msgid "...(truncated)"
+msgstr "...(bị cắt bớt)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "Tùy chọn 'columns' khác 80, chương trình ngoại trú không thể thực hiện"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Chọn máy in không thành công"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "tới %s trên %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Không rõ phông chữ của máy in: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Lỗi in: %s"
+
+msgid "Unknown"
+msgstr "Không rõ"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Đang in '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Tên bảng mã không cho phép \"%s\" trong tên phông chữ \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ký tự không cho phép '%c' trong tên phông chữ \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Tín hiệu đôi, thoát\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Nhận được tín hiệu chết %s\n"
+
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Nhận được tín hiệu chết\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Mở màn hình X mất %ld mili giây"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Lỗi X\n"
+
+msgid "Testing the X display failed"
+msgstr "Kiểm tra màn hình X không thành công"
+
+msgid "Opening the X display timed out"
+msgstr "Không mở được màn hình X trong thời gian cho phép (time out)"
+
msgid ""
"\n"
"Cannot execute shell "
@@ -4669,7 +3753,13 @@ msgstr ""
"\n"
"Không chạy được shell "
-#: ../os/shell.c:439
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Không chạy được shell sh\n"
+
msgid ""
"\n"
"shell returned "
@@ -4677,959 +3767,387 @@ msgstr ""
"\n"
"shell dừng làm việc "
-#: ../os_unix.c:465 ../os_unix.c:471
msgid ""
"\n"
-"Could not get security context for "
+"Cannot create pipes\n"
msgstr ""
+"\n"
+"Không tạo được đường ống (pipe)\n"
-#: ../os_unix.c:479
msgid ""
"\n"
-"Could not set security context for "
+"Cannot fork\n"
msgstr ""
+"\n"
+"Không thực hiện được fork()\n"
-#: ../os_unix.c:1558 ../os_unix.c:1647
-#, c-format
-msgid "dlerror = \"%s\""
+msgid ""
+"\n"
+"Command terminated\n"
msgstr ""
+"\n"
+"Câu lệnh bị gián đoạn\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mất kết nối ICE"
+
+msgid "Opening the X display failed"
+msgstr "Mở màn hình X không thành công"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP xử lý yêu cầu tự động ghi nhớ"
+
+msgid "XSMP opening connection"
+msgstr "XSMP mở kết nối"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP mất theo dõi kết nối ICE"
-#: ../path.c:1449
#, c-format
-msgid "E447: Can't find file \"%s\" in path"
-msgstr "E447: Không tìm thấy tập tin \"%s\" trong đường dẫn"
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP thực hiện SmcOpenConnection không thành công: %s"
+
+msgid "At line"
+msgstr "Tại dòng"
+
+msgid "Could not allocate memory for command line."
+msgstr "Không phân chia được bộ nhớ cho dòng lệnh."
+
+msgid "VIM Error"
+msgstr "Lỗi VIM"
+
+msgid "Could not load vim32.dll!"
+msgstr "Không nạp được vim32.dll!"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Không sửa được cái chỉ (pointer) hàm số tới DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "thoát shell với mã %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Nhận được sự kiện %s\n"
+
+msgid "close"
+msgstr "đóng"
+
+msgid "logoff"
+msgstr "thoát"
+
+msgid "shutdown"
+msgstr "tắt máy"
+
+msgid "E371: Command not found"
+msgstr "E371: Câu lệnh không tìm thấy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"Không tìm thấy VIMRUN.EXE trong $PATH.\n"
+"Lệnh ngoại trú sẽ không dừng lại sau khi hoàn thành.\n"
+"Thông tin chi tiết xem trong :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Cảnh báo Vim"
-#: ../quickfix.c:359
#, c-format
msgid "E372: Too many %%%c in format string"
msgstr "E372: Quá nhiều %%%c trong chuỗi định dạng"
-#: ../quickfix.c:371
#, c-format
msgid "E373: Unexpected %%%c in format string"
msgstr "E373: Không mong đợi %%%c trong chuỗi định dạng"
-#: ../quickfix.c:420
msgid "E374: Missing ] in format string"
msgstr "E374: Thiếu ] trong chuỗi định dạng"
-#: ../quickfix.c:431
#, c-format
msgid "E375: Unsupported %%%c in format string"
msgstr "E375: %%%c không được hỗ trợ trong chuỗi định dạng"
-#: ../quickfix.c:448
#, c-format
msgid "E376: Invalid %%%c in format string prefix"
msgstr "E376: Không cho phép %%%c trong tiền tố của chuỗi định dạng"
-#: ../quickfix.c:454
#, c-format
msgid "E377: Invalid %%%c in format string"
msgstr "E377: Không cho phép %%%c trong chuỗi định dạng"
-#. nothing found
-#: ../quickfix.c:477
msgid "E378: 'errorformat' contains no pattern"
msgstr "E378: Trong giá trị 'errorformat' thiếu mẫu (pattern)"
-#: ../quickfix.c:695
msgid "E379: Missing or empty directory name"
msgstr "E379: Tên thư mục không được đưa ra hoặc bằng một chuỗi rỗng"
-#: ../quickfix.c:1305
msgid "E553: No more items"
msgstr "E553: Không còn phần tử nào nữa"
-#: ../quickfix.c:1674
#, c-format
msgid "(%d of %d)%s%s: "
msgstr "(%d của %d)%s%s: "
-#: ../quickfix.c:1676
msgid " (line deleted)"
msgstr " (dòng bị xóa)"
-#: ../quickfix.c:1863
msgid "E380: At bottom of quickfix stack"
msgstr "E380: Ở dưới của đống sửa nhanh"
-#: ../quickfix.c:1869
msgid "E381: At top of quickfix stack"
msgstr "E381: Ở đầu của đống sửa nhanh"
-#: ../quickfix.c:1880
#, c-format
msgid "error list %d of %d; %d errors"
msgstr "danh sách lỗi %d của %d; %d lỗi"
-#: ../quickfix.c:2427
msgid "E382: Cannot write, 'buftype' option is set"
msgstr "E382: Không ghi nhớ được, giá trị 'buftype' không phải là chuỗi rỗng"
-#: ../quickfix.c:2812
-msgid "E683: File name missing or invalid pattern"
-msgstr ""
-
-#: ../quickfix.c:2911
-#, fuzzy, c-format
-msgid "Cannot open file \"%s\""
-msgstr "E624: Không thể mở tập tin \"%s\""
+# TODO: Capitalise first word of message?
+msgid "E369: Invalid item in %s%%[]"
+msgstr "E369: phần tử không cho phép trong %s%%[]"
-#: ../quickfix.c:3429
-#, fuzzy
-msgid "E681: Buffer is not loaded"
-msgstr "1 bộ đệm được bỏ nạp từ bộ nhớ"
+msgid "E339: Pattern too long"
+msgstr "E339: Mẫu (pattern) quá dài"
-#: ../quickfix.c:3487
-#, fuzzy
-msgid "E777: String or List expected"
-msgstr "E548: yêu cầu một số"
+msgid "E50: Too many \\z("
+msgstr "E50: Quá nhiều \\z("
-#: ../regexp.c:359
#, c-format
-msgid "E369: invalid item in %s%%[]"
-msgstr "E369: phần tử không cho phép trong %s%%[]"
+msgid "E51: Too many %s("
+msgstr "E51: Quá nhiều %s("
-#: ../regexp.c:374
-#, fuzzy, c-format
-msgid "E769: Missing ] after %s["
-msgstr "E69: Thiếu ] sau %s%%["
+msgid "E52: Unmatched \\z("
+msgstr "E52: Không có cặp cho \\z("
-#: ../regexp.c:375
#, c-format
msgid "E53: Unmatched %s%%("
msgstr "E53: Không có cặp cho %s%%("
-#: ../regexp.c:376
#, c-format
msgid "E54: Unmatched %s("
msgstr "E54: Không có cặp cho %s("
-#: ../regexp.c:377
#, c-format
msgid "E55: Unmatched %s)"
msgstr "E55: Không có cặp cho %s)"
-#: ../regexp.c:378
-msgid "E66: \\z( not allowed here"
-msgstr "E66: \\z( không thể sử dụng ở đây"
-
-#: ../regexp.c:379
-msgid "E67: \\z1 et al. not allowed here"
-msgstr "E67: \\z1 và tương tự không được sử dụng ở đây"
-
-#: ../regexp.c:380
-#, c-format
-msgid "E69: Missing ] after %s%%["
-msgstr "E69: Thiếu ] sau %s%%["
-
-#: ../regexp.c:381
#, c-format
-msgid "E70: Empty %s%%[]"
-msgstr "E70: %s%%[] rỗng"
-
-#: ../regexp.c:1209 ../regexp.c:1224
-msgid "E339: Pattern too long"
-msgstr "E339: Mẫu (pattern) quá dài"
+msgid "E56: %s* operand could be empty"
+msgstr "E56: operand %s* không thể rỗng"
-#: ../regexp.c:1371
-msgid "E50: Too many \\z("
-msgstr "E50: Quá nhiều \\z("
-
-#: ../regexp.c:1378
#, c-format
-msgid "E51: Too many %s("
-msgstr "E51: Quá nhiều %s("
+msgid "E57: %s+ operand could be empty"
+msgstr "E57: operand %s+ không thể rỗng"
-#: ../regexp.c:1427
-msgid "E52: Unmatched \\z("
-msgstr "E52: Không có cặp cho \\z("
+# TODO: Capitalise first word of message?
+msgid "E59: Invalid character after %s@"
+msgstr "E59: ký tự không cho phép sau %s@"
-#: ../regexp.c:1637
#, c-format
-msgid "E59: invalid character after %s@"
-msgstr "E59: ký tự không cho phép sau %s@"
+msgid "E58: %s{ operand could be empty"
+msgstr "E58: operand %s{ không thể rỗng"
-#: ../regexp.c:1672
#, c-format
msgid "E60: Too many complex %s{...}s"
msgstr "E60: Quá nhiều cấu trúc phức tạp %s{...}"
-#: ../regexp.c:1687
#, c-format
msgid "E61: Nested %s*"
msgstr "E61: %s* lồng vào"
-#: ../regexp.c:1690
#, c-format
msgid "E62: Nested %s%c"
msgstr "E62: %s%c lồng vào"
-#: ../regexp.c:1800
-msgid "E63: invalid use of \\_"
+# TODO: Capitalise first word of message?
+msgid "E63: Invalid use of \\_"
msgstr "E63: không cho phép sử dụng \\_"
-#: ../regexp.c:1850
#, c-format
msgid "E64: %s%c follows nothing"
msgstr "E64: %s%c không theo sau gì cả"
-#: ../regexp.c:1902
msgid "E65: Illegal back reference"
msgstr "E65: Không cho phép liên kết ngược lại"
-#: ../regexp.c:1943
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( không thể sử dụng ở đây"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 và tương tự không được sử dụng ở đây"
+
msgid "E68: Invalid character after \\z"
msgstr "E68: Ký tự không cho phép sau \\z"
-#: ../regexp.c:2049 ../regexp_nfa.c:1296
-#, fuzzy, c-format
-msgid "E678: Invalid character after %s%%[dxouU]"
-msgstr "E71: Ký tự không cho phép sau %s%%"
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Thiếu ] sau %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] rỗng"
-#: ../regexp.c:2107
#, c-format
msgid "E71: Invalid character after %s%%"
msgstr "E71: Ký tự không cho phép sau %s%%"
-#: ../regexp.c:3017
#, c-format
msgid "E554: Syntax error in %s{...}"
msgstr "E554: Lỗi cú pháp trong %s{...}"
-#: ../regexp.c:3805
-msgid "External submatches:\n"
-msgstr "Sự tương ứng con ngoài:\n"
-
-#: ../regexp.c:7022
-msgid ""
-"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
-"used "
-msgstr ""
-
-#: ../regexp_nfa.c:239
-msgid "E865: (NFA) Regexp end encountered prematurely"
-msgstr ""
-
-#: ../regexp_nfa.c:240
-#, c-format
-msgid "E866: (NFA regexp) Misplaced %c"
-msgstr ""
-
-#: ../regexp_nfa.c:242
-#, c-format
-msgid "E877: (NFA regexp) Invalid character class: %<PRId64>"
-msgstr ""
-
-#: ../regexp_nfa.c:1261
-#, c-format
-msgid "E867: (NFA) Unknown operator '\\z%c'"
-msgstr ""
-
-#: ../regexp_nfa.c:1387
-#, c-format
-msgid "E867: (NFA) Unknown operator '\\%%%c'"
-msgstr ""
-
-#: ../regexp_nfa.c:1802
-#, c-format
-msgid "E869: (NFA) Unknown operator '\\@%c'"
-msgstr ""
-
-#: ../regexp_nfa.c:1831
-msgid "E870: (NFA regexp) Error reading repetition limits"
-msgstr ""
-
-#. Can't have a multi follow a multi.
-#: ../regexp_nfa.c:1895
-msgid "E871: (NFA regexp) Can't have a multi follow a multi !"
-msgstr ""
-
-#. Too many `('
-#: ../regexp_nfa.c:2037
-msgid "E872: (NFA regexp) Too many '('"
-msgstr ""
-
-#: ../regexp_nfa.c:2042
-#, fuzzy
-msgid "E879: (NFA regexp) Too many \\z("
-msgstr "E50: Quá nhiều \\z("
-
-#: ../regexp_nfa.c:2066
-msgid "E873: (NFA regexp) proper termination error"
-msgstr ""
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: Sự cố được ngăn chặn; biểu thức chính quy quá phức tạp?"
-#: ../regexp_nfa.c:2599
-msgid "E874: (NFA) Could not pop the stack !"
-msgstr ""
-
-#: ../regexp_nfa.c:3298
-msgid ""
-"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
-"left on stack"
-msgstr ""
+# TODO: Capitalise first word of message?
+msgid "E363: Pattern caused out-of-stack error"
+msgstr "E363: sử dụng mẫu (pattern) gây ra lỗi out-of-stack"
-#: ../regexp_nfa.c:3302
-msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
-msgstr ""
-
-#: ../regexp_nfa.c:4571 ../regexp_nfa.c:4869
-msgid ""
-"Could not open temporary log file for writing, displaying on stderr ... "
-msgstr ""
+msgid "External submatches:\n"
+msgstr "Sự tương ứng con ngoài:\n"
-#: ../regexp_nfa.c:4840
#, c-format
-msgid "(NFA) COULD NOT OPEN %s !"
-msgstr ""
-
-#: ../regexp_nfa.c:6049
-#, fuzzy
-msgid "Could not open temporary log file for writing "
-msgstr "E214: Không tìm thấy tập tin tạm thời (temp) để ghi nhớ"
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld dòng được gấp"
-#: ../screen.c:7435
msgid " VREPLACE"
msgstr " THAY THẾ ẢO"
-#: ../screen.c:7437
msgid " REPLACE"
msgstr " THAY THẾ"
-#: ../screen.c:7440
msgid " REVERSE"
msgstr " NGƯỢC LẠI"
-#: ../screen.c:7441
msgid " INSERT"
msgstr " CHÈN"
-#: ../screen.c:7443
msgid " (insert)"
msgstr " (chèn)"
-#: ../screen.c:7445
msgid " (replace)"
msgstr " (thay thế)"
-#: ../screen.c:7447
msgid " (vreplace)"
msgstr " (thay thế ảo)"
-#: ../screen.c:7449
msgid " Hebrew"
msgstr " Do thái"
-#: ../screen.c:7454
msgid " Arabic"
msgstr " Ả rập"
-#: ../screen.c:7456
msgid " (lang)"
msgstr " (ngôn ngữ)"
-#: ../screen.c:7459
msgid " (paste)"
msgstr " (dán)"
-#: ../screen.c:7469
msgid " VISUAL"
msgstr " CHẾ ĐỘ VISUAL"
-#: ../screen.c:7470
msgid " VISUAL LINE"
msgstr " DÒNG VISUAL"
-#: ../screen.c:7471
msgid " VISUAL BLOCK"
msgstr " KHỐI VISUAL"
-#: ../screen.c:7472
msgid " SELECT"
msgstr " LỰA CHỌN"
-#: ../screen.c:7473
msgid " SELECT LINE"
msgstr " LỰA CHỌN DÒNG"
-#: ../screen.c:7474
msgid " SELECT BLOCK"
msgstr " LỰA CHỌN KHỐI"
-#: ../screen.c:7486 ../screen.c:7541
msgid "recording"
msgstr "đang ghi"
-#: ../search.c:487
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "tìm kiếm sẽ được tiếp tục từ CUỐI tài liệu"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "tìm kiếm sẽ được tiếp tục từ ĐẦU tài liệu"
+
#, c-format
msgid "E383: Invalid search string: %s"
msgstr "E383: Chuỗi tìm kiếm không đúng: %s"
-#: ../search.c:832
-#, c-format
-msgid "E384: search hit TOP without match for: %s"
+# TODO: Capitalise first word of message?
+msgid "E384: Search hit TOP without match for: %s"
msgstr "E384: tìm kiếm kết thúc ở ĐẦU tập tin; không tìm thấy %s"
-#: ../search.c:835
-#, c-format
-msgid "E385: search hit BOTTOM without match for: %s"
+# TODO: Capitalise first word of message?
+msgid "E385: Search hit BOTTOM without match for: %s"
msgstr "E385: tìm kiếm kết thúc ở CUỐI tập tin; không tìm thấy %s"
-#: ../search.c:1200
msgid "E386: Expected '?' or '/' after ';'"
msgstr "E386: Mong đợi nhập '?' hoặc '/' sau ';'"
-#: ../search.c:4085
msgid " (includes previously listed match)"
msgstr " (gồm cả những tương ứng đã liệt kê trước đây)"
-#. cursor at status line
-#: ../search.c:4104
msgid "--- Included files "
msgstr "--- Tập tin tính đến "
-#: ../search.c:4106
msgid "not found "
msgstr "không tìm thấy "
-#: ../search.c:4107
msgid "in path ---\n"
msgstr "trong đường dẫn ---\n"
-#: ../search.c:4168
msgid " (Already listed)"
msgstr " (Đã liệt kê)"
-#: ../search.c:4170
msgid " NOT FOUND"
msgstr " KHÔNG TÌM THẤY"
-#: ../search.c:4211
#, c-format
msgid "Scanning included file: %s"
msgstr "Quét trong tập tin được tính đến: %s"
-#: ../search.c:4216
-#, fuzzy, c-format
-msgid "Searching included file %s"
-msgstr "Quét trong tập tin được tính đến: %s"
-
-#: ../search.c:4405
msgid "E387: Match is on current line"
msgstr "E387: Tương ứng nằm trên dòng hiện tại"
-#: ../search.c:4517
msgid "All included files were found"
msgstr "Tìm thấy tất cả các tập tin được tính đến"
-#: ../search.c:4519
msgid "No included files"
msgstr "Không có tập tin được tính đến"
-#: ../search.c:4527
msgid "E388: Couldn't find definition"
msgstr "E388: Không tìm thấy định nghĩa"
-#: ../search.c:4529
msgid "E389: Couldn't find pattern"
msgstr "E389: Không tìm thấy mẫu (pattern)"
-#: ../search.c:4668
-#, fuzzy
-msgid "Substitute "
-msgstr "1 thay thế"
-
-#: ../search.c:4681
-#, c-format
-msgid ""
-"\n"
-"# Last %sSearch Pattern:\n"
-"~"
-msgstr ""
-
-#: ../spell.c:951
-#, fuzzy
-msgid "E759: Format error in spell file"
-msgstr "E297: Lỗi ghi nhớ tập tin trao đổi (swap)"
-
-#: ../spell.c:952
-msgid "E758: Truncated spell file"
-msgstr ""
-
-#: ../spell.c:953
-#, c-format
-msgid "Trailing text in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:954
-#, c-format
-msgid "Affix name too long in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:955
-#, fuzzy
-msgid "E761: Format error in affix file FOL, LOW or UPP"
-msgstr "E431: Lỗi định dạng trong tập tin thẻ ghi \"%s\""
-
-#: ../spell.c:957
-msgid "E762: Character in FOL, LOW or UPP is out of range"
-msgstr ""
-
-#: ../spell.c:958
-msgid "Compressing word tree..."
-msgstr ""
-
-#: ../spell.c:1951
-msgid "E756: Spell checking is not enabled"
-msgstr ""
-
-#: ../spell.c:2249
-#, c-format
-msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
-msgstr ""
-
-#: ../spell.c:2473
-#, fuzzy, c-format
-msgid "Reading spell file \"%s\""
-msgstr "Đang sử dụng tập tin trao đổi (swap) \"%s\""
-
-#: ../spell.c:2496
-#, fuzzy
-msgid "E757: This does not look like a spell file"
-msgstr "E307: %s không phải là tập tin trao đổi (swap) của Vim"
-
-#: ../spell.c:2501
-msgid "E771: Old spell file, needs to be updated"
-msgstr ""
-
-#: ../spell.c:2504
-msgid "E772: Spell file is for newer version of Vim"
-msgstr ""
-
-#: ../spell.c:2602
-#, fuzzy
-msgid "E770: Unsupported section in spell file"
-msgstr "E297: Lỗi ghi nhớ tập tin trao đổi (swap)"
-
-#: ../spell.c:3762
-#, fuzzy, c-format
-msgid "Warning: region %s not supported"
-msgstr "E519: Tùy chọn không được hỗ trợ"
-
-#: ../spell.c:4550
-#, fuzzy, c-format
-msgid "Reading affix file %s ..."
-msgstr "Tìm kiếm tập tin thẻ ghi %s"
-
-#: ../spell.c:4589 ../spell.c:5635 ../spell.c:6140
-#, c-format
-msgid "Conversion failure for word in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4630 ../spell.c:6170
-#, c-format
-msgid "Conversion in %s not supported: from %s to %s"
-msgstr ""
-
-#: ../spell.c:4642
-#, c-format
-msgid "Invalid value for FLAG in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4655
-#, c-format
-msgid "FLAG after using flags in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4723
-#, c-format
-msgid ""
-"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
-"%d"
-msgstr ""
-
-#: ../spell.c:4731
-#, c-format
-msgid ""
-"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
-"%d"
-msgstr ""
-
-#: ../spell.c:4747
-#, c-format
-msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4771
-#, c-format
-msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4777
-#, c-format
-msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4783
-#, c-format
-msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4795
-#, c-format
-msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4847
-#, c-format
-msgid "Different combining flag in continued affix block in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4850
-#, fuzzy, c-format
-msgid "Duplicate affix in %s line %d: %s"
-msgstr "E154: Thẻ ghi lặp lại \"%s\" trong tập tin %s"
-
-#: ../spell.c:4871
-#, c-format
-msgid ""
-"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
-"line %d: %s"
-msgstr ""
-
-#: ../spell.c:4893
-#, c-format
-msgid "Expected Y or N in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:4968
-#, c-format
-msgid "Broken condition in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:5091
-#, c-format
-msgid "Expected REP(SAL) count in %s line %d"
-msgstr ""
-
-#: ../spell.c:5120
-#, c-format
-msgid "Expected MAP count in %s line %d"
-msgstr ""
-
-#: ../spell.c:5132
-#, c-format
-msgid "Duplicate character in MAP in %s line %d"
-msgstr ""
-
-#: ../spell.c:5176
-#, c-format
-msgid "Unrecognized or duplicate item in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:5197
-#, c-format
-msgid "Missing FOL/LOW/UPP line in %s"
-msgstr ""
-
-#: ../spell.c:5220
-msgid "COMPOUNDSYLMAX used without SYLLABLE"
-msgstr ""
-
-#: ../spell.c:5236
-#, fuzzy
-msgid "Too many postponed prefixes"
-msgstr "Có quá nhiều tham số soạn thảo"
-
-#: ../spell.c:5238
-#, fuzzy
-msgid "Too many compound flags"
-msgstr "Có quá nhiều tham số soạn thảo"
-
-#: ../spell.c:5240
-msgid "Too many postponed prefixes and/or compound flags"
-msgstr ""
-
-#: ../spell.c:5250
-#, c-format
-msgid "Missing SOFO%s line in %s"
-msgstr ""
-
-#: ../spell.c:5253
-#, c-format
-msgid "Both SAL and SOFO lines in %s"
-msgstr ""
-
-#: ../spell.c:5331
-#, c-format
-msgid "Flag is not a number in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:5334
-#, c-format
-msgid "Illegal flag in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:5493 ../spell.c:5501
-#, c-format
-msgid "%s value differs from what is used in another .aff file"
-msgstr ""
-
-#: ../spell.c:5602
-#, fuzzy, c-format
-msgid "Reading dictionary file %s ..."
-msgstr "Quét từ điển: %s"
-
-#: ../spell.c:5611
-#, c-format
-msgid "E760: No word count in %s"
-msgstr ""
-
-#: ../spell.c:5669
-#, c-format
-msgid "line %6d, word %6d - %s"
-msgstr ""
-
-#: ../spell.c:5691
-#, fuzzy, c-format
-msgid "Duplicate word in %s line %d: %s"
-msgstr "Tìm thấy tương ứng trên mọi dòng: %s"
-
-#: ../spell.c:5694
-#, c-format
-msgid "First duplicate word in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:5746
-#, c-format
-msgid "%d duplicate word(s) in %s"
-msgstr ""
-
-#: ../spell.c:5748
-#, c-format
-msgid "Ignored %d word(s) with non-ASCII characters in %s"
-msgstr ""
-
-#: ../spell.c:6115
-#, fuzzy, c-format
-msgid "Reading word file %s ..."
-msgstr "Đọc từ đầu vào tiêu chuẩn stdin..."
-
-#: ../spell.c:6155
-#, c-format
-msgid "Duplicate /encoding= line ignored in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6159
-#, c-format
-msgid "/encoding= line after word ignored in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6180
-#, c-format
-msgid "Duplicate /regions= line ignored in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6185
-#, c-format
-msgid "Too many regions in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6198
-#, c-format
-msgid "/ line ignored in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6224
-#, fuzzy, c-format
-msgid "Invalid region nr in %s line %d: %s"
-msgstr "E573: Sử dụng id máy chủ không đúng: %s"
-
-#: ../spell.c:6230
-#, c-format
-msgid "Unrecognized flags in %s line %d: %s"
-msgstr ""
-
-#: ../spell.c:6257
-#, c-format
-msgid "Ignored %d words with non-ASCII characters"
-msgstr ""
-
-#: ../spell.c:6656
-#, c-format
-msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
-msgstr ""
-
-#: ../spell.c:7340
-msgid "Reading back spell file..."
-msgstr ""
-
-#. Go through the trie of good words, soundfold each word and add it to
-#. the soundfold trie.
-#: ../spell.c:7357
-msgid "Performing soundfolding..."
-msgstr ""
-
-#: ../spell.c:7368
-#, c-format
-msgid "Number of words after soundfolding: %<PRId64>"
-msgstr ""
-
-#: ../spell.c:7476
-#, c-format
-msgid "Total number of words: %d"
-msgstr ""
-
-#: ../spell.c:7655
-#, fuzzy, c-format
-msgid "Writing suggestion file %s ..."
-msgstr "Ghi tập tin viminfo \"%s\""
-
-#: ../spell.c:7707 ../spell.c:7927
-#, c-format
-msgid "Estimated runtime memory use: %d bytes"
-msgstr ""
-
-#: ../spell.c:7820
-msgid "E751: Output file name must not have region name"
-msgstr ""
-
-#: ../spell.c:7822
-#, fuzzy
-msgid "E754: Only up to 8 regions supported"
-msgstr "E519: Tùy chọn không được hỗ trợ"
-
-#: ../spell.c:7846
-#, fuzzy, c-format
-msgid "E755: Invalid region in %s"
-msgstr "E15: Biểu thức không cho phép: %s"
-
-#: ../spell.c:7907
-msgid "Warning: both compounding and NOBREAK specified"
-msgstr ""
-
-#: ../spell.c:7920
-#, fuzzy, c-format
-msgid "Writing spell file %s ..."
-msgstr "Ghi tập tin viminfo \"%s\""
-
-#: ../spell.c:7925
-msgid "Done!"
-msgstr ""
-
-#: ../spell.c:8034
-#, c-format
-msgid "E765: 'spellfile' does not have %<PRId64> entries"
-msgstr ""
-
-#: ../spell.c:8074
-#, c-format
-msgid "Word '%.*s' removed from %s"
-msgstr ""
-
-#: ../spell.c:8117
-#, c-format
-msgid "Word '%.*s' added to %s"
-msgstr ""
-
-#: ../spell.c:8381
-msgid "E763: Word characters differ between spell files"
-msgstr ""
-
-#: ../spell.c:8684
-msgid "Sorry, no suggestions"
-msgstr ""
-
-#: ../spell.c:8687
-#, fuzzy, c-format
-msgid "Sorry, only %<PRId64> suggestions"
-msgstr " trên %<PRId64> dòng"
-
-#. for when 'cmdheight' > 1
-#. avoid more prompt
-#: ../spell.c:8704
-#, fuzzy, c-format
-msgid "Change \"%.*s\" to:"
-msgstr "Ghi nhớ thay đổi vào \"%.*s\"?"
-
-#: ../spell.c:8737
-#, c-format
-msgid " < \"%.*s\""
-msgstr ""
-
-#: ../spell.c:8882
-#, fuzzy
-msgid "E752: No previous spell replacement"
-msgstr "E35: Không có biểu thức chính quy trước"
-
-#: ../spell.c:8925
-#, fuzzy, c-format
-msgid "E753: Not found: %s"
-msgstr "E334: Không tìm thấy trình đơn: %s"
-
-#: ../spell.c:9276
-#, fuzzy, c-format
-msgid "E778: This does not look like a .sug file: %s"
-msgstr "E307: %s không phải là tập tin trao đổi (swap) của Vim"
-
-#: ../spell.c:9282
-#, c-format
-msgid "E779: Old .sug file, needs to be updated: %s"
-msgstr ""
-
-#: ../spell.c:9286
-#, c-format
-msgid "E780: .sug file is for newer version of Vim: %s"
-msgstr ""
-
-#: ../spell.c:9295
-#, c-format
-msgid "E781: .sug file doesn't match .spl file: %s"
-msgstr ""
-
-#: ../spell.c:9305
-#, fuzzy, c-format
-msgid "E782: error while reading .sug file: %s"
-msgstr "E47: Lỗi khi đọc tập tin lỗi"
-
-#. This should have been checked when generating the .spl
-#. file.
-#: ../spell.c:11575
-msgid "E783: duplicate char in MAP entry"
-msgstr ""
-
-#: ../syntax.c:266
-msgid "No Syntax items defined for this buffer"
-msgstr "Không có phần tử cú pháp nào được định nghĩa cho bộ đệm này"
-
-#: ../syntax.c:3083 ../syntax.c:3104 ../syntax.c:3127
#, c-format
msgid "E390: Illegal argument: %s"
msgstr "E390: Tham số không cho phép: %s"
-#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
msgstr "E391: Không có cụm cú pháp như vậy: %s"
-#: ../syntax.c:3433
+msgid "No Syntax items defined for this buffer"
+msgstr "Không có phần tử cú pháp nào được định nghĩa cho bộ đệm này"
+
msgid "syncing on C-style comments"
msgstr "Đồng bộ hóa theo chú thích kiểu C"
-#: ../syntax.c:3439
msgid "no syncing"
msgstr "không đồng bộ hóa"
-#: ../syntax.c:3441
msgid "syncing starts "
msgstr "đồng bộ hóa bắt đầu "
-#: ../syntax.c:3443 ../syntax.c:3506
msgid " lines before top line"
msgstr " dòng trước dòng đầu tiên"
-#: ../syntax.c:3448
msgid ""
"\n"
"--- Syntax sync items ---"
@@ -5637,7 +4155,6 @@ msgstr ""
"\n"
"--- Phần tử đồng bộ hóa cú pháp ---"
-#: ../syntax.c:3452
msgid ""
"\n"
"syncing on items"
@@ -5645,7 +4162,6 @@ msgstr ""
"\n"
"đồng bộ hóa theo phần tử"
-#: ../syntax.c:3457
msgid ""
"\n"
"--- Syntax items ---"
@@ -5653,274 +4169,197 @@ msgstr ""
"\n"
"--- Phần tử cú pháp ---"
-#: ../syntax.c:3475
#, c-format
msgid "E392: No such syntax cluster: %s"
msgstr "E392: Không có cụm cú pháp như vậy: %s"
-#: ../syntax.c:3497
msgid "minimal "
msgstr "nhỏ nhất "
-#: ../syntax.c:3503
msgid "maximal "
msgstr "lớn nhất "
-#: ../syntax.c:3513
msgid "; match "
msgstr "; tương ứng "
-#: ../syntax.c:3515
msgid " line breaks"
msgstr " chuyển dòng"
-#: ../syntax.c:4076
-msgid "E395: contains argument not accepted here"
-msgstr "E395: không được sử dụng tham số contains ở đây"
-
-#: ../syntax.c:4096
-#, fuzzy
-msgid "E844: invalid cchar value"
-msgstr "E474: Tham số không cho phép"
-
-#: ../syntax.c:4107
msgid "E393: group[t]here not accepted here"
msgstr "E393: không được sử dụng group[t]here ở đây"
-#: ../syntax.c:4126
#, c-format
msgid "E394: Didn't find region item for %s"
msgstr "E394: Phần tử vùng cho %s không tìm thấy"
-#: ../syntax.c:4188
-msgid "E397: Filename required"
-msgstr "E397: Yêu cầu tên tập tin"
+# TODO: Capitalise first word of message?
+msgid "E395: Contains argument not accepted here"
+msgstr "E395: không được sử dụng tham số contains ở đây"
-#: ../syntax.c:4221
-#, fuzzy
-msgid "E847: Too many syntax includes"
-msgstr "E77: Quá nhiều tên tập tin"
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: không được sử dụng tham số containedin ở đây"
-#: ../syntax.c:4303
-#, fuzzy, c-format
-msgid "E789: Missing ']': %s"
-msgstr "E398: Thiếu '=': %s"
+msgid "E397: Filename required"
+msgstr "E397: Yêu cầu tên tập tin"
-#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
msgstr "E398: Thiếu '=': %s"
-#: ../syntax.c:4666
#, c-format
msgid "E399: Not enough arguments: syntax region %s"
msgstr "E399: Không đủ tham số: vùng cú pháp %s"
-#: ../syntax.c:4870
-#, fuzzy
-msgid "E848: Too many syntax clusters"
-msgstr "E391: Không có cụm cú pháp như vậy: %s"
-
-#: ../syntax.c:4954
msgid "E400: No cluster specified"
msgstr "E400: Chưa chỉ ra cụm"
-#. end delimiter not found
-#: ../syntax.c:4986
#, c-format
msgid "E401: Pattern delimiter not found: %s"
msgstr "E401: Không tìm thấy ký tự phân chia mẫu (pattern): %s"
-#: ../syntax.c:5049
#, c-format
msgid "E402: Garbage after pattern: %s"
msgstr "E402: Rác ở sau mẫu (pattern): %s"
-#: ../syntax.c:5120
-msgid "E403: syntax sync: line continuations pattern specified twice"
+# TODO: Capitalise first word of message?
+msgid "E403: syntax sync: Line continuations pattern specified twice"
msgstr "E403: đồng bộ hóa cú pháp: mẫu tiếp tục của dòng chỉ ra hai lần"
-#: ../syntax.c:5169
#, c-format
msgid "E404: Illegal arguments: %s"
msgstr "E404: Tham số không cho phép: %s"
-#: ../syntax.c:5217
#, c-format
msgid "E405: Missing equal sign: %s"
msgstr "E405: Thiếu dấu bằng: %s"
-#: ../syntax.c:5222
#, c-format
msgid "E406: Empty argument: %s"
msgstr "E406: Tham số trống rỗng: %s"
-#: ../syntax.c:5240
#, c-format
msgid "E407: %s not allowed here"
msgstr "E407: %s không được cho phép ở đây"
-#: ../syntax.c:5246
#, c-format
msgid "E408: %s must be first in contains list"
msgstr "E408: %s phải là đầu tiên trong danh sách contains"
-#: ../syntax.c:5304
#, c-format
msgid "E409: Unknown group name: %s"
msgstr "E409: Tên nhóm không biết: %s"
-#: ../syntax.c:5512
#, c-format
msgid "E410: Invalid :syntax subcommand: %s"
msgstr "E410: Câu lệnh con :syntax không đúng: %s"
-#: ../syntax.c:5854
-msgid ""
-" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
-msgstr ""
-
-#: ../syntax.c:6146
-msgid "E679: recursive loop loading syncolor.vim"
-msgstr ""
-
-#: ../syntax.c:6256
-#, c-format
-msgid "E411: highlight group not found: %s"
+# TODO: Capitalise first word of message?
+msgid "E411: Highlight group not found: %s"
msgstr "E411: không tìm thấy nhóm chiếu sáng cú pháp: %s"
-#: ../syntax.c:6278
#, c-format
msgid "E412: Not enough arguments: \":highlight link %s\""
msgstr "E412: Không đủ tham số: \":highlight link %s\""
-#: ../syntax.c:6284
#, c-format
msgid "E413: Too many arguments: \":highlight link %s\""
msgstr "E413: Quá nhiều tham số: \":highlight link %s\""
-#: ../syntax.c:6302
-msgid "E414: group has settings, highlight link ignored"
+# TODO: Capitalise first word of message?
+msgid "E414: Group has settings, highlight link ignored"
msgstr "E414: nhóm có thiết lập riêng, chiếu sáng liên kết bị bỏ qua"
-#: ../syntax.c:6367
-#, c-format
-msgid "E415: unexpected equal sign: %s"
+# TODO: Capitalise first word of message?
+msgid "E415: Unexpected equal sign: %s"
msgstr "E415: dấu bằng không được mong đợi: %s"
-#: ../syntax.c:6395
-#, c-format
-msgid "E416: missing equal sign: %s"
+# TODO: Capitalise first word of message?
+msgid "E416: Missing equal sign: %s"
msgstr "E416: thiếu dấu bằng: %s"
-#: ../syntax.c:6418
-#, c-format
-msgid "E417: missing argument: %s"
+# TODO: Capitalise first word of message?
+msgid "E417: Missing argument: %s"
msgstr "E417: thiếu tham số: %s"
-#: ../syntax.c:6446
#, c-format
msgid "E418: Illegal value: %s"
msgstr "E418: Giá trị không cho phép: %s"
-#: ../syntax.c:6496
msgid "E419: FG color unknown"
msgstr "E419: Không rõ màu văn bản (FG)"
-#: ../syntax.c:6504
msgid "E420: BG color unknown"
msgstr "E420: Không rõ màu nền sau (BG)"
-#: ../syntax.c:6564
#, c-format
msgid "E421: Color name or number not recognized: %s"
msgstr "E421: Tên hoặc số của màu không được nhận ra: %s"
-#: ../syntax.c:6714
-#, c-format
-msgid "E422: terminal code too long: %s"
+# TODO: Capitalise first word of message?
+msgid "E422: Terminal code too long: %s"
msgstr "E422: mã terminal quá dài: %s"
-#: ../syntax.c:6753
#, c-format
msgid "E423: Illegal argument: %s"
msgstr "E423: Tham số không cho phép: %s"
-#: ../syntax.c:6925
msgid "E424: Too many different highlighting attributes in use"
msgstr "E424: Sử dụng quá nhiều thuộc tính chiếu sáng cú pháp"
-#: ../syntax.c:7427
msgid "E669: Unprintable character in group name"
msgstr "E669: Ký tự không thể tin ra trong tên nhóm"
-#: ../highlight_group.c:1756
-msgid "E5248: Invalid character in group name"
-msgstr "E5248: Ký tự không cho phép trong tên nhóm"
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ký tự không cho phép trong tên nhóm"
-#: ../syntax.c:7448
-msgid "E849: Too many highlight and syntax groups"
-msgstr ""
-
-#: ../tag.c:104
-msgid "E555: at bottom of tag stack"
+# TODO: Capitalise first word of message?
+msgid "E555: At bottom of tag stack"
msgstr "E555: ở cuối đống thẻ ghi"
-#: ../tag.c:105
-msgid "E556: at top of tag stack"
+# TODO: Capitalise first word of message?
+msgid "E556: At top of tag stack"
msgstr "E556: ở đầu đống thẻ ghi"
-#: ../tag.c:380
msgid "E425: Cannot go before first matching tag"
msgstr "E425: Không chuyển được tới vị trí ở trước thẻ ghi tương ứng đầu tiên"
-#: ../tag.c:504
-#, c-format
-msgid "E426: tag not found: %s"
+# TODO: Capitalise first word of message?
+msgid "E426: Tag not found: %s"
msgstr "E426: không tìm thấy thẻ ghi: %s"
-#: ../tag.c:528
msgid " # pri kind tag"
msgstr " # pri loại thẻ ghi"
-#: ../tag.c:531
msgid "file\n"
msgstr "tập tin\n"
-#: ../tag.c:829
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "Hãy chọn số cần thiết (<CR> để dừng):"
+
msgid "E427: There is only one matching tag"
msgstr "E427: Chỉ có một thẻ ghi tương ứng"
-#: ../tag.c:831
msgid "E428: Cannot go beyond last matching tag"
msgstr "E428: Không chuyển được tới vị trí ở sau thẻ ghi tương ứng cuối cùng"
-#: ../tag.c:850
#, c-format
msgid "File \"%s\" does not exist"
msgstr "Tập tin \"%s\" không tồn tại"
-#. Give an indication of the number of matching tags
-#: ../tag.c:859
#, c-format
msgid "tag %d of %d%s"
msgstr "thẻ ghi %d của %d%s"
-#: ../tag.c:862
msgid " or more"
msgstr " và hơn nữa"
-#: ../tag.c:864
msgid " Using tag with different case!"
msgstr " Đang sử dụng thẻ ghi với kiểu chữ khác!"
-#: ../tag.c:909
#, c-format
msgid "E429: File \"%s\" does not exist"
msgstr "E429: Tập tin \"%s\" không tồn tại"
-#. Highlight title
-#: ../tag.c:960
msgid ""
"\n"
" # TO tag FROM line in file/text"
@@ -5928,79 +4367,58 @@ msgstr ""
"\n"
" # TỚI thẻ ghi TỪ dòng trong tập tin/văn bản"
-#: ../tag.c:1303
#, c-format
msgid "Searching tags file %s"
msgstr "Tìm kiếm tập tin thẻ ghi %s"
-#: ../tag.c:1545
-msgid "Ignoring long line in tags file"
-msgstr ""
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Đường dẫn tới tập tin thẻ ghi bị cắt bớt cho %s\n"
-#: ../tag.c:1915
#, c-format
msgid "E431: Format error in tags file \"%s\""
msgstr "E431: Lỗi định dạng trong tập tin thẻ ghi \"%s\""
-#: ../tag.c:1917
#, c-format
-msgid "Before byte %<PRId64>"
-msgstr "Trước byte %<PRId64>"
+msgid "Before byte %ld"
+msgstr "Trước byte %ld"
-#: ../tag.c:1929
#, c-format
msgid "E432: Tags file not sorted: %s"
msgstr "E432: Tập tin thẻ ghi chưa được sắp xếp: %s"
-#. never opened any tags file
-#: ../tag.c:1960
msgid "E433: No tags file"
msgstr "E433: Không có tập tin thẻ ghi"
-#: ../tag.c:2536
msgid "E434: Can't find tag pattern"
msgstr "E434: Không tìm thấy mẫu thẻ ghi"
-#: ../tag.c:2544
msgid "E435: Couldn't find tag, just guessing!"
msgstr "E435: Không tìm thấy thẻ ghi, đang thử đoán!"
-#: ../tag.c:2797
-#, c-format
-msgid "Duplicate field name: %s"
-msgstr ""
-
-#: ../term.c:1442
msgid "' not known. Available builtin terminals are:"
msgstr "' không rõ. Có các terminal gắn sẵn (builtin) sau:"
-#: ../term.c:1463
msgid "defaulting to '"
msgstr "theo mặc định '"
-#: ../term.c:1731
msgid "E557: Cannot open termcap file"
msgstr "E557: Không thể mở tập tin termcap"
-#: ../term.c:1735
msgid "E558: Terminal entry not found in terminfo"
msgstr "E558: Trong terminfo không có bản ghi nào về terminal này"
-#: ../term.c:1737
msgid "E559: Terminal entry not found in termcap"
msgstr "E559: Trong termcap không có bản ghi nào về terminal này"
-#: ../term.c:1878
#, c-format
msgid "E436: No \"%s\" entry in termcap"
msgstr "E436: Trong termcap không có bản ghi \"%s\""
-#: ../term.c:2249
-msgid "E437: terminal capability \"cm\" required"
+# TODO: Capitalise first word of message?
+msgid "E437: Terminal capability \"cm\" required"
msgstr "E437: cần khả năng của terminal \"cm\""
-#. Highlight title
-#: ../term.c:4376
msgid ""
"\n"
"--- Terminal keys ---"
@@ -6008,195 +4426,120 @@ msgstr ""
"\n"
"--- Phím terminal ---"
-#: ../ui.c:481
+msgid "new shell started\n"
+msgstr "đã chạy shell mới\n"
+
msgid "Vim: Error reading input, exiting...\n"
msgstr "Vim: Lỗi đọc dữ liệu nhập, thoát...\n"
-#. This happens when the FileChangedRO autocommand changes the
-#. * file in a way it becomes shorter.
-#: ../undo.c:379
-msgid "E881: Line count changed unexpectedly"
-msgstr ""
+msgid "No undo possible; continue anyway"
+msgstr "Không thể hủy thao tác; tiếp tục thực hiện"
-#: ../undo.c:627
-#, fuzzy, c-format
-msgid "E828: Cannot open undo file for writing: %s"
-msgstr "E212: Không thể mở tập tin để ghi nhớ"
+# TODO: Capitalise first word of message?
+msgid "E438: u_undo: Line numbers wrong"
+msgstr "E438: u_undo: số thứ tự dòng không đúng"
+
+msgid "1 change"
+msgstr "duy nhất 1 thay đổi"
-#: ../undo.c:717
#, c-format
-msgid "E825: Corrupted undo file (%s): %s"
-msgstr ""
+msgid "%ld changes"
+msgstr "%ld thay đổi"
-#: ../undo.c:1039
-msgid "Cannot write undo file in any directory in 'undodir'"
-msgstr ""
+# TODO: Capitalise first word of message?
+msgid "E439: Undo list corrupt"
+msgstr "E439: danh sách hủy thao tác (undo) bị hỏng"
-#: ../undo.c:1074
-#, c-format
-msgid "Will not overwrite with undo file, cannot read: %s"
-msgstr ""
+# TODO: Capitalise first word of message?
+msgid "E440: Undo line missing"
+msgstr "E440: bị mất dòng hủy thao tác"
-#: ../undo.c:1092
-#, c-format
-msgid "Will not overwrite, this is not an undo file: %s"
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
msgstr ""
+"\n"
+"Phiên bản với giao diện đồ họa GUI cho MS-Windows 16/32 bit"
-#: ../undo.c:1108
-msgid "Skipping undo file write, nothing to undo"
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
msgstr ""
+"\n"
+"Phiên bản với giao diện đồ họa GUI cho MS-Windows 32 bit"
-#: ../undo.c:1121
-#, fuzzy, c-format
-msgid "Writing undo file: %s"
-msgstr "Ghi tập tin viminfo \"%s\""
+msgid " in Win32s mode"
+msgstr " trong chế độ Win32"
-#: ../undo.c:1213
-#, fuzzy, c-format
-msgid "E829: write error in undo file: %s"
-msgstr "E297: Lỗi ghi nhớ tập tin trao đổi (swap)"
+msgid " with OLE support"
+msgstr " với hỗ trợ OLE"
-#: ../undo.c:1280
-#, c-format
-msgid "Not reading undo file, owner differs: %s"
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
msgstr ""
+"\n"
+"Phiên bản console cho MS-Windows 32 bit"
-#: ../undo.c:1292
-#, fuzzy, c-format
-msgid "Reading undo file: %s"
-msgstr "Đọc tập tin viminfo \"%s\"%s%s%s"
-
-#: ../undo.c:1299
-#, fuzzy, c-format
-msgid "E822: Cannot open undo file for reading: %s"
-msgstr "E195: Không thể mở tập tin viminfo để đọc"
-
-#: ../undo.c:1308
-#, fuzzy, c-format
-msgid "E823: Not an undo file: %s"
-msgstr "E484: Không mở được tập tin %s"
-
-#: ../undo.c:1313
-#, fuzzy, c-format
-msgid "E824: Incompatible undo file: %s"
-msgstr "E484: Không mở được tập tin %s"
-
-#: ../undo.c:1328
-msgid "File contents changed, cannot use undo info"
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
msgstr ""
+"\n"
+"Phiên bản cho MS-Windows 16 bit"
-#: ../undo.c:1497
-#, fuzzy, c-format
-msgid "Finished reading undo file %s"
-msgstr "thực hiện xong %s"
-
-#: ../undo.c:1586 ../undo.c:1812
-msgid "Already at oldest change"
+msgid ""
+"\n"
+"32-bit MS-DOS version"
msgstr ""
+"\n"
+"Phiên bản cho MS-DOS 32 bit"
-#: ../undo.c:1597 ../undo.c:1814
-msgid "Already at newest change"
+msgid ""
+"\n"
+"16-bit MS-DOS version"
msgstr ""
+"\n"
+"Phiên bản cho MS-DOS 16 bit"
-#: ../undo.c:1806
-#, fuzzy, c-format
-msgid "E830: Undo number %<PRId64> not found"
-msgstr "E92: Bộ đệm %<PRId64> không được tìm thấy"
-
-#: ../undo.c:1979
-msgid "E438: u_undo: line numbers wrong"
-msgstr "E438: u_undo: số thứ tự dòng không đúng"
-
-#: ../undo.c:2183
-#, fuzzy
-msgid "more line"
-msgstr "Thêm 1 dòng"
-
-#: ../undo.c:2185
-#, fuzzy
-msgid "more lines"
-msgstr "Thêm 1 dòng"
-
-#: ../undo.c:2187
-#, fuzzy
-msgid "line less"
-msgstr "Bớt 1 dòng"
-
-#: ../undo.c:2189
-#, fuzzy
-msgid "fewer lines"
-msgstr "Bớt %<PRId64> dòng"
-
-#: ../undo.c:2193
-#, fuzzy
-msgid "change"
-msgstr "duy nhất 1 thay đổi"
-
-#: ../undo.c:2195
-#, fuzzy
-msgid "changes"
-msgstr "duy nhất 1 thay đổi"
-
-#: ../undo.c:2225
-#, fuzzy, c-format
-msgid "%<PRId64> %s; %s #%<PRId64> %s"
-msgstr "Trên %<PRId64> dòng %s %d lần"
-
-#: ../undo.c:2228
-msgid "before"
+msgid ""
+"\n"
+"MacOS X (unix) version"
msgstr ""
+"\n"
+"Phiên bản cho MacOS X (unix)"
-#: ../undo.c:2228
-msgid "after"
+msgid ""
+"\n"
+"MacOS X version"
msgstr ""
+"\n"
+"Phiên bản cho MacOS X"
-#: ../undo.c:2325
-#, fuzzy
-msgid "Nothing to undo"
-msgstr "Không tìm thấy ánh xạ"
-
-#: ../undo.c:2330
-msgid "number changes when saved"
+msgid ""
+"\n"
+"MacOS version"
msgstr ""
+"\n"
+"Phiên bản cho MacOS"
-#: ../undo.c:2360
-#, fuzzy, c-format
-msgid "%<PRId64> seconds ago"
-msgstr "%<PRId64> Cột; "
-
-#: ../undo.c:2372
-#, fuzzy
-msgid "E790: undojoin is not allowed after undo"
-msgstr "E407: %s không được cho phép ở đây"
-
-#: ../undo.c:2466
-msgid "E439: undo list corrupt"
-msgstr "E439: danh sách hủy thao tác (undo) bị hỏng"
-
-#: ../undo.c:2495
-msgid "E440: undo line missing"
-msgstr "E440: bị mất dòng hủy thao tác"
-
-#: ../version.c:600
msgid ""
"\n"
-"Included patches: "
+"RISC OS version"
msgstr ""
"\n"
-"Bao gồm các bản vá lỗi: "
+"Phiên bản cho RISC OS"
-#: ../version.c:627
-#, fuzzy
msgid ""
"\n"
-"Extra patches: "
-msgstr "Sự tương ứng con ngoài:\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Bao gồm các bản vá lỗi: "
-#: ../version.c:639 ../version.c:864
msgid "Modified by "
msgstr "Với các thay đổi bởi "
-#: ../version.c:646
msgid ""
"\n"
"Compiled "
@@ -6204,11 +4547,9 @@ msgstr ""
"\n"
"Được biên dịch "
-#: ../version.c:649
msgid "by "
msgstr "bởi "
-#: ../version.c:660
msgid ""
"\n"
"Huge version "
@@ -6216,1521 +4557,574 @@ msgstr ""
"\n"
"Phiên bản khổng lồ "
-#: ../version.c:661
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Phiên bản lớn "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Phiên bản thông thường "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Phiên bản nhỏ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Phiên bản \"tí hon\" "
+
msgid "without GUI."
msgstr "không có giao diện đồ họa GUI."
-#: ../version.c:662
+msgid "with GTK2-GNOME GUI."
+msgstr "với giao diện đồ họa GUI GTK2-GNOME."
+
+msgid "with GTK-GNOME GUI."
+msgstr "với giao diện đồ họa GUI GTK-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "với giao diện đồ họa GUI GTK2."
+
+msgid "with GTK GUI."
+msgstr "với giao diện đồ họa GUI GTK."
+
+msgid "with X11-Motif GUI."
+msgstr "với giao diện đồ họa GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "với giao diện đồ họa GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "với giao diện đồ họa GUI X11-Athena."
+
+msgid "with BeOS GUI."
+msgstr "với giao diện đồ họa GUI BeOS."
+
+msgid "with Photon GUI."
+msgstr "với giao diện đồ họa GUI Photon."
+
+msgid "with GUI."
+msgstr "với giao diện đồ họa GUI."
+
+msgid "with Carbon GUI."
+msgstr "với giao diện đồ họa GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "với giao diện đồ họa GUI Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "với giao diện đồ họa (cổ điển) GUI."
+
msgid " Features included (+) or not (-):\n"
msgstr " Tính năng có (+) hoặc không (-):\n"
-#: ../version.c:667
msgid " system vimrc file: \""
msgstr " tập tin vimrc chung cho hệ thống: \""
-#: ../version.c:672
msgid " user vimrc file: \""
msgstr " tập tin vimrc của người dùng: \""
-#: ../version.c:677
msgid " 2nd user vimrc file: \""
msgstr " tập tin vimrc thứ hai của người dùng: \""
-#: ../version.c:682
msgid " 3rd user vimrc file: \""
msgstr " tập tin vimrc thứ ba của người dùng: \""
-#: ../version.c:687
msgid " user exrc file: \""
msgstr " tập tin exrc của người dùng: \""
-#: ../version.c:692
msgid " 2nd user exrc file: \""
msgstr " tập tin exrc thứ hai của người dùng: \""
-#: ../version.c:699
+msgid " system gvimrc file: \""
+msgstr " tập tin gvimrc chung cho hệ thống: \""
+
+msgid " user gvimrc file: \""
+msgstr " tập tin gvimrc của người dùng: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " tập tin gvimrc thứ hai của người dùng: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " tập tin gvimrc thứ ba của người dùng: \""
+
+msgid " system menu file: \""
+msgstr " tập tin trình đơn chung cho hệ thống: \""
+
msgid " fall-back for $VIM: \""
msgstr " giá trị $VIM theo mặc định: \""
-#: ../version.c:705
msgid " f-b for $VIMRUNTIME: \""
msgstr " giá trị $VIMRUNTIME theo mặc định: \""
-#: ../version.c:709
msgid "Compilation: "
msgstr "Tham số biên dịch: "
-#: ../version.c:712
+msgid "Compiler: "
+msgstr "Trình biên dịch: "
+
msgid "Linking: "
msgstr "Liên kết: "
-#: ../version.c:717
msgid " DEBUG BUILD"
msgstr " BIÊN DỊCH SỬA LỖI (DEBUG)"
-#: ../version.c:767
msgid "VIM - Vi IMproved"
msgstr "VIM ::: Vi IMproved (Vi cải tiến) ::: Phiên bản tiếng Việt"
-#: ../version.c:769
msgid "version "
msgstr "phiên bản "
-#: ../version.c:770
msgid "by Bram Moolenaar et al."
msgstr "Do Bram Moolenaar và những người khác thực hiện"
-#: ../version.c:774
msgid "Vim is open source and freely distributable"
msgstr "Vim là chương trình mã nguồn mở và phân phối tự do"
-#: ../version.c:776
msgid "Help poor children in Uganda!"
msgstr "Hãy giúp đỡ trẻ em nghèo Uganda!"
-#: ../version.c:777
msgid "type :help iccf<Enter> for information "
msgstr "hãy gõ :help iccf<Enter> để biết thêm thông tin"
-#: ../version.c:779
msgid "type :q<Enter> to exit "
msgstr " hãy gõ :q<Enter> để thoát khỏi chương trình "
-#: ../version.c:780
msgid "type :help<Enter> or <F1> for on-line help"
msgstr " hãy gõ :help<Enter> hoặc <F1> để có được trợ giúp "
-#: ../version.c:781
-msgid "type :help version7<Enter> for version info"
-msgstr "hãy gõ :help version7<Enter> để biết về phiên bản này "
+msgid "type :help version9<Enter> for version info"
+msgstr "hãy gõ :help version9<Enter> để biết về phiên bản này "
-#: ../version.c:784
msgid "Running in Vi compatible mode"
msgstr "Làm việc trong chế độ tương thích với Vi"
-#: ../version.c:785
msgid "type :set nocp<Enter> for Vim defaults"
msgstr "hãy gõ :set nocp<Enter> để chuyển vào chế độ Vim "
-#: ../version.c:786
msgid "type :help cp-default<Enter> for info on this"
msgstr "hãy gõ :help cp-default<Enter> để có thêm thông tin về điều này"
-#: ../version.c:827
+msgid "menu Help->Orphans for information "
+msgstr "trình đơn Trợ giúp->Mồ côi để có thêm thông tin "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Không chế độ, văn bản nhập vào sẽ được chèn"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "trình đơn Soạn thảo->Thiết lập chung->Chế độ chèn "
+
+msgid " for two modes "
+msgstr " cho hai chế độ "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr ""
+"trình đơn Soạn thảo->Thiết lập chung->Tương thích với Vi "
+
+msgid " for Vim defaults "
+msgstr ""
+" để chuyển vào chế độ Vim mặc định "
+
msgid "Sponsor Vim development!"
msgstr "Hãy giúp đỡ phát triển Vim!"
-#: ../version.c:828
msgid "Become a registered Vim user!"
msgstr "Hãy trở thành người dùng đăng ký của Vim!"
-#: ../version.c:831
msgid "type :help sponsor<Enter> for information "
msgstr "hãy gõ :help sponsor<Enter> để biết thêm thông tin "
-#: ../version.c:832
msgid "type :help register<Enter> for information "
msgstr "hãy gõ :help register<Enter> để biết thêm thông tin "
-#: ../version.c:834
msgid "menu Help->Sponsor/Register for information "
msgstr "trình đơn Trợ giúp->Giúp đỡ/Đăng ký để biết thêm thông tin "
-#: ../window.c:119
-msgid "Already only one window"
-msgstr "Chỉ có một cửa sổ"
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "CẢNH BÁO: nhận ra Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "hãy gõ :help windows95<Enter> để biết thêm thông tin "
-#: ../window.c:224
msgid "E441: There is no preview window"
msgstr "E441: Không có cửa sổ xem trước"
-#: ../window.c:559
msgid "E442: Can't split topleft and botright at the same time"
msgstr ""
"E442: Cửa sổ không thể đồng thời ở bên trái phía trên và bên phải phía dưới"
-#: ../window.c:1228
msgid "E443: Cannot rotate when another window is split"
msgstr "E443: Không đổi được chỗ khi cửa sổ khác được chia"
-#: ../window.c:1803
msgid "E444: Cannot close last window"
msgstr "E444: Không được đóng cửa sổ cuối cùng"
-#: ../window.c:1810
-#, fuzzy
-msgid "E813: Cannot close autocmd window"
-msgstr "E444: Không được đóng cửa sổ cuối cùng"
-
-#: ../window.c:1814
-#, fuzzy
-msgid "E814: Cannot close window, only autocmd window would remain"
-msgstr "E444: Không được đóng cửa sổ cuối cùng"
+msgid "Already only one window"
+msgstr "Chỉ có một cửa sổ"
-#: ../window.c:2717
msgid "E445: Other window contains changes"
msgstr "E445: Cửa sổ khác có thay đổi chưa được ghi nhớ"
-#: ../window.c:4805
msgid "E446: No file name under cursor"
msgstr "E446: Không có tên tập tin tại vị trí con trỏ"
-#~ msgid "[Error List]"
-#~ msgstr "[Danh sách lỗi]"
-
-#~ msgid "[No File]"
-#~ msgstr "[Không có tập tin]"
-
-#~ msgid "Patch file"
-#~ msgstr "Tập tin vá lỗi (patch)"
-
-#~ msgid "E106: Unknown variable: \"%s\""
-#~ msgstr "E106: Biến không biết: \"%s\""
-
-#~ msgid ""
-#~ "&OK\n"
-#~ "&Cancel"
-#~ msgstr ""
-#~ "&OK\n"
-#~ "&Hủy bỏ"
-
-#~ msgid "E240: No connection to Vim server"
-#~ msgstr "E240: Không có kết nối với máy chủ Vim"
-
-#~ msgid "E277: Unable to read a server reply"
-#~ msgstr "E277: Máy chủ không trả lời"
-
-#~ msgid "E241: Unable to send to %s"
-#~ msgstr "E241: Không thể gửi tin nhắn tới %s"
-
-#~ msgid "E130: Undefined function: %s"
-#~ msgstr "E130: Hàm số %s chưa xác định"
-
-#~ msgid "Save As"
-#~ msgstr "Ghi nhớ như"
-
-#~ msgid "Source Vim script"
-#~ msgstr "Thực hiện script của Vim"
-
-#~ msgid "Edit File"
-#~ msgstr "Soạn thảo tập tin"
-
-#~ msgid " (NOT FOUND)"
-#~ msgstr " (KHÔNG TÌM THẤY)"
-
-#~ msgid "Edit File in new window"
-#~ msgstr "Soạn thảo tập tin trong cửa sổ mới"
-
-#~ msgid "Append File"
-#~ msgstr "Thêm tập tin"
-
-#~ msgid "Window position: X %d, Y %d"
-#~ msgstr "Vị trí cửa sổ: X %d, Y %d"
-
-#~ msgid "Save Redirection"
-#~ msgstr "Chuyển hướng ghi nhớ"
-
-#~ msgid "Save View"
-#~ msgstr "Ghi nhớ vẻ ngoài"
-
-#~ msgid "Save Session"
-#~ msgstr "Ghi nhớ buổi làm việc"
-
-#~ msgid "Save Setup"
-#~ msgstr "Ghi nhớ cấu hình"
-
-#~ msgid "E196: No digraphs in this version"
-#~ msgstr "E196: Trong phiên bản này chữ ghép không được hỗ trợ"
-
-#~ msgid "[NL found]"
-#~ msgstr "[tìm thấy ký tự NL]"
-
-#~ msgid "[crypted]"
-#~ msgstr "[đã mã hóa]"
-
-#~ msgid "[CONVERSION ERROR]"
-#~ msgstr "[LỖI CHUYỂN BẢNG MÃ]"
-
-#~ msgid "NetBeans disallows writes of unmodified buffers"
-#~ msgstr "NetBeans không cho phép ghi nhớ bộ đệm chưa có thay đổi nào"
-
-#~ msgid "Partial writes disallowed for NetBeans buffers"
-#~ msgstr "Ghi nhớ một phần bộ đệm NetBeans không được cho phép"
-
-#~ msgid "E460: The resource fork would be lost (add ! to override)"
-#~ msgstr ""
-#~ "E460: Nhánh tài nguyên sẽ bị mất (thêm ! để bỏ qua việc kiểm tra lại)"
-
-#~ msgid "<cannot open> "
-#~ msgstr "<không thể mở> "
-
-#~ msgid "E616: vim_SelFile: can't get font %s"
-#~ msgstr "E616: vim_SelFile: không tìm thấy phông chữ %s"
-
-#~ msgid "E614: vim_SelFile: can't return to current directory"
-#~ msgstr "E614: vim_SelFile: không trở lại được thư mục hiện thời"
-
-#~ msgid "Pathname:"
-#~ msgstr "Đường dẫn tới tập tin:"
-
-#~ msgid "E615: vim_SelFile: can't get current directory"
-#~ msgstr "E615: vim_SelFile: không tìm thấy thư mục hiện thời"
-
-#~ msgid "OK"
-#~ msgstr "Đồng ý"
-
-#~ msgid "Cancel"
-#~ msgstr "Hủy bỏ"
-
-#~ msgid "Vim dialog"
-#~ msgstr "Hộp thoại Vim"
-
-#~ msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
-#~ msgstr "Thanh cuộn: Không thể xác định hình học của thanh cuộn."
-
-#~ msgid "E232: Cannot create BalloonEval with both message and callback"
-#~ msgstr ""
-#~ "E232: Không tạo được BalloonEval với cả thông báo và lời gọi ngược lại"
-
-#~ msgid "E229: Cannot start the GUI"
-#~ msgstr "E229: Không chạy được giao diện đồ họa GUI"
-
-#~ msgid "E230: Cannot read from \"%s\""
-#~ msgstr "E230: Không đọc được từ \"%s\""
-
-#~ msgid "E665: Cannot start GUI, no valid font found"
-#~ msgstr ""
-#~ "E665: Không chạy được giao diện đồ họa GUI, đưa ra phông chữ không đúng"
-
-#~ msgid "E231: 'guifontwide' invalid"
-#~ msgstr "E231: 'guifontwide' có giá trị không đúng"
-
-#~ msgid "E599: Value of 'imactivatekey' is invalid"
-#~ msgstr "E599: Giá trị của 'imactivatekey' không đúng"
-
-#~ msgid "E254: Cannot allocate color %s"
-#~ msgstr "E254: Không chỉ định được màu %s"
-
-#~ msgid "Vim dialog..."
-#~ msgstr "Hộp thoại Vim..."
-
-#~ msgid "Input _Methods"
-#~ msgstr "Phương pháp _nhập liệu"
-
-#~ msgid "VIM - Search and Replace..."
-#~ msgstr "VIM - Tìm kiếm và thay thế..."
-
-#~ msgid "VIM - Search..."
-#~ msgstr "VIM - Tìm kiếm..."
-
-#~ msgid "Find what:"
-#~ msgstr "Tìm kiếm gì:"
-
-#~ msgid "Replace with:"
-#~ msgstr "Thay thế bởi:"
-
-#~ msgid "Match whole word only"
-#~ msgstr "Chỉ tìm tương ứng hoàn toàn với từ"
-
-#~ msgid "Match case"
-#~ msgstr "Có tính kiểu chữ"
-
-#~ msgid "Direction"
-#~ msgstr "Hướng"
-
-#~ msgid "Up"
-#~ msgstr "Lên"
-
-#~ msgid "Down"
-#~ msgstr "Xuống"
-
-#~ msgid "Find Next"
-#~ msgstr "Tìm tiếp"
-
-#~ msgid "Replace"
-#~ msgstr "Thay thế"
-
-#~ msgid "Replace All"
-#~ msgstr "Thay thế tất cả"
-
-#~ msgid "Vim: Received \"die\" request from session manager\n"
-#~ msgstr "Vim: Nhận được yêu cầu \"chết\" (dừng) từ trình quản lý màn hình\n"
-
-#~ msgid "Vim: Main window unexpectedly destroyed\n"
-#~ msgstr "Vim: Cửa sổ chính đã bị đóng đột ngột\n"
-
-#~ msgid "Font Selection"
-#~ msgstr "Chọn phông chữ"
-
-#~ msgid "Used CUT_BUFFER0 instead of empty selection"
-#~ msgstr "Sử dụng CUT_BUFFER0 thay cho lựa chọn trống rỗng"
-
-#~ msgid "Filter"
-#~ msgstr "Đầu lọc"
-
-#~ msgid "Directories"
-#~ msgstr "Thư mục"
-
-#~ msgid "Help"
-#~ msgstr "Trợ giúp"
-
-#~ msgid "Files"
-#~ msgstr "Tập tin"
-
-#~ msgid "Selection"
-#~ msgstr "Lựa chọn"
-
-#~ msgid "Undo"
-#~ msgstr "Hủy thao tác"
-
-#~ msgid "E671: Cannot find window title \"%s\""
-#~ msgstr "E671: Không tìm được tiêu đề cửa sổ \"%s\""
-
-#~ msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
-#~ msgstr ""
-#~ "E243: Tham số không được hỗ trợ: \"-%s\"; Hãy sử dụng phiên bản OLE."
-
-#~ msgid "E672: Unable to open window inside MDI application"
-#~ msgstr "E672: Không mở được cửa sổ bên trong ứng dụng MDI"
-
-#~ msgid "Find string (use '\\\\' to find a '\\')"
-#~ msgstr "Tìm kiếm chuỗi (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
-
-#~ msgid "Find & Replace (use '\\\\' to find a '\\')"
-#~ msgstr "Tìm kiếm và Thay thế (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
-
-#~ msgid ""
-#~ "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
-#~ msgstr ""
-#~ "Vim E458: Không chỉ định được bản ghi trong bảng màu, một vài màu có thể "
-#~ "hiển thị không chính xác"
-
-#~ msgid "E250: Fonts for the following charsets are missing in fontset %s:"
-#~ msgstr "E250: Trong bộ phông chữ %s thiếu phông cho các bảng mã sau:"
-
-#~ msgid "E252: Fontset name: %s"
-#~ msgstr "E252: Bộ phông chữ: %s"
-
-#~ msgid "Font '%s' is not fixed-width"
-#~ msgstr "Phông chữ '%s' không phải là phông có độ rộng cố định (fixed-width)"
-
-#~ msgid "E253: Fontset name: %s\n"
-#~ msgstr "E253: Bộ phông chữ: %s\n"
-
-#~ msgid "Font0: %s\n"
-#~ msgstr "Font0: %s\n"
-
-#~ msgid "Font1: %s\n"
-#~ msgstr "Font1: %s\n"
-
-#~ msgid "Font%<PRId64> width is not twice that of font0\n"
-#~ msgstr ""
-#~ "Chiều rộng phông chữ font%<PRId64> phải lớn hơn hai lần so với chiều rộng "
-#~ "font0\n"
-
-#~ msgid "Font0 width: %<PRId64>\n"
-#~ msgstr "Chiều rộng font0: %<PRId64>\n"
-
-#~ msgid ""
-#~ "Font1 width: %<PRId64>\n"
-#~ "\n"
-#~ msgstr ""
-#~ "Chiều rộng font1: %<PRId64>\n"
-#~ "\n"
-
-#~ msgid "E256: Hangul automata ERROR"
-#~ msgstr "E256: LỖI máy tự động Hangual (tiếng Hàn)"
-
-#~ msgid "E563: stat error"
-#~ msgstr "E563: lỗi stat"
-
-#~ msgid "E625: cannot open cscope database: %s"
-#~ msgstr "E625: không mở được cơ sở dữ liệu cscope: %s"
-
-#~ msgid "E626: cannot get cscope database information"
-#~ msgstr "E626: không lấy được thông tin về cơ sở dữ liệu cscope"
-
-#~ msgid "E569: maximum number of cscope connections reached"
-#~ msgstr "E569: đã đạt tới số kết nối lớn nhất cho phép với cscope"
-
-#~ msgid ""
-#~ "E263: Sorry, this command is disabled, the Python library could not be "
-#~ "loaded."
-#~ msgstr ""
-#~ "E263: Rất tiếc câu lệnh này không làm việc, vì thư viện Python chưa được "
-#~ "nạp."
-
-#~ msgid "E659: Cannot invoke Python recursively"
-#~ msgstr "E659: Không thể gọi Python một cách đệ quy"
-
-#~ msgid "can't delete OutputObject attributes"
-#~ msgstr "Không xóa được thuộc tính OutputObject"
-
-#~ msgid "softspace must be an integer"
-#~ msgstr "giá trị softspace phải là một số nguyên"
-
-#~ msgid "invalid attribute"
-#~ msgstr "thuộc tính không đúng"
-
-#~ msgid "writelines() requires list of strings"
-#~ msgstr "writelines() yêu cầu một danh sách các chuỗi"
-
-#~ msgid "E264: Python: Error initialising I/O objects"
-#~ msgstr "E264: Python: Lỗi khi bắt đầu sử dụng vật thể I/O"
-
-#~ msgid "invalid expression"
-#~ msgstr "biểu thức không đúng"
-
-#~ msgid "expressions disabled at compile time"
-#~ msgstr "biểu thức bị tắt khi biên dịch"
-
-#~ msgid "attempt to refer to deleted buffer"
-#~ msgstr "cố chỉ đến bộ đệm đã bị xóa"
-
-#~ msgid "line number out of range"
-#~ msgstr "số thứ tự của dòng vượt quá giới hạn"
-
-#~ msgid "<buffer object (deleted) at %8lX>"
-#~ msgstr "<vật thể của bộ đệm (bị xóa) tại %8lX>"
-
-#~ msgid "invalid mark name"
-#~ msgstr "tên dấu hiệu không đúng"
-
-#~ msgid "no such buffer"
-#~ msgstr "không có bộ đệm như vậy"
-
-#~ msgid "attempt to refer to deleted window"
-#~ msgstr "cố chỉ đến cửa sổ đã bị đóng"
-
-#~ msgid "readonly attribute"
-#~ msgstr "thuộc tính chỉ đọc"
-
-#~ msgid "cursor position outside buffer"
-#~ msgstr "vị trí con trỏ nằm ngoài bộ đệm"
-
-#~ msgid "<window object (deleted) at %.8lX>"
-#~ msgstr "<vật thể của cửa sổ (bị xóa) tại %.8lX>"
-
-#~ msgid "<window object (unknown) at %.8lX>"
-#~ msgstr "<vật thể của cửa sổ (không rõ) tại %.8lX>"
-
-#~ msgid "<window %d>"
-#~ msgstr "<cửa sổ %d>"
-
-#~ msgid "no such window"
-#~ msgstr "không có cửa sổ như vậy"
-
-#~ msgid "cannot save undo information"
-#~ msgstr "không ghi được thông tin về việc hủy thao tác"
-
-#~ msgid "cannot delete line"
-#~ msgstr "không xóa được dòng"
-
-#~ msgid "cannot replace line"
-#~ msgstr "không thay thế được dòng"
-
-#~ msgid "cannot insert line"
-#~ msgstr "không chèn được dòng"
-
-#~ msgid "string cannot contain newlines"
-#~ msgstr "chuỗi không thể chứa ký tự dòng mới"
-
-#~ msgid ""
-#~ "E266: Sorry, this command is disabled, the Ruby library could not be "
-#~ "loaded."
-#~ msgstr ""
-#~ "E266: Rất tiếc câu lệnh này không làm việc, vì thư viện Ruby chưa đượcnạp."
-
-#~ msgid "E273: unknown longjmp status %d"
-#~ msgstr "E273: không rõ trạng thái của longjmp %d"
-
-#~ msgid "Toggle implementation/definition"
-#~ msgstr "Bật tắt giữa thi hành/định nghĩa"
-
-#~ msgid "Show base class of"
-#~ msgstr "Hiển thị hạng cơ bản của"
-
-#~ msgid "Show overridden member function"
-#~ msgstr "Hiển thị hàm số bị nạp đè lên"
-
-#~ msgid "Retrieve from file"
-#~ msgstr "Nhận từ tập tin"
-
-#~ msgid "Retrieve from project"
-#~ msgstr "Nhận từ dự án"
-
-#~ msgid "Retrieve from all projects"
-#~ msgstr "Nhận từ tất cả các dự án"
-
-#~ msgid "Retrieve"
-#~ msgstr "Nhận"
-
-#~ msgid "Show source of"
-#~ msgstr "Hiển thị mã nguồn"
-
-#~ msgid "Find symbol"
-#~ msgstr "Tìm ký hiệu"
-
-#~ msgid "Browse class"
-#~ msgstr "Duyệt hạng"
-
-#~ msgid "Show class in hierarchy"
-#~ msgstr "Hiển thị hạng trong hệ thống cấp bậc"
-
-#~ msgid "Show class in restricted hierarchy"
-#~ msgstr "Hiển thị hạng trong hệ thống cấp bậc giới hạn"
-
-#~ msgid "Xref refers to"
-#~ msgstr "Xref chỉ đến"
-
-#~ msgid "Xref referred by"
-#~ msgstr "Liên kết đến xref từ"
-
-#~ msgid "Xref has a"
-#~ msgstr "Xref có một"
-
-#~ msgid "Xref used by"
-#~ msgstr "Xref được sử dụng bởi"
-
-#~ msgid "Show docu of"
-#~ msgstr "Hiển thị docu của"
-
-#~ msgid "Generate docu for"
-#~ msgstr "Tạo docu cho"
-
-#~ msgid ""
-#~ "Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
-#~ "$PATH).\n"
-#~ msgstr ""
-#~ "Không kết nối được tới SNiFF+. Hãy kiểm tra cấu hình môi trường."
-#~ "(sniffemacs phải được chỉ ra trong biến $PATH).\n"
-
-#~ msgid "E274: Sniff: Error during read. Disconnected"
-#~ msgstr "E274: Sniff: Lỗi trong thời gian đọc. Ngắt kết nối"
-
-#~ msgid "SNiFF+ is currently "
-#~ msgstr "Trong thời điểm hiện nay SNiFF+ "
-
-#~ msgid "not "
-#~ msgstr "không "
-
-#~ msgid "connected"
-#~ msgstr "được kết nối"
-
-#~ msgid "E275: Unknown SNiFF+ request: %s"
-#~ msgstr "E275: không rõ yêu cầu của SNiFF+: %s"
-
-#~ msgid "E276: Error connecting to SNiFF+"
-#~ msgstr "E276: Lỗi kết nối với SNiFF+"
-
-#~ msgid "E278: SNiFF+ not connected"
-#~ msgstr "E278: SNiFF+ chưa được kết nối"
-
-#~ msgid "Sniff: Error during write. Disconnected"
-#~ msgstr "Sniff: Lỗi trong thời gian ghi nhớ. Ngắt kết nối"
-
-#~ msgid "not implemented yet"
-#~ msgstr "tạm thời chưa được thực thi"
-
-#~ msgid "unknown option"
-#~ msgstr "tùy chọn không rõ"
-
-#~ msgid "cannot set line(s)"
-#~ msgstr "không thể đặt (các) dòng"
-
-#~ msgid "mark not set"
-#~ msgstr "dấu hiệu chưa được đặt"
-
-#~ msgid "row %d column %d"
-#~ msgstr "hàng %d cột %d"
-
-#~ msgid "cannot insert/append line"
-#~ msgstr "không thể chèn hoặc thêm dòng"
-
-#~ msgid "unknown flag: "
-#~ msgstr "cờ không biết: "
-
-#~ msgid "unknown vimOption"
-#~ msgstr "không rõ tùy chọn vimOption"
-
-#~ msgid "keyboard interrupt"
-#~ msgstr "sự gián đoạn của bàn phím"
-
-#~ msgid "vim error"
-#~ msgstr "lỗi của vim"
-
-#~ msgid "cannot create buffer/window command: object is being deleted"
-#~ msgstr ""
-#~ "không tạo được câu lệnh của bộ đệm hay của cửa sổ: vật thể đang bị xóa"
-
-#~ msgid ""
-#~ "cannot register callback command: buffer/window is already being deleted"
-#~ msgstr ""
-#~ "không đăng ký được câu lệnh gọi ngược: bộ đệm hoặc cửa sổ đang bị xóa"
-
-#~ msgid ""
-#~ "E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-"
-#~ "dev@vim.org"
-#~ msgstr ""
-#~ "E280: LỖI NẶNG CỦA TCL: bị hỏng danh sách liên kết!? Hãy thông báo việc "
-#~ "nàyđến danh sách thư (mailing list) vim-dev@vim.org"
-
-#~ msgid "cannot register callback command: buffer/window reference not found"
-#~ msgstr ""
-#~ "không đăng ký được câu lệnh gọi ngược: không tìm thấy liên kết đến bộ đệm "
-#~ "hoặc cửa sổ"
-
-#~ msgid ""
-#~ "E571: Sorry, this command is disabled: the Tcl library could not be "
-#~ "loaded."
-#~ msgstr ""
-#~ "E571: Rất tiếc là câu lệnh này không làm việc, vì thư viện Tcl chưa được "
-#~ "nạp"
-
-#~ msgid ""
-#~ "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim."
-#~ "org"
-#~ msgstr ""
-#~ "E281: LỖI TCL: mã thoát ra không phải là một số nguyên!? Hãy thông báo "
-#~ "điều này đến danh sách thư (mailing list) vim-dev@vim.org"
-
-#~ msgid "cannot get line"
-#~ msgstr "không nhận được dòng"
-
-#~ msgid "Unable to register a command server name"
-#~ msgstr "Không đăng ký được một tên cho máy chủ câu lệnh"
-
-#~ msgid "E248: Failed to send command to the destination program"
-#~ msgstr "E248: Gửi câu lệnh vào chương trình khác không thành công"
-
-#~ msgid "E251: VIM instance registry property is badly formed. Deleted!"
-#~ msgstr "E251: Thuộc tính đăng ký của Vim được định dạng không đúng. Xóa!"
-
-#~ msgid "This Vim was not compiled with the diff feature."
-#~ msgstr "Vim không được biên dịch với tính năng hỗ trợ xem khác biệt (diff)."
-
-#~ msgid "-register\t\tRegister this gvim for OLE"
-#~ msgstr "-register\t\tĐăng ký gvim này cho OLE"
-
-#~ msgid "-unregister\t\tUnregister gvim for OLE"
-#~ msgstr "-unregister\t\tBỏ đăng ký gvim này cho OLE"
-
-#~ msgid "-g\t\t\tRun using GUI (like \"gvim\")"
-#~ msgstr "-g\t\t\tSử dụng giao diện đồ họa GUI (giống \"gvim\")"
-
-#~ msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
-#~ msgstr ""
-#~ "-f hoặc --nofork\tTrong chương trình hoạt động: Không thực hiện fork "
-#~ "khi chạy GUI"
-
-#~ msgid "-V[N]\t\tVerbose level"
-#~ msgstr "-V[N]\t\tMức độ chi tiết của thông báo"
-
-#~ msgid "-f\t\t\tDon't use newcli to open window"
-#~ msgstr "-f\t\t\tKhông sử dụng newcli để mở cửa sổ"
-
-#~ msgid "-dev <device>\t\tUse <device> for I/O"
-#~ msgstr "-dev <thiết bị>\t\tSử dụng <thiết bị> cho I/O"
-
-#~ msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
-#~ msgstr "-U <gvimrc>\t\tSử dụng <gvimrc> thay thế cho mọi .gvimrc"
-
-#~ msgid "-x\t\t\tEdit encrypted files"
-#~ msgstr "-x\t\t\tSoạn thảo tập tin đã mã hóa"
-
-#~ msgid "-display <display>\tConnect vim to this particular X-server"
-#~ msgstr "-display <màn hình>\tKết nối vim tới máy chủ X đã chỉ ra"
-
-#~ msgid "-X\t\t\tDo not connect to X server"
-#~ msgstr "-X\t\t\tKhông thực hiện việc kết nối tới máy chủ X"
-
-#~ msgid "--remote <files>\tEdit <files> in a Vim server if possible"
-#~ msgstr "--remote <tập tin>\tSoạn thảo <tập tin> trên máy chủ Vim nếu có thể"
-
-#~ msgid "--remote-silent <files> Same, don't complain if there is no server"
-#~ msgstr ""
-#~ "--remote-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có máy "
-#~ "chủ"
-
-#~ msgid ""
-#~ "--remote-wait <files> As --remote but wait for files to have been edited"
-#~ msgstr "--remote-wait <tập tin> Cũng như --remote, nhưng chờ sự kết thúc"
-
-#~ msgid ""
-#~ "--remote-wait-silent <files> Same, don't complain if there is no server"
-#~ msgstr ""
-#~ "--remote-wait-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có "
-#~ "máy chủ"
-
-#~ msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
-#~ msgstr "--remote-send <phím>\tGửi <phím> lên máy chủ Vim và thoát"
-
-#~ msgid ""
-#~ "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
-#~ msgstr ""
-#~ "--remote-expr <biểu thức>\tTính <biểu thức> trên máy chủ Vim và in ra kết "
-#~ "quả"
-
-#~ msgid "--serverlist\t\tList available Vim server names and exit"
-#~ msgstr "--serverlist\t\tHiển thị danh sách máy chủ Vim và thoát"
-
-#~ msgid "--servername <name>\tSend to/become the Vim server <name>"
-#~ msgstr "--servername <tên>\tGửi lên (hoặc trở thành) máy chủ Vim với <tên>"
-
-#~ msgid ""
-#~ "\n"
-#~ "Arguments recognised by gvim (Motif version):\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Tham số cho gvim (phiên bản Motif):\n"
-
-#~ msgid ""
-#~ "\n"
-#~ "Arguments recognised by gvim (neXtaw version):\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Tham số cho gvim (phiên bản neXtaw):\n"
-
-#~ msgid ""
-#~ "\n"
-#~ "Arguments recognised by gvim (Athena version):\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Tham số cho gvim (phiên bản Athena):\n"
-
-#~ msgid "-display <display>\tRun vim on <display>"
-#~ msgstr "-display <màn hình>\tChạy vim trong <màn hình> đã chỉ ra"
-
-#~ msgid "-iconic\t\tStart vim iconified"
-#~ msgstr "-iconic\t\tChạy vim ở dạng thu nhỏ"
-
-#~ msgid "-name <name>\t\tUse resource as if vim was <name>"
-#~ msgstr "-name <tên>\t\tSử dụng tài nguyên giống như khi vim có <tên>"
-
-#~ msgid "\t\t\t (Unimplemented)\n"
-#~ msgstr "\t\t\t (Chưa được thực thi)\n"
-
-#~ msgid "-background <color>\tUse <color> for the background (also: -bg)"
-#~ msgstr "-background <màu>\tSử dụng <màu> chỉ ra cho nền (cũng như: -bg)"
-
-#~ msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
-#~ msgstr ""
-#~ "-foreground <màu>\tSử dụng <màu> cho văn bản thông thường (cũng như: -fg)"
-
-#~ msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
-#~ msgstr ""
-#~ "-font <phông>\t\tSử dụng <phông> chữ cho văn bản thông thường (cũng như: -"
-#~ "fn)"
-
-#~ msgid "-boldfont <font>\tUse <font> for bold text"
-#~ msgstr "-boldfont <phông>\tSử dụng <phông> chữ cho văn bản in đậm"
-
-#~ msgid "-italicfont <font>\tUse <font> for italic text"
-#~ msgstr "-italicfont <phông>\tSử dụng <phông> chữ cho văn bản in nghiêng"
-
-#~ msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
-#~ msgstr ""
-#~ "-geometry <kích thước>\tSử dụng <kích thước> ban đầu (cũng như: -geom)"
-
-#~ msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
-#~ msgstr ""
-#~ "-borderwidth <rộng>\tSử dụng đường viền có chiều <rộng> (cũng như: -bw)"
-
-#~ msgid ""
-#~ "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
-#~ msgstr ""
-#~ "-scrollbarwidth <rộng> Sử dụng thanh cuộn với chiều <rộng> (cũng như: -sw)"
-
-#~ msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
-#~ msgstr ""
-#~ "-menuheight <cao>\tSử dụng thanh trình đơn với chiều <cao> (cũng như: -mh)"
-
-#~ msgid "-reverse\t\tUse reverse video (also: -rv)"
-#~ msgstr "-reverse\t\tSử dụng chế độ video đảo ngược (cũng như: -rv)"
-
-#~ msgid "+reverse\t\tDon't use reverse video (also: +rv)"
-#~ msgstr "+reverse\t\tKhông sử dụng chế độ video đảo ngược (cũng như: +rv)"
-
-#~ msgid "-xrm <resource>\tSet the specified resource"
-#~ msgstr "-xrm <tài nguyên>\tĐặt <tài nguyên> chỉ ra"
-
-#~ msgid ""
-#~ "\n"
-#~ "Arguments recognised by gvim (RISC OS version):\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Tham số cho gvim (phiên bản RISC OS):\n"
-
-#~ msgid "--columns <number>\tInitial width of window in columns"
-#~ msgstr "--columns <số>\tChiều rộng ban đầu của cửa sổ tính theo số cột"
-
-#~ msgid "--rows <number>\tInitial height of window in rows"
-#~ msgstr "--rows <số>\tChiều cao ban đầu của cửa sổ tính theo số dòng"
-
-#~ msgid ""
-#~ "\n"
-#~ "Arguments recognised by gvim (GTK+ version):\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Tham số cho gvim (phiên bản GTK+):\n"
-
-#~ msgid "-display <display>\tRun vim on <display> (also: --display)"
-#~ msgstr ""
-#~ "-display <màn hình>\tChạy vim trên <màn hình> chỉ ra (cũng như: --display)"
-
-#~ msgid "--role <role>\tSet a unique role to identify the main window"
-#~ msgstr "--role <vai trò>\tĐặt <vai trò> duy nhất để nhận diện cửa sổ chính"
-
-#~ msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
-#~ msgstr "--socketid <xid>\tMở Vim bên trong thành phần GTK khác"
-
-#~ msgid "-P <parent title>\tOpen Vim inside parent application"
-#~ msgstr "-P <tiêu đề của mẹ>\tMở Vim bên trong ứng dụng mẹ"
-
-#~ msgid "No display"
-#~ msgstr "Không có màn hình"
-
-#~ msgid ": Send failed.\n"
-#~ msgstr ": Gửi không thành công.\n"
-
-#~ msgid ": Send failed. Trying to execute locally\n"
-#~ msgstr ": Gửi không thành công. Thử thực hiện nội bộ\n"
-
-#~ msgid "%d of %d edited"
-#~ msgstr "đã soạn thảo %d từ %d"
-
-#~ msgid "No display: Send expression failed.\n"
-#~ msgstr "Không có màn hình: gửi biểu thức không thành công.\n"
-
-#~ msgid ": Send expression failed.\n"
-#~ msgstr ": Gửi biểu thức không thành công.\n"
-
-#~ msgid "E543: Not a valid codepage"
-#~ msgstr "E543: Bảng mã không cho phép"
-
-#~ msgid "E285: Failed to create input context"
-#~ msgstr "E285: Không tạo được nội dung nhập vào"
-
-#~ msgid "E286: Failed to open input method"
-#~ msgstr "E286: Việc thử mở phương pháp nhập không thành công"
-
-#~ msgid "E287: Warning: Could not set destroy callback to IM"
-#~ msgstr ""
-#~ "E287: Cảnh báo: không đặt được sự gọi ngược hủy diệt thành phương pháp "
-#~ "nhập"
-
-#~ msgid "E288: input method doesn't support any style"
-#~ msgstr "E288: phương pháp nhập không hỗ trợ bất kỳ phong cách (style) nào"
-
-#~ msgid "E289: input method doesn't support my preedit type"
-#~ msgstr "E289: phương pháp nhập không hỗ trợ loại soạn thảo trước của Vim"
-
-#~ msgid "E290: over-the-spot style requires fontset"
-#~ msgstr "E290: phong cách over-the-spot yêu cầu một bộ phông chữ"
-
-#~ msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
-#~ msgstr "E291: GTK+ cũ hơn 1.2.3. Vùng chỉ trạng thái không làm việc"
-
-#~ msgid "E292: Input Method Server is not running"
-#~ msgstr "E292: Máy chủ phương pháp nhập liệu chưa được chạy"
-
-#~ msgid ""
-#~ "\n"
-#~ " [not usable with this version of Vim]"
-#~ msgstr ""
-#~ "\n"
-#~ " [không sử dụng được với phiên bản này của Vim]"
-
-#~ msgid ""
-#~ "&Open Read-Only\n"
-#~ "&Edit anyway\n"
-#~ "&Recover\n"
-#~ "&Quit\n"
-#~ "&Abort\n"
-#~ "&Delete it"
-#~ msgstr ""
-#~ "&O Mở chỉ để đọc\n"
-#~ "&E Vẫn soạn thảo\n"
-#~ "&R Phục hồi\n"
-#~ "&Q Thoát\n"
-#~ "&A Gián đoạn&D Xóa nó"
-
-#~ msgid "Tear off this menu"
-#~ msgstr "Chia cắt trình đơn này"
-
-#~ msgid "[string too long]"
-#~ msgstr "[chuỗi quá dài]"
-
-#~ msgid "Hit ENTER to continue"
-#~ msgstr "Nhấn phím ENTER để tiếp tục"
-
-#~ msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
-#~ msgstr " (RET/BS: dòng, SPACE/b: trang, d/u: nửa trang, q: thoát)"
-
-#~ msgid " (RET: line, SPACE: page, d: half page, q: quit)"
-#~ msgstr " (RET: dòng, SPACE: trang, d: nửa trang, q: thoát)"
-
-#~ msgid "Save File dialog"
-#~ msgstr "Ghi nhớ tập tin"
-
-#~ msgid "Open File dialog"
-#~ msgstr "Mở tập tin"
-
-#~ msgid "E338: Sorry, no file browser in console mode"
-#~ msgstr ""
-#~ "E338: Xin lỗi nhưng không có trình duyệt tập tin trong chế độ kênh giao "
-#~ "tác (console)"
-
-#~ msgid "Vim: preserving files...\n"
-#~ msgstr "Vim: ghi nhớ các tập tin...\n"
-
-#~ msgid "Vim: Finished.\n"
-#~ msgstr "Vim: Đã xong.\n"
-
-#~ msgid "ERROR: "
-#~ msgstr "LỖI: "
-
-#~ msgid ""
-#~ "\n"
-#~ "[bytes] total alloc-freed %<PRIu64>-%<PRIu64>, in use %<PRIu64>, peak use "
-#~ "%<PRIu64>\n"
-#~ msgstr ""
-#~ "\n"
-#~ "[byte] tổng phân phối-còn trống %<PRIu64>-%<PRIu64>, sử dụng %<PRIu64>, "
-#~ "píc sử dụng %<PRIu64>\n"
-
-#~ msgid ""
-#~ "[calls] total re/malloc()'s %<PRIu64>, total free()'s %<PRIu64>\n"
-#~ "\n"
-#~ msgstr ""
-#~ "[gọi] tổng re/malloc() %<PRIu64>, tổng free() %<PRIu64>\n"
-#~ "\n"
-
-#~ msgid "E340: Line is becoming too long"
-#~ msgstr "E340: Dòng đang trở thành quá dài"
-
-#~ msgid "E341: Internal error: lalloc(%<PRId64>, )"
-#~ msgstr "E341: Lỗi nội bộ: lalloc(%<PRId64>, )"
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Không tìm thấy tập tin \"%s\" trong đường dẫn"
-#~ msgid "E547: Illegal mouseshape"
-#~ msgstr "E547: Dạng trỏ chuột không cho phép"
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Không nạp được thư viện %s"
-#~ msgid "Enter encryption key: "
-#~ msgstr "Nhập mật khẩu để mã hóa: "
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Xin lỗi, câu lệnh này bị tắt: không nạp được thư viện Perl."
-#~ msgid "Enter same key again: "
-#~ msgstr " Nhập lại mật khẩu:"
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Không cho phép sự tính toán Perl trong hộp cát mà không có môđun An "
+"toàn"
-#~ msgid "Keys don't match!"
-#~ msgstr "Hai mật khẩu không trùng nhau!"
+msgid "Edit with &multiple Vims"
+msgstr "Soạn thảo trong nhiều Vi&m"
-#~ msgid "Cannot connect to Netbeans #2"
-#~ msgstr "Không kết nối được với Netbeans #2"
+msgid "Edit with single &Vim"
+msgstr "Soạn thảo trong một &Vim"
-#~ msgid "Cannot connect to Netbeans"
-#~ msgstr "Không kết nối được với NetBeans"
+msgid "&Diff with Vim"
+msgstr "&So sánh (diff) qua Vim"
-#~ msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
-#~ msgstr ""
-#~ "E668: Chế độ truy cập thông tin về liên kết với NetBeans không đúng: \"%s"
-#~ "\""
+msgid "Edit with &Vim"
+msgstr "Soạn thảo trong &Vim"
-#~ msgid "read from Netbeans socket"
-#~ msgstr "đọc từ socket NetBeans"
+msgid "Edit with existing Vim - &"
+msgstr "Soạn thảo trong Vim đã chạy - &"
-#~ msgid "E658: NetBeans connection lost for buffer %<PRId64>"
-#~ msgstr "E658: Bị mất liên kết với NetBeans cho bộ đệm %<PRId64>"
+msgid "Edits the selected file(s) with Vim"
+msgstr "Soạn thảo (các) tập tin đã chọn trong Vim"
-#~ msgid "freeing %<PRId64> lines"
-#~ msgstr "đã làm sạch %<PRId64> dòng"
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Lỗi tạo tiến trình: Hãy kiểm tra xem gvim có trong đường dẫn không!"
-#~ msgid "E530: Cannot change term in GUI"
-#~ msgstr "E530: Không thể thay đổi terminal trong giao diện đồ họa GUI"
+msgid "gvimext.dll error"
+msgstr "lỗi gvimext.dll"
-#~ msgid "E531: Use \":gui\" to start the GUI"
-#~ msgstr "E531: Hãy sử dụng \":gui\" để chạy giao diện đồ họa GUI"
+msgid "Path length too long!"
+msgstr "Đường dẫn quá dài!"
-#~ msgid "E617: Cannot be changed in the GTK+ 2 GUI"
-#~ msgstr "E617: Không thể thay đổi trong giao diện đồ họa GTK+ 2"
+msgid "--No lines in buffer--"
+msgstr "-- Không có dòng nào trong bộ đệm --"
-#~ msgid "E597: can't select fontset"
-#~ msgstr "E597: không chọn được bộ phông chữ"
+msgid "E470: Command aborted"
+msgstr "E470: Câu lệnh bị dừng"
-#~ msgid "E598: Invalid fontset"
-#~ msgstr "E598: Bộ phông chữ không đúng"
+msgid "E471: Argument required"
+msgstr "E471: Cần chỉ ra tham số"
-#~ msgid "E533: can't select wide font"
-#~ msgstr "E533: không chọn được phông chữ với các ký tự có chiều rộng gấp đôi"
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Sau \\ phải là các ký tự /, ? hoặc &"
-#~ msgid "E534: Invalid wide font"
-#~ msgstr "E534: Phông chữ, với ký tự có chiều rộng gấp đôi, không đúng"
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Lỗi trong cửa sổ dòng lệnh; <CR> thực hiện, CTRL-C thoát"
-#~ msgid "E538: No mouse support"
-#~ msgstr "E538: Chuột không được hỗ trợ"
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Câu lệnh không cho phép từ exrc/vimrc trong thư mục hiện thời hoặc "
+"trong tìm kiếm thẻ ghi"
-#~ msgid "cannot open "
-#~ msgstr "không mở được "
+msgid "E171: Missing :endif"
+msgstr "E171: Thiếu câu lệnh :endif"
-#~ msgid "VIM: Can't open window!\n"
-#~ msgstr "VIM: Không mở được cửa sổ!\n"
+msgid "E600: Missing :endtry"
+msgstr "E600: Thiếu câu lệnh :endtry"
-#~ msgid "Need Amigados version 2.04 or later\n"
-#~ msgstr "Cần Amigados phiên bản 2.04 hoặc mới hơn\n"
+msgid "E170: Missing :endwhile"
+msgstr "E170: Thiếu câu lệnh :endwhile"
-#~ msgid "Need %s version %<PRId64>\n"
-#~ msgstr "Cần %s phiên bản %<PRId64>\n"
+msgid "E588: :endwhile without :while"
+msgstr "E588: Câu lệnh :endwhile không có lệnh :while (1 cặp)"
-#~ msgid "Cannot open NIL:\n"
-#~ msgstr "Không mở được NIL:\n"
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Tập tin đã tồn tại (thêm ! để ghi chèn)"
-#~ msgid "Cannot create "
-#~ msgstr "Không tạo được "
+msgid "E472: Command failed"
+msgstr "E472: Không thực hiện thành công câu lệnh"
-#~ msgid "Vim exiting with %d\n"
-#~ msgstr "Thoát Vim với mã %d\n"
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Không rõ bộ phông chữ: %s"
-#~ msgid "cannot change console mode ?!\n"
-#~ msgstr "không thay đổi được chế độ kênh giao tác (console)?!\n"
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Không rõ phông chữ: %s"
-#~ msgid "mch_get_shellsize: not a console??\n"
-#~ msgstr "mch_get_shellsize: không phải là kênh giao tác (console)??\n"
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Phông chữ \"%s\" không có độ rộng cố định (fixed-width)"
-#~ msgid "Cannot execute "
-#~ msgstr "Không chạy được "
+msgid "E473: Internal error"
+msgstr "E473: Lỗi nội bộ"
-#~ msgid "shell "
-#~ msgstr "shell "
+msgid "Interrupted"
+msgstr "Bị gián đoạn"
-#~ msgid " returned\n"
-#~ msgstr " thoát\n"
+msgid "E14: Invalid address"
+msgstr "E14: Địa chỉ không cho phép"
-#~ msgid "ANCHOR_BUF_SIZE too small."
-#~ msgstr "Giá trị ANCHOR_BUF_SIZE quá nhỏ."
+msgid "E474: Invalid argument"
+msgstr "E474: Tham số không cho phép"
-#~ msgid "I/O ERROR"
-#~ msgstr "LỖI I/O (NHẬP/XUẤT)"
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Tham số không cho phép: %s"
-#~ msgid "...(truncated)"
-#~ msgstr "...(bị cắt bớt)"
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Biểu thức không cho phép: %s"
-#~ msgid "'columns' is not 80, cannot execute external commands"
-#~ msgstr ""
-#~ "Tùy chọn 'columns' khác 80, chương trình ngoại trú không thể thực hiện"
+msgid "E16: Invalid range"
+msgstr "E16: Vùng không cho phép"
-#~ msgid "to %s on %s"
-#~ msgstr "tới %s trên %s"
+msgid "E476: Invalid command"
+msgstr "E476: Câu lệnh không cho phép"
-#~ msgid "E613: Unknown printer font: %s"
-#~ msgstr "E613: Không rõ phông chữ của máy in: %s"
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" là mộ thư mục"
-#~ msgid "E238: Print error: %s"
-#~ msgstr "E238: Lỗi in: %s"
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: Ở trước '=' có các ký tự không mong đợi"
-#~ msgid "Printing '%s'"
-#~ msgstr "Đang in '%s'"
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Gọi hàm số \"%s()\" của thư viện không thành công"
-#~ msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
-#~ msgstr "E244: Tên bảng mã không cho phép \"%s\" trong tên phông chữ \"%s\""
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nạp hàm số %s của thư viện không thành công"
-#~ msgid "E245: Illegal char '%c' in font name \"%s\""
-#~ msgstr "E245: Ký tự không cho phép '%c' trong tên phông chữ \"%s\""
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Dấu hiệu chỉ đến một số thứ tự dòng không đúng"
-#~ msgid "Vim: Double signal, exiting\n"
-#~ msgstr "Vim: Tín hiệu đôi, thoát\n"
+msgid "E20: Mark not set"
+msgstr "E20: Dấu hiệu không được xác định"
-#~ msgid "Vim: Caught deadly signal %s\n"
-#~ msgstr "Vim: Nhận được tín hiệu chết %s\n"
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Không thể thay đổi, vì tùy chọn 'modifiable' bị tắt"
-#~ msgid "Vim: Caught deadly signal\n"
-#~ msgstr "Vim: Nhận được tín hiệu chết\n"
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Các script lồng vào nhau quá sâu"
-#~ msgid "Opening the X display took %<PRId64> msec"
-#~ msgstr "Mở màn hình X mất %<PRId64> mili giây"
+msgid "E23: No alternate file"
+msgstr "E23: Không có tập tin xen kẽ"
-#~ msgid ""
-#~ "\n"
-#~ "Vim: Got X error\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Vim: Lỗi X\n"
+msgid "E24: No such abbreviation"
+msgstr "E24: Không có chữ viết tắt như vậy"
-#~ msgid "Testing the X display failed"
-#~ msgstr "Kiểm tra màn hình X không thành công"
+msgid "E477: No ! allowed"
+msgstr "E477: Không cho phép !"
-#~ msgid "Opening the X display timed out"
-#~ msgstr "Không mở được màn hình X trong thời gian cho phép (time out)"
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Không sử dụng được giao diện đồ họa vì không chọn khi biên dịch"
-#~ msgid ""
-#~ "\n"
-#~ "Cannot execute shell sh\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Không chạy được shell sh\n"
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Tiếng Do thái không được chọn khi biên dịch\n"
-#~ msgid ""
-#~ "\n"
-#~ "Cannot create pipes\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Không tạo được đường ống (pipe)\n"
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Tiếng Farsi không được chọn khi biên dịch\n"
-#~ msgid ""
-#~ "\n"
-#~ "Cannot fork\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Không thực hiện được fork()\n"
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Tiếng Ả Rập không được chọn khi biên dịch\n"
-#~ msgid ""
-#~ "\n"
-#~ "Command terminated\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Câu lệnh bị gián đoạn\n"
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Nhóm chiếu sáng cú pháp %s không tồn tại"
-#~ msgid "XSMP lost ICE connection"
-#~ msgstr "XSMP mất kết nối ICE"
+msgid "E29: No inserted text yet"
+msgstr "E29: Tạm thời chưa có văn bản được chèn"
-#~ msgid "Opening the X display failed"
-#~ msgstr "Mở màn hình X không thành công"
+msgid "E30: No previous command line"
+msgstr "E30: Không có dòng lệnh trước"
-#~ msgid "XSMP handling save-yourself request"
-#~ msgstr "XSMP xử lý yêu cầu tự động ghi nhớ"
+msgid "E31: No such mapping"
+msgstr "E31: Không có ánh xạ (mapping) như vậy"
-#~ msgid "XSMP opening connection"
-#~ msgstr "XSMP mở kết nối"
+msgid "E479: No match"
+msgstr "E479: Không có tương ứng"
-#~ msgid "XSMP ICE connection watch failed"
-#~ msgstr "XSMP mất theo dõi kết nối ICE"
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Không có tương ứng: %s"
-#~ msgid "XSMP SmcOpenConnection failed: %s"
-#~ msgstr "XSMP thực hiện SmcOpenConnection không thành công: %s"
+msgid "E32: No file name"
+msgstr "E32: Không có tên tập tin"
-#~ msgid "At line"
-#~ msgstr "Tại dòng"
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Không có biểu thức chính quy trước để thay thế"
-#~ msgid "Could not allocate memory for command line."
-#~ msgstr "Không phân chia được bộ nhớ cho dòng lệnh."
+msgid "E34: No previous command"
+msgstr "E34: Không có câu lệnh trước"
-#~ msgid "VIM Error"
-#~ msgstr "Lỗi VIM"
+msgid "E35: No previous regular expression"
+msgstr "E35: Không có biểu thức chính quy trước"
-#~ msgid "Could not load vim32.dll!"
-#~ msgstr "Không nạp được vim32.dll!"
+msgid "E481: No range allowed"
+msgstr "E481: Không cho phép sử dụng phạm vi"
-#~ msgid "Could not fix up function pointers to the DLL!"
-#~ msgstr "Không sửa được cái chỉ (pointer) hàm số tới DLL!"
+msgid "E36: Not enough room"
+msgstr "E36: Không đủ chỗ trống"
-#~ msgid "shell returned %d"
-#~ msgstr "thoát shell với mã %d"
+# TODO: Capitalise first word of message?
+msgid "E247: No registered server named \"%s\""
+msgstr "E247: máy chủ \"%s\" chưa đăng ký"
-#~ msgid "Vim: Caught %s event\n"
-#~ msgstr "Vim: Nhận được sự kiện %s\n"
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Không tạo được tập tin %s"
-#~ msgid "close"
-#~ msgstr "đóng"
+msgid "E483: Can't get temp file name"
+msgstr "E483: Không nhận được tên tập tin tạm thời (temp)"
-#~ msgid "logoff"
-#~ msgstr "thoát"
-
-#~ msgid "shutdown"
-#~ msgstr "tắt máy"
-
-#~ msgid "E371: Command not found"
-#~ msgstr "E371: Câu lệnh không tìm thấy"
-
-#~ msgid ""
-#~ "VIMRUN.EXE not found in your $PATH.\n"
-#~ "External commands will not pause after completion.\n"
-#~ "See :help win32-vimrun for more information."
-#~ msgstr ""
-#~ "Không tìm thấy VIMRUN.EXE trong $PATH.\n"
-#~ "Lệnh ngoại trú sẽ không dừng lại sau khi hoàn thành.\n"
-#~ "Thông tin chi tiết xem trong :help win32-vimrun"
-
-#~ msgid "Vim Warning"
-#~ msgstr "Cảnh báo Vim"
-
-#~ msgid "E56: %s* operand could be empty"
-#~ msgstr "E56: operand %s* không thể rỗng"
-
-#~ msgid "E57: %s+ operand could be empty"
-#~ msgstr "E57: operand %s+ không thể rỗng"
-
-#~ msgid "E58: %s{ operand could be empty"
-#~ msgstr "E58: operand %s{ không thể rỗng"
-
-#~ msgid "E361: Crash intercepted; regexp too complex?"
-#~ msgstr "E361: Sự cố được ngăn chặn; biểu thức chính quy quá phức tạp?"
-
-#~ msgid "E363: pattern caused out-of-stack error"
-#~ msgstr "E363: sử dụng mẫu (pattern) gây ra lỗi out-of-stack"
-
-#~ msgid "E396: containedin argument not accepted here"
-#~ msgstr "E396: không được sử dụng tham số containedin ở đây"
-
-#~ msgid "Enter nr of choice (<CR> to abort): "
-#~ msgstr "Hãy chọn số cần thiết (<CR> để dừng):"
-
-#~ msgid "E430: Tag file path truncated for %s\n"
-#~ msgstr "E430: Đường dẫn tới tập tin thẻ ghi bị cắt bớt cho %s\n"
-
-#~ msgid "new shell started\n"
-#~ msgstr "đã chạy shell mới\n"
-
-#~ msgid "No undo possible; continue anyway"
-#~ msgstr "Không thể hủy thao tác; tiếp tục thực hiện"
-
-#~ msgid ""
-#~ "\n"
-#~ "MS-Windows 16/32-bit GUI version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản với giao diện đồ họa GUI cho MS-Windows 16/32 bit"
-
-#~ msgid ""
-#~ "\n"
-#~ "MS-Windows 32-bit GUI version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản với giao diện đồ họa GUI cho MS-Windows 32 bit"
-
-#~ msgid " in Win32s mode"
-#~ msgstr " trong chế độ Win32"
-
-#~ msgid " with OLE support"
-#~ msgstr " với hỗ trợ OLE"
-
-#~ msgid ""
-#~ "\n"
-#~ "MS-Windows 32-bit console version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản console cho MS-Windows 32 bit"
-
-#~ msgid ""
-#~ "\n"
-#~ "MS-Windows 16-bit version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MS-Windows 16 bit"
-
-#~ msgid ""
-#~ "\n"
-#~ "32-bit MS-DOS version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MS-DOS 32 bit"
-
-#~ msgid ""
-#~ "\n"
-#~ "16-bit MS-DOS version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MS-DOS 16 bit"
-
-#~ msgid ""
-#~ "\n"
-#~ "MacOS X (unix) version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MacOS X (unix)"
-
-#~ msgid ""
-#~ "\n"
-#~ "MacOS X version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MacOS X"
-
-#~ msgid ""
-#~ "\n"
-#~ "MacOS version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho MacOS"
-
-#~ msgid ""
-#~ "\n"
-#~ "RISC OS version"
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản cho RISC OS"
-
-#~ msgid ""
-#~ "\n"
-#~ "Big version "
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản lớn "
-
-#~ msgid ""
-#~ "\n"
-#~ "Normal version "
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản thông thường "
-
-#~ msgid ""
-#~ "\n"
-#~ "Small version "
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản nhỏ "
-
-#~ msgid ""
-#~ "\n"
-#~ "Tiny version "
-#~ msgstr ""
-#~ "\n"
-#~ "Phiên bản \"tí hon\" "
-
-#~ msgid "with GTK2-GNOME GUI."
-#~ msgstr "với giao diện đồ họa GUI GTK2-GNOME."
-
-#~ msgid "with GTK-GNOME GUI."
-#~ msgstr "với giao diện đồ họa GUI GTK-GNOME."
-
-#~ msgid "with GTK2 GUI."
-#~ msgstr "với giao diện đồ họa GUI GTK2."
-
-#~ msgid "with GTK GUI."
-#~ msgstr "với giao diện đồ họa GUI GTK."
-
-#~ msgid "with X11-Motif GUI."
-#~ msgstr "với giao diện đồ họa GUI X11-Motif."
-
-#~ msgid "with X11-neXtaw GUI."
-#~ msgstr "với giao diện đồ họa GUI X11-neXtaw."
-
-#~ msgid "with X11-Athena GUI."
-#~ msgstr "với giao diện đồ họa GUI X11-Athena."
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Không mở được tập tin %s"
-#~ msgid "with BeOS GUI."
-#~ msgstr "với giao diện đồ họa GUI BeOS."
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Không đọc được tập tin %s"
-#~ msgid "with Photon GUI."
-#~ msgstr "với giao diện đồ họa GUI Photon."
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Thay đổi chưa được ghi nhớ (thêm ! để bỏ qua ghi nhớ)"
-#~ msgid "with GUI."
-#~ msgstr "với giao diện đồ họa GUI."
+msgid "E38: Null argument"
+msgstr "E38: Tham sô bằng 0"
-#~ msgid "with Carbon GUI."
-#~ msgstr "với giao diện đồ họa GUI Carbon."
+msgid "E39: Number expected"
+msgstr "E39: Yêu cầu một số"
-#~ msgid "with Cocoa GUI."
-#~ msgstr "với giao diện đồ họa GUI Cocoa."
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Không mở được tập tin lỗi %s"
-#~ msgid "with (classic) GUI."
-#~ msgstr "với giao diện đồ họa (cổ điển) GUI."
+# TODO: Capitalise first word of message?
+msgid "E233: Cannot open display"
+msgstr "E233: không mở được màn hình"
-#~ msgid " system gvimrc file: \""
-#~ msgstr " tập tin gvimrc chung cho hệ thống: \""
+msgid "E41: Out of memory!"
+msgstr "E41: Không đủ bộ nhớ!"
-#~ msgid " user gvimrc file: \""
-#~ msgstr " tập tin gvimrc của người dùng: \""
+msgid "Pattern not found"
+msgstr "Không tìm thấy mẫu (pattern)"
-#~ msgid "2nd user gvimrc file: \""
-#~ msgstr " tập tin gvimrc thứ hai của người dùng: \""
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Không tìm thấy mẫu (pattern): %s"
-#~ msgid "3rd user gvimrc file: \""
-#~ msgstr " tập tin gvimrc thứ ba của người dùng: \""
+msgid "E487: Argument must be positive"
+msgstr "E487: Tham số phải là một số dương"
-#~ msgid " system menu file: \""
-#~ msgstr " tập tin trình đơn chung cho hệ thống: \""
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Không quay lại được thư mục trước đó"
-#~ msgid "Compiler: "
-#~ msgstr "Trình biên dịch: "
+msgid "E42: No Errors"
+msgstr "E42: Không có lỗi"
-#~ msgid "menu Help->Orphans for information "
-#~ msgstr "trình đơn Trợ giúp->Mồ côi để có thêm thông tin "
+msgid "E43: Damaged match string"
+msgstr "E43: Chuỗi tương ứng bị hỏng"
-#~ msgid "Running modeless, typed text is inserted"
-#~ msgstr "Không chế độ, văn bản nhập vào sẽ được chèn"
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Chương trình xử lý biểu thức chính quy bị hỏng"
-#~ msgid "menu Edit->Global Settings->Toggle Insert Mode "
-#~ msgstr ""
-#~ "trình đơn Soạn thảo->Thiết lập chung->Chế độ chèn "
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Tùy chọn 'readonly' được bật (Hãy thêm ! để lờ đi)"
-#~ msgid " for two modes "
-#~ msgstr " cho hai chế độ "
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: Không thay đổi được biến chỉ đọc \"%s\""
-#~ msgid "menu Edit->Global Settings->Toggle Vi Compatible"
-#~ msgstr ""
-#~ "trình đơn Soạn thảo->Thiết lập chung->Tương thích với Vi "
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Lỗi khi đọc tập tin lỗi"
-#~ msgid " for Vim defaults "
-#~ msgstr ""
-#~ " để chuyển vào chế độ Vim mặc định "
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Không cho phép trong hộp cát (sandbox)"
-#~ msgid "WARNING: Windows 95/98/ME detected"
-#~ msgstr "CẢNH BÁO: nhận ra Windows 95/98/ME"
+msgid "E523: Not allowed here"
+msgstr "E523: Không cho phép ở đây"
-#~ msgid "type :help windows95<Enter> for info on this"
-#~ msgstr "hãy gõ :help windows95<Enter> để biết thêm thông tin "
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Chế độ màn hình không được hỗ trợ"
-#~ msgid "E370: Could not load library %s"
-#~ msgstr "E370: Không nạp được thư viện %s"
+msgid "E49: Invalid scroll size"
+msgstr "E49: Kích thước thanh cuộn không cho phép"
-#~ msgid ""
-#~ "Sorry, this command is disabled: the Perl library could not be loaded."
-#~ msgstr "Xin lỗi, câu lệnh này bị tắt: không nạp được thư viện Perl."
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Tùy chọn 'shell' là một chuỗi rỗng"
-#~ msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
-#~ msgstr ""
-#~ "E299: Không cho phép sự tính toán Perl trong hộp cát mà không có môđun An "
-#~ "toàn"
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Không đọc được dữ liệu về ký tự!"
-#~ msgid "Edit with &multiple Vims"
-#~ msgstr "Soạn thảo trong nhiều Vi&m"
+msgid "E72: Close error on swap file"
+msgstr "E72: Lỗi đóng tập tin trao đổi (swap)"
-#~ msgid "Edit with single &Vim"
-#~ msgstr "Soạn thảo trong một &Vim"
+# TODO: Capitalise first word of message?
+msgid "E73: Tag stack empty"
+msgstr "E73: đống thẻ ghi rỗng"
-#~ msgid "&Diff with Vim"
-#~ msgstr "&So sánh (diff) qua Vim"
+msgid "E74: Command too complex"
+msgstr "E74: Câu lệnh quá phức tạp"
-#~ msgid "Edit with &Vim"
-#~ msgstr "Soạn thảo trong &Vim"
+msgid "E75: Name too long"
+msgstr "E75: Tên quá dài"
-#~ msgid "Edit with existing Vim - &"
-#~ msgstr "Soạn thảo trong Vim đã chạy - &"
+msgid "E76: Too many ["
+msgstr "E76: Quá nhiều ký tự ["
-#~ msgid "Edits the selected file(s) with Vim"
-#~ msgstr "Soạn thảo (các) tập tin đã chọn trong Vim"
+msgid "E77: Too many file names"
+msgstr "E77: Quá nhiều tên tập tin"
-#~ msgid "Error creating process: Check if gvim is in your path!"
-#~ msgstr "Lỗi tạo tiến trình: Hãy kiểm tra xem gvim có trong đường dẫn không!"
+msgid "E488: Trailing characters"
+msgstr "E488: Ký tự thừa ở đuôi"
-#~ msgid "gvimext.dll error"
-#~ msgstr "lỗi gvimext.dll"
+msgid "E78: Unknown mark"
+msgstr "E78: Dấu hiệu không biết"
-#~ msgid "Path length too long!"
-#~ msgstr "Đường dẫn quá dài!"
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Không thực hiện được phép thế theo wildcard"
-#~ msgid "E234: Unknown fontset: %s"
-#~ msgstr "E234: Không rõ bộ phông chữ: %s"
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: giá trị của 'winheight' không thể nhỏ hơn 'winminheight'"
-#~ msgid "E235: Unknown font: %s"
-#~ msgstr "E235: Không rõ phông chữ: %s"
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: giá trị của 'winwidth' không thể nhỏ hơn 'winminwidth'"
-#~ msgid "E448: Could not load library function %s"
-#~ msgstr "E448: Nạp hàm số %s của thư viện không thành công"
+msgid "E80: Error while writing"
+msgstr "E80: Lỗi khi ghi nhớ"
-#~ msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
-#~ msgstr "E26: Tiếng Do thái không được chọn khi biên dịch\n"
+msgid "Zero count"
+msgstr "Giá trị của bộ đếm bằng 0"
-#~ msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
-#~ msgstr "E27: Tiếng Farsi không được chọn khi biên dịch\n"
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Sử dụng <SID> ngoài phạm vi script"
-#~ msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
-#~ msgstr "E800: Tiếng Ả Rập không được chọn khi biên dịch\n"
+msgid "E449: Invalid expression received"
+msgstr "E449: Nhận được một biểu thức không cho phép"
-#~ msgid "E247: no registered server named \"%s\""
-#~ msgstr "E247: máy chủ \"%s\" chưa đăng ký"
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Không thể thay đổi vùng đã được bảo vệ"
-#~ msgid "E233: cannot open display"
-#~ msgstr "E233: không mở được màn hình"
+msgid "No tutorial with that name found"
+msgstr "Không tìm thấy hướng dẫn (tutorial) có tên đó"
-#~ msgid "E463: Region is guarded, cannot modify"
-#~ msgstr "E463: Không thể thay đổi vùng đã được bảo vệ"
+msgid "Only one argument accepted (check spaces)"
+msgstr "Chỉ chấp nhận một tham số (vui lòng kiểm tra dấu cách)"
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 3f00b74e61..ff7471025f 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -159,10 +159,7 @@ char *estack_sfile(estack_arg_T which)
{
const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) {
- if (entry->es_name == NULL) {
- return NULL;
- }
- return xstrdup(entry->es_name);
+ return entry->es_name != NULL ? xstrdup(entry->es_name) : NULL;
}
// If evaluated in a function or autocommand, return the path of the script
@@ -499,7 +496,6 @@ static void runtime_search_path_unref(RuntimeSearchPath path, const int *ref)
/// return FAIL when no file could be sourced, OK otherwise.
static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- char *tail;
bool did_one = false;
char buf[MAXPATHL];
@@ -533,7 +529,7 @@ static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback,
} else if (buflen + strlen(name) + 2 < MAXPATHL) {
STRCPY(buf, item.path);
add_pathsep(buf);
- tail = buf + strlen(buf);
+ char *tail = buf + strlen(buf);
// Loop over all patterns in "name"
char *np = name;
@@ -935,7 +931,6 @@ static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool
/// @param is_pack whether the added dir is a "pack/*/start/*/" style package
static int add_pack_dir_to_rtp(char *fname, bool is_pack)
{
- char *p;
char *afterdir = NULL;
int retval = FAIL;
@@ -943,7 +938,7 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
char *p2 = p1;
char *p3 = p1;
char *p4 = p1;
- for (p = p1; *p; MB_PTR_ADV(p)) {
+ for (char *p = p1; *p; MB_PTR_ADV(p)) {
if (vim_ispathsep_nocolon(*p)) {
p4 = p3;
p3 = p2;
@@ -970,21 +965,21 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
// Also stop at the first "after" directory
size_t fname_len = strlen(ffname);
- char *buf = try_malloc(MAXPATHL);
- if (buf == NULL) {
- goto theend;
- }
+ char buf[MAXPATHL];
const char *insp = NULL;
const char *after_insp = NULL;
- for (const char *entry = p_rtp; *entry != NUL;) {
+ const char *entry = p_rtp;
+ while (*entry != NUL) {
const char *cur_entry = entry;
-
copy_option_part((char **)&entry, buf, MAXPATHL, ",");
- if ((p = strstr(buf, "after")) != NULL
- && p > buf
- && vim_ispathsep(p[-1])
- && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',')) {
+ char *p = strstr(buf, "after");
+ bool is_after = p != NULL
+ && p > buf
+ && vim_ispathsep(p[-1])
+ && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',');
+
+ if (is_after) {
if (insp == NULL) {
// Did not find "ffname" before the first "after" directory,
// insert it before this entry.
@@ -1000,12 +995,11 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
if (rtp_ffname == NULL) {
goto theend;
}
- bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
- xfree(rtp_ffname);
- if (match) {
+ if (path_fnamencmp(rtp_ffname, ffname, fname_len) == 0) {
// Insert "ffname" after this entry (and comma).
insp = entry;
}
+ xfree(rtp_ffname);
}
}
@@ -1075,7 +1069,6 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
retval = OK;
theend:
- xfree(buf);
xfree(ffname);
xfree(afterdir);
return retval;
@@ -1123,7 +1116,7 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
bool did_one = false;
if (cookie != &APP_LOAD) {
- char *buf = xmalloc(MAXPATHL);
+ char buf[MAXPATHL];
for (int i = 0; i < num_fnames; i++) {
bool found = false;
@@ -1138,7 +1131,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
if (!found) {
// directory is not yet in 'runtimepath', add it
if (add_pack_dir_to_rtp(fnames[i], false) == FAIL) {
- xfree(buf);
return;
}
}
@@ -1147,7 +1139,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
break;
}
}
- xfree(buf);
}
if (!all && did_one) {
@@ -1276,25 +1267,23 @@ void ex_packadd(exarg_T *eap)
static const char plugpat[] = "pack/*/%s/%s"; // NOLINT
int res = OK;
- // Round 1: use "start", round 2: use "opt".
- for (int round = 1; round <= 2; round++) {
- // Only look under "start" when loading packages wasn't done yet.
- if (round == 1 && did_source_packages) {
- continue;
- }
+ const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
+ char *pat = xmallocz(len);
+ void *cookie = eap->forceit ? &APP_ADD_DIR : &APP_BOTH;
- const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
- char *pat = xmallocz(len);
- vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
- // The first round don't give a "not found" error, in the second round
- // only when nothing was found in the first round.
- res =
- do_in_path(p_pp, "", pat,
- DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
- round == 1 ? add_start_pack_plugins : add_opt_pack_plugins,
- eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
- xfree(pat);
+ // Only look under "start" when loading packages wasn't done yet.
+ if (!did_source_packages) {
+ vim_snprintf(pat, len, plugpat, "start", eap->arg);
+ res = do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR,
+ add_start_pack_plugins, cookie);
}
+
+ // Give a "not found" error if nothing was found in 'start' or 'opt'.
+ vim_snprintf(pat, len, plugpat, "opt", eap->arg);
+ do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR + (res == FAIL ? DIP_ERR : 0),
+ add_opt_pack_plugins, cookie);
+
+ xfree(pat);
}
static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
@@ -2726,22 +2715,15 @@ retry:
/// Without the multi-byte feature it's simply ignored.
void ex_scriptencoding(exarg_T *eap)
{
- source_cookie_T *sp;
- char *name;
-
if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
emsg(_("E167: :scriptencoding used outside of a sourced file"));
return;
}
- if (*eap->arg != NUL) {
- name = enc_canonize(eap->arg);
- } else {
- name = eap->arg;
- }
+ char *name = (*eap->arg != NUL) ? enc_canonize(eap->arg) : eap->arg;
// Setup for conversion from the specified encoding to 'encoding'.
- sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
+ source_cookie_T *sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
convert_setup(&sp->conv, name, p_enc);
if (name != eap->arg) {
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 00e977710f..7437a7a32f 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -3141,7 +3141,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
c = *ws;
}
if (strstr(s, "^^") != NULL) {
- if (c != NUL) {
+ if (c != NUL && reslen < MAXWLEN) {
wres[reslen++] = c;
}
memmove(word, word + i + 1, sizeof(int) * (size_t)(wordlen - (i + 1) + 1));
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index b4496d6758..6d4af0fc57 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -619,6 +619,7 @@ bool terminal_enter(void)
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
showmode();
curwin->w_redr_status = true; // For mode() in statusline. #8323
+ redraw_custom_title_later();
ui_busy_start();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
may_trigger_modechanged();
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index 5fc014a50c..e705c02e83 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -10,6 +10,7 @@ M.vars = {
]=],
},
char = {
+ type = 'string',
desc = [=[
Argument for evaluating 'formatexpr' and used for the typed
character when using <expr> in an abbreviation |:map-<expr>|.
@@ -63,6 +64,7 @@ M.vars = {
]=],
},
completed_item = {
+ type = 'vim.v.completed_item',
desc = [=[
Dictionary containing the |complete-items| for the most
recently completed word after |CompleteDone|. Empty if the
@@ -94,6 +96,7 @@ M.vars = {
]=],
},
ctype = {
+ type = 'string',
desc = [=[
The current locale setting for characters of the runtime
environment. This allows Vim scripts to be aware of the
@@ -158,6 +161,7 @@ M.vars = {
]=],
},
event = {
+ type = 'vim.v.event',
desc = [=[
Dictionary of event data for the current |autocommand|. Valid
only during the event lifetime; storing or passing v:event is
@@ -208,6 +212,8 @@ M.vars = {
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
]=],
},
exception = {
@@ -236,6 +242,7 @@ M.vars = {
]=],
},
exiting = {
+ type = 'integer?',
desc = [=[
Exit code, or |v:null| before invoking the |VimLeavePre|
and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
@@ -468,6 +475,7 @@ M.vars = {
]=],
},
msgpack_types = {
+ type = 'table',
desc = [=[
Dictionary containing msgpack types used by |msgpackparse()|
and |msgpackdump()|. All types inside dictionary are fixed
@@ -633,6 +641,7 @@ M.vars = {
]=],
},
scrollstart = {
+ type = 'string',
desc = [=[
String describing the script or function that caused the
screen to scroll up. It's only set when it is empty, thus the
@@ -796,11 +805,13 @@ M.vars = {
]=],
},
testing = {
+ type = 'integer',
desc = [=[
Must be set before using `test_garbagecollect_now()`.
]=],
},
this_session = {
+ type = 'string',
desc = [=[
Full filename of the last loaded or saved session file.
Empty when no session file has been saved. See |:mksession|.
@@ -808,6 +819,7 @@ M.vars = {
]=],
},
throwpoint = {
+ type = 'string',
desc = [=[
The point where the exception most recently caught and not
finished was thrown. Not set when commands are typed. See
diff --git a/src/nvim/window.c b/src/nvim/window.c
index ac4c5a8e4a..79c3ce9304 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6189,7 +6189,7 @@ const char *did_set_winminheight(optset_T *args FUNC_ATTR_UNUSED)
// loop until there is a 'winminheight' that is possible
while (p_wmh > 0) {
const int room = Rows - (int)p_ch;
- const int needed = min_rows();
+ const int needed = min_rows_for_all_tabpages();
if (room >= needed) {
break;
}
@@ -7065,8 +7065,24 @@ int last_stl_height(bool morewin)
}
/// Return the minimal number of rows that is needed on the screen to display
-/// the current number of windows.
-int min_rows(void)
+/// the current number of windows for the given tab page.
+int min_rows(tabpage_T *tp) FUNC_ATTR_NONNULL_ALL
+{
+ if (firstwin == NULL) { // not initialized yet
+ return MIN_LINES;
+ }
+
+ int total = frame_minheight(tp->tp_topframe, NULL);
+ total += tabline_height() + global_stl_height();
+ if ((tp == curtab ? p_ch : tp->tp_ch_used) > 0) {
+ total++; // count the room for the command line
+ }
+ return total;
+}
+
+/// Return the minimal number of rows that is needed on the screen to display
+/// the current number of windows for all tab pages.
+int min_rows_for_all_tabpages(void)
{
if (firstwin == NULL) { // not initialized yet
return MIN_LINES;
@@ -7075,12 +7091,12 @@ int min_rows(void)
int total = 0;
FOR_ALL_TABS(tp) {
int n = frame_minheight(tp->tp_topframe, NULL);
+ if ((tp == curtab ? p_ch : tp->tp_ch_used) > 0) {
+ n++; // count the room for the command line
+ }
total = MAX(total, n);
}
total += tabline_height() + global_stl_height();
- if (p_ch > 0) {
- total += 1; // count the room for the command line
- }
return total;
}
diff --git a/src/vterm/vterm.c b/src/vterm/vterm.c
index e8c87929e2..530c513755 100644
--- a/src/vterm/vterm.c
+++ b/src/vterm/vterm.c
@@ -430,509 +430,3 @@ void vterm_check_version(int major, int minor)
// Happy
}
-
-// For unit tests.
-#ifndef NDEBUG
-
-int parser_text(const char bytes[], size_t len, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "text ");
- int i;
- for(i = 0; i < len; i++) {
- unsigned char b = bytes[i];
- if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) {
- break;
- }
- fprintf(f, i ? ",%x" : "%x", b);
- }
- fprintf(f, "\n");
- fclose(f);
-
- return i;
-}
-
-static void printchars(const char *s, size_t len, FILE *f)
-{
- while(len--) {
- fprintf(f, "%c", (s++)[0]);
- }
-}
-
-int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "csi %02x", command);
-
- if(leader && leader[0]) {
- fprintf(f, " L=");
- for(int i = 0; leader[i]; i++) {
- fprintf(f, "%02x", leader[i]);
- }
- }
-
- for(int i = 0; i < argcount; i++) {
- char sep = i ? ',' : ' ';
-
- if(args[i] == CSI_ARG_MISSING) {
- fprintf(f, "%c*", sep);
- } else {
- fprintf(f, "%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
- }
- }
-
- if(intermed && intermed[0]) {
- fprintf(f, " I=");
- for(int i = 0; intermed[i]; i++) {
- fprintf(f, "%02x", intermed[i]);
- }
- }
-
- fprintf(f, "\n");
-
- fclose(f);
-
- return 1;
-}
-
-int parser_osc(int command, VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "osc ");
-
- if(frag.initial) {
- if(command == -1) {
- fprintf(f, "[");
- } else {
- fprintf(f, "[%d;", command);
- }
- }
-
- printchars(frag.str, frag.len, f);
-
- if(frag.final) {
- fprintf(f, "]");
- }
-
- fprintf(f, "\n");
- fclose(f);
-
- return 1;
-}
-
-int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "dcs ");
-
- if(frag.initial) {
- fprintf(f, "[");
- for(int i = 0; i < commandlen; i++) {
- fprintf(f, "%c", command[i]);
- }
- }
-
- printchars(frag.str, frag.len,f);
-
- if(frag.final) {
- fprintf(f, "]");
- }
-
- fprintf(f, "\n");
- fclose(f);
-
- return 1;
-}
-
-int parser_apc(VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "apc ");
-
- if(frag.initial) {
- fprintf(f, "[");
- }
-
- printchars(frag.str, frag.len, f);
-
- if(frag.final) {
- fprintf(f, "]");
- }
-
- fprintf(f, "\n");
- fclose(f);
-
- return 1;
-}
-
-int parser_pm(VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "pm ");
-
- if(frag.initial) {
- fprintf(f, "[");
- }
-
- printchars(frag.str, frag.len,f);
-
- if(frag.final) {
- fprintf(f, "]");
- }
-
- fprintf(f, "\n");
- fclose(f);
-
- return 1;
-}
-
-int parser_sos(VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "sos ");
-
- if(frag.initial) {
- fprintf(f, "[");
- }
-
- printchars(frag.str, frag.len,f);
-
- if(frag.final) {
- fprintf(f, "]");
- }
-
- fprintf(f, "\n");
- fclose(f);
-
- return 1;
-}
-
-int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "selection-set mask=%04X ", mask);
- if(frag.initial) {
- fprintf(f, "[");
-}
- printchars(frag.str, frag.len, f);
- if(frag.final) {
- fprintf(f, "]");
-}
- fprintf(f,"\n");
-
- fclose(f);
- return 1;
-}
-
-int selection_query(VTermSelectionMask mask, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f,"selection-query mask=%04X\n", mask);
-
- fclose(f);
- return 1;
-}
-
-bool want_state_putglyph;
-int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
-{
- if(!want_state_putglyph) {
- return 1;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "putglyph ");
- for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
- fprintf(f, i ? ",%x" : "%x", info->chars[i]);
- }
- fprintf(f, " %d %d,%d", info->width, pos.row, pos.col);
- if(info->protected_cell) {
- fprintf(f, " prot");
- }
- if(info->dwl) {
- fprintf(f, " dwl");
- }
- if(info->dhl) {
- fprintf(f, " dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" );
- }
- fprintf(f, "\n");
-
- fclose(f);
-
- return 1;
-}
-
-bool want_state_movecursor;
-VTermPos state_pos;
-int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- state_pos = pos;
-
- if(want_state_movecursor) {
- fprintf(f,"movecursor %d,%d\n", pos.row, pos.col);
- }
-
- fclose(f);
- return 1;
-}
-
-bool want_state_scrollrect;
-int state_scrollrect(VTermRect rect, int downward, int rightward, void *user)
-{
- if(!want_state_scrollrect) {
- return 0;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
-
- fprintf(f,"scrollrect %d..%d,%d..%d => %+d,%+d\n",
- rect.start_row, rect.end_row, rect.start_col, rect.end_col,
- downward, rightward);
-
- fclose(f);
- return 1;
-}
-
-bool want_state_moverect;
-int state_moverect(VTermRect dest, VTermRect src, void *user)
-{
- if(!want_state_moverect) {
- return 0;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f,"moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
- src.start_row, src.end_row, src.start_col, src.end_col,
- dest.start_row, dest.end_row, dest.start_col, dest.end_col);
-
- fclose(f);
- return 1;
-}
-
-void print_color(const VTermColor *col)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- if (VTERM_COLOR_IS_RGB(col)) {
- fprintf(f,"rgb(%d,%d,%d", col->rgb.red, col->rgb.green, col->rgb.blue);
- }
- else if (VTERM_COLOR_IS_INDEXED(col)) {
- fprintf(f,"idx(%d", col->indexed.idx);
- }
- else {
- fprintf(f,"invalid(%d", col->type);
- }
- if (VTERM_COLOR_IS_DEFAULT_FG(col)) {
- fprintf(f,",is_default_fg");
- }
- if (VTERM_COLOR_IS_DEFAULT_BG(col)) {
- fprintf(f,",is_default_bg");
- }
- fprintf(f,")");
- fclose(f);
-}
-
-bool want_state_settermprop;
-int state_settermprop(VTermProp prop, VTermValue *val, void *user)
-{
- if(!want_state_settermprop) {
- return 1;
- }
-
- int errcode = 0;
- FILE *f = fopen(VTERM_TEST_FILE, "a");
-
- VTermValueType type = vterm_get_prop_type(prop);
- switch(type) {
- case VTERM_VALUETYPE_BOOL:
- fprintf(f,"settermprop %d %s\n", prop, val->boolean ? "true" : "false");
- errcode = 1;
- goto end;
- case VTERM_VALUETYPE_INT:
- fprintf(f,"settermprop %d %d\n", prop, val->number);
- errcode = 1;
- goto end;
- case VTERM_VALUETYPE_STRING:
- fprintf(f,"settermprop %d %s\"%.*s\"%s\n", prop,
- val->string.initial ? "[" : "", (int)val->string.len, val->string.str, val->string.final ? "]" : "");
- errcode=0;
- goto end;
- case VTERM_VALUETYPE_COLOR:
- fprintf(f,"settermprop %d ", prop);
- print_color(&val->color);
- fprintf(f,"\n");
- errcode=1;
- goto end;
- case VTERM_N_VALUETYPES:
- goto end;
- }
-
-end:
- fclose(f);
- return errcode;
-}
-
-bool want_state_erase;
-int state_erase(VTermRect rect, int selective, void *user)
-{
- if(!want_state_erase) {
- return 1;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
-
- fprintf(f,"erase %d..%d,%d..%d%s\n",
- rect.start_row, rect.end_row, rect.start_col, rect.end_col,
- selective ? " selective" : "");
-
- fclose(f);
- return 1;
-}
-
-struct {
- int bold;
- int underline;
- int italic;
- int blink;
- int reverse;
- int conceal;
- int strike;
- int font;
- int small;
- int baseline;
- VTermColor foreground;
- VTermColor background;
-} state_pen;
-
-int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
-{
- switch(attr) {
- case VTERM_ATTR_BOLD:
- state_pen.bold = val->boolean;
- break;
- case VTERM_ATTR_UNDERLINE:
- state_pen.underline = val->number;
- break;
- case VTERM_ATTR_ITALIC:
- state_pen.italic = val->boolean;
- break;
- case VTERM_ATTR_BLINK:
- state_pen.blink = val->boolean;
- break;
- case VTERM_ATTR_REVERSE:
- state_pen.reverse = val->boolean;
- break;
- case VTERM_ATTR_CONCEAL:
- state_pen.conceal = val->boolean;
- break;
- case VTERM_ATTR_STRIKE:
- state_pen.strike = val->boolean;
- break;
- case VTERM_ATTR_FONT:
- state_pen.font = val->number;
- break;
- case VTERM_ATTR_SMALL:
- state_pen.small = val->boolean;
- break;
- case VTERM_ATTR_BASELINE:
- state_pen.baseline = val->number;
- break;
- case VTERM_ATTR_FOREGROUND:
- state_pen.foreground = val->color;
- break;
- case VTERM_ATTR_BACKGROUND:
- state_pen.background = val->color;
- break;
-
- case VTERM_N_ATTRS:
- return 0;
- default:
- break;
- }
-
- return 1;
-}
-
-bool want_state_scrollback;
-int state_sb_clear(void *user) {
- if(!want_state_scrollback) {
- return 1;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f,"sb_clear\n");
- fclose(f);
-
- return 0;
-}
-
-bool want_screen_scrollback;
-int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
-{
- if(!want_screen_scrollback) {
- return 1;
- }
-
- int eol = cols;
- while(eol && !cells[eol-1].chars[0]) {
- eol--;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "sb_pushline %d =", cols);
- for(int c = 0; c < eol; c++) {
- fprintf(f, " %02X", cells[c].chars[0]);
- }
- fprintf(f, "\n");
-
- fclose(f);
-
- return 1;
-}
-
-int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
-{
- if(!want_screen_scrollback) {
- return 0;
- }
-
- // All lines of scrollback contain "ABCDE"
- for(int col = 0; col < cols; col++) {
- if(col < 5) {
- cells[col].chars[0] = 'A' + col;
- } else {
- cells[col].chars[0] = 0;
- }
-
- cells[col].width = 1;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f,"sb_popline %d\n", cols);
- fclose(f);
- return 1;
-}
-
-int screen_sb_clear(void *user)
-{
- if(!want_screen_scrollback) {
- return 1;
- }
-
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "sb_clear\n");
- fclose(f);
- return 0;
-}
-
-void term_output(const char *s, size_t len, void *user)
-{
- FILE *f = fopen(VTERM_TEST_FILE, "a");
- fprintf(f, "output ");
- for(int i = 0; i < len; i++) {
- fprintf(f, "%x%s", (unsigned char)s[i], i < len-1 ? "," : "\n");
- }
- fclose(f);
-}
-
-#endif
diff --git a/src/vterm/vterm.h b/src/vterm/vterm.h
index df6878f744..89fe2a58bb 100644
--- a/src/vterm/vterm.h
+++ b/src/vterm/vterm.h
@@ -635,40 +635,6 @@ void vterm_copy_cells(VTermRect dest,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user);
-#ifndef NDEBUG
-int parser_text(const char bytes[], size_t len, void *user);
-int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
-int parser_osc(int command, VTermStringFragment frag, void *user);
-int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
-int parser_apc(VTermStringFragment frag, void *user);
-int parser_pm(VTermStringFragment frag, void *user);
-int parser_sos(VTermStringFragment frag, void *user);
-int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user);
-int selection_query(VTermSelectionMask mask, void *user);
-int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user);
-int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
-int state_scrollrect(VTermRect rect, int downward, int rightward, void *user);
-int state_moverect(VTermRect dest, VTermRect src, void *user);
-int state_settermprop(VTermProp prop, VTermValue *val, void *user);
-int state_erase(VTermRect rect, int selective, void *user);
-int state_setpenattr(VTermAttr attr, VTermValue *val, void *user);
-int state_sb_clear(void *user);
-void print_color(const VTermColor *col);
-int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user);
-int screen_sb_popline(int cols, VTermScreenCell *cells, void *user);
-int screen_sb_clear(void *user);
-void term_output(const char *s, size_t len, void *user);
-EXTERN VTermPos state_pos;
-EXTERN bool want_state_putglyph INIT (=false);
-EXTERN bool want_state_movecursor INIT(= false);
-EXTERN bool want_state_erase INIT(= false);
-EXTERN bool want_state_scrollrect INIT(= false);
-EXTERN bool want_state_moverect INIT(= false);
-EXTERN bool want_state_settermprop INIT(= false);
-EXTERN bool want_state_scrollback INIT(= false);
-EXTERN bool want_screen_scrollback INIT(= false);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index 3f9883f43f..bb6456f45b 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -273,54 +273,72 @@ describe('autocmd api', function()
eq({}, api.nvim_get_autocmds({ event = 'User', pattern = 'Test' }))
end)
- it('receives an args table', function()
+ local function test_autocmd_args(event)
+ local function get_amatch(pat)
+ return event == 'User' and pat or vim.fs.normalize(n.fn.fnamemodify(pat, ':p'))
+ end
+
local group_id = api.nvim_create_augroup('TestGroup', {})
-- Having an existing autocmd calling expand("<afile>") shouldn't change args #18964
- api.nvim_create_autocmd('User', {
+ api.nvim_create_autocmd(event, {
group = 'TestGroup',
pattern = 'Te*',
command = 'call expand("<afile>")',
})
- local autocmd_id = exec_lua [[
- return vim.api.nvim_create_autocmd("User", {
+ local autocmd_id = exec_lua(([[
+ return vim.api.nvim_create_autocmd(%q, {
group = "TestGroup",
pattern = "Te*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
- ]]
+ ]]):format(event))
- api.nvim_exec_autocmds('User', { pattern = 'Test pattern' })
+ local exec_pat = 'Test pattern'
+ local amatch = get_amatch(exec_pat)
+ api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = group_id,
- event = 'User',
- match = 'Test pattern',
- file = 'Test pattern',
+ event = event,
+ match = amatch,
+ file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
-- Test without a group
- autocmd_id = exec_lua [[
- return vim.api.nvim_create_autocmd("User", {
+ autocmd_id = exec_lua(([[
+ return vim.api.nvim_create_autocmd(%q, {
pattern = "*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
- ]]
+ ]]):format(event))
- api.nvim_exec_autocmds('User', { pattern = 'some_pat' })
+ exec_pat = 'some_pat'
+ amatch = get_amatch(exec_pat)
+ api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = nil,
- event = 'User',
- match = 'some_pat',
- file = 'some_pat',
+ event = event,
+ match = amatch,
+ file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
+ end
+
+ describe('receives correct args table', function()
+ it('for event that takes non-file pattern', function()
+ test_autocmd_args('User')
+ end)
+
+ it('for event that takes file pattern', function()
+ test_autocmd_args('BufEnter')
+ end)
end)
it('can receive arbitrary data', function()
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 43be0c0e43..49c55288e8 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -249,7 +249,7 @@ describe('API/extmarks', function()
set_extmark(ns, 2, 1, 0, { right_gravity = false })
eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
feed('u')
- eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
+ eq({ { 1, 0, 0 }, { 2, 0, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 1bbfe203b6..8f98ae3650 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -309,6 +309,15 @@ describe('API: set highlight', function()
eq({ underdotted = true }, api.nvim_get_hl_by_name('Test_hl', true))
end)
+ it('can set all underline cterm attributes #31385', function()
+ local ns = get_ns()
+ local attrs = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed' }
+ for _, attr in ipairs(attrs) do
+ api.nvim_set_hl(ns, 'Test_' .. attr, { cterm = { [attr] = true } })
+ eq({ [attr] = true }, api.nvim_get_hl_by_name('Test_' .. attr, false))
+ end
+ end)
+
it('can set a highlight in the global namespace', function()
api.nvim_set_hl(0, 'Test_hl', highlight2_config)
eq(
diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua
index 617786eb2d..68c4ef7503 100644
--- a/test/functional/api/version_spec.lua
+++ b/test/functional/api/version_spec.lua
@@ -43,7 +43,7 @@ describe("api_info()['version']", function()
eq(0, fn.has('nvim-' .. major .. '.' .. minor .. '.' .. (patch + 1)))
eq(0, fn.has('nvim-' .. major .. '.' .. (minor + 1) .. '.' .. patch))
eq(0, fn.has('nvim-' .. (major + 1) .. '.' .. minor .. '.' .. patch))
- assert(build == nil or type(build) == 'string')
+ assert(build == vim.NIL or type(build) == 'string')
end)
end)
@@ -93,28 +93,28 @@ describe('api metadata', function()
local function clean_level_0(metadata)
for _, f in ipairs(metadata.functions) do
f.can_fail = nil
- f.async = nil
+ f.async = nil -- XXX: renamed to "fast".
f.receives_channel_id = nil
f.since = 0
end
end
- local api_info, compat, stable, api_level
+ local api_info --[[@type table]]
+ local compat --[[@type integer]]
+ local stable --[[@type integer]]
+ local api_level --[[@type integer]]
local old_api = {}
setup(function()
clear() -- Ensure a session before requesting api_info.
+ --[[@type { version: {api_compatible: integer, api_level: integer, api_prerelease: boolean} }]]
api_info = api.nvim_get_api_info()[2]
compat = api_info.version.api_compatible
api_level = api_info.version.api_level
- if api_info.version.api_prerelease then
- stable = api_level - 1
- else
- stable = api_level
- end
+ stable = api_info.version.api_prerelease and api_level - 1 or api_level
for level = compat, stable do
local path = ('test/functional/fixtures/api_level_' .. tostring(level) .. '.mpack')
- old_api[level] = read_mpack_file(path)
+ old_api[level] = read_mpack_file(path) --[[@type table]]
if old_api[level] == nil then
local errstr = 'missing metadata fixture for stable level ' .. level .. '. '
if level == api_level and not api_info.version.api_prerelease then
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index a445423efc..3b7cefb89f 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -188,9 +188,9 @@ describe('command-line option', function()
it('nvim -v, :version', function()
matches('Run ":verbose version"', fn.execute(':version'))
- matches('Compilation: .*Run :checkhealth', fn.execute(':verbose version'))
+ matches('fall%-back for %$VIM: .*Run :checkhealth', fn.execute(':verbose version'))
matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' }))
- matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
+ matches('fall%-back for %$VIM: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
end)
if is_os('win') then
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index 030181764d..c20d925713 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -1023,18 +1023,18 @@ describe('completion', function()
it("'ignorecase' 'infercase' CTRL-X CTRL-N #6451", function()
feed_command('set ignorecase infercase')
- feed_command('edit runtime/doc/backers.txt')
+ feed_command('edit runtime/doc/credits.txt')
feed('oX<C-X><C-N>')
screen:expect {
grid = [[
- *backers.txt* Nvim |
- Xnull^ |
- {12:Xnull }{101: } |
- {4:Xoxomoon }{101: } |
- {4:Xu }{101: } NVIM REFERENCE MANUAL |
- {4:Xpayn }{12: } |
- {4:Xinity }{12: } |
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 7} |
+ *credits.txt* Nvim |
+ Xvi^ |
+ {12:Xvi }{101: } |
+ {4:Xvim }{101: } |
+ {4:X11 }{12: } NVIM REFERENCE MANUAL |
+ {4:Xnull }{12: } |
+ {4:Xoxomoon }{12: } |
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 10} |
]],
}
end)
@@ -1265,7 +1265,7 @@ describe('completion', function()
command([[
call setline(1, ['aaaa'])
let ns_id = nvim_create_namespace('extmark')
- let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error'})
+ let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error' })
let mark = nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })
inoremap <C-x> <C-r>=Complete()<CR>
function Complete() abort
@@ -1302,5 +1302,28 @@ describe('completion', function()
aaaaa |
{5:-- INSERT --} |
]])
+ -- Also when completion leader is changed #31384
+ feed('<Esc>hi<C-N><C-P>a')
+ screen:expect({
+ grid = [[
+ {9:aa}a^aa |
+ {4:aaaa } |
+ {4:aaaaa } |
+ {5:-- Keyword completion (^N^P) }{19:Back at original} |
+ ]],
+ })
+ -- But still grows with end_right_gravity #31437
+ command(
+ "call nvim_buf_set_extmark(0, ns_id, 1, 0, { 'end_col':2, 'hl_group':'Error', 'end_right_gravity': 1 })"
+ )
+ feed('<Esc>ji<C-N>a')
+ screen:expect({
+ grid = [[
+ {9:aa}aaa |
+ {9:aaa}^aa |
+ aaaaa |
+ {5:-- INSERT --} |
+ ]],
+ })
end)
end)
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
index 3b0be5c9d9..b62c5afcfc 100644
--- a/test/functional/editor/defaults_spec.lua
+++ b/test/functional/editor/defaults_spec.lua
@@ -94,6 +94,74 @@ describe('default', function()
end)
describe('key mappings', function()
+ describe('Visual mode search mappings', function()
+ it('handle various chars properly', function()
+ n.clear({ args_rm = { '--cmd' } })
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.NvimDarkGray4 },
+ [2] = {
+ foreground = Screen.colors.NvimDarkGray3,
+ background = Screen.colors.NvimLightGray3,
+ },
+ [3] = {
+ foreground = Screen.colors.NvimLightGrey1,
+ background = Screen.colors.NvimDarkYellow,
+ },
+ [4] = {
+ foreground = Screen.colors.NvimDarkGrey1,
+ background = Screen.colors.NvimLightYellow,
+ },
+ })
+ n.api.nvim_buf_set_lines(0, 0, -1, true, {
+ [[testing <CR> /?\!1]],
+ [[testing <CR> /?\!2]],
+ [[testing <CR> /?\!3]],
+ [[testing <CR> /?\!4]],
+ })
+ n.feed('gg0vf!o*')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ /\Vtesting <CR> \/?\\! [2/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ /\Vtesting <CR> \/?\\! [3/4] |
+ ]])
+ n.feed('G0vf!o#')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ ?\Vtesting <CR> /?\\! [3/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ ?\Vtesting <CR> /?\\! [2/4] |
+ ]])
+ end)
+ end)
+
describe('unimpaired-style mappings', function()
it('show the command ouptut when successful', function()
n.clear({ args_rm = { '--cmd' } })
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
index bc58551a34..063bd05618 100644
--- a/test/functional/legacy/messages_spec.lua
+++ b/test/functional/legacy/messages_spec.lua
@@ -689,4 +689,43 @@ describe('messages', function()
]])
os.remove('b.txt')
end)
+
+ -- oldtest: Test_messagesopt_wait()
+ it('&messagesopt "wait"', function()
+ screen = Screen.new(45, 6)
+ command('set cmdheight=1')
+
+ -- Check hit-enter prompt
+ command('set messagesopt=hit-enter,history:500')
+ feed(":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ screen:expect([[
+ |
+ {3: }|
+ foo |
+ bar |
+ baz |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<CR>')
+
+ -- Check no hit-enter prompt when "wait:" is set
+ command('set messagesopt=wait:100,history:500')
+ feed(":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }|
+ {3: }|
+ foo |
+ bar |
+ baz |
+ ]],
+ timeout = 100,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 6a4f8d70f3..b75ff75b05 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -208,7 +208,7 @@ describe('filetype.lua', function()
eq('gitconfig', api.nvim_get_option_value('filetype', {}))
end)
- pending('works with :doautocmd BufRead #31306', function()
+ it('works with :doautocmd BufRead #31306', function()
clear({ args = { '--clean' } })
eq('', api.nvim_get_option_value('filetype', {}))
command('doautocmd BufRead README.md')
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index f0d49205e7..89f6ad6a0e 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -273,14 +273,14 @@ describe('vim.fs', function()
end)
it('works with a single marker', function()
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
it('works with multiple markers', function()
local bufnr = api.nvim_get_current_buf()
eq(
vim.fs.joinpath(test_source_path, 'test/functional/fixtures'),
- exec_lua([[return vim.fs.root(..., {'CMakeLists.txt', '.git'})]], bufnr)
+ exec_lua([[return vim.fs.root(..., {'CMakeLists.txt', 'CMakePresets.json'})]], bufnr)
)
end)
@@ -295,26 +295,26 @@ describe('vim.fs', function()
end)
it('works with a filename argument', function()
- eq(test_source_path, exec_lua([[return vim.fs.root(..., '.git')]], nvim_prog))
+ eq(test_source_path, exec_lua([[return vim.fs.root(..., 'CMakePresets.json')]], nvim_prog))
end)
it('works with a relative path', function()
eq(
test_source_path,
- exec_lua([[return vim.fs.root(..., '.git')]], vim.fs.basename(nvim_prog))
+ exec_lua([[return vim.fs.root(..., 'CMakePresets.json')]], vim.fs.basename(nvim_prog))
)
end)
it('uses cwd for unnamed buffers', function()
command('new')
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
it("uses cwd for buffers with non-empty 'buftype'", function()
command('new')
command('set buftype=nofile')
command('file lua://')
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
end)
diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua
index a6e814d739..8df42fcaa1 100644
--- a/test/functional/lua/json_spec.lua
+++ b/test/functional/lua/json_spec.lua
@@ -152,6 +152,45 @@ describe('vim.json.encode()', function()
clear()
end)
+ it('dumps strings with & without escaped slash', function()
+ -- With slash
+ eq('"Test\\/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = true })]]))
+ eq(
+ 'Test/',
+ exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = true }))]])
+ )
+
+ -- Without slash
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/')]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', {})]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { _invalid = true })]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = false })]]))
+ eq(
+ '"Test/"',
+ exec_lua([[return vim.json.encode('Test/', { _invalid = true, escape_slash = false })]])
+ )
+ eq(
+ 'Test/',
+ exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = false }))]])
+ )
+
+ -- Checks for for global side-effects
+ eq(
+ '"Test/"',
+ exec_lua([[
+ vim.json.encode('Test/', { escape_slash = true })
+ return vim.json.encode('Test/')
+ ]])
+ )
+ eq(
+ '"Test\\/"',
+ exec_lua([[
+ vim.json.encode('Test/', { escape_slash = false })
+ return vim.json.encode('Test/', { escape_slash = true })
+ ]])
+ )
+ end)
+
it('dumps strings', function()
eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
eq('""', exec_lua([[return vim.json.encode('')]]))
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index 3f847ca3be..6c320376c9 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -18,8 +18,7 @@ local function system_sync(cmd, opts)
local res = obj:wait()
-- Check the process is no longer running
- local proc = vim.api.nvim_get_proc(obj.pid)
- assert(not proc, 'process still exists')
+ assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists')
return res
end)
@@ -27,23 +26,23 @@ end
local function system_async(cmd, opts)
return exec_lua(function()
- _G.done = false
+ local done = false
+ local res --- @type vim.SystemCompleted?
local obj = vim.system(cmd, opts, function(obj)
- _G.done = true
- _G.ret = obj
+ done = true
+ res = obj
end)
local ok = vim.wait(10000, function()
- return _G.done
+ return done
end)
assert(ok, 'process did not exit')
-- Check the process is no longer running
- local proc = vim.api.nvim_get_proc(obj.pid)
- assert(not proc, 'process still exists')
+ assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists')
- return _G.ret
+ return res
end)
end
@@ -120,4 +119,33 @@ describe('vim.system', function()
system_sync({ './test' })
end)
end
+
+ it('always captures all content of stdout/stderr #30846', function()
+ t.skip(n.fn.executable('git') == 0, 'missing "git" command')
+ t.skip(n.fn.isdirectory('.git') == 0, 'missing ".git" directory')
+ eq(
+ 0,
+ exec_lua(function()
+ local done = 0
+ local fail = 0
+ for _ = 1, 200 do
+ vim.system(
+ { 'git', 'show', ':0:test/functional/plugin/lsp_spec.lua' },
+ { text = true },
+ function(o)
+ if o.code ~= 0 or #o.stdout == 0 then
+ fail = fail + 1
+ end
+ done = done + 1
+ end
+ )
+ end
+
+ local ok = vim.wait(10000, function()
+ return done == 200
+ end, 200)
+ return fail + (ok and 0 or 1)
+ end)
+ )
+ end)
end)
diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua
index 6127e83619..92e798e7f3 100644
--- a/test/functional/lua/with_spec.lua
+++ b/test/functional/lua/with_spec.lua
@@ -1621,4 +1621,21 @@ describe('vim._with', function()
matches('Invalid buffer', get_error('{ buf = -1 }, function() end'))
matches('Invalid window', get_error('{ win = -1 }, function() end'))
end)
+
+ it('no double-free when called from :filter browse oldfiles #31501', function()
+ exec_lua([=[
+ vim.api.nvim_create_autocmd('BufEnter', {
+ callback = function()
+ vim._with({ lockmarks = true }, function() end)
+ end,
+ })
+ vim.cmd([[
+ let v:oldfiles = ['Xoldfile']
+ call nvim_input('1<CR>')
+ noswapfile filter /Xoldfile/ browse oldfiles
+ ]])
+ ]=])
+ n.assert_alive()
+ eq('Xoldfile', fn.bufname('%'))
+ end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index ca9196562c..4ecb056d01 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -89,7 +89,7 @@ describe('vim.lsp.diagnostic', function()
return extmarks
end
- client_id = assert(vim.lsp.start_client {
+ client_id = assert(vim.lsp.start({
cmd_env = {
NVIM_LUA_NOTRACK = '1',
},
@@ -101,7 +101,7 @@ describe('vim.lsp.diagnostic', function()
'--headless',
},
offset_encoding = 'utf-16',
- })
+ }, { attach = false }))
end)
fake_uri = 'file:///fake/uri'
diff --git a/test/functional/plugin/lsp/folding_range_spec.lua b/test/functional/plugin/lsp/folding_range_spec.lua
new file mode 100644
index 0000000000..7e68a598d2
--- /dev/null
+++ b/test/functional/plugin/lsp/folding_range_spec.lua
@@ -0,0 +1,647 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+local t_lsp = require('test.functional.plugin.lsp.testutil')
+
+local eq = t.eq
+local tempname = t.tmpname
+
+local clear_notrace = t_lsp.clear_notrace
+local create_server_definition = t_lsp.create_server_definition
+
+local api = n.api
+local exec_lua = n.exec_lua
+local insert = n.insert
+local command = n.command
+local feed = n.feed
+
+describe('vim.lsp.folding_range', function()
+ local text = [[// foldLevel() {{{2
+/// @return fold level at line number "lnum" in the current window.
+static int foldLevel(linenr_T lnum)
+{
+ // While updating the folds lines between invalid_top and invalid_bot have
+ // an undefined fold level. Otherwise update the folds first.
+ if (invalid_top == 0) {
+ checkupdate(curwin);
+ } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {
+ return prev_lnum_lvl;
+ } else if (lnum >= invalid_top && lnum <= invalid_bot) {
+ return -1;
+ }
+
+ // Return quickly when there is no folding at all in this window.
+ if (!hasAnyFolding(curwin)) {
+ return 0;
+ }
+
+ return foldLevelWin(curwin, lnum);
+}]]
+
+ local result = {
+ {
+ endLine = 19,
+ kind = 'region',
+ startCharacter = 1,
+ startLine = 3,
+ },
+ {
+ endCharacter = 2,
+ endLine = 7,
+ kind = 'region',
+ startCharacter = 25,
+ startLine = 6,
+ },
+ {
+ endCharacter = 2,
+ endLine = 9,
+ kind = 'region',
+ startCharacter = 55,
+ startLine = 8,
+ },
+ {
+ endCharacter = 2,
+ endLine = 11,
+ kind = 'region',
+ startCharacter = 58,
+ startLine = 10,
+ },
+ {
+ endCharacter = 2,
+ endLine = 16,
+ kind = 'region',
+ startCharacter = 31,
+ startLine = 15,
+ },
+ {
+ endCharacter = 68,
+ endLine = 1,
+ kind = 'comment',
+ startCharacter = 2,
+ startLine = 0,
+ },
+ {
+ endCharacter = 64,
+ endLine = 5,
+ kind = 'comment',
+ startCharacter = 4,
+ startLine = 4,
+ },
+ }
+
+ local bufnr ---@type integer
+ local client_id ---@type integer
+
+ clear_notrace()
+ before_each(function()
+ clear_notrace()
+
+ exec_lua(create_server_definition)
+ bufnr = n.api.nvim_get_current_buf()
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ foldingRangeProvider = true,
+ },
+ handlers = {
+ ['textDocument/foldingRange'] = function(_, _, callback)
+ callback(nil, result)
+ end,
+ },
+ })
+
+ vim.api.nvim_win_set_buf(0, bufnr)
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ command('set foldmethod=expr foldcolumn=1 foldlevel=999')
+ insert(text)
+ end)
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
+ end)
+
+ describe('setup()', function()
+ ---@type integer
+ local bufnr_set_expr
+ ---@type integer
+ local bufnr_never_set_expr
+
+ local function buf_autocmd_num(bufnr_to_check)
+ return exec_lua(function()
+ return #vim.api.nvim_get_autocmds({ buffer = bufnr_to_check, event = 'LspNotify' })
+ end)
+ end
+
+ before_each(function()
+ command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
+ exec_lua(function()
+ bufnr_set_expr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr_set_expr)
+ end)
+ insert(text)
+ command('write ' .. tempname(false))
+ command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
+ exec_lua(function()
+ bufnr_never_set_expr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr_never_set_expr)
+ end)
+ insert(text)
+ api.nvim_win_set_buf(0, bufnr_set_expr)
+ end)
+
+ it('only create event hooks where foldexpr has been set', function()
+ eq(1, buf_autocmd_num(bufnr))
+ eq(1, buf_autocmd_num(bufnr_set_expr))
+ eq(0, buf_autocmd_num(bufnr_never_set_expr))
+ end)
+
+ it('does not create duplicate event hooks after reloaded', function()
+ command('edit')
+ eq(1, buf_autocmd_num(bufnr_set_expr))
+ end)
+
+ it('cleans up event hooks when buffer is unloaded', function()
+ command('bdelete')
+ eq(0, buf_autocmd_num(bufnr_set_expr))
+ end)
+ end)
+
+ describe('expr()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 45)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { bold = true, foreground = Screen.colors.Blue1 },
+ [3] = { bold = true, reverse = true },
+ [4] = { reverse = true },
+ })
+ command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
+ command([[split]])
+ end)
+
+ it('can compute fold levels', function()
+ ---@type table<integer, string>
+ local foldlevels = {}
+ for i = 1, 21 do
+ foldlevels[i] = exec_lua('return vim.lsp.foldexpr(' .. i .. ')')
+ end
+ eq({
+ [1] = '>1',
+ [2] = '<1',
+ [3] = '0',
+ [4] = '>1',
+ [5] = '>2',
+ [6] = '<2',
+ [7] = '>2',
+ [8] = '<2',
+ [9] = '>2',
+ [10] = '<2',
+ [11] = '>2',
+ [12] = '<2',
+ [13] = '1',
+ [14] = '1',
+ [15] = '1',
+ [16] = '>2',
+ [17] = '<2',
+ [18] = '1',
+ [19] = '1',
+ [20] = '<1',
+ [21] = '0',
+ }, foldlevels)
+ end)
+
+ it('updates folds in all windows', function()
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('persists wherever foldexpr is set', function()
+ command([[setlocal foldexpr=]])
+ feed('<C-w><C-w>zx')
+ screen:expect({
+ grid = [[
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('synchronizes changed rows with their previous foldlevels', function()
+ command('1,2d')
+ screen:expect({
+ grid = [[
+{1: }^static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{2:~ }|*2
+{3:[No Name] [+] }|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{2:~ }|*2
+{4:[No Name] [+] }|
+ |
+]],
+ })
+ end)
+
+ it('clears folds when sole client detaches', function()
+ exec_lua(function()
+ vim.lsp.buf_detach_client(bufnr, client_id)
+ end)
+ screen:expect({
+ grid = [[
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('remains valid after the client re-attaches.', function()
+ exec_lua(function()
+ vim.lsp.buf_detach_client(bufnr, client_id)
+ vim.lsp.buf_attach_client(bufnr, client_id)
+ end)
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+ end)
+
+ describe('foldtext()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 23)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
+ [3] = { bold = true, foreground = Screen.colors.Blue1 },
+ [4] = { bold = true, reverse = true },
+ [5] = { reverse = true },
+ })
+ command(
+ [[set foldexpr=v:lua.vim.lsp.foldexpr() foldtext=v:lua.vim.lsp.foldtext() foldlevel=1]]
+ )
+ end)
+
+ it('shows the first folded line if `collapsedText` does not exist', function()
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2: // While updating the folds lines between invalid_top and invalid_bot have···}|
+{1:+}{2: if (invalid_top == 0) {······················································}|
+{1:+}{2: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {························}|
+{1:+}{2: } else if (lnum >= invalid_top && lnum <= invalid_bot) {·····················}|
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:+}{2: if (!hasAnyFolding(curwin)) {················································}|
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*6
+ |
+ ]],
+ })
+ end)
+ end)
+
+ describe('foldclose()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 23)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
+ [3] = { bold = true, foreground = Screen.colors.Blue1 },
+ [4] = { bold = true, reverse = true },
+ [5] = { reverse = true },
+ })
+ command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
+ end)
+
+ it('closes all folds of one kind immediately', function()
+ exec_lua(function()
+ vim.lsp.foldclose('comment')
+ end)
+ screen:expect({
+ grid = [[
+{1:+}{2:+-- 2 lines: foldLevel()······················································}|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*3
+ |
+ ]],
+ })
+ end)
+
+ it('closes the smallest fold first', function()
+ exec_lua(function()
+ vim.lsp.foldclose('region')
+ end)
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:+}{2:+-- 17 lines: {································································}|
+{1: }^} |
+{3:~ }|*17
+ |
+ ]],
+ })
+ command('4foldopen')
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:+}{2:+--- 2 lines: if (invalid_top == 0) {·········································}|
+{1:+}{2:+--- 2 lines: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {···········}|
+{1:+}{2:+--- 2 lines: } else if (lnum >= invalid_top && lnum <= invalid_bot) {········}|
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:+}{2:+--- 2 lines: if (!hasAnyFolding(curwin)) {···································}|
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*5
+ |
+ ]],
+ })
+ end)
+
+ it('is defered when the buffer is not up-to-date', function()
+ exec_lua(function()
+ vim.lsp.foldclose('comment')
+ vim.lsp.util.buf_versions[bufnr] = 0
+ end)
+ screen:expect({
+ grid = [[
+{1:+}{2:+-- 2 lines: foldLevel()······················································}|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*3
+ |
+ ]],
+ })
+ end)
+ end)
+end)
diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua
deleted file mode 100644
index 4b05b676a8..0000000000
--- a/test/functional/plugin/lsp/handler_spec.lua
+++ /dev/null
@@ -1,42 +0,0 @@
-local t = require('test.testutil')
-local n = require('test.functional.testnvim')()
-
-local eq = t.eq
-local exec_lua = n.exec_lua
-local pcall_err = t.pcall_err
-local matches = t.matches
-
-describe('lsp-handlers', function()
- describe('vim.lsp._with_extend', function()
- it('should return a table with the default keys', function()
- eq(
- { hello = 'world' },
- exec_lua(function()
- return vim.lsp._with_extend('test', { hello = 'world' })
- end)
- )
- end)
-
- it('should override with config keys', function()
- eq(
- { hello = 'universe', other = true },
- exec_lua(function()
- return vim.lsp._with_extend(
- 'test',
- { other = true, hello = 'world' },
- { hello = 'universe' }
- )
- end)
- )
- end)
-
- it('should not allow invalid keys', function()
- matches(
- '.*Invalid option for `test`.*',
- pcall_err(exec_lua, function()
- return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
- end)
- )
- end)
- end)
-end)
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 280bd27207..9912bf2063 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -456,7 +456,7 @@ describe('semantic token highlighting', function()
vim.notify = function(...)
table.insert(_G.notifications, 1, { ... })
end
- return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }, { attach = false })
end)
eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index e30d1ba411..e735e20ff5 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -95,7 +95,7 @@ describe('LSP', function()
exec_lua(function()
_G.lsp = require('vim.lsp')
function _G.test__start_client()
- return vim.lsp.start_client {
+ return vim.lsp.start({
cmd_env = {
NVIM_LOG_FILE = fake_lsp_logfile,
NVIM_APPNAME = 'nvim_lsp_test',
@@ -112,7 +112,7 @@ describe('LSP', function()
name = 'test_folder',
},
},
- }
+ }, { attach = false })
end
_G.TEST_CLIENT1 = _G.test__start_client()
end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index f223cdd417..4d25fe62ad 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -511,7 +511,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
before_each(function()
clear()
- command('set number')
+ command('au TermOpen * set number')
end)
describe('in a line with no multibyte chars or trailing spaces,', function()
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 60b1510603..028c01f14a 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -65,40 +65,40 @@ static int nlua_schedule(lua_State *const lstate)
}]]
local hl_grid_legacy_c = [[
- {2:^/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) |
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} nlua_schedule(lua_State *{6:const} lstate) |
{ |
- {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION |
+ {15:if} (lua_type(lstate, {26:1}) != LUA_TFUNCTION |
|| lstate != lstate) { |
- lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} lua_error(lstate); |
+ lua_pushliteral(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} lua_error(lstate); |
} |
|
- LuaRef cb = nlua_ref(lstate, {5:1}); |
+ LuaRef cb = nlua_ref(lstate, {26:1}); |
|
multiqueue_put(main_loop.events, nlua_schedule_event, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
} |
{1:~ }|*2
|
]]
local hl_grid_ts_c = [[
- {2:^/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6: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); |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
} |
|
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
} |
{1:~ }|*2
|
@@ -145,10 +145,10 @@ local injection_grid_c = [[
]]
local injection_grid_expected_c = [[
- {3:int} x = {5:INT_MAX}; |
- #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
- #define foo {3:void} main() { \ |
- {4:return} {5:42}; \ |
+ {6:int} x = {26:INT_MAX}; |
+ #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
+ #define foo {6:void} main() { \ |
+ {15:return} {26:42}; \ |
} |
^ |
{1:~ }|*11
@@ -161,20 +161,6 @@ describe('treesitter highlighting (C)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { foreground = Screen.colors.Blue1 },
- [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [4] = { bold = true, foreground = Screen.colors.Brown },
- [5] = { foreground = Screen.colors.Magenta },
- [6] = { foreground = Screen.colors.Red },
- [7] = { bold = true, foreground = Screen.colors.SlateBlue },
- [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red },
- [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red },
- [11] = { foreground = Screen.colors.Cyan4 },
- }
-
command [[ hi link @error ErrorMsg ]]
command [[ hi link @warning WarningMsg ]]
end)
@@ -246,124 +232,124 @@ describe('treesitter highlighting (C)', function()
feed('5Goc<esc>dd')
- screen:expect {
+ 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:~ }|*2
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:^lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*2
+ |
+ ]],
+ })
feed('7Go*/<esc>')
- screen:expect {
+ 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); |
- {8:*^/} |
- } |
- |
- {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:~ }|
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ {9:*^/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|
+ |
+ ]],
+ })
feed('3Go/*<esc>')
- screen:expect {
+ 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) |
- { |
- {2:/^*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/^*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
feed('gg$')
feed('~')
- screen:expect {
+ screen:expect({
grid = [[
- {2:/// Schedule Lua callback on main loop's event queu^E} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queu^E} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
feed('re')
- screen:expect {
+ screen:expect({
grid = [[
- {2:/// Schedule Lua callback on main loop's event queu^e} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queu^e} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
end)
it('is updated with :sort', function()
@@ -372,83 +358,79 @@ describe('treesitter highlighting (C)', function()
local parser = vim.treesitter.get_parser(0, 'c')
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- {3:bool} ext_widgets[kUIExtCount]; |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:UI} *ui = uis[i]; |
- width = {5:MIN}(ui->width, width); |
- height = {5:MIN}(ui->height, height); |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]],
- }
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:UI} *ui = uis[i]; |
+ width = {26:MIN}(ui->width, width); |
+ height = {26:MIN}(ui->height, height); |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
feed ':sort<cr>'
- screen:expect {
+ screen:expect({
grid = [[
- ^ |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- {3:UI} *ui = uis[i]; |
- ext_widgets[i] = true; |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- height = {5:MIN}(ui->height, height); |
- width = {5:MIN}(ui->width, width); |
- } |
- {3:bool} ext_widgets[kUIExtCount]; |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- } |*2
- {3:void} ui_refresh({3:void}) |
- :sort |
- ]],
- }
+ ^ |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ {6:UI} *ui = uis[i]; |
+ ext_widgets[i] = true; |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ height = {26:MIN}(ui->height, height); |
+ width = {26:MIN}(ui->width, width); |
+ } |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ } |*2
+ {6:void} ui_refresh({6:void}) |
+ :sort |
+ ]],
+ })
- feed 'u'
+ feed 'u:<esc>'
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- {3:bool} ext_widgets[kUIExtCount]; |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:UI} *ui = uis[i]; |
- width = {5:MIN}(ui->width, width); |
- height = {5:MIN}(ui->height, height); |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- 19 changes; before #2 {MATCH:.*}|
- ]],
- }
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:UI} *ui = uis[i]; |
+ width = {26:MIN}(ui->width, width); |
+ height = {26:MIN}(ui->height, height); |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
end)
it('supports with custom parser', function()
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- }
-
insert(test_text_c)
screen:expect {
@@ -488,28 +470,28 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } })
end)
- screen:expect {
+ 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); |
- } |
- } |
- ^} |
- |
- ]],
- }
+ int {6:width} = {6:INT_MAX}, {6:height} = {6:INT_MAX}; |
+ bool {6:ext_widgets}[{6:kUIExtCount}]; |
+ for (UIExtension {6:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {6:inclusive} = {6:ui_override}(); |
+ for (size_t {6:i} = 0; i < ui_count; i++) { |
+ UI *{6:ui} = {6:uis}[{6:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {6:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
end)
it('supports injected languages', function()
@@ -567,18 +549,18 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} x = {5:INT_MAX}; |
- #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
- #define foo {3:void} main() { \ |
- {4:return} {5:42}; \ |
- } |
- ^ |
- {1:~ }|*11
- |
- ]],
- }
+ {6:int} x = {26:INT_MAX}; |
+ #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
+ #define foo {6:void} main() { \ |
+ {15:return} {26:42}; \ |
+ } |
+ ^ |
+ {1:~ }|*11
+ |
+ ]],
+ })
end)
it('supports highlighting with custom highlight groups', function()
@@ -595,27 +577,27 @@ describe('treesitter highlighting (C)', function()
-- This will change ONLY the literal strings to look like comments
-- The only literal string is the "vim.schedule: expected function" in this test.
exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]]
- screen:expect {
+ 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, {2:"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:~ }|*2
- |
- ]],
- }
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {18:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*2
+ |
+ ]],
+ })
screen:expect { unchanged = true }
end)
@@ -691,25 +673,25 @@ describe('treesitter highlighting (C)', function()
)
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:char}* x = {5:"Will somebody ever read this?"}; |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ {6:char}* x = {26:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
-- clearing specialization reactivates fallback
command [[ hi clear @foo.bar ]]
- screen:expect {
+ screen:expect({
grid = [[
- {5:char}* x = {5:"Will somebody ever read this?"}; |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ {26:char}* x = {26:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
end
)
@@ -740,27 +722,27 @@ describe('treesitter highlighting (C)', function()
})
end)
- screen:expect {
+ screen:expect({
grid = [[
- /// Schedule Lua callback on main loop's event queue |
- {4:R} int nlua_schedule(lua_State *const ) |
- { |
- if (lua_type(, 1) != LUA_TFUNCTION |
- || != ) { |
- lua_pushliteral(, "vim.schedule: expected function"); |
- return lua_error(); |
- } |
- |
- LuaRef cb = nlua_ref(, 1); |
- |
- {11:V}(main_loop.events, nlua_schedule_event, |
- 1, (void *)(ptrdiff_t)cb); |
- return 0; |
- ^} |
- {1:~ }|*2
- |
- ]],
- }
+ /// Schedule Lua callback on main loop's event queue |
+ {15:R} int nlua_schedule(lua_State *const ) |
+ { |
+ if (lua_type(, 1) != LUA_TFUNCTION |
+ || != ) { |
+ lua_pushliteral(, "vim.schedule: expected function"); |
+ return lua_error(); |
+ } |
+ |
+ LuaRef cb = nlua_ref(, 1); |
+ |
+ {25:V}(main_loop.events, nlua_schedule_event, |
+ 1, (void *)(ptrdiff_t)cb); |
+ return 0; |
+ ^} |
+ {1:~ }|*2
+ |
+ ]],
+ })
end)
it('@foo.bar groups has the correct fallback behavior', function()
@@ -801,16 +783,16 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- {5:int x = 4;} |
- {5:int y = 5;} |
- {5:int z = 6;} |
- ^ |
- {1:~ }|*13
- |
- ]],
- }
+ {26:int x = 4;} |
+ {26:int y = 5;} |
+ {26:int z = 6;} |
+ ^ |
+ {1:~ }|*13
+ |
+ ]],
+ })
end)
it('gives higher priority to more specific captures #27895', function()
@@ -830,14 +812,52 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- void foo(int {4:*}{11:bar}); |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ void foo(int {15:*}{25:bar}); |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
+ end)
+
+ it('highlights applied to first line of closed fold', function()
+ insert(hl_text_c)
+ exec_lua(function()
+ vim.treesitter.query.set('c', 'highlights', hl_query_c)
+ vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
+ end)
+ feed('ggjzfj')
+ command('set foldtext=')
+ screen:add_extra_attr_ids({
+ [100] = {
+ bold = true,
+ background = Screen.colors.LightGray,
+ foreground = Screen.colors.SeaGreen4,
+ },
+ [101] = { background = Screen.colors.LightGray, foreground = Screen.colors.DarkCyan },
+ })
+ screen:expect({
+ grid = [[
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {100:^static}{13: }{100:int}{13: }{101:nlua_schedule}{13:(}{100:lua_State}{13: *}{100:const}{13: lstate)················}|
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*3
+ |
+ ]],
+ })
end)
end)
@@ -847,13 +867,6 @@ describe('treesitter highlighting (lua)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue },
- [2] = { foreground = Screen.colors.DarkCyan },
- [3] = { foreground = Screen.colors.Magenta },
- [4] = { foreground = Screen.colors.SlateBlue },
- [5] = { bold = true, foreground = Screen.colors.Brown },
- }
end)
it('supports language injections', function()
@@ -867,15 +880,15 @@ describe('treesitter highlighting (lua)', function()
vim.treesitter.start()
end)
- screen:expect {
+ screen:expect({
grid = [[
- {5:local} {2:ffi} {5:=} {4:require(}{3:'ffi'}{4:)} |
- {2:ffi}{4:.}{2:cdef}{4:(}{3:"}{4:int}{3: }{4:(}{5:*}{3:fun}{4:)(int,}{3: }{4:char}{3: }{5:*}{4:);}{3:"}{4:)} |
- ^ |
- {1:~ }|*14
- |
- ]],
- }
+ {15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} |
+ {25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} |
+ ^ |
+ {1:~ }|*14
+ |
+ ]],
+ })
end)
end)
@@ -885,16 +898,6 @@ describe('treesitter highlighting (help)', function()
before_each(function()
clear()
screen = Screen.new(40, 6)
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.Blue1 },
- [2] = { bold = true, foreground = Screen.colors.Blue1 },
- [3] = { bold = true, foreground = Screen.colors.Brown },
- [4] = { foreground = Screen.colors.Cyan4 },
- [5] = { foreground = Screen.colors.Magenta1 },
- title = { bold = true, foreground = Screen.colors.Magenta1 },
- h1_delim = { nocombine = true, underdouble = true },
- h2_delim = { nocombine = true, underline = true },
- }
end)
it('defaults in vimdoc/highlights.scm', function()
@@ -918,13 +921,18 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.start()
end)
+ screen:add_extra_attr_ids({
+ [100] = { nocombine = true, underdouble = true },
+ [101] = { foreground = Screen.colors.Fuchsia, bold = true },
+ [102] = { underline = true, nocombine = true },
+ })
screen:expect({
grid = [[
- {h1_delim:^========================================}|
- {title:NVIM DOCUMENTATION} |
+ {100:^========================================}|
+ {101:NVIM DOCUMENTATION} |
|
- {h2_delim:----------------------------------------}|
- {title:ABOUT NVIM} |
+ {102:----------------------------------------}|
+ {101:ABOUT NVIM} |
|
]],
})
@@ -943,42 +951,42 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.start()
end)
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:ruby} |
- {1: -- comment} |
- {1: local this_is = 'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:ruby} |
+ {18: -- comment} |
+ {18: local this_is = 'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
n.api.nvim_buf_set_text(0, 0, 1, 0, 5, { 'lua' })
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:lua} |
- {1: -- comment} |
- {1: }{3:local}{1: }{4:this_is}{1: }{3:=}{1: }{5:'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:lua} |
+ {18: -- comment} |
+ {18: }{15:local}{18: }{25:this_is}{18: }{15:=}{18: }{26:'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
n.api.nvim_buf_set_text(0, 0, 1, 0, 4, { 'ruby' })
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:ruby} |
- {1: -- comment} |
- {1: local this_is = 'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:ruby} |
+ {18: -- comment} |
+ {18: local this_is = 'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
end)
it('correctly redraws injections subpriorities', function()
@@ -1003,16 +1011,16 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.highlighter.new(parser)
end)
- screen:expect {
+ screen:expect({
grid = [=[
- {3:local} {4:s} {3:=} {5:[[} |
- {5: }{3:local}{5: }{4:also}{5: }{3:=}{5: }{4:lua} |
- {5:]]} |
- ^ |
- {2:~ }|
- |
- ]=],
- }
+ {15:local} {25:s} {15:=} {26:[[} |
+ {26: }{15:local}{26: }{25:also}{26: }{15:=}{26: }{25:lua} |
+ {26:]]} |
+ ^ |
+ {1:~ }|
+ |
+ ]=],
+ })
end)
end)
@@ -1022,12 +1030,6 @@ describe('treesitter highlighting (nested injections)', function()
before_each(function()
clear()
screen = Screen.new(80, 7)
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.SlateBlue },
- [2] = { bold = true, foreground = Screen.colors.Brown },
- [3] = { foreground = Screen.colors.Cyan4 },
- [4] = { foreground = Screen.colors.Fuchsia },
- }
end)
it('correctly redraws nested injections (GitHub #25252)', function()
@@ -1054,32 +1056,32 @@ vim.cmd([[
-- invalidate the language tree
feed('ggi--[[<ESC>04x')
- screen:expect {
+ screen:expect({
grid = [[
- {2:^function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} |
- |
- {2:local} {3:lorem} {2:=} {1:{} |
- {3:ipsum} {2:=} {1:{},} |
- {3:bar} {2:=} {1:{},} |
- {1:}} |
- |
- ]],
- }
+ {15:^function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
+ |
+ {15:local} {25:lorem} {15:=} {16:{} |
+ {25:ipsum} {15:=} {16:{},} |
+ {25:bar} {15:=} {16:{},} |
+ {16:}} |
+ |
+ ]],
+ })
-- spam newline insert/delete to invalidate Lua > Vim > Lua region
feed('3jo<ESC>ddko<ESC>ddko<ESC>ddko<ESC>ddk0')
- screen:expect {
+ screen:expect({
grid = [[
- {2:function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} |
- |
- {2:local} {3:lorem} {2:=} {1:{} |
- ^ {3:ipsum} {2:=} {1:{},} |
- {3:bar} {2:=} {1:{},} |
- {1:}} |
- |
- ]],
- }
+ {15:function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
+ |
+ {15:local} {25:lorem} {15:=} {16:{} |
+ ^ {25:ipsum} {15:=} {16:{},} |
+ {25:bar} {15:=} {16:{},} |
+ {16:}} |
+ |
+ ]],
+ })
end)
end)
@@ -1156,20 +1158,6 @@ it('starting and stopping treesitter highlight in init.lua works #29541', functi
eq('', api.nvim_get_vvar('errmsg'))
local screen = Screen.new(65, 18)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { foreground = Screen.colors.Blue1 },
- [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [4] = { bold = true, foreground = Screen.colors.Brown },
- [5] = { foreground = Screen.colors.Magenta },
- [6] = { foreground = Screen.colors.Red },
- [7] = { bold = true, foreground = Screen.colors.SlateBlue },
- [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red },
- [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red },
- [11] = { foreground = Screen.colors.Cyan4 },
- }
-
fn.setreg('r', hl_text_c)
feed('i<C-R><C-O>r<Esc>gg')
-- legacy syntax highlighting is used
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 2f8d204d36..2f80cee226 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -1,5 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
+local ts_t = require('test.functional.treesitter.testutil')
local clear = n.clear
local dedent = t.dedent
@@ -8,6 +9,7 @@ local insert = n.insert
local exec_lua = n.exec_lua
local pcall_err = t.pcall_err
local feed = n.feed
+local run_query = ts_t.run_query
describe('treesitter parser API', function()
before_each(function()
@@ -644,6 +646,109 @@ print()
end)
end)
+ describe('trim! directive', function()
+ it('can trim all whitespace', function()
+ -- luacheck: push ignore 611 613
+ insert([=[
+ print([[
+
+ f
+ helllo
+ there
+ asdf
+ asdfassd
+
+
+
+ ]])
+ print([[
+
+
+
+ ]])
+
+ print([[]])
+
+ print([[
+ ]])
+
+ print([[ hello 😃 ]])
+ ]=])
+ -- luacheck: pop
+
+ local query_text = [[
+ ; query
+ ((string_content) @str
+ (#trim! @str 1 1 1 1))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'lua')
+ end)
+
+ eq({
+ { 'str', { 2, 12, 6, 10 } },
+ { 'str', { 11, 10, 11, 10 } },
+ { 'str', { 17, 10, 17, 10 } },
+ { 'str', { 19, 10, 19, 10 } },
+ { 'str', { 22, 15, 22, 25 } },
+ }, run_query('lua', query_text))
+ end)
+
+ it('trims only empty lines by default (backwards compatible)', function()
+ insert(dedent [[
+ ## Heading
+
+ With some text
+
+ ## And another
+
+ With some more here]])
+
+ local query_text = [[
+ ; query
+ ((section) @fold
+ (#trim! @fold))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'markdown')
+ end)
+
+ eq({
+ { 'fold', { 0, 0, 2, 14 } },
+ { 'fold', { 4, 0, 6, 19 } },
+ }, run_query('markdown', query_text))
+ end)
+
+ it('can trim lines', function()
+ insert(dedent [[
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ ]])
+
+ local query_text = [[
+ ; query
+ ((list_item
+ (list)) @fold
+ (#trim! @fold 1 1 1 1))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'markdown')
+ end)
+
+ eq({
+ { 'fold', { 0, 0, 4, 13 } },
+ { 'fold', { 1, 2, 3, 15 } },
+ }, run_query('markdown', query_text))
+ end)
+ end)
+
it('tracks the root range properly (#22911)', function()
insert([[
int main() {
@@ -659,32 +764,19 @@ print()
vim.treesitter.start(0, 'c')
end)
- local function run_query()
- return exec_lua(function()
- local query = vim.treesitter.query.parse('c', query0)
- local parser = vim.treesitter.get_parser()
- local tree = parser:parse()[1]
- local res = {}
- for id, node in query:iter_captures(tree:root()) do
- table.insert(res, { query.captures[id], node:range() })
- end
- return res
- end)
- end
-
eq({
- { 'function', 0, 0, 2, 1 },
- { 'declaration', 1, 2, 1, 12 },
- }, run_query())
+ { 'function', { 0, 0, 2, 1 } },
+ { 'declaration', { 1, 2, 1, 12 } },
+ }, run_query('c', query0))
n.command 'normal ggO'
insert('int a;')
eq({
- { 'declaration', 0, 0, 0, 6 },
- { 'function', 1, 0, 3, 1 },
- { 'declaration', 2, 2, 2, 12 },
- }, run_query())
+ { 'declaration', { 0, 0, 0, 6 } },
+ { 'function', { 1, 0, 3, 1 } },
+ { 'declaration', { 2, 2, 2, 12 } },
+ }, run_query('c', query0))
end)
it('handles ranges when source is a multiline string (#20419)', function()
diff --git a/test/functional/treesitter/testutil.lua b/test/functional/treesitter/testutil.lua
new file mode 100644
index 0000000000..f8934f06c3
--- /dev/null
+++ b/test/functional/treesitter/testutil.lua
@@ -0,0 +1,25 @@
+local n = require('test.functional.testnvim')()
+
+local exec_lua = n.exec_lua
+
+local M = {}
+
+---@param language string
+---@param query_string string
+function M.run_query(language, query_string)
+ return exec_lua(function(lang, query_str)
+ local query = vim.treesitter.query.parse(lang, query_str)
+ local parser = vim.treesitter.get_parser()
+ local tree = parser:parse()[1]
+ local res = {}
+ for id, node, metadata in query:iter_captures(tree:root(), 0) do
+ table.insert(
+ res,
+ { query.captures[id], metadata[id] and metadata[id].range or { node:range() } }
+ )
+ end
+ return res
+ end, language, query_string)
+end
+
+return M
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index d7c0657820..edf826a1d9 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -361,4 +361,38 @@ describe('ui/cursor', function()
end
end)
end)
+
+ it(':sleep does not hide cursor when sleeping', function()
+ n.feed(':sleep 100m | echo 42\n')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*3
+ :sleep 100m | echo 42 |
+ ]],
+ timeout = 100,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ 42 |
+ ]])
+ end)
+
+ it(':sleep! hides cursor when sleeping', function()
+ n.feed(':sleep! 100m | echo 42\n')
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }|*3
+ :sleep! 100m | echo 42 |
+ ]],
+ timeout = 100,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ 42 |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 8e15e6c35f..f5cb914299 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -37,10 +37,10 @@
-- Tests will often share a group of extra attribute sets to expect(). Those can be
-- defined at the beginning of a test:
--
--- screen:add_extra_attr_ids {
+-- screen:add_extra_attr_ids({
-- [100] = { background = Screen.colors.Plum1, underline = true },
-- [101] = { background = Screen.colors.Red1, bold = true, underline = true },
--- }
+-- })
--
-- To help write screen tests, see Screen:snapshot_util().
-- To debug screen tests, see Screen:redraw_debug().
@@ -454,7 +454,7 @@ end
--- screen:expect(grid, [attr_ids])
--- screen:expect(condition)
--- or keyword args (supports more options):
---- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
+--- screen:expect({ grid=[[...]], cmdline={...}, condition=function() ... end })
---
--- @param expected string|function|test.function.ui.screen.Expect
--- @param attr_ids? table<integer,table<string,any>>
@@ -1713,21 +1713,24 @@ function Screen:_print_snapshot()
end
end
local fn_name = modify_attrs and 'add_extra_attr_ids' or 'set_default_attr_ids'
- attrstr = ('screen:' .. fn_name .. ' {\n' .. table.concat(attrstrs, '\n') .. '\n}\n\n')
+ attrstr = ('screen:' .. fn_name .. '({\n' .. table.concat(attrstrs, '\n') .. '\n})\n\n')
end
- local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format(
- attrstr,
- kwargs.grid:gsub('\n', '\n ')
- )
+ local extstr = ''
for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then
- result = result .. ', ' .. k .. '=' .. fmt_ext_state(k, ext_state[k])
+ extstr = extstr .. '\n ' .. k .. ' = ' .. fmt_ext_state(k, ext_state[k]) .. ','
end
end
- result = result .. '\n})'
- return result
+ return ('%sscreen:expect(%s%s%s%s%s'):format(
+ attrstr,
+ #extstr > 0 and '{\n grid = [[\n ' or '[[\n',
+ #extstr > 0 and kwargs.grid:gsub('\n', '\n ') or kwargs.grid,
+ #extstr > 0 and '\n ]],' or '\n]]',
+ extstr,
+ #extstr > 0 and '\n})' or ')'
+ )
end
function Screen:print_snapshot()
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index f39e9ecc33..666d98c3b2 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -645,6 +645,59 @@ local function screen_tests(linegrid)
|
]])
end)
+
+ it('clamps &cmdheight for current tabpage', function()
+ command('set cmdheight=10 laststatus=2')
+ screen:expect([[
+ ^ |
+ {0:~ }|*2
+ {1:[No Name] }|
+ |*10
+ ]])
+ screen:try_resize(53, 8)
+ screen:expect([[
+ ^ |
+ {1:[No Name] }|
+ |*6
+ ]])
+ eq(6, api.nvim_get_option_value('cmdheight', {}))
+ end)
+
+ it('clamps &cmdheight for another tabpage #31380', function()
+ command('tabnew')
+ command('set cmdheight=9 laststatus=2')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*2
+ {1:[No Name] }|
+ |*9
+ ]])
+ command('tabprev')
+ screen:expect([[
+ {2: [No Name] }{4: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*10
+ {1:[No Name] }|
+ |
+ ]])
+ screen:try_resize(53, 8)
+ screen:expect([[
+ {2: [No Name] }{4: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*4
+ {1:[No Name] }|
+ |
+ ]])
+ command('tabnext')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {1:[No Name] }|
+ |*5
+ ]])
+ eq(5, api.nvim_get_option_value('cmdheight', {}))
+ end)
end)
describe('press enter', function()
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 7874c04c39..b7a2429ada 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -607,4 +607,77 @@ describe('Signs', function()
eq(6, infos[1].textoff)
eq(6, infos[2].textoff)
end)
+
+ it('auto width updated in all windows after sign placed in on_win #31438', function()
+ exec_lua([[
+ vim.cmd.call('setline(1, range(1, 500))')
+ vim.cmd('wincmd s | wincmd v | wincmd j | wincmd v')
+
+ _G.log, _G.needs_clear = {}, false
+ local ns_id, mark_id = vim.api.nvim_create_namespace('test'), nil
+
+ -- Add decoration which possibly clears all extmarks and adds one on line 499
+ local on_win = function(_, winid, bufnr, toprow, botrow)
+ if _G.needs_clear then
+ vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
+ _G.needs_clear = false
+ end
+
+ if toprow < 499 and 499 <= botrow then
+ mark_id = vim.api.nvim_buf_set_extmark(bufnr, ns_id, 499, 0, { id = mark_id, sign_text = '!', invalidate = true })
+ end
+ end
+ vim.api.nvim_set_decoration_provider(ns_id, { on_win = on_win })
+ ]])
+ screen:expect([[
+ 1 │1 |
+ 2 │2 |
+ 3 │3 |
+ 4 │4 |
+ 5 │5 |
+ 6 │6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ ^1 │1 |
+ 2 │2 |
+ 3 │3 |
+ 4 │4 |
+ 5 │5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('G')
+ screen:expect([[
+ {7: }1 │{7: }1 |
+ {7: }2 │{7: }2 |
+ {7: }3 │{7: }3 |
+ {7: }4 │{7: }4 |
+ {7: }5 │{7: }5 |
+ {7: }6 │{7: }6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ {7: }496 │{7: }1 |
+ {7: }497 │{7: }2 |
+ {7: }498 │{7: }3 |
+ {7: }499 │{7: }4 |
+ ! ^500 │{7: }5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed(':lua log, needs_clear = {}, true<CR>')
+ screen:expect([[
+ {7: }1 │{7: }1 |
+ {7: }2 │{7: }2 |
+ {7: }3 │{7: }3 |
+ {7: }4 │{7: }4 |
+ {7: }5 │{7: }5 |
+ {7: }6 │{7: }6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ {7: }496 │{7: }1 |
+ {7: }497 │{7: }2 |
+ {7: }498 │{7: }3 |
+ {7: }499 │{7: }4 |
+ ! ^500 │{7: }5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ :lua log, needs_clear = {}, true |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
index 66eb15478b..aa9ac3f5b5 100644
--- a/test/functional/ui/title_spec.lua
+++ b/test/functional/ui/title_spec.lua
@@ -37,6 +37,63 @@ describe('title', function()
end)
end)
+ it('is updated in Insert mode', function()
+ api.nvim_set_option_value('title', true, {})
+ screen:expect(function()
+ eq('[No Name] - Nvim', screen.title)
+ end)
+ feed('ifoo')
+ screen:expect(function()
+ eq('[No Name] + - Nvim', screen.title)
+ end)
+ feed('<Esc>')
+ api.nvim_set_option_value('titlestring', '%m %f (%{mode(1)}) | nvim', {})
+ screen:expect(function()
+ eq('[+] [No Name] (n) | nvim', screen.title)
+ end)
+ feed('i')
+ screen:expect(function()
+ eq('[+] [No Name] (i) | nvim', screen.title)
+ end)
+ feed('<Esc>')
+ screen:expect(function()
+ eq('[+] [No Name] (n) | nvim', screen.title)
+ end)
+ end)
+
+ it('is updated in Cmdline mode', function()
+ api.nvim_set_option_value('title', true, {})
+ api.nvim_set_option_value('titlestring', '%f (%{mode(1)}) | nvim', {})
+ screen:expect(function()
+ eq('[No Name] (n) | nvim', screen.title)
+ end)
+ feed(':')
+ screen:expect(function()
+ eq('[No Name] (c) | nvim', screen.title)
+ end)
+ feed('<Esc>')
+ screen:expect(function()
+ eq('[No Name] (n) | nvim', screen.title)
+ end)
+ end)
+
+ it('is updated in Terminal mode', function()
+ api.nvim_set_option_value('title', true, {})
+ api.nvim_set_option_value('titlestring', '(%{mode(1)}) | nvim', {})
+ fn.termopen({ n.testprg('shell-test'), 'INTERACT' })
+ screen:expect(function()
+ eq('(nt) | nvim', screen.title)
+ end)
+ feed('i')
+ screen:expect(function()
+ eq('(t) | nvim', screen.title)
+ end)
+ feed([[<C-\><C-N>]])
+ screen:expect(function()
+ eq('(nt) | nvim', screen.title)
+ end)
+ end)
+
describe('is not changed by', function()
local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
diff --git a/test/old/testdir/gen_opt_test.vim b/test/old/testdir/gen_opt_test.vim
index be5a7e6ee4..a2ad1eb8b4 100644
--- a/test/old/testdir/gen_opt_test.vim
+++ b/test/old/testdir/gen_opt_test.vim
@@ -117,7 +117,6 @@ let test_values = {
"\ 'imstyle': [[0, 1], [-1, 2, 999]],
\ 'lines': [[2, 24, 1000], [-1, 0, 1]],
\ 'linespace': [[-1, 0, 2, 4, 999], ['']],
- \ 'msghistory': [[0, 1, 100, 10000], [-1, 10001]],
\ 'numberwidth': [[1, 4, 8, 10, 11, 20], [-1, 0, 21]],
\ 'regexpengine': [[0, 1, 2], [-1, 3, 999]],
\ 'report': [[0, 1, 2, 9999], [-1]],
@@ -264,6 +263,14 @@ let test_values = {
\ 'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'],
\ ['xxx', 'eol:']],
\ 'matchpairs': [['', '(:)', '(:),<:>'], ['xxx']],
+ \ 'messagesopt': [['hit-enter,history:1', 'hit-enter,history:10000',
+ \ 'history:100,wait:100', 'history:0,wait:0',
+ \ 'hit-enter,history:1,wait:1'],
+ \ ['xxx', 'history:500', 'hit-enter,history:-1',
+ \ 'hit-enter,history:10001', 'history:0,wait:10001',
+ \ 'hit-enter', 'history:10,wait:99999999999999999999',
+ \ 'history:99999999999999999999,wait:10', 'wait:10',
+ \ 'history:-10', 'history:10,wait:-10']],
\ 'mkspellmem': [['10000,100,12'], ['', 'xxx', '10000,100']],
\ 'mouse': [['', 'n', 'v', 'i', 'c', 'h', 'a', 'r', 'nvi'],
\ ['xxx', 'n,v,i']],
diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim
index 058635c332..3d210695c4 100644
--- a/test/old/testdir/runtest.vim
+++ b/test/old/testdir/runtest.vim
@@ -55,6 +55,10 @@ silent! endwhile
" In the GUI we can always change the screen size.
if has('gui_running')
+ if has('gui_gtk')
+ " to keep screendump size unchanged
+ set guifont=Monospace\ 10
+ endif
set columns=80 lines=25
endif
diff --git a/test/old/testdir/setup.vim b/test/old/testdir/setup.vim
index e7b4bb1a88..b104d733f0 100644
--- a/test/old/testdir/setup.vim
+++ b/test/old/testdir/setup.vim
@@ -1,6 +1,5 @@
if exists('s:did_load')
" Align Nvim defaults to Vim.
- set backspace=
set commentstring=/*\ %s\ */
set complete=.,w,b,u,t,i
set define=^\\s*#\\s*define
diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim
index 64599c869a..40c09e61ac 100644
--- a/test/old/testdir/test_autocmd.vim
+++ b/test/old/testdir/test_autocmd.vim
@@ -1198,8 +1198,8 @@ func Test_OptionSet()
call assert_equal(g:opt[0], g:opt[1])
" 14: Setting option backspace through :let"
- let g:options = [['backspace', '', '', '', 'eol,indent,start', 'global', 'set']]
- let &bs = "eol,indent,start"
+ let g:options = [['backspace', 'indent,eol,start', 'indent,eol,start', 'indent,eol,start', '', 'global', 'set']]
+ let &bs = ''
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim
index 2f34ecb414..cbce0e908d 100644
--- a/test/old/testdir/test_cmdline.vim
+++ b/test/old/testdir/test_cmdline.vim
@@ -4181,30 +4181,4 @@ func Test_cd_bslash_completion_windows()
let &shellslash = save_shellslash
endfunc
-func Test_msghistory()
- " After setting 'msghistory' to 2 and outputting a message 4 times with
- " :echomsg, is the number of output lines of :messages 2?
- set msghistory=2
- echomsg 'foo'
- echomsg 'bar'
- echomsg 'baz'
- echomsg 'foobar'
- call assert_equal(['baz', 'foobar'], GetMessages())
-
- " When the number of messages is 10 and 'msghistory' is changed to 5, is the
- " number of output lines of :messages 5?
- set msghistory=10
- for num in range(1, 10)
- echomsg num
- endfor
- set msghistory=5
- call assert_equal(5, len(GetMessages()))
-
- " Check empty list
- set msghistory=0
- call assert_true(empty(GetMessages()))
-
- set msghistory&
-endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_compiler.vim b/test/old/testdir/test_compiler.vim
index 07b57b76d9..3ad6b365de 100644
--- a/test/old/testdir/test_compiler.vim
+++ b/test/old/testdir/test_compiler.vim
@@ -65,10 +65,10 @@ func Test_compiler_completion()
call assert_match('^"compiler ' .. clist .. '$', @:)
call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('"compiler pandoc pbx perl\( p[a-z_]\+\)\+ pylint pyunit', @:)
+ call assert_match('"compiler pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
call feedkeys(":compiler! p\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('"compiler! pandoc pbx perl\( p[a-z_]\+\)\+ pylint pyunit', @:)
+ call assert_match('"compiler! pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
endfunc
func Test_compiler_error()
@@ -78,3 +78,197 @@ func Test_compiler_error()
call assert_fails('compiler! doesnotexist', 'E666:')
unlet! g:current_compiler
endfunc
+
+func s:SpotBugsParseFilterMakePrg(dirname, makeprg)
+ let result = {}
+ let result.sourcepath = ''
+ let result.classfiles = []
+
+ " Get the argument after the rightmost occurrence of "-sourcepath".
+ let offset = strridx(a:makeprg, '-sourcepath')
+ if offset < 0
+ return result
+ endif
+ let offset += 1 + strlen('-sourcepath')
+ let result.sourcepath = matchstr(strpart(a:makeprg, offset), '.\{-}\ze[ \t]')
+
+ " Get the class file arguments, dropping the pathname prefix.
+ let offset = stridx(a:makeprg, a:dirname, offset)
+ if offset < 0
+ return result
+ endif
+
+ while offset > -1
+ let candidate = matchstr(a:makeprg, '[^ \t]\{-}\.class\>', offset)
+ if empty(candidate)
+ break
+ endif
+ call add(result.classfiles, candidate)
+ let offset = stridx(a:makeprg, a:dirname, (1 + strlen(candidate) + offset))
+ endwhile
+
+ call sort(result.classfiles)
+ return result
+endfunc
+
+func Test_compiler_spotbugs_makeprg()
+ let save_shellslash = &shellslash
+ set shellslash
+
+ call assert_true(mkdir('Xspotbugs/src/tests/α/β/γ/δ', 'pR'))
+ call assert_true(mkdir('Xspotbugs/tests/α/β/γ/δ', 'pR'))
+
+ let lines =<< trim END
+ // EOL comment. /*
+ abstract class
+ 𐌂1 /* Multiline comment. */ {
+ /* Multiline comment. */ // EOL comment. /*
+ static final String COMMENT_A_LIKE = "/*";
+ { new Object() {/* Try globbing. */}; }
+ static { interface 𐌉𐌉1 {} }
+ static class 𐌂11 { interface 𐌉𐌉2 {} }
+ }
+ /* Multiline comment. */ // EOL comment. /*
+ final class 𐌂2 {
+ public static void main(String... aa) {
+ record 𐌓() {}
+ enum 𐌄 {}
+ }
+ } // class
+ END
+
+ " THE EXPECTED RESULTS.
+ let results = {}
+ let results['Xspotbugs/src/tests/𐌂1.java'] = {
+ \ 'sourcepath': '%:p:h:S',
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/𐌂1$1.class',
+ \ 'Xspotbugs/tests/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/𐌂1.class',
+ \ 'Xspotbugs/tests/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/𐌂2.class']),
+ \ }
+ " No class file for an empty source file even with "-Xpkginfo:always".
+ let results['Xspotbugs/src/tests/package-info.java'] = {
+ \ 'sourcepath': '',
+ \ 'classfiles': [],
+ \ }
+ let results['Xspotbugs/src/tests/α/𐌂1.java'] = {
+ \ 'sourcepath': '%:p:h:h:S',
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/𐌂1.class',
+ \ 'Xspotbugs/tests/α/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/package-info.java'] = {
+ \ 'sourcepath': '%:p:h:S',
+ \ 'classfiles': ['Xspotbugs/tests/α/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/𐌂1.java'] = {
+ \ 'sourcepath': '%:p:h:h:h:S',
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/package-info.java'] = {
+ \ 'sourcepath': '%:p:h:S',
+ \ 'classfiles': ['Xspotbugs/tests/α/β/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/𐌂1.java'] = {
+ \ 'sourcepath': '%:p:h:h:h:h:S',
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/package-info.java'] = {
+ \ 'sourcepath': '%:p:h:S',
+ \ 'classfiles': ['Xspotbugs/tests/α/β/γ/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/δ/𐌂1.java'] = {
+ \ 'sourcepath': '%:p:h:h:h:h:h:S',
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/δ/package-info.java'] = {
+ \ 'sourcepath': '%:p:h:S',
+ \ 'classfiles': ['Xspotbugs/tests/α/β/γ/δ/package-info.class'],
+ \ }
+
+ " MAKE CLASS FILES DISCOVERABLE!
+ let g:spotbugs_properties = {
+ \ 'sourceDirPath': 'src/tests',
+ \ 'classDirPath': 'tests',
+ \ }
+
+ call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'sourcepath'))
+ call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'classfiles'))
+
+ " Write 45 mock-up class files for 10 source files.
+ for [class_dir, src_dir, package] in [
+ \ ['Xspotbugs/tests/', 'Xspotbugs/src/tests/', ''],
+ \ ['Xspotbugs/tests/α/', 'Xspotbugs/src/tests/α/', 'package α;'],
+ \ ['Xspotbugs/tests/α/β/', 'Xspotbugs/src/tests/α/β/', 'package α.β;'],
+ \ ['Xspotbugs/tests/α/β/γ/', 'Xspotbugs/src/tests/α/β/γ/', 'package α.β.γ;'],
+ \ ['Xspotbugs/tests/α/β/γ/δ/', 'Xspotbugs/src/tests/α/β/γ/δ/', 'package α.β.γ.δ;']]
+ for class_file in ['𐌂1$1.class', '𐌂1$1𐌉𐌉1.class', '𐌂1$𐌂11$𐌉𐌉2.class',
+ \ '𐌂1$𐌂11.class', '𐌂1.class', '𐌂2$1𐌄.class', '𐌂2$1𐌓.class', '𐌂2.class']
+ call writefile(0zcafe.babe.0000.0041, class_dir .. class_file)
+ endfor
+ call writefile(0zcafe.babe.0000.0041, class_dir .. 'package-info.class')
+
+ " Write Java source files.
+ let type_file = src_dir .. '𐌂1.java'
+ call writefile(insert(copy(lines), package), type_file)
+ let package_file = src_dir .. 'package-info.java'
+ call writefile([package], src_dir .. 'package-info.java')
+
+ for s in ['on', 'off']
+ execute 'syntax ' .. s
+
+ execute 'edit ' .. type_file
+ compiler spotbugs
+ let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
+ call assert_equal(results[type_file].sourcepath, result.sourcepath)
+ call assert_equal(results[type_file].classfiles, result.classfiles)
+ bwipeout
+
+ execute 'edit ' .. package_file
+ compiler spotbugs
+ let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
+ call assert_equal(results[package_file].sourcepath, result.sourcepath)
+ call assert_equal(results[package_file].classfiles, result.classfiles)
+ bwipeout
+ endfor
+ endfor
+
+ let &shellslash = save_shellslash
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_digraph.vim b/test/old/testdir/test_digraph.vim
index 8fbcd4d8ca..9c32b85f61 100644
--- a/test/old/testdir/test_digraph.vim
+++ b/test/old/testdir/test_digraph.vim
@@ -250,9 +250,12 @@ func Test_digraphs_option()
call Put_Dig_BS("P","=")
call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
" Not a digraph: this is different from <c-k>!
+ let _bs = &bs
+ set bs=
call Put_Dig_BS("a","\<bs>")
call Put_Dig_BS("\<bs>","a")
call assert_equal(['','a'], getline(line('.')-1,line('.')))
+ let &bs = _bs
" Grave
call Put_Dig_BS("a","!")
call Put_Dig_BS("!","e")
@@ -604,8 +607,10 @@ func Test_digraph_getlist_function()
" of digraphs returned.
call assert_equal(digraph_getlist()->len(), digraph_getlist(0)->len())
call assert_notequal(digraph_getlist()->len(), digraph_getlist(1)->len())
+ call assert_equal(digraph_getlist()->len(), digraph_getlist(v:false)->len())
+ call assert_notequal(digraph_getlist()->len(), digraph_getlist(v:true)->len())
- call assert_fails('call digraph_getlist(0z12)', 'E974: Using a Blob as a Number')
+ call assert_fails('call digraph_getlist(0z12)', 'E1212: Bool required for argument 1')
endfunc
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index 58064ea412..7e6a6dfac5 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -605,12 +605,13 @@ func s:GetFilenameChecks() abort
\ 'ps1xml': ['file.ps1xml'],
\ 'psf': ['file.psf'],
\ 'psl': ['file.psl'],
+ \ 'ptx': ['file.ptx'],
\ 'pug': ['file.pug'],
\ 'puppet': ['file.pp'],
\ 'purescript': ['file.purs'],
\ 'pymanifest': ['MANIFEST.in'],
\ 'pyret': ['file.arr'],
- \ 'pyrex': ['file.pyx', 'file.pxd'],
+ \ 'pyrex': ['file.pyx', 'file.pxd', 'file.pxi', 'file.pyx+'],
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', '.python_history', '.jline-jython.history', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'ql': ['file.ql', 'file.qll'],
\ 'qml': ['file.qml', 'file.qbs'],
@@ -886,7 +887,7 @@ func s:GetFilenameChecks() abort
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
\ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock',
- \ '/home/user/.kube/config'],
+ \ '/home/user/.kube/config', '.condarc', 'condarc'],
\ 'yang': ['file.yang'],
\ 'yuck': ['file.yuck'],
\ 'z8a': ['file.z8a'],
diff --git a/test/old/testdir/test_highlight.vim b/test/old/testdir/test_highlight.vim
index 0a64c63d30..56c7a9656f 100644
--- a/test/old/testdir/test_highlight.vim
+++ b/test/old/testdir/test_highlight.vim
@@ -785,8 +785,8 @@ func Test_1_highlight_Normalgroup_exists()
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)
+ " expect is DEFAULT_FONT of gui_gtk_x11.c (any size)
+ call assert_match('hi Normal\s*font=Monospace\>', hlNormal)
elseif has('gui_motif')
" expect is DEFAULT_FONT of gui_x11.c
call assert_match('hi Normal\s*font=7x13', hlNormal)
diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim
index dcacc11663..0998b04443 100644
--- a/test/old/testdir/test_indent.vim
+++ b/test/old/testdir/test_indent.vim
@@ -276,4 +276,31 @@ func Test_formatting_keeps_first_line_indent()
bwipe!
endfunc
+" Test for indenting with large amount, causes overflow
+func Test_indent_overflow_count()
+ throw 'skipped: TODO: '
+ new
+ setl sw=8
+ call setline(1, "abc")
+ norm! V2147483647>
+ " indents by INT_MAX
+ call assert_equal(2147483647, indent(1))
+ close!
+endfunc
+
+func Test_indent_overflow_count2()
+ throw 'skipped: Nvim does not support 64-bit number options'
+ new
+ " this only works, when long is 64bits
+ try
+ setl sw=0x180000000
+ catch /^Vim\%((\a\+)\)\=:E487:/
+ throw 'Skipped: value negative on this platform'
+ endtry
+ call setline(1, "\tabc")
+ norm! <<
+ call assert_equal(0, indent(1))
+ close!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index c02aa1db62..bf7477f088 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -253,6 +253,91 @@ func Test_CompleteDoneNone()
au! CompleteDone
endfunc
+func Test_CompleteDone_vevent_keys()
+ func OnDone()
+ let g:complete_word = get(v:event, 'complete_word', v:null)
+ let g:complete_type = get(v:event, 'complete_type', v:null)
+ endfunction
+
+ autocmd CompleteDone * :call OnDone()
+
+ func CompleteFunc(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}]
+ endfunc
+ set omnifunc=CompleteFunc
+ set completefunc=CompleteFunc
+ set completeopt+=menuone
+
+ new
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-N>\<C-Y>\<Esc>0", 'tx')
+ call assert_equal('bar', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<ESC>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim\<CR>completion test\<CR>\<C-X>\<C-l>\<C-Y>", 'tx')
+ call assert_equal('completion test', g:complete_word)
+ call assert_equal('whole_line', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-U>\<C-Y>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('function', g:complete_type)
+
+ inoremap <buffer> <f3> <cmd>call complete(1, ["red", "blue"])<cr>
+ call feedkeys("S\<f3>\<C-Y>", 'tx')
+ call assert_equal('red', g:complete_word)
+ call assert_equal('eval', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-V>\<C-Y>", 'tx')
+ call assert_equal('!', g:complete_word)
+ call assert_equal('cmdline', g:complete_type)
+
+ call writefile([''], 'foo_test', 'D')
+ call feedkeys("Sfoo\<C-X>\<C-F>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo_test', g:complete_word)
+ call assert_equal('files', g:complete_type)
+
+ call writefile(['hello help'], 'test_case.txt', 'D')
+ set dictionary=test_case.txt
+ call feedkeys("ggdGSh\<C-X>\<C-K>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('hello', g:complete_word)
+ call assert_equal('dictionary', g:complete_type)
+
+ set spell spelllang=en_us
+ call feedkeys("STheatre\<C-X>s\<C-Y>\<Esc>", 'tx')
+ call assert_equal('Theater', g:complete_word)
+ call assert_equal('spell', g:complete_type)
+
+ bwipe!
+ set completeopt& omnifunc& completefunc& spell& spelllang& dictionary&
+ autocmd! CompleteDone
+ delfunc OnDone
+ delfunc CompleteFunc
+ unlet g:complete_word
+ unlet g:complete_type
+endfunc
+
func Test_CompleteDoneDict()
au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1)
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0)
@@ -1509,7 +1594,7 @@ func Test_complete_item_refresh_always()
set completefunc=Tcomplete
exe "normal! iup\<C-X>\<C-U>\<BS>\<BS>\<BS>\<BS>\<BS>"
call assert_equal('up', getline(1))
- call assert_equal(2, g:CallCount)
+ call assert_equal(6, g:CallCount)
set completeopt&
set completefunc&
bw!
diff --git a/test/old/testdir/test_messages.vim b/test/old/testdir/test_messages.vim
index ac5184645f..bfead20142 100644
--- a/test/old/testdir/test_messages.vim
+++ b/test/old/testdir/test_messages.vim
@@ -216,6 +216,7 @@ endfunc
" Test more-prompt (see :help more-prompt).
func Test_message_more()
CheckRunVimInTerminal
+
let buf = RunVimInTerminal('', {'rows': 6})
call term_sendkeys(buf, ":call setline(1, range(1, 100))\n")
@@ -611,4 +612,50 @@ func Test_cmdheight_zero()
tabonly
endfunc
+func Test_messagesopt_history()
+ " After setting 'messagesopt' "history" to 2 and outputting a message 4 times
+ " with :echomsg, is the number of output lines of :messages 2?
+ set messagesopt=hit-enter,history:2
+ echomsg 'foo'
+ echomsg 'bar'
+ echomsg 'baz'
+ echomsg 'foobar'
+ call assert_equal(['baz', 'foobar'], GetMessages())
+
+ " When the number of messages is 10 and 'messagesopt' "history" is changed to
+ " 5, is the number of output lines of :messages 5?
+ set messagesopt=hit-enter,history:10
+ for num in range(1, 10)
+ echomsg num
+ endfor
+ set messagesopt=hit-enter,history:5
+ call assert_equal(5, len(GetMessages()))
+
+ " Check empty list
+ set messagesopt=hit-enter,history:0
+ call assert_true(empty(GetMessages()))
+
+ set messagesopt&
+endfunc
+
+func Test_messagesopt_wait()
+ CheckRunVimInTerminal
+
+ let buf = RunVimInTerminal('', {'rows': 6, 'cols': 45})
+ call term_sendkeys(buf, ":set cmdheight=1\n")
+
+ " Check hit-enter prompt
+ call term_sendkeys(buf, ":set messagesopt=hit-enter,history:500\n")
+ call term_sendkeys(buf, ":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
+ " Check no hit-enter prompt when "wait:" is set
+ call term_sendkeys(buf, ":set messagesopt=wait:100,history:500\n")
+ call term_sendkeys(buf, ":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ call WaitForAssert({-> assert_equal(' 0,0-1 All', term_getline(buf, 6))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim
index b6bdb1be52..d090186b62 100644
--- a/test/old/testdir/test_options.vim
+++ b/test/old/testdir/test_options.vim
@@ -496,7 +496,7 @@ func Test_set_completion_string_values()
" but don't exhaustively validate their results.
call assert_equal('single', getcompletion('set ambw=', 'cmdline')[0])
call assert_match('light\|dark', getcompletion('set bg=', 'cmdline')[1])
- call assert_equal('indent', getcompletion('set backspace=', 'cmdline')[0])
+ call assert_equal('indent,eol,start', getcompletion('set backspace=', 'cmdline')[0])
call assert_equal('yes', getcompletion('set backupcopy=', 'cmdline')[1])
call assert_equal('backspace', getcompletion('set belloff=', 'cmdline')[1])
call assert_equal('min:', getcompletion('set briopt=', 'cmdline')[1])
@@ -644,6 +644,10 @@ func Test_set_completion_string_values()
" call feedkeys(":set hl=8b i\<Left>\<Left>\<Tab>\<C-B>\"\<CR>", 'xt')
" call assert_equal("\"set hl=8bi i", @:)
+ " messagesopt
+ call assert_equal(['history:', 'hit-enter', 'wait:'],
+ \ getcompletion('set messagesopt+=', 'cmdline')->sort())
+
"
" Test flag lists
"
@@ -743,7 +747,6 @@ func Test_set_option_errors()
call assert_fails('set backupcopy=', 'E474:')
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
- call assert_fails('set msghistory=10001', 'E474:')
call assert_fails('set numberwidth=21', 'E474:')
call assert_fails('set colorcolumn=-a', 'E474:')
call assert_fails('set colorcolumn=a', 'E474:')
@@ -757,7 +760,6 @@ func Test_set_option_errors()
endif
call assert_fails('set helpheight=-1', 'E487:')
call assert_fails('set history=-1', 'E487:')
- call assert_fails('set msghistory=-1', 'E487:')
call assert_fails('set report=-1', 'E487:')
call assert_fails('set shiftwidth=-1', 'E487:')
call assert_fails('set sidescroll=-1', 'E487:')
@@ -2252,16 +2254,57 @@ func Test_opt_default()
call assert_equal('vt', &formatoptions)
set formatoptions&vim
call assert_equal('tcq', &formatoptions)
+
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
+ set fencs=latin1
+ set fencs&
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
+ set fencs=latin1
+ set all&
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
endfunc
" Test for the 'cmdheight' option
-func Test_cmdheight()
+func Test_opt_cmdheight()
%bw!
let ht = &lines
set cmdheight=9999
call assert_equal(1, winheight(0))
call assert_equal(ht - 1, &cmdheight)
set cmdheight&
+
+ " The status line should be taken into account.
+ set laststatus=2
+ set cmdheight=9999
+ call assert_equal(ht - 2, &cmdheight)
+ set cmdheight& laststatus=1 " Accommodate Nvim default
+
+ " The tabline should be taken into account only non-GUI.
+ set showtabline=2
+ set cmdheight=9999
+ if has('gui_running')
+ call assert_equal(ht - 1, &cmdheight)
+ else
+ call assert_equal(ht - 2, &cmdheight)
+ endif
+ set cmdheight& showtabline&
+
+ " The 'winminheight' should be taken into account.
+ set winheight=3 winminheight=3
+ split
+ set cmdheight=9999
+ call assert_equal(ht - 8, &cmdheight)
+ %bw!
+ set cmdheight& winminheight& winheight&
+
+ " Only the windows in the current tabpage are taken into account.
+ set winheight=3 winminheight=3 showtabline=0
+ split
+ tabnew
+ set cmdheight=9999
+ call assert_equal(ht - 3, &cmdheight)
+ %bw!
+ set cmdheight& winminheight& winheight& showtabline&
endfunc
" To specify a control character as an option value, '^' can be used
@@ -2476,6 +2519,7 @@ func Test_string_option_revert_on_failure()
\ ['lispoptions', 'expr:1', 'a123'],
\ ['listchars', 'tab:->', 'tab:'],
\ ['matchpairs', '<:>', '<:'],
+ \ ['messagesopt', 'hit-enter,history:100', 'a123'],
\ ['mkspellmem', '100000,1000,100', '100000'],
\ ['mouse', 'nvi', 'z'],
\ ['mousemodel', 'extend', 'a123'],
diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim
index 601ba6c688..33e86678c8 100644
--- a/test/old/testdir/test_popup.vim
+++ b/test/old/testdir/test_popup.vim
@@ -1675,4 +1675,29 @@ func Test_pum_completeitemalign()
call StopVimInTerminal(buf)
endfunc
+func Test_pum_keep_select()
+ CheckScreendump
+ let lines =<< trim END
+ set completeopt=menu,menuone,noinsert
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "ggSFab\<CR>Five\<CR>find\<CR>film\<CR>\<C-X>\<C-P>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_pum_keep_select_01', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf, 50)
+
+ call term_sendkeys(buf, "S\<C-X>\<C-P>")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "F")
+ call VerifyScreenDump(buf, 'Test_pum_keep_select_02', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call TermWait(buf, 50)
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_shift.vim b/test/old/testdir/test_shift.vim
index ec357dac88..f31c5a11e6 100644
--- a/test/old/testdir/test_shift.vim
+++ b/test/old/testdir/test_shift.vim
@@ -108,10 +108,809 @@ func Test_ex_shift_errors()
call assert_fails('>!', 'E477:')
call assert_fails('<!', 'E477:')
- " call assert_fails('2,1>', 'E493:')
- call assert_fails('execute "2,1>"', 'E493:')
- " call assert_fails('2,1<', 'E493:')
- call assert_fails('execute "2,1<"', 'E493:')
+ call assert_fails('2,1>', 'E493:')
+ call assert_fails('2,1<', 'E493:')
+endfunc
+
+" Test inserting a backspace at the start of a line.
+"
+" This is to verify the proper behavior of tabstop_start() as called from
+" ins_bs().
+"
+func Test_shift_ins_bs()
+ set backspace=indent,start
+ set softtabstop=11
+
+ call setline(1, repeat(" ", 33) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 22) . "word", getline(1))
+ call setline(1, repeat(" ", 23) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 22) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 11) . "word", getline(1))
+
+ set backspace& softtabstop&
+ bw!
+endfunc
+
+" Test inserting a backspace at the start of a line, with 'varsofttabstop'.
+"
+func Test_shift_ins_bs_vartabs()
+ CheckFeature vartabs
+ set backspace=indent,start
+ set varsofttabstop=13,11,7
+
+ call setline(1, repeat(" ", 44) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ call setline(1, repeat(" ", 39) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 31) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 24) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 13) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal( "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal( "word", getline(1))
+
+ set backspace& varsofttabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands.
+"
+func Test_shift_norm()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ norm! >>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ norm! >>
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands, with 'vartabstop'.
+"
+func Test_shift_norm_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ norm! >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 60) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround'.
+"
+func Test_shift_norm_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 25) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+
+ call setline(1, repeat(" ", 7) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ call setline(1, repeat(" ", 2) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 35) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+
+ call setline(1, repeat(" ", 9) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ call setline(1, repeat(" ", 2) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_norm_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I "
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands.
+"
+" See ":help v_<" and ":help v_>". See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ norm! V>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 32) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 27) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ norm! V>
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 44) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 37) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands, with 'vartabstop'.
+"
+" See ":help v_<" and ":help v_>". See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ norm! V>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 82) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 71) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround'.
+"
+func Test_shift_vis_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ norm! V2>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 30) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V2<
+ call assert_equal(repeat(" ", 25) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ norm! V2>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V<
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 35) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ call setline(1, " word")
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_vis_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V2<
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ norm! V3<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I "
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands.
+"
+func Test_shift_ex()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ >
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 32) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ >
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 44) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands, with vartabstop.
+"
+func Test_shift_ex_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ >
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 82) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround'.
+"
+func Test_shift_ex_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ >>>
+ call assert_equal(repeat(" ", 30) . "word", getline(1))
+
+ exe "norm! I "
+ <<<<
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ >>
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ >>>
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+
+ exe "norm! I "
+ <<<<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ >>
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_ex_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 80) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>.
+"
+func Test_shift_ins()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ " Shift by 'shiftwidth' right and left.
+
+ call setline(1, repeat(" ", 7) . "word")
+ exe "norm! 9|i\<C-T>"
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 24|i\<C-D>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ call setline(1, repeat(" ", 9) . "word")
+ exe "norm! 11|i\<C-T>"
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 32|i\<C-D>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>, with 'vartabstop'.
+"
+func Test_shift_ins_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ call setline(1, repeat(" ", 9) . "word")
+ exe "norm! 11|i\<C-T>"
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 51|i\<C-D>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim
index 8048fa6ff8..e173aa1e73 100644
--- a/test/old/testdir/test_window_cmd.vim
+++ b/test/old/testdir/test_window_cmd.vim
@@ -55,6 +55,27 @@ func Test_window_cmd_cmdwin_with_vsp()
set ls&vim
endfunc
+func Test_cmdheight_not_changed()
+ throw 'Skipped: N/A'
+ set cmdheight=2
+ set winminheight=0
+ augroup Maximize
+ autocmd WinEnter * wincmd _
+ augroup END
+ split
+ tabnew
+ tabfirst
+ call assert_equal(2, &cmdheight)
+
+ tabonly!
+ only
+ set winminheight& cmdheight&
+ augroup Maximize
+ au!
+ augroup END
+ augroup! Maximize
+endfunc
+
" Test for jumping to windows
func Test_window_jump()
new
diff --git a/test/unit/fixtures/vterm_test.c b/test/unit/fixtures/vterm_test.c
new file mode 100644
index 0000000000..47aa071f9b
--- /dev/null
+++ b/test/unit/fixtures/vterm_test.c
@@ -0,0 +1,504 @@
+#include "vterm_test.h"
+
+#include <stdio.h>
+
+int parser_text(const char bytes[], size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "text ");
+ size_t i;
+ for(i = 0; i < len; i++) {
+ unsigned char b = (unsigned char)bytes[i];
+ if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) {
+ break;
+ }
+ fprintf(f, i ? ",%x" : "%x", b);
+ }
+ fprintf(f, "\n");
+ fclose(f);
+
+ return (int)i;
+}
+
+static void printchars(const char *s, size_t len, FILE *f)
+{
+ while(len--) {
+ fprintf(f, "%c", (s++)[0]);
+ }
+}
+
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "csi %02x", command);
+
+ if(leader && leader[0]) {
+ fprintf(f, " L=");
+ for(int i = 0; leader[i]; i++) {
+ fprintf(f, "%02x", leader[i]);
+ }
+ }
+
+ for(int i = 0; i < argcount; i++) {
+ char sep = i ? ',' : ' ';
+
+ if(args[i] == CSI_ARG_MISSING) {
+ fprintf(f, "%c*", sep);
+ } else {
+ fprintf(f, "%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
+ }
+ }
+
+ if(intermed && intermed[0]) {
+ fprintf(f, " I=");
+ for(int i = 0; intermed[i]; i++) {
+ fprintf(f, "%02x", intermed[i]);
+ }
+ }
+
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int parser_osc(int command, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "osc ");
+
+ if(frag.initial) {
+ if(command == -1) {
+ fprintf(f, "[");
+ } else {
+ fprintf(f, "[%d;", command);
+ }
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "dcs ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ for(size_t i = 0; i < commandlen; i++) {
+ fprintf(f, "%c", command[i]);
+ }
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_apc(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "apc ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_pm(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "pm ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_sos(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sos ");
+
+ if(frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len,f);
+
+ if(frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "selection-set mask=%04X ", mask);
+ if(frag.initial) {
+ fprintf(f, "[");
+}
+ printchars(frag.str, frag.len, f);
+ if(frag.final) {
+ fprintf(f, "]");
+}
+ fprintf(f,"\n");
+
+ fclose(f);
+ return 1;
+}
+
+int selection_query(VTermSelectionMask mask, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"selection-query mask=%04X\n", mask);
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_putglyph;
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
+{
+ if(!want_state_putglyph) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "putglyph ");
+ for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
+ fprintf(f, i ? ",%x" : "%x", info->chars[i]);
+ }
+ fprintf(f, " %d %d,%d", info->width, pos.row, pos.col);
+ if(info->protected_cell) {
+ fprintf(f, " prot");
+ }
+ if(info->dwl) {
+ fprintf(f, " dwl");
+ }
+ if(info->dhl) {
+ fprintf(f, " dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" );
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+bool want_state_movecursor;
+VTermPos state_pos;
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ state_pos = pos;
+
+ if(want_state_movecursor) {
+ fprintf(f,"movecursor %d,%d\n", pos.row, pos.col);
+ }
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_scrollrect;
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user)
+{
+ if(!want_state_scrollrect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f,"scrollrect %d..%d,%d..%d => %+d,%+d\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ downward, rightward);
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_moverect;
+int state_moverect(VTermRect dest, VTermRect src, void *user)
+{
+ if(!want_state_moverect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
+ src.start_row, src.end_row, src.start_col, src.end_col,
+ dest.start_row, dest.end_row, dest.start_col, dest.end_col);
+
+ fclose(f);
+ return 1;
+}
+
+void print_color(const VTermColor *col)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ if (VTERM_COLOR_IS_RGB(col)) {
+ fprintf(f,"rgb(%d,%d,%d", col->rgb.red, col->rgb.green, col->rgb.blue);
+ }
+ else if (VTERM_COLOR_IS_INDEXED(col)) {
+ fprintf(f,"idx(%d", col->indexed.idx);
+ }
+ else {
+ fprintf(f,"invalid(%d", col->type);
+ }
+ if (VTERM_COLOR_IS_DEFAULT_FG(col)) {
+ fprintf(f,",is_default_fg");
+ }
+ if (VTERM_COLOR_IS_DEFAULT_BG(col)) {
+ fprintf(f,",is_default_bg");
+ }
+ fprintf(f,")");
+ fclose(f);
+}
+
+bool want_state_settermprop;
+int state_settermprop(VTermProp prop, VTermValue *val, void *user)
+{
+ if(!want_state_settermprop) {
+ return 1;
+ }
+
+ int errcode = 0;
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ VTermValueType type = vterm_get_prop_type(prop);
+ switch(type) {
+ case VTERM_VALUETYPE_BOOL:
+ fprintf(f,"settermprop %d %s\n", prop, val->boolean ? "true" : "false");
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_INT:
+ fprintf(f,"settermprop %d %d\n", prop, val->number);
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_STRING:
+ fprintf(f,"settermprop %d %s\"%.*s\"%s\n", prop,
+ val->string.initial ? "[" : "", (int)val->string.len, val->string.str, val->string.final ? "]" : "");
+ errcode=0;
+ goto end;
+ case VTERM_VALUETYPE_COLOR:
+ fprintf(f,"settermprop %d ", prop);
+ print_color(&val->color);
+ fprintf(f,"\n");
+ errcode=1;
+ goto end;
+ case VTERM_N_VALUETYPES:
+ goto end;
+ }
+
+end:
+ fclose(f);
+ return errcode;
+}
+
+bool want_state_erase;
+int state_erase(VTermRect rect, int selective, void *user)
+{
+ if(!want_state_erase) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f,"erase %d..%d,%d..%d%s\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ selective ? " selective" : "");
+
+ fclose(f);
+ return 1;
+}
+
+struct {
+ int bold;
+ int underline;
+ int italic;
+ int blink;
+ int reverse;
+ int conceal;
+ int strike;
+ int font;
+ int small;
+ int baseline;
+ VTermColor foreground;
+ VTermColor background;
+} state_pen;
+
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
+{
+ switch(attr) {
+ case VTERM_ATTR_BOLD:
+ state_pen.bold = val->boolean;
+ break;
+ case VTERM_ATTR_UNDERLINE:
+ state_pen.underline = val->number;
+ break;
+ case VTERM_ATTR_ITALIC:
+ state_pen.italic = val->boolean;
+ break;
+ case VTERM_ATTR_BLINK:
+ state_pen.blink = val->boolean;
+ break;
+ case VTERM_ATTR_REVERSE:
+ state_pen.reverse = val->boolean;
+ break;
+ case VTERM_ATTR_CONCEAL:
+ state_pen.conceal = val->boolean;
+ break;
+ case VTERM_ATTR_STRIKE:
+ state_pen.strike = val->boolean;
+ break;
+ case VTERM_ATTR_FONT:
+ state_pen.font = val->number;
+ break;
+ case VTERM_ATTR_SMALL:
+ state_pen.small = val->boolean;
+ break;
+ case VTERM_ATTR_BASELINE:
+ state_pen.baseline = val->number;
+ break;
+ case VTERM_ATTR_FOREGROUND:
+ state_pen.foreground = val->color;
+ break;
+ case VTERM_ATTR_BACKGROUND:
+ state_pen.background = val->color;
+ break;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+bool want_state_scrollback;
+int state_sb_clear(void *user) {
+ if(!want_state_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"sb_clear\n");
+ fclose(f);
+
+ return 0;
+}
+
+bool want_screen_scrollback;
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ if(!want_screen_scrollback) {
+ return 1;
+ }
+
+ int eol = cols;
+ while(eol && !cells[eol-1].chars[0]) {
+ eol--;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_pushline %d =", cols);
+ for(int c = 0; c < eol; c++) {
+ fprintf(f, " %02X", cells[c].chars[0]);
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
+{
+ if(!want_screen_scrollback) {
+ return 0;
+ }
+
+ // All lines of scrollback contain "ABCDE"
+ for(int col = 0; col < cols; col++) {
+ if(col < 5) {
+ cells[col].chars[0] = (uint32_t)('A' + col);
+ } else {
+ cells[col].chars[0] = 0;
+ }
+
+ cells[col].width = 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f,"sb_popline %d\n", cols);
+ fclose(f);
+ return 1;
+}
+
+int screen_sb_clear(void *user)
+{
+ if(!want_screen_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_clear\n");
+ fclose(f);
+ return 0;
+}
+
+void term_output(const char *s, size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "output ");
+ for(size_t i = 0; i < len; i++) {
+ fprintf(f, "%x%s", (unsigned char)s[i], i < len-1 ? "," : "\n");
+ }
+ fclose(f);
+}
diff --git a/test/unit/fixtures/vterm_test.h b/test/unit/fixtures/vterm_test.h
new file mode 100644
index 0000000000..924c6c1633
--- /dev/null
+++ b/test/unit/fixtures/vterm_test.h
@@ -0,0 +1,37 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "nvim/macros_defs.h"
+#include "vterm/vterm.h"
+
+int parser_text(const char bytes[], size_t len, void *user);
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
+int parser_osc(int command, VTermStringFragment frag, void *user);
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
+int parser_apc(VTermStringFragment frag, void *user);
+int parser_pm(VTermStringFragment frag, void *user);
+int parser_sos(VTermStringFragment frag, void *user);
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user);
+int selection_query(VTermSelectionMask mask, void *user);
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user);
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user);
+int state_moverect(VTermRect dest, VTermRect src, void *user);
+int state_settermprop(VTermProp prop, VTermValue *val, void *user);
+int state_erase(VTermRect rect, int selective, void *user);
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user);
+int state_sb_clear(void *user);
+void print_color(const VTermColor *col);
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user);
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user);
+int screen_sb_clear(void *user);
+void term_output(const char *s, size_t len, void *user);
+EXTERN VTermPos state_pos;
+EXTERN bool want_state_putglyph INIT (=false);
+EXTERN bool want_state_movecursor INIT(= false);
+EXTERN bool want_state_erase INIT(= false);
+EXTERN bool want_state_scrollrect INIT(= false);
+EXTERN bool want_state_moverect INIT(= false);
+EXTERN bool want_state_settermprop INIT(= false);
+EXTERN bool want_state_scrollback INIT(= false);
+EXTERN bool want_screen_scrollback INIT(= false);
diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua
index 4ea5d9c29a..a05579b4ff 100644
--- a/test/unit/vterm_spec.lua
+++ b/test/unit/vterm_spec.lua
@@ -79,7 +79,11 @@ local bit = require('bit')
--- @field vterm_state_set_callbacks function
--- @field vterm_state_set_selection_callbacks function
--- @field vterm_state_set_unrecognised_fallbacks function
-local vterm = t.cimport('./src/vterm/vterm.h', './src/vterm/vterm_internal.h')
+local vterm = t.cimport(
+ './src/vterm/vterm.h',
+ './src/vterm/vterm_internal.h',
+ './test/unit/fixtures/vterm_test.h'
+)
--- @return string
local function read_rm()