oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use crate::{display, lists, projection, structure};
2use serde_json::{json, Value};
3use yrs::{Doc, Transact, XmlOut};
4
5fn block(doc: &Doc, at: u32) -> Result<String, &'static str> {
6 let (id, _) = display::locate(doc, at, 0)?;
7 let root = doc.get_or_insert_xml_fragment("prosemirror");
8 let txn = doc.transact();
9 match projection::find(&root, &txn, &id) {
10 Some(XmlOut::Element(_)) => Ok(id),
11 Some(XmlOut::Text(_)) => structure::parent(&root, &txn, &id)
12 .map(|(parent, _)| projection::node_id(&XmlOut::Fragment(parent))).ok_or("missing_parent"),
13 _ => Err("missing_node"),
14 }
15}
16pub fn execute(doc: &Doc, request: &Value) -> Result<(), &'static str> {
17 let at = request["at"].as_u64().and_then(|n| u32::try_from(n).ok()).ok_or("invalid_range")?;
18 let kind = request["kind"].as_str().ok_or("invalid_command")?;
19 if !["paragraph", "heading", "blockquote", "bullet_list", "ordered_list"].contains(&kind) { return Err("invalid_command"); }
20 let id = block(doc, at)?;
21 match request["op"].as_str() {
22 Some("display_autoformat") => {
23 display::execute(doc, &json!({"at":at,"length":request["length"],"text":""}))?;
24 let command = json!({"op":"block","node":id,"type":kind,"level":request["level"]});
25 let target = lists::normalization_target(doc, &command);
26 structure::execute(doc, &command)?;
27 if let Some(id) = target.and_then(|t| lists::normalized_identity(doc, t)) {
28 lists::normalize(doc, &mut std::collections::HashSet::from([id]));
29 }
30 },
31 Some("display_revert_rule") => {
32 if lists::contains(doc, &id) {
33 lists::execute(doc, &json!({"node":id,"delta":-1}))?;
34 } else if kind == "blockquote" {
35 structure::execute(doc, &json!({"op":"block","node":id,"type":"blockquote"}))?;
36 }
37 let id = block(doc, at)?;
38 structure::execute(doc, &json!({"op":"block","node":id,"type":request["prior_type"],"level":request["prior_attrs"]["level"].as_str().and_then(|s| s.parse::<u32>().ok()).unwrap_or(1)}))?;
39 display::execute(doc, &json!({"at":at,"length":0,"text":request["text"]}))?;
40 },
41 Some("display_exit_list") => lists::execute(doc, &json!({"node":id,"delta":-1}))?,
42 _ => return Err("invalid_command"),
43 }
44 Ok(())
45}
46