a code review tool

feat(tui): scroll file list in code review view

+34 -5
+34 -5
lib/tui/code_review_view.ml
··· 69 69 let render_file_list 70 70 ~(flavor : Catppuccin.Flavor.t) 71 71 ~pane_width 72 + ~visible_height 73 + ~scroll_offset 72 74 ~selected_idx 73 75 ~(reviewed_files : String.Set.t) 74 76 file_paths 75 77 = 78 + let visible_files = 79 + List.filteri file_paths ~f:(fun i _ -> 80 + i >= scroll_offset && i < scroll_offset + visible_height) 81 + in 76 82 View.vcat 77 - (List.mapi file_paths ~f:(fun i path -> 83 + (List.mapi visible_files ~f:(fun vi path -> 84 + let i = vi + scroll_offset in 78 85 render_file_list_entry 79 86 ~flavor 80 87 ~pane_width ··· 213 220 in 214 221 (* Internal state *) 215 222 let selected_file_idx, set_selected_file_idx = Bonsai.state 0 graph in 223 + let file_list_offset, set_file_list_offset = Bonsai.state 0 graph in 216 224 let showing_approval_prompt, set_showing_approval_prompt = Bonsai.state false graph in 217 225 (* Reset when the change being reviewed changes *) 218 226 Bonsai.Edge.on_change ··· 220 228 ~trigger:`After_display 221 229 ~equal:[%equal: Change_id.t] 222 230 ~callback: 223 - (let%arr set_selected_file_idx and set_showing_approval_prompt in 231 + (let%arr set_selected_file_idx and set_file_list_offset and set_showing_approval_prompt in 224 232 fun _id -> 225 233 let open Effect.Let_syntax in 226 234 let%bind () = set_selected_file_idx 0 in 235 + let%bind () = set_file_list_offset 0 in 227 236 set_showing_approval_prompt false) 228 237 graph; 229 238 let selected_file_path = ··· 247 256 diff_pane ~dimensions:diff_dims ~change_id ~selected_file_path graph 248 257 in 249 258 (* Keyboard handler *) 259 + let visible_height = 260 + let%arr dimensions in 261 + dimensions.height - pad_h - footer_height - pad_h 262 + in 250 263 let handler = 251 264 let%arr showing_approval_prompt 252 265 and set_showing_approval_prompt ··· 254 267 and on_approve 255 268 and selected_file_idx 256 269 and set_selected_file_idx 270 + and file_list_offset 271 + and set_file_list_offset 272 + and visible_height 257 273 and reviewed_files 258 274 and set_reviewed_files 259 275 and diff_inject 260 276 and file_paths 261 277 and num_files in 278 + let select_file idx = 279 + let open Effect.Let_syntax in 280 + let%bind () = set_selected_file_idx idx in 281 + (* Adjust scroll offset to keep selection in view *) 282 + if idx < file_list_offset 283 + then set_file_list_offset idx 284 + else if idx >= file_list_offset + visible_height 285 + then set_file_list_offset (idx - visible_height + 1) 286 + else Effect.Ignore 287 + in 262 288 fun (event : Event.t) -> 263 289 if showing_approval_prompt 264 290 then ( ··· 275 301 | Key_press { key = Arrow `Down; mods = [] } -> 276 302 if num_files = 0 277 303 then Effect.Ignore 278 - else set_selected_file_idx (Int.min (selected_file_idx + 1) (num_files - 1)) 304 + else select_file (Int.min (selected_file_idx + 1) (num_files - 1)) 279 305 | Key_press { key = ASCII 'k'; mods = [] } 280 306 | Key_press { key = Arrow `Up; mods = [] } -> 281 - set_selected_file_idx (Int.max (selected_file_idx - 1) 0) 307 + select_file (Int.max (selected_file_idx - 1) 0) 282 308 | Key_press { key = ASCII 'R'; mods = [] } -> 283 309 (match List.nth file_paths selected_file_idx with 284 310 | None -> Effect.Ignore ··· 304 330 |> Option.map ~f:fst 305 331 in 306 332 match next_unreviewed with 307 - | Some idx -> set_selected_file_idx idx 333 + | Some idx -> select_file idx 308 334 | None -> set_showing_approval_prompt true)) 309 335 | Key_press { key = Page `Down; mods = [] } 310 336 | Key_press { key = ASCII 'd'; mods = [ Ctrl ] } -> diff_inject Down_half_screen ··· 322 348 let view = 323 349 let%arr dimensions 324 350 and selected_file_idx 351 + and file_list_offset 325 352 and reviewed_files 326 353 and showing_approval_prompt 327 354 and diff_scroll_view ··· 335 362 render_file_list 336 363 ~flavor 337 364 ~pane_width:left_pane_width 365 + ~visible_height:content_height 366 + ~scroll_offset:file_list_offset 338 367 ~selected_idx:selected_file_idx 339 368 ~reviewed_files 340 369 file_paths