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
type execution_result = {
output : string;
error : string option;
status : [ `Success | `Error ];
}
let initialize_toplevel () =
Sys.interactive := false;
Toploop.initialize_toplevel_env ();
Toploop.input_name := "//toplevel//";
Sys.interactive := true
let ensure_terminator code =
let trimmed_code = String.trim code in
if trimmed_code = "" || String.ends_with ~suffix:";;" trimmed_code then code
else code ^ ";;"
let execute printval pp_out pp_err s =
let s = ensure_terminator s in
let lb = Lexing.from_string s in
lb.lex_curr_p <-
{ pos_fname = "//toplevel//"; pos_lnum = 1; pos_bol = 0; pos_cnum = 0 };
let overall_success = ref true in
let old_warnings_formatter = !Location.formatter_for_warnings in
Location.formatter_for_warnings := pp_err;
let orig_input_lexbuf = !Location.input_lexbuf in
Location.input_lexbuf := Some lb;
let phrases = ref [] in
(try
while true do
let phr = !Toploop.parse_toplevel_phrase lb in
phrases := phr :: !phrases
done
with End_of_file -> ());
let phrases = List.rev !phrases in
let num_phrases = List.length phrases in
Fun.protect
(fun () ->
List.iteri
(fun i phr ->
try
let is_last = i = num_phrases - 1 in
let should_print = printval || is_last in
let exec_success = Toploop.execute_phrase should_print pp_out phr in
overall_success := !overall_success && exec_success
with
| Sys.Break ->
overall_success := false;
Format.fprintf pp_err "Interrupted.@."
| x ->
overall_success := false;
Errors.report_error pp_err x)
phrases)
~finally:(fun () ->
Location.formatter_for_warnings := old_warnings_formatter;
Location.input_lexbuf := orig_input_lexbuf;
Format.pp_print_flush pp_out ();
Format.pp_print_flush pp_err ());
!overall_success
let format_output output =
let output = String.trim output in
if output = "" then output
else
let lines = String.split_on_char '\n' output in
let is_figure_output =
List.exists
(fun line ->
let trimmed = String.trim line in
String.starts_with ~prefix:"- : Hugin.Figure.t" trimmed
|| String.starts_with ~prefix:"- : Hugin.figure" trimmed)
lines
&& List.exists
(fun line ->
let trimmed = String.trim line in
String.starts_with ~prefix:"![figure]" trimmed)
lines
in
if is_figure_output then
let rec = function
| [] -> []
| line :: rest ->
let trimmed = String.trim line in
if String.starts_with ~prefix:"![" trimmed then
line :: extract_images rest
else extract_images rest
in
String.concat "\n" (extract_images lines)
else
let rec split_content acc_code acc_markdown = function
| [] -> (List.rev acc_code, List.rev acc_markdown)
| line :: rest ->
let trimmed = String.trim line in
if
String.starts_with ~prefix:"![" trimmed
|| String.starts_with ~prefix:"<img" trimmed
|| String.starts_with ~prefix:"<svg" trimmed
|| String.starts_with ~prefix:"<figure" trimmed
|| String.starts_with ~prefix:"</figure" trimmed
then split_content acc_code (line :: acc_markdown) rest
else if trimmed = "" then
split_content acc_code acc_markdown rest
else split_content (line :: acc_code) acc_markdown rest
in
let code_lines, markdown_lines = split_content [] [] lines in
match (code_lines, markdown_lines) with
| [], [] -> ""
| [], md_lines ->
String.concat "\n" md_lines
| code_lines, [] ->
"```\n" ^ String.concat "\n" code_lines ^ "\n```"
| code_lines, md_lines ->
"```\n"
^ String.concat "\n" code_lines
^ "\n```\n"
^ String.concat "\n" md_lines