fix(dir): :browse edit opens dir browser #40930

Problem: `:browse edit` (and variants) without an argument fails instead
of opening a browser.

Solution: Dispatch to dir.lua using the cwd as the implied directory.
Replace the inherited GUI-only documentation with the supported
behavior. Support vsplit, split, tabedit variants.
This commit is contained in:
Barrett Ruth
2026-07-25 03:56:52 -07:00
committed by GitHub
parent fb6fb33d39
commit 4975a186f2
4 changed files with 65 additions and 99 deletions

View File

@@ -1290,43 +1290,22 @@ Examples: >
If you want to always use ":confirm", set the 'confirm' option.
*:browse* *:bro* *E338* *E614* *E615* *E616*
:bro[wse] {command} Open a file selection dialog for an argument to
{command}. At present this works for |:e|, |:w|,
|:wall|, |:wq|, |:wqall|, |:x|, |:xall|, |:exit|,
|:view|, |:sview|, |:r|, |:saveas|, |:sp|, |:mkexrc|,
|:mkvimrc|, |:mksession|, |:mkview|, |:split|,
|:vsplit|, |:tabe|, |:tabnew|, |:cfile|, |:cgetfile|,
|:caddfile|, |:lfile|, |:lgetfile|, |:laddfile|,
|:diffsplit|, |:diffpatch|, |:pedit|, |:redir|,
|:source|, |:update|, |:visual|, |:vsplit|,
and |:qall| if 'confirm' is set.
Note: only in Win32 GUI; in console `:browse edit`
works if the FileExplorer autocommand group exists.
When ":browse" is not possible you get an error
message. If {command} doesn't support browsing, the
{command} is executed without a dialog.
":browse set" works like |:options|.
See also |:oldfiles| for ":browse oldfiles".
*:browse* *:bro*
:bro[wse] {command} For |:edit|, |:split|, |:vsplit|, |:tabedit|, and
|:tabnew| without a file argument, open the current
directory with the |dir| browser. A third-party directory
browser may handle it instead; see |dir-disable|.
The syntax is best shown via some examples: >
:browse e $vim/foo
< Open the browser in the $vim/foo directory, and edit the
file chosen. >
:browse e
< Open the browser in the directory specified with 'browsedir',
and edit the file chosen. >
:browse w
< Open the browser in the directory of the current buffer,
with the current buffer filename as default, and save the
buffer under the filename chosen. >
:browse w C:/bar
< Open the browser in the C:/bar directory, with the current
buffer filename as default, and save the buffer under the
filename chosen.
Also see the 'browsedir' option.
For versions of Vim where browsing is not supported, the command is executed
unmodified.
With a file argument, or when {command} does not support
browsing, execute {command} unmodified.
Examples: >
:browse edit
< Open the current directory in the current window. >
:browse vsplit
< Open the current directory in a vertical split.
See |:oldfiles| for ":browse oldfiles".
*browsefilter*
For MS-Windows you can modify the filters that are used in the browse

View File

@@ -24,61 +24,24 @@ Table of contents: |usr_toc.txt|
==============================================================================
*31.1* The file browser
When using the File/Open... menu you get a file browser. This makes it easier
to find the file you want to edit. But what if you want to split a window to
edit another file? There is no menu entry for this. You could first use
Window/Split and then File/Open..., but that's more work.
Since you are typing most commands in Vim, opening the file browser with a
typed command is possible as well. To make the split command use the file
browser, prepend "browse": >
Nvim can open the current directory in its |dir| browser with: >
:browse edit
The same works when opening a split or tab page: >
:browse split
:browse vsplit
:browse tabedit
:browse tabnew
Select a file and then the ":split" command will be executed with it. If you
cancel the file dialog nothing happens, the window isn't split.
You can also specify a file name argument. This is used to tell the file
browser where to start. Example: >
A third-party directory browser may handle the directory instead; see
|dir-disable|. Use the browser's mappings to open a file.
:browse split /etc
When a file or directory argument is given, the command is executed normally.
For example: >
The file browser will pop up, starting in the directory "/etc".
The ":browse" command can be prepended to just about any command that opens a
file.
If no directory is specified, Vim will decide where to start the file
browser. By default it uses the same directory as the last time. Thus when
you used ":browse split" and selected a file in "/usr/local/share", the next
time you use a ":browse" it will start in "/usr/local/share" again.
This can be changed with the 'browsedir' option. It can have one of three
values:
last Use the last directory browsed (default)
buffer Use the same directory as the current buffer
current use the current directory
For example, when you are in the directory "/usr", editing the file
"/usr/local/share/readme", then the command: >
:set browsedir=buffer
:browse edit
Will start the browser in "/usr/local/share". Alternatively: >
:set browsedir=current
:browse edit
Will start the browser in "/usr".
Note:
To avoid using the mouse, most file browsers offer using key presses
to navigate. Since this is different for every system, it is not
explained here. Vim uses a standard browser when possible, your
system documentation should contain an explanation on the keyboard
shortcuts somewhere.
When you are not using the GUI version, you could use the file explorer window
to select files like in a file browser. However, this doesn't work for the
":browse" command. See |netrw-browse|.
:browse edit /etc
==============================================================================
*31.2* Confirmation

View File

@@ -5762,6 +5762,18 @@ bool set_ref_in_findfunc(int copyID)
return abort;
}
static void set_browse_edit_arg(exarg_T *eap)
{
if ((cmdmod.cmod_flags & CMOD_BROWSE) && *eap->arg == NUL
&& (eap->cmdidx == CMD_edit
|| eap->cmdidx == CMD_split
|| eap->cmdidx == CMD_vsplit
|| eap->cmdidx == CMD_tabedit
|| eap->cmdidx == CMD_tabnew)) {
eap->arg = ".";
}
}
/// :sview [+command] file split window with new file, read-only
/// :split [[+command] file] split window with current or new file
/// :vsplit [[+command] file] split window vertically with current or new file
@@ -5775,6 +5787,7 @@ bool set_ref_in_findfunc(int copyID)
/// :tabfind [+command] file open new Tab page and find "file"
void ex_splitview(exarg_T *eap)
{
set_browse_edit_arg(eap);
win_T *old_curwin = curwin;
char *fname = NULL;
const bool use_tab = eap->cmdidx == CMD_tabedit
@@ -6111,6 +6124,7 @@ static void ex_find(exarg_T *eap)
/// ":edit", ":badd", ":balt", ":visual".
static void ex_edit(exarg_T *eap)
{
set_browse_edit_arg(eap);
char *ffname = eap->cmdidx == CMD_enew ? NULL : eap->arg;
// Exclude commands which keep the window's current buffer

View File

@@ -683,19 +683,29 @@ describe('nvim.dir', function()
eq('netrw', api.nvim_get_option_value('filetype', { buf = 0 }))
end)
it('supports the FileExplorer browse contract', function()
if t.is_zig_build() then
return pending('broken with build.zig: TMPDIR relative cwd')
end
make_fixture()
n.clear({ args_rm = { '-u' } })
local cwd = fn.getcwd()
for _, case in ipairs({
{ command = 'edit', windows = 1, tabs = 1 },
{ command = 'split', windows = 2, tabs = 1 },
{ command = 'vsplit', windows = 2, tabs = 1 },
{ command = 'tabedit', windows = 1, tabs = 2 },
{ command = 'tabnew', windows = 1, tabs = 2 },
}) do
it(('":browse %s"'):format(case.command), function()
if t.is_zig_build() then
return pending('broken with build.zig: TMPDIR relative cwd')
end
make_fixture()
n.clear({ args_rm = { '-u' } })
local cwd = fn.getcwd()
cd(root)
command('browse edit .')
cd(cwd)
cd(root)
command('browse ' .. case.command)
cd(cwd)
assert_directory(root)
line_of('alpha.txt')
end)
eq(case.windows, #api.nvim_tabpage_list_wins(0))
eq(case.tabs, #api.nvim_list_tabpages())
assert_directory(root)
line_of('alpha.txt')
end)
end
end)