Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/SeerEditorManagerWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,9 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::gdbGotoDefinition, [this] (const QString& identifier) {
emit gdbGotoDefinitionForward(identifier);
});

// Send the Editor widget the command to load the file. ??? Do better than this.
editorWidget->sourceArea()->handleText(text);
Expand Down Expand Up @@ -1097,6 +1100,9 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::gdbGotoDefinition, [this] (const QString& identifier) {
emit gdbGotoDefinitionForward(identifier);
});

// Load the file.
editorWidget->sourceArea()->open(fullname, QFileInfo(file).fileName());
Expand Down
1 change: 1 addition & 0 deletions src/SeerEditorManagerWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
void requestSourceAndAssembly (QString address);
void showMessage (QString message, int time);
void assemblyTabShown (bool shown);
void gdbGotoDefinitionForward (const QString& identifier);

private:
SeerEditorWidgetSource* currentEditorWidgetTab ();
Expand Down
7 changes: 7 additions & 0 deletions src/SeerEditorWidgetSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
void showAlternateBar (bool flag);
void showReloadBar (bool flag);
void highlighterSettingsChanged ();
void gdbGotoDefinition (const QString& identifier);

public slots:
void handleText (const QString& text);
void handleHighlighterSettingsChanged ();
void handleWatchFileModified (const QString& path);
void handleBreakpointToolTip (QPoint pos, const QString& text);
void handleGotoDefinition ();

protected:
void resizeEvent (QResizeEvent* event);
Expand All @@ -163,6 +165,8 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
void updateBreakPointArea (const QRect& rect, int dy);

private:
bool isValidIdentifier (const QString& text);

QString _fullname;
QString _file;
QString _alternateDirectory;
Expand Down Expand Up @@ -194,6 +198,9 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {

int _sourceTabSize;
QString _externalEditorCommand;

bool _ctrlHeld = false;
QString _wordUnderCursor;
};

class SeerEditorWidgetSourceLineNumberArea : public QWidget {
Expand Down
58 changes: 58 additions & 0 deletions src/SeerEditorWidgetSourceAreas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPl
QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateBreakPointArea);
QObject::connect(this, &SeerEditorWidgetSourceArea::highlighterSettingsChanged, this, &SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged);

// Feature: Go to definition (F12)
QShortcut* gotoDefShortcut = new QShortcut(QKeySequence(Qt::Key_F12), this);
QObject::connect(gotoDefShortcut, &QShortcut::activated, this, &SeerEditorWidgetSourceArea::handleGotoDefinition);

setCurrentLine(0);

updateMarginAreasWidth(0);
Expand Down Expand Up @@ -2025,3 +2029,57 @@ void SeerEditorWidgetSourceBreakPointArea::mouseReleaseEvent (QMouseEvent* event
QWidget::mouseReleaseEvent(event);
}

/***********************************************************************************************************************
* Go to definition feature *
**********************************************************************************************************************/
// Check text and decide if that text is valid identifier (function, variable, type name)
bool SeerEditorWidgetSourceArea::isValidIdentifier(const QString& text)
{
static const QSet<QString> keywords = {
// Add your C and C++ keywords as QString literals here
"auto", "break", "case", "char", "const", "continue", "default", "do", "double",
"else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
"register", "restrict", "return", "short", "signed", "sizeof", "static", "struct",
"switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas",
"_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn",
"_Static_assert", "_Thread_local",

"alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch",
"char16_t", "char32_t", "class", "compl", "const_cast", "constexpr", "decltype",
"delete", "dynamic_cast", "explicit", "export", "false", "friend", "mutable", "namespace",
"new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private",
"protected", "public", "reinterpret_cast", "static_assert", "static_cast", "template",
"this", "thread_local", "throw", "true", "try", "typeid", "typename", "using",
"virtual", "wchar_t", "xor", "xor_eq"
};

if (text.isEmpty())
return false;

if (keywords.contains(text))
return false;

QChar firstChar = text[0];
if (!firstChar.isLetter() && firstChar != '_')
return false;

for (int i = 1; i < text.size(); ++i) {
QChar ch = text[i];
if (!ch.isLetterOrNumber() && ch != '_')
return false;
}

return true;
}

// When F12 is pressed, try to look for the word under cursor, if it's a valid identifier then emit gdbGotoDefinition signal
void SeerEditorWidgetSourceArea::handleGotoDefinition()
{
QTextCursor cursor = textCursor();
cursor.select(QTextCursor::WordUnderCursor);
QString wordUnderCursor = cursor.selectedText();
if (isValidIdentifier(wordUnderCursor))
{
emit gdbGotoDefinition(wordUnderCursor);
}
}
101 changes: 101 additions & 0 deletions src/SeerGdbWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, this, &SeerGdbWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, this, &SeerGdbWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, this, &SeerGdbWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, this, &SeerGdbWidget::handleText);

QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText);
Expand Down Expand Up @@ -366,6 +367,7 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
#endif

QObject::connect(this, &SeerGdbWidget::stateChanged, editorManagerWidget, &SeerEditorManagerWidget::handleGdbStateChanged);
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::gdbGotoDefinitionForward, this, &SeerGdbWidget::handleGdbGotoDefinition);

// Restore window settings.
readSettings();
Expand Down Expand Up @@ -796,6 +798,43 @@ void SeerGdbWidget::handleText (const QString& text) {

handleGdbSignalListValues("all");

}else if (text.startsWith("^done,symbols")) // seeking for function, variable and type identifiers
{
//^done,symbols={debug=[{filename=" ",fullname=" ",
// symbols=[{line=" ",name="uwTick",type="volatile uint32_t",description="volatile uint32_t uwTick;"},}]}
_gotoDefMutex.lock();

QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false);
QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false);

for (const auto& filename_entry : filenames_list) {

QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false);
QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false);

// If that file is not in source browser, skip it
if (sourceLibraryManagerWidget->sourceBrowserWidget()->findFileWithRegrex(fullname_text).isEmpty())
continue;

QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false);
QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false);

for (const auto& symbol_entry : symbols_list) {

QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false);
QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false);
// name_text may be st like: function_name(params...) , so only extract function_name part
name_text = name_text.section('(', 0, 0).trimmed();
if (name_text == _gotoDefIdentifier) // you found it! signal to open file
{
// editorManagerWidget->setEnableOpenFile(true); // raise this flag to allow opening file
editorManagerWidget->handleOpenFile(filename_text, fullname_text, line_text.toInt());
}
}
}

_gotoDefWaitCond.notify_one();
_gotoDefMutex.unlock();
}else{
// All other text is ignored by this widget.
}
Expand Down Expand Up @@ -3093,6 +3132,28 @@ void SeerGdbWidget::handleAboutToQuit () {
setIsQuitting(true);
}

void SeerGdbWidget::handleGdbGotoDefinition(const QString& identifier) {
// Raise the flag
_gotoDefIdentifier = identifier;
QApplication::setOverrideCursor(Qt::BusyCursor);
// Create a thread handling this
_workerThread = QThread::create([this]() {
gotoDefinitionWorker(_gotoDefIdentifier); // Run background logic here
});
QObject::connect(_workerThread, &QThread::finished, _workerThread, &QObject::deleteLater);
_workerThread->start();
}

void SeerGdbWidget::gotoDefinitionWorker(const QString& identifier) {

// For Desktop applications only
syncFindVariableIdentifier(identifier);
syncFindFunctionIdentifier(identifier);
syncFindTypeIdentifier(identifier);
// setSeekIdentifierFlag(false); // Lower the flag
QApplication::restoreOverrideCursor();
}

void SeerGdbWidget::writeSettings () {

//qDebug() << "Write Settings";
Expand Down Expand Up @@ -3855,3 +3916,43 @@ void SeerGdbWidget::delay (int seconds) {
}
}

/***********************************************************************************************************************
* Functions for handling Gdb and Seer synchronization *
**********************************************************************************************************************/
// For finding variable, function, and type identifiers in a synchronous manner
void SeerGdbWidget::syncFindVariableIdentifier(const QString& identifier)
{
_gotoDefMutex.lock();
emit requestFindVariableIdentifier(identifier);
_gotoDefWaitCond.wait(&_gotoDefMutex);
_gotoDefMutex.unlock();
}

void SeerGdbWidget::syncFindFunctionIdentifier (const QString& identifier)
{
_gotoDefMutex.lock();
emit requestFindFunctionIdentifier(identifier);
_gotoDefWaitCond.wait(&_gotoDefMutex);
_gotoDefMutex.unlock();
}

void SeerGdbWidget::syncFindTypeIdentifier (const QString& identifier)
{
_gotoDefMutex.lock();
emit requestFindTypeIdentifier(identifier);
_gotoDefWaitCond.wait(&_gotoDefMutex);
_gotoDefMutex.unlock();
}

void SeerGdbWidget::gdbFindVariableIdentifier(const QString& identifier)
{
handleGdbCommand("-symbol-info-variables --name " + identifier);
}
void SeerGdbWidget::gdbFindFunctionIdentifier (const QString& identifier)
{
handleGdbCommand("-symbol-info-functions --name " + identifier);
}
void SeerGdbWidget::gdbFindTypeIdentifier (const QString& identifier)
{
handleGdbCommand("-symbol-info-types --name " + identifier);
}
25 changes: 25 additions & 0 deletions src/SeerGdbWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include <QtCore/QProcess>
#include <QtCore/QVector>
#include <QtWidgets/QWidget>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>

#include "ui_SeerGdbWidget.h"

Expand Down Expand Up @@ -368,6 +371,11 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {

void handleAboutToQuit ();

void handleGdbGotoDefinition (const QString& identifier);
void gdbFindVariableIdentifier (const QString& identifier);
void gdbFindFunctionIdentifier (const QString& identifier);
void gdbFindTypeIdentifier (const QString& identifier);

signals:
void stoppingPointReached ();
void sessionTerminated ();
Expand All @@ -376,6 +384,9 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void recordSettingsChanged ();
void stateChanged ();
void gdbCommandLogout (const QString& text);
void requestFindVariableIdentifier (const QString& identifier);
void requestFindFunctionIdentifier (const QString& identifier);
void requestFindTypeIdentifier (const QString& identifier);

protected:

Expand All @@ -389,6 +400,13 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void sendGdbInterrupt (int signal);
void delay (int seconds);

void gotoDefinitionWorker (const QString& identifier);

// Functions for Gdb and Seer synchronization
void syncFindVariableIdentifier (const QString& identifier);
void syncFindFunctionIdentifier (const QString& identifier);
void syncFindTypeIdentifier (const QString& identifier);

bool _isQuitting;
QString _gdbLauncher;
QString _gdbProgram;
Expand Down Expand Up @@ -440,5 +458,12 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
QVector<QString> _dataExpressionName;

QStringList _ignoreFilePatterns;

QThread* _workerThread;

// Variable for Go to Definition handling
QString _gotoDefIdentifier;
QMutex _gotoDefMutex;
QWaitCondition _gotoDefWaitCond;
};

5 changes: 5 additions & 0 deletions src/SeerMainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) {
QObject::connect(gdbWidget, &SeerGdbWidget::sessionTerminated, runStatus, &SeerRunStatusIndicator::handleSessionTerminated);
handleRecordSettingsChanged();

// Connect Go to Definition signal/slot.
QObject::connect(gdbWidget, &SeerGdbWidget::requestFindVariableIdentifier, gdbWidget, &SeerGdbWidget::gdbFindVariableIdentifier);
QObject::connect(gdbWidget, &SeerGdbWidget::requestFindFunctionIdentifier, gdbWidget, &SeerGdbWidget::gdbFindFunctionIdentifier);
QObject::connect(gdbWidget, &SeerGdbWidget::requestFindTypeIdentifier, gdbWidget, &SeerGdbWidget::gdbFindTypeIdentifier);

//
// Initialize contents.
//
Expand Down
Loading