Skip to content

Commit

Permalink
adding update_text bindings through to core library (#97)
Browse files Browse the repository at this point in the history
* adding update_text bindings through to core library
* exposing updateText through Automerge-swift's Doc and adding test to exercise it
* updating documentation to expose Document.updateText() in curation
  • Loading branch information
heckj authored Jan 16, 2024
1 parent c430a92 commit 496f004
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 14 deletions.
17 changes: 17 additions & 0 deletions AutomergeUniffi/automerge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ public protocol DocProtocol {
func insertInList(obj: ObjId, index: UInt64, value: ScalarValue) throws
func insertObjectInList(obj: ObjId, index: UInt64, objType: ObjType) throws -> ObjId
func spliceText(obj: ObjId, start: UInt64, delete: Int64, chars: String) throws
func updateText(obj: ObjId, chars: String) throws
func splice(obj: ObjId, start: UInt64, delete: Int64, values: [ScalarValue]) throws
func mark(obj: ObjId, start: UInt64, end: UInt64, expand: ExpandMark, name: String, value: ScalarValue) throws
func marks(obj: ObjId) throws -> [Mark]
Expand Down Expand Up @@ -650,6 +651,19 @@ public class Doc: DocProtocol {
}
}

public func updateText(obj: ObjId, chars: String) throws {
try
rustCallWithError(FfiConverterTypeDocError.lift) {
uniffi_automerge_fn_method_doc_update_text(
self.pointer,

FfiConverterTypeObjId.lower(obj),
FfiConverterString.lower(chars),
$0
)
}
}

public func splice(obj: ObjId, start: UInt64, delete: Int64, values: [ScalarValue]) throws {
try
rustCallWithError(FfiConverterTypeDocError.lift) {
Expand Down Expand Up @@ -2682,6 +2696,9 @@ private var initializationResult: InitializationResult {
if uniffi_automerge_checksum_method_doc_splice_text() != 50590 {
return InitializationResult.apiChecksumMismatch
}
if uniffi_automerge_checksum_method_doc_update_text() != 28751 {
return InitializationResult.apiChecksumMismatch
}
if uniffi_automerge_checksum_method_doc_splice() != 26727 {
return InitializationResult.apiChecksumMismatch
}
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ let package = Package(
// themselves and link it through the "swift build -Xlinker path/to/libuniffi_automerge.a"
// for example: cargo build --manifest-path rust/Cargo.toml --target wasm32-wasi --release
.target(name: "automergeFFI", condition: .when(platforms: [
.iOS, .macOS, .macCatalyst, .tvOS, .watchOS
.iOS, .macOS, .macCatalyst, .tvOS, .watchOS,
])),
"_CAutomergeUniffi",
],
Expand Down
1 change: 1 addition & 0 deletions Sources/Automerge/Automerge.docc/Curation/Document.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
### Updating Text values

- ``spliceText(obj:start:delete:value:)``
- ``updateText(obj:value:)``
- ``mark(obj:start:end:expand:name:value:)``

### Setting and Reading cursors
Expand Down
17 changes: 17 additions & 0 deletions Sources/Automerge/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,23 @@ public final class Document: @unchecked Sendable {
}
}

/// Updates the text object with the value you specify.
///
/// - Parameters:
/// - obj: The identifier of the text object to update.
/// - value: The string value for the text
///
/// You can use updateText as an alternative to spliceText for low-level text updates.
/// This method creates a diff of the text, using Grapheme clusters, to apply updates to change the stored text to
/// what you provide.
public func updateText(obj: ObjId, value: String) throws {
try sync {
try self.doc.wrapErrors { doc in
try doc.updateText(obj: obj.bytes, chars: value)
}
}
}

/// Add or remove a mark to a given range of text
///
/// - Parameters:
Expand Down
5 changes: 5 additions & 0 deletions Sources/_CAutomergeUniffi/include/automergeFFI.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ RustBuffer uniffi_automerge_fn_method_doc_insert_object_in_list(void*_Nonnull pt
);
void uniffi_automerge_fn_method_doc_splice_text(void*_Nonnull ptr, RustBuffer obj, uint64_t start, int64_t delete, RustBuffer chars, RustCallStatus *_Nonnull out_status
);
void uniffi_automerge_fn_method_doc_update_text(void*_Nonnull ptr, RustBuffer obj, RustBuffer chars, RustCallStatus *_Nonnull out_status
);
void uniffi_automerge_fn_method_doc_splice(void*_Nonnull ptr, RustBuffer obj, uint64_t start, int64_t delete, RustBuffer values, RustCallStatus *_Nonnull out_status
);
void uniffi_automerge_fn_method_doc_mark(void*_Nonnull ptr, RustBuffer obj, uint64_t start, uint64_t end, RustBuffer expand, RustBuffer name, RustBuffer value, RustCallStatus *_Nonnull out_status
Expand Down Expand Up @@ -254,6 +256,9 @@ uint16_t uniffi_automerge_checksum_method_doc_insert_object_in_list(void
);
uint16_t uniffi_automerge_checksum_method_doc_splice_text(void

);
uint16_t uniffi_automerge_checksum_method_doc_update_text(void

);
uint16_t uniffi_automerge_checksum_method_doc_splice(void

Expand Down
36 changes: 23 additions & 13 deletions Tests/AutomergeTests/TestText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,45 @@ import Automerge
import XCTest

class TextTestCase: XCTestCase {
func testGetText() {
func testGetText() throws {
let doc = Document()
let text = try! doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
try! doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")
try doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")
XCTAssertEqual(try! doc.text(obj: text), "hello world!")
}

func testGetTextAt() {
func testGetTextAt() throws {
let doc = Document()
let text = try! doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
try! doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")
try doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")

let heads = doc.heads()

let doc2 = doc.fork()

try! doc2.spliceText(obj: text, start: 6, delete: 0, value: "wonderful ")
try! doc.spliceText(obj: text, start: 0, delete: 5, value: "Greetings")
try doc2.spliceText(obj: text, start: 6, delete: 0, value: "wonderful ")
try doc.spliceText(obj: text, start: 0, delete: 5, value: "Greetings")

try! doc.merge(other: doc2)
try doc.merge(other: doc2)

XCTAssertEqual(try! doc.text(obj: text), "Greetings wonderful world!")
XCTAssertEqual(try! doc.textAt(obj: text, heads: heads), "hello world!")
}

func testTextCursor() {
func testTextUpdate() throws {
let doc = Document()
let text = try doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
try doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")
XCTAssertEqual(try doc.text(obj: text), "hello world!")

try doc.updateText(obj: text, value: "A new text entry.")
XCTAssertEqual(try doc.text(obj: text), "A new text entry.")
}

func testTextCursor() throws {
let doc = Document()
let text = try! doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
try! doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")
try doc.spliceText(obj: text, start: 0, delete: 0, value: "hello world!")

let heads = doc.heads()

Expand All @@ -40,12 +50,12 @@ class TextTestCase: XCTestCase {
let c_world = try! doc.cursor(obj: text, position: 6)
XCTAssertEqual(try! doc.cursorPosition(obj: text, cursor: c_world), 6)

try! doc.spliceText(obj: text, start: 6, delete: 0, value: "wonderful ")
try doc.spliceText(obj: text, start: 6, delete: 0, value: "wonderful ")
XCTAssertEqual(try! doc.text(obj: text), "hello wonderful world!")
XCTAssertEqual(try! doc.cursorPosition(obj: text, cursor: c_hello), 0)
XCTAssertEqual(try! doc.cursorPosition(obj: text, cursor: c_world), 16)

try! doc.spliceText(obj: text, start: 0, delete: 5, value: "Greetings")
try doc.spliceText(obj: text, start: 0, delete: 5, value: "Greetings")
XCTAssertEqual(try! doc.text(obj: text), "Greetings wonderful world!")
XCTAssertEqual(try! doc.cursorPosition(obj: text, cursor: c_hello), 9)
XCTAssertEqual(try! doc.cursorPosition(obj: text, cursor: c_world), 20)
Expand All @@ -64,7 +74,7 @@ class TextTestCase: XCTestCase {
}

let doc = Automerge.Document()
let text = try! doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
let text = try doc.putObject(obj: ObjId.ROOT, key: "text", ty: .Text)
var stringLength = doc.length(obj: text)
XCTAssertEqual(stringLength, 0)

Expand All @@ -73,7 +83,7 @@ class TextTestCase: XCTestCase {
stringLength = doc.length(obj: text)
// print("Adding '\(stringToInsert)' at \(stringLength)")
try! doc.spliceText(obj: text, start: stringLength, delete: 0, value: stringToInsert)
// print("Combined text: \(try! doc.text(obj: text))")
// print("Combined text: \(try doc.text(obj: text))")
}

// flaky assertion, don't do it :: because length is in UTF-8 codepoints, not!!! grapheme clusters.
Expand Down
2 changes: 2 additions & 0 deletions rust/src/automerge.udl
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ interface Doc {

[Throws=DocError]
void splice_text(ObjId obj, u64 start, i64 delete, string chars);
[Throws=DocError]
void update_text(ObjId obj, string chars);

[Throws=DocError]
void splice(ObjId obj, u64 start, i64 delete, sequence<ScalarValue> values);
Expand Down
8 changes: 8 additions & 0 deletions rust/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,14 @@ impl Doc {
Ok(())
}

pub fn update_text(&self, obj: ObjId, value: String) -> Result<(), DocError> {
let obj = am::ObjId::from(obj);
let mut doc = self.0.write().unwrap();
assert_text(&*doc, &obj)?;
doc.update_text(&obj, value)?;
Ok(())
}

pub fn splice(
&self,
obj: ObjId,
Expand Down

0 comments on commit 496f004

Please sign in to comment.