-
Notifications
You must be signed in to change notification settings - Fork 125
/
consoleAnim.ml
124 lines (110 loc) · 3.79 KB
/
consoleAnim.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
(*
Copyright © 2011 MLstate
This file is part of OPA.
OPA is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License, version 3, as published by
the Free Software Foundation.
OPA is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
more details.
You should have received a copy of the GNU Affero General Public License
along with OPA. If not, see <http://www.gnu.org/licenses/>.
*)
type anim = string array array
type t = {
och : out_channel ;
step : int ref ;
auto_walking : bool ;
walk_anim : anim ;
turn_anim : anim ;
walk_anim_rev : anim ;
turn_anim_rev : anim ;
}
(* please, extend it if needed *)
let reverse_char = function
| '\\' -> '/'
| '/' -> '\\'
| '(' -> ')'
| ')' -> '('
| '[' -> ']'
| ']' -> '['
| '{' -> '}'
| '}' -> '{'
| '<' -> '>'
| '>' -> '<'
| c -> c
(* sorry, we can't use String.init because Base depends on Journal *)
let reverse_string s =
let len = String.length s in
let s' = String.make len ' ' in
for i = 0 to len - 1 do
s'.[i] <- reverse_char s.[len - 1 - i]
done;
s'
let print_frame och pos frame =
let output s = Pervasives.output_string och s in
let flush () = Pervasives.flush och in
let reset =
let n = Array.length frame in
if n > 1 then Printf.sprintf "\027[%dA\r" (n-1) else "\r" in
output "\r";
(* Print the frame *)
Array.iteri
(fun i l ->
if i <> 0 then output "\027E";
if pos <> 0 then output (Printf.sprintf "\027[%dC" pos);
output l)
frame;
output reset;
(* Then flush and clear, so that it's absent in further console printings *)
flush ();
(* if pos <> 0 then output (Printf.sprintf "\027[%dC" pos); *)
(* if Array.length frame <> 0 *)
(* then output (String.make (String.length frame.(0)) ' '); *)
Array.iteri
(fun i l ->
if i <> 0 then output "\027E";
if pos <> 0 then output (Printf.sprintf "\027[%dC" pos);
output (String.make (String.length l) ' '))
frame;
(* Replace the cursor where it was found *)
output reset
let anim t x =
let print_frame = print_frame t.och in
let walk_length = Array.length t.walk_anim in
let turn_length = Array.length t.turn_anim in
let i = x mod ((60 * walk_length + turn_length) * 2) in
if i < 60 * walk_length then
print_frame (if t.auto_walking then i / walk_length else 0) t.walk_anim.(i mod walk_length)
else if i < 60 * walk_length + turn_length then
print_frame (if t.auto_walking then 59 else 0) t.turn_anim.(i - 60 * walk_length)
else if i < 120 * walk_length + turn_length then
let j = i - 60 * walk_length - turn_length in
print_frame (if t.auto_walking then 60 - j / walk_length else 0) t.walk_anim_rev.(j mod walk_length)
else
let j = i - 120 * walk_length - turn_length in
print_frame 0 t.turn_anim_rev.(j)
let check ~auto_walking walk_anim turn_anim =
if auto_walking then begin
let check_frame frame =
if Array.length frame > 0 then
let l = String.length frame.(0) in
Array.iter (fun s -> if String.length s <> l then failwith "Different frame lengths") frame
in
Array.iter check_frame walk_anim;
Array.iter check_frame turn_anim
end
let init ?(och=stdout) ~auto_walking walk_anim turn_anim =
check ~auto_walking walk_anim turn_anim;
{
och = och ;
step = ref 0 ;
auto_walking = auto_walking ;
walk_anim = walk_anim ;
turn_anim = turn_anim ;
walk_anim_rev = Array.map (Array.map reverse_string) walk_anim ;
turn_anim_rev = Array.map (Array.map reverse_string) turn_anim ;
}
let reset t = t.step := 0
let update t = anim t !(t.step); incr t.step