summaryrefslogtreecommitdiff
path: root/src/buffer.hh
blob: f586af7c4e617caadb16b6e8a56ce0c5a936243b (plain)
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
#ifndef buffer_hh_INCLUDED
#define buffer_hh_INCLUDED

#include <string>
#include <vector>
#include <list>
#include <memory>

#include "line_and_column.hh"

namespace Kakoune
{

class Buffer;
class Window;

typedef int      BufferPos;
typedef int      BufferSize;
typedef char     BufferChar;
typedef std::basic_string<BufferChar> BufferString;

struct BufferCoord : LineAndColumn<BufferCoord>
{
    BufferCoord(int line = 0, int column = 0)
        : LineAndColumn(line, column) {}

    template<typename T>
    explicit BufferCoord(const LineAndColumn<T>& other)
        : LineAndColumn(other.line, other.column) {}
};

class BufferIterator
{
public:
    typedef BufferChar value_type;
    typedef BufferSize difference_type;
    typedef const value_type* pointer;
    typedef const value_type& reference;
    typedef std::bidirectional_iterator_tag iterator_category;

    BufferIterator() : m_buffer(NULL), m_position(0) {}
    BufferIterator(const Buffer& buffer, BufferPos position);
    BufferIterator& operator=(const BufferIterator& iterator);

    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;

    BufferChar operator* () const;
    BufferSize operator- (const BufferIterator& iterator) const;

    BufferIterator operator+ (BufferSize size) const;
    BufferIterator operator- (BufferSize size) const;

    BufferIterator& operator+= (BufferSize size);
    BufferIterator& operator-= (BufferSize size);

    BufferIterator& operator++ ();
    BufferIterator& operator-- ();

    bool is_begin() const;
    bool is_end() const;

    const Buffer& buffer() const;

private:
    const Buffer* m_buffer;
    BufferPos     m_position;
    friend class Buffer;
};

struct BufferModification
{
    enum Type { Insert, Erase };

    Type           type;
    BufferIterator position;
    BufferString   content;

    BufferModification(Type type, BufferIterator position,
                       BufferString content)
        : type(type), position(position), content(content) {}

    BufferModification inverse() const;
};

class BufferModificationListener
{
public:
    virtual void on_modification(const BufferModification& modification) = 0;
};

class Buffer
{
public:
    enum class Type
    {
        File,
        Scratch
    };

    Buffer(const std::string& name, Type type,
           const BufferString& initial_content = "");

    void           begin_undo_group();
    void           end_undo_group();

    bool           undo();
    bool           redo();

    void           erase(const BufferIterator& begin,
                         const BufferIterator& end);

    void           insert(const BufferIterator& position,
                          const BufferString& string);

    BufferString   string(const BufferIterator& begin,
                          const BufferIterator& end) const;

    BufferIterator begin() const;
    BufferIterator end() const;
    BufferSize     length() const;
    BufferSize     line_count() const;

    BufferIterator iterator_at(const BufferCoord& line_and_column) const;
    BufferCoord    line_and_column_at(const BufferIterator& iterator) const;

    BufferCoord     clamp(const BufferCoord& line_and_column) const;

    const std::string& name() const { return m_name; }

    const BufferString& content() const { return m_content; }

    Window* get_or_create_window();
    void delete_window(Window* window);

    bool is_modified() const;
    Type type() const { return m_type; }
    void notify_saved();

    void register_modification_listener(BufferModificationListener* listener);
    void unregister_modification_listener(BufferModificationListener* listener);

private:
    BufferChar at(BufferPos position) const;

    void       do_erase(const BufferIterator& begin,
                        const BufferIterator& end);

    void       do_insert(const BufferIterator& position,
                         const BufferString& string);

    friend class BufferIterator;

    std::vector<BufferPos> m_lines;

    void compute_lines();
    BufferPos line_at(const BufferIterator& iterator) const;
    BufferSize line_length(BufferPos line) const;

    BufferString m_content;

    std::string  m_name;
    const Type   m_type;

    typedef std::vector<BufferModification> UndoGroup;

    std::vector<UndoGroup>           m_history;
    std::vector<UndoGroup>::iterator m_history_cursor;
    UndoGroup                        m_current_undo_group;

    void apply_modification(const BufferModification& modification);
    void revert_modification(const BufferModification& modification);

    void append_modification(BufferModification&& modification);

    std::list<std::unique_ptr<Window>> m_windows;

    std::vector<UndoGroup>::iterator m_last_save_undo_group;

    std::vector<BufferModificationListener*> m_modification_listeners;
};

}

#include "buffer_iterator.inl.h"

#endif // buffer_hh_INCLUDED