@@ -828,16 +828,70 @@ internal.man_pages = function(opts)
828828 assert (vim .islist (opts .sections ), " sections should be a list" )
829829 opts .man_cmd = utils .get_lazy_default (opts .man_cmd , function ()
830830 local uname = vim .uv .os_uname ()
831- local sysname = string.lower (uname .sysname )
832- if sysname == " darwin" then
833- local major_version = tonumber (vim .fn .matchlist (uname .release , [[ ^\(\d\+\)\..*]] )[2 ]) or 0
834- return major_version >= 22 and { " apropos" , " ." } or { " apropos" , " " }
835- elseif sysname == " freebsd" then
831+ local sysname = uname .sysname :lower ()
832+ if sysname == " freebsd" then
836833 return { " apropos" , " ." }
837- else
834+ elseif sysname ~= " darwin " then
838835 return { " apropos" , " " }
839836 end
837+
838+ -- Cache apropos result on macOS speed up. macOS with SIP (System Integrity
839+ -- Protection) cannot update the whatis database, so makes apropos much
840+ -- slower. We cache results and invalidate it when the mtime's of man
841+ -- directories are changed.
842+ local mansects , cache_filename
843+ if vim .env .MANSECT then
844+ mansects = vim .split (vim .env .MANSECT , " :" )
845+ cache_filename = (" telescope-man-pages-%s" ):format (vim .env .MANSECT :gsub (" :" , " -" ))
846+ else
847+ -- This MANSECT default value is derived from apropos' man page
848+ mansects = vim .split (" 1:8:2:3:3lua:n:4:5:6:7:9:l" , " :" )
849+ cache_filename = " telescope-man-pages"
850+ end
851+ local cache_path = vim .fs .joinpath (vim .fn .stdpath " cache" , cache_filename )
852+ local cache_stat = vim .uv .fs_stat (cache_path )
853+
854+ if cache_stat and cache_stat .size > 0 then
855+ local manpath = vim .env .MANPATH or vim .trim (vim .system ({ " manpath" }):wait ().stdout )
856+ local man_dirs = vim .split (manpath , " :" , { trimempty = true })
857+
858+ local mansects_map = vim .iter (mansects ):fold ({}, function (a , b )
859+ a [b ] = true
860+ return a
861+ end )
862+ local function is_man_dir (path )
863+ local s = vim .fs .basename (path ):match " ^man(.*)$"
864+ return s and mansects_map [s ] or false
865+ end
866+
867+ -- Detect mtime of man directories that is newer than cache file
868+ local cache_invalid = vim .iter (man_dirs ):any (function (man_dir )
869+ local search = vim .fs .dir (man_dir , {
870+ depth = 2 ,
871+ skip = function (dir_name )
872+ return not is_man_dir (dir_name )
873+ end ,
874+ })
875+ return vim .iter (search ):any (function (ent , typ )
876+ if typ ~= " directory" or not is_man_dir (ent ) then
877+ return false
878+ end
879+ local dir = vim .fs .joinpath (man_dir , ent )
880+ local stat = vim .uv .fs_stat (dir )
881+ return stat and stat .mtime .sec > cache_stat .mtime .sec or false
882+ end )
883+ end )
884+
885+ if not cache_invalid then
886+ return { " cat" , cache_path }
887+ end
888+ end
889+
890+ local major_version = tonumber (vim .fn .matchlist (uname .release , [[ ^\(\d\+\)\..*]] )[2 ]) or 0
891+ local cmd = major_version >= 22 and " apropos ." or " apropos ' '"
892+ return { " sh" , " -c" , (" %s | tee %s" ):format (cmd , cache_path ) }
840893 end )
894+
841895 opts .entry_maker = opts .entry_maker or make_entry .gen_from_apropos (opts )
842896 opts .env = { PATH = vim .env .PATH , MANPATH = vim .env .MANPATH }
843897
0 commit comments