aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/netrw.vim411
-rw-r--r--runtime/doc/pi_netrw.txt108
-rw-r--r--runtime/plugin/netrwPlugin.vim9
3 files changed, 258 insertions, 270 deletions
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index d5e3a77dd4..d6caa50e7d 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -27,6 +27,11 @@
" 2024 Sep 19 by Vim Project: mf-selection highlight uses wrong pattern (#15700)
" 2024 Sep 21 by Vim Project: remove extraneous closing bracket (#15718)
" 2024 Oct 21 by Vim Project: remove netrwFileHandlers (#15895)
+" 2024 Oct 27 by Vim Project: clean up gx mapping (#15721)
+" 2024 Oct 30 by Vim Project: fix filetype detection for remote files (#15961)
+" 2024 Oct 30 by Vim Project: fix x mapping on cygwin (#13687)
+" 2024 Oct 31 by Vim Project: add netrw#Launch() and netrw#Open() (#15962)
+" 2024 Oct 31 by Vim Project: fix E874 when browsing remote dir (#15964)
" }}}
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
@@ -533,7 +538,6 @@ if !exists("g:netrw_sort_sequence")
endif
call s:NetrwInit("g:netrw_special_syntax" , 0)
call s:NetrwInit("g:netrw_ssh_browse_reject", '^total\s\+\d\+$')
-call s:NetrwInit("g:netrw_suppress_gx_mesg", 1)
call s:NetrwInit("g:netrw_use_noswf" , 1)
call s:NetrwInit("g:netrw_sizestyle" ,"b")
" Default values - t-w ---------- {{{3
@@ -1153,47 +1157,35 @@ fun! netrw#Lexplore(count,rightside,...)
" if a netrw window is already on the left-side of the tab
" and a directory has been specified, explore with that
" directory.
-" call Decho("case has input argument(s) (a:1<".a:1.">)")
let a1 = expand(a:1)
-" call Decho("a:1<".a:1."> curwin#".curwin,'~'.expand("<slnum>"))
exe "1wincmd w"
if &ft == "netrw"
-" call Decho("exe Explore ".fnameescape(a:1),'~'.expand("<slnum>"))
exe "Explore ".fnameescape(a1)
exe curwin."wincmd w"
let s:lexplore_win= curwin
let w:lexplore_buf= bufnr("%")
if exists("t:netrw_lexposn")
-" call Decho("forgetting t:netrw_lexposn",'~'.expand("<slnum>"))
unlet t:netrw_lexposn
endif
-" call Dret("netrw#Lexplore")
return
endif
exe curwin."wincmd w"
else
let a1= ""
-" call Decho("no input arguments")
endif
if exists("t:netrw_lexbufnr")
" check if t:netrw_lexbufnr refers to a netrw window
let lexwinnr = bufwinnr(t:netrw_lexbufnr)
-" call Decho("lexwinnr= bufwinnr(t:netrw_lexbufnr#".t:netrw_lexbufnr.")=".lexwinnr)
else
let lexwinnr= 0
-" call Decho("t:netrw_lexbufnr doesn't exist")
endif
-" call Decho("lexwinnr=".lexwinnr,'~'.expand("<slnum>"))
if lexwinnr > 0
" close down netrw explorer window
-" call Decho("t:netrw_lexbufnr#".t:netrw_lexbufnr.": close down netrw window",'~'.expand("<slnum>"))
exe lexwinnr."wincmd w"
let g:netrw_winsize = -winwidth(0)
let t:netrw_lexposn = winsaveview()
-" call Decho("saving posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>"))
-" call Decho("saving t:netrw_lexposn",'~'.expand("<slnum>"))
close
if lexwinnr < curwin
let curwin= curwin - 1
@@ -1202,11 +1194,9 @@ fun! netrw#Lexplore(count,rightside,...)
exe curwin."wincmd w"
endif
unlet t:netrw_lexbufnr
-" call Decho("unlet t:netrw_lexbufnr")
else
" open netrw explorer window
-" call Decho("t:netrw_lexbufnr<n/a>: open netrw explorer window",'~'.expand("<slnum>"))
exe "1wincmd w"
let keep_altv = g:netrw_altv
let g:netrw_altv = 0
@@ -1215,18 +1205,13 @@ fun! netrw#Lexplore(count,rightside,...)
let g:netrw_winsize = a:count
endif
let curfile= expand("%")
-" call Decho("curfile<".curfile.">",'~'.expand("<slnum>"))
exe (a:rightside? "botright" : "topleft")." vertical ".((g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize) . " new"
-" call Decho("new buf#".bufnr("%")." win#".winnr())
if a:0 > 0 && a1 != ""
-" call Decho("case 1: Explore ".a1,'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,a1)
exe "Explore ".fnameescape(a1)
elseif curfile =~ '^\a\{3,}://'
-" call Decho("case 2: Explore ".substitute(curfile,'[^/\\]*$','',''),'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,substitute(curfile,'[^/\\]*$','',''))
else
-" call Decho("case 3: Explore .",'~'.expand("<slnum>"))
call netrw#Explore(0,0,0,".")
endif
if a:count != 0
@@ -1239,11 +1224,7 @@ fun! netrw#Lexplore(count,rightside,...)
" Since the intended use of :Lexplore is to have an always-present explorer window, the extra
" effort to prevent mis-use of :Lex is warranted.
set bh=wipe
-" call Decho("let t:netrw_lexbufnr=".t:netrw_lexbufnr)
-" call Decho("t:netrw_lexposn".(exists("t:netrw_lexposn")? string(t:netrw_lexposn) : " n/a"))
if exists("t:netrw_lexposn")
-" call Decho("restoring to t:netrw_lexposn",'~'.expand("<slnum>"))
-" call Decho("restoring posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>"))
call winrestview(t:netrw_lexposn)
unlet t:netrw_lexposn
endif
@@ -1256,10 +1237,8 @@ fun! netrw#Lexplore(count,rightside,...)
else
let g:netrw_chgwin= 2
endif
-" call Decho("let g:netrw_chgwin=".g:netrw_chgwin)
endif
-" call Dret("netrw#Lexplore")
endfun
" ---------------------------------------------------------------------
@@ -1743,29 +1722,20 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwOptionsRestore: restore options (based on prior s:NetrwOptionsSave) {{{2
fun! s:NetrwOptionsRestore(vt)
-" call Dfunc("s:NetrwOptionsRestore(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> winnr($)=".winnr("$"))
-" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
if !exists("{a:vt}netrw_optionsave")
-" call Decho("case ".a:vt."netrw_optionsave : doesn't exist",'~'.expand("<slnum>"))
-
- " filereadable() returns zero for remote files (e.g. scp://localhost//etc/fstab)
- if filereadable(expand("%")) || expand("%") =~# '^\w\+://\f\+/'
-" call Decho("..doing filetype detect anyway")
+ " filereadable() returns zero for remote files (e.g. scp://user@localhost//etc/fstab)
+ " Note: @ may not be in 'isfname', so '^\w\+://\f\+/' may not match
+ if filereadable(expand("%")) || expand("%") =~# '^\w\+://\f\+'
filetype detect
-" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
else
setl ft=netrw
endif
-" call Decho("..ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("s:NetrwOptionsRestore : ".a:vt."netrw_optionsave doesn't exist")
return
endif
unlet {a:vt}netrw_optionsave
if exists("+acd")
if exists("{a:vt}netrw_acdkeep")
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
let curdir = getcwd()
let &l:acd = {a:vt}netrw_acdkeep
unlet {a:vt}netrw_acdkeep
@@ -1774,53 +1744,43 @@ fun! s:NetrwOptionsRestore(vt)
endif
endif
endif
-" call Decho("(s:NetrwOptionsRestore) #1 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_aikeep","&l:ai")
call s:NetrwRestoreSetting(a:vt."netrw_awkeep","&l:aw")
call s:NetrwRestoreSetting(a:vt."netrw_blkeep","&l:bl")
call s:NetrwRestoreSetting(a:vt."netrw_btkeep","&l:bt")
call s:NetrwRestoreSetting(a:vt."netrw_bombkeep","&l:bomb")
-" call Decho("(s:NetrwOptionsRestore) #2 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cedit","&cedit")
call s:NetrwRestoreSetting(a:vt."netrw_cikeep","&l:ci")
call s:NetrwRestoreSetting(a:vt."netrw_cinkeep","&l:cin")
call s:NetrwRestoreSetting(a:vt."netrw_cinokeep","&l:cino")
call s:NetrwRestoreSetting(a:vt."netrw_comkeep","&l:com")
-" call Decho("(s:NetrwOptionsRestore) #3 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cpokeep","&l:cpo")
call s:NetrwRestoreSetting(a:vt."netrw_diffkeep","&l:diff")
call s:NetrwRestoreSetting(a:vt."netrw_fenkeep","&l:fen")
if exists("g:netrw_ffkeep") && g:netrw_ffkeep
call s:NetrwRestoreSetting(a:vt."netrw_ffkeep")","&l:ff")
endif
-" call Decho("(s:NetrwOptionsRestore) #4 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_fokeep" ,"&l:fo")
call s:NetrwRestoreSetting(a:vt."netrw_gdkeep" ,"&l:gd")
call s:NetrwRestoreSetting(a:vt."netrw_gokeep" ,"&go")
call s:NetrwRestoreSetting(a:vt."netrw_hidkeep" ,"&l:hidden")
-" call Decho("(s:NetrwOptionsRestore) #5 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_imkeep" ,"&l:im")
call s:NetrwRestoreSetting(a:vt."netrw_iskkeep" ,"&l:isk")
-" call Decho("(s:NetrwOptionsRestore) #6 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_lines" ,"&lines")
-" call Decho("(s:NetrwOptionsRestore) #7 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_lskeep" ,"&l:ls")
call s:NetrwRestoreSetting(a:vt."netrw_makeep" ,"&l:ma")
call s:NetrwRestoreSetting(a:vt."netrw_magickeep","&l:magic")
call s:NetrwRestoreSetting(a:vt."netrw_modkeep" ,"&l:mod")
call s:NetrwRestoreSetting(a:vt."netrw_nukeep" ,"&l:nu")
-" call Decho("(s:NetrwOptionsRestore) #8 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_rnukeep" ,"&l:rnu")
call s:NetrwRestoreSetting(a:vt."netrw_repkeep" ,"&l:report")
call s:NetrwRestoreSetting(a:vt."netrw_rokeep" ,"&l:ro")
call s:NetrwRestoreSetting(a:vt."netrw_selkeep" ,"&l:sel")
-" call Decho("(s:NetrwOptionsRestore) #9 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_spellkeep","&l:spell")
call s:NetrwRestoreSetting(a:vt."netrw_twkeep" ,"&l:tw")
call s:NetrwRestoreSetting(a:vt."netrw_wigkeep" ,"&l:wig")
call s:NetrwRestoreSetting(a:vt."netrw_wrapkeep" ,"&l:wrap")
call s:NetrwRestoreSetting(a:vt."netrw_writekeep","&l:write")
-" call Decho("(s:NetrwOptionsRestore) #10 lines=".&lines)
call s:NetrwRestoreSetting("s:yykeep","@@")
" former problem: start with liststyle=0; press <i> : result, following line resets l:ts.
" Fixed; in s:PerformListing, when w:netrw_liststyle is s:LONGLIST, will use a printf to pad filename with spaces
@@ -1853,22 +1813,12 @@ fun! s:NetrwOptionsRestore(vt)
endif
call s:NetrwRestoreSetting(a:vt."netrw_slashkeep","@/")
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
-" call Decho("fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Decho("diff=".&l:diff." win#".winnr()." w:netrw_diffkeep=".(exists("w:netrw_diffkeep")? w:netrw_diffkeep : "doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("ts=".&l:ts,'~'.expand("<slnum>"))
" Moved the filetype detect here from NetrwGetFile() because remote files
" were having their filetype detect-generated settings overwritten by
" NetrwOptionRestore.
if &ft != "netrw"
-" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
filetype detect
-" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
endif
-" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
-" call Dret("s:NetrwOptionsRestore : tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> modified=".&modified." modifiable=".&modifiable." readonly=".&readonly)
endfun
" ---------------------------------------------------------------------
@@ -5244,32 +5194,132 @@ fun! s:NetrwBrowseUpDir(islocal)
" call Dret("s:NetrwBrowseUpDir")
endfun
+func s:redir()
+ " set up redirection (avoids browser messages)
+ " by default if not set, g:netrw_suppress_gx_mesg is true
+ if get(g:, 'netrw_suppress_gx_mesg', 1)
+ if &srr =~# "%s"
+ return printf(&srr, has("win32") ? "nul" : "/dev/null")
+ else
+ return &srr .. (has("win32") ? "nul" : "/dev/null")
+ endif
+ endif
+ return ''
+endfunc
+
+if has('unix')
+ if has('win32unix')
+ " Cygwin provides cygstart
+ if executable('cygstart')
+ fun! netrw#Launch(args)
+ exe 'silent ! cygstart --hide' a:args s:redir() | redraw!
+ endfun
+ elseif !empty($MSYSTEM) && executable('start')
+ " MSYS2/Git Bash comes by default without cygstart; see
+ " https://www.msys2.org/wiki/How-does-MSYS2-differ-from-Cygwin
+ " Instead it provides /usr/bin/start script running `cmd.exe //c start`
+ " Adding "" //b` sets void title, hides cmd window and blocks path conversion
+ " of /b to \b\ " by MSYS2; see https://www.msys2.org/docs/filesystem-paths/
+ fun! netrw#Launch(args)
+ exe 'silent !start "" //b' a:args s:redir() | redraw!
+ endfun
+ else
+ " imitate /usr/bin/start script for other environments and hope for the best
+ fun! netrw#Launch(args)
+ exe 'silent !cmd //c start "" //b' a:args s:redir() | redraw!
+ endfun
+ endif
+ elseif exists('$WSL_DISTRO_NAME') " use cmd.exe to start GUI apps in WSL
+ fun! netrw#Launch(args)
+ let args = a:args
+ exe 'silent !' ..
+ \ ((args =~? '\v<\f+\.(exe|com|bat|cmd)>') ?
+ \ 'cmd.exe /c start "" /b ' .. args :
+ \ 'nohup ' .. args .. ' ' .. s:redir() .. ' &')
+ \ | redraw!
+ endfun
+ else
+ fun! netrw#Launch(args)
+ exe ':silent ! nohup' a:args s:redir() '&' | redraw!
+ endfun
+ endif
+elseif has('win32')
+ fun! netrw#Launch(args)
+ exe 'silent !' .. (&shell =~? '\<cmd\.exe\>' ? '' : 'cmd.exe /c')
+ \ 'start "" /b' a:args s:redir() | redraw!
+ endfun
+else
+ fun! netrw#Launch(dummy)
+ echom 'No common launcher found'
+ endfun
+endif
+
+" Git Bash
+if has('win32unix')
+ " (cyg)start suffices
+ let s:os_viewer = ''
+" Windows / WSL
+elseif executable('explorer.exe')
+ let s:os_viewer = 'explorer.exe'
+" Linux / BSD
+elseif executable('xdg-open')
+ let s:os_viewer = 'xdg-open'
+" MacOS
+elseif executable('open')
+ let s:os_viewer = 'open'
+endif
+
+fun! s:viewer()
+ if exists('g:netrw_browsex_viewer') && executable(g:netrw_browsex_viewer)
+ " extract any viewing options. Assumes that they're set apart by spaces.
+ " call Decho("extract any viewing options from g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
+ if g:netrw_browsex_viewer =~ '\s'
+ let viewer = substitute(g:netrw_browsex_viewer,'\s.*$','','')
+ let viewopt = substitute(g:netrw_browsex_viewer,'^\S\+\s*','','')." "
+ let oviewer = ''
+ let cnt = 1
+ while !executable(viewer) && viewer != oviewer
+ let viewer = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\1','')
+ let viewopt = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\3','')." "
+ let cnt = cnt + 1
+ let oviewer = viewer
+ " call Decho("!exe: viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
+ endwhile
+ else
+ let viewer = g:netrw_browsex_viewer
+ let viewopt = ""
+ endif
+ " call Decho("viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
+ return viewer .. ' ' .. viewopt
+ else
+ if !exists('s:os_viewer')
+ call netrw#ErrorMsg(s:ERROR,"No program to open this path found. See :help Open for more information.",106)
+ else
+ return s:os_viewer
+ endif
+ endif
+endfun
+
+fun! netrw#Open(file) abort
+ call netrw#Launch(s:viewer() .. ' ' .. shellescape(a:file, 1))
+endf
+
+if !exists('g:netrw_regex_url')
+ let g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
+endif
+
" ---------------------------------------------------------------------
" netrw#BrowseX: (implements "x" and "gx") executes a special "viewer" script or program for the {{{2
" given filename; typically this means given their extension.
" 0=local, 1=remote
fun! netrw#BrowseX(fname,remote)
- let use_ctrlo= 1
-" call Dfunc("netrw#BrowseX(fname<".a:fname."> remote=".a:remote.") implements x and gx maps")
-
if a:remote == 0 && isdirectory(a:fname)
" if its really just a local directory, then do a "gf" instead
-" call Decho("remote≡0 and a:fname<".a:fname."> ".(isdirectory(a:fname)? "is a directory" : "is not a directory"),'~'.expand("<slnum>"))
-" call Decho("..appears to be a local directory; using e ".a:fname." instead",'~'.expand("<slnum>"))
exe "e ".a:fname
-" call Dret("netrw#BrowseX")
- return
elseif a:remote == 1 && a:fname !~ '^https\=:' && a:fname =~ '/$'
" remote directory, not a webpage access, looks like an attempt to do a directory listing
-" call Decho("remote≡1 and a:fname<".a:fname.">",'~'.expand("<slnum>"))
-" call Decho("..and fname ".((a:fname =~ '^https\=:')? 'matches' : 'does not match').'^https\=:','~'.expand("<slnum>"))
-" call Decho("..and fname ".((a:fname =~ '/$')? 'matches' : 'does not match').' /$','~'.expand("<slnum>"))
-" call Decho("..appears to be a remote directory listing request; using gf instead",'~'.expand("<slnum>"))
norm! gf
-" call Dret("netrw#BrowseX")
- return
endif
-" call Decho("not a local file nor a webpage request",'~'.expand("<slnum>"))
if exists("g:netrw_browsex_viewer") && exists("g:netrw_browsex_support_remote") && !g:netrw_browsex_support_remote
let remote = a:remote
@@ -5279,7 +5329,6 @@ fun! netrw#BrowseX(fname,remote)
let ykeep = @@
let screenposn = winsaveview()
-" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
" need to save and restore aw setting as gx can invoke this function from non-netrw buffers
let awkeep = &aw
@@ -5290,22 +5339,18 @@ fun! netrw#BrowseX(fname,remote)
if exists("g:Netrw_corehandler")
if type(g:Netrw_corehandler) == 2
" g:Netrw_corehandler is a function reference (see :help Funcref)
-" call Decho("g:Netrw_corehandler is a funcref",'~'.expand("<slnum>"))
call g:Netrw_corehandler(s:NetrwFile(a:fname))
elseif type(g:Netrw_corehandler) == 3
" g:Netrw_corehandler is a List of function references (see :help Funcref)
-" call Decho("g:Netrw_corehandler is a List",'~'.expand("<slnum>"))
for Fncref in g:Netrw_corehandler
if type(Fncref) == 2
call Fncref(a:fname)
endif
endfor
endif
-" call Decho("restoring posn: screenposn<".string(screenposn).">,'~'.expand("<slnum>"))"
call winrestview(screenposn)
let @@= ykeep
let &aw= awkeep
-" call Dret("netrw#BrowseX : coredump handler invoked")
return
endif
endif
@@ -5319,163 +5364,35 @@ fun! netrw#BrowseX(fname,remote)
if exten =~ "[\\/]"
let exten= ""
endif
-" call Decho("exten<".exten.">",'~'.expand("<slnum>"))
if remote == 1
" create a local copy
-" call Decho("remote: remote=".remote.": create a local copy of <".a:fname.">",'~'.expand("<slnum>"))
setl bh=delete
call netrw#NetRead(3,a:fname)
" attempt to rename tempfile
let basename= substitute(a:fname,'^\(.*\)/\(.*\)\.\([^.]*\)$','\2','')
let newname = substitute(s:netrw_tmpfile,'^\(.*\)/\(.*\)\.\([^.]*\)$','\1/'.basename.'.\3','')
-" call Decho("basename<".basename.">",'~'.expand("<slnum>"))
-" call Decho("newname <".newname.">",'~'.expand("<slnum>"))
if s:netrw_tmpfile != newname && newname != ""
if rename(s:netrw_tmpfile,newname) == 0
" renaming succeeded
-" call Decho("renaming succeeded (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
let fname= newname
else
" renaming failed
-" call Decho("renaming failed (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
let fname= s:netrw_tmpfile
endif
else
let fname= s:netrw_tmpfile
endif
else
-" call Decho("local: remote=".remote.": handling local copy of <".a:fname.">",'~'.expand("<slnum>"))
let fname= a:fname
" special ~ handler for local
if fname =~ '^\~' && expand("$HOME") != ""
-" call Decho('invoking special ~ handler','~'.expand("<slnum>"))
let fname= s:NetrwFile(substitute(fname,'^\~',expand("$HOME"),''))
endif
endif
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
-" call Decho("exten<".exten."> "."netrwFileHandlers#NFH_".exten."():exists=".exists("*netrwFileHandlers#NFH_".exten),'~'.expand("<slnum>"))
-
- " set up redirection (avoids browser messages)
- " by default, g:netrw_suppress_gx_mesg is true
- if g:netrw_suppress_gx_mesg
- if &srr =~ "%s"
- if has("win32")
- let redir= substitute(&srr,"%s","nul","")
- else
- let redir= substitute(&srr,"%s","/dev/null","")
- endif
- elseif has("win32")
- let redir= &srr . "nul"
- else
- let redir= &srr . "/dev/null"
- endif
- else
- let redir= ""
- endif
-" call Decho("set up redirection: redir{".redir."} srr{".&srr."}",'~'.expand("<slnum>"))
- " extract any viewing options. Assumes that they're set apart by spaces.
- if exists("g:netrw_browsex_viewer")
-" call Decho("extract any viewing options from g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
- if g:netrw_browsex_viewer =~ '\s'
- let viewer = substitute(g:netrw_browsex_viewer,'\s.*$','','')
- let viewopt = substitute(g:netrw_browsex_viewer,'^\S\+\s*','','')." "
- let oviewer = ''
- let cnt = 1
- while !executable(viewer) && viewer != oviewer
- let viewer = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\1','')
- let viewopt = substitute(g:netrw_browsex_viewer,'^\(\(^\S\+\s\+\)\{'.cnt.'}\S\+\)\(.*\)$','\3','')." "
- let cnt = cnt + 1
- let oviewer = viewer
-" call Decho("!exe: viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
- endwhile
- else
- let viewer = g:netrw_browsex_viewer
- let viewopt = ""
- endif
-" call Decho("viewer<".viewer."> viewopt<".viewopt.">",'~'.expand("<slnum>"))
- endif
-
- " execute the file handler
-" call Decho("execute the file handler (if any)",'~'.expand("<slnum>"))
- if exists("g:netrw_browsex_viewer") && executable(viewer)
-" call Decho("(netrw#BrowseX) g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !".viewer." ".viewopt.s:ShellEscape(fname,1).redir)
- let ret= v:shell_error
-
- elseif has("win32")
-" call Decho("(netrw#BrowseX) win".(has("win32")? "32" : "64"),'~'.expand("<slnum>"))
- if executable("start")
- call s:NetrwExe('sil! !start rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(fname,1))
- elseif executable("rundll32")
- call s:NetrwExe('sil! !rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(fname,1))
- else
- call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
- endif
- let ret= v:shell_error
-
- elseif has("win32unix")
- let winfname= 'c:\cygwin'.substitute(fname,'/','\\','g')
-" call Decho("(netrw#BrowseX) cygwin: winfname<".s:ShellEscape(winfname,1).">",'~'.expand("<slnum>"))
- if executable("start")
-" call Decho("(netrw#BrowseX) win32unix+start",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !start rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(winfname,1))
- elseif executable("rundll32")
-" call Decho("(netrw#BrowseX) win32unix+rundll32",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(winfname,1))
- elseif executable("cygstart")
-" call Decho("(netrw#BrowseX) win32unix+cygstart",'~'.expand("<slnum>"))
- call s:NetrwExe('sil !cygstart '.s:ShellEscape(fname,1))
- else
- call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
- endif
- let ret= v:shell_error
-
- elseif has("unix") && $DESKTOP_SESSION == "mate" && executable("atril")
-" call Decho("(netrw#BrowseX) unix and atril",'~'.expand("<slnum>"))
- if a:fname =~ '^https\=://'
- " atril does not appear to understand how to handle html -- so use gvim to edit the document
- let use_ctrlo= 0
-" call Decho("fname<".fname.">")
-" call Decho("a:fname<".a:fname.">")
- call s:NetrwExe("sil! !gvim ".fname.' -c "keepj keepalt file '.fnameescape(a:fname).'"')
-
- else
- call s:NetrwExe("sil !atril ".s:ShellEscape(fname,1).redir)
- endif
- let ret= v:shell_error
-
- elseif has("unix") && executable("kfmclient") && s:CheckIfKde()
-" call Decho("(netrw#BrowseX) unix and kfmclient",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !kfmclient exec ".s:ShellEscape(fname,1)." ".redir)
- let ret= v:shell_error
-
- elseif has("unix") && executable("exo-open") && executable("xdg-open") && executable("setsid")
-" call Decho("(netrw#BrowseX) unix, exo-open, xdg-open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !setsid xdg-open ".s:ShellEscape(fname,1).redir.'&')
- let ret= v:shell_error
-
- elseif has("unix") && executable("xdg-open")
-" call Decho("(netrw#BrowseX) unix and xdg-open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !xdg-open ".s:ShellEscape(fname,1).redir.'&')
- let ret= v:shell_error
-
- elseif has("macunix") && executable("open")
-" call Decho("(netrw#BrowseX) macunix and open",'~'.expand("<slnum>"))
- call s:NetrwExe("sil !open ".s:ShellEscape(fname,1)." ".redir)
- let ret= v:shell_error
- else
- call netrw#ErrorMsg(s:ERROR, "Couldn't find a program to open '".a:fname."'", 0)
- let ret=0
- endif
-
- if ret
- call netrw#ErrorMsg(s:ERROR, "Failed to open '".a:fname."'", 0)
- endif
-
- " restoring redraw! after external file handlers
- redraw!
+ " although shellescape(..., 1) is used in netrw#Open(), it's insufficient
+ call netrw#Open(escape(fname, '#%'))
" cleanup: remove temporary file,
" delete current buffer if success with handler,
@@ -5483,7 +5400,6 @@ fun! netrw#BrowseX(fname,remote)
" Feb 12, 2008: had to de-activate removal of
" temporary file because it wasn't getting seen.
" if remote == 1 && fname != a:fname
-"" call Decho("deleting temporary file<".fname.">",'~'.expand("<slnum>"))
" call s:NetrwDelete(fname)
" endif
@@ -5492,16 +5408,11 @@ fun! netrw#BrowseX(fname,remote)
if g:netrw_use_noswf
setl noswf
endif
- if use_ctrlo
- exe "sil! NetrwKeepj norm! \<c-o>"
- endif
+ exe "sil! NetrwKeepj norm! \<c-o>"
endif
-" call Decho("restoring posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
call winrestview(screenposn)
let @@ = ykeep
let &aw= awkeep
-
-" call Dret("netrw#BrowseX")
endfun
" ---------------------------------------------------------------------
@@ -5513,12 +5424,37 @@ fun! netrw#GX()
if &ft == "netrw"
let fname= s:NetrwGetWord()
else
- let fname= expand((exists("g:netrw_gx")? g:netrw_gx : '<cfile>'))
+ let fname= exists("g:netrw_gx")? expand(g:netrw_gx) : s:GetURL()
endif
" call Dret("netrw#GX <".fname.">")
return fname
endfun
+fun! s:GetURL() abort
+ let URL = ''
+ if exists('*Netrw_get_URL_' .. &filetype)
+ let URL = call('Netrw_get_URL_' .. &filetype, [])
+ endif
+ if !empty(URL) | return URL | endif
+ " URLs end in letter, digit or forward slash
+ let URL = matchstr(expand("<cWORD>"), '\<' .. g:netrw_regex_url .. '\ze[^A-Za-z0-9/]*$')
+ if !empty(URL) | return URL | endif
+
+ " Is it a file in the current work dir ...
+ let file = expand("<cfile>")
+ if filereadable(file) | return file | endif
+ " ... or in that of the current buffer?
+ let path = fnamemodify(expand('%'), ':p')
+ if isdirectory(path)
+ let dir = path
+ elseif filereadable(path)
+ let dir = fnamemodify(path, ':h')
+ endif
+ if exists('dir') && filereadable(dir..'/'..file) | return dir..'/'..file | endif
+
+ return ''
+endf
+
" ---------------------------------------------------------------------
" netrw#BrowseXVis: used by gx in visual mode to select a file for browsing {{{2
fun! netrw#BrowseXVis()
@@ -5753,7 +5689,7 @@ fun! s:NetrwGlob(direntry,expr,pare)
endif
let w:netrw_liststyle= keep_liststyle
else
- let path= s:ComposePath(fnameescape(a:direntry),a:expr)
+ let path= s:ComposePath(fnameescape(a:direntry), a:expr)
if has("win32")
" escape [ so it is not detected as wildcard character, see :h wildcard
let path= substitute(path, '[', '[[]', 'g')
@@ -5767,7 +5703,6 @@ fun! s:NetrwGlob(direntry,expr,pare)
let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")')
endif
endif
-" call Dret("s:NetrwGlob ".string(filelist))
return filelist
endfun
@@ -6670,6 +6605,7 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(2)<cr>
nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr>
+ nmap <buffer> <nowait> gx x
if !hasmapto('<Plug>NetrwHideEdit')
nmap <buffer> <c-h> <Plug>NetrwHideEdit
endif
@@ -8241,7 +8177,7 @@ fun! netrw#Shrink()
elseif winwidth(bufwinnr(t:netrw_lexbufnr)) >= 0
exe "vert resize ".t:netrw_winwidth
" call Decho("vert resize ".t:netrw_winwidth,'~'.expand("<slnum>"))
- else
+ else
call netrw#Lexplore(0,0)
endif
@@ -8558,7 +8494,7 @@ fun! s:NetrwPrevWinOpen(islocal)
" call Decho("COMBAK#11: mod=".&mod)
" call Decho("wincmd p (now in win#".winnr().") curdir<".curdir.">",'~'.expand("<slnum>"))
" call Decho("COMBAK#12: mod=".&mod)
-
+
if exists("s:lexplore_win") && s:lexplore_win == winnr()
" whoops -- user trying to open file in the Lexplore window.
" Use Lexplore's opening-file window instead.
@@ -9539,22 +9475,16 @@ endfun
" Called by s:PerformListing()
fun! s:NetrwTreeListing(dirname)
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
-" call Dfunc("s:NetrwTreeListing() bufname<".expand("%").">")
-" call Decho("curdir<".a:dirname.">",'~'.expand("<slnum>"))
-" call Decho("win#".winnr().": w:netrw_treetop ".(exists("w:netrw_treetop")? "exists" : "doesn't exist")." w:netrw_treedict ".(exists("w:netrw_treedict")? "exists" : "doesn't exit"),'~'.expand("<slnum>"))
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
" update the treetop
if !exists("w:netrw_treetop")
-" call Decho("update the treetop (w:netrw_treetop doesn't exist yet)",'~'.expand("<slnum>"))
let w:netrw_treetop= a:dirname
let s:netrw_treetop= w:netrw_treetop
-" call Decho("w:netrw_treetop<".w:netrw_treetop."> (reusing)",'~'.expand("<slnum>"))
- elseif (w:netrw_treetop =~ ('^'.a:dirname) && s:Strlen(a:dirname) < s:Strlen(w:netrw_treetop)) || a:dirname !~ ('^'.w:netrw_treetop)
-" call Decho("update the treetop (override w:netrw_treetop with a:dirname<".a:dirname.">)",'~'.expand("<slnum>"))
+ " use \V in case the directory contains specials chars like '$' or '~'
+ elseif (w:netrw_treetop =~ ('^'.'\V'.a:dirname) && s:Strlen(a:dirname) < s:Strlen(w:netrw_treetop))
+ \ || a:dirname !~ ('^'.'\V'.w:netrw_treetop)
let w:netrw_treetop= a:dirname
let s:netrw_treetop= w:netrw_treetop
-" call Decho("w:netrw_treetop<".w:netrw_treetop."> (went up)",'~'.expand("<slnum>"))
endif
if exists("w:netrw_treetop")
let s:netrw_treetop= w:netrw_treetop
@@ -9565,16 +9495,12 @@ fun! s:NetrwTreeListing(dirname)
if !exists("w:netrw_treedict")
" insure that we have a treedict, albeit empty
-" call Decho("initializing w:netrw_treedict to empty",'~'.expand("<slnum>"))
let w:netrw_treedict= {}
endif
" update the dictionary for the current directory
-" call Decho("updating: w:netrw_treedict[".a:dirname.'] -> [directory listing]','~'.expand("<slnum>"))
-" call Decho("w:netrw_bannercnt=".w:netrw_bannercnt." line($)=".line("$"),'~'.expand("<slnum>"))
exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$g@^\.\.\=/$@d _'
let w:netrw_treedict[a:dirname]= getline(w:netrw_bannercnt,line("$"))
-" call Decho("w:treedict[".a:dirname."]= ".string(w:netrw_treedict[a:dirname]),'~'.expand("<slnum>"))
exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d _"
" if past banner, record word
@@ -9583,23 +9509,17 @@ fun! s:NetrwTreeListing(dirname)
else
let fname= ""
endif
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
-" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
" display from treetop on down
-" call Decho("(s:NetrwTreeListing) w:netrw_treetop<".w:netrw_treetop.">")
NetrwKeepj call s:NetrwTreeDisplay(w:netrw_treetop,"")
-" call Decho("s:NetrwTreeDisplay) setl noma nomod ro",'~'.expand("<slnum>"))
" remove any blank line remaining as line#1 (happens in treelisting mode with banner suppressed)
while getline(1) =~ '^\s*$' && byte2line(1) > 0
-" call Decho("deleting blank line",'~'.expand("<slnum>"))
1d
endwhile
exe "setl ".g:netrw_bufsettings
-" call Dret("s:NetrwTreeListing : bufname<".expand("%").">")
return
endif
endfun
@@ -11963,7 +11883,7 @@ fun! s:NetrwEnew(...)
" call Dfunc("s:NetrwEnew() a:0=".a:0." win#".winnr()." winnr($)=".winnr("$")." bufnr($)=".bufnr("$")." expand(%)<".expand("%").">")
" call Decho("curdir<".((a:0>0)? a:1 : "")."> buf#".bufnr("%")."<".bufname("%").">",'~'.expand("<slnum>"))
- " Clean out the last buffer:
+ " Clean out the last buffer:
" Check if the last buffer has # > 1, is unlisted, is unnamed, and does not appear in a window
" If so, delete it.
call s:NetrwBufRemover(bufnr("$"))
@@ -12043,13 +11963,16 @@ endfun
" s:NetrwExe: executes a string using "!" {{{2
fun! s:NetrwExe(cmd)
" call Dfunc("s:NetrwExe(a:cmd<".a:cmd.">)")
- if has("win32") && &shell !~? 'cmd\|pwsh\|powershell' && !g:netrw_cygwin
+ if has("win32")
" call Decho("using win32:",expand("<slnum>"))
let savedShell=[&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash]
set shell& shellcmdflag& shellxquote& shellxescape&
set shellquote& shellpipe& shellredir& shellslash&
- exe a:cmd
- let [&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] = savedShell
+ try
+ exe a:cmd
+ finally
+ let [&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] = savedShell
+ endtry
else
" call Decho("exe ".a:cmd,'~'.expand("<slnum>"))
exe a:cmd
@@ -12152,7 +12075,7 @@ fun! s:NetrwHumanReadable(sz)
" call Dfunc("s:NetrwHumanReadable(sz=".a:sz.") type=".type(a:sz)." style=".g:netrw_sizestyle )
if g:netrw_sizestyle == 'h'
- if a:sz >= 1000000000
+ if a:sz >= 1000000000
let sz = printf("%.1f",a:sz/1000000000.0)."g"
elseif a:sz >= 10000000
let sz = printf("%d",a:sz/1000000)."m"
@@ -12580,7 +12503,7 @@ endfun
fun! s:ShellEscape(s, ...)
if has('win32') && $SHELL == '' && &shellslash
return printf('"%s"', substitute(a:s, '"', '""', 'g'))
- endif
+ endif
let f = a:0 > 0 ? a:1 : 0
return shellescape(a:s, f)
endfun
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index 7fc7d4140a..ccc899cd6d 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -1465,48 +1465,106 @@ With either form of the command, netrw will first ask for confirmation
that the removal is in fact what you want to do. If netrw doesn't have
permission to remove a file, it will issue an error message.
- *netrw-gx*
CUSTOMIZING BROWSING WITH A SPECIAL HANDLER *netrw-x* *netrw-handler* {{{2
Certain files, such as html, gif, jpeg, (word/office) doc, etc, files, are
best seen with a special handler (ie. a tool provided with your computer's
-operating system). Netrw allows one to invoke such special handlers by: >
+operating system). Netrw allows one to invoke such special handlers by:
- * when Exploring, hit the "x" key
- * when editing, hit gx with the cursor atop the special filename
-< (latter not available if the |g:netrw_nogx| variable exists)
+ * hitting gx with the cursor atop the file path or alternatively x
+ in a netrw buffer; the former can be disabled by defining the
+ |g:netrw_nogx| variable
+ * when in command line, typing :Open <path>, see |:Open| below.
-Netrw determines which special handler by the following method:
-
- * if |g:netrw_browsex_viewer| exists, then it will be used to attempt to
- view files. Examples of useful settings (place into your <.vimrc>): >
-
- :let g:netrw_browsex_viewer= "kfmclient exec"
-< or >
- :let g:netrw_browsex_viewer= "xdg-open"
-<
- If the viewer you wish to use does not support handling of a remote URL
- directory, set |g:netrw_browsex_support_remote| to 0.
- * for Windows 32 or 64, the URL and FileProtocolHandler dlls are used.
- * for Gnome (with gnome-open): gnome-open is used.
- * for KDE (with kfmclient) : kfmclient is used
- * for Mac OS X : open is used.
-
-The gx mapping extends to all buffers; apply "gx" while atop a word and netrw
-will apply a special handler to it (like "x" works when in a netrw buffer).
One may also use visual mode (see |visual-start|) to select the text that the
-special handler will use. Normally gx uses expand("<cfile>") to pick up the
-text under the cursor; one may change what |expand()| uses via the
+special handler will use. Normally gx checks for a close-by URL or file name
+to pick up the text under the cursor; one may change what |expand()| uses via the
|g:netrw_gx| variable (options include "<cword>", "<cWORD>"). Note that
expand("<cfile>") depends on the |'isfname'| setting. Alternatively, one may
select the text to be used by gx by making a visual selection (see
|visual-block|) and then pressing gx.
+The selection function can be adapted for each filetype by adding a function
+`Netrw_get_URL_<filetype>`, where <filetype> is given by the 'filetype'.
+The function should return the URL or file name to be used by gx, and will
+fall back to the default behavior if it returns an empty string.
+For example, special handlers for links Markdown and HTML are
+
+" make gx work on concealed links regardless of exact cursor position: >
+
+ function Netrw_get_URL_markdown()
+ " markdown URL such as [link text](http://ya.ru 'yandex search')
+ try
+ let save_view = winsaveview()
+ if searchpair('\[.\{-}\](', '', ')\zs', 'cbW', '', line('.')) > 0
+ return matchstr(getline('.')[col('.')-1:],
+ \ '\[.\{-}\](\zs' .. g:netrw_regex_url .. '\ze\(\s\+.\{-}\)\?)')
+ endif
+ finally
+ call winrestview(save_view)
+ return ''
+ endtry
+ endfunction
+
+ function Netrw_get_URL_html()
+ " HTML URL such as <a href='http://www.python.org'>Python is here</a>
+ " <a href="http://www.python.org"/>
+ try
+ let save_view = winsaveview()
+ if searchpair('<a\s\+href=', '', '\%(</a>\|/>\)\zs', 'cbW', '', line('.')) > 0
+ return matchstr(getline('.')[col('.') - 1 : ],
+ \ 'href=["'.."'"..']\?\zs\S\{-}\ze["'.."'"..']\?/\?>')
+ endif
+ finally
+ call winrestview(save_view)
+ return ''
+ endtry
+ endfunction
+<
+Other than a file path, the text under the cursor may be a URL. Netrw uses
+by default the following regular expression to determine if the text under the
+cursor is a URL:
+>
+ :let g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
+<
Associated setting variables:
|g:netrw_gx| control how gx picks up the text under the cursor
|g:netrw_nogx| prevent gx map while editing
|g:netrw_suppress_gx_mesg| controls gx's suppression of browser messages
+OPENING FILES AND LAUNCHING APPS *netrw-gx* *:Open* *:Launch* {{{2
+
+Netrw determines which special handler by the following method:
+
+ * if |g:netrw_browsex_viewer| exists, then it will be used to attempt to
+ view files. Examples of useful settings (place into your <.vimrc>):
+ If the viewer you wish to use does not support handling of a remote URL
+ directory, set |g:netrw_browsex_support_remote| to 0.
+ * otherwise:
+
+ * for Windows : explorer.exe is used
+ * for Mac OS X : open is used.
+ * for Linux : xdg-open is used.
+
+To open a path (or URL) <path> by the appropriate handler, type >
+
+ :Open <path>
+<
+No escaping, neither for the shell nor for Vim's command-line, is needed.
+
+To launch a specific application <app> <args>, often <args> being <path> >
+
+ :Launch <app> <args>.
+
+Since <args> can be arbitrarily complex, in particular contain many file
+paths, the escaping is left to the user.
+
+If you disabled the netrw plugin by setting g:loaded_netrwPlugin (see
+|netrw-noload|), then you can use >
+
+ :call netrw#Launch('<app> <args>')
+ :call netrw#Open('<path>')
+<
*netrw-curdir*
DELETING BOOKMARKS *netrw-mB* {{{2
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index c70e6518ff..775b650e71 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -1,9 +1,12 @@
" netrwPlugin.vim: Handles file transfer and remote directory listing across a network
" PLUGIN SECTION
" Maintainer: This runtime file is looking for a new maintainer.
-" Date: Feb 09, 2021
+" Date: Sep 09, 2021
" Last Change:
" 2024 May 08 by Vim Project: cleanup legacy Win9X checks
+" 2024 Oct 27 by Vim Project: cleanup gx mapping
+" 2024 Oct 28 by Vim Project: further improvements
+" 2024 Oct 31 by Vim Project: use autoloaded functions
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 1999-2021 Charles E. Campbell {{{1
@@ -31,6 +34,10 @@ set cpo&vim
" ---------------------------------------------------------------------
" Public Interface: {{{1
+" Commands Launch/URL {{{2
+command -complete=shellcmd -nargs=1 Launch call netrw#Launch(trim(<q-args>))
+command -complete=file -nargs=1 Open call netrw#Open(trim(<q-args>))
+" " }}}
" Local Browsing Autocmds: {{{2
augroup FileExplorer
au!