Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Tree reconciliate POC #1021

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions bindings/wysiwyg-ffi/src/ffi_composer_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::vec;

use widestring::Utf16String;

use crate::ffi_composer_state::ComposerState;
use crate::ffi_composer_update::ComposerUpdate;
use crate::ffi_dom::Dom;
use crate::ffi_dom_creation_error::DomCreationError;
use crate::ffi_link_actions::LinkAction;
use crate::ffi_mentions_state::MentionsState;
use crate::into_ffi::IntoFfi;
use crate::{ActionState, ComposerAction, SuggestionPattern};
use widestring::Utf16String;

#[derive(Default, uniffi::Object)]
pub struct ComposerModel {
Expand Down Expand Up @@ -375,6 +375,11 @@ impl ComposerModel {
self.inner.lock().unwrap().get_mentions_state().into()
}

pub fn get_dom(self: &Arc<Self>) -> Dom {
let inner_dom = self.inner.lock().unwrap().state.dom.clone();
Dom::from(inner_dom)
}

/// Force a panic for test purposes
pub fn debug_panic(self: &Arc<Self>) {
#[cfg(debug_assertions)]
Expand Down
154 changes: 154 additions & 0 deletions bindings/wysiwyg-ffi/src/ffi_dom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use widestring::Utf16String;
use wysiwyg::Dom as InnerDom;
use wysiwyg::DomHandle;
use wysiwyg::DomNode as InnerDomNode;

#[derive(uniffi::Record)]
pub struct Dom {
pub document: DomNode,
pub transaction_id: u32,
}

impl Dom {
pub fn from(inner: InnerDom<Utf16String>) -> Self {
let node =
DomNode::from(InnerDomNode::Container(inner.document().clone()));
Dom {
document: node,
transaction_id: u32::try_from(inner.transaction_id).unwrap(),
}
}
}

#[derive(uniffi::Enum)]
pub enum DomNode {
Container {
path: Vec<u32>,
kind: ContainerNodeKind,
children: Vec<DomNode>,
},
Text {
path: Vec<u32>,
text: String,
},
LineBreak {
path: Vec<u32>,
},
Mention {
path: Vec<u32>,
},
}

fn into_path(dom_handle: DomHandle) -> Vec<u32> {
dom_handle
.path
.unwrap()
.into_iter()
.map(|x| u32::try_from(x).unwrap())
.collect()
}

impl DomNode {
pub fn from(inner: wysiwyg::DomNode<Utf16String>) -> Self {
match inner {
wysiwyg::DomNode::Container(node) => DomNode::Container {
path: into_path(node.handle()),
kind: ContainerNodeKind::from(node.kind().clone()),
children: node
.children()
.iter()
.map(|x| DomNode::from(x.clone()))
.collect::<Vec<_>>(),
},
wysiwyg::DomNode::Text(node) => DomNode::Text {
path: into_path(node.handle()),
text: node.data().to_string(),
},
wysiwyg::DomNode::LineBreak(node) => DomNode::LineBreak {
path: into_path(node.handle()),
},
wysiwyg::DomNode::Mention(node) => DomNode::LineBreak {
path: into_path(node.handle()),
},
}
}
}

#[derive(uniffi::Enum)]
pub enum ContainerNodeKind {
Generic, // E.g. the root node (the containing div)
Formatting(InlineFormatType),
Link(String),
List(ListType),
ListItem,
CodeBlock,
Quote,
Paragraph,
}

impl ContainerNodeKind {
pub fn from(inner: wysiwyg::ContainerNodeKind<Utf16String>) -> Self {
match inner {
wysiwyg::ContainerNodeKind::Generic => ContainerNodeKind::Generic,
wysiwyg::ContainerNodeKind::Formatting(format_type) => {
ContainerNodeKind::Formatting(InlineFormatType::from(
format_type,
))
}
wysiwyg::ContainerNodeKind::Link(text) => {
ContainerNodeKind::Link(text.to_string())
}
wysiwyg::ContainerNodeKind::List(list_type) => {
ContainerNodeKind::List(ListType::from(list_type))
}
wysiwyg::ContainerNodeKind::ListItem => ContainerNodeKind::ListItem,
wysiwyg::ContainerNodeKind::CodeBlock => {
ContainerNodeKind::CodeBlock
}
wysiwyg::ContainerNodeKind::Quote => ContainerNodeKind::Quote,
wysiwyg::ContainerNodeKind::Paragraph => {
ContainerNodeKind::Paragraph
}
}
}
}

#[derive(uniffi::Enum)]
pub enum InlineFormatType {
Bold,
Italic,
StrikeThrough,
Underline,
InlineCode,
}

impl InlineFormatType {
pub fn from(inner: wysiwyg::InlineFormatType) -> Self {
match inner {
wysiwyg::InlineFormatType::Bold => InlineFormatType::Bold,
wysiwyg::InlineFormatType::Italic => InlineFormatType::Italic,
wysiwyg::InlineFormatType::StrikeThrough => {
InlineFormatType::StrikeThrough
}
wysiwyg::InlineFormatType::Underline => InlineFormatType::Underline,
wysiwyg::InlineFormatType::InlineCode => {
InlineFormatType::InlineCode
}
}
}
}

#[derive(uniffi::Enum)]
pub enum ListType {
Ordered,
Unordered,
}

impl ListType {
pub fn from(inner: wysiwyg::ListType) -> Self {
match inner {
wysiwyg::ListType::Ordered => ListType::Ordered,
wysiwyg::ListType::Unordered => ListType::Unordered,
}
}
}
10 changes: 8 additions & 2 deletions bindings/wysiwyg-ffi/src/ffi_text_update.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use widestring::Utf16String;

use crate::ffi_dom::DomNode;

#[derive(uniffi::Enum)]
pub enum TextUpdate {
Keep,
ReplaceAll {
replacement_html: Vec<u16>,
replacement_dom: DomNode,
start_utf16_codeunit: u32,
end_utf16_codeunit: u32,
},
Expand All @@ -22,7 +24,11 @@ impl TextUpdate {
let start_utf16_codeunit: usize = replace_all.start.into();
let end_utf16_codeunit: usize = replace_all.end.into();
Self::ReplaceAll {
replacement_html: replace_all.replacement_html.into_vec(),
replacement_dom: DomNode::from(
wysiwyg::DomNode::Container(
replace_all.replacement_dom.clone(),
),
),
start_utf16_codeunit: u32::try_from(start_utf16_codeunit)
.unwrap(),
end_utf16_codeunit: u32::try_from(end_utf16_codeunit)
Expand Down
1 change: 1 addition & 0 deletions bindings/wysiwyg-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod ffi_composer_action;
mod ffi_composer_model;
mod ffi_composer_state;
mod ffi_composer_update;
mod ffi_dom;
mod ffi_dom_creation_error;
mod ffi_link_actions;
mod ffi_mention_detector;
Expand Down
4 changes: 2 additions & 2 deletions crates/wysiwyg/src/composer_model/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ where
self.state.dom.assert_transaction_not_in_progress();

ComposerUpdate::replace_all(
self.state.dom.to_html(),
self.state.dom.document().clone(),
self.state.start,
self.state.end,
self.compute_menu_state(MenuStateComputeType::KeepIfUnchanged),
Expand All @@ -182,7 +182,7 @@ where
self.state.dom.assert_transaction_not_in_progress();

ComposerUpdate::replace_all(
self.state.dom.to_html(),
self.state.dom.document().clone(),
self.state.start,
self.state.end,
self.compute_menu_state(MenuStateComputeType::AlwaysUpdate),
Expand Down
7 changes: 4 additions & 3 deletions crates/wysiwyg/src/composer_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::dom::nodes::ContainerNode;
use crate::dom::UnicodeString;
use crate::link_action::LinkActionUpdate;
use crate::{
Location, MenuAction, MenuState, ReplaceAll, Selection, TextUpdate,
};

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq)]
pub struct ComposerUpdate<S>
where
S: UnicodeString,
Expand Down Expand Up @@ -70,7 +71,7 @@ where
}

pub fn replace_all(
replacement_html: S,
replacement_dom: ContainerNode<S>,
start: Location,
end: Location,
menu_state: MenuState,
Expand All @@ -79,7 +80,7 @@ where
) -> Self {
Self {
text_update: TextUpdate::ReplaceAll(ReplaceAll {
replacement_html,
replacement_dom,
start,
end,
}),
Expand Down
2 changes: 1 addition & 1 deletion crates/wysiwyg/src/dom/dom_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#[derive(Clone, Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct DomHandle {
// The location of a node in the tree, or None if we don't know yet
path: Option<Vec<usize>>,
pub path: Option<Vec<usize>>,
}

impl DomHandle {
Expand Down
4 changes: 4 additions & 0 deletions crates/wysiwyg/src/dom/dom_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ where
document: DomNode<S>,
#[cfg(any(test, feature = "assert-invariants"))]
is_transaction_in_progress: bool,
pub transaction_id: usize,
}

impl<S> Dom<S>
Expand All @@ -50,6 +51,7 @@ where
document: DomNode::Container(document),
#[cfg(any(test, feature = "assert-invariants"))]
is_transaction_in_progress: false,
transaction_id: 0,
}
}

Expand All @@ -68,6 +70,7 @@ where
document: root_node,
#[cfg(any(test, feature = "assert-invariants"))]
is_transaction_in_progress: false,
transaction_id: 0,
}
}

Expand Down Expand Up @@ -156,6 +159,7 @@ where
if !self.is_transaction_in_progress() {
panic!("Cannot end transaction as no transaction is in progress");
}
self.transaction_id = self.transaction_id + 1;
self.is_transaction_in_progress = false;
self.assert_invariants();
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wysiwyg/src/dom/nodes/container_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ pub struct ContainerNode<S>
where
S: UnicodeString,
{
pub handle: DomHandle,
name: S,
kind: ContainerNodeKind<S>,
attrs: Option<Vec<(S, S)>>,
children: Vec<DomNode<S>>,
handle: DomHandle,
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion crates/wysiwyg/src/dom/nodes/line_break_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ pub struct LineBreakNode<S>
where
S: UnicodeString,
{
pub handle: DomHandle,
_phantom_data: PhantomData<S>,
handle: DomHandle,
}

impl<S> Default for LineBreakNode<S>
Expand Down
2 changes: 1 addition & 1 deletion crates/wysiwyg/src/dom/nodes/mention_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ where
{
// `display_text` refers to that passed by the client which may, in some cases, be different
// from the ruma derived `Mention.display_text`
pub handle: DomHandle,
display_text: S,
kind: MentionNodeKind,
attributes: Vec<(S, S)>,
handle: DomHandle,
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion crates/wysiwyg/src/dom/nodes/text_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ pub struct TextNode<S>
where
S: UnicodeString,
{
pub handle: DomHandle,
data: S,
handle: DomHandle,
}

impl<S> TextNode<S>
Expand Down
3 changes: 3 additions & 0 deletions crates/wysiwyg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ pub use crate::composer_action::ComposerAction;
pub use crate::composer_model::ComposerModel;
pub use crate::composer_state::ComposerState;
pub use crate::composer_update::ComposerUpdate;
pub use crate::dom::nodes::ContainerNode;
pub use crate::dom::nodes::ContainerNodeKind;
pub use crate::dom::nodes::DomNode;
pub use crate::dom::parser::parse;
pub use crate::dom::Dom;
pub use crate::dom::DomCreationError;
pub use crate::dom::DomHandle;
pub use crate::dom::HtmlParseError;
Expand Down
Loading