524524--- Will throw error if path doesn't exist.
525525--- @return uv.aliases.fs_stat_table
526526function Path :stat ()
527- local res , _ , err_msg = uv .fs_stat (self :absolute ())
527+ local res , err = uv .fs_stat (self :absolute ())
528528 if res == nil then
529- error (err_msg )
529+ error (err )
530530 end
531531 return res
532532end
541541--- Will throw error if path doesn't exist.
542542--- @return uv.aliases.fs_stat_table
543543function Path :lstat ()
544- local res , _ , err_msg = uv .fs_lstat (self :absolute ())
544+ local res , err = uv .fs_lstat (self :absolute ())
545545 if res == nil then
546- error (err_msg )
546+ error (err )
547547 end
548548 return res
549549end
797797
798798--- Create directory
799799--- @param opts plenary.Path2.mkdirOpts ?
800- --- @return boolean success
801800function Path :mkdir (opts )
802801 opts = opts or {}
803802 opts .mode = vim .F .if_nil (opts .mode , 511 )
@@ -812,18 +811,18 @@ function Path:mkdir(opts)
812811
813812 local ok , err_msg , err_code = uv .fs_mkdir (abs_path , opts .mode )
814813 if ok then
815- return true
814+ return
816815 end
817816 if err_code == " EEXIST" then
818- return true
817+ return
819818 end
820819 if err_code == " ENOENT" then
821820 if not opts .parents or self .parent == self then
822821 error (err_msg )
823822 end
824823 self :parent ():mkdir { mode = opts .mode }
825824 uv .fs_mkdir (abs_path , opts .mode )
826- return true
825+ return
827826 end
828827
829828 error (err_msg )
850849--- 'touch' file.
851850--- If it doesn't exist, creates it including optionally, the parent directories
852851--- @param opts plenary.Path2.touchOpts ?
853- --- @return boolean success
854852function Path :touch (opts )
855853 opts = opts or {}
856854 opts .mode = vim .F .if_nil (opts .mode , 438 )
@@ -861,29 +859,192 @@ function Path:touch(opts)
861859 if self :exists () then
862860 local new_time = os.time ()
863861 uv .fs_utime (abs_path , new_time , new_time )
864- return true
862+ return
865863 end
866864
867865 if not not opts .parents then
868- local mode = type (opts .parents ) == " number" and opts .parents --- @cast mode number ?
866+ local mode = type (opts .parents ) == " number" and opts .parents or nil --- @cast mode number ?
869867 _ = Path :new (self :parent ()):mkdir { mode = mode , parents = true }
870868 end
871869
872- local fd , _ , err_msg = uv .fs_open (self :absolute (), " w" , opts .mode )
870+ local fd , err = uv .fs_open (self :absolute (), " w" , opts .mode )
873871 if fd == nil then
874- error (err_msg )
872+ error (err )
875873 end
876874
877875 local ok
878- ok , _ , err_msg = uv .fs_close (fd )
876+ ok , err = uv .fs_close (fd )
879877 if not ok then
880- error (err_msg )
878+ error (err )
881879 end
882-
883- return true
884880end
885881
882+ --- @class plenary.Path2.rmOpts
883+ --- @field recursive boolean ? remove directories and their content recursively (defaul : ` false` )
884+
885+ --- rm file or optional recursively remove directories and their content recursively
886+ --- @param opts plenary.Path2.rmOpts ?
886887function Path :rm (opts )
888+ opts = opts or {}
889+ opts .recursive = vim .F .if_nil (opts .recursive , false )
890+
891+ if not opts .recursive or not self :is_dir () then
892+ local ok , err = uv .fs_unlink (self :absolute ())
893+ if ok then
894+ return
895+ end
896+ if self :is_dir () then
897+ error (string.format (" Cannnot rm director '%s'." , self :absolute ()))
898+ end
899+ error (err )
900+ end
901+
902+ for p , dirs , files in self :walk (false ) do
903+ for _ , file in ipairs (files ) do
904+ print (" delete file" , file , (p / file ):absolute ())
905+ local _ , err = uv .fs_unlink ((p / file ):absolute ())
906+ if err then
907+ error (err )
908+ end
909+ end
910+
911+ for _ , dir in ipairs (dirs ) do
912+ print (" delete dir" , dir , (p / dir ):absolute ())
913+ local _ , err = uv .fs_rmdir ((p / dir ):absolute ())
914+ if err then
915+ error (err )
916+ end
917+ end
918+ end
919+
920+ self :rmdir ()
921+ end
922+
923+ --- read file synchronously or asynchronously
924+ --- @param callback fun ( data : string )? callback to use for async version , nil for default
925+ --- @return string ? data
926+ function Path :read (callback )
927+ if not self :is_file () then
928+ error (string.format (" '%s' is not a file" , self :absolute ()))
929+ end
930+
931+ if callback == nil then
932+ return self :_read_sync ()
933+ end
934+ return self :_read_async (callback )
935+ end
936+
937+ --- @private
938+ --- @return string
939+ function Path :_read_sync ()
940+ local fd , err = uv .fs_open (self :absolute (), " r" , 438 )
941+ if fd == nil then
942+ error (err )
943+ end
944+
945+ local stat = self :stat ()
946+ local data
947+ data , err = uv .fs_read (fd , stat .size , 0 )
948+ if data == nil then
949+ error (err )
950+ end
951+ return data
952+ end
953+
954+ --- @private
955+ --- @param callback fun ( data : string ) callback to use for async version , nil for default
956+ function Path :_read_async (callback )
957+ uv .fs_open (self :absolute (), " r" , 438 , function (err_open , fd )
958+ if err_open then
959+ error (err_open )
960+ end
961+
962+ uv .fs_fstat (fd , function (err_stat , stat )
963+ if err_stat or stat == nil then
964+ error (err_stat )
965+ end
966+
967+ uv .fs_read (fd , stat .size , 0 , function (err_read , data )
968+ if err_read or data == nil then
969+ error (err_read )
970+ end
971+ callback (data )
972+ end )
973+ end )
974+ end )
975+ end
976+
977+ --- read lines of a file into a list
978+ --- @return string[]
979+ function Path :readlines ()
980+ local data = assert (self :read ())
981+ return vim .split (data , " \r ?\n " )
982+ end
983+
984+ --- get an iterator for lines text in a file
985+ --- @return fun (): string ?
986+ function Path :iter_lines ()
987+ local data = assert (self :read ())
988+ return vim .gsplit (data , " \r ?\n " )
989+ end
990+
991+ --- @param top_down boolean ? walk from current path down (default : ` true ` )
992+ --- @return fun (): plenary.Path2 ?, string[] ?, string[] ? # iterator which yields (dirpath, dirnames, filenames)
993+ function Path :walk (top_down )
994+ top_down = vim .F .if_nil (top_down , true )
995+
996+ local queue = { self } --- @type plenary.Path2[]
997+ local curr_fs = nil --- @type uv_fs_t ?
998+ local curr_path = nil --- @type plenary.Path2
999+
1000+ local rev_res = {} --- @type [plenary.Path2 , string[] , string[]]
1001+
1002+ return function ()
1003+ while # queue > 0 or curr_fs do
1004+ if curr_fs == nil then
1005+ local p = table.remove (queue , 1 )
1006+ local fs , err = uv .fs_scandir (p :absolute ())
1007+
1008+ if fs == nil then
1009+ error (err )
1010+ end
1011+ curr_path = p
1012+ curr_fs = fs
1013+ end
1014+
1015+ if curr_fs then
1016+ local dirs = {}
1017+ local files = {}
1018+ while true do
1019+ local name , ty = uv .fs_scandir_next (curr_fs )
1020+ if name == nil then
1021+ curr_fs = nil
1022+ break
1023+ end
1024+
1025+ if ty == " directory" then
1026+ table.insert (queue , Path :new { curr_path , name })
1027+ table.insert (dirs , name )
1028+ else
1029+ table.insert (files , name )
1030+ end
1031+ end
1032+
1033+ if top_down then
1034+ return curr_path , dirs , files
1035+ else
1036+ table.insert (rev_res , { curr_path , dirs , files })
1037+ end
1038+ end
1039+ end
1040+
1041+ if not top_down and # rev_res > 0 then
1042+ local res = table.remove (rev_res )
1043+ return res [1 ], res [2 ], res [3 ]
1044+ end
1045+
1046+ return nil
1047+ end
8871048end
8881049
8891050return Path
0 commit comments