aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/actions/cache/action.yml2
-rw-r--r--.github/workflows/test.yml4
-rw-r--r--cmake.deps/deps.txt4
-rw-r--r--runtime/doc/api.txt2
-rw-r--r--runtime/doc/builtin.txt4
-rw-r--r--runtime/doc/deprecated.txt1
-rw-r--r--runtime/doc/help.txt2
-rw-r--r--runtime/doc/lua-guide.txt8
-rw-r--r--runtime/doc/lua.txt37
-rw-r--r--runtime/doc/luaref.txt6
-rw-r--r--runtime/doc/luvref.txt6
-rw-r--r--runtime/doc/news.txt18
-rw-r--r--runtime/doc/provider.txt2
-rw-r--r--runtime/doc/repeat.txt5
-rw-r--r--runtime/lua/_vim9script.lua2
-rw-r--r--runtime/lua/man.lua8
-rw-r--r--runtime/lua/nvim/health.lua2
-rw-r--r--runtime/lua/provider/health.lua10
-rw-r--r--runtime/lua/vim/_editor.lua8
-rw-r--r--runtime/lua/vim/_watch.lua6
-rw-r--r--runtime/lua/vim/filetype/options.lua2
-rw-r--r--runtime/lua/vim/fs.lua20
-rw-r--r--runtime/lua/vim/iter.lua39
-rw-r--r--runtime/lua/vim/loader.lua4
-rw-r--r--runtime/lua/vim/lsp.lua6
-rw-r--r--runtime/lua/vim/lsp/health.lua2
-rw-r--r--runtime/lua/vim/lsp/log.lua4
-rw-r--r--runtime/lua/vim/lsp/protocol.lua7
-rw-r--r--runtime/lua/vim/lsp/rpc.lua4
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua2
-rw-r--r--runtime/lua/vim/lsp/util.lua2
-rw-r--r--runtime/lua/vim/secure.lua6
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua4
-rw-r--r--scripts/gen_help_html.lua15
-rw-r--r--src/nvim/api/autocmd.c2
-rw-r--r--src/nvim/api/vim.c2
-rw-r--r--src/nvim/drawline.c224
-rw-r--r--src/nvim/drawline.h11
-rw-r--r--src/nvim/drawscreen.c29
-rw-r--r--src/nvim/edit.c27
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/eval/funcs.c21
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/grid.c9
-rw-r--r--src/nvim/lua/executor.c6
-rw-r--r--src/nvim/move.c12
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/ops.c1
-rw-r--r--src/nvim/runtime.c4
-rw-r--r--src/nvim/window.c69
-rw-r--r--test/benchmark/autocmd_spec.lua4
-rw-r--r--test/benchmark/iter_spec.lua4
-rw-r--r--test/benchmark/treesitter_spec.lua4
-rw-r--r--test/busted_runner.lua2
-rw-r--r--test/functional/core/startup_spec.lua2
-rw-r--r--test/functional/ex_cmds/source_spec.lua108
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua2
-rw-r--r--test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua2
-rw-r--r--test/functional/legacy/put_spec.lua25
-rw-r--r--test/functional/lua/highlight_spec.lua2
-rw-r--r--test/functional/lua/loop_spec.lua18
-rw-r--r--test/functional/lua/overrides_spec.lua4
-rw-r--r--test/functional/lua/thread_spec.lua42
-rw-r--r--test/functional/lua/vim_spec.lua16
-rw-r--r--test/functional/plugin/lsp/helpers.lua2
-rw-r--r--test/functional/plugin/lsp_spec.lua64
-rw-r--r--test/functional/terminal/tui_spec.lua6
-rw-r--r--test/functional/treesitter/parser_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua41
-rw-r--r--test/functional/ui/spell_spec.lua24
-rw-r--r--test/old/testdir/test_functions.vim28
-rw-r--r--test/old/testdir/test_put.vim18
-rw-r--r--test/old/testdir/test_registers.vim5
-rw-r--r--test/old/testdir/test_spell.vim11
-rw-r--r--test/old/testdir/test_utf8.vim15
-rw-r--r--test/old/testdir/test_window_cmd.vim13
76 files changed, 712 insertions, 439 deletions
diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml
index 07f8feaa84..9ad14b8c27 100644
--- a/.github/actions/cache/action.yml
+++ b/.github/actions/cache/action.yml
@@ -17,6 +17,6 @@ runs:
- uses: actions/cache@v3
with:
path: .deps
- key: ${{ env.CACHE_KEY }}-${{ hashFiles('cmake**', 'ci/**',
+ key: ${{ env.CACHE_KEY }}-${{ hashFiles('cmake**',
'.github/workflows/test.yml', 'CMakeLists.txt',
'runtime/CMakeLists.txt', 'src/nvim/**/CMakeLists.txt') }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b71718aad2..14546cb371 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -101,9 +101,7 @@ jobs:
flags: -D CMAKE_FIND_FRAMEWORK=NEVER
deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER
- # functionaltest-lua is our dumping ground for non-mainline configurations.
- # 1. Check that the tests pass with PUC Lua instead of LuaJIT.
- # 2. No treesitter parsers installed.
+ # Check that the tests pass with PUC Lua instead of LuaJIT.
- flavor: functionaltest-lua
cc: gcc
runner: ubuntu-22.04
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index 1a720bc1f3..80526dc84a 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -4,8 +4,8 @@ LIBUV_SHA256 458e34d5ef7f3c0394a2bfd8c39d757cb1553baa5959b9b4b45df63aa027a228
MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/c-6.0.0/msgpack-c-6.0.0.tar.gz
MSGPACK_SHA256 3654f5e2c652dc52e0a993e270bb57d5702b262703f03771c152bba51602aeba
-LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/224129a8e64bfa219d35cd03055bf03952f167f6.tar.gz
-LUAJIT_SHA256 a9bcd9e646e2b188e1d7e3fb594e04c61dda3b332dfd0378d41be19c1eae9d09
+LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/51fb2f2c3af778f03258fccee9092401ee4a0215.tar.gz
+LUAJIT_SHA256 d081eaa1a5bca419763712397f4696e0dd10db8d9b2e091e15c71d9fc50c24c9
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index ed8858820e..83422c9501 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -3242,7 +3242,7 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
pattern = {"*.c", "*.h"},
callback = function(ev)
- print(string.format('event fired: s', vim.inspect(ev)))
+ print(string.format('event fired: %s', vim.inspect(ev)))
end
})
<
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 7acc764644..27d52b7ac6 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -3927,8 +3927,8 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
{feature} argument is a feature name like "nvim-0.2.1" or
"win32", see below. See also |exists()|.
- To get the system name use |vim.loop|.os_uname() in Lua: >
- :lua print(vim.loop.os_uname().sysname)
+ To get the system name use |vim.uv|.os_uname() in Lua: >lua
+ print(vim.uv.os_uname().sysname)
< If the code has a syntax error then Vimscript may skip the
rest of the line. Put |:if| and |:endif| on separate lines to
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 9d4a7324bf..6494c53059 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -144,6 +144,7 @@ TREESITTER FUNCTIONS
LUA
- vim.register_keystroke_callback() Use |vim.on_key()| instead.
- *vim.pretty_print()* Use |vim.print()| instead.
+- *vim.loop* Use |vim.uv| instead.
NORMAL COMMANDS
- *]f* *[f* Same as "gf".
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index a1550d5c8b..aefaa0b7df 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -105,7 +105,7 @@ API (EXTENSIBILITY/SCRIPTING/PLUGINS)
|lua-guide| Nvim Lua guide
|lua| Lua API
|luaref| Lua reference manual
-|luvref| Luv (|vim.loop|) reference manual
+|luvref| Luv (|vim.uv|) reference manual
|autocmd| Event handlers
|job-control| Spawn and control multiple processes
|channel| Nvim asynchronous IO
diff --git a/runtime/doc/lua-guide.txt b/runtime/doc/lua-guide.txt
index 94db6aac0a..22f51ce8c7 100644
--- a/runtime/doc/lua-guide.txt
+++ b/runtime/doc/lua-guide.txt
@@ -114,10 +114,10 @@ Let's assume you have the following directory structure:
|-- after/
|-- ftplugin/
|-- lua/
- | |-- myluamodule.lua
- | |-- other_modules/
- | |-- anothermodule.lua
- | |-- init.lua
+ | |-- myluamodule.lua
+ | |-- other_modules/
+ | |-- anothermodule.lua
+ | |-- init.lua
|-- plugin/
|-- syntax/
|-- init.vim
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index ad9cb69ae0..54527c5a50 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -449,29 +449,24 @@ Note that underscore-prefixed functions (e.g. "_os_proc_children") are
internal/private and must not be used by plugins.
------------------------------------------------------------------------------
-VIM.LOOP *lua-loop* *vim.loop*
+VIM.UV *lua-loop* *vim.uv*
-`vim.loop` exposes all features of the Nvim event-loop. This is a low-level
-API that provides functionality for networking, filesystem, and process
-management. Try this command to see available functions: >vim
-
- :lua print(vim.inspect(vim.loop))
-<
-Internally, `vim.loop` wraps the "luv" Lua bindings for the LibUV library;
-see |luv-intro| for a full reference manual.
+`vim.uv` exposes the "luv" Lua bindings for the libUV library that Nvim uses
+for networking, filesystem, and process management, see |luvref.txt|.
+In particular, it allows interacting with the main Nvim |luv-event-loop|.
*E5560* *lua-loop-callbacks*
It is an error to directly invoke `vim.api` functions (except |api-fast|) in
-`vim.loop` callbacks. For example, this is an error: >lua
+`vim.uv` callbacks. For example, this is an error: >lua
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(1000, 0, function()
vim.api.nvim_command('echomsg "test"')
end)
<
To avoid the error use |vim.schedule_wrap()| to defer the callback: >lua
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(1000, 0, vim.schedule_wrap(function()
vim.api.nvim_command('echomsg "test"')
end))
@@ -484,7 +479,7 @@ Example: repeating timer
2. Execute it with ":luafile %". >lua
-- Create a timer handle (implementation detail: uv_timer_t).
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
local i = 0
-- Waits 1000ms, then repeats every 750ms until timer:close().
timer:start(1000, 750, function()
@@ -504,7 +499,7 @@ Example: File-change detection *watch-file*
5. Observe that the file reloads in Nvim (because on_change() calls
|:checktime|). >lua
- local w = vim.loop.new_fs_event()
+ local w = vim.uv.new_fs_event()
local function on_change(err, fname, status)
-- Do work...
vim.api.nvim_command('checktime')
@@ -528,11 +523,11 @@ Example: TCP echo-server *tcp-server*
4. Connect from any TCP client (e.g. "nc 0.0.0.0 36795"): >lua
local function create_server(host, port, on_connect)
- local server = vim.loop.new_tcp()
+ local server = vim.uv.new_tcp()
server:bind(host, port)
server:listen(128, function(err)
assert(not err, err) -- Check for errors.
- local sock = vim.loop.new_tcp()
+ local sock = vim.uv.new_tcp()
server:accept(sock) -- Accept client connection.
on_connect(sock) -- Start reading messages.
end)
@@ -553,14 +548,14 @@ Example: TCP echo-server *tcp-server*
Multithreading *lua-loop-threading*
Plugins can perform work in separate (os-level) threads using the threading
-APIs in luv, for instance `vim.loop.new_thread`. Note that every thread
+APIs in luv, for instance `vim.uv.new_thread`. Note that every thread
gets its own separate lua interpreter state, with no access to lua globals
in the main thread. Neither can the state of the editor (buffers, windows,
etc) be directly accessed from threads.
A subset of the `vim.*` API is available in threads. This includes:
-- `vim.loop` with a separate event loop per thread.
+- `vim.uv` with a separate event loop per thread.
- `vim.mpack` and `vim.json` (useful for serializing messages between threads)
- `require` in threads can use lua packages from the global |package.path|
- `print()` and `vim.inspect`
@@ -885,7 +880,7 @@ vim.defer_fn({fn}, {timeout}) *vim.defer_fn*
• {timeout} Time in ms to wait before calling {fn}
Returns: ~
- |vim.loop|.new_timer() object
+ |vim.uv|.new_timer() object
vim.wait({time} [, {callback}, {interval}, {fast_only}]) *vim.wait()*
Wait for {time} in milliseconds until {callback} returns `true`.
@@ -2531,7 +2526,7 @@ find({names}, {opts}) *vim.fs.find()*
-- location of Cargo.toml from the current buffer's path
local cargo = vim.fs.find('Cargo.toml', {
upward = true,
- stop = vim.loop.os_homedir(),
+ stop = vim.uv.os_homedir(),
path = vim.fs.dirname(vim.api.nvim_buf_get_name(0)),
})
@@ -3035,7 +3030,7 @@ Iter:find({self}, {f}) *Iter:find()*
Iter:fold({self}, {init}, {f}) *Iter:fold()*
Fold an iterator or table into a single value.
- Examples: >
+ Examples: >lua
-- Create a new table with only even values
local t = { a = 1, b = 2, c = 3, d = 4 }
diff --git a/runtime/doc/luaref.txt b/runtime/doc/luaref.txt
index aafdd5c43e..a01196e538 100644
--- a/runtime/doc/luaref.txt
+++ b/runtime/doc/luaref.txt
@@ -4101,16 +4101,16 @@ string.gsub({s}, {pattern}, {repl} [, {n}]) *string.gsub()*
x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"
- x = string.gsub("home = `HOME, user = ` USER", "%$(%w+)", os.getenv)
+ x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"
- x = string.gsub("4+5 = `return 4+5` ", "% `(.-)%` ", function (s)
+ x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
return loadstring(s)()
end)
--> x="4+5 = 9"
local t = {name="lua", version="5.1"}
- x = string.gsub(" `name%-` version.tar.gz", "%$(%w+)", t)
+ x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.1.tar.gz"
<
diff --git a/runtime/doc/luvref.txt b/runtime/doc/luvref.txt
index 79dd1248aa..131e7889e4 100644
--- a/runtime/doc/luvref.txt
+++ b/runtime/doc/luvref.txt
@@ -5,8 +5,8 @@
*luvref*
This file documents the Lua bindings for the LibUV library which is used for
-Nvim's event-loop and is accessible from Lua via |vim.loop| (e.g., |uv.version()|
-is exposed as `vim.loop.version()`).
+Nvim's event-loop and is accessible from Lua via |vim.uv| (e.g., |uv.version()|
+is exposed as `vim.uv.version()`).
For information about this manual, see |luv-credits|.
@@ -29,7 +29,7 @@ TCP Echo Server Example ~
Here is a small example showing a TCP echo server:
>lua
- local uv = vim.loop
+ local uv = vim.uv
local server = uv.new_tcp()
server:bind("127.0.0.1", 1337)
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 72eb182fa5..d51227f0c0 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -39,7 +39,18 @@ ADDED FEATURES *news-added*
The following new APIs or features were added.
-• Dynamic registration of LSP capabilities. An implication of this change is that checking a client's `server_capabilities` is no longer a sufficient indicator to see if a server supports a feature. Instead use `client.supports_method(<method>)`. It considers both the dynamic capabilities and static `server_capabilities`.
+• Nvim's LSP client now advertises the general.positionEncodings client
+ capability to indicate to servers that it supports utf-8, utf-16, and utf-32
+ encodings. If the server responds with the positionEncoding capability in
+ its initialization response, Nvim automatically sets the client's
+ `offset_encoding` field.
+
+• Dynamic registration of LSP capabilities. An implication of this change is
+ that checking a client's `server_capabilities` is no longer a sufficient
+ indicator to see if a server supports a feature. Instead use
+ `client.supports_method(<method>)`. It considers both the dynamic
+ capabilities and static `server_capabilities`.
+
• |vim.iter()| provides a generic iterator interface for tables and Lua
iterators |luaref-in|.
@@ -86,6 +97,9 @@ The following changes to existing APIs or features add new behavior.
• |LspRequest| autocmd callbacks now contain additional information about the LSP
request status update that occurred.
+• `:source` without arguments treats a buffer with its 'filetype' set to "lua"
+ as Lua code regardless of its extension.
+
==============================================================================
REMOVED FEATURES *news-removed*
@@ -115,4 +129,6 @@ release.
- |nvim_win_get_option()| Use |nvim_get_option_value()| instead.
- |nvim_win_set_option()| Use |nvim_set_option_value()| instead.
+• `vim.loop` has been renamed to `vim.uv`.
+
vim:tw=78:ts=8:sw=2:et:ft=help:norl:
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index 117997cec2..a476a56877 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -189,8 +189,8 @@ registers. Nvim looks for these clipboard tools, in order of priority:
- pbcopy, pbpaste (macOS)
- wl-copy, wl-paste (if $WAYLAND_DISPLAY is set)
- waycopy, waypaste (if $WAYLAND_DISPLAY is set)
- - xclip (if $DISPLAY is set)
- xsel (if $DISPLAY is set)
+ - 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)
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index b6cb126c3b..071b062957 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -183,7 +183,10 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:so* *:source* *load-vim-script*
:[range]so[urce] [file] Runs |Ex| commands or Lua code (".lua" files) from
- [file], or current buffer if no [file].
+ [file].
+ If no [file], the current buffer is used, and it is
+ treated as Lua code if its 'filetype' is "lua" or its
+ file name ends with ".lua".
Triggers the |SourcePre| autocommand.
*:source!*
:[range]so[urce]! {file}
diff --git a/runtime/lua/_vim9script.lua b/runtime/lua/_vim9script.lua
index b983878637..ca0e913d51 100644
--- a/runtime/lua/_vim9script.lua
+++ b/runtime/lua/_vim9script.lua
@@ -513,7 +513,7 @@ vim9['import'] = (function()
imported.absolute = setmetatable({}, {
__index = function(self, name)
- if vim.loop.fs_stat(name) then
+ if vim.uv.fs_stat(name) then
local result = loadfile(name)()
rawset(self, name, result)
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index ac493bdc7f..09265b1999 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -21,13 +21,13 @@ end
local function system(cmd_, silent, env)
local stdout_data = {} ---@type string[]
local stderr_data = {} ---@type string[]
- local stdout = assert(vim.loop.new_pipe(false))
- local stderr = assert(vim.loop.new_pipe(false))
+ local stdout = assert(vim.uv.new_pipe(false))
+ local stderr = assert(vim.uv.new_pipe(false))
local done = false
local exit_code ---@type integer?
- -- We use the `env` command here rather than the env option to vim.loop.spawn since spawn will
+ -- We use the `env` command here rather than the env option to vim.uv.spawn since spawn will
-- completely overwrite the environment when we just want to modify the existing one.
--
-- Overwriting mainly causes problems NixOS which relies heavily on a non-standard environment.
@@ -39,7 +39,7 @@ local function system(cmd_, silent, env)
end
local handle
- handle = vim.loop.spawn(cmd[1], {
+ handle = vim.uv.spawn(cmd[1], {
args = vim.list_slice(cmd, 2),
stdio = { nil, stdout, stderr },
}, function(code)
diff --git a/runtime/lua/nvim/health.lua b/runtime/lua/nvim/health.lua
index 19303d34f9..7ccb082a40 100644
--- a/runtime/lua/nvim/health.lua
+++ b/runtime/lua/nvim/health.lua
@@ -30,7 +30,7 @@ local function check_runtime()
local bad_files_msg = ''
for k, _ in pairs(bad_files) do
local path = ('%s/%s'):format(vim.env.VIMRUNTIME, k)
- if vim.loop.fs_stat(path) then
+ if vim.uv.fs_stat(path) then
bad_files[k] = true
bad_files_msg = ('%s%s\n'):format(bad_files_msg, path)
end
diff --git a/runtime/lua/provider/health.lua b/runtime/lua/provider/health.lua
index 3a60e38fe5..f2c19f53fb 100644
--- a/runtime/lua/provider/health.lua
+++ b/runtime/lua/provider/health.lua
@@ -5,7 +5,7 @@ local ok = vim.health.ok
local info = vim.health.info
local warn = vim.health.warn
local error = vim.health.error
-local iswin = vim.loop.os_uname().sysname == 'Windows_NT'
+local iswin = vim.uv.os_uname().sysname == 'Windows_NT'
local shell_error_code = 0
local function shell_error()
@@ -30,7 +30,7 @@ local function isdir(path)
if not path then
return false
end
- local stat = vim.loop.fs_stat(path)
+ local stat = vim.uv.fs_stat(path)
if not stat then
return false
end
@@ -41,7 +41,7 @@ local function isfile(path)
if not path then
return false
end
- local stat = vim.loop.fs_stat(path)
+ local stat = vim.uv.fs_stat(path)
if not stat then
return false
end
@@ -109,13 +109,13 @@ local function system(cmd, ...)
end
if not is_blank(stdin) then
- vim.cmd([[call jobsend(jobid, stdin)]])
+ vim.api.nvim_chan_send(jobid, stdin)
end
local res = vim.fn.jobwait({ jobid }, 30000)
if res[1] == -1 then
error('Command timed out: ' .. shellify(cmd))
- vim.cmd([[call jobstop(jobid)]])
+ vim.fn.jobstop(jobid)
elseif shell_error() and not ignore_error then
local emsg = 'Command error (job='
.. jobid
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index b26def5958..7b946a55e4 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -42,6 +42,10 @@ for k, v in pairs({
vim._submodules[k] = v
end
+-- Remove at Nvim 1.0
+---@deprecated
+vim.loop = vim.uv
+
-- There are things which have special rules in vim._init_packages
-- for legacy reasons (uri) or for performance (_inspector).
-- most new things should go into a submodule namespace ( vim.foobar.do_thing() )
@@ -159,7 +163,7 @@ do
--- - 3: ends the paste (exactly once)
---@returns boolean # false if client should cancel the paste.
function vim.paste(lines, phase)
- local now = vim.loop.now()
+ local now = vim.uv.now()
local is_first_chunk = phase < 2
local is_last_chunk = phase == -1 or phase == 3
if is_first_chunk then -- Reset flags.
@@ -483,7 +487,7 @@ end
---@return table timer luv timer object
function vim.defer_fn(fn, timeout)
vim.validate({ fn = { fn, 'c', true } })
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(
timeout,
0,
diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua
index dbffd726a2..3bd8a56f6e 100644
--- a/runtime/lua/vim/_watch.lua
+++ b/runtime/lua/vim/_watch.lua
@@ -46,7 +46,7 @@ function M.watch(path, opts, callback)
path = vim.fs.normalize(path)
local uvflags = opts and opts.uvflags or {}
- local handle, new_err = vim.loop.new_fs_event()
+ local handle, new_err = vim.uv.new_fs_event()
assert(not new_err, new_err)
local _, start_err = handle:start(path, uvflags, function(err, filename, events)
assert(not err, err)
@@ -57,7 +57,7 @@ function M.watch(path, opts, callback)
end
local change_type = events.change and M.FileChangeType.Changed or 0
if events.rename then
- local _, staterr, staterrname = vim.loop.fs_stat(fullpath)
+ local _, staterr, staterrname = vim.uv.fs_stat(fullpath)
if staterrname == 'ENOENT' then
change_type = M.FileChangeType.Deleted
else
@@ -99,7 +99,7 @@ local function poll_internal(path, opts, callback, watches)
}
if not watches.handle then
- local poll, new_err = vim.loop.new_fs_poll()
+ local poll, new_err = vim.uv.new_fs_poll()
assert(not new_err, new_err)
watches.handle = poll
local _, start_err = poll:start(
diff --git a/runtime/lua/vim/filetype/options.lua b/runtime/lua/vim/filetype/options.lua
index a093c249f7..2a28b5a8e3 100644
--- a/runtime/lua/vim/filetype/options.lua
+++ b/runtime/lua/vim/filetype/options.lua
@@ -34,7 +34,7 @@ local ft_option_cache = {} ---@type table<string,table<string,any>>
--- @param path string
--- @return integer
local function hash(path)
- local mtime0 = vim.loop.fs_stat(path).mtime
+ local mtime0 = vim.uv.fs_stat(path).mtime
return mtime0.sec * 1000000000 + mtime0.nsec
end
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index 864ba495f1..5e63fb6237 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -1,6 +1,6 @@
local M = {}
-local iswin = vim.loop.os_uname().sysname == 'Windows_NT'
+local iswin = vim.uv.os_uname().sysname == 'Windows_NT'
--- Iterate over all the parents of the given file or directory.
---
@@ -106,12 +106,12 @@ function M.dir(path, opts)
})
if not opts.depth or opts.depth == 1 then
- local fs = vim.loop.fs_scandir(M.normalize(path))
+ local fs = vim.uv.fs_scandir(M.normalize(path))
return function()
if not fs then
return
end
- return vim.loop.fs_scandir_next(fs)
+ return vim.uv.fs_scandir_next(fs)
end
end
@@ -121,9 +121,9 @@ function M.dir(path, opts)
while #dirs > 0 do
local dir0, level = unpack(table.remove(dirs, 1))
local dir = level == 1 and dir0 or M.joinpath(path, dir0)
- local fs = vim.loop.fs_scandir(M.normalize(dir))
+ local fs = vim.uv.fs_scandir(M.normalize(dir))
while fs do
- local name, t = vim.loop.fs_scandir_next(fs)
+ local name, t = vim.uv.fs_scandir_next(fs)
if not name then
break
end
@@ -158,7 +158,7 @@ end
--- -- location of Cargo.toml from the current buffer's path
--- local cargo = vim.fs.find('Cargo.toml', {
--- upward = true,
---- stop = vim.loop.os_homedir(),
+--- stop = vim.uv.os_homedir(),
--- path = vim.fs.dirname(vim.api.nvim_buf_get_name(0)),
--- })
---
@@ -212,7 +212,7 @@ function M.find(names, opts)
names = type(names) == 'string' and { names } or names
- local path = opts.path or vim.loop.cwd()
+ local path = opts.path or vim.uv.cwd()
local stop = opts.stop
local limit = opts.limit or 1
@@ -244,7 +244,7 @@ function M.find(names, opts)
local t = {}
for _, name in ipairs(names) do
local f = M.joinpath(p, name)
- local stat = vim.loop.fs_stat(f)
+ local stat = vim.uv.fs_stat(f)
if stat and (not opts.type or opts.type == stat.type) then
t[#t + 1] = f
end
@@ -337,7 +337,7 @@ function M.normalize(path, opts)
})
if path:sub(1, 1) == '~' then
- local home = vim.loop.os_homedir() or '~'
+ local home = vim.uv.os_homedir() or '~'
if home:sub(-1) == '\\' or home:sub(-1) == '/' then
home = home:sub(1, -2)
end
@@ -345,7 +345,7 @@ function M.normalize(path, opts)
end
if opts.expand_env == nil or opts.expand_env then
- path = path:gsub('%$([%w_]+)', vim.loop.os_getenv)
+ path = path:gsub('%$([%w_]+)', vim.uv.os_getenv)
end
path = path:gsub('\\', '/'):gsub('/+', '/')
diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua
index bda3508262..0e98d0437e 100644
--- a/runtime/lua/vim/iter.lua
+++ b/runtime/lua/vim/iter.lua
@@ -51,6 +51,8 @@
--- In addition to the |vim.iter()| function, the |vim.iter| module provides
--- convenience functions like |vim.iter.filter()| and |vim.iter.totable()|.
+---@class IterMod
+---@operator call:Iter
local M = {}
---@class Iter
@@ -64,7 +66,7 @@ end
---@class ListIter : Iter
---@field _table table Underlying table data
---@field _head number Index to the front of a table iterator
----@field _tail number Index to the end of a table iterator
+---@field _tail number Index to the end of a table iterator (exclusive)
local ListIter = {}
ListIter.__index = setmetatable(ListIter, Iter)
ListIter.__call = function(self)
@@ -319,23 +321,39 @@ end
---@private
function ListIter.totable(self)
- if self._head == 1 and self._tail == #self._table + 1 and self.next == ListIter.next then
- -- Sanitize packed table values
- if getmetatable(self._table[1]) == packedmt then
- for i = 1, #self._table do
- self._table[i] = sanitize(self._table[i])
- end
+ if self.next ~= ListIter.next or self._head >= self._tail then
+ return Iter.totable(self)
+ end
+
+ local needs_sanitize = getmetatable(self._table[1]) == packedmt
+
+ -- Reindex and sanitize.
+ local len = self._tail - self._head
+
+ if needs_sanitize then
+ for i = 1, len do
+ self._table[i] = sanitize(self._table[self._head - 1 + i])
end
- return self._table
+ else
+ for i = 1, len do
+ self._table[i] = self._table[self._head - 1 + i]
+ end
+ end
+
+ for i = len + 1, table.maxn(self._table) do
+ self._table[i] = nil
end
- return Iter.totable(self)
+ self._head = 1
+ self._tail = len + 1
+
+ return self._table
end
--- Fold an iterator or table into a single value.
---
--- Examples:
---- <pre>
+--- <pre>lua
--- -- Create a new table with only even values
--- local t = { a = 1, b = 2, c = 3, d = 4 }
--- local it = vim.iter(t)
@@ -974,6 +992,7 @@ function M.map(f, src, ...)
return Iter.new(src, ...):map(f):totable()
end
+---@type IterMod
return setmetatable(M, {
__call = function(_, ...)
return Iter.new(...)
diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua
index 66627fe4e7..9024bdb231 100644
--- a/runtime/lua/vim/loader.lua
+++ b/runtime/lua/vim/loader.lua
@@ -1,4 +1,4 @@
-local uv = vim.loop
+local uv = vim.uv
--- @type (fun(modename: string): fun()|string)[]
local loaders = package.loaders
@@ -465,7 +465,7 @@ end
--- @private
function Loader.track(stat, f)
return function(...)
- local start = vim.loop.hrtime()
+ local start = vim.uv.hrtime()
local r = { f(...) }
Loader._stats[stat] = Loader._stats[stat] or { total = 0, time = 0 }
Loader._stats[stat].total = Loader._stats[stat].total + 1
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index d64ed0b5a3..5f7a95ae14 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -10,7 +10,7 @@ local semantic_tokens = require('vim.lsp.semantic_tokens')
local api = vim.api
local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_exec_autocmds =
api.nvim_err_writeln, api.nvim_buf_get_lines, api.nvim_command, api.nvim_exec_autocmds
-local uv = vim.loop
+local uv = vim.uv
local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend
local validate = vim.validate
local if_nil = vim.F.if_nil
@@ -1344,6 +1344,10 @@ function lsp.start_client(config)
assert(result.capabilities, "initialize result doesn't contain capabilities")
client.server_capabilities = protocol.resolve_capabilities(client.server_capabilities)
+ if client.server_capabilities.positionEncoding then
+ client.offset_encoding = client.server_capabilities.positionEncoding
+ end
+
if next(config.settings) then
client.notify('workspace/didChangeConfiguration', { settings = config.settings })
end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index 6ca468393e..8817bb71de 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -22,7 +22,7 @@ function M.check()
local log_path = vim.lsp.get_log_path()
report_info(string.format('Log path: %s', log_path))
- local log_file = vim.loop.fs_stat(log_path)
+ local log_file = vim.uv.fs_stat(log_path)
local log_size = log_file and log_file.size or 0
local report_fn = (log_size / 1000000 > 100 and report_warn or report_info)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 3d5bc06c3f..07d0500797 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -31,7 +31,7 @@ do
end
end
- local path_sep = vim.loop.os_uname().version:match('Windows') and '\\' or '/'
+ local path_sep = vim.uv.os_uname().version:match('Windows') and '\\' or '/'
---@private
local function path_join(...)
return table.concat(vim.tbl_flatten({ ... }), path_sep)
@@ -68,7 +68,7 @@ do
return false
end
- local log_info = vim.loop.fs_stat(logfilename)
+ local log_info = vim.uv.fs_stat(logfilename)
if log_info and log_info.size > 1e9 then
local warn_msg = string.format(
'LSP client log is large (%d MB): %s',
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index a28ff407b7..7e49a572e7 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -634,6 +634,13 @@ export interface WorkspaceClientCapabilities {
--- capabilities.
function protocol.make_client_capabilities()
return {
+ general = {
+ positionEncodings = {
+ 'utf-8',
+ 'utf-16',
+ 'utf-32',
+ },
+ },
textDocument = {
semanticTokens = {
dynamicRegistration = false,
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index af3190c9bd..5f48effebf 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -1,4 +1,4 @@
-local uv = vim.loop
+local uv = vim.uv
local log = require('vim.lsp.log')
local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
@@ -691,7 +691,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
})
---@private
- --- Callback for |vim.loop.spawn()| Closes all streams and runs the `on_exit` dispatcher.
+ --- Callback for |vim.uv.spawn()| Closes all streams and runs the `on_exit` dispatcher.
---@param code (integer) Exit code
---@param signal (integer) Signal that was used to terminate (if any)
local function onexit(code, signal)
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index 376cac19a7..191cc7b400 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -2,7 +2,7 @@ local api = vim.api
local bit = require('bit')
local handlers = require('vim.lsp.handlers')
local util = require('vim.lsp.util')
-local uv = vim.loop
+local uv = vim.uv
--- @class STTokenRange
--- @field line integer line number 0-based
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 9fffc845b1..53f8dba814 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -4,7 +4,7 @@ local validate = vim.validate
local api = vim.api
local list_extend = vim.list_extend
local highlight = require('vim.highlight')
-local uv = vim.loop
+local uv = vim.uv
local npcall = vim.F.npcall
local split = vim.split
diff --git a/runtime/lua/vim/secure.lua b/runtime/lua/vim/secure.lua
index 443b152273..1a04e11231 100644
--- a/runtime/lua/vim/secure.lua
+++ b/runtime/lua/vim/secure.lua
@@ -51,7 +51,7 @@ end
--- trusted, or nil otherwise.
function M.read(path)
vim.validate({ path = { path, 's' } })
- local fullpath = vim.loop.fs_realpath(vim.fs.normalize(path))
+ local fullpath = vim.uv.fs_realpath(vim.fs.normalize(path))
if not fullpath then
return nil
end
@@ -149,13 +149,13 @@ function M.trust(opts)
local fullpath
if path then
- fullpath = vim.loop.fs_realpath(vim.fs.normalize(path))
+ fullpath = vim.uv.fs_realpath(vim.fs.normalize(path))
elseif bufnr then
local bufname = vim.api.nvim_buf_get_name(bufnr)
if bufname == '' then
return false, 'buffer is not associated with a file'
end
- fullpath = vim.loop.fs_realpath(vim.fs.normalize(bufname))
+ fullpath = vim.uv.fs_realpath(vim.fs.normalize(bufname))
else
error('one of "path" or "bufnr" is required')
end
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 244d88f3e0..cabfa8ccc0 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -170,11 +170,11 @@ end
---@param f fun(): R1, R2, R2
---@return integer, R1, R2, R3
local function tcall(f, ...)
- local start = vim.loop.hrtime()
+ local start = vim.uv.hrtime()
---@diagnostic disable-next-line
local r = { f(...) }
--- @type number
- local duration = (vim.loop.hrtime() - start) / 1000000
+ local duration = (vim.uv.hrtime() - start) / 1000000
return duration, unpack(r)
end
diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua
index 96289c45ec..7bc48a0662 100644
--- a/scripts/gen_help_html.lua
+++ b/scripts/gen_help_html.lua
@@ -461,6 +461,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
local hname = (node_text():gsub('%-%-%-%-+', ''):gsub('%=%=%=%=+', ''):gsub('%*.*%*', ''))
-- Use the first *tag* node as the heading anchor, if any.
local tagnode = first(root, 'tag')
+ -- Use the *tag* as the heading anchor id, if possible.
local tagname = tagnode and url_encode(node_text(tagnode:child(1), false)) or to_heading_tag(hname)
if node_name == 'h1' or #headings == 0 then
table.insert(headings, { name = hname, subheadings = {}, tag = tagname })
@@ -468,9 +469,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
table.insert(headings[#headings].subheadings, { name = hname, subheadings = {}, tag = tagname })
end
local el = node_name == 'h1' and 'h2' or 'h3'
- -- If we are re-using the *tag*, this heading anchor is redundant.
- local a = tagnode and '' or ('<a name="%s"></a>'):format(tagname)
- return ('%s<%s class="help-heading">%s</%s>\n'):format(a, el, text, el)
+ return ('<%s id="%s" class="help-heading">%s</%s>\n'):format(el, tagname, text, el)
elseif node_name == 'column_heading' or node_name == 'column_name' then
if root:has_error() then
return text
@@ -563,12 +562,14 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
return ''
end
local el = in_heading and 'span' or 'code'
- local s = ('%s<a name="%s"></a><%s class="%s">%s</%s>'):format(ws(), url_encode(tagname), el, cssclass, trimmed, el)
+ local s = ('%s<%s id="%s" class="%s">%s</%s>'):format(ws(), el, url_encode(tagname), cssclass, trimmed, el)
if opt.old then
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
if in_heading and prev ~= 'tag' then
+ -- Don't set "id", let the heading use the tag as its "id" (used by search engines).
+ s = ('%s<%s class="%s">%s</%s>'):format(ws(), el, cssclass, trimmed, el)
-- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2>
@@ -643,7 +644,7 @@ local function parse_buf(fname)
buf = fname
vim.cmd('sbuffer '..tostring(fname)) -- Buffer number.
end
- -- vim.treesitter.require_language('help', './build/lib/nvim/parser/vimdoc.so')
+ -- vim.treesitter.language.add('vimdoc', { path = vim.fn.expand('~/Library/Caches/tree-sitter/lib/vimdoc.so') })
local lang_tree = vim.treesitter.get_parser(buf)
return lang_tree, buf
end
@@ -784,7 +785,7 @@ local function gen_one(fname, to_fname, old, commit)
<div class="container golden-grid help-body">
<div class="col-wide">
- <a name="%s"></a><a name="%s"></a><h1>%s</h1>
+ <a name="%s"></a><h1 id="%s">%s</h1>
<p>
<i>
Nvim <code>:help</code> pages, <a href="https://github.com/neovim/neovim/blob/master/scripts/gen_help_html.lua">generated</a>
@@ -795,7 +796,7 @@ local function gen_one(fname, to_fname, old, commit)
<hr/>
%s
</div>
- ]]):format(logo_svg, stats.first_tags[1] or '', stats.first_tags[2] or '', title, vim.fs.basename(fname), main)
+ ]]):format(logo_svg, stats.first_tags[2] or '', stats.first_tags[1] or '', title, vim.fs.basename(fname), main)
local toc = [[
<div class="col-narrow toc">
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 14937cfd8f..0e06594663 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -347,7 +347,7 @@ cleanup:
/// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
/// pattern = {"*.c", "*.h"},
/// callback = function(ev)
-/// print(string.format('event fired: %s', vim.inspect(ev)))
+/// print(string.format('event fired: \%s', vim.inspect(ev)))
/// end
/// })
/// </pre>
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 36163859eb..4722195fe4 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -2180,7 +2180,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0;
if (wp->w_p_cul) {
- if (statuscol.foldinfo.fi_level > 0 && statuscol.foldinfo.fi_lines > 0) {
+ if (statuscol.foldinfo.fi_level != 0 && statuscol.foldinfo.fi_lines > 0) {
wp->w_cursorline = statuscol.foldinfo.fi_lnum;
}
statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR);
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 4968e667ed..49c4b6f32a 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -421,7 +421,7 @@ size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
size_t char_counter = 0;
int symbol = 0;
int len = 0;
- bool closed = foldinfo.fi_lines > 0;
+ bool closed = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
// Init to all spaces.
memset(p, ' ', MAX_MCO * (size_t)fdc + 1);
@@ -1021,21 +1021,21 @@ static void win_line_continue(winlinevars_T *wlv)
}
}
-/// Display line "lnum" of window 'wp' on the screen.
+/// Display line "lnum" of window "wp" on the screen.
/// wp->w_virtcol needs to be valid.
///
/// @param lnum line to display
/// @param startrow first row relative to window grid
/// @param endrow last grid row to be redrawn
-/// @param mod_top top line updated for changed text
/// @param number_only only update the number column
+/// @param spv 'spell' related variables kept between calls for "wp"
/// @param foldinfo fold info for this line
/// @param[in, out] providers decoration providers active this line
/// items will be disables if they cause errors
/// or explicitly return `false`.
///
/// @return the number of last row the line occupies.
-int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bool number_only,
+int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_only, spellvars_T *spv,
foldinfo_T foldinfo, DecorProviders *providers, char **provider_err)
{
winlinevars_T wlv; // variables passed between functions
@@ -1079,7 +1079,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
int eol_hl_off = 0; // 1 if highlighted char after EOL
bool draw_color_col = false; // highlight colorcolumn
int *color_cols = NULL; // pointer to according columns array
- bool has_spell = false; // this buffer has spell checking
#define SPWORDLEN 150
char nextline[SPWORDLEN * 2]; // text with start of the next line
int nextlinecol = 0; // column where nextline[] starts
@@ -1087,11 +1086,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
// starts
int spell_attr = 0; // attributes desired by spelling
int word_end = 0; // last byte with same spell_attr
- static linenr_T checked_lnum = 0; // line number for "checked_col"
- static int checked_col = 0; // column in "checked_lnum" up to which
- // there are no spell errors
- static int cap_col = -1; // column to check for Cap word
- static linenr_T capcol_lnum = 0; // line number where "cap_col"
int cur_checked_col = 0; // checked column for current line
int extra_check = 0; // has syntax or linebreak
int multi_attr = 0; // attributes desired by multibyte
@@ -1203,43 +1197,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
}
- if (!has_fold && !end_fill && spell_check_window(wp)) {
- // Prepare for spell checking.
- has_spell = true;
- extra_check = true;
-
- // Get the start of the next line, so that words that wrap to the next
- // line are found too: "et<line-break>al.".
- // Trick: skip a few chars for C/shell/Vim comments
- nextline[SPWORDLEN] = NUL;
- if (lnum < wp->w_buffer->b_ml.ml_line_count) {
- line = ml_get_buf(wp->w_buffer, lnum + 1, false);
- spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
- }
-
- // When a word wrapped from the previous line the start of the current
- // line is valid.
- if (lnum == checked_lnum) {
- cur_checked_col = checked_col;
- }
- checked_lnum = 0;
-
- // When there was a sentence end in the previous line may require a
- // word starting with capital in this line. In line 1 always check
- // the first word. Also check for sentence end in the line above
- // when updating the first row in a window, the top line with
- // changed text in a window, or if the previous line is folded.
- if (lnum == 1
- || ((startrow == 0 || mod_top == lnum
- || hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL))
- && check_need_cap(wp, lnum, 0))) {
- cap_col = 0;
- } else if (lnum != capcol_lnum) {
- cap_col = -1;
- }
- capcol_lnum = 0;
- }
-
// handle Visual active in this window
if (VIsual_active && wp->w_buffer == curwin->w_buffer) {
pos_T *top, *bot;
@@ -1420,18 +1377,46 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
line_attr_lowprio_save = wlv.line_attr_lowprio;
}
- line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum, false);
- ptr = line;
-
- if (has_spell && !number_only) {
- // For checking first word with a capital skip white space.
- if (cap_col == 0) {
- cap_col = (int)getwhitecols(line);
- }
+ if (spv->spv_has_spell && !number_only) {
+ // Prepare for spell checking.
+ extra_check = true;
- // To be able to spell-check over line boundaries copy the end of the
- // current line into nextline[]. Above the start of the next line was
- // copied to nextline[SPWORDLEN].
+ // When a word wrapped from the previous line the start of the
+ // current line is valid.
+ if (lnum == spv->spv_checked_lnum) {
+ cur_checked_col = spv->spv_checked_col;
+ }
+ // Previous line was not spell checked, check for capital. This happens
+ // for the first line in an updated region or after a closed fold.
+ if (spv->spv_capcol_lnum == 0 && check_need_cap(wp, lnum, 0)) {
+ spv->spv_cap_col = 0;
+ } else if (lnum != spv->spv_capcol_lnum) {
+ spv->spv_cap_col = -1;
+ }
+ spv->spv_checked_lnum = 0;
+
+ // Get the start of the next line, so that words that wrap to the
+ // next line are found too: "et<line-break>al.".
+ // Trick: skip a few chars for C/shell/Vim comments
+ nextline[SPWORDLEN] = NUL;
+ if (lnum < wp->w_buffer->b_ml.ml_line_count) {
+ line = ml_get_buf(wp->w_buffer, lnum + 1, false);
+ spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
+ }
+ assert(!end_fill);
+ line = ml_get_buf(wp->w_buffer, lnum, false);
+
+ // If current line is empty, check first word in next line for capital.
+ ptr = skipwhite(line);
+ if (*ptr == NUL) {
+ spv->spv_cap_col = 0;
+ spv->spv_capcol_lnum = lnum + 1;
+ } else if (spv->spv_cap_col == 0) {
+ // For checking first word with a capital skip white space.
+ spv->spv_cap_col = (int)(ptr - line);
+ }
+
+ // Copy the end of the current line into nextline[].
if (nextline[SPWORDLEN] == NUL) {
// No next line or it is empty.
nextlinecol = MAXCOL;
@@ -1454,6 +1439,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
}
}
+ line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum, false);
+ ptr = line;
+
colnr_T trailcol = MAXCOL; // start of trailing spaces
colnr_T leadcol = 0; // start of leading spaces
@@ -1541,7 +1529,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
}
// When spell checking a word we need to figure out the start of the
// word and if it's badly spelled or not.
- if (has_spell) {
+ if (spv->spv_has_spell) {
size_t len;
colnr_T linecol = (colnr_T)(ptr - line);
hlf_T spell_hlf = HLF_COUNT;
@@ -1807,7 +1795,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
int extmark_attr = 0;
if (wlv.draw_state == WL_LINE
- && (area_highlighting || has_spell || extra_check)) {
+ && (area_highlighting || spv->spv_has_spell || extra_check)) {
// handle Visual or match highlighting in this line
if (wlv.vcol == wlv.fromcol
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
@@ -1825,13 +1813,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
area_active = false;
}
- if (!has_fold) {
- if (has_decor && v >= 0) {
- bool selected = (area_active || (area_highlighting && noinvcur
- && wlv.vcol == wp->w_virtcol));
- extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off,
- selected, &decor_state);
+ if (has_decor && v >= 0) {
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && wlv.vcol == wp->w_virtcol));
+ extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, selected, &decor_state);
+ if (!has_fold) {
bool do_save = false;
handle_inline_virtual_text(wp, &wlv, v, &do_save);
if (do_save) {
@@ -1847,43 +1834,43 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
n_skip = 0;
}
}
+ }
- if (wlv.n_extra == 0) {
- // Check for start/end of 'hlsearch' and other matches.
- // After end, check for start/end of next match.
- // When another match, have to check for start again.
- v = (ptr - line);
- search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
- &has_match_conc, &match_conc, lcs_eol_one,
- &on_last_col, &search_attr_from_match);
- ptr = line + v; // "line" may have been changed
-
- // Do not allow a conceal over EOL otherwise EOL will be missed
- // and bad things happen.
- if (*ptr == NUL) {
- has_match_conc = 0;
- }
+ if (wlv.n_extra == 0) {
+ // Check for start/end of 'hlsearch' and other matches.
+ // After end, check for start/end of next match.
+ // When another match, have to check for start again.
+ v = (ptr - line);
+ search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
+ &has_match_conc, &match_conc, lcs_eol_one,
+ &on_last_col, &search_attr_from_match);
+ ptr = line + v; // "line" may have been changed
+
+ // Do not allow a conceal over EOL otherwise EOL will be missed
+ // and bad things happen.
+ if (*ptr == NUL) {
+ has_match_conc = 0;
}
+ }
- if (wlv.diff_hlf != (hlf_T)0) {
- // When there is extra text (eg: virtual text) it gets the
- // diff highlighting for the line, but not for changed text.
- if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start
- && wlv.n_extra == 0) {
- wlv.diff_hlf = HLF_TXD; // changed text
- }
- if (wlv.diff_hlf == HLF_TXD && ((ptr - line > change_end && wlv.n_extra == 0)
- || (wlv.n_extra > 0 && wlv.extra_for_extmark))) {
- wlv.diff_hlf = HLF_CHD; // changed line
- }
- wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
- // Overlay CursorLine onto diff-mode highlight.
- if (wlv.cul_attr) {
- wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine
- ? hl_combine_attr(hl_combine_attr(wlv.cul_attr, wlv.line_attr),
- hl_get_underline())
- : hl_combine_attr(wlv.line_attr, wlv.cul_attr);
- }
+ if (wlv.diff_hlf != (hlf_T)0) {
+ // When there is extra text (eg: virtual text) it gets the
+ // diff highlighting for the line, but not for changed text.
+ if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start
+ && wlv.n_extra == 0) {
+ wlv.diff_hlf = HLF_TXD; // changed text
+ }
+ if (wlv.diff_hlf == HLF_TXD && ((ptr - line > change_end && wlv.n_extra == 0)
+ || (wlv.n_extra > 0 && wlv.extra_for_extmark))) {
+ wlv.diff_hlf = HLF_CHD; // changed line
+ }
+ wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
+ // Overlay CursorLine onto diff-mode highlight.
+ if (wlv.cul_attr) {
+ wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine
+ ? hl_combine_attr(hl_combine_attr(wlv.cul_attr, wlv.line_attr),
+ hl_get_underline())
+ : hl_combine_attr(wlv.line_attr, wlv.cul_attr);
}
}
@@ -1995,7 +1982,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
}
wlv.extra_for_extmark = false;
}
- } else if (foldinfo.fi_lines > 0) {
+ } else if (has_fold) {
// skip writing the buffer line itself
c = NUL;
} else {
@@ -2126,7 +2113,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
did_emsg = false;
decor_attr = get_syntax_attr((colnr_T)v - 1,
- has_spell ? &can_spell : NULL, false);
+ spv->spv_has_spell ? &can_spell : NULL, false);
if (did_emsg) { // -V547
wp->w_s->b_syn_error = true;
@@ -2185,7 +2172,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
// @Spell cluster is not used or the current syntax item
// contains the @Spell cluster.
v = (ptr - line);
- if (has_spell && v >= word_end && v > cur_checked_col) {
+ if (spv->spv_has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0;
char *prev_ptr = ptr - mb_l;
// do not calculate cap_col at the end of the line or when
@@ -2202,8 +2189,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
} else {
p = prev_ptr;
}
- cap_col -= (int)(prev_ptr - line);
- size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, mod_top == 0);
+ spv->spv_cap_col -= (int)(prev_ptr - line);
+ size_t tmplen = spell_check(wp, p, &spell_hlf, &spv->spv_cap_col, spv->spv_unchanged);
assert(tmplen <= INT_MAX);
int len = (int)tmplen;
word_end = (int)v + len;
@@ -2224,8 +2211,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
&& (p - nextline) + len > nextline_idx) {
// Remember that the good word continues at the
// start of the next line.
- checked_lnum = lnum + 1;
- checked_col = (int)((p - nextline) + len - nextline_idx);
+ spv->spv_checked_lnum = lnum + 1;
+ spv->spv_checked_col = (int)((p - nextline) + len - nextline_idx);
}
// Turn index into actual attributes.
@@ -2233,17 +2220,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
spell_attr = highlight_attr[spell_hlf];
}
- if (cap_col > 0) {
- if (p != prev_ptr
- && (p - nextline) + cap_col >= nextline_idx) {
+ if (spv->spv_cap_col > 0) {
+ if (p != prev_ptr && (p - nextline) + spv->spv_cap_col >= nextline_idx) {
// Remember that the word in the next line
// must start with a capital.
- capcol_lnum = lnum + 1;
- cap_col = (int)((p - nextline) + cap_col
- - nextline_idx);
+ spv->spv_capcol_lnum = lnum + 1;
+ spv->spv_cap_col = (int)((p - nextline) + spv->spv_cap_col - nextline_idx);
} else {
// Compute the actual column.
- cap_col += (int)(prev_ptr - line);
+ spv->spv_cap_col += (int)(prev_ptr - line);
}
}
}
@@ -2767,8 +2752,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
? 1 : 0);
if (has_decor) {
- has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr,
- wlv.col + eol_skip);
+ has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip);
}
if (((wp->w_p_cuc
@@ -2862,7 +2846,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
if (wp == curwin && lnum == curwin->w_cursor.lnum) {
curwin->w_cline_row = startrow;
curwin->w_cline_height = wlv.row - startrow;
- curwin->w_cline_folded = foldinfo.fi_lines > 0;
+ curwin->w_cline_folded = has_fold;
curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
conceal_cursor_used = conceal_cursor_line(curwin);
}
@@ -3152,12 +3136,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bo
}
} // for every character in the line
- // After an empty line check first word for capital.
- if (*skipwhite(line) == NUL) {
- capcol_lnum = lnum + 1;
- cap_col = 0;
- }
-
kv_destroy(virt_lines);
xfree(wlv.p_extra_free);
return wlv.row;
diff --git a/src/nvim/drawline.h b/src/nvim/drawline.h
index 91261aba78..9a917df0c5 100644
--- a/src/nvim/drawline.h
+++ b/src/nvim/drawline.h
@@ -23,6 +23,17 @@ EXTERN kvec_t(WinExtmark) win_extmark_arr INIT(= KV_INITIAL_VALUE);
EXTERN bool conceal_cursor_used INIT(= false);
+// Spell checking variables passed from win_update() to win_line().
+typedef struct {
+ bool spv_has_spell; ///< drawn window has spell checking
+ bool spv_unchanged; ///< not updating for changed text
+ int spv_checked_col; ///< column in "checked_lnum" up to
+ ///< which there are no spell errors
+ linenr_T spv_checked_lnum; ///< line number for "checked_col"
+ int spv_cap_col; ///< column to check for Cap word
+ linenr_T spv_capcol_lnum; ///< line number for "cap_col"
+} spellvars_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "drawline.h.generated.h"
#endif
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 4f79ba87af..28a029d758 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -95,6 +95,7 @@
#include "nvim/profile.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
+#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/statusline.h"
#include "nvim/syntax.h"
@@ -1984,18 +1985,25 @@ static void win_update(win_T *wp, DecorProviders *providers)
if (wp->w_p_cul) {
// Make sure that the cursorline on a closed fold is redrawn
cursorline_fi = fold_info(wp, wp->w_cursor.lnum);
- if (cursorline_fi.fi_level > 0 && cursorline_fi.fi_lines > 0) {
+ if (cursorline_fi.fi_level != 0 && cursorline_fi.fi_lines > 0) {
wp->w_cursorline = cursorline_fi.fi_lnum;
}
}
win_check_ns_hl(wp);
+ spellvars_T spv = { 0 };
+ linenr_T lnum = wp->w_topline; // first line shown in window
+ // Initialize spell related variables for the first drawn line.
+ if (spell_check_window(wp)) {
+ spv.spv_has_spell = true;
+ spv.spv_unchanged = mod_top == 0;
+ }
+
// Update all the window rows.
int idx = 0; // first entry in w_lines[].wl_size
int row = 0; // current window row to display
int srow = 0; // starting row of the current line
- linenr_T lnum = wp->w_topline; // first line shown in window
bool eof = false; // if true, we hit the end of the file
bool didline = false; // if true, we finished the last line
@@ -2222,8 +2230,10 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// Display one line
- row = win_line(wp, lnum, srow, foldinfo.fi_lines ? srow : wp->w_grid.rows,
- mod_top, false, foldinfo, &line_providers, &provider_err);
+ spellvars_T zero_spv = { 0 };
+ row = win_line(wp, lnum, srow, foldinfo.fi_lines > 0 ? srow : wp->w_grid.rows, false,
+ foldinfo.fi_lines > 0 ? &zero_spv : &spv,
+ foldinfo, &line_providers, &provider_err);
if (foldinfo.fi_lines == 0) {
wp->w_lines[idx].wl_folded = false;
@@ -2235,6 +2245,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines[idx].wl_folded = true;
wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines;
did_update = DID_FOLD;
+ spv.spv_capcol_lnum = 0;
}
}
@@ -2260,7 +2271,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// text doesn't need to be drawn, but the number column does.
foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
cursorline_fi : fold_info(wp, lnum);
- (void)win_line(wp, lnum, srow, wp->w_grid.rows, mod_top, true,
+ (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, &spv,
info, &line_providers, &provider_err);
}
@@ -2271,6 +2282,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
did_update = DID_NONE;
+ spv.spv_capcol_lnum = 0;
}
// 'statuscolumn' width has changed or errored, start from the top.
@@ -2356,9 +2368,10 @@ static void win_update(win_T *wp, DecorProviders *providers)
if (j > 0 && !wp->w_botfill && row < wp->w_grid.rows) {
// Display filler text below last line. win_line() will check
// for ml_line_count+1 and only draw filler lines
- foldinfo_T info = { 0 };
- row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
- mod_top, false, info, &line_providers, &provider_err);
+ spellvars_T zero_spv = { 0 };
+ foldinfo_T zero_foldinfo = { 0 };
+ row = win_line(wp, wp->w_botline, row, wp->w_grid.rows, false, &zero_spv,
+ zero_foldinfo, &line_providers, &provider_err);
}
} else if (dollar_vcol == -1) {
wp->w_botline = lnum;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index d6d5ff8ac7..6b90c40c7c 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -2549,15 +2549,10 @@ int oneleft(void)
/// Move the cursor up "n" lines in window "wp".
/// Takes care of closed folds.
-/// Returns the new cursor line or zero for failure.
-linenr_T cursor_up_inner(win_T *wp, long n)
+void cursor_up_inner(win_T *wp, long n)
{
linenr_T lnum = wp->w_cursor.lnum;
- // This fails if the cursor is already in the first line.
- if (lnum <= 1) {
- return 0;
- }
if (n >= lnum) {
lnum = 1;
} else if (hasAnyFolding(wp)) {
@@ -2587,15 +2582,16 @@ linenr_T cursor_up_inner(win_T *wp, long n)
}
wp->w_cursor.lnum = lnum;
- return lnum;
}
/// @param upd_topline When true: update topline
int cursor_up(long n, int upd_topline)
{
- if (n > 0 && cursor_up_inner(curwin, n) == 0) {
+ // This fails if the cursor is already in the first line.
+ if (n > 0 && curwin->w_cursor.lnum <= 1) {
return FAIL;
}
+ cursor_up_inner(curwin, n);
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
@@ -2609,18 +2605,11 @@ int cursor_up(long n, int upd_topline)
/// Move the cursor down "n" lines in window "wp".
/// Takes care of closed folds.
-/// Returns the new cursor line or zero for failure.
-linenr_T cursor_down_inner(win_T *wp, long n)
+void cursor_down_inner(win_T *wp, long n)
{
linenr_T lnum = wp->w_cursor.lnum;
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
- // Move to last line of fold, will fail if it's the end-of-file.
- (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL);
- // This fails if the cursor is already in the last line.
- if (lnum >= line_count) {
- return FAIL;
- }
if (lnum + n >= line_count) {
lnum = line_count;
} else if (hasAnyFolding(wp)) {
@@ -2628,6 +2617,7 @@ linenr_T cursor_down_inner(win_T *wp, long n)
// count each sequence of folded lines as one logical line
while (n--) {
+ // Move to last line of fold, will fail if it's the end-of-file.
if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) {
lnum = last + 1;
} else {
@@ -2645,15 +2635,16 @@ linenr_T cursor_down_inner(win_T *wp, long n)
}
wp->w_cursor.lnum = lnum;
- return lnum;
}
/// @param upd_topline When true: update topline
int cursor_down(long n, int upd_topline)
{
- if (n > 0 && cursor_down_inner(curwin, n) == 0) {
+ // This fails if the cursor is already in the last line.
+ if (n > 0 && curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
return FAIL;
}
+ cursor_down_inner(curwin, n);
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 52924bf9a5..118c1d3012 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6511,6 +6511,10 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret
pos.coladd = 0;
if (name[0] == 'w' && dollar_lnum) {
+ // the "w_valid" flags are not reset when moving the cursor, but they
+ // do matter for update_topline() and validate_botline().
+ check_cursor_moved(curwin);
+
pos.col = 0;
if (name[1] == '0') { // "w0": first visible line
update_topline(curwin);
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 927c1b3d5c..04fd81c713 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -62,7 +62,7 @@
#include "nvim/getchar.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
-#include "nvim/grid_defs.h"
+#include "nvim/grid.h"
#include "nvim/hashtab.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
@@ -3238,7 +3238,7 @@ static bool has_wsl(void)
static TriState has_wsl = kNone;
if (has_wsl == kNone) {
Error err = ERROR_INIT;
- Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim.loop.os_uname()['release']:lower()"
+ Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim.uv.os_uname()['release']:lower()"
":match('microsoft') and true or false"),
(Array)ARRAY_DICT_INIT, &err);
assert(!ERROR_SET(&err));
@@ -6745,7 +6745,9 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) {
c = -1;
} else {
- c = utf_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col]);
+ char buf[MB_MAXBYTES + 1];
+ grid_getbytes(grid, row, col, buf, NULL);
+ c = utf_ptr2char(buf);
}
rettv->vval.v_number = c;
}
@@ -6763,10 +6765,13 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_list_alloc_ret(rettv, 0);
return;
}
+
+ char buf[MB_MAXBYTES + 1];
+ grid_getbytes(grid, row, col, buf, NULL);
int pcc[MAX_MCO];
- int c = utfc_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col], pcc);
+ int c = utfc_ptr2char(buf, pcc);
int composing_len = 0;
- while (pcc[composing_len] != 0) {
+ while (composing_len < MAX_MCO && pcc[composing_len] != 0) {
composing_len++;
}
tv_list_alloc_ret(rettv, composing_len + 1);
@@ -6806,7 +6811,9 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
return;
}
- rettv->vval.v_string = xstrdup((char *)grid->chars[grid->line_offset[row] + (size_t)col]);
+ char buf[MB_MAXBYTES + 1];
+ grid_getbytes(grid, row, col, buf, NULL);
+ rettv->vval.v_string = xstrdup(buf);
}
/// "search()" function
@@ -7201,7 +7208,7 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
/// Set the cursor or mark position.
-/// If 'charpos' is true, then use the column number as a character offset.
+/// If "charpos" is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index b0938fa711..88f3bc0b43 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2212,7 +2212,7 @@ module.cmds = {
},
{
command='registers',
- flags=bit.bor(EXTRA, NOTRLCOM, TRLBAR, CMDWIN, LOCK_OK),
+ flags=bit.bor(EXTRA, NOTRLCOM, TRLBAR, SBOXOK, CMDWIN, LOCK_OK),
addr_type='ADDR_NONE',
func='ex_display',
},
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 76dd2a073a..aa542c5a2f 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -138,8 +138,9 @@ void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr)
grid_puts(grid, buf, row, col, attr);
}
-/// get a single character directly from grid.chars into "bytes[]".
-/// Also return its attribute in *attrp;
+/// Get a single character directly from grid.chars into "bytes", which must
+/// have a size of "MB_MAXBYTES + 1".
+/// If "attrp" is not NULL, return the character's attribute in "*attrp".
void grid_getbytes(ScreenGrid *grid, int row, int col, char *bytes, int *attrp)
{
grid_adjust(&grid, &row, &col);
@@ -150,7 +151,9 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char *bytes, int *attrp)
}
size_t off = grid->line_offset[row] + (size_t)col;
- *attrp = grid->attrs[off];
+ if (attrp != NULL) {
+ *attrp = grid->attrs[off];
+ }
schar_copy(bytes, grid->chars[off]);
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 8c1d8addcd..36dcb6efcf 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -565,7 +565,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan
lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict");
lua_setfield(lstate, -2, "_empty_dict_mt");
- // vim.loop
+ // vim.uv
if (is_standalone) {
// do nothing, use libluv like in a standalone interpreter
} else if (is_thread) {
@@ -578,9 +578,9 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan
}
luaopen_luv(lstate);
lua_pushvalue(lstate, -1);
- lua_setfield(lstate, -3, "loop");
+ lua_setfield(lstate, -3, "uv");
- // package.loaded.luv = vim.loop
+ // package.loaded.luv = vim.uv
// otherwise luv will be reinitialized when require'luv'
lua_getglobal(lstate, "package");
lua_getfield(lstate, -1, "loaded");
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 9e8abbcd96..48691db26d 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -548,18 +548,20 @@ void set_topline(win_T *wp, linenr_T lnum)
redraw_later(wp, UPD_VALID);
}
-// Call this function when the length of the cursor line (in screen
-// characters) has changed, and the change is before the cursor.
-// Need to take care of w_botline separately!
+/// Call this function when the length of the cursor line (in screen
+/// characters) has changed, and the change is before the cursor.
+/// If the line length changed the number of screen lines might change,
+/// requiring updating w_topline. That may also invalidate w_crow.
+/// Need to take care of w_botline separately!
void changed_cline_bef_curs(void)
{
- curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
+ curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
|VALID_CHEIGHT|VALID_TOPLINE);
}
void changed_cline_bef_curs_win(win_T *wp)
{
- wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
+ wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
|VALID_CHEIGHT|VALID_TOPLINE);
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 60fff45323..f3909030c9 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2493,10 +2493,12 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant -= width2;
} else {
// to previous line
- if (!cursor_up_inner(curwin, 1)) {
+ if (curwin->w_cursor.lnum <= 1) {
retval = false;
break;
}
+ cursor_up_inner(curwin, 1);
+
linelen = linetabsize_str(get_cursor_line_ptr());
if (linelen > width1) {
int w = (((linelen - width1 - 1) / width2) + 1) * width2;
@@ -2516,11 +2518,13 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant += width2;
} else {
// to next line
- if (!cursor_down_inner(curwin, 1)) {
+ if (curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
retval = false;
break;
}
+ cursor_down_inner(curwin, 1);
curwin->w_curswant %= width2;
+
// Check if the cursor has moved below the number display
// when width1 < width2 (with cpoptions+=n). Subtract width2
// to get a negative value for w_curswant, which will get
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c39a3273da..2711c3d29c 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3484,6 +3484,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (lnum == curwin->w_cursor.lnum) {
// make sure curwin->w_virtcol is updated
changed_cline_bef_curs();
+ invalidate_botline();
curwin->w_cursor.col += (colnr_T)(totlen - 1);
}
changed_bytes(lnum, col);
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 4b27067fb8..964e2d0933 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -1926,8 +1926,8 @@ static void cmd_source_buffer(const exarg_T *const eap)
.buf = ga.ga_data,
.offset = 0,
};
- if (curbuf->b_fname
- && path_with_extension(curbuf->b_fname, "lua")) {
+ if (strequal(curbuf->b_p_ft, "lua")
+ || (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) {
nlua_source_using_linegetter(get_str_line, (void *)&cookie, ":source (no file)");
} else {
source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)");
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 90c8ba92f9..ebfa538afb 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1581,7 +1581,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// equalize the window sizes.
if (do_equal || dir != 0) {
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
- } else if (*p_spk != 'c' && !is_aucmd_win(wp)) {
+ } else if (!is_aucmd_win(wp)) {
win_fix_scroll(false);
}
@@ -2174,7 +2174,7 @@ void win_equal(win_T *next_curwin, bool current, int dir)
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
topframe, dir, 0, tabline_height(),
Columns, topframe->fr_height);
- if (*p_spk != 'c' && !is_aucmd_win(next_curwin)) {
+ if (!is_aucmd_win(next_curwin)) {
win_fix_scroll(true);
}
}
@@ -2970,9 +2970,7 @@ int win_close(win_T *win, bool free_buf, bool force)
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
} else {
(void)win_comp_pos();
- if (*p_spk != 'c') {
- win_fix_scroll(false);
- }
+ win_fix_scroll(false);
}
}
@@ -5364,7 +5362,7 @@ void win_new_screen_rows(void)
compute_cmdrow();
curtab->tp_ch_used = p_ch;
- if (*p_spk != 'c' && !skip_win_fix_scroll) {
+ if (!skip_win_fix_scroll) {
win_fix_scroll(true);
}
}
@@ -5811,9 +5809,7 @@ void win_setheight_win(int height, win_T *win)
msg_row = row;
msg_col = 0;
- if (*p_spk != 'c') {
- win_fix_scroll(true);
- }
+ win_fix_scroll(true);
redraw_all_later(UPD_NOT_VALID);
redraw_cmdline = true;
@@ -6293,9 +6289,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
curtab->tp_ch_used = p_ch;
- if (*p_spk != 'c') {
- win_fix_scroll(true);
- }
+ win_fix_scroll(true);
redraw_all_later(UPD_SOME_VALID);
showmode();
@@ -6414,15 +6408,18 @@ void set_fraction(win_T *wp)
}
}
-/// Handle scroll position for 'splitkeep'. Replaces scroll_to_fraction()
-/// call from win_set_inner_size(). Instead we iterate over all windows in a
-/// tabpage and calculate the new scroll position.
-/// TODO(luukvbaal): Ensure this also works with wrapped lines.
-/// Requires topline to be able to be set to a bufferline with some
-/// offset(row-wise scrolling/smoothscroll).
+/// Handle scroll position, depending on 'splitkeep'. Replaces the
+/// scroll_to_fraction() call from win_new_height() if 'splitkeep' is "screen"
+/// or "topline". Instead we iterate over all windows in a tabpage and
+/// calculate the new scroll position.
+/// TODO(vim): Ensure this also works with wrapped lines.
+/// Requires a not fully visible cursor line to be allowed at the bottom of
+/// a window("zb"), probably only when 'smoothscroll' is also set.
void win_fix_scroll(int resize)
{
- linenr_T lnum;
+ if (*p_spk == 'c') {
+ return; // 'splitkeep' is "cursor"
+ }
skip_update_topline = true;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -6431,17 +6428,20 @@ void win_fix_scroll(int resize)
// If window has moved update botline to keep the same screenlines.
if (*p_spk == 's' && wp->w_winrow != wp->w_prev_winrow
&& wp->w_botline - 1 <= wp->w_buffer->b_ml.ml_line_count) {
- lnum = wp->w_cursor.lnum;
int diff = (wp->w_winrow - wp->w_prev_winrow)
+ (wp->w_height - wp->w_prev_height);
+ linenr_T lnum = wp->w_cursor.lnum;
wp->w_cursor.lnum = wp->w_botline - 1;
+
// Add difference in height and row to botline.
if (diff > 0) {
cursor_down_inner(wp, diff);
} else {
cursor_up_inner(wp, -diff);
}
- // Bring the new cursor position to the bottom of the screen.
+
+ // Scroll to put the new cursor position at the bottom of the
+ // screen.
wp->w_fraction = FRACTION_MULT;
scroll_to_fraction(wp, wp->w_prev_height);
wp->w_cursor.lnum = lnum;
@@ -6470,36 +6470,37 @@ void win_fix_scroll(int resize)
static void win_fix_cursor(int normal)
{
win_T *wp = curwin;
- long so = get_scrolloff_value(wp);
- linenr_T nlnum = 0;
- linenr_T lnum = wp->w_cursor.lnum;
- if (wp->w_buffer->b_ml.ml_line_count < wp->w_height
- || skip_win_fix_cursor) {
+ if (skip_win_fix_cursor || wp->w_buffer->b_ml.ml_line_count < wp->w_height) {
return;
}
// Determine valid cursor range.
- so = MIN(wp->w_height_inner / 2, so);
+ long so = MIN(wp->w_height_inner / 2, get_scrolloff_value(wp));
+ linenr_T lnum = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = wp->w_topline;
- linenr_T top = cursor_down_inner(wp, so);
+ cursor_down_inner(wp, so);
+ linenr_T top = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = wp->w_botline - 1;
- linenr_T bot = cursor_up_inner(wp, so);
+ cursor_up_inner(wp, so);
+ linenr_T bot = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = lnum;
// Check if cursor position is above or below valid cursor range.
+ linenr_T nlnum = 0;
if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1) {
nlnum = bot;
} else if (lnum < top && wp->w_topline != 1) {
nlnum = (so == wp->w_height / 2) ? bot : top;
}
- if (nlnum) { // Cursor is invalid for current scroll position.
- if (normal) {
- // Save to jumplist and set cursor to avoid scrolling.
+ if (nlnum != 0) { // Cursor is invalid for current scroll position.
+ if (normal) { // Save to jumplist and set cursor to avoid scrolling.
setmark('\'');
wp->w_cursor.lnum = nlnum;
- } else {
- // Scroll instead when not in normal mode.
+ } else { // Scroll instead when not in normal mode.
wp->w_fraction = (nlnum == bot) ? FRACTION_MULT : 0;
scroll_to_fraction(wp, wp->w_prev_height);
validate_botline(curwin);
diff --git a/test/benchmark/autocmd_spec.lua b/test/benchmark/autocmd_spec.lua
index f243d9c94d..cd1af23640 100644
--- a/test/benchmark/autocmd_spec.lua
+++ b/test/benchmark/autocmd_spec.lua
@@ -12,10 +12,10 @@ describe('autocmd perf', function()
exec_lua([[
out = {}
function start()
- ts = vim.loop.hrtime()
+ ts = vim.uv.hrtime()
end
function stop(name)
- out[#out+1] = ('%14.6f ms - %s'):format((vim.loop.hrtime() - ts) / 1000000, name)
+ out[#out+1] = ('%14.6f ms - %s'):format((vim.uv.hrtime() - ts) / 1000000, name)
end
]])
end)
diff --git a/test/benchmark/iter_spec.lua b/test/benchmark/iter_spec.lua
index 8d77054e83..d176079997 100644
--- a/test/benchmark/iter_spec.lua
+++ b/test/benchmark/iter_spec.lua
@@ -35,9 +35,9 @@ describe('vim.iter perf', function()
local stats = {}
local result
for _ = 1, N do
- local tic = vim.loop.hrtime()
+ local tic = vim.uv.hrtime()
result = f(input)
- local toc = vim.loop.hrtime()
+ local toc = vim.uv.hrtime()
stats[#stats + 1] = (toc - tic) / 1000000
end
table.sort(stats)
diff --git a/test/benchmark/treesitter_spec.lua b/test/benchmark/treesitter_spec.lua
index 5ce128c54a..6d82f5de8d 100644
--- a/test/benchmark/treesitter_spec.lua
+++ b/test/benchmark/treesitter_spec.lua
@@ -37,7 +37,7 @@ describe('treesitter perf', function()
return "qq" .. acc .. "q"
end
- local start = vim.loop.hrtime()
+ local start = vim.uv.hrtime()
keys(mk_keys(10))
for _ = 1, 100 do
@@ -45,7 +45,7 @@ describe('treesitter perf', function()
vim.cmd'redraw!'
end
- return vim.loop.hrtime() - start
+ return vim.uv.hrtime() - start
]]
end)
diff --git a/test/busted_runner.lua b/test/busted_runner.lua
index 5604790069..d6864c6492 100644
--- a/test/busted_runner.lua
+++ b/test/busted_runner.lua
@@ -1,4 +1,4 @@
-local platform = vim.loop.os_uname()
+local platform = vim.uv.os_uname()
local deps_install_dir = os.getenv 'DEPS_INSTALL_DIR'
local suffix = (platform and platform.sysname:lower():find'windows') and '.dll' or '.so'
package.path = deps_install_dir.."/share/lua/5.1/?.lua;"..deps_install_dir.."/share/lua/5.1/?/init.lua;"..package.path
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index fe1b8e1c4e..54886d0c43 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -110,7 +110,7 @@ describe('startup', function()
exec_lua [[
local asan_options = os.getenv 'ASAN_OPTIONS'
if asan_options ~= nil and asan_options ~= '' then
- vim.loop.os_setenv('ASAN_OPTIONS', asan_options..':detect_leaks=0')
+ vim.uv.os_setenv('ASAN_OPTIONS', asan_options..':detect_leaks=0')
end
]]
-- nvim -l foo.lua -arg1 -- a b c
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 02f5bff021..24987354a4 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -7,6 +7,7 @@ local meths = helpers.meths
local feed = helpers.feed
local feed_command = helpers.feed_command
local write_file = helpers.write_file
+local tmpname = helpers.tmpname
local exec = helpers.exec
local exc_exec = helpers.exc_exec
local exec_lua = helpers.exec_lua
@@ -179,56 +180,65 @@ describe(':source', function()
os.remove(test_file)
end)
- it('can source selected region in lua file', function()
- local test_file = 'test.lua'
-
- write_file (test_file, [[
- vim.g.b = 5
- vim.g.b = 6
- vim.g.b = 7
- a = [=[
- "\ a
- \ b]=]
- ]])
-
- command('edit '..test_file)
-
- feed('ggjV')
- feed_command(':source')
- eq(6, eval('g:b'))
-
- feed('GVkk')
- feed_command(':source')
- eq(' "\\ a\n \\ b', exec_lua('return _G.a'))
-
- os.remove(test_file)
- end)
-
- it('can source current lua buffer without argument', function()
- local test_file = 'test.lua'
-
- write_file(test_file, [[
- vim.g.c = 10
- vim.g.c = 11
- vim.g.c = 12
- a = [=[
- \ 1
- "\ 2]=]
- vim.g.sfile_value = vim.fn.expand('<sfile>')
- vim.g.stack_value = vim.fn.expand('<stack>')
- vim.g.script_value = vim.fn.expand('<script>')
- ]])
-
- command('edit '..test_file)
- feed_command(':source')
-
- eq(12, eval('g:c'))
- eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
- eq(':source (no file)', meths.get_var('sfile_value'))
- eq(':source (no file)', meths.get_var('stack_value'))
- eq(':source (no file)', meths.get_var('script_value'))
+ describe('can source current buffer', function()
+ local function test_source_lua_curbuf()
+ it('selected region', function()
+ insert([[
+ vim.g.b = 5
+ vim.g.b = 6
+ vim.g.b = 7
+ a = [=[
+ "\ a
+ \ b]=]
+ ]])
+ feed('dd')
+
+ feed('ggjV')
+ feed_command(':source')
+ eq(6, eval('g:b'))
+
+ feed('GVkk')
+ feed_command(':source')
+ eq(' "\\ a\n \\ b', exec_lua('return _G.a'))
+ end)
+
+ it('whole buffer', function()
+ insert([[
+ vim.g.c = 10
+ vim.g.c = 11
+ vim.g.c = 12
+ a = [=[
+ \ 1
+ "\ 2]=]
+ vim.g.sfile_value = vim.fn.expand('<sfile>')
+ vim.g.stack_value = vim.fn.expand('<stack>')
+ vim.g.script_value = vim.fn.expand('<script>')
+ ]])
+ feed('dd')
+
+ feed_command(':source')
+
+ eq(12, eval('g:c'))
+ eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
+ eq(':source (no file)', meths.get_var('sfile_value'))
+ eq(':source (no file)', meths.get_var('stack_value'))
+ eq(':source (no file)', meths.get_var('script_value'))
+ end)
+ end
- os.remove(test_file)
+ describe('with ft=lua', function()
+ before_each(function()
+ command('setlocal ft=lua')
+ end)
+ test_source_lua_curbuf()
+ end)
+
+ describe('with .lua extension', function()
+ before_each(function()
+ command('edit ' .. tmpname() .. '.lua')
+ end)
+ test_source_lua_curbuf()
+ end)
end)
it("doesn't throw E484 for lua parsing/runtime errors", function()
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 001cd5770a..dc0428afdc 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -950,7 +950,7 @@ local test_name = arg[1]
local timeout = arg[2]
assert(type(test_name) == 'string', 'test_name must be specified as first arg.')
-local kill_timer = vim.loop.new_timer()
+local kill_timer = vim.uv.new_timer()
kill_timer:start(timeout or 1e3, 0, function()
kill_timer:stop()
kill_timer:close()
diff --git a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
index 45226ce24b..ffbd8a4f83 100644
--- a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
+++ b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
@@ -1,5 +1,5 @@
return function (val, res)
local handle
- handle = vim.loop.new_async(function() _G[res] = require'leftpad'(val) handle:close() end)
+ handle = vim.uv.new_async(function() _G[res] = require'leftpad'(val) handle:close() end)
handle:send()
end
diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
index e83fde774a..4a42a1c8a3 100644
--- a/test/functional/legacy/put_spec.lua
+++ b/test/functional/legacy/put_spec.lua
@@ -70,4 +70,29 @@ describe('put', function()
|
]])
end)
+
+ -- oldtest: Test_put_in_last_displayed_line()
+ it('in last displayed line', function()
+ local screen = Screen.new(75, 10)
+ screen:attach()
+ source([[
+ autocmd CursorMoved * eval line('w$')
+ let @a = 'x'->repeat(&columns * 2 - 2)
+ eval range(&lines)->setline(1)
+ call feedkeys('G"ap')
+ ]])
+
+ screen:expect([[
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ 6 |
+ 7 |
+ 8 |
+ 9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x |
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua
index 60d0ed5017..8e499f1e79 100644
--- a/test/functional/lua/highlight_spec.lua
+++ b/test/functional/lua/highlight_spec.lua
@@ -24,7 +24,7 @@ describe('vim.highlight.on_yank', function()
it('does not close timer twice', function()
exec_lua([[
vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}})
- vim.loop.sleep(10)
+ vim.uv.sleep(10)
vim.schedule(function()
vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}})
end)
diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua
index 7f3787d7bf..c0924fa0c0 100644
--- a/test/functional/lua/loop_spec.lua
+++ b/test/functional/lua/loop_spec.lua
@@ -14,24 +14,24 @@ local retry = helpers.retry
before_each(clear)
-describe('vim.loop', function()
+describe('vim.uv', function()
it('version', function()
- assert(funcs.luaeval('vim.loop.version()')>=72961, "libuv version too old")
- matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.loop.version_string()'))
+ assert(funcs.luaeval('vim.uv.version()')>=72961, "libuv version too old")
+ matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.uv.version_string()'))
end)
it('timer', function()
exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
local code=[[
- local loop = vim.loop
+ local uv = vim.uv
local touch = 0
local function wait(ms)
local this = coroutine.running()
assert(this)
- local timer = loop.new_timer()
+ local timer = uv.new_timer()
timer:start(ms, 0, vim.schedule_wrap(function ()
timer:close()
touch = touch + 1
@@ -73,7 +73,7 @@ describe('vim.loop', function()
-- deferred API functions are disabled, as their safety can't be guaranteed
exec_lua([[
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(20, 0, function ()
_G.is_fast = vim.in_fast_event()
timer:close()
@@ -101,7 +101,7 @@ describe('vim.loop', function()
-- callbacks can be scheduled to be executed in the main event loop
-- where the entire API is available
exec_lua([[
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(20, 0, vim.schedule_wrap(function ()
_G.is_fast = vim.in_fast_event()
timer:close()
@@ -127,7 +127,7 @@ describe('vim.loop', function()
-- fast (not deferred) API functions are allowed to be called directly
exec_lua([[
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(20, 0, function ()
timer:close()
-- input is queued for processing after the callback returns
@@ -151,6 +151,6 @@ describe('vim.loop', function()
end)
it("is equal to require('luv')", function()
- eq(true, exec_lua("return vim.loop == require('luv')"))
+ eq(true, exec_lua("return vim.uv == require('luv')"))
end)
end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 68e2525151..0fd8cb2f6a 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -119,7 +119,7 @@ describe('print', function()
exec_lua([[
local cmd = ...
function test()
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
local done = false
timer:start(10, 0, function()
print("very fast")
@@ -130,7 +130,7 @@ describe('print', function()
-- loop until we know for sure the callback has been executed
while not done do
os.execute(cmd)
- vim.loop.run("nowait") -- fake os_breakcheck()
+ vim.uv.run("nowait") -- fake os_breakcheck()
end
print("very slow")
vim.api.nvim_command("sleep 1m") -- force deferred event processing
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
index c7f2783cf3..e79d26a641 100644
--- a/test/functional/lua/thread_spec.lua
+++ b/test/functional/lua/thread_spec.lua
@@ -27,10 +27,10 @@ describe('thread', function()
it('entry func is executed in protected mode', function()
exec_lua [[
- local thread = vim.loop.new_thread(function()
+ local thread = vim.uv.new_thread(function()
error('Error in thread entry func')
end)
- vim.loop.thread_join(thread)
+ vim.uv.thread_join(thread)
]]
screen:expect([[
@@ -51,17 +51,17 @@ describe('thread', function()
it('callback is executed in protected mode', function()
exec_lua [[
- local thread = vim.loop.new_thread(function()
- local timer = vim.loop.new_timer()
+ local thread = vim.uv.new_thread(function()
+ local timer = vim.uv.new_timer()
local function ontimeout()
timer:stop()
timer:close()
error('Error in thread callback')
end
timer:start(10, 0, ontimeout)
- vim.loop.run()
+ vim.uv.run()
end)
- vim.loop.thread_join(thread)
+ vim.uv.thread_join(thread)
]]
screen:expect([[
@@ -83,10 +83,10 @@ describe('thread', function()
describe('print', function()
it('works', function()
exec_lua [[
- local thread = vim.loop.new_thread(function()
+ local thread = vim.uv.new_thread(function()
print('print in thread')
end)
- vim.loop.thread_join(thread)
+ vim.uv.thread_join(thread)
]]
screen:expect([[
@@ -105,10 +105,10 @@ describe('thread', function()
it('vim.inspect', function()
exec_lua [[
- local thread = vim.loop.new_thread(function()
+ local thread = vim.uv.new_thread(function()
print(vim.inspect({1,2}))
end)
- vim.loop.thread_join(thread)
+ vim.uv.thread_join(thread)
]]
screen:expect([[
@@ -140,13 +140,13 @@ describe('thread', function()
function Thread_Test:do_test()
local async
local on_async = self.on_async
- async = vim.loop.new_async(function(ret)
+ async = vim.uv.new_async(function(ret)
on_async(ret)
async:close()
end)
local thread =
- vim.loop.new_thread(self.entry_func, async, self.entry_str, self.args)
- vim.loop.thread_join(thread)
+ vim.uv.new_thread(self.entry_func, async, self.entry_str, self.args)
+ vim.uv.thread_join(thread)
end
Thread_Test.new = function(entry, on_async, ...)
@@ -175,10 +175,10 @@ describe('thread', function()
eq({'notification', 'result', {true}}, next_msg())
end)
- it('loop', function()
+ it('uv', function()
exec_lua [[
local entry = function(async)
- async:send(vim.loop.version())
+ async:send(vim.uv.version())
end
local on_async = function(ret)
vim.rpcnotify(1, ret)
@@ -259,7 +259,7 @@ describe('threadpool', function()
local after_work_fn = function(ret)
vim.rpcnotify(1, 'result', ret)
end
- local work = vim.loop.new_work(work_fn, after_work_fn)
+ local work = vim.uv.new_work(work_fn, after_work_fn)
work:queue()
]]
@@ -268,7 +268,7 @@ describe('threadpool', function()
it('with invalid argument', function()
local status = pcall_err(exec_lua, [[
- local work = vim.loop.new_thread(function() end, function() end)
+ local work = vim.uv.new_thread(function() end, function() end)
work:queue({})
]])
@@ -288,7 +288,7 @@ describe('threadpool', function()
})
exec_lua [[
- local work = vim.loop.new_work(function() return {} end, function() end)
+ local work = vim.uv.new_work(function() return {} end, function() end)
work:queue()
]]
@@ -319,7 +319,7 @@ describe('threadpool', function()
function Threadpool_Test:do_test()
local work =
- vim.loop.new_work(self.work_fn, self.after_work)
+ vim.uv.new_work(self.work_fn, self.after_work)
work:queue(self.work_fn_str, self.args)
end
@@ -334,10 +334,10 @@ describe('threadpool', function()
]]
end)
- it('loop', function()
+ it('uv', function()
exec_lua [[
local work_fn = function()
- return vim.loop.version()
+ return vim.uv.version()
end
local after_work_fn = function(ret)
vim.rpcnotify(1, ret)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 978a4fe0b6..55c03e21b3 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -882,7 +882,7 @@ describe('lua stdlib', function()
it('vim.fn is allowed in "fast" context by some functions #18306', function()
exec_lua([[
- local timer = vim.loop.new_timer()
+ local timer = vim.uv.new_timer()
timer:start(0, 0, function()
timer:close()
assert(vim.in_fast_event())
@@ -948,7 +948,7 @@ describe('lua stdlib', function()
})
screen:attach()
exec_lua([[
- timer = vim.loop.new_timer()
+ timer = vim.uv.new_timer()
timer:start(20, 0, function ()
-- notify ok (executed later when safe)
vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL})
@@ -2481,7 +2481,7 @@ describe('lua stdlib', function()
start_time = get_time()
vim.g.timer_result = false
- timer = vim.loop.new_timer()
+ timer = vim.uv.new_timer()
timer:start(100, 0, vim.schedule_wrap(function()
vim.g.timer_result = true
end))
@@ -2503,7 +2503,7 @@ describe('lua stdlib', function()
start_time = get_time()
vim.g.timer_result = false
- timer = vim.loop.new_timer()
+ timer = vim.uv.new_timer()
timer:start(100, 0, vim.schedule_wrap(function()
vim.g.timer_result = true
end))
@@ -2546,17 +2546,17 @@ describe('lua stdlib', function()
it('should allow waiting with no callback, explicit', function()
eq(true, exec_lua [[
- local start_time = vim.loop.hrtime()
+ local start_time = vim.uv.hrtime()
vim.wait(50, nil)
- return vim.loop.hrtime() - start_time > 25000
+ return vim.uv.hrtime() - start_time > 25000
]])
end)
it('should allow waiting with no callback, implicit', function()
eq(true, exec_lua [[
- local start_time = vim.loop.hrtime()
+ local start_time = vim.uv.hrtime()
vim.wait(50)
- return vim.loop.hrtime() - start_time > 25000
+ return vim.uv.hrtime() - start_time > 25000
]])
end)
diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua
index 86f7da0d2c..15e6a62781 100644
--- a/test/functional/plugin/lsp/helpers.lua
+++ b/test/functional/plugin/lsp/helpers.lua
@@ -99,7 +99,7 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
end;
});
workspace_folders = {{
- uri = 'file://' .. vim.loop.cwd(),
+ uri = 'file://' .. vim.uv.cwd(),
name = 'test_folder',
}};
on_init = function(client, result)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index e0ce62c0db..26fd2276fd 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -65,7 +65,7 @@ describe('LSP', function()
vim.v.progpath, '-l', fake_lsp_code, test_name;
};
workspace_folders = {{
- uri = 'file://' .. vim.loop.cwd(),
+ uri = 'file://' .. vim.uv.cwd(),
name = 'test_folder',
}};
}
@@ -218,6 +218,34 @@ describe('LSP', function()
})
end)
+ it("should set the client's offset_encoding when positionEncoding capability is supported", function()
+ clear()
+ exec_lua(create_server_definition)
+ local result = exec_lua([[
+ local server = _create_server({
+ capabilities = {
+ positionEncoding = "utf-8"
+ },
+ })
+
+ local client_id = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
+
+ if not client_id then
+ return 'vim.lsp.start did not return client_id'
+ end
+
+ local client = vim.lsp.get_client_by_id(client_id)
+ if not client then
+ return 'No client found with id ' .. client_id
+ end
+ return client.offset_encoding
+ ]])
+ eq('utf-8', result)
+ end)
+
it('should succeed with manual shutdown', function()
if is_ci() then
pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
@@ -2031,7 +2059,7 @@ describe('LSP', function()
}
}
exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
end)
it('Supports file creation in folder that needs to be created with CreateFile payload', function()
local tmpfile = helpers.tmpname()
@@ -2047,7 +2075,7 @@ describe('LSP', function()
}
}
exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
end)
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
local tmpfile = helpers.tmpname()
@@ -2065,7 +2093,7 @@ describe('LSP', function()
}
}
exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
eq('Dummy content', read_file(tmpfile))
end)
it('createFile overrides file if overwrite is set', function()
@@ -2085,7 +2113,7 @@ describe('LSP', function()
}
}
exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
eq('', read_file(tmpfile))
end)
it('DeleteFile delete file and buffer', function()
@@ -2106,7 +2134,7 @@ describe('LSP', function()
}
}
eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16'))
- eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
eq(false, exec_lua('return vim.api.nvim_buf_is_loaded(vim.fn.bufadd(...))', tmpfile))
end)
it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function()
@@ -2125,7 +2153,7 @@ describe('LSP', function()
}
}
eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
- eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', tmpfile))
end)
end)
@@ -2195,9 +2223,9 @@ describe('LSP', function()
return vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
]], old, new)
eq({'Test content'}, lines)
- local exists = exec_lua('return vim.loop.fs_stat(...) ~= nil', old)
+ local exists = exec_lua('return vim.uv.fs_stat(...) ~= nil', old)
eq(false, exists)
- exists = exec_lua('return vim.loop.fs_stat(...) ~= nil', new)
+ exists = exec_lua('return vim.uv.fs_stat(...) ~= nil', new)
eq(true, exists)
os.remove(new)
end)
@@ -2238,9 +2266,9 @@ describe('LSP', function()
return vim.fn.bufloaded(oldbufnr)
]], old_dir, new_dir, pathsep)
eq(0, lines)
- eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', old_dir))
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir))
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir .. pathsep .. file))
+ eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', old_dir))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new_dir))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new_dir .. pathsep .. file))
eq('Test content', read_file(new_dir .. pathsep .. file))
os.remove(new_dir)
@@ -2258,7 +2286,7 @@ describe('LSP', function()
vim.lsp.util.rename(old, new, { ignoreIfExists = true })
]], old, new)
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', old))
eq('New file', read_file(new))
exec_lua([[
@@ -2268,7 +2296,7 @@ describe('LSP', function()
vim.lsp.util.rename(old, new, { overwrite = false })
]], old, new)
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', old))
eq('New file', read_file(new))
end)
it('Does override target if overwrite is true', function()
@@ -2283,8 +2311,8 @@ describe('LSP', function()
vim.lsp.util.rename(old, new, { overwrite = true })
]], old, new)
- eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
- eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new))
+ eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', old))
+ eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new))
eq('Old file\n', read_file(new))
end)
end)
@@ -3669,7 +3697,7 @@ describe('LSP', function()
describe('cmd', function()
it('can connect to lsp server via rpc.connect', function()
local result = exec_lua [[
- local uv = vim.loop
+ local uv = vim.uv
local server = uv.new_tcp()
local init = nil
server:bind('127.0.0.1', 0)
@@ -3697,7 +3725,7 @@ describe('LSP', function()
describe('handlers', function()
it('handler can return false as response', function()
local result = exec_lua [[
- local uv = vim.loop
+ local uv = vim.uv
local server = uv.new_tcp()
local messages = {}
local responses = {}
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 1b65c1cddc..7723b6c7e7 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1554,7 +1554,7 @@ describe('TUI', function()
end)
it('no assert failure on deadly signal #21896', function()
- exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
+ exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
screen:expect({any = '%[Process exited 1%]'})
end)
@@ -1605,7 +1605,7 @@ describe('TUI', function()
foo |
{3:-- TERMINAL --} |
]])
- exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigwinch')]])
+ exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigwinch')]])
screen:expect([[
{1: } |
{4:~ }|
@@ -2517,7 +2517,7 @@ describe("TUI as a client", function()
-- No heap-use-after-free when receiving UI events after deadly signal #22184
server:request('nvim_input', ('a'):rep(1000))
- exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
+ exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
screen:expect({any = '%[Process exited 1%]'})
eq(0, meths.get_vvar('shell_error'))
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 14de07639b..e463382d07 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -182,11 +182,11 @@ void ui_refresh(void)
local function q(n)
return exec_lua ([[
local query, n = ...
- local before = vim.loop.hrtime()
+ local before = vim.uv.hrtime()
for i=1,n,1 do
cquery = vim.treesitter.query.parse("c", ...)
end
- local after = vim.loop.hrtime()
+ local after = vim.uv.hrtime()
return after - before
]], long_query, n)
end
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 54441984a3..cbf0178d28 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -666,6 +666,7 @@ describe('extmark decorations', function()
[30] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGray, underline = true};
[31] = {underline = true, foreground = Screen.colors.DarkCyan};
[32] = {underline = true};
+ [33] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
}
ns = meths.create_namespace 'test'
@@ -1147,6 +1148,46 @@ describe('extmark decorations', function()
]]}
end)
+ it('can have virtual text on folded line', function()
+ insert([[
+ 11111
+ 22222
+ 33333]])
+ command('1,2fold')
+ command('set nowrap')
+ screen:try_resize(50, 3)
+ feed('zb')
+ -- XXX: the behavior of overlay virtual text at non-zero column is strange:
+ -- 1. With 'wrap' it is never shown.
+ -- 2. With 'nowrap' it is shown only if the extmark is hidden before leftcol.
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'overlay' })
+ meths.buf_set_extmark(0, ns, 0, 1, { virt_text = {{'BB', 'Underlined'}}, hl_mode = 'combine', virt_text_win_col = 10 })
+ meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'CC', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'right_align' })
+ screen:expect{grid=[[
+ {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
+ 3333^3 |
+ |
+ ]]}
+ feed('zl')
+ screen:expect{grid=[[
+ {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
+ 333^3 |
+ |
+ ]]}
+ feed('zl')
+ screen:expect{grid=[[
+ {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
+ 33^3 |
+ |
+ ]]}
+ feed('zl')
+ screen:expect{grid=[[
+ {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
+ 3^3 |
+ |
+ ]]}
+ end)
+
it('can have virtual text which combines foreground and background groups', function()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 630d0d0948..d18e19e5b2 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -178,6 +178,30 @@ describe("'spell'", function()
{0:~ }|
|
]])
+ -- Adding an empty line does not remove Cap in "mod_bot" area
+ feed('zbO<Esc>')
+ screen:expect([[
+ This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
+ ^ |
+ {2:another} missing cap here |
+ {10:+-- 2 lines: Not·······························································}|
+ {2:and} here. |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- Multiple empty lines does not remove Cap in the line after
+ feed('O<Esc><C-L>')
+ screen:expect([[
+ This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
+ ^ |
+ |
+ {2:another} missing cap here |
+ {10:+-- 2 lines: Not·······························································}|
+ {2:and} here. |
+ {0:~ }|
+ |
+ ]])
end)
-- oldtest: Test_spell_compatible()
diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim
index 41a8610893..177fef9e99 100644
--- a/test/old/testdir/test_functions.vim
+++ b/test/old/testdir/test_functions.vim
@@ -2834,6 +2834,34 @@ func Test_screen_functions()
call assert_equal(-1, screenattr(-1, -1))
call assert_equal(-1, screenchar(-1, -1))
call assert_equal([], screenchars(-1, -1))
+
+ " Run this in a separate Vim instance to avoid messing up.
+ let after =<< trim [CODE]
+ scriptencoding utf-8
+ call setline(1, '口')
+ redraw
+ call assert_equal(0, screenattr(1, 1))
+ call assert_equal(char2nr('口'), screenchar(1, 1))
+ call assert_equal([char2nr('口')], screenchars(1, 1))
+ call assert_equal('口', screenstring(1, 1))
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [CODE]
+
+ let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950']
+ if !has('win32')
+ let encodings += ['euc-jp']
+ endif
+ if has('nvim')
+ let encodings = ['utf-8']
+ endif
+ for enc in encodings
+ let msg = 'enc=' .. enc
+ if RunVim([], after, $'--clean --cmd "set encoding={enc}"')
+ call assert_equal([], readfile('Xresult'), msg)
+ endif
+ call delete('Xresult')
+ endfor
endfunc
" Test for getcurpos() and setpos()
diff --git a/test/old/testdir/test_put.vim b/test/old/testdir/test_put.vim
index 212a979b4a..6c4bd28386 100644
--- a/test/old/testdir/test_put.vim
+++ b/test/old/testdir/test_put.vim
@@ -266,5 +266,23 @@ func Test_put_other_window()
call StopVimInTerminal(buf)
endfunc
+func Test_put_in_last_displayed_line()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ vim9script
+ autocmd CursorMoved * eval line('w$')
+ @a = 'x'->repeat(&columns * 2 - 2)
+ range(&lines)->setline(1)
+ feedkeys('G"ap')
+ END
+ call writefile(lines, 'Xtest_put_last_line', 'D')
+ let buf = RunVimInTerminal('-S Xtest_put_last_line', #{rows: 10})
+
+ call VerifyScreenDump(buf, 'Test_put_in_last_displayed_line_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_registers.vim b/test/old/testdir/test_registers.vim
index bbf1aa53b5..70dac535b4 100644
--- a/test/old/testdir/test_registers.vim
+++ b/test/old/testdir/test_registers.vim
@@ -55,8 +55,9 @@ func Test_display_registers()
call feedkeys("i\<C-R>=2*4\n\<esc>")
call feedkeys(":ls\n", 'xt')
- let a = execute('display')
- let b = execute('registers')
+ " these commands work in the sandbox
+ let a = execute('sandbox display')
+ let b = execute('sandbox registers')
call assert_equal(a, b)
call assert_match('^\nType Name Content\n'
diff --git a/test/old/testdir/test_spell.vim b/test/old/testdir/test_spell.vim
index b0b2668758..59b433d6e1 100644
--- a/test/old/testdir/test_spell.vim
+++ b/test/old/testdir/test_spell.vim
@@ -962,6 +962,7 @@ func Test_spell_screendump()
CheckScreendump
let lines =<< trim END
+ call test_override('alloc_lines', 1)
call setline(1, [
\ "This is some text without any spell errors. Everything",
\ "should just be black, nothing wrong here.",
@@ -984,6 +985,7 @@ func Test_spell_screendump_spellcap()
CheckScreendump
let lines =<< trim END
+ call test_override('alloc_lines', 1)
call setline(1, [
\ " This line has a sepll error. and missing caps and trailing spaces. ",
\ "another missing cap here.",
@@ -1023,6 +1025,14 @@ func Test_spell_screendump_spellcap()
call term_sendkeys(buf, "\<C-E>\<C-L>")
call VerifyScreenDump(buf, 'Test_spell_8', {})
+ " Adding an empty line does not remove Cap in "mod_bot" area
+ call term_sendkeys(buf, "zbO\<Esc>")
+ call VerifyScreenDump(buf, 'Test_spell_9', {})
+
+ " Multiple empty lines does not remove Cap in the line after
+ call term_sendkeys(buf, "O\<Esc>\<C-L>")
+ call VerifyScreenDump(buf, 'Test_spell_10', {})
+
" clean up
call StopVimInTerminal(buf)
endfunc
@@ -1031,6 +1041,7 @@ func Test_spell_compatible()
CheckScreendump
let lines =<< trim END
+ call test_override('alloc_lines', 1)
call setline(1, [
\ "test "->repeat(20),
\ "",
diff --git a/test/old/testdir/test_utf8.vim b/test/old/testdir/test_utf8.vim
index 00b060a9e2..a5a9624ec3 100644
--- a/test/old/testdir/test_utf8.vim
+++ b/test/old/testdir/test_utf8.vim
@@ -88,7 +88,20 @@ func Test_screenchar_utf8()
call assert_equal("B", screenstring(1, 2))
call assert_equal("C\u0308", screenstring(1, 3))
- " 2-cells, with composing characters
+ " 1-cell, with 6 composing characters
+ set maxcombine=6
+ call setline(1, ["ABC" .. repeat("\u0308", 6)])
+ redraw
+ call assert_equal([0x0041], screenchars(1, 1))
+ call assert_equal([0x0042], 1->screenchars(2))
+ " This should not use uninitialized memory
+ call assert_equal([0x0043] + repeat([0x0308], 6), screenchars(1, 3))
+ call assert_equal("A", screenstring(1, 1))
+ call assert_equal("B", screenstring(1, 2))
+ call assert_equal("C" .. repeat("\u0308", 6), screenstring(1, 3))
+ set maxcombine&
+
+ " 2-cells, with composing characters
let text = "\u3042\u3044\u3046\u3099"
call setline(1, text)
redraw
diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim
index d4ff241366..7d4932a2b5 100644
--- a/test/old/testdir/test_window_cmd.vim
+++ b/test/old/testdir/test_window_cmd.vim
@@ -1763,9 +1763,20 @@ endfunc
func Test_splitkeep_misc()
set splitkeep=screen
- set splitbelow
call setline(1, range(1, &lines))
+ " Cursor is adjusted to start and end of buffer
+ norm M
+ wincmd s
+ resize 1
+ call assert_equal(1, line('.'))
+ wincmd j
+ norm GM
+ resize 1
+ call assert_equal(&lines, line('.'))
+ only!
+
+ set splitbelow
norm Gzz
let top = line('w0')
" No scroll when aucmd_win is opened