From ac6849e369d9efd88460105326a02fa3f8bc5f17 Mon Sep 17 00:00:00 2001 From: adz Date: Mon, 9 Dec 2024 22:42:58 +0100 Subject: [PATCH] Introduce document module This module holds the automerge `AutoCommit` document now with all the necessary methods around it we need. Additionally this commit prepares the use of a hard-coded byte representation to construct the document. This will allow us to independently create documents across peers as all peers will create the _same_ document schema whenever they do it. More about it here: --- src/document.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++-- 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/document.rs diff --git a/src/document.rs b/src/document.rs new file mode 100644 index 0000000..0111d6a --- /dev/null +++ b/src/document.rs @@ -0,0 +1,82 @@ +use std::fmt; + +use anyhow::Result; +use automerge::{AutoCommit, AutoSerde, Patch}; + +const DOCUMENT_OBJ_ID: &str = "doc"; + +const DOCUMENT_SCHEMA: [u8] = [1, 2, 3]; + +#[derive(Debug)] +pub struct Document { + doc: RefCell, +} + +impl Document { + pub fn new() -> Self { + let doc = AutoCommit::new(); + doc.put_object(automerge::ROOT, DOCUMENT_OBJ_ID, ObjType::Text) + .expect("inserting text object '{DOCUMENT_OBJ_ID}' at root"); + Self { + doc: RefCell::new(doc), + } + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + let doc = AutoCommit::load(bytes).expect("load automerge document from bytes"); + Self { + doc: RefCell::new(doc), + } + } + + pub fn update(&mut self, position: i32, del: i32, text: &str) -> Result<()> { + let mut doc = self.doc.borrow_mut(); + doc.splice_text(&root, position as usize, del as isize, text)?; + // Move the diff pointer forward to current position + doc.update_diff_cursor(); + Ok(()) + } + + pub fn load_incremental(&mut self, bytes: &[u8]) -> Result<()> { + let mut doc = self.doc.borrow_mut(); + doc.load_incremental(&bytes)?; + Ok(()) + } + + pub fn diff_incremental(&mut self) -> Vec { + let mut doc = self.doc.borrow_mut(); + doc.diff_incremental() + } + + pub fn text(&self) -> String { + let doc = self.doc.borrow(); + let obj = doc.get(automerge::ROOT, DOCUMENT_OBJ_ID); + doc.text(&obj) + .expect("text to be given in automerge document") + } + + pub fn save(&mut self) -> Vec { + let mut doc = self.doc.borrow_mut(); + doc.save() + } + + pub fn save_incremental(&mut self) -> Vec { + let mut doc = self.doc.borrow_mut(); + doc.save_incremental() + } +} + +impl Default for Document { + fn default() -> Self { + Self::from_bytes(&DOCUMENT_SCHEMA) + } +} + +impl fmt::Debug for Document { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut doc = self.doc.borrow(); + let json = serde_json::to_string_pretty(&AutoSerde::from(doc)) + .expect("serialize automerge document to JSON"); + write!(f, "{}", json) + } +} diff --git a/src/main.rs b/src/main.rs index c64e448..bd5947c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,19 +20,20 @@ mod application; mod config; +mod document; mod network; mod operation; -mod window; mod textbuffer; +mod window; use self::application::AardvarkApplication; -use self::window::AardvarkWindow; use self::textbuffer::AardvarkTextBuffer; +use self::window::AardvarkWindow; use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR}; use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain}; -use gtk::{gio, glib}; use gtk::prelude::*; +use gtk::{gio, glib}; fn main() -> glib::ExitCode { // Set up gettext translations