diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-11-15 20:36:45 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-15 21:03:15 +0100 |
commit | 57f7009b9e7f01391a1e41dbb93a5f35ee2c0863 (patch) | |
tree | 867b01f3df8fc0b3d1569df602b966448d37d24d | |
parent | 27a30fdc2af021142e1a641dc8e5352cb674741f (diff) | |
download | serenity-57f7009b9e7f01391a1e41dbb93a5f35ee2c0863.zip |
GTextEditor: Allow GTextDocumentSpans to be "skippable"
Setting the is_skippable flag on a GTextDocumentSpan will now cause the
cursor to skip over that span when moving with Ctrl+Left/Right.
-rw-r--r-- | Libraries/LibGUI/GTextDocument.cpp | 34 | ||||
-rw-r--r-- | Libraries/LibGUI/GTextDocument.h | 4 | ||||
-rw-r--r-- | Libraries/LibGUI/GTextEditor.cpp | 44 |
3 files changed, 56 insertions, 26 deletions
diff --git a/Libraries/LibGUI/GTextDocument.cpp b/Libraries/LibGUI/GTextDocument.cpp index 5eb40a6fc9..69b9be02a4 100644 --- a/Libraries/LibGUI/GTextDocument.cpp +++ b/Libraries/LibGUI/GTextDocument.cpp @@ -298,3 +298,37 @@ Vector<GTextRange> GTextDocument::find_all(const StringView& needle) const } return ranges; } + +Optional<GTextDocumentSpan> GTextDocument::first_non_skippable_span_before(const GTextPosition& position) const +{ + for (int i = m_spans.size() - 1; i >= 0; --i) { + if (!m_spans[i].range.contains(position)) + continue; + while ((i - 1) >= 0 && m_spans[i - 1].is_skippable) + --i; + if (i <= 0) + return {}; + return m_spans[i - 1]; + } + return {}; +} + +Optional<GTextDocumentSpan> GTextDocument::first_non_skippable_span_after(const GTextPosition& position) const +{ + for (int i = 0; i < m_spans.size(); ++i) { + if (!m_spans[i].range.contains(position)) + continue; + while ((i + 1) < m_spans.size() && m_spans[i + 1].is_skippable) + ++i; + if (i >= (m_spans.size() - 1)) + return {}; + return m_spans[i + 1]; + } + return {}; +} + + + + + + diff --git a/Libraries/LibGUI/GTextDocument.h b/Libraries/LibGUI/GTextDocument.h index 5bf0954f83..04cc9e32ba 100644 --- a/Libraries/LibGUI/GTextDocument.h +++ b/Libraries/LibGUI/GTextDocument.h @@ -15,6 +15,7 @@ class GTextDocumentLine; struct GTextDocumentSpan { GTextRange range; Color color; + bool is_skippable { false }; const Font* font { nullptr }; }; @@ -76,6 +77,9 @@ public: char character_at(const GTextPosition&) const; + Optional<GTextDocumentSpan> first_non_skippable_span_before(const GTextPosition&) const; + Optional<GTextDocumentSpan> first_non_skippable_span_after(const GTextPosition&) const; + private: explicit GTextDocument(Client* client); diff --git a/Libraries/LibGUI/GTextEditor.cpp b/Libraries/LibGUI/GTextEditor.cpp index 39983062d2..ae5b4fc2ed 100644 --- a/Libraries/LibGUI/GTextEditor.cpp +++ b/Libraries/LibGUI/GTextEditor.cpp @@ -678,19 +678,15 @@ void GTextEditor::keydown_event(GKeyEvent& event) if (event.key() == KeyCode::Key_Left) { if (event.ctrl() && document().has_spans()) { // FIXME: Do something nice when the document has no spans. - for (int i = 0; i < document().spans().size(); ++i) { - if (!document().spans()[i].range.contains(m_cursor)) - continue; - GTextPosition new_cursor = i == 0 - ? GTextPosition(0, 0) - : document().spans()[i - 1].range.start(); - toggle_selection_if_needed_for_event(event); - set_cursor(new_cursor); - if (event.shift() && m_selection.start().is_valid()) { - m_selection.set_end(m_cursor); - did_update_selection(); - } - break; + auto span = document().first_non_skippable_span_before(m_cursor); + GTextPosition new_cursor = !span.has_value() + ? GTextPosition(0, 0) + : span.value().range.start(); + toggle_selection_if_needed_for_event(event); + set_cursor(new_cursor); + if (event.shift() && m_selection.start().is_valid()) { + m_selection.set_end(m_cursor); + did_update_selection(); } return; } @@ -717,19 +713,15 @@ void GTextEditor::keydown_event(GKeyEvent& event) if (event.key() == KeyCode::Key_Right) { if (event.ctrl() && document().has_spans()) { // FIXME: Do something nice when the document has no spans. - for (int i = 0; i < document().spans().size(); ++i) { - if (!document().spans()[i].range.contains(m_cursor)) - continue; - GTextPosition new_cursor = i == (document().spans().size() - 1) - ? document().spans().last().range.end() - : document().spans()[i + 1].range.start(); - toggle_selection_if_needed_for_event(event); - set_cursor(new_cursor); - if (event.shift() && m_selection.start().is_valid()) { - m_selection.set_end(m_cursor); - did_update_selection(); - } - break; + auto span = document().first_non_skippable_span_after(m_cursor); + GTextPosition new_cursor = !span.has_value() + ? document().spans().last().range.end() + : span.value().range.start(); + toggle_selection_if_needed_for_event(event); + set_cursor(new_cursor); + if (event.shift() && m_selection.start().is_valid()) { + m_selection.set_end(m_cursor); + did_update_selection(); } return; } |