From 71770e000b6bec4bbe1a09e0506c68f4594c74c0 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 25 Apr 2019 22:56:09 +0200 Subject: [PATCH] GTextEditor: Add very basic automatic indentation. This is off by default, but enabled by TextEditor. It simply inserts the same number of leading spaces as the previous line when hitting Enter. :^) --- AK/AKString.h | 2 ++ AK/String.cpp | 10 ++++++++++ Applications/TextEditor/main.cpp | 1 + LibGUI/GTextEditor.cpp | 22 ++++++++++++++++++++-- LibGUI/GTextEditor.h | 5 +++++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/AK/AKString.h b/AK/AKString.h index 2370a2bd4d..8df1bf162d 100644 --- a/AK/AKString.h +++ b/AK/AKString.h @@ -61,6 +61,8 @@ public: { } + static String repeated(char, int count); + int to_int(bool& ok) const; unsigned to_uint(bool& ok) const; diff --git a/AK/String.cpp b/AK/String.cpp index a87473d323..beacc5b881 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -166,4 +166,14 @@ bool String::ends_with(const String& str) const return !memcmp(characters() + (length() - str.length()), str.characters(), str.length()); } +String String::repeated(char ch, int count) +{ + if (!count) + return empty(); + char* buffer; + auto impl = StringImpl::create_uninitialized(count, buffer); + memset(buffer, ch, count); + return *impl; +} + } diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp index 4ba1c3d184..5588792e0e 100644 --- a/Applications/TextEditor/main.cpp +++ b/Applications/TextEditor/main.cpp @@ -25,6 +25,7 @@ int main(int argc, char** argv) auto* toolbar = new GToolBar(widget); auto* text_editor = new GTextEditor(GTextEditor::MultiLine, widget); text_editor->set_ruler_visible(true); + text_editor->set_automatic_indentation_enabled(true); auto* statusbar = new GStatusBar(widget); text_editor->on_cursor_change = [statusbar, text_editor] { diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index c8e169ab6a..3f8776c60e 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -562,10 +562,23 @@ void GTextEditor::insert_at_cursor(char ch) return; } if (at_tail || at_head) { - m_lines.insert(m_cursor.line() + (at_tail ? 1 : 0), make()); + String new_line_contents; + if (m_automatic_indentation_enabled && at_tail) { + int leading_spaces = 0; + auto& old_line = *m_lines[m_cursor.line()]; + for (int i = 0; i < old_line.length(); ++i) { + if (old_line.characters()[i] == ' ') + ++leading_spaces; + else + break; + } + if (leading_spaces) + new_line_contents = String::repeated(' ', leading_spaces); + } + m_lines.insert(m_cursor.line() + (at_tail ? 1 : 0), make(new_line_contents)); update(); did_change(); - set_cursor(m_cursor.line() + 1, 0); + set_cursor(m_cursor.line() + 1, m_lines[m_cursor.line() + 1]->length()); return; } auto new_line = make(); @@ -709,6 +722,11 @@ GTextEditor::Line::Line() clear(); } +GTextEditor::Line::Line(const String& text) +{ + set_text(text); +} + void GTextEditor::Line::clear() { m_text.clear(); diff --git a/LibGUI/GTextEditor.h b/LibGUI/GTextEditor.h index 0b3a78fbdd..b8896f6f51 100644 --- a/LibGUI/GTextEditor.h +++ b/LibGUI/GTextEditor.h @@ -70,6 +70,9 @@ public: GTextEditor(Type, GWidget* parent); virtual ~GTextEditor() override; + bool is_automatic_indentation() const { return m_automatic_indentation_enabled; } + void set_automatic_indentation_enabled(bool enabled) { m_automatic_indentation_enabled = enabled; } + TextAlignment text_alignment() const { return m_text_alignment; } void set_text_alignment(TextAlignment); @@ -145,6 +148,7 @@ private: friend class GTextEditor; public: Line(); + explicit Line(const String&); const char* characters() const { return m_text.data(); } int length() const { return m_text.size() - 1; } @@ -191,6 +195,7 @@ private: bool m_in_drag_select { false }; bool m_ruler_visible { false }; bool m_have_pending_change_notification { false }; + bool m_automatic_indentation_enabled { false }; int m_line_spacing { 4 }; int m_soft_tab_width { 4 }; int m_horizontal_content_padding { 2 };