From 6b35517b634b86c66ae527313e28626a717bf846 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Mon, 21 Aug 2023 15:18:24 +0800 Subject: [PATCH] feat: add text editing support --- y-octo-node/index.d.ts | 10 +++++++++ y-octo-node/index.js | 3 ++- y-octo-node/src/doc.rs | 2 +- y-octo-node/src/text.rs | 37 +++++++++++++++++++++++++++++++++- y-octo-node/tests/doc.spec.mts | 24 ++++++++++++++++++++-- 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/y-octo-node/index.d.ts b/y-octo-node/index.d.ts index 314a412..188add4 100644 --- a/y-octo-node/index.d.ts +++ b/y-octo-node/index.d.ts @@ -6,4 +6,14 @@ export class Doc { constructor(clientId?: number | undefined | null) get clientId(): number + get guid(): string + get keys(): Array + getOrCreateText(key: string): Text +} +export class Text { + get len(): number + get isEmpty(): boolean + insert(charIndex: number, str: string): void + remove(charIndex: number, len: number): void + toString(): string } diff --git a/y-octo-node/index.js b/y-octo-node/index.js index de30966..6644d1e 100644 --- a/y-octo-node/index.js +++ b/y-octo-node/index.js @@ -252,6 +252,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { Doc } = nativeBinding +const { Doc, Text } = nativeBinding module.exports.Doc = Doc +module.exports.Text = Text diff --git a/y-octo-node/src/doc.rs b/y-octo-node/src/doc.rs index 7ab663c..d7be1b9 100644 --- a/y-octo-node/src/doc.rs +++ b/y-octo-node/src/doc.rs @@ -9,7 +9,7 @@ pub struct Doc { #[napi] impl Doc { - // #[napi(constructor)] + #[napi(constructor)] pub fn new(client_id: Option) -> Self { Self { doc: if let Some(client_id) = client_id { diff --git a/y-octo-node/src/text.rs b/y-octo-node/src/text.rs index 631ffab..c18fe69 100644 --- a/y-octo-node/src/text.rs +++ b/y-octo-node/src/text.rs @@ -9,7 +9,6 @@ pub struct Text { #[napi] impl Text { - // #[napi(constructor)] pub(crate) fn new(text: YText) -> Self { Self { text } } @@ -18,6 +17,30 @@ impl Text { pub fn len(&self) -> i64 { self.text.len() as i64 } + + #[napi(getter)] + pub fn is_empty(&self) -> bool { + self.text.is_empty() + } + + #[napi] + pub fn insert(&mut self, char_index: i64, str: String) -> Result<()> { + self.text + .insert(char_index as u64, str) + .map_err(|e| anyhow::Error::from(e)) + } + + #[napi] + pub fn remove(&mut self, char_index: i64, len: i64) -> Result<()> { + self.text + .remove(char_index as u64, len as u64) + .map_err(|e| anyhow::Error::from(e)) + } + + #[napi] + pub fn to_string(&self) -> String { + self.text.to_string() + } } #[cfg(test)] @@ -30,4 +53,16 @@ mod tests { let text = doc.get_or_create_text("text".into()).unwrap(); assert_eq!(text.len(), 0); } + + #[test] + fn test_text_edit() { + let mut doc = Doc::new(None); + let mut text = doc.get_or_create_text("text".into()).unwrap(); + text.insert(0, "hello".into()).unwrap(); + assert_eq!(text.to_string(), "hello"); + text.insert(5, " world".into()).unwrap(); + assert_eq!(text.to_string(), "hello world"); + text.remove(5, 6).unwrap(); + assert_eq!(text.to_string(), "hello"); + } } diff --git a/y-octo-node/tests/doc.spec.mts b/y-octo-node/tests/doc.spec.mts index 9ff18cb..3cb38a0 100644 --- a/y-octo-node/tests/doc.spec.mts +++ b/y-octo-node/tests/doc.spec.mts @@ -1,4 +1,4 @@ -import { equal } from "node:assert"; +import { equal, deepEqual } from "node:assert"; import { test } from "node:test"; import { Doc } from "../index"; @@ -7,7 +7,7 @@ test("y-octo doc", { concurrency: false }, async (t) => { let client_id: number; let doc: Doc | null; t.beforeEach(async () => { - client_id = (Math.random() * 100000) | 1; + client_id = (Math.random() * 100000) | 0; doc = new Doc(client_id); }); @@ -19,4 +19,24 @@ test("y-octo doc", { concurrency: false }, async (t) => { await t.test("doc id should be set", () => { equal(doc?.clientId, client_id); }); + + await t.test("text should be created", () => { + let text = doc?.getOrCreateText("text"); + deepEqual(doc?.keys, ["text"]); + equal(text?.len, 0); + }); + + await t.test("text editing", () => { + let text = doc?.getOrCreateText("text"); + text?.insert(0, "a"); + text?.insert(1, "b"); + text?.insert(2, "c"); + equal(text?.toString(), "abc"); + text?.remove(0, 1); + equal(text?.toString(), "bc"); + text?.remove(1, 1); + equal(text?.toString(), "b"); + text?.remove(0, 1); + equal(text?.toString(), ""); + }); });