aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.builds/freebsd.yml12
-rw-r--r--.builds/openbsd.yml2
-rw-r--r--.github/workflows/ci.yml17
-rw-r--r--.github/workflows/release.yml2
-rw-r--r--contrib/flake.lock12
-rw-r--r--runtime/doc/api.txt7
-rw-r--r--runtime/doc/repeat.txt5
-rw-r--r--runtime/lua/vim/_editor.lua52
-rw-r--r--runtime/lua/vim/_init_packages.lua20
-rw-r--r--runtime/lua/vim/shared.lua8
-rw-r--r--src/nvim/CMakeLists.txt1
-rw-r--r--src/nvim/api/autocmd.c112
-rw-r--r--src/nvim/autocmd.c59
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/ex_cmds2.c4
-rw-r--r--src/nvim/lua/executor.c3
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/ops.c70
-rw-r--r--src/nvim/screen.c6
-rw-r--r--src/nvim/testdir/test_autochdir.vim61
-rw-r--r--src/nvim/testdir/test_diffmode.vim26
-rw-r--r--src/nvim/testdir/test_registers.vim76
-rw-r--r--src/nvim/window.c3
-rw-r--r--src/nvim/window.h25
-rw-r--r--test/functional/api/autocmd_spec.lua89
-rw-r--r--test/functional/legacy/autochdir_spec.lua94
-rw-r--r--test/functional/lua/vim_spec.lua4
-rw-r--r--test/functional/options/autochdir_spec.lua31
-rw-r--r--test/functional/terminal/highlight_spec.lua15
-rw-r--r--test/functional/ui/diff_spec.lua26
-rw-r--r--test/functional/ui/highlight_spec.lua60
-rw-r--r--third-party/CMakeLists.txt8
-rw-r--r--third-party/cmake/BuildLibuv.cmake4
-rw-r--r--third-party/patches/libuv-disable-typedef-MinGW.patch19
36 files changed, 711 insertions, 229 deletions
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 508dcacd3c..2d06b1e685 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -1,4 +1,4 @@
-image: freebsd/12.x
+image: freebsd/latest
packages:
- cmake
@@ -35,10 +35,6 @@ tasks:
- unittest: |
cd neovim
gmake unittest
-
-# Unfortunately, oldtest is tanking hard on sourcehut's FreeBSD instance
-# and not producing any logs as a result. So don't do this task for now.
-# Ref: https://github.com/neovim/neovim/pull/11477#discussion_r352095005.
-# - test-oldtest: |
-# cd neovim
-# gmake oldtest
+- oldtest: |
+ cd neovim
+ gmake oldtest
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
index 2f9ccdc1be..0aaa003820 100644
--- a/.builds/openbsd.yml
+++ b/.builds/openbsd.yml
@@ -1,6 +1,6 @@
# sourcehut CI: https://builds.sr.ht/~jmk/neovim
-image: openbsd/6.9
+image: openbsd/latest
packages:
- autoconf-2.71
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3565b20bfc..41a22af538 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,6 +19,11 @@ concurrency:
jobs:
lint:
+ # This job tests two things: it lints the code but also builds neovim using
+ # system dependencies instead of bundled dependencies. This is to make sure
+ # we are able to build neovim without pigeonholing ourselves into specifics
+ # of the bundled dependencies.
+
if: (github.event_name == 'pull_request' && github.base_ref == 'master' && !github.event.pull_request.draft) || (github.event_name == 'push' && github.ref == 'refs/heads/master')
runs-on: ubuntu-20.04
timeout-minutes: 10
@@ -100,7 +105,7 @@ jobs:
- name: Cache dependencies
run: ./ci/before_cache.sh
- unixish:
+ posix:
name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
strategy:
fail-fast: false
@@ -120,6 +125,12 @@ jobs:
- cc: clang
runner: macos-11.0
os: osx
+
+ # The functionaltest-lua test two things simultaneously:
+ # 1. Check that the tests pass with PUC Lua instead of LuaJIT.
+ # 2. Use as oldest/minimum versions of dependencies/build tools we
+ # still explicitly support so we don't accidentally rely on
+ # features that is only available on later versions.
- flavor: functionaltest-lua
cc: gcc
runner: ubuntu-20.04
@@ -172,8 +183,8 @@ jobs:
- name: Install brew packages
if: matrix.os == 'osx'
run: |
- brew update >/dev/null
- brew install automake ccache perl cpanminus ninja
+ brew update --quiet
+ brew install automake ccache cpanminus ninja
- name: Setup interpreter packages
run: ./ci/install.sh
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e954b57175..8e0b13d59c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -85,7 +85,7 @@ jobs:
fetch-depth: 0
- name: Install brew packages
run: |
- brew update >/dev/null
+ brew update --quiet
brew install automake ninja
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly')
run: printf 'NVIM_BUILD_TYPE=Release\n' >> $GITHUB_ENV
diff --git a/contrib/flake.lock b/contrib/flake.lock
index c4d7f120ba..b72e1f8d5f 100644
--- a/contrib/flake.lock
+++ b/contrib/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"flake-utils": {
"locked": {
- "lastModified": 1629481132,
- "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=",
+ "lastModified": 1644229661,
+ "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "997f7efcb746a9c140ce1f13c72263189225f482",
+ "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
"type": "github"
},
"original": {
@@ -17,11 +17,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1630074300,
- "narHash": "sha256-BFM7OiXRs0RvSUZd6NCGAKWVPn3VodgYQ4TUQXxbMBU=",
+ "lastModified": 1646254136,
+ "narHash": "sha256-8nQx02tTzgYO21BP/dy5BCRopE8OwE8Drsw98j+Qoaw=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "21c937f8cb1e6adcfeb36dfd6c90d9d9bfab1d28",
+ "rev": "3e072546ea98db00c2364b81491b893673267827",
"type": "github"
},
"original": {
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 73536d174a..eefe6e5a47 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -3165,7 +3165,7 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
• create a |autocmd-buflocal| autocmd.
• NOTE: Cannot be used with {pattern}
- • group: (string) The augroup name
+ • group: (string|int) The augroup name or id
• once: (boolean) - See |autocmd-once|
• nested: (boolean) - See |autocmd-nested|
• desc: (string) - Description of the autocmd
@@ -3213,7 +3213,7 @@ nvim_do_autocmd({event}, {*opts}) *nvim_do_autocmd()*
"*".
• NOTE: Cannot be used with {buffer}
- • group (string) - autocmd group name
+ • group (string|int) - autocmd group name or id
• modeline (boolean) - Default true, see
|<nomodeline>|
@@ -3224,7 +3224,8 @@ nvim_get_autocmds({*opts}) *nvim_get_autocmds()*
{opts} Optional Parameters:
• event : Name or list of name of events to match
against
- • group (string): Name of group to match against
+ • group (string|int): Name or id of group to match
+ against
• pattern: Pattern or list of patterns to match
against. Cannot be used with {buffer}
• buffer: Buffer number or list of buffer numbers
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 05529dc90a..994f97bba0 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -161,6 +161,11 @@ Q Repeat the last recorded register [count] times.
result of evaluating the expression is executed as an
Ex command.
Mappings are not recognized in these commands.
+ When the |line-continuation| character (\) is present
+ at the beginning of a line in a linewise register,
+ then it is combined with the previous line. This is
+ useful for yanking and executing parts of a Vim
+ script.
*:@:*
:[addr]@: Repeat last command-line. First set cursor at line
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index ddd1147468..2251aca004 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -3,9 +3,11 @@
-- Lua code lives in one of three places:
-- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the
-- `inspect` and `lpeg` modules.
--- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests.
--- (This will go away if we migrate to nvim as the test-runner.)
--- 3. runtime/lua/vim/_editor.lua: Compiled-into Nvim itself.
+-- 2. runtime/lua/vim/shared.lua: pure lua functions which always
+-- are available. Used in the test runner, as well as worker threads
+-- and processes launched from Nvim.
+-- 3. runtime/lua/vim/_editor.lua: Code which directly interacts with
+-- the Nvim editor state. Only available in the main thread.
--
-- Guideline: "If in doubt, put it in the runtime".
--
@@ -35,43 +37,19 @@
-- - https://github.com/howl-editor/howl/tree/master/lib/howl/util
local vim = assert(vim)
-assert(vim.inspect)
-- These are for loading runtime modules lazily since they aren't available in
-- the nvim binary as specified in executor.c
-setmetatable(vim, {
- __index = function(t, key)
- if key == 'treesitter' then
- t.treesitter = require('vim.treesitter')
- return t.treesitter
- elseif key == 'filetype' then
- t.filetype = require('vim.filetype')
- return t.filetype
- elseif key == 'F' then
- t.F = require('vim.F')
- return t.F
- elseif require('vim.uri')[key] ~= nil then
- -- Expose all `vim.uri` functions on the `vim` module.
- t[key] = require('vim.uri')[key]
- return t[key]
- elseif key == 'lsp' then
- t.lsp = require('vim.lsp')
- return t.lsp
- elseif key == 'highlight' then
- t.highlight = require('vim.highlight')
- return t.highlight
- elseif key == 'diagnostic' then
- t.diagnostic = require('vim.diagnostic')
- return t.diagnostic
- elseif key == 'keymap' then
- t.keymap = require('vim.keymap')
- return t.keymap
- elseif key == 'ui' then
- t.ui = require('vim.ui')
- return t.ui
- end
- end
-})
+for k,v in pairs {
+ treesitter=true;
+ filetype = true;
+ F=true;
+ lsp=true;
+ highlight=true;
+ diagnostic=true;
+ keymap=true;
+ ui=true;
+} do vim._submodules[k] = v end
vim.log = {
levels = {
diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua
index dcb402287c..7d27741f1b 100644
--- a/runtime/lua/vim/_init_packages.lua
+++ b/runtime/lua/vim/_init_packages.lua
@@ -50,7 +50,25 @@ table.insert(package.loaders, 2, vim._load_package)
-- builtin functions which always should be available
require'vim.shared'
-vim.inspect = require'vim.inspect'
+
+vim._submodules = {inspect=true}
+
+-- These are for loading runtime modules in the vim namespace lazily.
+setmetatable(vim, {
+ __index = function(t, key)
+ if vim._submodules[key] then
+ t[key] = require('vim.'..key)
+ return t[key]
+ elseif vim.startswith(key, 'uri_') then
+ local val = require('vim.uri')[key]
+ if val ~= nil then
+ -- Expose all `vim.uri` functions on the `vim` module.
+ t[key] = val
+ return t[key]
+ end
+ end
+ end
+})
--- <Docs described in |vim.empty_dict()| >
---@private
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 48d0bd3672..8124b23eb1 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1,8 +1,10 @@
-- Functions shared by Nvim and its test-suite.
--
--- The singular purpose of this module is to share code with the Nvim
--- test-suite. If, in the future, Nvim itself is used to run the test-suite
--- instead of "vanilla Lua", these functions could move to runtime/lua/vim/_editor.lua
+-- These are "pure" lua functions not depending of the state of the editor.
+-- Thus they should always be available whenever nvim-related lua code is run,
+-- regardless if it is code in the editor itself, or in worker threads/processes,
+-- or the test suite. (Eventually the test suite will be run in a worker process,
+-- so this wouldn't be a separate case to consider)
local vim = vim or {}
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 9abefbe02a..9f29cae29d 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -342,6 +342,7 @@ add_custom_command(
${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap"
DEPENDS
${CHAR_BLOB_GENERATOR}
+ ${LUA_INIT_PACKAGES_MODULE_SOURCE}
${LUA_EDITOR_MODULE_SOURCE}
${LUA_SHARED_MODULE_SOURCE}
${LUA_INSPECT_MODULE_SOURCE}
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 685667ac64..5ede0e5265 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -40,7 +40,7 @@ static int64_t next_autocmd_id = 1;
///
/// @param opts Optional Parameters:
/// - event : Name or list of name of events to match against
-/// - group (string): Name of group to match against
+/// - group (string|int): Name or id of group to match against
/// - pattern: Pattern or list of patterns to match against. Cannot be used with {buffer}
/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands
/// |autocmd-buflocal|. Cannot be used with {pattern}
@@ -62,19 +62,27 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
int group = 0;
- if (opts->group.type != kObjectTypeNil) {
- Object v = opts->group;
- if (v.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "group must be a string.");
- goto cleanup;
- }
-
- group = augroup_find(v.data.string.data);
-
- if (group < 0) {
- api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ group = augroup_find(opts->group.data.string.data);
+ if (group < 0) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ group = (int)opts->group.data.integer;
+ char *name = augroup_name(group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "group must be a string or an integer.");
goto cleanup;
- }
}
if (opts->event.type != kObjectTypeNil) {
@@ -321,7 +329,7 @@ cleanup:
/// - buffer: (bufnr)
/// - create a |autocmd-buflocal| autocmd.
/// - NOTE: Cannot be used with {pattern}
-/// - group: (string) The augroup name
+/// - group: (string|int) The augroup name or id
/// - once: (boolean) - See |autocmd-once|
/// - nested: (boolean) - See |autocmd-nested|
/// - desc: (string) - Description of the autocmd
@@ -406,23 +414,29 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
bool is_once = api_object_to_bool(opts->once, "once", false, err);
bool is_nested = api_object_to_bool(opts->nested, "nested", false, err);
- // TODO(tjdevries): accept number for namespace instead
- if (opts->group.type != kObjectTypeNil) {
- Object *v = &opts->group;
- if (v->type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "'group' must be a string");
- goto cleanup;
- }
-
- au_group = augroup_find(v->data.string.data);
-
- if (au_group == AUGROUP_ERROR) {
- api_set_error(err,
- kErrorTypeException,
- "invalid augroup: %s", v->data.string.data);
-
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ au_group = augroup_find(opts->group.data.string.data);
+ if (au_group == AUGROUP_ERROR) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "invalid augroup: %s", opts->group.data.string.data);
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ au_group = (int)opts->group.data.integer;
+ char *name = augroup_name(au_group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group);
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer.");
goto cleanup;
- }
}
if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) {
@@ -624,7 +638,7 @@ void nvim_del_augroup_by_name(String name)
/// - NOTE: Cannot be used with {pattern}
/// - pattern (string|table) - optional, defaults to "*".
/// - NOTE: Cannot be used with {buffer}
-/// - group (string) - autocmd group name
+/// - group (string|int) - autocmd group name or id
/// - modeline (boolean) - Default true, see |<nomodeline>|
void nvim_do_autocmd(Object event, Dict(do_autocmd) *opts, Error *err)
FUNC_API_SINCE(9)
@@ -644,21 +658,29 @@ void nvim_do_autocmd(Object event, Dict(do_autocmd) *opts, Error *err)
goto cleanup;
}
- if (opts->group.type != kObjectTypeNil) {
- if (opts->group.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "'group' must be a string");
- goto cleanup;
- }
-
- au_group = augroup_find(opts->group.data.string.data);
-
- if (au_group == AUGROUP_ERROR) {
- api_set_error(err,
- kErrorTypeException,
- "invalid augroup: %s", opts->group.data.string.data);
-
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ au_group = augroup_find(opts->group.data.string.data);
+ if (au_group == AUGROUP_ERROR) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "invalid augroup: %s", opts->group.data.string.data);
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ au_group = (int)opts->group.data.integer;
+ char *name = augroup_name(au_group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group);
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer.");
goto cleanup;
- }
}
if (opts->buffer.type != kObjectTypeNil) {
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 7cb493f57d..a850e5c1a0 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -105,15 +105,24 @@ static char_u *old_termresponse = NULL;
#define FOR_ALL_AUPATS_IN_EVENT(event, ap) \
for (AutoPat *ap = first_autopat[event]; ap != NULL; ap = ap->next) // NOLINT
-// Map of autocmd group names.
+// Map of autocmd group names and ids.
// name -> ID
-static Map(String, int) augroup_map = MAP_INIT;
+// ID -> name
+static Map(String, int) map_augroup_name_to_id = MAP_INIT;
+static Map(int, String) map_augroup_id_to_name = MAP_INIT;
-static void augroup_map_del(char *name)
+static void augroup_map_del(int id, char *name)
{
- String key = map_key(String, int)(&augroup_map, cstr_as_string(name));
- map_del(String, int)(&augroup_map, key);
- api_free_string(key);
+ if (name != NULL) {
+ String key = map_key(String, int)(&map_augroup_name_to_id, cstr_as_string(name));
+ map_del(String, int)(&map_augroup_name_to_id, key);
+ api_free_string(key);
+ }
+ if (id > 0) {
+ String mapped = map_get(int, String)(&map_augroup_id_to_name, id);
+ api_free_string(mapped);
+ map_del(int, String)(&map_augroup_id_to_name, id);
+ }
}
@@ -382,12 +391,14 @@ int augroup_add(char *name)
}
if (existing_id == AUGROUP_DELETED) {
- augroup_map_del(name);
+ augroup_map_del(existing_id, name);
}
int next_id = next_augroup_id++;
- String name_copy = cstr_to_string(name);
- map_put(String, int)(&augroup_map, name_copy, next_id);
+ String name_key = cstr_to_string(name);
+ String name_val = cstr_to_string(name);
+ map_put(String, int)(&map_augroup_name_to_id, name_key, next_id);
+ map_put(int, String)(&map_augroup_id_to_name, next_id, name_val);
return next_id;
}
@@ -416,7 +427,8 @@ void augroup_del(char *name, bool stupid_legacy_mode)
FOR_ALL_AUPATS_IN_EVENT(event, ap) {
if (ap->group == i && ap->pat != NULL) {
give_warning((char_u *)_("W19: Deleting augroup that is still in use"), true);
- map_put(String, int)(&augroup_map, cstr_as_string(name), AUGROUP_DELETED);
+ map_put(String, int)(&map_augroup_name_to_id, cstr_as_string(name), AUGROUP_DELETED);
+ augroup_map_del(ap->group, NULL);
return;
}
}
@@ -432,7 +444,7 @@ void augroup_del(char *name, bool stupid_legacy_mode)
}
// Remove the group because it's not currently in use.
- augroup_map_del(name);
+ augroup_map_del(i, name);
au_cleanup();
}
}
@@ -445,7 +457,7 @@ void augroup_del(char *name, bool stupid_legacy_mode)
int augroup_find(const char *name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- int existing_id = map_get(String, int)(&augroup_map, cstr_as_string((char *)name));
+ int existing_id = map_get(String, int)(&map_augroup_name_to_id, cstr_as_string((char *)name));
if (existing_id == AUGROUP_DELETED) {
return existing_id;
}
@@ -487,13 +499,10 @@ char *augroup_name(int group)
return NULL;
}
- String key;
- int value;
- map_foreach(&augroup_map, key, value, {
- if (value == group) {
- return key.data;
- }
- });
+ String key = map_get(int, String)(&map_augroup_id_to_name, group);
+ if (key.data != NULL) {
+ return key.data;
+ }
// If it's not in the map anymore, then it must have been deleted.
return (char *)get_deleted_augroup();
@@ -526,7 +535,7 @@ void do_augroup(char_u *arg, int del_group)
String name;
int value;
- map_foreach(&augroup_map, name, value, {
+ map_foreach(&map_augroup_name_to_id, name, value, {
if (value > 0) {
msg_puts(name.data);
} else {
@@ -556,11 +565,17 @@ void free_all_autocmds(void)
// Delete the augroup_map, including free the data
String name;
int id;
- map_foreach(&augroup_map, name, id, {
+ map_foreach(&map_augroup_name_to_id, name, id, {
+ (void)id;
+ api_free_string(name);
+ })
+ map_destroy(String, int)(&map_augroup_name_to_id);
+
+ map_foreach(&map_augroup_id_to_name, id, name, {
(void)id;
api_free_string(name);
})
- map_destroy(String, int)(&augroup_map);
+ map_destroy(int, String)(&map_augroup_id_to_name);
}
#endif
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index aa7b9e80a4..8cdb03c341 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -7789,8 +7789,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co
break;
case kCallbackLua:
- ILOG(" We tryin to call dat dang lua ref ");
- nlua_call_ref(callback->data.luaref, "aucmd", args, false, NULL);
+ nlua_call_ref(callback->data.luaref, NULL, args, false, NULL);
return false;
break;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index d207dcb527..f47c9c482b 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -11411,7 +11411,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
case 'u': {
const size_t len = STRLEN(what);
if (len <= 5 || (TOLOWER_ASC(what[5]) == 'l' && len <= 9)) { // underline
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
} else if (TOLOWER_ASC(what[5]) == 'c') { // undercurl
p = highlight_has_attr(id, HL_UNDERCURL, modec);
} else if (len > 9 && TOLOWER_ASC(what[9]) == 'l') { // underlineline
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 2a40e50014..5c040adc1c 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1698,7 +1698,7 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize,
return false;
}
if (ga->ga_len > init_growsize) {
- ga_set_growsize(ga, MAX(ga->ga_len, 8000));
+ ga_set_growsize(ga, MIN(ga->ga_len, 8000));
}
ga_concat_len(ga, (const char *)line + 1, len - 1);
return true;
@@ -1852,7 +1852,7 @@ static void cmd_source_buffer(const exarg_T *const eap)
for (linenr_T curr_lnum = eap->line1; curr_lnum <= final_lnum; curr_lnum++) {
// Adjust growsize to current length to speed up concatenating many lines.
if (ga.ga_len > 400) {
- ga_set_growsize(&ga, MAX(ga.ga_len, 8000));
+ ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
}
ga_concat(&ga, (char *)ml_get(curr_lnum));
ga_append(&ga, NL);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 29a3c515c2..6aaff100ca 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -565,7 +565,8 @@ static bool nlua_init_packages(lua_State *lstate)
lua_getglobal(lstate, "require");
lua_pushstring(lstate, "vim._init_packages");
if (nlua_pcall(lstate, 1, 0)) {
- nlua_error(lstate, _("E5106: Error while loading packages: %.*s\n"));
+ mch_errmsg(lua_tostring(lstate, -1));
+ mch_errmsg("\n");
return false;
}
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 091d653046..4e39eb8c07 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -178,6 +178,7 @@ MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
+MAP_IMPL(int, String, DEFAULT_INITIALIZER)
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index c9c89bf2fd..00f72386a7 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -47,6 +47,7 @@ MAP_DECLS(String, MsgpackRpcRequestHandler)
MAP_DECLS(HlEntry, int)
MAP_DECLS(String, handle_T)
MAP_DECLS(String, int)
+MAP_DECLS(int, String)
MAP_DECLS(ColorKey, ColorItem)
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b5c7020dee..3f51210781 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1023,6 +1023,60 @@ static int stuff_yank(int regname, char_u *p)
static int execreg_lastc = NUL;
+/// When executing a register as a series of ex-commands, if the
+/// line-continuation character is used for a line, then join it with one or
+/// more previous lines. Note that lines are processed backwards starting from
+/// the last line in the register.
+///
+/// @param lines list of lines in the register
+/// @param idx index of the line starting with \ or "\. Join this line with all the immediate
+/// predecessor lines that start with a \ and the first line that doesn't start
+/// with a \. Lines that start with a comment "\ character are ignored.
+/// @returns the concatenated line. The index of the line that should be
+/// processed next is returned in idx.
+static char_u *execreg_line_continuation(char_u **lines, size_t *idx)
+{
+ size_t i = *idx;
+ assert(i > 0);
+ const size_t cmd_end = i;
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char_u), 400);
+
+ char_u *p;
+
+ // search backwards to find the first line of this command.
+ // Any line not starting with \ or "\ is the start of the
+ // command.
+ while (--i > 0) {
+ p = skipwhite(lines[i]);
+ if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
+ break;
+ }
+ }
+ const size_t cmd_start = i;
+
+ // join all the lines
+ ga_concat(&ga, (char *)lines[cmd_start]);
+ for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
+ p = skipwhite(lines[j]);
+ if (*p == '\\') {
+ // Adjust the growsize to the current length to
+ // speed up concatenating many lines.
+ if (ga.ga_len > 400) {
+ ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
+ }
+ ga_concat(&ga, (char *)(p + 1));
+ }
+ }
+ ga_append(&ga, NUL);
+ char_u *str = vim_strsave(ga.ga_data);
+ ga_clear(&ga);
+
+ *idx = i;
+ return str;
+}
+
/// Execute a yank register: copy it into the stuff buffer
///
/// @param colon insert ':' before each line
@@ -1111,7 +1165,21 @@ int do_execreg(int regname, int colon, int addcr, int silent)
return FAIL;
}
}
- escaped = vim_strsave_escape_ks(reg->y_array[i]);
+
+ // Handle line-continuation for :@<register>
+ char_u *str = reg->y_array[i];
+ bool free_str = false;
+ if (colon && i > 0) {
+ p = skipwhite(str);
+ if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')) {
+ str = execreg_line_continuation(reg->y_array, &i);
+ free_str = true;
+ }
+ }
+ escaped = vim_strsave_escape_ks(str);
+ if (free_str) {
+ xfree(str);
+ }
retval = ins_typebuf(escaped, remap, 0, true, silent);
xfree(escaped);
if (retval == FAIL) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index ee1acd8d03..1cdee7c972 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2890,9 +2890,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
} else if (wp->w_p_cul
&& lnum == wp->w_cursor.lnum
&& (wp->w_p_culopt_flags & CULOPT_NBR)
- && (row == startrow
- || wp->w_p_culopt_flags & CULOPT_LINE)
- && filler_todo == 0) {
+ && (row == startrow + filler_lines
+ || (row > startrow + filler_lines
+ && wp->w_p_culopt_flags & CULOPT_LINE))) {
// When 'cursorline' is set highlight the line number of
// the current line differently.
// When 'cursorlineopt' has "screenline" only highlight
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 53ed4617f7..4229095f9f 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -26,6 +26,54 @@ func Test_set_filename()
call delete('samples/Xtest')
endfunc
+func Test_set_filename_other_window()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ call test_autochdir()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+endfunc
+
+func Test_acd_win_execute()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ set acd
+ call test_autochdir()
+
+ call mkdir('Xfile')
+ let winid = win_getid()
+ new Xfile/file
+ call assert_match('testdir.Xfile$', getcwd())
+ cd ..
+ call assert_match('testdir$', getcwd())
+ call win_execute(winid, 'echo')
+ call assert_match('testdir$', getcwd())
+
+ bwipe!
+ set noacd
+ call chdir(cwd)
+ call delete('Xfile', 'rf')
+endfunc
+
func Test_verbose_pwd()
CheckFunction test_autochdir
let cwd = getcwd()
@@ -42,20 +90,27 @@ func Test_verbose_pwd()
set acd
wincmd w
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
- execute 'lcd' cwd
- call assert_match('\[window\].*testdir$', execute('verbose pwd'))
execute 'tcd' cwd
call assert_match('\[tabpage\].*testdir$', execute('verbose pwd'))
execute 'cd' cwd
call assert_match('\[global\].*testdir$', execute('verbose pwd'))
+ execute 'lcd' cwd
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
edit
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
+ enew
+ wincmd w
+ call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
set noacd
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
wincmd w
- call assert_match('\[global\].*testdir', execute('verbose pwd'))
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
+ execute 'cd' cwd
+ call assert_match('\[global\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 482d39056f..10eb979b45 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1017,6 +1017,32 @@ func Test_diff_with_cursorline()
call delete('Xtest_diff_cursorline')
endfunc
+func Test_diff_with_cursorline_number()
+ CheckScreendump
+
+ let lines =<< trim END
+ hi CursorLine ctermbg=red ctermfg=white
+ hi CursorLineNr ctermbg=white ctermfg=black cterm=underline
+ set cursorline number
+ call setline(1, ["baz", "foo", "foo", "bar"])
+ 2
+ vnew
+ call setline(1, ["foo", "foo", "bar"])
+ windo diffthis
+ 1wincmd w
+ END
+ call writefile(lines, 'Xtest_diff_cursorline_number')
+ let buf = RunVimInTerminal('-S Xtest_diff_cursorline_number', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_01', {})
+ call term_sendkeys(buf, ":set cursorlineopt=number\r")
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_cursorline_number')
+endfunc
+
func Test_diff_with_cursorline_breakindent()
CheckScreendump
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 23e39eba35..ecc65b240b 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -482,6 +482,82 @@ func Test_v_register()
bwipe!
endfunc
+" Test for executing the contents of a register as an Ex command with line
+" continuation.
+func Test_execute_reg_as_ex_cmd()
+ " Line continuation with just two lines
+ let code =<< trim END
+ let l = [
+ \ 1]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1], l)
+
+ " Line continuation with more than two lines
+ let code =<< trim END
+ let l = [
+ \ 1,
+ \ 2,
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use comments interspersed with code
+ let code =<< trim END
+ let l = [
+ "\ one
+ \ 1,
+ "\ two
+ \ 2,
+ "\ three
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use line continuation in the middle
+ let code =<< trim END
+ let a = "one"
+ let l = [
+ \ 1,
+ \ 2]
+ let b = "two"
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2], l)
+ call assert_equal("one", a)
+ call assert_equal("two", b)
+
+ " only one line with a \
+ let @r = "\\let l = 1"
+ call assert_fails('@r', 'E10:')
+
+ " only one line with a "\
+ let @r = ' "\ let i = 1'
+ @r
+ call assert_false(exists('i'))
+
+ " first line also begins with a \
+ let @r = "\\let l = [\n\\ 1]"
+ call assert_fails('@r', 'E10:')
+
+ " Test with a large number of lines
+ let @r = "let str = \n"
+ let @r ..= repeat(" \\ 'abcdefghijklmnopqrstuvwxyz' ..\n", 312)
+ let @r ..= ' \ ""'
+ @r
+ call assert_equal(repeat('abcdefghijklmnopqrstuvwxyz', 312), str)
+endfunc
+
func Test_ve_blockpaste()
new
set ve=all
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 83048d911f..d5299202b0 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6763,9 +6763,6 @@ void restore_win_noblock(switchwin_T *switchwin, bool no_display)
curwin = switchwin->sw_curwin;
curbuf = curwin->w_buffer;
}
- // If called by win_execute() and executing the command changed the
- // directory, it now has to be restored.
- fix_current_dir();
}
/// Make "buf" the current buffer.
diff --git a/src/nvim/window.h b/src/nvim/window.h
index e2fd2c515d..42701f72b4 100644
--- a/src/nvim/window.h
+++ b/src/nvim/window.h
@@ -5,6 +5,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/mark.h"
+#include "nvim/os/os.h"
// Values for file_name_in_line()
#define FNAME_MESS 1 // give error message
@@ -47,12 +48,36 @@ typedef struct {
do { \
win_T *const wp_ = (wp); \
const pos_T curpos_ = wp_->w_cursor; \
+ char_u cwd_[MAXPATHL]; \
+ char_u autocwd_[MAXPATHL]; \
+ bool apply_acd_ = false; \
+ int cwd_status_ = FAIL; \
+ /* Getting and setting directory can be slow on some systems, only do */ \
+ /* this when the current or target window/tab have a local directory or */ \
+ /* 'acd' is set. */ \
+ if (curwin != wp \
+ && (curwin->w_localdir != NULL || wp->w_localdir != NULL \
+ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
+ || p_acd)) { \
+ cwd_status_ = os_dirname(cwd_, MAXPATHL); \
+ } \
+ /* If 'acd' is set, check we are using that directory. If yes, then */ \
+ /* apply 'acd' afterwards, otherwise restore the current directory. */ \
+ if (cwd_status_ == OK && p_acd) { \
+ do_autochdir(); \
+ apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && STRCMP(cwd_, autocwd_) == 0; \
+ } \
switchwin_T switchwin_; \
if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
check_cursor(); \
block; \
} \
restore_win_noblock(&switchwin_, true); \
+ if (apply_acd_) { \
+ do_autochdir(); \
+ } else if (cwd_status_ == OK) { \
+ os_chdir((char *)cwd_); \
+ } \
/* Update the status line if the cursor moved. */ \
if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
wp_->w_redr_status = true; \
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index e8dc284925..372cbf2c30 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -281,6 +281,31 @@ describe('autocmd api', function()
eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
end)
+
+ it('should return autocmds when group is specified by id', function()
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auid }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auid, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
+
+ it('should return autocmds when group is specified by name', function()
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auname }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auname, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
end)
describe('groups', function()
@@ -331,7 +356,7 @@ describe('autocmd api', function()
end)
describe('groups: 2', function()
- it('raises error for undefined augroup', function()
+ it('raises error for undefined augroup name', function()
local success, code = unpack(meths.exec_lua([[
return {pcall(function()
vim.api.nvim_create_autocmd("FileType", {
@@ -345,6 +370,39 @@ describe('autocmd api', function()
eq(false, success)
matches('invalid augroup: NotDefined', code)
end)
+
+ it('raises error for undefined augroup id', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ -- Make sure the augroup is deleted
+ vim.api.nvim_del_augroup_by_id(1)
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = 1,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches('invalid augroup: 1', code)
+ end)
+
+ it('raises error for invalid group type', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = true,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches("'group' must be a string or an integer", code)
+ end)
end)
describe('patterns', function()
@@ -497,6 +555,35 @@ describe('autocmd api', function()
meths.do_autocmd("User", { pattern = "TestCommand" })
eq('matched', meths.get_var('matched'))
end)
+
+ it('can pass group by id', function()
+ meths.set_var("group_executed", false)
+
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auid,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.do_autocmd("FileType", { group = auid })
+ eq(true, meths.get_var("group_executed"))
+ end)
+
+ it('can pass group by name', function()
+ meths.set_var("group_executed", false)
+
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auname,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.do_autocmd("FileType", { group = auname })
+ eq(true, meths.get_var("group_executed"))
+ end)
end)
describe('nvim_create_augroup', function()
diff --git a/test/functional/legacy/autochdir_spec.lua b/test/functional/legacy/autochdir_spec.lua
index 37a94476a0..13cb6cd287 100644
--- a/test/functional/legacy/autochdir_spec.lua
+++ b/test/functional/legacy/autochdir_spec.lua
@@ -1,8 +1,12 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear, eq, matches = helpers.clear, helpers.eq, helpers.matches
-local eval, command, call = helpers.eval, helpers.command, helpers.call
-local exec_capture = helpers.exec_capture
+local eval, command, call, meths = helpers.eval, helpers.command, helpers.call, helpers.meths
+local source, exec_capture = helpers.source, helpers.exec_capture
+
+local function expected_empty()
+ eq({}, meths.get_vvar('errors'))
+end
describe('autochdir behavior', function()
local dir = 'Xtest_functional_legacy_autochdir'
@@ -10,19 +14,66 @@ describe('autochdir behavior', function()
before_each(function()
lfs.mkdir(dir)
clear()
+ command('set shellslash')
end)
after_each(function()
helpers.rmdir(dir)
end)
- -- Tests vim/vim/777 without test_autochdir().
+ -- Tests vim/vim#777 without test_autochdir().
it('sets filename', function()
command('set acd')
command('new')
command('w '..dir..'/Xtest')
eq('Xtest', eval("expand('%')"))
- eq(dir, eval([[substitute(getcwd(), '.*[/\\]\(\k*\)', '\1', '')]]))
+ eq(dir, eval([[substitute(getcwd(), '.*/\(\k*\)', '\1', '')]]))
+ end)
+
+ it(':file in win_execute() does not cause wrong directory', function()
+ command('cd '..dir)
+ source([[
+ func Test_set_filename_other_window()
+ let cwd = getcwd()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+ endfunc
+ ]])
+ call('Test_set_filename_other_window')
+ expected_empty()
+ end)
+
+ it('win_execute() does not change directory', function()
+ local subdir = 'Xfile'
+ command('cd '..dir)
+ command('set acd')
+ call('mkdir', subdir)
+ local winid = eval('win_getid()')
+ command('new '..subdir..'/file')
+ matches(dir..'/'..subdir..'$', eval('getcwd()'))
+ command('cd ..')
+ matches(dir..'$', eval('getcwd()'))
+ call('win_execute', winid, 'echo')
+ matches(dir..'$', eval('getcwd()'))
end)
it(':verbose pwd shows whether autochdir is used', function()
@@ -30,29 +81,36 @@ describe('autochdir behavior', function()
command('cd '..dir)
local cwd = eval('getcwd()')
command('edit global.txt')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
call('mkdir', subdir)
command('split '..subdir..'/local.txt')
command('lcd '..subdir)
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set autochdir')
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set acd')
command('wincmd w')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
- command('lcd '..cwd)
- matches('%[window%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
command('tcd '..cwd)
- matches('%[tabpage%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[tabpage%].*'..dir..'$', exec_capture('verbose pwd'))
command('cd '..cwd)
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('lcd '..cwd)
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
command('edit')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('enew')
command('wincmd w')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set noautochdir')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set noacd')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('cd '..cwd)
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 3dacb7a114..e66e08d9d0 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -1,6 +1,5 @@
-- Test suite for testing interactions with API bindings
local helpers = require('test.functional.helpers')(after_each)
-local isCI = require('test.helpers').isCI
local Screen = require('test.functional.ui.screen')
local funcs = helpers.funcs
@@ -2558,9 +2557,6 @@ describe('lua: builtin modules', function()
it('does not work when disabled without runtime', function()
- if isCI('sourcehut') then
- pending('causes a core dump')
- end
clear{args={'--luamod-dev'}, env={VIMRUNTIME='fixtures/a'}}
-- error checking could be better here. just check that --luamod-dev
-- does anything at all by breaking with missing runtime..
diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua
index 2fce0a5ed9..74959a8e76 100644
--- a/test/functional/options/autochdir_spec.lua
+++ b/test/functional/options/autochdir_spec.lua
@@ -1,7 +1,9 @@
+local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
-local getcwd = helpers.funcs.getcwd
+local funcs = helpers.funcs
+local command = helpers.command
describe("'autochdir'", function()
it('given on the shell gets processed properly', function()
@@ -9,11 +11,34 @@ describe("'autochdir'", function()
-- By default 'autochdir' is off, thus getcwd() returns the repo root.
clear(targetdir..'/tty-test.c')
- local rootdir = getcwd()
+ local rootdir = funcs.getcwd()
local expected = rootdir .. '/' .. targetdir
-- With 'autochdir' on, we should get the directory of tty-test.c.
clear('--cmd', 'set autochdir', targetdir..'/tty-test.c')
- eq(helpers.iswin() and expected:gsub('/', '\\') or expected, getcwd())
+ eq(helpers.iswin() and expected:gsub('/', '\\') or expected, funcs.getcwd())
+ end)
+
+ it('is not overwritten by getwinvar() call #17609',function()
+ local curdir = string.gsub(lfs.currentdir(), '\\', '/')
+ local dir_a = curdir..'/Xtest-functional-options-autochdir.dir_a'
+ local dir_b = curdir..'/Xtest-functional-options-autochdir.dir_b'
+ lfs.mkdir(dir_a)
+ lfs.mkdir(dir_b)
+ clear()
+ command('set shellslash')
+ command('set autochdir')
+ command('edit '..dir_a..'/file1')
+ eq(dir_a, funcs.getcwd())
+ command('lcd '..dir_b)
+ eq(dir_b, funcs.getcwd())
+ command('botright vnew ../file2')
+ eq(curdir, funcs.getcwd())
+ command('wincmd w')
+ eq(dir_a, funcs.getcwd())
+ funcs.getwinvar(2, 'foo')
+ eq(dir_a, funcs.getcwd())
+ helpers.rmdir(dir_a)
+ helpers.rmdir(dir_b)
end)
end)
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index ebbae1df14..ab4b4e9147 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -305,10 +305,17 @@ describe('synIDattr()', function()
eq('79', eval('synIDattr(hlID("Keyword"), "fg")'))
end)
- it('returns "1" if group has "strikethrough" attribute', function()
- eq('', eval('synIDattr(hlID("Normal"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough", "gui")'))
+ it('returns "1" if group has given highlight attribute', function()
+ local hl_attrs = {
+ 'underline', 'underlineline', 'undercurl', 'underdot', 'underdash', 'strikethrough'
+ }
+ for _,hl_attr in ipairs(hl_attrs) do
+ local context = 'using ' .. hl_attr .. ' attr'
+ command('highlight Keyword cterm=' .. hl_attr .. ' gui=' .. hl_attr)
+ eq('', eval('synIDattr(hlID("Normal"), "'.. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '", "gui")'), context)
+ end
end)
end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index bd2692d19a..3a25d7e813 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -6,7 +6,7 @@ local clear = helpers.clear
local command = helpers.command
local insert = helpers.insert
local write_file = helpers.write_file
-local source = helpers.source
+local exec = helpers.exec
describe('Diff mode screen', function()
local fname = 'Xtest-functional-diff-screen-1'
@@ -1075,10 +1075,8 @@ it('diff updates line numbers below filler lines', function()
[9] = {background = Screen.colors.LightMagenta},
[10] = {bold = true, foreground = Screen.colors.Brown},
[11] = {foreground = Screen.colors.Brown},
- [12] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
- [13] = {background = Screen.colors.Gray90};
})
- source([[
+ exec([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
vnew
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
@@ -1135,24 +1133,6 @@ it('diff updates line numbers below filler lines', function()
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
- command("set signcolumn number tgc cursorline cursorlineopt=number,line")
- command("hi CursorLineNr guibg=red")
- screen:expect{grid=[[
- {1: }a {3:│}{11: 2 }a |
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{12:3 }{13:^a }|
- {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 2 }b |
- {1: }b {3:│}{11: 3 }b |
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {6:~ }{3:│}{6:~ }|
- {3:[No Name] [+] }{7:[No Name] [+] }|
- signcolumn=auto |
- ]]}
end)
it('Align the filler lines when changing text in diff mode', function()
@@ -1169,7 +1149,7 @@ it('Align the filler lines when changing text in diff mode', function()
[7] = {foreground = Screen.colors.Blue1, bold = true};
[8] = {reverse = true, bold = true};
})
- source([[
+ exec([[
call setline(1, range(1, 15))
vnew
call setline(1, range(9, 15))
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 12643eec1e..64f0ba3419 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -840,7 +840,7 @@ describe("'listchars' highlight", function()
end)
end)
-describe('CursorLine highlight', function()
+describe('CursorLine and CursorLineNr highlights', function()
before_each(clear)
it('overridden by Error, ColorColumn if fg not set', function()
@@ -1081,7 +1081,7 @@ describe('CursorLine highlight', function()
]])
end)
- it('with split-windows in diff-mode', function()
+ it('with split windows in diff mode', function()
local screen = Screen.new(50,12)
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
@@ -1093,7 +1093,6 @@ describe('CursorLine highlight', function()
[7] = {background = Screen.colors.Red, foreground = Screen.colors.White},
[8] = {bold = true, foreground = Screen.colors.Blue1},
[9] = {bold = true, reverse = true},
- [10] = {bold = true},
})
screen:attach()
@@ -1170,6 +1169,61 @@ describe('CursorLine highlight', function()
background = Screen.colors.Red},
})
end)
+
+ it('CursorLineNr shows correctly just below filler lines', function()
+ local screen = Screen.new(50,12)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [2] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1},
+ [3] = {reverse = true},
+ [4] = {background = Screen.colors.LightBlue},
+ [5] = {background = Screen.colors.Red, foreground = Screen.colors.White},
+ [6] = {background = Screen.colors.White, bold = true, foreground = Screen.colors.Black},
+ [7] = {bold = true, foreground = Screen.colors.Blue1},
+ [8] = {bold = true, reverse = true},
+ [9] = {foreground = Screen.colors.Brown},
+ })
+ screen:attach()
+
+ command('hi CursorLine guibg=red guifg=white')
+ command('hi CursorLineNr guibg=white guifg=black gui=bold')
+ command('set cursorline number')
+ command('call setline(1, ["baz", "foo", "foo", "bar"])')
+ feed('2gg0')
+ command('vnew')
+ command('call setline(1, ["foo", "foo", "bar"])')
+ command('windo diffthis')
+ command('1wincmd w')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}{3:│}{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }{5:^foo }{3:│}{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo {3:│}{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar {3:│}{1: }{9: 4 }bar |
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command('set cursorlineopt=number')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}{3:│}{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }^foo {3:│}{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo {3:│}{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar {3:│}{1: }{9: 4 }bar |
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ end)
end)
describe('ColorColumn highlight', function()
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 3c96954c9f..30c4752b87 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -144,8 +144,8 @@ endif()
include(ExternalProject)
-set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.42.0.tar.gz)
-set(LIBUV_SHA256 371e5419708f6aaeb8656671f89400b92a9bba6443369af1bb70bcd6e4b3c764)
+set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.44.0.tar.gz)
+set(LIBUV_SHA256 f2482d547009d26d4d590ed6588043c540e707c833df52536744cb9a809e6617)
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0/msgpack-3.0.0.tar.gz)
set(MSGPACK_SHA256 bfbb71b7c02f806393bc3cbc491b40523b89e64f83860c58e3e54af47de176e4)
@@ -203,8 +203,8 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891
set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz)
set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2)
-set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.3.tar.gz)
-set(TREESITTER_SHA256 ab52fe93e0c658cff656b9d10d67cdd29084247052964eba13ed6f0e9fa3bd36)
+set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.6.tar.gz)
+set(TREESITTER_SHA256 4d37eaef8a402a385998ff9aca3e1043b4a3bba899bceeff27a7178e1165b9de)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)
diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake
index 1d6a217575..42650308a8 100644
--- a/third-party/cmake/BuildLibuv.cmake
+++ b/third-party/cmake/BuildLibuv.cmake
@@ -63,10 +63,6 @@ elseif(WIN32)
set(BUILD_SHARED ON)
elseif(MINGW)
set(BUILD_SHARED OFF)
- set(LIBUV_PATCH_COMMAND
- ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libuv init
- COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libuv apply --ignore-whitespace
- ${CMAKE_CURRENT_SOURCE_DIR}/patches/libuv-disable-typedef-MinGW.patch)
else()
message(FATAL_ERROR "Trying to build libuv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()
diff --git a/third-party/patches/libuv-disable-typedef-MinGW.patch b/third-party/patches/libuv-disable-typedef-MinGW.patch
deleted file mode 100644
index a47893cede..0000000000
--- a/third-party/patches/libuv-disable-typedef-MinGW.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff --git a/include/uv/win.h b/include/uv/win.h
-index f5f1d3a3..64a0dfd9 100644
---- a/include/uv/win.h
-+++ b/include/uv/win.h
-@@ -45,7 +45,14 @@ typedef struct pollfd {
- #endif
-
- #include <mswsock.h>
-+// Disable the typedef in mstcpip.h of MinGW.
-+#define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__
-+#define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__
-+#define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__
- #include <ws2tcpip.h>
-+#undef _TCP_INITIAL_RTO_PARAMETERS
-+#undef TCP_INITIAL_RTO_PARAMETERS
-+#undef PTCP_INITIAL_RTO_PARAMETERS
- #include <windows.h>
-
- #include <process.h>