2023-07-06 14:11:36 +02:00
|
|
|
// Copyright (C) 2023 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
|
|
|
|
|
|
#include "compilerexplorereditor.h"
|
|
|
|
|
#include "compilerexplorerconstants.h"
|
|
|
|
|
#include "compilerexploreroptions.h"
|
|
|
|
|
#include "compilerexplorersettings.h"
|
|
|
|
|
#include "compilerexplorertr.h"
|
|
|
|
|
|
|
|
|
|
#include <aggregation/aggregate.h>
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2023-07-06 14:11:36 +02:00
|
|
|
#include <coreplugin/coreconstants.h>
|
|
|
|
|
#include <coreplugin/icontext.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
|
|
|
|
#include <texteditor/textdocument.h>
|
|
|
|
|
#include <texteditor/texteditor.h>
|
|
|
|
|
#include <texteditor/texteditoractionhandler.h>
|
|
|
|
|
#include <texteditor/textmark.h>
|
|
|
|
|
|
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
#include <utils/algorithm.h>
|
2023-07-06 14:11:36 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
#include <utils/layoutbuilder.h>
|
|
|
|
|
#include <utils/mimetypes2/mimetype.h>
|
2023-08-17 08:50:33 +02:00
|
|
|
#include <utils/mimeutils.h>
|
2023-09-21 09:32:07 +02:00
|
|
|
#include <utils/store.h>
|
2023-07-06 14:11:36 +02:00
|
|
|
#include <utils/utilsicons.h>
|
|
|
|
|
|
|
|
|
|
#include <QCompleter>
|
|
|
|
|
#include <QDockWidget>
|
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
|
#include <QPushButton>
|
|
|
|
|
#include <QSplitter>
|
|
|
|
|
#include <QStackedLayout>
|
|
|
|
|
#include <QStandardItemModel>
|
|
|
|
|
#include <QTemporaryFile>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QToolButton>
|
2023-09-21 09:32:07 +02:00
|
|
|
#include <QUndoStack>
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
using namespace Aggregation;
|
|
|
|
|
using namespace TextEditor;
|
2023-08-28 15:11:10 +02:00
|
|
|
using namespace Utils;
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
namespace CompilerExplorer {
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
CodeEditorWidget::CodeEditorWidget(const std::shared_ptr<SourceSettings> &settings,
|
|
|
|
|
QUndoStack *undoStack)
|
|
|
|
|
: m_settings(settings)
|
|
|
|
|
, m_undoStack(undoStack){};
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
void CodeEditorWidget::updateHighlighter()
|
|
|
|
|
{
|
|
|
|
|
const QString ext = m_settings->languageExtension();
|
|
|
|
|
if (ext.isEmpty())
|
|
|
|
|
return;
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
Utils::MimeType mimeType = Utils::mimeTypeForFile("foo" + ext);
|
|
|
|
|
configureGenericHighlighter(mimeType);
|
|
|
|
|
}
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
class SourceTextDocument : public TextDocument
|
|
|
|
|
{
|
|
|
|
|
public:
|
2023-09-21 09:32:07 +02:00
|
|
|
class OpaqueUndoCommand : public QUndoCommand
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
OpaqueUndoCommand(SourceTextDocument *doc)
|
|
|
|
|
: m_doc(doc)
|
|
|
|
|
{}
|
|
|
|
|
void undo() override { m_doc->undo(); }
|
|
|
|
|
void redo() override { m_doc->redo(); }
|
|
|
|
|
SourceTextDocument *m_doc;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SourceTextDocument(const std::shared_ptr<SourceSettings> &settings, QUndoStack *undoStack)
|
2023-08-17 08:50:33 +02:00
|
|
|
{
|
|
|
|
|
setPlainText(settings->source());
|
|
|
|
|
|
|
|
|
|
connect(this, &TextDocument::contentsChanged, this, [settings, this] {
|
|
|
|
|
settings->source.setVolatileValue(plainText());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(&settings->source, &Utils::StringAspect::changed, this, [settings, this] {
|
|
|
|
|
if (settings->source.volatileValue() != plainText())
|
|
|
|
|
setPlainText(settings->source.volatileValue());
|
|
|
|
|
});
|
2023-09-21 09:32:07 +02:00
|
|
|
|
|
|
|
|
connect(this->document(), &QTextDocument::undoCommandAdded, this, [this, undoStack] {
|
|
|
|
|
undoStack->push(new OpaqueUndoCommand(this));
|
|
|
|
|
});
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
2023-09-21 09:32:07 +02:00
|
|
|
|
|
|
|
|
void undo() { document()->undo(); }
|
|
|
|
|
void redo() { document()->redo(); }
|
2023-08-17 08:50:33 +02:00
|
|
|
};
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
JsonSettingsDocument::JsonSettingsDocument(QUndoStack *undoStack)
|
|
|
|
|
: m_undoStack(undoStack)
|
2023-08-17 08:50:33 +02:00
|
|
|
{
|
|
|
|
|
setId(Constants::CE_EDITOR_ID);
|
2023-08-24 13:24:05 +02:00
|
|
|
setMimeType("application/compiler-explorer");
|
2023-09-26 07:25:25 +02:00
|
|
|
connect(&m_ceSettings, &CompilerExplorerSettings::changed, this, [this] {
|
|
|
|
|
emit changed();
|
|
|
|
|
emit contentsChanged();
|
|
|
|
|
});
|
|
|
|
|
m_ceSettings.setAutoApply(false);
|
2023-09-21 09:32:07 +02:00
|
|
|
m_ceSettings.setUndoStack(undoStack);
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Core::IDocument::OpenResult JsonSettingsDocument::open(QString *errorString,
|
2023-08-28 15:11:10 +02:00
|
|
|
const FilePath &filePath,
|
|
|
|
|
const FilePath &realFilePath)
|
2023-08-17 08:50:33 +02:00
|
|
|
{
|
|
|
|
|
if (!filePath.isReadableFile())
|
|
|
|
|
return OpenResult::ReadError;
|
|
|
|
|
|
|
|
|
|
auto contents = realFilePath.fileContents();
|
|
|
|
|
if (!contents) {
|
|
|
|
|
if (errorString)
|
|
|
|
|
*errorString = contents.error();
|
|
|
|
|
return OpenResult::ReadError;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-14 14:05:32 +02:00
|
|
|
auto result = storeFromJson(*contents);
|
|
|
|
|
if (!result) {
|
2023-08-17 08:50:33 +02:00
|
|
|
if (errorString)
|
2023-09-14 14:05:32 +02:00
|
|
|
*errorString = result.error();
|
|
|
|
|
return OpenResult::ReadError;
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-26 09:20:26 +02:00
|
|
|
setFilePath(filePath);
|
|
|
|
|
|
2023-09-14 14:05:32 +02:00
|
|
|
m_ceSettings.fromMap(*result);
|
2023-08-17 08:50:33 +02:00
|
|
|
emit settingsChanged();
|
|
|
|
|
return OpenResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
bool JsonSettingsDocument::saveImpl(QString *errorString, const FilePath &newFilePath, bool autoSave)
|
2023-07-06 14:11:36 +02:00
|
|
|
{
|
2023-09-21 09:32:07 +02:00
|
|
|
Store store;
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
if (autoSave) {
|
|
|
|
|
if (m_windowStateCallback)
|
2023-08-24 13:24:05 +02:00
|
|
|
m_ceSettings.windowState.setVolatileValue(m_windowStateCallback());
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
m_ceSettings.volatileToMap(store);
|
2023-08-17 08:50:33 +02:00
|
|
|
} else {
|
|
|
|
|
if (m_windowStateCallback)
|
2023-08-24 13:24:05 +02:00
|
|
|
m_ceSettings.windowState.setValue(m_windowStateCallback());
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-08-24 13:24:05 +02:00
|
|
|
m_ceSettings.apply();
|
2023-09-21 09:32:07 +02:00
|
|
|
m_ceSettings.toMap(store);
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Utils::FilePath path = newFilePath.isEmpty() ? filePath() : newFilePath;
|
|
|
|
|
|
2023-09-26 07:25:25 +02:00
|
|
|
if (!newFilePath.isEmpty() && !autoSave) {
|
|
|
|
|
setPreferredDisplayName({});
|
2023-08-17 08:50:33 +02:00
|
|
|
setFilePath(newFilePath);
|
2023-09-26 07:25:25 +02:00
|
|
|
}
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
auto result = path.writeFileContents(jsonFromStore(store));
|
2023-08-17 08:50:33 +02:00
|
|
|
if (!result && errorString) {
|
|
|
|
|
*errorString = result.error();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-26 09:20:26 +02:00
|
|
|
emit changed();
|
2023-08-17 08:50:33 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsonSettingsDocument::isModified() const
|
|
|
|
|
{
|
2023-08-24 13:24:05 +02:00
|
|
|
return m_ceSettings.isDirty();
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsonSettingsDocument::setContents(const QByteArray &contents)
|
|
|
|
|
{
|
2023-09-14 14:05:32 +02:00
|
|
|
auto result = storeFromJson(contents);
|
|
|
|
|
QTC_ASSERT_EXPECTED(result, return false);
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-14 14:05:32 +02:00
|
|
|
m_ceSettings.fromMap(*result);
|
2023-08-17 08:50:33 +02:00
|
|
|
|
|
|
|
|
emit settingsChanged();
|
2023-09-26 07:25:25 +02:00
|
|
|
emit changed();
|
|
|
|
|
emit contentsChanged();
|
2023-08-17 08:50:33 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
SourceEditorWidget::SourceEditorWidget(const std::shared_ptr<SourceSettings> &settings,
|
|
|
|
|
QUndoStack *undoStack)
|
2023-08-17 08:50:33 +02:00
|
|
|
: m_sourceSettings(settings)
|
|
|
|
|
{
|
2023-09-21 09:32:07 +02:00
|
|
|
m_codeEditor = new CodeEditorWidget(m_sourceSettings, undoStack);
|
|
|
|
|
|
|
|
|
|
connect(m_codeEditor, &CodeEditorWidget::gotFocus, this, &SourceEditorWidget::gotFocus);
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
TextDocumentPtr document = TextDocumentPtr(new SourceTextDocument(m_sourceSettings, undoStack));
|
2023-08-17 08:50:33 +02:00
|
|
|
|
|
|
|
|
connect(document.get(),
|
|
|
|
|
&SourceTextDocument::changed,
|
|
|
|
|
this,
|
|
|
|
|
&SourceEditorWidget::sourceCodeChanged);
|
|
|
|
|
|
|
|
|
|
m_codeEditor->setTextDocument(document);
|
|
|
|
|
m_codeEditor->updateHighlighter();
|
|
|
|
|
|
|
|
|
|
auto addCompilerButton = new QPushButton;
|
|
|
|
|
addCompilerButton->setText(Tr::tr("Add compiler"));
|
2023-09-21 09:32:07 +02:00
|
|
|
connect(addCompilerButton, &QPushButton::clicked, this, &SourceEditorWidget::addCompiler);
|
|
|
|
|
|
|
|
|
|
auto removeSourceButton = new QPushButton;
|
|
|
|
|
removeSourceButton->setIcon(Utils::Icons::EDIT_CLEAR.icon());
|
|
|
|
|
removeSourceButton->setToolTip(Tr::tr("Remove source"));
|
|
|
|
|
connect(removeSourceButton, &QPushButton::clicked, this, &SourceEditorWidget::remove);
|
2023-08-17 08:50:33 +02:00
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
using namespace Layouting;
|
|
|
|
|
|
|
|
|
|
Column {
|
|
|
|
|
Row {
|
|
|
|
|
settings->languageId,
|
|
|
|
|
addCompilerButton,
|
2023-09-21 09:32:07 +02:00
|
|
|
removeSourceButton,
|
2023-08-17 08:50:33 +02:00
|
|
|
},
|
|
|
|
|
m_codeEditor,
|
|
|
|
|
}.attachTo(this);
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
setWindowTitle("Source code");
|
|
|
|
|
setObjectName("source_code");
|
|
|
|
|
|
|
|
|
|
setFocusProxy(m_codeEditor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SourceEditorWidget::sourceCode()
|
|
|
|
|
{
|
|
|
|
|
if (m_codeEditor && m_codeEditor->textDocument())
|
|
|
|
|
return QString::fromUtf8(m_codeEditor->textDocument()->contents());
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompilerWidget::CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSettings,
|
|
|
|
|
const std::shared_ptr<CompilerSettings> &compilerSettings)
|
|
|
|
|
: m_sourceSettings(sourceSettings)
|
|
|
|
|
, m_compilerSettings(compilerSettings)
|
|
|
|
|
{
|
|
|
|
|
using namespace Layouting;
|
2023-08-28 15:11:10 +02:00
|
|
|
Store map;
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
m_delayTimer = new QTimer(this);
|
|
|
|
|
m_delayTimer->setSingleShot(true);
|
|
|
|
|
m_delayTimer->setInterval(500ms);
|
|
|
|
|
connect(m_delayTimer, &QTimer::timeout, this, &CompilerWidget::doCompile);
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
connect(m_compilerSettings.get(),
|
|
|
|
|
&CompilerSettings::changed,
|
|
|
|
|
m_delayTimer,
|
|
|
|
|
qOverload<>(&QTimer::start));
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
m_asmEditor = new AsmEditorWidget;
|
2023-07-06 14:11:36 +02:00
|
|
|
m_asmDocument = QSharedPointer<TextDocument>(new TextDocument);
|
|
|
|
|
m_asmDocument->setFilePath("asm.asm");
|
|
|
|
|
m_asmEditor->setTextDocument(m_asmDocument);
|
|
|
|
|
m_asmEditor->configureGenericHighlighter(Utils::mimeTypeForName("text/x-asm"));
|
2023-09-21 09:32:07 +02:00
|
|
|
m_asmEditor->setReadOnly(true);
|
|
|
|
|
|
|
|
|
|
connect(m_asmEditor, &AsmEditorWidget::gotFocus, this, &CompilerWidget::gotFocus);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
auto advButton = new QPushButton;
|
|
|
|
|
QSplitter *splitter{nullptr};
|
|
|
|
|
|
|
|
|
|
auto advDlg = new QAction;
|
|
|
|
|
advDlg->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon());
|
|
|
|
|
advDlg->setIconText(Tr::tr("Advanced Options"));
|
|
|
|
|
connect(advDlg, &QAction::triggered, this, [advButton, this] {
|
2023-08-17 08:50:33 +02:00
|
|
|
CompilerExplorerOptions *dlg = new CompilerExplorerOptions(*m_compilerSettings, advButton);
|
2023-07-06 14:11:36 +02:00
|
|
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
dlg->setWindowFlag(Qt::WindowType::Popup);
|
|
|
|
|
dlg->show();
|
|
|
|
|
QRect rect = dlg->geometry();
|
|
|
|
|
rect.moveTopRight(advButton->mapToGlobal(QPoint(advButton->width(), advButton->height())));
|
|
|
|
|
dlg->setGeometry(rect);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(advButton, &QPushButton::clicked, advDlg, &QAction::trigger);
|
|
|
|
|
advButton->setIcon(advDlg->icon());
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
auto removeCompilerBtn = new QPushButton;
|
|
|
|
|
removeCompilerBtn->setIcon(Utils::Icons::EDIT_CLEAR.icon());
|
|
|
|
|
removeCompilerBtn->setToolTip(Tr::tr("Remove compiler"));
|
|
|
|
|
connect(removeCompilerBtn, &QPushButton::clicked, this, &CompilerWidget::remove);
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
compile(m_sourceSettings->source());
|
|
|
|
|
|
|
|
|
|
connect(&m_sourceSettings->source, &Utils::StringAspect::volatileValueChanged, this, [this] {
|
|
|
|
|
compile(m_sourceSettings->source.volatileValue());
|
|
|
|
|
});
|
|
|
|
|
|
2023-07-06 14:11:36 +02:00
|
|
|
// clang-format off
|
|
|
|
|
Column {
|
|
|
|
|
Row {
|
2023-08-17 08:50:33 +02:00
|
|
|
m_compilerSettings->compiler,
|
2023-07-06 14:11:36 +02:00
|
|
|
advButton,
|
2023-09-21 09:32:07 +02:00
|
|
|
removeCompilerBtn,
|
2023-07-06 14:11:36 +02:00
|
|
|
},
|
|
|
|
|
Splitter {
|
|
|
|
|
bindTo(&splitter),
|
|
|
|
|
m_asmEditor,
|
|
|
|
|
createTerminal()
|
|
|
|
|
}
|
|
|
|
|
}.attachTo(this);
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
m_spinner = new SpinnerSolution::Spinner(SpinnerSolution::SpinnerSize::Large, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Core::SearchableTerminal *CompilerWidget::createTerminal()
|
|
|
|
|
{
|
|
|
|
|
m_resultTerminal = new Core::SearchableTerminal();
|
|
|
|
|
m_resultTerminal->setAllowBlinkingCursor(false);
|
|
|
|
|
std::array<QColor, 20> colors{Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi0),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi1),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi2),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi3),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi4),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi5),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi6),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi7),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi8),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi9),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi10),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi11),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi12),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi13),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi14),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalAnsi15),
|
|
|
|
|
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalForeground),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalBackground),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalSelection),
|
|
|
|
|
Utils::creatorTheme()->color(Utils::Theme::TerminalFindMatch)};
|
|
|
|
|
|
|
|
|
|
m_resultTerminal->setColors(colors);
|
|
|
|
|
|
|
|
|
|
return m_resultTerminal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompilerWidget::compile(const QString &source)
|
|
|
|
|
{
|
|
|
|
|
m_source = source;
|
|
|
|
|
m_delayTimer->start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompilerWidget::doCompile()
|
|
|
|
|
{
|
|
|
|
|
using namespace Api;
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
QString compilerId = m_compilerSettings->compiler();
|
2023-07-06 14:11:36 +02:00
|
|
|
if (compilerId.isEmpty())
|
|
|
|
|
compilerId = "clang_trunk";
|
|
|
|
|
|
|
|
|
|
m_spinner->setVisible(true);
|
|
|
|
|
m_asmEditor->setEnabled(false);
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
CompileParameters params
|
|
|
|
|
= CompileParameters(compilerId)
|
|
|
|
|
.source(m_source)
|
|
|
|
|
.language(m_sourceSettings->languageId.volatileValue())
|
|
|
|
|
.options(CompileParameters::Options()
|
|
|
|
|
.userArguments(m_compilerSettings->compilerOptions.volatileValue())
|
|
|
|
|
.compilerOptions({false, false})
|
|
|
|
|
.filters({false,
|
|
|
|
|
m_compilerSettings->compileToBinaryObject.volatileValue(),
|
|
|
|
|
true,
|
|
|
|
|
m_compilerSettings->demangleIdentifiers.volatileValue(),
|
|
|
|
|
true,
|
|
|
|
|
m_compilerSettings->executeCode.volatileValue(),
|
|
|
|
|
m_compilerSettings->intelAsmSyntax.volatileValue(),
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false})
|
|
|
|
|
.libraries(m_compilerSettings->libraries.volatileValue()));
|
|
|
|
|
|
|
|
|
|
auto f = Api::compile(m_sourceSettings->apiConfigFunction()(), params);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
m_compileWatcher.reset(new QFutureWatcher<CompileResult>);
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
connect(m_compileWatcher.get(), &QFutureWatcher<CompileResult>::finished, this, [this] {
|
|
|
|
|
m_spinner->setVisible(false);
|
|
|
|
|
m_asmEditor->setEnabled(true);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Api::CompileResult r = m_compileWatcher->result();
|
|
|
|
|
|
|
|
|
|
m_resultTerminal->restart();
|
|
|
|
|
m_resultTerminal->writeToTerminal("\x1b[?25l", false);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
for (const auto &err : r.stdErr)
|
|
|
|
|
m_resultTerminal->writeToTerminal((err.text + "\r\n").toUtf8(), false);
|
|
|
|
|
for (const auto &out : r.stdOut)
|
|
|
|
|
m_resultTerminal->writeToTerminal((out.text + "\r\n").toUtf8(), false);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
m_resultTerminal->writeToTerminal(
|
|
|
|
|
QString("ASM generation compiler returned: %1\r\n\r\n").arg(r.code).toUtf8(), true);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
if (r.execResult) {
|
|
|
|
|
for (const auto &err : r.execResult->buildResult.stdErr)
|
2023-07-06 14:11:36 +02:00
|
|
|
m_resultTerminal->writeToTerminal((err.text + "\r\n").toUtf8(), false);
|
2023-09-21 09:32:07 +02:00
|
|
|
for (const auto &out : r.execResult->buildResult.stdOut)
|
2023-07-06 14:11:36 +02:00
|
|
|
m_resultTerminal->writeToTerminal((out.text + "\r\n").toUtf8(), false);
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
m_resultTerminal
|
|
|
|
|
->writeToTerminal(QString("Execution build compiler returned: %1\r\n\r\n")
|
|
|
|
|
.arg(r.execResult->buildResult.code)
|
|
|
|
|
.toUtf8(),
|
|
|
|
|
true);
|
|
|
|
|
|
|
|
|
|
if (r.execResult->didExecute) {
|
|
|
|
|
m_resultTerminal->writeToTerminal(QString("Program returned: %1\r\n")
|
|
|
|
|
.arg(r.execResult->code)
|
|
|
|
|
.toUtf8(),
|
|
|
|
|
true);
|
|
|
|
|
|
|
|
|
|
for (const auto &err : r.execResult->stdErrLines)
|
|
|
|
|
m_resultTerminal
|
|
|
|
|
->writeToTerminal((" \033[0;31m" + err + "\033[0m\r\n\r\n").toUtf8(),
|
|
|
|
|
false);
|
|
|
|
|
for (const auto &out : r.execResult->stdOutLines)
|
|
|
|
|
m_resultTerminal->writeToTerminal((out + "\r\n").toUtf8(), false);
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
2023-09-21 09:32:07 +02:00
|
|
|
}
|
|
|
|
|
qDeleteAll(m_marks);
|
|
|
|
|
m_marks.clear();
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
QString asmText;
|
|
|
|
|
for (auto l : r.assemblyLines)
|
|
|
|
|
asmText += l.text + "\n";
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
m_asmDocument->setPlainText(asmText);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
int i = 0;
|
|
|
|
|
for (auto l : r.assemblyLines) {
|
|
|
|
|
i++;
|
|
|
|
|
if (l.opcodes.empty())
|
|
|
|
|
continue;
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
auto mark = new TextMark(m_asmDocument.get(), i, TextMarkCategory{"Bytes", "Bytes"});
|
|
|
|
|
mark->setLineAnnotation(l.opcodes.join(' '));
|
|
|
|
|
m_marks.append(mark);
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
2023-09-21 09:32:07 +02:00
|
|
|
} catch (const std::exception &e) {
|
|
|
|
|
qCritical() << "Exception: " << e.what();
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-07-06 14:11:36 +02:00
|
|
|
|
|
|
|
|
m_compileWatcher->setFuture(f);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
EditorWidget::EditorWidget(const QSharedPointer<JsonSettingsDocument> &document,
|
|
|
|
|
QUndoStack *undoStack,
|
|
|
|
|
TextEditorActionHandler &actionHandler,
|
|
|
|
|
QWidget *parent)
|
2023-07-06 14:11:36 +02:00
|
|
|
: Utils::FancyMainWindow(parent)
|
2023-08-17 08:50:33 +02:00
|
|
|
, m_document(document)
|
2023-09-26 10:28:49 +02:00
|
|
|
, m_undoStack(undoStack)
|
|
|
|
|
, m_actionHandler(actionHandler)
|
2023-07-06 14:11:36 +02:00
|
|
|
{
|
|
|
|
|
setAutoHideTitleBars(false);
|
|
|
|
|
setDockNestingEnabled(true);
|
|
|
|
|
setDocumentMode(true);
|
|
|
|
|
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::TabPosition::South);
|
|
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
document->setWindowStateCallback([this] { return windowStateCallback(); });
|
|
|
|
|
|
|
|
|
|
document->settings()->m_sources.setItemAddedCallback<SourceSettings>(
|
|
|
|
|
[this](const std::shared_ptr<SourceSettings> &source) { addSourceEditor(source); });
|
|
|
|
|
|
|
|
|
|
document->settings()->m_sources.setItemRemovedCallback<SourceSettings>(
|
|
|
|
|
[this](const std::shared_ptr<SourceSettings> &source) { removeSourceEditor(source); });
|
|
|
|
|
|
|
|
|
|
connect(document.get(),
|
|
|
|
|
&JsonSettingsDocument::settingsChanged,
|
|
|
|
|
this,
|
|
|
|
|
&EditorWidget::recreateEditors);
|
|
|
|
|
|
|
|
|
|
connect(this, &EditorWidget::gotFocus, this, [&actionHandler] {
|
|
|
|
|
actionHandler.updateCurrentEditor();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_context = new Core::IContext(this);
|
|
|
|
|
m_context->setWidget(this);
|
|
|
|
|
m_context->setContext(Core::Context(Constants::CE_EDITOR_CONTEXT_ID));
|
|
|
|
|
Core::ICore::addContextObject(m_context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorWidget::~EditorWidget()
|
|
|
|
|
{
|
|
|
|
|
m_compilerWidgets.clear();
|
|
|
|
|
m_sourceWidgets.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorWidget::focusInEvent(QFocusEvent *event)
|
|
|
|
|
{
|
|
|
|
|
emit gotFocus();
|
|
|
|
|
FancyMainWindow::focusInEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorWidget::addCompiler(const std::shared_ptr<SourceSettings> &sourceSettings,
|
|
|
|
|
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
|
|
|
|
int idx,
|
|
|
|
|
QDockWidget *parentDockWidget)
|
|
|
|
|
{
|
|
|
|
|
auto compiler = new CompilerWidget(sourceSettings, compilerSettings);
|
|
|
|
|
compiler->setWindowTitle("Compiler #" + QString::number(idx));
|
|
|
|
|
compiler->setObjectName("compiler_" + QString::number(idx));
|
|
|
|
|
QDockWidget *dockWidget = addDockForWidget(compiler, parentDockWidget);
|
|
|
|
|
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
|
|
|
|
|
m_compilerWidgets.append(dockWidget);
|
|
|
|
|
|
|
|
|
|
connect(compiler,
|
|
|
|
|
&CompilerWidget::remove,
|
|
|
|
|
this,
|
|
|
|
|
[sourceSettings = sourceSettings.get(), compilerSettings = compilerSettings.get()] {
|
|
|
|
|
sourceSettings->compilers.removeItem(compilerSettings->shared_from_this());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(compiler, &CompilerWidget::gotFocus, this, [this]() {
|
|
|
|
|
m_actionHandler.updateCurrentEditor();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap EditorWidget::windowStateCallback()
|
|
|
|
|
{
|
|
|
|
|
auto settings = saveSettings();
|
|
|
|
|
QVariantMap result;
|
|
|
|
|
|
|
|
|
|
for (const auto &key : settings.keys()) {
|
|
|
|
|
// QTBUG-116339
|
|
|
|
|
if (key != "State") {
|
|
|
|
|
result.insert(key, settings.value(key));
|
|
|
|
|
} else {
|
|
|
|
|
QVariantMap m;
|
|
|
|
|
m["type"] = "Base64";
|
|
|
|
|
m["value"] = settings.value(key).toByteArray().toBase64();
|
|
|
|
|
result.insert(key, m);
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
2023-09-26 10:28:49 +02:00
|
|
|
}
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorWidget::addSourceEditor(const std::shared_ptr<SourceSettings> &sourceSettings)
|
|
|
|
|
{
|
|
|
|
|
auto sourceEditor = new SourceEditorWidget(sourceSettings, m_undoStack);
|
|
|
|
|
sourceEditor->setWindowTitle("Source Code #" + QString::number(m_sourceWidgets.size() + 1));
|
|
|
|
|
sourceEditor->setObjectName("source_code_editor_" + QString::number(m_sourceWidgets.size() + 1));
|
|
|
|
|
|
|
|
|
|
QDockWidget *dockWidget = addDockForWidget(sourceEditor);
|
|
|
|
|
connect(sourceEditor, &SourceEditorWidget::remove, this, [this, sourceSettings]() {
|
|
|
|
|
m_undoStack->beginMacro("Remove source");
|
|
|
|
|
sourceSettings->compilers.clear();
|
|
|
|
|
m_document->settings()->m_sources.removeItem(sourceSettings->shared_from_this());
|
|
|
|
|
m_undoStack->endMacro();
|
|
|
|
|
|
|
|
|
|
setupHelpWidget();
|
2023-08-17 08:50:33 +02:00
|
|
|
});
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
connect(sourceEditor, &SourceEditorWidget::addCompiler, this, [sourceSettings]() {
|
|
|
|
|
auto newCompiler = std::make_shared<CompilerSettings>(sourceSettings->apiConfigFunction());
|
|
|
|
|
newCompiler->setLanguageId(sourceSettings->languageId());
|
|
|
|
|
sourceSettings->compilers.addItem(newCompiler);
|
|
|
|
|
});
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
connect(sourceEditor, &SourceEditorWidget::gotFocus, this, [this]() {
|
|
|
|
|
m_actionHandler.updateCurrentEditor();
|
|
|
|
|
});
|
2023-09-21 09:32:07 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
|
|
|
|
|
|
|
|
|
|
sourceSettings->compilers.forEachItem<CompilerSettings>(
|
|
|
|
|
[this, sourceSettings, dockWidget](const std::shared_ptr<CompilerSettings> &compilerSettings,
|
|
|
|
|
int idx) {
|
|
|
|
|
addCompiler(sourceSettings, compilerSettings, idx + 1, dockWidget);
|
2023-09-21 09:32:07 +02:00
|
|
|
});
|
|
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
sourceSettings->compilers.setItemAddedCallback<CompilerSettings>(
|
|
|
|
|
[this, sourceSettings, dockWidget](
|
|
|
|
|
const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
|
|
|
|
addCompiler(sourceSettings->shared_from_this(),
|
|
|
|
|
compilerSettings,
|
|
|
|
|
sourceSettings->compilers.size(),
|
|
|
|
|
dockWidget);
|
|
|
|
|
});
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
sourceSettings->compilers.setItemRemovedCallback<CompilerSettings>(
|
|
|
|
|
[this, sourceSettings](const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
|
|
|
|
auto it = std::find_if(m_compilerWidgets.begin(),
|
|
|
|
|
m_compilerWidgets.end(),
|
|
|
|
|
[compilerSettings](const QDockWidget *c) {
|
|
|
|
|
return static_cast<CompilerWidget *>(c->widget())
|
|
|
|
|
->m_compilerSettings
|
|
|
|
|
== compilerSettings;
|
|
|
|
|
});
|
|
|
|
|
QTC_ASSERT(it != m_compilerWidgets.end(), return);
|
|
|
|
|
delete *it;
|
|
|
|
|
m_compilerWidgets.erase(it);
|
|
|
|
|
});
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
m_sourceWidgets.append(dockWidget);
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
setupHelpWidget();
|
|
|
|
|
}
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
void EditorWidget::removeSourceEditor(const std::shared_ptr<SourceSettings> &sourceSettings)
|
|
|
|
|
{
|
|
|
|
|
auto it
|
|
|
|
|
= std::find_if(m_sourceWidgets.begin(),
|
|
|
|
|
m_sourceWidgets.end(),
|
|
|
|
|
[sourceSettings](const QDockWidget *c) {
|
|
|
|
|
return static_cast<SourceEditorWidget *>(c->widget())->sourceSettings()
|
|
|
|
|
== sourceSettings.get();
|
|
|
|
|
});
|
|
|
|
|
QTC_ASSERT(it != m_sourceWidgets.end(), return);
|
|
|
|
|
delete *it;
|
|
|
|
|
m_sourceWidgets.erase(it);
|
|
|
|
|
}
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
void EditorWidget::recreateEditors()
|
|
|
|
|
{
|
|
|
|
|
qDeleteAll(m_sourceWidgets);
|
|
|
|
|
qDeleteAll(m_compilerWidgets);
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
m_sourceWidgets.clear();
|
|
|
|
|
m_compilerWidgets.clear();
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
m_document->settings()->m_sources.forEachItem<SourceSettings>(
|
|
|
|
|
[this](const auto &sourceSettings) { addSourceEditor(sourceSettings); });
|
|
|
|
|
|
|
|
|
|
QVariantMap windowState = m_document->settings()->windowState.value();
|
|
|
|
|
|
|
|
|
|
if (!windowState.isEmpty()) {
|
|
|
|
|
QHash<QString, QVariant> hashMap;
|
|
|
|
|
for (const auto &key : windowState.keys()) {
|
|
|
|
|
if (key != "State")
|
|
|
|
|
hashMap.insert(key, windowState.value(key));
|
|
|
|
|
else {
|
|
|
|
|
QVariant v = windowState.value(key);
|
|
|
|
|
if (v.userType() == QMetaType::QByteArray) {
|
|
|
|
|
hashMap.insert(key, v);
|
|
|
|
|
} else if (v.userType() == QMetaType::QVariantMap) {
|
|
|
|
|
QVariantMap m = v.toMap();
|
|
|
|
|
if (m.value("type") == "Base64") {
|
|
|
|
|
hashMap.insert(key, QByteArray::fromBase64(m.value("value").toByteArray()));
|
2023-08-17 08:50:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
restoreSettings(hashMap);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
void EditorWidget::setupHelpWidget()
|
|
|
|
|
{
|
|
|
|
|
if (m_document->settings()->m_sources.size() == 0) {
|
|
|
|
|
setCentralWidget(createHelpWidget());
|
|
|
|
|
} else {
|
|
|
|
|
delete takeCentralWidget();
|
|
|
|
|
}
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-26 10:28:49 +02:00
|
|
|
QWidget *EditorWidget::createHelpWidget() const
|
2023-07-06 14:11:36 +02:00
|
|
|
{
|
2023-09-26 10:28:49 +02:00
|
|
|
using namespace Layouting;
|
|
|
|
|
|
|
|
|
|
auto addSourceButton = new QPushButton(Tr::tr("Add source code"));
|
|
|
|
|
connect(addSourceButton, &QPushButton::clicked, this, [this] {
|
|
|
|
|
auto newSource = std::make_shared<SourceSettings>(
|
|
|
|
|
[settings = m_document->settings()] { return settings->apiConfig(); });
|
|
|
|
|
m_document->settings()->m_sources.addItem(newSource);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
return Column {
|
|
|
|
|
st,
|
|
|
|
|
Row {
|
|
|
|
|
st,
|
|
|
|
|
Column {
|
|
|
|
|
Tr::tr("No source code added yet. Add one using the button below."),
|
|
|
|
|
Row { st, addSourceButton, st }
|
|
|
|
|
},
|
|
|
|
|
st,
|
|
|
|
|
},
|
|
|
|
|
st,
|
|
|
|
|
}.emerge();
|
|
|
|
|
// clang-format on
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
TextEditor::TextEditorWidget *EditorWidget::focusedEditorWidget() const
|
|
|
|
|
{
|
|
|
|
|
for (const QDockWidget *sourceWidget : m_sourceWidgets) {
|
|
|
|
|
TextEditorWidget *textEditor
|
|
|
|
|
= qobject_cast<SourceEditorWidget *>(sourceWidget->widget())->textEditor();
|
|
|
|
|
if (textEditor->hasFocus())
|
|
|
|
|
return textEditor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const QDockWidget *compilerWidget : m_compilerWidgets) {
|
|
|
|
|
TextEditorWidget *textEditor
|
|
|
|
|
= qobject_cast<CompilerWidget *>(compilerWidget->widget())->textEditor();
|
|
|
|
|
if (textEditor->hasFocus())
|
|
|
|
|
return textEditor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-06 14:11:36 +02:00
|
|
|
class Editor : public Core::IEditor
|
|
|
|
|
{
|
|
|
|
|
public:
|
2023-09-21 09:32:07 +02:00
|
|
|
Editor(TextEditorActionHandler &actionHandler)
|
|
|
|
|
: m_document(new JsonSettingsDocument(&m_undoStack))
|
2023-07-06 14:11:36 +02:00
|
|
|
{
|
2023-09-21 09:32:07 +02:00
|
|
|
setWidget(new EditorWidget(m_document, &m_undoStack, actionHandler));
|
|
|
|
|
|
|
|
|
|
connect(&m_undoStack, &QUndoStack::canUndoChanged, this, [&actionHandler] {
|
|
|
|
|
actionHandler.updateActions();
|
|
|
|
|
});
|
|
|
|
|
connect(&m_undoStack, &QUndoStack::canRedoChanged, this, [&actionHandler] {
|
|
|
|
|
actionHandler.updateActions();
|
|
|
|
|
});
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
~Editor()
|
|
|
|
|
{
|
|
|
|
|
if (m_document->isModified()) {
|
|
|
|
|
auto settings = m_document->settings();
|
|
|
|
|
if (settings->isDirty()) {
|
|
|
|
|
settings->apply();
|
|
|
|
|
Utils::Store store;
|
|
|
|
|
settings->toMap(store);
|
|
|
|
|
QJsonDocument doc = QJsonDocument::fromVariant(Utils::mapFromStore(store));
|
|
|
|
|
|
|
|
|
|
CompilerExplorer::settings().defaultDocument.setValue(
|
|
|
|
|
QString::fromUtf8(doc.toJson()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete widget();
|
|
|
|
|
}
|
2023-08-17 08:50:33 +02:00
|
|
|
|
2023-07-06 14:11:36 +02:00
|
|
|
Core::IDocument *document() const override { return m_document.data(); }
|
|
|
|
|
QWidget *toolBar() override { return nullptr; }
|
|
|
|
|
|
2023-08-17 08:50:33 +02:00
|
|
|
QSharedPointer<JsonSettingsDocument> m_document;
|
2023-09-21 09:32:07 +02:00
|
|
|
QUndoStack m_undoStack;
|
2023-07-06 14:11:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EditorFactory::EditorFactory()
|
|
|
|
|
: m_actionHandler(Constants::CE_EDITOR_ID,
|
|
|
|
|
Constants::CE_EDITOR_CONTEXT_ID,
|
|
|
|
|
TextEditor::TextEditorActionHandler::None,
|
|
|
|
|
[](Core::IEditor *editor) -> TextEditorWidget * {
|
2023-09-21 09:32:07 +02:00
|
|
|
return static_cast<EditorWidget *>(editor->widget())->focusedEditorWidget();
|
2023-07-06 14:11:36 +02:00
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
setId(Constants::CE_EDITOR_ID);
|
|
|
|
|
setDisplayName(Tr::tr("Compiler Explorer Editor"));
|
2023-08-24 13:24:05 +02:00
|
|
|
setMimeTypes({"application/compiler-explorer"});
|
2023-07-06 14:11:36 +02:00
|
|
|
|
2023-09-21 09:32:07 +02:00
|
|
|
auto undoStackFromEditor = [](Core::IEditor *editor) -> QUndoStack * {
|
|
|
|
|
if (!editor)
|
|
|
|
|
return nullptr;
|
|
|
|
|
return &static_cast<Editor *>(editor)->m_undoStack;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
m_actionHandler.setCanUndoCallback([undoStackFromEditor](Core::IEditor *editor) {
|
|
|
|
|
if (auto undoStack = undoStackFromEditor(editor))
|
|
|
|
|
return undoStack->canUndo();
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_actionHandler.setCanRedoCallback([undoStackFromEditor](Core::IEditor *editor) {
|
|
|
|
|
if (auto undoStack = undoStackFromEditor(editor))
|
|
|
|
|
return undoStack->canRedo();
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setEditorCreator([this]() { return new Editor(m_actionHandler); });
|
2023-07-06 14:11:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace CompilerExplorer
|