Files
eepp/src/tools/eterm/eterm.cpp
Martín Lucas Golini 8991a089fc eterm clean up.
2024-03-15 20:22:15 -03:00

319 lines
11 KiB
C++

#include <args/args.hxx>
#include <eepp/ee.hpp>
#include <eterm/terminal/terminaldisplay.hpp>
#include <iostream>
EE::Window::Window* win = NULL;
std::shared_ptr<TerminalDisplay> terminal = nullptr;
Clock lastRender;
Clock secondsCounter;
Time frameTime{ Time::Zero };
bool benchmarkMode{ false };
std::string windowStringData;
std::map<std::string, TerminalColorScheme> terminalColorSchemes;
void loadColorSchemes( const std::string& resPath ) {
auto configPath = Sys::getConfigPath( "eterm" );
auto colorSchemes =
TerminalColorScheme::loadFromFile( resPath + "colorschemes/terminalcolorschemes.conf" );
auto colorSchemesPath = configPath + FileSystem::getOSSlash() + "colorschemes";
if ( FileSystem::isDirectory( colorSchemesPath ) ) {
auto colorSchemesFiles = FileSystem::filesGetInPath( colorSchemesPath );
for ( auto& file : colorSchemesFiles ) {
auto colorSchemesInFile = TerminalColorScheme::loadFromFile( file );
std::copy( colorSchemesInFile.begin(), colorSchemesInFile.end(),
std::back_inserter( colorSchemes ) );
}
}
for ( auto colorScheme : colorSchemes )
terminalColorSchemes.insert( { colorScheme.getName(), colorScheme } );
}
void inputCallback( InputEvent* event ) {
if ( !terminal || event->Type == InputEvent::EventsSent )
return;
switch ( event->Type ) {
case InputEvent::MouseMotion: {
terminal->onMouseMove( win->getInput()->getMousePos(),
win->getInput()->getPressTrigger() );
break;
}
case InputEvent::MouseButtonDown: {
terminal->onMouseDown( win->getInput()->getMousePos(),
win->getInput()->getPressTrigger() );
#if EE_PLATFORM == EE_PLATFORM_ANDROID
win->startTextInput();
#endif
break;
}
case InputEvent::MouseButtonUp: {
terminal->onMouseUp( win->getInput()->getMousePos(),
win->getInput()->getReleaseTrigger() );
if ( win->getInput()->getDoubleClickTrigger() ) {
terminal->onMouseDoubleClick( win->getInput()->getMousePos(),
win->getInput()->getDoubleClickTrigger() );
}
break;
}
case InputEvent::Window: {
switch ( event->window.type ) {
case InputEvent::WindowKeyboardFocusLost:
case InputEvent::WindowKeyboardFocusGain: {
terminal->setFocus( win->hasFocus() );
break;
}
}
break;
}
case InputEvent::KeyUp: {
break;
}
case InputEvent::KeyDown: {
terminal->onKeyDown( event->key.keysym.sym, event->key.keysym.unicode,
event->key.keysym.mod, event->key.keysym.scancode );
#if EE_PLATFORM == EE_PLATFORM_ANDROID
if ( event->key.keysym.sym == KEY_RETURN ||
event->key.keysym.scancode == SCANCODE_RETURN ) {
win->startTextInput();
}
#endif
break;
}
case InputEvent::TextInput: {
terminal->onTextInput( event->text.text );
break;
}
case InputEvent::VideoExpose:
terminal->setFocus( win->hasFocus() );
terminal->invalidate();
break;
case InputEvent::VideoResize: {
terminal->setPosition( { 0, 0 } );
terminal->setSize( win->getSize().asFloat() );
break;
}
}
}
EE_MAIN_FUNC int main( int argc, char* argv[] ) {
#ifdef EE_DEBUG
Log::instance()->setLogToStdOut( true );
Log::instance()->setLiveWrite( true );
#endif
args::ArgumentParser parser( "eterm" );
args::HelpFlag help( parser, "help", "Display this help menu", { 'h', "help" } );
args::ValueFlag<std::string> shell( parser, "shell", "Shell name or path", { 's', "shell" },
"" );
args::ValueFlag<std::string> shellArgs( parser, "shell-args", "Shell command line arguments",
{ "shell-args" }, "" );
args::ValueFlag<size_t> historySize( parser, "scrollback", "Maximum history size (lines)",
{ 'l', "scrollback" }, 10000 );
args::Flag fb( parser, "framebuffer", "Use frame buffer (more memory usage, less CPU usage)",
{ "fb", "framebuffer" } );
args::ValueFlag<std::string> fontPath( parser, "fontpath", "Font path", { 'f', "font" } );
args::ValueFlag<std::string> fallbackFontPathF( parser, "fallback-fontpath",
"Fallback Font path", { "fallback-font" } );
args::ValueFlag<Float> fontSize( parser, "fontsize", "Font size (in dp)", { "fontsize" }, 11 );
args::ValueFlag<Float> width( parser, "winwidth", "Window width (in dp)", { "width" }, 1280 );
args::ValueFlag<Float> height( parser, "winheight", "Window height (in dp)", { "height" },
720 );
args::ValueFlag<Float> pixelDenstiyConf( parser, "pixel-density",
"Set default application pixel density",
{ 'd', "pixel-density" } );
args::Positional<std::string> wd( parser, "wording-dir", "Working Directory / executable" );
args::Flag closeOnExit( parser, "close-on-exit",
"close the application when the executable exits", { 'c', "close" } );
args::ValueFlag<std::string> executeInShell(
parser, "execute-in-shell", "execute program in shell", { 'e', "execute" }, "" );
args::Flag vsync( parser, "vsync", "Enable vsync", { "vsync" } );
args::ValueFlag<std::string> colorScheme( parser, "color-scheme", "Load color scheme",
{ "color-scheme" }, "" );
args::Flag listColorSchemes( parser, "color-schemes", "Lists color schemes",
{ "list-color-schemes" } );
args::ValueFlag<Uint32> maxFPS( parser, "max-fps",
"Maximum rendering frames per second of the terminal. Default "
"value will be the refresh rate of the screen.",
{ "max-fps" }, 0 );
args::Flag benchmarkModeFlag(
parser, "benchmark-mode",
"Render as much as possible to measure the rendering performance.", { "benchmark-mode" } );
try {
parser.ParseCLI( argc, argv );
} catch ( const args::Help& ) {
std::cout << parser;
return EXIT_SUCCESS;
} catch ( const args::ParseError& e ) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return EXIT_FAILURE;
} catch ( args::ValidationError& e ) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return EXIT_FAILURE;
}
DisplayManager* displayManager = Engine::instance()->getDisplayManager();
Display* currentDisplay = displayManager->getDisplayIndex( 0 );
std::string resPath = Sys::getProcessPath();
#if EE_PLATFORM == EE_PLATFORM_MACOS
if ( String::contains( resPath, "ecode.app" ) ) {
resPath = FileSystem::getCurrentWorkingDirectory();
FileSystem::dirAddSlashAtEnd( resPath );
}
#elif EE_PLATFORM == EE_PLATFORM_LINUX
if ( String::contains( resPath, ".mount_" ) ) {
resPath = FileSystem::getCurrentWorkingDirectory();
FileSystem::dirAddSlashAtEnd( resPath );
}
#elif EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN
resPath += "eterm/";
#endif
resPath += "assets";
FileSystem::dirAddSlashAtEnd( resPath );
if ( listColorSchemes.Get() || colorScheme )
loadColorSchemes( resPath );
if ( listColorSchemes.Get() ) {
std::cout << "Color schemes:\n";
for ( const auto& tcs : terminalColorSchemes )
std::cout << "\t" << tcs.first << "\n";
return EXIT_SUCCESS;
}
displayManager->enableScreenSaver();
displayManager->enableMouseFocusClickThrough();
displayManager->disableBypassCompositor();
Sizei winSize( width.Get(), height.Get() );
win = Engine::instance()->createWindow(
WindowSettings( winSize.getWidth(), winSize.getHeight(), "eterm", WindowStyle::Default,
WindowBackend::Default, 32, resPath + "icon/eterm.png",
pixelDenstiyConf ? pixelDenstiyConf.Get()
: currentDisplay->getPixelDensity() ),
ContextSettings( vsync.Get() ) );
if ( win->isOpen() ) {
win->setClearColor( RGB( 0, 0, 0 ) );
benchmarkMode = benchmarkModeFlag.Get();
FontTrueType* fontMono = nullptr;
if ( fontPath && FileSystem::fileExists( fontPath.Get() ) ) {
FileInfo file( fontPath.Get() );
fontMono = FontTrueType::New( "monospace" );
if ( fontMono->loadFromFile( file.getFilepath() ) ) {
FontFamily::loadFromRegular( fontMono );
} else {
fontMono = nullptr;
}
}
if ( fontMono == nullptr ) {
fontMono = FontTrueType::New( "monospace" );
fontMono->loadFromFile( resPath + "fonts/DejaVuSansMonoNerdFontComplete.ttf" );
FontFamily::loadFromRegular( fontMono, "DejaVuSansMono" );
}
if ( FileSystem::fileExists( resPath + "fonts/NotoColorEmoji.ttf" ) ) {
FontTrueType::New( "emoji-color" )
->loadFromFile( resPath + "fonts/NotoColorEmoji.ttf" );
} else if ( FileSystem::fileExists( resPath + "fonts/NotoEmoji-Regular.ttf" ) ) {
FontTrueType::New( "emoji-font" )
->loadFromFile( resPath + "fonts/NotoEmoji-Regular.ttf" );
}
std::string fallbackFontPath( fallbackFontPathF
? fallbackFontPathF.Get()
: resPath + "fonts/DroidSansFallbackFull.ttf" );
if ( FileSystem::fileExists( fallbackFontPath ) ) {
FontTrueType* fallbackFont = FontTrueType::New( "fallback-font" );
if ( fallbackFont->loadFromFile( fallbackFontPath ) )
FontManager::instance()->addFallbackFont( fallbackFont );
}
Float realMaxFPS = maxFPS.Get() ? maxFPS.Get() : currentDisplay->getRefreshRate();
frameTime = benchmarkMode ? Time::Zero : Milliseconds( 1000.f / realMaxFPS );
FileInfo file( wd ? wd.Get() : FileSystem::getCurrentWorkingDirectory() );
terminal = TerminalDisplay::create(
win, fontMono, PixelDensity::dpToPx( fontSize.Get() ), win->getSize().asFloat(),
file.isRegularFile() && file.isExecutable() ? file.getFilepath() : shell.Get(),
shellArgs ? String::split( shellArgs.Get() ) : std::vector<std::string>(),
file.getDirectoryPath(), historySize.Get(), nullptr, fb.Get(),
!( file.isRegularFile() && file.isExecutable() ) );
if ( terminal->getTerminal() == nullptr ) {
win->close();
win->showMessageBox( EE::Window::Window::MessageBoxType::Error, "eterm",
"Operating System not supported." );
terminal.reset();
Engine::destroySingleton();
MemoryManager::showResults();
return EXIT_FAILURE;
}
terminal->getTerminal()->setAllowMemoryTrimnming( true );
terminal->pushEventCallback( [&closeOnExit]( const TerminalDisplay::Event& event ) {
if ( event.type == TerminalDisplay::EventType::TITLE ) {
windowStringData = event.eventData;
win->setTitle( "eterm - " + windowStringData );
} else if ( event.type == TerminalDisplay::EventType::PROCESS_EXIT &&
closeOnExit.Get() ) {
win->close();
}
} );
if ( shell )
terminal->setKeepAlive( false );
if ( colorScheme ) {
auto selColorScheme = terminalColorSchemes.find( colorScheme.Get() );
if ( selColorScheme != terminalColorSchemes.end() )
terminal->setColorScheme( selColorScheme->second );
}
if ( !executeInShell.Get().empty() )
terminal->executeFile( executeInShell.Get() );
win->startTextInput();
win->getInput()->pushCallback( &inputCallback );
win->runMainLoop( [] {
bool termNeedsUpdate = false;
win->getInput()->update();
if ( terminal )
termNeedsUpdate = !terminal->update();
if ( terminal && ( benchmarkMode || terminal->isDirty() ) &&
( !termNeedsUpdate || lastRender.getElapsedTime() >= frameTime ) ) {
lastRender.restart();
win->clear();
terminal->draw();
win->display();
} else if ( !benchmarkMode && !termNeedsUpdate ) {
win->getInput()->waitEvent( Milliseconds( win->hasFocus() ? 16 : 100 ) );
}
if ( benchmarkMode && secondsCounter.getElapsedTime() >= Seconds( 1 ) ) {
win->setTitle( "eterm - " + windowStringData + " - " +
String::toString( win->getFPS() ) + " FPS" );
secondsCounter.restart();
}
} );
}
terminal.reset();
Engine::destroySingleton();
MemoryManager::showResults();
return EXIT_SUCCESS;
}