aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/netrw.vim136
-rw-r--r--runtime/doc/pi_netrw.txt99
-rw-r--r--runtime/plugin/netrwPlugin.vim84
3 files changed, 195 insertions, 124 deletions
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index d5e3a77dd4..23440c085f 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -27,6 +27,7 @@
" 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)
" }}}
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
@@ -533,7 +534,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
@@ -5356,25 +5356,6 @@ fun! netrw#BrowseX(fname,remote)
" 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>"))
@@ -5397,86 +5378,14 @@ fun! netrw#BrowseX(fname,remote)
" 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
+ exe 'Launch' viewer viewopt shellescape(fname, 1)
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)
+ " though shellescape(..., 1) is used in Open, it's insufficient
+ exe 'Open' escape(fname, '#%')
endif
- " restoring redraw! after external file handlers
- redraw!
-
" cleanup: remove temporary file,
" delete current buffer if success with handler,
" return to prior buffer (directory listing)
@@ -5513,12 +5422,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()
@@ -6670,6 +6604,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
@@ -12043,13 +11978,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
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index 7fc7d4140a..ed95cbb851 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -1465,42 +1465,93 @@ 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*
+ *netrw-gx* *Open* *Launch*
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>
-Netrw determines which special handler by the following method:
+One may also use visual mode (see |visual-start|) to select the text that 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.
- * if |g:netrw_browsex_viewer| exists, then it will be used to attempt to
- view files. Examples of useful settings (place into your <.vimrc>): >
+The selection function can be adapted for each filetype by adding a function
+Netrw_get_URL_<filetype>, where <filetype> is given by &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
+<
- :let g:netrw_browsex_viewer= "kfmclient exec"
-< or >
- :let g:netrw_browsex_viewer= "xdg-open"
+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:
+>
+ g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
<
+
+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.
- * 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.
+ * otherwise:
-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
-|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.
+ * for Windows : explorer.exe is used
+ * for Mac OS X : open is used.
+ * for Linux : xdg-open is used.
+
+To open a file <filepath> by the appropriate handler, type
+
+ :Open <filepath>
+
+No escaping, neither for the shell, nor for Vim's command-line is needed.
+
+To launch a specific application <app> <args>, often <args> being <filepath>,
+
+ :Launch <app> <args>.
+
+Since <args> can be arbitrarily complex, in particular contain many file
+paths, the escaping is left to the user.
Associated setting variables:
|g:netrw_gx| control how gx picks up the text under the cursor
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index c70e6518ff..59fb7e727e 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -1,9 +1,10 @@
" 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
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 1999-2021 Charles E. Campbell {{{1
@@ -31,6 +32,87 @@ set cpo&vim
" ---------------------------------------------------------------------
" Public Interface: {{{1
+" Commands Launch/URL {{{2
+" surpress output of command; use bang for GUI applications
+
+" set up redirection (avoids browser messages)
+" by default, g:netrw_suppress_gx_mesg is true
+if get(g:, ':netrw_suppress_gx_mesg', 1)
+ if &srr =~# "%s"
+ let s:redir = printf(&srr, has("win32") ? "nul" : "/dev/null")
+ else
+ let s:redir= &srr .. (has("win32") ? "nul" : "/dev/null")
+ endif
+else
+ let s:redir= ""
+endif
+
+if has('unix')
+ if has('win32unix')
+ " If cygstart provided, then assume Cygwin and use cygstart --hide; see man cygstart.
+ if executable('cygstart')
+ command -complete=shellcmd -nargs=1 -bang Launch
+ \ exe 'silent ! cygstart --hide' trim(<q-args>) s:redir | redraw!
+ 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/
+ command -complete=shellcmd -nargs=1 -bang Launch
+ \ exe 'silent !start "" //b' trim(<q-args>) s:redir | redraw!
+ else
+ " imitate /usr/bin/start script for other environments and hope for the best
+ command -complete=shellcmd -nargs=1 -bang Launch
+ \ exe 'silent !cmd //c start "" //b' trim(<q-args>) s:redir | redraw!
+ endif
+ elseif exists('$WSL_DISTRO_NAME') " use cmd.exe to start GUI apps in WSL
+ command -complete=shellcmd -nargs=1 -bang Launch execute ':silent !'..
+ \ ((<q-args> =~? '\v<\f+\.(exe|com|bat|cmd)>') ?
+ \ 'cmd.exe /c start "" /b' trim(<q-args>) :
+ \ 'nohup ' trim(<q-args>) s:redir '&')
+ \ | redraw!
+ else
+ command -complete=shellcmd -nargs=1 -bang Launch
+ \ exe ':silent ! nohup' trim(<q-args>) s:redir '&' | redraw!
+ endif
+elseif has('win32')
+ command -complete=shellcmd -nargs=1 -bang Launch
+ \ exe 'silent !'.. (&shell =~? '\<cmd\.exe\>' ? '' : 'cmd.exe /c')
+ \ 'start /b ' trim(<q-args>) s:redir | redraw!
+endif
+if exists(':Launch') == 2
+ " Git Bash
+ if has('win32unix')
+ " start suffices
+ let s:cmd = ''
+ " Windows / WSL
+ elseif executable('explorer.exe')
+ let s:cmd = 'explorer.exe'
+ " Linux / BSD
+ elseif executable('xdg-open')
+ let s:cmd = 'xdg-open'
+ " MacOS
+ elseif executable('open')
+ let s:cmd = 'open'
+ else
+ s:cmd = ''
+ endif
+ function s:Open(cmd, file)
+ if empty(a:cmd) && !exists('g:netrw_browsex_viewer')
+ echoerr "No program to open this path found. See :help Open for more information."
+ else
+ Launch cmd shellescape(a:file, 1)
+ endif
+ endfunction
+ command -complete=file -nargs=1 Open call s:Open(s:cmd, <q-args>)
+endif
+
+if !exists('g:netrw_regex_url')
+ let g:netrw_regex_url = '\%(\%(http\|ftp\|irc\)s\?\|file\)://\S\{-}'
+endif
+
+" " }}}
" Local Browsing Autocmds: {{{2
augroup FileExplorer
au!