-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathundo.h
145 lines (128 loc) · 6.01 KB
/
undo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Copyright (C) 2015 Richard Burke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef WED_UNDO_H
#define WED_UNDO_H
#include <stddef.h>
#include "list.h"
#include "status.h"
#include "buffer_pos.h"
/* An unlimited linear undo/redo implementation */
/* All operations on the text in a buffer can be thought of
* as a sequence of insertions and deletions. That is, there are two
* base operations that are performed on a buffer from which
* all higher level operations derive. We can therefore
* track all changes to buffer text by tracking the insertions and deletions
* that take place and grouping them appropriately. */
/* The enum below is used to categorise a text change
* as either an insert or a delete */
typedef enum {
TCT_INSERT,
TCT_DELETE
} TextChangeType;
typedef struct TextChange TextChange;
/* The properties of a text change
* i.e. The properties of an insert or delete */
struct TextChange {
TextChangeType change_type; /* Insert or delete */
BufferPos pos; /* The position in the buffer where this change took place */
size_t str_len; /* The length of the text inserted or deleted */
char *str; /* For delete: the text from the buffer that has been deleted
For insert: this variable is NULL
str is NULL for insert because the buffer already stores
the text that has been inserted, so storing it here also
would be unnecessary duplication */
};
/* Text changes aren't the only possible changes that we could want
* to track to provide undo/redo e.g. A user closes a buffer
* accidentally and re-opens it with <C-z>
* The enum and union below are to allow other types of change to be
* tracked whilst adding extra functionality such as the ability to
* group changes together into a single action.
* Currently only text changes are tracked and have undo/redo */
/* The type of change that took place on the buffer */
typedef enum {
BCT_TEXT_CHANGE, /* A text change */
BCT_GROUPED_CHANGE /* A change comprised of multiple child changes
i.e. multiple changes grouped together into one */
} BufferChangeType;
/* Abstraction of a change to allow other types of changes
* to be tracked */
typedef union {
TextChange *text_change;
} Change;
typedef struct BufferChange BufferChange;
/* A change to a buffer */
struct BufferChange {
BufferChangeType change_type; /* The type of change */
BufferChange *next; /* Changes are stored in a linked list */
List *children; /* If this is not a grouped change then
children will be NULL, otherwise this is a list
of all the child BufferChange changes this
grouped change is composed of */
Change change; /* The actual change details and data. For a grouped
change this is NULL (i.e. the pointers in the union
are NULL) as this change is simply a container for
its child changes */
size_t version; /* Set to 0 and incremented when a sequential change is
grouped to this change. This is used by the
BufferChangeState struct to determine if a buffer has
been modified */
};
/* This is the top level struct containing undo and redo stacks
* that track all changes made to a buffer */
typedef struct {
BufferChange *undo; /* Undo stack */
BufferChange *redo; /* Redo stack */
int group_changes; /* When true all subsequent BufferChange's are
grouped together as children of a single
BufferChange until set to false */
int accept_new_changes; /* Set true by default. When false all further
changes are ignored. This is used when
actually applying an undo/redo which
will require inserting/deleting text */
} BufferChanges;
/* Stores the most recent change on the undo stack. This can be used to take
* a snapshot and determine in future if a subsequent change has been made to
* a buffer */
typedef struct {
const BufferChange *change; /* This is used only for comparison
with the most recent change on the
undo stack and is never dereferenced
as it could point to freed memory */
size_t version; /* The version of the most recent change on the undo
stack */
} BufferChangeState;
struct Buffer;
void bc_init(BufferChanges *);
void bc_free(BufferChanges *);
Status bc_add_text_insert(BufferChanges *, size_t str_len, const BufferPos *);
Status bc_add_text_delete(BufferChanges *, const char *str, size_t str_len,
const BufferPos *);
int bc_can_undo(const BufferChanges *);
int bc_can_redo(const BufferChanges *);
int bc_grouped_changes_started(const BufferChanges *);
Status bc_start_grouped_changes(BufferChanges *);
Status bc_end_grouped_changes(BufferChanges *);
Status bc_undo(BufferChanges *, struct Buffer *);
Status bc_redo(BufferChanges *, struct Buffer *);
int bc_enabled(const BufferChanges *);
void bc_disable(BufferChanges *);
void bc_enable(BufferChanges *);
BufferChangeState bc_get_current_state(const BufferChanges *);
int bc_has_state_changed(const BufferChanges *, BufferChangeState);
#endif