From ef7ebf4dbc470c27b3b79a257ad0598719f03b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 6 Jul 2022 02:06:42 -0300 Subject: [PATCH] Added terminal global keybindings. --- .../eepp/ui/tools/uicodeeditorsplitter.hpp | 10 +- src/eepp/ui/tools/uicodeeditorsplitter.cpp | 66 +++++++------ .../eterm/include/eterm/ui/uiterminal.hpp | 28 ++++++ src/modules/eterm/src/eterm/ui/uiterminal.cpp | 68 ++++++++++++- src/tools/ecode/ecode.cpp | 99 +++++++++++++++++-- src/tools/ecode/ecode.hpp | 4 +- src/tools/ecode/version.hpp | 2 +- 7 files changed, 228 insertions(+), 49 deletions(-) diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index 2b6fe4d2c..eadb01173 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -49,7 +49,7 @@ class EE_API UICodeEditorSplitter { virtual ~UICodeEditorSplitter(); - virtual bool tryTabClose(UIWidget* widget ); + virtual bool tryTabClose( UIWidget* widget ); void closeTab( UIWidget* widget ); @@ -58,13 +58,13 @@ class EE_API UICodeEditorSplitter { void switchToTab( Int32 index ); - UITabWidget* findPreviousSplit( UICodeEditor* editor ); + UITabWidget* findPreviousSplit( UIWidget* widget ); - void switchPreviousSplit( UICodeEditor* editor ); + void switchPreviousSplit( UIWidget* widget ); - UITabWidget* findNextSplit( UICodeEditor* editor ); + UITabWidget* findNextSplit( UIWidget* widget ); - void switchNextSplit( UICodeEditor* editor ); + void switchNextSplit( UIWidget* widget ); void setCurrentEditor( UICodeEditor* editor ); diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 0110f5382..5703c1577 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -23,8 +23,8 @@ UICodeEditorSplitter::getLocalDefaultKeybindings() { { { KEY_L, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "lock-toggle" }, { { KEY_T, KeyMod::getDefaultModifier() }, "create-new" }, { { KEY_W, KeyMod::getDefaultModifier() }, "close-tab" }, - { { KEY_TAB, KeyMod::getDefaultModifier() }, "next-doc" }, - { { KEY_TAB, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "previous-doc" }, + { { KEY_TAB, KeyMod::getDefaultModifier() }, "next-tab" }, + { { KEY_TAB, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "previous-tab" }, { { KEY_J, KEYMOD_LALT | KEYMOD_SHIFT }, "split-left" }, { { KEY_L, KEYMOD_LALT | KEYMOD_SHIFT }, "split-right" }, { { KEY_I, KEYMOD_LALT | KEYMOD_SHIFT }, "split-top" }, @@ -61,8 +61,8 @@ std::vector UICodeEditorSplitter::getUnlockedCommands() { const std::vector unlockedCmds{ "lock-toggle", "create-new", "close-tab", - "next-doc", - "previous-doc", + "next-tab", + "previous-tab", "split-left", "split-right", "split-top", @@ -217,25 +217,27 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() { mCurrentColorScheme = mColorSchemes.begin()->first; applyColorScheme( mColorSchemes[mCurrentColorScheme] ); } ); - doc.setCommand( "switch-to-previous-split", [&] { switchPreviousSplit( mCurEditor ); } ); - doc.setCommand( "switch-to-next-split", [&] { switchNextSplit( mCurEditor ); } ); - doc.setCommand( "close-tab", [&] { tryTabClose( mCurEditor ); } ); + + /* Splitter commands */ + doc.setCommand( "switch-to-previous-split", [&] { switchPreviousSplit( mCurWidget ); } ); + doc.setCommand( "switch-to-next-split", [&] { switchNextSplit( mCurWidget ); } ); + doc.setCommand( "close-tab", [&] { tryTabClose( mCurWidget ); } ); doc.setCommand( "create-new", [&] { - auto d = createCodeEditorInTabWidget( tabWidgetFromEditor( mCurEditor ) ); + auto d = createCodeEditorInTabWidget( tabWidgetFromWidget( mCurWidget ) ); d.first->getTabWidget()->setTabSelected( d.first ); } ); - doc.setCommand( "next-doc", [&] { - UITabWidget* tabWidget = tabWidgetFromEditor( mCurEditor ); + doc.setCommand( "next-tab", [&] { + UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget ); if ( tabWidget && tabWidget->getTabCount() > 1 ) { - UITab* tab = (UITab*)mCurEditor->getData(); + UITab* tab = (UITab*)mCurWidget->getData(); Uint32 tabIndex = tabWidget->getTabIndex( tab ); switchToTab( ( tabIndex + 1 ) % tabWidget->getTabCount() ); } } ); - doc.setCommand( "previous-doc", [&] { - UITabWidget* tabWidget = tabWidgetFromEditor( mCurEditor ); + doc.setCommand( "previous-tab", [&] { + UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget ); if ( tabWidget && tabWidget->getTabCount() > 1 ) { - UITab* tab = (UITab*)mCurEditor->getData(); + UITab* tab = (UITab*)mCurWidget->getData(); Uint32 tabIndex = tabWidget->getTabIndex( tab ); Int32 newTabIndex = (Int32)tabIndex - 1; switchToTab( newTabIndex < 0 ? tabWidget->getTabCount() - newTabIndex : newTabIndex ); @@ -244,13 +246,13 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() { for ( int i = 1; i <= 10; i++ ) doc.setCommand( String::format( "switch-to-tab-%d", i ), [&, i] { switchToTab( i - 1 ); } ); doc.setCommand( "switch-to-first-tab", [&] { - UITabWidget* tabWidget = tabWidgetFromEditor( mCurEditor ); + UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget ); if ( tabWidget && tabWidget->getTabCount() ) { switchToTab( 0 ); } } ); doc.setCommand( "switch-to-last-tab", [&] { - UITabWidget* tabWidget = tabWidgetFromEditor( mCurEditor ); + UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget ); if ( tabWidget && tabWidget->getTabCount() ) { switchToTab( tabWidget->getTabCount() - 1 ); } @@ -263,6 +265,8 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() { if ( UISplitter* splitter = splitterFromWidget( mCurWidget ) ) splitter->swap(); } ); + /* Splitter commands */ + doc.setCommand( "open-containing-folder", [&] { if ( mCurEditor ) mCurEditor->openContainingFolder(); @@ -797,19 +801,19 @@ UISplitter* UICodeEditorSplitter::split( const SplitDirection& direction, UIWidg } void UICodeEditorSplitter::switchToTab( Int32 index ) { - UITabWidget* tabWidget = tabWidgetFromEditor( mCurEditor ); + UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget ); if ( tabWidget ) { tabWidget->setTabSelected( eeclamp( index, 0, tabWidget->getTabCount() - 1 ) ); } } -UITabWidget* UICodeEditorSplitter::findPreviousSplit( UICodeEditor* editor ) { - if ( !editor ) +UITabWidget* UICodeEditorSplitter::findPreviousSplit( UIWidget* widget ) { + if ( !widget ) return nullptr; - UISplitter* splitter = splitterFromEditor( editor ); + UISplitter* splitter = splitterFromWidget( widget ); if ( !splitter ) return nullptr; - UITabWidget* tabWidget = tabWidgetFromEditor( editor ); + UITabWidget* tabWidget = tabWidgetFromWidget( widget ); if ( tabWidget ) { auto it = std::find( mTabWidgets.rbegin(), mTabWidgets.rend(), tabWidget ); if ( it != mTabWidgets.rend() && ++it != mTabWidgets.rend() ) { @@ -819,13 +823,13 @@ UITabWidget* UICodeEditorSplitter::findPreviousSplit( UICodeEditor* editor ) { return nullptr; } -void UICodeEditorSplitter::switchPreviousSplit( UICodeEditor* editor ) { - UITabWidget* tabWidget = findPreviousSplit( editor ); +void UICodeEditorSplitter::switchPreviousSplit( UIWidget* widget ) { + UITabWidget* tabWidget = findPreviousSplit( widget ); if ( tabWidget && tabWidget->getTabSelected() && tabWidget->getTabSelected()->getOwnedWidget() ) { tabWidget->getTabSelected()->getOwnedWidget()->setFocus(); } else { - tabWidget = findNextSplit( editor ); + tabWidget = findNextSplit( widget ); if ( tabWidget && tabWidget->getTabSelected() && tabWidget->getTabSelected()->getOwnedWidget() ) { tabWidget->getTabSelected()->getOwnedWidget()->setFocus(); @@ -833,13 +837,13 @@ void UICodeEditorSplitter::switchPreviousSplit( UICodeEditor* editor ) { } } -UITabWidget* UICodeEditorSplitter::findNextSplit( UICodeEditor* editor ) { - if ( !editor ) +UITabWidget* UICodeEditorSplitter::findNextSplit( UIWidget* widget ) { + if ( !widget ) return nullptr; - UISplitter* splitter = splitterFromEditor( editor ); + UISplitter* splitter = splitterFromWidget( widget ); if ( !splitter ) return nullptr; - UITabWidget* tabWidget = tabWidgetFromEditor( editor ); + UITabWidget* tabWidget = tabWidgetFromWidget( widget ); if ( tabWidget ) { auto it = std::find( mTabWidgets.begin(), mTabWidgets.end(), tabWidget ); if ( it != mTabWidgets.end() && ++it != mTabWidgets.end() ) { @@ -849,13 +853,13 @@ UITabWidget* UICodeEditorSplitter::findNextSplit( UICodeEditor* editor ) { return nullptr; } -void UICodeEditorSplitter::switchNextSplit( UICodeEditor* editor ) { - UITabWidget* tabWidget = findNextSplit( editor ); +void UICodeEditorSplitter::switchNextSplit( UIWidget* widget ) { + UITabWidget* tabWidget = findNextSplit( widget ); if ( tabWidget && tabWidget->getTabSelected() && tabWidget->getTabSelected()->getOwnedWidget() ) { tabWidget->getTabSelected()->getOwnedWidget()->setFocus(); } else { - tabWidget = findPreviousSplit( editor ); + tabWidget = findPreviousSplit( widget ); if ( tabWidget && tabWidget->getTabSelected() && tabWidget->getTabSelected()->getOwnedWidget() ) { tabWidget->getTabSelected()->getOwnedWidget()->setFocus(); diff --git a/src/modules/eterm/include/eterm/ui/uiterminal.hpp b/src/modules/eterm/include/eterm/ui/uiterminal.hpp index 21d588b63..ef8c51ab7 100644 --- a/src/modules/eterm/include/eterm/ui/uiterminal.hpp +++ b/src/modules/eterm/include/eterm/ui/uiterminal.hpp @@ -1,6 +1,7 @@ #ifndef ETERM_UI_UITERMINAL_HPP #define ETERM_UI_UITERMINAL_HPP +#include #include #include @@ -16,6 +17,7 @@ class EE_API UITerminal : public UIWidget { const std::string& workingDir = "", const size_t& historySize = 10000, IProcessFactory* processFactory = nullptr, const bool& useFrameBuffer = false ); + typedef std::function TerminalCommand; static UITerminal* New( const std::shared_ptr& terminalDisplay ); @@ -35,10 +37,36 @@ class EE_API UITerminal : public UIWidget { void setTitle( const std::string& title ); + KeyBindings& getKeyBindings(); + + void setKeyBindings( const KeyBindings& keyBindings ); + + void addKeyBindingString( const std::string& shortcut, const std::string& command ); + + void addKeyBinding( const KeyBindings::Shortcut& shortcut, const std::string& command ); + + void replaceKeyBindingString( const std::string& shortcut, const std::string& command ); + + void replaceKeyBinding( const KeyBindings::Shortcut& shortcut, const std::string& command ); + + void addKeyBindsString( const std::map& binds ); + + void addKeyBinds( const std::map& binds ); + + void execute( const std::string& command ); + + void setCommands( const std::map& cmds ); + + void setCommand( const std::string& command, const TerminalCommand& func ); + + bool hasCommand( const std::string& command ); + protected: std::string mTitle; bool mIsCustomTitle{ false }; bool mDraggingSel{ false }; + KeyBindings mKeyBindings; + std::map mCommands; UITerminal( const std::shared_ptr& terminalDisplay ); diff --git a/src/modules/eterm/src/eterm/ui/uiterminal.cpp b/src/modules/eterm/src/eterm/ui/uiterminal.cpp index e5ffe94ac..9edd396fd 100644 --- a/src/modules/eterm/src/eterm/ui/uiterminal.cpp +++ b/src/modules/eterm/src/eterm/ui/uiterminal.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -38,7 +39,9 @@ void UITerminal::draw() { } UITerminal::UITerminal( const std::shared_ptr& terminalDisplay ) : - UIWidget( "terminal" ), mTerm( terminalDisplay ) { + UIWidget( "terminal" ), + mKeyBindings( getUISceneNode()->getWindow()->getInput() ), + mTerm( terminalDisplay ) { mFlags |= UI_TAB_STOP; mTerm->pushEventCallback( [&]( const TerminalDisplay::Event& event ) { if ( event.type == TerminalDisplay::EventType::TITLE && getParent() ) { @@ -73,12 +76,75 @@ void UITerminal::setTitle( const std::string& title ) { } } +KeyBindings& UITerminal::getKeyBindings() { + return mKeyBindings; +} + +void UITerminal::setKeyBindings( const KeyBindings& keyBindings ) { + mKeyBindings = keyBindings; +} + +void UITerminal::addKeyBindingString( const std::string& shortcut, const std::string& command ) { + mKeyBindings.addKeybindString( shortcut, command ); +} + +void UITerminal::addKeyBinding( const KeyBindings::Shortcut& shortcut, + const std::string& command ) { + mKeyBindings.addKeybind( shortcut, command ); +} + +void UITerminal::replaceKeyBindingString( const std::string& shortcut, + const std::string& command ) { + mKeyBindings.replaceKeybindString( shortcut, command ); +} + +void UITerminal::replaceKeyBinding( const KeyBindings::Shortcut& shortcut, + const std::string& command ) { + mKeyBindings.replaceKeybind( shortcut, command ); +} + +void UITerminal::addKeyBindsString( const std::map& binds ) { + mKeyBindings.addKeybindsString( binds ); +} + +void UITerminal::addKeyBinds( const std::map& binds ) { + mKeyBindings.addKeybinds( binds ); +} + +void UITerminal::execute( const std::string& command ) { + auto cmdIt = mCommands.find( command ); + if ( cmdIt != mCommands.end() ) { + cmdIt->second(); + } +} + +void UITerminal::setCommands( const std::map& cmds ) { + mCommands.insert( cmds.begin(), cmds.end() ); +} + +void UITerminal::setCommand( const std::string& command, const UITerminal::TerminalCommand& func ) { + mCommands[command] = func; +} + +bool UITerminal::hasCommand( const std::string& command ) { + return mCommands.find( command ) != mCommands.end(); +} + Uint32 UITerminal::onTextInput( const TextInputEvent& event ) { mTerm->onTextInput( event.getChar() ); return 1; } Uint32 UITerminal::onKeyDown( const KeyEvent& event ) { + if ( mUISceneNode->getUIEventDispatcher()->justGainedFocus() ) + return 0; + + std::string cmd = mKeyBindings.getCommandFromKeyBind( { event.getKeyCode(), event.getMod() } ); + if ( !cmd.empty() ) { + execute( cmd ); + return 1; + } + mTerm->onKeyDown( event.getKeyCode(), event.getChar(), event.getMod(), event.getScancode() ); return 1; } diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 5061228d1..4e5f63c76 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -300,8 +300,14 @@ UIFileDialog* App::saveFileDialog( UICodeEditor* editor, bool focusOnClose ) { } void App::runCommand( const std::string& command ) { - if ( mEditorSplitter->getCurEditor() ) - mEditorSplitter->getCurEditor()->getDocument().execute( command ); + if ( mEditorSplitter->getCurWidget() ) { + if ( mEditorSplitter->getCurWidget()->isType( UI_TYPE_CODEEDITOR ) ) { + mEditorSplitter->getCurWidget()->asType()->getDocument().execute( + command ); + } else if ( mEditorSplitter->getCurWidget()->isType( UI_TYPE_TERMINAL ) ) { + mEditorSplitter->getCurWidget()->asType()->execute( command ); + } + } } void App::loadConfig() { @@ -1769,10 +1775,18 @@ const CodeEditorConfig& App::getCodeEditorConfig() const { return mConfig.editor; } +std::map App::getAppKeybindings() { + return { + { { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "create-new-terminal" }, + }; +} + std::map App::getDefaultKeybindings() { auto bindings = UICodeEditorSplitter::getDefaultKeybindings(); auto local = getLocalKeybindings(); + auto app = getAppKeybindings(); local.insert( bindings.begin(), bindings.end() ); + local.insert( app.begin(), app.end() ); return local; } @@ -1982,12 +1996,81 @@ void App::createNewTerminal() { return; setAppTitle( event->getNode()->asType()->getTitle() ); } ); -} - -std::map> App::getGlobalCommands() { - std::map> cmds; - - return cmds; + term->addKeyBinds( getLocalKeybindings() ); + term->addKeyBinds( UICodeEditorSplitter::getLocalDefaultKeybindings() ); + term->addKeyBinds( getAppKeybindings() ); + for ( int i = 1; i <= 10; i++ ) + term->setCommand( String::format( "switch-to-tab-%d", i ), + [&, i] { mEditorSplitter->switchToTab( i - 1 ); } ); + term->setCommand( "switch-to-first-tab", [&] { + UITabWidget* tabWidget = + mEditorSplitter->tabWidgetFromWidget( mEditorSplitter->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() ) { + mEditorSplitter->switchToTab( 0 ); + } + } ); + term->setCommand( "switch-to-last-tab", [&] { + UITabWidget* tabWidget = + mEditorSplitter->tabWidgetFromWidget( mEditorSplitter->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() ) { + mEditorSplitter->switchToTab( tabWidget->getTabCount() - 1 ); + } + } ); + term->setCommand( "switch-to-previous-split", [&] { + mEditorSplitter->switchPreviousSplit( mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "switch-to-next-split", [&] { + mEditorSplitter->switchNextSplit( mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "close-tab", + [&] { mEditorSplitter->tryTabClose( mEditorSplitter->getCurWidget() ); } ); + term->setCommand( "create-new", [&] { + auto d = mEditorSplitter->createCodeEditorInTabWidget( + mEditorSplitter->tabWidgetFromWidget( mEditorSplitter->getCurWidget() ) ); + d.first->getTabWidget()->setTabSelected( d.first ); + } ); + term->setCommand( "next-tab", [&] { + UITabWidget* tabWidget = + mEditorSplitter->tabWidgetFromWidget( mEditorSplitter->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() > 1 ) { + UITab* tab = (UITab*)mEditorSplitter->getCurWidget()->getData(); + Uint32 tabIndex = tabWidget->getTabIndex( tab ); + mEditorSplitter->switchToTab( ( tabIndex + 1 ) % tabWidget->getTabCount() ); + } + } ); + term->setCommand( "previous-tab", [&] { + UITabWidget* tabWidget = + mEditorSplitter->tabWidgetFromWidget( mEditorSplitter->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() > 1 ) { + UITab* tab = (UITab*)mEditorSplitter->getCurWidget()->getData(); + Uint32 tabIndex = tabWidget->getTabIndex( tab ); + Int32 newTabIndex = (Int32)tabIndex - 1; + mEditorSplitter->switchToTab( newTabIndex < 0 ? tabWidget->getTabCount() - newTabIndex + : newTabIndex ); + } + } ); + term->setCommand( "split-right", [&] { + mEditorSplitter->split( UICodeEditorSplitter::SplitDirection::Right, + mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "split-bottom", [&] { + mEditorSplitter->split( UICodeEditorSplitter::SplitDirection::Bottom, + mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "split-left", [&] { + mEditorSplitter->split( UICodeEditorSplitter::SplitDirection::Left, + mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "split-top", [&] { + mEditorSplitter->split( UICodeEditorSplitter::SplitDirection::Top, + mEditorSplitter->getCurWidget() ); + } ); + term->setCommand( "split-swap", [&] { + if ( UISplitter* splitter = + mEditorSplitter->splitterFromWidget( mEditorSplitter->getCurWidget() ) ) + splitter->swap(); + } ); + term->setCommand( "create-new-terminal", [&] { createNewTerminal(); } ); } void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 06d7b5759..663a27daf 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -82,7 +82,7 @@ class App : public UICodeEditorSplitter::Client { void createNewTerminal(); - std::map> getGlobalCommands(); + std::map getAppKeybindings(); protected: EE::Window::Window* mWindow{ nullptr }; @@ -171,8 +171,6 @@ class App : public UICodeEditorSplitter::Client { std::string titleFromEditor( UICodeEditor* editor ); - bool tryTabClose( UICodeEditor* editor ); - bool onCloseRequestCallback( EE::Window::Window* ); void addRemainingTabWidgets( Node* widget ); diff --git a/src/tools/ecode/version.hpp b/src/tools/ecode/version.hpp index 2a2185347..a28b96778 100644 --- a/src/tools/ecode/version.hpp +++ b/src/tools/ecode/version.hpp @@ -7,7 +7,7 @@ using namespace EE; #define ECODE_MAJOR_VERSION 0 -#define ECODE_MINOR_VERSION 1 +#define ECODE_MINOR_VERSION 2 #define ECODE_PATCH_LEVEL 0 #define ECODE_CODENAME "Viriya"