Blender  V3.3
text_undo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <errno.h>
8 #include <string.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_text_types.h"
13 
14 #include "BLI_array_store.h"
15 #include "BLI_array_utils.h"
16 
17 #include "BLT_translation.h"
18 
19 #include "PIL_time.h"
20 
21 #include "BKE_context.h"
22 #include "BKE_main.h"
23 #include "BKE_report.h"
24 #include "BKE_text.h"
25 #include "BKE_undo_system.h"
26 
27 #include "WM_api.h"
28 #include "WM_types.h"
29 
30 #include "ED_curve.h"
31 #include "ED_screen.h"
32 #include "ED_text.h"
33 #include "ED_undo.h"
34 
35 #include "UI_interface.h"
36 #include "UI_resources.h"
37 
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40 
41 #include "text_format.h"
42 #include "text_intern.h"
43 
44 /* -------------------------------------------------------------------- */
48 #define ARRAY_CHUNK_SIZE 128
49 
53 typedef struct TextState {
55 
59 
61 {
62  size_t buf_len = 0;
63  uchar *buf = (uchar *)txt_to_buf_for_undo(text, &buf_len);
64  state->buf_array_state = BLI_array_store_state_add(buffer_store, buf, buf_len, NULL);
65  MEM_freeN(buf);
66 
67  state->cursor_line = txt_get_span(text->lines.first, text->curl);
68  state->cursor_column = text->curc;
69 
70  if (txt_has_sel(text)) {
71  state->cursor_line_select = (text->curl == text->sell) ?
72  state->cursor_line :
73  txt_get_span(text->lines.first, text->sell);
74  state->cursor_column_select = text->selc;
75  }
76  else {
77  state->cursor_line_select = state->cursor_line;
78  state->cursor_column_select = state->cursor_column;
79  }
80 }
81 
82 static void text_state_decode(TextState *state, Text *text)
83 {
84  size_t buf_len;
85  {
86  const uchar *buf = BLI_array_store_state_data_get_alloc(state->buf_array_state, &buf_len);
87  txt_from_buf_for_undo(text, (const char *)buf, buf_len);
88  MEM_freeN((void *)buf);
89  }
90 
91  const bool has_select = ((state->cursor_line != state->cursor_line_select) ||
92  (state->cursor_column != state->cursor_column_select));
93  if (has_select) {
94  txt_move_to(text, state->cursor_line_select, state->cursor_column_select, false);
95  }
96  txt_move_to(text, state->cursor_line, state->cursor_column, has_select);
97 }
98 
101 /* -------------------------------------------------------------------- */
105 typedef struct TextUndoStep {
107  UndoRefID_Text text_ref;
114 
115 static struct {
117  int users;
119 
121 {
123  if (g_text_buffers.buffer_store == NULL) {
125  }
126  g_text_buffers.users += 1;
127  const size_t total_size_prev = BLI_array_store_calc_size_compacted_get(
128  g_text_buffers.buffer_store);
129 
130  text_state_encode(state, text, g_text_buffers.buffer_store);
131 
132  return BLI_array_store_calc_size_compacted_get(g_text_buffers.buffer_store) - total_size_prev;
133 }
134 
136 {
137  /* Only use when operators initialized. */
138  UndoStack *ustack = ED_undo_stack_get();
139  return (ustack->step_init && (ustack->step_init->type == BKE_UNDOSYS_TYPE_TEXT));
140 }
141 
143 {
144  TextUndoStep *us = (TextUndoStep *)us_p;
146 
147  Text *text = CTX_data_edit_text(C);
148 
149  /* Avoid writing the initial state where possible,
150  * failing to do this won't cause bugs, it's just inefficient. */
151  bool write_init = true;
152  UndoStack *ustack = ED_undo_stack_get();
153  if (ustack->step_active) {
154  if (ustack->step_active->type == BKE_UNDOSYS_TYPE_TEXT) {
155  TextUndoStep *us_active = (TextUndoStep *)ustack->step_active;
156  if (STREQ(text->id.name, us_active->text_ref.name)) {
157  write_init = false;
158  }
159  }
160  }
161 
162  if (write_init) {
164  }
165  us->text_ref.ptr = text;
166 }
167 
168 static bool text_undosys_step_encode(struct bContext *C,
169  struct Main *UNUSED(bmain),
170  UndoStep *us_p)
171 {
172  TextUndoStep *us = (TextUndoStep *)us_p;
173 
174  Text *text = us->text_ref.ptr;
175  BLI_assert(text == CTX_data_edit_text(C));
177 
179 
180  us_p->is_applied = true;
181 
182  return true;
183 }
184 
185 static void text_undosys_step_decode(struct bContext *C,
186  struct Main *UNUSED(bmain),
187  UndoStep *us_p,
188  const eUndoStepDir dir,
189  bool is_final)
190 {
191  BLI_assert(dir != STEP_INVALID);
192 
193  TextUndoStep *us = (TextUndoStep *)us_p;
194  Text *text = us->text_ref.ptr;
195 
196  TextState *state;
197  if ((us->states[0].buf_array_state != NULL) && (dir == STEP_UNDO) && !is_final) {
198  state = &us->states[0];
199  }
200  else {
201  state = &us->states[1];
202  }
203 
204  text_state_decode(state, text);
205 
207  if (st) {
208  /* Not essential, always show text being undo where possible. */
209  st->text = text;
210  }
214 }
215 
217 {
218  TextUndoStep *us = (TextUndoStep *)us_p;
219 
220  for (int i = 0; i < ARRAY_SIZE(us->states); i++) {
221  TextState *state = &us->states[i];
222  if (state->buf_array_state) {
223  BLI_array_store_state_remove(g_text_buffers.buffer_store, state->buf_array_state);
224  g_text_buffers.users -= 1;
225  if (g_text_buffers.users == 0) {
227  g_text_buffers.buffer_store = NULL;
228  }
229  }
230  }
231 }
232 
234  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
235  void *user_data)
236 {
237  TextUndoStep *us = (TextUndoStep *)us_p;
238  foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
239 }
240 
242 {
243  ut->name = "Text";
244  ut->poll = text_undosys_poll;
249 
251 
253 
254  ut->step_size = sizeof(TextUndoStep);
255 }
256 
259 /* -------------------------------------------------------------------- */
264 {
265  UndoStack *ustack = ED_undo_stack_get();
266  Main *bmain = CTX_data_main(C);
267  wmWindowManager *wm = bmain->wm.first;
268  if (wm->op_undo_depth <= 1) {
270  return us_p;
271  }
272  return NULL;
273 }
274 
struct SpaceText * CTX_wm_space_text(const bContext *C)
Definition: context.c:806
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct Text * CTX_data_edit_text(const bContext *C)
Definition: context.c:1380
void txt_from_buf_for_undo(struct Text *text, const char *buf, size_t buf_len) ATTR_NONNULL(1
bool txt_has_sel(const struct Text *text)
int txt_get_span(struct TextLine *from, struct TextLine *to)
Definition: text.c:676
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel)
Definition: text.c:1096
char * txt_to_buf_for_undo(struct Text *text, size_t *r_buf_len) ATTR_NONNULL(1
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut)
Definition: undo_system.c:449
eUndoStepDir
@ STEP_INVALID
@ STEP_UNDO
const UndoType * BKE_UNDOSYS_TYPE_TEXT
Definition: undo_system.c:58
void(* UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref)
Efficient in-memory storage of multiple similar arrays.
void * BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
Definition: array_store.c:1580
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
Definition: array_store.c:1545
BArrayStore * BLI_array_store_create(unsigned int stride, unsigned int chunk_count)
Definition: array_store.c:1388
BArrayState * BLI_array_store_state_add(BArrayStore *bs, const void *data, size_t data_len, const BArrayState *state_reference)
Definition: array_store.c:1497
void BLI_array_store_destroy(BArrayStore *bs)
Definition: array_store.c:1441
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
Definition: array_store.c:1478
Generic array manipulation API.
#define BLI_array_is_zeroed(arr, arr_len)
#define BLI_assert(a)
Definition: BLI_assert.h:46
unsigned char uchar
Definition: BLI_sys_types.h:70
#define ARRAY_SIZE(arr)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define STREQ(a, b)
struct UndoStack * ED_undo_stack_get(void)
Definition: ed_undo.c:473
Read Guarded memory(de)allocation.
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
#define NA_EDITED
Definition: WM_types.h:523
#define NC_TEXT
Definition: WM_types.h:336
void * user_data
const int state
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase wm
Definition: BKE_main.h:197
int cursor_line
Definition: text_undo.c:56
int cursor_column
Definition: text_undo.c:57
BArrayState * buf_array_state
Definition: text_undo.c:54
int cursor_line_select
Definition: text_undo.c:56
int cursor_column_select
Definition: text_undo.c:57
TextState states[2]
Definition: text_undo.c:112
UndoRefID_Text text_ref
Definition: text_undo.c:107
UndoStep step
Definition: text_undo.c:106
ListBase lines
TextLine * curl
int selc
TextLine * sell
int curc
struct UndoStep * step_active
struct UndoStep * step_init
const struct UndoType * type
bool is_applied
size_t data_size
size_t step_size
void(* step_decode)(struct bContext *C, struct Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us)
void(* step_encode_init)(struct bContext *C, UndoStep *us)
void(* step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
const char * name
void(* step_free)(UndoStep *us)
bool(* poll)(struct bContext *C)
void text_update_cursor_moved(struct bContext *C)
void text_drawcache_tag_update(struct SpaceText *st, int full)
static void text_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
Definition: text_undo.c:233
static void text_state_encode(TextState *state, Text *text, BArrayStore *buffer_store)
Definition: text_undo.c:60
static bool text_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
Definition: text_undo.c:168
void ED_text_undosys_type(UndoType *ut)
Definition: text_undo.c:241
static struct @558 g_text_buffers
#define ARRAY_CHUNK_SIZE
Definition: text_undo.c:48
static bool text_undosys_poll(bContext *UNUSED(C))
Definition: text_undo.c:135
static size_t text_undosys_step_encode_to_state(TextState *state, Text *text)
Definition: text_undo.c:120
static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
Definition: text_undo.c:142
static void text_undosys_step_free(UndoStep *us_p)
Definition: text_undo.c:216
struct TextUndoStep TextUndoStep
static void text_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, const eUndoStepDir dir, bool is_final)
Definition: text_undo.c:185
UndoStep * ED_text_undo_push_init(bContext *C)
Definition: text_undo.c:263
int users
Definition: text_undo.c:117
BArrayStore * buffer_store
Definition: text_undo.c:116
static void text_state_decode(TextState *state, Text *text)
Definition: text_undo.c:82
struct TextState TextState
void WM_event_add_notifier(const bContext *C, uint type, void *reference)