package core_extended
Extra components that are not as closely vetted or as stable as Core
Install
Dune Dependency
Authors
Maintainers
Sources
v0.17.0.tar.gz
sha256=17de5f7cf59818d757bb0625c55f0afc84509122645b7782fb522ac98c3be446
doc/src/core_extended.find_files/find_files.ml.html
Source file find_files.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
open Core open Poly module Unix = Core_unix type file_info = Filename.t * Unix.stats type path = string list let path_append path x = x :: path let path_to_string ?base path = match base, path with | None, [] -> "." | Some base, [] -> base | None, _ -> String.concat ~sep:"/" (List.rev path) | Some base, _ -> base ^/ String.concat ~sep:"/" (List.rev path) ;; module Options = struct type error_handler = | Ignore | Print | Raise | Handle_with of (Filename.t -> exn -> unit) type t = { min_depth : int ; max_depth : int option ; follow_links : bool ; on_open_errors : error_handler ; on_stat_errors : error_handler ; filter : (file_info -> bool) option ; skip_dir : (file_info -> bool) option ; relative_paths : bool } let default = { min_depth = 1 ; max_depth = None ; follow_links = false ; on_open_errors = Raise ; on_stat_errors = Raise ; filter = None ; skip_dir = None ; relative_paths = false } ;; let ignore_errors = { default with on_open_errors = Ignore; on_stat_errors = Ignore } end module O = Options type t = { base : string ; options : Options.t ; already_seen : (int * int, unit) Hashtbl.t ; (* device num * inode *) mutable to_visit : (path * int) list ; (* dir to traverse and the depth it is at *) mutable current_dir : path ; mutable current_handle : [ `Just_created | `Starting | `Handle of Unix.dir_handle ] ; mutable depth : int ; mutable closed : bool } let full_path_name t path = path_to_string ~base:t.base path let output_path_name t path = path_to_string ?base:(if t.options.O.relative_paths then None else Some t.base) path ;; let rec open_next_dir t = match t.to_visit with | [] -> None | (dir_name, depth) :: rest -> (try t.to_visit <- rest; t.current_handle <- `Handle (Unix.opendir (full_path_name t dir_name)); t.current_dir <- dir_name; t.depth <- depth; Some () with | e -> (match t.options.O.on_open_errors with | O.Ignore -> open_next_dir t | O.Raise -> raise e | O.Handle_with f -> f (output_path_name t dir_name) e; open_next_dir t | O.Print -> Printf.eprintf !"unable to open %s - %{Exn}\n" (output_path_name t dir_name) e; open_next_dir t)) ;; let closedir t = match t.current_handle with | `Just_created | `Starting -> () | `Handle handle -> (try Unix.closedir handle with | Unix.Unix_error _ -> ()) ;; let close t = if not t.closed then ( t.closed <- true; closedir t; Hashtbl.clear t.already_seen; t.to_visit <- []) ;; (* returns the next file from the conceptual stream and updates the state of t - this is the only way that t should ever be updated *) let rec next t = assert (not t.closed); let stat path = let full_fn = full_path_name t path in let output_fn = output_path_name t path in try let stat = if t.options.O.follow_links then Unix.stat else Unix.lstat in Some (output_fn, path, stat full_fn) with | e -> (match t.options.O.on_stat_errors with | O.Ignore -> None | O.Raise -> raise e | O.Handle_with f -> f output_fn e; None | O.Print -> Printf.eprintf !"unable to stat %s - %{Exn}\n" output_fn e; None) in let is_new ((_output_fn, _path, stats) as info) = if stats.Unix.st_kind <> Unix.S_DIR then Some info else ( let uid = stats.Unix.st_dev, stats.Unix.st_ino in match Hashtbl.find t.already_seen uid with | Some () -> None | None -> Hashtbl.set t.already_seen ~key:uid ~data:(); Some info) in let handle_dirs (output_fn, path, stats) = let info = output_fn, stats in if match t.options.O.skip_dir with | None -> false | Some f -> f info then None else ( (* if this is a directory we need to decide if we will be traversing into it later... *) let visit () = t.to_visit <- (path, t.depth + 1) :: t.to_visit in if stats.Unix.st_kind = Unix.S_DIR then ( match t.options.O.max_depth with | None -> visit () | Some max_depth -> if t.depth < max_depth then visit () else ()); Some info) in let filter file = if t.depth < t.options.O.min_depth then None else ( match t.options.O.filter with | None -> Some file | Some f -> if f file then Some file else None) in let handle_child path = (* each function in this bind returns None if the file should be skipped, and Some f i if it thinks it's ok to emit - possibly updating the state or transforming f along the way *) let ( >>= ) t f = Option.bind t ~f in let skip = try stat path >>= is_new >>= handle_dirs >>= filter with | e -> closedir t; raise e in match skip with | None -> next t | file -> file in let with_next_dir k = match open_next_dir t with | None -> close t; None | Some () -> k () in match t.current_handle with | `Just_created -> (match t.options.O.max_depth with | Some d when d < 0 -> close t; None | None | Some _ -> t.current_handle <- `Starting; handle_child t.current_dir) | `Starting -> with_next_dir (fun () -> next t) | `Handle current_handle -> let dirent = match Unix.readdir_opt current_handle with | Some fn -> `Dirent fn | None -> closedir t; `End_of_directory in (match dirent with | `End_of_directory -> with_next_dir (fun () -> next t) | `Dirent ("." | "..") -> next t | `Dirent basename -> handle_child (path_append t.current_dir basename)) ;; let create ?(options = Options.default) dir = { base = dir ; options ; already_seen = Hashtbl.Poly.create () ~size:11 ; to_visit = [] ; current_dir = [] ; current_handle = `Just_created ; depth = 0 ; closed = false } ;; let iter t ~f = let rec loop () = match next t with | None -> () | Some file -> f file; loop () in loop () ;; let fold t ~init ~f = let rec loop acc = match next t with | None -> acc | Some file -> loop (f acc file) in loop init ;; let to_list t = List.rev (fold t ~init:[] ~f:(fun acc file -> file :: acc)) let find_all ?options dir = let t = create ?options dir in to_list t ;;
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>