Skip to content

Commit f65bb99

Browse files
Add Go to Definition feature
1 parent b7b09cc commit f65bb99

5 files changed

Lines changed: 144 additions & 2 deletions

File tree

src/SeerEditorManagerWidget.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ bool SeerEditorManagerWidget::editorAutoSourceReload () const {
481481
return _editorAutoSourceReload;
482482
}
483483

484+
void SeerEditorManagerWidget::setSourceBrowserWidget (SeerSourceBrowserWidget* sourceBrowserWidget) {
485+
_sourceBrowserWidget = sourceBrowserWidget;
486+
}
487+
484488
void SeerEditorManagerWidget::handleText (const QString& text) {
485489

486490
// Update the current line.
@@ -801,6 +805,41 @@ void SeerEditorManagerWidget::handleText (const QString& text) {
801805
i->widget->sourceArea()->eraseColorCurrentLine(line_text.toInt());
802806
}
803807
}
808+
}else if ( text.contains(QRegularExpression("^([0-9]+)\\^done,symbols={")))
809+
{
810+
if (text.startsWith(_idTypeDefinition + "^done,symbols={") || text.startsWith(_idFunctionDefinition + "^done,symbols={") ||
811+
text.startsWith(_idVariableDefinition + "^done,symbols={")) // Handle Go to Definition
812+
{
813+
//^10done,symbols={debug=[{filename=" ",fullname=" ",
814+
// symbols=[{line=" ",name="uwTick",type="volatile uint32_t",description="volatile uint32_t uwTick;"},}]}]
815+
QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false);
816+
QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false);
817+
818+
for (const auto& filename_entry : filenames_list) {
819+
820+
QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false);
821+
QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false);
822+
823+
// If that file is not in source browser, skip it
824+
if (_sourceBrowserWidget->findFileWithRegrex(fullname_text).isEmpty())
825+
continue;
826+
827+
QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false);
828+
QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false);
829+
830+
for (const auto& symbol_entry : symbols_list) {
831+
832+
QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false);
833+
QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false);
834+
// name_text may be st like: function_name(params...) , so only extract function_name part
835+
name_text = name_text.section('(', 0, 0).trimmed();
836+
if (name_text == _gotoDefIdentifier) // you found it! Open file
837+
{
838+
handleOpenFile(filename_text, fullname_text, line_text.toInt());
839+
}
840+
}
841+
}
842+
}
804843
}
805844
else{
806845
// Ignore others.
@@ -1060,6 +1099,7 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
10601099
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
10611100
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
10621101
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation);
1102+
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder);
10631103

10641104
// Send the Editor widget the command to load the file. ??? Do better than this.
10651105
editorWidget->sourceArea()->handleText(text);
@@ -1124,6 +1164,7 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
11241164
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
11251165
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
11261166
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation);
1167+
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder);
11271168

11281169
// Load the file.
11291170
editorWidget->sourceArea()->open(fullname, QFileInfo(file).fileName());
@@ -1633,4 +1674,27 @@ void SeerEditorManagerWidget::mousePressEvent(QMouseEvent *event)
16331674
{
16341675
QWidget::mousePressEvent(event);
16351676
}
1636-
}
1677+
}
1678+
1679+
/***********************************************************************************************************************
1680+
* Functions for handling tracing identifier *
1681+
**********************************************************************************************************************/
1682+
void SeerEditorManagerWidget::gotoDefinitionForwarder(const QString& identifier)
1683+
{
1684+
_gotoDefIdentifier = identifier;
1685+
1686+
// Create a unique ID for the function definition request and send the command to gdb
1687+
_idFunctionDefinition = QString::number(Seer::createID());
1688+
QString gdbCommand = _idFunctionDefinition + "-symbol-info-functions --name " + _gotoDefIdentifier;
1689+
emit gotoDefinitionForward(gdbCommand);
1690+
1691+
// Create a unique ID for the variable definition request and send the command to gdb
1692+
_idVariableDefinition = QString::number(Seer::createID());
1693+
gdbCommand = _idVariableDefinition + "-symbol-info-variables --name " + _gotoDefIdentifier;
1694+
emit gotoDefinitionForward(gdbCommand);
1695+
1696+
// Create a unique ID for the type definition request and send the command to gdb
1697+
_idTypeDefinition = QString::number(Seer::createID());
1698+
gdbCommand = _idTypeDefinition + "-symbol-info-types --name " + _gotoDefIdentifier;
1699+
emit gotoDefinitionForward(gdbCommand);
1700+
}

src/SeerEditorManagerWidget.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "SeerEditorManagerEntry.h"
99
#include "SeerHighlighterSettings.h"
1010
#include "SeerKeySettings.h"
11+
#include "SeerSourceBrowserWidget.h"
1112
#include <QtGui/QFont>
1213
#include <QtWidgets/QWidget>
1314
#include <QtCore/QMap>
@@ -75,6 +76,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
7576
const QString& editorExternalEditorCommand () const;
7677
void setEditorAutoSourceReload (bool flag);
7778
bool editorAutoSourceReload () const;
79+
void setSourceBrowserWidget (SeerSourceBrowserWidget* sourceBrowserWidget);
7880

7981
public slots:
8082
void handleText (const QString& text);
@@ -117,6 +119,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
117119
void handleTextSearchToolButtonClicked ();
118120
void handleHelpToolButtonClicked ();
119121
void handleAddAlternateDirectory (QString path);
122+
void gotoDefinitionForwarder (const QString& identifier);
120123

121124
signals:
122125
void refreshBreakpointsList ();
@@ -141,6 +144,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
141144
void requestSourceAndAssembly (QString address);
142145
void showMessage (QString message, int time);
143146
void assemblyTabShown (bool shown);
147+
void gotoDefinitionForward (const QString& identifier, bool ignoreErrors = false);
144148

145149
private:
146150
SeerEditorWidgetSource* currentEditorWidgetTab ();
@@ -155,6 +159,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
155159

156160
SeerEditorManagerEntries _entries;
157161
SeerHighlighterSettings _editorHighlighterSettings;
162+
SeerSourceBrowserWidget* _sourceBrowserWidget; // Point to source browser widget in SeerGdbWidget
158163
bool _editorHighlighterEnabled;
159164
QFont _editorFont;
160165
QStringList _editorAlternateDirectories;
@@ -179,5 +184,11 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
179184
// list of cursor positions for mouse navigation (back/forward)
180185
QList<SeerEditorWidgetSourceArea::SeerCurrentFile> _listForwardFiles;
181186
int _forwardFilesIndex = -1;
187+
188+
// _id of identifier for Go to definition
189+
QString _idFunctionDefinition;
190+
QString _idVariableDefinition;
191+
QString _idTypeDefinition;
192+
QString _gotoDefIdentifier;
182193
};
183194

src/SeerEditorWidgetSource.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,14 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
145145
void showReloadBar (bool flag);
146146
void highlighterSettingsChanged ();
147147
void addToMouseNavigation (const SeerCurrentFile& currentFile);
148+
void signalGotoDefinition (const QString& identifier);
148149

149150
public slots:
150151
void handleText (const QString& text);
151152
void handleHighlighterSettingsChanged ();
152153
void handleWatchFileModified (const QString& path);
153154
void handleBreakpointToolTip (QPoint pos, const QString& text);
155+
void handleGotoDefinitionF12 ();
154156

155157
protected:
156158
void resizeEvent (QResizeEvent* event);
@@ -170,6 +172,8 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
170172

171173
private:
172174
void handleCursorPositionChanged ();
175+
bool isValidIdentifier (const QString& text);
176+
173177
QString _fullname;
174178
QString _file;
175179
QString _alternateDirectory;

src/SeerEditorWidgetSourceAreas.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPl
7272
// Connect cursor position changed signal.
7373
QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerEditorWidgetSourceArea::handleCursorPositionChanged);
7474

75+
// Add F12 shortcut. F12 -> SeerEditorWidgetSourceArea::handleGotoDefinitionF12 -> emit gotoDefinition(wordUnderCursor)
76+
QShortcut *shortcutF12 = new QShortcut(QKeySequence("F12"), this);
77+
QObject::connect(shortcutF12, &QShortcut::activated, this, &SeerEditorWidgetSourceArea::handleGotoDefinitionF12);
78+
7579
setCurrentLine(0);
7680

7781
updateMarginAreasWidth(0);
@@ -2051,6 +2055,7 @@ void SeerEditorWidgetSourceBreakPointArea::mouseReleaseEvent (QMouseEvent* event
20512055
**********************************************************************************************************************/
20522056
void SeerEditorWidgetSourceArea::mousePressEvent(QMouseEvent *event)
20532057
{
2058+
// This part is for mouse navigation feature
20542059
if (event->button() == Qt::XButton1 || event->button() == Qt::XButton2) {
20552060
// Avoid the default back/forward action
20562061
_ignoreThumbMouseEvent ++;
@@ -2086,3 +2091,58 @@ void SeerEditorWidgetSourceArea::handleCursorPositionChanged()
20862091
}
20872092
} );
20882093
}
2094+
2095+
/***********************************************************************************************************************
2096+
* Go to definition (F12) feature *
2097+
**********************************************************************************************************************/
2098+
// Check text and decide if that text is valid identifier (function, variable, type name)
2099+
bool SeerEditorWidgetSourceArea::isValidIdentifier(const QString& text)
2100+
{
2101+
static const QSet<QString> keywords = {
2102+
// Add your C and C++ keywords as QString literals here
2103+
"auto", "break", "case", "char", "const", "continue", "default", "do", "double",
2104+
"else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
2105+
"register", "restrict", "return", "short", "signed", "sizeof", "static", "struct",
2106+
"switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas",
2107+
"_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn",
2108+
"_Static_assert", "_Thread_local",
2109+
2110+
"alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch",
2111+
"char16_t", "char32_t", "class", "compl", "const_cast", "constexpr", "decltype",
2112+
"delete", "dynamic_cast", "explicit", "export", "false", "friend", "mutable", "namespace",
2113+
"new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private",
2114+
"protected", "public", "reinterpret_cast", "static_assert", "static_cast", "template",
2115+
"this", "thread_local", "throw", "true", "try", "typeid", "typename", "using",
2116+
"virtual", "wchar_t", "xor", "xor_eq"
2117+
};
2118+
2119+
if (text.isEmpty())
2120+
return false;
2121+
2122+
if (keywords.contains(text))
2123+
return false;
2124+
2125+
QChar firstChar = text[0];
2126+
if (!firstChar.isLetter() && firstChar != '_')
2127+
return false;
2128+
2129+
for (int i = 1; i < text.size(); ++i) {
2130+
QChar ch = text[i];
2131+
if (!ch.isLetterOrNumber() && ch != '_')
2132+
return false;
2133+
}
2134+
2135+
return true;
2136+
}
2137+
2138+
// When F12 is pressed, try to look for the word under cursor, if it's a valid identifier then emit signalGotoDefinition
2139+
void SeerEditorWidgetSourceArea::handleGotoDefinitionF12()
2140+
{
2141+
QTextCursor cursor = textCursor();
2142+
cursor.select(QTextCursor::WordUnderCursor);
2143+
QString wordUnderCursor = cursor.selectedText();
2144+
if (isValidIdentifier(wordUnderCursor))
2145+
{
2146+
emit signalGotoDefinition(wordUnderCursor);
2147+
}
2148+
}

src/SeerGdbWidget.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
358358
QObject::connect(sourceCommandLogsSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved);
359359
QObject::connect(stackThreadManagerSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved);
360360
QObject::connect(commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList);
361+
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::gotoDefinitionForward, this, &SeerGdbWidget::handleGdbCommand);
361362

362363
#if SEER_GDB_LOGOUT == 1
363364
// Direct all GdbWidget and GdbMonitor log to GDB Log, for debugging
@@ -369,6 +370,9 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
369370

370371
// Restore window settings.
371372
readSettings();
373+
374+
// Set source browser widget for editor manager widget, so that editor manager can check if a file is in source browser before opening it
375+
editorManagerWidget->setSourceBrowserWidget(sourceLibraryManagerWidget->sourceBrowserWidget());
372376
}
373377

374378
SeerGdbWidget::~SeerGdbWidget () {
@@ -3854,4 +3858,3 @@ void SeerGdbWidget::delay (int seconds) {
38543858
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
38553859
}
38563860
}
3857-

0 commit comments

Comments
 (0)