this repo has no description
at main 179 lines 7.2 kB view raw
1(** Individual code cell within an x-ocaml page. 2 3 A cell is a single code editor + output region embedded in the page. Each 4 cell has a {!mode} that controls its appearance and behaviour: 5 6 - {b Interactive}: visible, editable. The default for cells without a 7 [mode] attribute. Edits are ephemeral (lost on page refresh). 8 - {b Exercise}: visible, editable. The reader writes or modifies code here. 9 - {b Test}: visible, read-only. Contains assertions that validate exercise 10 code. Linked to an exercise cell and run automatically after it. 11 - {b Hidden}: invisible. Provides definitions (types, helpers) available to 12 subsequent cells without cluttering the page. 13 14 Cells form a linear chain via {!set_prev}. When a cell is run, all 15 preceding cells that haven't completed are run first, ensuring definitions 16 are available. The chain determines line-number offsets so error locations 17 map correctly to the page. 18 19 {2 Test linking} 20 21 A {!Test} cell can be linked to an {!Exercise} cell in two ways: 22 23 - {b Positional}: if no [data-for] is set, a test cell links to the nearest 24 preceding exercise cell. 25 - {b Explicit}: [data-for="some-id"] links to the exercise cell whose 26 [data-id] is ["some-id"], regardless of position. 27 28 Linking is established by the page-level orchestrator ({!Page}), not by the 29 cell itself. The cell exposes {!set_on_completed} so the page can register 30 a callback that triggers linked test cells after a successful run. *) 31 32(** {1 Mode} *) 33 34type mode = 35 | Interactive (** Visible, editable. Edits are ephemeral. *) 36 | Exercise (** Visible, editable. *) 37 | Test (** Visible, read-only. Linked to an exercise cell. *) 38 | Hidden (** Invisible. Provides definitions to later cells. *) 39 40val mode_of_string : string -> mode 41(** [mode_of_string s] parses a mode from an HTML attribute value. 42 Returns {!Interactive} for unrecognised strings. *) 43 44val string_of_mode : mode -> string 45(** [string_of_mode m] returns the canonical lowercase string for a mode. *) 46 47(** {1 Cell type} *) 48 49type t 50(** An individual code cell. Mutable: tracks execution status, editor state, 51 and position in the cell chain. *) 52 53(** {1 Creation} *) 54 55val init : 56 id:int -> 57 mode:mode -> 58 run_on:[ `Click | `Load ] -> 59 ?cell_id:string -> 60 ?cell_for:string -> 61 ?cell_env:string -> 62 ?filename:string -> 63 ?merlin:bool -> 64 ?extra_style:Jstr.t -> 65 ?inline_style:Jstr.t -> 66 eval_fn:(id:int -> line_number:int -> string -> unit) -> 67 fmt_fn:(id:int -> string -> unit) -> 68 post_fn:(X_protocol.request -> unit) -> 69 Webcomponent.t -> 70 t 71(** Create and initialise a cell. 72 73 Attaches a shadow DOM to the given web component, creates the CodeMirror 74 editor (unless the mode is {!Hidden}), and sets up the merlin integration 75 (unless [~merlin:false] is passed). 76 77 @param id Unique numeric identifier (typically the cell's position on page). 78 @param mode Determines editability and visibility. 79 @param run_on Whether to run automatically on page load or only on click. 80 @param cell_id Optional [data-id] attribute for test-linking targets. 81 @param cell_for Optional [data-for] attribute linking a test to an exercise. 82 @param cell_env Optional [data-env] for future environment scoping. 83 @param filename Optional filename for merlin and error reporting. 84 @param merlin Whether to enable merlin integration. Default [true]; 85 set to [false] to disable completions and type-on-hover for this cell. 86 Has no effect on {!Hidden} cells, which never have merlin regardless. 87 @param extra_style URL to an external stylesheet to load. 88 @param inline_style Inline CSS for the [:host] selector. 89 @param eval_fn Called to evaluate code. Receives the cell [~id], 90 [~line_number] offset, and the source code string. 91 @param fmt_fn Called to format code. Receives the cell [~id] and source. 92 @param post_fn Called to send raw protocol messages (for merlin). *) 93 94(** {1 Accessors} *) 95 96val id : t -> int 97(** The cell's numeric identifier. *) 98 99val mode : t -> mode 100(** The cell's mode. *) 101 102val cell_id : t -> string option 103(** The [data-id] attribute, if set. Used as a target for [data-for] linking. *) 104 105val cell_for : t -> string option 106(** The [data-for] attribute, if set. Links a test cell to an exercise cell. *) 107 108val cell_env : t -> string option 109(** The [data-env] attribute, if set. Reserved for environment scoping. *) 110 111val source : t -> string 112(** The current source code. Reads from the CodeMirror editor if present, 113 otherwise from the internal text buffer (for hidden cells). *) 114 115val has_completed : t -> bool 116(** [true] if the cell has been run and completed successfully since the last 117 invalidation. *) 118 119(** {1 Execution} *) 120 121val run : t -> unit 122(** Run this cell. If preceding cells in the chain have not completed, they 123 are run first (cascading). Does nothing if the cell is already running. *) 124 125val loadable : t -> bool 126(** [true] if the cell's [run_on] is [`Load]. *) 127 128val completed_run : t -> X_protocol.output list -> unit 129(** Called by the backend when evaluation completes. Displays the output and 130 marks the cell as successfully run. If the next cell in the chain was 131 waiting, triggers it. 132 133 After marking the cell complete, fires any callback registered via 134 {!set_on_completed}. The callback fires after every completed run, 135 regardless of whether the output contains errors. *) 136 137val set_on_completed : t -> (t -> unit) -> unit 138(** [set_on_completed cell f] registers [f] to be called each time [cell] 139 completes a run. Used by {!Page} to trigger linked test cells after 140 an exercise cell finishes. 141 142 Replaces any previously registered callback. *) 143 144val set_stop_fn : t -> (unit -> unit) -> unit 145(** [set_stop_fn cell f] registers [f] to be called when the user clicks 146 "Stop" while the cell is running. Typically [f] resets the backend 147 and all cells. *) 148 149val reset_status : t -> unit 150(** Reset the cell to {!Not_run} state: clears output messages, restores 151 the "Run" button text, and resets test-result tracking flags. 152 Does {e not} invalidate the cell chain. *) 153 154(** {1 Chain management} *) 155 156val set_prev : prev:t option -> t -> unit 157(** [set_prev ~prev cell] sets [cell]'s predecessor in the execution chain. 158 Updates line-number offsets for all subsequent cells. The previous cell's 159 [next] pointer is updated as well. *) 160 161(** {1 Content and display} *) 162 163val set_source : t -> string -> unit 164(** Replace the cell's source code. Updates the editor if present. *) 165 166val add_message : t -> int -> X_protocol.output list -> unit 167(** [add_message cell loc msgs] adds output messages at character offset 168 [loc] in the cell's editor. No-op for hidden cells. *) 169 170val start : t -> Webcomponent.t -> unit 171(** [start cell element] reads the initial source from the element's 172 [textContent] and loads it into the cell. Called once after the 173 WebComponent's [connectedCallback]. *) 174 175(** {1 Merlin integration} *) 176 177val receive_merlin : t -> Protocol.answer -> unit 178(** Handle a merlin response for this cell. No-op if the cell has no 179 merlin worker. *)