package miaou-driver-matrix

  1. Overview
  2. Docs
Miaou high-performance terminal driver with diff rendering

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.5.2.tar.gz
md5=60a3b9f181f24572a06a9492532bfdda
sha512=fcc35a275066be2900e6201782faf47503076fa4640f08cf78067835a6f447b74613009e55b2ac799adb7ca46f1bffa261fc5971753f2cc3c6bef327511c7ef6

doc/src/miaou-driver-matrix.driver/matrix_driver.ml.html

Source file matrix_driver.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
(*****************************************************************************)
(*                                                                           *)
(* SPDX-License-Identifier: MIT                                              *)
(* Copyright (c) 2025 Nomadic Labs <contact@nomadic-labs.com>                *)
(*                                                                           *)
(*****************************************************************************)

(** Terminal backend for the Matrix driver.

    Handles terminal-specific lifecycle (setup, raw mode, signals, cleanup)
    and delegates the main loop to {!Matrix_main_loop}. *)

open Miaou_core

let available = true

module Fibers = Miaou_helpers.Fiber_runtime

let run ?(config = None) (initial_page : (module Tui_page.PAGE_SIG)) :
    [`Quit | `Back | `SwitchTo of string] =
  Fibers.with_page_switch (fun env _page_sw ->
      (* Load configuration *)
      let config =
        match config with Some c -> c | None -> Matrix_config.load ()
      in

      (* Setup terminal *)
      let terminal = Matrix_terminal.setup () in
      at_exit (fun () -> Matrix_terminal.cleanup terminal) ;

      (* Get terminal size *)
      let rows, cols = Matrix_terminal.size terminal in

      (* Create buffer *)
      let buffer = Matrix_buffer.create ~rows ~cols in

      (* Create parser and writer *)
      let parser = Matrix_ansi_parser.create () in
      let writer = Matrix_ansi_writer.create () in

      (* Create input handler *)
      let input =
        Matrix_input.create ~handle_sigint:config.handle_sigint terminal
      in

      (* Build I/O interface for the shared main loop *)
      let io : Matrix_io.t =
        {
          write = Matrix_terminal.write terminal;
          drain = (fun () -> Matrix_input.drain input);
          size = (fun () -> Matrix_terminal.size terminal);
          invalidate_size_cache =
            (fun () -> Matrix_terminal.invalidate_size_cache terminal);
        }
      in

      (* Create render loop with terminal write function *)
      let render_loop =
        Matrix_render_loop.create
          ~config
          ~buffer
          ~writer
          ~write:(Matrix_terminal.write terminal)
      in

      (* Configure inline vs alt-screen before entering raw mode *)
      Matrix_terminal.set_alt_screen terminal (not config.inline_mode) ;

      (* Enter raw mode and enable mouse (mouse off in inline mode) *)
      Matrix_terminal.enter_raw terminal ;
      if config.enable_mouse && not config.inline_mode then
        Matrix_terminal.enable_mouse terminal ;

      (* Re-check size after raw mode; some terminals report 80x24 initially *)
      let sleep_s seconds = Eio.Time.sleep env#clock seconds in
      let rec read_size_retry attempts last =
        if attempts <= 0 then last
        else (
          Matrix_terminal.invalidate_size_cache terminal ;
          let s = Matrix_terminal.size terminal in
          if s <> last && s <> (24, 80) then s
          else (
            sleep_s 0.02 ;
            read_size_retry (attempts - 1) s))
      in
      let rows2, cols2 = read_size_retry 5 (rows, cols) in
      if rows2 <> rows || cols2 <> cols then
        Matrix_buffer.resize buffer ~rows:rows2 ~cols:cols2 ;

      (* Hide cursor *)
      Matrix_terminal.write terminal Matrix_ansi_writer.cursor_hide ;

      (* Clear screen initially. In inline mode we skip the clear and let
         the diff renderer paint over the current scrollback contents
         starting from the cursor position; the final frame stays in
         scrollback after exit. *)
      if not config.inline_mode then
        Matrix_terminal.write terminal "\027[2J\027[H" ;

      (* Start render domain - runs at 60 FPS in parallel *)
      Matrix_render_loop.start render_loop ;

      (* Start decoupled input reader fiber *)
      Matrix_input.start input ;

      (* Build context for the shared main loop *)
      let ctx : Matrix_main_loop.context =
        {config; buffer; parser; render_loop; io}
      in

      (* Run the shared main loop *)
      let result = Matrix_main_loop.run ctx ~env initial_page in

      (* Cleanup *)
      Matrix_input.stop input ;
      Matrix_render_loop.shutdown render_loop ;
      Matrix_terminal.write terminal Matrix_ansi_writer.cursor_show ;
      Matrix_terminal.write terminal "\027[0m" ;
      (* Save screen content for debugging - will be printed after exit *)
      let screen_dump = Matrix_buffer.dump_to_string buffer in
      Matrix_terminal.set_exit_screen_dump terminal screen_dump ;
      Matrix_terminal.cleanup terminal ;

      result)