Blender V4.3
text_undo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cerrno>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_text_types.h"
15
16#include "BLI_array_store.h"
17#include "BLI_array_utils.h" /* For `BLI_array_is_zeroed`. */
18
19#include "BKE_context.hh"
20#include "BKE_main.hh"
21#include "BKE_text.h"
22#include "BKE_undo_system.hh"
23
24#include "WM_api.hh"
25#include "WM_types.hh"
26
27#include "ED_screen.hh"
28#include "ED_text.hh"
29#include "ED_undo.hh"
30
31#include "text_intern.hh"
32
33/* -------------------------------------------------------------------- */
37#define ARRAY_CHUNK_SIZE 128
38
48
50{
51 size_t buf_len = 0;
52 uchar *buf = (uchar *)txt_to_buf_for_undo(text, &buf_len);
53 state->buf_array_state = BLI_array_store_state_add(buffer_store, buf, buf_len, nullptr);
54 MEM_freeN(buf);
55
56 state->cursor_line = txt_get_span(static_cast<TextLine *>(text->lines.first), text->curl);
57 state->cursor_column = text->curc;
58
59 if (txt_has_sel(text)) {
60 state->cursor_line_select = (text->curl == text->sell) ?
61 state->cursor_line :
62 txt_get_span(static_cast<TextLine *>(text->lines.first),
63 text->sell);
64 state->cursor_column_select = text->selc;
65 }
66 else {
67 state->cursor_line_select = state->cursor_line;
68 state->cursor_column_select = state->cursor_column;
69 }
70}
71
73{
74 size_t buf_len;
75 {
76 const uchar *buf = static_cast<const uchar *>(
77 BLI_array_store_state_data_get_alloc(state->buf_array_state, &buf_len));
78 txt_from_buf_for_undo(text, (const char *)buf, buf_len);
79 MEM_freeN((void *)buf);
80 }
81
82 const bool has_select = ((state->cursor_line != state->cursor_line_select) ||
83 (state->cursor_column != state->cursor_column_select));
84 if (has_select) {
85 txt_move_to(text, state->cursor_line_select, state->cursor_column_select, false);
86 }
87 txt_move_to(text, state->cursor_line, state->cursor_column, has_select);
88}
89
92/* -------------------------------------------------------------------- */
98 UndoRefID_Text text_ref;
104};
105
106static struct {
108 int users;
109} g_text_buffers = {nullptr};
110
112{
114 if (g_text_buffers.buffer_store == nullptr) {
116 }
117 g_text_buffers.users += 1;
118 const size_t total_size_prev = BLI_array_store_calc_size_compacted_get(
119 g_text_buffers.buffer_store);
120
121 text_state_encode(state, text, g_text_buffers.buffer_store);
122
123 return BLI_array_store_calc_size_compacted_get(g_text_buffers.buffer_store) - total_size_prev;
124}
125
126static bool text_undosys_poll(bContext * /*C*/)
127{
128 /* Only use when operators initialized. */
129 UndoStack *ustack = ED_undo_stack_get();
130 return (ustack->step_init && (ustack->step_init->type == BKE_UNDOSYS_TYPE_TEXT));
131}
132
134{
135 TextUndoStep *us = (TextUndoStep *)us_p;
137
138 Text *text = CTX_data_edit_text(C);
139
140 /* Avoid writing the initial state where possible,
141 * failing to do this won't cause bugs, it's just inefficient. */
142 bool write_init = true;
143 UndoStack *ustack = ED_undo_stack_get();
144 if (ustack->step_active) {
145 if (ustack->step_active->type == BKE_UNDOSYS_TYPE_TEXT) {
146 TextUndoStep *us_active = (TextUndoStep *)ustack->step_active;
147 if (STREQ(text->id.name, us_active->text_ref.name)) {
148 write_init = false;
149 }
150 }
151 }
152
153 if (write_init) {
155 }
156 us->text_ref.ptr = text;
157}
158
159static bool text_undosys_step_encode(bContext *C, Main * /*bmain*/, UndoStep *us_p)
160{
161 TextUndoStep *us = (TextUndoStep *)us_p;
162
163 Text *text = us->text_ref.ptr;
164 BLI_assert(text == CTX_data_edit_text(C));
166
168
169 us_p->is_applied = true;
170
171 return true;
172}
173
175 bContext *C, Main * /*bmain*/, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
176{
177 BLI_assert(dir != STEP_INVALID);
178
179 TextUndoStep *us = (TextUndoStep *)us_p;
180 Text *text = us->text_ref.ptr;
181
183 if ((us->states[0].buf_array_state != nullptr) && (dir == STEP_UNDO) && !is_final) {
184 state = &us->states[0];
185 }
186 else {
187 state = &us->states[1];
188 }
189
191
193 if (st) {
194 /* Not essential, always show text being undo where possible. */
195 st->text = text;
196 }
200}
201
203{
204 TextUndoStep *us = (TextUndoStep *)us_p;
205
206 for (int i = 0; i < ARRAY_SIZE(us->states); i++) {
207 TextState *state = &us->states[i];
208 if (state->buf_array_state) {
209 BLI_array_store_state_remove(g_text_buffers.buffer_store, state->buf_array_state);
210 g_text_buffers.users -= 1;
211 if (g_text_buffers.users == 0) {
213 g_text_buffers.buffer_store = nullptr;
214 }
215 }
216 }
217}
218
220 UndoTypeForEachIDRefFn foreach_ID_ref_fn,
221 void *user_data)
222{
223 TextUndoStep *us = (TextUndoStep *)us_p;
224 foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
225}
226
242
245/* -------------------------------------------------------------------- */
250{
251 UndoStack *ustack = ED_undo_stack_get();
252 Main *bmain = CTX_data_main(C);
253 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
254 if (wm->op_undo_depth <= 1) {
256 ustack, C, nullptr, BKE_UNDOSYS_TYPE_TEXT);
257 return us_p;
258 }
259 return nullptr;
260}
261
SpaceText * CTX_wm_space_text(const bContext *C)
Text * CTX_data_edit_text(const bContext *C)
Main * CTX_data_main(const bContext *C)
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)
char * txt_to_buf_for_undo(struct Text *text, size_t *r_buf_len) ATTR_NONNULL(1
int txt_get_span(const struct TextLine *from, const struct TextLine *to)
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel)
Definition text.cc:1099
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
void(*)(void *user_data, UndoRefID *id_ref) UndoTypeForEachIDRefFn
eUndoStepDir
@ STEP_INVALID
@ STEP_UNDO
const UndoType * BKE_UNDOSYS_TYPE_TEXT
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
Efficient in-memory storage of multiple similar arrays.
BArrayState * BLI_array_store_state_add(BArrayStore *bs, const void *data, size_t data_len, const BArrayState *state_reference)
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
void * BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
void BLI_array_store_destroy(BArrayStore *bs)
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
BArrayStore * BLI_array_store_create(unsigned int stride, unsigned int chunk_count)
Generic array manipulation API.
#define BLI_array_is_zeroed(arr, arr_len)
#define BLI_assert(a)
Definition BLI_assert.h:50
unsigned char uchar
#define ARRAY_SIZE(arr)
#define UNUSED_VARS_NDEBUG(...)
#define STREQ(a, b)
UndoStack * ED_undo_stack_get()
Definition ed_undo.cc:455
Read Guarded memory(de)allocation.
#define NA_EDITED
Definition WM_types.hh:550
#define NC_TEXT
Definition WM_types.hh:353
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static ulong state[N]
void * first
ListBase wm
Definition BKE_main.hh:239
struct Text * text
int cursor_line
Definition text_undo.cc:45
int cursor_column
Definition text_undo.cc:46
BArrayState * buf_array_state
Definition text_undo.cc:43
int cursor_line_select
Definition text_undo.cc:45
int cursor_column_select
Definition text_undo.cc:46
TextState states[2]
Definition text_undo.cc:103
UndoRefID_Text text_ref
Definition text_undo.cc:98
UndoStep step
Definition text_undo.cc:97
UndoStep * step_init
UndoStep * step_active
size_t data_size
const UndoType * type
void(* step_encode_init)(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(* step_decode)(bContext *C, Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(bContext *C, Main *bmain, UndoStep *us)
void space_text_drawcache_tag_update(SpaceText *st, bool full)
void space_text_update_cursor_moved(bContext *C)
static void text_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
Definition text_undo.cc:219
static void text_state_encode(TextState *state, Text *text, BArrayStore *buffer_store)
Definition text_undo.cc:49
void ED_text_undosys_type(UndoType *ut)
Definition text_undo.cc:227
static struct @528 g_text_buffers
#define ARRAY_CHUNK_SIZE
Definition text_undo.cc:37
static void text_undosys_step_encode_init(bContext *C, UndoStep *us_p)
Definition text_undo.cc:133
UndoStep * ED_text_undo_push_init(bContext *C)
Definition text_undo.cc:249
static bool text_undosys_poll(bContext *)
Definition text_undo.cc:126
static size_t text_undosys_step_encode_to_state(TextState *state, Text *text)
Definition text_undo.cc:111
static bool text_undosys_step_encode(bContext *C, Main *, UndoStep *us_p)
Definition text_undo.cc:159
static void text_undosys_step_free(UndoStep *us_p)
Definition text_undo.cc:202
static void text_undosys_step_decode(bContext *C, Main *, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
Definition text_undo.cc:174
int users
Definition text_undo.cc:108
BArrayStore * buffer_store
Definition text_undo.cc:107
static void text_state_decode(TextState *state, Text *text)
Definition text_undo.cc:72
void WM_event_add_notifier(const bContext *C, uint type, void *reference)