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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
#ifndef buffer_hh_INCLUDED
#define buffer_hh_INCLUDED
#include "clock.hh"
#include "coord.hh"
#include "flags.hh"
#include "safe_ptr.hh"
#include "scope.hh"
#include "shared_string.hh"
#include "value.hh"
#include "vector.hh"
#include <time.h>
namespace Kakoune
{
enum class EolFormat
{
Lf,
Crlf
};
constexpr Array<EnumDesc<EolFormat>, 2> enum_desc(EolFormat)
{
return { {
{ EolFormat::Lf, "lf" },
{ EolFormat::Crlf, "crlf" },
} };
}
enum class ByteOrderMark
{
None,
Utf8
};
constexpr Array<EnumDesc<ByteOrderMark>, 2> enum_desc(ByteOrderMark)
{
return { {
{ ByteOrderMark::None, "none" },
{ ByteOrderMark::Utf8, "utf8" },
} };
}
class Buffer;
constexpr timespec InvalidTime = { -1, -1 };
// A BufferIterator permits to iterate over the characters of a buffer
class BufferIterator
{
public:
using value_type = char;
using difference_type = ssize_t;
using pointer = const value_type*;
using reference = const value_type&;
using iterator_category = std::random_access_iterator_tag;
BufferIterator() : m_buffer(nullptr) {}
BufferIterator(const Buffer& buffer, BufferCoord coord);
bool operator== (const BufferIterator& iterator) const;
bool operator!= (const BufferIterator& iterator) const;
bool operator< (const BufferIterator& iterator) const;
bool operator<= (const BufferIterator& iterator) const;
bool operator> (const BufferIterator& iterator) const;
bool operator>= (const BufferIterator& iterator) const;
const char& operator* () const;
const char& operator[](size_t n) const;
size_t operator- (const BufferIterator& iterator) const;
BufferIterator operator+ (ByteCount size) const;
BufferIterator operator- (ByteCount size) const;
BufferIterator& operator+= (ByteCount size);
BufferIterator& operator-= (ByteCount size);
BufferIterator& operator++ ();
BufferIterator& operator-- ();
BufferIterator operator++ (int);
BufferIterator operator-- (int);
const BufferCoord& coord() const { return m_coord; }
private:
SafePtr<const Buffer> m_buffer;
StringView m_line;
BufferCoord m_coord;
LineCount m_last_line;
};
using BufferLines = Vector<StringDataPtr, MemoryDomain::BufferContent>;
// A Buffer is a in-memory representation of a file
//
// The Buffer class permits to read and mutate this file
// representation. It also manage modifications undo/redo and
// provides tools to deal with the line/column nature of text.
class Buffer : public SafeCountable, public OptionManagerWatcher, public Scope
{
public:
enum class Flags
{
None = 0,
File = 1 << 0,
New = 1 << 1,
Fifo = 1 << 2,
NoUndo = 1 << 3,
NoHooks = 1 << 4,
Debug = 1 << 5,
ReadOnly = 1 << 6,
};
Buffer(String name, Flags flags, StringView data = {},
timespec fs_timestamp = InvalidTime);
Buffer(const Buffer&) = delete;
Buffer& operator= (const Buffer&) = delete;
~Buffer();
Flags flags() const { return m_flags; }
Flags& flags() { return m_flags; }
bool set_name(String name);
void update_display_name();
BufferCoord insert(BufferCoord pos, StringView content);
BufferCoord erase(BufferCoord begin, BufferCoord end);
BufferCoord replace(BufferCoord begin, BufferCoord end, StringView content);
size_t timestamp() const;
timespec fs_timestamp() const;
void set_fs_timestamp(timespec ts);
void commit_undo_group();
bool undo(size_t count = 1) noexcept;
bool redo(size_t count = 1) noexcept;
bool move_to(size_t history_id) noexcept;
size_t current_history_id() const noexcept;
String string(BufferCoord begin, BufferCoord end) const;
const char& byte_at(BufferCoord c) const;
ByteCount distance(BufferCoord begin, BufferCoord end) const;
BufferCoord advance(BufferCoord coord, ByteCount count) const;
BufferCoord next(BufferCoord coord) const;
BufferCoord prev(BufferCoord coord) const;
BufferCoord char_next(BufferCoord coord) const;
BufferCoord char_prev(BufferCoord coord) const;
BufferCoord back_coord() const;
BufferCoord end_coord() const;
bool is_valid(BufferCoord c) const;
bool is_end(BufferCoord c) const;
BufferCoord last_modification_coord() const;
BufferIterator begin() const;
BufferIterator end() const;
LineCount line_count() const;
StringView operator[](LineCount line) const
{ return m_lines[line]; }
const StringDataPtr& line_storage(LineCount line) const
{ return m_lines.get_storage(line); }
// returns an iterator at given coordinates. clamp line_and_column
BufferIterator iterator_at(BufferCoord coord) const;
// returns nearest valid coordinates from given ones
BufferCoord clamp(BufferCoord coord) const;
BufferCoord offset_coord(BufferCoord coord, CharCount offset);
BufferCoordAndTarget offset_coord(BufferCoordAndTarget coord, LineCount offset);
const String& name() const { return m_name; }
const String& display_name() const { return m_display_name; }
// returns true if the buffer is in a different state than
// the last time it was saved
bool is_modified() const;
// notify the buffer that it was saved in the current state
void notify_saved();
ValueMap& values() const { return m_values; }
void run_hook_in_own_context(StringView hook_name, StringView param,
String client_name = "");
void reload(StringView data, timespec fs_timestamp = InvalidTime);
void check_invariant() const;
struct Change
{
enum Type : char { Insert, Erase };
Type type;
bool at_end;
BufferCoord begin;
BufferCoord end;
};
ConstArrayView<Change> changes_since(size_t timestamp) const;
String debug_description() const;
// Methods called by the buffer manager
void on_registered();
void on_unregistered();
private:
void on_option_changed(const Option& option) override;
BufferCoord do_insert(BufferCoord pos, StringView content);
BufferCoord do_erase(BufferCoord begin, BufferCoord end);
struct Modification;
void apply_modification(const Modification& modification);
void revert_modification(const Modification& modification);
struct LineList : BufferLines
{
[[gnu::always_inline]]
StringDataPtr& get_storage(LineCount line)
{ return BufferLines::operator[]((int)line); }
[[gnu::always_inline]]
const StringDataPtr& get_storage(LineCount line) const
{ return BufferLines::operator[]((int)line); }
[[gnu::always_inline]]
StringView operator[](LineCount line) const
{ return get_storage(line)->strview(); }
StringView front() const { return BufferLines::front()->strview(); }
StringView back() const { return BufferLines::back()->strview(); }
};
LineList m_lines;
String m_name;
String m_display_name;
Flags m_flags;
using UndoGroup = Vector<Modification, MemoryDomain::BufferMeta>;
struct HistoryNode : SafeCountable, UseMemoryDomain<MemoryDomain::BufferMeta>
{
HistoryNode(size_t id, HistoryNode* parent);
size_t id;
SafePtr<HistoryNode> parent;
UndoGroup undo_group;
Vector<std::unique_ptr<HistoryNode>, MemoryDomain::BufferMeta> childs;
SafePtr<HistoryNode> redo_child;
TimePoint timepoint;
};
size_t m_next_history_id = 0;
HistoryNode m_history;
SafePtr<HistoryNode> m_history_cursor;
SafePtr<HistoryNode> m_last_save_history_cursor;
UndoGroup m_current_undo_group;
void move_to(HistoryNode* history_node) noexcept;
template<typename Func> HistoryNode* find_history_node(HistoryNode* node, const Func& func);
Vector<Change, MemoryDomain::BufferMeta> m_changes;
timespec m_fs_timestamp;
// Values are just data holding by the buffer, they are not part of its
// observable state
mutable ValueMap m_values;
};
template<> struct WithBitOps<Buffer::Flags> : std::true_type {};
}
#include "buffer.inl.hh"
#endif // buffer_hh_INCLUDED
|