diff --git a/src/haz3lweb/ColorSteps.re b/src/haz3lweb/ColorSteps.re index fe242aeffc..3cd2d4f981 100644 --- a/src/haz3lweb/ColorSteps.re +++ b/src/haz3lweb/ColorSteps.re @@ -1,3 +1,6 @@ +open Sexplib.Std; + +[@deriving (show({with_path: false}), sexp, yojson)] type colorMap = Haz3lcore.Id.Map.t(string); /*[@deriving sexp]*/ diff --git a/src/haz3lweb/DebugConsole.re b/src/haz3lweb/DebugConsole.re index 54acffe00f..2c546edbcf 100644 --- a/src/haz3lweb/DebugConsole.re +++ b/src/haz3lweb/DebugConsole.re @@ -6,7 +6,7 @@ open Haz3lcore; let print = ( - {settings, editors, ui_state: {active_editor, _}, results, _}: Model.t, + {globals: {settings, _}, editors, active_editor, results, _}: Model.t, key: string, ) : unit => { diff --git a/src/haz3lweb/Grading.re b/src/haz3lweb/Grading.re index 43e5473a65..731f526acb 100644 --- a/src/haz3lweb/Grading.re +++ b/src/haz3lweb/Grading.re @@ -66,9 +66,14 @@ module TestValidationReport = { report.test_results |> Option.map(test_results => TestView.test_bar( - ~inject, + ~inject_jump= + TestView.jump_to_test( + ~inject, + YourTestsValidation, + _, + (), + ), ~test_results, - YourTestsValidation, ) ), ), @@ -444,7 +449,11 @@ module ImplGradingReport = { @ Option.to_list( report.test_results |> Option.map(test_results => - TestView.test_bar(~inject, ~test_results, HiddenTests) + TestView.test_bar( + ~inject_jump= + TestView.jump_to_test(~inject, HiddenTests, _, ()), + ~test_results, + ) ), ), ), diff --git a/src/haz3lweb/Keyboard.re b/src/haz3lweb/Keyboard.re index bad937c531..7f7281ac7c 100644 --- a/src/haz3lweb/Keyboard.re +++ b/src/haz3lweb/Keyboard.re @@ -13,7 +13,7 @@ let handle_key_event = (k: Key.t): option(Update.t) => { keydown, making an update here may trigger an entire extra redraw, contingent on model.cutoff */ switch (key) { - | "Alt" => Some(SetMeta(ShowBackpackTargets(false))) + | "Alt" => Some(Globals(SetShowBackpackTargets(false))) | _ => None } | {key: D(key), sys: _, shift: Down, meta: Up, ctrl: Up, alt: Up} @@ -111,7 +111,7 @@ let handle_key_event = (k: Key.t): option(Update.t) => { switch (sys, key) { | (_, "ArrowLeft") => now(MoveToBackpackTarget(Left(ByToken))) | (_, "ArrowRight") => now(MoveToBackpackTarget(Right(ByToken))) - | (_, "Alt") => Some(SetMeta(ShowBackpackTargets(true))) + | (_, "Alt") => Some(Globals(SetShowBackpackTargets(true))) | (_, "ArrowUp") => now(MoveToBackpackTarget(Up)) | (_, "ArrowDown") => now(MoveToBackpackTarget(Down)) | _ => None diff --git a/src/haz3lweb/Log.re b/src/haz3lweb/Log.re index d7a5665824..e4c7ec4812 100644 --- a/src/haz3lweb/Log.re +++ b/src/haz3lweb/Log.re @@ -4,7 +4,10 @@ open Sexplib.Std; let is_action_logged: UpdateAction.t => bool = fun - | SetMeta(_) + | Globals( + SetMousedown(_) | SetShowBackpackTargets(_) | SetFontMetrics(_) | + JumpToTile(_), + ) | Save | InitImportAll(_) | InitImportScratchpad(_) @@ -18,7 +21,7 @@ let is_action_logged: UpdateAction.t => bool = | Reset | TAB | Assistant(_) - | Set(_) + | Globals(Set(_)) | SwitchScratchSlide(_) | SwitchDocumentationSlide(_) | MakeActive(_) diff --git a/src/haz3lweb/Main.re b/src/haz3lweb/Main.re index e1268431af..02f2906b3d 100644 --- a/src/haz3lweb/Main.re +++ b/src/haz3lweb/Main.re @@ -79,7 +79,7 @@ module App = { let on_startup = (~schedule_action, m: Model.t) => { let _ = observe_font_specimen("font-specimen", fm => - schedule_action(Haz3lweb.Update.SetMeta(FontMetrics(fm))) + schedule_action(Haz3lweb.Update.Globals(SetFontMetrics(fm))) ); JsUtil.focus_clipboard_shim(); @@ -138,6 +138,6 @@ switch (JsUtil.Fragment.get_current()) { (module App), ~debug=false, ~bind_to_element_with_id="container", - ~initial_model=Model.load(Model.blank), + ~initial_model=Model.load(), ) }; diff --git a/src/haz3lweb/Model.re b/src/haz3lweb/Model.re index e4557589fb..5681711980 100644 --- a/src/haz3lweb/Model.re +++ b/src/haz3lweb/Model.re @@ -18,45 +18,17 @@ open Haz3lcore; [@deriving (show({with_path: false}), yojson, sexp)] type timestamp = float; -/* Non-persistent application state */ -[@deriving (show({with_path: false}), yojson, sexp)] -type ui_state = { - font_metrics: FontMetrics.t, - show_backpack_targets: bool, - mousedown: bool, - active_editor: option(Editors.Selection.t), -}; - -let ui_state_init = { - font_metrics: FontMetrics.init, - show_backpack_targets: false, - mousedown: false, - active_editor: None, -}; - type t = { editors: Editors.t, - settings: Settings.t, results: ModelResults.t, statics: CachedStatics.t, explainThisModel: ExplainThisModel.t, - ui_state, + globals: Globals.t, + active_editor: option(Editors.Selection.t), }; let cutoff = (===); -let mk = (editors, results, statics) => { - editors, - settings: Init.startup.settings, - results, - statics, - explainThisModel: ExplainThisModel.init, - ui_state: ui_state_init, -}; - -let blank = - mk(Editors.Scratch(0, []), ModelResults.empty, CachedStatics.empty); - let load_editors = (~settings: Settings.t): (Editors.t, ModelResults.t) => switch (settings.mode) { | Scratch => @@ -86,19 +58,23 @@ let save_editors = Store.Exercise.save((n, specs, exercise), ~instructor_mode) }; -let load = (init_model: t): t => { - let settings = Store.Settings.load(); - let explainThisModel = Store.ExplainThisModel.load(); +let load = (): t => { + let globals = Globals.Model.load(); + let settings = globals.settings; let (editors, results) = load_editors(~settings); - let ui_state = init_model.ui_state; let statics = Editors.mk_statics(~settings, editors); - {editors, settings, results, statics, explainThisModel, ui_state}; + let explainThisModel = Store.ExplainThisModel.load(); + {editors, results, statics, globals, explainThisModel, active_editor: None}; }; -let save = ({editors, settings, explainThisModel, results, _}: t) => { - save_editors(editors, results, ~instructor_mode=settings.instructor_mode); +let save = ({editors, globals, results, explainThisModel, _}: t) => { + save_editors( + editors, + results, + ~instructor_mode=globals.settings.instructor_mode, + ); + Globals.Model.save(globals); Store.ExplainThisModel.save(explainThisModel); - Store.Settings.save(settings); }; let save_and_return = (model: t) => { @@ -114,12 +90,12 @@ let reset = (model: t): t => { ignore(Store.Scratch.init(~settings)); ignore(Store.Documentation.init(~settings)); ignore(Store.Exercise.init(~instructor_mode=true)); - let new_model = load(blank); + let new_model = load(); { ...new_model, - ui_state: { - ...model.ui_state, - font_metrics: model.ui_state.font_metrics, + globals: { + ...model.globals, + font_metrics: model.globals.font_metrics, }, }; }; diff --git a/src/haz3lweb/Settings.re b/src/haz3lweb/Settings.re deleted file mode 100644 index d64917b0ab..0000000000 --- a/src/haz3lweb/Settings.re +++ /dev/null @@ -1,35 +0,0 @@ -open Sexplib.Std; - -[@deriving (show({with_path: false}), sexp, yojson)] -type mode = - | Scratch - | Documentation - | Exercises; - -let mode_of_string = (s: string): mode => - switch (s) { - | "Scratch" => Scratch - | "Documentation" => Documentation - | "Exercises" => Exercises - | _ => failwith("mode_of_string: unknown mode:" ++ s) - }; - -[@deriving (show({with_path: false}), sexp, yojson)] -type t = { - captions: bool, - secondary_icons: bool, - core: Haz3lcore.CoreSettings.t, - async_evaluation: bool, - context_inspector: bool, - instructor_mode: bool, - benchmark: bool, - explainThis: ExplainThisModel.Settings.t, - mode, -}; - -let fix_instructor_mode = settings => - if (settings.instructor_mode && !ExerciseSettings.show_instructor) { - {...settings, instructor_mode: false}; - } else { - settings; - }; diff --git a/src/haz3lweb/Store.re b/src/haz3lweb/Store.re index 0c4ac3fe23..2b655ea2d8 100644 --- a/src/haz3lweb/Store.re +++ b/src/haz3lweb/Store.re @@ -29,7 +29,7 @@ module Settings = { data |> Sexplib.Sexp.of_string |> Settings.t_of_sexp - |> Settings.fix_instructor_mode + |> Settings.Model.fix_instructor_mode ) { | _ => print_endline("Could not deserialize settings."); diff --git a/src/haz3lweb/Update.re b/src/haz3lweb/Update.re index dbeb8b65bd..b00c22a50c 100644 --- a/src/haz3lweb/Update.re +++ b/src/haz3lweb/Update.re @@ -2,192 +2,11 @@ open Haz3lcore; include UpdateAction; // to prevent circularity -let update_settings = - (a: settings_action, {settings, _} as model: Model.t): Model.t => - switch (a) { - | Statics => - /* NOTE: dynamics depends on statics, so if dynamics is on and - we're turning statics off, turn dynamics off as well */ - { - ...model, - settings: { - ...settings, - core: { - statics: !settings.core.statics, - assist: !settings.core.statics, - elaborate: settings.core.elaborate, - dynamics: !settings.core.statics && settings.core.dynamics, - evaluation: settings.core.evaluation, - }, - }, - } - | Elaborate => { - ...model, - settings: { - ...settings, - core: { - statics: !settings.core.elaborate || settings.core.statics, - assist: settings.core.assist, - elaborate: !settings.core.elaborate, - dynamics: settings.core.dynamics, - evaluation: settings.core.evaluation, - }, - }, - } - | Dynamics => { - ...model, - settings: { - ...settings, - core: { - statics: !settings.core.dynamics || settings.core.statics, - assist: settings.core.assist, - elaborate: settings.core.elaborate, - dynamics: !settings.core.dynamics, - evaluation: settings.core.evaluation, - }, - }, - } - | Assist => { - ...model, - settings: { - ...settings, - core: { - statics: !settings.core.assist || settings.core.statics, - assist: !settings.core.assist, - elaborate: settings.core.elaborate, - dynamics: settings.core.dynamics, - evaluation: settings.core.evaluation, - }, - }, - } - | Evaluation(u) => - let evaluation = settings.core.evaluation; - let evaluation' = { - switch (u) { - | ShowRecord => { - ...evaluation, - stepper_history: !evaluation.stepper_history, - } - | ShowCaseClauses => { - ...evaluation, - show_case_clauses: !evaluation.show_case_clauses, - } - | ShowFnBodies => { - ...evaluation, - show_fn_bodies: !evaluation.show_fn_bodies, - } - | ShowCasts => {...evaluation, show_casts: !evaluation.show_casts} - | ShowFixpoints => { - ...evaluation, - show_fixpoints: !evaluation.show_fixpoints, - } - | ShowLookups => { - ...evaluation, - show_lookup_steps: !evaluation.show_lookup_steps, - } - | ShowFilters => { - ...evaluation, - show_stepper_filters: !evaluation.show_stepper_filters, - } - | ShowSettings => { - ...evaluation, - show_settings: !evaluation.show_settings, - } - | ShowHiddenSteps => { - ...evaluation, - show_hidden_steps: !evaluation.show_hidden_steps, - } - }; - }; - { - ...model, - settings: { - ...settings, - core: { - ...settings.core, - evaluation: evaluation', - }, - }, - }; - | ExplainThis(ToggleShow) => - let explainThis = { - ...settings.explainThis, - show: !settings.explainThis.show, - }; - let settings = {...settings, explainThis}; - {...model, settings}; - | ExplainThis(ToggleShowFeedback) => - let explainThis = { - ...settings.explainThis, - show_feedback: !settings.explainThis.show_feedback, - }; - let settings = {...settings, explainThis}; - {...model, settings}; - | ExplainThis(SetHighlight(a)) => - let highlight: ExplainThisModel.Settings.highlight = - switch (a, settings.explainThis.highlight) { - | (Toggle, All) => NoHighlight - | (Toggle, _) => All - | (Hover(_), All) => All - | (Hover(id), _) => One(id) - | (UnsetHover, All) => All - | (UnsetHover, _) => NoHighlight - }; - let explainThis = {...settings.explainThis, highlight}; - let settings = {...settings, explainThis}; - {...model, settings}; - | Benchmark => { - ...model, - settings: { - ...settings, - benchmark: !settings.benchmark, - }, - } - | Captions => { - ...model, - settings: { - ...settings, - captions: !settings.captions, - }, - } - | SecondaryIcons => { - ...model, - settings: { - ...settings, - secondary_icons: !settings.secondary_icons, - }, - } - | ContextInspector => { - ...model, - settings: { - ...settings, - context_inspector: !settings.context_inspector, - }, - } - | InstructorMode => - let new_mode = !settings.instructor_mode; - { - ...model, - editors: Editors.set_instructor_mode(model.editors, new_mode), - settings: { - ...settings, - instructor_mode: !settings.instructor_mode, - }, - }; - | Mode(mode) => { - ...model, - settings: { - ...settings, - mode, - }, - } - }; - let schedule_evaluation = (~schedule_action, model: Model.t): unit => - if (model.settings.core.dynamics) { + if (model.globals.settings.core.dynamics) { let elabs = Editors.get_spliced_elabs( - ~settings=model.settings, + ~settings=model.globals.settings, model.statics, model.editors, ); @@ -212,11 +31,15 @@ let schedule_evaluation = (~schedule_action, model: Model.t): unit => /* Not sending stepper to worker for now bc closure perf */ let new_rs = model.results - |> ModelResults.update_elabs(~settings=model.settings.core, elabs); + |> ModelResults.update_elabs( + ~settings=model.globals.settings.core, + elabs, + ); let step_rs = ModelResults.to_step(new_rs); if (!ModelResults.is_empty(step_rs)) { let new_rs = - step_rs |> ModelResults.run_pending(~settings=model.settings.core); + step_rs + |> ModelResults.run_pending(~settings=model.globals.settings.core); schedule_action(UpdateResult(new_rs)); } else { schedule_action(UpdateResult(new_rs)); @@ -227,10 +50,13 @@ let update_cached_data = (~schedule_action, update, m: Model.t): Model.t => { let update_statics = is_edit(update) || reevaluate_post_update(update); let update_dynamics = reevaluate_post_update(update); let m = - update_statics || update_dynamics && m.settings.core.statics - ? {...m, statics: Editors.mk_statics(~settings=m.settings, m.editors)} + update_statics || update_dynamics && m.globals.settings.core.statics + ? { + ...m, + statics: Editors.mk_statics(~settings=m.globals.settings, m.editors), + } : m; - if (update_dynamics && m.settings.core.dynamics) { + if (update_dynamics && m.globals.settings.core.dynamics) { schedule_evaluation(~schedule_action, m); m; } else { @@ -241,19 +67,19 @@ let update_cached_data = (~schedule_action, update, m: Model.t): Model.t => { let perform_action = (model: Model.t, a: Action.t): Result.t(Model.t) => switch ( Editors.get_selected_editor( - ~selection=model.ui_state.active_editor |> Option.get, + ~selection=model.active_editor |> Option.get, model.editors, model.results, ) |> Option.get - |> Haz3lcore.Perform.go(~settings=model.settings.core, a) + |> Haz3lcore.Perform.go(~settings=model.globals.settings.core, a) ) { | exception (Invalid_argument(_)) => Ok(model) | Error(err) => Error(FailedToPerform(err)) | Ok(ed) => let (editors, results) = Editors.put_selected_editor( - ~selection=model.ui_state.active_editor |> Option.get, + ~selection=model.active_editor |> Option.get, model.editors, model.results, ed, @@ -317,36 +143,47 @@ let export_persistent_data = () => { print_endline("INFO: Persistent data exported to Init.ml"); }; -let ui_state_update = - (ui_state: Model.ui_state, update: set_meta, ~schedule_action as _) - : Model.ui_state => { - switch (update) { - | Mousedown => {...ui_state, mousedown: true} - | Mouseup => {...ui_state, mousedown: false} - | ShowBackpackTargets(b) => {...ui_state, show_backpack_targets: b} - | FontMetrics(font_metrics) => {...ui_state, font_metrics} - }; -}; - let rec apply = (model: Model.t, update: t, state: State.t, ~schedule_action) : Result.t(Model.t) => { let m: Result.t(Model.t) = switch (update) { | Reset => Ok(Model.reset(model)) - | Set(Evaluation(_) as s_action) => Ok(update_settings(s_action, model)) - | Set(s_action) => - let model = update_settings(s_action, model); - Model.save(model); - switch (update) { - // NOTE: Load here necessary to load editors on switching mode - | Set(Mode(_)) => Ok(Model.load(model)) - | _ => Ok(model) - }; - | SetMeta(action) => - let ui_state = - ui_state_update(model.ui_state, action, ~schedule_action); - Ok({...model, ui_state}); + | Globals(SetMousedown(b)) => + Ok({ + ...model, + globals: { + ...model.globals, + mousedown: b, + }, + }) + | Globals(SetShowBackpackTargets(b)) => + Ok({ + ...model, + globals: { + ...model.globals, + show_backpack_targets: b, + }, + }) + | Globals(SetFontMetrics(fm)) => + Ok({ + ...model, + globals: { + ...model.globals, + font_metrics: fm, + }, + }) + | Globals(Set(s)) => + Ok({ + ...model, + globals: { + ...model.globals, + settings: Settings.Update.update(s, model.globals.settings), + }, + }) + | Globals(JumpToTile(tile)) => + // TODO: jump to tiles in other editors + perform_actions(model, [Jump(TileId(tile))]) | UpdateExplainThisModel(u) => let explainThisModel = ExplainThisUpdate.set_update(model.explainThisModel, u); @@ -363,7 +200,7 @@ let rec apply = | None => Ok(model) | Some(data) => Export.import_all(data, ~specs=ExerciseSettings.exercises); - Ok(Model.load(model)); + Ok(Model.load()); } | InitImportScratchpad(file) => JsUtil.read_file(file, data => @@ -377,11 +214,11 @@ let rec apply = export_persistent_data(); Ok(model); | ResetCurrentEditor => - let instructor_mode = model.settings.instructor_mode; + let instructor_mode = model.globals.settings.instructor_mode; let editors = Editors.reset_current(model.editors, ~instructor_mode); Model.save_and_return({...model, editors}); | SwitchScratchSlide(n) => - let instructor_mode = model.settings.instructor_mode; + let instructor_mode = model.globals.settings.instructor_mode; switch (switch_scratch_slide(model.editors, ~instructor_mode, n)) { | None => Error(FailedToSwitch) | Some(editors) => Model.save_and_return({...model, editors}) @@ -391,14 +228,7 @@ let rec apply = | None => Error(FailedToSwitch) | Some(editors) => Model.save_and_return({...model, editors}) } - | MakeActive(pos) => - Ok({ - ...model, - ui_state: { - ...model.ui_state, - active_editor: Some(pos), - }, - }) + | MakeActive(pos) => Ok({...model, active_editor: Some(pos)}) | TAB => /* Attempt to act intelligently when TAB is pressed. * TODO(andrew): Consider more advanced TAB logic. Instead @@ -408,7 +238,7 @@ let rec apply = * put down, farthest position where can put down, next hole */ let z = Editors.get_selected_editor( - ~selection=model.ui_state.active_editor |> Option.get, + ~selection=model.active_editor |> Option.get, model.editors, model.results, ) @@ -421,7 +251,9 @@ let rec apply = ? PerformAction(Put_down) : MoveToNextHole(Right); apply(model, a, state, ~schedule_action); | PerformAction(a) - when model.settings.core.assist && model.settings.core.statics => + when + model.globals.settings.core.assist + && model.globals.settings.core.statics => open Result.Syntax; let* model = perform_actions(model, [ResetSuggestion, a]); // let actions = @@ -436,7 +268,7 @@ let rec apply = /* This serializes the current editor to text, resets the current editor, and then deserializes. It is intended as a (tactical) nuclear option for weird backpack states */ - switch (model.ui_state.active_editor) { + switch (model.active_editor) { | None => Ok(model) | Some(selection) => switch ( @@ -476,7 +308,7 @@ let rec apply = | Undo => switch ( Editors.update_selected_editor( - ~selection=model.ui_state.active_editor, + ~selection=model.active_editor, editor => switch (Haz3lcore.Editor.undo(editor)) { | None => Error(Cant_undo) @@ -492,7 +324,7 @@ let rec apply = | Redo => switch ( Editors.update_selected_editor( - ~selection=model.ui_state.active_editor, + ~selection=model.active_editor, editor => switch (Haz3lcore.Editor.redo(editor)) { | None => Error(Cant_redo) @@ -529,7 +361,9 @@ let rec apply = let r = model.results |> ModelResults.find(key) - |> ModelResult.step_backward(~settings=model.settings.core.evaluation); + |> ModelResult.step_backward( + ~settings=model.globals.settings.core.evaluation, + ); Ok({...model, results: model.results |> ModelResults.add(key, r)}); | StepperAction(key, HideStepper) | ToggleStepper(key) => @@ -541,7 +375,9 @@ let rec apply = Some( v |> Option.value(~default=NoElab: ModelResult.t) - |> ModelResult.toggle_stepper(~settings=model.settings.core), + |> ModelResult.toggle_stepper( + ~settings=model.globals.settings.core, + ), ) ), }) diff --git a/src/haz3lweb/UpdateAction.re b/src/haz3lweb/UpdateAction.re index b52668a880..d446b0bb77 100644 --- a/src/haz3lweb/UpdateAction.re +++ b/src/haz3lweb/UpdateAction.re @@ -2,33 +2,6 @@ open Sexplib.Std; open Util; open Haz3lcore; -[@deriving (show({with_path: false}), sexp, yojson)] -type evaluation_settings_action = - | ShowRecord - | ShowCaseClauses - | ShowFnBodies - | ShowCasts - | ShowFixpoints - | ShowLookups - | ShowFilters - | ShowSettings - | ShowHiddenSteps; - -[@deriving (show({with_path: false}), sexp, yojson)] -type settings_action = - | Captions - | SecondaryIcons - | Statics - | Dynamics - | Assist - | Elaborate - | Benchmark - | ContextInspector - | InstructorMode - | Evaluation(evaluation_settings_action) - | ExplainThis(ExplainThisModel.Settings.action) - | Mode(Settings.mode); - [@deriving (show({with_path: false}), sexp, yojson)] type stepper_action = | StepForward(int) @@ -44,13 +17,6 @@ type agent_action = | Prompt(agent) | AcceptSuggestion; -[@deriving (show({with_path: false}), sexp, yojson)] -type set_meta = - | Mousedown - | Mouseup - | ShowBackpackTargets(bool) - | FontMetrics(FontMetrics.t); - [@deriving (show({with_path: false}), sexp, yojson)] type benchmark_action = | Start @@ -69,9 +35,8 @@ type cell_action = [@deriving (show({with_path: false}), sexp, yojson)] type t = /* meta */ + | Globals(Globals.Update.t) | Reset - | Set(settings_action) - | SetMeta(set_meta) | UpdateExplainThisModel(ExplainThisUpdate.update) | ExportPersistentData | DebugConsole(string) @@ -121,7 +86,7 @@ module Result = { let is_edit: t => bool = fun | PerformAction(a) => Action.is_edit(a) - | Set(s_action) => + | Globals(Set(s_action)) => switch (s_action) { | Mode(_) => true | Captions @@ -136,13 +101,11 @@ let is_edit: t => bool = | InstructorMode | Evaluation(_) => false } - | SetMeta(meta_action) => - switch (meta_action) { - | Mousedown - | Mouseup - | ShowBackpackTargets(_) - | FontMetrics(_) => false - } + | Globals( + SetMousedown(_) | SetShowBackpackTargets(_) | SetFontMetrics(_) | + JumpToTile(_), + ) => + false | Cut | Undo | Redo @@ -174,7 +137,7 @@ let is_edit: t => bool = let reevaluate_post_update: t => bool = fun | PerformAction(a) => Action.is_edit(a) - | Set(s_action) => + | Globals(Set(s_action)) => switch (s_action) { | Assist | Captions @@ -196,13 +159,11 @@ let reevaluate_post_update: t => bool = | InstructorMode | Mode(_) => true } - | SetMeta(meta_action) => - switch (meta_action) { - | Mousedown - | Mouseup - | ShowBackpackTargets(_) - | FontMetrics(_) => false - } + | Globals( + SetMousedown(_) | SetShowBackpackTargets(_) | SetFontMetrics(_) | + JumpToTile(_), + ) => + false | Assistant(AcceptSuggestion) => true | Assistant(Prompt(_)) => false | MoveToNextHole(_) @@ -233,7 +194,7 @@ let reevaluate_post_update: t => bool = let should_scroll_to_caret = fun - | Set(s_action) => + | Globals(Set(s_action)) => switch (s_action) { | Mode(_) => true | Captions @@ -248,13 +209,9 @@ let should_scroll_to_caret = | InstructorMode | Evaluation(_) => false } - | SetMeta(meta_action) => - switch (meta_action) { - | FontMetrics(_) => true - | Mousedown - | Mouseup - | ShowBackpackTargets(_) => false - } + | Globals(SetFontMetrics(_)) => true + | Globals(SetMousedown(_) | SetShowBackpackTargets(_) | JumpToTile(_)) => + false | Assistant(Prompt(_)) | UpdateResult(_) | UpdateEvals(_) diff --git a/src/haz3lweb/globals/Globals.re b/src/haz3lweb/globals/Globals.re new file mode 100644 index 0000000000..2591f724f3 --- /dev/null +++ b/src/haz3lweb/globals/Globals.re @@ -0,0 +1,67 @@ +open Sexplib.Std; + +/* This single data structure collects together all the app-wide values + that might be of interest to view functions. Most view functions then + take ~globals as an argument.*/ + +module Action = { + [@deriving (show({with_path: false}), sexp, yojson)] + type t = + | SetMousedown(bool) + | SetShowBackpackTargets(bool) + | SetFontMetrics(FontMetrics.t) + | Set(Settings.Update.t) + | JumpToTile(Haz3lcore.Id.t); +}; + +module Model = { + [@deriving (show({with_path: false}), sexp, yojson)] + type t = { + // Persistent: + settings: Settings.t, + // State: + font_metrics: FontMetrics.t, + show_backpack_targets: bool, + mousedown: bool, + // Calculated: + color_highlights: option(ColorSteps.colorMap), + // Other: + inject_global: Action.t => Ui_effect.t(unit), + /* inject_global is not really part of the model, but added here for + convenience to avoid having to pass it around everywhere. Can only + be used in view functions. */ + }; + + let load = () => { + let settings = Store.Settings.load(); + { + font_metrics: FontMetrics.init, + show_backpack_targets: false, + mousedown: false, + settings, + color_highlights: None, + inject_global: _ => + failwith( + "Cannot use inject_global outside of the main view function!", + ), + }; + }; + + let save = model => { + Store.Settings.save(model.settings); + }; +}; + +module Update = { + include Action; + + // Update is handled by the top-level update function + + let calculate = (color_highlights, model: Model.t): Model.t => { + ...model, + color_highlights, + }; +}; + +[@deriving (show({with_path: false}), sexp, yojson)] +type t = Model.t; diff --git a/src/haz3lweb/globals/Settings.re b/src/haz3lweb/globals/Settings.re new file mode 100644 index 0000000000..c77d381877 --- /dev/null +++ b/src/haz3lweb/globals/Settings.re @@ -0,0 +1,192 @@ +open Sexplib.Std; + +module Model = { + [@deriving (show({with_path: false}), sexp, yojson)] + type mode = + | Scratch + | Documentation + | Exercises; + + let mode_of_string = (s: string): mode => + switch (s) { + | "Scratch" => Scratch + | "Documentation" => Documentation + | "Exercises" => Exercises + | _ => failwith("mode_of_string: unknown mode:" ++ s) + }; + + [@deriving (show({with_path: false}), sexp, yojson)] + type t = { + captions: bool, + secondary_icons: bool, + core: Haz3lcore.CoreSettings.t, + async_evaluation: bool, + context_inspector: bool, + instructor_mode: bool, + benchmark: bool, + explainThis: ExplainThisModel.Settings.t, + mode, + }; + + let fix_instructor_mode = settings => + if (settings.instructor_mode && !ExerciseSettings.show_instructor) { + {...settings, instructor_mode: false}; + } else { + settings; + }; +}; + +module Update = { + [@deriving (show({with_path: false}), sexp, yojson)] + type evaluation = + | ShowRecord + | ShowCaseClauses + | ShowFnBodies + | ShowCasts + | ShowFixpoints + | ShowLookups + | ShowFilters + | ShowSettings + | ShowHiddenSteps; + + [@deriving (show({with_path: false}), sexp, yojson)] + type t = + | Captions + | SecondaryIcons + | Statics + | Dynamics + | Assist + | Elaborate + | Benchmark + | ContextInspector + | InstructorMode + | Evaluation(evaluation) + | ExplainThis(ExplainThisModel.Settings.action) + | Mode(Model.mode); + + let update = (action, settings: Model.t): Model.t => + switch (action) { + | Statics => { + ...settings, + core: { + ...settings.core, + statics: !settings.core.statics, + assist: !settings.core.statics, + dynamics: !settings.core.statics && settings.core.dynamics, + }, + } + | Elaborate => { + ...settings, + core: { + ...settings.core, + statics: !settings.core.elaborate || settings.core.statics, + elaborate: !settings.core.elaborate, + }, + } + | Dynamics => { + ...settings, + core: { + ...settings.core, + statics: !settings.core.dynamics || settings.core.statics, + dynamics: !settings.core.dynamics, + }, + } + | Assist => { + ...settings, + core: { + ...settings.core, + statics: !settings.core.assist || settings.core.statics, + assist: !settings.core.assist, + }, + } + | Evaluation(u) => + let evaluation = settings.core.evaluation; + let evaluation: Haz3lcore.CoreSettings.Evaluation.t = + switch (u) { + | ShowRecord => { + ...evaluation, + stepper_history: !evaluation.stepper_history, + } + | ShowCaseClauses => { + ...evaluation, + show_case_clauses: !evaluation.show_case_clauses, + } + | ShowFnBodies => { + ...evaluation, + show_fn_bodies: !evaluation.show_fn_bodies, + } + | ShowCasts => {...evaluation, show_casts: !evaluation.show_casts} + | ShowFixpoints => { + ...evaluation, + show_fixpoints: !evaluation.show_fixpoints, + } + | ShowLookups => { + ...evaluation, + show_lookup_steps: !evaluation.show_lookup_steps, + } + | ShowFilters => { + ...evaluation, + show_stepper_filters: !evaluation.show_stepper_filters, + } + | ShowSettings => { + ...evaluation, + show_settings: !evaluation.show_settings, + } + | ShowHiddenSteps => { + ...evaluation, + show_hidden_steps: !evaluation.show_hidden_steps, + } + }; + { + ...settings, + core: { + ...settings.core, + evaluation, + }, + }; + | ExplainThis(ToggleShow) => { + ...settings, + explainThis: { + ...settings.explainThis, + show: !settings.explainThis.show, + }, + } + | ExplainThis(ToggleShowFeedback) => { + ...settings, + explainThis: { + ...settings.explainThis, + show_feedback: !settings.explainThis.show_feedback, + }, + } + | ExplainThis(SetHighlight(a)) => + let highlight: ExplainThisModel.Settings.highlight = + switch (a, settings.explainThis.highlight) { + | (Toggle, All) => NoHighlight + | (Toggle, _) => All + | (Hover(_), All) => All + | (Hover(id), _) => One(id) + | (UnsetHover, All) => All + | (UnsetHover, _) => NoHighlight + }; + let explainThis = {...settings.explainThis, highlight}; + {...settings, explainThis}; + | Benchmark => {...settings, benchmark: !settings.benchmark} + | Captions => {...settings, captions: !settings.captions} + | SecondaryIcons => { + ...settings, + secondary_icons: !settings.secondary_icons, + } + | ContextInspector => { + ...settings, + context_inspector: !settings.context_inspector, + } + | InstructorMode => { + ...settings, //TODO[Matt]: Make sure instructor mode actually makes prelude read-only + instructor_mode: !settings.instructor_mode, + } + | Mode(mode) => {...settings, mode} + }; +}; + +[@deriving (show({with_path: false}), sexp, yojson)] +type t = Model.t; diff --git a/src/haz3lweb/view/Code.re b/src/haz3lweb/view/Code.re index a68fbbe6a8..dcf4c49703 100644 --- a/src/haz3lweb/view/Code.re +++ b/src/haz3lweb/view/Code.re @@ -147,10 +147,10 @@ let simple_view = ); }; -let of_hole = (~font_metrics, ~measured, g: Grout.t) => +let of_hole = (~globals: Globals.t, ~measured, g: Grout.t) => // TODO(d) fix sort EmptyHoleDec.view( - ~font_metrics, + ~font_metrics=globals.font_metrics, { measurement: Measured.find_g(g, measured), mold: Mold.of_grout(g, Any), @@ -159,18 +159,17 @@ let of_hole = (~font_metrics, ~measured, g: Grout.t) => let view = ( + ~globals: Globals.t, ~sort: Sort.t, - ~font_metrics, - ~settings: Settings.t, {state: {meta: {measured, buffer_ids, unselected, holes, _}, _}, _}: Editor.t, ) : Node.t => { module Text = Text({ let map = measured; - let settings = settings; + let settings = globals.settings; }); let code = Text.of_segment(buffer_ids, false, sort, unselected); - let holes = List.map(of_hole(~measured, ~font_metrics), holes); + let holes = List.map(of_hole(~measured, ~globals), holes); div(~attr=Attr.class_("code"), [span_c("code-text", code), ...holes]); }; diff --git a/src/haz3lweb/view/CtxInspector.re b/src/haz3lweb/view/CtxInspector.re index 82ceadc086..65299c1be2 100644 --- a/src/haz3lweb/view/CtxInspector.re +++ b/src/haz3lweb/view/CtxInspector.re @@ -3,7 +3,7 @@ open Node; open Util.Web; let jump_to = entry => - UpdateAction.PerformAction(Jump(TileId(Haz3lcore.Ctx.get_id(entry)))); + Globals.Update.JumpToTile(Haz3lcore.Ctx.get_id(entry)); let context_entry_view = (~inject, entry: Haz3lcore.Ctx.entry): Node.t => { let div_name = @@ -52,11 +52,11 @@ let ctx_sorts_view = (~inject, ci: Haz3lcore.Statics.Info.t) => |> List.rev |> List.map(context_entry_view(~inject)); -let view = - (~inject, ~settings: Settings.t, ci: Haz3lcore.Statics.Info.t): Node.t => { +let view = (~globals: Globals.t, ci: Haz3lcore.Statics.Info.t): Node.t => { let clss = clss( - ["context-inspector"] @ (settings.context_inspector ? ["visible"] : []), + ["context-inspector"] + @ (globals.settings.context_inspector ? ["visible"] : []), ); - div(~attr=clss, ctx_sorts_view(~inject, ci)); + div(~attr=clss, ctx_sorts_view(~inject=globals.inject_global, ci)); }; diff --git a/src/haz3lweb/view/CursorInspector.re b/src/haz3lweb/view/CursorInspector.re index d32eafad23..70d7ba34b8 100644 --- a/src/haz3lweb/view/CursorInspector.re +++ b/src/haz3lweb/view/CursorInspector.re @@ -12,44 +12,50 @@ let div_ok = div(~attr=clss([okc])); let code_err = (code: string): Node.t => div(~attr=clss(["code"]), [text(code)]); -let explain_this_toggle = (~inject, ~show_explain_this: bool): Node.t => { +let explain_this_toggle = (~globals: Globals.t): Node.t => { let tooltip = "Toggle language documentation"; let toggle_explain_this = _ => Virtual_dom.Vdom.Effect.Many([ - inject(Update.Set(ExplainThis(ToggleShow))), + globals.inject_global(Set(ExplainThis(ToggleShow))), Virtual_dom.Vdom.Effect.Stop_propagation, ]); div( ~attr=clss(["explain-this-button"]), - [Widgets.toggle(~tooltip, "?", show_explain_this, toggle_explain_this)], + [ + Widgets.toggle( + ~tooltip, + "?", + globals.settings.explainThis.show, + toggle_explain_this, + ), + ], ); }; let cls_view = (ci: Info.t): Node.t => div(~attr=clss(["syntax-class"]), [text(ci |> Info.cls_of |> Cls.show)]); -let ctx_toggle = (~inject, context_inspector: bool): Node.t => +let ctx_toggle = (~globals: Globals.t): Node.t => div( ~attr= Attr.many([ - Attr.on_click(_ => inject(Update.Set(ContextInspector))), - clss(["gamma"] @ (context_inspector ? ["visible"] : [])), + Attr.on_click(_ => globals.inject_global(Set(ContextInspector))), + clss( + ["gamma"] @ (globals.settings.context_inspector ? ["visible"] : []), + ), ]), [text("Γ")], ); -let term_view = (~inject, ~settings: Settings.t, ci) => { +let term_view = (~globals: Globals.t, ci) => { let sort = ci |> Info.sort_of |> Sort.show; div( ~attr=clss(["ci-header", sort] @ (Info.is_error(ci) ? [errc] : [])), [ - ctx_toggle(~inject, settings.context_inspector), - CtxInspector.view(~inject, ~settings, ci), + ctx_toggle(~globals), + CtxInspector.view(~globals, ci), div(~attr=clss(["term-tag"]), [text(sort)]), - explain_this_toggle( - ~inject, - ~show_explain_this=settings.explainThis.show, - ), + explain_this_toggle(~globals), cls_view(ci), ], ); @@ -238,12 +244,9 @@ let tpat_view = (_: Cls.t, status: Info.status_tpat) => let secondary_view = (cls: Cls.t) => div_ok([text(cls |> Cls.show)]); -let view_of_info = (~inject, ~settings, ci): Node.t => { +let view_of_info = (~globals, ci): Node.t => { let wrapper = status_view => - div( - ~attr=clss(["info"]), - [term_view(~inject, ~settings, ci), status_view], - ); + div(~attr=clss(["info"]), [term_view(~globals, ci), status_view]); switch (ci) { | Secondary(_) => wrapper(div([])) | InfoExp({cls, status, _}) => wrapper(exp_view(cls, status)) @@ -253,13 +256,13 @@ let view_of_info = (~inject, ~settings, ci): Node.t => { }; }; -let inspector_view = (~inject, ~settings, ci): Node.t => +let inspector_view = (~globals, ci): Node.t => div( ~attr=clss(["cursor-inspector"] @ [Info.is_error(ci) ? errc : okc]), - [view_of_info(~inject, ~settings, ci)], + [view_of_info(~globals, ci)], ); -let view = (~inject, ~settings: Settings.t, cursor_info: option(Info.t)) => { +let view = (~globals: Globals.t, cursor_info: option(Info.t)) => { let bar_view = div(~attr=Attr.id("bottom-bar")); let err_view = err => bar_view([ @@ -269,11 +272,11 @@ let view = (~inject, ~settings: Settings.t, cursor_info: option(Info.t)) => { ), ]); switch (cursor_info) { - | _ when !settings.core.statics => div_empty + | _ when !globals.settings.core.statics => div_empty | None => err_view("Whitespace or Comment") | Some(ci) => bar_view([ - inspector_view(~inject, ~settings, ci), + inspector_view(~globals, ci), div( ~attr=clss(["id"]), [text(String.sub(Id.to_string(Info.id_of(ci)), 0, 4))], diff --git a/src/haz3lweb/view/Deco.re b/src/haz3lweb/view/Deco.re index 2348d5a3bf..1af0706bcc 100644 --- a/src/haz3lweb/view/Deco.re +++ b/src/haz3lweb/view/Deco.re @@ -3,12 +3,12 @@ open Util; open Haz3lcore; module Deco = (M: { - let ui_state: Model.ui_state; + let globals: Globals.t; let editor: Editor.t; }) => { - let font_metrics = M.ui_state.font_metrics; + let font_metrics = M.globals.font_metrics; let map = M.editor.state.meta.measured; - let show_backpack_targets = M.ui_state.show_backpack_targets; + let show_backpack_targets = M.globals.show_backpack_targets; let terms = M.editor.state.meta.terms; let term_ranges = M.editor.state.meta.term_ranges; let tiles = M.editor.state.meta.tiles; @@ -317,12 +317,14 @@ module Deco = (M: { let statics = eh => err_holes(eh); - let editor = (zipper, sel_seg) => - List.concat([ - caret(zipper), - indicated_piece_deco(zipper), - selected_pieces(zipper), - backpack(zipper), - targets'(zipper.backpack, sel_seg), - ]); + let editor = (zipper, sel_seg, selected) => + selected + ? List.concat([ + caret(zipper), + indicated_piece_deco(zipper), + selected_pieces(zipper), + backpack(zipper), + targets'(zipper.backpack, sel_seg), + ]) + : []; }; diff --git a/src/haz3lweb/view/EditorModeView.re b/src/haz3lweb/view/EditorModeView.re index bd1c9afddf..d3448b05ff 100644 --- a/src/haz3lweb/view/EditorModeView.re +++ b/src/haz3lweb/view/EditorModeView.re @@ -8,17 +8,19 @@ let option_view = (name, n) => [text(n)], ); -let mode_menu = (~inject: Update.t => 'a, ~mode: Settings.mode) => +let mode_menu = (~inject: Update.t => 'a, ~mode: Settings.Model.mode) => div( ~attr=Attr.many([Attr.class_("mode-name"), Attr.title("Toggle Mode")]), [ select( ~attr= Attr.on_change((_, name) => - inject(Set(Mode(Settings.mode_of_string(name)))) + inject( + Globals(Set(Mode(Settings.Model.mode_of_string(name)))), + ) ), List.map( - option_view(Settings.show_mode(mode)), + option_view(Settings.Model.show_mode(mode)), ["Scratch", "Documentation", "Exercises"], ), ), @@ -98,14 +100,14 @@ let instructor_toggle = (~inject, ~instructor_mode) => ExerciseSettings.show_instructor ? [ toggle("🎓", ~tooltip="Toggle Instructor Mode", instructor_mode, _ => - inject(Update.Set(InstructorMode)) + inject(Globals.Update.Set(InstructorMode)) ), ] : []; let exercises_view = (~inject, ~cur_slide, ~specs, ~instructor_mode) => { [mode_menu(~inject, ~mode=Exercises)] - @ instructor_toggle(~inject, ~instructor_mode) + @ instructor_toggle(~inject=u => inject(Globals(u)), ~instructor_mode) @ slide_select(~inject, ~cur_slide, ~num_slides=List.length(specs)); }; diff --git a/src/haz3lweb/view/ExerciseMode.re b/src/haz3lweb/view/ExerciseMode.re index fe5e927d7a..6d425fc0fd 100644 --- a/src/haz3lweb/view/ExerciseMode.re +++ b/src/haz3lweb/view/ExerciseMode.re @@ -21,11 +21,10 @@ let render_cells = (settings: Settings.t, v: list(vis_marked(Node.t))) => { let view = ( + ~globals: Globals.t, + ~inject, ~select, - ~inject_global, - ~ui_state: Model.ui_state, ~selection: option((Exercise.pos, Editors.Selection.cell)), - ~settings: Settings.t, ~exercise, ~results, ~highlights, @@ -33,9 +32,9 @@ let view = let Exercise.{eds} = exercise; let stitched_dynamics = Exercise.stitch_dynamic( - settings.core, + globals.settings.core, exercise, - settings.core.dynamics ? Some(results) : None, + globals.settings.core.dynamics ? Some(results) : None, ); let { test_validation, @@ -62,6 +61,7 @@ let view = this_pos: Exercise.pos, ) => { CellEditor.view( + ~globals, ~select=s => select((this_pos, s)), ~selected= switch (selection) { @@ -71,21 +71,18 @@ let view = ~inject= fun | ResultAction(StepperEditorAction(_, a)) - | MainEditor(a) => inject_global(UpdateAction.PerformAction(a)) + | MainEditor(a) => inject(UpdateAction.PerformAction(a)) | ResultAction(StepperAction(a)) => - inject_global( + inject( UpdateAction.StepperAction( Exercise.key_for_statics(this_pos), a, ), ) | ResultAction(ToggleStepper) => - inject_global( + inject( UpdateAction.ToggleStepper(Exercise.key_for_statics(this_pos)), ), - ~inject_global, - ~ui_state, - ~settings, ~highlights, ~result_kind, ~caption=Cell.caption(caption, ~rest=?subcaption), @@ -119,7 +116,7 @@ let view = editor_view( Prelude, ~caption="Prelude", - ~subcaption=settings.instructor_mode ? "" : " (Read-Only)", + ~subcaption=globals.settings.instructor_mode ? "" : " (Read-Only)", ~editor=eds.prelude, ~di=prelude, ), @@ -164,7 +161,10 @@ let view = switch (specific_ctx) { | None => Node.div([text("No context available")]) // TODO show exercise configuration error | Some(specific_ctx) => - CtxInspector.ctx_view(~inject=inject_global, specific_ctx) + CtxInspector.ctx_view( + ~inject=globals.inject_global, + specific_ctx, + ) }; }; }; @@ -211,7 +211,7 @@ let view = let mutation_testing_view = Always( Grading.MutationTestingReport.view( - ~inject=inject_global, + ~inject, grading_report.mutation_testing_report, grading_report.point_distribution.mutation_testing, ), @@ -259,7 +259,7 @@ let view = let impl_grading_view = Always( Grading.ImplGradingReport.view( - ~inject=inject_global, + ~inject, ~report=grading_report.impl_grading_report, ~syntax_report=grading_report.syntax_report, ~max_points=grading_report.point_distribution.impl_grading, @@ -268,7 +268,7 @@ let view = [score_view, title_view, prompt_view] @ render_cells( - settings, + globals.settings, [ prelude_view, correct_impl_view, diff --git a/src/haz3lweb/view/ExplainThis.re b/src/haz3lweb/view/ExplainThis.re index 1b2480bbeb..606b044bec 100644 --- a/src/haz3lweb/view/ExplainThis.re +++ b/src/haz3lweb/view/ExplainThis.re @@ -105,10 +105,18 @@ let highlight = Attr.many([ classes, Attr.on_mouseenter(_ => - inject(UpdateAction.Set(ExplainThis(SetHighlight(Hover(id))))) + inject( + UpdateAction.Globals( + Set(ExplainThis(SetHighlight(Hover(id)))), + ), + ) ), Attr.on_mouseleave(_ => - inject(UpdateAction.Set(ExplainThis(SetHighlight(UnsetHover)))) + inject( + UpdateAction.Globals( + Set(ExplainThis(SetHighlight(UnsetHover))), + ), + ) ), Attr.on_click(_ => inject(UpdateAction.PerformAction(Select(Term(Id(id, Left))))) @@ -206,10 +214,9 @@ let mk_explanation = let expander_deco = ( + ~globals as {font_metrics, settings, _} as globals: Globals.t, ~docs: ExplainThisModel.t, - ~settings: Settings.t, ~inject, - ~ui_state as {font_metrics, _} as ui_state: Model.ui_state, ~options: list((ExplainThisForm.form_id, Segment.t)), ~group: ExplainThisForm.group, ~doc: ExplainThisForm.form, @@ -218,7 +225,7 @@ let expander_deco = module Deco = Deco.Deco({ let editor = editor; - let ui_state = ui_state; + let globals = globals; }); switch (doc.expandable_id, List.length(options)) { | (None, _) @@ -326,9 +333,8 @@ let expander_deco = let example_view = ( + ~globals: Globals.t, ~inject, - ~ui_state, - ~settings: Settings.t, ~group_id, ~form_id, ~examples: list(ExplainThisForm.example), @@ -342,7 +348,7 @@ let example_view = List.mapi( (_, {term, message, sub_id, _}: ExplainThisForm.example) => { let feedback = - settings.explainThis.show_feedback + globals.settings.explainThis.show_feedback ? [ example_feedback_view( ~inject, @@ -357,11 +363,9 @@ let example_view = ~attr=clss(["example"]), [ CellEditor.view( + ~globals, ~select=_ => Ui_effect.Ignore, ~inject=_ => Ui_effect.Ignore, - ~inject_global=_ => Ui_effect.Ignore, - ~ui_state, - ~settings, ~highlights=None, ~selected=None, ~caption=None, @@ -373,19 +377,19 @@ let example_view = MakeTerm.from_zip_for_sem(editor.state.zipper); let statics = CachedStatics.statics_of_term( - ~settings=settings.core, + ~settings=globals.settings.core, term, editor, ); let result: ModelResult.t = - settings.core.dynamics + globals.settings.core.dynamics ? Evaluation({ elab: { d: term, }, evaluation: Interface.evaluate( - ~settings=settings.core, + ~settings=globals.settings.core, term, ), previous: ResultPending, @@ -446,8 +450,7 @@ let rec bypass_parens_typ = (typ: Typ.t) => { type message_mode = | MessageContent( UpdateAction.t => Virtual_dom.Vdom.Effect.t(unit), - Model.ui_state, - Settings.t, + Globals.t, ) | Colorings; @@ -480,10 +483,10 @@ let get_doc = | (_, None) => doc.explanation }; switch (mode) { - | MessageContent(inject, ui_state, settings) => + | MessageContent(inject, globals) => let (explanation, color_map) = mk_explanation( - ~settings, + ~settings=globals.settings, ~inject, group.id, doc.id, @@ -508,10 +511,9 @@ let get_doc = Editor.init(~read_only=true, doc.syntactic_form |> Zipper.unzip); let expander_deco = expander_deco( + ~globals, ~docs, - ~settings, ~inject, - ~ui_state, ~options, ~group, ~doc, @@ -523,7 +525,7 @@ let get_doc = module Deco = Deco.Deco({ let editor = editor; - let ui_state = ui_state; + let globals = globals; }); Deco.color_highlights(ColorSteps.to_list(highlights)); | None => [] @@ -531,17 +533,15 @@ let get_doc = let statics = CachedStatics.empty_statics; let syntactic_form_view = ReadOnlyEditor.view( - ~ui_state, - ~settings, + ~globals, ~overlays=highlight_deco @ [expander_deco], ~sort, {editor, statics}, ); let example_view = example_view( + ~globals, ~inject, - ~ui_state, - ~settings, ~group_id=group.id, ~form_id=doc.id, ~examples=doc.examples, @@ -2398,18 +2398,13 @@ let get_color_map = let view = ( + ~globals: Globals.t, ~inject, - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~explainThisModel: ExplainThisModel.t, info: option(Info.t), ) => { let (syn_form, (explanation, _), example) = - get_doc( - ~docs=explainThisModel, - info, - MessageContent(inject, ui_state, settings), - ); + get_doc(~docs=explainThisModel, info, MessageContent(inject, globals)); div( ~attr=Attr.id("side-bar"), [ @@ -2422,16 +2417,18 @@ let view = Widgets.toggle( ~tooltip="Toggle highlighting", "🔆", - settings.explainThis.highlight == All, + globals.settings.explainThis.highlight == All, _ => - inject(UpdateAction.Set(ExplainThis(SetHighlight(Toggle)))) + globals.inject_global( + Set(ExplainThis(SetHighlight(Toggle))), + ) ), div( ~attr= Attr.many([ clss(["close"]), Attr.on_click(_ => - inject(UpdateAction.Set(ExplainThis(ToggleShow))) + globals.inject_global(Set(ExplainThis(ToggleShow))) ), ]), [text("x")], diff --git a/src/haz3lweb/view/NutMenu.re b/src/haz3lweb/view/NutMenu.re index 7b771c40fb..8f32f67b4d 100644 --- a/src/haz3lweb/view/NutMenu.re +++ b/src/haz3lweb/view/NutMenu.re @@ -49,7 +49,7 @@ let settings_menu = ) => { let toggle = (icon, tooltip, bool, setting) => toggle_named(icon, ~tooltip, bool, _ => - inject(UpdateAction.Set(setting)) + inject(UpdateAction.Globals(Set(setting))) ); [ toggle("τ", "Toggle Statics", core.statics, Statics), diff --git a/src/haz3lweb/view/Page.re b/src/haz3lweb/view/Page.re index aa10d55b8b..27b042fc0c 100644 --- a/src/haz3lweb/view/Page.re +++ b/src/haz3lweb/view/Page.re @@ -7,7 +7,7 @@ open Node; let handlers = (~inject: UpdateAction.t => Ui_effect.t(unit), model) => { let get_selection = (model: Model.t): option(string) => { - let* selection = model.ui_state.active_editor; + let* selection = model.active_editor; Editors.get_selected_editor(~selection, model.editors, model.results) |> Option.map(Printer.to_string_selection); }; @@ -26,7 +26,7 @@ let handlers = (~inject: UpdateAction.t => Ui_effect.t(unit), model) => { Attr.on_keyup(key_handler(~inject, ~dir=KeyUp)), Attr.on_keydown(key_handler(~inject, ~dir=KeyDown)), /* safety handler in case mousedown overlay doesn't catch it */ - Attr.on_mouseup(_ => inject(SetMeta(Mouseup))), + Attr.on_mouseup(_ => inject(Globals(SetMousedown(false)))), Attr.on_blur(_ => { JsUtil.focus_clipboard_shim(); Effect.Ignore; @@ -63,16 +63,18 @@ let handlers = (~inject: UpdateAction.t => Ui_effect.t(unit), model) => { let main_view = ( ~inject: UpdateAction.t => Ui_effect.t(unit), - {settings, editors, explainThisModel, results, statics, ui_state, _}: Model.t, + {globals, editors, explainThisModel, results, statics, active_editor, _}: Model.t, ) => { + let globals = {...globals, inject_global: x => inject(Globals(x))}; + let settings = globals.settings; let _ = - switch (ui_state.active_editor) { + switch (active_editor) { | Some(ae) => print_endline("SELECTED: " ++ Editors.Selection.show(ae)) | None => print_endline("NO ACTIVE EDITOR") }; let cursor_info = Editors.get_cursor_info( - ~selection=ui_state.active_editor, + ~selection=active_editor, ~settings, editors, results, @@ -85,16 +87,10 @@ let main_view = @ [div(~attr=Attr.id("title"), [text("hazel")])] @ [EditorModeView.view(~inject, ~settings, ~editors)], ); - let bottom_bar = CursorInspector.view(~inject, ~settings, cursor_info); + let bottom_bar = CursorInspector.view(~globals, cursor_info); let sidebar = settings.explainThis.show && settings.core.statics - ? ExplainThis.view( - ~inject, - ~ui_state, - ~settings, - ~explainThisModel, - cursor_info, - ) + ? ExplainThis.view(~globals, ~inject, ~explainThisModel, cursor_info) : div([]); let highlights = ExplainThis.get_color_map(~settings, ~explainThisModel, cursor_info); @@ -105,7 +101,7 @@ let main_view = let result_key = ScratchSlide.scratch_key(string_of_int(idx)); let statics = CachedStatics.lookup(statics, result_key); let selected = - switch (ui_state.active_editor) { + switch (active_editor) { | Some(Editors.Selection.Scratch(i)) => Some(i) | _ => None }; @@ -114,8 +110,7 @@ let main_view = s => inject(UpdateAction.MakeActive(Editors.Selection.Scratch(s))), ~inject, - ~ui_state, - ~settings, + ~globals, ~highlights, ~results, ~result_key, @@ -132,7 +127,7 @@ let main_view = |> Option.to_list; let statics = CachedStatics.lookup(statics, result_key); let selected = - switch (ui_state.active_editor) { + switch (active_editor) { | Some(Editors.Selection.Scratch(i)) => Some(i) | _ => None }; @@ -142,8 +137,7 @@ let main_view = s => inject(UpdateAction.MakeActive(Editors.Selection.Scratch(s))), ~inject, - ~ui_state, - ~settings, + ~globals, ~highlights, ~results, ~result_key, @@ -153,7 +147,7 @@ let main_view = ); | Exercises(_, _, exercise) => let selection = - switch (ui_state.active_editor) { + switch (active_editor) { | Some(Editors.Selection.Exercises(pos, sel)) => Some((pos, sel)) | _ => None }; @@ -163,9 +157,8 @@ let main_view = inject( UpdateAction.MakeActive(Editors.Selection.Exercises(pos, sel)), ), - ~inject_global=inject, - ~ui_state, - ~settings, + ~inject, + ~globals, ~selection, ~highlights, ~results, @@ -178,7 +171,7 @@ let main_view = ~attr= Attr.many([ Attr.id("main"), - Attr.classes([Settings.show_mode(settings.mode)]), + Attr.classes([Settings.Model.show_mode(settings.mode)]), ]), editors_view, ), diff --git a/src/haz3lweb/view/ScratchMode.re b/src/haz3lweb/view/ScratchMode.re index a7ca37aec0..554aabdf0f 100644 --- a/src/haz3lweb/view/ScratchMode.re +++ b/src/haz3lweb/view/ScratchMode.re @@ -2,10 +2,9 @@ open Haz3lcore; let view = ( + ~globals, ~select, ~inject: UpdateAction.t => Ui_effect.t(unit), - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~highlights, ~results: ModelResults.t, ~result_key, @@ -16,6 +15,7 @@ let view = let result = ModelResults.lookup(results, result_key) |> Option.get; [ CellEditor.view( + ~globals, ~select, ~inject= fun @@ -25,9 +25,6 @@ let view = | ResultAction(ToggleStepper) => inject(ToggleStepper(result_key)) | ResultAction(StepperEditorAction(_, a)) => inject(PerformAction(a)), - ~inject_global=inject, - ~ui_state, - ~settings, ~highlights, ~selected, ~locked=false, diff --git a/src/haz3lweb/view/SettingsModal.re b/src/haz3lweb/view/SettingsModal.re index 0a2993f61c..aa0b1de050 100644 --- a/src/haz3lweb/view/SettingsModal.re +++ b/src/haz3lweb/view/SettingsModal.re @@ -2,15 +2,17 @@ open Virtual_dom.Vdom; open Node; open Haz3lcore; -let view = (~inject, settings: CoreSettings.Evaluation.t) => { +let view = + ( + ~inject: Settings.Update.t => Ui_effect.t(unit), + settings: CoreSettings.Evaluation.t, + ) => { let modal = div(~attr=Attr.many([Attr.class_("settings-modal")])); - let setting = (icon, name, current, action: UpdateAction.settings_action) => + let setting = (icon, name, current, action: Settings.Update.t) => div( ~attr=Attr.many([Attr.class_("settings-toggle")]), [ - Widgets.toggle(~tooltip=name, icon, current, _ => - inject(Update.Set(action)) - ), + Widgets.toggle(~tooltip=name, icon, current, _ => inject(action)), text(name), ], ); @@ -18,11 +20,7 @@ let view = (~inject, settings: CoreSettings.Evaluation.t) => { modal([ div( ~attr=Attr.many([Attr.class_("settings-modal-top")]), - [ - Widgets.button(Icons.x, _ => - inject(Update.Set(Evaluation(ShowSettings))) - ), - ], + [Widgets.button(Icons.x, _ => inject(Evaluation(ShowSettings)))], ), setting( "h", @@ -77,9 +75,7 @@ let view = (~inject, settings: CoreSettings.Evaluation.t) => { ~attr= Attr.many([ Attr.class_("modal-back"), - Attr.on_mousedown(_ => - inject(Update.Set(Evaluation(ShowSettings))) - ), + Attr.on_mousedown(_ => inject(Evaluation(ShowSettings))), ]), [], ), diff --git a/src/haz3lweb/view/TestView.re b/src/haz3lweb/view/TestView.re index b6acb77f60..a7289f7df0 100644 --- a/src/haz3lweb/view/TestView.re +++ b/src/haz3lweb/view/TestView.re @@ -118,22 +118,22 @@ let jump_to_test = (~inject, pos, id, _) => { // }, // ); -let test_bar_segment = (~inject, pos, (id, reports)) => { +let test_bar_segment = (~inject_jump, (id, reports)) => { let status = reports |> TestMap.joint_status |> TestStatus.to_string; div( ~attr= Attr.many([ clss(["segment", status]), - Attr.on_click(jump_to_test(~inject, pos, id)), + Attr.on_click(_ => inject_jump(id)), ]), [], ); }; -let test_bar = (~inject, ~test_results: TestResults.t, pos) => +let test_bar = (~inject_jump, ~test_results: TestResults.t) => div( ~attr=Attr.class_("test-bar"), - List.map(test_bar_segment(~inject, pos), test_results.test_map), + List.map(test_bar_segment(~inject_jump), test_results.test_map), ); // result_summary_str and test_summary_str have been moved to haz3lcore/TestResults.re @@ -160,7 +160,7 @@ let test_text = (test_results: TestResults.t): Node.t => ], ); -let test_summary = (~inject, ~test_results: option(TestResults.t)) => { +let test_summary = (~inject_jump, ~test_results: option(TestResults.t)) => { div( ~attr=clss(["test-summary"]), { @@ -168,7 +168,7 @@ let test_summary = (~inject, ~test_results: option(TestResults.t)) => { | None => [Node.text("No test results available.")] | Some(test_results) => [ test_text(test_results), - test_bar(~inject, ~test_results, YourTestsTesting), + test_bar(~inject_jump, ~test_results), ] }; }, diff --git a/src/haz3lweb/view/assistant/UpdateAssistant.re b/src/haz3lweb/view/assistant/UpdateAssistant.re index 63d3abbd54..06cc961931 100644 --- a/src/haz3lweb/view/assistant/UpdateAssistant.re +++ b/src/haz3lweb/view/assistant/UpdateAssistant.re @@ -5,7 +5,7 @@ open OptUtil.Syntax; let assistant_action_to_editor_actions = ( - {settings, ui_state: {active_editor: selection, _}, _} as model: Model.t, + {globals: {settings, _}, active_editor: selection, _} as model: Model.t, agent_action, ) : list(Action.t) => diff --git a/src/haz3lweb/view/editor/Cell.re b/src/haz3lweb/view/editor/Cell.re index c4834291b9..c0bce4730b 100644 --- a/src/haz3lweb/view/editor/Cell.re +++ b/src/haz3lweb/view/editor/Cell.re @@ -1,4 +1,3 @@ -open Haz3lcore; open Virtual_dom.Vdom; open Node; @@ -24,10 +23,6 @@ let report_footer_view = content => { div(~attr=Attr.classes(["cell-item", "cell-report"]), content); }; -let test_report_footer_view = (~inject, ~test_results: option(TestResults.t)) => { - report_footer_view([TestView.test_summary(~inject, ~test_results)]); -}; - let panel = (~classes=[], content, ~footer: option(t)) => { simple_cell_view( [div(~attr=Attr.classes(["cell-item", "panel"] @ classes), content)] diff --git a/src/haz3lweb/view/editor/CellEditor.re b/src/haz3lweb/view/editor/CellEditor.re index 858828c345..4f72c9335e 100644 --- a/src/haz3lweb/view/editor/CellEditor.re +++ b/src/haz3lweb/view/editor/CellEditor.re @@ -19,11 +19,9 @@ type event = CodeEditor.event; let view = ( + ~globals: Globals.t, ~select: Editors.Selection.cell => Ui_effect.t(unit), ~inject, - ~inject_global, - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~highlights: option(ColorSteps.colorMap), ~selected: option(Editors.Selection.cell), ~caption: option(Node.t)=?, @@ -34,15 +32,16 @@ let view = ) => { let (footer, overlays) = CellResult.view( + ~globals, ~signal= fun | MakeActive(a) => select(a) - | MouseUp => inject_global(Update.SetMeta(Mouseup)) - | MouseDown => inject_global(Update.SetMeta(Mousedown)), + | JumpTo(id) => + Effect.Many([ + select(MainEditor), + inject(MainEditor(Jump(TileId(id)))), + ]), ~inject=a => inject(ResultAction(a)), - ~inject_global, - ~ui_state, - ~settings, ~selected=selected == Some(Result(0)), ~result_kind?, ~locked, @@ -58,19 +57,15 @@ let view = Option.to_list(caption) @ [ CodeEditor.view( + ~globals, ~signal= locked ? _ => Ui_effect.Ignore : fun - | MouseUp => inject_global(Update.SetMeta(Mouseup)) - | MouseDown => inject_global(Update.SetMeta(Mousedown)) | MakeActive => select(Editors.Selection.MainEditor), ~inject= locked - ? _ => Ui_effect.Ignore - : (action => inject_global(PerformAction(action))), - ~ui_state, - ~settings, + ? _ => Ui_effect.Ignore : (action => inject(MainEditor(action))), ~selected=selected == Some(MainEditor), ~highlights, ~overlays=overlays(model.editor.editor), diff --git a/src/haz3lweb/view/editor/CellResult.re b/src/haz3lweb/view/editor/CellResult.re index 9c005c0f1e..6ff0bc7791 100644 --- a/src/haz3lweb/view/editor/CellResult.re +++ b/src/haz3lweb/view/editor/CellResult.re @@ -29,8 +29,7 @@ let update = (~settings: CoreSettings.t, action, model) => module View = { type event = | MakeActive(Editors.Selection.cell) - | MouseUp - | MouseDown; + | JumpTo(Haz3lcore.Id.t); let error_msg = (err: ProgramResult.error) => switch (err) { @@ -48,11 +47,9 @@ module View = { let stepper_view = ( + ~globals as {settings, inject_global, _} as globals: Globals.t, ~signal as _: event => Ui_effect.t(unit), ~inject: action => Ui_effect.t(unit), - ~inject_global: Update.t => Ui_effect.t(unit), - ~ui_state, - ~settings: Settings.t, ~read_only: bool, stepper: Stepper.t, ) => { @@ -105,10 +102,9 @@ module View = { div(~attr=Attr.class_("equiv"), [Node.text("≡")]), StepperEditor.Steppable.view( // TODO: Maybe get rid of this signal? + ~globals, ~signal= (TakeStep(x)) => inject(StepperAction(StepForward(x))), - ~ui_state, - ~settings, ~overlays=[], current_model, ), @@ -116,10 +112,9 @@ module View = { : [ div(~attr=Attr.class_("equiv"), [Node.text("≡")]), StepperEditor.Steppable.view( + ~globals, ~signal= (TakeStep(x)) => inject(StepperAction(StepForward(x))), - ~ui_state, - ~settings, ~overlays=[], current_model, ), @@ -150,12 +145,7 @@ module View = { ), [ div(~attr=Attr.class_("equiv"), [Node.text("≡")]), - StepperEditor.Stepped.view( - ~ui_state, - ~settings, - ~overlays=[], - model, - ), + StepperEditor.Stepped.view(~globals, ~overlays=[], model), div( ~attr=Attr.classes(["stepper-justification"]), step.chosen_step @@ -200,7 +190,7 @@ module View = { @ ( settings.core.evaluation.show_settings ? SettingsModal.view( - ~inject=inject_global, + ~inject=u => inject_global(Set(u)), settings.core.evaluation, ) : [] @@ -210,10 +200,9 @@ module View = { let live_eval = ( + ~globals: Globals.t, ~signal: event => Ui_effect.t(unit), ~inject: action => Ui_effect.t(unit), - ~ui_state, - ~settings: Settings.t, ~selected, ~locked, result: ModelResult.eval_result, @@ -228,12 +217,9 @@ module View = { CodeEditor.view( ~signal= fun - | MakeActive => signal(MakeActive(MainEditor)) - | MouseUp => signal(MouseUp) - | MouseDown => signal(MouseDown), + | MakeActive => signal(MakeActive(MainEditor)), ~inject=a => inject(StepperEditorAction(0, a)), - ~ui_state, - ~settings, + ~globals, ~selected, ~highlights=None, ~sort=Sort.root, @@ -278,39 +264,28 @@ module View = { let footer = ( + ~globals: Globals.t, ~signal, ~inject, - ~inject_global, - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~result: ModelResult.t, ~selected: option(int), ~locked, ) => switch (result) { - | _ when !settings.core.dynamics => [] + | _ when !globals.settings.core.dynamics => [] | NoElab => [] | Evaluation(result) => [ live_eval( + ~globals, ~signal, ~inject, - ~ui_state, - ~settings, ~selected=selected == Some(0), ~locked, result, ), ] | Stepper(s) => - stepper_view( - ~signal, - ~inject, - ~inject_global, - ~settings, - ~ui_state, - ~read_only=locked, - s, - ) + stepper_view(~globals, ~signal, ~inject, ~read_only=locked, s) }; let test_status_icon_view = @@ -347,11 +322,9 @@ module View = { let view = ( + ~globals: Globals.t, ~signal: event => Ui_effect.t(unit), ~inject: action => Ui_effect.t(unit), - ~inject_global: UpdateAction.t => Ui_effect.t(unit), - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~selected: bool, ~result_kind=EvalResults, ~locked: bool, @@ -359,14 +332,12 @@ module View = { ) => switch (result_kind) { // Normal case: - | EvalResults when settings.core.dynamics => + | EvalResults when globals.settings.core.dynamics => let result = footer( + ~globals, ~signal, ~inject, - ~inject_global, - ~ui_state: Model.ui_state, - ~settings, ~result=model, ~selected=selected ? Some(0) : None, ~locked, @@ -375,7 +346,7 @@ module View = { switch (ModelResult.test_results(model)) { | Some(result) => test_result_layer( - ~font_metrics=ui_state.font_metrics, + ~font_metrics=globals.font_metrics, ~measured=editor.state.meta.measured, result, ) @@ -384,14 +355,13 @@ module View = { (result, test_overlay); // Just showing elaboration because evaluation is off: - | EvalResults when settings.core.elaborate => + | EvalResults when globals.settings.core.elaborate => let result = [ text("Evaluation disabled, showing elaboration:"), switch (ModelResult.get_elaboration(model)) { | Some(elab) => ReadOnlyEditor.view( - ~ui_state, - ~settings, + ~globals, { editor: elab.d |> ExpToSegment.exp_to_editor(~inline=false), statics: CachedStatics.empty_statics, @@ -413,7 +383,7 @@ module View = { switch (ModelResult.test_results(model)) { | Some(result) => test_result_layer( - ~font_metrics=ui_state.font_metrics, + ~font_metrics=globals.font_metrics, ~measured=editor.state.meta.measured, result, ) @@ -422,7 +392,10 @@ module View = { ( [ Cell.report_footer_view([ - TestView.test_summary(~inject=inject_global, ~test_results), + TestView.test_summary( + ~inject_jump=tile => signal(JumpTo(tile)), + ~test_results, + ), ]), ], test_overlay, diff --git a/src/haz3lweb/view/editor/CodeEditor.re b/src/haz3lweb/view/editor/CodeEditor.re index c7d54946f7..c31edd0ea6 100644 --- a/src/haz3lweb/view/editor/CodeEditor.re +++ b/src/haz3lweb/view/editor/CodeEditor.re @@ -12,9 +12,7 @@ let update = ReadOnlyEditor.update; let calculate = ReadOnlyEditor.calculate; type event = - | MakeActive - | MouseUp - | MouseDown; + | MakeActive; module View = { let get_goal = @@ -35,13 +33,13 @@ module View = { }; }; - let mousedown_overlay = (~signal, ~inject, ~font_metrics) => + let mousedown_overlay = (~globals: Globals.t, ~inject) => Node.div( ~attr= Attr.many( Attr.[ id("mousedown-overlay"), - on_mouseup(_ => signal(MouseUp)), + on_mouseup(_ => globals.inject_global(SetMousedown(false))), on_mousemove(e => { let mouse_handler = e##.target |> Js.Opt.get(_, _ => failwith("no target")); @@ -53,7 +51,8 @@ module View = { "code-container", ) |> Option.get; - let goal = get_goal(~font_metrics, text_box, e); + let goal = + get_goal(~font_metrics=globals.font_metrics, text_box, e); inject(Action.Select(Resize(Goal(Point(goal))))); }), ], @@ -61,10 +60,10 @@ module View = { [], ); - let mousedown_handler = (~signal, ~inject, ~font_metrics, evt) => { + let mousedown_handler = (~globals: Globals.t, ~signal, ~inject, evt) => { let goal = get_goal( - ~font_metrics, + ~font_metrics=globals.font_metrics, evt##.currentTarget |> Js.Opt.get(_, _ => failwith("")) |> JsUtil.get_child_with_class(_, "code-container") @@ -80,7 +79,7 @@ module View = { ]) | (false, 1) => Effect.Many([ - signal(MouseDown), + globals.inject_global(SetMousedown(true)), signal(MakeActive), inject(Action.Move(Goal(Point(goal)))), ]) @@ -91,10 +90,9 @@ module View = { let view = ( + ~globals: Globals.t, ~signal: event => Ui_effect.t(unit), ~inject: action => Ui_effect.t(unit), - ~ui_state: Model.ui_state, - ~settings: Settings.t, ~selected: bool, ~highlights: option(ColorSteps.colorMap), ~overlays: list(Node.t)=[], @@ -105,9 +103,13 @@ module View = { module Deco = Deco.Deco({ let editor = model.editor; - let ui_state = ui_state; + let globals = globals; }); - Deco.editor(model.editor.state.zipper, model.editor.state.meta.segment) + Deco.editor( + model.editor.state.zipper, + model.editor.state.meta.segment, + selected, + ) @ ( switch (highlights) { | Some(colorMap) => @@ -117,24 +119,11 @@ module View = { ); }; let overlays = edit_decos @ overlays; - let code_view = - ReadOnlyEditor.view(~ui_state, ~settings, ~overlays, ~sort?, model); + let code_view = ReadOnlyEditor.view(~globals, ~overlays, ~sort?, model); let mousedown_overlay = - selected && ui_state.mousedown - ? [ - mousedown_overlay( - ~signal, - ~inject, - ~font_metrics=ui_state.font_metrics, - ), - ] - : []; - let on_mousedown = - mousedown_handler( - ~signal, - ~inject, - ~font_metrics=ui_state.font_metrics, - ); + selected && globals.mousedown + ? [mousedown_overlay(~globals, ~inject)] : []; + let on_mousedown = mousedown_handler(~globals, ~signal, ~inject); Node.div( ~attr= Attr.many([ diff --git a/src/haz3lweb/view/editor/ReadOnlyEditor.re b/src/haz3lweb/view/editor/ReadOnlyEditor.re index 6129af4d56..3c8e7948c5 100644 --- a/src/haz3lweb/view/editor/ReadOnlyEditor.re +++ b/src/haz3lweb/view/editor/ReadOnlyEditor.re @@ -35,24 +35,12 @@ type event; type selection; let view = - ( - ~ui_state: Model.ui_state, - ~settings, - ~overlays: list(Node.t)=[], - ~sort=Sort.root, - model: model, - ) => { - let code_text_view = - Code.view( - ~sort, - ~font_metrics=ui_state.font_metrics, - ~settings, - model.editor, - ); + (~globals, ~overlays: list(Node.t)=[], ~sort=Sort.root, model: model) => { + let code_text_view = Code.view(~globals, ~sort, model.editor); let statics_decos = { module Deco = Deco.Deco({ - let ui_state = ui_state; + let globals = globals; let editor = model.editor; }); Deco.statics(model.statics.error_ids); diff --git a/src/haz3lweb/view/editor/StepperEditor.re b/src/haz3lweb/view/editor/StepperEditor.re index 4b2eea0af4..83b8f5656b 100644 --- a/src/haz3lweb/view/editor/StepperEditor.re +++ b/src/haz3lweb/view/editor/StepperEditor.re @@ -13,17 +13,16 @@ module Stepped = { type selection = ReadOnlyEditor.selection; - let view = - (~ui_state: Model.ui_state, ~settings, ~overlays=[], model: model) => { + let view = (~globals: Globals.t, ~overlays=[], model: model) => { let overlays = { module Deco = Deco.Deco({ let editor = model.editor.editor; - let ui_state = ui_state; + let globals = globals; }); overlays @ Deco.taken_step(model.step_id); }; - ReadOnlyEditor.view(~ui_state, ~settings, ~overlays, model.editor); + ReadOnlyEditor.view(~globals, ~overlays, model.editor); }; }; @@ -40,9 +39,8 @@ module Steppable = { let view = ( + ~globals: Globals.t, ~signal: event => Ui_effect.t(unit), - ~ui_state: Model.ui_state, - ~settings, ~overlays=[], model: model, ) => { @@ -50,11 +48,11 @@ module Steppable = { module Deco = Deco.Deco({ let editor = model.editor.editor; - let ui_state = ui_state; + let globals = globals; }); overlays @ Deco.next_steps(model.next_steps, ~inject=x => signal(TakeStep(x))); }; - ReadOnlyEditor.view(~ui_state, ~settings, ~overlays, model.editor); + ReadOnlyEditor.view(~globals, ~overlays, model.editor); }; };