diff --git a/bin/assets/plugins/debugger.json b/bin/assets/plugins/debugger.json index 2fca1d720..81484151d 100644 --- a/bin/assets/plugins/debugger.json +++ b/bin/assets/plugins/debugger.json @@ -248,6 +248,7 @@ "command_arguments": [ "${env:VSCODE_JS_DEBUG_PATH}/src/dapDebugServer.js", "${randPort}", "127.0.0.1" ] }, "languages": ["javascript", "typescript"], + "unstable_frame_id": true, "configurations": [ { "name": "Launch script", diff --git a/src/eepp/system/log.cpp b/src/eepp/system/log.cpp index 0897d12d7..1e8b6b20e 100644 --- a/src/eepp/system/log.cpp +++ b/src/eepp/system/log.cpp @@ -5,6 +5,8 @@ #if EE_PLATFORM == EE_PLATFORM_ANDROID #include +#elif EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN +#include #endif #if defined( EE_COMPILER_MSVC ) @@ -132,6 +134,8 @@ void Log::write( const std::string_view& text ) { #else OutputDebugString( text.c_str() ); #endif +#elif EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN + emscripten_console_log( text.data() ); #else std::cout << text << std::flush; #endif @@ -200,6 +204,8 @@ void Log::writel( const std::string_view& text ) { OutputDebugString( text.data() ); OutputDebugString( "\n" ); #endif +#elif EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN + emscripten_console_log( text.data() ); #else std::cout << text << std::endl; #endif diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index dc58a0e87..c0432cc0e 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -823,6 +823,13 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed } if ( !j.is_discarded() ) { editorsToLoad = countTotalEditors( j ); + if ( editorsToLoad <= 0 ) { + app->getUISceneNode()->runOnMainThread( [app] { + if ( !app->getFileToOpen().empty() ) { + app->loadFileDelayed(); + } + } ); + } loadDocuments( editorSplitter, j, curTabWidget, app, sessionSnapshotFiles ); } } diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index a117a63d0..9a9e2f330 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -699,11 +699,7 @@ bool App::loadConfig( const LogLevel& logLevel, const Sizeu& displaySize, bool s mLogsPath = mConfigPath + "ecode.log"; -#ifndef EE_DEBUG Log::create( mLogsPath, logLevel, stdOutLogs, !disableFileLogs ); -#else - Log::create( mLogsPath, logLevel, stdOutLogs, !disableFileLogs ); -#endif Log::instance()->setKeepLog( true ); @@ -4057,8 +4053,11 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe globalClock.getElapsedTime().asMilliseconds() ); #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN - if ( file.empty() ) - downloadFileWeb( "https://raw.githubusercontent.com/SpartanJ/eepp/develop/README.md" ); + if ( file.empty() || !mFileToOpen.empty() ) + downloadFileWeb( + mFileToOpen.empty() + ? "https://raw.githubusercontent.com/SpartanJ/eepp/develop/README.md" + : mFileToOpen ); #endif if ( mConfig.workspace.checkForUpdatesAtStartup ) diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 57f101f26..9138b5145 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -225,6 +225,14 @@ void DebuggerClientListener::setRemoteRoot( const std::string& newRemoteRoot ) { mRemoteRoot = newRemoteRoot; } +bool DebuggerClientListener::isUnstableFrameId() const { + return mUnstableFrameId; +} + +void DebuggerClientListener::setUnstableFrameId( bool unstableFrameId ) { + mUnstableFrameId = unstableFrameId; +} + void DebuggerClientListener::initialized( const SessionId& ) { sendBreakpoints(); } @@ -382,9 +390,8 @@ void DebuggerClientListener::changeScope( const StackFrame& f ) { TextRange range{ { f.line - 1, f.column - 1 }, { f.line - 1, f.column - 1 } }; std::string path( f.source->path ); - mPlugin->getUISceneNode()->runOnMainThread( [this, path, range] { - mPlugin->getPluginContext()->focusOrLoadFile( path, range ); - } ); + mPlugin->getUISceneNode()->runOnMainThread( + [this, path, range] { mPlugin->getPluginContext()->focusOrLoadFile( path, range ); } ); mCurrentScopePos = { f.source->path, f.line }; @@ -436,7 +443,8 @@ void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& st ExpandedState::Location location{ mCurrentScopePos->first, mCurrentScopePos->second, mCurrentFrameId }; mPlugin->mExpressionsHolder->restoreExpandedState( - location, mClient, getStatusDebuggerController()->getUIExpressions(), true ); + location, mClient, getStatusDebuggerController()->getUIExpressions(), true, + mUnstableFrameId ); } ); } } @@ -452,7 +460,7 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& auto child = std::make_shared( scope.name, scope.variablesReference ); mVariablesHolder->addChild( child ); if ( ( !mPlugin->mFetchRegisters && scope.name == "Registers" ) || - ( !mPlugin->mFetchGlobals && scope.name == "Globals" ) ) + ( !mPlugin->mFetchGlobals && ( scope.name == "Global" || scope.name == "Globals" ) ) ) continue; mClient->variables( scope.variablesReference ); } @@ -477,7 +485,8 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& ModelVariableNode* node = static_cast( index.internalData() ); if ( ( !mPlugin->mFetchRegisters && node->var.name == "Registers" ) || - ( !mPlugin->mFetchGlobals && node->var.name == "Globals" ) ) + ( !mPlugin->mFetchGlobals && + ( node->var.name == "Global" || node->var.name == "Globals" ) ) ) continue; uiVars->tryOpenModelIndex( index ); } @@ -495,7 +504,8 @@ void DebuggerClientListener::variables( const int variablesReference, std::vecto ExpandedState::Location location{ mCurrentScopePos->first, mCurrentScopePos->second, mCurrentFrameId }; mVariablesHolder->restoreExpandedState( location, mClient, - getStatusDebuggerController()->getUIVariables() ); + getStatusDebuggerController()->getUIVariables(), + false, mUnstableFrameId ); } } diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp index d8e835da5..62a29f4e3 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp @@ -109,6 +109,10 @@ class DebuggerClientListener : public DebuggerClient::Listener { void setRemoteRoot( const std::string& newRemoteRoot ); + bool isUnstableFrameId() const; + + void setUnstableFrameId( bool unstableFrameId ); + protected: DebuggerClient* mClient{ nullptr }; DebuggerPlugin* mPlugin{ nullptr }; @@ -116,6 +120,7 @@ class DebuggerClientListener : public DebuggerClient::Listener { std::optional> mCurrentScopePos; bool mPausedToRefreshBreakpoints{ false }; bool mIsRemote{ false }; + bool mUnstableFrameId{ false }; int mCurrentThreadId{ 1 }; int mCurrentFrameId{ 0 }; std::shared_ptr mThreadsModel; diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index cf7d218d6..9352c3fc0 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -467,6 +467,7 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi for ( const auto& dap : dapArr ) { DapTool dapTool; dapTool.name = dap.value( "name", "" ); + dapTool.unstableFrameId = dap.value( "unstable_frame_id", false ); if ( dap.contains( "type" ) && dap["type"].is_array() ) { for ( const auto& obj : dap["type"] ) @@ -1969,7 +1970,7 @@ void DebuggerPlugin::prepareAndRun( DapTool debugger, DapConfig config, [this, protocolSettings = std::move( protocolSettings ), randomPort, debugger = std::move( debugger ), forceUseProgram, usesPorts]() mutable { run( debugger.name, std::move( protocolSettings ), std::move( debugger.run ), - randomPort, forceUseProgram, usesPorts ); + randomPort, forceUseProgram, usesPorts, debugger.unstableFrameId ); }, [this]( const Uint64& ) { if ( !mDebugger || !mDebugger->started() ) { @@ -2114,7 +2115,7 @@ void DebuggerPlugin::initStatusDebuggerController() { void DebuggerPlugin::run( const std::string& debugger, ProtocolSettings&& protocolSettings, DapRunConfig&& runConfig, int randPort, bool forceUseProgram, - bool usesPorts ) { + bool usesPorts, bool unstableFrameId ) { std::optional cmdOpt = debuggerBinaryExists( debugger, runConfig ); if ( !cmdOpt && ( protocolSettings.launchRequestType == REQUEST_TYPE_LAUNCH || @@ -2237,6 +2238,7 @@ void DebuggerPlugin::run( const std::string& debugger, ProtocolSettings&& protoc mListener = std::make_unique( mDebugger.get(), this ); mListener->setIsRemote( isRemote ); + mListener->setUnstableFrameId( unstableFrameId ); if ( isRemote ) { // mListener->setLocalRoot( localRoot ); diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index d176ec39a..c971d3c7b 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -37,6 +37,7 @@ struct DapTool { bool redirectStdout{ false }; bool redirectStderr{ false }; bool supportsSourceRequest{ false }; + bool unstableFrameId{ false }; }; struct DapConfigurationInput { @@ -191,7 +192,8 @@ class DebuggerPlugin : public PluginBase { void runConfig( const std::string& debugger, const std::string& configuration ); void run( const std::string& debugger, ProtocolSettings&& protocolSettings, - DapRunConfig&& runConfig, int randPort, bool forceUseProgram, bool usesPorts ); + DapRunConfig&& runConfig, int randPort, bool forceUseProgram, bool usesPorts, + bool unstableFrameId ); void exitDebugger( bool requestDisconnect = false ); diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp index 1504e6b6f..d13cf6a2a 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp @@ -335,12 +335,13 @@ bool VariablesHolder::resolvePath( std::vector path, DebuggerClient return false; } + static int getLocationDistance( const ExpandedState::Location& loc1, - const ExpandedState::Location& loc2 ) { + const ExpandedState::Location& loc2, bool unstableFrameId ) { if ( loc1.filePath != loc2.filePath ) return std::numeric_limits::max(); - if ( loc1.frameIndex != loc2.frameIndex ) { + if ( !unstableFrameId && loc1.frameIndex != loc2.frameIndex ) { return std::numeric_limits::max() / 2; // Different frame but same file is better than different file } @@ -350,7 +351,7 @@ static int getLocationDistance( const ExpandedState::Location& loc1, bool VariablesHolder::restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, UITreeView* uiVariables, - bool uniqueLocation ) { + bool uniqueLocation, bool unstableFrameId ) { mCurrentLocation = location; auto it = uniqueLocation ? mExpandedStates.begin() : mExpandedStates.find( location ); @@ -360,7 +361,7 @@ bool VariablesHolder::restoreExpandedState( const ExpandedState::Location& locat int minDistance = std::numeric_limits::max(); for ( const auto& state : mExpandedStates ) { - int distance = getLocationDistance( location, state.first ); + int distance = getLocationDistance( location, state.first, unstableFrameId ); if ( distance < minDistance ) { minDistance = distance; nearestLoc = &state.first; diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp index 144069f1c..f68fe9a3f 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp @@ -142,7 +142,8 @@ class VariablesHolder { void removeExpandedState( const ModelIndex& index, bool uniqueLocation = false ); bool restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, - UITreeView* uiVariables, bool uniqueLocation = false ); + UITreeView* uiVariables, bool uniqueLocation = false, + bool unstableFrameId = false ); std::shared_ptr getModel() { return mModel; } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index df69bd3dd..1a07b575b 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -1577,57 +1577,11 @@ void LSPClientPlugin::getSymbolInfo( UICodeEditor* editor ) { auto server = mClientManager.getOneLSPClientServer( editor ); if ( server == nullptr ) return; - server->documentHover( - editor->getDocument().getURI(), editor->getDocument().getSelection().start(), - [this, editor]( const Int64&, const LSPHover& resp ) { - json j; - auto& doc = editor->getDocument(); - j["uri"] = doc.getURI().toString(); - j["line"] = doc.getSelection().start().line(); - j["character"] = doc.getSelection().start().column(); - auto errResp = mManager->sendRequest( PluginMessageType::GetErrorOrWarning, - PluginMessageFormat::JSON, &j ); - if ( !resp.contents.empty() && !resp.contents[0].value.empty() ) { - editor->runOnMainThread( [editor, resp, errResp, this]() { - mSymbolInfoShowing = true; - if ( errResp.isResponse() ) { - LSPHover cresp( resp ); - cresp.contents[0].value = - errResp.getResponse().data["text"].get() + "\n\n" + - cresp.contents[0].value; - displayTooltip( - editor, cresp, - editor - ->getScreenPosition( editor->getDocument().getSelection().start() ) - .getPosition() ); - } else { - displayTooltip( - editor, resp, - editor - ->getScreenPosition( editor->getDocument().getSelection().start() ) - .getPosition() ); - } - } ); - } else if ( errResp.isResponse() ) { - LSPHover tresp; - tresp.range = - TextRange::fromString( errResp.getResponse().data["range"].get() ); - tresp.contents.push_back( - { LSPMarkupKind::MarkDown, - errResp.getResponse().data["text"].get() } ); - editor->runOnMainThread( [editor, tresp, this]() { - mSymbolInfoShowing = true; - displayTooltip( - editor, tresp, - editor->getScreenPosition( editor->getDocument().getSelection().start() ) - .getPosition() ); - } ); - } else { - json data = getURIAndPositionJSON( editor ); - mManager->sendRequest( PluginMessageType::SignatureHelp, PluginMessageFormat::JSON, - &data ); - } - } ); + server->documentHover( editor->getDocument().getURI(), + editor->getDocument().getSelection().start(), + [this, editor]( const Int64&, const LSPHover& resp ) { + onDocumentHoverResponse( editor, resp, false ); + } ); } void LSPClientPlugin::onUnregister( UICodeEditor* editor ) { @@ -1767,7 +1721,7 @@ void LSPClientPlugin::hideTooltip( UICodeEditor* editor ) { } } -TextPosition currentMouseTextPosition( UICodeEditor* editor ) { +static TextPosition currentMouseTextPosition( UICodeEditor* editor ) { return editor->resolveScreenPosition( editor->getUISceneNode()->getWindow()->getInput()->getMousePos().asFloat() ); } @@ -1842,6 +1796,66 @@ void LSPClientPlugin::tryDisplayTooltip( UICodeEditor* editor, const LSPHover& r displayTooltip( editor, resp, position.asFloat() ); } +void LSPClientPlugin::onDocumentHoverResponse( UICodeEditor* editor, const LSPHover& resp, + bool fromMousePos, + std::optional screenPos ) { + const auto& displayTooltipFn = [this, fromMousePos]( UICodeEditor* editor, const LSPHover& resp, + const Vector2f& position ) { + if ( fromMousePos ) + tryDisplayTooltip( editor, resp, position.asInt() ); + else + displayTooltip( editor, resp, position ); + }; + + const auto& getFinalPosFn = [screenPos]( UICodeEditor* editor ) { + return screenPos ? *screenPos + : editor->getScreenPosition( editor->getDocument().getSelection().start() ) + .getPosition(); + }; + + auto& doc = editor->getDocument(); + json j; + TextPosition textPosition = + fromMousePos ? currentMouseTextPosition( editor ) : doc.getSelection().start(); + j["uri"] = doc.getURI().toString(); + j["line"] = textPosition.line(); + j["character"] = textPosition.column(); + auto errResp = mManager->sendRequest( PluginMessageType::GetErrorOrWarning, + PluginMessageFormat::JSON, &j ); + if ( !resp.contents.empty() && !resp.contents[0].value.empty() ) { + editor->runOnMainThread( [editor, resp, errResp, this, screenPos, displayTooltipFn, + getFinalPosFn]() { + mSymbolInfoShowing = true; + auto pos = + screenPos + ? *screenPos + : editor->getScreenPosition( editor->getDocument().getSelection().start() ) + .getPosition(); + if ( errResp.isResponse() ) { + LSPHover cresp( resp ); + cresp.contents[0].value = errResp.getResponse().data["text"].get() + + "\n\n" + cresp.contents[0].value; + displayTooltipFn( editor, cresp, getFinalPosFn( editor ) ); + } else { + displayTooltipFn( editor, resp, pos ); + } + } ); + } else if ( errResp.isResponse() ) { + LSPHover tresp; + tresp.range = + TextRange::fromString( errResp.getResponse().data["range"].get() ); + tresp.contents.push_back( + { LSPMarkupKind::MarkDown, errResp.getResponse().data["text"].get() } ); + editor->runOnMainThread( [editor, tresp, this, displayTooltipFn, getFinalPosFn]() { + mSymbolInfoShowing = true; + displayTooltipFn( editor, tresp, getFinalPosFn( editor ) ); + } ); + } else { + json data = getURIAndPositionJSON( editor ); + mManager->sendRequest( PluginMessageType::SignatureHelp, PluginMessageFormat::JSON, &data ); + } +} + bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position, const Uint32& flags ) { auto localPos( editor->convertToNodeSpace( position.asFloat() ) ); @@ -1882,11 +1896,14 @@ bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& positio if ( editorExists( editor ) && !resp.contents.empty() && !resp.contents[0].value.empty() ) { editor->runOnMainThread( [editor, resp, this]() { - auto mousePos = - editor->getUISceneNode()->getWindow()->getInput()->getMousePos(); - if ( !editor->getScreenRect().contains( mousePos.asFloat() ) ) + auto mousePos = editor->getUISceneNode() + ->getWindow() + ->getInput() + ->getMousePos() + .asFloat(); + if ( !editor->getScreenRect().contains( mousePos ) ) return; - tryDisplayTooltip( editor, resp, mousePos ); + onDocumentHoverResponse( editor, resp, true, mousePos ); } ); } } ); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp index f3e7e14cb..11da92d6d 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -27,7 +27,7 @@ class LSPClientPlugin : public Plugin { public: static PluginDefinition Definition() { return { "lspclient", "LSP Client", "Language Server Protocol Client.", - LSPClientPlugin::New, { 0, 2, 8 }, LSPClientPlugin::NewSync }; + LSPClientPlugin::New, { 0, 2, 9 }, LSPClientPlugin::NewSync }; } static Plugin* New( PluginManager* pluginManager ); @@ -220,6 +220,9 @@ class LSPClientPlugin : public Plugin { std::shared_ptr createDocSymbolsModel( URI uri, const std::string& query = "" ); + + void onDocumentHoverResponse( UICodeEditor* editor, const LSPHover& resp, bool fromMousePos, + std::optional screenPos = {} ); }; } // namespace ecode