runtime: decouple Open and Launch commands and gx mapping from netrw

closes: #16494
fixes: ##16486

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Luca Saccarola
2025-01-25 16:07:12 +01:00
committed by Christian Brabandt
parent d65aa1bbdb
commit c729d6d154
8 changed files with 192 additions and 166 deletions

View File

@ -2,19 +2,128 @@ vim9script
# Vim runtime support library
#
# Maintainer: The Vim Project <https://github.com/vim/vim>
# Last Change: 2023 Oct 25
# Maintainer: The Vim Project <https://github.com/vim/vim>
# Last Change: 2025 Jan 24
export def IsSafeExecutable(filetype: string, executable: string): bool
if empty(exepath(executable))
return v:false
if empty(exepath(executable))
return v:false
endif
var cwd = getcwd()
return get(g:, filetype .. '_exec', get(g:, 'plugin_exec', 0))
&& (fnamemodify(exepath(executable), ':p:h') !=# cwd
|| (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1
&& cwd != '.'))
enddef
def Redir(): string
if get(g:, 'netrw_suppress_gx_mesg', true)
if &srr =~# "%s"
return printf(&srr, has("win32") ? "nul" : "/dev/null")
elseif &srr =~# '>&\?$'
return &srr .. (has("win32") ? "nul" : "/dev/null")
else
return &srr .. (has("win32") ? "> nul" : "> /dev/null")
endif
var cwd = getcwd()
return get(g:, filetype .. '_exec', get(g:, 'plugin_exec', 0))
&& (fnamemodify(exepath(executable), ':p:h') !=# cwd
|| (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1
&& cwd != '.'))
endif
return ''
enddef
if has('unix')
if has('win32unix')
# Cygwin provides cygstart
if executable('cygstart')
export def Launch(args: string)
execute 'silent ! cygstart --hide' args Redir() | redraw!
enddef
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/
export def Launch(args: string)
execute 'silent !start "" //b' args Redir() | redraw!
enddef
else
# imitate /usr/bin/start script for other environments and hope for the best
export def Launch(args: string)
execute 'silent !cmd //c start "" //b' args Redir() | redraw!
enddef
endif
elseif exists('$WSL_DISTRO_NAME') # use cmd.exe to start GUI apps in WSL
export def Launch(args: string)
execute 'silent !' ..
((args =~? '\v<\f+\.(exe|com|bat|cmd)>') ?
$'cmd.exe /c start /b {args} {Redir()}' :
$'nohup {args} {Redir()} &')
| redraw!
enddef
else
export def Launch(args: string)
execute ':silent ! nohup' args Redir() (has('gui_running') ? '' : '&') | redraw!
enddef
endif
elseif has('win32')
export def Launch(args: string)
execute 'silent !' .. (&shell =~? '\<cmd\.exe\>' ? '' : 'cmd.exe /c')
'start "" /b' args Redir() | redraw!
enddef
else
export def Launch(dummy: string)
echom 'No common launcher found'
enddef
endif
var os_viewer = null_string
# Git Bash
if has('win32unix')
# (cyg)start suffices
os_viewer = ''
# Windows / WSL
elseif executable('explorer.exe')
os_viewer = 'explorer.exe'
# Linux / BSD
elseif executable('xdg-open')
os_viewer = 'xdg-open'
# MacOS
elseif executable('open')
os_viewer = 'open'
endif
def Viewer(): string
# g:Openprg could be a string of program + its arguments, test if first
# argument is executable
var user_viewer = get(g:, "Openprg", get(g:, "netrw_browsex_viewer", ""))
# Take care of an off-by-one check for "for" too
if executable(trim(user_viewer))
return user_viewer
endif
var args = split(user_viewer, '\s\+\zs')
var viewer = get(args, 0, '')
for arg in args[1 :]
if executable(trim(viewer))
return user_viewer
endif
viewer ..= arg
endfor
if os_viewer == null
echoerr "No program to open this path found. See :help Open for more information."
endif
return os_viewer
enddef
export def Open(file: string)
Launch($"{Viewer()} {shellescape(file, 1)}")
enddef
# Uncomment this line to check for compilation errors early
# defcompile
# vim: ts=8 sts=2 sw=2 et

View File

@ -1,4 +1,4 @@
*eval.txt* For Vim version 9.1. Last change: 2025 Jan 02
*eval.txt* For Vim version 9.1. Last change: 2025 Jan 25
VIM REFERENCE MANUAL by Bram Moolenaar
@ -4907,5 +4907,40 @@ executable. It takes the following arguments:
filetype string
executable string
*dist#vim9#Open()* *:Open*
*g:Openprg*
dist#vim9#Open(file: string) ~
Opens `path` with the system default handler (macOS `open`, Windows
`explorer.exe`, Linux `xdg-open`, …). If the variable |g:Openprg| exists the
string specified in the variable is used instead.
NOTE: Escaping of the path is automatically applied.
Usage: >vim
:call dist#vim9#Open(<path>)
:Open <path>
<
*dist#vim9#Launch()* *:Launch*
dist#vim9#Launch(file: string) ~
Launches <args> with the appropriate system programs. Intended for launching
GUI programs within Vim.
NOTE: escaping of <args> is left to the user
Examples: >vim
vim9script
import autoload 'dist/vim9.vim'
# Execute 'makeprg' into another xterm window
vim9.Launch('xterm ' .. expandcmd(&makeprg))
<
Usage: >vim
:call dist#vim9#Launch(<args>)
:Launch <app> <args>.
<
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -803,8 +803,6 @@ tag char note action in Normal mode ~
|gu| gu{motion} 2 make Nmove text lowercase
|gv| gv reselect the previous Visual area
|gw| gw{motion} 2 format Nmove text and keep cursor
|netrw-gx| gx execute application for file name under the
cursor (only with |netrw| plugin)
|g@| g@{motion} call 'operatorfunc'
|g~| g~{motion} 2 swap case for Nmove text
|g<Down>| g<Down> 1 same as "gj"

View File

@ -2133,7 +2133,7 @@ $quote eval.txt /*$quote*
:LP pi_logipat.txt /*:LP*
:LPE pi_logipat.txt /*:LPE*
:LPF pi_logipat.txt /*:LPF*
:Launch pi_netrw.txt /*:Launch*
:Launch eval.txt /*:Launch*
:Lexplore pi_netrw.txt /*:Lexplore*
:Lfilter quickfix.txt /*:Lfilter*
:LogiPat pi_logipat.txt /*:LogiPat*
@ -2151,7 +2151,7 @@ $quote eval.txt /*$quote*
:Ntree pi_netrw.txt /*:Ntree*
:Nw pi_netrw.txt /*:Nw*
:Nwrite pi_netrw.txt /*:Nwrite*
:Open pi_netrw.txt /*:Open*
:Open eval.txt /*:Open*
:Over terminal.txt /*:Over*
:P various.txt /*:P*
:Pexplore pi_netrw.txt /*:Pexplore*
@ -6879,6 +6879,8 @@ disable-menus gui.txt /*disable-menus*
discard editing.txt /*discard*
dist#vim eval.txt /*dist#vim*
dist#vim9 eval.txt /*dist#vim9*
dist#vim9#Launch() eval.txt /*dist#vim9#Launch()*
dist#vim9#Open() eval.txt /*dist#vim9#Open()*
distribute-script usr_51.txt /*distribute-script*
distributed-plugins usr_05.txt /*distributed-plugins*
distribution intro.txt /*distribution*
@ -7527,6 +7529,7 @@ g:NetrwTopLvlMenu pi_netrw.txt /*g:NetrwTopLvlMenu*
g:Netrw_UserMaps pi_netrw.txt /*g:Netrw_UserMaps*
g:Netrw_corehandler pi_netrw.txt /*g:Netrw_corehandler*
g:Netrw_funcref pi_netrw.txt /*g:Netrw_funcref*
g:Openprg eval.txt /*g:Openprg*
g:actual_curbuf options.txt /*g:actual_curbuf*
g:actual_curwin options.txt /*g:actual_curwin*
g:ada#Comment ft_ada.txt /*g:ada#Comment*
@ -7630,8 +7633,6 @@ g:netrw_altv pi_netrw.txt /*g:netrw_altv*
g:netrw_banner pi_netrw.txt /*g:netrw_banner*
g:netrw_bannerbackslash pi_netrw.txt /*g:netrw_bannerbackslash*
g:netrw_browse_split pi_netrw.txt /*g:netrw_browse_split*
g:netrw_browsex_support_remote pi_netrw.txt /*g:netrw_browsex_support_remote*
g:netrw_browsex_viewer pi_netrw.txt /*g:netrw_browsex_viewer*
g:netrw_bufsettings pi_netrw.txt /*g:netrw_bufsettings*
g:netrw_chgperm pi_netrw.txt /*g:netrw_chgperm*
g:netrw_chgwin pi_netrw.txt /*g:netrw_chgwin*
@ -7660,7 +7661,6 @@ g:netrw_ftp_timelist_cmd pi_netrw.txt /*g:netrw_ftp_timelist_cmd*
g:netrw_ftpextracmd pi_netrw.txt /*g:netrw_ftpextracmd*
g:netrw_ftpmode pi_netrw.txt /*g:netrw_ftpmode*
g:netrw_glob_escape pi_netrw.txt /*g:netrw_glob_escape*
g:netrw_gx pi_netrw.txt /*g:netrw_gx*
g:netrw_hide pi_netrw.txt /*g:netrw_hide*
g:netrw_home pi_netrw.txt /*g:netrw_home*
g:netrw_http_cmd pi_netrw.txt /*g:netrw_http_cmd*
@ -7686,7 +7686,6 @@ g:netrw_menu pi_netrw.txt /*g:netrw_menu*
g:netrw_mkdir_cmd pi_netrw.txt /*g:netrw_mkdir_cmd*
g:netrw_mousemaps pi_netrw.txt /*g:netrw_mousemaps*
g:netrw_nobeval pi_netrw.txt /*g:netrw_nobeval*
g:netrw_nogx pi_netrw.txt /*g:netrw_nogx*
g:netrw_preview pi_netrw.txt /*g:netrw_preview*
g:netrw_rcp_cmd pi_netrw.txt /*g:netrw_rcp_cmd*
g:netrw_remote_mkdir pi_netrw.txt /*g:netrw_remote_mkdir*
@ -9031,8 +9030,6 @@ netrw-gitignore pi_netrw.txt /*netrw-gitignore*
netrw-gn pi_netrw.txt /*netrw-gn*
netrw-gp pi_netrw.txt /*netrw-gp*
netrw-grep pi_netrw.txt /*netrw-grep*
netrw-gx pi_netrw.txt /*netrw-gx*
netrw-handler pi_netrw.txt /*netrw-handler*
netrw-help pi_netrw.txt /*netrw-help*
netrw-hexplore pi_netrw.txt /*netrw-hexplore*
netrw-hide pi_netrw.txt /*netrw-hide*
@ -9161,7 +9158,6 @@ netrw-vexplore pi_netrw.txt /*netrw-vexplore*
netrw-windows-netrc pi_netrw.txt /*netrw-windows-netrc*
netrw-windows-s pi_netrw.txt /*netrw-windows-s*
netrw-write pi_netrw.txt /*netrw-write*
netrw-x pi_netrw.txt /*netrw-x*
netrw-xfer pi_netrw.txt /*netrw-xfer*
netrw.txt pi_netrw.txt /*netrw.txt*
netrw.vim pi_netrw.txt /*netrw.vim*

View File

@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2025 Jan 23
*version9.txt* For Vim version 9.1. Last change: 2025 Jan 25
VIM REFERENCE MANUAL by Bram Moolenaar
@ -41626,6 +41626,8 @@ Changed~
- |v:stacktrace| The stack trace of the exception most recently caught and
not finished
- New option value "nosort" for 'completeopt'
- add |dist#vim9#Launch()| and |dist#vim9#Open()| to the |vim-script-library|
and decouple it from |netrw|
*added-9.2*
Added ~

View File

@ -403,9 +403,6 @@ settings are described below, in |netrw-browser-options|, and in
*g:netrw_menu* =0 disable netrw's menu
=1 (default) netrw's menu enabled
*g:netrw_nogx* if this variable exists, then the "gx" map will not
be available (see |netrw-gx|)
*g:netrw_uid* (ftp) user-id, retained on a per-vim-session basis
*s:netrw_passwd* (ftp) password, retained on a per-vim-session basis
@ -1113,7 +1110,7 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
U Change to subsequently-visited directory |netrw-U|
v Enter the file/directory under the cursor in a new |netrw-v|
browser window. A vertical split is used.
x View file with an associated program |netrw-x|
x View file with an associated program. (see |:Open|)
X Execute filename under cursor via |system()| |netrw-X|
% Open a new file in netrw's current directory |netrw-%|
@ -1466,106 +1463,6 @@ 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.
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:
* 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.
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.
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
return ''
finally
call winrestview(save_view)
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
return ''
finally
call winrestview(save_view)
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.
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
@ -2585,14 +2482,6 @@ your browsing preferences. (see also: |netrw-settings|)
|netrw-C| |netrw-cr|
|netrw-ctrl-r|
*g:netrw_browsex_viewer* specify user's preference for a viewer: >
"kfmclient exec"
"gnome-open"
<
*g:netrw_browsex_support_remote*
specify if the specified viewer supports a
remote URL. (see |netrw-handler|).
*g:netrw_chgperm* Unix/Linux: "chmod PERM FILENAME"
Windows: "cacls FILENAME /e /p PERM"
Used to change access permission for a file.
@ -2615,12 +2504,11 @@ your browsing preferences. (see also: |netrw-settings|)
*g:Netrw_corehandler* Allows one to specify something additional
to do when handling <core> files via netrw's
browser's "x" command (see |netrw-x|). If
present, g:Netrw_corehandler specifies
either one or more function references
(see |Funcref|). (the capital g:Netrw...
is required its holding a function reference)
browser's "x" command. If present,
g:Netrw_corehandler specifies either one or
more function references (see |Funcref|).
(the capital g:Netrw... is required its
holding a function reference)
*g:netrw_ctags* ="ctags"
The default external program used to create
@ -2769,11 +2657,6 @@ your browsing preferences. (see also: |netrw-settings|)
These characters in directory names are
escaped before applying glob()
*g:netrw_gx* ="<cfile>"
This option controls how gx (|netrw-gx|) picks
up the text under the cursor. See |expand()|
for possibilities.
*g:netrw_hide* Controlled by the "a" map (see |netrw-a|)
=0 : show all
=1 : show not-hidden files

View File

@ -20,12 +20,6 @@ let g:loaded_netrwPlugin = "v175"
let s:keepcpo = &cpo
set cpo&vim
" Commands Launch/URL: {{{
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: {{{
augroup FileExplorer
@ -85,21 +79,6 @@ command! -bang NetrwClean call netrw#Clean(<bang>0)
" }}}
" Maps: {{{
if !exists("g:netrw_nogx")
if maparg('gx','n') == ""
if !hasmapto('<Plug>NetrwBrowseX')
nmap <unique> gx <Plug>NetrwBrowseX
endif
nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(netrw#GX(),netrw#CheckIfRemote(netrw#GX()))<cr>
endif
if maparg('gx','x') == ""
if !hasmapto('<Plug>NetrwBrowseXVis')
xmap <unique> gx <Plug>NetrwBrowseXVis
endif
xno <silent> <Plug>NetrwBrowseXVis :<c-u>call netrw#BrowseXVis()<cr>
endif
endif
if exists("g:netrw_usetab") && g:netrw_usetab
if maparg('<c-tab>','n') == ""
nmap <unique> <c-tab> <Plug>NetrwShrink

View File

@ -0,0 +1,24 @@
vim9script
# Vim runtime support library
#
# Maintainer: The Vim Project <https://github.com/vim/vim>
# Last Change: 2025 Jan 24
import autoload 'dist/vim9.vim'
command -complete=shellcmd -nargs=1 Launch vim9.Launch(trim(<q-args>))
command -complete=file -nargs=1 Open vim9.Open(trim(<q-args>))
const no_gx = get(g:, "nogx", get(g:, "netrw_nogx", false))
if !no_gx
if maparg('gx', 'n') == ""
const file = get(g:, 'netrw_gx', '<cfile>')
nnoremap <unique> gx <scriptcmd>vim9.Open(expand(file))<CR>
endif
if maparg('gx', 'x') == ""
xnoremap <unique> gx <scriptcmd>vim9.Open(getregion(getpos('v'), getpos('.'), { type: mode() })->join())<CR>
endif
endif
# vim: ts=8 sts=2 sw=2 et