Skip to content

Commit

Permalink
Merge pull request #486 from Horusiath/yffi-insert-text-delta
Browse files Browse the repository at this point in the history
yffi: ytext_insert_delta function
  • Loading branch information
Horusiath authored Aug 25, 2024
2 parents 8f96925 + 7af9522 commit b442681
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 43 deletions.
115 changes: 102 additions & 13 deletions tests-ffi/include/libyrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,52 @@ typedef struct YInput {
union YInputContent value;
} YInput;

/**
* A data type representing a single change to be performed in sequence of changes defined
* as parameter to a `ytext_insert_delta` function. A type of change can be detected using
* a `tag` field:
*
* 1. `Y_EVENT_CHANGE_ADD` marks a new characters added to a collection. In this case `insert`
* field contains a pointer to a list of newly inserted values, while `len` field informs about
* their count. Additionally `attributes_len` nad `attributes` carry information about optional
* formatting attributes applied to edited blocks.
* 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this case
* `len` field informs about number of removed elements.
* 3. `Y_EVENT_CHANGE_RETAIN` marks a number of characters that have not been changed, counted from
* the previous element. `len` field informs about number of retained elements. Additionally
* `attributes_len` nad `attributes` carry information about optional formatting attributes applied
* to edited blocks.
*/
typedef struct YDeltaIn {
/**
* Tag field used to identify particular type of change made:
*
* 1. `Y_EVENT_CHANGE_ADD` marks a new elements added to a collection. In this case `values`
* field contains a pointer to a list of newly inserted values, while `len` field informs about
* their count.
* 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this
* case `len` field informs about number of removed elements.
* 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
* from the previous element. `len` field informs about number of retained elements.
*/
uint8_t tag;
/**
* Number of element affected by current type of change. It can refer to a number of
* inserted `values`, number of deleted element or a number of retained (unchanged) values.
*/
uint32_t len;
/**
* A nullable pointer to a list of formatting attributes assigned to an edited area represented
* by this delta.
*/
const struct YInput *attributes;
/**
* Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
* length stored in `len` field) of newly inserted values.
*/
const struct YInput *insert;
} YDeltaIn;

/**
* A chunk of text contents formatted with the same set of attributes.
*/
Expand Down Expand Up @@ -838,7 +884,7 @@ typedef struct YDeltaAttr {
* change structs separated by retained changes (marking eg. number of elements that can be safely
* skipped, since they remained unchanged).
*/
typedef struct YDelta {
typedef struct YDeltaOut {
/**
* Tag field used to identify particular type of change made:
*
Expand All @@ -850,17 +896,12 @@ typedef struct YDelta {
* 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
* from the previous element. `len` field informs about number of retained elements.
*/
char tag;
uint8_t tag;
/**
* Number of element affected by current type of a change. It can refer to a number of
* Number of element affected by current type of change. It can refer to a number of
* inserted `values`, number of deleted element or a number of retained (unchanged) values.
*/
uint32_t len;
/**
* Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
* length stored in `len` field) of newly inserted values.
*/
struct YOutput *insert;
/**
* A number of formatting attributes assigned to an edited area represented by this delta.
*/
Expand All @@ -870,7 +911,12 @@ typedef struct YDelta {
* by this delta.
*/
struct YDeltaAttr *attributes;
} YDelta;
/**
* Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
* length stored in `len` field) of newly inserted values.
*/
struct YOutput *insert;
} YDeltaOut;

/**
* A data type representing a single change detected over an observed shared collection. A type
Expand Down Expand Up @@ -901,7 +947,7 @@ typedef struct YEventChange {
* 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
* from the previous element. `len` field informs about number of retained elements.
*/
char tag;
uint8_t tag;
/**
* Number of element affected by current type of a change. It can refer to a number of
* inserted `values`, number of deleted element or a number of retained (unchanged) values.
Expand Down Expand Up @@ -1474,6 +1520,49 @@ void ytext_insert_embed(const Branch *txt,
const struct YInput *content,
const struct YInput *attrs);

/**
* Performs a series of changes over the given `YText` shared ref type, described by the `delta`
* parameter:
*
* - Deltas constructed with `ydelta_input_retain` will move cursor position by the given number
* of elements. If formatting attributes were defined, all elements skipped over this way will be
* wrapped by given formatting attributes.
* - Deltas constructed with `ydelta_input_delete` will tell cursor to remove a corresponding
* number of elements.
* - Deltas constructed with `ydelta_input_insert` will tell cursor to insert given elements into
* current cursor position. While these elements can be of any type (used for embedding ie.
* shared types or binary payload like images), for the text insertion a `yinput_string`
* is expected. If formatting attributes were specified, inserted elements will be wrapped by
* given formatting attributes.
*/
void ytext_insert_delta(const Branch *txt,
YTransaction *txn,
struct YDeltaIn *delta,
uint32_t delta_len);

/**
* Creates a parameter for `ytext_insert_delta` function. This parameter will move cursor position
* by the `len` of elements. If formatting `attrs` were defined, all elements skipped over this
* way will be wrapped by given formatting attributes.
*/
struct YDeltaIn ydelta_input_retain(uint32_t len, const struct YInput *attrs);

/**
* Creates a parameter for `ytext_insert_delta` function. This parameter will tell cursor to remove
* a corresponding number of elements, starting from current cursor position.
*/
struct YDeltaIn ydelta_input_delete(uint32_t len);

/**
* Creates a parameter for `ytext_insert_delta` function. This parameter will tell cursor to insert
* given elements into current cursor position. While these elements can be of any type (used for
* embedding ie. shared types or binary payload like images), for the text insertion a `yinput_string`
* is expected. If formatting attributes were specified, inserted elements will be wrapped by
* given formatting attributes.
*/
struct YDeltaIn ydelta_input_insert(const struct YInput *data,
const struct YInput *attrs);

/**
* Removes a range of characters, starting a a given `index`. This range must fit within the bounds
* of a current `YText`, otherwise this function call will fail.
Expand Down Expand Up @@ -2339,7 +2428,7 @@ void ypath_destroy(struct YPathSegment *path, uint32_t len);
* Delta returned from this function should eventually be released using `yevent_delta_destroy`
* function.
*/
struct YDelta *ytext_event_delta(const struct YTextEvent *e, uint32_t *len);
struct YDeltaOut *ytext_event_delta(const struct YTextEvent *e, uint32_t *len);

/**
* Returns a sequence of changes produced by sequence component of shared collections (such as
Expand All @@ -2349,7 +2438,7 @@ struct YDelta *ytext_event_delta(const struct YTextEvent *e, uint32_t *len);
* Delta returned from this function should eventually be released using `yevent_delta_destroy`
* function.
*/
struct YDelta *yxmltext_event_delta(const struct YXmlTextEvent *e, uint32_t *len);
struct YDeltaOut *yxmltext_event_delta(const struct YXmlTextEvent *e, uint32_t *len);

/**
* Returns a sequence of changes produced by sequence component of shared collections (such as
Expand All @@ -2374,7 +2463,7 @@ struct YEventChange *yxmlelem_event_delta(const struct YXmlEvent *e, uint32_t *l
/**
* Releases memory allocated by the object returned from `yevent_delta` function.
*/
void ytext_delta_destroy(struct YDelta *delta, uint32_t len);
void ytext_delta_destroy(struct YDeltaOut *delta, uint32_t len);

/**
* Releases memory allocated by the object returned from `yevent_delta` function.
Expand Down
42 changes: 39 additions & 3 deletions tests-ffi/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ TEST_CASE("YXmlElement basic") {

typedef struct YTextEventTest {
uint32_t delta_len;
YDelta *delta;
YDeltaOut *delta;
Branch *target;
} YEventTest;

Expand Down Expand Up @@ -477,6 +477,42 @@ TEST_CASE("YText observe") {
ydoc_destroy(doc);
}


TEST_CASE("YText insert delta") {
YDoc *doc = ydoc_new_with_id(1);
Branch *f = yxmlfragment(doc, "frag");
YTransaction *txn = ydoc_write_transaction(doc, 0, NULL);
Branch *txt = yxmlelem_insert_text(f, txn, 0);

// initial text state
ytext_insert(txt, txn, 0, "halo world", NULL);

// construct delta
char *bold_str = "bold";
YInput bold = yinput_bool(Y_TRUE);
const YInput attrs = yinput_json_map(&bold_str, &bold, 1);

YDeltaIn i0 = ydelta_input_retain(1, NULL);
YDeltaIn i1 = ydelta_input_delete(1);
const YInput typo_fix = yinput_string("el");
YDeltaIn i2 = ydelta_input_insert(&typo_fix, NULL);
YDeltaIn i3 = ydelta_input_retain(3, NULL);
YDeltaIn i4 = ydelta_input_retain(5, &attrs);
YDeltaIn delta[5] = {i0, i1, i2, i3, i4};

ytext_insert_delta(txt, txn, delta, 5);
ytransaction_commit(txn);

txn = ydoc_read_transaction(doc);
char *str = yxmltext_string(txt, txn);

REQUIRE(strcmp(str, "hello <bold>world</bold>") == 0);

ystring_destroy(str);
ytransaction_commit(txn);
ydoc_destroy(doc);
}

TEST_CASE("YText insert embed") {
YDoc *doc = ydoc_new_with_id(1);
Branch *txt = ytext(doc, "test");
Expand All @@ -503,7 +539,7 @@ TEST_CASE("YText insert embed") {

REQUIRE(t->delta_len == 3);

YDelta d = t->delta[0];
YDeltaOut d = t->delta[0];
REQUIRE(d.tag == Y_EVENT_CHANGE_ADD);
REQUIRE(d.insert->len == 1);
REQUIRE(strcmp(youtput_read_string(d.insert), "a") == 0);
Expand Down Expand Up @@ -804,7 +840,7 @@ TEST_CASE("YMap observe") {
typedef struct YXmlTextEventTest {
uint32_t delta_len;
uint32_t keys_len;
YDelta *delta;
YDeltaOut *delta;
Branch *target;
YEventKeyChange *keys;
} YXmlTextEventTest;
Expand Down
Loading

0 comments on commit b442681

Please sign in to comment.