Skip to content

Commit c7b6866

Browse files
committed
Exception catching
1 parent 723b8ec commit c7b6866

File tree

7 files changed

+417
-58
lines changed

7 files changed

+417
-58
lines changed

src/web/Main.re

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -19,61 +19,35 @@ let restart_caret_animation = () =>
1919

2020
let apply =
2121
(
22-
model: Logged.Model.t,
23-
action: Logged.Update.t,
22+
model: CrashHandling.Model.t,
23+
action: CrashHandling.Update.t,
2424
~schedule_action,
2525
~schedule_autosave,
2626
)
27-
: Logged.Model.t => {
27+
: CrashHandling.Model.t => {
2828
restart_caret_animation();
2929

3030
/* This function is split into two phases, update and calculate.
3131
The intention is that eventually, the calculate phase will be
3232
done automatically by incremental calculation. */
3333
// ---------- UPDATE PHASE ----------
34-
let updated: Updated.t(Logged.Model.t) =
35-
try(
36-
Logged.Update.update(
37-
~import_log=Log.import,
38-
~get_log_and=Log.get_and,
39-
~schedule_action,
40-
action,
41-
model,
42-
)
43-
) {
44-
| Haz3lcore.Action.Failure.Exception(t) =>
45-
Printf.printf(
46-
"ERROR: Action.Failure: %s\n",
47-
t |> Haz3lcore.Action.Failure.show,
48-
);
49-
model |> Updated.return_quiet;
50-
| exc =>
51-
Printf.printf(
52-
"ERROR: Exception during apply: %s\n",
53-
Printexc.to_string(exc),
54-
);
55-
model |> Updated.return_quiet;
56-
};
34+
let updated: Updated.t(CrashHandling.Model.t) =
35+
CrashHandling.Update.update(
36+
~import_log=Log.import,
37+
~get_log_and=Log.get_and,
38+
~schedule_action,
39+
action,
40+
model,
41+
);
5742
// ---------- CALCULATE PHASE ----------
5843
let model' =
59-
try(
60-
updated.model
61-
|> Logged.Update.calculate(
62-
~schedule_action,
63-
~is_edited=updated.is_edit,
64-
~dynamics=true,
65-
)
66-
) {
67-
| exc =>
68-
Printf.printf(
69-
"ERROR: Exception during calculate: %s\n",
70-
Printexc.to_string(exc),
71-
);
72-
{
73-
...model,
74-
replay_toggle: false,
75-
};
76-
};
44+
CrashHandling.Update.calculate(
45+
~schedule_action,
46+
~is_edited=updated.is_edit,
47+
~dynamics=true,
48+
model,
49+
updated.model,
50+
);
7751

7852
if (updated.is_edit) {
7953
schedule_autosave(
@@ -98,8 +72,8 @@ let start = {
9872
let%sub save_scheduler = BonsaiUtil.Alarm.alarm;
9973
let%sub (app_model, app_inject) =
10074
Bonsai.state_machine1(
101-
(module Logged.Model),
102-
(module Logged.Update),
75+
(module CrashHandling.Model),
76+
(module CrashHandling.Update),
10377
~apply_action=
10478
(~inject, ~schedule_event, input) => {
10579
let schedule_action = x => schedule_event(inject(x));
@@ -112,12 +86,13 @@ let start = {
11286
apply(~schedule_action, ~schedule_autosave);
11387
},
11488
~default_model=
115-
Logged.Model.init()
116-
|> Logged.Update.calculate(
117-
~schedule_action=_ => (),
118-
~is_edited=true,
119-
~dynamics=false,
120-
),
89+
CrashHandling.Update.calculate(
90+
~schedule_action=_ => (),
91+
~is_edited=true,
92+
~dynamics=false,
93+
CrashHandling.Model.init(),
94+
CrashHandling.Model.init(),
95+
),
12196
save_scheduler,
12297
);
12398

@@ -130,7 +105,7 @@ let start = {
130105
let%map app_inject = app_inject
131106
and model = app_model;
132107
Ui_effect.Many(
133-
model.replay_toggle
108+
model.model.replay_toggle
134109
? [app_inject(Page.Update.Globals(Log(NextLog)))] : [],
135110
);
136111
};
@@ -220,7 +195,7 @@ let start = {
220195
let _ = Haz3lcore.ProbePerform.FocusEffect.execute();
221196
/* Update floating elements (backpack) to viewport coordinates */
222197
FloatingElement.update_all();
223-
model.current.current.globals.settings.core.statics
198+
model.model.current.current.globals.settings.core.statics
224199
? Animation.go() : ();
225200
},
226201
(),
@@ -232,7 +207,11 @@ let start = {
232207
let%arr app_model = app_model
233208
and app_inject = app_inject;
234209
try(
235-
Logged.View.view(app_model, ~inject=app_inject, ~get_log_and=Log.get_and)
210+
CrashHandling.View.view(
211+
~get_log_and=Log.get_and,
212+
~inject=app_inject,
213+
app_model,
214+
)
236215
) {
237216
| exc =>
238217
print_endline(

src/web/app/CrashHandling.re

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
open Util;
2+
3+
module Model = {
4+
[@deriving (sexp, yojson)]
5+
type state = Logged.Model.t;
6+
[@deriving (sexp, yojson)]
7+
type current_exception =
8+
| NoException
9+
| Update(string)
10+
| Calculate(string);
11+
12+
[@deriving (sexp, yojson)]
13+
type t = {
14+
model: state,
15+
current_exception,
16+
};
17+
18+
let equal = (===);
19+
20+
let init = () => {
21+
model: Logged.Model.init(),
22+
current_exception: NoException,
23+
};
24+
};
25+
26+
module Update = {
27+
[@deriving (sexp, yojson)]
28+
type t = Logged.Update.t;
29+
30+
let update =
31+
(
32+
~import_log,
33+
~get_log_and,
34+
~schedule_action: t => unit,
35+
action: t,
36+
model: Model.t,
37+
)
38+
: Updated.t(Model.t) =>
39+
switch (action) {
40+
| Globals(ClearException) =>
41+
{
42+
...model,
43+
current_exception: NoException,
44+
}
45+
|> Updated.return_quiet
46+
| _ when model.current_exception == NoException =>
47+
try({
48+
let updated =
49+
Logged.Update.update(
50+
~import_log,
51+
~get_log_and,
52+
~schedule_action,
53+
action,
54+
model.model,
55+
);
56+
{
57+
...updated,
58+
model: {
59+
model: updated.model,
60+
current_exception: NoException,
61+
},
62+
};
63+
}) {
64+
| Haz3lcore.Action.Failure.Exception(t) =>
65+
Printf.printf(
66+
"ERROR: Action.Failure: %s\n",
67+
t |> Haz3lcore.Action.Failure.show,
68+
);
69+
model |> Updated.return_quiet;
70+
| exn =>
71+
let msg = Printexc.to_string(exn);
72+
print_endline("CrashHandling: Caught exception in update: " ++ msg);
73+
Updated.return_quiet({
74+
...model,
75+
current_exception: Update(msg),
76+
});
77+
}
78+
| _ => model |> Updated.return_quiet
79+
};
80+
81+
let calculate =
82+
(
83+
~schedule_action: t => unit,
84+
~is_edited: bool,
85+
~dynamics,
86+
previous_model: Model.t,
87+
model: Model.t,
88+
)
89+
: Model.t =>
90+
try({
91+
model:
92+
model.model
93+
|> Logged.Update.calculate(~schedule_action, ~is_edited, ~dynamics),
94+
current_exception: model.current_exception,
95+
}) {
96+
| exn =>
97+
let msg = Printexc.to_string(exn);
98+
print_endline("CrashHandling: Caught exception in calculate: " ++ msg);
99+
{
100+
...previous_model,
101+
current_exception: Calculate(msg),
102+
};
103+
};
104+
};
105+
106+
module View = {
107+
open Virtual_dom.Vdom;
108+
open WebUtil.Node;
109+
110+
let hsod_view =
111+
(~title: string, ~msg: string, ~inject_backtrack: Ui_effect.t(unit)) =>
112+
div(
113+
~attrs=[Attr.class_("hsod-container")],
114+
[
115+
div(
116+
~attrs=[Attr.class_("hsod")],
117+
[
118+
div(
119+
~attrs=[Attr.class_("hsod-inner")],
120+
[
121+
div(
122+
~attrs=[Attr.class_("hsod-img")],
123+
[
124+
Node.img(
125+
~attrs=[
126+
Attr.create("src", "/img/dead-hazel.png"),
127+
Attr.create("alt", "dead hazel"),
128+
],
129+
(),
130+
),
131+
],
132+
),
133+
div(
134+
~attrs=[Attr.class_("hsod-body")],
135+
[
136+
h1([Node.text(title)]),
137+
pre([Node.text(msg)]),
138+
div(
139+
~attrs=[Attr.class_("hsod-links")],
140+
[
141+
// button(
142+
// ~attrs=[
143+
// Attr.create("type", "button"),
144+
// Attr.class_("hsod-button"),
145+
// Attr.on_click(_ => {
146+
// let confirmed =
147+
// JsUtil.confirm(
148+
// "Are you SURE you want to reset Hazel to its initial state? You will lose any existing code that you have written!",
149+
// );
150+
// if (confirmed) {
151+
// JsUtil.clear_localstore();
152+
// Js_of_ocaml.Dom_html.window##.location##reload;
153+
// };
154+
// Virtual_dom.Vdom.Effect.Ignore;
155+
// }),
156+
// ],
157+
// [Node.text("Reset Hazel")],
158+
// ),
159+
a(
160+
~attrs=[
161+
Attr.create(
162+
"href",
163+
"https://github.com/hazelgrove/hazel/issues/new",
164+
),
165+
Attr.create("target", "_blank"),
166+
Attr.class_("hsod-link"),
167+
],
168+
[Node.text("Report this issue on GitHub")],
169+
),
170+
button(
171+
~attrs=[
172+
Attr.create("type", "button"),
173+
Attr.classes([
174+
"hsod-button",
175+
"hsod-button-primary",
176+
]),
177+
Attr.on_click(_ => inject_backtrack),
178+
],
179+
[Node.text("Revert to previous state")],
180+
),
181+
],
182+
),
183+
],
184+
),
185+
],
186+
),
187+
],
188+
),
189+
],
190+
);
191+
192+
let view =
193+
(~get_log_and, ~inject: Update.t => Ui_effect.t(unit), model: Model.t) =>
194+
switch (model.current_exception) {
195+
| NoException => Logged.View.view(~get_log_and, ~inject, model.model)
196+
| Update(msg) =>
197+
hsod_view(
198+
~title="Exception during Update",
199+
~msg,
200+
~inject_backtrack=inject(Globals(ClearException)),
201+
)
202+
| Calculate(msg) =>
203+
hsod_view(
204+
~title="Exception during Calculate",
205+
~msg,
206+
~inject_backtrack=inject(Globals(ClearException)),
207+
)
208+
| exception exn =>
209+
let msg = Printexc.to_string(exn);
210+
hsod_view(
211+
~title="Exception during View",
212+
~msg,
213+
~inject_backtrack=inject(Globals(Undo)),
214+
);
215+
};
216+
};

src/web/app/Page.re

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,11 @@ module Update = {
246246
};
247247
| Log(_)
248248
| Undo
249-
| Redo =>
250-
failwith("Undo/Redo/Log import are handled in the history module")
249+
| Redo
250+
| ClearException =>
251+
failwith(
252+
"Undo/Redo/Log import/ClearException are handled in higher-level modules",
253+
)
251254
};
252255
};
253256

src/web/app/globals/Globals.re

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ module Action = {
6666
| Redo // global actions so they can be accessed by the command palette
6767
| Log(log)
6868
| SetMetaDown(bool)
69-
| UpdateVisibleRows(VisibleRows.t);
69+
| UpdateVisibleRows(VisibleRows.t)
70+
| ClearException;
7071
};
7172

7273
module Model = {
@@ -157,6 +158,7 @@ module Update = {
157158
| SetMetaDown(_) => false
158159
| UpdateVisibleRows(_) => false
159160
| Log(_) => false
161+
| ClearException => false
160162
};
161163
};
162164
};

src/web/www/img/dead-hazel.png

1.36 MB
Loading

src/web/www/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
@import "style/stepper.css";
2020
@import "style/toggle.css";
2121
@import "style/theorems.css";
22+
@import "style/hsod.css";
2223

2324
/* BASE ELEMENTS */
2425

0 commit comments

Comments
 (0)