@@ -429,11 +429,13 @@ function Path:mkdir(opts)
429
429
local parents = F .if_nil (opts .parents , false , opts .parents )
430
430
local exists_ok = F .if_nil (opts .exists_ok , true , opts .exists_ok )
431
431
432
- if not exists_ok and self :exists () then
432
+ local exists = self :exists ()
433
+ if not exists_ok and exists then
433
434
error (" FileExistsError:" .. self :absolute ())
434
435
end
435
436
436
- if not uv .fs_mkdir (self :_fs_filename (), mode ) then
437
+ -- fs_mkdir returns nil if folder exists
438
+ if not uv .fs_mkdir (self :_fs_filename (), mode ) and not exists then
437
439
if parents then
438
440
local dirs = self :_split ()
439
441
local processed = " "
@@ -500,20 +502,77 @@ function Path:rename(opts)
500
502
return status
501
503
end
502
504
505
+ --- Copy files or folders with defaults akin to GNU's `cp`.
506
+ --- @param opts table : options to pass to toggling registered actions
507
+ --- @field destination string | Path : target file path to copy to
508
+ --- @field recursive bool : whether to copy folders recursively (default : false )
509
+ --- @field override bool : whether to override files (default : true )
510
+ --- @field interactive bool : confirm if copy would override ; precedes ` override` (default : false )
511
+ --- @field respect_gitignore bool : skip folders ignored by all detected ` gitignore` s (default : false )
512
+ --- @field hidden bool : whether to add hidden files in recursively copying folders (default : true )
513
+ --- @field parents bool : whether to create possibly non-existing parent dirs of ` opts.destination` (default : false )
514
+ --- @field exists_ok bool : whether ok if ` opts.destination` exists , if so folders are merged (default : true )
515
+ --- @return table {[Path of destination] : bool } indicating success of copy ; nested tables constitute sub dirs
503
516
function Path :copy (opts )
504
517
opts = opts or {}
518
+ opts .recursive = F .if_nil (opts .recursive , false , opts .recursive )
519
+ opts .override = F .if_nil (opts .override , true , opts .override )
505
520
521
+ local dest = opts .destination
506
522
-- handles `.`, `..`, `./`, and `../`
507
- if opts .destination :match " ^%.%.?/?\\ ?.+" then
508
- opts .destination = {
509
- uv .fs_realpath (opts .destination :sub (1 , 3 )),
510
- opts .destination :sub (4 , # opts .destination ),
523
+ if not Path .is_path (dest ) then
524
+ if type (dest ) == " string" and dest :match " ^%.%.?/?\\ ?.+" then
525
+ dest = {
526
+ uv .fs_realpath (dest :sub (1 , 3 )),
527
+ dest :sub (4 , # dest ),
528
+ }
529
+ end
530
+ dest = Path :new (dest )
531
+ end
532
+ -- success is true in case file is copied, false otherwise
533
+ local success = {}
534
+ if not self :is_dir () then
535
+ if opts .interactive and dest :exists () then
536
+ vim .ui .select (
537
+ { " Yes" , " No" },
538
+ { prompt = string.format (" Overwrite existing %s?" , dest :absolute ()) },
539
+ function (_ , idx )
540
+ success [dest ] = uv .fs_copyfile (self :absolute (), dest :absolute (), { excl = not (idx == 1 ) }) or false
541
+ end
542
+ )
543
+ else
544
+ -- nil: not overriden if `override = false`
545
+ success [dest ] = uv .fs_copyfile (self :absolute (), dest :absolute (), { excl = not opts .override }) or false
546
+ end
547
+ return success
548
+ end
549
+ -- dir
550
+ if opts .recursive then
551
+ dest :mkdir {
552
+ parents = F .if_nil (opts .parents , false , opts .parents ),
553
+ exists_ok = F .if_nil (opts .exists_ok , true , opts .exists_ok ),
511
554
}
555
+ local scan = require " plenary.scandir"
556
+ local data = scan .scan_dir (self .filename , {
557
+ respect_gitignore = F .if_nil (opts .respect_gitignore , false , opts .respect_gitignore ),
558
+ hidden = F .if_nil (opts .hidden , true , opts .hidden ),
559
+ depth = 1 ,
560
+ add_dirs = true ,
561
+ })
562
+ for _ , entry in ipairs (data ) do
563
+ local entry_path = Path :new (entry )
564
+ local suffix = table.remove (entry_path :_split ())
565
+ local new_dest = dest :joinpath (suffix )
566
+ -- clear destination as it might be Path table otherwise failing w/ extend
567
+ opts .destination = nil
568
+ local new_opts = vim .tbl_deep_extend (" force" , opts , { destination = new_dest })
569
+ -- nil: not overriden if `override = false`
570
+ success [new_dest ] = entry_path :copy (new_opts ) or false
571
+ end
572
+ return success
573
+ else
574
+ error (string.format (" Warning: %s was not copied as `recursive=false`" , self :absolute ()))
512
575
end
513
-
514
- local dest = Path :new (opts .destination )
515
-
516
- return uv .fs_copyfile (self :absolute (), dest :absolute (), { excl = true })
517
576
end
518
577
519
578
function Path :touch (opts )
0 commit comments