9 files changed,
+68,
-108
M
array.go
+0,
-15
1@@ -106,21 +106,6 @@ func (a *Array) RemoveRange(txn *Transaction, index, length uint32) error {
2 return nil
3 }
4
5-// Move moves an element from source index to target index.
6-func (a *Array) Move(txn *Transaction, source, target uint32) error {
7- if a.branch == nil {
8- return ErrNilBranch
9- }
10- if txn == nil || txn.ptr == nil {
11- return ErrNilTransaction
12- }
13- if !txn.IsWriteable() {
14- return ErrNotWriteable
15- }
16- C.yarray_move(a.branch, txn.ptr, C.uint32_t(source), C.uint32_t(target))
17- return nil
18-}
19-
20 // Iter returns an iterator over the array.
21 func (a *Array) Iter(txn *Transaction) (*ArrayIter, error) {
22 if a.branch == nil {
+0,
-36
1@@ -112,39 +112,3 @@ func TestArrayPush(t *testing.T) {
2 }
3 }
4
5-func TestArrayMove(t *testing.T) {
6- doc, err := ygo.NewDoc()
7- if err != nil {
8- t.Fatalf("failed to create doc: %v", err)
9- }
10- defer doc.Destroy()
11-
12- arr, err := doc.GetArray("test")
13- if err != nil {
14- t.Fatalf("failed to get array: %v", err)
15- }
16- defer arr.Destroy()
17-
18- var length uint32
19-
20- err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
21- items := []ygo.Input{ygo.Int(1), ygo.Int(2), ygo.Int(3)}
22- arr.InsertRange(txn, 0, items)
23-
24- // Move element 0 to position 2
25- arr.Move(txn, 0, 2)
26-
27- // Array should now have [2, 3, 1]
28- // Just verify length is preserved
29- var err error
30- length = arr.Len()
31- return err
32- })
33- if err != nil {
34- t.Fatalf("transaction failed: %v", err)
35- }
36-
37- if length != 3 {
38- t.Errorf("expected length 3, got %d", length)
39- }
40-}
+0,
-0
+41,
-29
1@@ -221,6 +221,32 @@ typedef struct YSubscription {} YSubscription;
2 */
3 #define Y_OFFSET_UTF16 1
4
5+/**
6+ * Boolean flag used to determine if deleted blocks should be garbage collected or not
7+ * during the transaction commits. Setting this value to 0 means GC will be performed.
8+ */
9+#define Y_SKIP_GC (1 << 1)
10+
11+/**
12+ * Boolean flag used to determine if subdocument should be loaded automatically.
13+ * If this is a subdocument, remote peers will load the document as well automatically.
14+ */
15+#define Y_AUTO_LOAD (1 << 2)
16+
17+/**
18+ * Boolean flag used to determine whether the document should be synced by the provider now.
19+ */
20+#define Y_SHOULD_LOAD (1 << 3)
21+
22+/**
23+ * Whenever we receive an update that might remove piece of text, it might turn out that it was
24+ * surrounded by the formatting attributes, that now are effectively dead and unrenderable, but
25+ * still are considered alive blocks.
26+ *
27+ * This flag orders cleanup of dangling formatting attributes.
28+ */
29+#define Y_CLEANUP_FMT (1 << 4)
30+
31 /**
32 * Error code: couldn't read data from input stream.
33 */
34@@ -353,27 +379,15 @@ typedef struct YOptions {
35 */
36 const char *collection_id;
37 /**
38- * Encoding used by text editing operations on this document. It's used to compute
39- * `YText`/`YXmlText` insertion offsets and text lengths. Either:
40- *
41- * - `Y_OFFSET_BYTES`
42- * - `Y_OFFSET_UTF16`
43- */
44- uint8_t encoding;
45- /**
46- * Boolean flag used to determine if deleted blocks should be garbage collected or not
47- * during the transaction commits. Setting this value to 0 means GC will be performed.
48+ * Boolean flags used to configure document options:
49+ * - `Y_OFFSET_BYTES`: use UTF-8 byte length for text indexes and offsets.
50+ * - `Y_OFFSET_UTF16`: use UTF-16 code points for text indexes and offsets.
51+ * - `Y_SKIP_GC`: skip automatic garbage collection at transaction commit (useful for snapshots and keeping historical traces).
52+ * - `Y_AUTO_LOAD`: all subdocuments should be loaded automatically.
53+ * - `Y_SHOULD_LOAD`: should current document be synced with its provider immediatelly?
54+ * - `Y_CLEANUP_TEXT_FMT`: automatically remove dangling formatting attributes.
55 */
56- uint8_t skip_gc;
57- /**
58- * Boolean flag used to determine if subdocument should be loaded automatically.
59- * If this is a subdocument, remote peers will load the document as well automatically.
60- */
61- uint8_t auto_load;
62- /**
63- * Boolean flag used to determine whether the document should be synced by the provider now.
64- */
65- uint8_t should_load;
66+ uint8_t flags;
67 } YOptions;
68
69 /**
70@@ -536,7 +550,7 @@ typedef struct YIdRangeSeq {
71 * `entries_count` field. ClientIDs reside under `client_ids` and their corresponding range
72 * sequences can be found under the same index of `ranges` field.
73 */
74-typedef struct YDeleteSet {
75+typedef struct YIdSet {
76 /**
77 * Number of client identifier entries.
78 */
79@@ -553,7 +567,7 @@ typedef struct YDeleteSet {
80 * the same index.
81 */
82 struct YIdRangeSeq *ranges;
83-} YDeleteSet;
84+} YIdSet;
85
86 /**
87 * Event generated for callbacks subscribed using `ydoc_observe_after_transaction`. It contains
88@@ -571,7 +585,7 @@ typedef struct YAfterTransactionEvent {
89 /**
90 * Information about all items deleted within the scope of a transaction.
91 */
92- struct YDeleteSet delete_set;
93+ struct YIdSet delete_set;
94 } YAfterTransactionEvent;
95
96 typedef struct YSubdocsEvent {
97@@ -1439,9 +1453,9 @@ char *ytransaction_encode_state_from_snapshot_v2(const YTransaction *txn,
98 * Return `NULL` if there's no missing delete set and all deletions have been applied.
99 * See also: `ytransaction_pending_update`
100 */
101-struct YDeleteSet *ytransaction_pending_ds(const YTransaction *txn);
102+struct YIdSet *ytransaction_pending_ds(const YTransaction *txn);
103
104-void ydelete_set_destroy(struct YDeleteSet *ds);
105+void ydelete_set_destroy(struct YIdSet *ds);
106
107 /**
108 * Returns a pending update associated with an underlying `YDoc`. Pending update contains update
109@@ -1674,8 +1688,6 @@ void yarray_insert_range(const Branch *array,
110 */
111 void yarray_remove_range(const Branch *array, YTransaction *txn, uint32_t index, uint32_t len);
112
113-void yarray_move(const Branch *array, YTransaction *txn, uint32_t source, uint32_t target);
114-
115 /**
116 * Returns an iterator, which can be used to traverse over all elements of an `array` (`array`'s
117 * length can be determined using [yarray_len] function).
118@@ -2563,7 +2575,7 @@ void yevent_keys_destroy(struct YEventKeyChange *keys, uint32_t len);
119 *
120 * This object can be deallocated via `yundo_manager_destroy`.
121 */
122-YUndoManager *yundo_manager(const YDoc *doc, const struct YUndoManagerOptions *options);
123+YUndoManager *yundo_manager(const struct YUndoManagerOptions *options);
124
125 /**
126 * Deallocated undo manager instance created via `yundo_manager`.
127@@ -2586,7 +2598,7 @@ void yundo_manager_remove_origin(YUndoManager *mgr, uint32_t origin_len, const c
128 /**
129 * Add specific shared type to be tracked by this instance of an undo manager.
130 */
131-void yundo_manager_add_scope(YUndoManager *mgr, const Branch *ytype);
132+void yundo_manager_add_scope(YUndoManager *mgr, const YDoc *doc, const Branch *ytype);
133
134 /**
135 * Removes all the undo/redo stack changes tracked by current undo manager. This also cleans up
+0,
-0
+11,
-8
1@@ -47,12 +47,13 @@ type DocOptions struct {
2 // DefaultOptions returns default document options.
3 func DefaultOptions() DocOptions {
4 var cOpts C.YOptions = C.yoptions()
5+ flags := uint8(cOpts.flags)
6 return DocOptions{
7 ClientID: uint64(cOpts.id),
8- Encoding: OffsetKind(cOpts.encoding),
9- SkipGC: cOpts.skip_gc != 0,
10- AutoLoad: cOpts.auto_load != 0,
11- ShouldLoad: cOpts.should_load != 0,
12+ Encoding: OffsetKind(flags & 0x01),
13+ SkipGC: flags&C.Y_SKIP_GC != 0,
14+ AutoLoad: flags&C.Y_AUTO_LOAD != 0,
15+ ShouldLoad: flags&C.Y_SHOULD_LOAD != 0,
16 }
17 }
18
19@@ -60,16 +61,18 @@ func DefaultOptions() DocOptions {
20 func (o DocOptions) toC() C.YOptions {
21 var cOpts C.YOptions
22 cOpts.id = C.uint64_t(o.ClientID)
23- cOpts.encoding = C.uint8_t(o.Encoding)
24+ var flags C.uint8_t
25+ flags = C.uint8_t(o.Encoding)
26 if o.SkipGC {
27- cOpts.skip_gc = 1
28+ flags |= C.Y_SKIP_GC
29 }
30 if o.AutoLoad {
31- cOpts.auto_load = 1
32+ flags |= C.Y_AUTO_LOAD
33 }
34 if o.ShouldLoad {
35- cOpts.should_load = 1
36+ flags |= C.Y_SHOULD_LOAD
37 }
38+ cOpts.flags = flags
39 if o.GUID != "" {
40 cOpts.guid = stringToC(o.GUID)
41 }
M
undo.go
+9,
-13
1@@ -22,21 +22,14 @@ type UndoManager struct {
2 ptr *C.YUndoManager
3 }
4
5-// NewUndoManager creates an undo manager for a document.
6-func NewUndoManager(doc *Doc, opts *UndoManagerOptions) (*UndoManager, error) {
7- if doc == nil {
8- return nil, fmt.Errorf("document is nil")
9- }
10- if doc.ptr == nil {
11- return nil, ErrNilDocument
12- }
13-
14+// NewUndoManager creates an undo manager.
15+func NewUndoManager(opts *UndoManagerOptions) (*UndoManager, error) {
16 var cOpts *C.YUndoManagerOptions
17 if opts != nil {
18 cOpts = &C.YUndoManagerOptions{capture_timeout_millis: C.int32_t(opts.CaptureTimeoutMillis)}
19 }
20
21- ptr := C.yundo_manager(doc.ptr, cOpts)
22+ ptr := C.yundo_manager(cOpts)
23 if ptr == nil {
24 return nil, fmt.Errorf("failed to create undo manager")
25 }
26@@ -53,11 +46,14 @@ func (m *UndoManager) Destroy() {
27 }
28 }
29
30-// AddScope adds a shared type to be tracked.
31-func (m *UndoManager) AddScope(t interface{ Branch() unsafe.Pointer }) error {
32+// AddScope adds a shared type in a document to be tracked.
33+func (m *UndoManager) AddScope(doc *Doc, t interface{ Branch() unsafe.Pointer }) error {
34 if m.ptr == nil {
35 return fmt.Errorf("undo manager is nil")
36 }
37+ if doc == nil || doc.ptr == nil {
38+ return ErrNilDocument
39+ }
40 if t == nil {
41 return fmt.Errorf("target is nil")
42 }
43@@ -65,7 +61,7 @@ func (m *UndoManager) AddScope(t interface{ Branch() unsafe.Pointer }) error {
44 if branch == nil {
45 return ErrNilBranch
46 }
47- C.yundo_manager_add_scope(m.ptr, (*C.Branch)(branch))
48+ C.yundo_manager_add_scope(m.ptr, doc.ptr, (*C.Branch)(branch))
49 return nil
50 }
51
+6,
-6
1@@ -20,14 +20,14 @@ func TestUndoManagerBasic(t *testing.T) {
2
3 // Create undo manager with 0 timeout to capture each change separately
4 opts := &ygo.UndoManagerOptions{CaptureTimeoutMillis: 0}
5- mgr, err := ygo.NewUndoManager(d1, opts)
6+ mgr, err := ygo.NewUndoManager(opts)
7 if err != nil {
8 t.Fatalf("failed to create undo manager: %v", err)
9 }
10 defer mgr.Destroy()
11
12 // Add scope
13- if err := mgr.AddScope(txt1); err != nil {
14+ if err := mgr.AddScope(d1, txt1); err != nil {
15 t.Fatalf("failed to add scope: %v", err)
16 }
17
18@@ -134,12 +134,12 @@ func TestUndoManagerStop(t *testing.T) {
19 }
20 defer txt1.Destroy()
21
22- mgr, err := ygo.NewUndoManager(d1, nil)
23+ mgr, err := ygo.NewUndoManager(nil)
24 if err != nil {
25 t.Fatalf("failed to create undo manager: %v", err)
26 }
27 defer mgr.Destroy()
28- if err := mgr.AddScope(txt1); err != nil {
29+ if err := mgr.AddScope(d1, txt1); err != nil {
30 t.Fatalf("failed to add scope: %v", err)
31 }
32
33@@ -195,12 +195,12 @@ func TestUndoManagerWithRemoteChanges(t *testing.T) {
34 }
35 defer txt1.Destroy()
36
37- mgr, err := ygo.NewUndoManager(d1, &ygo.UndoManagerOptions{CaptureTimeoutMillis: 0})
38+ mgr, err := ygo.NewUndoManager(&ygo.UndoManagerOptions{CaptureTimeoutMillis: 0})
39 if err != nil {
40 t.Fatalf("failed to create undo manager: %v", err)
41 }
42 defer mgr.Destroy()
43- if err := mgr.AddScope(txt1); err != nil {
44+ if err := mgr.AddScope(d1, txt1); err != nil {
45 t.Fatalf("failed to add scope: %v", err)
46 }
47
M
yjs.go
+1,
-1
1@@ -10,7 +10,7 @@ package ygo
2 import "C"
3
4 // Version of the yffi library we're binding to
5-const YFFIVersion = "v0.25.0"
6+const YFFIVersion = "v0.27.3"
7
8 // Utility function to convert Go string to C string (must be freed by caller)
9 func stringToC(s string) *C.char {