vim-patch:a2d87ba: runtime(netrw): Use right file system commands initialization for Windows

closes: vim/vim#19287
fixes:  vim/vim#12290

a2d87ba615

Co-authored-by: Miguel Barro <miguel.barro@live.com>
This commit is contained in:
zeertzjq
2026-02-16 06:31:16 +08:00
parent fd2ea27425
commit ed12d56163
3 changed files with 561 additions and 164 deletions

View File

@@ -18,6 +18,7 @@
" 2025 Nov 28 by Vim Project fix undefined variable in *NetrwMenu #18829
" 2025 Dec 26 by Vim Project fix use of g:netrw_cygwin #19015
" 2026 Jan 19 by Vim Project do not create swapfiles #18854
" 2026 Feb 15 by Vim Project fix global variable initialization for MS-Windows #19287
" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
@@ -265,8 +266,8 @@ if !exists("g:netrw_localcopycmd")
let g:netrw_localcopycmdopt = ''
if has("win32") && !g:netrw_cygwin
let g:netrw_localcopycmd = expand("$COMSPEC", v:true)
let g:netrw_localcopycmdopt = '/c copy'
let g:netrw_localcopycmd = $COMSPEC
let g:netrw_localcopycmdopt = ' /c copy'
endif
endif
@@ -275,30 +276,31 @@ if !exists("g:netrw_localcopydircmd")
let g:netrw_localcopydircmdopt = '-R'
if has("win32") && !g:netrw_cygwin
let g:netrw_localcopydircmd = "cp"
call s:NetrwInit("g:netrw_localcopydircmdopt", "-R")
let g:netrw_localcopydircmd = "xcopy"
let g:netrw_localcopydircmdopt = " /E /I /H /C /Y"
endif
endif
if has("win32")
if g:netrw_cygwin
call s:NetrwInit("g:netrw_localmkdir","mkdir")
if !exists("g:netrw_localmkdir")
if has("win32")
if g:netrw_cygwin
let g:netrw_localmkdir= "mkdir"
else
let g:netrw_localmkdir = $COMSPEC
let g:netrw_localmkdiropt= " /c mkdir"
endif
else
call s:NetrwInit("g:netrw_localmkdir",expand("$COMSPEC", v:true))
call s:NetrwInit("g:netrw_localmkdiropt"," /c mkdir")
let g:netrw_localmkdir= "mkdir"
endif
else
call s:NetrwInit("g:netrw_localmkdir","mkdir")
endif
call s:NetrwInit("g:netrw_remote_mkdir","mkdir")
if !exists("g:netrw_localmovecmd")
if has("win32")
if g:netrw_cygwin
let g:netrw_localmovecmd= "mv"
else
let g:netrw_localmovecmd = expand("$COMSPEC", v:true)
call s:NetrwInit("g:netrw_localmovecmdopt"," /c move")
let g:netrw_localmovecmd = $COMSPEC
let g:netrw_localmovecmdopt= " /c move"
endif
elseif has("unix") || has("macunix")
let g:netrw_localmovecmd= "mv"
@@ -980,7 +982,7 @@ function netrw#Obtain(islocal,fname,...)
" obtain a file from local b:netrw_curdir to (local) tgtdir
if exists("b:netrw_curdir") && getcwd() != b:netrw_curdir
let topath = netrw#fs#ComposePath(tgtdir,"")
if has("win32")
if has("win32") && !g:netrw_cygwin
" transfer files one at time
for fname in fnamelist
call system(g:netrw_localcopycmd.g:netrw_localcopycmdopt." ".netrw#os#Escape(fname)." ".netrw#os#Escape(topath))
@@ -4735,38 +4737,16 @@ function s:NetrwMakeDir(usrhost)
" requested new local directory is neither a pre-existing file or
" directory, so make it!
if exists("*mkdir")
if has("unix")
call mkdir(fullnewdir,"p",xor(0777, system("umask")))
else
call mkdir(fullnewdir,"p")
endif
if has("unix")
call mkdir(fullnewdir,"p",xor(0777, system("umask")))
else
let netrw_origdir= netrw#fs#Cwd(1)
if s:NetrwLcd(b:netrw_curdir)
return
endif
call netrw#os#Execute("sil! !".g:netrw_localmkdir.g:netrw_localmkdiropt.' '.netrw#os#Escape(newdirname,1))
if v:shell_error != 0
let @@= ykeep
call netrw#msg#Notify('ERROR', printf('consider setting g:netrw_localmkdir<%s> to something that works', g:netrw_localmkdir))
return
endif
if !g:netrw_keepdir
if s:NetrwLcd(netrw_origdir)
return
endif
endif
call mkdir(fullnewdir,"p")
endif
if v:shell_error == 0
" refresh listing
let svpos= winsaveview()
call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
call winrestview(svpos)
else
call netrw#msg#Notify('ERROR', printf('unable to make directory<%s>', newdirname))
endif
" on success refresh listing
let svpos= winsaveview()
call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./',0))
call winrestview(svpos)
elseif !exists("b:netrw_method") || b:netrw_method == 4
" Remote mkdir: using ssh
@@ -5350,17 +5330,14 @@ function s:NetrwMarkFileCopy(islocal,...)
let curdir = s:NetrwGetCurdir(a:islocal)
let curbufnr = bufnr("%")
if b:netrw_curdir !~ '/$'
if !exists("b:netrw_curdir")
let b:netrw_curdir= curdir
endif
let b:netrw_curdir= b:netrw_curdir."/"
if !exists("b:netrw_curdir")
let b:netrw_curdir= curdir
endif
" sanity check
if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
call netrw#msg#Notify('ERROR', 'there are no marked files in this window (:help netrw-mf)')
return
return 0
endif
if !exists("s:netrwmftgt")
@@ -5368,7 +5345,7 @@ function s:NetrwMarkFileCopy(islocal,...)
return 0
endif
if a:islocal && s:netrwmftgt_islocal
if a:islocal && s:netrwmftgt_islocal
" Copy marked files, local directory to local directory
if !executable(g:netrw_localcopycmd)
call netrw#msg#Notify('ERROR', printf('g:netrw_localcopycmd<%s> not executable on your system, aborting', g:netrw_localcopycmd))
@@ -5376,69 +5353,85 @@ function s:NetrwMarkFileCopy(islocal,...)
endif
" copy marked files while within the same directory (ie. allow renaming)
if simplify(s:netrwmftgt) ==# simplify(b:netrw_curdir)
if len(s:netrwmarkfilelist_{bufnr('%')}) == 1
" only one marked file
let args = netrw#os#Escape(b:netrw_curdir.s:netrwmarkfilelist_{bufnr('%')}[0])
let oldname = s:netrwmarkfilelist_{bufnr('%')}[0]
elseif a:0 == 1
" this happens when the next case was used to recursively call s:NetrwMarkFileCopy()
let args = netrw#os#Escape(b:netrw_curdir.a:1)
let oldname = a:1
else
" copy multiple marked files inside the same directory
let s:recursive= 1
for oldname in s:netrwmarkfilelist_{bufnr("%")}
let ret= s:NetrwMarkFileCopy(a:islocal,oldname)
if ret == 0
break
endif
endfor
unlet s:recursive
call s:NetrwUnmarkList(curbufnr,curdir)
return ret
endif
if simplify(s:netrwmftgt."/") ==# simplify(b:netrw_curdir."/")
" copy multiple marked files inside the same directory
for oldname in s:netrwmarkfilelist_{curbufnr}
call inputsave()
let newname= input(printf("Copy %s to: ", oldname), oldname, 'file')
call inputrestore()
call inputsave()
let newname= input(printf("Copy %s to: ", oldname), oldname, 'file')
call inputrestore()
if empty(newname)
return 0
endif
if empty(newname)
return 0
endif
let tgt = netrw#fs#ComposePath(s:netrwmftgt, newname)
let oldname = netrw#fs#ComposePath(b:netrw_curdir, oldname)
if tgt ==# oldname
continue
endif
let args = netrw#os#Escape(oldname)
let tgt = netrw#os#Escape(s:netrwmftgt.'/'.newname)
let ret = filecopy(oldname, tgt)
if ret == v:false
call netrw#msg#Notify('ERROR', $'copy failed, unable to filecopy() <{oldname}> to <{tgt}>')
break
endif
endfor
call s:NetrwUnmarkList(curbufnr,curdir)
NetrwKeepj call s:NetrwRefreshDir(a:islocal, b:netrw_curdir)
return ret
else
let args = join(map(deepcopy(s:netrwmarkfilelist_{bufnr('%')}),"netrw#os#Escape(b:netrw_curdir.\"/\".v:val)"))
let tgt = netrw#os#Escape(s:netrwmftgt)
let args = []
for arg in s:netrwmarkfilelist_{curbufnr}
call add(args, netrw#fs#ComposePath(b:netrw_curdir, arg))
endfor
let tgt = s:netrwmftgt
endif
if !g:netrw_cygwin && has("win32")
let args = substitute(args,'/','\\','g')
let tgt = substitute(tgt, '/','\\','g')
endif
if args =~ "'" |let args= substitute(args,"'\\(.*\\)'",'\1','')|endif
if tgt =~ "'" |let tgt = substitute(tgt ,"'\\(.*\\)'",'\1','')|endif
if args =~ '//'|let args= substitute(args,'//','/','g')|endif
if tgt =~ '//'|let tgt = substitute(tgt ,'//','/','g')|endif
let copycmd = g:netrw_localcopycmd
let copycmdopt = g:netrw_localcopycmdopt
if isdirectory(s:NetrwFile(args))
" on Windows, no builtin command supports copying multiple files at once
" (powershell's Copy-Item cmdlet does but requires , as file separator)
if len(s:netrwmarkfilelist_{curbufnr}) > 1 && has("win32") && !g:netrw_cygwin
" copy multiple marked files
for file in args
let dest = netrw#fs#ComposePath(tgt, fnamemodify(file, ':t'))
let ret = filecopy(file, dest)
if ret == v:false
call netrw#msg#Notify('ERROR', $'copy failed, unable to filecopy() <{file}> to <{dest}>')
break
endif
endfor
call s:NetrwUnmarkList(curbufnr,curdir)
NetrwKeepj call s:NetrwRefreshDir(a:islocal, b:netrw_curdir)
return ret
endif
if len(args) == 1 && isdirectory(s:NetrwFile(args[0]))
let copycmd = g:netrw_localcopydircmd
let copycmdopt = g:netrw_localcopydircmdopt
if has('win32') && !g:netrw_cygwin
if has('win32') && g:netrw_localcopydircmd == "xcopy"
" window's xcopy doesn't copy a directory to a target properly. Instead, it copies a directory's
" contents to a target. One must append the source directory name to the target to get xcopy to
" do the right thing.
let tgt= tgt.'\'.substitute(a:1,'^.*[\\/]','','')
let tgt = netrw#fs#ComposePath(tgt, fnamemodify(simplify(netrw#fs#PathJoin(args[0],".")),":t"))
endif
endif
call system(printf("%s %s '%s' '%s'", copycmd, copycmdopt, args, tgt))
" prepare arguments for shell call
let args = join(map(args,'netrw#os#Escape(v:val)'))
let tgt = netrw#os#Escape(tgt)
" enforce noshellslash for system calls
if exists('+shellslash') && &shellslash
for var in ['copycmd', 'args', 'tgt']
let {var} = substitute({var}, '/', '\', 'g')
endfor
endif
" shell call
let shell_cmd = printf("%s %s %s %s", copycmd, copycmdopt, args, tgt)
call system(shell_cmd)
if v:shell_error != 0
if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && g:netrw_keepdir
call netrw#msg#Notify('ERROR', printf("copy failed; perhaps due to vim's current directory<%s> not matching netrw's (%s) (see :help netrw-cd)", getcwd(), b:netrw_curdir))
@@ -5450,11 +5443,11 @@ function s:NetrwMarkFileCopy(islocal,...)
elseif a:islocal && !s:netrwmftgt_islocal
" Copy marked files, local directory to remote directory
NetrwKeepj call s:NetrwUpload(s:netrwmarkfilelist_{bufnr('%')},s:netrwmftgt)
NetrwKeepj call s:NetrwUpload(s:netrwmarkfilelist_{curbufnr},s:netrwmftgt)
elseif !a:islocal && s:netrwmftgt_islocal
" Copy marked files, remote directory to local directory
NetrwKeepj call netrw#Obtain(a:islocal,s:netrwmarkfilelist_{bufnr('%')},s:netrwmftgt)
NetrwKeepj call netrw#Obtain(a:islocal,s:netrwmarkfilelist_{curbufnr},s:netrwmftgt)
elseif !a:islocal && !s:netrwmftgt_islocal
" Copy marked files, remote directory to remote directory
@@ -5463,24 +5456,16 @@ function s:NetrwMarkFileCopy(islocal,...)
if tmpdir !~ '/'
let tmpdir= curdir."/".tmpdir
endif
if exists("*mkdir")
call mkdir(tmpdir)
else
call netrw#os#Execute("sil! !".g:netrw_localmkdir.g:netrw_localmkdiropt.' '.netrw#os#Escape(tmpdir,1))
if v:shell_error != 0
call netrw#msg#Notify('WARNING', printf("consider setting g:netrw_localmkdir<%s> to something that works", g:netrw_localmkdir))
return
endif
endif
call mkdir(tmpdir)
if isdirectory(s:NetrwFile(tmpdir))
if s:NetrwLcd(tmpdir)
return
endif
NetrwKeepj call netrw#Obtain(a:islocal,s:netrwmarkfilelist_{bufnr('%')},tmpdir)
let localfiles= map(deepcopy(s:netrwmarkfilelist_{bufnr('%')}),'substitute(v:val,"^.*/","","")')
NetrwKeepj call netrw#Obtain(a:islocal,s:netrwmarkfilelist_{curbufnr},tmpdir)
let localfiles= map(deepcopy(s:netrwmarkfilelist_{curbufnr}),'substitute(v:val,"^.*/","","")')
NetrwKeepj call s:NetrwUpload(localfiles,s:netrwmftgt)
if getcwd() == tmpdir
for fname in s:netrwmarkfilelist_{bufnr('%')}
for fname in s:netrwmarkfilelist_{curbufnr}
call netrw#fs#Remove(fname)
endfor
if s:NetrwLcd(curdir)
@@ -5502,18 +5487,13 @@ function s:NetrwMarkFileCopy(islocal,...)
" -------
" remove markings from local buffer
call s:NetrwUnmarkList(curbufnr,curdir) " remove markings from local buffer
if exists("s:recursive")
else
endif
" see s:LocalFastBrowser() for g:netrw_fastbrowse interpretation (refreshing done for both slow and medium)
if g:netrw_fastbrowse <= 1
NetrwKeepj call s:LocalBrowseRefresh()
else
" refresh local and targets for fast browsing
if !exists("s:recursive")
" remove markings from local buffer
NetrwKeepj call s:NetrwUnmarkList(curbufnr,curdir)
endif
" remove markings from local buffer
NetrwKeepj call s:NetrwUnmarkList(curbufnr,curdir)
" refresh buffers
if s:netrwmftgt_islocal
@@ -5882,28 +5862,35 @@ function s:NetrwMarkFileMove(islocal)
call netrw#msg#Notify('ERROR', printf('g:netrw_localmovecmd<%s> not executable on your system, aborting', g:netrw_localmovecmd))
return
endif
let tgt = netrw#os#Escape(s:netrwmftgt)
if !g:netrw_cygwin && has("win32")
let tgt= substitute(tgt, '/','\\','g')
if g:netrw_localmovecmd =~ '\s'
let movecmd = substitute(g:netrw_localmovecmd,'\s.*$','','')
let movecmdargs = substitute(g:netrw_localmovecmd,'^.\{-}\(\s.*\)$','\1','')
let movecmd = netrw#fs#WinPath(movecmd).movecmdargs
else
let movecmd = netrw#fs#WinPath(g:netrw_localmovecmd)
endif
if has("win32") && !g:netrw_cygwin && g:netrw_localmovecmd =~ '\s' && g:netrw_localmovecmdopt == ""
let movecmd = substitute(g:netrw_localmovecmd,'\s.*$','','')
let movecmdargs = substitute(g:netrw_localmovecmd,'^.\{-}\(\s.*\)$','\1','')
else
let movecmd = netrw#fs#WinPath(g:netrw_localmovecmd)
let movecmd = g:netrw_localmovecmd
let movecmdargs = g:netrw_localmovecmdopt
endif
for fname in s:netrwmarkfilelist_{bufnr("%")}
" build args list
let args = []
for fname in s:netrwmarkfilelist_{curbufnr}
if g:netrw_keepdir
" Jul 19, 2022: fixing file move when g:netrw_keepdir is 1
let fname= b:netrw_curdir."/".fname
let fname= netrw#fs#ComposePath(b:netrw_curdir, fname)
endif
if !g:netrw_cygwin && has("win32")
let fname= substitute(fname,'/','\\','g')
endif
let ret= system(movecmd.g:netrw_localmovecmdopt." ".netrw#os#Escape(fname)." ".tgt)
call add(args, netrw#os#Escape(fname))
endfor
" enforce noshellslash for system calls
if exists('+shellslash') && &shellslash
let tgt = substitute(tgt, '/', '\', 'g')
call map(args, "substitute(v:val, '/', '\\', 'g')")
endif
for fname in args
let shell_cmd = printf("%s %s %s %s", movecmd, movecmdargs, fname, tgt)
let ret= system(shell_cmd)
if v:shell_error != 0
if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && !g:netrw_keepdir
call netrw#msg#Notify('ERROR', printf("move failed; perhaps due to vim's current directory<%s> not matching netrw's (%s) (see :help netrw-cd)", getcwd(), b:netrw_curdir))
@@ -5916,7 +5903,7 @@ function s:NetrwMarkFileMove(islocal)
elseif a:islocal && !s:netrwmftgt_islocal
" move: local -> remote
let mflist= s:netrwmarkfilelist_{bufnr("%")}
let mflist= s:netrwmarkfilelist_{curbufnr}
NetrwKeepj call s:NetrwMarkFileCopy(a:islocal)
for fname in mflist
let barefname = substitute(fname,'^\(.*/\)\(.\{-}\)$','\2','')
@@ -5926,7 +5913,7 @@ function s:NetrwMarkFileMove(islocal)
elseif !a:islocal && s:netrwmftgt_islocal
" move: remote -> local
let mflist= s:netrwmarkfilelist_{bufnr("%")}
let mflist= s:netrwmarkfilelist_{curbufnr}
NetrwKeepj call s:NetrwMarkFileCopy(a:islocal)
for fname in mflist
let barefname = substitute(fname,'^\(.*/\)\(.\{-}\)$','\2','')
@@ -5936,7 +5923,7 @@ function s:NetrwMarkFileMove(islocal)
elseif !a:islocal && !s:netrwmftgt_islocal
" move: remote -> remote
let mflist= s:netrwmarkfilelist_{bufnr("%")}
let mflist= s:netrwmarkfilelist_{curbufnr}
NetrwKeepj call s:NetrwMarkFileCopy(a:islocal)
for fname in mflist
let barefname = substitute(fname,'^\(.*/\)\(.\{-}\)$','\2','')

View File

@@ -24,6 +24,7 @@ endfunction
" netrw#fs#ComposePath: Appends a new part to a path taking different systems into consideration {{{
function! netrw#fs#ComposePath(base, subdir)
const slash = !exists('+shellslash') || &shellslash ? '/' : '\'
if has('amiga')
let ec = a:base[strdisplaywidth(a:base)-1]
if ec != '/' && ec != ':'
@@ -40,7 +41,7 @@ function! netrw#fs#ComposePath(base, subdir)
if a:base =~ '[/\\]$'
let ret = a:base . a:subdir
else
let ret = a:base . '/' . a:subdir
let ret = a:base . slash . a:subdir
endif
elseif a:base =~ '^\a\{3,}://'

View File

@@ -1,32 +1,218 @@
let s:netrw_path = $VIMRUNTIME . '/pack/dist/opt/netrw/autoload/netrw.vim'
let s:netrw_test_dir = 'samples'
let s:netrw_test_path = s:netrw_test_dir . '/netrw.vim'
const s:testdir = expand("<script>:h")
const s:runtimedir = simplify(s:testdir . '/../../../runtime')
const s:netrw_path = s:runtimedir . '/pack/dist/opt/netrw/autoload/netrw.vim'
const s:netrw_test_path = s:testdir . '/samples/netrw.vim'
const s:testScript =<< trim END
" Testing functions: {{{1
function! TestNetrwCaptureRemotePath(dirname)
call s:RemotePathAnalysis(a:dirname)
return {"method": s:method, "user": s:user, "machine": s:machine, "port": s:port, "path": s:path, "fname": s:fname}
endfunction
" Test directory creation via s:NetrwMakeDir()
" Precondition: inputsave() and inputrestore() must be disabled in s:NetrwMakeDir
function s:test_inputsave()
if exists("s:inputguards_disabled") && s:inputguards_disabled
return
endif
call inputsave()
endfunction
function s:test_inputrestore()
if exists("s:inputguards_disabled") && s:inputguards_disabled
return
endif
call inputrestore()
endfunction
function s:test_input(prompt, text = v:null, completion = v:null) " Nvim: use v:null instead of v:none
if exists("s:inputdefaults_disabled") && s:inputdefaults_disabled || a:text == v:null
return input(a:prompt)
elseif a:completion == v:null
return input(a:prompt, a:text)
endif
return input(a:prompt, a:text, a:completion)
endfunction
function Test_NetrwMakeDir(parentdir = $HOME, dirname = "NetrwMakeDir", symlink = 0) abort
if a:symlink
" Plainly delegate, this device is necessary because feedkeys() can't
" access script functions directly.
call s:NetrwMakeDir('')
" wipe out the test buffer
bw
" reenable the guards
let s:inputguards_disabled = 0
else
" Use feedkeys() to simulate user input (directory name)
new
let b:netrw_curdir = a:parentdir
let s:inputguards_disabled = 1
call feedkeys($"\<Cmd>call Test_NetrwMakeDir('{a:parentdir}', '{a:dirname}', 1)\<CR>{a:dirname}\<CR>", "x")
endif
endfunction
" Test file copy operations via s:NetrwMarkFileCopy()
function Test_NetrwMarkFileCopy(source_dir, target_dir, marked_files) abort
" set up
new
let b:netrw_curdir= a:source_dir
let s:netrwmftgt = a:target_dir
let s:netrwmarkfilelist_{bufnr("%")} = a:marked_files
let s:netrwmftgt_islocal = 1
" delegate
call s:NetrwMarkFileCopy(1)
" wipe out the test buffer
bw
endfunction
" Corner case: copy into the same dir triggers a user prompt
function Test_NetrwMarkFileCopy_SameDir(dir = $HOME, symlink = 0) abort
const filename = "filename.txt"
const file = netrw#fs#PathJoin(a:dir, filename)
const newfilename = "newfilename.txt"
const newfile = netrw#fs#PathJoin(a:dir, newfilename)
if a:symlink
" Plainly delegate, this device is necessary because feedkeys() can't
" access script functions directly.
" set up
new
let b:netrw_curdir = a:dir
let s:netrwmftgt = a:dir
let s:netrwmarkfilelist_{bufnr("%")} = [filename]
let s:netrwmftgt_islocal = 1
" delegate
call s:NetrwMarkFileCopy(1)
" validate
call assert_equalfile(file, newfile, "File copy in same dir failed")
" tear down
call delete(file)
call delete(newfile)
" wipe out the test buffer
bw
" reenable the guards
let s:inputguards_disabled = 0
let s:inputdefaults_disabled = 0
else
" Use feedkeys() to simulate user input (directory name)
let s:inputguards_disabled = 1
let s:inputdefaults_disabled = 1
call writefile([$"NetrwMarkFileCopy test file"], file)
call feedkeys($"\<Cmd>call Test_NetrwMarkFileCopy_SameDir('{a:dir}', 1)\<CR>{newfilename}\<CR>", "x")
endif
endfunction
" Test file copy operations via s:NetrwMarkFileMove()
function Test_NetrwMarkFileMove(source_dir, target_dir, marked_files) abort
" set up
new
let b:netrw_curdir= a:source_dir
let s:netrwmftgt = a:target_dir
let s:netrwmarkfilelist_{bufnr("%")} = a:marked_files
let s:netrwmftgt_islocal = 1
" delegate
call s:NetrwMarkFileMove(1)
" wipe out the test buffer
bw
endfunction
" }}}
END
"make copy of netrw script and add function to print local variables"
func s:appendDebugToNetrw(netrw_path, netrw_test_path)
let netrwScript = readfile(a:netrw_path)
let netrwScript += [
\ '\n',
\ '"-- test helpers ---"',
\ 'function! TestNetrwCaptureRemotePath(dirname)',
\ ' call s:RemotePathAnalysis(a:dirname)',
\ ' return {"method": s:method, "user": s:user, "machine": s:machine, "port": s:port, "path": s:path, "fname": s:fname}',
\ 'endfunction'
\ ]
" load the netrw script
execute "split" a:netrw_test_path
execute "read" a:netrw_path
" replace input guards for convenient testing versions
%substitute@call inputsave()@call s:test_inputsave()@g
%substitute@call inputrestore()@call s:test_inputrestore()@g
%substitute@\<input(@s:test_input(@g
call cursor(1,1)
let pos = search("Settings Restoration:")-1
" insert the test functions before the end guard
call assert_false(append(pos, s:testScript))
" save the modified script content
write
bwipe!
call writefile(netrwScript, a:netrw_test_path)
execute 'source' a:netrw_test_path
endfunction
func s:setup()
func SetUp()
" prepare modified netrw script
call s:appendDebugToNetrw(s:netrw_path, s:netrw_test_path)
" source the modified script
exe "source" s:netrw_test_path
" Rig the package. The modified script guard prevents loading it again.
let &runtimepath=s:runtimedir
let &packpath=s:runtimedir
packadd netrw
" use proper path
if has('win32')
let $HOME = substitute($HOME, '/', '\\', 'g')
endif
endfunction
func s:cleanup()
func TearDown()
" cleanup
call delete(s:netrw_test_path)
endfunction
func SetShell(shell)
" select different shells
if a:shell == "default"
set shell& shellcmdflag& shellxquote& shellpipe& shellredir&
if has("win32")
" Nvim: default 'shell' is "sh" due to $SHELL being set in Makefile,
" but here 'shell' should be cmd.exe.
set shell=cmd.exe
endif
elseif a:shell == "powershell" " help dos-powershell
" powershell desktop is windows only
if !has("win32")
throw 'Skipped: powershell desktop is missing'
endif
set shell=powershell shellcmdflag=-NoProfile\ -Command shellxquote=\"
set shellpipe=2>&1\ \|\ Out-File\ -Encoding\ default shellredir=2>&1\ \|\ Out-File\ -Encoding\ default
elseif a:shell == "pwsh" " help dos-powershell
" powershell core works crossplatform
if !executable("pwsh")
throw 'Skipped: powershell core is missing'
endif
set shell=pwsh shellcmdflag=-NoProfile\ -c shellpipe=>%s\ 2>&1 shellredir=>%s\ 2>&1
if has("win32")
set shellxquote=\"
else
set shellxquote=
endif
else
call assert_report("Trying to select an unknown shell")
endif
" Nvim: 'shellxquote' needs to be empty for the tests for work.
set shellxquote=
endfunc
func s:combine
\( usernames
\, methods
@@ -62,19 +248,16 @@ endfunction
func Test_netrw_parse_remote_simple()
call s:setup()
let result = TestNetrwCaptureRemotePath('scp://user@localhost:2222/test.txt')
call assert_equal(result.method, 'scp')
call assert_equal(result.user, 'user')
call assert_equal(result.machine, 'localhost')
call assert_equal(result.port, '2222')
call assert_equal(result.path, 'test.txt')
call s:cleanup()
endfunction
"testing different combinations"
func Test_netrw_parse_regular_usernames()
call s:setup()
" --- sample data for combinations ---"
let usernames = ["root", "toor", "user01", "skillIssue"]
@@ -86,47 +269,273 @@ func Test_netrw_parse_regular_usernames()
call s:combine(usernames, methods, hosts, ports, dirs, files)
call s:cleanup()
endfunc
"Host myserver
" HostName 192.168.1.42
" User alice
func Test_netrw_parse_ssh_config_entries()
call s:setup()
let result = TestNetrwCaptureRemotePath('scp://myserver//etc/nginx/nginx.conf')
call assert_equal(result.method, 'scp')
call assert_equal(result.user, '')
call assert_equal(result.machine, 'myserver')
call assert_equal(result.port, '')
call assert_equal(result.path, '/etc/nginx/nginx.conf')
call s:cleanup()
endfunction
"username containing special-chars"
func Test_netrw_parse_special_char_user()
call s:setup()
let result = TestNetrwCaptureRemotePath('scp://user-01@localhost:2222/test.txt')
call assert_equal(result.method, 'scp')
call assert_equal(result.user, 'user-01')
call assert_equal(result.machine, 'localhost')
call assert_equal(result.port, '2222')
call assert_equal(result.path, 'test.txt')
call s:cleanup()
endfunction
func Test_netrw_wipe_empty_buffer_fastpath()
" SetUp() may have opened some buffers
let previous = bufnr('$')
let g:netrw_fastbrowse=0
packadd netrw
call setline(1, 'foobar')
let bufnr = bufnr('%')
tabnew
Explore
call search('README.txt', 'W')
exe ":norm \<cr>"
call assert_equal(4, bufnr('$'))
call assert_equal(previous + 2, bufnr('$'))
call assert_true(bufexists(bufnr))
bw
unlet! netrw_fastbrowse
endfunction
" ---------------------------------
" Testing file management functions
" ---------------------------------
" Browser directory creation
func s:netrw_mkdir()
" create a testdir in the fake $HOME
call Test_NetrwMakeDir($HOME, "NetrwMakeDir")
" Check the test directory was created
let test_dir = netrw#fs#PathJoin($HOME, "NetrwMakeDir")
call WaitForAssert({-> assert_true(
\ isdirectory(test_dir),
\ "Unable to create a dir via s:NetrwMakeDir()")
\ })
" remove the test directory
call delete(test_dir, 'd')
endfunc
func Test_netrw_mkdir_default()
call SetShell('default')
call s:netrw_mkdir()
endfunc
func Test_netrw_mkdir_powershell()
call SetShell('powershell')
call s:netrw_mkdir()
endfunc
func Test_netrw_mkdir_pwsh()
call SetShell('pwsh')
call s:netrw_mkdir()
endfunc
func s:netrw_filecopy(count = 1)
" setup
let marked_files = []
let source_dir = netrw#fs#PathJoin($HOME, "src")
let target_dir = netrw#fs#PathJoin($HOME, "target")
call mkdir(source_dir, "R")
call mkdir(target_dir, "R")
for i in range(a:count)
call add(marked_files, $"testfile{i}.txt")
call writefile(
\ [$"NetrwMarkFileCopy test file {i}"],
\ netrw#fs#PathJoin(source_dir, marked_files[-1]))
endfor
" delegate
call Test_NetrwMarkFileCopy(source_dir, target_dir, marked_files)
" verify
for file in marked_files
call assert_equalfile(
\ netrw#fs#PathJoin(source_dir, file),
\ netrw#fs#PathJoin(target_dir, file),
\ "File copy failed for " . file)
endfor
endfunc
" Browser file copy
func s:test_netrw_filecopy()
" if shellslash is available, check both settings
if exists('+shellslash')
set shellslash&
call s:netrw_filecopy(1)
call s:netrw_filecopy(10)
set shellslash!
endif
call s:netrw_filecopy(1)
call s:netrw_filecopy(10)
endfunc
func Test_netrw_filecopy_default()
call SetShell('default')
call s:test_netrw_filecopy()
endfunc
func Test_netrw_filecopy_powershell()
call SetShell('powershell')
call s:test_netrw_filecopy()
endfunc
func Test_netrw_filecopy_pwsh()
call SetShell('pwsh')
call s:test_netrw_filecopy()
endfunc
" Browser recursive directory copy
func s:netrw_dircopy(count = 1)
" setup
let marked_dirname = "test_dir"
let marked_dir = netrw#fs#PathJoin($HOME, marked_dirname)
let target_dir = netrw#fs#PathJoin($HOME, "target")
call mkdir(marked_dir, "R")
call mkdir(target_dir, "R")
let dir_content = []
for i in range(a:count)
call add(dir_content, $"testfile{i}.txt")
call writefile(
\ [$"NetrwMarkFileCopy test dir content {i}"],
\ netrw#fs#PathJoin(marked_dir, dir_content[-1]))
endfor
" delegate
call Test_NetrwMarkFileCopy($HOME, target_dir, [marked_dirname])
" verify
for file in dir_content
call assert_equalfile(
\ netrw#fs#PathJoin(marked_dir, file),
\ netrw#fs#PathJoin(target_dir, marked_dirname, file),
\ "File copy failed for " . file)
endfor
endfunc
func s:test_netrw_dircopy()
" if shellslash is available, check both settings
if exists('+shellslash')
set shellslash&
call s:netrw_dircopy(10)
set shellslash!
endif
call s:netrw_dircopy(10)
endfunc
func Test_netrw_dircopy_default()
call SetShell('default')
call s:test_netrw_dircopy()
endfunc
func Test_netrw_dircopy_powershell()
call SetShell('powershell')
call s:test_netrw_dircopy()
endfunc
func Test_netrw_dircopy_pwsh()
call SetShell('pwsh')
call s:test_netrw_dircopy()
endfunc
" Copy file into the same directory with a different name
func Test_netrw_dircopy_rename_default()
call SetShell('default')
call Test_NetrwMarkFileCopy_SameDir()
endfunc
func Test_netrw_dircopy_rename_powershell()
call SetShell('powershell')
call Test_NetrwMarkFileCopy_SameDir()
endfunc
func Test_netrw_dircopy_rename_pwsh()
call SetShell('pwsh')
call Test_NetrwMarkFileCopy_SameDir()
endfunc
" Browser file move
func s:netrw_filemove(count = 1)
" setup
let marked_files = []
let source_dir = netrw#fs#PathJoin($HOME, "src")
let target_dir = netrw#fs#PathJoin($HOME, "target")
call mkdir(source_dir, "R")
call mkdir(target_dir, "R")
for i in range(a:count)
call add(marked_files, $"testfile{i}.txt")
call writefile(
\ [$"NetrwMarkFileMove test file {i}"],
\ netrw#fs#PathJoin(source_dir, marked_files[-1]))
endfor
" delegate
call Test_NetrwMarkFileMove(source_dir, target_dir, marked_files)
" verify
for i in range(a:count)
call assert_equal(
\ [$"NetrwMarkFileMove test file {i}"],
\ readfile(netrw#fs#PathJoin(target_dir, $"testfile{i}.txt")),
\ $"File move failed for testfile{i}.txt")
endfor
endfunc
func s:test_netrw_filemove()
" if shellslash is available, check both settings
if exists('+shellslash')
set shellslash&
call s:netrw_filemove(10)
set shellslash!
endif
call s:netrw_filemove(10)
endfunc
func Test_netrw_filemove_default()
call SetShell('default')
call s:test_netrw_filemove()
endfunc
func Test_netrw_filemove_powershell()
call SetShell('powershell')
call s:test_netrw_filemove()
endfunc
func Test_netrw_filemove_pwsh()
call SetShell('pwsh')
call s:test_netrw_filemove()
endfunc
" vim:ts=8 sts=2 sw=2 et