1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:28:12 +00:00

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.
This commit is contained in:
Andreas Kling 2019-11-15 20:36:45 +01:00
parent 27a30fdc2a
commit 57f7009b9e
3 changed files with 56 additions and 26 deletions

View file

@ -298,3 +298,37 @@ Vector<GTextRange> GTextDocument::find_all(const StringView& needle) const
} }
return ranges; 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 {};
}

View file

@ -15,6 +15,7 @@ class GTextDocumentLine;
struct GTextDocumentSpan { struct GTextDocumentSpan {
GTextRange range; GTextRange range;
Color color; Color color;
bool is_skippable { false };
const Font* font { nullptr }; const Font* font { nullptr };
}; };
@ -76,6 +77,9 @@ public:
char character_at(const GTextPosition&) const; 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: private:
explicit GTextDocument(Client* client); explicit GTextDocument(Client* client);

View file

@ -678,19 +678,15 @@ void GTextEditor::keydown_event(GKeyEvent& event)
if (event.key() == KeyCode::Key_Left) { if (event.key() == KeyCode::Key_Left) {
if (event.ctrl() && document().has_spans()) { if (event.ctrl() && document().has_spans()) {
// FIXME: Do something nice when the document has no spans. // FIXME: Do something nice when the document has no spans.
for (int i = 0; i < document().spans().size(); ++i) { auto span = document().first_non_skippable_span_before(m_cursor);
if (!document().spans()[i].range.contains(m_cursor)) GTextPosition new_cursor = !span.has_value()
continue; ? GTextPosition(0, 0)
GTextPosition new_cursor = i == 0 : span.value().range.start();
? GTextPosition(0, 0) toggle_selection_if_needed_for_event(event);
: document().spans()[i - 1].range.start(); set_cursor(new_cursor);
toggle_selection_if_needed_for_event(event); if (event.shift() && m_selection.start().is_valid()) {
set_cursor(new_cursor); m_selection.set_end(m_cursor);
if (event.shift() && m_selection.start().is_valid()) { did_update_selection();
m_selection.set_end(m_cursor);
did_update_selection();
}
break;
} }
return; return;
} }
@ -717,19 +713,15 @@ void GTextEditor::keydown_event(GKeyEvent& event)
if (event.key() == KeyCode::Key_Right) { if (event.key() == KeyCode::Key_Right) {
if (event.ctrl() && document().has_spans()) { if (event.ctrl() && document().has_spans()) {
// FIXME: Do something nice when the document has no spans. // FIXME: Do something nice when the document has no spans.
for (int i = 0; i < document().spans().size(); ++i) { auto span = document().first_non_skippable_span_after(m_cursor);
if (!document().spans()[i].range.contains(m_cursor)) GTextPosition new_cursor = !span.has_value()
continue; ? document().spans().last().range.end()
GTextPosition new_cursor = i == (document().spans().size() - 1) : span.value().range.start();
? document().spans().last().range.end() toggle_selection_if_needed_for_event(event);
: document().spans()[i + 1].range.start(); set_cursor(new_cursor);
toggle_selection_if_needed_for_event(event); if (event.shift() && m_selection.start().is_valid()) {
set_cursor(new_cursor); m_selection.set_end(m_cursor);
if (event.shift() && m_selection.start().is_valid()) { did_update_selection();
m_selection.set_end(m_cursor);
did_update_selection();
}
break;
} }
return; return;
} }