summaryrefslogtreecommitdiff
path: root/src/selection.hh
blob: 5f0ce459235302e968fefaf26df41a738efa5a62 (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
#ifndef selection_hh_INCLUDED
#define selection_hh_INCLUDED

#include "buffer.hh"

namespace Kakoune
{

using CaptureList = std::vector<String>;

// A selection is a Selection, associated with a CaptureList
struct Selection
{
    Selection() = default;
    Selection(ByteCoord pos) : Selection(pos,pos) {}
    Selection(ByteCoord anchor, ByteCoord cursor,
              CaptureList captures = {})
        : m_anchor{anchor}, m_cursor{cursor},
          m_captures(std::move(captures)) {}

    void merge_with(const Selection& range);

    ByteCoord& anchor() { return m_anchor; }
    ByteCoord& cursor() { return m_cursor; }

    const ByteCoord& anchor() const { return m_anchor; }
    const ByteCoord& cursor() const { return m_cursor; }

    CaptureList& captures() { return m_captures; }
    const CaptureList& captures() const { return m_captures; }

    bool operator== (const Selection& other) const
    {
        return m_anchor == other.m_anchor and m_cursor == other.m_cursor;
    }

    const ByteCoord& min() const { return std::min(m_anchor, m_cursor); }
    const ByteCoord& max() const { return std::max(m_anchor, m_cursor); }

private:
    ByteCoord m_anchor;
    ByteCoord m_cursor;

    CaptureList m_captures;
};

inline bool overlaps(const Selection& lhs, const Selection& rhs)
{
    return lhs.min() <= rhs.min() ? lhs.max() >= rhs.min()
                                  : lhs.min() <= rhs.max();
}

static bool compare_selections(const Selection& lhs, const Selection& rhs)
{
    return lhs.min() < rhs.min();
}

struct SelectionList
{
    SelectionList(const Buffer& buffer, Selection s);
    SelectionList(const Buffer& buffer, Selection s, size_t timestamp);
    SelectionList(const Buffer& buffer, std::vector<Selection> s);
    SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp);

    void update();

    void check_invariant() const;

    const Selection& main() const { return (*this)[m_main]; }
    Selection& main() { return (*this)[m_main]; }
    size_t main_index() const { return m_main; }
    void set_main_index(size_t main) { kak_assert(main < size()); m_main = main; }

    void rotate_main(int count) { m_main = (m_main + count) % size(); }

    void avoid_eol();

    void push_back(const Selection& sel) { m_selections.push_back(sel); }
    void push_back(Selection&& sel) { m_selections.push_back(std::move(sel)); }

    Selection& operator[](size_t i) { return m_selections[i]; }
    const Selection& operator[](size_t i) const { return m_selections[i]; }

    SelectionList& operator=(std::vector<Selection> list)
    {
        m_selections = std::move(list);
        m_main = size()-1;
        sort_and_merge_overlapping();
        check_invariant();
        return *this;
    }

    using iterator = std::vector<Selection>::iterator;
    iterator begin() { return m_selections.begin(); }
    iterator end() { return m_selections.end(); }

    using reverse_iterator = std::vector<Selection>::reverse_iterator;
    reverse_iterator rbegin() { return m_selections.rbegin(); }
    reverse_iterator rend() { return m_selections.rend(); }

    using const_iterator = std::vector<Selection>::const_iterator;
    const_iterator begin() const { return m_selections.begin(); }
    const_iterator end() const { return m_selections.end(); }

    template<typename... Args>
    iterator insert(Args... args)
    {
        return m_selections.insert(std::forward<Args>(args)...);
    }

    template<typename... Args>
    iterator erase(Args... args)
    {
        return m_selections.erase(std::forward<Args>(args)...);
    }

    size_t size() const { return m_selections.size(); }
    bool empty() const { return m_selections.empty(); }

    bool operator==(const SelectionList& other) const { return m_buffer == other.m_buffer and m_selections == other.m_selections; }
    bool operator!=(const SelectionList& other) const { return !((*this) == other); }

    template<typename OverlapsFunc>
    void merge_overlapping(OverlapsFunc overlaps)
    {
        kak_assert(std::is_sorted(begin(), end(), compare_selections));
        size_t i = 0;
        for (size_t j = 1; j < size(); ++j)
        {
            if (overlaps((*this)[i], (*this)[j]))
            {
                (*this)[i].merge_with((*this)[j]);
                if (i < m_main)
                    --m_main;
            }
            else
            {
                ++i;
                if (i != j)
                    (*this)[i] = std::move((*this)[j]);
            }
        }
        erase(begin() + i + 1, end());
        kak_assert(std::is_sorted(begin(), end(), compare_selections));
    }

    void sort_and_merge_overlapping();

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

    size_t timestamp() const { return m_timestamp; }
    void set_timestamp(size_t timestamp) { m_timestamp = timestamp; }

private:
    size_t m_main = 0;
    std::vector<Selection> m_selections;

    safe_ptr<const Buffer> m_buffer;
    size_t m_timestamp;
};

void update_insert(std::vector<Selection>& sels, ByteCoord begin, ByteCoord end, bool at_end);
void update_erase(std::vector<Selection>& sels, ByteCoord begin, ByteCoord end, bool at_end);

}

#endif // selection_hh_INCLUDED