summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorhuttongrabiel <huttonthomas@icloud.com>2022-06-18 12:03:49 -0700
committerSam Atkins <atkinssj@gmail.com>2022-07-08 11:47:56 +0100
commit9369610bf4097824b08df7fa89f6cfebc7c0706e (patch)
treec539894d80f50a8e3ab6b02fbce5b9cb382fcfda /Userland
parent2fbaa7996c9f9fdbfcebf3af95fab88a89de62ac (diff)
downloadserenity-9369610bf4097824b08df7fa89f6cfebc7c0706e.zip
LibGUI: Unindent selected text on shift+tab press
Selected text is unindented when Shift+Tab is pressed. Select text, indent it with Tab, then unindent with Shift+Tab.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGUI/TextDocument.cpp29
-rw-r--r--Userland/Libraries/LibGUI/TextDocument.h12
-rw-r--r--Userland/Libraries/LibGUI/TextEditor.cpp21
-rw-r--r--Userland/Libraries/LibGUI/TextEditor.h1
4 files changed, 63 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGUI/TextDocument.cpp b/Userland/Libraries/LibGUI/TextDocument.cpp
index cc0f60d1ad..c58f667708 100644
--- a/Userland/Libraries/LibGUI/TextDocument.cpp
+++ b/Userland/Libraries/LibGUI/TextDocument.cpp
@@ -959,6 +959,35 @@ void IndentSelection::undo()
m_document.set_all_cursors(m_range.start());
}
+UnindentSelection::UnindentSelection(TextDocument& document, size_t tab_width, TextRange const& range)
+ : TextDocumentUndoCommand(document)
+ , m_tab_width(tab_width)
+ , m_range(range)
+{
+}
+
+void UnindentSelection::redo()
+{
+ for (size_t i = m_range.start().line(); i <= m_range.end().line(); i++) {
+ if (m_document.line(i).leading_spaces() >= m_tab_width)
+ m_document.remove({ { i, 0 }, { i, m_tab_width } });
+ else
+ m_document.remove({ { i, 0 }, { i, m_document.line(i).leading_spaces() } });
+ }
+
+ m_document.set_all_cursors(m_range.start());
+}
+
+void UnindentSelection::undo()
+{
+ auto const tab = String::repeated(' ', m_tab_width);
+
+ for (size_t i = m_range.start().line(); i <= m_range.end().line(); i++)
+ m_document.insert_at({ i, 0 }, tab, m_client);
+
+ m_document.set_all_cursors(m_range.start());
+}
+
TextPosition TextDocument::insert_at(TextPosition const& position, StringView text, Client const* client)
{
TextPosition cursor = position;
diff --git a/Userland/Libraries/LibGUI/TextDocument.h b/Userland/Libraries/LibGUI/TextDocument.h
index 32b28e3292..0af3140d31 100644
--- a/Userland/Libraries/LibGUI/TextDocument.h
+++ b/Userland/Libraries/LibGUI/TextDocument.h
@@ -271,4 +271,16 @@ private:
TextRange m_range;
};
+class UnindentSelection : public TextDocumentUndoCommand {
+public:
+ UnindentSelection(TextDocument&, size_t tab_width, TextRange const&);
+ virtual void undo() override;
+ virtual void redo() override;
+ TextRange const& range() const { return m_range; }
+
+private:
+ size_t m_tab_width { 0 };
+ TextRange m_range;
+};
+
}
diff --git a/Userland/Libraries/LibGUI/TextEditor.cpp b/Userland/Libraries/LibGUI/TextEditor.cpp
index f61aabff25..698935fe75 100644
--- a/Userland/Libraries/LibGUI/TextEditor.cpp
+++ b/Userland/Libraries/LibGUI/TextEditor.cpp
@@ -869,6 +869,10 @@ void TextEditor::keydown_event(KeyEvent& event)
if (event.key() == KeyCode::Key_Tab) {
if (has_selection()) {
+ if (event.modifiers() == Mod_Shift) {
+ unindent_selection();
+ return;
+ }
if (is_indenting_selection()) {
indent_selection();
return;
@@ -988,6 +992,23 @@ void TextEditor::indent_selection()
}
}
+void TextEditor::unindent_selection()
+{
+ auto const selection_start = m_selection.start() > m_selection.end() ? m_selection.end() : m_selection.start();
+ auto const selection_end = m_selection.end() > m_selection.start() ? m_selection.end() : m_selection.start();
+
+ if (current_line().first_non_whitespace_column() != 0) {
+ if (current_line().first_non_whitespace_column() > m_soft_tab_width && selection_start.column() != 0) {
+ m_selection.set_start({ selection_start.line(), selection_start.column() - m_soft_tab_width });
+ m_selection.set_end({ selection_end.line(), selection_end.column() - m_soft_tab_width });
+ } else if (selection_start.column() != 0) {
+ m_selection.set_start({ selection_start.line(), selection_start.column() - current_line().leading_spaces() });
+ m_selection.set_end({ selection_end.line(), selection_end.column() - current_line().leading_spaces() });
+ }
+ execute<UnindentSelection>(m_soft_tab_width, TextRange(selection_start, selection_end));
+ }
+}
+
void TextEditor::delete_previous_word()
{
TextRange to_erase(document().first_word_before(m_cursor, true), m_cursor);
diff --git a/Userland/Libraries/LibGUI/TextEditor.h b/Userland/Libraries/LibGUI/TextEditor.h
index 53865c831d..518730dd0e 100644
--- a/Userland/Libraries/LibGUI/TextEditor.h
+++ b/Userland/Libraries/LibGUI/TextEditor.h
@@ -153,6 +153,7 @@ public:
virtual void redo();
bool is_indenting_selection();
void indent_selection();
+ void unindent_selection();
Function<void()> on_change;
Function<void(bool modified)> on_modified_change;