forked from qt-creator/qt-creator
CompilerExplorer: Add assembly => source links
When hovering over the assembly, the matching source lines are highlighted. Links inside the assembly are now clickable. Change-Id: I22479a2e1badcfd95e0f341b2556fc93c8469625 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -226,7 +226,7 @@ struct CompilerResult
|
|||||||
|
|
||||||
struct CompileResult : CompilerResult
|
struct CompileResult : CompilerResult
|
||||||
{
|
{
|
||||||
struct Asm
|
struct AssemblyLine
|
||||||
{
|
{
|
||||||
// A part of the asm that is a (hyper)link to a label (the name references labelDefinitions)
|
// A part of the asm that is a (hyper)link to a label (the name references labelDefinitions)
|
||||||
struct Label
|
struct Label
|
||||||
@@ -246,34 +246,68 @@ struct CompileResult : CompilerResult
|
|||||||
label.range.endCol = object["range"]["endCol"].toInt();
|
label.range.endCol = object["range"]["endCol"].toInt();
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const Label &other) const
|
||||||
|
{
|
||||||
|
return name == other.name && range.startCol == other.range.startCol
|
||||||
|
&& range.endCol == other.range.endCol;
|
||||||
|
}
|
||||||
|
bool operator!=(const Label &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
QList<Label> labels;
|
QList<Label> labels;
|
||||||
// The part of the source that generated this asm
|
// The part of the source that generated this asm
|
||||||
struct
|
struct Source
|
||||||
{
|
{
|
||||||
int column;
|
std::optional<int> column;
|
||||||
QString file;
|
QString file;
|
||||||
int line;
|
int line;
|
||||||
} source;
|
bool operator==(const Source &other) const
|
||||||
|
{
|
||||||
|
return column == other.column && file == other.file && line == other.line;
|
||||||
|
}
|
||||||
|
bool operator!=(const Source &other) const { return !(*this == other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<Source> source;
|
||||||
|
|
||||||
QString text;
|
QString text;
|
||||||
QStringList opcodes;
|
QStringList opcodes;
|
||||||
|
|
||||||
static Asm fromJson(const QJsonObject &object)
|
static AssemblyLine fromJson(const QJsonObject &object)
|
||||||
{
|
{
|
||||||
Asm asm_;
|
AssemblyLine line;
|
||||||
asm_.text = object["text"].toString();
|
line.text = object["text"].toString();
|
||||||
auto opcodes = object["opcodes"].toArray();
|
auto opcodes = object["opcodes"].toArray();
|
||||||
for (const auto &opcode : opcodes)
|
for (const auto &opcode : opcodes)
|
||||||
asm_.opcodes.append(opcode.toString());
|
line.opcodes.append(opcode.toString());
|
||||||
asm_.source.column = object["source"]["column"].toInt();
|
|
||||||
asm_.source.file = object["source"]["file"].toString();
|
auto itSource = object.find("source");
|
||||||
asm_.source.line = object["source"]["line"].toInt();
|
if (itSource != object.end() && !itSource->isNull()) {
|
||||||
|
std::optional<int> columnOpt;
|
||||||
|
auto source = itSource->toObject();
|
||||||
|
|
||||||
|
auto itColumn = source.find("column");
|
||||||
|
if (itColumn != source.end() && !itColumn->isNull())
|
||||||
|
columnOpt = itColumn->toInt();
|
||||||
|
|
||||||
|
line.source = Source{
|
||||||
|
columnOpt,
|
||||||
|
source["file"].toString(),
|
||||||
|
source["line"].toInt(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &label : object["labels"].toArray()) {
|
for (const auto &label : object["labels"].toArray()) {
|
||||||
asm_.labels.append(Label::fromJson(label.toObject()));
|
line.labels.append(Label::fromJson(label.toObject()));
|
||||||
}
|
}
|
||||||
return asm_;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const AssemblyLine &other) const
|
||||||
|
{
|
||||||
|
return source == other.source && text == other.text && opcodes == other.opcodes;
|
||||||
|
}
|
||||||
|
bool operator!=(const AssemblyLine &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExecResult
|
struct ExecResult
|
||||||
@@ -304,7 +338,7 @@ struct CompileResult : CompilerResult
|
|||||||
};
|
};
|
||||||
|
|
||||||
QMap<QString, int> labelDefinitions;
|
QMap<QString, int> labelDefinitions;
|
||||||
QList<Asm> assemblyLines;
|
QList<AssemblyLine> assemblyLines;
|
||||||
|
|
||||||
std::optional<ExecResult> execResult;
|
std::optional<ExecResult> execResult;
|
||||||
|
|
||||||
@@ -327,7 +361,7 @@ struct CompileResult : CompilerResult
|
|||||||
|
|
||||||
if (object.contains("asm")) {
|
if (object.contains("asm")) {
|
||||||
for (const auto &asmLine : object["asm"].toArray())
|
for (const auto &asmLine : object["asm"].toArray())
|
||||||
result.assemblyLines.append(Asm::fromJson(asmLine.toObject()));
|
result.assemblyLines.append(AssemblyLine::fromJson(asmLine.toObject()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("execResult"))
|
if (object.contains("execResult"))
|
||||||
|
@@ -15,9 +15,11 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
|
#include <texteditor/fontsettings.h>
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
#include <texteditor/texteditoractionhandler.h>
|
#include <texteditor/texteditoractionhandler.h>
|
||||||
|
#include <texteditor/texteditorsettings.h>
|
||||||
#include <texteditor/textmark.h>
|
#include <texteditor/textmark.h>
|
||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
@@ -55,6 +57,13 @@ using namespace Utils;
|
|||||||
|
|
||||||
namespace CompilerExplorer {
|
namespace CompilerExplorer {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LinkProperty = QTextFormat::UserProperty + 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr char AsmEditorLinks[] = "AsmEditor.Links";
|
||||||
|
constexpr char SourceEditorHoverLine[] = "SourceEditor.HoveredLine";
|
||||||
|
|
||||||
CodeEditorWidget::CodeEditorWidget(const std::shared_ptr<SourceSettings> &settings,
|
CodeEditorWidget::CodeEditorWidget(const std::shared_ptr<SourceSettings> &settings,
|
||||||
QUndoStack *undoStack)
|
QUndoStack *undoStack)
|
||||||
: m_settings(settings)
|
: m_settings(settings)
|
||||||
@@ -264,6 +273,57 @@ QString SourceEditorWidget::sourceCode()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceEditorWidget::markSourceLocation(
|
||||||
|
const std::optional<Api::CompileResult::AssemblyLine> &assemblyLine)
|
||||||
|
{
|
||||||
|
if (!assemblyLine || !assemblyLine->source) {
|
||||||
|
m_codeEditor->setExtraSelections(SourceEditorHoverLine, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto source = *assemblyLine->source;
|
||||||
|
|
||||||
|
// If this is a location in a different file we cannot highlight it
|
||||||
|
if (!source.file.isEmpty()) {
|
||||||
|
m_codeEditor->setExtraSelections(SourceEditorHoverLine, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lines are 1-based, so if we get 0 it means we don't have a valid location
|
||||||
|
if (source.line == 0) {
|
||||||
|
m_codeEditor->setExtraSelections(SourceEditorHoverLine, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QTextEdit::ExtraSelection> selections;
|
||||||
|
|
||||||
|
const TextEditor::FontSettings fs = TextEditor::TextEditorSettings::fontSettings();
|
||||||
|
QTextCharFormat background = fs.toTextCharFormat(TextEditor::C_CURRENT_LINE);
|
||||||
|
QTextCharFormat column = fs.toTextCharFormat(TextEditor::C_OCCURRENCES);
|
||||||
|
|
||||||
|
QTextBlock block = m_codeEditor->textDocument()->document()->findBlockByLineNumber(source.line
|
||||||
|
- 1);
|
||||||
|
|
||||||
|
QTextEdit::ExtraSelection selection;
|
||||||
|
selection.cursor = QTextCursor(m_codeEditor->textDocument()->document());
|
||||||
|
selection.cursor.setPosition(block.position());
|
||||||
|
selection.cursor.setPosition(qMax(block.position(), block.position() + block.length() - 1),
|
||||||
|
QTextCursor::KeepAnchor);
|
||||||
|
selection.cursor.setKeepPositionOnInsert(true);
|
||||||
|
selection.format = background;
|
||||||
|
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
||||||
|
selections.append(selection);
|
||||||
|
|
||||||
|
if (source.column) {
|
||||||
|
selection.cursor.setPosition(block.position() + *source.column - 1);
|
||||||
|
selection.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||||
|
selection.format = column;
|
||||||
|
selections.append(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_codeEditor->setExtraSelections(SourceEditorHoverLine, selections);
|
||||||
|
}
|
||||||
|
|
||||||
CompilerWidget::CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSettings,
|
CompilerWidget::CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSettings,
|
||||||
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
||||||
QUndoStack *undoStack)
|
QUndoStack *undoStack)
|
||||||
@@ -286,8 +346,14 @@ CompilerWidget::CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSett
|
|||||||
auto toolBar = new StyledBar;
|
auto toolBar = new StyledBar;
|
||||||
|
|
||||||
m_asmEditor = new AsmEditorWidget(undoStack);
|
m_asmEditor = new AsmEditorWidget(undoStack);
|
||||||
m_asmDocument = QSharedPointer<TextDocument>(new TextDocument);
|
m_asmDocument = QSharedPointer<AsmDocument>(new AsmDocument);
|
||||||
m_asmEditor->setTextDocument(m_asmDocument);
|
m_asmEditor->setTextDocument(m_asmDocument);
|
||||||
|
|
||||||
|
connect(m_asmEditor,
|
||||||
|
&AsmEditorWidget::hoveredLineChanged,
|
||||||
|
this,
|
||||||
|
&CompilerWidget::hoveredLineChanged);
|
||||||
|
|
||||||
QTC_ASSERT_EXPECTED(m_asmEditor->configureGenericHighlighter("Intel x86 (NASM)"),
|
QTC_ASSERT_EXPECTED(m_asmEditor->configureGenericHighlighter("Intel x86 (NASM)"),
|
||||||
m_asmEditor->configureGenericHighlighter(
|
m_asmEditor->configureGenericHighlighter(
|
||||||
Utils::mimeTypeForName("text/x-asm")));
|
Utils::mimeTypeForName("text/x-asm")));
|
||||||
@@ -464,28 +530,9 @@ void CompilerWidget::doCompile()
|
|||||||
m_resultTerminal->writeToTerminal((out + "\r\n").toUtf8(), false);
|
m_resultTerminal->writeToTerminal((out + "\r\n").toUtf8(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDeleteAll(m_marks);
|
|
||||||
m_marks.clear();
|
|
||||||
|
|
||||||
QString asmText;
|
const QList<QTextEdit::ExtraSelection> links = m_asmDocument->setCompileResult(r);
|
||||||
for (auto l : r.assemblyLines)
|
m_asmEditor->setExtraSelections(AsmEditorLinks, links);
|
||||||
asmText += l.text + "\n";
|
|
||||||
|
|
||||||
m_asmDocument->setPlainText(asmText);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (auto l : r.assemblyLines) {
|
|
||||||
i++;
|
|
||||||
if (l.opcodes.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto mark = new TextMark(m_asmDocument.get(),
|
|
||||||
i,
|
|
||||||
TextMarkCategory{Tr::tr("Bytes"), "Bytes"});
|
|
||||||
m_asmDocument->addMark(mark);
|
|
||||||
mark->setLineAnnotation(l.opcodes.join(' '));
|
|
||||||
m_marks.append(mark);
|
|
||||||
}
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
Core::MessageManager::writeDisrupting(
|
Core::MessageManager::writeDisrupting(
|
||||||
Tr::tr("Failed to compile: \"%1\".").arg(QString::fromUtf8(e.what())));
|
Tr::tr("Failed to compile: \"%1\".").arg(QString::fromUtf8(e.what())));
|
||||||
@@ -541,7 +588,7 @@ void EditorWidget::focusInEvent(QFocusEvent *event)
|
|||||||
FancyMainWindow::focusInEvent(event);
|
FancyMainWindow::focusInEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidget::addCompiler(const std::shared_ptr<SourceSettings> &sourceSettings,
|
CompilerWidget *EditorWidget::addCompiler(const std::shared_ptr<SourceSettings> &sourceSettings,
|
||||||
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
||||||
int idx)
|
int idx)
|
||||||
{
|
{
|
||||||
@@ -563,6 +610,8 @@ void EditorWidget::addCompiler(const std::shared_ptr<SourceSettings> &sourceSett
|
|||||||
connect(compiler, &CompilerWidget::gotFocus, this, [this] {
|
connect(compiler, &CompilerWidget::gotFocus, this, [this] {
|
||||||
m_actionHandler.updateCurrentEditor();
|
m_actionHandler.updateCurrentEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EditorWidget::windowStateCallback()
|
QVariantMap EditorWidget::windowStateCallback()
|
||||||
@@ -608,15 +657,27 @@ void EditorWidget::addSourceEditor(const std::shared_ptr<SourceSettings> &source
|
|||||||
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
|
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
|
||||||
|
|
||||||
sourceSettings->compilers.forEachItem<CompilerSettings>(
|
sourceSettings->compilers.forEachItem<CompilerSettings>(
|
||||||
[this, sourceSettings](const std::shared_ptr<CompilerSettings> &compilerSettings, int idx) {
|
[this,
|
||||||
addCompiler(sourceSettings, compilerSettings, idx + 1);
|
sourceEditor,
|
||||||
|
sourceSettings](const std::shared_ptr<CompilerSettings> &compilerSettings, int idx) {
|
||||||
|
auto compilerWidget = addCompiler(sourceSettings, compilerSettings, idx + 1);
|
||||||
|
connect(compilerWidget,
|
||||||
|
&CompilerWidget::hoveredLineChanged,
|
||||||
|
sourceEditor,
|
||||||
|
&SourceEditorWidget::markSourceLocation);
|
||||||
});
|
});
|
||||||
|
|
||||||
sourceSettings->compilers.setItemAddedCallback<CompilerSettings>(
|
sourceSettings->compilers.setItemAddedCallback<CompilerSettings>(
|
||||||
[this, sourceSettings](const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
[this, sourceEditor, sourceSettings](
|
||||||
addCompiler(sourceSettings->shared_from_this(),
|
const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
||||||
|
auto compilerWidget = addCompiler(sourceSettings->shared_from_this(),
|
||||||
compilerSettings,
|
compilerSettings,
|
||||||
sourceSettings->compilers.size());
|
sourceSettings->compilers.size());
|
||||||
|
|
||||||
|
connect(compilerWidget,
|
||||||
|
&CompilerWidget::hoveredLineChanged,
|
||||||
|
sourceEditor,
|
||||||
|
&SourceEditorWidget::markSourceLocation);
|
||||||
});
|
});
|
||||||
|
|
||||||
sourceSettings->compilers.setItemRemovedCallback<CompilerSettings>(
|
sourceSettings->compilers.setItemRemovedCallback<CompilerSettings>(
|
||||||
@@ -885,8 +946,129 @@ EditorFactory::EditorFactory()
|
|||||||
setEditorCreator([this]() { return new Editor(m_actionHandler); });
|
setEditorCreator([this]() { return new Editor(m_actionHandler); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QTextEdit::ExtraSelection> AsmDocument::setCompileResult(
|
||||||
|
const Api::CompileResult &compileResult)
|
||||||
|
{
|
||||||
|
m_assemblyLines = compileResult.assemblyLines;
|
||||||
|
|
||||||
|
document()->clear();
|
||||||
|
qDeleteAll(m_marks);
|
||||||
|
m_marks.clear();
|
||||||
|
|
||||||
|
QString asmText;
|
||||||
|
QTextCursor cursor(document());
|
||||||
|
|
||||||
|
QTextCharFormat linkFormat = TextEditor::TextEditorSettings::fontSettings().toTextCharFormat(
|
||||||
|
TextEditor::C_LINK);
|
||||||
|
|
||||||
|
QList<QTextEdit::ExtraSelection> links;
|
||||||
|
|
||||||
|
auto labelRow = [&labels = std::as_const(compileResult.labelDefinitions)](
|
||||||
|
const QString &labelName) -> std::optional<int> {
|
||||||
|
auto it = labels.find(labelName);
|
||||||
|
if (it != labels.end())
|
||||||
|
return *it;
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
setPlainText(
|
||||||
|
Utils::transform(m_assemblyLines, [](const auto &line) { return line.text; }).join('\n'));
|
||||||
|
|
||||||
|
int currentLine = 0;
|
||||||
|
for (auto l : m_assemblyLines) {
|
||||||
|
currentLine++;
|
||||||
|
|
||||||
|
auto createLabelLink = [currentLine, &linkFormat, &cursor, labelRow](
|
||||||
|
const Api::CompileResult::AssemblyLine::Label &label) {
|
||||||
|
QTextEdit::ExtraSelection selection;
|
||||||
|
selection.cursor = cursor;
|
||||||
|
QTextBlock block = cursor.document()->findBlockByLineNumber(currentLine - 1);
|
||||||
|
selection.cursor.setPosition(block.position() + label.range.startCol - 1);
|
||||||
|
selection.cursor.setPosition(block.position() + label.range.endCol - 1,
|
||||||
|
QTextCursor::KeepAnchor);
|
||||||
|
selection.cursor.setKeepPositionOnInsert(true);
|
||||||
|
selection.format = linkFormat;
|
||||||
|
|
||||||
|
if (auto lRow = labelRow(label.name))
|
||||||
|
selection.format.setProperty(LinkProperty, *lRow);
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
};
|
||||||
|
|
||||||
|
links.append(Utils::transform(l.labels, createLabelLink));
|
||||||
|
|
||||||
|
if (!l.opcodes.empty()) {
|
||||||
|
auto mark = new TextMark(this, currentLine, TextMarkCategory{Tr::tr("Bytes"), "Bytes"});
|
||||||
|
addMark(mark);
|
||||||
|
mark->setLineAnnotation(l.opcodes.join(' '));
|
||||||
|
m_marks.append(mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit contentsChanged();
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
AsmEditorWidget::AsmEditorWidget(QUndoStack *stack)
|
AsmEditorWidget::AsmEditorWidget(QUndoStack *stack)
|
||||||
: m_undoStack(stack)
|
: m_undoStack(stack)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void AsmEditorWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
const QTextCursor cursor = cursorForPosition(event->pos());
|
||||||
|
|
||||||
|
int line = cursor.block().blockNumber();
|
||||||
|
auto document = static_cast<AsmDocument *>(textDocument());
|
||||||
|
|
||||||
|
std::optional<Api::CompileResult::AssemblyLine> newLine;
|
||||||
|
if (line < document->asmLines().size())
|
||||||
|
newLine = document->asmLines()[line];
|
||||||
|
|
||||||
|
if (m_currentlyHoveredLine != newLine) {
|
||||||
|
m_currentlyHoveredLine = newLine;
|
||||||
|
emit hoveredLineChanged(newLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditorWidget::mouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsmEditorWidget::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
if (m_currentlyHoveredLine) {
|
||||||
|
m_currentlyHoveredLine = std::nullopt;
|
||||||
|
emit hoveredLineChanged(std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditorWidget::leaveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsmEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||||
|
const Utils::LinkHandler &processLinkCallback,
|
||||||
|
bool,
|
||||||
|
bool)
|
||||||
|
{
|
||||||
|
QList<QTextEdit::ExtraSelection> links = this->extraSelections(AsmEditorLinks);
|
||||||
|
|
||||||
|
auto contains = [cursor](const QTextEdit::ExtraSelection &selection) {
|
||||||
|
if (selection.format.hasProperty(LinkProperty)
|
||||||
|
&& selection.cursor.selectionStart() <= cursor.position()
|
||||||
|
&& selection.cursor.selectionEnd() >= cursor.position()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (std::optional<QTextEdit::ExtraSelection> selection = Utils::findOr(links,
|
||||||
|
std::nullopt,
|
||||||
|
contains)) {
|
||||||
|
const int row = selection->format.property(LinkProperty).toInt();
|
||||||
|
Link link{{}, row, 0};
|
||||||
|
link.linkTextStart = selection->cursor.selectionStart();
|
||||||
|
link.linkTextEnd = selection->cursor.selectionEnd();
|
||||||
|
|
||||||
|
processLinkCallback(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CompilerExplorer
|
} // namespace CompilerExplorer
|
||||||
|
@@ -30,6 +30,7 @@ namespace CompilerExplorer {
|
|||||||
|
|
||||||
class JsonSettingsDocument;
|
class JsonSettingsDocument;
|
||||||
class SourceEditorWidget;
|
class SourceEditorWidget;
|
||||||
|
class AsmDocument;
|
||||||
|
|
||||||
class CodeEditorWidget : public TextEditor::TextEditorWidget
|
class CodeEditorWidget : public TextEditor::TextEditorWidget
|
||||||
{
|
{
|
||||||
@@ -56,6 +57,19 @@ private:
|
|||||||
QUndoStack *m_undoStack;
|
QUndoStack *m_undoStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AsmDocument : public TextEditor::TextDocument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TextEditor::TextDocument::TextDocument;
|
||||||
|
|
||||||
|
QList<QTextEdit::ExtraSelection> setCompileResult(const Api::CompileResult &compileResult);
|
||||||
|
QList<Api::CompileResult::AssemblyLine> &asmLines() { return m_assemblyLines; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<Api::CompileResult::AssemblyLine> m_assemblyLines;
|
||||||
|
QList<TextEditor::TextMark *> m_marks;
|
||||||
|
};
|
||||||
|
|
||||||
class AsmEditorWidget : public TextEditor::TextEditorWidget
|
class AsmEditorWidget : public TextEditor::TextEditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -69,14 +83,25 @@ public:
|
|||||||
emit gotFocus();
|
emit gotFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void findLinkAt(const QTextCursor &,
|
||||||
|
const Utils::LinkHandler &processLinkCallback,
|
||||||
|
bool resolveTarget = true,
|
||||||
|
bool inNextSplit = false) override;
|
||||||
|
|
||||||
void undo() override { m_undoStack->undo(); }
|
void undo() override { m_undoStack->undo(); }
|
||||||
void redo() override { m_undoStack->redo(); }
|
void redo() override { m_undoStack->redo(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
void leaveEvent(QEvent *event) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void gotFocus();
|
void gotFocus();
|
||||||
|
void hoveredLineChanged(const std::optional<Api::CompileResult::AssemblyLine> &assemblyLine);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUndoStack *m_undoStack;
|
QUndoStack *m_undoStack;
|
||||||
|
std::optional<Api::CompileResult::AssemblyLine> m_currentlyHoveredLine;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JsonSettingsDocument : public Core::IDocument
|
class JsonSettingsDocument : public Core::IDocument
|
||||||
@@ -128,6 +153,9 @@ public:
|
|||||||
|
|
||||||
TextEditor::TextEditorWidget *textEditor() { return m_codeEditor; }
|
TextEditor::TextEditorWidget *textEditor() { return m_codeEditor; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void markSourceLocation(const std::optional<Api::CompileResult::AssemblyLine> &assemblyLine);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sourceCodeChanged();
|
void sourceCodeChanged();
|
||||||
void remove();
|
void remove();
|
||||||
@@ -163,19 +191,19 @@ private:
|
|||||||
signals:
|
signals:
|
||||||
void remove();
|
void remove();
|
||||||
void gotFocus();
|
void gotFocus();
|
||||||
|
void hoveredLineChanged(const std::optional<Api::CompileResult::AssemblyLine> &assemblyLine);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsmEditorWidget *m_asmEditor{nullptr};
|
AsmEditorWidget *m_asmEditor{nullptr};
|
||||||
Core::SearchableTerminal *m_resultTerminal{nullptr};
|
Core::SearchableTerminal *m_resultTerminal{nullptr};
|
||||||
|
|
||||||
SpinnerSolution::Spinner *m_spinner{nullptr};
|
SpinnerSolution::Spinner *m_spinner{nullptr};
|
||||||
QSharedPointer<TextEditor::TextDocument> m_asmDocument;
|
QSharedPointer<AsmDocument> m_asmDocument;
|
||||||
|
|
||||||
std::unique_ptr<QFutureWatcher<Api::CompileResult>> m_compileWatcher;
|
std::unique_ptr<QFutureWatcher<Api::CompileResult>> m_compileWatcher;
|
||||||
|
|
||||||
QString m_source;
|
QString m_source;
|
||||||
QTimer *m_delayTimer{nullptr};
|
QTimer *m_delayTimer{nullptr};
|
||||||
QList<TextEditor::TextMark *> m_marks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HelperWidget : public QWidget
|
class HelperWidget : public QWidget
|
||||||
@@ -213,7 +241,7 @@ protected:
|
|||||||
void setupHelpWidget();
|
void setupHelpWidget();
|
||||||
QWidget *createHelpWidget() const;
|
QWidget *createHelpWidget() const;
|
||||||
|
|
||||||
void addCompiler(const std::shared_ptr<SourceSettings> &sourceSettings,
|
CompilerWidget *addCompiler(const std::shared_ptr<SourceSettings> &sourceSettings,
|
||||||
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
||||||
int idx);
|
int idx);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user