package miaou-core

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file direct_page.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
(******************************************************************************)
(*                                                                            *)
(* SPDX-License-Identifier: MIT                                               *)
(* Copyright (c) 2026 Nomadic Labs <contact@nomadic-labs.com>                 *)
(*                                                                            *)
(******************************************************************************)

type _ Effect.t +=
  | Navigate : string -> unit Effect.t
  | Go_back : unit Effect.t
  | Quit_app : unit Effect.t

let navigate page = Effect.perform (Navigate page)

let go_back () = Effect.perform Go_back

let quit () = Effect.perform Quit_app

let run f =
  let nav = ref None in
  let result =
    Effect.Deep.try_with
      f
      ()
      {
        effc =
          (fun (type a) (eff : a Effect.t) ->
            match eff with
            | Navigate page ->
                Some
                  (fun (k : (a, _) Effect.Deep.continuation) ->
                    nav := Some (`Goto page) ;
                    Effect.Deep.continue k ())
            | Go_back ->
                Some
                  (fun (k : (a, _) Effect.Deep.continuation) ->
                    nav := Some `Back ;
                    Effect.Deep.continue k ())
            | Quit_app ->
                Some
                  (fun (k : (a, _) Effect.Deep.continuation) ->
                    nav := Some `Quit ;
                    Effect.Deep.continue k ())
            | _ -> None);
      }
  in
  (result, !nav)

module type REQUIRED = sig
  type state

  val init : unit -> state

  val view : state -> focus:bool -> size:LTerm_geom.size -> string

  (** Key handler. Use [navigate], [go_back], [quit] for navigation. *)
  val on_key : state -> string -> size:LTerm_geom.size -> state
end

module type FULL = sig
  include REQUIRED

  (** Display-only key hints for footer. *)
  val key_hints : state -> (string * string) list

  (** @deprecated Use [key_hints] instead. *)
  val keymap : state -> (string * string) list

  val refresh : state -> state

  val has_modal : state -> bool

  val on_modal_key : state -> string -> size:LTerm_geom.size -> state
end

module With_defaults (R : REQUIRED) : FULL with type state = R.state = struct
  include R

  let key_hints _ = []

  let keymap = key_hints

  let refresh s = s

  let has_modal _ = false

  let on_modal_key s _ ~size:_ = s
end

module Make (D : FULL) : Tui_page.PAGE_SIG = struct
  type state = D.state

  type msg = unit

  type key_binding = state Tui_page.key_binding_desc

  type pstate = state Navigation.t

  let init () = Navigation.make (D.init ())

  let update ps _ = ps

  let view ps ~focus ~size = D.view ps.Navigation.s ~focus ~size

  let with_nav ps f =
    let s', nav = run (fun () -> f ps.Navigation.s) in
    let ps' = {ps with Navigation.s = s'} in
    match nav with
    | Some (`Goto page) -> Navigation.goto page ps'
    | Some `Back -> Navigation.back ps'
    | Some `Quit -> Navigation.quit ps'
    | None -> ps'

  (** New typed key handler. Converts Keys.t to string and calls D.on_key. *)
  let on_key ps key ~size =
    let key_str = Keys.to_string key in
    let ps' = with_nav ps (fun s -> D.on_key s key_str ~size) in
    (* Direct_page always bubbles - navigation is via effects *)
    (ps', Miaou_interfaces.Key_event.Bubble)

  (** New typed modal key handler. *)
  let on_modal_key ps key ~size =
    let key_str = Keys.to_string key in
    let ps' = with_nav ps (fun s -> D.on_modal_key s key_str ~size) in
    (ps', Miaou_interfaces.Key_event.Bubble)

  (** Display-only key hints for footer. *)
  let key_hints ps =
    List.map
      (fun (key, help) -> Tui_page.{key; help})
      (D.key_hints ps.Navigation.s)

  (** @deprecated Legacy string-based key handler. *)
  let handle_key ps key ~size = with_nav ps (fun s -> D.on_key s key ~size)

  (** @deprecated Legacy string-based modal key handler. *)
  let handle_modal_key ps key ~size =
    with_nav ps (fun s -> D.on_modal_key s key ~size)

  let refresh ps = with_nav ps (fun s -> D.refresh s)

  (** @deprecated Use [key_hints] instead. *)
  let keymap ps =
    List.map
      (fun (key, help) ->
        {Tui_page.key; action = Fun.id; help; display_only = true})
      (D.keymap ps.Navigation.s)

  let has_modal ps = D.has_modal ps.Navigation.s

  let move ps _ = ps

  let service_select ps _ = ps

  let service_cycle ps _ = ps

  let back ps = Navigation.back ps

  let handled_keys () = []
end