refactor address deep good-taste review findings

- Add lib/list_ext.ml with take/drop helpers; replace all 6 List.filteri-as-take/drop patterns in handlers.ml and repo.ml - Replace 4-level nested match in language_of_content with a local ( <|> ) lazy option combinator for flat chaining - Routes.dispatch now returns None for malformed action URLs (e.g. /repo/commit/ without a hash) instead of silently falling back to Summary — these properly 404 - Replace nested match for page query param with >>= pipeline

Commit
d8f3aff1b0122ec80640cd94c0f7628b8d4897e0
Author
Claude Sonnet 4 <claude@anthropic.invalid>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/handlers.ml
index a07ed755..b0f773e1 100644..100644
@@ -93,10 +93,10 @@
93 93 let author = Dream.query request "author" in
94 94 let committer = Dream.query request "committer" in
95 95 let page =
96 Removed: match Dream.query request "page" with
97 Removed: | None -> 1
98 Removed: | Some s -> (
99 Removed: match int_of_string_opt s with Some p when p > 0 -> p | _ -> 1)
96 Added: let ( >>= ) = Option.bind in
97 Added: Dream.query request "page" >>= int_of_string_opt
98 Added: >>= (fun p -> if p > 0 then Some p else None)
99 Added: |> Option.value ~default:1
100 100 in
101 101 let offset = (page - 1) * page_size in
102 102 (* Fetch one beyond orphan threshold to detect whether more exist *)
@@ -107,8 +107,7 @@
107 107 in
108 108 let total = List.length all_commits in
109 109 let after_offset =
110 Removed: if offset >= total then []
111 Removed: else List.filteri (fun i _ -> i >= offset) all_commits
110 Added: if offset >= total then [] else List_ext.drop offset all_commits
112 111 in
113 112 let remaining = List.length after_offset in
114 113 (* Avoid a final page with fewer than 10 items — absorb them into this
@@ -117,9 +116,7 @@
117 116 if remaining > page_size && remaining <= page_size + 10 then remaining
118 117 else page_size
119 118 in
120 Removed: let page_commits =
121 Removed: List.filteri (fun i _ -> i < effective_size) after_offset
122 Removed: in
119 Added: let page_commits = List_ext.take effective_size after_offset in
123 120 let has_next = remaining > effective_size in
124 121 let has_prev = page > 1 in
125 122 Views.Repo.commits ?filter_type ?author ?committer ~page ~has_prev ~has_next
@@ -136,7 +133,7 @@
136 133 if remaining > page_size && remaining <= page_size + 10 then remaining
137 134 else page_size
138 135 in
139 Removed: let page_commits = List.filteri (fun i _ -> i < effective_size) commits in
136 Added: let page_commits = List_ext.take effective_size commits in
140 137 let has_next = remaining > effective_size in
141 138 Views.Repo.commits ~page:1 ~has_prev:false ~has_next context page_commits
142 139
lib/list_ext.ml
index 00000000..8b109d47 000000..100644
@@ -0,0 +1,13 @@
1 Added: (* -*- mode: tuareg; -*- *)
2 Added:
3 Added: (** List utilities not in the OCaml 5.2 stdlib. *)
4 Added:
5 Added: let rec take n = function
6 Added: | _ when n <= 0 -> []
7 Added: | [] -> []
8 Added: | x :: rest -> x :: take (n - 1) rest
9 Added:
10 Added: let rec drop n = function
11 Added: | l when n <= 0 -> l
12 Added: | [] -> []
13 Added: | _ :: rest -> drop (n - 1) rest
lib/routes.ml
index 40fb0ef9..b06385c6 100644..100644
@@ -79,19 +79,19 @@
79 79 else
80 80 let action =
81 81 match (seg, rest) with
82 Removed: | "summary", _ -> Summary
83 Removed: | "commits", [] -> Commits_page
84 Removed: | "commits", [ branch ] -> Commits_for_branch branch
85 Removed: | "commit", [ hash ] -> Commit_detail hash
86 Removed: | "files", _ -> Files_page
87 Removed: | "file", [ hash ] -> File_detail hash
88 Removed: | "branches", _ -> Branches_page
89 Removed: | "tags", _ -> Tags_page
90 Removed: | "README", _ -> Readme_page
91 Removed: | "raw", [ hash ] -> Raw hash
92 Removed: | _ -> Summary
82 Added: | "summary", _ -> Some Summary
83 Added: | "commits", [] -> Some Commits_page
84 Added: | "commits", [ branch ] -> Some (Commits_for_branch branch)
85 Added: | "commit", [ hash ] -> Some (Commit_detail hash)
86 Added: | "files", _ -> Some Files_page
87 Added: | "file", [ hash ] -> Some (File_detail hash)
88 Added: | "branches", _ -> Some Branches_page
89 Added: | "tags", _ -> Some Tags_page
90 Added: | "README", _ -> Some Readme_page
91 Added: | "raw", [ hash ] -> Some (Raw hash)
92 Added: | _ -> None
93 93 in
94 Removed: Some (repo, action)
94 Added: Option.map (fun a -> (repo, a)) action
95 95 | seg :: rest -> find_split (seg :: repo_acc) rest
96 96 in
97 97 find_split [] segments
lib/views/repo.ml
index 0963eee6..3c3cbfa4 100644..100644
@@ -231,25 +231,21 @@
231 231 let len = List.length lines in
232 232 let first_lines =
233 233 let n = min 5 len in
234 Removed: List.filteri (fun i _ -> i < n) lines
234 Added: List_ext.take n lines
235 235 in
236 236 let last_lines =
237 237 let start = max 0 (len - 5) in
238 Removed: List.filteri (fun i _ -> i >= start) lines
238 Added: List_ext.drop start lines
239 239 in
240 240 let try_lines detector lines = List.find_map detector lines in
241 Added: let ( <|> ) a b = match a with Some _ -> a | None -> b () in
241 242 match first_lines with
242 243 | [] -> None
243 Removed: | first :: _ -> (
244 Removed: match language_of_shebang first with
245 Removed: | Some _ as result -> result
246 Removed: | None -> (
247 Removed: match try_lines language_of_emacs_prop first_lines with
248 Removed: | Some _ as result -> result
249 Removed: | None -> (
250 Removed: match try_lines language_of_vim_modeline first_lines with
251 Removed: | Some _ as result -> result
252 Removed: | None -> try_lines language_of_vim_modeline last_lines)))
244 Added: | first :: _ ->
245 Added: ( ( language_of_shebang first <|> fun () ->
246 Added: try_lines language_of_emacs_prop first_lines )
247 Added: <|> fun () -> try_lines language_of_vim_modeline first_lines )
248 Added: <|> fun () -> try_lines language_of_vim_modeline last_lines
253 249
254 250 let page_title context = context.repo ^ " — " ^ context.description
255 251
@@ -459,9 +455,7 @@
459 455 let total = List.length children in
460 456 let displayed, overflow =
461 457 if total <= max_display then (children, 0)
462 Removed: else
463 Removed: ( List.filteri (fun i _ -> i < max_display) children,
464 Removed: total - max_display )
458 Added: else (List_ext.take max_display children, total - max_display)
465 459 in
466 460 let overflow_item =
467 461 if overflow = 0 then []