terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

support await_read for async integration with nottui

+318 -121
+11
forks/nottui/dune-project
··· 56 56 (= :version)) 57 57 (notty 58 58 (>= 0.2)))) 59 + 60 + (package 61 + (name nottui_picos) 62 + (synopsis "Run Nottui UIs using picos") 63 + (documentation "https://let-def.github.io/lwd/doc") 64 + (depends 65 + (picos(>= 0.6.0)) 66 + (nottui 67 + (= :version)) 68 + (notty 69 + (>= 0.2))))
+137 -88
forks/nottui/lib/nottui/nottui_main.ml
··· 87 87 ;; 88 88 89 89 let release_reversable ((v, _) : handle) = 90 - Log.debug (fun m -> m "Maybe release or remove %d from reversable focus stack" (Lwd.peek v)); 90 + Log.debug (fun m -> 91 + m "Maybe release or remove %d from reversable focus stack" (Lwd.peek v)); 91 92 (* we should only release if we actually have the focus*) 92 93 if var_equal !currently_focused v 93 94 then ( ··· 95 96 match !focus_stack with 96 97 | hd :: tl -> 97 98 request_var hd; 98 - Log.debug (fun m -> m "Released reversable focus %d in echange form %d" (Lwd.peek v) (Lwd.peek v)); 99 + Log.debug (fun m -> 100 + m "Released reversable focus %d in echange form %d" (Lwd.peek v) (Lwd.peek v)); 99 101 focus_stack := tl 100 102 | _ -> ()) 101 103 else ( ··· 1056 1058 module Ui_loop = struct 1057 1059 open Notty_unix 1058 1060 1059 - let await_read_unix fd timeout: [`Ready|`NotReady]= 1060 - let rec select ()= 1061 - match Unix.select[fd] [] [fd] timeout with 1062 - | [], [], []-> `NotReady 1063 - | _-> `Ready 1064 - | exception Unix.Unix_error (Unix.EINTR, _, _) -> select () 1061 + module Internal = struct 1062 + type step = 1063 + ?process_event:bool 1064 + -> ?timeout:float 1065 + -> renderer:Renderer.t 1066 + -> Term.t 1067 + -> ui Lwd.root 1068 + -> unit 1069 + 1070 + let await_read_unix fd timeout : [ `Ready | `NotReady ] = 1071 + let rec select () = 1072 + match Unix.select [ fd ] [] [ fd ] timeout with 1073 + | [], [], [] -> `NotReady 1074 + | _ -> `Ready 1075 + | exception Unix.Unix_error (Unix.EINTR, _, _) -> select () 1065 1076 in 1066 - select () 1077 + select () 1078 + ;; 1067 1079 1080 + (* FIXME Uses of [quick_sample] and [quick_release] should be replaced by 1081 + [sample] and [release] with the appropriate release management. *) 1068 1082 1083 + let step 1084 + ?(await_read = await_read_unix) 1085 + ?(process_event = true) 1086 + ?(timeout = -1.0) 1087 + ~renderer 1088 + term 1089 + root 1090 + = 1091 + let size = Term.size term in 1092 + let image = 1093 + let rec stabilize () = 1094 + let tree = Lwd.quick_sample root in 1095 + Renderer.update renderer size tree; 1096 + let image = Renderer.image renderer in 1097 + if Lwd.is_damaged root then stabilize () else image 1098 + in 1099 + stabilize () 1100 + in 1101 + Term.image term image; 1102 + if process_event 1103 + then ( 1104 + let wait_for_event () = 1105 + let i, _ = Term.fds term in 1106 + match await_read i timeout with 1107 + | `NotReady -> Term.pending term 1108 + | `Ready -> true 1109 + in 1110 + let has_event = timeout < 0.0 || Term.pending term || wait_for_event () in 1111 + if has_event 1112 + then ( 1113 + match Term.event term with 1114 + | `End -> () 1115 + | `Resize _ -> () 1116 + | #Unescape.event as event -> 1117 + let event = (event : Unescape.event :> Ui.event) in 1118 + ignore (Renderer.dispatch_event renderer event : [ `Handled | `Unhandled ]))) 1119 + ;; 1069 1120 1070 - (* FIXME Uses of [quick_sample] and [quick_release] should be replaced by 1071 - [sample] and [release] with the appropriate release management. *) 1121 + type run_with_term_intern = 1122 + step:step 1123 + -> Term.t 1124 + -> ?tick_period:float 1125 + -> ?tick:(unit -> unit) 1126 + -> renderer:Renderer.t 1127 + -> bool Lwd.var 1128 + -> ui Lwd.t 1129 + -> unit 1130 + 1131 + type run_with_term = 1132 + Term.t 1133 + -> ?tick_period:float 1134 + -> ?tick:(unit -> unit) 1135 + -> renderer:Renderer.t 1136 + -> bool Lwd.var 1137 + -> ui Lwd.t 1138 + -> unit 1139 + 1140 + let run_with_term : run_with_term_intern = 1141 + fun ~(step : step) term ?tick_period ?(tick = ignore) ~renderer quit t -> 1142 + let quit = Lwd.observe (Lwd.get quit) in 1143 + let root = Lwd.observe t in 1144 + let rec loop () = 1145 + let quit = Lwd.quick_sample quit in 1146 + if not quit 1147 + then ( 1148 + step ~process_event:true ?timeout:tick_period ~renderer term root; 1149 + tick (); 1150 + loop ()) 1151 + in 1152 + loop (); 1153 + ignore (Lwd.quick_release root); 1154 + ignore (Lwd.quick_release quit) 1155 + ;; 1072 1156 1073 - let step ?(await_read=await_read_unix) ?(process_event = true) ?(timeout = -1.0) ~renderer term root = 1074 - let size = Term.size term in 1075 - let image = 1076 - let rec stabilize () = 1077 - let tree = Lwd.quick_sample root in 1078 - Renderer.update renderer size tree; 1079 - let image = Renderer.image renderer in 1080 - if Lwd.is_damaged root then stabilize () else image 1157 + let run 1158 + ~(run_with_term : run_with_term) 1159 + ?tick_period 1160 + ?tick 1161 + ?term 1162 + ?(renderer = Renderer.make ()) 1163 + ?quit 1164 + ?(quit_on_escape = true) 1165 + ?(quit_on_ctrl_q = true) 1166 + t 1167 + = 1168 + let quit = 1169 + match quit with 1170 + | Some quit -> quit 1171 + | None -> Lwd.var false 1081 1172 in 1082 - stabilize () 1083 - in 1084 - Term.image term image; 1085 - if process_event 1086 - then ( 1087 - let wait_for_event () = 1088 - let i, _ = Term.fds term in 1089 - match await_read i timeout with 1090 - | `NotReady -> Term.pending term 1091 - | `Ready-> true 1173 + let t = 1174 + Lwd.map 1175 + t 1176 + ~f: 1177 + (Ui.event_filter (function 1178 + | `Key (`ASCII 'Q', [ `Ctrl ]) when quit_on_ctrl_q -> 1179 + Lwd.set quit true; 1180 + `Handled 1181 + | `Key (`Escape, []) when quit_on_escape -> 1182 + Lwd.set quit true; 1183 + `Handled 1184 + | _ -> `Unhandled)) 1092 1185 in 1093 - let has_event = timeout < 0.0 || Term.pending term || wait_for_event () in 1094 - if has_event 1095 - then ( 1096 - match Term.event term with 1097 - | `End -> () 1098 - | `Resize _ -> () 1099 - | #Unescape.event as event -> 1100 - let event = (event : Unescape.event :> Ui.event) in 1101 - ignore (Renderer.dispatch_event renderer event : [ `Handled | `Unhandled ]))) 1102 - ;; 1186 + match term with 1187 + | Some term -> run_with_term term ?tick_period ?tick ~renderer quit t 1188 + | None -> 1189 + let term = Term.create () in 1190 + run_with_term term ?tick_period ?tick ~renderer quit t; 1191 + Term.release term 1192 + ;; 1193 + end 1103 1194 1104 - let run_with_term term ?tick_period ?(tick = ignore) ~renderer quit t = 1105 - let quit = Lwd.observe (Lwd.get quit) in 1106 - let root = Lwd.observe t in 1107 - let rec loop () = 1108 - let quit = Lwd.quick_sample quit in 1109 - if not quit 1110 - then ( 1111 - step ~process_event:true ?timeout:tick_period ~renderer term root; 1112 - tick (); 1113 - loop ()) 1114 - in 1115 - loop (); 1116 - ignore (Lwd.quick_release root); 1117 - ignore (Lwd.quick_release quit) 1118 - ;; 1195 + let step = Internal.step ~await_read:Internal.await_read_unix 1196 + let run_with_term = Internal.run_with_term ~step 1119 1197 1120 - let run 1121 - ?tick_period 1122 - ?tick 1123 - ?term 1124 - ?(renderer = Renderer.make ()) 1125 - ?quit 1126 - ?(quit_on_escape = true) 1127 - ?(quit_on_ctrl_q = true) 1128 - t 1129 - = 1130 - let quit = 1131 - match quit with 1132 - | Some quit -> quit 1133 - | None -> Lwd.var false 1134 - in 1135 - let t = 1136 - Lwd.map 1137 - t 1138 - ~f: 1139 - (Ui.event_filter (function 1140 - | `Key (`ASCII 'Q', [ `Ctrl ]) when quit_on_ctrl_q -> 1141 - Lwd.set quit true; 1142 - `Handled 1143 - | `Key (`Escape, []) when quit_on_escape -> 1144 - Lwd.set quit true; 1145 - `Handled 1146 - | _ -> `Unhandled)) 1147 - in 1148 - match term with 1149 - | Some term -> run_with_term term ?tick_period ?tick ~renderer quit t 1150 - | None -> 1151 - let term = Term.create () in 1152 - run_with_term term ?tick_period ?tick ~renderer quit t; 1153 - Term.release term 1198 + let run = 1199 + Internal.run 1200 + ~run_with_term: 1201 + (Internal.run_with_term 1202 + ~step:(Internal.step ~await_read:Internal.await_read_unix)) 1154 1203 ;; 1155 1204 end
+67 -3
forks/nottui/lib/nottui/nottui_main.mli
··· 366 366 module Ui_loop : sig 367 367 open Notty_unix 368 368 369 - 370 369 (** Run one step of the main loop. 371 370 372 371 Update output image describe by the provided [root]. 373 372 If [process_event], wait up to [timeout] seconds for an input event, then 374 373 consume and dispatch it. *) 375 374 val step 376 - : ?await_read:(Unix.file_descr -> float -> [ `Ready | `NotReady ]) 377 - -> ?process_event:bool 375 + : ?process_event:bool 378 376 -> ?timeout:float 379 377 -> renderer:Renderer.t 380 378 -> Term.t ··· 402 400 -> ?quit_on_ctrl_q:bool 403 401 -> ui Lwd.t 404 402 -> unit 403 + 404 + module Internal : sig 405 + (** Provides slightly more powerful interfaces as compared to the Ui_llop module. 406 + 407 + Allows you to override the step/ await_read function. 408 + 409 + This should allow you to implement your own concurrency framework and modify how stepping is done. *) 410 + 411 + type step = 412 + ?process_event:bool 413 + -> ?timeout:float 414 + -> renderer:Renderer.t 415 + -> Term.t 416 + -> ui Lwd.root 417 + -> unit 418 + 419 + val await_read_unix : Unix.file_descr -> float -> [ `NotReady | `Ready ] 420 + 421 + (** Run one step of the main loop. 422 + 423 + Update output image describe by the provided [root]. 424 + If [process_event], wait up to [timeout] seconds for an input event, then 425 + consume and dispatch it. 426 + 427 + [?await_read]- A function that waits for the file handle to be ready for reading for up to the provided timeout (-1.0 for no timeout). This exists entirely so this waiting can be overriden to interoperate with an effects based async system. *) 428 + val step 429 + : ?await_read:(Unix.file_descr -> float -> [ `Ready | `NotReady ]) 430 + -> ?process_event:bool 431 + -> ?timeout:float 432 + -> renderer:Renderer.t 433 + -> Term.t 434 + -> ui Lwd.root 435 + -> unit 436 + 437 + type run_with_term_intern= 438 + step:step 439 + -> Term.t 440 + -> ?tick_period:float 441 + -> ?tick:(unit -> unit) 442 + -> renderer:Renderer.t 443 + -> bool Lwd.var 444 + -> ui Lwd.t 445 + -> unit 446 + 447 + type run_with_term= 448 + Term.t 449 + -> ?tick_period:float 450 + -> ?tick:(unit -> unit) 451 + -> renderer:Renderer.t 452 + -> bool Lwd.var 453 + -> ui Lwd.t 454 + -> unit 455 + val run_with_term:run_with_term_intern 456 + 457 + val run: 458 + run_with_term:run_with_term 459 + -> ?tick_period:float 460 + -> ?tick:(unit -> unit) 461 + -> ?term:Term.t 462 + -> ?renderer:Renderer.t 463 + -> ?quit:bool Lwd.var 464 + -> ?quit_on_escape:bool 465 + -> ?quit_on_ctrl_q:bool 466 + -> ui Lwd.t 467 + -> unit 468 + end 405 469 end
+5
forks/nottui/lib/nottui_picos/dune
··· 1 + (library 2 + (name nottui_picos) 3 + (public_name nottui_picos) 4 + (libraries nottui picos picos_std.structured picos_io picos_std.finally ) 5 + )
+32
forks/nottui/lib/nottui_picos/nottui_picos.ml
··· 1 + open Notty 2 + open Nottui 3 + open Picos 4 + open Picos_std_structured 5 + open Picos_std_finally 6 + 7 + module Ui_loop = struct 8 + let step in_fd = 9 + Ui_loop.Internal.step ~await_read:(fun _ timeout -> 10 + (*await the read inside a promise*) 11 + let rec select ()= 12 + match Picos_io.Unix.select [in_fd] [] [in_fd ] timeout with 13 + | [], [], [] -> `NotReady 14 + | _ -> `Ready 15 + | exception Unix.Unix_error (Unix.EINTR, _, _) -> select () 16 + 17 + in 18 + select () 19 + ) 20 + ;; 21 + 22 + let run_with_term term = 23 + let in_fd,out_fd= Notty_unix.Term.fds term in 24 + let in_fd=Picos_io_fd.create in_fd in 25 + let step= step in_fd in 26 + 27 + Ui_loop.Internal.run_with_term ~step term 28 + ;; 29 + 30 + 31 + let run = Ui_loop.Internal.run ~run_with_term 32 + end
+47
forks/nottui/lib/nottui_picos/nottui_picos.mli
··· 1 + 2 + open Notty 3 + open Nottui 4 + open Picos 5 + module Ui_loop : sig 6 + open Notty_unix 7 + 8 + 9 + (** Run one step of the main loop. 10 + 11 + Update output image describe by the provided [root]. 12 + If [process_event], wait up to [timeout] seconds for an input event, then 13 + consume and dispatch it. 14 + 15 + *) 16 + val step: 17 + Picos_io_fd.t 18 + -> ?process_event:bool 19 + -> ?timeout:float 20 + -> renderer:Renderer.t 21 + -> Term.t 22 + -> ui Lwd.root 23 + -> unit 24 + 25 + (** Repeatedly run steps of the main loop, until either: 26 + - [quit] becomes true, 27 + - the ui computation raises an exception, 28 + - if [quit_on_ctrl_q] was true or not provided, wait for Ctrl-Q event 29 + - if [quit_on_escape] was true or not provided, wait for Escape event 30 + 31 + Specific [term] or [renderer] instances can be provided, otherwise new 32 + ones will be allocated and released. 33 + 34 + Uses Picos for concurrency. 35 + The only change vs the normal version is this yields whenever waiting for input 36 + *) 37 + val run 38 + : ?tick_period:float 39 + -> ?tick:(unit -> unit) 40 + -> ?term:Term.t 41 + -> ?renderer:Renderer.t 42 + -> ?quit:bool Lwd.var 43 + -> ?quit_on_escape:bool 44 + -> ?quit_on_ctrl_q:bool 45 + -> ui Lwd.t 46 + -> unit 47 + end
+1
jj_tui/bin/dune
··· 5 5 signal 6 6 jj_tui 7 7 nottui 8 + nottui_picos 8 9 base 9 10 stdio 10 11 picos_io
+18 -30
jj_tui/bin/main.ml
··· 5 5 open Picos_std_structured 6 6 open Jj_tui.Logging 7 7 8 + let await_read_unix fd timeout : [ `Ready | `NotReady ] = 9 + let rec select () = 10 + match Unix.select [ fd ] [] [ fd ] timeout with 11 + | [], [], [] -> 12 + `NotReady 13 + | _ -> 14 + `Ready 15 + | exception Unix.Unix_error (Unix.EINTR, _, _) -> 16 + select () 17 + in 18 + select () 19 + ;; 20 + 8 21 (* let file_logger ~logs_stream= 9 22 let logs_crs=Picos_std_sync.Stream.tap logs_stream in 10 23 let file=Picos_io.Unix.openfile "" in ··· 28 41 `Unhandled) 29 42 in 30 43 let rec loop () = 31 - let open Picos_std_event in 32 44 if not (Lwd.peek quit) 33 45 then ( 34 46 (* let start_time = Unix.gettimeofday() in *) ··· 36 48 let prev_term_width, prev_term_height = Lwd.peek Vars.term_width_height in 37 49 if term_width <> prev_term_width || term_height <> prev_term_height 38 50 then Lwd.set Vars.term_width_height (term_width, term_height); 39 - let stored_fd=ref (Obj.magic()) in 40 - Nottui.Ui_loop.step 41 - ~await_read:(fun unix_fd timeout -> 42 - 43 - let fd = 44 - if (Picos_io_fd.unsafe_get (!stored_fd)) = unix_fd then 45 - !stored_fd 46 - else 47 - let picos_fd=Picos_io_fd.create ~dispose:false unix_fd in 48 - stored_fd:=picos_fd; 49 - picos_fd 50 - in 51 - let res = 52 - let event_ret ret = Event.map (fun _ -> ret) in 53 - Picos_std_event.Event.select 54 - [ 55 - Picos_io_select.on fd `R |> event_ret `Ready 56 - ; Picos_io_select.on fd `W |> event_ret `Ready 57 - ; Picos_io_select.timeout ~seconds:timeout |> event_ret `NotReady 58 - ] 59 - in 60 - res) 51 + Nottui_picos.step 52 + ~await_read:(fun fd timeout -> 53 + (*await the read inside a promise*) 54 + Promise.await @@ Flock.fork_as_promise (fun _ -> await_read_unix fd timeout)) 61 55 ~process_event:true 62 56 ~timeout:0.01 63 57 ~renderer 64 58 term 65 59 (Lwd.observe @@ root); 66 - (*Sleep for a bit to stop spinning the cpu 67 - TODO: May not be needed, nottui may sleep for a bit anyway 68 - *) 69 - (* let end_time = Unix.gettimeofday () in *) 70 - (* let elapsed = end_time -. start_time in *) 71 - (* let sleep_time = max 0.01 (0.01 -. elapsed) in *) 72 - (* Picos_io.Unix.sleepf sleep_time; *) 73 60 loop ()) 74 61 in 75 62 loop () ··· 83 70 Flock.terminate () 84 71 ;; 85 72 73 + Picos_io.Unix 86 74 let start () = 87 75 Picos_mux_multififo.run_on ~n_domains:1 (fun _ -> 88 76 Flock.join_after @@ fun () ->