···143143 let term_width_height : (int * int) Lwd.var = Lwd.var (0, 0)
144144 let get_term () = Option.get !term
145145146146- let reset_selection () =
147147- Flock.fork (fun _ ->
148148- Picos_std_structured.Control.sleep ~seconds:0.7;
149149- [%log info "Resetting selection"];
150150- ui_state.reset_selection |> Signal.trigger)
146146+ let reset_selection_debouncer =
147147+ Jj_tui.Debounce.make
148148+ ~delay:0.7
149149+ ~merge:(fun () () -> ())
150150+ ~run:(fun () ->
151151+ [%log info "Resetting selection"];
152152+ ui_state.reset_selection |> Signal.trigger)
153153+ ()
151154 ;;
155155+156156+ let reset_selection () = Jj_tui.Debounce.push reset_selection_debouncer ()
152157153158 (**Gets an id for the currently hovered revision. If the change_id is unique we use that, if it's not we return a commit_id instead*)
154159 let get_hovered_rev () = Lwd.peek ui_state.hovered_revision |> get_unique_id
···186191 ;;
187192188193 let get_rebase_preview_active () = Lwd.peek ui_state.rebase_preview_active
189189-190194 let get_rebase_preview_mode () = Lwd.peek ui_state.rebase_preview_mode
191191-192195 let get_rebase_preview_mode_lwd () = Lwd.get ui_state.rebase_preview_mode
193193-194196 let get_rebase_preview_source_mode () = Lwd.peek ui_state.rebase_preview_source_mode
195195-196197 let get_rebase_preview_source_mode_lwd () = Lwd.get ui_state.rebase_preview_source_mode
197198198199 let set_rebase_preview_source_mode mode =
···200201 ;;
201202202203 let get_rebase_preview_targets () = Lwd.peek ui_state.rebase_preview_targets
203203-204204 let get_rebase_preview_sources () = Lwd.peek ui_state.rebase_preview_sources
205205-206206- let set_rebase_preview_active active =
207207- Lwd.set ui_state.rebase_preview_active active
208208- ;;
209209-210210- let set_rebase_preview_targets targets =
211211- Lwd.set ui_state.rebase_preview_targets targets
212212- ;;
213213-214214- let set_rebase_preview_sources sources =
215215- Lwd.set ui_state.rebase_preview_sources sources
216216- ;;
217217-205205+ let set_rebase_preview_active active = Lwd.set ui_state.rebase_preview_active active
206206+ let set_rebase_preview_targets targets = Lwd.set ui_state.rebase_preview_targets targets
207207+ let set_rebase_preview_sources sources = Lwd.set ui_state.rebase_preview_sources sources
218208 let set_rebase_preview_invalid msg = Lwd.set ui_state.rebase_preview_invalid msg
219209220210 let clear_rebase_preview () =
+12-21
jj_tui/bin/show_view.ml
···1616let statusStream = Stream.create ()
1717let lastMessage = ref None
18181919+let push_status_debouncer =
2020+ Jj_tui.Debounce.make
2121+ ~delay:0.05
2222+ ~merge:(fun _ new_ -> new_)
2323+ ~run:(fun status -> Stream.push statusStream status)
2424+ ()
2525+;;
2626+1927let push_status status =
2028 lastMessage := Some status;
2121- Stream.push statusStream status
2929+ Jj_tui.Debounce.push push_status_debouncer status
2230;;
23312432(** pushes the last message to the queue again to re-render everything *)
···7987 res
8088 ;;
81898282- let get_latest_message cursor =
8383- let rec seek_latest last cursor =
8484- let peeked = Stream.peek_opt cursor in
8585- match peeked with
8686- | Some (last, new_cursor) ->
8787- seek_latest last new_cursor
8888- | None ->
8989- [%log debug "skipping to next status because two were queued"];
9090- last, cursor
9191- in
9292- let msg, new_cursor = cursor |> Stream.read in
9393- (*little 50ms delay to let us move to the next one if it's ready*)
9494- Picos.Fiber.sleep ~seconds:0.05;
9595- (*if the queue isn't empty just skip the current because we really only ever want the newest*)
9696- seek_latest msg new_cursor
9797- ;;
9898-9990 (* Wait for messages to come in the stream.
100100- When a message comes, we try to render it.
101101- If a new message comes, we cancel the current computation and then start the new rendering
9191+ When a message comes, we try to render it.
9292+ If a new message comes, we cancel the current computation and then start the new rendering
10293 *)
10394 let render_loop stream =
10495 let current_summary_computation = ref (Promise.of_value ()) in
···10798 let cursor = ref (Stream.tap stream) in
10899 while true do
109100 [%log debug "waiting for next status"];
110110- let msg, new_cursor = get_latest_message !cursor in
101101+ let msg, new_cursor = Stream.read !cursor in
111102 cursor := new_cursor;
112103 [%log debug "cancelling older status because of new message"];
113104 Promise.terminate_after ~seconds:0. !current_summary_computation;
+31
jj_tui/lib/debounce.ml
···11open Picos_std_structured
2233+(**
44+ A small, reusable debouncer for Picos fibers.
55+66+ The debouncer coalesces rapid [push] calls into a single delayed execution.
77+ Callers provide a [merge] function to combine queued values and a [run]
88+ function for the final work item.
99+1010+ Internally, both the debounce timer and the active run are represented as
1111+ cancelable promises. This keeps latest-wins behavior explicit and avoids
1212+ leaking background work.
1313+1414+ Warning:
1515+ - This module uses [Flock.fork_as_promise], so calls to {!make} and {!push}
1616+ must happen inside a running flock scope.
1717+ - The [run] callback should not swallow [Control.Terminate], otherwise
1818+ cancellation cannot stop stale work promptly.
1919+*)
320type 'a t = {
421 delay : float
522 ; merge : 'a -> 'a -> 'a
···926 ; current_computation : unit Promise.t ref
1027}
11282929+(** [make ~delay ~merge ~run ()] creates a debouncer.
3030+3131+ - [delay] is the debounce window in seconds.
3232+ - [merge old new_] combines queued values when multiple pushes arrive.
3333+ - [run value] performs the debounced action.
3434+3535+ [run] executes in a fiber forked from the current flock.
3636+*)
1237let make ~delay ~merge ~run () =
1338 {
1439 delay
···2045 }
2146;;
22474848+(** [push t value] enqueues a new value for debounced processing.
4949+5050+ Repeated pushes during the debounce window are merged with [merge]. When the
5151+ timer elapses, only the latest merged value is executed. Any previously
5252+ running [run] fiber is canceled before a new one is started.
5353+*)
2354let push t value =
2455 t.pending
2556 := Some