Undo System: replace with simpler binary diffing buffer storage
Applying/undoing incremental changes didn't fit well when mixed with periodic snapshots from mem-file undo. This moves to a much simpler undo system. - Uses array storage with de-duplication from `BLI_array_store`. - Loads the buffer into existing text data, for better performance on large files. - Has the advantage that Python operators can be supported since we don't depend on hard coded undo operations. Solves T67045, T66695, T65909.
This commit is contained in:
@@ -30,7 +30,6 @@ extern "C" {
|
||||
struct Main;
|
||||
struct Text;
|
||||
struct TextLine;
|
||||
struct TextUndoBuf;
|
||||
|
||||
void BKE_text_free_lines(struct Text *text);
|
||||
void BKE_text_free(struct Text *text);
|
||||
@@ -49,8 +48,8 @@ void BKE_text_copy_data(struct Main *bmain,
|
||||
const int flag);
|
||||
struct Text *BKE_text_copy(struct Main *bmain, const struct Text *ta);
|
||||
void BKE_text_make_local(struct Main *bmain, struct Text *text, const bool lib_local);
|
||||
void BKE_text_clear(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void BKE_text_write(struct Text *text, struct TextUndoBuf *utxt, const char *str);
|
||||
void BKE_text_clear(struct Text *text);
|
||||
void BKE_text_write(struct Text *text, const char *str);
|
||||
int BKE_text_file_modified_check(struct Text *text);
|
||||
void BKE_text_file_modified_ignore(struct Text *text);
|
||||
|
||||
@@ -77,29 +76,26 @@ void txt_move_eol(struct Text *text, const bool sel);
|
||||
void txt_move_toline(struct Text *text, unsigned int line, const bool sel);
|
||||
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel);
|
||||
void txt_pop_sel(struct Text *text);
|
||||
void txt_delete_char(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_delete_word(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_delete_selected(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_delete_char(struct Text *text);
|
||||
void txt_delete_word(struct Text *text);
|
||||
void txt_delete_selected(struct Text *text);
|
||||
void txt_sel_all(struct Text *text);
|
||||
void txt_sel_clear(struct Text *text);
|
||||
void txt_sel_line(struct Text *text);
|
||||
char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen);
|
||||
void txt_insert_buf(struct Text *text, struct TextUndoBuf *utxt, const char *in_buffer);
|
||||
void txt_undo_add_op(struct Text *text, struct TextUndoBuf *utxt, int op);
|
||||
void txt_do_undo(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_do_redo(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_split_curline(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_backspace_char(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_backspace_word(struct Text *text, struct TextUndoBuf *utxt);
|
||||
bool txt_add_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
|
||||
bool txt_add_raw_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
|
||||
bool txt_replace_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
|
||||
void txt_unindent(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_comment(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_indent(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_uncomment(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_move_lines(struct Text *text, struct TextUndoBuf *utxt, const int direction);
|
||||
void txt_duplicate_line(struct Text *text, struct TextUndoBuf *utxt);
|
||||
void txt_insert_buf(struct Text *text, const char *in_buffer);
|
||||
void txt_split_curline(struct Text *text);
|
||||
void txt_backspace_char(struct Text *text);
|
||||
void txt_backspace_word(struct Text *text);
|
||||
bool txt_add_char(struct Text *text, unsigned int add);
|
||||
bool txt_add_raw_char(struct Text *text, unsigned int add);
|
||||
bool txt_replace_char(struct Text *text, unsigned int add);
|
||||
void txt_unindent(struct Text *text);
|
||||
void txt_comment(struct Text *text);
|
||||
void txt_indent(struct Text *text);
|
||||
void txt_uncomment(struct Text *text);
|
||||
void txt_move_lines(struct Text *text, const int direction);
|
||||
void txt_duplicate_line(struct Text *text);
|
||||
int txt_setcurr_tab_spaces(struct Text *text, int space);
|
||||
bool txt_cursor_is_line_start(struct Text *text);
|
||||
bool txt_cursor_is_line_end(struct Text *text);
|
||||
@@ -125,10 +121,9 @@ enum {
|
||||
TXT_MOVE_LINE_DOWN = 1,
|
||||
};
|
||||
|
||||
typedef struct TextUndoBuf {
|
||||
char *buf;
|
||||
int pos, len;
|
||||
} TextUndoBuf;
|
||||
/* Fast non-validating buffer conversion for undo. */
|
||||
char *txt_to_buf_for_undo(struct Text *text, int *r_buf_strlen);
|
||||
void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -79,96 +79,24 @@
|
||||
*
|
||||
* Display
|
||||
* --
|
||||
*
|
||||
* The st->top determines at what line the top of the text is displayed.
|
||||
* If the user moves the cursor the st containing that cursor should
|
||||
* be popped ... other st's retain their own top location.
|
||||
*
|
||||
* Undo
|
||||
* --
|
||||
* Undo/Redo works by storing
|
||||
* events in a queue, and a pointer
|
||||
* to the current position in the
|
||||
* queue...
|
||||
*
|
||||
* Events are stored using an
|
||||
* arbitrary op-code system
|
||||
* to keep track of
|
||||
* a) the two cursors (normal and selected)
|
||||
* b) input (visible and control (ie backspace))
|
||||
*
|
||||
* input data is stored as its
|
||||
* ASCII value, the opcodes are
|
||||
* then selected to not conflict.
|
||||
*
|
||||
* opcodes with data in between are
|
||||
* written at the beginning and end
|
||||
* of the data to allow undo and redo
|
||||
* to simply check the code at the current
|
||||
* undo position
|
||||
*/
|
||||
|
||||
/* Undo opcodes */
|
||||
|
||||
enum {
|
||||
/* Complex editing */
|
||||
/* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */
|
||||
/* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */
|
||||
/* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */
|
||||
/* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */
|
||||
UNDO_INSERT_1 = 013,
|
||||
UNDO_INSERT_2 = 014,
|
||||
UNDO_INSERT_3 = 015,
|
||||
UNDO_INSERT_4 = 016,
|
||||
|
||||
UNDO_BS_1 = 017,
|
||||
UNDO_BS_2 = 020,
|
||||
UNDO_BS_3 = 021,
|
||||
UNDO_BS_4 = 022,
|
||||
|
||||
UNDO_DEL_1 = 023,
|
||||
UNDO_DEL_2 = 024,
|
||||
UNDO_DEL_3 = 025,
|
||||
UNDO_DEL_4 = 026,
|
||||
|
||||
/* Text block (opcode is followed
|
||||
* by 4 character length ID + the text
|
||||
* block itself + the 4 character length
|
||||
* ID (repeat) and opcode (repeat)) */
|
||||
UNDO_DBLOCK = 027, /* Delete block */
|
||||
UNDO_IBLOCK = 030, /* Insert block */
|
||||
|
||||
/* Misc */
|
||||
UNDO_INDENT = 032,
|
||||
UNDO_UNINDENT = 033,
|
||||
UNDO_COMMENT = 034,
|
||||
UNDO_UNCOMMENT = 035,
|
||||
|
||||
UNDO_MOVE_LINES_UP = 036,
|
||||
UNDO_MOVE_LINES_DOWN = 037,
|
||||
|
||||
UNDO_DUPLICATE = 040,
|
||||
};
|
||||
|
||||
/***/
|
||||
|
||||
static void txt_pop_first(Text *text);
|
||||
static void txt_pop_last(Text *text);
|
||||
static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf);
|
||||
static void txt_delete_line(Text *text, TextLine *line);
|
||||
static void txt_delete_sel(Text *text, TextUndoBuf *utxt);
|
||||
static void txt_delete_sel(Text *text);
|
||||
static void txt_make_dirty(Text *text);
|
||||
|
||||
/***/
|
||||
|
||||
/**
|
||||
* Set to true when undoing (so we don't generate undo steps while undoing).
|
||||
*
|
||||
* Also use to disable undo entirely.
|
||||
*/
|
||||
static bool undoing;
|
||||
|
||||
/**
|
||||
* \note caller must handle `undo_buf` and `compiled` members.
|
||||
* \note caller must handle `compiled` member.
|
||||
*/
|
||||
void BKE_text_free_lines(Text *text)
|
||||
{
|
||||
@@ -516,29 +444,17 @@ void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
|
||||
BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
|
||||
}
|
||||
|
||||
void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */
|
||||
void BKE_text_clear(Text *text) /* called directly from rna */
|
||||
{
|
||||
const bool undoing_orig = undoing;
|
||||
undoing = (utxt == NULL);
|
||||
|
||||
txt_sel_all(text);
|
||||
txt_delete_sel(text, utxt);
|
||||
|
||||
undoing = undoing_orig;
|
||||
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */
|
||||
void BKE_text_write(Text *text, const char *str) /* called directly from rna */
|
||||
{
|
||||
const bool undoing_orig = undoing;
|
||||
undoing = (utxt == NULL);
|
||||
|
||||
txt_insert_buf(text, utxt, str);
|
||||
txt_insert_buf(text, str);
|
||||
txt_move_eof(text, 0);
|
||||
|
||||
undoing = undoing_orig;
|
||||
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
@@ -1270,7 +1186,7 @@ bool txt_has_sel(Text *text)
|
||||
return ((text->curl != text->sell) || (text->curc != text->selc));
|
||||
}
|
||||
|
||||
static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
|
||||
static void txt_delete_sel(Text *text)
|
||||
{
|
||||
TextLine *tmpl;
|
||||
char *buf;
|
||||
@@ -1288,12 +1204,6 @@ static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
|
||||
|
||||
txt_order_cursors(text, false);
|
||||
|
||||
if (!undoing) {
|
||||
buf = txt_sel_to_buf(text, NULL);
|
||||
txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf);
|
||||
MEM_freeN(buf);
|
||||
}
|
||||
|
||||
buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
|
||||
|
||||
strncpy(buf, text->curl->line, text->curc);
|
||||
@@ -1349,6 +1259,106 @@ void txt_sel_line(Text *text)
|
||||
text->selc = text->sell->len;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Buffer Conversion for Undo/Redo
|
||||
*
|
||||
* Buffer conversion functions that rely on the buffer already being validated.
|
||||
*
|
||||
* The only requirement for these functions is that they're reverse-able,
|
||||
* the undo logic doesn't inspect their content.
|
||||
*
|
||||
* Currently buffers:
|
||||
* - Always ends with a new-line.
|
||||
* - Are not null terminated.
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
|
||||
*/
|
||||
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
|
||||
{
|
||||
int buf_len = 0;
|
||||
for (const TextLine *l = text->lines.first; l; l = l->next) {
|
||||
buf_len += l->len + 1;
|
||||
}
|
||||
char *buf = MEM_mallocN(buf_len, __func__);
|
||||
char *buf_step = buf;
|
||||
for (const TextLine *l = text->lines.first; l; l = l->next) {
|
||||
memcpy(buf_step, l->line, l->len);
|
||||
buf_step += l->len;
|
||||
*buf_step++ = '\n';
|
||||
}
|
||||
*r_buf_len = buf_len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a buffer from #txt_to_buf_for_undo.
|
||||
*/
|
||||
void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
|
||||
{
|
||||
const char *buf_end = buf + buf_len;
|
||||
const char *buf_step = buf;
|
||||
|
||||
/* First re-use existing lines.
|
||||
* Good for undo since it means in practice many operations re-use all
|
||||
* except for the modified line. */
|
||||
TextLine *l_src = text->lines.first;
|
||||
BLI_listbase_clear(&text->lines);
|
||||
while (buf_step != buf_end && l_src) {
|
||||
/* New lines are ensured by #txt_to_buf_for_undo. */
|
||||
const char *buf_step_next = strchr(buf_step, '\n');
|
||||
const int len = buf_step_next - buf_step;
|
||||
|
||||
TextLine *l = l_src;
|
||||
l_src = l_src->next;
|
||||
if (l->len != len) {
|
||||
l->line = MEM_reallocN(l->line, len + 1);
|
||||
l->len = len;
|
||||
}
|
||||
MEM_SAFE_FREE(l->format);
|
||||
|
||||
memcpy(l->line, buf_step, len);
|
||||
l->line[len] = '\0';
|
||||
BLI_addtail(&text->lines, l);
|
||||
buf_step = buf_step_next + 1;
|
||||
}
|
||||
|
||||
/* If we have extra lines. */
|
||||
while (l_src != NULL) {
|
||||
TextLine *l_src_next = l_src->next;
|
||||
MEM_freeN(l_src->line);
|
||||
if (l_src->format) {
|
||||
MEM_freeN(l_src->format);
|
||||
}
|
||||
MEM_freeN(l_src);
|
||||
l_src = l_src_next;
|
||||
}
|
||||
|
||||
while (buf_step != buf_end) {
|
||||
/* New lines are ensured by #txt_to_buf_for_undo. */
|
||||
const char *buf_step_next = strchr(buf_step, '\n');
|
||||
const int len = buf_step_next - buf_step;
|
||||
|
||||
TextLine *l = MEM_mallocN(sizeof(TextLine), "textline");
|
||||
l->line = MEM_mallocN(len + 1, "textline_string");
|
||||
l->len = len;
|
||||
l->format = NULL;
|
||||
|
||||
memcpy(l->line, buf_step, len);
|
||||
l->line[len] = '\0';
|
||||
BLI_addtail(&text->lines, l);
|
||||
buf_step = buf_step_next + 1;
|
||||
}
|
||||
|
||||
text->curl = text->sell = text->lines.first;
|
||||
text->curc = text->selc = 0;
|
||||
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/***************************/
|
||||
/* Cut and paste functions */
|
||||
/***************************/
|
||||
@@ -1575,9 +1585,8 @@ char *txt_sel_to_buf(Text *text, int *r_buf_strlen)
|
||||
return buf;
|
||||
}
|
||||
|
||||
void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
|
||||
void txt_insert_buf(Text *text, const char *in_buffer)
|
||||
{
|
||||
const bool undoing_orig = undoing;
|
||||
int l = 0, len;
|
||||
size_t i = 0, j;
|
||||
TextLine *add;
|
||||
@@ -1587,24 +1596,19 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
|
||||
len = strlen(in_buffer);
|
||||
buffer = BLI_strdupn(in_buffer, len);
|
||||
len += txt_extended_ascii_as_utf8(&buffer);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer);
|
||||
}
|
||||
undoing = true;
|
||||
|
||||
/* Read the first line (or as close as possible */
|
||||
while (buffer[i] && buffer[i] != '\n') {
|
||||
txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i));
|
||||
txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i));
|
||||
}
|
||||
|
||||
if (buffer[i] == '\n') {
|
||||
txt_split_curline(text, utxt);
|
||||
txt_split_curline(text);
|
||||
i++;
|
||||
|
||||
while (i < len) {
|
||||
@@ -1622,7 +1626,7 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
|
||||
}
|
||||
else {
|
||||
for (j = i - l; j < i && j < len;) {
|
||||
txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j));
|
||||
txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1630,1046 +1634,13 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
|
||||
}
|
||||
|
||||
MEM_freeN(buffer);
|
||||
undoing = undoing_orig;
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Undo functions */
|
||||
/******************/
|
||||
|
||||
static bool max_undo_test(TextUndoBuf *utxt, int x)
|
||||
{
|
||||
/* Normally over-allocating is preferred,
|
||||
* however in this case the buffer is small enough and re-allocation
|
||||
* fast enough for each undo step that it's not a problem to allocate each time.
|
||||
* This also saves on some memory when we have many text buffers
|
||||
* that would have an empty undo memory allocated.
|
||||
*/
|
||||
|
||||
/* Add one for the null terminator. */
|
||||
utxt->len = utxt->pos + x + 1;
|
||||
if (utxt->len > TXT_MAX_UNDO) {
|
||||
/* XXX error("Undo limit reached, buffer cleared\n"); */
|
||||
MEM_freeN(utxt->buf);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
/* Small reallocations on each undo step is fine. */
|
||||
utxt->buf = MEM_recallocN(utxt->buf, utxt->len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt)
|
||||
{
|
||||
int undo_pos_end = utxt->pos + 1;
|
||||
BLI_assert(undo_pos_end + 1 == utxt->len);
|
||||
utxt->buf[undo_pos_end] = '\0';
|
||||
}
|
||||
|
||||
/* Call once undo is done. */
|
||||
#ifndef NDEBUG
|
||||
|
||||
#endif
|
||||
|
||||
#if 0 /* UNUSED */
|
||||
static void dump_buffer(TextUndoBuf *utxt)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i++ < utxt->undo_pos)
|
||||
printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]);
|
||||
}
|
||||
|
||||
/* Note: this function is outdated and must be updated if needed for future use */
|
||||
void txt_print_undo(Text *text)
|
||||
{
|
||||
int i = 0;
|
||||
int op;
|
||||
const char *ops;
|
||||
int linep, charp;
|
||||
|
||||
dump_buffer(text);
|
||||
|
||||
printf("---< Undo Buffer >---\n");
|
||||
|
||||
printf("UndoPosition is %d\n", utxt->pos);
|
||||
|
||||
while (i <= utxt->pos) {
|
||||
op = utxt->buf[i];
|
||||
|
||||
if (op == UNDO_INSERT_1) {
|
||||
ops = "Insert ascii ";
|
||||
}
|
||||
else if (op == UNDO_INSERT_2) {
|
||||
ops = "Insert 2 bytes ";
|
||||
}
|
||||
else if (op == UNDO_INSERT_3) {
|
||||
ops = "Insert 3 bytes ";
|
||||
}
|
||||
else if (op == UNDO_INSERT_4) {
|
||||
ops = "Insert unicode ";
|
||||
}
|
||||
else if (op == UNDO_BS_1) {
|
||||
ops = "Backspace for ascii ";
|
||||
}
|
||||
else if (op == UNDO_BS_2) {
|
||||
ops = "Backspace for 2 bytes ";
|
||||
}
|
||||
else if (op == UNDO_BS_3) {
|
||||
ops = "Backspace for 3 bytes ";
|
||||
}
|
||||
else if (op == UNDO_BS_4) {
|
||||
ops = "Backspace for unicode ";
|
||||
}
|
||||
else if (op == UNDO_DEL_1) {
|
||||
ops = "Delete ascii ";
|
||||
}
|
||||
else if (op == UNDO_DEL_2) {
|
||||
ops = "Delete 2 bytes ";
|
||||
}
|
||||
else if (op == UNDO_DEL_3) {
|
||||
ops = "Delete 3 bytes ";
|
||||
}
|
||||
else if (op == UNDO_DEL_4) {
|
||||
ops = "Delete unicode ";
|
||||
}
|
||||
else if (op == UNDO_DBLOCK) {
|
||||
ops = "Delete text block";
|
||||
}
|
||||
else if (op == UNDO_IBLOCK) {
|
||||
ops = "Insert text block";
|
||||
}
|
||||
else if (op == UNDO_INDENT) {
|
||||
ops = "Indent ";
|
||||
}
|
||||
else if (op == UNDO_UNINDENT) {
|
||||
ops = "Unindent ";
|
||||
}
|
||||
else if (op == UNDO_COMMENT) {
|
||||
ops = "Comment ";
|
||||
}
|
||||
else if (op == UNDO_UNCOMMENT) {
|
||||
ops = "Uncomment ";
|
||||
}
|
||||
else {
|
||||
ops = "Unknown";
|
||||
}
|
||||
|
||||
printf("Op (%o) at %d = %s", op, i, ops);
|
||||
if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
|
||||
i++;
|
||||
printf(" - Char is ");
|
||||
switch (op) {
|
||||
case UNDO_INSERT_1:
|
||||
case UNDO_BS_1:
|
||||
case UNDO_DEL_1:
|
||||
printf("%c", utxt->buf[i]);
|
||||
i++;
|
||||
break;
|
||||
case UNDO_INSERT_2:
|
||||
case UNDO_BS_2:
|
||||
case UNDO_DEL_2:
|
||||
printf("%c%c", utxt->buf[i], utxt->buf[i + 1]);
|
||||
i += 2;
|
||||
break;
|
||||
case UNDO_INSERT_3:
|
||||
case UNDO_BS_3:
|
||||
case UNDO_DEL_3:
|
||||
printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]);
|
||||
i += 3;
|
||||
break;
|
||||
case UNDO_INSERT_4:
|
||||
case UNDO_BS_4:
|
||||
case UNDO_DEL_4: {
|
||||
unsigned int uc;
|
||||
char c[BLI_UTF8_MAX + 1];
|
||||
size_t c_len;
|
||||
uc = utxt->buf[i];
|
||||
i++;
|
||||
uc = uc + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
uc = uc + (utxt->buf[i] << 16);
|
||||
i++;
|
||||
uc = uc + (utxt->buf[i] << 24);
|
||||
i++;
|
||||
c_len = BLI_str_utf8_from_unicode(uc, c);
|
||||
c[c_len] = '\0';
|
||||
puts(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) {
|
||||
i++;
|
||||
|
||||
linep = utxt->buf[i];
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 16);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 24);
|
||||
i++;
|
||||
|
||||
printf(" (length %d) <", linep);
|
||||
|
||||
while (linep > 0) {
|
||||
putchar(utxt->buf[i]);
|
||||
linep--;
|
||||
i++;
|
||||
}
|
||||
|
||||
linep = utxt->buf[i];
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 16);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 24);
|
||||
i++;
|
||||
printf("> (%d)", linep);
|
||||
}
|
||||
else if (op == UNDO_INDENT || op == UNDO_UNINDENT) {
|
||||
i++;
|
||||
|
||||
charp = utxt->buf[i];
|
||||
i++;
|
||||
charp = charp + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
|
||||
linep = utxt->buf[i];
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 16);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 24);
|
||||
i++;
|
||||
|
||||
printf("to <%d, %d> ", linep, charp);
|
||||
|
||||
charp = utxt->buf[i];
|
||||
i++;
|
||||
charp = charp + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
|
||||
linep = utxt->buf[i];
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 8);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 16);
|
||||
i++;
|
||||
linep = linep + (utxt->buf[i] << 24);
|
||||
i++;
|
||||
|
||||
printf("from <%d, %d>", linep, charp);
|
||||
}
|
||||
|
||||
printf(" %d\n", i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value)
|
||||
{
|
||||
undo_buf[*undo_pos] = (value)&0xff;
|
||||
(*undo_pos)++;
|
||||
undo_buf[*undo_pos] = (value >> 8) & 0xff;
|
||||
(*undo_pos)++;
|
||||
}
|
||||
|
||||
static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value)
|
||||
{
|
||||
undo_buf[*undo_pos] = (value)&0xff;
|
||||
(*undo_pos)++;
|
||||
undo_buf[*undo_pos] = (value >> 8) & 0xff;
|
||||
(*undo_pos)++;
|
||||
undo_buf[*undo_pos] = (value >> 16) & 0xff;
|
||||
(*undo_pos)++;
|
||||
undo_buf[*undo_pos] = (value >> 24) & 0xff;
|
||||
(*undo_pos)++;
|
||||
}
|
||||
|
||||
/* store the cur cursor to the undo buffer (6 bytes)*/
|
||||
static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt)
|
||||
{
|
||||
txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc);
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl));
|
||||
}
|
||||
|
||||
/* store the sel cursor to the undo buffer (6 bytes) */
|
||||
static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt)
|
||||
{
|
||||
txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc);
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell));
|
||||
}
|
||||
|
||||
/* store both cursors to the undo buffer (12 bytes) */
|
||||
static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt)
|
||||
{
|
||||
txt_undo_store_cur(text, utxt);
|
||||
txt_undo_store_sel(text, utxt);
|
||||
}
|
||||
|
||||
/* store an operator along with a block of data */
|
||||
static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf)
|
||||
{
|
||||
unsigned int length = strlen(buf);
|
||||
|
||||
if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) {
|
||||
return;
|
||||
}
|
||||
/* 2 bytes */
|
||||
utxt->pos++;
|
||||
utxt->buf[utxt->pos] = op;
|
||||
utxt->pos++;
|
||||
/* 12 bytes */
|
||||
txt_undo_store_cursors(text, utxt);
|
||||
/* 4 bytes */
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
|
||||
/* 'length' bytes */
|
||||
memcpy(utxt->buf + utxt->pos, buf, length);
|
||||
utxt->pos += length;
|
||||
/* 4 bytes */
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
|
||||
/* 1 byte */
|
||||
utxt->buf[utxt->pos] = op;
|
||||
|
||||
txt_undo_end(text, utxt);
|
||||
}
|
||||
|
||||
/* store a regular operator */
|
||||
void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op)
|
||||
{
|
||||
if (!max_undo_test(utxt, 2 + 12 + 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 2 bytes */
|
||||
utxt->pos++;
|
||||
utxt->buf[utxt->pos] = op;
|
||||
utxt->pos++;
|
||||
/* 12 bytes */
|
||||
txt_undo_store_cursors(text, utxt);
|
||||
/* 1 byte */
|
||||
utxt->buf[utxt->pos] = op;
|
||||
|
||||
txt_undo_end(text, utxt);
|
||||
}
|
||||
|
||||
/* store an operator for a single character */
|
||||
static void txt_undo_add_charop(Text *text, TextUndoBuf *utxt, int op_start, unsigned int c)
|
||||
{
|
||||
char utf8[BLI_UTF8_MAX];
|
||||
size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
|
||||
|
||||
if (utf8_size < 4 && 0) {
|
||||
if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) {
|
||||
return;
|
||||
}
|
||||
/* 2 bytes */
|
||||
utxt->pos++;
|
||||
utxt->buf[utxt->pos] = op_start + utf8_size - 1;
|
||||
utxt->pos++;
|
||||
/* 6 bytes */
|
||||
txt_undo_store_cur(text, utxt);
|
||||
/* 'utf8_size' bytes */
|
||||
for (i = 0; i < utf8_size; i++) {
|
||||
utxt->buf[utxt->pos] = utf8[i];
|
||||
utxt->pos++;
|
||||
}
|
||||
/* 1 byte */
|
||||
utxt->buf[utxt->pos] = op_start + utf8_size - 1;
|
||||
}
|
||||
else {
|
||||
if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) {
|
||||
return;
|
||||
}
|
||||
/* 2 bytes */
|
||||
utxt->pos++;
|
||||
utxt->buf[utxt->pos] = op_start + 3;
|
||||
utxt->pos++;
|
||||
/* 6 bytes */
|
||||
txt_undo_store_cur(text, utxt);
|
||||
/* 4 bytes */
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, c);
|
||||
/* 1 byte */
|
||||
utxt->buf[utxt->pos] = op_start + 3;
|
||||
}
|
||||
|
||||
txt_undo_end(text, utxt);
|
||||
}
|
||||
|
||||
/* extends Link */
|
||||
struct LinkInt {
|
||||
struct LinkInt *next, *prev;
|
||||
int value;
|
||||
};
|
||||
|
||||
/**
|
||||
* UnindentLines points to a #ListBase composed of #LinkInt elements, listing the numbers
|
||||
* of the lines that should not be indented back.
|
||||
*/
|
||||
static void txt_undo_add_unprefix_op(Text *text,
|
||||
TextUndoBuf *utxt,
|
||||
char undo_op,
|
||||
const ListBase *line_index_mask,
|
||||
const int line_index_mask_len)
|
||||
{
|
||||
struct LinkInt *idata;
|
||||
|
||||
BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
|
||||
|
||||
/* OP byte + u32 count + counted u32 line numbers + u32 count + 12-bytes selection + OP byte. */
|
||||
if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 2 bytes */
|
||||
utxt->pos++;
|
||||
utxt->buf[utxt->pos] = undo_op;
|
||||
utxt->pos++;
|
||||
/* Adding number of line numbers to read
|
||||
* 4 bytes */
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
|
||||
|
||||
/* Adding line-numbers of lines that shall not be indented if undoing.
|
||||
* 'line_index_mask_len * 4' bytes */
|
||||
for (idata = line_index_mask->first; idata; idata = idata->next) {
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value);
|
||||
}
|
||||
|
||||
/* Adding number of line numbers to read again.
|
||||
* 4 bytes */
|
||||
txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
|
||||
/* Adding current selection.
|
||||
* 12 bytes */
|
||||
txt_undo_store_cursors(text, utxt);
|
||||
/* Closing with OP (same as above).
|
||||
* 1 byte */
|
||||
utxt->buf[utxt->pos] = undo_op;
|
||||
/* Marking as last undo operation */
|
||||
txt_undo_end(text, utxt);
|
||||
}
|
||||
|
||||
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
|
||||
{
|
||||
unsigned short val;
|
||||
val = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
val = (val << 8) + undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos)
|
||||
{
|
||||
unsigned int val;
|
||||
val = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
val = (val << 8) + undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
val = (val << 8) + undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
val = (val << 8) + undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read the cur cursor from the undo buffer */
|
||||
static void txt_undo_read_cur(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *curln,
|
||||
unsigned short *curc)
|
||||
{
|
||||
*curln = txt_undo_read_uint32(undo_buf, undo_pos);
|
||||
*curc = txt_undo_read_uint16(undo_buf, undo_pos);
|
||||
}
|
||||
|
||||
/* read the sel cursor from the undo buffer */
|
||||
static void txt_undo_read_sel(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *selln,
|
||||
unsigned short *selc)
|
||||
{
|
||||
*selln = txt_undo_read_uint32(undo_buf, undo_pos);
|
||||
*selc = txt_undo_read_uint16(undo_buf, undo_pos);
|
||||
}
|
||||
|
||||
/* read both cursors from the undo buffer */
|
||||
static void txt_undo_read_cursors(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *curln,
|
||||
unsigned short *curc,
|
||||
unsigned int *selln,
|
||||
unsigned short *selc)
|
||||
{
|
||||
txt_undo_read_sel(undo_buf, undo_pos, selln, selc);
|
||||
txt_undo_read_cur(undo_buf, undo_pos, curln, curc);
|
||||
}
|
||||
|
||||
static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
|
||||
{
|
||||
unsigned int unicode;
|
||||
char utf8[BLI_UTF8_MAX + 1];
|
||||
|
||||
switch (bytes) {
|
||||
case 1: /* ascii */
|
||||
unicode = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
break;
|
||||
case 2: /* 2-byte symbol */
|
||||
utf8[2] = '\0';
|
||||
utf8[1] = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
utf8[0] = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
unicode = BLI_str_utf8_as_unicode(utf8);
|
||||
break;
|
||||
case 3: /* 3-byte symbol */
|
||||
utf8[3] = '\0';
|
||||
utf8[2] = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
utf8[1] = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
utf8[0] = undo_buf[*undo_pos];
|
||||
(*undo_pos)--;
|
||||
unicode = BLI_str_utf8_as_unicode(utf8);
|
||||
break;
|
||||
case 4: /* 32-bit unicode symbol */
|
||||
unicode = txt_undo_read_uint32(undo_buf, undo_pos);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
BLI_assert(0);
|
||||
unicode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return unicode;
|
||||
}
|
||||
|
||||
static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos)
|
||||
{
|
||||
unsigned short val;
|
||||
val = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
val = val + (undo_buf[*undo_pos] << 8);
|
||||
(*undo_pos)++;
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos)
|
||||
{
|
||||
unsigned int val;
|
||||
val = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
val = val + (undo_buf[*undo_pos] << 8);
|
||||
(*undo_pos)++;
|
||||
val = val + (undo_buf[*undo_pos] << 16);
|
||||
(*undo_pos)++;
|
||||
val = val + (undo_buf[*undo_pos] << 24);
|
||||
(*undo_pos)++;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* redo read cur cursor from the undo buffer */
|
||||
static void txt_redo_read_cur(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *curln,
|
||||
unsigned short *curc)
|
||||
{
|
||||
*curc = txt_redo_read_uint16(undo_buf, undo_pos);
|
||||
*curln = txt_redo_read_uint32(undo_buf, undo_pos);
|
||||
}
|
||||
|
||||
/* redo read sel cursor from the undo buffer */
|
||||
static void txt_redo_read_sel(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *selln,
|
||||
unsigned short *selc)
|
||||
{
|
||||
*selc = txt_redo_read_uint16(undo_buf, undo_pos);
|
||||
*selln = txt_redo_read_uint32(undo_buf, undo_pos);
|
||||
}
|
||||
|
||||
/* redo read both cursors from the undo buffer */
|
||||
static void txt_redo_read_cursors(const char *undo_buf,
|
||||
int *undo_pos,
|
||||
unsigned int *curln,
|
||||
unsigned short *curc,
|
||||
unsigned int *selln,
|
||||
unsigned short *selc)
|
||||
{
|
||||
txt_redo_read_cur(undo_buf, undo_pos, curln, curc);
|
||||
txt_redo_read_sel(undo_buf, undo_pos, selln, selc);
|
||||
}
|
||||
|
||||
static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
|
||||
{
|
||||
unsigned int unicode;
|
||||
char utf8[BLI_UTF8_MAX + 1];
|
||||
|
||||
switch (bytes) {
|
||||
case 1: /* ascii */
|
||||
unicode = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
break;
|
||||
case 2: /* 2-byte symbol */
|
||||
utf8[0] = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
utf8[1] = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
utf8[2] = '\0';
|
||||
unicode = BLI_str_utf8_as_unicode(utf8);
|
||||
break;
|
||||
case 3: /* 3-byte symbol */
|
||||
utf8[0] = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
utf8[1] = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
utf8[2] = undo_buf[*undo_pos];
|
||||
(*undo_pos)++;
|
||||
utf8[3] = '\0';
|
||||
unicode = BLI_str_utf8_as_unicode(utf8);
|
||||
break;
|
||||
case 4: /* 32-bit unicode symbol */
|
||||
unicode = txt_redo_read_uint32(undo_buf, undo_pos);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
BLI_assert(0);
|
||||
unicode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return unicode;
|
||||
}
|
||||
|
||||
void txt_do_undo(Text *text, TextUndoBuf *utxt)
|
||||
{
|
||||
int op = utxt->buf[utxt->pos];
|
||||
int prev_flags;
|
||||
unsigned int linep;
|
||||
unsigned int uni_char;
|
||||
unsigned int curln, selln;
|
||||
unsigned short curc, selc;
|
||||
unsigned short charp;
|
||||
char *buf;
|
||||
|
||||
if (utxt->pos < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
utxt->pos--;
|
||||
|
||||
undoing = 1;
|
||||
|
||||
switch (op) {
|
||||
case UNDO_INSERT_1:
|
||||
case UNDO_INSERT_2:
|
||||
case UNDO_INSERT_3:
|
||||
case UNDO_INSERT_4:
|
||||
utxt->pos -= op - UNDO_INSERT_1 + 1;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
txt_delete_char(text, utxt);
|
||||
|
||||
utxt->pos--;
|
||||
break;
|
||||
|
||||
case UNDO_BS_1:
|
||||
case UNDO_BS_2:
|
||||
case UNDO_BS_3:
|
||||
case UNDO_BS_4:
|
||||
charp = op - UNDO_BS_1 + 1;
|
||||
uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
txt_add_char(text, utxt, uni_char);
|
||||
|
||||
utxt->pos--;
|
||||
break;
|
||||
|
||||
case UNDO_DEL_1:
|
||||
case UNDO_DEL_2:
|
||||
case UNDO_DEL_3:
|
||||
case UNDO_DEL_4:
|
||||
charp = op - UNDO_DEL_1 + 1;
|
||||
uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
txt_add_char(text, utxt, uni_char);
|
||||
|
||||
txt_move_left(text, 0);
|
||||
|
||||
utxt->pos--;
|
||||
break;
|
||||
|
||||
case UNDO_DBLOCK: {
|
||||
int i;
|
||||
/* length of the string in the buffer */
|
||||
linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
|
||||
|
||||
buf = MEM_mallocN(linep + 1, "dblock buffer");
|
||||
for (i = 0; i < linep; i++) {
|
||||
buf[(linep - 1) - i] = utxt->buf[utxt->pos];
|
||||
utxt->pos--;
|
||||
}
|
||||
buf[i] = 0;
|
||||
|
||||
/* skip over the length that was stored again */
|
||||
utxt->pos -= 4;
|
||||
|
||||
/* Get the cursor positions */
|
||||
txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
|
||||
/* move cur to location that needs buff inserted */
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
|
||||
txt_insert_buf(text, utxt, buf);
|
||||
MEM_freeN(buf);
|
||||
|
||||
/* restore the cursors */
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
utxt->pos--;
|
||||
|
||||
break;
|
||||
}
|
||||
case UNDO_IBLOCK: {
|
||||
int i;
|
||||
/* length of the string in the buffer */
|
||||
linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
|
||||
|
||||
/* txt_backspace_char removes utf8-characters, not bytes */
|
||||
buf = MEM_mallocN(linep + 1, "iblock buffer");
|
||||
for (i = 0; i < linep; i++) {
|
||||
buf[(linep - 1) - i] = utxt->buf[utxt->pos];
|
||||
utxt->pos--;
|
||||
}
|
||||
buf[i] = 0;
|
||||
linep = BLI_strlen_utf8(buf);
|
||||
MEM_freeN(buf);
|
||||
|
||||
/* skip over the length that was stored again */
|
||||
utxt->pos -= 4;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
if ((curln == selln) && (curc == selc)) {
|
||||
/* disable tabs to spaces since moving right may involve skipping multiple spaces */
|
||||
prev_flags = text->flags;
|
||||
text->flags &= ~TXT_TABSTOSPACES;
|
||||
|
||||
for (i = 0; i < linep; i++) {
|
||||
txt_move_right(text, 1);
|
||||
}
|
||||
|
||||
text->flags = prev_flags;
|
||||
}
|
||||
|
||||
txt_delete_selected(text, utxt);
|
||||
|
||||
utxt->pos--;
|
||||
break;
|
||||
}
|
||||
case UNDO_INDENT:
|
||||
case UNDO_COMMENT:
|
||||
case UNDO_DUPLICATE:
|
||||
case UNDO_MOVE_LINES_UP:
|
||||
case UNDO_MOVE_LINES_DOWN:
|
||||
/* get and restore the cursors */
|
||||
txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
if (op == UNDO_INDENT) {
|
||||
txt_unindent(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_COMMENT) {
|
||||
txt_uncomment(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_DUPLICATE) {
|
||||
txt_delete_line(text, text->curl->next);
|
||||
}
|
||||
else if (op == UNDO_MOVE_LINES_UP) {
|
||||
txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
|
||||
}
|
||||
else if (op == UNDO_MOVE_LINES_DOWN) {
|
||||
txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
|
||||
}
|
||||
|
||||
utxt->pos--;
|
||||
break;
|
||||
case UNDO_UNINDENT:
|
||||
case UNDO_UNCOMMENT: {
|
||||
void (*txt_prefix_fn)(Text *, TextUndoBuf *);
|
||||
void (*txt_unprefix_fn)(Text *, TextUndoBuf *);
|
||||
int count;
|
||||
int i;
|
||||
/* Get and restore the cursors */
|
||||
txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
/* Un-unindent */
|
||||
if (op == UNDO_UNINDENT) {
|
||||
txt_prefix_fn = txt_indent;
|
||||
txt_unprefix_fn = txt_unindent;
|
||||
}
|
||||
else {
|
||||
txt_prefix_fn = txt_comment;
|
||||
txt_unprefix_fn = txt_uncomment;
|
||||
}
|
||||
|
||||
txt_prefix_fn(text, utxt);
|
||||
|
||||
/* Get the count */
|
||||
count = txt_undo_read_uint32(utxt->buf, &utxt->pos);
|
||||
/* Iterate! */
|
||||
txt_pop_sel(text);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0);
|
||||
/* Un-un-unindent/comment */
|
||||
txt_unprefix_fn(text, utxt);
|
||||
}
|
||||
/* Restore selection */
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
/* Jumo over count */
|
||||
txt_undo_read_uint32(utxt->buf, &utxt->pos);
|
||||
/* Jump over closing OP byte */
|
||||
utxt->pos--;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// XXX error("Undo buffer error - resetting");
|
||||
utxt->pos = -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
undoing = 0;
|
||||
}
|
||||
|
||||
void txt_do_redo(Text *text, TextUndoBuf *utxt)
|
||||
{
|
||||
char op;
|
||||
char *buf;
|
||||
unsigned int linep;
|
||||
unsigned short charp;
|
||||
unsigned int uni_uchar;
|
||||
unsigned int curln, selln;
|
||||
unsigned short curc, selc;
|
||||
|
||||
utxt->pos++;
|
||||
op = utxt->buf[utxt->pos];
|
||||
|
||||
if (!op) {
|
||||
utxt->pos--;
|
||||
return;
|
||||
}
|
||||
|
||||
undoing = 1;
|
||||
|
||||
switch (op) {
|
||||
case UNDO_INSERT_1:
|
||||
case UNDO_INSERT_2:
|
||||
case UNDO_INSERT_3:
|
||||
case UNDO_INSERT_4:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
charp = op - UNDO_INSERT_1 + 1;
|
||||
uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp);
|
||||
|
||||
txt_add_char(text, utxt, uni_uchar);
|
||||
break;
|
||||
|
||||
case UNDO_BS_1:
|
||||
case UNDO_BS_2:
|
||||
case UNDO_BS_3:
|
||||
case UNDO_BS_4:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
utxt->pos += op - UNDO_BS_1 + 1;
|
||||
|
||||
/* move right so we backspace the correct char */
|
||||
txt_move_right(text, 0);
|
||||
txt_backspace_char(text, utxt);
|
||||
|
||||
break;
|
||||
|
||||
case UNDO_DEL_1:
|
||||
case UNDO_DEL_2:
|
||||
case UNDO_DEL_3:
|
||||
case UNDO_DEL_4:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
utxt->pos += op - UNDO_DEL_1 + 1;
|
||||
|
||||
txt_delete_char(text, utxt);
|
||||
|
||||
break;
|
||||
|
||||
case UNDO_DBLOCK:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
/* length of the block */
|
||||
linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
|
||||
|
||||
utxt->pos += linep;
|
||||
|
||||
/* skip over the length that was stored again */
|
||||
utxt->pos += 4;
|
||||
|
||||
txt_delete_sel(text, utxt);
|
||||
|
||||
break;
|
||||
|
||||
case UNDO_IBLOCK:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, curln, curc, 1);
|
||||
|
||||
/* length of the block */
|
||||
linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
|
||||
|
||||
buf = MEM_mallocN(linep + 1, "iblock buffer");
|
||||
memcpy(buf, &utxt->buf[utxt->pos], linep);
|
||||
utxt->pos += linep;
|
||||
buf[linep] = 0;
|
||||
|
||||
txt_insert_buf(text, utxt, buf);
|
||||
MEM_freeN(buf);
|
||||
|
||||
/* skip over the length that was stored again */
|
||||
utxt->pos += 4;
|
||||
|
||||
break;
|
||||
|
||||
case UNDO_INDENT:
|
||||
case UNDO_COMMENT:
|
||||
case UNDO_UNCOMMENT:
|
||||
case UNDO_DUPLICATE:
|
||||
case UNDO_MOVE_LINES_UP:
|
||||
case UNDO_MOVE_LINES_DOWN:
|
||||
utxt->pos++;
|
||||
|
||||
/* get and restore the cursors */
|
||||
txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
if (op == UNDO_INDENT) {
|
||||
txt_indent(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_COMMENT) {
|
||||
txt_comment(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_UNCOMMENT) {
|
||||
txt_uncomment(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_DUPLICATE) {
|
||||
txt_duplicate_line(text, utxt);
|
||||
}
|
||||
else if (op == UNDO_MOVE_LINES_UP) {
|
||||
/* offset the cursor by + 1 */
|
||||
txt_move_to(text, curln + 1, curc, 0);
|
||||
txt_move_to(text, selln + 1, selc, 1);
|
||||
|
||||
txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
|
||||
}
|
||||
else if (op == UNDO_MOVE_LINES_DOWN) {
|
||||
/* offset the cursor by - 1 */
|
||||
txt_move_to(text, curln - 1, curc, 0);
|
||||
txt_move_to(text, selln - 1, selc, 1);
|
||||
|
||||
txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
|
||||
}
|
||||
|
||||
/* re-restore the cursors since they got moved when redoing */
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
|
||||
break;
|
||||
case UNDO_UNINDENT: {
|
||||
int count;
|
||||
int i;
|
||||
|
||||
utxt->pos++;
|
||||
/* Scan all the stuff described in txt_undo_add_unindent_op */
|
||||
count = txt_redo_read_uint32(utxt->buf, &utxt->pos);
|
||||
for (i = 0; i < count; i++) {
|
||||
txt_redo_read_uint32(utxt->buf, &utxt->pos);
|
||||
}
|
||||
/* Count again */
|
||||
txt_redo_read_uint32(utxt->buf, &utxt->pos);
|
||||
/* Get the selection and re-unindent */
|
||||
txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
|
||||
txt_move_to(text, curln, curc, 0);
|
||||
txt_move_to(text, selln, selc, 1);
|
||||
txt_unindent(text, utxt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// XXX error("Undo buffer error - resetting");
|
||||
utxt->pos = -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
undoing = 0;
|
||||
}
|
||||
|
||||
/**************************/
|
||||
/* Line editing functions */
|
||||
/**************************/
|
||||
|
||||
void txt_split_curline(Text *text, TextUndoBuf *utxt)
|
||||
void txt_split_curline(Text *text)
|
||||
{
|
||||
TextLine *ins;
|
||||
char *left, *right;
|
||||
@@ -2678,11 +1649,7 @@ void txt_split_curline(Text *text, TextUndoBuf *utxt)
|
||||
return;
|
||||
}
|
||||
|
||||
txt_delete_sel(text, utxt);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n');
|
||||
}
|
||||
txt_delete_sel(text);
|
||||
|
||||
/* Make the two half strings */
|
||||
|
||||
@@ -2765,7 +1732,7 @@ static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
|
||||
txt_clean_text(text);
|
||||
}
|
||||
|
||||
void txt_duplicate_line(Text *text, TextUndoBuf *utxt)
|
||||
void txt_duplicate_line(Text *text)
|
||||
{
|
||||
TextLine *textline;
|
||||
|
||||
@@ -2779,14 +1746,10 @@ void txt_duplicate_line(Text *text, TextUndoBuf *utxt)
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_op(text, utxt, UNDO_DUPLICATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void txt_delete_char(Text *text, TextUndoBuf *utxt)
|
||||
void txt_delete_char(Text *text)
|
||||
{
|
||||
unsigned int c = '\n';
|
||||
|
||||
@@ -2795,7 +1758,7 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt)
|
||||
}
|
||||
|
||||
if (txt_has_sel(text)) { /* deleting a selection */
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
return;
|
||||
}
|
||||
@@ -2811,6 +1774,7 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt)
|
||||
else { /* Just deleting a char */
|
||||
size_t c_len = 0;
|
||||
c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
|
||||
UNUSED_VARS(c);
|
||||
|
||||
memmove(text->curl->line + text->curc,
|
||||
text->curl->line + text->curc + c_len,
|
||||
@@ -2823,20 +1787,16 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt)
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_charop(text, utxt, UNDO_DEL_1, c);
|
||||
}
|
||||
}
|
||||
|
||||
void txt_delete_word(Text *text, TextUndoBuf *utxt)
|
||||
void txt_delete_word(Text *text)
|
||||
{
|
||||
txt_jump_right(text, true, true);
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
void txt_backspace_char(Text *text, TextUndoBuf *utxt)
|
||||
void txt_backspace_char(Text *text)
|
||||
{
|
||||
unsigned int c = '\n';
|
||||
|
||||
@@ -2845,7 +1805,7 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt)
|
||||
}
|
||||
|
||||
if (txt_has_sel(text)) { /* deleting a selection */
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
return;
|
||||
}
|
||||
@@ -2864,6 +1824,7 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt)
|
||||
size_t c_len = 0;
|
||||
const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
|
||||
c = BLI_str_utf8_as_unicode_and_size(prev, &c_len);
|
||||
UNUSED_VARS(c);
|
||||
|
||||
/* source and destination overlap, don't use memcpy() */
|
||||
memmove(text->curl->line + text->curc - c_len,
|
||||
@@ -2878,16 +1839,12 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt)
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_charop(text, utxt, UNDO_BS_1, c);
|
||||
}
|
||||
}
|
||||
|
||||
void txt_backspace_word(Text *text, TextUndoBuf *utxt)
|
||||
void txt_backspace_word(Text *text)
|
||||
{
|
||||
txt_jump_left(text, true, true);
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
@@ -2896,17 +1853,17 @@ void txt_backspace_word(Text *text, TextUndoBuf *utxt)
|
||||
* Remember to change this string according to max tab size */
|
||||
static char tab_to_spaces[] = " ";
|
||||
|
||||
static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt)
|
||||
static void txt_convert_tab_to_spaces(Text *text)
|
||||
{
|
||||
/* sb aims to pad adjust the tab-width needed so that the right number of spaces
|
||||
* is added so that the indention of the line is the right width (i.e. aligned
|
||||
* to multiples of TXT_TABSIZE)
|
||||
*/
|
||||
const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
|
||||
txt_insert_buf(text, utxt, sb);
|
||||
txt_insert_buf(text, sb);
|
||||
}
|
||||
|
||||
static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs)
|
||||
static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
|
||||
{
|
||||
char *tmp, ch[BLI_UTF8_MAX];
|
||||
size_t add_len;
|
||||
@@ -2916,21 +1873,17 @@ static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add,
|
||||
}
|
||||
|
||||
if (add == '\n') {
|
||||
txt_split_curline(text, utxt);
|
||||
txt_split_curline(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* insert spaces rather than tabs */
|
||||
if (add == '\t' && replace_tabs) {
|
||||
txt_convert_tab_to_spaces(text, utxt);
|
||||
txt_convert_tab_to_spaces(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
txt_delete_sel(text, utxt);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
|
||||
}
|
||||
txt_delete_sel(text);
|
||||
|
||||
add_len = BLI_str_utf8_from_unicode(add, ch);
|
||||
|
||||
@@ -2953,23 +1906,23 @@ static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add,
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add)
|
||||
bool txt_add_char(Text *text, unsigned int add)
|
||||
{
|
||||
return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0);
|
||||
return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0);
|
||||
}
|
||||
|
||||
bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add)
|
||||
bool txt_add_raw_char(Text *text, unsigned int add)
|
||||
{
|
||||
return txt_add_char_intern(text, utxt, add, 0);
|
||||
return txt_add_char_intern(text, add, 0);
|
||||
}
|
||||
|
||||
void txt_delete_selected(Text *text, TextUndoBuf *utxt)
|
||||
void txt_delete_selected(Text *text)
|
||||
{
|
||||
txt_delete_sel(text, utxt);
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
}
|
||||
|
||||
bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
|
||||
bool txt_replace_char(Text *text, unsigned int add)
|
||||
{
|
||||
unsigned int del;
|
||||
size_t del_size = 0, add_size;
|
||||
@@ -2981,10 +1934,11 @@ bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
|
||||
|
||||
/* If text is selected or we're at the end of the line just use txt_add_char */
|
||||
if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
|
||||
return txt_add_char(text, utxt, add);
|
||||
return txt_add_char(text, add);
|
||||
}
|
||||
|
||||
del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
|
||||
UNUSED_VARS(del);
|
||||
add_size = BLI_str_utf8_from_unicode(add, ch);
|
||||
|
||||
if (add_size > del_size) {
|
||||
@@ -3010,16 +1964,6 @@ bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
|
||||
txt_pop_sel(text);
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
/* Should probably create a new op for this */
|
||||
if (!undoing) {
|
||||
txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
|
||||
text->curc -= add_size;
|
||||
txt_pop_sel(text);
|
||||
txt_undo_add_charop(text, utxt, UNDO_DEL_1, del);
|
||||
text->curc += add_size;
|
||||
txt_pop_sel(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3098,26 +2042,14 @@ static void txt_select_prefix(Text *text, const char *add)
|
||||
*
|
||||
* \note caller must handle undo.
|
||||
*/
|
||||
static void txt_select_unprefix(Text *text,
|
||||
const char *remove,
|
||||
ListBase *r_line_index_mask,
|
||||
int *r_line_index_mask_len)
|
||||
static void txt_select_unprefix(Text *text, const char *remove)
|
||||
{
|
||||
int num = 0;
|
||||
const int indentlen = strlen(remove);
|
||||
bool unindented_first = false;
|
||||
|
||||
int curl_span_init = 0;
|
||||
|
||||
BLI_assert(!ELEM(NULL, text->curl, text->sell));
|
||||
|
||||
BLI_listbase_clear(r_line_index_mask);
|
||||
*r_line_index_mask_len = 0;
|
||||
|
||||
if (!undoing) {
|
||||
curl_span_init = txt_get_span(text->lines.first, text->curl);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
bool changed = false;
|
||||
if (STREQLEN(text->curl->line, remove, indentlen)) {
|
||||
@@ -3128,16 +2060,6 @@ static void txt_select_unprefix(Text *text,
|
||||
memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (!undoing) {
|
||||
/* Create list element for 0 indent line */
|
||||
struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
|
||||
idata->value = curl_span_init + num;
|
||||
BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
|
||||
BLI_addtail(r_line_index_mask, idata);
|
||||
(*r_line_index_mask_len) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
@@ -3166,7 +2088,7 @@ static void txt_select_unprefix(Text *text,
|
||||
/* caller must handle undo */
|
||||
}
|
||||
|
||||
void txt_comment(Text *text, TextUndoBuf *utxt)
|
||||
void txt_comment(Text *text)
|
||||
{
|
||||
const char *prefix = "#";
|
||||
|
||||
@@ -3175,32 +2097,20 @@ void txt_comment(Text *text, TextUndoBuf *utxt)
|
||||
}
|
||||
|
||||
txt_select_prefix(text, prefix);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_op(text, utxt, UNDO_COMMENT);
|
||||
}
|
||||
}
|
||||
|
||||
void txt_uncomment(Text *text, TextUndoBuf *utxt)
|
||||
void txt_uncomment(Text *text)
|
||||
{
|
||||
const char *prefix = "#";
|
||||
ListBase line_index_mask;
|
||||
int line_index_mask_len;
|
||||
|
||||
if (ELEM(NULL, text->curl, text->sell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
|
||||
}
|
||||
|
||||
BLI_freelistN(&line_index_mask);
|
||||
txt_select_unprefix(text, prefix);
|
||||
}
|
||||
|
||||
void txt_indent(Text *text, TextUndoBuf *utxt)
|
||||
void txt_indent(Text *text)
|
||||
{
|
||||
const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
|
||||
|
||||
@@ -3209,32 +2119,20 @@ void txt_indent(Text *text, TextUndoBuf *utxt)
|
||||
}
|
||||
|
||||
txt_select_prefix(text, prefix);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_op(text, utxt, UNDO_INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
void txt_unindent(Text *text, TextUndoBuf *utxt)
|
||||
void txt_unindent(Text *text)
|
||||
{
|
||||
const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
|
||||
ListBase line_index_mask;
|
||||
int line_index_mask_len;
|
||||
|
||||
if (ELEM(NULL, text->curl, text->sell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
|
||||
}
|
||||
|
||||
BLI_freelistN(&line_index_mask);
|
||||
txt_select_unprefix(text, prefix);
|
||||
}
|
||||
|
||||
void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction)
|
||||
void txt_move_lines(struct Text *text, const int direction)
|
||||
{
|
||||
TextLine *line_other;
|
||||
|
||||
@@ -3263,11 +2161,6 @@ void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction)
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
if (!undoing) {
|
||||
txt_undo_add_op(
|
||||
text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
|
||||
}
|
||||
}
|
||||
|
||||
int txt_setcurr_tab_spaces(Text *text, int space)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
struct ARegion;
|
||||
struct SpaceText;
|
||||
struct TextUndoBuf;
|
||||
struct UndoStep;
|
||||
struct UndoType;
|
||||
|
||||
bool ED_text_region_location_from_cursor(struct SpaceText *st,
|
||||
@@ -37,6 +37,6 @@ bool ED_text_region_location_from_cursor(struct SpaceText *st,
|
||||
/* text_undo.c */
|
||||
void ED_text_undosys_type(struct UndoType *ut);
|
||||
|
||||
struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C);
|
||||
struct UndoStep *ED_text_undo_push_init(struct bContext *C);
|
||||
|
||||
#endif /* __ED_TEXT_H__ */
|
||||
|
||||
@@ -1052,8 +1052,7 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
|
||||
|
||||
if (str) {
|
||||
TextUndoBuf *utxt = NULL; // FIXME
|
||||
BKE_text_write(txt, utxt, str);
|
||||
BKE_text_write(txt, str);
|
||||
MEM_freeN(str);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
@@ -260,7 +260,7 @@ static void get_suggest_prefix(Text *text, int offset)
|
||||
texttool_suggest_prefix(line + i, len);
|
||||
}
|
||||
|
||||
static void confirm_suggestion(Text *text, TextUndoBuf *utxt)
|
||||
static void confirm_suggestion(Text *text)
|
||||
{
|
||||
SuggItem *sel;
|
||||
int i, over = 0;
|
||||
@@ -285,7 +285,7 @@ static void confirm_suggestion(Text *text, TextUndoBuf *utxt)
|
||||
// for (i = 0; i < skipleft; i++)
|
||||
// txt_move_left(text, 0);
|
||||
BLI_assert(memcmp(sel->name, &line[i], over) == 0);
|
||||
txt_insert_buf(text, utxt, sel->name + over);
|
||||
txt_insert_buf(text, sel->name + over);
|
||||
|
||||
// for (i = 0; i < skipleft; i++)
|
||||
// txt_move_right(text, 0);
|
||||
@@ -308,8 +308,8 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent *
|
||||
ED_area_tag_redraw(CTX_wm_area(C));
|
||||
|
||||
if (texttool_suggest_first() == texttool_suggest_last()) {
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text, utxt);
|
||||
ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text);
|
||||
text_update_line_edited(st->text->curl);
|
||||
text_autocomplete_free(C, op);
|
||||
ED_undo_push(C, op->type->name);
|
||||
@@ -371,8 +371,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
|
||||
case MIDDLEMOUSE:
|
||||
if (event->val == KM_PRESS) {
|
||||
if (text_do_suggest_select(st, ar)) {
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text, utxt);
|
||||
ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text);
|
||||
text_update_line_edited(st->text->curl);
|
||||
ED_undo_push(C, op->type->name);
|
||||
swallow = 1;
|
||||
@@ -410,8 +410,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
|
||||
case PADENTER:
|
||||
if (event->val == KM_PRESS) {
|
||||
if (tools & TOOL_SUGG_LIST) {
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text, utxt);
|
||||
ED_text_undo_push_init(C);
|
||||
confirm_suggestion(st->text);
|
||||
text_update_line_edited(st->text->curl);
|
||||
ED_undo_push(C, op->type->name);
|
||||
swallow = 1;
|
||||
|
||||
@@ -840,7 +840,7 @@ static int text_paste_exec(bContext *C, wmOperator *op)
|
||||
|
||||
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
/* Convert clipboard content indentation to spaces if specified */
|
||||
if (text->flags & TXT_TABSTOSPACES) {
|
||||
@@ -849,7 +849,7 @@ static int text_paste_exec(bContext *C, wmOperator *op)
|
||||
buf = new_buf;
|
||||
}
|
||||
|
||||
txt_insert_buf(text, utxt, buf);
|
||||
txt_insert_buf(text, buf);
|
||||
text_update_edited(text);
|
||||
|
||||
MEM_freeN(buf);
|
||||
@@ -893,9 +893,9 @@ static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Text *text = CTX_data_edit_text(C);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
txt_duplicate_line(text, utxt);
|
||||
txt_duplicate_line(text);
|
||||
|
||||
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
|
||||
|
||||
@@ -971,8 +971,8 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
txt_copy_clipboard(text);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
txt_delete_selected(text, utxt);
|
||||
ED_text_undo_push_init(C);
|
||||
txt_delete_selected(text);
|
||||
|
||||
text_update_cursor_moved(C);
|
||||
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
|
||||
@@ -1008,14 +1008,14 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
if (txt_has_sel(text)) {
|
||||
txt_order_cursors(text, false);
|
||||
txt_indent(text, utxt);
|
||||
txt_indent(text);
|
||||
}
|
||||
else {
|
||||
txt_add_char(text, utxt, '\t');
|
||||
txt_add_char(text, '\t');
|
||||
}
|
||||
|
||||
text_update_edited(text);
|
||||
@@ -1049,10 +1049,10 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
txt_order_cursors(text, false);
|
||||
txt_unindent(text, utxt);
|
||||
txt_unindent(text);
|
||||
|
||||
text_update_edited(text);
|
||||
|
||||
@@ -1090,15 +1090,15 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
// double check tabs/spaces before splitting the line
|
||||
curts = txt_setcurr_tab_spaces(text, space);
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
txt_split_curline(text, utxt);
|
||||
ED_text_undo_push_init(C);
|
||||
txt_split_curline(text);
|
||||
|
||||
for (a = 0; a < curts; a++) {
|
||||
if (text->flags & TXT_TABSTOSPACES) {
|
||||
txt_add_char(text, utxt, ' ');
|
||||
txt_add_char(text, ' ');
|
||||
}
|
||||
else {
|
||||
txt_add_char(text, utxt, '\t');
|
||||
txt_add_char(text, '\t');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1139,10 +1139,10 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
if (txt_has_sel(text)) {
|
||||
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
txt_order_cursors(text, false);
|
||||
txt_comment(text, utxt);
|
||||
txt_comment(text);
|
||||
text_update_edited(text);
|
||||
|
||||
text_update_cursor_moved(C);
|
||||
@@ -1177,10 +1177,10 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
if (txt_has_sel(text)) {
|
||||
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
txt_order_cursors(text, false);
|
||||
txt_uncomment(text, utxt);
|
||||
txt_uncomment(text);
|
||||
text_update_edited(text);
|
||||
|
||||
text_update_cursor_moved(C);
|
||||
@@ -1446,9 +1446,9 @@ static int move_lines_exec(bContext *C, wmOperator *op)
|
||||
Text *text = CTX_data_edit_text(C);
|
||||
const int direction = RNA_enum_get(op->ptr, "direction");
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
txt_move_lines(text, utxt, direction);
|
||||
txt_move_lines(text, direction);
|
||||
|
||||
text_update_cursor_moved(C);
|
||||
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
|
||||
@@ -2230,13 +2230,13 @@ static int text_delete_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
if (type == DEL_PREV_WORD) {
|
||||
if (txt_cursor_is_line_start(text)) {
|
||||
txt_backspace_char(text, utxt);
|
||||
txt_backspace_char(text);
|
||||
}
|
||||
txt_backspace_word(text, utxt);
|
||||
txt_backspace_word(text);
|
||||
}
|
||||
else if (type == DEL_PREV_CHAR) {
|
||||
|
||||
@@ -2252,13 +2252,13 @@ static int text_delete_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
txt_backspace_char(text, utxt);
|
||||
txt_backspace_char(text);
|
||||
}
|
||||
else if (type == DEL_NEXT_WORD) {
|
||||
if (txt_cursor_is_line_end(text)) {
|
||||
txt_delete_char(text, utxt);
|
||||
txt_delete_char(text);
|
||||
}
|
||||
txt_delete_word(text, utxt);
|
||||
txt_delete_word(text);
|
||||
}
|
||||
else if (type == DEL_NEXT_CHAR) {
|
||||
|
||||
@@ -2274,7 +2274,7 @@ static int text_delete_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
txt_delete_char(text, utxt);
|
||||
txt_delete_char(text);
|
||||
}
|
||||
|
||||
text_update_line_edited(text->curl);
|
||||
@@ -3190,18 +3190,18 @@ static int text_insert_exec(bContext *C, wmOperator *op)
|
||||
|
||||
str = RNA_string_get_alloc(op->ptr, "text", NULL, 0);
|
||||
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
ED_text_undo_push_init(C);
|
||||
|
||||
if (st && st->overwrite) {
|
||||
while (str[i]) {
|
||||
code = BLI_str_utf8_as_unicode_step(str, &i);
|
||||
done |= txt_replace_char(text, utxt, code);
|
||||
done |= txt_replace_char(text, code);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (str[i]) {
|
||||
code = BLI_str_utf8_as_unicode_step(str, &i);
|
||||
done |= txt_add_char(text, utxt, code);
|
||||
done |= txt_add_char(text, code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3319,8 +3319,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
|
||||
|
||||
if (found) {
|
||||
if (mode == TEXT_REPLACE) {
|
||||
TextUndoBuf *utxt = ED_text_undo_push_init(C);
|
||||
txt_insert_buf(text, utxt, st->replacestr);
|
||||
ED_text_undo_push_init(C);
|
||||
txt_insert_buf(text, st->replacestr);
|
||||
if (text->curl && text->curl->format) {
|
||||
MEM_freeN(text->curl->format);
|
||||
text->curl->format = NULL;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "DNA_text_types.h"
|
||||
|
||||
#include "BLI_array_store.h"
|
||||
#include "BLI_array_utils.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_text.h"
|
||||
#include "BKE_undo_system.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
@@ -53,18 +55,32 @@
|
||||
#include "text_intern.h"
|
||||
#include "text_format.h"
|
||||
|
||||
/* TODO(campbell): undo_system: move text undo out of text block. */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Implements ED Undo System
|
||||
* \{ */
|
||||
|
||||
#define ARRAY_CHUNK_SIZE 128
|
||||
|
||||
typedef struct TextUndoStep {
|
||||
UndoStep step;
|
||||
UndoRefID_Text text_ref;
|
||||
TextUndoBuf data;
|
||||
struct {
|
||||
BArrayState *state;
|
||||
int buf_len;
|
||||
} data;
|
||||
|
||||
struct {
|
||||
int line, line_select;
|
||||
int column, column_select;
|
||||
} cursor;
|
||||
|
||||
} TextUndoStep;
|
||||
|
||||
static struct {
|
||||
BArrayStore *buffer_store;
|
||||
int users;
|
||||
} g_text_buffers = {NULL};
|
||||
|
||||
static bool text_undosys_poll(bContext *UNUSED(C))
|
||||
{
|
||||
/* Only use when operators initialized. */
|
||||
@@ -77,12 +93,8 @@ static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
|
||||
TextUndoStep *us = (TextUndoStep *)us_p;
|
||||
BLI_assert(BLI_array_is_zeroed(&us->data, 1));
|
||||
|
||||
UNUSED_VARS(C);
|
||||
UNUSED_VARS(C, us);
|
||||
/* XXX, use to set the undo type only. */
|
||||
|
||||
us->data.buf = NULL;
|
||||
us->data.len = 0;
|
||||
us->data.pos = -1;
|
||||
}
|
||||
|
||||
static bool text_undosys_step_encode(struct bContext *C,
|
||||
@@ -93,104 +105,66 @@ static bool text_undosys_step_encode(struct bContext *C,
|
||||
|
||||
Text *text = CTX_data_edit_text(C);
|
||||
|
||||
/* No undo data was generated. Hint, use global undo here. */
|
||||
if ((us->data.pos == -1) || (us->data.buf == NULL)) {
|
||||
return false;
|
||||
int buf_len = 0;
|
||||
|
||||
uchar *buf = (uchar *)txt_to_buf_for_undo(text, &buf_len);
|
||||
if (g_text_buffers.buffer_store == NULL) {
|
||||
g_text_buffers.buffer_store = BLI_array_store_create(1, ARRAY_CHUNK_SIZE);
|
||||
}
|
||||
g_text_buffers.users += 1;
|
||||
const size_t total_size_prev = BLI_array_store_calc_size_compacted_get(
|
||||
g_text_buffers.buffer_store);
|
||||
|
||||
us->data.state = BLI_array_store_state_add(g_text_buffers.buffer_store, buf, buf_len, NULL);
|
||||
MEM_freeN(buf);
|
||||
|
||||
us->cursor.line = txt_get_span(text->lines.first, text->curl);
|
||||
us->cursor.column = text->curc;
|
||||
|
||||
if (txt_has_sel(text)) {
|
||||
us->cursor.line_select = (text->curl == text->sell) ?
|
||||
us->cursor.line :
|
||||
txt_get_span(text->lines.first, text->sell);
|
||||
us->cursor.column_select = text->selc;
|
||||
}
|
||||
else {
|
||||
us->cursor.line_select = us->cursor.line;
|
||||
us->cursor.column_select = us->cursor.column;
|
||||
}
|
||||
|
||||
us_p->is_applied = true;
|
||||
|
||||
us->text_ref.ptr = text;
|
||||
|
||||
us->step.data_size = us->data.len;
|
||||
us->step.data_size = BLI_array_store_calc_size_compacted_get(g_text_buffers.buffer_store) -
|
||||
total_size_prev;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void text_undosys_step_decode_undo_impl(Text *text, TextUndoStep *us)
|
||||
{
|
||||
BLI_assert(us->step.is_applied == true);
|
||||
TextUndoBuf data = us->data;
|
||||
while (data.pos > -1) {
|
||||
txt_do_undo(text, &data);
|
||||
}
|
||||
BLI_assert(data.pos == -1);
|
||||
us->step.is_applied = false;
|
||||
}
|
||||
|
||||
static void text_undosys_step_decode_redo_impl(Text *text, TextUndoStep *us)
|
||||
{
|
||||
BLI_assert(us->step.is_applied == false);
|
||||
TextUndoBuf data = us->data;
|
||||
data.pos = -1;
|
||||
while (data.pos < us->data.pos) {
|
||||
txt_do_redo(text, &data);
|
||||
}
|
||||
BLI_assert(data.pos == us->data.pos);
|
||||
us->step.is_applied = true;
|
||||
}
|
||||
|
||||
static void text_undosys_step_decode_undo(TextUndoStep *us, bool is_final)
|
||||
{
|
||||
TextUndoStep *us_iter = us;
|
||||
while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
|
||||
if (us_iter->step.next->is_applied == false) {
|
||||
break;
|
||||
}
|
||||
us_iter = (TextUndoStep *)us_iter->step.next;
|
||||
}
|
||||
Text *text_prev = NULL;
|
||||
while ((us_iter != us) || (is_final && us_iter == us)) {
|
||||
Text *text = us_iter->text_ref.ptr;
|
||||
text_undosys_step_decode_undo_impl(text, us_iter);
|
||||
if (text_prev != text) {
|
||||
text_update_edited(text);
|
||||
text_prev = text;
|
||||
}
|
||||
if (is_final) {
|
||||
break;
|
||||
}
|
||||
us_iter = (TextUndoStep *)us_iter->step.prev;
|
||||
}
|
||||
}
|
||||
|
||||
static void text_undosys_step_decode_redo(TextUndoStep *us)
|
||||
{
|
||||
TextUndoStep *us_iter = us;
|
||||
while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
|
||||
if (us_iter->step.prev->is_applied == true) {
|
||||
break;
|
||||
}
|
||||
us_iter = (TextUndoStep *)us_iter->step.prev;
|
||||
}
|
||||
Text *text_prev = NULL;
|
||||
while (us_iter && (us_iter->step.is_applied == false)) {
|
||||
Text *text = us_iter->text_ref.ptr;
|
||||
text_undosys_step_decode_redo_impl(text, us_iter);
|
||||
if (text_prev != text) {
|
||||
text_update_edited(text);
|
||||
text_prev = text;
|
||||
}
|
||||
if (us_iter == us) {
|
||||
break;
|
||||
}
|
||||
us_iter = (TextUndoStep *)us_iter->step.next;
|
||||
}
|
||||
}
|
||||
|
||||
static void text_undosys_step_decode(
|
||||
struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int dir, bool is_final)
|
||||
static void text_undosys_step_decode(struct bContext *C,
|
||||
struct Main *UNUSED(bmain),
|
||||
UndoStep *us_p,
|
||||
int UNUSED(dir),
|
||||
bool UNUSED(is_final))
|
||||
{
|
||||
TextUndoStep *us = (TextUndoStep *)us_p;
|
||||
|
||||
if (dir < 0) {
|
||||
text_undosys_step_decode_undo(us, is_final);
|
||||
}
|
||||
else {
|
||||
text_undosys_step_decode_redo(us);
|
||||
}
|
||||
|
||||
Text *text = us->text_ref.ptr;
|
||||
size_t buf_len;
|
||||
|
||||
{
|
||||
const uchar *buf = BLI_array_store_state_data_get_alloc(us->data.state, &buf_len);
|
||||
txt_from_buf_for_undo(text, (const char *)buf, buf_len);
|
||||
MEM_freeN((void *)buf);
|
||||
}
|
||||
|
||||
const bool has_select = ((us->cursor.line != us->cursor.line_select) ||
|
||||
(us->cursor.column != us->cursor.column_select));
|
||||
if (has_select) {
|
||||
txt_move_to(text, us->cursor.line_select, us->cursor.column_select, false);
|
||||
}
|
||||
txt_move_to(text, us->cursor.line, us->cursor.column, has_select);
|
||||
|
||||
SpaceText *st = CTX_wm_space_text(C);
|
||||
if (st) {
|
||||
/* Not essential, always show text being undo where possible. */
|
||||
@@ -204,7 +178,14 @@ static void text_undosys_step_decode(
|
||||
static void text_undosys_step_free(UndoStep *us_p)
|
||||
{
|
||||
TextUndoStep *us = (TextUndoStep *)us_p;
|
||||
MEM_SAFE_FREE(us->data.buf);
|
||||
|
||||
BLI_array_store_state_remove(g_text_buffers.buffer_store, us->data.state);
|
||||
|
||||
g_text_buffers.users -= 1;
|
||||
if (g_text_buffers.users == 0) {
|
||||
BLI_array_store_destroy(g_text_buffers.buffer_store);
|
||||
g_text_buffers.buffer_store = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void text_undosys_foreach_ID_ref(UndoStep *us_p,
|
||||
@@ -240,12 +221,16 @@ void ED_text_undosys_type(UndoType *ut)
|
||||
* \{ */
|
||||
|
||||
/* Use operator system to finish the undo step. */
|
||||
TextUndoBuf *ED_text_undo_push_init(bContext *C)
|
||||
UndoStep *ED_text_undo_push_init(bContext *C)
|
||||
{
|
||||
UndoStack *ustack = ED_undo_stack_get();
|
||||
UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT);
|
||||
TextUndoStep *us = (TextUndoStep *)us_p;
|
||||
return &us->data;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm->op_undo_depth <= 1) {
|
||||
UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT);
|
||||
return us_p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -55,8 +55,6 @@ typedef struct Text {
|
||||
} Text;
|
||||
|
||||
#define TXT_TABSIZE 4
|
||||
#define TXT_INIT_UNDO 1024
|
||||
#define TXT_MAX_UNDO (TXT_INIT_UNDO * TXT_INIT_UNDO)
|
||||
|
||||
/* text flags */
|
||||
enum {
|
||||
|
||||
@@ -34,13 +34,13 @@
|
||||
|
||||
static void rna_Text_clear(Text *text)
|
||||
{
|
||||
BKE_text_clear(text, NULL);
|
||||
BKE_text_clear(text);
|
||||
WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
|
||||
}
|
||||
|
||||
static void rna_Text_write(Text *text, const char *str)
|
||||
{
|
||||
BKE_text_write(text, NULL, str);
|
||||
BKE_text_write(text, str);
|
||||
WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user