L'éditeur démarre en mode normal. Les commandes sont les suivantes:
: -> passer en mode commande
0 -> revenir aux coordonnées 0:0
- s -> mets la case pointée à la valeur actuelle
- q, d -> mets la valeur actuelle à la précédente, ou la suivante
f -> effectue une étape de simulation
+ i -> passe en mode insertion
h, j, k, l -> se déplace d'une case à gauche, en bas, en haut,
ou à droite.
- i, o -> zoome, ou dézoome
+ o, p -> zoome, ou dézoome
-Toute commande (sauf s, :, et 0) peut être précédée d'un nombre (en
+Toute commande (sauf i, :, et 0) peut être précédée d'un nombre (en
décimal, ne commençant pas par 0) qui indique le nombre de fois que l'on
souhaite l'exécuter.
On peut activer l'autocomplétion en faisant une tabulation.
Toutes les autres touches servent simplement à écrire la commande.
+En mode insertion, que l'on active en faisant i, on peut définir la
+valeur des différentes cases:
+ \n -> Reviens à la première colonne, à la ligne d'en dessous.
+ ESC -> Reviens en mode normal.
+ Tout autre caractère est converti en un type de case, et écrit
+ dans la case actuelle avant de passer à la case de
+ droite.
+
J'accepterai avec plaisir les contributions utiles envoyées par mail
(via git send-mail) à mon adresse personelle (indiquée sur mon site).
* with this program. If not, see <https://www.gnu.org/licenses/>.
*)
-type 'c editor_state_aux = { board: 'c Automata.board; pos: int * int; current: 'c; size: int }
+type 'c editor_state_aux = { board: 'c Automata.board; pos: int * int; size: int }
type editor_state = EditorState : (module Automata.Automaton with type t = 'c) * 'c editor_state_aux -> editor_state
match Automata.automata with
| auto :: _ ->
let module Auto = (val auto) in
- EditorState
- ( (module Auto),
- { board = Automata.initial (module Auto); pos = (0, 0); current = Auto.default; size = 16 } )
+ EditorState ((module Auto), { board = Automata.initial (module Auto); pos = (0, 0); size = 16 })
| [] -> assert false
module rec ModeAux : sig
let module M = (val m) in
M.name
-let render_world (EditorState (m, { board; current; pos = px, py; size })) =
+let render_world (EditorState (m, { board; pos = px, py; size })) =
let module M = (val m) in
let w = (Graphics.size_x () / size) + 1
and h = (Graphics.size_y () / size) + 1 in
Graphics.draw_rect ((x - wx) * size) ((y - wy) * size) size size
done
done;
- let r, g, b = M.color current in
- let r, g, b = (int_of_char r, int_of_char g, int_of_char b) in
- Graphics.set_color (Graphics.rgb r g b);
- Graphics.fill_rect (((px - wx) * size) + 5) (((py - wy) * size) + 5) (max (size - 10) 1) (max (size - 10) 1);
Graphics.set_color (Graphics.rgb 127 127 127);
- Graphics.draw_rect (((px - wx) * size) + 5) (((py - wy) * size) + 5) (max (size - 10) 1) (max (size - 10) 1)
+ Graphics.draw_rect (((px - wx) * size) + 1) (((py - wy) * size) + 1) (size - 2) (size - 2)
module rec Command : (Mode with type initer = string) = struct
type state = string * string list
match List.find_opt (fun m -> get_name m = auto) Automata.automata with
| Some auto ->
let module M = (val auto) in
- ( EditorState
- ( (module M),
- { board = Automata.initial (module M); pos = (0, 0); current = M.default; size = 16 }
- ),
+ ( EditorState ((module M), { board = Automata.initial (module M); pos = (0, 0); size = 16 }),
Either.right (ModeAux.ModeAndState ((module Normal), Normal.initial ())) )
| None ->
Printf.fprintf stderr "Automate inconnu: `%s' !\n%!" auto;
let auto = List.find (fun m -> get_name m = name) Automata.automata in
let module M = (val auto) in
( EditorState
- ( (module M),
- {
- board = Automata.deserialise (module M) f;
- pos = st.pos;
- current = M.default;
- size = st.size;
- } ),
+ ((module M), { board = Automata.deserialise (module M) f; pos = st.pos; size = st.size }),
Either.right (ModeAux.ModeAndState ((module Normal), Normal.initial ())) ))
with Sys_error _ ->
Printf.fprintf stderr "Failed to write file `%s' !\n%!" f;
end
and Normal : (Mode with type initer = unit) = struct
- module rec Impl : (Mode with type initer = unit) = struct
- type state = { n: int option }
+ type state = { n: int option }
- type initer = unit
+ type initer = unit
- let initial () = { n = None }
+ let initial () = { n = None }
- let render st _ = render_world st
+ let render st _ = render_world st
- let update (EditorState (m, st)) n =
- let module M = (val m) in
- let set_current ({ board; pos = x, y; current; _ } as st) =
- { st with board = Automata.set x y current board }
- in
- let chpos dx dy ({ pos = x, y; _ } as st) = { st with pos = (x + dx, y + dy) } in
- let chsize ds ({ size; _ } as st) = { st with size = max (size + ds) 1 } in
- let chcur f st = { st with current = f st.current } in
- let chnum d { n } = { n = Some ((Option.value n ~default:0 * 10) + d) } in
- let ntimes { n } =
- let rec iter_n n f v =
- match n with
- | 0 -> v
- | n -> iter_n (n - 1) f (f v)
- in
- iter_n (Option.value n ~default:1)
- in
- function
- | ':' -> (EditorState (m, st), Either.right (ModeAux.ModeAndState ((module Command), Command.initial "")))
- | '0' when n.n = None -> (EditorState (m, { st with pos = (0, 0) }), Either.left n)
- | c when '0' <= c && c <= '9' ->
- (EditorState (m, st), Either.left (chnum (int_of_char c - int_of_char '0') n))
- | 's' -> (EditorState (m, set_current st), Either.left { n = None })
- | 'q' -> (EditorState (m, ntimes n (chcur M.prev) st), Either.left { n = None })
- | 'd' -> (EditorState (m, ntimes n (chcur M.next) st), Either.left { n = None })
- | 'f' ->
- ( EditorState (m, ntimes n (fun st -> { st with board = Automata.update (module M) st.board }) st),
- Either.left { n = None } )
- | 'k' -> (EditorState (m, ntimes n (chpos 0 1) st), Either.left { n = None })
- | 'h' -> (EditorState (m, ntimes n (chpos (-1) 0) st), Either.left { n = None })
- | 'j' -> (EditorState (m, ntimes n (chpos 0 (-1)) st), Either.left { n = None })
- | 'l' -> (EditorState (m, ntimes n (chpos 1 0) st), Either.left { n = None })
- | 'i' -> (EditorState (m, ntimes n (chsize 1) st), Either.left { n = None })
- | 'o' -> (EditorState (m, ntimes n (chsize (-1)) st), Either.left { n = None })
- | _ -> (EditorState (m, st), Either.left { n = None })
- end
+ let update (EditorState (m, st)) n =
+ let module M = (val m) in
+ let chpos dx dy ({ pos = x, y; _ } as st) = { st with pos = (x + dx, y + dy) } in
+ let chsize ds ({ size; _ } as st) = { st with size = max (size + ds) 1 } in
+ let chnum d { n } = { n = Some ((Option.value n ~default:0 * 10) + d) } in
+ let ntimes { n } =
+ let rec iter_n n f v =
+ match n with
+ | 0 -> v
+ | n -> iter_n (n - 1) f (f v)
+ in
+ iter_n (Option.value n ~default:1)
+ in
+ function
+ | ':' -> (EditorState (m, st), Either.right (ModeAux.ModeAndState ((module Command), Command.initial "")))
+ | '0' when n.n = None -> (EditorState (m, { st with pos = (0, 0) }), Either.left n)
+ | c when '0' <= c && c <= '9' -> (EditorState (m, st), Either.left (chnum (int_of_char c - int_of_char '0') n))
+ | 'f' ->
+ ( EditorState (m, ntimes n (fun st -> { st with board = Automata.update (module M) st.board }) st),
+ Either.left { n = None } )
+ | 'i' ->
+ ( EditorState (m, st),
+ Either.right (ModeAux.ModeAndState ((module Insert), Insert.initial (fst st.pos))) )
+ | 'k' -> (EditorState (m, ntimes n (chpos 0 1) st), Either.left { n = None })
+ | 'h' -> (EditorState (m, ntimes n (chpos (-1) 0) st), Either.left { n = None })
+ | 'j' -> (EditorState (m, ntimes n (chpos 0 (-1)) st), Either.left { n = None })
+ | 'l' -> (EditorState (m, ntimes n (chpos 1 0) st), Either.left { n = None })
+ | 'o' -> (EditorState (m, ntimes n (chsize 1) st), Either.left { n = None })
+ | 'p' -> (EditorState (m, ntimes n (chsize (-1)) st), Either.left { n = None })
+ | _ -> (EditorState (m, st), Either.left { n = None })
+end
- include Impl
+and Insert : (Mode with type initer = int) = struct
+ type state = { col: int }
+
+ type initer = int
+
+ let initial col = { col }
+
+ let render st _ = render_world st
+
+ let update (EditorState (m, st)) { col } =
+ let module M = (val m) in
+ let set_current ({ board; pos = x, y; _ } as st) c =
+ { st with board = Automata.set x y c board; pos = (x + 1, y) }
+ in
+ let next_line ({ pos = _, y; _ } as st) = { st with pos = (col, y - 1) } in
+ function
+ | '\e' -> (EditorState (m, st), Either.right (ModeAux.ModeAndState ((module Normal), Normal.initial ())))
+ | '\r' -> (EditorState (m, next_line st), Either.left { col })
+ | c -> (
+ match M.of_char c with
+ | Some c -> (EditorState (m, set_current st c), Either.left { col })
+ | None -> (EditorState (m, st), Either.left { col }))
end