aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/ui.txt4
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/os/fs.c8
-rw-r--r--src/nvim/tui/tui.c8
-rw-r--r--src/nvim/ui.c6
-rw-r--r--test/functional/ui/embed_spec.lua50
-rw-r--r--test/functional/ui/screen.lua6
7 files changed, 82 insertions, 2 deletions
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 8546478935..c81420d1f2 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -228,6 +228,10 @@ the editor.
however a UI might still use such options when rendering raw text
sent from Nvim, like for |ui-cmdline|.
+["chdir", path] ~
+ The |current-directory| of the embedded Nvim process changed to
+ `path`.
+
["mode_change", mode, mode_idx] ~
Editor mode changed. The `mode` parameter is a string representing
the current mode. `mode_idx` is an index into the array emitted in
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index bda0c72423..c2f02c34f8 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -39,6 +39,8 @@ void screenshot(String path)
FUNC_API_SINCE(7);
void option_set(String name, Object value)
FUNC_API_SINCE(4);
+void chdir(String path)
+ FUNC_API_SINCE(12);
// Stop event is not exported as such, represented by EOF in the msgpack stream.
void stop(void)
FUNC_API_NOEXPORT;
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 09203990bb..d80539708d 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -33,6 +33,7 @@
# include <sys/xattr.h>
#endif
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@@ -44,6 +45,7 @@
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/types_defs.h"
+#include "nvim/ui.h"
#include "nvim/vim_defs.h"
#ifdef HAVE_SYS_UIO_H
@@ -90,7 +92,11 @@ int os_chdir(const char *path)
smsg(0, "chdir(%s)", path);
verbose_leave();
}
- return uv_chdir(path);
+ int err = uv_chdir(path);
+ if (err == 0) {
+ ui_call_chdir(cstr_as_string((char *)path));
+ }
+ return err;
}
/// Get the name of current directory.
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 6b8b73a2a0..f9560ce076 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1500,6 +1500,14 @@ void tui_option_set(TUIData *tui, String name, Object value)
}
}
+void tui_chdir(TUIData *tui, String path)
+{
+ int err = uv_chdir(path.data);
+ if (err != 0) {
+ ELOG("Failed to chdir to %s: %s", path.data, strerror(err));
+ }
+}
+
void tui_raw_line(TUIData *tui, Integer g, Integer linerow, Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 8888535878..316342c028 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -384,6 +384,12 @@ void ui_attach_impl(UI *ui, uint64_t chanid)
ui_refresh_options();
resettitle();
+ char cwd[MAXPATHL];
+ size_t cwdlen = sizeof(cwd);
+ if (uv_cwd(cwd, &cwdlen) == 0) {
+ ui_call_chdir((String){ .data = cwd, .size = cwdlen });
+ }
+
for (UIExtension i = kUIGlobalCount; (int)i < kUIExtCount; i++) {
ui_set_ext_option(ui, i, ui->ui_ext[i]);
}
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
index e655ee1b54..f6bdd2215d 100644
--- a/test/functional/ui/embed_spec.lua
+++ b/test/functional/ui/embed_spec.lua
@@ -171,6 +171,56 @@ describe('--embed UI', function()
}
eq({ [16711935] = true }, seen) -- we only saw the last one, despite 16777215 was set internally earlier
end)
+
+ it('updates cwd of attached UI #21771', function()
+ clear { args_rm = { '--headless' } }
+
+ local screen = Screen.new(40, 8)
+ screen:attach()
+
+ screen:expect {
+ condition = function()
+ eq(helpers.paths.test_source_path, screen.pwd)
+ end,
+ }
+
+ -- Change global cwd
+ helpers.command(string.format('cd %s/src/nvim', helpers.paths.test_source_path))
+
+ screen:expect {
+ condition = function()
+ eq(string.format('%s/src/nvim', helpers.paths.test_source_path), screen.pwd)
+ end,
+ }
+
+ -- Split the window and change the cwd in the split
+ helpers.command('new')
+ helpers.command(string.format('lcd %s/test', helpers.paths.test_source_path))
+
+ screen:expect {
+ condition = function()
+ eq(string.format('%s/test', helpers.paths.test_source_path), screen.pwd)
+ end,
+ }
+
+ -- Move to the original window
+ helpers.command('wincmd p')
+
+ screen:expect {
+ condition = function()
+ eq(string.format('%s/src/nvim', helpers.paths.test_source_path), screen.pwd)
+ end,
+ }
+
+ -- Change global cwd again
+ helpers.command(string.format('cd %s', helpers.paths.test_source_path))
+
+ screen:expect {
+ condition = function()
+ eq(helpers.paths.test_source_path, screen.pwd)
+ end,
+ }
+ end)
end)
describe('--embed --listen UI', function()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 644ee910b6..07333f2e21 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -140,6 +140,7 @@ function Screen.new(width, height)
suspended = false,
mode = 'normal',
options = {},
+ pwd = '',
popupmenu = nil,
cmdline = {},
cmdline_block = {},
@@ -212,7 +213,6 @@ function Screen:attach(options, session)
if options.ext_linegrid == nil then
options.ext_linegrid = true
end
-
self._session = session
self._options = options
self._clear_attrs = (not options.ext_linegrid) and {} or nil
@@ -1108,6 +1108,10 @@ function Screen:_handle_option_set(name, value)
self.options[name] = value
end
+function Screen:_handle_chdir(path)
+ self.pwd = vim.fs.normalize(path, { expand_env = false })
+end
+
function Screen:_handle_popupmenu_show(items, selected, row, col, grid)
self.popupmenu = { items = items, pos = selected, anchor = { grid, row, col } }
end