524
524
--- Will throw error if path doesn't exist.
525
525
--- @return uv.aliases.fs_stat_table
526
526
function Path :stat ()
527
- local res , _ , err_msg = uv .fs_stat (self :absolute ())
527
+ local res , err = uv .fs_stat (self :absolute ())
528
528
if res == nil then
529
- error (err_msg )
529
+ error (err )
530
530
end
531
531
return res
532
532
end
541
541
--- Will throw error if path doesn't exist.
542
542
--- @return uv.aliases.fs_stat_table
543
543
function Path :lstat ()
544
- local res , _ , err_msg = uv .fs_lstat (self :absolute ())
544
+ local res , err = uv .fs_lstat (self :absolute ())
545
545
if res == nil then
546
- error (err_msg )
546
+ error (err )
547
547
end
548
548
return res
549
549
end
797
797
798
798
--- Create directory
799
799
--- @param opts plenary.Path2.mkdirOpts ?
800
- --- @return boolean success
801
800
function Path :mkdir (opts )
802
801
opts = opts or {}
803
802
opts .mode = vim .F .if_nil (opts .mode , 511 )
@@ -812,18 +811,18 @@ function Path:mkdir(opts)
812
811
813
812
local ok , err_msg , err_code = uv .fs_mkdir (abs_path , opts .mode )
814
813
if ok then
815
- return true
814
+ return
816
815
end
817
816
if err_code == " EEXIST" then
818
- return true
817
+ return
819
818
end
820
819
if err_code == " ENOENT" then
821
820
if not opts .parents or self .parent == self then
822
821
error (err_msg )
823
822
end
824
823
self :parent ():mkdir { mode = opts .mode }
825
824
uv .fs_mkdir (abs_path , opts .mode )
826
- return true
825
+ return
827
826
end
828
827
829
828
error (err_msg )
850
849
--- 'touch' file.
851
850
--- If it doesn't exist, creates it including optionally, the parent directories
852
851
--- @param opts plenary.Path2.touchOpts ?
853
- --- @return boolean success
854
852
function Path :touch (opts )
855
853
opts = opts or {}
856
854
opts .mode = vim .F .if_nil (opts .mode , 438 )
@@ -861,29 +859,192 @@ function Path:touch(opts)
861
859
if self :exists () then
862
860
local new_time = os.time ()
863
861
uv .fs_utime (abs_path , new_time , new_time )
864
- return true
862
+ return
865
863
end
866
864
867
865
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 ?
869
867
_ = Path :new (self :parent ()):mkdir { mode = mode , parents = true }
870
868
end
871
869
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 )
873
871
if fd == nil then
874
- error (err_msg )
872
+ error (err )
875
873
end
876
874
877
875
local ok
878
- ok , _ , err_msg = uv .fs_close (fd )
876
+ ok , err = uv .fs_close (fd )
879
877
if not ok then
880
- error (err_msg )
878
+ error (err )
881
879
end
882
-
883
- return true
884
880
end
885
881
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 ?
886
887
function 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
887
1048
end
888
1049
889
1050
return Path
0 commit comments