summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-11-15 20:36:45 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-11-15 21:03:15 +0100
commit57f7009b9e7f01391a1e41dbb93a5f35ee2c0863 (patch)
tree867b01f3df8fc0b3d1569df602b966448d37d24d
parent27a30fdc2af021142e1a641dc8e5352cb674741f (diff)
downloadserenity-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.cpp34
-rw-r--r--Libraries/LibGUI/GTextDocument.h4
-rw-r--r--Libraries/LibGUI/GTextEditor.cpp44
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;
}