Added Open in New Window and Move to New Window as tab right-click options and Edit options (SpartanJ/ecode#629).

Added `Move Tab to Start` and `Move Tab to End` in tab right-click options (SpartanJ/ecode#630).
Added `--profile` CLI option (SpartanJ/ecode#634).
Added `--disable-plugins` CLI option (SpartanJ/ecode#635).
Moved `crashes` directory to profile directory (SpartanJ/ecode#639).
Added `Settings -> Terminal -> Close Terminal Tab on Exit` (SpartanJ/ecode#643).
This commit is contained in:
Martín Lucas Golini
2025-09-10 01:35:11 -03:00
parent 3a7e4add3a
commit 97a89902e2
13 changed files with 261 additions and 72 deletions

View File

@@ -98,6 +98,8 @@ class EE_API UITabWidget : public UIWidget {
void insertTab( UITab* tab, const Uint32& index );
bool moveTab( UITab* tab, Uint32 index );
virtual void setTheme( UITheme* theme );
UITab* getTabSelected() const;
@@ -207,7 +209,7 @@ class EE_API UITabWidget : public UIWidget {
UIScrollBar* getTabScroll() const;
void swapTabs( UITab* left, UITab* right );
bool swapTabs( UITab* left, UITab* right );
void setSplitFunction( SplitFunctionCb cb, Float splitEdgePercent = 0.1 );

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 17.0.0, 2025-08-21T16:38:02. -->
<!-- Written by QtCreator 17.0.1, 2025-09-09T20:47:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@@ -647,7 +647,9 @@ void UICodeEditor::onFontStyleChanged() {
void UICodeEditor::onDocumentLoaded( TextDocument* ) {
if ( mInvalidateOnLoaded ) {
onDocumentLoaded();
ensureMainThread( [this] {
onDocumentLoaded();
} );
mInvalidateOnLoaded = false;
}
}

View File

@@ -981,9 +981,9 @@ void UITabWidget::tryCloseTab( UITab* tab, FocusTabBehavior focusTabBehavior ) {
removeTab( tab, true, false, focusTabBehavior );
}
void UITabWidget::swapTabs( UITab* left, UITab* right ) {
bool UITabWidget::swapTabs( UITab* left, UITab* right ) {
if ( !left || !right || left->getTabWidget() != this || right->getTabWidget() != this )
return;
return false;
Uint32 leftIndex = getTabIndex( left );
Uint32 rightIndex = getTabIndex( right );
if ( leftIndex != eeINDEX_NOT_FOUND && rightIndex != eeINDEX_NOT_FOUND ) {
@@ -995,7 +995,36 @@ void UITabWidget::swapTabs( UITab* left, UITab* right ) {
mTabs[rightIndex] = left;
posTabs();
zorderTabs();
return true;
}
return false;
}
bool UITabWidget::moveTab( UITab* tab, Uint32 index ) {
auto tabIndex = getTabIndex( tab );
if ( tabIndex == eeINDEX_NOT_FOUND || mTabs.empty() )
return false;
if ( index >= mTabs.size() )
index = mTabs.size() - 1;
if ( tabIndex == index )
return false;
if ( tabIndex > index ) {
while ( tabIndex > index ) {
swapTabs( mTabs[tabIndex], mTabs[tabIndex - 1] );
tabIndex--;
}
} else {
while ( tabIndex < index ) {
swapTabs( mTabs[tabIndex], mTabs[tabIndex + 1] );
tabIndex++;
}
}
return true;
}
void UITabWidget::setSplitFunction( SplitFunctionCb cb, Float splitEdgePercent ) {

View File

@@ -221,6 +221,7 @@ void AppConfig::load( const std::string& confPath, std::string& keybindingsPath,
term.scrollback = ini.getValueI( "terminal", "scrollback", 10000 );
term.unsupportedOSWarnDisabled =
ini.getValueB( "terminal", "unsupported_os_warn_disabled", false );
term.closeTerminalTabOnExit = ini.getValueB( "terminal", "close_terminal_tab_on_exit", false );
workspace.restoreLastSession = ini.getValueB( "workspace", "restore_last_session", false );
workspace.checkForUpdatesAtStartup =
@@ -242,7 +243,8 @@ void AppConfig::load( const std::string& confPath, std::string& keybindingsPath,
iniInfo = FileInfo( ini.path() );
pluginManager->setPluginsEnabled( pluginsEnabled, sync );
if ( !pluginManager->pluginsDisabled() )
pluginManager->setPluginsEnabled( pluginsEnabled, sync );
}
void AppConfig::save( const std::vector<std::string>& recentFiles,
@@ -377,6 +379,7 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
NewTerminalOrientation::toString( term.newTerminalOrientation ) );
ini.setValue( "terminal", "scrollback", String::toString( term.scrollback ) );
ini.setValueB( "terminal", "unsupported_os_warn_disabled", term.unsupportedOSWarnDisabled );
ini.setValueB( "terminal", "close_terminal_tab_on_exit", term.closeTerminalTabOnExit );
ini.setValueB( "window", "vsync", context.VSync );
ini.setValue( "window", "glversion",
@@ -389,9 +392,11 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
workspace.checkForUpdatesAtStartup );
ini.setValueB( "workspace", "session_snapshot", workspace.sessionSnapshot );
const auto& pluginsEnabled = pluginManager->getPluginsEnabled();
for ( const auto& plugin : pluginsEnabled )
ini.setValueB( "plugins", plugin.first, plugin.second );
if ( !pluginManager->pluginsDisabled() ) {
const auto& pluginsEnabled = pluginManager->getPluginsEnabled();
for ( const auto& plugin : pluginsEnabled )
ini.setValueB( "plugins", plugin.first, plugin.second );
}
for ( const auto& langExt : languagesExtensions.priorities )
ini.setValue( "languages_extensions", langExt.first, langExt.second );

View File

@@ -175,6 +175,7 @@ struct TerminalConfig {
NewTerminalOrientation::Horizontal };
Uint64 scrollback{ 10000 };
bool unsupportedOSWarnDisabled{ false };
bool closeTerminalTabOnExit{ false };
};
struct WorkspaceConfig {

View File

@@ -176,7 +176,7 @@ class WindowsSignalHandling {
}
static void handle_stacktrace( int skip_frames = 0 ) {
std::string crashesPath( Sys::getProcessPath() );
std::string crashesPath( Sys::getConfigPath( "ecode" ) );
FileSystem::dirAddSlashAtEnd( crashesPath );
crashesPath += "crashes";
FileSystem::dirAddSlashAtEnd( crashesPath );

View File

@@ -614,11 +614,13 @@ void App::initPluginManager() {
mPluginManager->registerPlugin( AIAssistantPlugin::Definition() );
mPluginManager->registerPlugin( SpellCheckerPlugin::Definition() );
mPluginManager->registerPlugin( DiscordRPCplugin::Definition() );
mPluginManager->setPluginsDisabled( mDisablePlugins );
}
std::pair<bool, std::string> App::generateConfigPath() {
if ( mPortableMode ) {
std::string path( Sys::getProcessPath() + "config" );
std::string path( mProfilePath.empty() ? ( Sys::getProcessPath() + "config" )
: mProfilePath );
FileSystem::dirAddSlashAtEnd( path );
bool fileExists = FileSystem::fileExists( path );
@@ -1482,14 +1484,9 @@ void App::onTabCreated( UITab* tab, UIWidget* ) {
menuAdd( "split_top", "Split Top", "split-vertical", "split-top" );
menuAdd( "split_bottom", "Split Bottom", "split-vertical", "split-bottom" );
menu->addSeparator();
menuAdd( "open_containing_folder_ellipsis", "Open Containing Folder...", "folder-open",
"open-containing-folder" );
menuAdd( "open_in_new_window_ellipsis", "Open in New Window...", "window",
"open-in-new-window" );
menuAdd( "copy_containing_folder_path_ellipsis", "Copy Containing Folder Path...",
"copy", "copy-containing-folder-path" );
@@ -1497,6 +1494,21 @@ void App::onTabCreated( UITab* tab, UIWidget* ) {
menuAdd( "copy_file_path_and_position", "Copy File Path and Position", "copy",
"copy-file-path-and-position" );
menu->addSeparator();
menuAdd( "open_in_new_window", "Open in New Window", "window", "open-in-new-window" );
menuAdd( "move_to_new_window", "Move to New Window", "window", "move-to-new-window" );
}
if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ||
tab->getOwnedWidget()->isType( UI_TYPE_TERMINAL ) ) {
menu->addSeparator();
menuAdd( "move_tab_to_start", "Move Tab To Start", "window", "move-tab-to-start" );
menuAdd( "move_tab_to_end", "Move Tab To End", "window", "move-tab-to-end" );
}
menu->addEventListener( Event::OnItemClicked, [tab, this]( const Event* event ) {
@@ -2496,6 +2508,40 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
Sys::execute( cmd );
}
} );
doc.setCommand( "move-to-new-window", [this] {
auto editor = mSplitter->getCurEditor();
if ( editor == nullptr || editor->getDocumentRef() == nullptr ||
editor->getDocumentRef()->getFilePath().empty() )
return;
UITabWidget* tabWidget = mSplitter->tabWidgetFromEditor( editor );
if ( tabWidget )
tabWidget->removeTab( (UITab*)editor->getData() );
std::string processPath = Sys::getProcessFilePath();
if ( !processPath.empty() ) {
auto cmd( processPath + " -x \"" + editor->getDocumentRef()->getFilePath() + "\"" );
Sys::execute( cmd );
}
} );
doc.setCommand( "move-tab-to-start", [this] {
auto widget = mSplitter->getCurWidget();
if ( widget == nullptr || widget->getData() == 0 )
return;
UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( widget );
if ( tabWidget ) {
UITab* tab = (UITab*)widget->getData();
tabWidget->moveTab( tab, 0 );
}
} );
doc.setCommand( "move-tab-to-end", [this] {
auto widget = mSplitter->getCurWidget();
if ( widget == nullptr || widget->getData() == 0 )
return;
UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( widget );
if ( tabWidget ) {
UITab* tab = (UITab*)widget->getData();
tabWidget->moveTab( tab, tabWidget->getTabCount() );
}
} );
registerUnlockedCommands( doc );
editor->on( Event::OnDocumentSave, [this]( const Event* event ) {
@@ -3551,11 +3597,7 @@ bool App::needsRedirectToRunningProcess( std::string file ) {
return true;
}
void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDensity,
const std::string& colorScheme, bool terminal, bool frameBuffer, bool benchmarkMode,
std::string css, const std::string& fileToOpen, bool stdOutLogs,
bool disableFileLogs, bool openClean, bool portable, std::string language,
bool incognito, bool prematureExit ) {
void App::init( InitParameters& params ) {
Http::setThreadPool( mThreadPool );
DisplayManager* displayManager = Engine::instance()->getDisplayManager();
Display* currentDisplay = displayManager->getDisplayIndex( 0 );
@@ -3565,11 +3607,13 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
return;
}
mIncognito = incognito;
mPortableMode = portable;
mIncognito = params.incognito;
mPortableMode = params.portable || !params.profile.empty();
mProfilePath = params.profile;
mDisplayDPI = currentDisplay->getDPI();
mUseFrameBuffer = frameBuffer;
mBenchmarkMode = benchmarkMode;
mUseFrameBuffer = params.frameBuffer;
mBenchmarkMode = params.benchmarkMode;
mDisablePlugins = params.disablePlugins;
mResPath = Sys::getProcessPath();
#if EE_PLATFORM == EE_PLATFORM_LINUX
@@ -3581,13 +3625,13 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
mResPath += "assets";
FileSystem::dirAddSlashAtEnd( mResPath );
bool firstRun = loadConfig( logLevel, currentDisplay->getSize(), prematureExit, stdOutLogs,
disableFileLogs );
bool firstRun = loadConfig( params.logLevel, currentDisplay->getSize(), params.prematureExit,
params.stdOutLogs, params.disableFileLogs );
if ( prematureExit )
if ( params.prematureExit )
return;
if ( !openClean && needsRedirectToRunningProcess( file ) )
if ( !params.openClean && needsRedirectToRunningProcess( params.file ) )
return;
currentDisplay = displayManager->getDisplayIndex( mConfig.windowState.displayIndex <
@@ -3598,15 +3642,15 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
#if EE_PLATFORM == EE_PLATFORM_ANDROID
mConfig.windowState.pixelDensity =
pidelDensity > 0
? pidelDensity
params.pidelDensity > 0
? params.pidelDensity
: ( mConfig.windowState.pixelDensity > 0 ? mConfig.windowState.pixelDensity
: currentDisplay->getPixelDensity() > 2 ? currentDisplay->getPixelDensity() / 2
: currentDisplay->getPixelDensity() );
#else
mConfig.windowState.pixelDensity =
pidelDensity > 0
? pidelDensity
params.pidelDensity > 0
? params.pidelDensity
: ( mConfig.windowState.pixelDensity > 0 ? mConfig.windowState.pixelDensity
: currentDisplay->getPixelDensity() );
#endif
@@ -3955,19 +3999,19 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
mUISceneNode->setThreadPool( mThreadPool );
mUIColorScheme = mConfig.ui.colorScheme;
if ( language.empty() )
language = mConfig.ui.language;
if ( !language.empty() )
mUISceneNode->getTranslator().setCurrentLanguage( language );
if ( params.language.empty() )
params.language = mConfig.ui.language;
if ( !params.language.empty() )
mUISceneNode->getTranslator().setCurrentLanguage( params.language );
std::string currentLanguage( mUISceneNode->getTranslator().getCurrentLanguage() );
mi18nPath = mResPath + "i18n" + FileSystem::getOSSlash();
std::string langPath( mi18nPath + currentLanguage + ".xml" );
if ( currentLanguage != "en" && FileSystem::fileExists( langPath ) )
mUISceneNode->getTranslator().loadFromFile( langPath );
if ( !colorScheme.empty() ) {
mUIColorScheme =
colorScheme == "light" ? ColorSchemePreference::Light : ColorSchemePreference::Dark;
if ( !params.colorScheme.empty() ) {
mUIColorScheme = params.colorScheme == "light" ? ColorSchemePreference::Light
: ColorSchemePreference::Dark;
}
mUISceneNode->setColorSchemePreference( mUIColorScheme );
@@ -3987,12 +4031,12 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
setTheme( getThemePath() );
if ( css.empty() )
css = mConfigPath + "style.css";
if ( params.css.empty() )
params.css = mConfigPath + "style.css";
if ( FileSystem::fileExists( css ) ) {
if ( FileSystem::fileExists( params.css ) ) {
CSS::StyleSheetParser parser;
if ( parser.loadFromFile( css ) )
if ( parser.loadFromFile( params.css ) )
mUISceneNode->combineStyleSheet( parser.getStyleSheet(), false );
}
@@ -4051,7 +4095,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
mUISceneNode->on( Event::KeyDown, [this]( const Event* event ) {
trySendUnlockedCmd( *static_cast<const KeyEvent*>( event ) );
} );
if ( logLevel == LogLevel::Debug )
if ( params.logLevel == LogLevel::Debug )
mUISceneNode->setVerbose( true );
mDocInfo->setVisible( mConfig.editor.showDocInfo );
@@ -4174,15 +4218,15 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
file = "";
#endif
if ( terminal && file.empty() && fileToOpen.empty() ) {
if ( params.terminal && params.file.empty() && params.fileToOpen.empty() ) {
showSidePanel( false );
showStatusBar( false );
mTerminalManager->createNewTerminal();
} else {
initProjectTreeView( file, openClean );
initProjectTreeView( params.file, params.openClean );
}
mFileToOpen = fileToOpen;
mFileToOpen = params.fileToOpen;
Log::info( "Init ProjectTreeView took: %.2f ms",
globalClock.getElapsedTime().asMilliseconds() );
@@ -4348,10 +4392,18 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
"Try to set the default language the editor will be loaded. The language must be supported "
"in order to this option do something.",
{ "language" }, "" );
args::ValueFlag<std::string> profile( parser, "profile", "Start with profile at <path>",
{ "profile" }, "" );
args::Flag disablePlugins( parser, "disable-plugins",
"Disable all plugins. This option is not persisted and is effective "
"only when the command opens a new window.",
{ "disable-plugins" } );
#ifdef EE_TEXT_SHAPER_ENABLED
args::Flag textShaper( parser, "text-shaper", "Enables text-shaping capabilities",
{ "text-shaper" } );
#endif
std::vector<std::string> args;
try {
args = Sys::parseArguments( argc, argv );
@@ -4408,15 +4460,29 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
Text::TextShaperEnabled = true;
#endif
App::InitParameters params;
params.logLevel = logLevel.Get();
params.file = folder ? folder.Get() : fileOrFolderPos.Get();
params.pidelDensity = pixelDensityConf ? pixelDensityConf.Get() : 0.f;
params.colorScheme = prefersColorScheme ? prefersColorScheme.Get() : "";
params.terminal = terminal.Get();
params.frameBuffer = fb.Get();
params.benchmarkMode = benchmarkMode.Get();
params.css = css.Get();
params.fileToOpen = file.Get();
params.stdOutLogs = verbose.Get();
params.disableFileLogs = disableFileLogs.Get();
params.openClean = openClean.Get();
params.portable = portable.Get();
params.language = language.Get();
params.incognito = incognito.Get();
params.prematureExit = health || ( healthLang && !healthLang.Get().empty() ) ||
( exportLangPath && !exportLangPath.Get().empty() );
params.profile = profile.Get();
params.disablePlugins = disablePlugins.Get();
appInstance = eeNew( App, ( jobs, args ) );
appInstance->init( logLevel.Get(), folder ? folder.Get() : fileOrFolderPos.Get(),
pixelDensityConf ? pixelDensityConf.Get() : 0.f,
prefersColorScheme ? prefersColorScheme.Get() : "", terminal.Get(), fb.Get(),
benchmarkMode.Get(), css.Get(), file.Get(), verbose.Get(),
disableFileLogs.Get(), openClean.Get(), portable.Get(), language.Get(),
incognito.Get(),
health || ( healthLang && !healthLang.Get().empty() ) ||
( exportLangPath && !exportLangPath.Get().empty() ) );
appInstance->init( params );
if ( exportLangPath && !exportLangPath.Get().empty() ) {
Sys::windowAttachConsole();

View File

@@ -38,11 +38,28 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
~App();
void init( const LogLevel& logLevel, std::string file, const Float& pidelDensity,
const std::string& colorScheme, bool terminal, bool frameBuffer, bool benchmarkMode,
std::string css, const std::string& fileToOpen, bool stdOutLogs,
bool disableFileLogs, bool openClean, bool portable, std::string language,
bool incognito, bool prematureExit );
struct InitParameters {
LogLevel logLevel{ LogLevel::Info };
std::string file;
Float pidelDensity{ 0.f };
std::string colorScheme;
bool terminal{ false };
bool frameBuffer{ false };
bool benchmarkMode{ false };
std::string css;
std::string fileToOpen;
bool stdOutLogs{ false };
bool disableFileLogs{ false};
bool openClean{ false };
bool portable{ false };
std::string language;
bool incognito{ false };
bool prematureExit{ false };
std::string profile;
bool disablePlugins{ false };
};
void init( InitParameters& );
void createWidgetInspector();
@@ -552,6 +569,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
const std::string& getLanguagesPath() const { return mLanguagesPath; }
bool pluginsDisabled() const { return mDisablePlugins; }
protected:
std::vector<std::string> mArgs;
EE::Window::Window* mWindow{ nullptr };
@@ -605,6 +624,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
bool mDirTreeReady{ false };
bool mUseFrameBuffer{ false };
bool mBenchmarkMode{ false };
bool mDisablePlugins{ false };
bool mPortableMode{ false };
bool mPortableModeFailed{ false };
bool mDestroyingApp{ false };
@@ -656,6 +676,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
std::condition_variable mAsyncResourcesLoadCond;
std::vector<SyntaxColorScheme> mColorSchemes;
bool mAsyncResourcesLoaded{ false };
std::string mProfilePath;
void sortSidePanel();

View File

@@ -134,6 +134,8 @@ class PluginContextProvider {
virtual AppConfig& getConfig() = 0;
virtual bool isDirTreeReady() const = 0;
virtual bool pluginsDisabled() const = 0;
};
} // namespace ecode

View File

@@ -257,8 +257,8 @@ class PluginRequestHandle {
protected:
PluginIDType mId{ 0 };
PluginImmediateResponse
mResponse; //! Some requests can be responded immediately, so the message comes in the handle
PluginImmediateResponse mResponse; //! Some requests can be responded immediately, so the
//! message comes in the handle
};
class PluginManager {
@@ -275,9 +275,8 @@ class PluginManager {
using OnLoadFileCb = std::function<void( const std::string&, const OnFileLoadedCb& )>;
PluginManager( const std::string& resourcesPath, const std::string& pluginsPath,
const std::string& configPath,
std::shared_ptr<ThreadPool> pool, const OnLoadFileCb& loadFileCb,
PluginContextProvider* context );
const std::string& configPath, std::shared_ptr<ThreadPool> pool,
const OnLoadFileCb& loadFileCb, PluginContextProvider* context );
~PluginManager();
@@ -368,6 +367,10 @@ class PluginManager {
void forEachPlugin( std::function<void( Plugin* )> fn );
void setPluginsDisabled( bool pluginsDisabled ) { mPluginsDisabled = pluginsDisabled; }
bool pluginsDisabled() const { return mPluginsDisabled; }
protected:
using SubscribedPlugins =
std::map<std::string, std::function<PluginRequestHandle( const PluginMessage& )>>;
@@ -392,6 +395,7 @@ class PluginManager {
UnorderedSet<Plugin*> mPluginsFSSubs;
bool mClosing{ false };
bool mPluginReloadEnabled{ false };
bool mPluginsDisabled{ false };
bool hasDefinition( const std::string& id );

View File

@@ -963,6 +963,11 @@ UIMenu* SettingsMenu::createTerminalMenu() {
mTerminalMenu->addSubMenu( i18n( "new_terminal_behavior", "New Terminal Behavior" ),
findIcon( "terminal" ), newTerminalBehaviorSubMenu );
mTerminalMenu
->addCheckBox( i18n( "close_terminal_tab_on_exit", "Close Terminal Tab on Exit" ),
mApp->getConfig().term.closeTerminalTabOnExit )
->setId( "close-terminal-tab-on-exit" );
mTerminalMenu
->add( i18n( "configure_terminal_shell", "Configure Terminal Shell" ),
findIcon( "terminal" ), getKeybind( "configure-terminal-shell" ) )
@@ -980,7 +985,14 @@ UIMenu* SettingsMenu::createTerminalMenu() {
mTerminalMenu->on( Event::OnItemClicked, [this]( const Event* event ) {
const std::string& id( event->getNode()->getId() );
if ( mSplitter->getCurWidget() && mSplitter->getCurWidget()->isType( UI_TYPE_TERMINAL ) ) {
if ( "close-terminal-tab-on-exit" == id ) {
bool active = event->getNode()->asType<UIMenuCheckBox>()->isActive();
mApp->getConfig().term.closeTerminalTabOnExit = active;
mSplitter->forEachWidgetType( UI_TYPE_TERMINAL, [active]( UIWidget* widget ) {
widget->asType<UITerminal>()->getTerm()->setKeepAlive( !active );
} );
} else if ( mSplitter->getCurWidget() &&
mSplitter->getCurWidget()->isType( UI_TYPE_TERMINAL ) ) {
UITerminal* terminal = mSplitter->getCurWidget()->asType<UITerminal>();
if ( "exclusive-mode" == id ) {
terminal->setExclusiveMode(
@@ -1027,10 +1039,6 @@ UIMenu* SettingsMenu::createEditMenu() {
->add( i18n( "open_containing_folder_ellipsis", "Open Containing Folder..." ),
findIcon( "folder-open" ), getKeybind( "open-containing-folder" ) )
->setId( "open-containing-folder" );
mEditMenu
->add( i18n( "open_in_new_window_ellipsis", "Open in New Window..." ), findIcon( "window" ),
getKeybind( "open-in-new-window" ) )
->setId( "open-in-new-window" );
mEditMenu
->add( i18n( "copy_containing_folder_path_ellipsis", "Copy Containing Folder Path..." ),
findIcon( "copy" ), getKeybind( "copy-containing-folder-path" ) )
@@ -1039,17 +1047,32 @@ UIMenu* SettingsMenu::createEditMenu() {
->add( i18n( "copy_file_path", "Copy File Path" ), findIcon( "copy" ),
getKeybind( "copy-file-path" ) )
->setId( "copy-file-path" );
UIMenuSeparator* moveSep = mEditMenu->addSeparator();
mEditMenu
->add( i18n( "open_in_new_window", "Open in New Window" ), findIcon( "window" ),
getKeybind( "open-in-new-window" ) )
->setId( "open-in-new-window" );
mEditMenu
->add( i18n( "move_to_new_window", "Move to New Window" ), findIcon( "window" ),
getKeybind( "move-to-new-window" ) )
->setId( "move-to-new-window" );
UIMenuSeparator* fileSep = mEditMenu->addSeparator();
mEditMenu
->add( i18n( "key_bindings", "Key Bindings" ), findIcon( "keybindings" ),
getKeybind( "keybindings" ) )
->setId( "keybindings" );
mEditMenu->on( Event::OnItemClicked, [this]( const Event* event ) {
if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) )
return;
runCommand( event->getNode()->getId() );
} );
mEditMenu->on( Event::OnMenuShow, [this, fileSep]( const Event* ) {
mEditMenu->on( Event::OnMenuShow, [this, fileSep, moveSep]( const Event* ) {
if ( !mSplitter->curEditorExistsAndFocused() ) {
mEditMenu->getItemId( "undo" )->setEnabled( false );
mEditMenu->getItemId( "redo" )->setEnabled( false );
@@ -1058,7 +1081,9 @@ UIMenu* SettingsMenu::createEditMenu() {
mEditMenu->getItemId( "open-containing-folder" )->setVisible( false );
mEditMenu->getItemId( "copy-containing-folder-path" )->setVisible( false );
mEditMenu->getItemId( "open-in-new-window" )->setVisible( false );
mEditMenu->getItemId( "move-to-new-window" )->setVisible( false );
mEditMenu->getItemId( "copy-file-path" )->setVisible( false );
moveSep->setVisible( false );
fileSep->setVisible( false );
return;
}
@@ -1070,7 +1095,9 @@ UIMenu* SettingsMenu::createEditMenu() {
mEditMenu->getItemId( "open-containing-folder" )->setVisible( doc->hasFilepath() );
mEditMenu->getItemId( "copy-containing-folder-path" )->setVisible( doc->hasFilepath() );
mEditMenu->getItemId( "open-in-new-window" )->setVisible( doc->hasFilepath() );
mEditMenu->getItemId( "move-to-new-window" )->setVisible( doc->hasFilepath() );
mEditMenu->getItemId( "copy-file-path" )->setVisible( doc->hasFilepath() );
moveSep->setVisible( true );
fileSep->setVisible( doc->hasFilepath() );
} );
return mEditMenu;

View File

@@ -524,6 +524,16 @@ UITerminal* TerminalManager::createNewTerminal(
term->setTitle( title );
auto csIt = mTerminalColorSchemes.find( mTerminalCurrentColorScheme );
term->getTerm()->getTerminal()->setAllowMemoryTrimnming( true );
term->getTerm()->setKeepAlive( !mApp->getConfig().term.closeTerminalTabOnExit );
term->getTerm()->pushEventCallback( [this, term]( const TerminalDisplay::Event& event ) {
if ( event.type == TerminalDisplay::EventType::PROCESS_EXIT &&
mApp->getConfig().term.closeTerminalTabOnExit && term->getData() != 0 ) {
UITab* tab = (UITab*)term->getData();
auto* tabWidget = mApp->getSplitter()->tabWidgetFromWidget( term );
if ( tabWidget )
tabWidget->removeTab( tab );
}
} );
term->setColorScheme( csIt != mTerminalColorSchemes.end()
? mTerminalColorSchemes.at( mTerminalCurrentColorScheme )
: TerminalColorScheme::getDefault() );
@@ -566,6 +576,26 @@ UITerminal* TerminalManager::createNewTerminal(
term->setExclusiveMode( !term->getExclusiveMode() );
mApp->updateTerminalMenu();
} );
term->setCommand( "move-tab-to-start", [this] {
auto widget = mApp->getSplitter()->getCurWidget();
if ( widget == nullptr || widget->getData() == 0 )
return;
UITabWidget* tabWidget = mApp->getSplitter()->tabWidgetFromWidget( widget );
if ( tabWidget ) {
UITab* tab = (UITab*)widget->getData();
tabWidget->moveTab( tab, 0 );
}
} );
term->setCommand( "move-tab-to-end", [this] {
auto widget = mApp->getSplitter()->getCurWidget();
if ( widget == nullptr || widget->getData() == 0 )
return;
UITabWidget* tabWidget = mApp->getSplitter()->tabWidgetFromWidget( widget );
if ( tabWidget ) {
UITab* tab = (UITab*)widget->getData();
tabWidget->moveTab( tab, tabWidget->getTabCount() );
}
} );
mApp->registerUnlockedCommands( *term );
term->setFocus();
return term;