mirror of
https://github.com/neovim/neovim.git
synced 2026-08-14 11:29:31 +00:00
fix(cwd): validate getcwd(…, -1)
This commit is contained in:
@@ -1357,7 +1357,7 @@ Use |getcwd()| to get the effective directory from the current scope. The
|
||||
window-local working directory takes precedence over the buffer-local working
|
||||
directory, which takes precedence over the tab-local working directory, which
|
||||
in turn takes precedence over the global working directory. If a local
|
||||
working directory (window, buffer or tab) does not exist, the next-higher
|
||||
working directory (tab, window or buffer) does not exist, the next-higher
|
||||
scope in the hierarchy applies.
|
||||
|
||||
*:cd* *E747* *E472*
|
||||
@@ -1388,7 +1388,7 @@ scope in the hierarchy applies.
|
||||
|
||||
*:tc* *:tcd*
|
||||
:tc[d][!] {path} Like |:cd|, but only set the directory for the current
|
||||
tab. The current buffer and window will also use this
|
||||
tab. The current window and buffer will also use this
|
||||
directory. The current directory is not changed for
|
||||
windows in other tabs and for windows in the current
|
||||
tab that have their own window-local directory, or for
|
||||
@@ -1401,15 +1401,10 @@ scope in the hierarchy applies.
|
||||
*:tch* *:tchdir*
|
||||
:tch[dir][!] Same as |:tcd|.
|
||||
|
||||
*:bc* *:bcd*
|
||||
:bc[d][!] {path} Like |:cd|, but only set the current directory for the
|
||||
current buffer. The current directory for other
|
||||
windows or buffers or tabs is not changed.
|
||||
|
||||
*:lc* *:lcd*
|
||||
:lc[d][!] {path} Like |:cd|, but only set the current directory for the
|
||||
current window. The current directory for other
|
||||
windows, tabs, or buffers is not changed.
|
||||
tabs, windows, or buffers is not changed.
|
||||
|
||||
*:lch* *:lchdir*
|
||||
:lch[dir][!] Same as |:lcd|.
|
||||
@@ -1418,6 +1413,18 @@ scope in the hierarchy applies.
|
||||
:lc[d][!] - Change to the previous current directory (before the
|
||||
previous ":lcd {path}" command).
|
||||
|
||||
*:bc* *:bcd*
|
||||
:bc[d][!] [path] Like |:cd|, but only set the current directory for the
|
||||
current buffer. The current directory for other
|
||||
tabs, windows, or buffers is not changed.
|
||||
|
||||
*:bcd-*
|
||||
:bc[d][!] - Change to the previous buffer-local current directory
|
||||
(before the last ":bcd [path]" command).
|
||||
|
||||
*:bch* *:bchdir*
|
||||
:bch[dir][!] Same as |:bcd|.
|
||||
|
||||
*:pw* *:pwd* *E187*
|
||||
:pw[d] Print the current directory name.
|
||||
Also see |getcwd()|.
|
||||
@@ -1429,24 +1436,34 @@ scope in the hierarchy applies.
|
||||
:verbose pwd
|
||||
[global] /path/to/current
|
||||
|
||||
" Set by :lcd
|
||||
:verbose pwd
|
||||
[window] /path/to/current
|
||||
|
||||
" Set by :tcd
|
||||
:verbose pwd
|
||||
[tabpage] /path/to/current
|
||||
|
||||
So long as no |:lcd| or |:tcd| command has been used, all windows share the
|
||||
same current directory. Using a command to jump to another window doesn't
|
||||
change anything for the current directory.
|
||||
" Set by :lcd
|
||||
:verbose pwd
|
||||
[window] /path/to/current
|
||||
|
||||
" Set by :bcd
|
||||
:verbose pwd
|
||||
[buffer] /path/to/current
|
||||
|
||||
So long as no |:tcd|, |:lcd| or |:bcd| command has been used, all windows
|
||||
share the same current directory. Using a command to jump to another window
|
||||
doesn't change anything for the current directory.
|
||||
|
||||
When |:lcd| has been used for a window, the specified directory becomes the
|
||||
current directory for that window. Windows where the |:lcd| command has not
|
||||
been used stick to the global or tab-local directory. When jumping to another
|
||||
window the current directory is changed to the last specified local current
|
||||
directory. If none was specified, the global or tab-local directory is used.
|
||||
When creating a new window it inherits the local directory of the current window.
|
||||
been used stick to the buffer-local, tab-local or global directory. When
|
||||
jumping to another window the current directory is changed to the last
|
||||
specified local current directory. If none was specified, the buffer-local,
|
||||
tab-local or global directory is used. When creating a new window it
|
||||
inherits the local directory of the current window.
|
||||
|
||||
When |:bcd| has been used for a buffer, the specified directory becomes the
|
||||
current directory whenever that buffer is entered, unless the window has its
|
||||
own window-local directory. A new buffer created with |:edit| or |:enew|
|
||||
inherits the buffer-local directory of the previous current buffer.
|
||||
|
||||
When changing tabs the same behaviour applies. If the current tab has no
|
||||
local working directory the global working directory is used.
|
||||
|
||||
@@ -1181,6 +1181,8 @@ Tag Command Action ~
|
||||
|:ball| :ba[ll] open a window for each buffer in the buffer list
|
||||
|:badd| :bad[d] add buffer to the buffer list
|
||||
|:balt| :balt like ":badd" but also set the alternate file
|
||||
|:bcd| :bc[d] change directory for buffer
|
||||
|:bchdir| :bch[dir] change directory for buffer
|
||||
|:bdelete| :bd[elete] remove a buffer from the buffer list
|
||||
|:belowright| :bel[owright] make split window appear right or below
|
||||
|:bfirst| :bf[irst] go to first buffer in the buffer list
|
||||
|
||||
@@ -312,6 +312,7 @@ Command-line:
|
||||
is open. The |cmdwin-char| is shown via 'statuscolumn'.
|
||||
|
||||
Commands:
|
||||
- |:bcd|
|
||||
- |:checkhealth|
|
||||
- |:connect|
|
||||
- |:detach|
|
||||
|
||||
@@ -3774,9 +3774,8 @@ getcwd([{winnr} [, {tabnr} [, {bufnr}]]])
|
||||
directory of the window indicated by {winnr}.
|
||||
|
||||
If {bufnr} is provided, {winnr} and {tabnr} must be -1 and the
|
||||
working directory of that buffer is returned. If {bufnr} is
|
||||
-1, it is ignored, and the global working directory is
|
||||
returned.
|
||||
working directory of that buffer is returned. An argument may
|
||||
be -1 only if all preceding arguments are -1.
|
||||
Examples of buffer usage: >vim
|
||||
getcwd(-1, -1, 0) " Get current buffer's directory
|
||||
getcwd(-1, -1, 3) " Get directory of buffer #3
|
||||
@@ -5013,15 +5012,15 @@ has_key({dict}, {key}) *has_key()*
|
||||
(`0|1`)
|
||||
|
||||
haslocaldir([{winnr} [, {tabnr} [, {bufnr} ]]]) *haslocaldir()*
|
||||
Checks whether the window, tabpage or buffer has set a local
|
||||
Checks whether the tabpage, window or buffer has set a local
|
||||
working directory. Returns 1 when the window has set a local
|
||||
path via |:lcd|, or when {winnr} is -1 and the tabpage has set
|
||||
a local path via |:tcd|, or when {winnr} and {tabnr} are -1
|
||||
and {bufnr} has set a local path via |:bcd|, otherwise 0.
|
||||
|
||||
Tabs, windows and buffers are identified by their respective
|
||||
numbers, 0 means current tab or window. Missing argument
|
||||
implies 0. Thus the following are equivalent: >vim
|
||||
numbers, 0 means current tab, window or buffer. Missing
|
||||
argument implies 0. Thus the following are equivalent: >vim
|
||||
echo haslocaldir()
|
||||
echo haslocaldir(0)
|
||||
echo haslocaldir(0, 0)
|
||||
@@ -5030,7 +5029,8 @@ haslocaldir([{winnr} [, {tabnr} [, {bufnr} ]]]) *haslocaldir()*
|
||||
{winnr} is a |window-number| or |window-ID|.
|
||||
If {winnr} is -1 it is ignored, only the tab is resolved.
|
||||
If {bufnr} is provided, {winnr} and {tabnr} must be -1 and
|
||||
only the buffer is resolved.
|
||||
only the buffer is resolved. An argument may be -1 only if
|
||||
all preceding arguments are -1.
|
||||
Examples of buffer usage: >vim
|
||||
haslocaldir(-1, -1, 0) " Current buf has a local directory?
|
||||
haslocaldir(-1, -1, 3) " Buf #3 has a local directory?
|
||||
|
||||
14
runtime/lua/vim/_meta/vimfn.gen.lua
generated
14
runtime/lua/vim/_meta/vimfn.gen.lua
generated
@@ -3341,9 +3341,8 @@ function vim.fn.getcursorcharpos(winid) end
|
||||
--- directory of the window indicated by {winnr}.
|
||||
---
|
||||
--- If {bufnr} is provided, {winnr} and {tabnr} must be -1 and the
|
||||
--- working directory of that buffer is returned. If {bufnr} is
|
||||
--- -1, it is ignored, and the global working directory is
|
||||
--- returned.
|
||||
--- working directory of that buffer is returned. An argument may
|
||||
--- be -1 only if all preceding arguments are -1.
|
||||
--- Examples of buffer usage: >vim
|
||||
--- getcwd(-1, -1, 0) " Get current buffer's directory
|
||||
--- getcwd(-1, -1, 3) " Get directory of buffer #3
|
||||
@@ -4462,15 +4461,15 @@ function vim.fn.has(feature) end
|
||||
--- @return 0|1
|
||||
function vim.fn.has_key(dict, key) end
|
||||
|
||||
--- Checks whether the window, tabpage or buffer has set a local
|
||||
--- Checks whether the tabpage, window or buffer has set a local
|
||||
--- working directory. Returns 1 when the window has set a local
|
||||
--- path via |:lcd|, or when {winnr} is -1 and the tabpage has set
|
||||
--- a local path via |:tcd|, or when {winnr} and {tabnr} are -1
|
||||
--- and {bufnr} has set a local path via |:bcd|, otherwise 0.
|
||||
---
|
||||
--- Tabs, windows and buffers are identified by their respective
|
||||
--- numbers, 0 means current tab or window. Missing argument
|
||||
--- implies 0. Thus the following are equivalent: >vim
|
||||
--- numbers, 0 means current tab, window or buffer. Missing
|
||||
--- argument implies 0. Thus the following are equivalent: >vim
|
||||
--- echo haslocaldir()
|
||||
--- echo haslocaldir(0)
|
||||
--- echo haslocaldir(0, 0)
|
||||
@@ -4479,7 +4478,8 @@ function vim.fn.has_key(dict, key) end
|
||||
--- {winnr} is a |window-number| or |window-ID|.
|
||||
--- If {winnr} is -1 it is ignored, only the tab is resolved.
|
||||
--- If {bufnr} is provided, {winnr} and {tabnr} must be -1 and
|
||||
--- only the buffer is resolved.
|
||||
--- only the buffer is resolved. An argument may be -1 only if
|
||||
--- all preceding arguments are -1.
|
||||
--- Examples of buffer usage: >vim
|
||||
--- haslocaldir(-1, -1, 0) " Current buf has a local directory?
|
||||
--- haslocaldir(-1, -1, 3) " Buf #3 has a local directory?
|
||||
|
||||
@@ -4116,9 +4116,8 @@ M.funcs = {
|
||||
directory of the window indicated by {winnr}.
|
||||
|
||||
If {bufnr} is provided, {winnr} and {tabnr} must be -1 and the
|
||||
working directory of that buffer is returned. If {bufnr} is
|
||||
-1, it is ignored, and the global working directory is
|
||||
returned.
|
||||
working directory of that buffer is returned. An argument may
|
||||
be -1 only if all preceding arguments are -1.
|
||||
Examples of buffer usage: >vim
|
||||
getcwd(-1, -1, 0) " Get current buffer's directory
|
||||
getcwd(-1, -1, 3) " Get directory of buffer #3
|
||||
@@ -5429,15 +5428,15 @@ M.funcs = {
|
||||
args = { 0, 3 },
|
||||
base = 1,
|
||||
desc = [=[
|
||||
Checks whether the window, tabpage or buffer has set a local
|
||||
Checks whether the tabpage, window or buffer has set a local
|
||||
working directory. Returns 1 when the window has set a local
|
||||
path via |:lcd|, or when {winnr} is -1 and the tabpage has set
|
||||
a local path via |:tcd|, or when {winnr} and {tabnr} are -1
|
||||
and {bufnr} has set a local path via |:bcd|, otherwise 0.
|
||||
|
||||
Tabs, windows and buffers are identified by their respective
|
||||
numbers, 0 means current tab or window. Missing argument
|
||||
implies 0. Thus the following are equivalent: >vim
|
||||
numbers, 0 means current tab, window or buffer. Missing
|
||||
argument implies 0. Thus the following are equivalent: >vim
|
||||
echo haslocaldir()
|
||||
echo haslocaldir(0)
|
||||
echo haslocaldir(0, 0)
|
||||
@@ -5446,7 +5445,8 @@ M.funcs = {
|
||||
{winnr} is a |window-number| or |window-ID|.
|
||||
If {winnr} is -1 it is ignored, only the tab is resolved.
|
||||
If {bufnr} is provided, {winnr} and {tabnr} must be -1 and
|
||||
only the buffer is resolved.
|
||||
only the buffer is resolved. An argument may be -1 only if
|
||||
all preceding arguments are -1.
|
||||
Examples of buffer usage: >vim
|
||||
haslocaldir(-1, -1, 0) " Current buf has a local directory?
|
||||
haslocaldir(-1, -1, 3) " Buf #3 has a local directory?
|
||||
|
||||
@@ -681,6 +681,16 @@ static bool getcwd_scope_args(typval_T *argvars, CdScope default_scope, CdScope
|
||||
}
|
||||
}
|
||||
|
||||
// An argument may only be -1 if all preceding arguments are -1: `(2, 3, -1)` is an error.
|
||||
bool explicit_scope = false;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
explicit_scope = explicit_scope || argv[i] >= 0;
|
||||
if (explicit_scope && argv[i] < 0) {
|
||||
emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Narrowest requested scope. Imagine X >= 0:
|
||||
switch (argc) {
|
||||
case 0:
|
||||
@@ -705,7 +715,7 @@ static bool getcwd_scope_args(typval_T *argvars, CdScope default_scope, CdScope
|
||||
if (argv[kBufArg] >= 0) {
|
||||
*scope = kCdScopeBuffer; // (-1, -1, X)
|
||||
} else {
|
||||
*scope = kCdScopeGlobal; // (..., ..., -1)
|
||||
*scope = kCdScopeGlobal; // (-1, -1, -1)
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -737,10 +747,6 @@ static bool getcwd_scope_args(typval_T *argvars, CdScope default_scope, CdScope
|
||||
|
||||
// Find the window in `tp` by number.
|
||||
if (argv[kWinArg] >= 0) {
|
||||
if (argv[kTabArg] < 0) {
|
||||
emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
|
||||
return false;
|
||||
}
|
||||
if (argv[kWinArg] > 0) {
|
||||
*win = find_win_by_nr(&argvars[0], *tp);
|
||||
if (*win == NULL) {
|
||||
|
||||
@@ -6222,7 +6222,7 @@ static char **get_prevdir(CdScope scope)
|
||||
|
||||
/// Deal with the side effects of changing the current directory.
|
||||
///
|
||||
/// @param scope Scope of the function call (global, tab, buffer or window).
|
||||
/// @param scope Scope of the function call (global, tab, window or buffer).
|
||||
static void post_chdir(CdScope scope, bool trigger_dirchanged)
|
||||
{
|
||||
// Always overwrite the window-local CWD.
|
||||
@@ -6275,9 +6275,9 @@ static void post_chdir(CdScope scope, bool trigger_dirchanged)
|
||||
}
|
||||
}
|
||||
|
||||
/// Change directory function used by :cd/:tcd/:bcd/:lcd Ex commands and the chdir() function.
|
||||
/// Change directory function used by :cd/:tcd/:lcd/:bcd Ex commands and the chdir() function.
|
||||
/// @param new_dir The directory to change to.
|
||||
/// @param scope Scope of the function call (global, tab, buffer or window).
|
||||
/// @param scope Scope of the function call (global, tab, window or buffer).
|
||||
/// @return true if the directory is successfully changed.
|
||||
bool changedir_func(char *new_dir, CdScope scope)
|
||||
{
|
||||
@@ -6333,7 +6333,7 @@ bool changedir_func(char *new_dir, CdScope scope)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ":cd", ":tcd", ":bcd", ":lcd", ":chdir", "tchdir", ":bchdir", and ":lchdir".
|
||||
/// ":cd", ":tcd", ":lcd", ":bcd", ":chdir", ":tchdir", ":lchdir", and ":bchdir".
|
||||
void ex_cd(exarg_T *eap)
|
||||
{
|
||||
char *new_dir = eap->arg;
|
||||
|
||||
@@ -45,7 +45,7 @@ typedef enum {
|
||||
/// What caused the current directory to change.
|
||||
typedef enum {
|
||||
kCdCauseOther = -1,
|
||||
kCdCauseManual, ///< Using `:cd`, `:bcd`, `:tcd`, `:lcd` or `chdir()`.
|
||||
kCdCauseManual, ///< Using `:cd`, `:tcd`, `:lcd`, `:bcd` or `chdir()`.
|
||||
kCdCauseWindow, ///< Switching to another window.
|
||||
kCdCauseBuffer, ///< Switching to another buffer.
|
||||
kCdCauseAuto, ///< On 'autochdir'.
|
||||
|
||||
@@ -438,32 +438,32 @@ for _, cmd in ipairs { 'getcwd', 'haslocaldir' } do
|
||||
end)
|
||||
|
||||
it('validation', function()
|
||||
local err474 = 'Vim(call):E474: Invalid argument'
|
||||
eq(err474, pcall_err(command, ('call %s("some string")'):format(cmd)))
|
||||
eq(err474, pcall_err(command, ('call %s(1.0)'):format(cmd)))
|
||||
eq(err474, pcall_err(command, ('call %s([1, 2])'):format(cmd)))
|
||||
eq(err474, pcall_err(command, ('call %s({"key": "value"})'):format(cmd)))
|
||||
eq(err474, pcall_err(command, ('call %s(function("tr"))'):format(cmd)))
|
||||
eq(err474, pcall_err(command, ('call %s(-2)'):format(cmd)))
|
||||
local err474 = 'Vim:E474: Invalid argument'
|
||||
eq(err474, pcall_err(call, cmd, 'some string'))
|
||||
eq(err474, pcall_err(call, cmd, 1.5))
|
||||
eq(err474, pcall_err(call, cmd, { 1, 2 }))
|
||||
eq(err474, pcall_err(call, cmd, { key = 'value' }))
|
||||
eq(err474, pcall_err(call, cmd, -2))
|
||||
-- Funcref is not representable over RPC.
|
||||
eq(
|
||||
'Vim(call):E474: Invalid argument',
|
||||
pcall_err(command, ('call %s(function("tr"))'):format(cmd))
|
||||
)
|
||||
|
||||
-- -1 preceded by an argument >= 0
|
||||
local err5001 = 'Vim:E5001: Higher scope cannot be -1 if lower scope is >= 0.'
|
||||
eq(err5001, pcall_err(call, cmd, 0, -1))
|
||||
eq(err5001, pcall_err(call, cmd, 2, 3, -1))
|
||||
eq(err5001, pcall_err(call, cmd, -1, 0, -1))
|
||||
eq(err5001, pcall_err(call, cmd, 0, -1, 0))
|
||||
-- Buffer scope requires window and tab args to be -1.
|
||||
local err5006 = 'Vim:E5006: Window and tab scope must be -1 when using buffer scope'
|
||||
eq(err5006, pcall_err(call, cmd, 0, 0, 0))
|
||||
eq(err5006, pcall_err(call, cmd, 1, 2, 3))
|
||||
eq('Vim:E5007: Cannot find buffer number.', pcall_err(call, cmd, -1, -1, 99999))
|
||||
eq(
|
||||
'Vim(call):E5001: Higher scope cannot be -1 if lower scope is >= 0.',
|
||||
pcall_err(command, ('call %s(0, -1)'):format(cmd))
|
||||
)
|
||||
-- Buffer scope requires window and tab arguments of -1.
|
||||
local err5006 = 'Vim(call):E5006: Window and tab scope must be -1 when using buffer scope'
|
||||
eq(err5006, pcall_err(command, ('call %s(0, 0, 0)'):format(cmd)))
|
||||
eq(err5006, pcall_err(command, ('call %s(1, 2, 3)'):format(cmd)))
|
||||
-- Nonexistent buffer.
|
||||
eq(
|
||||
'Vim(call):E5007: Cannot find buffer number.',
|
||||
pcall_err(command, ('call %s(-1, -1, 99999)'):format(cmd))
|
||||
)
|
||||
-- Too many arguments.
|
||||
eq(
|
||||
('Vim(call):E118: Too many arguments for function: %s'):format(cmd),
|
||||
pcall_err(command, ('call %s(0, 0, 0, 0)'):format(cmd))
|
||||
('Vim:E118: Too many arguments for function: %s'):format(cmd),
|
||||
pcall_err(call, cmd, 0, 0, 0, 0)
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user