diff --git a/examples/list/dune b/examples/list/dune index 890388a..b00e73b 100644 --- a/examples/list/dune +++ b/examples/list/dune @@ -1,3 +1,3 @@ (executable - (name main) - (libraries minttea spices leaves str)) + (name main) + (libraries minttea spices leaves str)) diff --git a/minttea/config.ml b/minttea/config.ml new file mode 100644 index 0000000..a0dceaf --- /dev/null +++ b/minttea/config.ml @@ -0,0 +1 @@ +type t = { render_mode : [ `clear | `persist ]; fps : int } diff --git a/minttea/io_loop.ml b/minttea/io_loop.ml index f9091bc..27675b9 100644 --- a/minttea/io_loop.ml +++ b/minttea/io_loop.ml @@ -46,5 +46,5 @@ let run runner = link runner; let termios = Stdin.setup () in let _worker = spawn_link (fun () -> loop runner) in - let _ = receive () in + let _ = receive_any () in Stdin.shutdown termios diff --git a/minttea/minttea.ml b/minttea/minttea.ml index 30e33fd..00f14df 100644 --- a/minttea/minttea.ml +++ b/minttea/minttea.ml @@ -3,21 +3,23 @@ module Event = Event module Command = Command module App = App module Program = Program +module Config = Config +let config ?(render_mode = `clear) ?(fps = 60) () = Config.{ render_mode; fps } let app = App.make -let run ?(fps = 60) ~initial_model app = - let prog = Program.make ~app ~fps in +let run ?(config = config ()) ~initial_model app = + let prog = Program.make ~app ~config in Program.run prog initial_model; Logger.trace (fun f -> f "terminating") -let start app ~initial_model = +let start ?(config = config ()) app ~initial_model = let module App = struct let start () = Logger.set_log_level None; let pid = spawn_link (fun () -> - run app ~initial_model; + run ~config app ~initial_model; Logger.trace (fun f -> f "about to shutdown"); shutdown ~status:0 ()) in diff --git a/minttea/minttea.mli b/minttea/minttea.mli index 2770820..afa6023 100644 --- a/minttea/minttea.mli +++ b/minttea/minttea.mli @@ -1,5 +1,11 @@ open Riot +module Config : sig + type t +end + +val config : ?render_mode:[ `clear | `persist ] -> ?fps:int -> unit -> Config.t + module Event : sig type modifier = No_modifier | Ctrl @@ -46,5 +52,5 @@ val app : unit -> 'model App.t -val run : ?fps:int -> initial_model:'model -> 'model App.t -> unit -val start : 'model App.t -> initial_model:'model -> unit +val run : ?config:Config.t -> initial_model:'model -> 'model App.t -> unit +val start : ?config:Config.t -> 'model App.t -> initial_model:'model -> unit diff --git a/minttea/program.ml b/minttea/program.ml index dda53b5..1378aef 100644 --- a/minttea/program.ml +++ b/minttea/program.ml @@ -1,15 +1,15 @@ open Riot type Message.t += Timer of unit Ref.t | Shutdown -type 'model t = { app : 'model App.t; fps : int } +type 'model t = { app : 'model App.t; config : Config.t } -let make ~app ~fps = { app; fps } +let make ~app ~config = { app; config } exception Exit let rec loop renderer (app : 'model App.t) (model : 'model) = let event = - match receive () with + match receive_any () with | Timer ref -> Event.Timer ref | Io_loop.Input event -> event | message -> Event.Custom message @@ -55,14 +55,14 @@ let init { app; _ } initial_model renderer = Renderer.render renderer view; loop renderer app initial_model -let run ({ fps; _ } as t) initial_model = +let run ({ config; _ } as t) initial_model = Printexc.record_backtrace true; let renderer = spawn (fun () -> (* NOTE(@leostera): reintroduce this when riot brings back process-stealing *) (* process_flag (Priority High); *) let runner = Process.await_name "Minttea.runner" in - Renderer.run ~fps ~runner) + Renderer.run ~config ~runner) in let runner = spawn (fun () -> diff --git a/minttea/renderer.ml b/minttea/renderer.ml index 7b0cff8..86bb25a 100644 --- a/minttea/renderer.ml +++ b/minttea/renderer.ml @@ -14,6 +14,7 @@ type t = { ticker : Timer.timer; width : int; height : int; + render_mode : [ `clear | `persist ]; mutable buffer : string; mutable last_render : string; mutable lines_rendered : int; @@ -27,7 +28,7 @@ let same_as_last_flush t = t.buffer = t.last_render let lines t = t.buffer |> String.split_on_char '\n' let rec loop t = - match receive () with + match receive_any () with | Shutdown -> flush t; restore t @@ -61,7 +62,7 @@ and flush t = let new_lines_this_flush = List.length new_lines in (* clean last rendered lines *) - if t.lines_rendered > 0 then + if t.render_mode = `clear && t.lines_rendered > 0 then for _i = 1 to t.lines_rendered - 1 do Terminal.clear_line (); Terminal.cursor_up 1 @@ -107,7 +108,8 @@ let max_fps = 120 let cap fps = Int.max 1 (Int.min fps max_fps) |> Int.to_float let fps_to_float fps = 1. /. cap fps *. 1_000. |> Int64.of_float -let run ~fps ~runner = +let run ~config ~runner = + let Config.{ render_mode; fps } = config in let ticker = Riot.Timer.send_interval ~every:(fps_to_float fps) (self ()) Tick |> Result.get_ok @@ -123,6 +125,7 @@ let run ~fps ~runner = is_altscreen_active = false; lines_rendered = 0; cursor_visibility = `visible; + render_mode; } let render pid output = send pid (Render output) diff --git a/minttea/renderer.mli b/minttea/renderer.mli index b017ccf..749a7a1 100644 --- a/minttea/renderer.mli +++ b/minttea/renderer.mli @@ -1,6 +1,6 @@ open Riot -val run : fps:int -> runner:Pid.t -> unit +val run : config:Config.t -> runner:Pid.t -> unit val render : Pid.t -> string -> unit val enter_alt_screen : Pid.t -> unit val exit_alt_screen : Pid.t -> unit