diff options
Diffstat (limited to 'lib/editor.ml')
| -rw-r--r-- | lib/editor.ml | 85 |
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 | |||
| 2 | module Buffer = EditorBuffer | 2 | module Buffer = EditorBuffer |
| 3 | open Util | 3 | open Util |
| 4 | 4 | ||
| 5 | type mode = Normal | Insert | 5 | type mode = Normal | Insert | Control |
| 6 | type cursor = int * int | 6 | type cursor = int * int |
| 7 | 7 | ||
| 8 | type editor = { | 8 | type 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 | ||
| 20 | type t = editor | 24 | type 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 | ||
| 43 | let string_of_mode = function | ||
| 44 | | Insert -> " I " | ||
| 45 | | Normal -> " N " | ||
| 46 | | Control -> " C " | ||
| 47 | |||
| 48 | let 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 | |||
| 35 | type 'a action = t -> 'a * t | 88 | type 'a action = t -> 'a * t |
| 36 | 89 | ||
| 37 | module Action = struct | 90 | module 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 | ||
| 380 | let handle_next_command = | 455 | let handle_next_command = |
| 381 | let open Action in | 456 | let open Action in |
