@@ -28,7 +28,6 @@ int os_get_uname(uv_uid_t uid, char *s, size_t len);
2828--- @field show_hidden boolean
2929--- @field normal_when_fits boolean
3030--- @field use_trash boolean
31- --- @field file_dir_based boolean
3231--- @field keymaps KeyMapConfig
3332
3433--- @type DiredConfig
@@ -37,7 +36,6 @@ local Config = setmetatable({}, {
3736 local default = {
3837 show_hidden = true ,
3938 normal_when_fits = false ,
40- file_dir_based = true ,
4139 shortcuts = ' sdfhlwertyuopzxcvbnmSDFGHLQWERTYUOPZXCVBNM' ,
4240 use_trash = true ,
4341 keymaps = {
@@ -234,10 +232,10 @@ local Actions = {}
234232UI .Entry = {
235233 render = function (state , row , entry )
236234 local formatted = {
237- perms = Format .permissions (entry .stat .mode ),
235+ perms = entry . perms or Format .permissions (entry .stat .mode ),
238236 user = entry .user or Format .username (entry .stat .uid ),
239- size = Format .size (entry .stat .size ),
240- time = Format .friendly_time (entry .stat .mtime .sec ),
237+ size = entry . size or Format .size (entry .stat .size ),
238+ time = entry . date or Format .friendly_time (entry .stat .mtime .sec ),
241239 name = entry .name .. (entry .stat .type == ' directory' and SEPARATOR or ' ' ),
242240 }
243241 api .nvim_buf_set_lines (
@@ -729,101 +727,43 @@ local function create_shortcut_manager()
729727end
730728
731729local function parse_fd_output (line , current_path )
732- local perms , links , user , group , size_str , month , day , time , path
733- perms , links , user , group , size_str , month , day , time , path =
734- line :match (' ^(%S+)%s+(%d+)%s+(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s+(.+)$' )
735-
736- if not path then
730+ if # line == 0 then
737731 return nil
738732 end
739-
740- local is_directory = perms :sub (1 , 1 ) == ' d'
741-
742- local mode = 0
743- if perms :match (' r' , 2 ) then
744- mode = mode + 0x100
745- end
746- if perms :match (' w' , 3 ) then
747- mode = mode + 0x080
748- end
749- if perms :match (' x' , 4 ) then
750- mode = mode + 0x040
751- end
752- if perms :match (' r' , 5 ) then
753- mode = mode + 0x020
754- end
755- if perms :match (' w' , 6 ) then
756- mode = mode + 0x010
757- end
758- if perms :match (' x' , 7 ) then
759- mode = mode + 0x008
760- end
761- if perms :match (' r' , 8 ) then
762- mode = mode + 0x004
763- end
764- if perms :match (' w' , 9 ) then
765- mode = mode + 0x002
766- end
767- if perms :match (' x' , 10 ) then
768- mode = mode + 0x001
769- end
770-
771- local size = 0
772- local size_num , size_unit = size_str :match (' ^([%d%.]+)(.*)$' )
773- if size_num then
774- size = tonumber (size_num ) or 0
775- if size_unit == ' K' or size_unit == ' KB' then
776- size = size * 1024
777- elseif size_unit == ' M' or size_unit == ' MB' then
778- size = size * 1024 * 1024
779- elseif size_unit == ' G' or size_unit == ' GB' then
780- size = size * 1024 * 1024 * 1024
733+ local entry = {}
734+ local data = Iter (vim .split (line , ' %s' )):map (function (item )
735+ if # item > 0 then
736+ return item
781737 end
738+ end ):totable ()
739+ if # data < 9 then
740+ return
782741 end
783-
784- local timestamp = os.time ({
785- year = os.date (' %Y' ),
786- month = ({
787- Jan = 1 ,
788- Feb = 2 ,
789- Mar = 3 ,
790- Apr = 4 ,
791- May = 5 ,
792- Jun = 6 ,
793- Jul = 7 ,
794- Aug = 8 ,
795- Sep = 9 ,
796- Oct = 10 ,
797- Nov = 11 ,
798- Dec = 12 ,
799- })[month ] or 1 ,
800- day = tonumber (day ) or 1 ,
801- hour = tonumber (time :match (' ^(%d+)' )) or 0 ,
802- min = tonumber (time :match (' :(%d+)' )) or 0 ,
803- })
804-
805- -- local name = vim.fs.basename(path)
806- local entry = {
807- name = path :sub (# current_path + 1 ):gsub (' ^' .. SEPARATOR , ' ' ),
808- path = path ,
809- user = user ,
810- stat = {
811- mode = mode ,
812- size = size ,
813- mtime = { sec = timestamp },
814- type = is_directory and ' directory' or ' file' ,
815- },
742+ entry .perms = data [1 ]:gsub (' @$' , ' ' )
743+ entry .user = data [3 ]
744+ entry .size = data [5 ]
745+ entry .date = (' %s %s %s' ):format (data [6 ], data [7 ], data [8 ])
746+
747+ local name = data [9 ]:sub (# current_path + 1 )
748+ if name :sub (1 , 1 ) == ' /' or name :sub (1 , 1 ) == ' \\ ' then
749+ name = name :sub (2 )
750+ end
751+ entry .name = name
752+ entry .stat = {
753+ type = entry .perms :sub (1 , 1 ) == ' d' and ' directory' or ' file' ,
816754 }
817-
818755 return entry
819756end
820757
821758local function create_debounced_search ()
822759 local timer = nil
823760 local last_search = ' '
824761 local is_searching = false
762+ --- @type vim.SystemObj | nil
825763 local current_job = nil
826764 local pending_search = nil
765+ local search_id = 0
766+ local handled_results = 0
827767
828768 local function cleanup ()
829769 if timer then
@@ -833,21 +773,30 @@ local function create_debounced_search()
833773 timer :close ()
834774 timer = nil
835775 end
836-
837776 if current_job and not current_job :is_closing () then
838777 current_job :kill (9 )
839778 current_job = nil
840779 end
841780 end
842781
843- local function process_and_display_results (results , search_text , callback )
844- local filters = {}
782+ local reset = function ()
783+ last_search = ' '
784+ is_searching = false
785+ handled_results = 0
786+ search_id = search_id + 1
787+ cleanup ()
788+ end
789+
790+ local function process_and_display_results (results , search_text , callback , id )
791+ if id ~= search_id then
792+ return
793+ end
845794
795+ local filters = {}
846796 if # results > 0 then
847797 local names = Iter (results ):map (function (entry )
848798 return entry .name
849799 end ):totable ()
850-
851800 local res = vim .fn .matchfuzzypos (names , search_text )
852801 for _ , entry in ipairs (results ) do
853802 for k , v in ipairs (res [1 ]) do
@@ -858,41 +807,41 @@ local function create_debounced_search()
858807 end
859808 end
860809 end
861-
862810 table.sort (filters , function (a , b )
863811 return a .score > b .score
864812 end )
865813 end
866-
867- callback (filters )
814+ callback (filters , handled_results )
868815 end
869816
870817 local function execute_search (state , search_text , callback )
871- if search_text == last_search and not pending_search then
818+ if search_text == last_search then
872819 return
873820 end
874-
875- if current_job and not current_job :is_closing () then
876- current_job :kill (9 )
877- current_job = nil
878- end
879-
821+ reset ()
880822 is_searching = true
881823 last_search = search_text
882-
883- local results = {}
824+ search_id = search_id + 1
825+ local current_search_id = search_id
884826 current_job = vim .system ({
885827 ' fd' ,
886828 ' -l' ,
887829 ' -i' ,
888830 ' -H' ,
831+ ' --max-depth' ,
832+ ' 5' ,
889833 ' --color' ,
890834 ' never' ,
891835 search_text ,
892836 state .current_path ,
893837 }, {
894838 text = true ,
895839 stdout = function (_ , data )
840+ if current_search_id ~= search_id then
841+ return
842+ end
843+
844+ local results = {}
896845 if data then
897846 for _ , line in ipairs (vim .split (data , ' \n ' )) do
898847 if # line > 0 then
@@ -905,77 +854,37 @@ local function create_debounced_search()
905854 end
906855 end
907856
908- if # results >= 50 then
909- local current_results = vim . deepcopy ( results )
857+ if current_search_id == search_id and # results > 0 then
858+ handled_results = handled_results + # results
910859 vim .schedule (function ()
911- process_and_display_results (current_results , search_text , callback )
860+ process_and_display_results (results , search_text , callback , current_search_id )
912861 end )
913862 end
914863 end
915864 end ,
916865 }, function (obj )
866+ if current_search_id ~= search_id then
867+ return
868+ end
869+
917870 if obj .code ~= 0 and obj .code ~= 1 then
918871 Notify .err (' Search error: ' .. (obj .stderr or ' Unknown error' ))
919872 end
920-
921- vim .schedule (function ()
922- process_and_display_results (results , search_text , callback )
923-
924- is_searching = false
925- current_job = nil
926-
927- if pending_search then
928- local pending = pending_search
929- pending_search = nil
930- execute_search (state , pending .text , pending .callback )
931- end
932- end )
933873 end )
934874 end
935875
936876 return {
937877 search = function (state , search_text , callback , delay )
938878 delay = delay or 100
939-
940879 if is_searching then
941- pending_search = { text = search_text , callback = callback }
942- return
880+ reset ()
943881 end
944-
945- if not timer then
946- timer = assert (vim .uv .new_timer ())
947- end
948-
949- if timer :is_active () then
950- timer :stop ()
951- end
952-
953- if # search_text == 0 then
954- last_search = ' '
955- return vim .schedule (function ()
956- callback (state .entries )
957- end )
958- end
959-
960- timer :start (
961- delay ,
962- 0 ,
963- vim .schedule_wrap (function ()
964- execute_search (state , search_text , callback )
965- end )
966- )
882+ timer = assert (vim .uv .new_timer ())
883+ timer :start (delay , 0 , function ()
884+ execute_search (state , search_text , callback )
885+ end )
967886 end ,
968887 destroy = cleanup ,
969- reset = function ()
970- last_search = ' '
971- is_searching = false
972- pending_search = nil
973-
974- if current_job and not current_job :is_closing () then
975- current_job :kill (9 ) -- SIGKILL
976- current_job = nil
977- end
978- end ,
979888 }
980889end
981890
@@ -1065,9 +974,25 @@ Browser.State = {
1065974 update_display (state , state .entries )
1066975 return
1067976 end
1068- state .search_engine .search (state , query , function (entries )
977+ state .entries = {}
978+ state .search_engine .search (state , query , function (entries , count )
979+ state .entries = vim .list_extend (state .entries , entries )
980+ if count > 100 then
981+ state .count_mark =
982+ api .nvim_buf_set_extmark (new_state .search_buf , ns_id , 0 , 0 , {
983+ id = state .count_mark or nil ,
984+ virt_text = {
985+ {
986+ (' [1/%d] Find File: ' ):format (count ),
987+ ' DiredTitle' ,
988+ },
989+ },
990+ virt_text_pos = ' inline' ,
991+ })
992+ return
993+ end
1069994 update_display (state , entries )
1070- end , 80 )
995+ end , 50 )
1071996 end ,
1072997 on_detach = function ()
1073998 if state .search_engine then
@@ -1711,12 +1636,7 @@ end
17111636
17121637local function browse_directory (path )
17131638 path = path :find (SEPARATOR .. ' $' ) and path or path .. SEPARATOR
1714- if Config .file_dir_based then
1715- local fname = api .nvim_buf_get_name (0 )
1716- if # fname > 0 then
1717- path = vim .fs .dirname (fname ) .. SEPARATOR
1718- end
1719- end
1639+
17201640 F .IO
17211641 .chain (Browser .State .create (path ), function (state )
17221642 return F .IO .chain (Browser .setup (state ), function (s )
0 commit comments