More fixes. Added debuggers to health tool.

This commit is contained in:
Martín Lucas Golini
2025-01-13 01:24:30 -03:00
parent 882e68542e
commit fb3b866f29
9 changed files with 179 additions and 29 deletions
+112 -6
View File
@@ -1,4 +1,5 @@
#include "featureshealth.hpp"
#include "plugins/debugger/debuggerplugin.hpp"
#include "plugins/formatter/formatterplugin.hpp"
#include "plugins/linter/linterplugin.hpp"
#include "plugins/lsp/lspclientplugin.hpp"
@@ -28,6 +29,7 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
bool ownsLinter = false;
bool ownsFormatter = false;
bool ownsLSP = false;
bool ownsDebugger = false;
const auto& definitions = SyntaxDefinitionManager::instance()->getDefinitions();
@@ -38,6 +40,8 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
LSPClientPlugin* lsp = static_cast<LSPClientPlugin*>( pluginManager->get( "lspclient" ) );
DebuggerPlugin* debugger = static_cast<DebuggerPlugin*>( pluginManager->get( "debugger" ) );
if ( !linter ) {
ownsLinter = true;
linter = static_cast<LinterPlugin*>( LinterPlugin::NewSync( pluginManager ) );
@@ -52,6 +56,11 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
lsp = static_cast<LSPClientPlugin*>( LSPClientPlugin::NewSync( pluginManager ) );
}
if ( !debugger ) {
ownsDebugger = true;
debugger = static_cast<DebuggerPlugin*>( DebuggerPlugin::NewSync( pluginManager ) );
}
for ( const auto& def : definitions ) {
if ( !def.isVisible() )
continue;
@@ -97,6 +106,18 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
}
}
if ( debugger ) {
std::vector<DapTool> found = debugger->getDebuggersForLang( def.getLSPName() );
for ( const auto& dbg : found ) {
FeatureStatus debugger;
debugger.name = dbg.name;
debugger.url = dbg.url;
debugger.path = Sys::which( dbg.run.command );
debugger.found = !debugger.path.empty();
lang.debugger.emplace_back( std::move( debugger ) );
}
}
langs.emplace_back( std::move( lang ) );
}
@@ -109,6 +130,9 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
if ( ownsLSP )
eeSAFE_DELETE( lsp );
if ( ownsDebugger )
eeSAFE_DELETE( debugger );
std::sort( langs.begin(), langs.end(), sortKey );
return langs;
@@ -121,9 +145,9 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
table.format().border_top( "" ).border_bottom( "" ).border_left( "" ).border_right( "" ).corner(
"" );
size_t numRows = 5;
size_t numRows = 6;
table.add_row( { "Language", "Highlight", "LSP", "Linter", "Formatter" } );
table.add_row( { "Language", "Highlight", "LSP", "Linter", "Formatter", "Debugger" } );
for ( size_t i = 0; i < numRows; ++i ) {
table[0][i]
@@ -155,7 +179,23 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
formatterName = "[" + ht.formatter.name + "](" + ht.formatter.url + ")";
}
table.add_row( { ht.lang, check, lspName, linterName, formatterName } );
std::string debuggerName =
ht.debugger.empty()
? "None"
: std::accumulate( ht.debugger.begin(), ht.debugger.end(), std::string{},
[]( const std::string& acc, const FeatureStatus& item ) {
return acc.empty() ? item.name : acc + " / " + item.name;
} );
if ( OutputFormat::Markdown == format && !ht.debugger.empty() ) {
debuggerName = std::accumulate(
ht.debugger.begin(), ht.debugger.end(), std::string{},
[]( const std::string& acc, const FeatureStatus& item ) {
return acc.empty() ? "[" + item.name + "](" + item.url + ")"
: acc + " / " + "[" + item.name + "](" + item.url + ")";
} );
}
table.add_row( { ht.lang, check, lspName, linterName, formatterName, debuggerName } );
auto& row = table[table.size() - 1];
@@ -181,6 +221,16 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
} else {
row[4].format().font_color( tabulate::Color::yellow );
}
if ( !ht.debugger.empty() ) {
row[5].format().font_color(
std::any_of( ht.debugger.begin(), ht.debugger.end(),
[]( const FeatureStatus& item ) { return item.found; } )
? tabulate::Color::green
: tabulate::Color::red );
} else {
row[5].format().font_color( tabulate::Color::yellow );
}
}
if ( OutputFormat::Markdown == format ) {
@@ -239,6 +289,21 @@ void FeaturesHealth::doHealth( PluginManager* pluginManager, const std::string&
std::cout << "Configured formatter: " << formatterName << "\n\033[00m";
if ( !hr.formatter.name.empty() )
std::cout << "Binary for formatter: " << formatterBinary << "\n\033[00m";
if ( !hr.debugger.empty() ) {
for ( const auto& dbg : hr.debugger ) {
std::string debuggerName =
hr.debugger.empty() ? "\033[33mNone" : "\033[32m" + dbg.name;
std::string debuggerBinary =
dbg.found ? "\033[32m" + dbg.path : "\033[31m" + notFound;
std::cout << "Configured debugger: " << debuggerName << "\n\033[00m";
if ( !dbg.name.empty() )
std::cout << "Binary for debugger: " << debuggerBinary << "\n\033[00m";
}
} else {
std::cout << "Configured debugger: " << "\033[31m" + notFound << "\n\033[00m";
}
}
}
@@ -254,11 +319,11 @@ class HealthModel : public Model {
virtual size_t rowCount( const ModelIndex& ) const { return mData.size(); }
virtual size_t columnCount( const ModelIndex& ) const { return 5; }
virtual size_t columnCount( const ModelIndex& ) const { return 6; }
virtual std::string columnName( const size_t& idx ) const {
static const std::vector<std::string> columns = { "language", "highlight", "LSP", "linter",
"formatter" };
static const std::vector<std::string> columns = { "language", "highlight", "LSP",
"linter", "formatter", "debugger" };
if ( idx < columns.size() )
return mSceneNode->i18n( columns[idx], String::capitalize( columns[idx] ) );
return "";
@@ -297,6 +362,16 @@ class HealthModel : public Model {
return Variant( lang.linter.name.empty() ? none : lang.linter.name );
case 4:
return Variant( lang.formatter.name.empty() ? none : lang.formatter.name );
case 5:
return Variant(
lang.debugger.empty()
? none
: std::accumulate(
lang.debugger.begin(), lang.debugger.end(), std::string{},
[]( const std::string& acc,
const FeaturesHealth::FeatureStatus& item ) {
return acc.empty() ? item.name : acc + " / " + item.name;
} ) );
default: {
}
}
@@ -324,6 +399,18 @@ class HealthModel : public Model {
else
return Variant( HEALTH_NONE );
break;
case 5:
if ( !lang.debugger.empty() )
return Variant(
std::any_of( lang.debugger.begin(), lang.debugger.end(),
[]( const FeaturesHealth::FeatureStatus& item ) {
return item.found;
} )
? HEALTH_SUCCESS
: HEALTH_ERROR );
else
return Variant( HEALTH_NONE );
break;
default: {
}
}
@@ -463,6 +550,25 @@ void FeaturesHealth::displayHealth( PluginManager* pluginManager, UISceneNode* s
lang.formatter.path.empty() ? patherr : "" );
}
for ( const auto& debugger : lang.debugger ) {
type = debugger.url.empty() ? "TextView"
: String::format( "Anchor href='%s'", debugger.url );
l += String::format( "<hbox><TextView text='%s: ' /><%s text='%s' class='%s' /></hbox>",
I18N( "configured_debugger", "Configured debugger" ), type,
debugger.name.empty() ? none : debugger.name,
debugger.found ? "success"
: ( debugger.name.empty() ? "none" : "error" ) );
if ( !debugger.name.empty() ) {
l += String::format( "<hbox><TextView text='%s: ' /><TextView text='%s' class='%s' "
"tooltip='%s' /></hbox>",
I18N( "binary_for_debugger", "Binary for debugger" ),
debugger.path.empty() ? notFound : debugger.path,
!debugger.path.empty() ? "success" : "error",
debugger.path.empty() ? patherr : "" );
}
}
sceneNode->loadLayoutFromString( l, healthLangInfo );
healthLangInfo->setVisible( true );
} );
+1
View File
@@ -38,6 +38,7 @@ class FeaturesHealth {
FeatureStatus linter;
FeatureStatus formatter;
FeatureStatus lsp;
std::vector<FeatureStatus> debugger;
};
static std::vector<LangHealth> getHealth( PluginManager* pluginManager,
@@ -1226,6 +1226,10 @@ bool AutoCompletePlugin::onMouseMove( UICodeEditor* editor, const Vector2i& posi
return false;
Vector2f localPos( editor->convertToNodeSpace( position.asFloat() ) );
if ( localPos.x <= editor->getGutterWidth() )
return false;
if ( mBoxRect.contains( localPos ) ) {
editor->getUISceneNode()->setCursor( Cursor::Hand );
return true;
@@ -156,9 +156,8 @@ void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) {
mPlugin->setUIDebuggingState( StatusDebuggerController::State::Paused );
auto sdc = getStatusDebuggerController();
if ( sdc ) {
if ( sdc )
sdc->getWidget()->runOnMainThread( [sdc] { sdc->show(); } );
}
}
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {
@@ -216,18 +215,19 @@ void DebuggerClientListener::changeScope( const StackFrame& f ) {
mCurrentScopePos = { f.source->path, f.line };
if ( getStatusDebuggerController() && getStatusDebuggerController()->getUIStack() )
getStatusDebuggerController()->getUIStack()->setSelection( mStackModel->index( f.id ) );
auto sdc = getStatusDebuggerController();
if ( sdc && sdc->getUIStack() )
sdc->getUIStack()->setSelection( mStackModel->index( f.id ) );
}
void DebuggerClientListener::changeThread( int id ) {
mCurrentThreadId = id;
if ( mThreadsModel )
mThreadsModel->setCurrentThreadId( id );
if ( getStatusDebuggerController() && getStatusDebuggerController()->getUIThreads() ) {
getStatusDebuggerController()->getUIThreads()->setSelection(
mThreadsModel->fromThreadId( id ) );
}
auto sdc = getStatusDebuggerController();
if ( sdc && sdc->getUIThreads() )
sdc->getUIThreads()->setSelection( mThreadsModel->fromThreadId( id ) );
}
void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& stack ) {
@@ -270,14 +270,17 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector<Scope>&&
mVariablesHolder->clear();
for ( const auto& scope : scopes ) {
if ( !mPlugin->mDisplayRegisters && scope.name == "Registers" )
continue;
auto child = std::make_shared<ModelVariableNode>( scope.name, scope.variablesReference );
mVariablesHolder->addChild( child );
mClient->variables( scope.variablesReference );
}
if ( !getStatusDebuggerController() )
auto sdc = getStatusDebuggerController();
if ( nullptr == sdc )
return;
auto uiVars = getStatusDebuggerController()->getUIVariables();
auto uiVars = sdc->getUIVariables();
if ( uiVars ) {
uiVars->runOnMainThread( [uiVars] {
auto model = uiVars->getModel();
@@ -307,6 +310,7 @@ void DebuggerClientListener::breakpointChanged( const BreakpointEvent& ) {}
void DebuggerClientListener::expressionEvaluated( const std::string& /*expression*/,
const std::optional<EvaluateInfo>& ) {}
void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/,
const std::vector<GotoTarget>& /*targets*/ ) {}
@@ -205,6 +205,17 @@ void DebuggerPlugin::onLoadProject( const std::string& projectFolder,
}
}
std::vector<DapTool> DebuggerPlugin::getDebuggersForLang( const std::string& language ) {
std::vector<DapTool> tools;
for ( const auto& dap : mDaps ) {
auto found = std::find_if( dap.languagesSupported.begin(), dap.languagesSupported.end(),
[&language]( const auto& l ) { return l == language; } );
if ( found != dap.languagesSupported.end() )
tools.push_back( dap );
}
return tools;
}
void DebuggerPlugin::resetExpressions() {
if ( !mExpressionsHolder )
return;
@@ -306,6 +317,14 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi
true, true );
}
if ( j.contains( "config" ) ) {
auto& config = j["config"];
if ( config.contains( "display_registers" ) )
mDisplayRegisters = config.value( "display_registers", false );
else if ( updateConfigFile )
config["display_registers"] = mDisplayRegisters;
}
if ( j.contains( "dap" ) ) {
auto& dapArr = j["dap"];
mDaps.reserve( dapArr.size() );
@@ -577,7 +596,7 @@ void DebuggerPlugin::buildSidePanelTab() {
<DropDownList id="debugger_list" layout_width="mp" layout_height="wrap_content" margin-top="2dp" />
<TextView text="@string(debugger_configuration, Debugger Configuration)" focusable="false" margin-top="8dp" />
<DropDownList id="debugger_conf_list" layout_width="mp" layout_height="wrap_content" margin-top="2dp" />
<PushButton id="debugger_run_button" lw="mp" lh="wc" text="@string(run, Run)" margin-top="8dp" icon="icon(play, 12dp)" />
<PushButton id="debugger_run_button" lw="mp" lh="wc" text="@string(run, Run)" margin-top="8dp" icon="icon(debug-alt, 12dp)" />
<hbox id="panel_debugger_buttons" lw="wc" lh="wc" layout_gravity="center_horizontal" visible="false" clip="none" margin-top="8dp">
<PushButton id="panel_debugger_continue" class="debugger_continue" lw="24dp" lh="24dp" icon="icon(debug-continue, 12dp)" tooltip="@string(continue, Continue)" />
<PushButton id="panel_debugger_pause" class="debugger_pause" lw="24dp" lh="24dp" icon="icon(debug-pause, 12dp)" tooltip="@string(pause, Pause)" />
@@ -1337,8 +1356,6 @@ void DebuggerPlugin::runConfig( const std::string& debugger, const std::string&
std::string fallbackCommand = debuggerIt->fallbackCommand;
mRunButton->setEnabled( false );
mThreadPool->run(
[this, protocolSettings = std::move( protocolSettings ),
runSettings = std::move( runConfig ), findBinary = std::move( findBinary ),
@@ -1517,7 +1534,7 @@ void DebuggerPlugin::updatePanelUIState( StatusDebuggerController::State state )
mPanelBoxButtons.stepOut->setVisible( isDebugging )
->setEnabled( state == StatusDebuggerController::State::Paused );
mRunButton->setText( isDebugging ? i18n( "Stop Debugging", "Stop Debugging" )
mRunButton->setText( isDebugging ? i18n( "Stop Debugger", "Stop Debugger" )
: i18n( "debug", "Debug" ) );
}
@@ -1629,6 +1646,10 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
return false;
}
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
if ( localPos.x <= editor->getGutterWidth() )
return false;
editor->debounce(
[this, editor, position]() {
if ( !mManager->getSplitter()->editorExists( editor ) )
@@ -1637,7 +1658,8 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
auto range = editor->getDocument().getWordRangeInPosition( docPos, true );
auto expression = editor->getDocument().getWordInPosition( docPos, true ).toUtf8();
if ( !range.isValid() || expression.empty() )
if ( !range.isValid() || expression.empty() ||
LuaPattern::hasMatches( expression, "^[%p%s]+$" ) )
return;
mCurrentHover = range;
@@ -1667,6 +1689,7 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
},
mHoverDelay, getMouseMoveHash( editor ) );
tryHideTooltip( editor, position );
editor->updateMouseCursor( position.asFloat() );
return true;
}
@@ -62,10 +62,13 @@ class DebuggerPlugin : public PluginBase {
void onLoadProject( const std::string& projectFolder,
const std::string& projectStatePath ) override;
std::vector<DapTool> getDebuggersForLang( const std::string& lang );
protected:
friend class DebuggerClientListener;
bool mInitialized{ false };
bool mDisplayRegisters{ false };
std::string mProjectPath;
std::vector<DapTool> mDaps;
@@ -182,10 +182,12 @@ void VariablesHolder::addVariables( const int variablesReference, std::vector<Va
auto found = parentNode->getChild( var.name );
if ( found ) {
( *found )->var = std::move( var );
ModelVariableNode::NodePtr child = *found;
child->var = std::move( var );
if ( child->var.variablesReference != 0 )
nodeMap[child->var.variablesReference] = *found;
if ( ( *found )->var.variablesReference != 0 )
nodeMap[( *found )->var.variablesReference] = *found;
continue;
}
@@ -1,5 +1,5 @@
#include "../../stringhelper.hpp"
#include "linterplugin.hpp"
#include "linterplugin.hpp"
#include "../../stringhelper.hpp"
#include <algorithm>
#include <eepp/graphics/primitives.hpp>
#include <eepp/graphics/text.hpp>
@@ -1295,11 +1295,15 @@ bool LinterPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& pos, const
tryHideHoveringMatch( editor );
return false;
}
Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) );
TextPosition cursorPosition = editor->resolveScreenPosition( pos.asFloat() );
if ( localPos.x <= editor->getGutterWidth() )
return false;
Lock l( mMatchesMutex );
auto it = mMatches.find( editor->getDocumentRef().get() );
if ( it != mMatches.end() ) {
Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) );
TextPosition cursorPosition = editor->resolveScreenPosition( pos.asFloat() );
auto matchIt = it->second.find( cursorPosition.line() );
if ( matchIt != it->second.end() ) {
auto& matches = matchIt->second;
@@ -1830,8 +1830,11 @@ void LSPClientPlugin::tryDisplayTooltip( UICodeEditor* editor, const LSPHover& r
bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position,
const Uint32& flags ) {
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
if ( localPos.x <= editor->getGutterWidth() )
return false;
if ( mBreadcrumb ) {
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
if ( localPos.y < mPluginTopSpace && localPos.x < editor->getTopAreaWidth() &&
localPos.x >= 0 ) {
if ( !mHoveringBreadcrumb ) {