summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorZac <zacary.gillerat@connect.qut.edu.au>2021-01-27 15:49:29 +1000
committerAndreas Kling <kling@serenityos.org>2021-02-02 16:08:20 +0100
commitbd6d0d229581e830c7a69cdb29252b9f63e0434a (patch)
tree84a2d3e93e80de3de0dda826632301664e3d9995 /Userland
parente11ec20650e5182f47675210dcd71e7301c34905 (diff)
downloadserenity-bd6d0d229581e830c7a69cdb29252b9f63e0434a.zip
TextEditor: Add vim status indicators to the statusbar
When using the VimEditingEngine in the TextEditor, vim's mode and the previous key are shown in the editor's statusbar.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Applications/TextEditor/TextEditorWidget.cpp20
-rw-r--r--Userland/Applications/TextEditor/TextEditorWidget.h3
-rw-r--r--Userland/Applications/TextEditor/TextEditorWindow.gml1
-rw-r--r--Userland/Libraries/LibGUI/EditingEngine.h9
-rw-r--r--Userland/Libraries/LibGUI/RegularEditingEngine.cpp5
-rw-r--r--Userland/Libraries/LibGUI/RegularEditingEngine.h2
-rw-r--r--Userland/Libraries/LibGUI/TextEditor.cpp47
-rw-r--r--Userland/Libraries/LibGUI/TextEditor.h8
-rw-r--r--Userland/Libraries/LibGUI/VimEditingEngine.cpp37
-rw-r--r--Userland/Libraries/LibGUI/VimEditingEngine.h59
10 files changed, 171 insertions, 20 deletions
diff --git a/Userland/Applications/TextEditor/TextEditorWidget.cpp b/Userland/Applications/TextEditor/TextEditorWidget.cpp
index 9d31b106f8..1bd7ac19aa 100644
--- a/Userland/Applications/TextEditor/TextEditorWidget.cpp
+++ b/Userland/Applications/TextEditor/TextEditorWidget.cpp
@@ -39,11 +39,13 @@
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/CppSyntaxHighlighter.h>
+#include <LibGUI/EditingEngine.h>
#include <LibGUI/FilePicker.h>
#include <LibGUI/FontPicker.h>
#include <LibGUI/GMLSyntaxHighlighter.h>
#include <LibGUI/INISyntaxHighlighter.h>
#include <LibGUI/JSSyntaxHighlighter.h>
+#include <LibGUI/Label.h>
#include <LibGUI/Menu.h>
#include <LibGUI/MenuBar.h>
#include <LibGUI/MessageBox.h>
@@ -57,6 +59,7 @@
#include <LibGUI/ToolBarContainer.h>
#include <LibGUI/VimEditingEngine.h>
#include <LibGfx/Font.h>
+#include <LibGfx/FontDatabase.h>
#include <LibMarkdown/Document.h>
#include <LibWeb/OutOfProcessWebView.h>
#include <string.h>
@@ -301,6 +304,21 @@ TextEditorWidget::TextEditorWidget()
m_statusbar = *find_descendant_of_type_named<GUI::StatusBar>("statusbar");
+ m_statusbar->label(m_vim_mode_statusbar_index)->set_visible(m_editor->editing_engine()->type() == GUI::EditingEngineType::Vim);
+ m_statusbar->label(m_vim_mode_statusbar_index)->set_font(Gfx::FontDatabase::default_bold_font());
+
+ m_statusbar->label(m_vim_previous_keys_statusbar_index)->set_visible(m_editor->editing_engine()->type() == GUI::EditingEngineType::Vim);
+
+ m_editor->on_vim_statusbar_messages_changed = [this] {
+ m_statusbar->set_text(m_vim_mode_statusbar_index, m_editor->vim_mode_statusbar_message());
+ m_statusbar->set_text(m_vim_previous_keys_statusbar_index, m_editor->vim_previous_keys_statusbar_message());
+ };
+
+ m_editor->on_editing_engine_changed = [this]() {
+ m_statusbar->label(m_vim_mode_statusbar_index)->set_visible(m_editor->editing_engine()->type() == GUI::EditingEngineType::Vim);
+ m_statusbar->label(m_vim_previous_keys_statusbar_index)->set_visible(m_editor->editing_engine()->type() == GUI::EditingEngineType::Vim);
+ };
+
m_editor->on_cursor_change = [this] { update_statusbar_cursor_position(); };
m_new_action = GUI::Action::create("New", { Mod_Ctrl, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new.png"), [this](const GUI::Action&) {
@@ -666,5 +684,5 @@ void TextEditorWidget::update_statusbar_cursor_position()
{
StringBuilder builder;
builder.appendff("Line: {}, Column: {}", m_editor->cursor().line() + 1, m_editor->cursor().column());
- m_statusbar->set_text(builder.to_string());
+ m_statusbar->set_text(m_cursor_position_statusbar_index, builder.to_string());
}
diff --git a/Userland/Applications/TextEditor/TextEditorWidget.h b/Userland/Applications/TextEditor/TextEditorWidget.h
index 763087b9e4..28c4a9c3fd 100644
--- a/Userland/Applications/TextEditor/TextEditorWidget.h
+++ b/Userland/Applications/TextEditor/TextEditorWidget.h
@@ -91,6 +91,9 @@ private:
RefPtr<GUI::Action> m_html_preview_action;
RefPtr<GUI::StatusBar> m_statusbar;
+ const int m_cursor_position_statusbar_index = 0;
+ const int m_vim_mode_statusbar_index = 1;
+ const int m_vim_previous_keys_statusbar_index = 2;
RefPtr<GUI::TextBox> m_find_textbox;
RefPtr<GUI::TextBox> m_replace_textbox;
diff --git a/Userland/Applications/TextEditor/TextEditorWindow.gml b/Userland/Applications/TextEditor/TextEditorWindow.gml
index 433d01abff..b13865f697 100644
--- a/Userland/Applications/TextEditor/TextEditorWindow.gml
+++ b/Userland/Applications/TextEditor/TextEditorWindow.gml
@@ -84,5 +84,6 @@
@GUI::StatusBar {
name: "statusbar"
+ label_count: 3
}
}
diff --git a/Userland/Libraries/LibGUI/EditingEngine.h b/Userland/Libraries/LibGUI/EditingEngine.h
index a9eb525acf..3da65d2f09 100644
--- a/Userland/Libraries/LibGUI/EditingEngine.h
+++ b/Userland/Libraries/LibGUI/EditingEngine.h
@@ -37,6 +37,11 @@ enum CursorWidth {
WIDE
};
+enum EditingEngineType {
+ Regular,
+ Vim
+};
+
class EditingEngine {
AK_MAKE_NONCOPYABLE(EditingEngine);
AK_MAKE_NONMOVABLE(EditingEngine);
@@ -51,11 +56,15 @@ public:
virtual bool on_key(const KeyEvent& event);
+ EditingEngineType type() const { return m_editing_engine_type; }
+
protected:
EditingEngine() { }
WeakPtr<TextEditor> m_editor;
+ EditingEngineType m_editing_engine_type;
+
void move_one_left(const KeyEvent& event);
void move_one_right(const KeyEvent& event);
void move_one_up(const KeyEvent& event);
diff --git a/Userland/Libraries/LibGUI/RegularEditingEngine.cpp b/Userland/Libraries/LibGUI/RegularEditingEngine.cpp
index ffcbe941cd..653d6da7bb 100644
--- a/Userland/Libraries/LibGUI/RegularEditingEngine.cpp
+++ b/Userland/Libraries/LibGUI/RegularEditingEngine.cpp
@@ -30,6 +30,11 @@
namespace GUI {
+RegularEditingEngine::RegularEditingEngine()
+{
+ m_editing_engine_type = EditingEngineType::Regular;
+}
+
CursorWidth RegularEditingEngine::cursor_width() const
{
return CursorWidth::NARROW;
diff --git a/Userland/Libraries/LibGUI/RegularEditingEngine.h b/Userland/Libraries/LibGUI/RegularEditingEngine.h
index 87e51b08d8..c91250333d 100644
--- a/Userland/Libraries/LibGUI/RegularEditingEngine.h
+++ b/Userland/Libraries/LibGUI/RegularEditingEngine.h
@@ -33,6 +33,8 @@ namespace GUI {
class RegularEditingEngine final : public EditingEngine {
public:
+ RegularEditingEngine();
+
virtual CursorWidth cursor_width() const override;
virtual bool on_key(const KeyEvent& event) override;
diff --git a/Userland/Libraries/LibGUI/TextEditor.cpp b/Userland/Libraries/LibGUI/TextEditor.cpp
index 55be2949e6..20615bcdce 100644
--- a/Userland/Libraries/LibGUI/TextEditor.cpp
+++ b/Userland/Libraries/LibGUI/TextEditor.cpp
@@ -40,6 +40,7 @@
#include <LibGUI/ScrollBar.h>
#include <LibGUI/SyntaxHighlighter.h>
#include <LibGUI/TextEditor.h>
+#include <LibGUI/VimEditingEngine.h>
#include <LibGUI/Window.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Font.h>
@@ -1625,6 +1626,52 @@ void TextEditor::set_editing_engine(OwnPtr<EditingEngine> editing_engine)
update_cursor();
stop_timer();
start_timer(500);
+
+ if (on_editing_engine_changed)
+ on_editing_engine_changed();
+
+ if (m_editing_engine->type() == EditingEngineType::Vim) {
+ VimEditingEngine* vim = dynamic_cast<VimEditingEngine*>(m_editing_engine.ptr());
+ vim->on_mode_change = [&](VimMode mode) {
+ switch (mode) {
+ case Normal:
+ m_vim_mode_statusbar_message = {};
+ break;
+ case Insert:
+ m_vim_mode_statusbar_message = "-- INSERT --";
+ break;
+ case Visual:
+ m_vim_mode_statusbar_message = "-- VISUAL --";
+ break;
+ default:
+ dbgln("Unhandled vim mode");
+ m_vim_mode_statusbar_message = {};
+ }
+ if (on_vim_statusbar_messages_changed)
+ on_vim_statusbar_messages_changed();
+ };
+
+ // FIXME: Update this method to take multiple previous keys when that is implemented
+ vim->on_previous_keys_change = [&](const VimEditingEngine::PreviousKey& event, bool has_previous_key) {
+ if (has_previous_key) {
+ StringBuilder sb = StringBuilder(1);
+ sb.append_code_point(event.code_point);
+ m_vim_previous_keys_statusbar_message = sb.to_string();
+ } else {
+ m_vim_previous_keys_statusbar_message = {};
+ }
+ if (on_vim_statusbar_messages_changed)
+ on_vim_statusbar_messages_changed();
+ };
+ } else {
+ m_vim_mode_statusbar_message = {};
+ m_vim_previous_keys_statusbar_message = {};
+ if (on_vim_statusbar_messages_changed)
+ on_vim_statusbar_messages_changed();
+ if (on_editing_engine_changed) {
+ on_editing_engine_changed();
+ }
+ }
}
int TextEditor::line_height() const
diff --git a/Userland/Libraries/LibGUI/TextEditor.h b/Userland/Libraries/LibGUI/TextEditor.h
index 956e3cfcce..0bc742b80e 100644
--- a/Userland/Libraries/LibGUI/TextEditor.h
+++ b/Userland/Libraries/LibGUI/TextEditor.h
@@ -150,6 +150,8 @@ public:
Function<void()> on_down_pressed;
Function<void()> on_pageup_pressed;
Function<void()> on_pagedown_pressed;
+ Function<void()> on_vim_statusbar_messages_changed;
+ Function<void()> on_editing_engine_changed;
Action& undo_action() { return *m_undo_action; }
Action& redo_action() { return *m_redo_action; }
@@ -195,6 +197,9 @@ public:
void delete_text_range(TextRange);
+ String vim_mode_statusbar_message() const { return m_vim_mode_statusbar_message; }
+ String vim_previous_keys_statusbar_message() const { return m_vim_previous_keys_statusbar_message; }
+
protected:
explicit TextEditor(Type = Type::MultiLine);
@@ -351,6 +356,9 @@ private:
Gfx::IntPoint m_last_mousemove_position;
RefPtr<Gfx::Bitmap> m_icon;
+
+ String m_vim_mode_statusbar_message {};
+ String m_vim_previous_keys_statusbar_message {};
};
}
diff --git a/Userland/Libraries/LibGUI/VimEditingEngine.cpp b/Userland/Libraries/LibGUI/VimEditingEngine.cpp
index 60a6a2b21b..213e267d35 100644
--- a/Userland/Libraries/LibGUI/VimEditingEngine.cpp
+++ b/Userland/Libraries/LibGUI/VimEditingEngine.cpp
@@ -30,6 +30,11 @@
namespace GUI {
+VimEditingEngine::VimEditingEngine()
+{
+ m_editing_engine_type = EditingEngineType::Vim;
+}
+
CursorWidth VimEditingEngine::cursor_width() const
{
return m_vim_mode == VimMode::Insert ? CursorWidth::NARROW : CursorWidth::WIDE;
@@ -101,19 +106,19 @@ bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
delete_to.set_column(delete_to.column() + 1);
m_editor->delete_text_range(TextRange(m_editor->cursor(), delete_to).normalized());
}
- m_previous_key = {};
+ clear_previous_key();
} else if (m_previous_key == KeyCode::Key_G) {
if (event.key() == KeyCode::Key_G) {
move_to_first_line();
} else if (event.key() == KeyCode::Key_E) {
move_to_end_of_previous_word();
}
- m_previous_key = {};
+ clear_previous_key();
} else if (m_previous_key == KeyCode::Key_Y) {
if (event.key() == KeyCode::Key_Y) {
yank(Line);
}
- m_previous_key = {};
+ clear_previous_key();
} else if (m_previous_key == KeyCode::Key_C) {
if (event.key() == KeyCode::Key_C) {
// Needed because the code to replace the deleted line is called after delete_line() so
@@ -169,7 +174,7 @@ bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
m_editor->delete_text_range(TextRange(adjusted_cursor, delete_to).normalized());
switch_to_insert_mode();
}
- m_previous_key = {};
+ clear_previous_key();
} else {
// Handle first any key codes that are to be applied regardless of modifiers.
switch (event.key()) {
@@ -240,7 +245,7 @@ bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
move_to_beginning_of_previous_word();
break;
case (KeyCode::Key_C):
- m_previous_key = event.key();
+ set_previous_key(event);
break;
case (KeyCode::Key_Backspace):
case (KeyCode::Key_H):
@@ -248,13 +253,13 @@ bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
move_one_left(event);
break;
case (KeyCode::Key_D):
- m_previous_key = event.key();
+ set_previous_key(event);
break;
case (KeyCode::Key_E):
move_to_end_of_next_word();
break;
case (KeyCode::Key_G):
- m_previous_key = event.key();
+ set_previous_key(event);
break;
case (KeyCode::Key_Down):
case (KeyCode::Key_J):
@@ -293,7 +298,7 @@ bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
switch_to_visual_mode();
break;
case (KeyCode::Key_Y):
- m_previous_key = event.key();
+ set_previous_key(event);
break;
case (KeyCode::Key_P):
put(event);
@@ -316,7 +321,7 @@ bool VimEditingEngine::on_key_in_visual_mode(const KeyEvent& event)
move_to_end_of_previous_word();
update_selection_on_cursor_move();
}
- m_previous_key = {};
+ clear_previous_key();
} else {
// Handle first any key codes that are to be applied regardless of modifiers.
switch (event.key()) {
@@ -391,7 +396,7 @@ bool VimEditingEngine::on_key_in_visual_mode(const KeyEvent& event)
update_selection_on_cursor_move();
break;
case (KeyCode::Key_G):
- m_previous_key = event.key();
+ set_previous_key(event);
break;
case (KeyCode::Key_Down):
case (KeyCode::Key_J):
@@ -448,26 +453,32 @@ void VimEditingEngine::switch_to_normal_mode()
{
m_vim_mode = VimMode::Normal;
m_editor->reset_cursor_blink();
- m_previous_key = {};
+ clear_previous_key();
clear_visual_mode_data();
+ if (on_mode_change)
+ on_mode_change(m_vim_mode);
};
void VimEditingEngine::switch_to_insert_mode()
{
m_vim_mode = VimMode::Insert;
m_editor->reset_cursor_blink();
- m_previous_key = {};
+ clear_previous_key();
clear_visual_mode_data();
+ if (on_mode_change)
+ on_mode_change(m_vim_mode);
};
void VimEditingEngine::switch_to_visual_mode()
{
m_vim_mode = VimMode::Visual;
m_editor->reset_cursor_blink();
- m_previous_key = {};
+ clear_previous_key();
m_selection_start_position = m_editor->cursor();
m_editor->selection()->set(m_editor->cursor(), { m_editor->cursor().line(), m_editor->cursor().column() + 1 });
m_editor->did_update_selection();
+ if (on_mode_change)
+ on_mode_change(m_vim_mode);
}
void VimEditingEngine::update_selection_on_cursor_move()
diff --git a/Userland/Libraries/LibGUI/VimEditingEngine.h b/Userland/Libraries/LibGUI/VimEditingEngine.h
index 007472d0f9..7af4e60677 100644
--- a/Userland/Libraries/LibGUI/VimEditingEngine.h
+++ b/Userland/Libraries/LibGUI/VimEditingEngine.h
@@ -30,20 +30,48 @@
namespace GUI {
+enum VimMode {
+ Normal,
+ Insert,
+ Visual
+};
+
class VimEditingEngine final : public EditingEngine {
public:
+ VimEditingEngine();
+
virtual CursorWidth cursor_width() const override;
virtual bool on_key(const KeyEvent& event) override;
-private:
- enum VimMode {
- Normal,
- Insert,
- Visual
+ class PreviousKey {
+ public:
+ PreviousKey() = default;
+ PreviousKey(const KeyEvent& event)
+ : key(event.key())
+ , code_point(event.code_point())
+ {
+ }
+
+ bool operator==(const KeyCode& key) const
+ {
+ return this->key == key;
+ }
+
+ bool operator==(const u32& code_point) const
+ {
+ return this->code_point == code_point;
+ }
+
+ KeyCode key {};
+ u32 code_point {};
};
+ Function<void(VimMode)> on_mode_change;
+ Function<void(const PreviousKey&, bool has_previous_key)> on_previous_keys_change;
+
+private:
enum YankType {
Line,
Selection
@@ -61,7 +89,26 @@ private:
void update_selection_on_cursor_move();
void clear_visual_mode_data();
- KeyCode m_previous_key {};
+ // FIXME Support multiple previous keys, this is a temporary measure.
+ PreviousKey m_previous_key {};
+ bool has_previous_key { false };
+
+ void set_previous_key(PreviousKey event)
+ {
+ m_previous_key = event;
+ has_previous_key = true;
+ if (on_previous_keys_change)
+ on_previous_keys_change(m_previous_key, has_previous_key);
+ }
+
+ void clear_previous_key()
+ {
+ m_previous_key = {};
+ has_previous_key = false;
+ if (on_previous_keys_change)
+ on_previous_keys_change(m_previous_key, has_previous_key);
+ }
+
void switch_to_normal_mode();
void switch_to_insert_mode();
void switch_to_visual_mode();