- persist keybindings in keybindings.cfg with configurable primary and secondary modifiers
  - hot-reload bindings and merge newly introduced defaults
  - open keybindings.cfg in a terminal-font-sized code editor tab
  - indicate unsaved keybinding changes using the modified-tab marker
  - share tab and split commands between terminals and the keybindings editor
  - add bindings for terminal actions, tab navigation, numbered tabs, splits, renaming, and tab movement
  - expose keybindings through terminal and tab context menus
  - add tab split and move-left/right context menu actions
This commit is contained in:
Martín Lucas Golini
2026-09-09 14:32:43 -03:00
parent 410c9ba09f
commit fe91253276
5 changed files with 287 additions and 61 deletions
+53 -55
View File
@@ -5,8 +5,8 @@
namespace eterm {
void App::TerminalSplitterClient::onTabCreated( UITab* tab, UIWidget* ) {
if ( mApp.terminalIcon )
void App::TerminalSplitterClient::onTabCreated( UITab* tab, UIWidget* widget ) {
if ( mApp.terminalIcon && widget && widget->isType( UI_TYPE_TERMINAL ) )
tab->setIcon( mApp.terminalIcon->createDrawable( PixelDensity::dpToPxI( 12 ) ) );
mApp.configureTab( tab );
}
@@ -393,6 +393,12 @@ void App::configureTab( UITab* tab ) {
addItem( i18n( "close_tabs_to_the_right", "Close Tabs To The Right" ), "",
"close-tabs-to-the-right" );
menu->addSeparator();
addItem( i18n( "split_left", "Split Left" ), "split-horizontal", "split-left" );
addItem( i18n( "split_right", "Split Right" ), "split-horizontal", "split-right" );
addItem( i18n( "split_top", "Split Top" ), "split-vertical", "split-top" );
addItem( i18n( "split_bottom", "Split Bottom" ), "split-vertical", "split-bottom" );
menu->addSeparator();
auto* exclusiveMode = menu->addCheckBox(
i18n( "enable_exclusive_mode", "Enable Exclusive Mode" ), terminal->getExclusiveMode(),
@@ -404,6 +410,11 @@ void App::configureTab( UITab* tab ) {
menu->addSeparator();
const bool canMove = clickedTab->getTabWidget()->getTabCount() > 1;
const Uint32 tabIndex = clickedTab->getTabWidget()->getTabIndex( clickedTab );
addItem( i18n( "move_tab_left", "Move Tab Left" ), "", "move-tab-left" )
->setEnabled( canMove && tabIndex > 0 );
addItem( i18n( "move_tab_right", "Move Tab Right" ), "", "move-tab-right" )
->setEnabled( canMove && tabIndex + 1 < clickedTab->getTabWidget()->getTabCount() );
addItem( i18n( "move_tab_to_start", "Move Tab To Start" ), "window", "move-tab-to-start" )
->setEnabled( canMove );
addItem( i18n( "move_tab_to_end", "Move Tab To End" ), "window", "move-tab-to-end" )
@@ -511,6 +522,7 @@ UITerminal* App::createTerminal( UITabWidget* target ) {
addItem( i18n( "new_terminal", "New Terminal" ), "terminal", "create-new-terminal" );
menu->addSeparator();
addItem( i18n( "settings", "Settings" ), "settings", "open-settings" );
addItem( i18n( "key_bindings", "Keybindings" ), "keybindings", "open-keybindings" );
menu->on( Event::OnItemClicked, [this, terminal]( const Event* itemEvent ) {
if ( !itemEvent->getNode()->isType( UI_TYPE_MENUITEM ) )
return;
@@ -530,68 +542,33 @@ UITerminal* App::createTerminal( UITabWidget* target ) {
return terminal;
}
UITerminal* App::createTerminalSplit( SplitDirection direction, UITerminal* terminal ) {
auto* source = terminal ? tabSplitter->tabWidgetFromWidget( terminal ) : nullptr;
UITerminal* App::createTerminalSplit( SplitDirection direction, UIWidget* widget ) {
auto* source = widget ? tabSplitter->tabWidgetFromWidget( widget ) : nullptr;
auto* target = source ? tabSplitter->splitTabWidget( direction, source ) : nullptr;
return target ? createTerminal( target ) : nullptr;
}
void App::moveTab( UIWidget* widget, int offset ) {
if ( !widget || offset == 0 )
return;
auto* tabs = tabSplitter->tabWidgetFromWidget( widget );
auto* tab = tabs ? tabs->getTabFromOwnedWidget( widget ) : nullptr;
if ( !tab )
return;
const Uint32 index = tabs->getTabIndex( tab );
if ( offset < 0 && index > 0 )
tabs->moveTab( tab, index - 1 );
else if ( offset > 0 && index + 1 < tabs->getTabCount() )
tabs->moveTab( tab, index + 1 );
}
void App::addTabKeyBindings( UITerminal* terminal ) {
tabSplitter->registerSplitterCommands( *terminal );
terminal->setCommand( "create-new-terminal", [this] { createNewTerminal(); } );
terminal->setCommand( "open-settings", [this] { showSettings(); } );
terminal->setCommand( "debug-widget-tree-view",
[this] { UIWidgetInspector::create( scene ); } );
registerTabCommands( *terminal, terminal );
terminal->setCommand( "terminal-rename", [this, terminal] { renameSession( terminal ); } );
terminal->setCommand( UITerminal::getExclusiveModeToggleCommandName(), [terminal] {
terminal->setExclusiveMode( !terminal->getExclusiveMode() );
} );
terminal->setCommand( "next-tab", [this, terminal] {
if ( auto* tabs = tabSplitter->tabWidgetFromWidget( terminal ) )
tabs->focusNextTab();
} );
terminal->setCommand( "previous-tab", [this, terminal] {
if ( auto* tabs = tabSplitter->tabWidgetFromWidget( terminal ) )
tabs->focusPreviousTab();
} );
terminal->setCommand( "split-right", [this, terminal] {
createTerminalSplit( SplitDirection::Right, terminal );
} );
terminal->setCommand( "split-bottom", [this, terminal] {
createTerminalSplit( SplitDirection::Bottom, terminal );
} );
terminal->setCommand(
"split-left", [this, terminal] { createTerminalSplit( SplitDirection::Left, terminal ); } );
terminal->setCommand(
"split-top", [this, terminal] { createTerminalSplit( SplitDirection::Top, terminal ); } );
terminal->setCommand( "switch-to-previous-split",
[this, terminal] { tabSplitter->switchPreviousSplit( terminal ); } );
terminal->setCommand( "switch-to-next-split",
[this, terminal] { tabSplitter->switchNextSplit( terminal ); } );
terminal->addKeyBinding( { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_SHIFT },
"create-new-terminal" );
terminal->addKeyBinding( { KEY_COMMA, KeyMod::getDefaultModifier() }, "open-settings" );
terminal->addKeyBinding( { KEY_W, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "close-tab" );
terminal->addKeyBinding( { KEY_F11, KeyMod::getDefaultModifier() | KEYMOD_SHIFT },
"debug-widget-tree-view" );
terminal->addKeyBinding( { KEY_PAGEDOWN, KEYMOD_CTRL }, "next-tab" );
terminal->addKeyBinding( { KEY_PAGEUP, KEYMOD_CTRL }, "previous-tab" );
terminal->addKeyBinding( { KEY_TAB, KEYMOD_CTRL }, "next-tab" );
terminal->addKeyBinding( { KEY_TAB, KEYMOD_CTRL | KEYMOD_SHIFT }, "previous-tab" );
terminal->addKeyBinding( { KEY_L, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT },
"split-right" );
terminal->addKeyBinding( { KEY_K, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT },
"split-bottom" );
terminal->addKeyBinding( { KEY_J, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT },
"split-left" );
terminal->addKeyBinding( { KEY_I, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT },
"split-top" );
terminal->addKeyBinding(
{ KEY_J, KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() },
"switch-to-previous-split" );
terminal->addKeyBinding(
{ KEY_L, KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() },
"switch-to-next-split" );
applyKeybindings( terminal );
}
bool App::closeWindow( EE::Window::Window* ) {
@@ -809,6 +786,11 @@ int App::run( int argc, char* argv[] ) {
scene = app.getUI();
if ( !appWindow || !appWindow->isOpen() || !scene )
return EXIT_FAILURE;
keybindingsPath = config->getConfigPath() + "keybindings.cfg";
loadKeybindings();
fileWatcher = std::make_unique<efsw::FileWatcher>();
fileWatcher->addWatch( config->getConfigPath(), this );
fileWatcher->watch();
scene->setColorSchemePreference( config->theme.uiColorScheme );
scene->getUIThemeManager()->setDefaultFontSize( config->font.uiSize );
FileSystem::changeWorkingDirectory( initialWorkingDirectory );
@@ -829,6 +811,19 @@ int App::run( int argc, char* argv[] ) {
tint: var(--primary);
cursor: hand;
}
Tab.tab_modified > Tab::close {
foreground-image: url("data:image/svg,<svg viewBox='0 0 24 24' width='12' height='12' fill='#ffffff'><path d='M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z'></path></svg>");
foreground-tint: var(--primary);
foreground-size: 6dp 6dp;
foreground-position: center;
opacity: 1;
}
Tab.tab_modified > Tab::close:hover {
foreground-image: url("data:image/svg,<svg width='16' height='16' viewBox='0 0 16 16'><path fill='#ffffff' fill-rule='evenodd' d='M 2.3432061,13.657206 A 8.0002061,8.0002061 0 1 1 13.657206,2.3432061 8.0002061,8.0002061 0 0 1 2.3432061,13.657206 Z m 3.687,-8.6869999 a 0.75,0.75 0 0 0 -1.06,1.06 l 1.97,1.97 -1.97,1.97 a 0.75,0.75 0 1 0 1.06,1.0599999 l 1.97,-1.9699999 1.97,1.9699999 A 0.75,0.75 0 1 0 11.030206,9.9702061 l -1.9699999,-1.97 1.9699999,-1.97 a 0.75,0.75 0 1 0 -1.0599999,-1.06 l -1.97,1.97 z' /></svg>");
foreground-tint: var(--tab-close-hover);
foreground-size: 10dp 10dp;
foreground-position: center;
}
)css" );
auto& resourceScope = *scene->getResourceScope();
@@ -976,6 +971,8 @@ int App::run( int argc, char* argv[] ) {
appWindow->runMainLoop( [this] {
appWindow->getInput()->update();
SceneManager::instance()->update();
if ( keybindingsChanged.exchange( false, std::memory_order_acq_rel ) )
reloadKeybindings();
queueExitedTabs();
// Process-exit events are drained from UITerminal scheduled updates. Removing a tab from
// that callback would mutate the scheduled-widget set while it is being traversed.
@@ -998,6 +995,7 @@ int App::run( int argc, char* argv[] ) {
secondsCounter.restart();
}
} );
fileWatcher.reset();
return EXIT_SUCCESS;
}
+47 -2
View File
@@ -2,6 +2,7 @@
#include "appconfig.hpp"
#include <args/args.hxx>
#include <atomic>
#include <eepp/core/small_vector.hpp>
#include <eepp/ee.hpp>
#include <eepp/ui/iconmanager.hpp>
@@ -12,6 +13,7 @@
#include <eepp/ui/uiapplication.hpp>
#include <eepp/ui/uilinearlayout.hpp>
#include <eepp/ui/uimessagebox.hpp>
#include <efsw/efsw.hpp>
#include <eterm/ui/uiterminal.hpp>
using namespace EE;
@@ -41,7 +43,7 @@ struct TerminalLaunchConfig {
bool closeOnExit{ false };
};
class App {
class App : private efsw::FileWatchListener {
public:
int run( int argc, char* argv[] );
@@ -91,10 +93,48 @@ class App {
UITerminal* createTerminal( UITabWidget* target = nullptr );
UITerminal* createTerminalSplit( SplitDirection direction, UITerminal* terminal );
UITerminal* createTerminalSplit( SplitDirection direction, UIWidget* widget );
void moveTab( UIWidget* widget, int offset );
template <typename T> void registerTabCommands( T& commandTarget, UIWidget* widget ) {
tabSplitter->registerSplitterCommands( commandTarget );
commandTarget.setCommand( "create-new-terminal", [this] { createNewTerminal(); } );
commandTarget.setCommand( "open-settings", [this] { showSettings(); } );
commandTarget.setCommand( "open-keybindings", [this] { openKeybindings(); } );
commandTarget.setCommand( "debug-widget-tree-view",
[this] { UIWidgetInspector::create( scene ); } );
commandTarget.setCommand( "move-tab-left", [this, widget] { moveTab( widget, -1 ); } );
commandTarget.setCommand( "move-tab-right", [this, widget] { moveTab( widget, 1 ); } );
commandTarget.setCommand( "split-right", [this, widget] {
createTerminalSplit( SplitDirection::Right, widget );
} );
commandTarget.setCommand( "split-bottom", [this, widget] {
createTerminalSplit( SplitDirection::Bottom, widget );
} );
commandTarget.setCommand(
"split-left", [this, widget] { createTerminalSplit( SplitDirection::Left, widget ); } );
commandTarget.setCommand(
"split-top", [this, widget] { createTerminalSplit( SplitDirection::Top, widget ); } );
}
void addTabKeyBindings( UITerminal* terminal );
KeyBindings::ShortcutMap getDefaultKeybindings() const;
void loadKeybindings();
void reloadKeybindings();
void applyKeybindings( UITerminal* terminal );
void applyKeybindings( UICodeEditor* editor );
void openKeybindings();
void handleFileAction( efsw::WatchID, const std::string& dir, const std::string& filename,
efsw::Action action, const std::string& oldFilename ) override;
void showSettings();
void openFontPicker( bool uiFont, bool fallbackFont = false );
@@ -117,6 +157,7 @@ class App {
UIIcon* terminalIcon{ nullptr };
UIMessageBox* closeDialog{ nullptr };
UIWindow* settingsWindow{ nullptr };
UICodeEditor* keybindingsEditor{ nullptr };
UIWidget* closeDialogWidget{ nullptr };
UIWindow* maximizedTabWidgetWindow{ nullptr };
UITabWidget* maximizedTabWidget{ nullptr };
@@ -124,6 +165,10 @@ class App {
TerminalLaunchConfig terminalConfig;
std::unique_ptr<eterm::AppConfig> config;
std::map<std::string, TerminalColorScheme> terminalColorSchemes;
std::unordered_map<std::string, std::string> keybindings;
std::string keybindingsPath;
std::unique_ptr<efsw::FileWatcher> fileWatcher;
std::atomic<bool> keybindingsChanged{ false };
const TerminalColorScheme* selectedColorScheme{ nullptr };
Float terminalFontSize{ 12 };
bool warnBeforeClose{ false };
+183
View File
@@ -0,0 +1,183 @@
#include "eterm.hpp"
#include <eepp/system/filesystem.hpp>
#include <eepp/system/inifile.hpp>
#include <eepp/ui/uicodeeditor.hpp>
namespace eterm {
KeyBindings::ShortcutMap App::getDefaultKeybindings() const {
return {
{ { KEY_C, KEYMOD_CTRL | KEYMOD_SHIFT }, "terminal-copy" },
{ { KEY_V, KEYMOD_CTRL | KEYMOD_SHIFT }, "terminal-paste" },
{ { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "create-new-terminal" },
{ { KEY_E,
KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT },
UITerminal::getExclusiveModeToggleCommandName() },
{ { KEY_S, KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() },
"terminal-rename" },
{ { KEY_COMMA, KeyMod::getDefaultModifier() }, "open-settings" },
{ { KEY_W, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "close-tab" },
{ { KEY_F11, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "debug-widget-tree-view" },
{ { KEY_PAGEDOWN, KEYMOD_CTRL }, "next-tab" },
{ { KEY_PAGEUP, KEYMOD_CTRL }, "previous-tab" },
{ { KEY_TAB, KEYMOD_CTRL }, "next-tab" },
{ { KEY_TAB, KEYMOD_CTRL | KEYMOD_SHIFT }, "previous-tab" },
{ { KEY_1, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-1" },
{ { KEY_2, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-2" },
{ { KEY_3, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-3" },
{ { KEY_4, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-4" },
{ { KEY_5, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-5" },
{ { KEY_6, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-6" },
{ { KEY_7, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-7" },
{ { KEY_8, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-8" },
{ { KEY_9, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-tab-9" },
{ { KEY_0, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "switch-to-last-tab" },
{ { KEY_LEFT, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "move-tab-left" },
{ { KEY_RIGHT, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "move-tab-right" },
{ { KEY_L, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "split-right" },
{ { KEY_K, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "split-bottom" },
{ { KEY_J, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "split-left" },
{ { KEY_I, KeyMod::getDefaultSecondaryModifier() | KEYMOD_SHIFT }, "split-top" },
{ { KEY_J, KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() },
"switch-to-previous-split" },
{ { KEY_L, KeyMod::getDefaultModifier() | KeyMod::getDefaultSecondaryModifier() },
"switch-to-next-split" },
};
}
void App::loadKeybindings() {
IniFile ini( keybindingsPath );
bool changed = false;
std::string defaultModifier = ini.getValue( "modifier", "mod" );
if ( defaultModifier.empty() ) {
defaultModifier = KeyMod::getDefaultModifierString();
ini.setValue( "modifier", "mod", defaultModifier );
changed = true;
}
if ( const Uint32 modifier = KeyMod::getKeyMod( defaultModifier ); modifier != KEYMOD_NONE )
KeyMod::setDefaultModifier( modifier );
std::string defaultSecondaryModifier = ini.getValue( "modifier", "mod2" );
if ( defaultSecondaryModifier.empty() ) {
defaultSecondaryModifier = KeyMod::getDefaultSecondaryModifierString();
ini.setValue( "modifier", "mod2", defaultSecondaryModifier );
changed = true;
}
if ( const Uint32 modifier = KeyMod::getKeyMod( defaultSecondaryModifier );
modifier != KEYMOD_NONE && !( modifier & KeyMod::getDefaultModifier() ) ) {
KeyMod::setDefaultSecondaryModifier( modifier );
} else {
defaultSecondaryModifier = KeyMod::getDefaultSecondaryModifierString();
ini.setValue( "modifier", "mod2", defaultSecondaryModifier );
changed = true;
}
KeyBindings formatter( appWindow->getInput() );
auto defaults = getDefaultKeybindings();
const bool hasKeybindings = ini.findKey( "eterm" ) != IniFile::noID;
if ( hasKeybindings ) {
keybindings = ini.getKeyUnorderedMap( "eterm" );
} else {
keybindings.clear();
for ( const auto& shortcut : KeyBindings::getOrderedShortcuts( defaults ) ) {
const auto& command = defaults.find( shortcut )->second;
const std::string shortcutString = formatter.getShortcutString( shortcut );
keybindings[shortcutString] = command;
ini.setValue( "eterm", shortcutString, command );
}
changed = true;
}
if ( hasKeybindings ) {
std::unordered_map<std::string, std::string> commands;
for ( const auto& [shortcut, command] : keybindings )
commands[command] = shortcut;
for ( const auto& shortcut : KeyBindings::getOrderedShortcuts( defaults ) ) {
const auto& command = defaults.find( shortcut )->second;
const std::string shortcutString = formatter.getShortcutString( shortcut );
if ( commands.find( command ) == commands.end() &&
keybindings.find( shortcutString ) == keybindings.end() ) {
keybindings[shortcutString] = command;
commands[command] = shortcutString;
ini.setValue( "eterm", shortcutString, command );
changed = true;
}
}
}
if ( changed )
ini.writeFile();
}
void App::applyKeybindings( UITerminal* terminal ) {
terminal->getKeyBindings().reset();
terminal->getKeyBindings().addKeybindsStringUnordered( keybindings );
}
void App::applyKeybindings( UICodeEditor* editor ) {
editor->getKeyBindings().setKeybinds( *UICodeEditor::getDefaultKeybindings() );
editor->addKeyBinding( { KEY_S, KeyMod::getDefaultModifier() }, "save-doc", true );
editor->getKeyBindings().addKeybindsStringUnordered( keybindings );
}
void App::reloadKeybindings() {
if ( !FileSystem::fileExists( keybindingsPath ) )
return;
keybindings.clear();
loadKeybindings();
forEachTerminal( [this]( UITerminal* terminal ) { applyKeybindings( terminal ); } );
if ( keybindingsEditor && tabSplitter->ownedWidgetExists( keybindingsEditor ) )
applyKeybindings( keybindingsEditor );
}
void App::openKeybindings() {
if ( keybindingsEditor && tabSplitter->ownedWidgetExists( keybindingsEditor ) ) {
if ( auto* tabs = tabSplitter->tabWidgetFromWidget( keybindingsEditor ) )
tabs->setTabSelected( tabs->getTabFromOwnedWidget( keybindingsEditor ) );
keybindingsEditor->setFocus();
return;
}
auto* editor = UICodeEditor::New();
if ( editor->loadFromFile( keybindingsPath ) == TextDocument::LoadStatus::Failed ) {
editor->close();
return;
}
editor->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
editor->setFontSize( terminalFontSize );
editor->setSyntaxDefinition( editor->getDocument().guessSyntax() );
editor->getDocument().setCommand( "save-doc", [editor] { editor->getDocument().save(); } );
registerTabCommands( editor->getDocument(), editor );
applyKeybindings( editor );
editor->on( Event::OnClose, [this, editor]( const Event* ) {
if ( keybindingsEditor == editor )
keybindingsEditor = nullptr;
} );
auto* current = tabSplitter->getCurWidget();
auto* target =
current ? tabSplitter->tabWidgetFromWidget( current ) : tabSplitter->getFirstTabWidget();
keybindingsEditor = editor;
auto* tab = tabSplitter->createWidgetInTabWidget( target, editor, "keybindings.cfg" ).first;
const auto updateTabState = [editor, tab]( const Event* ) {
const bool dirty = editor->getDocument().isDirty();
tab->removeClass( dirty ? "tab_clear" : "tab_modified" );
tab->addClass( dirty ? "tab_modified" : "tab_clear" );
};
editor->on( Event::OnTextChanged, updateTabState );
editor->on( Event::OnDocumentUndoRedo, updateTabState );
editor->on( Event::OnDocumentSave, updateTabState );
updateTabState( nullptr );
editor->setFocus();
}
void App::handleFileAction( efsw::WatchID, const std::string&, const std::string& filename,
efsw::Action action, const std::string& oldFilename ) {
if ( ( filename == "keybindings.cfg" || oldFilename == "keybindings.cfg" ) &&
( action == efsw::Actions::Add || action == efsw::Actions::Modified ||
action == efsw::Actions::Moved ) ) {
keybindingsChanged.store( true, std::memory_order_release );
}
}
} // namespace eterm