vim-patch:9.2.0502: runtime(netrw): bookmark handling can be improved (#39900)

Problem:  To goto or delete a bookmark, one needs to prefix a count
          for the bookmark number (e.g., "2gb" to open bookmark#2).
          As the bookmark list gets or deletes entries, the numbers
          keep changing, requiring listing the bookmarks with qb to
          discover the desired bookmark number. Typing gb or mB
          without a count targets g:netrw_bookmarklist[-1].
Solution: If no count is given to gb or mB, list all bookmarks and
          prompt for a number using inputlist(), similar to tag jump
          with g].

closes: vim/vim#20211

35b767a090

Co-authored-by: J. Paulo Seibt <jpseibt@gmail.com>
This commit is contained in:
zeertzjq
2026-05-20 09:12:12 +08:00
committed by GitHub
parent 62dcd07787
commit 3bc21c0903
3 changed files with 111 additions and 20 deletions

View File

@@ -2707,7 +2707,7 @@ endfunction
" s:NetrwBookHistHandler: {{{2
" 0: (user: <mb>) bookmark current directory
" 1: (user: <gb>) change to the bookmarked directory
" 1: (user: <gb>) change to the bookmarked path
" 2: (user: <qb>) list bookmarks
" 3: (browsing) records current directory history
" 4: (user: <u>) go up (previous) directory, using history
@@ -2737,11 +2737,33 @@ function s:NetrwBookHistHandler(chg,curdir)
endtry
elseif a:chg == 1
" change to the bookmarked directory
if exists("g:netrw_bookmarklist[v:count-1]")
exe "NetrwKeepj e ".fnameescape(g:netrw_bookmarklist[v:count-1])
" change to bookmarked path
if exists("g:netrw_bookmarklist") && !empty(g:netrw_bookmarklist)
let len_bookmarklist = len(g:netrw_bookmarklist)
let bookmark_num = v:count
" v:count value is set to zero if no count (prefix) is given to the `gb` map
if bookmark_num == 0
" list bookmarks and prompt for a bookmark number
let goto_list = [" # | Goto Bookmark:"]
let i = 0
while i < len_bookmarklist
call add(goto_list, printf("%3d| %s", i + 1, g:netrw_bookmarklist[i]))
let i += 1
endwhile
let bookmark_num = inputlist(goto_list)
endif
if bookmark_num > 0
if bookmark_num <= len_bookmarklist
exe "NetrwKeepj e " . fnameescape(g:netrw_bookmarklist[bookmark_num - 1])
else
echomsg "Sorry, bookmark#" . bookmark_num . " doesn't exist!"
endif
endif
" Exit silently if user cancels with `q` or empty after inputlist()
else
echomsg "Sorry, bookmark#".v:count." doesn't exist!"
echo "Bookmark list is empty."
endif
elseif a:chg == 2
@@ -2842,16 +2864,38 @@ function s:NetrwBookHistHandler(chg,curdir)
endif
elseif a:chg == 6
if exists("s:netrwmarkfilelist_{curbufnr}")
if exists("s:netrwmarkfilelist_{curbufnr}") && !empty(s:netrwmarkfilelist_{curbufnr})
call s:NetrwBookmark(1)
echo "removed marked files from bookmarks"
elseif exists("g:netrw_bookmarklist") && !empty(g:netrw_bookmarklist)
let len_bookmarklist = len(g:netrw_bookmarklist)
let bookmark_num = v:count
" v:count value is set to zero if no count (prefix) is given to the `gb` map
if bookmark_num == 0
" list bookmarks and prompt for a bookmark number
let goto_list = [" # | Delete Bookmark:"]
let i = 0
while i < len_bookmarklist
call add(goto_list, printf("%3d| %s", i + 1, g:netrw_bookmarklist[i]))
let i += 1
endwhile
let bookmark_num = inputlist(goto_list)
endif
if bookmark_num > 0
if bookmark_num <= len_bookmarklist
let bookmark_path = g:netrw_bookmarklist[bookmark_num - 1]
call s:MergeBookmarks()
NetrwKeepj call remove(g:netrw_bookmarklist, bookmark_num - 1)
echo "removed " . bookmark_path . " from g:netrw_bookmarklist."
else
echomsg "Sorry, bookmark#" . bookmark_num . " doesn't exist!"
endif
endif
" Exit silently if user cancels with `q` or empty after inputlist()
else
" delete the v:count'th bookmark
let iremove = v:count
let dremove = g:netrw_bookmarklist[iremove - 1]
call s:MergeBookmarks()
NetrwKeepj call remove(g:netrw_bookmarklist,iremove-1)
echo "removed ".dremove." from g:netrw_bookmarklist"
echo "Bookmark list is empty."
endif
try

View File

@@ -1046,7 +1046,7 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
C Setting the editing window |netrw-C|
d Make a directory |netrw-d|
D Attempt to remove the file(s)/directory(ies) |netrw-D|
gb Go to previous bookmarked directory |netrw-gb|
gb Go to bookmark |netrw-gb|
gd Force treatment as directory |netrw-gd|
gf Force treatment as file |netrw-gf|
gh Quick hide/unhide of dot-files |netrw-gh|
@@ -1055,11 +1055,12 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
i Cycle between thin, long, wide, and tree listings |netrw-i|
I Toggle the displaying of the banner |netrw-I|
mb Bookmark current directory |netrw-mb|
mB Delete bookmark |netrw-mB|
mc Copy marked files to marked-file target directory |netrw-mc|
md Apply diff to marked files (up to 3) |netrw-md|
me Place marked files on arg list and edit them |netrw-me|
mf Mark a file |netrw-mf|
mF Unmark files |netrw-mF|
mF Unmark buffer-local files |netrw-mF|
mg Apply vimgrep to marked files |netrw-mg|
mh Toggle marked file suffices' presence on hiding list |netrw-mh|
mm Move marked files to marked-file target directory |netrw-mm|
@@ -1364,13 +1365,16 @@ Currently, this only works for local files.
Associated setting variables: |g:netrw_chgperm|
CHANGING TO A BOOKMARKED DIRECTORY *netrw-gb* {{{2
CHANGING TO A BOOKMARKED PATH *netrw-gb* {{{2
To change directory back to a bookmarked directory, use
To change to a bookmarked path, use
{cnt}gb
[{cnt}]gb
Any count may be used to reference any of the bookmarks.
If {cnt} is omitted, it shows a list of the current bookmarks
and prompts for a bookmark number to go to.
Note that |netrw-qb| shows both bookmarks and history; to go
to a location stored in the history see |netrw-u| and |netrw-U|.
@@ -1433,10 +1437,13 @@ DELETING BOOKMARKS *netrw-mB* {{{2
To delete a bookmark, use >
{cnt}mB
[{cnt}]mB
If there are marked files, then mB will remove them from the
bookmark list.
If no files are marked and {cnt} is omitted, it shows a list
of the current bookmarks and prompts for a bookmark number
to delete.
Alternatively, one may use :NetrwMB! (see |netrw-:NetrwMB|). >

View File

@@ -337,7 +337,9 @@ func Test_netrw_parse_special_char_user()
call assert_equal(result.path, 'test.txt')
endfunction
func Test_netrw_empty_buffer_fastpath_wipe()
" Note: Test_netrw_a_empty_buffer_fastpath_wipe() should run before
" any other tests that open a netrw buffer (e.g, :Explore).
func Test_netrw_a_empty_buffer_fastpath_wipe()
" SetUp() may have opened some buffers
let previous = bufnr('$')
let g:netrw_fastbrowse=0
@@ -724,7 +726,44 @@ func Test_netrw_bookmark_marked_file()
let g:netrw_keepdir = save_keepdir
if save_bookmarklist is v:null
unlet g:netrw_bookmarklist
unlet! g:netrw_bookmarklist
else
let g:netrw_bookmarklist = save_bookmarklist
endif
bw!
endfunc
" Typing gb or mB without a count should prompt
" for a bookmark number through an inputlist().
" Expected dialog output (gb): # | Goto Bookmark:
" 1| /foo/bar/baz
"
" Expected dialog output (mB): # | Delete Bookmark:
" 1| /foo/bar/baz
func Test_netrw_bookmark_goto_delete_prompt()
let save_home = g:netrw_home
let save_bookmarklist = exists('g:netrw_bookmarklist') ? g:netrw_bookmarklist : v:null
let g:netrw_home = getcwd()
let g:netrw_bookmarklist = ['/foo/bar/baz']
Explore .
" Inject 'q' to cancel the inputlist() prompt
call feedkeys('q', 't')
let dialog_out = execute('normal gb')
call assert_match('Goto Bookmark:', dialog_out)
call feedkeys('q', 't')
let dialog_out = execute('normal mB')
call assert_match('Delete Bookmark:', dialog_out)
" Tear down
call delete(g:netrw_home . '/.netrwbook')
call delete(g:netrw_home . '/.netrwhist')
let g:netrw_home = save_home
if save_bookmarklist is v:null
unlet! g:netrw_bookmarklist
else
let g:netrw_bookmarklist = save_bookmarklist
endif
@@ -787,4 +826,5 @@ func Test_netrw_injection()
unlet! g:netrw_home g:netrw_dirhistmax g:netrw_dirhistcnt g:netrw_dirhist_1 g:injected
endtry
endfunc
" vim:ts=8 sts=2 sw=2 et