summaryrefslogtreecommitdiff
path: root/src/editor.hh
blob: 8778a1a0ceccdf0fd838c3d6bec95d77e771de49 (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
#ifndef editor_hh_INCLUDED
#define editor_hh_INCLUDED

#include "buffer.hh"
#include "dynamic_selection_list.hh"
#include "memoryview.hh"

namespace Kakoune
{

namespace InputModes { class Insert; }

class Register;

enum class SelectMode
{
    Replace,
    Extend,
    Append,
    ReplaceMain,
};

enum class InsertMode : unsigned
{
    Insert,
    Append,
    Replace,
    InsertAtLineBegin,
    InsertAtNextLineBegin,
    AppendAtLineEnd,
    OpenLineBelow,
    OpenLineAbove
};

// An Editor is a buffer mutator
//
// The Editor class provides methods to manipulate a set of selections
// and to use these selections to mutate it's buffer.
class Editor : public SafeCountable
{
public:
    typedef std::function<Selection (const Buffer&, const Selection&)> Selector;
    typedef std::function<SelectionList (const Buffer&, const Selection&)>  MultiSelector;

    Editor(Buffer& buffer);
    virtual ~Editor() {}

    Buffer& buffer() const { return *m_buffer; }

    void erase();

    void insert(const String& string,
                InsertMode mode = InsertMode::Insert);
    void insert(memoryview<String> strings,
                InsertMode mode = InsertMode::Insert);

    void move_selections(LineCount move,
                         SelectMode mode = SelectMode::Replace);
    void move_selections(CharCount move,
                         SelectMode mode = SelectMode::Replace);
    void clear_selections();
    void flip_selections();
    void keep_selection(int index);
    void remove_selection(int index);
    void select(BufferCoord c, SelectMode mode = SelectMode::Replace)
    { select(Selection{ buffer().clamp(c) }, mode); }
    void select(const Selection& sel,
                SelectMode mode = SelectMode::Replace);
    void select(const Selector& selector,
                SelectMode mode = SelectMode::Replace);
    void select(SelectionList selections);
    void multi_select(const MultiSelector& selector);

    void rotate_selections(int count) { m_main_sel = (m_main_sel + count) % m_selections.size(); }

    const SelectionList& selections() const { return m_selections; }
    const Selection& main_selection() const { return m_selections[m_main_sel]; }
    size_t main_selection_index() const { return m_main_sel; }
    std::vector<String>  selections_content() const;

    bool undo();
    bool redo();

    bool is_editing() const { return m_edition_level!= 0; }
private:
    friend struct scoped_edition;
    friend class InputModes::Insert;
    void begin_edition();
    void end_edition();

    virtual BufferCoord offset_coord(BufferCoord coord, LineCount move);
    virtual BufferCoord offset_coord(BufferCoord coord, CharCount move);

    int m_edition_level;

    void check_invariant() const;

    safe_ptr<Buffer>         m_buffer;
    DynamicSelectionList     m_selections;
    size_t                   m_main_sel;
};

struct scoped_edition
{
    scoped_edition(Editor& editor)
        : m_editor(editor)
    { m_editor.begin_edition(); }

    ~scoped_edition()
    { m_editor.end_edition(); }

    Editor& editor() const { return m_editor; }
private:
    Editor& m_editor;
};

void avoid_eol(const Buffer& buffer, BufferCoord& coord);
void avoid_eol(const Buffer& buffer, Range& sel);
void sort_and_merge_overlapping(SelectionList& selections, size_t& main_selection);

}

#endif // editor_hh_INCLUDED