aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake.deps/deps.txt4
-rw-r--r--runtime/doc/motion.txt130
-rw-r--r--runtime/doc/options.txt11
-rw-r--r--runtime/lua/vim/_editor.lua1
-rw-r--r--runtime/lua/vim/_meta.lua1
-rw-r--r--runtime/lua/vim/_meta/options.lua11
-rw-r--r--runtime/lua/vim/filetype.lua1
-rw-r--r--runtime/lua/vim/func.lua41
-rw-r--r--runtime/lua/vim/func/_memoize.lua59
-rw-r--r--runtime/lua/vim/treesitter/_query_linter.lua54
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua10
-rw-r--r--runtime/lua/vim/treesitter/query.lua34
-rw-r--r--scripts/lua2dox.lua6
-rw-r--r--src/nvim/CMakeLists.txt8
-rw-r--r--src/nvim/decoration.c9
-rw-r--r--src/nvim/decoration.h1
-rw-r--r--src/nvim/drawline.c78
-rw-r--r--src/nvim/mouse.c92
-rw-r--r--src/nvim/options.lua11
-rw-r--r--src/nvim/optionstr.c2
-rw-r--r--test/functional/ui/decorations_spec.lua130
-rw-r--r--test/functional/ui/float_spec.lua184
-rw-r--r--test/functional/ui/fold_spec.lua33
-rw-r--r--test/functional/ui/mouse_spec.lua4
-rw-r--r--test/functional/ui/multigrid_spec.lua1
-rw-r--r--test/functional/ui/statuscolumn_spec.lua2
-rw-r--r--test/old/testdir/test_filetype.vim1
-rw-r--r--test/old/testdir/test_jumplist.vim66
-rw-r--r--test/old/testdir/test_normal.vim33
-rw-r--r--test/old/testdir/test_virtualedit.vim23
30 files changed, 779 insertions, 262 deletions
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index 945f8d5f45..4c23803560 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -4,8 +4,8 @@ LIBUV_SHA256 7aa66be3413ae10605e1f5c9ae934504ffe317ef68ea16fdaa83e23905c681bd
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/e897c5743f97a6b05c59852709092e7da4119914.tar.gz
-LUAJIT_SHA256 f28030c61602bffd28a445f3fef23198264a845aab94d909587bac6c12c8b874
+LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/d1a2fef8a8f53b0055ee041f7f63d83a27444ffa.tar.gz
+LUAJIT_SHA256 7d4dd85cbf224c70f2014203903202a90f3cfe7b1c6e7b1b36f8ae472dfc7fba
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index dc92601bfc..5e18595d22 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -1050,14 +1050,14 @@ can go to cursor positions before older jumps, and back again. Thus you can
move up and down the list. There is a separate jump list for each window.
The maximum number of entries is fixed at 100.
-For example, after three jump commands you have this jump list:
-
- jump line col file/text ~
- 3 1 0 some text ~
- 2 70 0 another line ~
- 1 1154 23 end. ~
- > ~
+For example, after three jump commands you have this jump list: >
+ jump line col file/text
+ 3 1 0 some text
+ 2 70 0 another line
+ 1 1154 23 end.
+ >
+<
The "file/text" column shows the file name, or the text at the jump if it is
in the current file (an indent is removed and a long line is truncated to fit
in the window).
@@ -1066,14 +1066,14 @@ The marker ">" indicates the current position in the jumplist. It may not be
shown when filtering the |:jumps| command using |:filter|
You are currently in line 1167. If you then use the CTRL-O command, the
-cursor is put in line 1154. This results in:
-
- jump line col file/text ~
- 2 1 0 some text ~
- 1 70 0 another line ~
- > 0 1154 23 end. ~
- 1 1167 0 foo bar ~
+cursor is put in line 1154. This results in: >
+ jump line col file/text
+ 2 1 0 some text
+ 1 70 0 another line
+ > 0 1154 23 end.
+ 1 1167 0 foo bar
+<
The pointer will be set at the last used jump position. The next CTRL-O
command will use the entry above it, the next CTRL-I command will use the
entry below it. If the pointer is below the last entry, this indicates that
@@ -1097,15 +1097,15 @@ command. You can explicitly add a jump by setting the ' mark with "m'". Note
that calling setpos() does not do this.
After the CTRL-O command that got you into line 1154 you could give another
-jump command (e.g., "G"). The jump list would then become:
-
- jump line col file/text ~
- 4 1 0 some text ~
- 3 70 0 another line ~
- 2 1167 0 foo bar ~
- 1 1154 23 end. ~
- > ~
-
+jump command (e.g., "G"). The jump list would then become: >
+
+ jump line col file/text
+ 4 1 0 some text
+ 3 70 0 another line
+ 2 1167 0 foo bar
+ 1 1154 23 end.
+ >
+<
The line numbers will be adjusted for deleted and inserted lines. This fails
if you stop editing a file without writing, like with ":n!".
@@ -1115,60 +1115,44 @@ If you have included the ' item in the 'shada' option the jumplist will be
stored in the ShaDa file and restored when starting Vim.
*jumplist-stack*
-When jumpoptions includes "stack", the jumplist behaves like the history in a
-web browser and like the tag stack. When jumping to a new location from the
-middle of the jumplist, the locations after the current position will be
-discarded.
-
-This behavior corresponds to the following situation in a web browser.
-Navigate to first.com, second.com, third.com, fourth.com and then fifth.com.
-Then navigate backwards twice so that third.com is displayed. At that point,
-the history is:
-- first.com
-- second.com
-- third.com <--
-- fourth.com
-- fifth.com
-
-Finally, navigate to a different webpage, new.com. The history is
-- first.com
-- second.com
-- third.com
-- new.com <--
-
-When the jumpoptions includes "stack", this is the behavior of Nvim as well.
-That is, given a jumplist like the following in which CTRL-O has been used to
-move back three times to location X
-
- jump line col file/text
- 2 1260 8 src/nvim/mark.c <-- location X-2
- 1 685 0 src/nvim/option_defs.h <-- location X-1
-> 0 462 36 src/nvim/option_defs.h <-- location X
- 1 479 39 src/nvim/option_defs.h
- 2 213 2 src/nvim/mark.c
- 3 181 0 src/nvim/mark.c
-
+When 'jumpoptions' option includes "stack", the jumplist behaves like the tag
+stack. When jumping to a new location from the middle of the jumplist, the
+locations after the current position will be discarded. With this option set
+you can move through a tree of jump locations. When going back up a branch and
+then down another branch, CTRL-O still takes you further up the tree.
+
+Given a jumplist like the following in which CTRL-O has been used to move back
+three times to location X: >
+
+ jump line col file/text
+ 2 1260 8 mark.c <-- location X-2
+ 1 685 0 eval.c <-- location X-1
+ > 0 462 36 eval.c <-- location X
+ 1 479 39 eval.c
+ 2 213 2 mark.c
+ 3 181 0 mark.c
+<
jumping to (new) location Y results in the locations after the current
-locations being removed:
-
- jump line col file/text
- 3 1260 8 src/nvim/mark.c
- 2 685 0 src/nvim/option_defs.h
- 1 462 36 src/nvim/option_defs.h <-- location X
->
+locations being removed: >
+ jump line col file/text
+ 3 1260 8 mark.c <-- location X-2
+ 2 685 0 eval.c <-- location X-1
+ 1 462 36 eval.c <-- location X
+ >
+<
Then, when yet another location Z is jumped to, the new location Y appears
directly after location X in the jumplist and location X remains in the same
-position relative to the locations (X-1, X-2, etc., ...) that had been before it
-prior to the original jump from X to Y:
-
- jump line col file/text
- 4 1260 8 src/nvim/mark.c <-- location X-2
- 3 685 0 src/nvim/option_defs.h <-- location X-1
- 2 462 36 src/nvim/option_defs.h <-- location X
- 1 100 0 src/nvim/option_defs.h <-- location Y
->
-
+position relative to the locations (X-1, X-2, etc., ...) that had been before
+it prior to the original jump from X to Y: >
+
+ jump line col file/text
+ 4 1260 8 mark.c <-- location X-2
+ 3 685 0 eval.c <-- location X-1
+ 2 462 36 eval.c <-- location X
+ 1 100 0 buffer.c <-- location Y
+ >
+<
CHANGE LIST JUMPS *changelist* *change-list-jumps* *E664*
When making a change the cursor position is remembered. One position is
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 96bf2eef63..deb64bf18d 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3569,12 +3569,11 @@ A jump table for the options with a short description can be found at |Q_op|.
'jumpoptions' 'jop' string (default "")
global
List of words that change the behavior of the |jumplist|.
- stack Make the jumplist behave like the tagstack or like a
- web browser. Relative location of entries in the
- jumplist is preserved at the cost of discarding
- subsequent entries when navigating backwards in the
- jumplist and then jumping to a location.
- |jumplist-stack|
+ stack Make the jumplist behave like the tagstack.
+ Relative location of entries in the jumplist is
+ preserved at the cost of discarding subsequent entries
+ when navigating backwards in the jumplist and then
+ jumping to a location. |jumplist-stack|
view When moving through the jumplist, |changelist|,
|alternate-file| or using |mark-motions| try to
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 0215cae0cb..8322777633 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -29,6 +29,7 @@ for k, v in pairs({
treesitter = true,
filetype = true,
loader = true,
+ func = true,
F = true,
lsp = true,
highlight = true,
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index 5e4f390ca3..ddd0a0eb49 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -10,6 +10,7 @@ vim._watch = require('vim._watch')
vim.diagnostic = require('vim.diagnostic')
vim.filetype = require('vim.filetype')
vim.fs = require('vim.fs')
+vim.func = require('vim.func')
vim.health = require('vim.health')
vim.highlight = require('vim.highlight')
vim.iter = require('vim.iter')
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 734096a755..b8bdfbc3f7 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -3485,12 +3485,11 @@ vim.go.joinspaces = vim.o.joinspaces
vim.go.js = vim.go.joinspaces
--- List of words that change the behavior of the `jumplist`.
---- stack Make the jumplist behave like the tagstack or like a
---- web browser. Relative location of entries in the
---- jumplist is preserved at the cost of discarding
---- subsequent entries when navigating backwards in the
---- jumplist and then jumping to a location.
---- `jumplist-stack`
+--- stack Make the jumplist behave like the tagstack.
+--- Relative location of entries in the jumplist is
+--- preserved at the cost of discarding subsequent entries
+--- when navigating backwards in the jumplist and then
+--- jumping to a location. `jumplist-stack`
---
--- view When moving through the jumplist, `changelist|,
--- |alternate-file` or using `mark-motions` try to
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index c7f025f9e7..5ae4e508ef 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -210,6 +210,7 @@ local extension = {
astro = 'astro',
atl = 'atlas',
as = 'atlas',
+ zed = 'authzed',
ahk = 'autohotkey',
au3 = 'autoit',
ave = 'ave',
diff --git a/runtime/lua/vim/func.lua b/runtime/lua/vim/func.lua
new file mode 100644
index 0000000000..206d1bae95
--- /dev/null
+++ b/runtime/lua/vim/func.lua
@@ -0,0 +1,41 @@
+local M = {}
+
+-- TODO(lewis6991): Private for now until:
+-- - There are other places in the codebase that could benefit from this
+-- (e.g. LSP), but might require other changes to accommodate.
+-- - Invalidation of the cache needs to be controllable. Using weak tables
+-- is an acceptable invalidation policy, but it shouldn't be the only
+-- one.
+-- - I don't think the story around `hash` is completely thought out. We
+-- may be able to have a good default hash by hashing each argument,
+-- so basically a better 'concat'.
+-- - Need to support multi level caches. Can be done by allow `hash` to
+-- return multiple values.
+--
+--- Memoizes a function {fn} using {hash} to hash the arguments.
+---
+--- Internally uses a |lua-weaktable| to cache the results of {fn} meaning the
+--- cache will be invalidated whenever Lua does garbage collection.
+---
+--- The memoized function returns shared references so be wary about
+--- mutating return values.
+---
+--- @generic F: function
+--- @param hash integer|string|function Hash function to create a hash to use as a key to
+--- store results. Possible values:
+--- - When integer, refers to the index of an argument of {fn} to hash.
+--- This argument can have any type.
+--- - When function, is evaluated using the same arguments passed to {fn}.
+--- - When `concat`, the hash is determined by string concatenating all the
+--- arguments passed to {fn}.
+--- - When `concat-n`, the hash is determined by string concatenating the
+--- first n arguments passed to {fn}.
+---
+--- @param fn F Function to memoize.
+--- @return F # Memoized version of {fn}
+--- @nodoc
+function M._memoize(hash, fn)
+ return require('vim.func._memoize')(hash, fn)
+end
+
+return M
diff --git a/runtime/lua/vim/func/_memoize.lua b/runtime/lua/vim/func/_memoize.lua
new file mode 100644
index 0000000000..835bf64c93
--- /dev/null
+++ b/runtime/lua/vim/func/_memoize.lua
@@ -0,0 +1,59 @@
+--- Module for private utility functions
+
+--- @param argc integer?
+--- @return fun(...): any
+local function concat_hash(argc)
+ return function(...)
+ return table.concat({ ... }, '%%', 1, argc)
+ end
+end
+
+--- @param idx integer
+--- @return fun(...): any
+local function idx_hash(idx)
+ return function(...)
+ return select(idx, ...)
+ end
+end
+
+--- @param hash integer|string|fun(...): any
+--- @return fun(...): any
+local function resolve_hash(hash)
+ if type(hash) == 'number' then
+ hash = idx_hash(hash)
+ elseif type(hash) == 'string' then
+ local c = hash == 'concat' or hash:match('^concat%-(%d+)')
+ if c then
+ hash = concat_hash(tonumber(c))
+ else
+ error('invalid value for hash: ' .. hash)
+ end
+ end
+ --- @cast hash -integer
+ return hash
+end
+
+--- @generic F: function
+--- @param hash integer|string|fun(...): any
+--- @param fn F
+--- @return F
+return function(hash, fn)
+ vim.validate({
+ hash = { hash, { 'number', 'string', 'function' } },
+ fn = { fn, 'function' },
+ })
+
+ ---@type table<any,table<any,any>>
+ local cache = setmetatable({}, { __mode = 'kv' })
+
+ hash = resolve_hash(hash)
+
+ return function(...)
+ local key = hash(...)
+ if cache[key] == nil then
+ cache[key] = vim.F.pack_len(fn(...))
+ end
+
+ return vim.F.unpack_len(cache[key])
+ end
+end
diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua
index abf0bf345d..87d74789a3 100644
--- a/runtime/lua/vim/treesitter/_query_linter.lua
+++ b/runtime/lua/vim/treesitter/_query_linter.lua
@@ -10,20 +10,12 @@ local M = {}
--- @alias vim.treesitter.ParseError {msg: string, range: Range4}
---- @private
---- Caches parse results for queries for each language.
---- Entries of parse_cache[lang][query_text] will either be true for successful parse or contain the
---- message and range of the parse error.
---- @type table<string,table<string,vim.treesitter.ParseError|true>>
-local parse_cache = {}
-
--- Contains language dependent context for the query linter
--- @class QueryLinterLanguageContext
--- @field lang string? Current `lang` of the targeted parser
--- @field parser_info table? Parser info returned by vim.treesitter.language.inspect
--- @field is_first_lang boolean Whether this is the first language of a linter run checking queries for multiple `langs`
---- @private
--- Adds a diagnostic for node in the query buffer
--- @param diagnostics Diagnostic[]
--- @param range Range4
@@ -42,7 +34,6 @@ local function add_lint_for_node(diagnostics, range, lint, lang)
}
end
---- @private
--- Determines the target language of a query file by its path: <lang>/<query_type>.scm
--- @param buf integer
--- @return string?
@@ -53,7 +44,6 @@ local function guess_query_lang(buf)
end
end
---- @private
--- @param buf integer
--- @param opts QueryLinterOpts|QueryLinterNormalizedOpts|nil
--- @return QueryLinterNormalizedOpts
@@ -87,7 +77,6 @@ local lint_query = [[;; query
(ERROR) @error
]]
---- @private
--- @param err string
--- @param node TSNode
--- @return vim.treesitter.ParseError
@@ -112,38 +101,26 @@ local function get_error_entry(err, node)
}
end
---- @private
--- @param node TSNode
--- @param buf integer
--- @param lang string
---- @param diagnostics Diagnostic[]
-local function check_toplevel(node, buf, lang, diagnostics)
- local query_text = vim.treesitter.get_node_text(node, buf)
-
- if not parse_cache[lang] then
- parse_cache[lang] = {}
- end
-
- local lang_cache = parse_cache[lang]
-
- if lang_cache[query_text] == nil then
- local cache_val, err = pcall(vim.treesitter.query.parse, lang, query_text) ---@type boolean|vim.treesitter.ParseError, string|Query
-
- if not cache_val and type(err) == 'string' then
- cache_val = get_error_entry(err, node)
- end
-
- lang_cache[query_text] = cache_val
- end
+local function hash_parse(node, buf, lang)
+ return tostring(node:id()) .. tostring(buf) .. tostring(vim.b[buf].changedtick) .. lang
+end
- local cache_entry = lang_cache[query_text]
+--- @param node TSNode
+--- @param buf integer
+--- @param lang string
+--- @return vim.treesitter.ParseError?
+local parse = vim.func._memoize(hash_parse, function(node, buf, lang)
+ local query_text = vim.treesitter.get_node_text(node, buf)
+ local ok, err = pcall(vim.treesitter.query.parse, lang, query_text) ---@type boolean|vim.treesitter.ParseError, string|Query
- if type(cache_entry) ~= 'boolean' then
- add_lint_for_node(diagnostics, cache_entry.range, cache_entry.msg, lang)
+ if not ok and type(err) == 'string' then
+ return get_error_entry(err, node)
end
-end
+end)
---- @private
--- @param buf integer
--- @param match table<integer,TSNode>
--- @param query Query
@@ -164,7 +141,10 @@ local function lint_match(buf, match, query, lang_context, diagnostics)
-- other checks rely on Neovim parser introspection
if lang and parser_info and cap_id == 'toplevel' then
- check_toplevel(node, buf, lang, diagnostics)
+ local err = parse(node, buf, lang)
+ if err then
+ add_lint_for_node(diagnostics, err.range, err.msg, lang)
+ end
end
end
end
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index f931291ed7..b2c4e9167d 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -738,12 +738,14 @@ local function add_injection(t, tree_index, pattern, lang, combined, ranges)
end
-- TODO(clason): replace by refactored `ts.has_parser` API (without registering)
----@param lang string parser name
----@return boolean # true if parser for {lang} exists on rtp
-local has_parser = function(lang)
+--- The result of this function is cached to prevent nvim_get_runtime_file from being
+--- called too often
+--- @param lang string parser name
+--- @return boolean # true if parser for {lang} exists on rtp
+local has_parser = vim.func._memoize(1, function(lang)
return vim._ts_has_language(lang)
or #vim.api.nvim_get_runtime_file('parser/' .. lang .. '.*', false) > 0
-end
+end)
--- Return parser name for language (if exists) or filetype (if registered and exists).
--- Also attempts with the input lower-cased.
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 313d837d5c..8cbbffcd60 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -191,12 +191,6 @@ function M.set(lang, query_name, text)
explicit_queries[lang][query_name] = M.parse(lang, text)
end
---- `false` if query files didn't exist or were empty
----@type table<string, table<string, Query|false>>
-local query_get_cache = vim.defaulttable(function()
- return setmetatable({}, { __mode = 'v' })
-end)
-
---@deprecated
function M.get_query(...)
vim.deprecate('vim.treesitter.query.get_query()', 'vim.treesitter.query.get()', '0.10')
@@ -209,34 +203,19 @@ end
---@param query_name string Name of the query (e.g. "highlights")
---
---@return Query|nil Parsed query
-function M.get(lang, query_name)
+M.get = vim.func._memoize('concat-2', function(lang, query_name)
if explicit_queries[lang][query_name] then
return explicit_queries[lang][query_name]
end
- local cached = query_get_cache[lang][query_name]
- if cached then
- return cached
- elseif cached == false then
- return nil
- end
-
local query_files = M.get_files(lang, query_name)
local query_string = read_query_files(query_files)
if #query_string == 0 then
- query_get_cache[lang][query_name] = false
return nil
end
- local query = M.parse(lang, query_string)
- query_get_cache[lang][query_name] = query
- return query
-end
-
----@type table<string, table<string, Query>>
-local query_parse_cache = vim.defaulttable(function()
- return setmetatable({}, { __mode = 'v' })
+ return M.parse(lang, query_string)
end)
---@deprecated
@@ -262,20 +241,15 @@ end
---@param query string Query in s-expr syntax
---
---@return Query Parsed query
-function M.parse(lang, query)
+M.parse = vim.func._memoize('concat-2', function(lang, query)
language.add(lang)
- local cached = query_parse_cache[lang][query]
- if cached then
- return cached
- end
local self = setmetatable({}, Query)
self.query = vim._ts_parse_query(lang, query)
self.info = self.query:inspect()
self.captures = self.info.captures
- query_parse_cache[lang][query] = self
return self
-end
+end)
---@deprecated
function M.get_range(...)
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 7594a0e7df..1c8bc5a3cb 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -361,6 +361,12 @@ local function process_line(line, in_stream, generics)
return process_block_comment(line:sub(5), in_stream)
end
+ -- Hax... I'm sorry
+ -- M.fun = vim.memoize(function(...)
+ -- ->
+ -- function M.fun(...)
+ line = line:gsub('^(.+) = .*_memoize%([^,]+, function%((.*)%)$', 'function %1(%2)')
+
if line:find('^function') or line:find('^local%s+function') then
return process_function_header(line)
end
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 82a88c6774..94e5e6ee28 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -879,7 +879,13 @@ set(VIMDOC_FILES
)
glob_wrapper(API_SOURCES ${PROJECT_SOURCE_DIR}/src/nvim/api/*.c)
-glob_wrapper(LUA_SOURCES ${NVIM_RUNTIME_DIR}/lua/vim/*.lua)
+
+glob_wrapper(LUA_SOURCES
+ ${NVIM_RUNTIME_DIR}/lua/vim/*.lua
+ ${NVIM_RUNTIME_DIR}/lua/vim/filetype/*.lua
+ ${NVIM_RUNTIME_DIR}/lua/vim/lsp/*.lua
+ ${NVIM_RUNTIME_DIR}/lua/vim/treesitter/*.lua
+)
add_custom_command(
OUTPUT ${VIMDOC_FILES}
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index f4ca31040a..b70f070a51 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -254,7 +254,7 @@ static void decor_add(DecorState *state, int start_row, int start_col, int end_r
DecorRange range = { start_row, start_col, end_row, end_col,
*decor, attr_id,
- kv_size(decor->virt_text) && owned, -1, ns_id, mark_id };
+ kv_size(decor->virt_text) && owned, -10, ns_id, mark_id };
kv_pushp(state->active);
size_t index;
@@ -268,10 +268,10 @@ static void decor_add(DecorState *state, int start_row, int start_col, int end_r
kv_A(state->active, index) = range;
}
-/// Initialize the draw_col of a newly-added non-inline virtual text item.
+/// Initialize the draw_col of a newly-added virtual text item.
static void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
{
- if (win_col < 0) {
+ if (win_col < 0 && item->decor.virt_text_pos != kVTInline) {
item->draw_col = win_col;
} else if (item->decor.virt_text_pos == kVTOverlay) {
item->draw_col = (item->decor.virt_text_hide && hidden) ? INT_MIN : win_col;
@@ -371,8 +371,7 @@ next_mark:
spell = item.decor.spell;
}
if (item.start_row == state->row && item.start_col <= col
- && decor_virt_pos(&item.decor) && item.draw_col == -1
- && item.decor.virt_text_pos != kVTInline) {
+ && decor_virt_pos(&item.decor) && item.draw_col == -10) {
decor_init_draw_col(win_col, hidden, &item);
}
if (keep) {
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 0f191aa870..fef5ff7c2a 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -85,6 +85,7 @@ typedef struct {
/// Screen column to draw the virtual text.
/// When -1, the virtual text may be drawn after deciding where.
/// When -3, the virtual text should be drawn on the next screen line.
+ /// When -10, the virtual text has just been added.
/// When INT_MIN, the virtual text should no longer be drawn.
int draw_col;
uint64_t ns_id;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 5fda200a43..73021d83a8 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -223,7 +223,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
if (*p == TAB) {
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
for (int c = 0; c < cells; c++) {
- dest[c] = schar_from_ascii(' ');
+ dest[rl ? -c : c] = schar_from_ascii(' ');
}
goto done;
} else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) {
@@ -257,7 +257,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
dest[0] = schar_from_cc(u8c, u8cc);
}
if (cells > 1) {
- dest[1] = 0;
+ dest[rl ? -1 : 1] = 0;
}
done:
s->p += c_len;
@@ -277,12 +277,20 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
}
if (item->draw_col == -1) {
if (item->decor.virt_text_pos == kVTRightAlign) {
- right_pos -= item->decor.virt_text_width;
+ if (wp->w_p_rl) {
+ right_pos += item->decor.virt_text_width;
+ } else {
+ right_pos -= item->decor.virt_text_width;
+ }
item->draw_col = right_pos;
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
item->draw_col = state->eol_col;
} else if (item->decor.virt_text_pos == kVTWinCol) {
- item->draw_col = MAX(item->decor.col + col_off, 0);
+ if (wp->w_p_rl) {
+ item->draw_col = MIN(col_off - item->decor.col, wp->w_grid.cols - 1);
+ } else {
+ item->draw_col = MAX(col_off + item->decor.col, 0);
+ }
}
}
if (item->draw_col < 0) {
@@ -297,25 +305,33 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
}
if (kv_size(item->decor.virt_text)) {
col = draw_virt_text_item(buf, item->draw_col, item->decor.virt_text,
- item->decor.hl_mode, max_col, item->draw_col - col_off);
+ item->decor.hl_mode, max_col, item->draw_col - col_off, wp->w_p_rl);
}
item->draw_col = INT_MIN; // deactivate
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
- state->eol_col = col + 1;
+ if (wp->w_p_rl) {
+ state->eol_col = col - 1;
+ } else {
+ state->eol_col = col + 1;
+ }
}
- *end_col = MAX(*end_col, col);
+ if (wp->w_p_rl) {
+ *end_col = MIN(*end_col, col);
+ } else {
+ *end_col = MAX(*end_col, col);
+ }
}
}
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
- int vcol)
+ int vcol, bool rl)
{
LineState s = LINE_STATE("");
int virt_attr = 0;
size_t virt_pos = 0;
- while (col < max_col) {
+ while (rl ? col > max_col : col < max_col) {
if (!*s.p) {
if (virt_pos >= kv_size(vt)) {
break;
@@ -346,20 +362,27 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
attr = virt_attr;
}
schar_T dummy[2];
+ bool rl_overwrote_double_width = linebuf_char[col] == 0;
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
- max_col - col, false, vcol);
+ rl ? col - max_col : max_col - col, rl, vcol);
// If we failed to emit a char, we still need to put a space and advance.
if (cells < 1) {
linebuf_char[col] = schar_from_ascii(' ');
cells = 1;
}
for (int c = 0; c < cells; c++) {
- linebuf_attr[col++] = attr;
+ linebuf_attr[col] = attr;
+ if (rl) {
+ col--;
+ } else {
+ col++;
+ }
}
- if (col < max_col && linebuf_char[col] == 0) {
- // If the left half of a double-width char is overwritten,
- // change the right half to a space so that grid redraws properly,
- // but don't advance the current column.
+ // If one half of a double-width char is overwritten,
+ // change the other half to a space so that grid redraws properly,
+ // but don't advance the current column.
+ if ((rl && col > max_col && rl_overwrote_double_width)
+ || (!rl && col < max_col && linebuf_char[col] == 0)) {
linebuf_char[col] = schar_from_ascii(' ');
}
vcol += cells;
@@ -1387,8 +1410,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin);
statuscol.use_cul = use_cursor_line_highlight(wp, lnum);
statuscol.sign_cul_id = statuscol.use_cul ? sign_cul.hl_id : 0;
- statuscol.num_attr = sign_num.hl_id ? syn_id2attr(sign_num.hl_id)
- : get_line_number_attr(wp, &wlv);
+ statuscol.num_attr = sign_num.hl_id > 0 ? syn_id2attr(sign_num.hl_id) : 0;
} else {
if (sign_cul.hl_id > 0) {
sign_cul_attr = syn_id2attr(sign_cul.hl_id);
@@ -1675,13 +1697,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
}
}
- if (!virt_line_offset) {
+ if (virt_line_offset == 0) {
// Skip the column states if there is a "virt_left_col" line.
wlv.draw_state = WL_BRI - 1;
} else if (statuscol.draw) {
// Skip fold, sign and number states if 'statuscolumn' is set.
wlv.draw_state = WL_STC - 1;
}
+ if (virt_line_offset >= 0 && wp->w_p_rl) {
+ virt_line_offset = wp->w_grid.cols - 1 - virt_line_offset;
+ }
}
if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
@@ -1714,6 +1739,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.draw_state = WL_STC;
// Draw the 'statuscolumn' if option is set.
if (statuscol.draw) {
+ if (sign_num.hl_id == 0) {
+ statuscol.num_attr = get_line_number_attr(wp, &wlv);
+ }
if (statuscol.textp == NULL) {
v = (ptr - line);
get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol);
@@ -1769,7 +1797,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& wlv.vcol >= wp->w_virtcol)
|| (number_only && wlv.draw_state > WL_STC))
&& wlv.filler_todo <= 0) {
- draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row);
+ draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
grid_put_linebuf(grid, wlv.row, 0, wlv.col, -grid->cols, wp->w_p_rl, wp, bg_attr, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
@@ -2805,7 +2833,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
? 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 + (wp->w_p_rl ? -eol_skip : eol_skip));
}
if (((wp->w_p_cuc
@@ -2893,9 +2922,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
if (kv_size(fold_vt) > 0) {
- draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0);
+ draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine,
+ wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
}
- draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row);
+ draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false);
wlv.row++;
@@ -3159,9 +3189,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int draw_col = wlv.col - wlv.boguscols;
if (virt_line_offset >= 0) {
draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line,
- kHlModeReplace, grid->cols, 0);
+ kHlModeReplace, wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
} else if (wlv.filler_todo <= 0) {
- draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, wlv.row);
+ draw_virt_text(wp, buf, win_col_offset, &draw_col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
}
grid_put_linebuf(grid, wlv.row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap);
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index e35385dd43..33d7bc2e51 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -1849,57 +1849,59 @@ static void mouse_check_grid(colnr_T *vcolp, int *flagsp)
int click_grid = mouse_grid;
int click_row = mouse_row;
int click_col = mouse_col;
- int max_row = Rows;
- int max_col = Columns;
- bool multigrid = ui_has(kUIMultigrid);
- colnr_T col_from_screen = -1;
+ // XXX: this doesn't change click_grid if it is 1, even with multigrid
win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
- if (wp && multigrid) {
- max_row = wp->w_grid_alloc.rows;
- max_col = wp->w_grid_alloc.cols;
- }
-
- if (wp && mouse_row >= 0 && mouse_row < max_row
- && mouse_col >= 0 && mouse_col < max_col) {
- ScreenGrid *gp = multigrid ? &wp->w_grid_alloc : &default_grid;
- int use_row = multigrid && mouse_grid == 0 ? click_row : mouse_row;
- int use_col = multigrid && mouse_grid == 0 ? click_col : mouse_col;
-
- if (gp->chars != NULL) {
- const size_t off = gp->line_offset[use_row] + (size_t)use_col;
-
- // Only use vcols[] after the window was redrawn. Mainly matters
- // for tests, a user would not click before redrawing.
- if (wp->w_redr_type == 0) {
- col_from_screen = gp->vcols[off];
- }
-
- if (col_from_screen == MAXCOL) {
- // When clicking after end of line, still need to set correct curswant
- size_t off_l = gp->line_offset[use_row];
- if (gp->vcols[off_l] < MAXCOL) {
- // Binary search to find last char in line
- size_t off_r = off;
- while (off_l < off_r) {
- size_t off_m = (off_l + off_r + 1) / 2;
- if (gp->vcols[off_m] < MAXCOL) {
- off_l = off_m;
- } else {
- off_r = off_m - 1;
- }
- }
- *vcolp = gp->vcols[off_r] + (int)(off - off_r);
+ // Only use vcols[] after the window was redrawn. Mainly matters
+ // for tests, a user would not click before redrawing.
+ if (wp == NULL || wp->w_redr_type != 0) {
+ return;
+ }
+ ScreenGrid *gp = &wp->w_grid;
+ int start_row = 0;
+ int start_col = 0;
+ grid_adjust(&gp, &start_row, &start_col);
+ if (gp->handle != click_grid || gp->chars == NULL) {
+ return;
+ }
+ click_row += start_row;
+ click_col += start_col;
+ if (click_row < 0 || click_row >= gp->rows
+ || click_col < 0 || click_col >= gp->cols) {
+ return;
+ }
+
+ const size_t off = gp->line_offset[click_row] + (size_t)click_col;
+ colnr_T col_from_screen = gp->vcols[off];
+
+ if (col_from_screen == MAXCOL) {
+ // When clicking after end of line, still need to set correct curswant
+ size_t off_l = gp->line_offset[click_row] + (size_t)start_col;
+ if (gp->vcols[off_l] < MAXCOL) {
+ // Binary search to find last char in line
+ size_t off_r = off;
+ while (off_l < off_r) {
+ size_t off_m = (off_l + off_r + 1) / 2;
+ if (gp->vcols[off_m] < MAXCOL) {
+ off_l = off_m;
} else {
- // Shouldn't normally happen
- *vcolp = MAXCOL;
+ off_r = off_m - 1;
}
- } else if (col_from_screen >= 0) {
- // Use the virtual column from vcols[], it is accurate also after
- // concealed characters.
- *vcolp = col_from_screen;
}
+ colnr_T eol_vcol = gp->vcols[off_r];
+ assert(eol_vcol < MAXCOL);
+ // This may be -2 or -3 with 'foldcolumn' and empty line.
+ // In that case set it to -1 as it's just before start of line.
+ eol_vcol = MAX(eol_vcol, -1);
+ *vcolp = eol_vcol + (int)(off - off_r);
+ } else {
+ // Clicking on an empty line
+ *vcolp = click_col - start_col;
}
+ } else if (col_from_screen >= 0) {
+ // Use the virtual column from vcols[], it is accurate also after
+ // concealed characters.
+ *vcolp = col_from_screen;
}
if (col_from_screen == -2) {
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 2a1c76fd9a..e5821b62bd 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -4443,12 +4443,11 @@ return {
deny_duplicates = true,
desc = [=[
List of words that change the behavior of the |jumplist|.
- stack Make the jumplist behave like the tagstack or like a
- web browser. Relative location of entries in the
- jumplist is preserved at the cost of discarding
- subsequent entries when navigating backwards in the
- jumplist and then jumping to a location.
- |jumplist-stack|
+ stack Make the jumplist behave like the tagstack.
+ Relative location of entries in the jumplist is
+ preserved at the cost of discarding subsequent entries
+ when navigating backwards in the jumplist and then
+ jumping to a location. |jumplist-stack|
view When moving through the jumplist, |changelist|,
|alternate-file| or using |mark-motions| try to
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 17afd10ee3..cf8e6cf641 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -151,13 +151,13 @@ void didset_string_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, true);
(void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, true);
(void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
- (void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, true);
(void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
}
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index daa4b4bdb3..d6a6243be2 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1237,6 +1237,25 @@ describe('extmark decorations', function()
|
]]}
+ meths.buf_set_extmark(0, ns, 4, 50, { virt_text={{'EOL', 'NonText'}} })
+ screen:expect{grid=[[
+ for _,item in ipairs(items) do |
+ local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+ if |
+ hl_id_cell ~= nil then {4:Much} {4:MUCH}|
+ --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}|
+ l_id_cell {1:EOL} |
+ end |
+ for _ = 1, (count or 1) do |
+ local cell = line[colpos] |
+ {1:-} cell.text = text {1:-}|
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ |
+ ]]}
+
feed '.'
screen:expect{grid=[[
for _,item in ipairs(items) do |
@@ -1244,7 +1263,7 @@ describe('extmark decorations', function()
if |
hl_id_cell ~= nil then {4:Much} {4:MUCH}|
--^ -- -- -- -- -- -- -- -- -- -- -- hl_id |
- = hl_id_cell {4:Error} {4:ERROR}|
+ = hl_id_cell {1:EOL} {4:Error} {4:ERROR}|
end |
for _ = 1, (count or 1) do |
local cell = line[colpos] |
@@ -1264,7 +1283,7 @@ describe('extmark decorations', function()
{2: 3 } if |
{2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}|
{2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl|
- {2: }_id = hl_id_cell {4:Error} {4:ERROR}|
+ {2: }_id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}|
{2: 6 } end |
{2: 7 } for _ = 1, (count or 1) do |
{2: 8 } local cell = line[colpos] |
@@ -1283,7 +1302,7 @@ describe('extmark decorations', function()
{2: 3 } if |
{2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}|
{2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl|
- _id = hl_id_cell {4:Error} {4:ERROR}|
+ _id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}|
{2: 6 } end |
{2: 7 } for _ = 1, (count or 1) do |
{2: 8 } local cell = line[colpos] |
@@ -1891,6 +1910,84 @@ describe('extmark decorations', function()
|
]]}
end)
+
+ it('virtual text works with rightleft', function()
+ screen:try_resize(50, 3)
+ insert('abcdefghijklmn')
+ feed('0')
+ command('set rightleft')
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'EOL', 'Underlined'}}})
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'right_align', 'Underlined'}}, virt_text_pos = 'right_align' })
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'win_col', 'Underlined'}}, virt_text_win_col = 20 })
+ meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' })
+ screen:expect{grid=[[
+ {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}b^a|
+ {1: ~}|
+ |
+ ]]}
+
+ insert(('#'):rep(32))
+ feed('0')
+ screen:expect{grid=[[
+ {28:ngila_tdeyalrevo}ba#####{28:loc_niw}###################^#|
+ {1: ~}|
+ |
+ ]]}
+
+ insert(('#'):rep(16))
+ feed('0')
+ screen:expect{grid=[[
+ {28:ngila_thgir}############{28:loc_niw}###################^#|
+ {28:LOE} nml{28:deyalrevo}|
+ |
+ ]]}
+
+ insert('###')
+ feed('0')
+ screen:expect{grid=[[
+ #################################################^#|
+ {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}ba#|
+ |
+ ]]}
+
+ command('set number')
+ screen:expect{grid=[[
+ #############################################^#{2: 1 }|
+ {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####{2: }|
+ |
+ ]]}
+
+ command('set cpoptions+=n')
+ screen:expect{grid=[[
+ #############################################^#{2: 1 }|
+ {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####|
+ |
+ ]]}
+ end)
+
+ it('works with double width char and rightleft', function()
+ screen:try_resize(50, 3)
+ insert('abcdefghij口klmnop')
+ feed('0')
+ command('set rightleft')
+ screen:expect{grid=[[
+ ponmlk口jihgfedcb^a|
+ {1: ~}|
+ |
+ ]]}
+ meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' })
+ screen:expect{grid=[[
+ ponmlk {28:deyalrevo}b^a|
+ {1: ~}|
+ |
+ ]]}
+ meths.buf_set_extmark(0, ns, 0, 15, { virt_text = {{'古', 'Underlined'}}, virt_text_pos = 'overlay' })
+ screen:expect{grid=[[
+ po{28:古}lk {28:deyalrevo}b^a|
+ {1: ~}|
+ |
+ ]]}
+ end)
end)
describe('decorations: inline virtual text', function()
@@ -4226,6 +4323,7 @@ if (h->n_buckets < new_n_buckets) { // expand
end)
it('does not show twice if end_row or end_col is specified #18622', function()
+ screen:try_resize(50, 8)
insert([[
aaa
bbb
@@ -4241,10 +4339,28 @@ if (h->n_buckets < new_n_buckets) { // expand
dd^d |
{1:VIRT LINE 2} |
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with rightleft', function()
+ screen:try_resize(50, 8)
+ insert([[
+ aaa
+ bbb
+ ccc
+ ddd]])
+ command('set number rightleft')
+ meths.buf_set_extmark(0, ns, 0, 0, {virt_lines = {{{'VIRT LINE 1', 'NonText'}}}, virt_lines_leftcol = true})
+ meths.buf_set_extmark(0, ns, 3, 0, {virt_lines = {{{'VIRT LINE 2', 'NonText'}}}})
+ screen:expect{grid=[[
+ aaa{9: 1 }|
+ {1:1 ENIL TRIV}|
+ bbb{9: 2 }|
+ ccc{9: 3 }|
+ ^ddd{9: 4 }|
+ {1:2 ENIL TRIV}{9: }|
+ {1: ~}|
|
]]}
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index f75fb52108..4fea513249 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -6287,7 +6287,7 @@ describe('float window', function()
end
if multigrid then
- meths.input_mouse('left', 'press', '', 1, 0, 0)
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
@@ -6366,7 +6366,7 @@ describe('float window', function()
end
if multigrid then
- meths.input_mouse('left', 'press', '', 1, 0, 0)
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
@@ -8764,6 +8764,186 @@ describe('float window', function()
end
end)
+ it('left click sets correct curswant in float window with border', function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'', '', ''})
+ meths.open_win(buf, false, {relative='editor', width=20, height=3, row=0, col=5, border='single'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{1: }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 3, 1)
+ else
+ meths.input_mouse('left', 'press', '', 0, 3, 6)
+ end
+ eq({0, 3, 1, 0, 1}, funcs.getcurpos())
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 3, 2)
+ else
+ meths.input_mouse('left', 'press', '', 0, 3, 7)
+ end
+ eq({0, 3, 1, 0, 2}, funcs.getcurpos())
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 3, 10)
+ else
+ meths.input_mouse('left', 'press', '', 0, 3, 15)
+ end
+ eq({0, 3, 1, 0, 10}, funcs.getcurpos())
+
+ command('setlocal foldcolumn=1')
+ feed('zfkgg')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌────────────────────┐}|
+ {5:│}{19: }{1:^ }{5:│}|
+ {5:│}{19:+}{28:+-- 2 lines: ·····}{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [4] = {win = {id = 1001}, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{19: }{1:^ }{5:│}{0: }|
+ {0:~ }{5:│}{19:+}{28:+-- 2 lines: ·····}{5:│}{0: }|
+ {0:~ }{5:│}{2:~ }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 2, 1)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌────────────────────┐}|
+ {5:│}{19: }{1:^ }{5:│}|
+ {5:│}{19:-}{1: }{5:│}|
+ {5:│}{19:│}{1: }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
+ }}
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 6)
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{19: }{1:^ }{5:│}{0: }|
+ {0:~ }{5:│}{19:-}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{19:│}{1: }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 2, 2)
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 7)
+ end
+ eq({0, 2, 1, 0, 1}, funcs.getcurpos())
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 2, 3)
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 8)
+ end
+ eq({0, 2, 1, 0, 2}, funcs.getcurpos())
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 2, 11)
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 16)
+ end
+ eq({0, 2, 1, 0, 10}, funcs.getcurpos())
+ end)
+
it("'winblend' option", function()
screen:try_resize(50,9)
screen:set_default_attr_ids({
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index c8ca5be282..5e907f82ba 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -3047,6 +3047,39 @@ describe("folded lines", function()
{11:-- VISUAL LINE --} |
]])
end
+
+ meths.set_option_value('rightleft', true, {})
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [3:------------------------------]|
+ ## grid 2
+ a si sihT{7: }|
+ {14:hsilgnE dila}^v{7: -}|
+ {20: desopmoc ecnetnes}{19: }{15:--}{7: +│}|
+ {15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}|
+ {1: ~}|
+ {1: ~}|
+ ## grid 3
+ {11:-- VISUAL LINE --} |
+ ]])
+ else
+ screen:expect([[
+ a si sihT{7: }|
+ {14:hsilgnE dila}^v{7: -}|
+ {20: desopmoc ecnetnes}{19: }{15:--}{7: +│}|
+ {15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}|
+ {1: ~}|
+ {1: ~}|
+ {11:-- VISUAL LINE --} |
+ ]])
+ end
end)
end
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index a8d01cfbf1..fd24174f74 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1676,7 +1676,7 @@ describe('ui/mouse/input', function()
end)
- it('getmousepos works correctly', function()
+ it('getmousepos() works correctly', function()
local winwidth = meths.get_option_value('winwidth', {})
-- Set winwidth=1 so that window sizes don't change.
meths.set_option_value('winwidth', 1, {})
@@ -1771,7 +1771,7 @@ describe('ui/mouse/input', function()
-- Test that mouse position values are properly set for ordinary windows.
-- Set the float to be unfocusable instead of closing, to additionally test
- -- that getmousepos does not consider unfocusable floats. (see discussion
+ -- that getmousepos() does not consider unfocusable floats. (see discussion
-- in PR #14937 for details).
opts.focusable = false
meths.win_set_config(float, opts)
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 1778c8218b..6f4082beda 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -2307,6 +2307,7 @@ describe('ext_multigrid', function()
{1:~ }|
]]}
+ -- XXX: mouse_check_grid() doesn't work properly when clicking on grid 1
meths.input_mouse('left', 'press', '', 1, 6, 20)
-- TODO(bfredl): "batching" input_mouse is formally not supported yet.
-- Normally it should work fine in async context when nvim is not blocked,
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 742976cbe2..a7830abe8f 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -475,7 +475,7 @@ describe('statuscolumn', function()
aaaaaaaaa |
{1:virtual-2 15}virt_line1 |
{1:virtual-2 15}virt_line2 |
- {1:buffer 0 16}{5:^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {4:buffer 0 16}{5:^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{5:aaaaaaaaa }|
{1:virtual-1 16}END |
{0:~ }|
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index e2b977c2b8..e5d7085d71 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -97,6 +97,7 @@ func s:GetFilenameChecks() abort
\ 'asterisk': ['asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'],
\ 'astro': ['file.astro'],
\ 'atlas': ['file.atl', 'file.as'],
+ \ 'authzed': ['file.zed'],
\ 'autohotkey': ['file.ahk'],
\ 'autoit': ['file.au3'],
\ 'automake': ['GNUmakefile.am', 'makefile.am', 'Makefile.am'],
diff --git a/test/old/testdir/test_jumplist.vim b/test/old/testdir/test_jumplist.vim
index 91ad940e18..b4dcdad9d6 100644
--- a/test/old/testdir/test_jumplist.vim
+++ b/test/old/testdir/test_jumplist.vim
@@ -104,4 +104,70 @@ d
bwipe!
endfunc
+" Test for 'jumpoptions'
+func Test_jumpoptions()
+ new
+ call setline(1, range(1, 200))
+ clearjumps
+ set jumpoptions=stack
+
+ " Jump around to add some locations to the jump list.
+ normal 10G
+ normal 20G
+ normal 30G
+ normal 40G
+ normal 50G
+ let bnr = bufnr()
+
+ " discards the tail when navigating from the middle
+ exe "normal \<C-O>\<C-O>"
+ call assert_equal([
+ \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 40, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 50, 'bufnr': bnr, 'col': 0, 'coladd': 0}
+ \ ], 3], getjumplist())
+
+ " new jump location is added immediately after the last one
+ normal 90G
+ call assert_equal([
+ \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ ], 4], getjumplist())
+
+ " does not add the same location twice adjacently
+ normal 60G
+ normal 60G
+ call assert_equal([
+ \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 90, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ "\ Nvim: avoids useless/phantom jumps
+ "\ {'lnum': 60, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ "\ ], 6], getjumplist())
+ \ ], 5], getjumplist())
+
+ " does add the same location twice non adjacently
+ normal 10G
+ normal 20G
+ call assert_equal([
+ \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 90, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 60, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ ], 7], getjumplist())
+
+ set jumpoptions&
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index 3c21041899..09d3f0432f 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -4107,6 +4107,39 @@ func Test_normal_click_on_double_width_char()
let &mouse = save_mouse
endfunc
+func Test_normal_click_on_empty_line()
+ let save_mouse = &mouse
+ set mouse=a
+ botright new
+ call setline(1, ['', '', ''])
+ let row = win_screenpos(0)[0] + 2
+ 20vsplit
+ redraw
+
+ call Ntest_setmouse(row, 1)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 1], getcurpos())
+ call Ntest_setmouse(row, 2)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 2], getcurpos())
+ call Ntest_setmouse(row, 10)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 10], getcurpos())
+
+ call Ntest_setmouse(row, 21 + 1)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 1], getcurpos())
+ call Ntest_setmouse(row, 21 + 2)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 2], getcurpos())
+ call Ntest_setmouse(row, 21 + 10)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal([0, 3, 1, 0, 10], getcurpos())
+
+ bwipe!
+ let &mouse = save_mouse
+endfunc
+
func Test_normal33_g_cmd_nonblank()
" Test that g<End> goes to the last non-blank char and g$ to the last
" visible column
diff --git a/test/old/testdir/test_virtualedit.vim b/test/old/testdir/test_virtualedit.vim
index 6ff51e36fb..4c11fcd99e 100644
--- a/test/old/testdir/test_virtualedit.vim
+++ b/test/old/testdir/test_virtualedit.vim
@@ -564,35 +564,38 @@ func Test_virtualedit_mouse()
let save_mouse = &mouse
set mouse=a
set virtualedit=all
- new
+ botright new
+ let row = win_screenpos(0)[0]
+ 20vsplit
+ wincmd p
call setline(1, ["text\tword"])
redraw
- call Ntest_setmouse(1, 4)
+ call Ntest_setmouse(row, 21 + 4)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 4, 0, 4], getcurpos())
- call Ntest_setmouse(1, 5)
+ call Ntest_setmouse(row, 21 + 5)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 5, 0, 5], getcurpos())
- call Ntest_setmouse(1, 6)
+ call Ntest_setmouse(row, 21 + 6)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 5, 1, 6], getcurpos())
- call Ntest_setmouse(1, 7)
+ call Ntest_setmouse(row, 21 + 7)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 5, 2, 7], getcurpos())
- call Ntest_setmouse(1, 8)
+ call Ntest_setmouse(row, 21 + 8)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 5, 3, 8], getcurpos())
- call Ntest_setmouse(1, 9)
+ call Ntest_setmouse(row, 21 + 9)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 6, 0, 9], getcurpos())
- call Ntest_setmouse(1, 12)
+ call Ntest_setmouse(row, 21 + 12)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 9, 0, 12], getcurpos())
- call Ntest_setmouse(1, 13)
+ call Ntest_setmouse(row, 21 + 13)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 10, 0, 13], getcurpos())
- call Ntest_setmouse(1, 15)
+ call Ntest_setmouse(row, 21 + 15)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 10, 2, 15], getcurpos())