Skip to content

Commit f3da8a1

Browse files
committed
Exception catching
1 parent 723b8ec commit f3da8a1

File tree

7 files changed

+420
-58
lines changed

7 files changed

+420
-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: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
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+
| Updated.InvalidAction =>
71+
print_endline("cannot perform action");
72+
model |> Updated.return_quiet;
73+
| exn =>
74+
let msg = Printexc.to_string(exn);
75+
print_endline("CrashHandling: Caught exception in update: " ++ msg);
76+
Updated.return_quiet({
77+
...model,
78+
current_exception: Update(msg),
79+
});
80+
}
81+
| _ => model |> Updated.return_quiet
82+
};
83+
84+
let calculate =
85+
(
86+
~schedule_action: t => unit,
87+
~is_edited: bool,
88+
~dynamics,
89+
previous_model: Model.t,
90+
model: Model.t,
91+
)
92+
: Model.t =>
93+
try({
94+
model:
95+
model.model
96+
|> Logged.Update.calculate(~schedule_action, ~is_edited, ~dynamics),
97+
current_exception: model.current_exception,
98+
}) {
99+
| exn =>
100+
let msg = Printexc.to_string(exn);
101+
print_endline("CrashHandling: Caught exception in calculate: " ++ msg);
102+
{
103+
...previous_model,
104+
current_exception: Calculate(msg),
105+
};
106+
};
107+
};
108+
109+
module View = {
110+
open Virtual_dom.Vdom;
111+
open WebUtil.Node;
112+
113+
let hsod_view =
114+
(~title: string, ~msg: string, ~inject_backtrack: Ui_effect.t(unit)) =>
115+
div(
116+
~attrs=[Attr.class_("hsod-container")],
117+
[
118+
div(
119+
~attrs=[Attr.class_("hsod")],
120+
[
121+
div(
122+
~attrs=[Attr.class_("hsod-inner")],
123+
[
124+
div(
125+
~attrs=[Attr.class_("hsod-img")],
126+
[
127+
Node.img(
128+
~attrs=[
129+
Attr.create("src", "img/dead-hazel.png"),
130+
Attr.create("alt", "dead hazel"),
131+
],
132+
(),
133+
),
134+
],
135+
),
136+
div(
137+
~attrs=[Attr.class_("hsod-body")],
138+
[
139+
h1([Node.text(title)]),
140+
pre([Node.text(msg)]),
141+
div(
142+
~attrs=[Attr.class_("hsod-links")],
143+
[
144+
// button(
145+
// ~attrs=[
146+
// Attr.create("type", "button"),
147+
// Attr.class_("hsod-button"),
148+
// Attr.on_click(_ => {
149+
// let confirmed =
150+
// JsUtil.confirm(
151+
// "Are you SURE you want to reset Hazel to its initial state? You will lose any existing code that you have written!",
152+
// );
153+
// if (confirmed) {
154+
// JsUtil.clear_localstore();
155+
// Js_of_ocaml.Dom_html.window##.location##reload;
156+
// };
157+
// Virtual_dom.Vdom.Effect.Ignore;
158+
// }),
159+
// ],
160+
// [Node.text("Reset Hazel")],
161+
// ),
162+
a(
163+
~attrs=[
164+
Attr.create(
165+
"href",
166+
"https://github.com/hazelgrove/hazel/issues/new",
167+
),
168+
Attr.create("target", "_blank"),
169+
Attr.class_("hsod-link"),
170+
],
171+
[Node.text("Report this issue on GitHub")],
172+
),
173+
button(
174+
~attrs=[
175+
Attr.create("type", "button"),
176+
Attr.classes([
177+
"hsod-button",
178+
"hsod-button-primary",
179+
]),
180+
Attr.on_click(_ => inject_backtrack),
181+
],
182+
[Node.text("Revert to previous state")],
183+
),
184+
],
185+
),
186+
],
187+
),
188+
],
189+
),
190+
],
191+
),
192+
],
193+
);
194+
195+
let view =
196+
(~get_log_and, ~inject: Update.t => Ui_effect.t(unit), model: Model.t) =>
197+
switch (model.current_exception) {
198+
| NoException => Logged.View.view(~get_log_and, ~inject, model.model)
199+
| Update(msg) =>
200+
hsod_view(
201+
~title="Exception during Update",
202+
~msg,
203+
~inject_backtrack=inject(Globals(ClearException)),
204+
)
205+
| Calculate(msg) =>
206+
hsod_view(
207+
~title="Exception during Calculate",
208+
~msg,
209+
~inject_backtrack=inject(Globals(ClearException)),
210+
)
211+
| exception exn =>
212+
let msg = Printexc.to_string(exn);
213+
hsod_view(
214+
~title="Exception during View",
215+
~msg,
216+
~inject_backtrack=inject(Globals(Undo)),
217+
);
218+
};
219+
};

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

0 commit comments

Comments
 (0)