summaryrefslogtreecommitdiff
path: root/lib/editor.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/editor.ml')
-rw-r--r--lib/editor.ml85
1 files changed, 80 insertions, 5 deletions
diff --git a/lib/editor.ml b/lib/editor.ml
index 69dc666..c34d558 100644
--- a/lib/editor.ml
+++ b/lib/editor.ml
@@ -2,7 +2,7 @@ open Base
2module Buffer = EditorBuffer 2module Buffer = EditorBuffer
3open Util 3open Util
4 4
5type mode = Normal | Insert 5type mode = Normal | Insert | Control
6type cursor = int * int 6type cursor = int * int
7 7
8type editor = { 8type editor = {
@@ -15,6 +15,10 @@ type editor = {
15 pending : Key.t Sequence.t; 15 pending : Key.t Sequence.t;
16 i_pending : Command.t Sequence.t; 16 i_pending : Command.t Sequence.t;
17 n_pending : Command.t Sequence.t; 17 n_pending : Command.t Sequence.t;
18 status_size : int;
19 message : string option;
20 message_timestamp : float;
21 message_duration : float;
18} 22}
19 23
20type t = editor 24type t = editor
@@ -30,8 +34,57 @@ let init (c : Config.t) : editor =
30 pending = Key.stream; 34 pending = Key.stream;
31 i_pending = Command.i_stream; 35 i_pending = Command.i_stream;
32 n_pending = Command.n_stream; 36 n_pending = Command.n_stream;
37 status_size = 2;
38 message = Some "Hello, control line!";
39 message_timestamp = Unix.time ();
40 message_duration = 5.;
33 } 41 }
34 42
43let string_of_mode = function
44 | Insert -> " I "
45 | Normal -> " N "
46 | Control -> " C "
47
48let statusbar e =
49 let open Text in
50 (* let open Sequence.Infix in *)
51 let w = e.term.size |> snd in
52 let status =
53 let mode = e.mode |> string_of_mode |> sequence_of_string in
54 let msize = Sequence.length mode
55 and path =
56 Buffer.(
57 e.buffer |> Option.map ~f:kind
58 |> Option.value ~default:No_name
59 |> string_of_kind |> sequence_of_string)
60 and br, bc =
61 Option.(e.buffer |> map ~f:Buffer.size |> value ~default:(0, 0))
62 and cr, cc =
63 Option.(
64 e.buffer
65 |> map ~f:(Buffer.cursor ~rendered:false)
66 |> value ~default:(0, 0))
67 in
68 let perc =
69 match cr with
70 | 0 -> "Top"
71 | n when n = br -> "Bot"
72 | n -> Printf.sprintf "%2d%%" (100 * n / br)
73 in
74 let nav =
75 Printf.sprintf "%d/%d %2d/%2d [%s] " cr br cc bc perc
76 |> sequence_of_string
77 in
78 let nsize = Sequence.length nav in
79 spread ~l:(bold mode) ~lsize:msize ~c:path ~r:(bold nav) ~rsize:nsize
80 ~fill:' ' w
81 |> invert
82 and control =
83 let msg = Option.value ~default:"" e.message |> sequence_of_string in
84 spread ~l:msg ~fill:' ' w
85 in
86 Sequence.(take (of_list [ status; control ]) e.status_size)
87
35type 'a action = t -> 'a * t 88type 'a action = t -> 'a * t
36 89
37module Action = struct 90module Action = struct
@@ -71,6 +124,8 @@ module Action = struct
71 let update_cursor = 124 let update_cursor =
72 let aux e = 125 let aux e =
73 let dx, dy = e.offset and rs, cs = e.term.size in 126 let dx, dy = e.offset and rs, cs = e.term.size in
127 (* Limit cursor to buffer view *)
128 let rs = rs - e.status_size in
74 match Option.map ~f:Buffer.cursor e.buffer with 129 match Option.map ~f:Buffer.cursor e.buffer with
75 | None -> { e with cursor = (1, 1); offset = (0, 0) } 130 | None -> { e with cursor = (1, 1); offset = (0, 0) }
76 | Some (cx, cy) -> 131 | Some (cx, cy) ->
@@ -107,22 +162,41 @@ module Action = struct
107 let x, y = e.offset 162 let x, y = e.offset
108 and ((r, c) as size) = e.term.size 163 and ((r, c) as size) = e.term.size
109 and fill = Sequence.singleton '~' 164 and fill = Sequence.singleton '~'
165 and status = statusbar e
110 and limit = 166 and limit =
111 Buffer.(if e.rendered then rendered_view else unrendered_view) 167 Buffer.(if e.rendered then rendered_view else unrendered_view)
112 in 168 in
113 let view = 169 let ssize = e.status_size in
170 let bufview =
114 Option.( 171 Option.(
115 e.buffer >>| limit x y r c 172 e.buffer
173 >>| limit x y (r - ssize) c
116 |> value ~default:(welcome size) 174 |> value ~default:(welcome size)
117 |> Text.extend ~fill r) 175 |> Text.extend ~fill r
176 |> Fn.flip Sequence.take (r - ssize))
118 in 177 in
119 Terminal.redraw view e.cursor 178 let screen = Sequence.append bufview status in
179 Terminal.redraw screen e.cursor
120 in 180 in
121 get >>| aux 181 get >>| aux
122 182
123 (* TODO: save logic *) 183 (* TODO: save logic *)
124 let quit n = Stdlib.exit n 184 let quit n = Stdlib.exit n
125 185
186 (* Statusbar *)
187 let set_message m e =
188 ((), { e with message = m; message_timestamp = Unix.time () })
189
190
191 let tick =
192 let check_message_timestamp e =
193 let now = Unix.time () in
194 let expired = Float.(e.message_timestamp < now - e.message_duration) in
195 if Option.is_some e.message && expired then { e with message = None }
196 else e
197 in
198 get >>| check_message_timestamp >>= put
199
126 (* Debug *) 200 (* Debug *)
127 let get_rendered e = (e.rendered, e) 201 let get_rendered e = (e.rendered, e)
128 let set_rendered r e = ((), { e with rendered = r }) 202 let set_rendered r e = ((), { e with rendered = r })
@@ -376,6 +450,7 @@ let handle_next_command m e =
376 match Sequence.next e.n_pending with 450 match Sequence.next e.n_pending with
377 | None -> ((), e) 451 | None -> ((), e)
378 | Some (h, t) -> handle_normal_command h { e with n_pending = t }) 452 | Some (h, t) -> handle_normal_command h { e with n_pending = t })
453 | Control -> failwith "unimplemented"
379 454
380let handle_next_command = 455let handle_next_command =
381 let open Action in 456 let open Action in